@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.
- package/README.md +3 -3
- package/es/Accordion/style.d.mts +1 -1
- package/es/CodeDiff/DiffPanel.mjs +2 -2
- package/es/CodeDiff/DiffPanel.mjs.map +1 -1
- package/es/Drawer/atoms.mjs +2 -1
- package/es/Drawer/atoms.mjs.map +1 -1
- package/es/Drawer/style.mjs.map +1 -1
- package/es/DropdownMenu/atoms.mjs +2 -1
- package/es/DropdownMenu/atoms.mjs.map +1 -1
- package/es/FloatingPanel/style.mjs +3 -2
- package/es/FloatingPanel/style.mjs.map +1 -1
- package/es/Form/Form.mjs +6 -2
- package/es/Form/Form.mjs.map +1 -1
- package/es/Form/style.mjs +3 -3
- package/es/Form/style.mjs.map +1 -1
- package/es/Form/type.d.mts +7 -0
- package/es/Modal/atoms.mjs +2 -1
- package/es/Modal/atoms.mjs.map +1 -1
- package/es/Popover/PopoverInGroup.mjs +2 -1
- package/es/Popover/PopoverInGroup.mjs.map +1 -1
- package/es/Popover/atoms.mjs +2 -1
- package/es/Popover/atoms.mjs.map +1 -1
- package/es/Popover/style.mjs +1 -1
- package/es/Popover/style.mjs.map +1 -1
- package/es/ProTable/hooks/useFetchData.mjs +1 -1
- package/es/ProTable/hooks/useFetchData.mjs.map +1 -1
- package/es/ProTable/parts/FieldControl.mjs +28 -11
- package/es/ProTable/parts/FieldControl.mjs.map +1 -1
- package/es/ProTable/style.mjs +9 -0
- package/es/ProTable/style.mjs.map +1 -1
- package/es/ProTable/type.d.mts +5 -2
- package/es/Segmented/Segmented.mjs +2 -1
- package/es/Segmented/Segmented.mjs.map +1 -1
- package/es/Segmented/type.d.mts +7 -0
- package/es/Select/atoms.mjs +2 -1
- package/es/Select/atoms.mjs.map +1 -1
- package/es/Switch/Switch.mjs +8 -1
- package/es/Switch/Switch.mjs.map +1 -1
- package/es/Switch/atoms.d.mts +7 -1
- package/es/Switch/atoms.mjs +20 -4
- package/es/Switch/atoms.mjs.map +1 -1
- package/es/Switch/style.mjs +33 -2
- package/es/Switch/style.mjs.map +1 -1
- package/es/Table/Table.mjs +14 -5
- package/es/Table/Table.mjs.map +1 -1
- package/es/Table/render/FixedFrost.mjs +11 -2
- package/es/Table/render/FixedFrost.mjs.map +1 -1
- package/es/Table/style.mjs +4 -0
- package/es/Table/style.mjs.map +1 -1
- package/es/Toast/dodge.mjs +0 -1
- package/es/Toast/dodge.mjs.map +1 -1
- package/es/Toast/dodge.stylex.mjs +1 -4
- package/es/Toast/dodge.stylex.mjs.map +1 -1
- package/es/Toast/style.mjs +1 -1
- package/es/Toast/style.mjs.map +1 -1
- package/es/Tooltip/TooltipInGroup.mjs +2 -1
- package/es/Tooltip/TooltipInGroup.mjs.map +1 -1
- package/es/Tooltip/TooltipStandalone.mjs +2 -1
- package/es/Tooltip/TooltipStandalone.mjs.map +1 -1
- package/es/Tooltip/style.mjs +2 -2
- package/es/Tooltip/style.mjs.map +1 -1
- package/es/color/index.d.mts +2 -1
- package/es/color/index.mjs +2 -1
- package/es/color/status/error.mjs +67 -0
- package/es/color/status/error.mjs.map +1 -0
- package/es/color/status/index.d.mts +11 -0
- package/es/color/status/index.mjs +15 -0
- package/es/color/status/index.mjs.map +1 -0
- package/es/color/status/info.mjs +67 -0
- package/es/color/status/info.mjs.map +1 -0
- package/es/color/status/success.mjs +67 -0
- package/es/color/status/success.mjs.map +1 -0
- package/es/color/status/warning.mjs +67 -0
- package/es/color/status/warning.mjs.map +1 -0
- package/es/hooks/useNativeButton.mjs +1 -0
- package/es/hooks/useNativeButton.mjs.map +1 -1
- package/es/index.d.mts +4 -2
- package/es/index.mjs +4 -2
- package/es/style.css +114 -23
- package/es/styles/index.d.mts +4 -2
- package/es/styles/index.mjs +4 -2
- package/es/styles/stylex/cssVar.stylex.mjs +3 -0
- package/es/styles/stylex/cssVar.stylex.mjs.map +1 -1
- package/es/styles/theme/createLobeToken.d.mts +11 -7
- package/es/styles/theme/createLobeToken.mjs +3 -2
- package/es/styles/theme/createLobeToken.mjs.map +1 -1
- package/es/styles/theme/customNeutral.d.mts +28 -0
- package/es/styles/theme/customNeutral.mjs +84 -0
- package/es/styles/theme/customNeutral.mjs.map +1 -0
- package/es/styles/theme/customPalette.d.mts +6 -0
- package/es/styles/theme/customPalette.mjs +32 -0
- package/es/styles/theme/customPalette.mjs.map +1 -0
- package/es/styles/theme/customPrimary.mjs +52 -17
- package/es/styles/theme/customPrimary.mjs.map +1 -1
- package/es/styles/theme/scope.d.mts +7 -5
- package/es/styles/theme/scope.mjs +105 -22
- package/es/styles/theme/scope.mjs.map +1 -1
- package/es/styles/theme/themeCss.d.mts +3 -0
- package/es/styles/theme/themeCss.mjs +46 -1
- package/es/styles/theme/themeCss.mjs.map +1 -1
- package/es/styles/theme/token/legacy.mjs +12 -12
- package/es/styles/theme/token/legacy.mjs.map +1 -1
- package/es/styles/theme/token/neutral.mjs +13 -7
- package/es/styles/theme/token/neutral.mjs.map +1 -1
- package/es/styles/theme/token/neutralText.d.mts +4 -0
- package/es/styles/theme/token/neutralText.mjs +91 -0
- package/es/styles/theme/token/neutralText.mjs.map +1 -0
- package/es/styles/theme/token/palette.mjs +16 -41
- package/es/styles/theme/token/palette.mjs.map +1 -1
- package/es/styles/theme/token/static.mjs +3 -0
- package/es/styles/theme/token/static.mjs.map +1 -1
- package/es/theme.css +293 -290
- package/es/utils/getElementRef.mjs +17 -0
- package/es/utils/getElementRef.mjs.map +1 -0
- package/package.json +1 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
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?:
|
|
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 {
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
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,
|
|
56
|
-
darkA: retintAlpha(preset.darkA, preset.dark,
|
|
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
|
|
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 {
|
|
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?:
|
|
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?:
|
|
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: [
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
style,
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|
157
|
-
|
|
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
|
-
|
|
161
|
-
|
|
242
|
+
neutral ?? null,
|
|
243
|
+
palette ?? null,
|
|
244
|
+
styles
|
|
162
245
|
])})`;
|
|
163
246
|
return /* @__PURE__ */ jsx("script", {
|
|
164
247
|
suppressHydrationWarning: true,
|