@ankhorage/surface 0.2.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/dist/examples/DocsExamples.d.ts.map +1 -1
- package/dist/examples/DocsExamples.js +0 -2
- package/dist/examples/DocsExamples.js.map +1 -1
- package/dist/internal/resolvers/resolveControlSize.d.ts +2 -2
- package/dist/internal/resolvers/resolveControlSize.d.ts.map +1 -1
- package/dist/internal/resolvers/resolveControlSize.js.map +1 -1
- package/dist/internal/resolvers/resolveIconSize.d.ts +2 -2
- package/dist/internal/resolvers/resolveIconSize.d.ts.map +1 -1
- package/dist/internal/resolvers/resolveIconSize.js.map +1 -1
- package/dist/internal/resolvers/resolveInteractiveColors.d.ts +3 -3
- package/dist/internal/resolvers/resolveInteractiveColors.d.ts.map +1 -1
- package/dist/internal/resolvers/resolveInteractiveColors.js.map +1 -1
- package/dist/internal/resolvers/resolveSelectionControlColors.d.ts +2 -2
- package/dist/internal/resolvers/resolveSelectionControlColors.d.ts.map +1 -1
- package/dist/internal/resolvers/resolveSelectionControlColors.js.map +1 -1
- package/dist/internal/resolvers/resolveTextColor.d.ts +3 -3
- package/dist/internal/resolvers/resolveTextColor.d.ts.map +1 -1
- package/dist/internal/resolvers/resolveTextColor.js.map +1 -1
- package/dist/internal/resolvers/resolveTextStyles.d.ts +3 -3
- package/dist/internal/resolvers/resolveTextStyles.d.ts.map +1 -1
- package/dist/internal/resolvers/resolveTextStyles.js.map +1 -1
- package/dist/internal/resolvers/resolveTone.d.ts +2 -2
- package/dist/internal/resolvers/resolveTone.d.ts.map +1 -1
- package/dist/internal/resolvers/resolveTone.js.map +1 -1
- package/dist/layout/Container.d.ts +2 -2
- package/dist/layout/Container.d.ts.map +1 -1
- package/dist/layout/Container.js.map +1 -1
- package/dist/layout/helpers.d.ts +9 -9
- package/dist/layout/helpers.d.ts.map +1 -1
- package/dist/layout/helpers.js.map +1 -1
- package/dist/primitives/heading/resolveHeadingStyle.d.ts +2 -2
- package/dist/primitives/heading/resolveHeadingStyle.d.ts.map +1 -1
- package/dist/primitives/heading/resolveHeadingStyle.js.map +1 -1
- package/dist/primitives/icon/Icon.d.ts +3 -3
- package/dist/primitives/icon/Icon.d.ts.map +1 -1
- package/dist/primitives/icon/Icon.js.map +1 -1
- package/dist/theme/ThemeContext.d.ts +3 -3
- package/dist/theme/ThemeContext.d.ts.map +1 -1
- package/dist/theme/ThemeContext.js.map +1 -1
- package/dist/theme/colorEngine.d.ts +10 -11
- package/dist/theme/colorEngine.d.ts.map +1 -1
- package/dist/theme/colorEngine.js +102 -412
- package/dist/theme/colorEngine.js.map +1 -1
- package/dist/theme/createTheme.d.ts +3 -3
- package/dist/theme/createTheme.d.ts.map +1 -1
- package/dist/theme/createTheme.js +2 -4
- package/dist/theme/createTheme.js.map +1 -1
- package/dist/theme/types.d.ts +5 -17
- package/dist/theme/types.d.ts.map +1 -1
- package/dist/theme/types.js.map +1 -1
- package/package.json +3 -4
- package/src/examples/DocsExamples.tsx +0 -2
- package/src/internal/resolvers/resolveControlSize.ts +5 -2
- package/src/internal/resolvers/resolveIconSize.ts +2 -2
- package/src/internal/resolvers/resolveInteractiveColors.ts +3 -3
- package/src/internal/resolvers/resolveSelectionControlColors.ts +2 -2
- package/src/internal/resolvers/resolveTextColor.ts +3 -3
- package/src/internal/resolvers/resolveTextStyles.ts +6 -6
- package/src/internal/resolvers/resolveTone.ts +2 -2
- package/src/layout/Container.tsx +2 -2
- package/src/layout/helpers.test.ts +2 -2
- package/src/layout/helpers.ts +12 -9
- package/src/primitives/heading/resolveHeadingStyle.ts +2 -2
- package/src/primitives/icon/Icon.tsx +3 -3
- package/src/theme/ThemeContext.tsx +2 -2
- package/src/theme/colorEngine.test.ts +158 -154
- package/src/theme/colorEngine.ts +128 -477
- package/src/theme/createTheme.ts +6 -8
- package/src/theme/types.ts +15 -18
- package/src/utils/deepMerge.test.ts +0 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.d.ts","sourceRoot":"","sources":["../../../src/primitives/icon/Icon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAI9D,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"Icon.d.ts","sourceRoot":"","sources":["../../../src/primitives/icon/Icon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAI9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGtD,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,YAAY,CAAC,SAAS,CAAC,GAAG,MAAM,CAAC;IAC9C,KAAK,CAAC,EAAE,MAAM,YAAY,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC;IAC9C,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,IAAI,CAAC,EACnB,IAAI,EACJ,QAAqB,EACrB,IAAU,EACV,KAAc,EACd,KAAK,EACL,MAAM,GACP,EAAE,SAAS;;;;;;8CAaX"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Icon.js","sourceRoot":"","sources":["../../../src/primitives/icon/Icon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAkC,MAAM,cAAc,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAatE,MAAM,UAAU,IAAI,CAAC,EACnB,IAAI,EACJ,QAAQ,GAAG,UAAU,EACrB,IAAI,GAAG,GAAG,EACV,KAAK,GAAG,MAAM,EACd,KAAK,EACL,MAAM,GACI;IACV,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC7B,MAAM,aAAa,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACzD,MAAM,YAAY,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzF,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAExD,OAAO,KAAK,CAAC,aAAa,CAAC,aAAa,EAAE;QACxC,KAAK,EAAE,aAAa;QACpB,IAAI;QACJ,IAAI,EAAE,YAAY;QAClB,KAAK;QACL,MAAM;KACP,CAAC,CAAC;AACL,CAAC","sourcesContent":["import React from 'react';\nimport { type StyleProp, type TextStyle } from 'react-native';\n\nimport { resolveToken } from '../../theme/resolveToken';\nimport { useTheme } from '../../theme/ThemeContext';\nimport type {
|
|
1
|
+
{"version":3,"file":"Icon.js","sourceRoot":"","sources":["../../../src/primitives/icon/Icon.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAkC,MAAM,cAAc,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAatE,MAAM,UAAU,IAAI,CAAC,EACnB,IAAI,EACJ,QAAQ,GAAG,UAAU,EACrB,IAAI,GAAG,GAAG,EACV,KAAK,GAAG,MAAM,EACd,KAAK,EACL,MAAM,GACI;IACV,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC7B,MAAM,aAAa,GAAG,wBAAwB,CAAC,QAAQ,CAAC,CAAC;IACzD,MAAM,YAAY,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzF,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAExD,OAAO,KAAK,CAAC,aAAa,CAAC,aAAa,EAAE;QACxC,KAAK,EAAE,aAAa;QACpB,IAAI;QACJ,IAAI,EAAE,YAAY;QAClB,KAAK;QACL,MAAM;KACP,CAAC,CAAC;AACL,CAAC","sourcesContent":["import React from 'react';\nimport { type StyleProp, type TextStyle } from 'react-native';\n\nimport { resolveToken } from '../../theme/resolveToken';\nimport { useTheme } from '../../theme/ThemeContext';\nimport type { SurfaceTheme } from '../../theme/types';\nimport { resolveExpoIconComponent } from './resolveExpoIconComponent';\n\nexport type IconProvider = string;\n\nexport interface IconProps {\n name: string;\n provider?: IconProvider;\n size?: keyof SurfaceTheme['spacing'] | number;\n color?: keyof SurfaceTheme['colors'] | string;\n style?: StyleProp<TextStyle>;\n testID?: string;\n}\n\nexport function Icon({\n name,\n provider = 'Ionicons',\n size = 'm',\n color = 'text',\n style,\n testID,\n}: IconProps) {\n const { theme } = useTheme();\n const IconComponent = resolveExpoIconComponent(provider);\n const resolvedSize = typeof size === 'number' ? size : resolveToken(theme.spacing, size);\n const resolvedColor = resolveToken(theme.colors, color);\n\n return React.createElement(IconComponent, {\n color: resolvedColor,\n name,\n size: resolvedSize,\n style,\n testID,\n });\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { SurfaceTheme, ThemeConfig } from './types';
|
|
3
3
|
export declare const ThemeContext: React.Context<{
|
|
4
|
-
theme:
|
|
4
|
+
theme: SurfaceTheme;
|
|
5
5
|
mode: "light" | "dark";
|
|
6
6
|
setThemeConfig: (config: Partial<ThemeConfig>) => void;
|
|
7
7
|
setMode: (mode: "light" | "dark") => void;
|
|
@@ -13,7 +13,7 @@ export declare const ThemeProvider: ({ children, initialConfig, initialMode, }:
|
|
|
13
13
|
initialMode?: "light" | "dark";
|
|
14
14
|
}) => React.JSX.Element;
|
|
15
15
|
export declare const useTheme: () => {
|
|
16
|
-
theme:
|
|
16
|
+
theme: SurfaceTheme;
|
|
17
17
|
mode: "light" | "dark";
|
|
18
18
|
setThemeConfig: (config: Partial<ThemeConfig>) => void;
|
|
19
19
|
setMode: (mode: "light" | "dark") => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeContext.d.ts","sourceRoot":"","sources":["../../src/theme/ThemeContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAQlE,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"ThemeContext.d.ts","sourceRoot":"","sources":["../../src/theme/ThemeContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAQlE,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAIzD,eAAO,MAAM,YAAY;WAChB,YAAY;UACb,OAAO,GAAG,MAAM;oBACN,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI;aAC7C,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI;mBAC1B,OAAO;EAWtB,CAAC;AAEH,eAAO,MAAM,aAAa,GAAI,2CAI3B;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACrC,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAChC,sBA0CA,CAAC;AAEF,eAAO,MAAM,QAAQ;WArEZ,YAAY;UACb,OAAO,GAAG,MAAM;oBACN,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI;aAC7C,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,KAAK,IAAI;mBAC1B,OAAO;CAmEvB,CAAC;AAEF,eAAO,MAAM,cAAc,iBAvEA,OAAO,CAAC,WAAW,CAAC,KAAK,IA0EnD,CAAC;AAEF,eAAO,MAAM,YAAY;;oBA3EP,OAAO,GAAG,MAAM,KAAK,IAAI;CA8E1C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeContext.js","sourceRoot":"","sources":["../../src/theme/ThemeContext.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\n\nimport { useFontContext } from '../context/FontContext';\nimport { ResponsiveProvider } from '../core/responsive/ResponsiveProvider';\nimport { OverlayProvider } from '../internal/overlay/OverlayProvider';\nimport { isDeepEqual } from '../utils/deepEqual';\nimport { deepMerge } from '../utils/deepMerge';\nimport { createTheme } from './createTheme';\nimport type {
|
|
1
|
+
{"version":3,"file":"ThemeContext.js","sourceRoot":"","sources":["../../src/theme/ThemeContext.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\n\nimport { useFontContext } from '../context/FontContext';\nimport { ResponsiveProvider } from '../core/responsive/ResponsiveProvider';\nimport { OverlayProvider } from '../internal/overlay/OverlayProvider';\nimport { isDeepEqual } from '../utils/deepEqual';\nimport { deepMerge } from '../utils/deepMerge';\nimport { createTheme } from './createTheme';\nimport type { SurfaceTheme, ThemeConfig } from './types';\n\nconst defaultTheme = createTheme();\n\nexport const ThemeContext = createContext<{\n theme: SurfaceTheme;\n mode: 'light' | 'dark';\n setThemeConfig: (config: Partial<ThemeConfig>) => void;\n setMode: (mode: 'light' | 'dark') => void;\n _hasProvider?: boolean;\n}>({\n theme: defaultTheme,\n mode: 'light',\n setThemeConfig: () => {\n /* fallback */\n },\n setMode: () => {\n /* fallback */\n },\n _hasProvider: false,\n});\n\nexport const ThemeProvider = ({\n children,\n initialConfig,\n initialMode = 'light',\n}: {\n children: React.ReactNode;\n initialConfig?: Partial<ThemeConfig>;\n initialMode?: 'light' | 'dark';\n}) => {\n const [config, setConfig] = React.useState<ThemeConfig>(() =>\n initialConfig ? deepMerge(defaultTheme.config, initialConfig) : defaultTheme.config,\n );\n const [mode, setMode] = React.useState<'light' | 'dark'>(initialMode);\n const { activeFontId } = useFontContext();\n\n // Keep state in sync with prop for real-time Studio updates\n React.useEffect(() => {\n if (initialConfig) {\n setConfig((prev) => {\n const merged = deepMerge(prev, initialConfig);\n if (isDeepEqual(prev, merged)) return prev;\n return merged;\n });\n }\n }, [initialConfig]);\n\n const theme = useMemo(\n () => createTheme(config, mode, activeFontId),\n [config, mode, activeFontId],\n );\n\n const value = useMemo(\n () => ({\n theme,\n mode,\n setThemeConfig: (newConfig: Partial<ThemeConfig>) =>\n setConfig((prev) => deepMerge(prev, newConfig)),\n setMode,\n _hasProvider: true,\n }),\n [theme, mode],\n );\n\n return (\n <ResponsiveProvider>\n <ThemeContext.Provider value={value}>\n <OverlayProvider>{children}</OverlayProvider>\n </ThemeContext.Provider>\n </ResponsiveProvider>\n );\n};\n\nexport const useTheme = () => {\n return useContext(ThemeContext);\n};\n\nexport const useThemeConfig = () => {\n const { setThemeConfig } = useTheme();\n return setThemeConfig;\n};\n\nexport const useThemeMode = () => {\n const { mode, setMode } = useTheme();\n return { mode, setMode };\n};\n"]}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
export declare function
|
|
1
|
+
import type { GeneratedThemeModeColors, GeneratedThemeSwatches, HexColor, SemanticColorReferenceMap, SemanticColorToken } from '@ankhorage/color-theory';
|
|
2
|
+
import type { ThemeConfig } from '@ankhorage/contracts';
|
|
3
|
+
import type { ThemeSemantics } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Surface semantic resolver: maps color-theory SemanticColorToken references
|
|
6
|
+
* to hex values from the generated swatches.
|
|
7
|
+
*/
|
|
8
|
+
export type SurfaceSemanticColors = Record<SemanticColorToken, HexColor>;
|
|
9
|
+
export declare function resolveSemanticColors(generated: GeneratedThemeModeColors, references: SemanticColorReferenceMap): SurfaceSemanticColors;
|
|
10
10
|
export declare function generatePalette(config: ThemeConfig, mode?: 'light' | 'dark'): {
|
|
11
11
|
colors: Record<string, string>;
|
|
12
|
-
|
|
12
|
+
swatches: GeneratedThemeSwatches;
|
|
13
13
|
semantics: ThemeSemantics;
|
|
14
14
|
};
|
|
15
|
-
export {};
|
|
16
15
|
//# sourceMappingURL=colorEngine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"colorEngine.d.ts","sourceRoot":"","sources":["../../src/theme/colorEngine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"colorEngine.d.ts","sourceRoot":"","sources":["../../src/theme/colorEngine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,wBAAwB,EACxB,sBAAsB,EACtB,QAAQ,EACR,yBAAyB,EACzB,kBAAkB,EACnB,MAAM,yBAAyB,CAAC;AAOjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAOV,cAAc,EACf,MAAM,SAAS,CAAC;AAOjB;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;AAEzE,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,wBAAwB,EACnC,UAAU,EAAE,yBAAyB,GACpC,qBAAqB,CAUvB;AA8DD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,WAAW,EACnB,IAAI,GAAE,OAAO,GAAG,MAAgB,GAC/B;IACD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,SAAS,EAAE,cAAc,CAAC;CAC3B,CAsFA"}
|
|
@@ -1,418 +1,94 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* Lightness anchors per internal palette kind
|
|
13
|
-
*/
|
|
14
|
-
const ROLE_PALETTE_LIGHTNESS_ANCHORS = {
|
|
15
|
-
grayscale: 0.62,
|
|
16
|
-
neutral: 0.62,
|
|
17
|
-
pastel: 0.7,
|
|
18
|
-
earth: 0.55,
|
|
19
|
-
mineral: 0.58,
|
|
20
|
-
muted: 0.6,
|
|
21
|
-
jewel: 0.62,
|
|
22
|
-
fluorescent: 0.65,
|
|
23
|
-
obsidian: 0.12,
|
|
24
|
-
vaporwave: 0.7,
|
|
25
|
-
monochromeAccent: 0.62,
|
|
26
|
-
};
|
|
27
|
-
/**
|
|
28
|
-
* Chroma curve per step to prevent "tinted whites" and "glow"
|
|
29
|
-
* Peak energy at 500, falloff at extremes.
|
|
30
|
-
*/
|
|
31
|
-
const CHROMA_BY_STEP = [0.1, 0.18, 0.3, 0.45, 0.7, 1.0, 0.92, 0.8, 0.6, 0.4, 0.25];
|
|
32
|
-
/**
|
|
33
|
-
* Deterministic Chroma Anchors (OKLCH C)
|
|
34
|
-
*/
|
|
35
|
-
const ROLE_PALETTE_CHROMA_ANCHORS = {
|
|
36
|
-
grayscale: 0,
|
|
37
|
-
neutral: 0.02,
|
|
38
|
-
pastel: 0.08,
|
|
39
|
-
earth: 0.05,
|
|
40
|
-
mineral: 0.07,
|
|
41
|
-
muted: 0.04,
|
|
42
|
-
jewel: 0.16,
|
|
43
|
-
fluorescent: 0.26,
|
|
44
|
-
obsidian: 0.01,
|
|
45
|
-
vaporwave: 0.2,
|
|
46
|
-
monochromeAccent: 0.02,
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* Chroma Hierarchy Rule
|
|
50
|
-
*/
|
|
51
|
-
const CHROMA_HIERARCHY = {
|
|
52
|
-
primary: 1.0,
|
|
53
|
-
secondary: 0.7,
|
|
54
|
-
accent: 0.4,
|
|
55
|
-
surface: 0.1,
|
|
56
|
-
};
|
|
57
|
-
/**
|
|
58
|
-
* Semantic Step Mapping
|
|
59
|
-
*/
|
|
60
|
-
const SEMANTIC_STEPS = {
|
|
61
|
-
light: {
|
|
62
|
-
bg: 0, // 50
|
|
63
|
-
bgSubtle: 1, // 100
|
|
64
|
-
surface: 1, // 100
|
|
65
|
-
surfaceHover: 2, // 200
|
|
66
|
-
surfaceActive: 3, // 300
|
|
67
|
-
border: 3, // 300
|
|
68
|
-
borderStrong: 4, // 400
|
|
69
|
-
divider: 2, // 200
|
|
70
|
-
text: 9, // 900
|
|
71
|
-
textMuted: 7, // 700
|
|
72
|
-
textSubtle: 6, // 600
|
|
73
|
-
solid: 5, // 500
|
|
74
|
-
softBg: 1, // 100
|
|
75
|
-
softHover: 2, // 200
|
|
76
|
-
softActive: 3, // 300
|
|
77
|
-
outline: 4, // 400
|
|
78
|
-
},
|
|
79
|
-
dark: {
|
|
80
|
-
bg: 0, // 50
|
|
81
|
-
bgSubtle: 1, // 100
|
|
82
|
-
surface: 1, // 100
|
|
83
|
-
surfaceHover: 2, // 200
|
|
84
|
-
surfaceActive: 3, // 300
|
|
85
|
-
border: 3, // 300
|
|
86
|
-
borderStrong: 4, // 400
|
|
87
|
-
divider: 2, // 200
|
|
88
|
-
text: 10, // 950
|
|
89
|
-
textMuted: 8, // 800
|
|
90
|
-
textSubtle: 7, // 700
|
|
91
|
-
solid: 5, // 500
|
|
92
|
-
softBg: 1, // 100
|
|
93
|
-
softHover: 2, // 200
|
|
94
|
-
softActive: 3, // 300
|
|
95
|
-
outline: 4, // 400
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
export function generateColorScale(baseColor, isDark) {
|
|
99
|
-
const scale = {};
|
|
100
|
-
const curve = isDark ? LIGHTNESS_CURVES.dark : LIGHTNESS_CURVES.light;
|
|
101
|
-
// Dark-mode chroma rule: reduce chroma by 25%
|
|
102
|
-
const chromaMultiplier = isDark ? 0.75 : 1.0;
|
|
103
|
-
const targetChroma = baseColor.c * chromaMultiplier;
|
|
104
|
-
SCALE_STEPS.forEach((step, index) => {
|
|
105
|
-
const lightness = curve[index];
|
|
106
|
-
const chromaByStep = CHROMA_BY_STEP[index];
|
|
107
|
-
if (lightness === undefined || chromaByStep === undefined) {
|
|
108
|
-
return;
|
|
1
|
+
import { generateColorSwatch, generateThemeModeColors, getReadableForeground, parseHexColorOrThrow, } from '@ankhorage/color-theory';
|
|
2
|
+
// Fixed hex values for semantic status colors (not theme-generated)
|
|
3
|
+
const DANGER_HEX = parseHexColorOrThrow('#ef4444');
|
|
4
|
+
const SUCCESS_HEX = parseHexColorOrThrow('#22c55e');
|
|
5
|
+
const WARNING_HEX = parseHexColorOrThrow('#f59e0b');
|
|
6
|
+
export function resolveSemanticColors(generated, references) {
|
|
7
|
+
return Object.fromEntries(Object.entries(references).map(([token, ref]) => {
|
|
8
|
+
const swatch = generated.swatches[ref.role];
|
|
9
|
+
if (!swatch) {
|
|
10
|
+
throw new Error(`Missing swatch for role '${ref.role}' (token: '${token}')`);
|
|
109
11
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const stepColor = { ...baseColor, l: lightness, c: stepChroma };
|
|
113
|
-
scale[step] = formatHex(stepColor);
|
|
114
|
-
});
|
|
115
|
-
return scale;
|
|
12
|
+
return [token, swatch[ref.step]];
|
|
13
|
+
}));
|
|
116
14
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return [h, (h + 120) % 360, (h + 240) % 360];
|
|
133
|
-
case 'tetradic':
|
|
134
|
-
return [h, (h + 90) % 360, (h + 180) % 360, (h + 270) % 360];
|
|
135
|
-
default:
|
|
136
|
-
return [h];
|
|
15
|
+
function buildNeutralSemantics(neutralSwatch, isDark) {
|
|
16
|
+
if (isDark) {
|
|
17
|
+
return {
|
|
18
|
+
bg: neutralSwatch[950],
|
|
19
|
+
bgSubtle: neutralSwatch[900],
|
|
20
|
+
surface: neutralSwatch[900],
|
|
21
|
+
surfaceHover: neutralSwatch[800],
|
|
22
|
+
surfaceActive: neutralSwatch[700],
|
|
23
|
+
border: neutralSwatch[800],
|
|
24
|
+
borderStrong: neutralSwatch[600],
|
|
25
|
+
divider: neutralSwatch[800],
|
|
26
|
+
text: neutralSwatch[50],
|
|
27
|
+
textMuted: neutralSwatch[200],
|
|
28
|
+
textSubtle: neutralSwatch[300],
|
|
29
|
+
};
|
|
137
30
|
}
|
|
31
|
+
return {
|
|
32
|
+
bg: neutralSwatch[50],
|
|
33
|
+
bgSubtle: neutralSwatch[100],
|
|
34
|
+
surface: neutralSwatch[100],
|
|
35
|
+
surfaceHover: neutralSwatch[200],
|
|
36
|
+
surfaceActive: neutralSwatch[300],
|
|
37
|
+
border: neutralSwatch[200],
|
|
38
|
+
borderStrong: neutralSwatch[300],
|
|
39
|
+
divider: neutralSwatch[200],
|
|
40
|
+
text: neutralSwatch[900],
|
|
41
|
+
textMuted: neutralSwatch[700],
|
|
42
|
+
textSubtle: neutralSwatch[600],
|
|
43
|
+
};
|
|
138
44
|
}
|
|
139
|
-
function
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
surface: 'earth',
|
|
154
|
-
primary: 'mineral',
|
|
155
|
-
secondary: 'mineral',
|
|
156
|
-
accent: 'jewel',
|
|
157
|
-
highlight: 'jewel',
|
|
158
|
-
};
|
|
159
|
-
case 'mineral':
|
|
160
|
-
return {
|
|
161
|
-
bg: 'mineral',
|
|
162
|
-
surface: 'mineral',
|
|
163
|
-
primary: 'jewel',
|
|
164
|
-
secondary: 'mineral',
|
|
165
|
-
accent: 'jewel',
|
|
166
|
-
highlight: 'fluorescent',
|
|
167
|
-
};
|
|
168
|
-
case 'muted':
|
|
169
|
-
return {
|
|
170
|
-
bg: 'muted',
|
|
171
|
-
surface: 'muted',
|
|
172
|
-
primary: 'jewel',
|
|
173
|
-
secondary: 'muted',
|
|
174
|
-
accent: 'jewel',
|
|
175
|
-
highlight: 'fluorescent',
|
|
176
|
-
};
|
|
177
|
-
case 'jewel':
|
|
178
|
-
return {
|
|
179
|
-
bg: 'grayscale',
|
|
180
|
-
surface: 'grayscale',
|
|
181
|
-
primary: 'jewel',
|
|
182
|
-
secondary: 'jewel',
|
|
183
|
-
accent: 'jewel',
|
|
184
|
-
highlight: 'fluorescent',
|
|
185
|
-
};
|
|
186
|
-
case 'fluorescent':
|
|
187
|
-
return {
|
|
188
|
-
bg: 'obsidian',
|
|
189
|
-
surface: 'obsidian',
|
|
190
|
-
primary: 'fluorescent',
|
|
191
|
-
secondary: 'jewel',
|
|
192
|
-
accent: 'fluorescent',
|
|
193
|
-
highlight: 'fluorescent',
|
|
194
|
-
};
|
|
195
|
-
case 'obsidian':
|
|
196
|
-
return {
|
|
197
|
-
bg: 'obsidian',
|
|
198
|
-
surface: 'obsidian',
|
|
199
|
-
primary: 'fluorescent',
|
|
200
|
-
secondary: 'jewel',
|
|
201
|
-
accent: 'fluorescent',
|
|
202
|
-
highlight: 'fluorescent',
|
|
203
|
-
};
|
|
204
|
-
case 'vaporwave':
|
|
205
|
-
return {
|
|
206
|
-
bg: 'pastel',
|
|
207
|
-
surface: 'pastel',
|
|
208
|
-
primary: 'fluorescent',
|
|
209
|
-
secondary: 'jewel',
|
|
210
|
-
accent: 'fluorescent',
|
|
211
|
-
highlight: 'fluorescent',
|
|
212
|
-
};
|
|
213
|
-
case 'monochromeAccent':
|
|
214
|
-
return {
|
|
215
|
-
bg: 'grayscale',
|
|
216
|
-
surface: 'grayscale',
|
|
217
|
-
primary: 'jewel',
|
|
218
|
-
secondary: 'grayscale',
|
|
219
|
-
accent: 'jewel',
|
|
220
|
-
highlight: 'fluorescent',
|
|
221
|
-
};
|
|
222
|
-
default: // neutral
|
|
223
|
-
return {
|
|
224
|
-
bg: 'grayscale',
|
|
225
|
-
surface: 'grayscale',
|
|
226
|
-
primary: 'jewel',
|
|
227
|
-
secondary: 'pastel',
|
|
228
|
-
accent: 'jewel',
|
|
229
|
-
highlight: 'fluorescent',
|
|
230
|
-
};
|
|
45
|
+
function buildRoleSemantics(swatch, isDark) {
|
|
46
|
+
const base = swatch[500];
|
|
47
|
+
const { foreground: onSolidText } = getReadableForeground(base);
|
|
48
|
+
if (isDark) {
|
|
49
|
+
return {
|
|
50
|
+
base,
|
|
51
|
+
hover: swatch[400],
|
|
52
|
+
strong: swatch[300],
|
|
53
|
+
softBg: swatch[900],
|
|
54
|
+
softHover: swatch[800],
|
|
55
|
+
softActive: swatch[700],
|
|
56
|
+
outline: swatch[500],
|
|
57
|
+
onSolidText,
|
|
58
|
+
};
|
|
231
59
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const diff50 = Math.abs(solid.l - n50.l);
|
|
243
|
-
const diff950 = Math.abs(solid.l - n950.l);
|
|
244
|
-
return diff50 >= diff950 ? neutral50 : neutral950;
|
|
60
|
+
return {
|
|
61
|
+
base,
|
|
62
|
+
hover: swatch[600],
|
|
63
|
+
strong: swatch[700],
|
|
64
|
+
softBg: swatch[100],
|
|
65
|
+
softHover: swatch[200],
|
|
66
|
+
softActive: swatch[300],
|
|
67
|
+
outline: swatch[400],
|
|
68
|
+
onSolidText,
|
|
69
|
+
};
|
|
245
70
|
}
|
|
246
71
|
export function generatePalette(config, mode = 'light') {
|
|
247
72
|
const modeConfig = mode === 'dark' ? config.dark : config.light;
|
|
248
|
-
const { primaryColor, harmony, colorTone } = modeConfig;
|
|
249
|
-
let base = oklch(primaryColor);
|
|
250
|
-
if (!base) {
|
|
251
|
-
console.warn(`[colorEngine] Invalid primary color: "${primaryColor}". Falling back to default blue.`);
|
|
252
|
-
base = oklch('#3B82F6');
|
|
253
|
-
}
|
|
254
|
-
const baseHue = base?.h ?? 0;
|
|
255
|
-
const hues = getHarmonyHues(baseHue, harmony);
|
|
256
|
-
const rolePalette = getColorToneRolePalette(colorTone);
|
|
257
|
-
// 1. Resolve Chromas
|
|
258
|
-
const getC = (t) => ROLE_PALETTE_CHROMA_ANCHORS[t];
|
|
259
|
-
const getHue = (index, fallback) => hues[index] ?? fallback;
|
|
260
|
-
const primaryChroma = getC(rolePalette.primary);
|
|
261
|
-
const secondaryChroma = getC(rolePalette.secondary) * CHROMA_HIERARCHY.secondary;
|
|
262
|
-
const tertiaryChroma = getC(rolePalette.accent) * CHROMA_HIERARCHY.accent;
|
|
263
|
-
const highlightChroma = getC(rolePalette.highlight);
|
|
264
|
-
const surfaceChroma = Math.min(0.02, getC(rolePalette.bg) * CHROMA_HIERARCHY.surface);
|
|
265
|
-
// 2. Stable Role Assignment
|
|
266
|
-
let pHue = getHue(0, baseHue);
|
|
267
|
-
let sHue = getHue(0, baseHue);
|
|
268
|
-
let aHue = getHue(0, baseHue);
|
|
269
|
-
let hHue = harmony === 'tetradic' ? getHue(3, getHue(0, baseHue)) : (getHue(0, baseHue) + 60) % 360; // Yellow-ish offset if no tetradic
|
|
270
|
-
switch (harmony) {
|
|
271
|
-
case 'complementary':
|
|
272
|
-
pHue = getHue(0, pHue);
|
|
273
|
-
aHue = getHue(1, pHue);
|
|
274
|
-
sHue = (getHue(0, pHue) + 30) % 360;
|
|
275
|
-
break;
|
|
276
|
-
case 'splitComplementary':
|
|
277
|
-
case 'triadic':
|
|
278
|
-
pHue = getHue(0, pHue);
|
|
279
|
-
sHue = getHue(1, pHue);
|
|
280
|
-
aHue = getHue(2, sHue);
|
|
281
|
-
break;
|
|
282
|
-
case 'tetradic':
|
|
283
|
-
pHue = getHue(0, pHue);
|
|
284
|
-
sHue = getHue(1, pHue);
|
|
285
|
-
aHue = getHue(2, sHue);
|
|
286
|
-
hHue = getHue(3, aHue);
|
|
287
|
-
break;
|
|
288
|
-
case 'analogous':
|
|
289
|
-
pHue = getHue(1, pHue);
|
|
290
|
-
sHue = getHue(0, pHue);
|
|
291
|
-
aHue = getHue(2, sHue);
|
|
292
|
-
break;
|
|
293
|
-
}
|
|
294
|
-
// 3. Build Bases with tuned lightness
|
|
295
|
-
const getL = (t) => ROLE_PALETTE_LIGHTNESS_ANCHORS[t];
|
|
296
|
-
const primaryBase = {
|
|
297
|
-
mode: 'oklch',
|
|
298
|
-
l: getL(rolePalette.primary),
|
|
299
|
-
c: primaryChroma,
|
|
300
|
-
h: pHue,
|
|
301
|
-
};
|
|
302
|
-
const secondaryBase = {
|
|
303
|
-
mode: 'oklch',
|
|
304
|
-
l: getL(rolePalette.secondary),
|
|
305
|
-
c: secondaryChroma,
|
|
306
|
-
h: sHue,
|
|
307
|
-
};
|
|
308
|
-
const accentBase = {
|
|
309
|
-
mode: 'oklch',
|
|
310
|
-
l: getL(rolePalette.accent),
|
|
311
|
-
c: tertiaryChroma,
|
|
312
|
-
h: aHue,
|
|
313
|
-
};
|
|
314
|
-
const highlightBase = {
|
|
315
|
-
mode: 'oklch',
|
|
316
|
-
l: getL(rolePalette.highlight),
|
|
317
|
-
c: highlightChroma,
|
|
318
|
-
h: hHue,
|
|
319
|
-
};
|
|
320
|
-
const dangerBase = {
|
|
321
|
-
mode: 'oklch',
|
|
322
|
-
l: 0.6,
|
|
323
|
-
c: 0.2,
|
|
324
|
-
h: 25,
|
|
325
|
-
};
|
|
326
|
-
const successBase = {
|
|
327
|
-
mode: 'oklch',
|
|
328
|
-
l: 0.6,
|
|
329
|
-
c: 0.2,
|
|
330
|
-
h: 145,
|
|
331
|
-
};
|
|
332
|
-
const warningBase = {
|
|
333
|
-
mode: 'oklch',
|
|
334
|
-
l: 0.75,
|
|
335
|
-
c: 0.15,
|
|
336
|
-
h: 85,
|
|
337
|
-
};
|
|
338
|
-
const neutralBase = surfaceChroma === 0
|
|
339
|
-
? { mode: 'oklch', l: 0.62, c: 0 }
|
|
340
|
-
: { mode: 'oklch', l: 0.62, c: surfaceChroma, h: 260 };
|
|
341
|
-
// 4. Generate Scales
|
|
342
73
|
const isDark = mode === 'dark';
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
bgSubtle: getStep(scale, steps.bgSubtle),
|
|
362
|
-
surface: getStep(scale, steps.surface),
|
|
363
|
-
surfaceHover: getStep(scale, steps.surfaceHover),
|
|
364
|
-
surfaceActive: getStep(scale, steps.surfaceActive),
|
|
365
|
-
border: getStep(scale, steps.border),
|
|
366
|
-
borderStrong: getStep(scale, steps.borderStrong),
|
|
367
|
-
divider: getStep(scale, steps.divider),
|
|
368
|
-
text: getStep(scale, steps.text),
|
|
369
|
-
textMuted: getStep(scale, steps.textMuted),
|
|
370
|
-
textSubtle: getStep(scale, steps.textSubtle),
|
|
371
|
-
});
|
|
372
|
-
const getColorMapping = (scale, neutralScale) => {
|
|
373
|
-
const solid = getStep(scale, steps.solid);
|
|
374
|
-
const softChromaLimit = 0.08;
|
|
375
|
-
// Chroma capping for soft tokens
|
|
376
|
-
const getSoftStep = (idx) => {
|
|
377
|
-
const hex = getStep(scale, idx);
|
|
378
|
-
const color = oklch(hex);
|
|
379
|
-
if (color && color.c > softChromaLimit) {
|
|
380
|
-
return formatHex({ ...color, c: softChromaLimit });
|
|
381
|
-
}
|
|
382
|
-
return hex;
|
|
383
|
-
};
|
|
384
|
-
return {
|
|
385
|
-
base: solid,
|
|
386
|
-
hover: getStep(scale, 6), // 600
|
|
387
|
-
strong: getStep(scale, 7), // 700
|
|
388
|
-
softBg: getSoftStep(steps.softBg),
|
|
389
|
-
softHover: getSoftStep(steps.softHover),
|
|
390
|
-
softActive: getSoftStep(steps.softActive),
|
|
391
|
-
outline: getStep(scale, steps.outline),
|
|
392
|
-
onSolidText: getBestContrast(solid, getStep(neutralScale, 0), getStep(neutralScale, 10)),
|
|
393
|
-
};
|
|
394
|
-
};
|
|
395
|
-
const neutral = getNeutralMapping(scales.neutral);
|
|
396
|
-
const brand = getColorMapping(scales.primary, scales.neutral);
|
|
397
|
-
const neutralAction = getColorMapping(scales.neutral, scales.neutral);
|
|
398
|
-
const danger = getColorMapping(scales.danger, scales.neutral);
|
|
399
|
-
const success = getColorMapping(scales.success, scales.neutral);
|
|
400
|
-
const warning = getColorMapping(scales.warning, scales.neutral);
|
|
401
|
-
const colors = {
|
|
402
|
-
primary: getStep(scales.primary, steps.solid),
|
|
403
|
-
secondary: getStep(scales.secondary, steps.solid),
|
|
404
|
-
accent: getStep(scales.accent, steps.solid),
|
|
405
|
-
highlight: getStep(scales.highlight, steps.solid),
|
|
406
|
-
background: neutral.bg,
|
|
407
|
-
surface: neutral.surface,
|
|
408
|
-
text: neutral.text,
|
|
409
|
-
textSecondary: neutral.textMuted,
|
|
410
|
-
border: neutral.border,
|
|
411
|
-
error: getStep(scales.danger, steps.solid),
|
|
412
|
-
success: getStep(scales.success, steps.solid),
|
|
413
|
-
warning: getStep(scales.warning, steps.solid),
|
|
414
|
-
};
|
|
415
|
-
const surface = {
|
|
74
|
+
// Throws deterministically on invalid primary color
|
|
75
|
+
parseHexColorOrThrow(modeConfig.primaryColor);
|
|
76
|
+
const generated = generateThemeModeColors(modeConfig);
|
|
77
|
+
const { swatches } = generated;
|
|
78
|
+
const neutralSwatch = swatches.neutral;
|
|
79
|
+
const neutral = buildNeutralSemantics(neutralSwatch, isDark);
|
|
80
|
+
const brand = buildRoleSemantics(swatches.primary, isDark);
|
|
81
|
+
// Fallback to primary swatch for missing ordinal roles
|
|
82
|
+
const secondarySwatch = swatches.secondary ?? swatches.primary;
|
|
83
|
+
const tertiarySwatch = swatches.tertiary ?? swatches.primary;
|
|
84
|
+
const quaternarySwatch = swatches.quaternary ?? swatches.primary;
|
|
85
|
+
const dangerSwatch = generateColorSwatch(DANGER_HEX).swatch;
|
|
86
|
+
const successSwatch = generateColorSwatch(SUCCESS_HEX).swatch;
|
|
87
|
+
const warningSwatch = generateColorSwatch(WARNING_HEX).swatch;
|
|
88
|
+
const danger = buildRoleSemantics(dangerSwatch, isDark);
|
|
89
|
+
const success = buildRoleSemantics(successSwatch, isDark);
|
|
90
|
+
const warning = buildRoleSemantics(warningSwatch, isDark);
|
|
91
|
+
const surfaceSemantics = {
|
|
416
92
|
default: neutral.surface,
|
|
417
93
|
subtle: neutral.bgSubtle,
|
|
418
94
|
raised: neutral.surface,
|
|
@@ -430,22 +106,36 @@ export function generatePalette(config, mode = 'light') {
|
|
|
430
106
|
};
|
|
431
107
|
const action = {
|
|
432
108
|
primary: brand,
|
|
433
|
-
neutral:
|
|
109
|
+
neutral: buildRoleSemantics(neutralSwatch, isDark),
|
|
434
110
|
danger,
|
|
435
111
|
};
|
|
112
|
+
const colors = {
|
|
113
|
+
primary: brand.base,
|
|
114
|
+
secondary: secondarySwatch[500],
|
|
115
|
+
accent: tertiarySwatch[500],
|
|
116
|
+
highlight: quaternarySwatch[500],
|
|
117
|
+
background: neutral.bg,
|
|
118
|
+
surface: neutral.surface,
|
|
119
|
+
text: neutral.text,
|
|
120
|
+
textSecondary: neutral.textMuted,
|
|
121
|
+
border: neutral.border,
|
|
122
|
+
error: danger.base,
|
|
123
|
+
success: success.base,
|
|
124
|
+
warning: warning.base,
|
|
125
|
+
};
|
|
436
126
|
return {
|
|
437
127
|
colors,
|
|
438
|
-
|
|
128
|
+
swatches,
|
|
439
129
|
semantics: {
|
|
440
130
|
neutral,
|
|
441
131
|
brand,
|
|
442
|
-
secondary:
|
|
443
|
-
accent:
|
|
444
|
-
highlight:
|
|
132
|
+
secondary: buildRoleSemantics(secondarySwatch, isDark),
|
|
133
|
+
accent: buildRoleSemantics(tertiarySwatch, isDark),
|
|
134
|
+
highlight: buildRoleSemantics(quaternarySwatch, isDark),
|
|
445
135
|
danger,
|
|
446
136
|
success,
|
|
447
137
|
warning,
|
|
448
|
-
surface,
|
|
138
|
+
surface: surfaceSemantics,
|
|
449
139
|
content,
|
|
450
140
|
border,
|
|
451
141
|
action,
|