import React, { FC, useState } from 'react';
import { styled } from '@storybook/theming';
import memoize from 'memoizerific';
import uniq from 'lodash/uniq';
import { PropSummaryValue } from './types';
import { WithTooltipPure } from '../../tooltip/WithTooltip';
import { Icons } from '../../icon/icon';
import { SyntaxHighlighter } from '../../syntaxhighlighter/syntaxhighlighter';
import { codeCommon } from '../../typography/shared';
interface ArgValueProps {
value?: PropSummaryValue;
initialExpandedArgs?: boolean;
}
interface ArgTextProps {
text: string;
}
interface ArgSummaryProps {
value: PropSummaryValue;
initialExpandedArgs?: boolean;
}
const ITEMS_BEFORE_EXPANSION = 8;
const Summary = styled.div<{ isExpanded?: boolean }>(({ isExpanded }) => ({
display: 'flex',
flexDirection: isExpanded ? 'column' : 'row',
flexWrap: 'wrap',
alignItems: 'flex-start',
marginBottom: '-4px',
minWidth: 100,
}));
const Text = styled.span<{}>(codeCommon, ({ theme }) => ({
flex: '0 0 auto',
fontFamily: theme.typography.fonts.mono,
fontSize: theme.typography.size.s1,
wordBreak: 'break-word',
margin: 0,
marginRight: '4px',
marginBottom: '4px',
paddingTop: '2px',
paddingBottom: '2px',
lineHeight: '13px',
whiteSpace: 'normal',
maxWidth: '100%',
}));
const ExpandButton = styled.button<{}>(({ theme }) => ({
fontFamily: theme.typography.fonts.mono,
color: theme.color.secondary,
marginBottom: '4px',
background: 'none',
border: 'none',
}));
const Expandable = styled.div<{}>(codeCommon, ({ theme }) => ({
fontFamily: theme.typography.fonts.mono,
color: theme.color.secondary,
fontSize: theme.typography.size.s1, // overrides codeCommon
margin: 0,
whiteSpace: 'nowrap',
display: 'flex',
alignItems: 'center',
}));
const Detail = styled.div<{ width: string }>(({ theme, width }) => ({
width,
minWidth: 200,
maxWidth: 800,
padding: 15,
// Dont remove the mono fontFamily here even if it seem useless, this is used by the browser to calculate the length of a "ch" unit.
fontFamily: theme.typography.fonts.mono,
fontSize: theme.typography.size.s1,
// Most custom stylesheet will reset the box-sizing to "border-box" and will break the tooltip.
boxSizing: 'content-box',
'& code': {
padding: '0 !important',
},
}));
const ArrowIcon = styled(Icons)({
height: 10,
width: 10,
minWidth: 10,
marginLeft: 4,
});
const EmptyArg = () => {
return -;
};
const ArgText: FC = ({ text }) => {
return {text};
};
const calculateDetailWidth = memoize(1000)((detail: string): string => {
const lines = detail.split(/\r?\n/);
return `${Math.max(...lines.map((x) => x.length))}ch`;
});
const getSummaryItems = (summary: string) => {
if (!summary) return [summary];
const splittedItems = summary.split('|');
const summaryItems = splittedItems.map((value) => value.trim());
return uniq(summaryItems);
};
const renderSummaryItems = (summaryItems: string[], isExpanded = true) => {
let items = summaryItems;
if (!isExpanded) {
items = summaryItems.slice(0, ITEMS_BEFORE_EXPANSION);
}
return items.map((item) => );
};
const ArgSummary: FC = ({ value, initialExpandedArgs }) => {
const { summary, detail } = value;
const [isOpen, setIsOpen] = useState(false);
const [isExpanded, setIsExpanded] = useState(initialExpandedArgs || false);
if (summary === undefined || summary === null) return null;
// summary is used for the default value
// below check fixes not displaying default values for boolean typescript vars
const summaryAsString = typeof summary.toString === 'function' ? summary.toString() : summary;
if (detail == null) {
const summaryItems = getSummaryItems(summaryAsString);
const itemsCount = summaryItems.length;
const hasManyItems = itemsCount > ITEMS_BEFORE_EXPANSION;
return hasManyItems ? (
{renderSummaryItems(summaryItems, isExpanded)}
setIsExpanded(!isExpanded)}>
{isExpanded ? 'Show less...' : `Show ${itemsCount - ITEMS_BEFORE_EXPANSION} more...`}
) : (
{renderSummaryItems(summaryItems)}
);
}
return (
{
setIsOpen(isVisible);
}}
tooltip={
{detail}
}
>
{summaryAsString}
);
};
export const ArgValue: FC = ({ value, initialExpandedArgs }) => {
return value == null ? (
) : (
);
};