@fangxinyan/lumina 0.6.2 → 0.6.3

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 (141) hide show
  1. package/README.md +2 -1
  2. package/dist/{Alert-JJ7GB3UU.css → Alert-QBKIDY5H.css} +7 -0
  3. package/dist/Alert.cjs +3 -3
  4. package/dist/Alert.d.cts +3 -2
  5. package/dist/Alert.d.ts +3 -2
  6. package/dist/Alert.js +2 -2
  7. package/dist/AutoComplete.cjs +5 -5
  8. package/dist/AutoComplete.js +4 -4
  9. package/dist/Badge.d.cts +1 -0
  10. package/dist/Badge.d.ts +1 -0
  11. package/dist/{Button-SDQD25AG.css → Button-4Z3Q6KII.css} +56 -36
  12. package/dist/Button.cjs +3 -3
  13. package/dist/Button.d.cts +6 -5
  14. package/dist/Button.d.ts +6 -5
  15. package/dist/Button.js +2 -2
  16. package/dist/Calendar.cjs +3 -3
  17. package/dist/Calendar.js +2 -2
  18. package/dist/{Cascader-C2DFSMKJ.css → Cascader-3BLLA7EN.css} +13 -0
  19. package/dist/Cascader.cjs +5 -5
  20. package/dist/Cascader.d.cts +4 -2
  21. package/dist/Cascader.d.ts +4 -2
  22. package/dist/Cascader.js +4 -4
  23. package/dist/Checkbox.cjs +3 -3
  24. package/dist/Checkbox.js +2 -2
  25. package/dist/Collapse.cjs +3 -3
  26. package/dist/Collapse.js +2 -2
  27. package/dist/CommandPalette.cjs +5 -5
  28. package/dist/CommandPalette.js +4 -4
  29. package/dist/Drawer.cjs +3 -3
  30. package/dist/Drawer.js +2 -2
  31. package/dist/Icon.cjs +55 -47
  32. package/dist/Icon.d.cts +9 -1
  33. package/dist/Icon.d.ts +9 -1
  34. package/dist/Icon.js +1 -1
  35. package/dist/{Image-4MN34O6P.css → Image-MRYQCRQ5.css} +78 -0
  36. package/dist/Image.cjs +12 -4
  37. package/dist/Image.d.cts +79 -6
  38. package/dist/Image.d.ts +79 -6
  39. package/dist/Image.js +2 -2
  40. package/dist/{Input-3G4ONWNU.css → Input-HUBJ55OH.css} +10 -0
  41. package/dist/Input.cjs +5 -5
  42. package/dist/Input.d.cts +4 -3
  43. package/dist/Input.d.ts +4 -3
  44. package/dist/Input.js +3 -3
  45. package/dist/InputNumber.cjs +5 -5
  46. package/dist/InputNumber.js +4 -4
  47. package/dist/Message.cjs +6 -6
  48. package/dist/Message.js +2 -2
  49. package/dist/Modal.cjs +4 -4
  50. package/dist/Modal.d.cts +1 -0
  51. package/dist/Modal.d.ts +1 -0
  52. package/dist/Modal.js +3 -3
  53. package/dist/Pagination.cjs +7 -7
  54. package/dist/Pagination.js +6 -6
  55. package/dist/{Select-JVBQAZBG.css → Select-Z5VYPEEY.css} +26 -1
  56. package/dist/Select.cjs +6 -6
  57. package/dist/Select.d.cts +4 -3
  58. package/dist/Select.d.ts +4 -3
  59. package/dist/Select.js +5 -5
  60. package/dist/Table.cjs +9 -9
  61. package/dist/Table.js +8 -8
  62. package/dist/TablePro.cjs +10 -10
  63. package/dist/TablePro.js +9 -9
  64. package/dist/{Tag-LB3OOJAO.css → Tag-HDYCDPFS.css} +14 -1
  65. package/dist/Tag.cjs +3 -3
  66. package/dist/Tag.d.cts +4 -3
  67. package/dist/Tag.d.ts +4 -3
  68. package/dist/Tag.js +2 -2
  69. package/dist/Textarea.cjs +4 -4
  70. package/dist/Textarea.js +2 -2
  71. package/dist/Theme.cjs +14 -10
  72. package/dist/Theme.d.cts +29 -6
  73. package/dist/Theme.d.ts +29 -6
  74. package/dist/Theme.js +1 -1
  75. package/dist/Typography.cjs +7 -7
  76. package/dist/Typography.d.cts +1 -0
  77. package/dist/Typography.d.ts +1 -0
  78. package/dist/Typography.js +2 -2
  79. package/dist/{chunk-MT7UWY6T.cjs → chunk-2HQCUBA7.cjs} +2 -2
  80. package/dist/{chunk-OF3SGLZY.js → chunk-47VG2P34.js} +9 -1
  81. package/dist/{chunk-ZIP7F4UF.cjs → chunk-5DKRY67M.cjs} +4 -4
  82. package/dist/{chunk-DQTSTJ6O.js → chunk-5H5YP2TB.js} +3 -3
  83. package/dist/{chunk-QGHYQCF3.cjs → chunk-5MN3PMF4.cjs} +8 -8
  84. package/dist/{chunk-FBVVRTX2.cjs → chunk-6HMTV6P4.cjs} +2 -2
  85. package/dist/{chunk-RF2EY5JS.cjs → chunk-6ZXQJRAT.cjs} +153 -34
  86. package/dist/{chunk-4WTU5P3O.cjs → chunk-7AG524YZ.cjs} +3 -3
  87. package/dist/{chunk-CEJ7VBR6.js → chunk-7IYKKLV3.js} +2 -2
  88. package/dist/{chunk-FJNWUELL.js → chunk-AAGF7K3L.js} +1 -1
  89. package/dist/{chunk-AWXCSX6J.js → chunk-BPOOVO5T.js} +3 -3
  90. package/dist/{chunk-EJBHR2P5.js → chunk-BVQ77VRY.js} +2 -2
  91. package/dist/{chunk-7NGMQIST.js → chunk-CETNCRZ4.js} +2 -2
  92. package/dist/{chunk-K2KYM7LW.cjs → chunk-DG5VQ6BO.cjs} +2 -2
  93. package/dist/chunk-DWAN57G4.js +243 -0
  94. package/dist/{chunk-CXWEOAVU.js → chunk-ET6DYQVZ.js} +1 -1
  95. package/dist/{chunk-WKKSAGYH.js → chunk-FBYUZOZP.js} +7 -7
  96. package/dist/{chunk-EIY7KEJ3.cjs → chunk-FGW5GJ22.cjs} +2 -2
  97. package/dist/{chunk-33NCTOEB.js → chunk-FWPBORRB.js} +1 -1
  98. package/dist/{chunk-EQEJTN3V.js → chunk-GIZU3H6H.js} +1 -1
  99. package/dist/{chunk-HPFQXYKG.cjs → chunk-H4LGWZMH.cjs} +9 -9
  100. package/dist/{chunk-6LZ54NPO.cjs → chunk-HKF2V5MM.cjs} +33 -23
  101. package/dist/{chunk-WGZ2KJTZ.js → chunk-HLFH5HWR.js} +1 -1
  102. package/dist/{chunk-UMDGS4BP.js → chunk-I5WTQ5Y3.js} +4 -4
  103. package/dist/{chunk-MUXP7ASL.js → chunk-J2HZTJO6.js} +1 -1
  104. package/dist/{chunk-NN25YMOL.js → chunk-J5ZGYQZK.js} +153 -35
  105. package/dist/{chunk-CHMCL7AV.js → chunk-JCEHZ336.js} +1 -1
  106. package/dist/{chunk-FFZ6OMZI.js → chunk-JVUVOR6S.js} +1 -1
  107. package/dist/{chunk-ON4DEDMI.js → chunk-K5IGFBDR.js} +1 -1
  108. package/dist/{chunk-35ZGBAA3.cjs → chunk-K7FV7W6U.cjs} +5 -5
  109. package/dist/{chunk-XD3JGL5O.js → chunk-ME5BZ2WA.js} +1 -1
  110. package/dist/{chunk-OQBDU5I2.cjs → chunk-MPVCYU2K.cjs} +2 -2
  111. package/dist/{chunk-CUXV6QNN.cjs → chunk-P6EZG2R7.cjs} +5 -5
  112. package/dist/{chunk-SKMP2A5O.cjs → chunk-P6P4DGLF.cjs} +2 -2
  113. package/dist/{chunk-TEG7NJHS.cjs → chunk-PULGVK2I.cjs} +2 -2
  114. package/dist/{chunk-TZJH5HBT.cjs → chunk-QP3VCSRY.cjs} +5 -5
  115. package/dist/{chunk-MQV2XN4B.cjs → chunk-R2TEDH2F.cjs} +5 -5
  116. package/dist/{chunk-JD7A6VM3.js → chunk-SQGPSMSK.js} +5 -5
  117. package/dist/{chunk-GNEZQMKH.js → chunk-TGL5BGMR.js} +4 -4
  118. package/dist/{chunk-5WAXZJG5.cjs → chunk-TP567B3L.cjs} +5 -5
  119. package/dist/{chunk-XTIN5545.js → chunk-UKS23N3L.js} +31 -21
  120. package/dist/{chunk-TJII7BQ2.cjs → chunk-V272XR3F.cjs} +10 -0
  121. package/dist/chunk-VFFIE2VO.cjs +271 -0
  122. package/dist/{chunk-OYMJVU66.cjs → chunk-X5GCOMC3.cjs} +15 -15
  123. package/dist/{chunk-3AS5B7MQ.cjs → chunk-XSN4TLN5.cjs} +10 -10
  124. package/dist/{chunk-6ACKL3WH.cjs → chunk-ZKE73UQF.cjs} +3 -3
  125. package/dist/index.cjs +130 -110
  126. package/dist/index.d.cts +5 -5
  127. package/dist/index.d.ts +5 -5
  128. package/dist/index.js +24 -24
  129. package/dist/styles.css +202 -38
  130. package/docs/llms/alert.md +4 -3
  131. package/docs/llms/button.md +4 -3
  132. package/docs/llms/cascader.md +3 -0
  133. package/docs/llms/image.md +72 -1
  134. package/docs/llms/input.md +3 -2
  135. package/docs/llms/select.md +2 -2
  136. package/docs/llms/tag.md +3 -2
  137. package/docs/llms/theme.md +41 -4
  138. package/docs/llms.md +4 -4
  139. package/package.json +16 -1
  140. package/dist/chunk-B2KEZQ6S.cjs +0 -116
  141. package/dist/chunk-PH3YECMF.js +0 -90
@@ -49,24 +49,95 @@ var FONT_STACKS = {
49
49
  };
50
50
  var DEFAULT_CONFIG = {
51
51
  mode: "light",
52
+ colorScheme: "light",
52
53
  accent: "sky",
53
54
  density: "comfortable",
54
55
  intensity: 5,
55
56
  radius: 20,
56
57
  font: "sf",
57
- tokens: {}
58
+ tokens: {},
59
+ themes: {}
58
60
  };
59
61
  var isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
62
+ function isThemeBaseMode(mode) {
63
+ return mode === "light" || mode === "dark";
64
+ }
65
+ function isBuiltInThemeMode(mode) {
66
+ return mode === "light" || mode === "dark" || mode === "system";
67
+ }
68
+ function getThemePreset(themes, mode) {
69
+ if (!mode || isBuiltInThemeMode(mode)) return void 0;
70
+ return themes?.[mode];
71
+ }
72
+ function applyThemePreset(config, mode) {
73
+ const preset = getThemePreset(config.themes, mode);
74
+ if (!preset) {
75
+ return {
76
+ ...config,
77
+ mode,
78
+ colorScheme: isThemeBaseMode(mode) ? mode : config.colorScheme
79
+ };
80
+ }
81
+ return {
82
+ ...config,
83
+ mode,
84
+ colorScheme: preset.base ?? config.colorScheme ?? DEFAULT_CONFIG.colorScheme,
85
+ accent: preset.accent ?? config.accent,
86
+ density: preset.density ?? config.density,
87
+ intensity: preset.intensity ?? config.intensity,
88
+ radius: preset.radius ?? config.radius,
89
+ font: preset.font ?? config.font,
90
+ tokens: preset.tokens ? { ...preset.tokens } : config.tokens
91
+ };
92
+ }
93
+ function resolveThemeConfig(config) {
94
+ const mode = config.mode ?? DEFAULT_CONFIG.mode;
95
+ const themes = config.themes ?? DEFAULT_CONFIG.themes;
96
+ const preset = getThemePreset(themes, mode);
97
+ const presetConfig = preset ? {
98
+ ...preset.base ? { colorScheme: preset.base } : null,
99
+ ...preset.accent ? { accent: preset.accent } : null,
100
+ ...preset.density ? { density: preset.density } : null,
101
+ ...preset.intensity != null ? { intensity: preset.intensity } : null,
102
+ ...preset.radius != null ? { radius: preset.radius } : null,
103
+ ...preset.font ? { font: preset.font } : null
104
+ } : {};
105
+ const merged = {
106
+ ...DEFAULT_CONFIG,
107
+ ...presetConfig,
108
+ ...config,
109
+ mode,
110
+ themes,
111
+ tokens: {
112
+ ...preset?.tokens ?? {},
113
+ ...config.tokens ?? {}
114
+ }
115
+ };
116
+ return {
117
+ ...merged,
118
+ colorScheme: merged.colorScheme ?? preset?.base ?? DEFAULT_CONFIG.colorScheme,
119
+ accent: merged.accent ?? preset?.accent ?? DEFAULT_CONFIG.accent,
120
+ density: merged.density ?? preset?.density ?? DEFAULT_CONFIG.density,
121
+ intensity: merged.intensity ?? preset?.intensity ?? DEFAULT_CONFIG.intensity,
122
+ radius: merged.radius ?? preset?.radius ?? DEFAULT_CONFIG.radius,
123
+ font: merged.font ?? preset?.font ?? DEFAULT_CONFIG.font
124
+ };
125
+ }
60
126
  function resolveThemeMode(mode) {
61
127
  if (mode !== "system") return mode;
62
128
  if (!isBrowser) return "light";
63
129
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
64
130
  }
65
- function normalizeAccentInput(input, resolvedMode) {
131
+ function resolveThemeColorScheme(mode, themes, fallback) {
132
+ if (mode === "system") return fallback ?? resolveThemeMode(mode);
133
+ if (isThemeBaseMode(mode)) return mode;
134
+ return getThemePreset(themes, mode)?.base ?? fallback ?? DEFAULT_CONFIG.colorScheme;
135
+ }
136
+ function normalizeAccentInput(input, colorScheme) {
66
137
  if (typeof input === "string" && input in ACCENT_PRESETS) {
67
138
  const key = input;
68
139
  const base = ACCENT_PRESETS[key];
69
- if (resolvedMode === "dark") {
140
+ if (colorScheme === "dark") {
70
141
  return { key, palette: { ...base, ...ACCENT_PRESETS_DARK[key] } };
71
142
  }
72
143
  return { key, palette: base };
@@ -74,18 +145,20 @@ function normalizeAccentInput(input, resolvedMode) {
74
145
  const raw = typeof input === "string" ? { accent: input } : input;
75
146
  const { accent } = raw;
76
147
  const ink = raw.ink ?? `color-mix(in oklch, ${accent} 65%, black)`;
77
- const soft = raw.soft ?? (resolvedMode === "dark" ? `color-mix(in oklch, ${accent} 30%, black)` : `color-mix(in oklch, ${accent} 15%, white)`);
78
- const glow = raw.glow ?? (resolvedMode === "dark" ? `color-mix(in oklch, ${accent} 18%, transparent)` : `color-mix(in oklch, ${accent} 35%, transparent)`);
148
+ const soft = raw.soft ?? (colorScheme === "dark" ? `color-mix(in oklch, ${accent} 30%, black)` : `color-mix(in oklch, ${accent} 15%, white)`);
149
+ const glow = raw.glow ?? (colorScheme === "dark" ? `color-mix(in oklch, ${accent} 18%, transparent)` : `color-mix(in oklch, ${accent} 35%, transparent)`);
79
150
  return { key: "custom", palette: { accent, ink, soft, glow } };
80
151
  }
81
152
  function toVar(key) {
82
153
  return key.startsWith("--") ? key : `--${key}`;
83
154
  }
84
155
  function applyTheme(target, config) {
85
- const cfg = { ...DEFAULT_CONFIG, ...config };
86
- const resolvedMode = resolveThemeMode(cfg.mode);
87
- const { key, palette } = normalizeAccentInput(cfg.accent, resolvedMode);
88
- target.dataset.theme = resolvedMode;
156
+ const cfg = resolveThemeConfig(config);
157
+ resolveThemeMode(cfg.mode);
158
+ const colorScheme = resolveThemeColorScheme(cfg.mode, cfg.themes, cfg.colorScheme);
159
+ const { key, palette } = normalizeAccentInput(cfg.accent, colorScheme);
160
+ target.dataset.theme = colorScheme;
161
+ target.dataset.themeMode = cfg.mode;
89
162
  target.dataset.density = cfg.density;
90
163
  if (key === "custom") {
91
164
  delete target.dataset.accent;
@@ -146,7 +219,8 @@ function loadPersisted(key) {
146
219
  function persist(key, cfg) {
147
220
  if (!key || !isBrowser) return;
148
221
  try {
149
- localStorage.setItem(key, JSON.stringify(cfg));
222
+ const { themes: _themes, ...persisted } = cfg;
223
+ localStorage.setItem(key, JSON.stringify(persisted));
150
224
  } catch {
151
225
  }
152
226
  }
@@ -164,41 +238,69 @@ var ThemeProvider = (props) => {
164
238
  const initialConfig = React__namespace.useMemo(() => {
165
239
  const fromProps = {
166
240
  mode: configProps.mode ?? DEFAULT_CONFIG.mode,
241
+ colorScheme: configProps.colorScheme,
167
242
  accent: configProps.accent ?? DEFAULT_CONFIG.accent,
168
243
  density: configProps.density ?? DEFAULT_CONFIG.density,
169
244
  intensity: configProps.intensity ?? DEFAULT_CONFIG.intensity,
170
245
  radius: configProps.radius ?? DEFAULT_CONFIG.radius,
171
246
  font: configProps.font ?? DEFAULT_CONFIG.font,
172
- tokens: configProps.tokens ?? {}
247
+ tokens: configProps.tokens ?? {},
248
+ themes: configProps.themes ?? DEFAULT_CONFIG.themes
173
249
  };
174
250
  const persisted = loadPersisted(storageKey);
175
- return persisted ? { ...fromProps, ...persisted } : fromProps;
251
+ const seeded = applyThemePreset(fromProps, fromProps.mode ?? DEFAULT_CONFIG.mode);
252
+ const withExplicitProps = {
253
+ ...seeded,
254
+ ...configProps.colorScheme ? { colorScheme: configProps.colorScheme } : null,
255
+ ...configProps.accent ? { accent: configProps.accent } : null,
256
+ ...configProps.density ? { density: configProps.density } : null,
257
+ ...configProps.intensity != null ? { intensity: configProps.intensity } : null,
258
+ ...configProps.radius != null ? { radius: configProps.radius } : null,
259
+ ...configProps.font ? { font: configProps.font } : null,
260
+ ...configProps.tokens ? { tokens: configProps.tokens } : null
261
+ };
262
+ if (!persisted) return withExplicitProps;
263
+ const persistedMode = persisted.mode ?? withExplicitProps.mode ?? DEFAULT_CONFIG.mode;
264
+ return {
265
+ ...applyThemePreset({ ...withExplicitProps, mode: persistedMode }, persistedMode),
266
+ ...persisted
267
+ };
176
268
  }, []);
177
269
  const [config, setConfig] = React__namespace.useState(initialConfig);
178
270
  React__namespace.useEffect(() => {
179
271
  setConfig((c) => {
272
+ const base = {
273
+ ...c,
274
+ themes: configProps.themes ?? c.themes
275
+ };
276
+ const mode = configProps.mode ?? c.mode ?? DEFAULT_CONFIG.mode;
277
+ const nextFromMode = configProps.mode ? applyThemePreset(base, mode) : base;
180
278
  const next = {
181
- mode: configProps.mode ?? c.mode,
182
- accent: configProps.accent ?? c.accent,
183
- density: configProps.density ?? c.density,
184
- intensity: configProps.intensity ?? c.intensity,
185
- radius: configProps.radius ?? c.radius,
186
- font: configProps.font ?? c.font,
187
- tokens: configProps.tokens ?? c.tokens
279
+ ...nextFromMode,
280
+ mode,
281
+ colorScheme: configProps.colorScheme ?? nextFromMode.colorScheme,
282
+ accent: configProps.accent ?? nextFromMode.accent,
283
+ density: configProps.density ?? nextFromMode.density,
284
+ intensity: configProps.intensity ?? nextFromMode.intensity,
285
+ radius: configProps.radius ?? nextFromMode.radius,
286
+ font: configProps.font ?? nextFromMode.font,
287
+ tokens: configProps.tokens ?? nextFromMode.tokens
188
288
  };
189
- if (next.mode === c.mode && next.accent === c.accent && next.density === c.density && next.intensity === c.intensity && next.radius === c.radius && next.font === c.font && next.tokens === c.tokens) {
289
+ if (next.mode === c.mode && next.colorScheme === c.colorScheme && next.accent === c.accent && next.density === c.density && next.intensity === c.intensity && next.radius === c.radius && next.font === c.font && next.tokens === c.tokens && next.themes === c.themes) {
190
290
  return c;
191
291
  }
192
292
  return next;
193
293
  });
194
294
  }, [
195
295
  configProps.mode,
296
+ configProps.colorScheme,
196
297
  configProps.accent,
197
298
  configProps.density,
198
299
  configProps.intensity,
199
300
  configProps.radius,
200
301
  configProps.font,
201
- configProps.tokens
302
+ configProps.tokens,
303
+ configProps.themes
202
304
  ]);
203
305
  const [systemDark, setSystemDark] = React__namespace.useState(
204
306
  () => isBrowser && window.matchMedia("(prefers-color-scheme: dark)").matches
@@ -210,32 +312,47 @@ var ThemeProvider = (props) => {
210
312
  mql.addEventListener?.("change", handler);
211
313
  return () => mql.removeEventListener?.("change", handler);
212
314
  }, []);
213
- const resolvedMode = config.mode === "system" ? systemDark ? "dark" : "light" : config.mode;
315
+ const effectiveConfig = React__namespace.useMemo(() => resolveThemeConfig(config), [config]);
316
+ const activeTheme = React__namespace.useMemo(
317
+ () => getThemePreset(effectiveConfig.themes, effectiveConfig.mode) ?? null,
318
+ [effectiveConfig.mode, effectiveConfig.themes]
319
+ );
320
+ const colorScheme = effectiveConfig.mode === "system" ? systemDark ? "dark" : "light" : isThemeBaseMode(effectiveConfig.mode) ? effectiveConfig.mode : effectiveConfig.colorScheme ?? activeTheme?.base ?? DEFAULT_CONFIG.colorScheme;
321
+ const resolvedMode = effectiveConfig.mode === "system" ? colorScheme : effectiveConfig.mode;
214
322
  const { key: accentKey, palette: accentPalette } = React__namespace.useMemo(
215
- () => normalizeAccentInput(config.accent, resolvedMode),
216
- [config.accent, resolvedMode]
323
+ () => normalizeAccentInput(effectiveConfig.accent, colorScheme),
324
+ [effectiveConfig.accent, colorScheme]
217
325
  );
218
326
  const scopeRef = React__namespace.useRef(null);
327
+ const appliedTokenKeysRef = React__namespace.useRef(/* @__PURE__ */ new Set());
219
328
  React__namespace.useEffect(() => {
220
329
  if (!isBrowser) return;
221
330
  const el = target === "root" ? document.documentElement : scopeRef.current;
222
331
  if (!el) return;
223
- applyTheme(el, { ...config, mode: resolvedMode });
332
+ const nextTokenKeys = new Set(Object.keys(effectiveConfig.tokens));
333
+ for (const key of appliedTokenKeysRef.current) {
334
+ if (!nextTokenKeys.has(key)) el.style.removeProperty(toVar(key));
335
+ }
336
+ applyTheme(el, { ...effectiveConfig, colorScheme });
337
+ appliedTokenKeysRef.current = nextTokenKeys;
224
338
  persist(storageKey, config);
225
- }, [config, resolvedMode, target, storageKey]);
339
+ }, [config, effectiveConfig, colorScheme, target, storageKey]);
226
340
  const value = React__namespace.useMemo(() => {
227
341
  const patch = (p) => setConfig((c) => ({ ...c, ...p }));
228
342
  return {
229
- mode: config.mode,
343
+ mode: effectiveConfig.mode,
230
344
  resolvedMode,
345
+ colorScheme,
231
346
  accent: accentKey,
232
347
  accentPalette,
233
- density: config.density,
234
- intensity: config.intensity,
235
- radius: config.radius,
236
- font: config.font,
237
- tokens: config.tokens ?? {},
238
- setMode: (m) => patch({ mode: m }),
348
+ density: effectiveConfig.density,
349
+ intensity: effectiveConfig.intensity,
350
+ radius: effectiveConfig.radius,
351
+ font: effectiveConfig.font,
352
+ tokens: effectiveConfig.tokens,
353
+ themes: effectiveConfig.themes,
354
+ activeTheme,
355
+ setMode: (m) => setConfig((c) => applyThemePreset(c, m)),
239
356
  toggleMode: () => setConfig((c) => ({
240
357
  ...c,
241
358
  mode: c.mode === "dark" ? "light" : "dark"
@@ -246,10 +363,11 @@ var ThemeProvider = (props) => {
246
363
  setRadius: (n) => patch({ radius: n }),
247
364
  setFont: (f) => patch({ font: f }),
248
365
  setTokens: (t) => patch({ tokens: t }),
366
+ setThemes: (t) => patch({ themes: t }),
249
367
  update: patch,
250
368
  reset: () => setConfig(initialConfig)
251
369
  };
252
- }, [config, resolvedMode, accentKey, accentPalette, initialConfig]);
370
+ }, [effectiveConfig, resolvedMode, colorScheme, accentKey, accentPalette, activeTheme, initialConfig]);
253
371
  const onChangeRef = React__namespace.useRef(onChange);
254
372
  onChangeRef.current = onChange;
255
373
  React__namespace.useEffect(() => {
@@ -276,6 +394,7 @@ exports.FONT_STACKS = FONT_STACKS;
276
394
  exports.ThemeProvider = ThemeProvider;
277
395
  exports.applyTheme = applyTheme;
278
396
  exports.normalizeAccentInput = normalizeAccentInput;
397
+ exports.resolveThemeColorScheme = resolveThemeColorScheme;
279
398
  exports.resolveThemeMode = resolveThemeMode;
280
399
  exports.useTheme = useTheme;
281
400
  exports.useThemeOptional = useThemeOptional;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkTJII7BQ2_cjs = require('./chunk-TJII7BQ2.cjs');
3
+ var chunkV272XR3F_cjs = require('./chunk-V272XR3F.cjs');
4
4
  require('./tokens-BIIUTPKN.css');
5
5
  require('./shared-NJHRNLRH.css');
6
6
  require('./Calendar-LHZELUDL.css');
@@ -66,7 +66,7 @@ var Calendar = React__namespace.forwardRef(({
66
66
  className: "btn icon sm ghost",
67
67
  onClick: () => setView(new Date(view.getFullYear(), view.getMonth() - 1, 1)),
68
68
  "aria-label": "Previous month",
69
- children: /* @__PURE__ */ jsxRuntime.jsx(chunkTJII7BQ2_cjs.Icon, { name: "chevLeft", size: 14 })
69
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkV272XR3F_cjs.Icon, { name: "chevLeft", size: 14 })
70
70
  }
71
71
  ),
72
72
  /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "calendar-title", children: [
@@ -82,7 +82,7 @@ var Calendar = React__namespace.forwardRef(({
82
82
  className: "btn icon sm ghost",
83
83
  onClick: () => setView(new Date(view.getFullYear(), view.getMonth() + 1, 1)),
84
84
  "aria-label": "Next month",
85
- children: /* @__PURE__ */ jsxRuntime.jsx(chunkTJII7BQ2_cjs.Icon, { name: "chevRight", size: 14 })
85
+ children: /* @__PURE__ */ jsxRuntime.jsx(chunkV272XR3F_cjs.Icon, { name: "chevRight", size: 14 })
86
86
  }
87
87
  )
88
88
  ] }),
@@ -1,5 +1,5 @@
1
- import { Button } from './chunk-JD7A6VM3.js';
2
- import { Icon } from './chunk-OF3SGLZY.js';
1
+ import { Button } from './chunk-SQGPSMSK.js';
2
+ import { Icon } from './chunk-47VG2P34.js';
3
3
  import './tokens-BIIUTPKN.css';
4
4
  import './shared-NJHRNLRH.css';
5
5
  import './Modal-2QNDW4SO.css';
@@ -1,5 +1,5 @@
1
1
  import { useFloating } from './chunk-DUFRASGO.js';
2
- import { Input } from './chunk-XTIN5545.js';
2
+ import { Input } from './chunk-UKS23N3L.js';
3
3
  import './tokens-BIIUTPKN.css';
4
4
  import './shared-NJHRNLRH.css';
5
5
  import './AutoComplete-P5KZMZO5.css';
@@ -1,7 +1,7 @@
1
- import { Pagination } from './chunk-7NGMQIST.js';
2
- import { Checkbox } from './chunk-EQEJTN3V.js';
1
+ import { Pagination } from './chunk-CETNCRZ4.js';
2
+ import { Checkbox } from './chunk-GIZU3H6H.js';
3
3
  import { useFloating } from './chunk-DUFRASGO.js';
4
- import { Icon } from './chunk-OF3SGLZY.js';
4
+ import { Icon } from './chunk-47VG2P34.js';
5
5
  import './tokens-BIIUTPKN.css';
6
6
  import './shared-NJHRNLRH.css';
7
7
  import './Table-ATJJQLKU.css';
@@ -1,5 +1,5 @@
1
- import { Input } from './chunk-XTIN5545.js';
2
- import { Icon } from './chunk-OF3SGLZY.js';
1
+ import { Input } from './chunk-UKS23N3L.js';
2
+ import { Icon } from './chunk-47VG2P34.js';
3
3
  import './tokens-BIIUTPKN.css';
4
4
  import './shared-NJHRNLRH.css';
5
5
  import './InputNumber-VXQIWLQC.css';
@@ -1,5 +1,5 @@
1
- import { Select } from './chunk-WKKSAGYH.js';
2
- import { Icon } from './chunk-OF3SGLZY.js';
1
+ import { Select } from './chunk-FBYUZOZP.js';
2
+ import { Icon } from './chunk-47VG2P34.js';
3
3
  import './tokens-BIIUTPKN.css';
4
4
  import './shared-NJHRNLRH.css';
5
5
  import './Pagination-YIRYJUXP.css';
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk3AS5B7MQ_cjs = require('./chunk-3AS5B7MQ.cjs');
3
+ var chunkXSN4TLN5_cjs = require('./chunk-XSN4TLN5.cjs');
4
4
  require('./tokens-BIIUTPKN.css');
5
5
  require('./shared-NJHRNLRH.css');
6
6
  require('./TablePro-3XVHYLSL.css');
@@ -20,7 +20,7 @@ function TablePro({
20
20
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "table-toolbar-main", children: toolbar }),
21
21
  actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "table-toolbar-actions", children: actions })
22
22
  ] }),
23
- /* @__PURE__ */ jsxRuntime.jsx(chunk3AS5B7MQ_cjs.Table, { ...tableProps, className: "joined" }),
23
+ /* @__PURE__ */ jsxRuntime.jsx(chunkXSN4TLN5_cjs.Table, { ...tableProps, className: "joined" }),
24
24
  footer && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "table-footer", children: footer })
25
25
  ] });
26
26
  }
@@ -0,0 +1,243 @@
1
+ import { Icon } from './chunk-47VG2P34.js';
2
+ import './tokens-BIIUTPKN.css';
3
+ import './shared-NJHRNLRH.css';
4
+ import './Image-MRYQCRQ5.css';
5
+ import * as React from 'react';
6
+ import ReactDOM from 'react-dom';
7
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
8
+
9
+ var Image = React.forwardRef(({
10
+ src,
11
+ alt,
12
+ width = 200,
13
+ height,
14
+ variant = "framed",
15
+ frame,
16
+ padding,
17
+ objectFit,
18
+ objectPosition,
19
+ preview,
20
+ hover = true,
21
+ placeholder,
22
+ imgProps,
23
+ className = "",
24
+ style,
25
+ ...rest
26
+ }, ref) => {
27
+ const [loaded, setLoaded] = React.useState(false);
28
+ const [err, setErr] = React.useState(false);
29
+ const [open, setOpen] = React.useState(false);
30
+ const visualFrame = frame ?? variant === "framed";
31
+ const resolvedHeight = height ?? (variant === "icon" ? width : 140);
32
+ const resolvedPadding = padding ?? (visualFrame ? void 0 : 0);
33
+ const resolvedObjectFit = objectFit ?? (variant === "icon" ? "contain" : "cover");
34
+ const canPreview = (preview ?? variant === "framed") && loaded && !err;
35
+ const {
36
+ className: imgClassName = "",
37
+ style: imgStyle,
38
+ onLoad,
39
+ onError,
40
+ ...imageRest
41
+ } = imgProps ?? {};
42
+ React.useEffect(() => {
43
+ setLoaded(false);
44
+ setErr(false);
45
+ setOpen(false);
46
+ }, [src]);
47
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
48
+ /* @__PURE__ */ jsx(
49
+ "div",
50
+ {
51
+ ref,
52
+ className: `n-image ${variant} ${visualFrame ? "framed" : "unframed"} ${hover ? "hover" : ""} ${canPreview ? "clickable" : ""} ${className}`,
53
+ style: { width, ...resolvedPadding !== void 0 ? { padding: resolvedPadding } : {}, ...style },
54
+ onClick: () => canPreview && setOpen(true),
55
+ ...rest,
56
+ children: /* @__PURE__ */ jsxs("div", { className: "n-image-frame", style: { width: "100%", height: resolvedHeight }, children: [
57
+ !err && src && /* @__PURE__ */ jsx(
58
+ "img",
59
+ {
60
+ ...imageRest,
61
+ src,
62
+ alt,
63
+ className: imgClassName,
64
+ style: { objectFit: resolvedObjectFit, objectPosition, ...imgStyle },
65
+ onLoad: (event) => {
66
+ setLoaded(true);
67
+ onLoad?.(event);
68
+ },
69
+ onError: (event) => {
70
+ setErr(true);
71
+ onError?.(event);
72
+ }
73
+ }
74
+ ),
75
+ /* @__PURE__ */ jsx("div", { className: `n-image-placeholder ${loaded && !err ? "loaded" : ""}`, children: placeholder ?? /* @__PURE__ */ jsx(Icon, { name: "image", size: 28 }) }),
76
+ canPreview && /* @__PURE__ */ jsxs(Fragment, { children: [
77
+ /* @__PURE__ */ jsxs("div", { className: "image-hint", children: [
78
+ /* @__PURE__ */ jsx(Icon, { name: "eye", size: 14 }),
79
+ /* @__PURE__ */ jsx("span", { children: "\u70B9\u51FB\u67E5\u770B" })
80
+ ] }),
81
+ /* @__PURE__ */ jsxs("div", { className: "image-actions", onClick: (e) => e.stopPropagation(), children: [
82
+ /* @__PURE__ */ jsx(
83
+ "button",
84
+ {
85
+ type: "button",
86
+ className: "ia-btn",
87
+ onClick: () => setOpen(true),
88
+ "aria-label": "\u9884\u89C8",
89
+ children: /* @__PURE__ */ jsx(Icon, { name: "eye", size: 13 })
90
+ }
91
+ ),
92
+ src && /* @__PURE__ */ jsx("a", { className: "ia-btn", href: src, download: true, "aria-label": "\u4E0B\u8F7D", children: /* @__PURE__ */ jsx(Icon, { name: "download", size: 13 }) })
93
+ ] })
94
+ ] })
95
+ ] })
96
+ }
97
+ ),
98
+ open && typeof document !== "undefined" && ReactDOM.createPortal(
99
+ /* @__PURE__ */ jsx("div", { className: "image-preview-overlay", onClick: () => setOpen(false), children: /* @__PURE__ */ jsx("img", { src, alt, onClick: (e) => e.stopPropagation() }) }),
100
+ document.body
101
+ )
102
+ ] });
103
+ });
104
+ Image.displayName = "Image";
105
+ var ImageGrid = React.forwardRef(({
106
+ images,
107
+ columns,
108
+ itemHeight = 130,
109
+ minItemWidth = 160,
110
+ gap = 14,
111
+ imageProps,
112
+ className = "",
113
+ style,
114
+ ...rest
115
+ }, ref) => /* @__PURE__ */ jsx(
116
+ "div",
117
+ {
118
+ ref,
119
+ className,
120
+ style: {
121
+ display: "grid",
122
+ gap,
123
+ gridTemplateColumns: columns ? `repeat(${columns}, 1fr)` : `repeat(auto-fill, minmax(${typeof minItemWidth === "number" ? `${minItemWidth}px` : minItemWidth}, 1fr))`,
124
+ ...style
125
+ },
126
+ ...rest,
127
+ children: images.map((img, i) => /* @__PURE__ */ jsx(
128
+ Image,
129
+ {
130
+ ...imageProps,
131
+ ...img,
132
+ src: img.src,
133
+ alt: img.alt,
134
+ width: img.width ?? "100%",
135
+ height: img.height ?? itemHeight
136
+ },
137
+ i
138
+ ))
139
+ }
140
+ ));
141
+ ImageGrid.displayName = "ImageGrid";
142
+ var SpriteImage = React.forwardRef(({
143
+ src,
144
+ sprite,
145
+ alt,
146
+ width,
147
+ height,
148
+ scale = 1,
149
+ backgroundSize,
150
+ variant = "icon",
151
+ frame,
152
+ padding,
153
+ className = "",
154
+ style,
155
+ ...rest
156
+ }, ref) => {
157
+ const visualFrame = frame ?? variant === "framed";
158
+ const resolvedWidth = width ?? sprite.width * scale;
159
+ const resolvedHeight = height ?? sprite.height * scale;
160
+ const resolvedPadding = padding ?? (visualFrame ? void 0 : 0);
161
+ return /* @__PURE__ */ jsx(
162
+ "div",
163
+ {
164
+ ref,
165
+ className: `n-sprite-image ${variant} ${visualFrame ? "framed" : "unframed"} ${className}`,
166
+ role: alt ? "img" : void 0,
167
+ "aria-label": alt || void 0,
168
+ "aria-hidden": alt === "" ? true : void 0,
169
+ style: { width: resolvedWidth, ...resolvedPadding !== void 0 ? { padding: resolvedPadding } : {}, ...style },
170
+ ...rest,
171
+ children: /* @__PURE__ */ jsx("div", { className: "n-sprite-image-frame", style: { height: resolvedHeight }, children: /* @__PURE__ */ jsx(
172
+ "span",
173
+ {
174
+ className: "n-sprite-image-sprite",
175
+ style: {
176
+ width: sprite.width,
177
+ height: sprite.height,
178
+ backgroundImage: `url(${JSON.stringify(src)})`,
179
+ backgroundPosition: `${-sprite.x}px ${-sprite.y}px`,
180
+ backgroundSize,
181
+ transform: scale !== 1 ? `scale(${scale})` : void 0
182
+ }
183
+ }
184
+ ) })
185
+ }
186
+ );
187
+ });
188
+ SpriteImage.displayName = "SpriteImage";
189
+ var insetStyle = (inset) => {
190
+ if (inset == null) return { inset: 0 };
191
+ if (typeof inset === "number" || typeof inset === "string") return { inset };
192
+ return inset;
193
+ };
194
+ var LayeredImage = React.forwardRef(({
195
+ layers,
196
+ width = 64,
197
+ height = 64,
198
+ variant = "icon",
199
+ frame,
200
+ padding,
201
+ className = "",
202
+ style,
203
+ ...rest
204
+ }, ref) => {
205
+ const visualFrame = frame ?? variant === "framed";
206
+ const resolvedPadding = padding ?? (visualFrame ? void 0 : 0);
207
+ return /* @__PURE__ */ jsx(
208
+ "div",
209
+ {
210
+ ref,
211
+ className: `n-layered-image ${variant} ${visualFrame ? "framed" : "unframed"} ${className}`,
212
+ style: { width, ...resolvedPadding !== void 0 ? { padding: resolvedPadding } : {}, ...style },
213
+ ...rest,
214
+ children: /* @__PURE__ */ jsx("div", { className: "n-layered-image-frame", style: { height }, children: layers.map(({ src: layerSrc, alt: layerAlt = "", fit = "contain", inset, zIndex, className: layerClassName = "", style: layerStyle, ...layerRest }, index) => /* @__PURE__ */ jsx(
215
+ "span",
216
+ {
217
+ className: "n-layered-image-layer",
218
+ style: {
219
+ zIndex,
220
+ ...insetStyle(inset)
221
+ },
222
+ children: /* @__PURE__ */ jsx(
223
+ "img",
224
+ {
225
+ ...layerRest,
226
+ src: layerSrc,
227
+ alt: layerAlt,
228
+ className: layerClassName,
229
+ style: {
230
+ objectFit: fit,
231
+ ...layerStyle
232
+ }
233
+ }
234
+ )
235
+ },
236
+ `${layerSrc}-${index}`
237
+ )) })
238
+ }
239
+ );
240
+ });
241
+ LayeredImage.displayName = "LayeredImage";
242
+
243
+ export { Image, ImageGrid, LayeredImage, SpriteImage };
@@ -1,4 +1,4 @@
1
- import { Icon } from './chunk-OF3SGLZY.js';
1
+ import { Icon } from './chunk-47VG2P34.js';
2
2
  import './tokens-BIIUTPKN.css';
3
3
  import './shared-NJHRNLRH.css';
4
4
  import './Typography-NKPWTJCV.css';