Skip to content

Commit

Permalink
Fix resolve duplicate modal crash with object values (#3026)
Browse files Browse the repository at this point in the history
* fix(crash): better handling of typography/composite tokens for resolve duplicate modal token value preview

* fix: array box shadow preview in duplicate resolve modal

* test(coverage): add duplicate composition token

* fix(ui): use single bg colour for string value in duplicate token modal

---------

Co-authored-by: macintoshhelper <6757532+macintoshhelper@users.noreply.github.com>
  • Loading branch information
macintoshhelper and macintoshhelper authored Jul 26, 2024
1 parent f178cdc commit 49dfc25
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { useUIDSeed } from 'react-uid';
import {
Heading, RadioGroup, RadioIndicator, RadioItem, RadioItemBefore,
Stack,
Expand All @@ -7,8 +8,13 @@ import {
} from '@tokens-studio/ui';
import { SingleToken } from '@/types/tokens';
import Box from '../Box';
import { TokenTooltipContentValue } from '../TokenTooltip/TokenTooltipContentValue';
import { isSingleBoxShadowToken } from '@/utils/is';
import { SingleShadowValueDisplay } from '../TokenTooltip/SingleShadowValueDisplay';
import { TokenBoxshadowValue } from '@/types/values';

function ResolveDuplicateTokenSingle({ token }: { token: SingleToken }) {
const seed = useUIDSeed();
return (
<Tooltip label={`Type: ${token.type}`}>
<Box
Expand All @@ -20,9 +26,24 @@ function ResolveDuplicateTokenSingle({ token }: { token: SingleToken }) {
border: (typeof token.value === 'string' && (token.value as string).startsWith('#')) ? `1px solid ${token.value as string}` : undefined,
}}
>
<Text>
{token.value as string}
</Text>
{(isSingleBoxShadowToken(token) && Array.isArray(token.value)) ? (
<Stack direction="column" align="start" gap={3} wrap>
{token.value.map((t, index) => (
<SingleShadowValueDisplay
key={seed(t)}
value={Array.isArray(token.value) ? token.value[index] as TokenBoxshadowValue : undefined}
resolvedValue={t as TokenBoxshadowValue}
/>
))}
</Stack>
) : (
<>
{/* Comment to avoid nested ternary warning */}
{typeof token.value === 'string' ? <Text>{token.value as string}</Text>
: <TokenTooltipContentValue token={token} ignoreResolvedValue />}
</>

)}
</Box>
</Tooltip>
);
Expand All @@ -47,7 +68,10 @@ export default function ResolveDuplicateTokenGroup({
key={`${groupKey}`}
>
<Stack direction="row" css={{ marginBottom: '$4' }}>
<Heading size="small"><Box as="span" css={{ minWidth: '$9', display: 'inline-flex' }}>Token</Box>{groupKey}</Heading>
<Heading size="small">
<Box as="span" css={{ minWidth: '$9', display: 'inline-flex' }}>Token</Box>
{groupKey}
</Heading>
</Stack>
<Stack direction="row">
<Heading size="small" css={{ minWidth: '$9' }}>Value</Heading>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ import { CompositionTokenValue } from '@/types/CompositionTokenProperty';
type Props = {
property: string;
value: SingleToken['value'] | number;
resolvedValue: CompositionTokenValue | number;
resolvedValue: CompositionTokenValue | number | false;
};

export const SingleCompositionValueDisplay: React.FC<React.PropsWithChildren<React.PropsWithChildren<Props>>> = ({ property, value, resolvedValue }) => (
<TooltipProperty
label={property}
value={typeof value === 'string' || typeof value === 'number' ? value : '…'}
resolvedValue={typeof resolvedValue === 'string' || typeof resolvedValue === 'number' ? resolvedValue : '…'}
/>
);
export const SingleCompositionValueDisplay: React.FC<React.PropsWithChildren<React.PropsWithChildren<Props>>> = ({ property, value, resolvedValue }) => {
const resolvedValueString = (typeof resolvedValue === 'string' || typeof resolvedValue === 'number' || resolvedValue === undefined) ? resolvedValue : '…';
return (
<TooltipProperty
label={property}
value={typeof value === 'string' || typeof value === 'number' ? value : '…'}
resolvedValue={(resolvedValue === false) ? undefined : resolvedValueString}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Stack from '../Stack';

type Props = {
value: TokenTypographyValue;
resolvedValue: TokenTypographyValue;
resolvedValue?: TokenTypographyValue;
};

export const SingleTypographyValueDisplay: React.FC<React.PropsWithChildren<React.PropsWithChildren<Props>>> = ({ value, resolvedValue }) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,19 @@ import { SingleColorValueDisplay } from './SingleColorValueDisplay';

type Props = {
token: SingleToken;
ignoreResolvedValue?: boolean;
};

// Returns token value in display format
export const TokenTooltipContentValue: React.FC<React.PropsWithChildren<React.PropsWithChildren<Props>>> = ({ token }) => {
export const TokenTooltipContentValue: React.FC<React.PropsWithChildren<React.PropsWithChildren<Props>>> = ({ token, ignoreResolvedValue }) => {
const seed = useUIDSeed();
const tokensContext = React.useContext(TokensContext);
const { getTokenValue } = useTokens();
const resolvedValue = React.useMemo(() => getTokenValue(token.name, tokensContext.resolvedTokens)?.value, [
const resolvedValue = React.useMemo(() => (ignoreResolvedValue ? undefined : getTokenValue(token.name, tokensContext.resolvedTokens)?.value), [
token,
getTokenValue,
tokensContext.resolvedTokens,
ignoreResolvedValue,
]);

if (isSingleTypographyToken(token, true)) {
Expand All @@ -43,7 +45,7 @@ export const TokenTooltipContentValue: React.FC<React.PropsWithChildren<React.Pr
}

if (
resolvedValue
(resolvedValue || ignoreResolvedValue)
&& typeof resolvedValue !== 'string'
&& !Array.isArray(resolvedValue)
&& isSingleCompositionToken(token, true)
Expand All @@ -56,7 +58,7 @@ export const TokenTooltipContentValue: React.FC<React.PropsWithChildren<React.Pr
property={property}
value={value}
// @TODO strengthen the type checking here
resolvedValue={get(resolvedValue, property) as CompositionTokenValue}
resolvedValue={ignoreResolvedValue ? false : get(resolvedValue as SingleToken, property) as CompositionTokenValue}
/>
))}
</Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { createMockStore, render, waitFor } from '../../../../tests/config/setup
import { TokenTypes } from '@/constants/TokenTypes';

import TokensBottomBar from '../TokensBottomBar';
import { BoxShadowTypes } from '@/constants/BoxShadowTypes';

function emptyFunc() {}

Expand Down Expand Up @@ -59,6 +60,66 @@ describe('TokenBottomBar', () => {
value: '#000000',
description: 'regular color token',
},
{
name: 'boxShadow.default',
type: TokenTypes.BOX_SHADOW,
value: [
{
x: '4',
y: '0',
blur: '0',
spread: '0',
color: '#000000',
type: BoxShadowTypes.INNER_SHADOW,
},
{
x: '4',
y: '0',
blur: '0',
spread: '0',
color: '#000000',
type: BoxShadowTypes.INNER_SHADOW,
},
],
},
{
name: 'boxShadow.default',
type: TokenTypes.BOX_SHADOW,
value: [
{
x: '2',
y: '0',
blur: '0',
spread: '0',
color: '#000000',
type: BoxShadowTypes.INNER_SHADOW,
},
{
x: '2',
y: '0',
blur: '0',
spread: '0',
color: '#000000',
type: BoxShadowTypes.INNER_SHADOW,
},
],
},
{
name: 'composition.default',
type: TokenTypes.COMPOSITION,
value: {
height: '20px',
minHeight: '20px',
},
},
{
name: 'composition.default',
type: TokenTypes.COMPOSITION,
value: {
height: '40px',
minHeight: '40px',
},
},
],
},
},
Expand Down

0 comments on commit 49dfc25

Please sign in to comment.