@lobehub/ui 6.0.0-beta.9 → 6.0.1

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.
Files changed (115) hide show
  1. package/README.md +3 -3
  2. package/es/Accordion/style.d.mts +1 -1
  3. package/es/CodeDiff/DiffPanel.mjs +2 -2
  4. package/es/CodeDiff/DiffPanel.mjs.map +1 -1
  5. package/es/Drawer/atoms.mjs +2 -1
  6. package/es/Drawer/atoms.mjs.map +1 -1
  7. package/es/Drawer/style.mjs.map +1 -1
  8. package/es/DropdownMenu/atoms.mjs +2 -1
  9. package/es/DropdownMenu/atoms.mjs.map +1 -1
  10. package/es/FloatingPanel/style.mjs +3 -2
  11. package/es/FloatingPanel/style.mjs.map +1 -1
  12. package/es/Form/Form.mjs +6 -2
  13. package/es/Form/Form.mjs.map +1 -1
  14. package/es/Form/style.mjs +3 -3
  15. package/es/Form/style.mjs.map +1 -1
  16. package/es/Form/type.d.mts +7 -0
  17. package/es/Modal/atoms.mjs +2 -1
  18. package/es/Modal/atoms.mjs.map +1 -1
  19. package/es/Popover/PopoverInGroup.mjs +2 -1
  20. package/es/Popover/PopoverInGroup.mjs.map +1 -1
  21. package/es/Popover/atoms.mjs +2 -1
  22. package/es/Popover/atoms.mjs.map +1 -1
  23. package/es/Popover/style.mjs +1 -1
  24. package/es/Popover/style.mjs.map +1 -1
  25. package/es/ProTable/hooks/useFetchData.mjs +1 -1
  26. package/es/ProTable/hooks/useFetchData.mjs.map +1 -1
  27. package/es/ProTable/parts/FieldControl.mjs +28 -11
  28. package/es/ProTable/parts/FieldControl.mjs.map +1 -1
  29. package/es/ProTable/style.mjs +9 -0
  30. package/es/ProTable/style.mjs.map +1 -1
  31. package/es/ProTable/type.d.mts +5 -2
  32. package/es/Segmented/Segmented.mjs +2 -1
  33. package/es/Segmented/Segmented.mjs.map +1 -1
  34. package/es/Segmented/type.d.mts +7 -0
  35. package/es/Select/atoms.mjs +2 -1
  36. package/es/Select/atoms.mjs.map +1 -1
  37. package/es/Switch/Switch.mjs +8 -1
  38. package/es/Switch/Switch.mjs.map +1 -1
  39. package/es/Switch/atoms.d.mts +7 -1
  40. package/es/Switch/atoms.mjs +20 -4
  41. package/es/Switch/atoms.mjs.map +1 -1
  42. package/es/Switch/style.mjs +33 -2
  43. package/es/Switch/style.mjs.map +1 -1
  44. package/es/Table/Table.mjs +14 -5
  45. package/es/Table/Table.mjs.map +1 -1
  46. package/es/Table/render/FixedFrost.mjs +11 -2
  47. package/es/Table/render/FixedFrost.mjs.map +1 -1
  48. package/es/Table/style.mjs +4 -0
  49. package/es/Table/style.mjs.map +1 -1
  50. package/es/Toast/dodge.mjs +0 -1
  51. package/es/Toast/dodge.mjs.map +1 -1
  52. package/es/Toast/dodge.stylex.mjs +1 -4
  53. package/es/Toast/dodge.stylex.mjs.map +1 -1
  54. package/es/Toast/style.mjs +1 -1
  55. package/es/Toast/style.mjs.map +1 -1
  56. package/es/Tooltip/TooltipInGroup.mjs +2 -1
  57. package/es/Tooltip/TooltipInGroup.mjs.map +1 -1
  58. package/es/Tooltip/TooltipStandalone.mjs +2 -1
  59. package/es/Tooltip/TooltipStandalone.mjs.map +1 -1
  60. package/es/Tooltip/style.mjs +2 -2
  61. package/es/Tooltip/style.mjs.map +1 -1
  62. package/es/color/index.d.mts +2 -1
  63. package/es/color/index.mjs +2 -1
  64. package/es/color/status/error.mjs +67 -0
  65. package/es/color/status/error.mjs.map +1 -0
  66. package/es/color/status/index.d.mts +11 -0
  67. package/es/color/status/index.mjs +15 -0
  68. package/es/color/status/index.mjs.map +1 -0
  69. package/es/color/status/info.mjs +67 -0
  70. package/es/color/status/info.mjs.map +1 -0
  71. package/es/color/status/success.mjs +67 -0
  72. package/es/color/status/success.mjs.map +1 -0
  73. package/es/color/status/warning.mjs +67 -0
  74. package/es/color/status/warning.mjs.map +1 -0
  75. package/es/hooks/useNativeButton.mjs +1 -0
  76. package/es/hooks/useNativeButton.mjs.map +1 -1
  77. package/es/index.d.mts +4 -2
  78. package/es/index.mjs +4 -2
  79. package/es/style.css +114 -23
  80. package/es/styles/index.d.mts +4 -2
  81. package/es/styles/index.mjs +4 -2
  82. package/es/styles/stylex/cssVar.stylex.mjs +3 -0
  83. package/es/styles/stylex/cssVar.stylex.mjs.map +1 -1
  84. package/es/styles/theme/createLobeToken.d.mts +11 -7
  85. package/es/styles/theme/createLobeToken.mjs +3 -2
  86. package/es/styles/theme/createLobeToken.mjs.map +1 -1
  87. package/es/styles/theme/customNeutral.d.mts +28 -0
  88. package/es/styles/theme/customNeutral.mjs +84 -0
  89. package/es/styles/theme/customNeutral.mjs.map +1 -0
  90. package/es/styles/theme/customPalette.d.mts +6 -0
  91. package/es/styles/theme/customPalette.mjs +32 -0
  92. package/es/styles/theme/customPalette.mjs.map +1 -0
  93. package/es/styles/theme/customPrimary.mjs +52 -17
  94. package/es/styles/theme/customPrimary.mjs.map +1 -1
  95. package/es/styles/theme/scope.d.mts +7 -5
  96. package/es/styles/theme/scope.mjs +105 -22
  97. package/es/styles/theme/scope.mjs.map +1 -1
  98. package/es/styles/theme/themeCss.d.mts +3 -0
  99. package/es/styles/theme/themeCss.mjs +46 -1
  100. package/es/styles/theme/themeCss.mjs.map +1 -1
  101. package/es/styles/theme/token/legacy.mjs +12 -12
  102. package/es/styles/theme/token/legacy.mjs.map +1 -1
  103. package/es/styles/theme/token/neutral.mjs +13 -7
  104. package/es/styles/theme/token/neutral.mjs.map +1 -1
  105. package/es/styles/theme/token/neutralText.d.mts +4 -0
  106. package/es/styles/theme/token/neutralText.mjs +91 -0
  107. package/es/styles/theme/token/neutralText.mjs.map +1 -0
  108. package/es/styles/theme/token/palette.mjs +16 -41
  109. package/es/styles/theme/token/palette.mjs.map +1 -1
  110. package/es/styles/theme/token/static.mjs +3 -0
  111. package/es/styles/theme/token/static.mjs.map +1 -1
  112. package/es/theme.css +293 -290
  113. package/es/utils/getElementRef.mjs +17 -0
  114. package/es/utils/getElementRef.mjs.map +1 -0
  115. package/package.json +1 -1
@@ -1,12 +1,13 @@
1
- import { NeutralColors } from "../customTheme.mjs";
1
+ import { LobeNeutralColor } from "./customNeutral.mjs";
2
2
  import { LobePrimaryColor } from "./customPrimary.mjs";
3
3
  //#region src/styles/theme/createLobeToken.d.ts
4
4
  export interface CreateLobeTokenParams {
5
5
  appearance: 'light' | 'dark';
6
- neutralColor?: NeutralColors;
6
+ neutralColor?: LobeNeutralColor;
7
+ palette?: string;
7
8
  primaryColor?: LobePrimaryColor;
8
9
  }
9
- export declare const createLobeTokenGroups: ({ appearance, neutralColor, primaryColor }: CreateLobeTokenParams) => {
10
+ export declare const createLobeTokenGroups: ({ appearance, neutralColor, palette: paletteName, primaryColor }: CreateLobeTokenParams) => {
10
11
  neutral: {
11
12
  colorBgContainerDisabled: string;
12
13
  colorBgContainerSecondary: string;
@@ -29,6 +30,10 @@ export declare const createLobeTokenGroups: ({ appearance, neutralColor, primary
29
30
  controlItemBgActiveDisabled: string;
30
31
  controlItemBgHover: string;
31
32
  controlTmpOutline: string;
33
+ colorText: string;
34
+ colorTextQuaternary: string;
35
+ colorTextSecondary: string;
36
+ colorTextTertiary: string;
32
37
  colorBgContainer: string;
33
38
  colorBgElevated: string;
34
39
  colorBgLayout: string;
@@ -40,10 +45,6 @@ export declare const createLobeTokenGroups: ({ appearance, neutralColor, primary
40
45
  colorFillQuaternary: string;
41
46
  colorFillSecondary: string;
42
47
  colorFillTertiary: string;
43
- colorText: string;
44
- colorTextQuaternary: string;
45
- colorTextSecondary: string;
46
- colorTextTertiary: string;
47
48
  };
48
49
  palette: {
49
50
  colorErrorAffix: string;
@@ -1291,6 +1292,9 @@ export declare const createLobeTokenGroups: ({ appearance, neutralColor, primary
1291
1292
  motionEaseOutBack: string;
1292
1293
  motionEaseOutCirc: string;
1293
1294
  motionEaseOutQuint: string;
1295
+ motionSpringBouncy: string;
1296
+ motionSpringSmooth: string;
1297
+ motionSpringSnappy: string;
1294
1298
  motionUnit: number;
1295
1299
  opacityImage: number;
1296
1300
  opacityLoading: number;
@@ -1,10 +1,11 @@
1
+ import { resolveStatusScales } from "./customPalette.mjs";
1
2
  import { createNeutralToken } from "./token/neutral.mjs";
2
3
  import { createPaletteToken } from "./token/palette.mjs";
3
4
  import { createPrimaryToken } from "./token/primary.mjs";
4
5
  import { staticToken } from "./token/static.mjs";
5
6
  //#region src/styles/theme/createLobeToken.ts
6
- const createLobeTokenGroups = ({ appearance, neutralColor, primaryColor }) => {
7
- const palette = createPaletteToken(appearance);
7
+ const createLobeTokenGroups = ({ appearance, neutralColor, palette: paletteName, primaryColor }) => {
8
+ const palette = createPaletteToken(appearance, resolveStatusScales(paletteName));
8
9
  return {
9
10
  neutral: createNeutralToken(appearance, neutralColor, palette),
10
11
  palette,
@@ -1 +1 @@
1
- {"version":3,"file":"createLobeToken.mjs","names":[],"sources":["../../../src/styles/theme/createLobeToken.ts"],"sourcesContent":["import type { NeutralColors } from '../customTheme';\nimport type { LobePrimaryColor } from './customPrimary';\nimport { createNeutralToken } from './token/neutral';\nimport { createPaletteToken } from './token/palette';\nimport { createPrimaryToken } from './token/primary';\nimport { staticToken } from './token/static';\n\nexport interface CreateLobeTokenParams {\n appearance: 'light' | 'dark';\n neutralColor?: NeutralColors;\n primaryColor?: LobePrimaryColor;\n}\n\nexport const createLobeTokenGroups = ({\n appearance,\n neutralColor,\n primaryColor,\n}: CreateLobeTokenParams) => {\n const palette = createPaletteToken(appearance);\n\n return {\n neutral: createNeutralToken(appearance, neutralColor, palette),\n palette,\n primary: createPrimaryToken(appearance, primaryColor),\n static: staticToken,\n };\n};\n\nexport type LobeTokenGroups = ReturnType<typeof createLobeTokenGroups>;\n\nexport type LobeToken = LobeTokenGroups['static'] &\n LobeTokenGroups['palette'] &\n LobeTokenGroups['primary'] &\n LobeTokenGroups['neutral'];\n\nexport const createLobeToken = (params: CreateLobeTokenParams): LobeToken => {\n const groups = createLobeTokenGroups(params);\n\n return { ...groups.static, ...groups.palette, ...groups.primary, ...groups.neutral };\n};\n"],"mappings":";;;;;AAaA,MAAa,yBAAyB,EACpC,YACA,cACA,mBAC2B;CAC3B,MAAM,UAAU,mBAAmB,UAAU;CAE7C,OAAO;EACL,SAAS,mBAAmB,YAAY,cAAc,OAAO;EAC7D;EACA,SAAS,mBAAmB,YAAY,YAAY;EACpD,QAAQ;CACV;AACF;AASA,MAAa,mBAAmB,WAA6C;CAC3E,MAAM,SAAS,sBAAsB,MAAM;CAE3C,OAAO;EAAE,GAAG,OAAO;EAAQ,GAAG,OAAO;EAAS,GAAG,OAAO;EAAS,GAAG,OAAO;CAAQ;AACrF"}
1
+ {"version":3,"file":"createLobeToken.mjs","names":[],"sources":["../../../src/styles/theme/createLobeToken.ts"],"sourcesContent":["import type { LobeNeutralColor } from './customNeutral';\nimport { resolveStatusScales } from './customPalette';\nimport type { LobePrimaryColor } from './customPrimary';\nimport { createNeutralToken } from './token/neutral';\nimport { createPaletteToken } from './token/palette';\nimport { createPrimaryToken } from './token/primary';\nimport { staticToken } from './token/static';\n\nexport interface CreateLobeTokenParams {\n appearance: 'light' | 'dark';\n neutralColor?: LobeNeutralColor;\n palette?: string;\n primaryColor?: LobePrimaryColor;\n}\n\nexport const createLobeTokenGroups = ({\n appearance,\n neutralColor,\n palette: paletteName,\n primaryColor,\n}: CreateLobeTokenParams) => {\n const palette = createPaletteToken(appearance, resolveStatusScales(paletteName));\n\n return {\n neutral: createNeutralToken(appearance, neutralColor, palette),\n palette,\n primary: createPrimaryToken(appearance, primaryColor),\n static: staticToken,\n };\n};\n\nexport type LobeTokenGroups = ReturnType<typeof createLobeTokenGroups>;\n\nexport type LobeToken = LobeTokenGroups['static'] &\n LobeTokenGroups['palette'] &\n LobeTokenGroups['primary'] &\n LobeTokenGroups['neutral'];\n\nexport const createLobeToken = (params: CreateLobeTokenParams): LobeToken => {\n const groups = createLobeTokenGroups(params);\n\n return { ...groups.static, ...groups.palette, ...groups.primary, ...groups.neutral };\n};\n"],"mappings":";;;;;;AAeA,MAAa,yBAAyB,EACpC,YACA,cACA,SAAS,aACT,mBAC2B;CAC3B,MAAM,UAAU,mBAAmB,YAAY,oBAAoB,WAAW,CAAC;CAE/E,OAAO;EACL,SAAS,mBAAmB,YAAY,cAAc,OAAO;EAC7D;EACA,SAAS,mBAAmB,YAAY,YAAY;EACpD,QAAQ;CACV;AACF;AASA,MAAa,mBAAmB,WAA6C;CAC3E,MAAM,SAAS,sBAAsB,MAAM;CAE3C,OAAO;EAAE,GAAG,OAAO;EAAQ,GAAG,OAAO;EAAS,GAAG,OAAO;EAAS,GAAG,OAAO;CAAQ;AACrF"}
@@ -0,0 +1,28 @@
1
+ import { ColorScaleItem } from "../../color/types.mjs";
2
+ import { NeutralColors } from "../customTheme.mjs";
3
+ import { NeutralTextLadder } from "./token/neutralText.mjs";
4
+ //#region src/styles/theme/customNeutral.d.ts
5
+ /** Any 6-digit hex: tints the default gray ladder with its hue and chroma. */
6
+ export type CustomNeutralColor = `#${string}`;
7
+ /** A preset, a 6-digit hex, or a name registered with `registerLobeNeutral`. */
8
+ export type LobeNeutralColor = NeutralColors | CustomNeutralColor | (string & {});
9
+ export interface LobeNeutralScale {
10
+ /** Full 13-step scale (light / dark solid + alpha), same shape as the presets. */
11
+ scale: ColorScaleItem;
12
+ /** Text ladder [text, secondary, tertiary, quaternary]; defaults to the scale's steps 12/10/8/6. */
13
+ text?: Partial<NeutralTextLadder>;
14
+ }
15
+ export interface ResolvedNeutral {
16
+ scale: ColorScaleItem;
17
+ text: NeutralTextLadder;
18
+ }
19
+ export declare const isCustomNeutralColor: (value?: string) => value is CustomNeutralColor;
20
+ /**
21
+ * Register a full custom neutral scale under `name`, then select it with
22
+ * `setLobeTheme({ neutralColor: name })` / `ThemeScope` / `LobeThemeScript`.
23
+ */
24
+ export declare const registerLobeNeutral: (name: string, neutral: LobeNeutralScale | ColorScaleItem) => void;
25
+ /** Same construction as the presets: the gray ladder's lightness, retinted to the hex's hue. */
26
+ export declare const generateNeutralScale: (color: CustomNeutralColor) => ResolvedNeutral;
27
+ //#endregion
28
+ //# sourceMappingURL=customNeutral.d.mts.map
@@ -0,0 +1,84 @@
1
+ import { notifyPaletteChange } from "./customPalette.mjs";
2
+ import gray from "../../color/colors/gray.mjs";
3
+ import { neutralColorScales } from "../../color/neutrals/index.mjs";
4
+ import { neutralText } from "./token/neutralText.mjs";
5
+ import chroma from "chroma-js";
6
+ //#region src/styles/theme/customNeutral.ts
7
+ const HEX = /^#[\da-f]{6}$/i;
8
+ const NAME = /^[\w-]+$/;
9
+ const MAX_CHROMA = .05;
10
+ const isCustomNeutralColor = (value) => !!value && HEX.test(value);
11
+ const registry = /* @__PURE__ */ new Map();
12
+ const isRegisteredNeutral = (name) => !!name && registry.has(name);
13
+ /**
14
+ * Register a full custom neutral scale under `name`, then select it with
15
+ * `setLobeTheme({ neutralColor: name })` / `ThemeScope` / `LobeThemeScript`.
16
+ */
17
+ const registerLobeNeutral = (name, neutral) => {
18
+ if (!NAME.test(name)) throw new Error(`Invalid neutral name "${name}": use letters, digits, _ or -`);
19
+ if (name in neutralColorScales) throw new Error(`"${name}" is a built-in neutral preset`);
20
+ registry.set(name, "scale" in neutral ? neutral : { scale: neutral });
21
+ notifyPaletteChange();
22
+ };
23
+ const tint = (color, h, c) => {
24
+ const source = chroma(color);
25
+ const [l] = source.oklch();
26
+ return chroma.oklch(l, c, h).alpha(source.alpha());
27
+ };
28
+ const tintSteps = (steps, h, c, alpha) => steps.map((step) => alpha ? tint(step, h, c).css() : tint(step, h, c).hex());
29
+ const cache = /* @__PURE__ */ new Map();
30
+ /** Same construction as the presets: the gray ladder's lightness, retinted to the hex's hue. */
31
+ const generateNeutralScale = (color) => {
32
+ const hex = color.toLowerCase();
33
+ const cached = cache.get(hex);
34
+ if (cached) return cached;
35
+ const [, rawC, rawH] = chroma(hex).oklch();
36
+ const h = Number.isNaN(rawH) ? 0 : rawH;
37
+ const c = Math.min(rawC || 0, MAX_CHROMA);
38
+ const base = neutralText.gray;
39
+ const result = {
40
+ scale: {
41
+ dark: tintSteps(gray.dark, h, c, false),
42
+ darkA: tintSteps(gray.darkA, h, c, true),
43
+ light: tintSteps(gray.light, h, c, false),
44
+ lightA: tintSteps(gray.lightA, h, c, true)
45
+ },
46
+ text: {
47
+ dark: tintSteps(base.dark, h, c, false),
48
+ light: tintSteps(base.light, h, c, false)
49
+ }
50
+ };
51
+ cache.set(hex, result);
52
+ return result;
53
+ };
54
+ const ladderOf = (scale, appearance) => {
55
+ const s = scale[appearance];
56
+ return [
57
+ s[12],
58
+ s[10],
59
+ s[8],
60
+ s[6]
61
+ ];
62
+ };
63
+ const resolveNeutral = (neutralColor) => {
64
+ if (isCustomNeutralColor(neutralColor)) return generateNeutralScale(neutralColor);
65
+ const registered = neutralColor ? registry.get(neutralColor) : void 0;
66
+ if (registered) return {
67
+ scale: registered.scale,
68
+ text: {
69
+ dark: registered.text?.dark ?? ladderOf(registered.scale, "dark"),
70
+ light: registered.text?.light ?? ladderOf(registered.scale, "light")
71
+ }
72
+ };
73
+ const preset = neutralColor && neutralColor in neutralColorScales ? neutralColor : void 0;
74
+ return {
75
+ scale: preset && neutralColorScales[preset] || gray,
76
+ text: neutralText[preset || "gray"]
77
+ };
78
+ };
79
+ /** True when the value needs its own injected stylesheet (not a built-in preset). */
80
+ const isCustomNeutral = (value) => isCustomNeutralColor(value) || isRegisteredNeutral(value);
81
+ //#endregion
82
+ export { generateNeutralScale, isCustomNeutral, isCustomNeutralColor, isRegisteredNeutral, registerLobeNeutral, resolveNeutral };
83
+
84
+ //# sourceMappingURL=customNeutral.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customNeutral.mjs","names":[],"sources":["../../../src/styles/theme/customNeutral.ts"],"sourcesContent":["import chroma from 'chroma-js';\n\nimport { gray } from '@/color/colors';\nimport { neutralColorScales } from '@/color/neutrals';\nimport type { ColorScaleItem } from '@/color/types';\n\nimport type { NeutralColors } from '../customTheme';\nimport { notifyPaletteChange } from './customPalette';\nimport { neutralText,type NeutralTextLadder } from './token/neutralText';\n\n/** Any 6-digit hex: tints the default gray ladder with its hue and chroma. */\nexport type CustomNeutralColor = `#${string}`;\n/** A preset, a 6-digit hex, or a name registered with `registerLobeNeutral`. */\nexport type LobeNeutralColor = NeutralColors | CustomNeutralColor | (string & {});\n\nexport interface LobeNeutralScale {\n /** Full 13-step scale (light / dark solid + alpha), same shape as the presets. */\n scale: ColorScaleItem;\n /** Text ladder [text, secondary, tertiary, quaternary]; defaults to the scale's steps 12/10/8/6. */\n text?: Partial<NeutralTextLadder>;\n}\n\nexport interface ResolvedNeutral {\n scale: ColorScaleItem;\n text: NeutralTextLadder;\n}\n\nconst HEX = /^#[\\da-f]{6}$/i;\nconst NAME = /^[\\w-]+$/;\n// Neutrals stay neutral: presets peak around 0.02 oklch chroma.\nconst MAX_CHROMA = 0.05;\n\nexport const isCustomNeutralColor = (value?: string): value is CustomNeutralColor =>\n !!value && HEX.test(value);\n\nconst registry = new Map<string, LobeNeutralScale>();\n\nexport const isRegisteredNeutral = (name?: string): name is string => !!name && registry.has(name);\n\n/**\n * Register a full custom neutral scale under `name`, then select it with\n * `setLobeTheme({ neutralColor: name })` / `ThemeScope` / `LobeThemeScript`.\n */\nexport const registerLobeNeutral = (name: string, neutral: LobeNeutralScale | ColorScaleItem) => {\n if (!NAME.test(name))\n throw new Error(`Invalid neutral name \"${name}\": use letters, digits, _ or -`);\n if (name in neutralColorScales) throw new Error(`\"${name}\" is a built-in neutral preset`);\n registry.set(name, 'scale' in neutral ? neutral : { scale: neutral });\n notifyPaletteChange();\n};\n\nconst tint = (color: string, h: number, c: number) => {\n const source = chroma(color);\n const [l] = source.oklch();\n return chroma.oklch(l, c, h).alpha(source.alpha());\n};\n\nconst tintSteps = <T extends readonly string[]>(steps: T, h: number, c: number, alpha: boolean) =>\n steps.map((step) => (alpha ? tint(step, h, c).css() : tint(step, h, c).hex())) as unknown as T;\n\nconst cache = new Map<string, ResolvedNeutral>();\n\n/** Same construction as the presets: the gray ladder's lightness, retinted to the hex's hue. */\nexport const generateNeutralScale = (color: CustomNeutralColor): ResolvedNeutral => {\n const hex = color.toLowerCase();\n const cached = cache.get(hex);\n if (cached) return cached;\n\n const [, rawC, rawH] = chroma(hex).oklch();\n const h = Number.isNaN(rawH) ? 0 : rawH;\n const c = Math.min(rawC || 0, MAX_CHROMA);\n const base = neutralText.gray;\n const result: ResolvedNeutral = {\n scale: {\n dark: tintSteps(gray.dark, h, c, false),\n darkA: tintSteps(gray.darkA, h, c, true),\n light: tintSteps(gray.light, h, c, false),\n lightA: tintSteps(gray.lightA, h, c, true),\n },\n text: {\n dark: tintSteps(base.dark, h, c, false),\n light: tintSteps(base.light, h, c, false),\n },\n };\n\n cache.set(hex, result);\n return result;\n};\n\nconst ladderOf = (scale: ColorScaleItem, appearance: 'light' | 'dark') => {\n const s = scale[appearance];\n return [s[12], s[10], s[8], s[6]] as [string, string, string, string];\n};\n\nexport const resolveNeutral = (neutralColor?: LobeNeutralColor): ResolvedNeutral => {\n if (isCustomNeutralColor(neutralColor)) return generateNeutralScale(neutralColor);\n const registered = neutralColor ? registry.get(neutralColor) : undefined;\n if (registered)\n return {\n scale: registered.scale,\n text: {\n dark: registered.text?.dark ?? ladderOf(registered.scale, 'dark'),\n light: registered.text?.light ?? ladderOf(registered.scale, 'light'),\n },\n };\n const preset =\n neutralColor && neutralColor in neutralColorScales\n ? (neutralColor as NeutralColors)\n : undefined;\n return {\n scale: (preset && neutralColorScales[preset]) || gray,\n text: neutralText[preset || 'gray'],\n };\n};\n\n/** True when the value needs its own injected stylesheet (not a built-in preset). */\nexport const isCustomNeutral = (value?: string): value is string =>\n isCustomNeutralColor(value) || isRegisteredNeutral(value);\n"],"mappings":";;;;;;AA2BA,MAAM,MAAM;AACZ,MAAM,OAAO;AAEb,MAAM,aAAa;AAEnB,MAAa,wBAAwB,UACnC,CAAC,CAAC,SAAS,IAAI,KAAK,KAAK;AAE3B,MAAM,2BAAW,IAAI,IAA8B;AAEnD,MAAa,uBAAuB,SAAkC,CAAC,CAAC,QAAQ,SAAS,IAAI,IAAI;;;;;AAMjG,MAAa,uBAAuB,MAAc,YAA+C;CAC/F,IAAI,CAAC,KAAK,KAAK,IAAI,GACjB,MAAM,IAAI,MAAM,yBAAyB,KAAK,+BAA+B;CAC/E,IAAI,QAAQ,oBAAoB,MAAM,IAAI,MAAM,IAAI,KAAK,+BAA+B;CACxF,SAAS,IAAI,MAAM,WAAW,UAAU,UAAU,EAAE,OAAO,QAAQ,CAAC;CACpE,oBAAoB;AACtB;AAEA,MAAM,QAAQ,OAAe,GAAW,MAAc;CACpD,MAAM,SAAS,OAAO,KAAK;CAC3B,MAAM,CAAC,KAAK,OAAO,MAAM;CACzB,OAAO,OAAO,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC;AACnD;AAEA,MAAM,aAA0C,OAAU,GAAW,GAAW,UAC9E,MAAM,KAAK,SAAU,QAAQ,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAE;AAE/E,MAAM,wBAAQ,IAAI,IAA6B;;AAG/C,MAAa,wBAAwB,UAA+C;CAClF,MAAM,MAAM,MAAM,YAAY;CAC9B,MAAM,SAAS,MAAM,IAAI,GAAG;CAC5B,IAAI,QAAQ,OAAO;CAEnB,MAAM,GAAG,MAAM,QAAQ,OAAO,GAAG,CAAC,CAAC,MAAM;CACzC,MAAM,IAAI,OAAO,MAAM,IAAI,IAAI,IAAI;CACnC,MAAM,IAAI,KAAK,IAAI,QAAQ,GAAG,UAAU;CACxC,MAAM,OAAO,YAAY;CACzB,MAAM,SAA0B;EAC9B,OAAO;GACL,MAAM,UAAU,KAAK,MAAM,GAAG,GAAG,KAAK;GACtC,OAAO,UAAU,KAAK,OAAO,GAAG,GAAG,IAAI;GACvC,OAAO,UAAU,KAAK,OAAO,GAAG,GAAG,KAAK;GACxC,QAAQ,UAAU,KAAK,QAAQ,GAAG,GAAG,IAAI;EAC3C;EACA,MAAM;GACJ,MAAM,UAAU,KAAK,MAAM,GAAG,GAAG,KAAK;GACtC,OAAO,UAAU,KAAK,OAAO,GAAG,GAAG,KAAK;EAC1C;CACF;CAEA,MAAM,IAAI,KAAK,MAAM;CACrB,OAAO;AACT;AAEA,MAAM,YAAY,OAAuB,eAAiC;CACxE,MAAM,IAAI,MAAM;CAChB,OAAO;EAAC,EAAE;EAAK,EAAE;EAAK,EAAE;EAAI,EAAE;CAAE;AAClC;AAEA,MAAa,kBAAkB,iBAAqD;CAClF,IAAI,qBAAqB,YAAY,GAAG,OAAO,qBAAqB,YAAY;CAChF,MAAM,aAAa,eAAe,SAAS,IAAI,YAAY,IAAI,KAAA;CAC/D,IAAI,YACF,OAAO;EACL,OAAO,WAAW;EAClB,MAAM;GACJ,MAAM,WAAW,MAAM,QAAQ,SAAS,WAAW,OAAO,MAAM;GAChE,OAAO,WAAW,MAAM,SAAS,SAAS,WAAW,OAAO,OAAO;EACrE;CACF;CACF,MAAM,SACJ,gBAAgB,gBAAgB,qBAC3B,eACD,KAAA;CACN,OAAO;EACL,OAAQ,UAAU,mBAAmB,WAAY;EACjD,MAAM,YAAY,UAAU;CAC9B;AACF;;AAGA,MAAa,mBAAmB,UAC9B,qBAAqB,KAAK,KAAK,oBAAoB,KAAK"}
@@ -0,0 +1,6 @@
1
+ import { StatusColorScales } from "../../color/status/index.mjs";
2
+ //#region src/styles/theme/customPalette.d.ts
3
+ export type LobeStatusPalette = Partial<StatusColorScales>;
4
+ export declare const registerLobePalette: (name: string, palette: LobeStatusPalette) => void;
5
+ //#endregion
6
+ //# sourceMappingURL=customPalette.d.mts.map
@@ -0,0 +1,32 @@
1
+ import { statusColorScales } from "../../color/status/index.mjs";
2
+ //#region src/styles/theme/customPalette.ts
3
+ const NAME = /^[\w-]+$/;
4
+ const registry = /* @__PURE__ */ new Map();
5
+ const listeners = /* @__PURE__ */ new Set();
6
+ let revision = 0;
7
+ const registerLobePalette = (name, palette) => {
8
+ if (!NAME.test(name)) throw new Error(`Invalid palette name "${name}": use letters, digits, _ or -`);
9
+ registry.set(name, palette);
10
+ notifyPaletteChange();
11
+ };
12
+ /** Bumps the revision so mounted scopes / useTheme pick up a re-registered palette or neutral. */
13
+ const notifyPaletteChange = () => {
14
+ revision++;
15
+ for (const listener of listeners) listener();
16
+ };
17
+ const getPaletteRevision = () => revision;
18
+ const subscribePalettes = (listener) => {
19
+ listeners.add(listener);
20
+ return () => {
21
+ listeners.delete(listener);
22
+ };
23
+ };
24
+ const isRegisteredPalette = (name) => !!name && registry.has(name);
25
+ const resolveStatusScales = (name) => isRegisteredPalette(name) ? {
26
+ ...statusColorScales,
27
+ ...registry.get(name)
28
+ } : statusColorScales;
29
+ //#endregion
30
+ export { getPaletteRevision, isRegisteredPalette, notifyPaletteChange, registerLobePalette, resolveStatusScales, subscribePalettes };
31
+
32
+ //# sourceMappingURL=customPalette.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customPalette.mjs","names":[],"sources":["../../../src/styles/theme/customPalette.ts"],"sourcesContent":["import { type StatusColorScales, statusColorScales } from '@/color/status';\n\nexport type LobeStatusPalette = Partial<StatusColorScales>;\n\nconst NAME = /^[\\w-]+$/;\n\nconst registry = new Map<string, LobeStatusPalette>();\nconst listeners = new Set<() => void>();\nlet revision = 0;\n\nexport const registerLobePalette = (name: string, palette: LobeStatusPalette) => {\n if (!NAME.test(name))\n throw new Error(`Invalid palette name \"${name}\": use letters, digits, _ or -`);\n registry.set(name, palette);\n notifyPaletteChange();\n};\n\n/** Bumps the revision so mounted scopes / useTheme pick up a re-registered palette or neutral. */\nexport const notifyPaletteChange = () => {\n revision++;\n for (const listener of listeners) listener();\n};\n\nexport const getPaletteRevision = () => revision;\n\nexport const subscribePalettes = (listener: () => void) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n};\n\nexport const isRegisteredPalette = (name?: string): name is string => !!name && registry.has(name);\n\nexport const resolveStatusScales = (name?: string): StatusColorScales =>\n isRegisteredPalette(name) ? { ...statusColorScales, ...registry.get(name) } : statusColorScales;\n"],"mappings":";;AAIA,MAAM,OAAO;AAEb,MAAM,2BAAW,IAAI,IAA+B;AACpD,MAAM,4BAAY,IAAI,IAAgB;AACtC,IAAI,WAAW;AAEf,MAAa,uBAAuB,MAAc,YAA+B;CAC/E,IAAI,CAAC,KAAK,KAAK,IAAI,GACjB,MAAM,IAAI,MAAM,yBAAyB,KAAK,+BAA+B;CAC/E,SAAS,IAAI,MAAM,OAAO;CAC1B,oBAAoB;AACtB;;AAGA,MAAa,4BAA4B;CACvC;CACA,KAAK,MAAM,YAAY,WAAW,SAAS;AAC7C;AAEA,MAAa,2BAA2B;AAExC,MAAa,qBAAqB,aAAyB;CACzD,UAAU,IAAI,QAAQ;CACtB,aAAa;EACX,UAAU,OAAO,QAAQ;CAC3B;AACF;AAEA,MAAa,uBAAuB,SAAkC,CAAC,CAAC,QAAQ,SAAS,IAAI,IAAI;AAEjG,MAAa,uBAAuB,SAClC,oBAAoB,IAAI,IAAI;CAAE,GAAG;CAAmB,GAAG,SAAS,IAAI,IAAI;AAAE,IAAI"}
@@ -1,3 +1,4 @@
1
+ import gray from "../../color/colors/gray.mjs";
1
2
  import { colorScales } from "../../color/colors/index.mjs";
2
3
  import { primaryColors } from "../customTheme.mjs";
3
4
  import chroma from "chroma-js";
@@ -5,12 +6,26 @@ import chroma from "chroma-js";
5
6
  const HEX = /^#[\da-f]{6}$/i;
6
7
  const isCustomPrimaryColor = (value) => !!value && HEX.test(value);
7
8
  const ANCHOR = 9;
8
- const ANCHORED_STEPS = /* @__PURE__ */ new Set([
9
- 7,
10
- 8,
11
- 10
12
- ]);
9
+ const SHIFT_WEIGHT = [
10
+ 0,
11
+ 0,
12
+ 0,
13
+ 0,
14
+ 0,
15
+ .25,
16
+ .5,
17
+ .75,
18
+ 1,
19
+ 1,
20
+ 1,
21
+ .5,
22
+ 0
23
+ ];
24
+ const MIN_STEP_GAP = .015;
25
+ const LIGHTNESS_WEIGHT = 100;
13
26
  const MAX_CHROMA_RATIO = 2;
27
+ const DARK_SURFACE = gray.dark[1];
28
+ const MIN_DARK_CONTRAST = 4.5;
14
29
  const oklch = (color) => {
15
30
  const [l, c, h] = chroma(color).oklch();
16
31
  return {
@@ -23,17 +38,35 @@ const hueDistance = (a, b) => {
23
38
  const d = Math.abs(a - b) % 360;
24
39
  return d > 180 ? 360 - d : d;
25
40
  };
26
- const nearestPreset = (hue) => Object.keys(primaryColors).reduce((best, name) => hueDistance(oklch(primaryColors[name]).h, hue) < hueDistance(oklch(primaryColors[best]).h, hue) ? name : best);
41
+ const presetDistance = (name, target) => {
42
+ const preset = oklch(primaryColors[name]);
43
+ return hueDistance(preset.h, target.h) + LIGHTNESS_WEIGHT * Math.abs(preset.l - target.l);
44
+ };
45
+ const nearestPreset = (target) => Object.keys(primaryColors).reduce((best, name) => presetDistance(name, target) < presetDistance(best, target) ? name : best);
27
46
  const clamp = (value) => Math.min(1, Math.max(0, value));
28
- const retintSolid = (steps, target, hex) => {
47
+ const readableOnDark = (hex) => {
48
+ const { c, h, l } = oklch(hex);
49
+ let lightness = l;
50
+ let color = hex;
51
+ while (chroma.contrast(color, DARK_SURFACE) < MIN_DARK_CONTRAST && lightness < 1) {
52
+ lightness = Math.min(1, lightness + .005);
53
+ color = chroma.oklch(lightness, c, h).hex();
54
+ }
55
+ return color;
56
+ };
57
+ const orderLightness = (lightness, direction) => {
58
+ const ordered = [...lightness];
59
+ for (let i = 10; i < ordered.length; i++) ordered[i] = direction > 0 ? Math.max(ordered[i], ordered[i - 1] + MIN_STEP_GAP) : Math.min(ordered[i], ordered[i - 1] - MIN_STEP_GAP);
60
+ for (let i = 8; i >= 0; i--) ordered[i] = direction > 0 ? Math.min(ordered[i], ordered[i + 1] - MIN_STEP_GAP) : Math.max(ordered[i], ordered[i + 1] + MIN_STEP_GAP);
61
+ return ordered.map(clamp);
62
+ };
63
+ const retintSolid = (steps, target, hex, direction) => {
29
64
  const anchor = oklch(steps[ANCHOR]);
30
65
  const ratio = anchor.c > 0 ? Math.min(target.c / anchor.c, MAX_CHROMA_RATIO) : 0;
31
- return steps.map((step, i) => {
32
- if (i === ANCHOR) return hex;
33
- const { c, l } = oklch(step);
34
- const lightness = ANCHORED_STEPS.has(i) ? clamp(target.l + l - anchor.l) : l;
35
- return chroma.oklch(lightness, c * ratio, target.h).hex();
36
- });
66
+ const shift = target.l - anchor.l;
67
+ const source = steps.map(oklch);
68
+ const lightness = orderLightness(source.map(({ l }, i) => i === ANCHOR ? target.l : l + SHIFT_WEIGHT[i] * shift), direction);
69
+ return source.map(({ c }, i) => i === ANCHOR ? hex : chroma.oklch(lightness[i], c * ratio, target.h).hex());
37
70
  };
38
71
  const retintAlpha = (steps, solid, target) => {
39
72
  const anchor = oklch(solid[ANCHOR]);
@@ -50,11 +83,13 @@ const generatePrimaryScale = (color) => {
50
83
  const cached = cache.get(hex);
51
84
  if (cached) return cached;
52
85
  const target = oklch(hex);
53
- const preset = colorScales[nearestPreset(target.h)];
86
+ const preset = colorScales[nearestPreset(target)];
87
+ const darkHex = readableOnDark(hex);
88
+ const darkTarget = oklch(darkHex);
54
89
  const scale = {
55
- dark: retintSolid(preset.dark, target, hex),
56
- darkA: retintAlpha(preset.darkA, preset.dark, target),
57
- light: retintSolid(preset.light, target, hex),
90
+ dark: retintSolid(preset.dark, darkTarget, darkHex, 1),
91
+ darkA: retintAlpha(preset.darkA, preset.dark, darkTarget),
92
+ light: retintSolid(preset.light, target, hex, -1),
58
93
  lightA: retintAlpha(preset.lightA, preset.light, target)
59
94
  };
60
95
  cache.set(hex, scale);
@@ -1 +1 @@
1
- {"version":3,"file":"customPrimary.mjs","names":[],"sources":["../../../src/styles/theme/customPrimary.ts"],"sourcesContent":["import chroma from 'chroma-js';\n\nimport { colorScales } from '@/color/colors';\nimport type { ColorScaleItem } from '@/color/types';\n\nimport { type PrimaryColors, primaryColors } from '../customTheme';\n\nexport type CustomPrimaryColor = `#${string}`;\nexport type LobePrimaryColor = PrimaryColors | CustomPrimaryColor;\n\nconst HEX = /^#[\\da-f]{6}$/i;\n\nexport const isCustomPrimaryColor = (value?: string): value is CustomPrimaryColor =>\n !!value && HEX.test(value);\n\nconst ANCHOR = 9;\nconst ANCHORED_STEPS = new Set([7, 8, 10]);\nconst MAX_CHROMA_RATIO = 2;\n\nconst oklch = (color: string) => {\n const [l, c, h] = chroma(color).oklch();\n return { c, h: Number.isNaN(h) ? 0 : h, l };\n};\n\nconst hueDistance = (a: number, b: number) => {\n const d = Math.abs(a - b) % 360;\n return d > 180 ? 360 - d : d;\n};\n\nconst nearestPreset = (hue: number) =>\n (Object.keys(primaryColors) as PrimaryColors[]).reduce((best, name) =>\n hueDistance(oklch(primaryColors[name]).h, hue) < hueDistance(oklch(primaryColors[best]).h, hue)\n ? name\n : best,\n );\n\nconst clamp = (value: number) => Math.min(1, Math.max(0, value));\n\ntype Steps = ColorScaleItem['light'];\n\nconst retintSolid = (steps: Steps, target: ReturnType<typeof oklch>, hex: string): Steps => {\n const anchor = oklch(steps[ANCHOR]);\n const ratio = anchor.c > 0 ? Math.min(target.c / anchor.c, MAX_CHROMA_RATIO) : 0;\n\n return steps.map((step, i) => {\n if (i === ANCHOR) return hex;\n const { c, l } = oklch(step);\n const lightness = ANCHORED_STEPS.has(i) ? clamp(target.l + l - anchor.l) : l;\n return chroma.oklch(lightness, c * ratio, target.h).hex();\n }) as Steps;\n};\n\nconst retintAlpha = (steps: Steps, solid: Steps, target: ReturnType<typeof oklch>): Steps => {\n const anchor = oklch(solid[ANCHOR]);\n const ratio = anchor.c > 0 ? Math.min(target.c / anchor.c, MAX_CHROMA_RATIO) : 0;\n\n return steps.map((step) => {\n const color = chroma(step);\n const { c, l } = oklch(step);\n return chroma\n .oklch(l, c * ratio, target.h)\n .alpha(color.alpha())\n .css();\n }) as Steps;\n};\n\nconst cache = new Map<string, ColorScaleItem>();\n\nexport const generatePrimaryScale = (color: CustomPrimaryColor): ColorScaleItem => {\n const hex = color.toLowerCase();\n const cached = cache.get(hex);\n if (cached) return cached;\n\n const target = oklch(hex);\n const preset = colorScales[nearestPreset(target.h)];\n const scale: ColorScaleItem = {\n dark: retintSolid(preset.dark, target, hex),\n darkA: retintAlpha(preset.darkA, preset.dark, target),\n light: retintSolid(preset.light, target, hex),\n lightA: retintAlpha(preset.lightA, preset.light, target),\n };\n\n cache.set(hex, scale);\n return scale;\n};\n"],"mappings":";;;;AAUA,MAAM,MAAM;AAEZ,MAAa,wBAAwB,UACnC,CAAC,CAAC,SAAS,IAAI,KAAK,KAAK;AAE3B,MAAM,SAAS;AACf,MAAM,iCAAiB,IAAI,IAAI;CAAC;CAAG;CAAG;AAAE,CAAC;AACzC,MAAM,mBAAmB;AAEzB,MAAM,SAAS,UAAkB;CAC/B,MAAM,CAAC,GAAG,GAAG,KAAK,OAAO,KAAK,CAAC,CAAC,MAAM;CACtC,OAAO;EAAE;EAAG,GAAG,OAAO,MAAM,CAAC,IAAI,IAAI;EAAG;CAAE;AAC5C;AAEA,MAAM,eAAe,GAAW,MAAc;CAC5C,MAAM,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI;CAC5B,OAAO,IAAI,MAAM,MAAM,IAAI;AAC7B;AAEA,MAAM,iBAAiB,QACpB,OAAO,KAAK,aAAa,CAAC,CAAqB,QAAQ,MAAM,SAC5D,YAAY,MAAM,cAAc,KAAK,CAAC,CAAC,GAAG,GAAG,IAAI,YAAY,MAAM,cAAc,KAAK,CAAC,CAAC,GAAG,GAAG,IAC1F,OACA,IACN;AAEF,MAAM,SAAS,UAAkB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;AAI/D,MAAM,eAAe,OAAc,QAAkC,QAAuB;CAC1F,MAAM,SAAS,MAAM,MAAM,OAAO;CAClC,MAAM,QAAQ,OAAO,IAAI,IAAI,KAAK,IAAI,OAAO,IAAI,OAAO,GAAG,gBAAgB,IAAI;CAE/E,OAAO,MAAM,KAAK,MAAM,MAAM;EAC5B,IAAI,MAAM,QAAQ,OAAO;EACzB,MAAM,EAAE,GAAG,MAAM,MAAM,IAAI;EAC3B,MAAM,YAAY,eAAe,IAAI,CAAC,IAAI,MAAM,OAAO,IAAI,IAAI,OAAO,CAAC,IAAI;EAC3E,OAAO,OAAO,MAAM,WAAW,IAAI,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI;CAC1D,CAAC;AACH;AAEA,MAAM,eAAe,OAAc,OAAc,WAA4C;CAC3F,MAAM,SAAS,MAAM,MAAM,OAAO;CAClC,MAAM,QAAQ,OAAO,IAAI,IAAI,KAAK,IAAI,OAAO,IAAI,OAAO,GAAG,gBAAgB,IAAI;CAE/E,OAAO,MAAM,KAAK,SAAS;EACzB,MAAM,QAAQ,OAAO,IAAI;EACzB,MAAM,EAAE,GAAG,MAAM,MAAM,IAAI;EAC3B,OAAO,OACJ,MAAM,GAAG,IAAI,OAAO,OAAO,CAAC,CAAC,CAC7B,MAAM,MAAM,MAAM,CAAC,CAAC,CACpB,IAAI;CACT,CAAC;AACH;AAEA,MAAM,wBAAQ,IAAI,IAA4B;AAE9C,MAAa,wBAAwB,UAA8C;CACjF,MAAM,MAAM,MAAM,YAAY;CAC9B,MAAM,SAAS,MAAM,IAAI,GAAG;CAC5B,IAAI,QAAQ,OAAO;CAEnB,MAAM,SAAS,MAAM,GAAG;CACxB,MAAM,SAAS,YAAY,cAAc,OAAO,CAAC;CACjD,MAAM,QAAwB;EAC5B,MAAM,YAAY,OAAO,MAAM,QAAQ,GAAG;EAC1C,OAAO,YAAY,OAAO,OAAO,OAAO,MAAM,MAAM;EACpD,OAAO,YAAY,OAAO,OAAO,QAAQ,GAAG;EAC5C,QAAQ,YAAY,OAAO,QAAQ,OAAO,OAAO,MAAM;CACzD;CAEA,MAAM,IAAI,KAAK,KAAK;CACpB,OAAO;AACT"}
1
+ {"version":3,"file":"customPrimary.mjs","names":[],"sources":["../../../src/styles/theme/customPrimary.ts"],"sourcesContent":["import chroma from 'chroma-js';\n\nimport { colorScales, gray } from '@/color/colors';\nimport type { ColorScaleItem } from '@/color/types';\n\nimport { type PrimaryColors, primaryColors } from '../customTheme';\n\nexport type CustomPrimaryColor = `#${string}`;\nexport type LobePrimaryColor = PrimaryColors | CustomPrimaryColor;\n\nconst HEX = /^#[\\da-f]{6}$/i;\n\nexport const isCustomPrimaryColor = (value?: string): value is CustomPrimaryColor =>\n !!value && HEX.test(value);\n\nconst ANCHOR = 9;\nconst SHIFT_WEIGHT = [0, 0, 0, 0, 0, 0.25, 0.5, 0.75, 1, 1, 1, 0.5, 0];\nconst MIN_STEP_GAP = 0.015;\nconst LIGHTNESS_WEIGHT = 100;\nconst MAX_CHROMA_RATIO = 2;\nconst DARK_SURFACE = gray.dark[1];\nconst MIN_DARK_CONTRAST = 4.5;\n\nconst oklch = (color: string) => {\n const [l, c, h] = chroma(color).oklch();\n return { c, h: Number.isNaN(h) ? 0 : h, l };\n};\n\nconst hueDistance = (a: number, b: number) => {\n const d = Math.abs(a - b) % 360;\n return d > 180 ? 360 - d : d;\n};\n\nconst presetDistance = (name: PrimaryColors, target: ReturnType<typeof oklch>) => {\n const preset = oklch(primaryColors[name]);\n return hueDistance(preset.h, target.h) + LIGHTNESS_WEIGHT * Math.abs(preset.l - target.l);\n};\n\nconst nearestPreset = (target: ReturnType<typeof oklch>) =>\n (Object.keys(primaryColors) as PrimaryColors[]).reduce((best, name) =>\n presetDistance(name, target) < presetDistance(best, target) ? name : best,\n );\n\nconst clamp = (value: number) => Math.min(1, Math.max(0, value));\n\nconst readableOnDark = (hex: string) => {\n const { c, h, l } = oklch(hex);\n let lightness = l;\n let color = hex;\n while (chroma.contrast(color, DARK_SURFACE) < MIN_DARK_CONTRAST && lightness < 1) {\n lightness = Math.min(1, lightness + 0.005);\n color = chroma.oklch(lightness, c, h).hex();\n }\n return color;\n};\n\nconst orderLightness = (lightness: number[], direction: 1 | -1) => {\n const ordered = [...lightness];\n for (let i = ANCHOR + 1; i < ordered.length; i++)\n ordered[i] =\n direction > 0\n ? Math.max(ordered[i], ordered[i - 1] + MIN_STEP_GAP)\n : Math.min(ordered[i], ordered[i - 1] - MIN_STEP_GAP);\n for (let i = ANCHOR - 1; i >= 0; i--)\n ordered[i] =\n direction > 0\n ? Math.min(ordered[i], ordered[i + 1] - MIN_STEP_GAP)\n : Math.max(ordered[i], ordered[i + 1] + MIN_STEP_GAP);\n return ordered.map(clamp);\n};\n\ntype Steps = ColorScaleItem['light'];\n\nconst retintSolid = (\n steps: Steps,\n target: ReturnType<typeof oklch>,\n hex: string,\n direction: 1 | -1,\n): Steps => {\n const anchor = oklch(steps[ANCHOR]);\n const ratio = anchor.c > 0 ? Math.min(target.c / anchor.c, MAX_CHROMA_RATIO) : 0;\n const shift = target.l - anchor.l;\n const source = steps.map(oklch);\n const lightness = orderLightness(\n source.map(({ l }, i) => (i === ANCHOR ? target.l : l + SHIFT_WEIGHT[i] * shift)),\n direction,\n );\n\n return source.map(({ c }, i) =>\n i === ANCHOR ? hex : chroma.oklch(lightness[i], c * ratio, target.h).hex(),\n ) as Steps;\n};\n\nconst retintAlpha = (steps: Steps, solid: Steps, target: ReturnType<typeof oklch>): Steps => {\n const anchor = oklch(solid[ANCHOR]);\n const ratio = anchor.c > 0 ? Math.min(target.c / anchor.c, MAX_CHROMA_RATIO) : 0;\n\n return steps.map((step) => {\n const color = chroma(step);\n const { c, l } = oklch(step);\n return chroma\n .oklch(l, c * ratio, target.h)\n .alpha(color.alpha())\n .css();\n }) as Steps;\n};\n\nconst cache = new Map<string, ColorScaleItem>();\n\nexport const generatePrimaryScale = (color: CustomPrimaryColor): ColorScaleItem => {\n const hex = color.toLowerCase();\n const cached = cache.get(hex);\n if (cached) return cached;\n\n const target = oklch(hex);\n const preset = colorScales[nearestPreset(target)];\n const darkHex = readableOnDark(hex);\n const darkTarget = oklch(darkHex);\n const scale: ColorScaleItem = {\n dark: retintSolid(preset.dark, darkTarget, darkHex, 1),\n darkA: retintAlpha(preset.darkA, preset.dark, darkTarget),\n light: retintSolid(preset.light, target, hex, -1),\n lightA: retintAlpha(preset.lightA, preset.light, target),\n };\n\n cache.set(hex, scale);\n return scale;\n};\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { NeutralColors } from "../customTheme.mjs";
1
+ import { LobeNeutralColor } from "./customNeutral.mjs";
2
2
  import { LobePrimaryColor } from "./customPrimary.mjs";
3
3
  import { LobeToken } from "./createLobeToken.mjs";
4
4
  import { CSSProperties, ReactNode } from "react";
@@ -6,7 +6,8 @@ import { CSSProperties, ReactNode } from "react";
6
6
  export type LobeAppearance = 'light' | 'dark';
7
7
  export interface LobeThemeState {
8
8
  appearance: LobeAppearance;
9
- neutralColor?: NeutralColors;
9
+ neutralColor?: LobeNeutralColor;
10
+ palette?: string;
10
11
  primaryColor?: LobePrimaryColor;
11
12
  }
12
13
  export declare const setLobeTheme: (state: Partial<LobeThemeState>, root?: HTMLElement) => void;
@@ -15,7 +16,7 @@ export interface ThemeScopeProps extends Partial<LobeThemeState> {
15
16
  className?: string;
16
17
  style?: CSSProperties;
17
18
  }
18
- export declare const ThemeScope: ({ appearance, children, className, neutralColor, primaryColor, style }: ThemeScopeProps) => import("react").JSX.Element;
19
+ export declare const ThemeScope: ({ appearance, children, className, neutralColor, palette, primaryColor, style }: ThemeScopeProps) => import("react").JSX.Element;
19
20
  export declare const useThemeMode: () => {
20
21
  appearance: LobeAppearance;
21
22
  isDarkMode: boolean;
@@ -39,11 +40,12 @@ export type ResponsiveState = Record<Breakpoint | 'mobile' | 'tablet' | 'laptop'
39
40
  export declare const useResponsive: () => ResponsiveState;
40
41
  export interface LobeThemeScriptProps {
41
42
  appearance?: LobeAppearance | 'system';
42
- neutralColor?: NeutralColors;
43
+ neutralColor?: LobeNeutralColor;
43
44
  nonce?: string;
45
+ palette?: string;
44
46
  primaryColor?: LobePrimaryColor;
45
47
  }
46
- export declare const LobeThemeScript: ({ appearance, neutralColor, nonce, primaryColor }: LobeThemeScriptProps) => import("react").JSX.Element;
48
+ export declare const LobeThemeScript: ({ appearance, neutralColor, nonce, palette, primaryColor }: LobeThemeScriptProps) => import("react").JSX.Element;
47
49
  //#endregion
48
50
  export {};
49
51
  //# sourceMappingURL=scope.d.mts.map
@@ -1,18 +1,22 @@
1
1
  "use client";
2
+ import { getPaletteRevision, isRegisteredPalette, subscribePalettes } from "./customPalette.mjs";
3
+ import { isCustomNeutral } from "./customNeutral.mjs";
2
4
  import { isCustomPrimaryColor } from "./customPrimary.mjs";
3
5
  import { staticToken } from "./token/static.mjs";
4
6
  import { createLobeToken } from "./createLobeToken.mjs";
5
- import { getCustomPrimaryCss } from "./themeCss.mjs";
7
+ import { getCustomNeutralCss, getCustomPaletteCss, getCustomPrimaryCss, getPaletteNeutralCss } from "./themeCss.mjs";
6
8
  import { createContext, use, useMemo, useSyncExternalStore } from "react";
7
9
  import { jsx, jsxs } from "react/jsx-runtime";
8
10
  //#region src/styles/theme/scope.tsx
9
11
  const ATTRIBUTES = [
10
12
  "data-theme",
11
13
  "data-primary-color",
12
- "data-neutral-color"
14
+ "data-neutral-color",
15
+ "data-palette"
13
16
  ];
14
- const toAttributes = ({ appearance, neutralColor, primaryColor }) => ({
17
+ const toAttributes = ({ appearance, neutralColor, palette, primaryColor }) => ({
15
18
  "data-neutral-color": neutralColor,
19
+ "data-palette": palette,
16
20
  "data-primary-color": primaryColor,
17
21
  "data-theme": appearance
18
22
  });
@@ -26,6 +30,46 @@ const ensureCustomPrimaryStyle = (color, doc) => {
26
30
  style.textContent = getCustomPrimaryCss(color);
27
31
  doc.head.append(style);
28
32
  };
33
+ const normalizeNeutral = (color) => color?.startsWith("#") ? color.toLowerCase() : color;
34
+ /** Encodes hex vs registered name so `#0e1010` and a neutral named `0e1010` never collide. */
35
+ const neutralKey = (value) => value.startsWith("#") ? `hex-${value.slice(1)}` : `name-${value}`;
36
+ const neutralStyleId = (value) => `lobe-neutral-${neutralKey(value)}`;
37
+ /** Written every time (a re-registered neutral must replace its old rules). */
38
+ const ensureNeutralStyle = (value, doc) => {
39
+ const id = neutralStyleId(value);
40
+ let style = doc.getElementById(id);
41
+ if (!style) {
42
+ style = doc.createElement("style");
43
+ style.id = id;
44
+ doc.head.append(style);
45
+ }
46
+ const css = getCustomNeutralCss(value);
47
+ if (style.textContent !== css) style.textContent = css;
48
+ };
49
+ const paletteStyleId = (name) => `lobe-palette-${name}`;
50
+ const ensurePaletteStyle = (name, doc) => {
51
+ const id = paletteStyleId(name);
52
+ let style = doc.getElementById(id);
53
+ if (!style) {
54
+ style = doc.createElement("style");
55
+ style.id = id;
56
+ doc.head.append(style);
57
+ }
58
+ const css = getCustomPaletteCss(name);
59
+ if (style.textContent !== css) style.textContent = css;
60
+ };
61
+ const paletteNeutralStyleId = (name, neutral) => `lobe-palette-${name}--neutral-${neutralKey(neutral)}`;
62
+ const ensurePaletteNeutralStyle = (name, neutral, doc) => {
63
+ const id = paletteNeutralStyleId(name, neutral);
64
+ let style = doc.getElementById(id);
65
+ if (!style) {
66
+ style = doc.createElement("style");
67
+ style.id = id;
68
+ doc.head.append(style);
69
+ }
70
+ const css = getPaletteNeutralCss(name, neutral);
71
+ if (style.textContent !== css) style.textContent = css;
72
+ };
29
73
  const setLobeTheme = (state, root = document.documentElement) => {
30
74
  const next = {
31
75
  ...readThemeState(root),
@@ -33,15 +77,23 @@ const setLobeTheme = (state, root = document.documentElement) => {
33
77
  };
34
78
  next.primaryColor = normalizePrimary(next.primaryColor);
35
79
  if (isCustomPrimaryColor(next.primaryColor)) ensureCustomPrimaryStyle(next.primaryColor, root.ownerDocument);
80
+ next.neutralColor = normalizeNeutral(next.neutralColor);
81
+ if (isCustomNeutral(next.neutralColor)) ensureNeutralStyle(next.neutralColor, root.ownerDocument);
82
+ if (isRegisteredPalette(next.palette)) {
83
+ ensurePaletteStyle(next.palette, root.ownerDocument);
84
+ if (next.neutralColor) ensurePaletteNeutralStyle(next.palette, next.neutralColor, root.ownerDocument);
85
+ }
36
86
  for (const [name, value] of Object.entries(toAttributes(next))) if (value) root.setAttribute(name, value);
37
87
  else root.removeAttribute(name);
38
88
  };
39
89
  const readThemeState = (el) => ({
40
90
  appearance: el.dataset.theme === "dark" ? "dark" : "light",
41
91
  neutralColor: el.dataset.neutralColor || void 0,
92
+ palette: el.dataset.palette || void 0,
42
93
  primaryColor: el.dataset.primaryColor || void 0
43
94
  });
44
- const stateKey = (state) => `${state.appearance}|${state.primaryColor ?? ""}|${state.neutralColor ?? ""}`;
95
+ const stateKey = (state) => `${state.appearance}|${state.primaryColor ?? ""}|${state.neutralColor ?? ""}|${state.palette ?? ""}`;
96
+ const usePaletteRevision = () => useSyncExternalStore(subscribePalettes, getPaletteRevision, getPaletteRevision);
45
97
  const SERVER_STATE = { appearance: "light" };
46
98
  let rootSnapshot = SERVER_STATE;
47
99
  const getRootSnapshot = () => {
@@ -63,31 +115,54 @@ const useThemeState = () => {
63
115
  const root = useSyncExternalStore(subscribeRoot, getRootSnapshot, () => SERVER_STATE);
64
116
  return scoped ?? root;
65
117
  };
66
- const ThemeScope = ({ appearance, children, className, neutralColor, primaryColor, style }) => {
118
+ const ThemeScope = ({ appearance, children, className, neutralColor, palette, primaryColor, style }) => {
67
119
  const parent = useThemeState();
68
120
  const state = useMemo(() => ({
69
121
  appearance: appearance ?? parent.appearance,
70
- neutralColor: neutralColor ?? parent.neutralColor,
122
+ neutralColor: normalizeNeutral(neutralColor) ?? parent.neutralColor,
123
+ palette: palette ?? parent.palette,
71
124
  primaryColor: normalizePrimary(primaryColor) ?? parent.primaryColor
72
125
  }), [
73
126
  appearance,
74
127
  neutralColor,
128
+ palette,
75
129
  primaryColor,
76
130
  parent
77
131
  ]);
78
132
  const customPrimary = isCustomPrimaryColor(state.primaryColor) ? state.primaryColor : void 0;
133
+ const paletteRevision = usePaletteRevision();
134
+ const customPalette = isRegisteredPalette(state.palette) ? state.palette : void 0;
135
+ const customNeutral = isCustomNeutral(state.neutralColor) ? state.neutralColor : void 0;
79
136
  return /* @__PURE__ */ jsxs(ThemeScopeContext, {
80
137
  value: state,
81
- children: [customPrimary && /* @__PURE__ */ jsx("style", {
82
- href: customPrimaryStyleId(customPrimary),
83
- precedence: "lobe-theme",
84
- children: getCustomPrimaryCss(customPrimary)
85
- }), /* @__PURE__ */ jsx("div", {
86
- className,
87
- style,
88
- ...toAttributes(state),
89
- children
90
- })]
138
+ children: [
139
+ customPrimary && /* @__PURE__ */ jsx("style", {
140
+ href: customPrimaryStyleId(customPrimary),
141
+ precedence: "lobe-theme",
142
+ children: getCustomPrimaryCss(customPrimary)
143
+ }),
144
+ customNeutral && /* @__PURE__ */ jsx("style", {
145
+ href: `${neutralStyleId(customNeutral)}-${paletteRevision}`,
146
+ precedence: "lobe-theme",
147
+ children: getCustomNeutralCss(customNeutral)
148
+ }),
149
+ customPalette && /* @__PURE__ */ jsx("style", {
150
+ href: `${paletteStyleId(customPalette)}-${paletteRevision}`,
151
+ precedence: "lobe-theme",
152
+ children: getCustomPaletteCss(customPalette)
153
+ }),
154
+ customPalette && state.neutralColor && /* @__PURE__ */ jsx("style", {
155
+ href: `${paletteNeutralStyleId(customPalette, state.neutralColor)}-${paletteRevision}`,
156
+ precedence: "lobe-theme",
157
+ children: getPaletteNeutralCss(customPalette, state.neutralColor)
158
+ }),
159
+ /* @__PURE__ */ jsx("div", {
160
+ className,
161
+ style,
162
+ ...toAttributes(state),
163
+ children
164
+ })
165
+ ]
91
166
  });
92
167
  };
93
168
  const useThemeMode = () => {
@@ -100,7 +175,7 @@ const useThemeMode = () => {
100
175
  const themeCache = /* @__PURE__ */ new Map();
101
176
  const useTheme = () => {
102
177
  const state = useThemeState();
103
- const key = stateKey(state);
178
+ const key = `${stateKey(state)}@${usePaletteRevision()}`;
104
179
  let theme = themeCache.get(key);
105
180
  if (!theme) {
106
181
  theme = {
@@ -151,14 +226,22 @@ const subscribeResponsive = (onChange) => {
151
226
  };
152
227
  };
153
228
  const useResponsive = () => useSyncExternalStore(subscribeResponsive, getResponsiveSnapshot, () => SERVER_RESPONSIVE);
154
- const LobeThemeScript = ({ appearance, neutralColor, nonce, primaryColor }) => {
229
+ const LobeThemeScript = ({ appearance, neutralColor, nonce, palette, primaryColor }) => {
155
230
  const primary = normalizePrimary(primaryColor);
156
- const custom = isCustomPrimaryColor(primary) ? [customPrimaryStyleId(primary), getCustomPrimaryCss(primary)] : [null, null];
157
- const script = `(function(a,p,n,i,c){var d=document.documentElement;if(a==='system')a=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light';if(a)d.setAttribute('data-theme',a);else if(!d.hasAttribute('data-theme'))d.setAttribute('data-theme','light');if(p)d.setAttribute('data-primary-color',p);if(n)d.setAttribute('data-neutral-color',n);if(c&&!document.getElementById(i)){var s=document.createElement('style');s.id=i;s.textContent=c;document.head.appendChild(s);}}).apply(null,${JSON.stringify([
231
+ const styles = [];
232
+ if (isCustomPrimaryColor(primary)) styles.push([customPrimaryStyleId(primary), getCustomPrimaryCss(primary)]);
233
+ const neutral = normalizeNeutral(neutralColor);
234
+ if (isCustomNeutral(neutral)) styles.push([neutralStyleId(neutral), getCustomNeutralCss(neutral)]);
235
+ if (isRegisteredPalette(palette)) {
236
+ styles.push([paletteStyleId(palette), getCustomPaletteCss(palette)]);
237
+ if (neutral) styles.push([paletteNeutralStyleId(palette, neutral), getPaletteNeutralCss(palette, neutral)]);
238
+ }
239
+ const script = `(function(a,p,n,q,t){var d=document.documentElement;if(a==='system')a=matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light';if(a)d.setAttribute('data-theme',a);else if(!d.hasAttribute('data-theme'))d.setAttribute('data-theme','light');if(p)d.setAttribute('data-primary-color',p);if(n)d.setAttribute('data-neutral-color',n);if(q)d.setAttribute('data-palette',q);t.forEach(function(x){if(document.getElementById(x[0]))return;var s=document.createElement('style');s.id=x[0];s.textContent=x[1];document.head.appendChild(s);});}).apply(null,${JSON.stringify([
158
240
  appearance ?? null,
159
241
  primary ?? null,
160
- neutralColor ?? null,
161
- ...custom
242
+ neutral ?? null,
243
+ palette ?? null,
244
+ styles
162
245
  ])})`;
163
246
  return /* @__PURE__ */ jsx("script", {
164
247
  suppressHydrationWarning: true,