diff --git a/scripts/buildFigma.ts b/scripts/buildFigma.ts index 1e2d37b40..6ad80b5bc 100644 --- a/scripts/buildFigma.ts +++ b/scripts/buildFigma.ts @@ -3,6 +3,7 @@ import {PrimerStyleDictionary} from '../src/primerStyleDictionary.js' import {themes} from './themes.config.js' import {figma} from '../src/platforms/index.js' import type {ConfigGeneratorOptions} from '../src/types/styleDictionaryConfigGenerator.js' +import {getFallbackTheme} from './utilities/getFallbackTheme.js' const buildFigma = async (buildOptions: ConfigGeneratorOptions): Promise => { /** ----------------------------------- @@ -225,7 +226,9 @@ const buildFigma = async (buildOptions: ConfigGeneratorOptions): Promise = source, include, platforms: { - figma: figma(`figma/shadows/${name}.json`, buildOptions.prefix, buildOptions.buildPath, {theme}), + figma: figma(`figma/shadows/${name}.json`, buildOptions.prefix, buildOptions.buildPath, { + theme: [theme, getFallbackTheme(theme)], + }), }, }) diff --git a/scripts/buildTokens.ts b/scripts/buildTokens.ts index 8bb7da315..0cd5ec2a1 100644 --- a/scripts/buildTokens.ts +++ b/scripts/buildTokens.ts @@ -10,6 +10,7 @@ import type {TokenBuildInput} from '../src/types/tokenBuildInput.js' import glob from 'fast-glob' import {themes} from './themes.config.js' import fs from 'fs' +import {getFallbackTheme} from './utilities/getFallbackTheme.js' /** * getStyleDictionaryConfig @@ -39,13 +40,13 @@ const getStyleDictionaryConfig: StyleDictionaryConfigGenerator = ( Object.entries({ css: css(`css/${filename}.css`, options.prefix, options.buildPath, { themed: options.themed, - theme: options.theme, + theme: [options.theme, getFallbackTheme(options.theme)], }), docJson: docJson(`docs/${filename}.json`, options.prefix, options.buildPath, { - theme: options.theme, + theme: [options.theme, getFallbackTheme(options.theme)], }), styleLint: styleLint(`styleLint/${filename}.json`, options.prefix, options.buildPath, { - theme: options.theme, + theme: [options.theme, getFallbackTheme(options.theme)], }), fallbacks: fallbacks(`fallbacks/${filename}.json`, options.prefix, options.buildPath), ...platforms, @@ -66,7 +67,7 @@ export const buildDesignTokens = async (buildOptions: ConfigGeneratorOptions): P platforms: { css: css(`internalCss/${filename}.css`, buildOptions.prefix, buildOptions.buildPath, { themed: true, - theme, + theme: [theme, getFallbackTheme(theme)], }), }, }) @@ -88,7 +89,7 @@ export const buildDesignTokens = async (buildOptions: ConfigGeneratorOptions): P `functional/themes/${filename}`, source, include, - {...buildOptions, themed: true, theme}, + {...buildOptions, themed: true, theme: [theme, getFallbackTheme(theme)]}, // disable fallbacks for themes {fallbacks: undefined}, ), diff --git a/scripts/utilities/getFallbackTheme.ts b/scripts/utilities/getFallbackTheme.ts new file mode 100644 index 000000000..bf121e33b --- /dev/null +++ b/scripts/utilities/getFallbackTheme.ts @@ -0,0 +1,3 @@ +export const getFallbackTheme = (theme?: string) => { + return theme ? (theme.startsWith('light') ? 'light' : 'dark') : undefined +} diff --git a/src/preprocessors/themeOverrides.test.ts b/src/preprocessors/themeOverrides.test.ts index 02d11c0c6..1461f4433 100644 --- a/src/preprocessors/themeOverrides.test.ts +++ b/src/preprocessors/themeOverrides.test.ts @@ -139,4 +139,73 @@ describe('Preprocessor: themeOverrides', () => { }), ).toStrictEqual(resultDictionary.tokens) }) + + it('works with fallback theme', () => { + const dictionary = getMockDictionary({ + valueOverride: getMockToken({ + name: 'red', + description: 'This is a description', + $value: 'transformedValue', + path: ['tokens', 'subgroup', 'red'], + $extensions: { + 'org.primer.overrides': { + dark: 'darkValue', + }, + }, + }), + objectOverride: getMockToken({ + name: 'red', + description: 'This is a description', + $value: 'transformedValue', + path: ['tokens', 'subgroup', 'red'], + $extensions: { + 'org.primer.overrides': { + dark: { + $value: 'darkValue', + description: 'DarkMode description', + }, + }, + }, + }), + }) + + const resultDictionary = getMockDictionary({ + valueOverride: getMockToken({ + name: 'red', + description: 'This is a description', + $value: 'darkValue', + path: ['tokens', 'subgroup', 'red'], + $extensions: { + 'org.primer.overrides': { + dark: 'darkValue', + }, + }, + }), + objectOverride: getMockToken({ + name: 'red', + description: 'DarkMode description', + $value: 'darkValue', + path: ['tokens', 'subgroup', 'red'], + $extensions: { + 'org.primer.overrides': { + dark: { + $value: 'darkValue', + description: 'DarkMode description', + }, + }, + }, + }), + }) + + expect( + themeOverrides.preprocessor(dictionary.tokens, { + options: {themeOverrides: {theme: ['dark-dimmed', undefined]}}, + }), + ).toStrictEqual(dictionary.tokens) + expect( + themeOverrides.preprocessor(dictionary.tokens, { + options: {themeOverrides: {theme: ['dark-dimmed', 'dark']}}, + }), + ).toStrictEqual(resultDictionary.tokens) + }) }) diff --git a/src/preprocessors/themeOverrides.ts b/src/preprocessors/themeOverrides.ts index 5b45adf89..9ac2fd4db 100644 --- a/src/preprocessors/themeOverrides.ts +++ b/src/preprocessors/themeOverrides.ts @@ -6,16 +6,20 @@ export const themeOverrides: Preprocessor = { preprocessor: (dictionary: PreprocessedTokens, config: PlatformConfig): PreprocessedTokens => { const extensionProp = config.options?.themeOverrides?.extensionProp || 'org.primer.overrides' const valueProp = config.options?.themeOverrides?.valueProp || '$value' - const currentTheme = config.options?.themeOverrides?.theme - + const [currentTheme, fallbackTheme] = asArray(config.options?.themeOverrides?.theme) const tokens = transformTokens(dictionary, token => { // return early if no theme value is set - if (!currentTheme || !token.$extensions?.[extensionProp] || !token.$extensions?.[extensionProp][currentTheme]) { + if ( + !currentTheme || + !token.$extensions?.[extensionProp] || + (!token.$extensions?.[extensionProp][currentTheme] && !token.$extensions?.[extensionProp][fallbackTheme]) + ) { return token } // get override - const override = token.$extensions?.[extensionProp][currentTheme] + const override = + token.$extensions?.[extensionProp][currentTheme] || token.$extensions?.[extensionProp][fallbackTheme] // token an theme value exist return { ...token, diff --git a/src/tokens/component/diffBlob.json5 b/src/tokens/component/diffBlob.json5 index e955ae738..411945056 100644 --- a/src/tokens/component/diffBlob.json5 +++ b/src/tokens/component/diffBlob.json5 @@ -195,7 +195,7 @@ }, 'dark-high-contrast': '{bgColor.danger.emphasis}', 'dark-tritanopia': { - $value: '{base.color.orange.4}', + $value: '{base.color.red.4}', alpha: 0.4, }, dark: { @@ -239,7 +239,7 @@ alpha: 0.3, }, 'dark-tritanopia': { - $value: '{base.color.orange.4}', + $value: '{base.color.red.4}', alpha: 0.3, }, dark: { diff --git a/src/tokens/functional/color/dark/app-dark.json5 b/src/tokens/functional/color/dark/app-dark.json5 index 3a74c2594..cb067abad 100644 --- a/src/tokens/functional/color/dark/app-dark.json5 +++ b/src/tokens/functional/color/dark/app-dark.json5 @@ -32,291 +32,6 @@ }, }, }, - diffBlob: { - additionLine: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{bgColor.success.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - alpha: 0.15, - }, - }, - additionWord: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{base.color.green.4}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - alpha: 0.4, - }, - }, - additionNum: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{base.color.green.3}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - alpha: 0.3, - }, - }, - deletionLine: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{bgColor.danger.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - deletionWord: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{base.color.red.4}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - alpha: 0.4, - }, - }, - deletionNum: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{base.color.red.4}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - alpha: 0.3, - }, - }, - hunkLine: { - fgColor: { - $value: '{fgColor.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{bgColor.accent.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - hunkNum: { - fgColor: { - rest: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - hover: { - $value: '{fgColor.onEmphasis}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - }, - bgColor: { - rest: { - $value: '{base.color.blue.8}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - hover: { - $value: '{bgColor.accent.emphasis}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - }, - emptyNum: { - bgColor: { - $value: '{bgColor.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - emptyLine: { - bgColor: { - $value: '{bgColor.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - expander: { - iconColor: { - $value: '{fgColor.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - }, - }, codeMirror: { fgColor: { $value: '{fgColor.default}', diff --git a/src/tokens/functional/color/light/app-light.json5 b/src/tokens/functional/color/light/app-light.json5 index 108cb4a26..425cc1d37 100644 --- a/src/tokens/functional/color/light/app-light.json5 +++ b/src/tokens/functional/color/light/app-light.json5 @@ -29,265 +29,6 @@ }, }, }, - diffBlob: { - additionLine: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{bgColor.success.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - additionWord: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{base.color.green.1}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - additionNum: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{base.color.green.1}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - deletionLine: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{bgColor.danger.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - deletionWord: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{base.color.red.1}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - deletionNum: { - fgColor: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - bgColor: { - $value: '{base.color.red.1}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - hunkLine: { - bgColor: { - $value: '{bgColor.accent.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - fgColor: { - $value: '{fgColor.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - }, - hunkNum: { - fgColor: { - rest: { - $value: '{fgColor.default}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - hover: { - $value: '{fgColor.onEmphasis}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - }, - bgColor: { - rest: { - $value: '{base.color.blue.1}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - hover: { - $value: '{bgColor.accent.emphasis}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - }, - emptyNum: { - bgColor: { - $value: '{bgColor.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - emptyLine: { - bgColor: { - $value: '{bgColor.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - expander: { - iconColor: { - $value: '{fgColor.muted}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['fgColor'], - }, - }, - }, - }, - }, codeMirror: { fgColor: { $value: '{fgColor.default}', diff --git a/src/tokens/functional/color/light/overrides/light.high-contrast.json5 b/src/tokens/functional/color/light/overrides/light.high-contrast.json5 index 695dc9c76..e04234d9b 100644 --- a/src/tokens/functional/color/light/overrides/light.high-contrast.json5 +++ b/src/tokens/functional/color/light/overrides/light.high-contrast.json5 @@ -440,45 +440,6 @@ }, }, }, - diffBlob: { - additionWord: { - fgColor: { - $value: '{fgColor.onEmphasis}', - $type: 'color', - }, - bgColor: { - $value: '{base.color.green.5}', - $type: 'color', - alpha: 1, - }, - }, - deletionWord: { - fgColor: { - $value: '{fgColor.onEmphasis}', - $type: 'color', - }, - bgColor: { - $value: '{base.color.red.5}', - $type: 'color', - alpha: 1, - }, - }, - hunkNum: { - bgColor: { - rest: { - $value: '{base.color.blue.1}', - $type: 'color', - alpha: 1, - }, - }, - }, - expander: { - iconColor: { - $value: '{fgColor.default}', - $type: 'color', - }, - }, - }, header: { borderColor: { divider: { diff --git a/src/tokens/functional/color/light/overrides/light.protanopia-deuteranopia.json5 b/src/tokens/functional/color/light/overrides/light.protanopia-deuteranopia.json5 index 1c30bba3d..899000d92 100644 --- a/src/tokens/functional/color/light/overrides/light.protanopia-deuteranopia.json5 +++ b/src/tokens/functional/color/light/overrides/light.protanopia-deuteranopia.json5 @@ -110,77 +110,6 @@ }, }, }, - diffBlob: { - additionNum: { - bgColor: { - $value: '{base.color.blue.1}', - $type: 'color', - }, - }, - additionWord: { - bgColor: { - $value: '{base.color.blue.1}', - $type: 'color', - }, - }, - deletionNum: { - bgColor: { - $value: '{base.color.orange.1}', - $type: 'color', - }, - }, - deletionWord: { - bgColor: { - $value: '{base.color.orange.1}', - $type: 'color', - }, - }, - hunkLine: { - bgColor: { - $value: '{base.color.neutral.1}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - hunkNum: { - bgColor: { - rest: { - $value: '{base.color.neutral.3}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - hover: { - $value: '{base.color.neutral.7}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - fgColor: { - hover: { - $value: '{fgColor.default}', - $type: 'color', - }, - }, - }, - }, codeMirror: { syntax: { fgColor: { diff --git a/src/tokens/functional/color/light/overrides/light.tritanopia.json5 b/src/tokens/functional/color/light/overrides/light.tritanopia.json5 index 48c49f1ad..0740fa55c 100644 --- a/src/tokens/functional/color/light/overrides/light.tritanopia.json5 +++ b/src/tokens/functional/color/light/overrides/light.tritanopia.json5 @@ -110,77 +110,6 @@ }, }, }, - diffBlob: { - additionNum: { - bgColor: { - $value: '{base.color.blue.1}', - $type: 'color', - }, - }, - additionWord: { - bgColor: { - $value: '{base.color.blue.1}', - $type: 'color', - }, - }, - deletionNum: { - bgColor: { - $value: '{base.color.red.1}', - $type: 'color', - }, - }, - deletionWord: { - bgColor: { - $value: '{base.color.red.1}', - $type: 'color', - }, - }, - hunkLine: { - bgColor: { - $value: '{base.color.neutral.1}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - hunkNum: { - bgColor: { - rest: { - $value: '{base.color.neutral.3}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - hover: { - $value: '{base.color.neutral.7}', - $type: 'color', - $extensions: { - 'org.primer.figma': { - collection: 'mode', - group: 'component', - scopes: ['bgColor'], - }, - }, - }, - }, - fgColor: { - hover: { - $value: '{fgColor.default}', - $type: 'color', - }, - }, - }, - }, codeMirror: { syntax: { fgColor: { diff --git a/src/transformers/figmaAttributes.ts b/src/transformers/figmaAttributes.ts index 3cc8bb61c..3cb5eda3f 100644 --- a/src/transformers/figmaAttributes.ts +++ b/src/transformers/figmaAttributes.ts @@ -1,4 +1,5 @@ import type {PlatformConfig, Transform, TransformedToken} from 'style-dictionary/types' +import {asArray} from '../utilities/asArray.js' type FigmaVariableScope = | 'ALL_SCOPES' @@ -70,7 +71,7 @@ export const figmaAttributes: Transform = { transform: (token: TransformedToken, platform: PlatformConfig = {}) => { const {modeOverride, collection, scopes, group, codeSyntax} = token.$extensions?.['org.primer.figma'] || {} return { - mode: platform.options?.theme || modeOverride || 'default', + mode: asArray(platform.options?.theme)[0] || modeOverride || 'default', collection, group: group || collection, scopes: getScopes(scopes), diff --git a/src/types/styleDictionaryConfigGenerator.d.ts b/src/types/styleDictionaryConfigGenerator.d.ts index 9990e4ec2..c58f88dfd 100644 --- a/src/types/styleDictionaryConfigGenerator.d.ts +++ b/src/types/styleDictionaryConfigGenerator.d.ts @@ -4,7 +4,7 @@ export type ConfigGeneratorOptions = { buildPath: string prefix?: string themed?: boolean - theme?: string + theme?: string | [string, string] } export type StyleDictionaryConfigGenerator = ( diff --git a/src/types/tokenBuildInput.d.ts b/src/types/tokenBuildInput.d.ts index 6cc65bf42..158382864 100644 --- a/src/types/tokenBuildInput.d.ts +++ b/src/types/tokenBuildInput.d.ts @@ -4,7 +4,7 @@ export type TokenBuildInput = { // Array of `filepaths` to token files that should be converted and included in the output. Accepts relative or glob paths. source: string[] // The mode of the theme - theme?: string + theme: string // Array of `filepaths` to token fils that should NOT be included in the output, but should be available to reference during compilation e.g. base color scales include: string[] } diff --git a/src/utilities/asArray.test.ts b/src/utilities/asArray.test.ts new file mode 100644 index 000000000..f4cb90d32 --- /dev/null +++ b/src/utilities/asArray.test.ts @@ -0,0 +1,16 @@ +import {asArray} from './asArray.js' + +describe('Utilities: asArray', () => { + it('returns an array from a single item', () => { + expect(asArray('string')).toStrictEqual(['string']) + }) + + it('returns an array from an array of items', () => { + expect(asArray(['string', 'string2'])).toStrictEqual(['string', 'string2']) + }) + + it('returns an empty array from undefined', () => { + expect(asArray(undefined)).toStrictEqual([]) + expect(asArray([undefined])).toStrictEqual([]) + }) +}) diff --git a/src/utilities/asArray.ts b/src/utilities/asArray.ts new file mode 100644 index 000000000..1f5181024 --- /dev/null +++ b/src/utilities/asArray.ts @@ -0,0 +1 @@ +export const asArray = (item: unknown) => (Array.isArray(item) ? item : [item]).filter(Boolean)