diff --git a/.changeset/gentle-suns-relax.md b/.changeset/gentle-suns-relax.md new file mode 100644 index 00000000000..8feb0399b49 --- /dev/null +++ b/.changeset/gentle-suns-relax.md @@ -0,0 +1,5 @@ +--- +'@shopify/polaris-tokens': major +--- + +Deprecated a collection of types, utils, and JSON exports diff --git a/polaris-for-vscode/src/server.ts b/polaris-for-vscode/src/server.ts index b2f0707aa1a..eeb47936342 100644 --- a/polaris-for-vscode/src/server.ts +++ b/polaris-for-vscode/src/server.ts @@ -1,5 +1,9 @@ -import {createVar, metadata} from '@shopify/polaris-tokens'; -import type {MetadataGroup} from '@shopify/polaris-tokens'; +import type {MetaTheme, MetaTokenGroupShape} from '@shopify/polaris-tokens'; +import { + createVarName, + metaThemeDefault, + isTokenName, +} from '@shopify/polaris-tokens'; import { createConnection, TextDocuments, @@ -19,16 +23,16 @@ const excludedTokenGroupNames = [] as const; type ExcludedTokenGroupName = typeof excludedTokenGroupNames[number]; -type TokenGroupName = Exclude; +type TokenGroupName = Exclude; const tokenGroups = Object.fromEntries( - Object.entries(metadata).filter( + Object.entries(metaThemeDefault).filter( ([tokenGroupName]) => !excludedTokenGroupNames.includes( tokenGroupName as ExcludedTokenGroupName, ), ), -) as unknown as Omit; +) as unknown as Omit; type TokenGroupCompletionItems = { [T in TokenGroupName]: CompletionItem[]; @@ -39,19 +43,25 @@ type TokenGroupCompletionItems = { */ const tokenGroupCompletionItems = Object.fromEntries( Object.entries(tokenGroups).map( - ([tokenGroupName, tokenGroup]: [string, MetadataGroup]) => { + ([tokenGroupName, tokenGroup]: [string, MetaTokenGroupShape]) => { const completionItems: CompletionItem[] = Object.entries(tokenGroup).map( - ([tokenName, tokenProperties]): CompletionItem => ({ - label: createVar(tokenName), - insertText: `${createVar(tokenName)}`, - detail: tokenProperties.value, - documentation: tokenProperties.description, - filterText: createVar(tokenName), - kind: - tokenGroupName === 'color' - ? CompletionItemKind.Color - : CompletionItemKind.Variable, - }), + ([tokenName, tokenProperties]): CompletionItem => { + if (!isTokenName(tokenName)) { + throw new Error(`Invalid token name: ${tokenName}`); + } + + return { + label: createVarName(tokenName), + insertText: `${createVarName(tokenName)}`, + detail: tokenProperties.value, + documentation: tokenProperties.description, + filterText: createVarName(tokenName), + kind: + tokenGroupName === 'color' + ? CompletionItemKind.Color + : CompletionItemKind.Variable, + }; + }, ); return [tokenGroupName, completionItems]; diff --git a/polaris-migrator/src/migrations/v9-scss-replace-color/transform.ts b/polaris-migrator/src/migrations/v9-scss-replace-color/transform.ts index 54d9d3ce508..106e7978b99 100644 --- a/polaris-migrator/src/migrations/v9-scss-replace-color/transform.ts +++ b/polaris-migrator/src/migrations/v9-scss-replace-color/transform.ts @@ -2,7 +2,6 @@ import type {FileInfo, API, Options} from 'jscodeshift'; import type {Plugin} from 'postcss'; import postcss from 'postcss'; import valueParser from 'postcss-value-parser'; -import {createVar} from '@shopify/polaris-tokens'; import type {NamespaceOptions} from '../../utilities/sass'; import { @@ -239,5 +238,7 @@ const propertyMaps = { }; const polarisCustomPropertyRegEx = new RegExp( - Object.keys(tokenColors).map(createVar).join('|'), + Object.keys(tokenColors) + .map((tokenName) => `--p-${tokenName}`) + .join('|'), ); diff --git a/polaris-migrator/src/utilities/sass.ts b/polaris-migrator/src/utilities/sass.ts index 40fdde08445..07c2f437031 100644 --- a/polaris-migrator/src/utilities/sass.ts +++ b/polaris-migrator/src/utilities/sass.ts @@ -18,14 +18,14 @@ import type { Dimension, } from 'postcss-value-parser'; import valueParser from 'postcss-value-parser'; -import {toPx, getCustomPropertyNames, tokens} from '@shopify/polaris-tokens'; +import {toPx, getThemeVarNames, themeDefault} from '@shopify/polaris-tokens'; import {POLARIS_MIGRATOR_COMMENT} from './constants'; const defaultNamespace = ''; -const polarisCustomPropertyRegEx = new RegExp( - getCustomPropertyNames(tokens).join('|'), +const themeVarNamesRegExp = new RegExp( + getThemeVarNames(themeDefault).join('|'), ); function getNamespace(options?: NamespaceOptions) { @@ -325,7 +325,7 @@ export function isTransformableDuration( export function isPolarisVar(node: Node): boolean { return ( isSassFunction('var', node) && - polarisCustomPropertyRegEx.test(node.nodes?.[0]?.value ?? '') + themeVarNamesRegExp.test(node.nodes?.[0]?.value ?? '') ); } diff --git a/polaris-react/src/components/ActionList/components/Item/Item.tsx b/polaris-react/src/components/ActionList/components/Item/Item.tsx index 2f8aea5d10d..daa1550f588 100644 --- a/polaris-react/src/components/ActionList/components/Item/Item.tsx +++ b/polaris-react/src/components/ActionList/components/Item/Item.tsx @@ -1,5 +1,4 @@ import React, {useRef, useState} from 'react'; -import {zIndex} from '@shopify/polaris-tokens'; import {classNames} from '../../../../utilities/css'; import type {ActionListItemDescriptor} from '../../../../types'; @@ -14,6 +13,7 @@ import {InlineStack} from '../../../InlineStack'; import {Box} from '../../../Box'; import {Tooltip} from '../../../Tooltip'; import {useIsomorphicLayoutEffect} from '../../../../utilities/use-isomorphic-layout-effect'; +import {useTheme} from '../../../../utilities/use-theme'; export type ItemProps = ActionListItemDescriptor; @@ -155,6 +155,7 @@ export function Item({ } export const TruncateText = ({children}: {children: string}) => { + const theme = useTheme(); const textRef = useRef(null); const [isOverflowing, setIsOverflowing] = useState(false); useIsomorphicLayoutEffect(() => { @@ -174,7 +175,7 @@ export const TruncateText = ({children}: {children: string}) => { return isOverflowing ? ( { }; const navigationMarkup = navigation ? ( - - - - - + + + + )} + ) : null; const loadingMarkup = diff --git a/polaris-react/src/components/IndexTable/IndexTable.tsx b/polaris-react/src/components/IndexTable/IndexTable.tsx index db7276dd631..73352705d0c 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.tsx @@ -1,7 +1,7 @@ import React, {useRef, useState, useEffect, useCallback, useMemo} from 'react'; import {SortAscendingMajor, SortDescendingMajor} from '@shopify/polaris-icons'; import {CSSTransition} from 'react-transition-group'; -import {tokens, toPx, motion} from '@shopify/polaris-tokens'; +import {themeDefault, toPx} from '@shopify/polaris-tokens'; import {debounce} from '../../utilities/debounce'; import {useToggle} from '../../utilities/use-toggle'; @@ -39,6 +39,7 @@ import type { Width, TooltipOverlayProps, } from '../Tooltip'; +import {useTheme} from '../../utilities/use-theme'; import {getTableHeadingsBySelector} from './utilities'; import {ScrollContainer, Cell, Row} from './components'; @@ -146,6 +147,8 @@ function IndexTableBase({ hasZebraStriping, ...restProps }: IndexTableBaseProps) { + const theme = useTheme(); + const { loading, bulkSelectState, @@ -546,7 +549,7 @@ function IndexTableBase({ { return typeof window === 'undefined' ? false : window.innerWidth < - parseFloat(toPx(tokens.breakpoints['breakpoints-sm']) ?? ''); + parseFloat(toPx(themeDefault.breakpoints['breakpoints-sm']) ?? ''); }; function getHeadingKey(heading: IndexTableHeading): string { diff --git a/polaris-react/src/components/Modal/components/Dialog/Dialog.tsx b/polaris-react/src/components/Modal/components/Dialog/Dialog.tsx index 1da7b01e6dc..625b5affa23 100644 --- a/polaris-react/src/components/Modal/components/Dialog/Dialog.tsx +++ b/polaris-react/src/components/Modal/components/Dialog/Dialog.tsx @@ -1,7 +1,6 @@ import React, {useContext, useRef, useEffect} from 'react'; import type {SetStateAction, Dispatch} from 'react'; import {Transition, CSSTransition} from 'react-transition-group'; -import {motion} from '@shopify/polaris-tokens'; import {classNames, variationName} from '../../../../utilities/css'; import {focusFirstFocusableNode} from '../../../../utilities/focus'; @@ -11,6 +10,7 @@ import {TrapFocus} from '../../../TrapFocus'; import type {ModalSize} from '../../Modal'; import {Text} from '../../../Text'; import {FrameContext} from '../../../../utilities/frame'; +import {useTheme} from '../../../../utilities/use-theme'; import styles from './Dialog.scss'; @@ -43,6 +43,7 @@ export function Dialog({ hasToasts, ...props }: DialogProps) { + const theme = useTheme(); const containerNode = useRef(null); const frameContext = useContext(FrameContext); let toastMessages; @@ -95,7 +96,7 @@ export function Dialog({ nodeRef={containerNode} mountOnEnter unmountOnExit - timeout={parseInt(motion['motion-duration-200'], 10)} + timeout={parseInt(theme.motion['motion-duration-200'], 10)} onEntered={onEntered} onExited={onExited} > diff --git a/polaris-react/src/components/PolarisTestProvider/PolarisTestProvider.tsx b/polaris-react/src/components/PolarisTestProvider/PolarisTestProvider.tsx index f5e5e954823..f232423d7c5 100644 --- a/polaris-react/src/components/PolarisTestProvider/PolarisTestProvider.tsx +++ b/polaris-react/src/components/PolarisTestProvider/PolarisTestProvider.tsx @@ -1,4 +1,6 @@ import React, {useMemo, Fragment, StrictMode} from 'react'; +import type {ThemeName} from '@shopify/polaris-tokens'; +import {themeNameDefault} from '@shopify/polaris-tokens'; import {PortalsManager} from '../PortalsManager'; import {FocusManager} from '../FocusManager'; @@ -19,6 +21,7 @@ import type {LinkLikeComponent} from '../../utilities/link'; import {FeaturesContext} from '../../utilities/features'; import type {FeaturesConfig} from '../../utilities/features'; import {EphemeralPresenceManager} from '../EphemeralPresenceManager'; +import {ThemeContext, getTheme} from '../../utilities/use-theme'; type FrameContextType = NonNullable>; type MediaQueryContextType = NonNullable< @@ -36,6 +39,7 @@ export interface WithPolarisTestProviderOptions { link?: LinkLikeComponent; mediaQuery?: Partial; features?: FeaturesConfig; + theme?: ThemeName; // Contexts provided by Frame frame?: Partial; } @@ -58,6 +62,7 @@ export function PolarisTestProvider({ mediaQuery, features, frame, + theme = themeNameDefault, }: PolarisTestProviderProps) { const Wrapper = strict ? StrictMode : Fragment; const intl = useMemo(() => new I18n(i18n || {}), [i18n]); @@ -71,27 +76,29 @@ export function PolarisTestProvider({ return ( - - - - - - - - - - - {children} - - - - - - - - - - + + + + + + + + + + + + {children} + + + + + + + + + + + ); } diff --git a/polaris-react/src/components/Popover/components/PopoverOverlay/PopoverOverlay.tsx b/polaris-react/src/components/Popover/components/PopoverOverlay/PopoverOverlay.tsx index 894550d273e..f974c8578ee 100644 --- a/polaris-react/src/components/Popover/components/PopoverOverlay/PopoverOverlay.tsx +++ b/polaris-react/src/components/Popover/components/PopoverOverlay/PopoverOverlay.tsx @@ -1,5 +1,5 @@ import React, {PureComponent, Children, createRef} from 'react'; -import {motion} from '@shopify/polaris-tokens'; +import {themeDefault} from '@shopify/polaris-tokens'; import {findFirstKeyboardFocusableNode} from '../../../../utilities/focus'; import {classNames} from '../../../../utilities/css'; @@ -106,7 +106,9 @@ export class PopoverOverlay extends PureComponent { this.clearTransitionTimeout(); this.enteringTimer = window.setTimeout(() => { this.setState({transitionStatus: TransitionStatus.Entered}); - }, parseInt(motion['motion-duration-100'], 10)); + // Important: This will not update when the active theme changes. + // Update this to `useTheme` once converted to a function component. + }, parseInt(themeDefault.motion['motion-duration-100'], 10)); }); } diff --git a/polaris-react/src/components/ProgressBar/ProgressBar.tsx b/polaris-react/src/components/ProgressBar/ProgressBar.tsx index 73dd5c33801..03edfce82bc 100644 --- a/polaris-react/src/components/ProgressBar/ProgressBar.tsx +++ b/polaris-react/src/components/ProgressBar/ProgressBar.tsx @@ -1,9 +1,9 @@ import React, {useRef} from 'react'; import {CSSTransition} from 'react-transition-group'; -import {motion} from '@shopify/polaris-tokens'; import {classNames, variationName} from '../../utilities/css'; import {useI18n} from '../../utilities/i18n'; +import {useTheme} from '../../utilities/use-theme'; import styles from './ProgressBar.scss'; @@ -44,6 +44,7 @@ export function ProgressBar({ animated: hasAppearAnimation = true, ariaLabelledBy, }: ProgressBarProps) { + const theme = useTheme(); const i18n = useI18n(); const indicatorRef = useRef(null); @@ -63,8 +64,8 @@ export function ProgressBar({ const parsedProgress = parseProgress(progress, warningMessage); const progressBarDuration = hasAppearAnimation - ? motion['motion-duration-500'] - : motion['motion-duration-0']; + ? theme.motion['motion-duration-500'] + : theme.motion['motion-duration-0']; /* eslint-disable @shopify/jsx-no-hardcoded-content */ return ( diff --git a/polaris-react/src/components/ResourceList/ResourceList.tsx b/polaris-react/src/components/ResourceList/ResourceList.tsx index 3b2eed60686..8afcca9ad8b 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.tsx @@ -7,7 +7,7 @@ import React, { Children, } from 'react'; import {EnableSelectionMinor} from '@shopify/polaris-icons'; -import {tokens, toPx} from '@shopify/polaris-tokens'; +import {themeDefault, toPx} from '@shopify/polaris-tokens'; import {debounce} from '../../utilities/debounce'; import {classNames} from '../../utilities/css'; @@ -54,7 +54,7 @@ const isBreakpointsXS = () => { return typeof window === 'undefined' ? false : window.innerWidth < - parseFloat(toPx(tokens.breakpoints['breakpoints-sm']) ?? ''); + parseFloat(toPx(themeDefault.breakpoints['breakpoints-sm']) ?? ''); }; function defaultIdForItem( diff --git a/polaris-react/src/components/Sheet/Sheet.tsx b/polaris-react/src/components/Sheet/Sheet.tsx index a7f8ae7f361..5bbbb6e8a95 100644 --- a/polaris-react/src/components/Sheet/Sheet.tsx +++ b/polaris-react/src/components/Sheet/Sheet.tsx @@ -1,6 +1,5 @@ import React, {useCallback, useRef, useEffect} from 'react'; import {CSSTransition} from 'react-transition-group'; -import {motion} from '@shopify/polaris-tokens'; import {focusFirstFocusableNode} from '../../utilities/focus'; import {useMediaQuery} from '../../utilities/media-query'; @@ -11,6 +10,7 @@ import {Backdrop} from '../Backdrop'; import {TrapFocus} from '../TrapFocus'; import {Portal} from '../Portal'; import {KeypressListener} from '../KeypressListener'; +import {useTheme} from '../../utilities/use-theme'; import styles from './Sheet.scss'; @@ -55,6 +55,7 @@ export function Sheet({ accessibilityLabel, activator, }: SheetProps) { + const theme = useTheme(); const {isNavigationCollapsed} = useMediaQuery(); const container = useRef(null); const activatorRef = useRef(null); @@ -94,7 +95,7 @@ export function Sheet({ classNames={ isNavigationCollapsed ? BOTTOM_CLASS_NAMES : RIGHT_CLASS_NAMES } - timeout={parseInt(motion['motion-duration-300'], 10)} + timeout={parseInt(theme.motion['motion-duration-300'], 10)} in={open} mountOnEnter unmountOnExit diff --git a/polaris-react/src/utilities/breakpoints.ts b/polaris-react/src/utilities/breakpoints.ts index a13de8d365e..accf3edc2b5 100644 --- a/polaris-react/src/utilities/breakpoints.ts +++ b/polaris-react/src/utilities/breakpoints.ts @@ -1,5 +1,5 @@ import {useState} from 'react'; -import {getMediaConditions, breakpoints} from '@shopify/polaris-tokens'; +import {getMediaConditions, themeDefault} from '@shopify/polaris-tokens'; import type { BreakpointsAlias, BreakpointsAliasDirection, @@ -56,7 +56,9 @@ type BreakpointsMatches = { [DirectionAlias in BreakpointsDirectionAlias]: boolean; }; -const breakpointsQueryEntries = getBreakpointsQueryEntries(breakpoints); +const breakpointsQueryEntries = getBreakpointsQueryEntries( + themeDefault.breakpoints, +); function getMatches(defaults?: UseBreakpointsOptions['defaults']) { if (!isServer) { diff --git a/polaris-react/src/utilities/sticky-manager/sticky-manager.ts b/polaris-react/src/utilities/sticky-manager/sticky-manager.ts index 399e85015f3..4997c542f54 100644 --- a/polaris-react/src/utilities/sticky-manager/sticky-manager.ts +++ b/polaris-react/src/utilities/sticky-manager/sticky-manager.ts @@ -1,4 +1,4 @@ -import {space} from '@shopify/polaris-tokens'; +import {themeDefault} from '@shopify/polaris-tokens'; import {debounce} from '../debounce'; import {dataPolarisTopBar, scrollable} from '../../components/shared'; @@ -135,7 +135,13 @@ export class StickyManager { } const stickyOffset = offset - ? this.getOffset(stickyNode) + parseInt(space['space-500'], 10) + ? this.getOffset(stickyNode) + + parseInt( + // Important: This will not update when the active theme changes. + // Update this to `useTheme` once converted to a function component. + themeDefault.space['space-500'], + 10, + ) : this.getOffset(stickyNode); const scrollPosition = scrollTop + stickyOffset; diff --git a/polaris-react/src/utilities/tests/use-breakpoints.test.tsx b/polaris-react/src/utilities/tests/use-breakpoints.test.tsx index b0883efa6ad..9e609b51461 100644 --- a/polaris-react/src/utilities/tests/use-breakpoints.test.tsx +++ b/polaris-react/src/utilities/tests/use-breakpoints.test.tsx @@ -1,13 +1,13 @@ import React from 'react'; import {mount} from 'tests/utilities'; import {matchMedia} from '@shopify/jest-dom-mocks'; -import {breakpoints, getMediaConditions} from '@shopify/polaris-tokens'; +import {themeDefault, getMediaConditions} from '@shopify/polaris-tokens'; import type {BreakpointsTokenName} from '@shopify/polaris-tokens'; import {useBreakpoints, getBreakpointsQueryEntries} from '../breakpoints'; import type {BreakpointsDirectionAlias} from '../breakpoints'; -const mediaConditions = getMediaConditions(breakpoints); +const mediaConditions = getMediaConditions(themeDefault.breakpoints); describe('useBreakpoints', () => { beforeEach(() => { @@ -124,7 +124,7 @@ function setMediaWidth(breakpointsTokenName: BreakpointsTokenName) { describe('getBreakpointsQueryEntries', () => { it('converts breakpoints tokens into entries with direction/alias names', () => { const directionAliases: BreakpointsDirectionAlias[] = - getBreakpointsQueryEntries(breakpoints).map( + getBreakpointsQueryEntries(themeDefault.breakpoints).map( ([directionAlias]) => directionAlias, ); diff --git a/polaris-react/src/utilities/use-theme.ts b/polaris-react/src/utilities/use-theme.ts index 33f0f33d4d2..39c7788036d 100644 --- a/polaris-react/src/utilities/use-theme.ts +++ b/polaris-react/src/utilities/use-theme.ts @@ -19,3 +19,9 @@ export function useTheme() { return theme; } + +export function UseTheme(props: {children(theme: Theme): JSX.Element}) { + const theme = useTheme(); + + return props.children(theme); +} diff --git a/polaris-react/tests/utilities/breakpoints.tsx b/polaris-react/tests/utilities/breakpoints.tsx index b15b24871f4..0636d694408 100644 --- a/polaris-react/tests/utilities/breakpoints.tsx +++ b/polaris-react/tests/utilities/breakpoints.tsx @@ -1,7 +1,7 @@ -import {breakpoints, getMediaConditions} from '@shopify/polaris-tokens'; +import {themeDefault, getMediaConditions} from '@shopify/polaris-tokens'; import type {BreakpointsTokenName} from '@shopify/polaris-tokens'; -const mediaConditions = getMediaConditions(breakpoints); +const mediaConditions = getMediaConditions(themeDefault.breakpoints); export function setMediaWidth(breakpointsTokenName: BreakpointsTokenName) { const aliasDirectionConditions = Object.values( diff --git a/polaris-tokens/package.json b/polaris-tokens/package.json index 16041d2452b..4ce41d96042 100644 --- a/polaris-tokens/package.json +++ b/polaris-tokens/package.json @@ -14,7 +14,6 @@ "import": "./dist/esm/build/index.mjs", "require": "./dist/cjs/build/index.js" }, - "./json/*": "./dist/json/*", "./css/*": "./dist/css/*", "./scss/*": "./dist/scss/*" }, diff --git a/polaris-tokens/scripts/index.ts b/polaris-tokens/scripts/index.ts index 37502cb78e0..3865c88884d 100644 --- a/polaris-tokens/scripts/index.ts +++ b/polaris-tokens/scripts/index.ts @@ -1,13 +1,7 @@ -import {toJSON} from './toJSON'; import {toMediaConditions} from './toMediaConditions'; import {toStyleSheet} from './toStyleSheet'; import {toValues} from './toValues'; (async () => { - await Promise.all([ - toJSON(), - toMediaConditions(), - toStyleSheet(), - toValues(), - ]); + await Promise.all([toMediaConditions(), toStyleSheet(), toValues()]); })(); diff --git a/polaris-tokens/scripts/toJSON.ts b/polaris-tokens/scripts/toJSON.ts deleted file mode 100644 index 6299d273520..00000000000 --- a/polaris-tokens/scripts/toJSON.ts +++ /dev/null @@ -1,22 +0,0 @@ -import fs from 'fs'; -import path from 'path'; - -import {metaThemeDefault} from '../src/themes'; - -const outputDir = path.join(__dirname, '../dist/json'); - -export async function toJSON() { - await fs.promises.mkdir(outputDir, {recursive: true}).catch((error) => { - if (error.code !== 'EEXIST') { - throw error; - } - }); - - for (const [tokenGroupName, metaTokenGroup] of Object.entries( - metaThemeDefault, - )) { - const filePath = path.join(outputDir, `${tokenGroupName}.json`); - - await fs.promises.writeFile(filePath, JSON.stringify(metaTokenGroup)); - } -} diff --git a/polaris-tokens/scripts/toStyleSheet.ts b/polaris-tokens/scripts/toStyleSheet.ts index 067756bef89..9c0a07a3443 100644 --- a/polaris-tokens/scripts/toStyleSheet.ts +++ b/polaris-tokens/scripts/toStyleSheet.ts @@ -1,11 +1,15 @@ import fs from 'fs'; import path from 'path'; -import type {MetaThemeShape, MetaTokenGroupShape} from '../src/themes/types'; +import type { + MetaThemeShape, + MetaTokenGroupShape, + TokenName, +} from '../src/themes/types'; import {metaThemePartials, metaThemeDefault} from '../src/themes'; import {themeNameDefault} from '../src/themes/constants'; -import {createThemeSelector} from '../src/themes/utils'; -import {createVar} from '../src/utilities'; +import {createThemeSelector, isTokenName} from '../src/themes/utils'; +import {createVarName} from '../src/utils'; import type {Entries} from '../src/types'; const cssOutputDir = path.join(__dirname, '../dist/css'); @@ -23,11 +27,16 @@ export function getMetaThemeDecls(metaTheme: MetaThemeShape) { /** Creates CSS declarations from a token group. */ export function getMetaTokenGroupDecls(metaTokenGroup: MetaTokenGroupShape) { return Object.entries(metaTokenGroup) - .map(([tokenName, {value}]) => - tokenName.startsWith('motion-keyframes') - ? `${createVar(tokenName)}:p-${tokenName};` - : `${createVar(tokenName)}:${value};`, - ) + .map((entry) => { + const [tokenName, {value}] = entry as [ + TokenName, + MetaTokenGroupShape[string], + ]; + + return tokenName.startsWith('motion-keyframes') + ? `${createVarName(tokenName)}:p-${tokenName};` + : `${createVarName(tokenName)}:${value};`; + }) .join(''); } diff --git a/polaris-tokens/scripts/toValues.ts b/polaris-tokens/scripts/toValues.ts index 631563f207e..42e77ecde52 100644 --- a/polaris-tokens/scripts/toValues.ts +++ b/polaris-tokens/scripts/toValues.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import path from 'path'; -import {metaThemes, metaThemeDefault} from '../src/themes'; +import {metaThemes} from '../src/themes'; import { extractMetaThemeValues, resolveMetaThemeRefs, @@ -16,16 +16,12 @@ export async function toValues() { } }); - const themeDefault = extractMetaThemeValues( - resolveMetaThemeRefs(metaThemeDefault), - ); - await fs.promises.writeFile( path.join(outputDir, 'index.ts'), [ + `import {themeNameDefault} from '../src/index';`, + `import {createIsTokenName} from '../src/themes/utils';`, `export * from '../src/index';`, - Object.entries(themeDefault).map(createExport), - createExport(['tokens', themeDefault]), createExport([ 'themes', Object.fromEntries( @@ -35,6 +31,8 @@ export async function toValues() { ]), ), ]), + `export const themeDefault = themes[themeNameDefault];`, + `export const isTokenName = createIsTokenName(themes[themeNameDefault]);`, ] .flat() .join('\n'), diff --git a/polaris-tokens/src/index.ts b/polaris-tokens/src/index.ts index 1f583c3e37d..6139a6cc81c 100644 --- a/polaris-tokens/src/index.ts +++ b/polaris-tokens/src/index.ts @@ -1,14 +1,27 @@ -export * from './metadata'; -export * from './utilities'; export {breakpointsAliases} from './themes/base/breakpoints'; -export type { - TokenGroup, - Tokens, - MetadataProperties, - MetadataGroup, -} from './types'; -export type {ThemeName, Theme} from './themes/types'; +export type {BreakpointsAliasDirection} from './utils'; + +export { + createVar, + createVarName, + getThemeVarNames, + getMediaConditions, + toPx, + toPxs, + toRem, +} from './utils'; + +export {metaThemes, metaThemeDefault} from './themes'; + +export type { + MetaTheme, + MetaThemeShape, + MetaTokenGroupShape, + MetaTokenProperties, + Theme, + ThemeName, +} from './themes/types'; export {themeNameDefault, themeNames} from './themes/constants'; diff --git a/polaris-tokens/src/metadata.ts b/polaris-tokens/src/metadata.ts deleted file mode 100644 index 94f52359b45..00000000000 --- a/polaris-tokens/src/metadata.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {metaThemeDefault} from './themes'; -import type {Exact, MetadataBase} from './types'; -import {resolveMetaThemeRefs} from './themes/utils'; - -export const metadata = resolveMetaThemeRefs(metaThemeDefault); - -export type Metadata = typeof metadata; - -/** - * Identity function that simply returns the provided tokens with metadata, but additionally - * validates the input matches the `Metadata` type exactly and infers all members. - */ -export function createMetadata>(metadata: T) { - return metadata; -} diff --git a/polaris-tokens/src/themes/base/border.ts b/polaris-tokens/src/themes/base/border.ts index 022cf6cb942..47923987c91 100644 --- a/polaris-tokens/src/themes/base/border.ts +++ b/polaris-tokens/src/themes/base/border.ts @@ -1,6 +1,5 @@ import type {MetaTokenProperties} from '../types'; import {size} from '../../size'; -import {createVar as createVarName} from '../../utilities'; export type BorderRadiusScale = | '0' @@ -73,7 +72,3 @@ export const border: { value: size[100], }, }; - -export function createVar(borderTokenName: BorderTokenName) { - return `var(${createVarName(borderTokenName)})`; -} diff --git a/polaris-tokens/src/themes/base/font.ts b/polaris-tokens/src/themes/base/font.ts index 667c0f214b9..02dc18e4f68 100644 --- a/polaris-tokens/src/themes/base/font.ts +++ b/polaris-tokens/src/themes/base/font.ts @@ -1,6 +1,5 @@ import {size} from '../../size'; import type {MetaTokenProperties} from '../types'; -import {createVar as createVarName} from '../../utilities'; export type FontFamilyPrefix = 'font-family'; type FontFamilyAlias = 'sans' | 'mono'; @@ -143,7 +142,3 @@ export const font: { value: size[1200], }, }; - -export function createVar(fontTokenName: FontTokenName) { - return `var(${createVarName(fontTokenName)})`; -} diff --git a/polaris-tokens/src/themes/base/index.ts b/polaris-tokens/src/themes/base/index.ts index cc913acbec9..c96ed9a94eb 100644 --- a/polaris-tokens/src/themes/base/index.ts +++ b/polaris-tokens/src/themes/base/index.ts @@ -1,5 +1,4 @@ -import {createExact, tokensToRems} from '../../utilities'; -import type {MetaThemeShape} from '../types'; +import {createMetaThemeBase} from '../../utils'; import {border} from './border'; import {breakpoints} from './breakpoints'; @@ -13,18 +12,16 @@ import {text} from './text'; import {width} from './width'; import {zIndex} from './zIndex'; -const createMetaThemeBase = createExact(); - export const metaThemeBase = createMetaThemeBase({ - border: tokensToRems(border), - breakpoints: tokensToRems(breakpoints), + border, + breakpoints, color, - font: tokensToRems(font), - height: tokensToRems(height), + font, + height, motion, - shadow: tokensToRems(shadow), - space: tokensToRems(space), + shadow, + space, text, - width: tokensToRems(width), + width, zIndex, }); diff --git a/polaris-tokens/src/themes/base/space.ts b/polaris-tokens/src/themes/base/space.ts index 3b1f73388f0..74065f6d1f5 100644 --- a/polaris-tokens/src/themes/base/space.ts +++ b/polaris-tokens/src/themes/base/space.ts @@ -1,5 +1,5 @@ import {size} from '../../size'; -import {createVarName} from '../../utilities'; +import {createVarName} from '../../utils'; import type {MetaTokenProperties} from '../types'; export type SpaceScale = diff --git a/polaris-tokens/src/themes/base/text.ts b/polaris-tokens/src/themes/base/text.ts index 0f1c6cea8a0..a927b7501d3 100644 --- a/polaris-tokens/src/themes/base/text.ts +++ b/polaris-tokens/src/themes/base/text.ts @@ -1,7 +1,7 @@ import type {MetaTokenProperties} from '../types'; +import {createVar} from '../../utils'; import type {FontPrefix} from './font'; -import {createVar} from './font'; export type TextVariant = | 'heading-3xl' diff --git a/polaris-tokens/src/themes/types.ts b/polaris-tokens/src/themes/types.ts index 38e00fb636c..1a96ca1b823 100644 --- a/polaris-tokens/src/themes/types.ts +++ b/polaris-tokens/src/themes/types.ts @@ -8,6 +8,12 @@ export type ThemeName = typeof themeNames[number]; export type ThemeBase = ExtractMetaThemeValues; export type Theme = ExtractMetaThemeValues; +export type TokenName = { + [TokenGroupName in keyof Theme]: { + [TokenName in keyof Theme[TokenGroupName]]: TokenName; + }[keyof Theme[TokenGroupName]]; +}[keyof Theme]; + export interface MetaTokenProperties { value: string; description?: string; diff --git a/polaris-tokens/src/themes/utils.ts b/polaris-tokens/src/themes/utils.ts index df5b72de184..2ad2111c393 100644 --- a/polaris-tokens/src/themes/utils.ts +++ b/polaris-tokens/src/themes/utils.ts @@ -1,7 +1,7 @@ import deepmerge from 'deepmerge'; import type {Entry, Exact} from '../types'; -import {createExact} from '../utilities'; +import {getTokenNames, tokenGroupToRems, tokenGroupNamesToRems} from '../utils'; import type { ExtractMetaThemeValues, @@ -11,10 +11,40 @@ import type { MetaThemePartialShape, MetaTokenGroupShape, ThemeName, + TokenName, + Theme, } from './types'; import {metaThemeBase} from './base'; -export const createMetaThemePartial = createExact(); +/** + * Mimics the behavior of an identity function: + * - Validates the input matches the `MetaThemeShape` type exactly + * - Converts all `px` values to `rem` + * - Infers all members + * + * @example + * ``` + * const example = createMetaThemePartial({ + * color: { + * bg: {value: '#fff'}, + * }, + * }) + * ``` + * + * Where `typeof example` is inferred as `{ color: { bg: { value: string } } }` + */ +export function createMetaThemePartial< + T extends Exact, +>(metaThemePartial: T) { + return Object.fromEntries( + Object.entries(metaThemePartial).map(([tokenGroupName, tokenGroup]) => [ + tokenGroupName, + tokenGroup && tokenGroupNamesToRems.includes(tokenGroupName) + ? tokenGroupToRems(tokenGroup) + : tokenGroup, + ]), + ) as T; +} export function createMetaTheme>( metaThemePartial: T, @@ -89,3 +119,16 @@ export function resolveMetaThemeRefs( ]), ) as T; } + +export function createIsTokenName(theme: Theme | MetaTheme) { + const tokenNames = new Set(getTokenNames(theme)); + + return (tokenName: unknown): tokenName is TokenName => + tokenNames.has(tokenName as TokenName); +} + +/** + * Important: Do not export from Polaris tokens. This utility is exposed + * in the `toValues` build step to ensure the `metaTheme` isn't in client bundles. + */ +export const isTokenName = createIsTokenName(metaThemeBase); diff --git a/polaris-tokens/src/types.ts b/polaris-tokens/src/types.ts index c8f2450e842..8dc1892b978 100644 --- a/polaris-tokens/src/types.ts +++ b/polaris-tokens/src/types.ts @@ -1,30 +1,7 @@ -import type {Metadata} from './metadata'; - export type Entry = [keyof T, T[keyof T]]; export type Entries = Entry[]; export type Experimental = `${T}-experimental`; -export interface MetadataProperties { - description?: string; - value: string; -} - -export interface MetadataGroup { - [token: string]: MetadataProperties; -} - -export interface MetadataBase { - [tokenGroup: string]: MetadataGroup; -} - -export type TokenGroup = { - [K in keyof T]: T[K]['value']; -}; - -export type Tokens = { - [TokenGroupName in keyof Metadata]: TokenGroup; -}; - // The following utility types are copied directly from `type-fest`: // https://github.com/sindresorhus/type-fest diff --git a/polaris-tokens/src/utilities.ts b/polaris-tokens/src/utils.ts similarity index 74% rename from polaris-tokens/src/utilities.ts rename to polaris-tokens/src/utils.ts index 9918777a493..0939459fe6d 100644 --- a/polaris-tokens/src/utilities.ts +++ b/polaris-tokens/src/utils.ts @@ -1,9 +1,16 @@ -import type {Entry, Exact, MetadataGroup, Tokens, TokenGroup} from './types'; +import type {Entry, Exact} from './types'; import type { breakpoints as metaBreakpointsTokenGroup, BreakpointsTokenGroup, BreakpointsTokenName, } from './themes/base/breakpoints'; +import type { + MetaTheme, + MetaThemeShape, + MetaTokenGroupShape, + Theme, + TokenName, +} from './themes/types'; const BASE_FONT_SIZE = 16; @@ -87,24 +94,26 @@ export function rem(value: string) { ); } -export function tokensToRems>(tokenGroup: T) { +export function tokenGroupToRems( + metaTokenGroup: T, +) { return Object.fromEntries( - Object.entries(tokenGroup).map(([token, properties]) => [ - token, - {...properties, value: rem(properties.value)}, + Object.entries(metaTokenGroup).map(([tokenName, tokenProperties]) => [ + tokenName, + {...tokenProperties, value: rem(tokenProperties.value)}, ]), - // We loose the `tokenGroup` inference after transforming the object with + // We loose the `metaTokenGroup` inference after transforming the object with // `Object.fromEntries()` and `Object.entries()`. Thus, we cast the result // back to `T` since we are simply converting the `value` from px to rem. ) as T; } -export function createVarName(token: string) { - return `--p-${token}`; +export function createVarName(tokenName: TokenName) { + return `--p-${tokenName}`; } -export function createVar(token: string) { - return `--p-${token}`; +export function createVar(tokenName: TokenName) { + return `var(${createVarName(tokenName)})`; } /** @@ -112,35 +121,25 @@ export function createVar(token: string) { * * Result: ['p-keyframes-fade-in', 'p-keyframes-spin', etc...] */ -export function getKeyframeNames(motionTokenGroup: TokenGroup) { +export function getKeyframeNames(motionTokenGroup: MetaTokenGroupShape) { return Object.keys(motionTokenGroup) .map((token) => (token.startsWith('keyframes') ? `p-${token}` : null)) .filter(Boolean); } +export function getTokenNames(theme: Theme | MetaTheme): TokenName[] { + return Object.values(theme).flatMap((tokenGroup) => + Object.keys(tokenGroup), + ) as TokenName[]; +} + /** * Allowed Polaris token custom properties. * * Result: ['--p-color-bg', '--p-color-text', etc...] */ -export function getCustomPropertyNames(tokens: Tokens) { - return Object.entries(tokens) - .map(([_, tokenGroup]: [string, TokenGroup]) => - Object.keys(tokenGroup).map((token) => createVar(token)), - ) - .flat(); -} - -export function removeMetadata>( - tokenGroup: T, -) { - return Object.fromEntries( - Object.entries(tokenGroup).map((entry): Entry => { - const [tokenName, {value}] = entry as Entry; - - return [tokenName, value]; - }), - ) as TokenGroup; +export function getThemeVarNames(theme: Theme) { + return getTokenNames(theme).map(createVarName); } export type MetaBreakpointsTokenGroup = typeof metaBreakpointsTokenGroup; @@ -224,26 +223,43 @@ export function isKeyOf( return Object.keys(obj).includes(key as string); } +export const tokenGroupNamesToRems = [ + 'border', + 'breakpoints', + 'font', + 'height', + 'shadow', + 'space', + 'text', + 'width', +]; + /** - * Identity function creator that returns the provided input, - * but additionally validates the input matches the type exactly - * and infers all members. - * - * TODO: Replace all instances with `satisfies` when we upgrade - * to TypeScript >=4.9 + * Mimics the behavior of an identity function: + * - Validates the input matches the `MetaThemeShape` type exactly + * - Converts all `px` values to `rem` + * - Infers all members * * @example * ``` - * type ExampleShape = { [key: string]: string } - * const createExample = createExact() - * - * const example = createExample({ - * foo: 'bar', + * const example = createMetaThemeBase({ + * color: { + * bg: {value: '#fff'}, + * }, * }) * ``` * - * Where `typeof example` is inferred as `{ foo: string }` + * Where `typeof example` is inferred as `{ color: { bg: { value: string } } }` */ -export function createExact() { - return >(obj: U) => obj; +export function createMetaThemeBase>( + metaTheme: T, +): T { + return Object.fromEntries( + Object.entries(metaTheme).map(([tokenGroupName, tokenGroup]) => [ + tokenGroupName, + tokenGroupNamesToRems.includes(tokenGroupName) + ? tokenGroupToRems(tokenGroup) + : tokenGroup, + ]), + ) as T; } diff --git a/polaris-tokens/tests/utilities.test.js b/polaris-tokens/tests/utilities.test.js index 7f7b4909cb3..4bea98d5246 100644 --- a/polaris-tokens/tests/utilities.test.js +++ b/polaris-tokens/tests/utilities.test.js @@ -1,14 +1,15 @@ import { createVar, - getCustomPropertyNames, + createVarName, + getThemeVarNames, getKeyframeNames, - tokensToRems, + tokenGroupToRems, toPx, toEm, toRem, getUnit, getMediaConditions, -} from '../src/utilities'; +} from '../src/utils'; import {resolveMetaThemeRefs} from '../src/themes/utils'; const mockTokenGroup = { @@ -42,17 +43,26 @@ const mockTokens = { }; describe('createVar', () => { - it('converts the token into a polaris css variable name', () => { + it('converts the token into a polaris css variable', () => { const token = 'foo'; const result = createVar(token); + expect(result).toBe(`var(--p-${token})`); + }); +}); + +describe('createVarName', () => { + it('converts the token into a polaris css variable name', () => { + const token = 'foo'; + const result = createVarName(token); + expect(result).toBe(`--p-${token}`); }); }); -describe('getCustomPropertyNames', () => { +describe('getThemeVarNames', () => { it('extracts the token names', () => { - expect(getCustomPropertyNames(mockTokens)).toStrictEqual([ + expect(getThemeVarNames(mockTokens)).toStrictEqual([ '--p-design-token-1', '--p-design-token-2', ]); @@ -68,7 +78,7 @@ describe('getKeyframeNames', () => { }); }); -describe('tokensToRems', () => { +describe('tokenGroupToRems', () => { it("converts a token group's value from px to rems", () => { const tokenGroup = { foo: {value: '12px'}, @@ -76,7 +86,7 @@ describe('tokensToRems', () => { baz: {value: '16px 32px'}, }; - const result = tokensToRems(tokenGroup); + const result = tokenGroupToRems(tokenGroup); expect(result.foo.value).toBe('0.75rem'); expect(result.bar.value).toBe('1rem'); @@ -152,7 +162,6 @@ describe('toRem', () => { describe('getMediaConditions', () => { it('transforms breakpoints tokens into directional media conditions', () => { - /** @type {TokenGroup} */ const breakpoints = { breakpoint1: '16px', breakpoint2: '32px', diff --git a/polaris.shopify.com/content/version-guides/migrating-from-v11-to-v12.md b/polaris.shopify.com/content/version-guides/migrating-from-v11-to-v12.md index 92b5b6077f4..334a31c903e 100644 --- a/polaris.shopify.com/content/version-guides/migrating-from-v11-to-v12.md +++ b/polaris.shopify.com/content/version-guides/migrating-from-v11-to-v12.md @@ -881,6 +881,54 @@ git commit -m "Manually migrate X custom properties from Polaris v11 to v12" npx stylelint ``` +### `@shopify/polaris-tokens` updates + +#### Renames + +- `getCustomPropertyNames` renamed to `getThemeVarNames` +- `createVar` renamed to `createVarName` + +#### Deprecations + +##### Deprecated Utilities + +If you are using these utilities, feel free to copy them from v11 into your own codebase. + +- `createExact` +- `getKeyframeNames` +- `getUnit` +- `isKeyOf` +- `rem` +- `removeMetadata` +- `toEm` +- `tokensToRems` + +##### Deprecated Types + +- `Tokens` type is now deprecated, use the `Theme` type instead + +##### Deprecated all JSON exports + +- `@shopify/polaris-tokens/json/border.json` +- `@shopify/polaris-tokens/json/breakpoints.json` +- `@shopify/polaris-tokens/json/color.json` +- `@shopify/polaris-tokens/json/font.json` +- `@shopify/polaris-tokens/json/height.json` +- `@shopify/polaris-tokens/json/motion.json` +- `@shopify/polaris-tokens/json/shadow.json` +- `@shopify/polaris-tokens/json/space.json` +- `@shopify/polaris-tokens/json/text.json` +- `@shopify/polaris-tokens/json/width.json` +- `@shopify/polaris-tokens/json/zIndex.json` + +If you are using these exports, update the implementation to import `themes` and `JSON.stringify` the theme you need. + +```diff +- const color = require('@shopify/polaris-tokens/json/color.json'); ++ const {themes} = require('@shopify/polaris-tokens'); ++ const color = JSON.stringify(themes.light.color); +``` + ## Manual updates and fixes ### A new web font diff --git a/polaris.shopify.com/pages/api/search/v0/index.tsx b/polaris.shopify.com/pages/api/search/v0/index.tsx index 12d6a3a4b81..8f970c2a270 100644 --- a/polaris.shopify.com/pages/api/search/v0/index.tsx +++ b/polaris.shopify.com/pages/api/search/v0/index.tsx @@ -1,6 +1,6 @@ import type {NextApiRequest, NextApiResponse} from 'next'; import Fuse from 'fuse.js'; -import {metadata, MetadataProperties} from '@shopify/polaris-tokens'; +import {metaThemeDefault, MetaTokenProperties} from '@shopify/polaris-tokens'; import iconMetadata from '@shopify/polaris-icons/metadata'; import { @@ -75,7 +75,7 @@ const getSearchResults = (query?: string) => { }); }); - const {color, border, font, motion, shadow, space, zIndex} = metadata; + const {color, border, font, motion, shadow, space, zIndex} = metaThemeDefault; const tokenGroups = { color, border, @@ -88,7 +88,7 @@ const getSearchResults = (query?: string) => { Object.entries(tokenGroups).forEach(([groupSlug, tokenGroup]) => { Object.entries(tokenGroup).forEach( - ([tokenName, tokenProperties]: [string, MetadataProperties]) => { + ([tokenName, tokenProperties]: [string, MetaTokenProperties]) => { results.push({ id: slugify(`tokens ${tokenName}`), category: 'tokens', diff --git a/polaris.shopify.com/pages/api/tokens/v0/[tokens].tsx b/polaris.shopify.com/pages/api/tokens/v0/[tokens].tsx index dbb26f27df1..1ba4c7b88a4 100644 --- a/polaris.shopify.com/pages/api/tokens/v0/[tokens].tsx +++ b/polaris.shopify.com/pages/api/tokens/v0/[tokens].tsx @@ -1,9 +1,15 @@ -import {createVar, tokens, TokenGroup} from '@shopify/polaris-tokens'; +import type {Theme} from '@shopify/polaris-tokens'; +import { + createVarName, + isTokenName, + themeDefault, +} from '@shopify/polaris-tokens'; import type {NextApiRequest, NextApiResponse} from 'next'; -type TokenGroupKey = keyof typeof tokens; +type TokenGroupName = keyof Theme; +type TokenGroup = Theme[TokenGroupName]; -export const tokenGroupKeys = Object.keys(tokens) as TokenGroupKey[]; +export const tokenGroupNames = Object.keys(themeDefault) as TokenGroupName[]; const formats = ['json', 'css'] as const; @@ -13,22 +19,28 @@ function isFormat(format: unknown): format is Format { return formats.includes(format as Format); } -function isTokenGroupKey(key: unknown): key is TokenGroupKey { - return tokenGroupKeys.includes(key as TokenGroupKey); +function isTokenGroupName(key: unknown): key is TokenGroupName { + return tokenGroupNames.includes(key as TokenGroupName); } /** * Format the token data into: css or json */ -const formatTokenGroup = (tokenGroup: TokenGroup, format: Format) => { +const formatTokenGroup = (tokenGroup: Partial, format: Format) => { const tokenValues = Object.fromEntries( Object.entries(tokenGroup).map(([token, value]) => [token, value]), ); if (format === 'css') { return Object.keys(tokenValues) - .reduce((result, token) => { - const cssVariable = `${createVar(token)}: ${tokenValues[token]};`; + .reduce((result, tokenName) => { + if (!isTokenName(tokenName)) { + throw new Error(`Invalid token name: ${tokenName}`); + } + + const cssVariable = `${createVarName(tokenName)}: ${ + tokenValues[tokenName] + };`; result.push(cssVariable); @@ -45,19 +57,19 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { if (typeof formatParam === 'string') { const tokenGroupParam = req.query.tokens || ''; - let tokenData: TokenGroup = {}; + let tokenData: Partial = {}; // Determine which list(s) we are querying for based on the token param if (tokenGroupParam === 'all') { - tokenGroupKeys.forEach((group) => { - const tokenGroup = tokens[group]; + tokenGroupNames.forEach((tokenGroupName) => { + const tokenGroup = themeDefault[tokenGroupName]; tokenData = {...tokenData, ...tokenGroup}; }); } - if (isTokenGroupKey(tokenGroupParam)) { - const tokenGroup: TokenGroup = tokens[tokenGroupParam]; + if (isTokenGroupName(tokenGroupParam)) { + const tokenGroup: TokenGroup = themeDefault[tokenGroupParam]; tokenData = {...tokenData, ...tokenGroup}; } diff --git a/polaris.shopify.com/pages/api/tokens/v0/index.tsx b/polaris.shopify.com/pages/api/tokens/v0/index.tsx index 17f6cbb9761..90e62a40606 100644 --- a/polaris.shopify.com/pages/api/tokens/v0/index.tsx +++ b/polaris.shopify.com/pages/api/tokens/v0/index.tsx @@ -1,6 +1,6 @@ import type {NextApiRequest, NextApiResponse} from 'next'; -import {tokenGroupKeys} from './[tokens]'; +import {tokenGroupNames} from './[tokens]'; const getGithubUrl = (file: string) => { const fileName = `${file}.ts`; @@ -66,14 +66,14 @@ const html = ` - ${tokenGroupKeys - .map((tokenGroup) => { - const url = `/api/tokens/v0/${tokenGroup}`; + ${tokenGroupNames + .map((tokenGroupName) => { + const url = `/api/tokens/v0/${tokenGroupName}`; const cssUrl = `${url}?format=css`; return ` - ${tokenGroup} + ${tokenGroupName} ${url} @@ -81,7 +81,7 @@ const html = ` ${cssUrl} - File + File `; diff --git a/polaris.shopify.com/playroom.config.js b/polaris.shopify.com/playroom.config.js index 6fa4814f956..a3ca555f0a4 100644 --- a/polaris.shopify.com/playroom.config.js +++ b/polaris.shopify.com/playroom.config.js @@ -4,7 +4,7 @@ // Workaround: restart the next dev server after each change to the playroom config and associated files. const path = require('path'); -const {breakpoints, toPx} = require('@shopify/polaris-tokens'); +const {themeDefault, toPx} = require('@shopify/polaris-tokens'); const {playroom} = require('./constants'); // Note: We insert a 320 breakpoint to ensure we capture a representation of the @@ -13,7 +13,7 @@ const {playroom} = require('./constants'); // phone size you'll encounter) const breakpointsConfig = [ 320, - ...Object.values(breakpoints) + ...Object.values(themeDefault.breakpoints) .map((value) => +toPx(value).replace('px', '')) .filter((val) => val > 0), ]; diff --git a/polaris.shopify.com/src/components/TokensPage/TokensPage.tsx b/polaris.shopify.com/src/components/TokensPage/TokensPage.tsx index 535b2ba0864..e10b014dfcb 100644 --- a/polaris.shopify.com/src/components/TokensPage/TokensPage.tsx +++ b/polaris.shopify.com/src/components/TokensPage/TokensPage.tsx @@ -1,5 +1,5 @@ import styles from './TokensPage.module.scss'; -import {MetadataGroup, metadata as allTokens} from '@shopify/polaris-tokens'; +import {MetaTokenGroupShape, metaThemeDefault} from '@shopify/polaris-tokens'; import {Status, TokenPropertiesWithName} from '../../types'; import TokenList from '../TokenList'; import Link from 'next/link'; @@ -78,7 +78,7 @@ const navItems: NavItem[] = [ function tokensToFilteredArray( filter: string, - tokenGroup: MetadataGroup, + tokenGroup: MetaTokenGroupShape, ): TokenPropertiesWithName[] { return Object.entries(tokenGroup) .filter(([name]) => { @@ -94,17 +94,17 @@ function TokensPage({tokenGroup}: Props) { const router = useRouter(); const tokens = { - border: tokensToFilteredArray(filter, allTokens.border), - breakpoints: tokensToFilteredArray(filter, allTokens.breakpoints), - color: tokensToFilteredArray(filter, allTokens.color), - font: tokensToFilteredArray(filter, allTokens.font), - height: tokensToFilteredArray(filter, allTokens.height), - motion: tokensToFilteredArray(filter, allTokens.motion), - shadow: tokensToFilteredArray(filter, allTokens.shadow), - space: tokensToFilteredArray(filter, allTokens.space), - text: tokensToFilteredArray(filter, allTokens.text), - width: tokensToFilteredArray(filter, allTokens.width), - zIndex: tokensToFilteredArray(filter, allTokens.zIndex), + border: tokensToFilteredArray(filter, metaThemeDefault.border), + breakpoints: tokensToFilteredArray(filter, metaThemeDefault.breakpoints), + color: tokensToFilteredArray(filter, metaThemeDefault.color), + font: tokensToFilteredArray(filter, metaThemeDefault.font), + height: tokensToFilteredArray(filter, metaThemeDefault.height), + motion: tokensToFilteredArray(filter, metaThemeDefault.motion), + shadow: tokensToFilteredArray(filter, metaThemeDefault.shadow), + space: tokensToFilteredArray(filter, metaThemeDefault.space), + text: tokensToFilteredArray(filter, metaThemeDefault.text), + width: tokensToFilteredArray(filter, metaThemeDefault.width), + zIndex: tokensToFilteredArray(filter, metaThemeDefault.zIndex), }; const keyframeStyles = tokens['motion'] diff --git a/polaris.shopify.com/src/types.ts b/polaris.shopify.com/src/types.ts index 390b900a89b..0f395a194a7 100644 --- a/polaris.shopify.com/src/types.ts +++ b/polaris.shopify.com/src/types.ts @@ -1,4 +1,4 @@ -import type {MetadataProperties} from '@shopify/polaris-tokens'; +import type {MetaTokenProperties} from '@shopify/polaris-tokens'; import type {Icon} from '@shopify/polaris-icons/metadata'; import type {MDXRemoteSerializeResult} from 'next-mdx-remote'; @@ -96,7 +96,7 @@ export type MarkdownFile = { readme: string; }; -export interface TokenPropertiesWithName extends MetadataProperties { +export interface TokenPropertiesWithName extends MetaTokenProperties { name: string; } diff --git a/stylelint-polaris/index.js b/stylelint-polaris/index.js index 26296b8dcea..cabbf1689ba 100644 --- a/stylelint-polaris/index.js +++ b/stylelint-polaris/index.js @@ -1,7 +1,7 @@ const { - getCustomPropertyNames, createVar, - tokens, + getThemeVarNames, + themeDefault, } = require('@shopify/polaris-tokens'); const disallowedUnits = [ @@ -117,7 +117,7 @@ const stylelintPolarisCoverageOptions = { '/.+/': [ // Note: Order is important // This pattern allows use of `--p-*` custom properties that are valid Polaris tokens - ...getCustomPropertyNames(tokens), + ...getThemeVarNames(themeDefault), // This pattern flags unknown `--p-*` custom properties or usage of deprecated `--pc-*` custom properties private to polaris-react /--(?!(p|pc)-).+/, ], @@ -405,8 +405,8 @@ const stylelintPolarisCoverageOptions = { { 'declaration-property-value-allowed-list': [ { - 'z-index': Object.keys(tokens.zIndex).map( - (token) => `var(${createVar(token)})`, + 'z-index': Object.keys(themeDefault.zIndex).map((tokenName) => + createVar(tokenName), ), }, ], diff --git a/stylelint-polaris/plugins/custom-property-allowed-list/index.test.js b/stylelint-polaris/plugins/custom-property-allowed-list/index.test.js index 7357ac5cb70..e2b78f0660c 100644 --- a/stylelint-polaris/plugins/custom-property-allowed-list/index.test.js +++ b/stylelint-polaris/plugins/custom-property-allowed-list/index.test.js @@ -1,8 +1,8 @@ -const {getCustomPropertyNames, tokens} = require('@shopify/polaris-tokens'); +const {getThemeVarNames, themeDefault} = require('@shopify/polaris-tokens'); const {messages, ruleName} = require('.'); -const polarisCustomPropertyNames = getCustomPropertyNames(tokens); +const themeVarNames = getThemeVarNames(themeDefault); /* --p-* Tokens are to be defined in polaris-tokens. @@ -20,10 +20,7 @@ const config = [ { allowedProperties: [allowedCustomPropertyNames], allowedValues: { - '/.+/': [ - ...polarisCustomPropertyNames, - invalidOrDeprecatedPrivateCustomPropertyNames, - ], + '/.+/': [...themeVarNames, invalidOrDeprecatedPrivateCustomPropertyNames], }, }, ];