import { Box } from '@luke-ui/react/box'; import { Button } from '@luke-ui/react/button'; import { Cluster } from '@luke-ui/react/cluster'; import { Icon } from '@luke-ui/react/icon'; import { Stack } from '@luke-ui/react/stack'; import { Text } from '@luke-ui/react/text'; import { TextInputField } from '@luke-ui/react/text-input-field'; import { vars } from '@luke-ui/react/theme'; import { cx } from '@luke-ui/react/utils'; import type { CSSProperties, JSX, ReactNode } from 'react'; import { useState } from 'react'; import { Button as RacButton } from 'react-aria-components/Button'; import { Disclosure, DisclosurePanel } from 'react-aria-components/Disclosure'; import { Heading } from 'react-aria-components/Heading'; import type { ThemeToken, ThemeTokenFamily } from '../generated/token-reference.generated.js'; import { themeTokens } from '../generated/token-reference.generated.js'; import type { TokenPurposeGroup } from '../lib/token-purpose-groups.js'; import { tokenPurposeGroups } from '../lib/token-purpose-groups.js'; import { DocsLink } from './docs-link.js'; const TOTAL_TOKEN_COUNT = themeTokens.length; const VARIABLE_BY_PATH = new Map(themeTokens.map((token) => [token.path, token.variable])); const MOTION_KEYFRAMES = `@keyframes luke-docs-token-motion { from { transform: translateX(-0.75rem); } to { transform: translateX(0.75rem); } } @media (prefers-reduced-motion: reduce) { [data-token-motion] { animation: none !important; } }`; const FALLBACK_MOTION_DURATION = '0.9s'; const FALLBACK_MOTION_EASING = 'ease-in-out'; const stageStyle = { borderColor: vars.color.border.decorative, borderRadius: vars.radius.detail, borderStyle: 'solid', borderWidth: 1, } as const satisfies CSSProperties; /** Purpose-grouped index of every public token, sampled in the active theme. */ export function TokenExplorer(): JSX.Element { const [filter, setFilter] = useState(''); const query = filter.trim().toLowerCase(); const groups = matchGroups(query); const matchCount = groups.reduce((total, group) => total + group.tokens.length, 0); const countText = query === '' ? `${TOTAL_TOKEN_COUNT} tokens` : `${matchCount} of ${TOTAL_TOKEN_COUNT}`; return ( } size="small" value={filter} /> {countText} {groups.length === 0 ? ( setFilter('')} query={filter.trim()} /> ) : ( groups.map((group) => ) )} ); } function matchGroups(query: string): ReadonlyArray { if (query === '') return tokenPurposeGroups; return tokenPurposeGroups.flatMap((group) => { if (group.title.toLowerCase().includes(query)) return [group]; const tokens = group.tokens.filter((token) => { return ( token.path.toLowerCase().includes(query) || token.variable.toLowerCase().includes(query) ); }); return tokens.length === 0 ? [] : [{ ...group, tokens }]; }); } function PurposeDetails({ group }: { group: TokenPurposeGroup }) { return ( {group.title} {group.tokens.length} {group.description} {group.related ? ( {group.related.label} ) : null} ); } function TokenTable({ showSamples, tokens, }: { showSamples: boolean; tokens: ReadonlyArray; }) { return (
{showSamples ? ( ) : null} {tokens.map((token) => ( {showSamples ? ( ) : null} ))}
Sample vars path CSS variable
{token.path} {token.variable}
); } function TokenSample({ token }: { token: ThemeToken }) { const Sample = FAMILY_SAMPLES[token.family]; return ; } function SampleFrame({ children, className, justifyContent = 'center', paddingInline, style, }: { children?: ReactNode; className?: string; justifyContent?: 'center' | 'flex-start'; paddingInline?: 'sp8'; style?: CSSProperties; }): JSX.Element { return ( {children} ); } function ColorSample({ variable }: ThemeToken) { return ( ); } function DepthSample({ variable }: ThemeToken) { return ( ); } function FinishSample({ variable }: ThemeToken) { return ( ); } function RadiusSample({ variable }: ThemeToken) { return ( ); } function SpaceSample({ variable }: ThemeToken) { return ( ); } function SizeSample({ variable }: ThemeToken) { return ( ); } function InteractionSample({ variable }: ThemeToken) { return ( ); } function MotionSample({ path, variable }: ThemeToken) { const axis = path.split('.')[1]; return ( ); } function TextSample({ children = 'Aa', style }: { children?: ReactNode; style: CSSProperties }) { return ( {children} ); } function TrimSample({ property, variable, }: { property: 'marginBlockEnd' | 'marginBlockStart'; variable: string; }) { return ( ); } function FontSample({ path, variable }: ThemeToken) { const [, section, property] = path.split('.'); if (section === 'family') return ; if (section === 'weight') return ; const stepFontSizeVariable = VARIABLE_BY_PATH.get(`font.${section}.fontSize`); const fontSize = stepFontSizeVariable ? `var(${stepFontSizeVariable})` : undefined; if (property === 'fontSize') return ; if (property === 'lineHeight') { return ( Aa
Aa
); } if (property === 'letterSpacing') { return ; } if (property === 'baselineTrim') { return ; } if (property === 'capHeightTrim') { return ; } return ; } const FAMILY_SAMPLES: Record ReactNode> = { actionControlFinish: FinishSample, color: ColorSample, controlSize: SizeSample, depth: DepthSample, font: FontSample, iconSize: SizeSample, interaction: InteractionSample, motion: MotionSample, radius: RadiusSample, space: SpaceSample, }; function EmptyState({ onClear, query }: { onClear: () => void; query: string }) { return ( No token matches "{query}" ); }