@fangxinyan/lumina 0.1.2 → 0.1.4

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 (73) hide show
  1. package/dist/{Cascader-TO2QMSLJ.css → Cascader-DTRTTXC2.css} +1 -4
  2. package/dist/Cascader.cjs +3 -2
  3. package/dist/Cascader.js +2 -1
  4. package/dist/ColorPicker-GP7AQYUU.css +233 -0
  5. package/dist/ColorPicker.cjs +13 -0
  6. package/dist/ColorPicker.cjs.map +1 -0
  7. package/dist/ColorPicker.d.cts +42 -0
  8. package/dist/ColorPicker.d.ts +42 -0
  9. package/dist/ColorPicker.js +4 -0
  10. package/dist/ColorPicker.js.map +1 -0
  11. package/dist/Popover-MGCMOXYP.css +10 -0
  12. package/dist/Popover.cjs +3 -2
  13. package/dist/Popover.js +2 -1
  14. package/dist/{Select-DDJJBQEL.css → Select-EDG37C37.css} +1 -4
  15. package/dist/Select.cjs +3 -2
  16. package/dist/Select.js +2 -1
  17. package/dist/{Tooltip-RT4BOVTD.css → Tooltip-ST24GY4S.css} +1 -6
  18. package/dist/Tooltip.cjs +3 -2
  19. package/dist/Tooltip.js +2 -1
  20. package/dist/Typography-NKPWTJCV.css +235 -0
  21. package/dist/Typography.cjs +29 -0
  22. package/dist/Typography.cjs.map +1 -0
  23. package/dist/Typography.d.cts +151 -0
  24. package/dist/Typography.d.ts +151 -0
  25. package/dist/Typography.js +4 -0
  26. package/dist/Typography.js.map +1 -0
  27. package/dist/{chunk-RMD6KQ4H.cjs → chunk-3UFU63X7.cjs} +29 -7
  28. package/dist/chunk-3UFU63X7.cjs.map +1 -0
  29. package/dist/chunk-5WF6M47X.cjs +510 -0
  30. package/dist/chunk-5WF6M47X.cjs.map +1 -0
  31. package/dist/chunk-GZGZR4FT.js +484 -0
  32. package/dist/chunk-GZGZR4FT.js.map +1 -0
  33. package/dist/{chunk-U6ODMPTI.cjs → chunk-HKAQILD2.cjs} +33 -19
  34. package/dist/chunk-HKAQILD2.cjs.map +1 -0
  35. package/dist/{chunk-ZMDVK2U3.cjs → chunk-KGYLUZOU.cjs} +61 -38
  36. package/dist/chunk-KGYLUZOU.cjs.map +1 -0
  37. package/dist/chunk-NE4YEBFH.js +66 -0
  38. package/dist/chunk-NE4YEBFH.js.map +1 -0
  39. package/dist/{chunk-XRZ5OKZH.js → chunk-OEHCA5IV.js} +38 -24
  40. package/dist/chunk-OEHCA5IV.js.map +1 -0
  41. package/dist/{chunk-T5AH4FCV.js → chunk-OYH6A7IQ.js} +61 -38
  42. package/dist/chunk-OYH6A7IQ.js.map +1 -0
  43. package/dist/chunk-QTGDYQOT.cjs +357 -0
  44. package/dist/chunk-QTGDYQOT.cjs.map +1 -0
  45. package/dist/chunk-RPD2OIIP.js +335 -0
  46. package/dist/chunk-RPD2OIIP.js.map +1 -0
  47. package/dist/chunk-RZ2E3XEU.cjs +131 -0
  48. package/dist/chunk-RZ2E3XEU.cjs.map +1 -0
  49. package/dist/{chunk-ZXM247EM.cjs → chunk-TWBJCFEJ.cjs} +38 -24
  50. package/dist/chunk-TWBJCFEJ.cjs.map +1 -0
  51. package/dist/chunk-V2DIQ3RH.js +109 -0
  52. package/dist/chunk-V2DIQ3RH.js.map +1 -0
  53. package/dist/chunk-WNGG25QX.js +56 -0
  54. package/dist/chunk-WNGG25QX.js.map +1 -0
  55. package/dist/index.cjs +50 -23
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.cts +3 -1
  58. package/dist/index.d.ts +3 -1
  59. package/dist/index.js +10 -7
  60. package/dist/index.js.map +1 -1
  61. package/dist/styles.css +434 -20
  62. package/package.json +1 -1
  63. package/dist/Popover-WXEVUYBG.css +0 -15
  64. package/dist/chunk-OUJBCNWD.js +0 -52
  65. package/dist/chunk-OUJBCNWD.js.map +0 -1
  66. package/dist/chunk-RMD6KQ4H.cjs.map +0 -1
  67. package/dist/chunk-T5AH4FCV.js.map +0 -1
  68. package/dist/chunk-U6ODMPTI.cjs.map +0 -1
  69. package/dist/chunk-XRZ5OKZH.js.map +0 -1
  70. package/dist/chunk-Y6FVCCUE.js +0 -34
  71. package/dist/chunk-Y6FVCCUE.js.map +0 -1
  72. package/dist/chunk-ZMDVK2U3.cjs.map +0 -1
  73. package/dist/chunk-ZXM247EM.cjs.map +0 -1
@@ -0,0 +1,335 @@
1
+ import { useFloating } from './chunk-V2DIQ3RH.js';
2
+ import './tokens-HWQ7KWPG.css';
3
+ import './shared-NJHRNLRH.css';
4
+ import './ColorPicker-GP7AQYUU.css';
5
+ import * as React from 'react';
6
+ import { createPortal } from 'react-dom';
7
+ import { jsxs, jsx } from 'react/jsx-runtime';
8
+
9
+ var clamp = (n, lo, hi) => Math.min(Math.max(n, lo), hi);
10
+ function normalizeHex(input) {
11
+ const s = input.trim().replace(/^#/, "");
12
+ if (!/^([\da-f]{3}|[\da-f]{6})$/i.test(s)) return null;
13
+ const full = s.length === 3 ? s.split("").map((c) => c + c).join("") : s;
14
+ return "#" + full.toLowerCase();
15
+ }
16
+ function hexToRgb(hex) {
17
+ const n = normalizeHex(hex);
18
+ if (!n) return null;
19
+ const int = parseInt(n.slice(1), 16);
20
+ return [int >> 16 & 255, int >> 8 & 255, int & 255];
21
+ }
22
+ function rgbToHex(r, g, b) {
23
+ const to = (x) => {
24
+ const h = clamp(Math.round(x), 0, 255).toString(16);
25
+ return h.length === 1 ? "0" + h : h;
26
+ };
27
+ return "#" + to(r) + to(g) + to(b);
28
+ }
29
+ function rgbToHsv(r, g, b) {
30
+ const R = r / 255;
31
+ const G = g / 255;
32
+ const B = b / 255;
33
+ const max = Math.max(R, G, B);
34
+ const min = Math.min(R, G, B);
35
+ const d = max - min;
36
+ let h = 0;
37
+ if (d !== 0) {
38
+ if (max === R) h = (G - B) / d % 6;
39
+ else if (max === G) h = (B - R) / d + 2;
40
+ else h = (R - G) / d + 4;
41
+ h *= 60;
42
+ if (h < 0) h += 360;
43
+ }
44
+ const s = max === 0 ? 0 : d / max * 100;
45
+ const v = max * 100;
46
+ return [h, s, v];
47
+ }
48
+ function hsvToRgb(h, s, v) {
49
+ const S = s / 100;
50
+ const V = v / 100;
51
+ const c = V * S;
52
+ const hh = h % 360 / 60;
53
+ const x = c * (1 - Math.abs(hh % 2 - 1));
54
+ const m = V - c;
55
+ let r = 0;
56
+ let g = 0;
57
+ let b = 0;
58
+ if (hh < 1) [r, g, b] = [c, x, 0];
59
+ else if (hh < 2) [r, g, b] = [x, c, 0];
60
+ else if (hh < 3) [r, g, b] = [0, c, x];
61
+ else if (hh < 4) [r, g, b] = [0, x, c];
62
+ else if (hh < 5) [r, g, b] = [x, 0, c];
63
+ else [r, g, b] = [c, 0, x];
64
+ return [(r + m) * 255, (g + m) * 255, (b + m) * 255];
65
+ }
66
+ var hexToHsv = (hex) => {
67
+ const rgb = hexToRgb(hex);
68
+ return rgb ? rgbToHsv(...rgb) : null;
69
+ };
70
+ var hsvToHex = (h, s, v) => rgbToHex(...hsvToRgb(h, s, v));
71
+ var DEFAULT_PRESETS = [
72
+ "#ff6b6b",
73
+ "#ffa94d",
74
+ "#ffd43b",
75
+ "#51cf66",
76
+ "#22b8cf",
77
+ "#339af0",
78
+ "#845ef7",
79
+ "#f06595",
80
+ "#868e96",
81
+ "#212529"
82
+ ];
83
+ var SaturationBoard = ({ hue, s, v, onChange }) => {
84
+ const ref = React.useRef(null);
85
+ const compute = (clientX, clientY) => {
86
+ const el = ref.current;
87
+ if (!el) return { s, v };
88
+ const rect = el.getBoundingClientRect();
89
+ const ns = clamp((clientX - rect.left) / rect.width * 100, 0, 100);
90
+ const nv = clamp(100 - (clientY - rect.top) / rect.height * 100, 0, 100);
91
+ return { s: ns, v: nv };
92
+ };
93
+ const handlePointerDown = (e) => {
94
+ const el = ref.current;
95
+ if (!el) return;
96
+ el.setPointerCapture(e.pointerId);
97
+ const first = compute(e.clientX, e.clientY);
98
+ onChange(first.s, first.v, false);
99
+ const move = (ev) => {
100
+ const c = compute(ev.clientX, ev.clientY);
101
+ onChange(c.s, c.v, false);
102
+ };
103
+ const up = (ev) => {
104
+ const c = compute(ev.clientX, ev.clientY);
105
+ onChange(c.s, c.v, true);
106
+ el.releasePointerCapture(e.pointerId);
107
+ el.removeEventListener("pointermove", move);
108
+ el.removeEventListener("pointerup", up);
109
+ el.removeEventListener("pointercancel", up);
110
+ };
111
+ el.addEventListener("pointermove", move);
112
+ el.addEventListener("pointerup", up);
113
+ el.addEventListener("pointercancel", up);
114
+ };
115
+ return /* @__PURE__ */ jsxs(
116
+ "div",
117
+ {
118
+ ref,
119
+ className: "cp-board",
120
+ style: { background: `hsl(${hue}, 100%, 50%)` },
121
+ onPointerDown: handlePointerDown,
122
+ children: [
123
+ /* @__PURE__ */ jsx("div", { className: "cp-board-white" }),
124
+ /* @__PURE__ */ jsx("div", { className: "cp-board-black" }),
125
+ /* @__PURE__ */ jsx(
126
+ "div",
127
+ {
128
+ className: "cp-board-thumb",
129
+ style: { left: `${s}%`, top: `${100 - v}%` }
130
+ }
131
+ )
132
+ ]
133
+ }
134
+ );
135
+ };
136
+ var HueSlider = ({ hue, onChange }) => {
137
+ const ref = React.useRef(null);
138
+ const compute = (clientX) => {
139
+ const el = ref.current;
140
+ if (!el) return hue;
141
+ const rect = el.getBoundingClientRect();
142
+ return clamp((clientX - rect.left) / rect.width * 360, 0, 360);
143
+ };
144
+ const handlePointerDown = (e) => {
145
+ const el = ref.current;
146
+ if (!el) return;
147
+ el.setPointerCapture(e.pointerId);
148
+ onChange(compute(e.clientX), false);
149
+ const move = (ev) => onChange(compute(ev.clientX), false);
150
+ const up = (ev) => {
151
+ onChange(compute(ev.clientX), true);
152
+ el.releasePointerCapture(e.pointerId);
153
+ el.removeEventListener("pointermove", move);
154
+ el.removeEventListener("pointerup", up);
155
+ el.removeEventListener("pointercancel", up);
156
+ };
157
+ el.addEventListener("pointermove", move);
158
+ el.addEventListener("pointerup", up);
159
+ el.addEventListener("pointercancel", up);
160
+ };
161
+ return /* @__PURE__ */ jsx("div", { ref, className: "cp-hue", onPointerDown: handlePointerDown, children: /* @__PURE__ */ jsx(
162
+ "div",
163
+ {
164
+ className: "cp-hue-thumb",
165
+ style: { left: `${hue / 360 * 100}%` }
166
+ }
167
+ ) });
168
+ };
169
+ var ColorPicker = React.forwardRef(
170
+ (props, ref) => {
171
+ const {
172
+ value,
173
+ defaultValue = "#845ef7",
174
+ onChange,
175
+ onChangeComplete,
176
+ disabled,
177
+ size = "md",
178
+ placement = "bottom",
179
+ presets = DEFAULT_PRESETS,
180
+ showText = false,
181
+ children,
182
+ open: openProp,
183
+ defaultOpen = false,
184
+ onOpenChange,
185
+ className = "",
186
+ style
187
+ } = props;
188
+ const isControlled = value != null;
189
+ const [internal, setInternal] = React.useState(
190
+ normalizeHex(defaultValue) ?? "#845ef7"
191
+ );
192
+ const current = normalizeHex((isControlled ? value : internal) ?? "") ?? "#845ef7";
193
+ const isOpenControlled = openProp != null;
194
+ const [openState, setOpenState] = React.useState(defaultOpen);
195
+ const open = isOpenControlled ? !!openProp : openState;
196
+ const setOpen = (next) => {
197
+ if (!isOpenControlled) setOpenState(next);
198
+ onOpenChange?.(next);
199
+ };
200
+ const [inputText, setInputText] = React.useState(current);
201
+ React.useEffect(() => setInputText(current), [current]);
202
+ const { triggerRef, floatingStyle } = useFloating({
203
+ open,
204
+ placement,
205
+ panelWidth: 256,
206
+ panelHeight: 300
207
+ });
208
+ const panelRef = React.useRef(null);
209
+ React.useImperativeHandle(ref, () => triggerRef.current);
210
+ React.useEffect(() => {
211
+ if (!open) return;
212
+ const onDown = (e) => {
213
+ const t = e.target;
214
+ if (triggerRef.current?.contains(t)) return;
215
+ if (panelRef.current?.contains(t)) return;
216
+ setOpen(false);
217
+ };
218
+ const onKey = (e) => {
219
+ if (e.key === "Escape") setOpen(false);
220
+ };
221
+ document.addEventListener("mousedown", onDown);
222
+ document.addEventListener("keydown", onKey);
223
+ return () => {
224
+ document.removeEventListener("mousedown", onDown);
225
+ document.removeEventListener("keydown", onKey);
226
+ };
227
+ }, [open]);
228
+ const commit = (hex, done) => {
229
+ const n = normalizeHex(hex);
230
+ if (!n) return;
231
+ if (!isControlled) setInternal(n);
232
+ onChange?.(n);
233
+ if (done) onChangeComplete?.(n);
234
+ };
235
+ const hsv = hexToHsv(current) ?? [0, 100, 100];
236
+ const [h, s, v] = hsv;
237
+ const handleBoard = (ns, nv, done) => {
238
+ commit(hsvToHex(h, ns, nv), done);
239
+ };
240
+ const handleHue = (nh, done) => {
241
+ commit(hsvToHex(nh, s, v), done);
242
+ };
243
+ const handleInputBlur = () => {
244
+ const n = normalizeHex(inputText);
245
+ if (n) commit(n, true);
246
+ else setInputText(current);
247
+ };
248
+ const handleInputKey = (e) => {
249
+ if (e.key === "Enter") {
250
+ e.preventDefault();
251
+ e.target.blur();
252
+ }
253
+ };
254
+ return /* @__PURE__ */ jsxs(
255
+ "div",
256
+ {
257
+ className: `cp ${placement} ${open ? "open" : ""} ${className}`,
258
+ style,
259
+ children: [
260
+ children ? /* @__PURE__ */ jsx(
261
+ "button",
262
+ {
263
+ type: "button",
264
+ ref: triggerRef,
265
+ className: "cp-custom-trigger",
266
+ disabled,
267
+ onClick: () => !disabled && setOpen(!open),
268
+ children
269
+ }
270
+ ) : /* @__PURE__ */ jsxs(
271
+ "button",
272
+ {
273
+ type: "button",
274
+ ref: triggerRef,
275
+ className: `cp-trigger ${size}`,
276
+ disabled,
277
+ onClick: () => !disabled && setOpen(!open),
278
+ "aria-label": `\u9009\u62E9\u989C\u8272 (\u5F53\u524D ${current})`,
279
+ children: [
280
+ /* @__PURE__ */ jsx("span", { className: "cp-swatch", style: { background: current } }),
281
+ showText && /* @__PURE__ */ jsx("span", { className: "cp-text", children: current })
282
+ ]
283
+ }
284
+ ),
285
+ open && !disabled && typeof document !== "undefined" && createPortal(
286
+ /* @__PURE__ */ jsxs(
287
+ "div",
288
+ {
289
+ ref: panelRef,
290
+ className: "cp-panel",
291
+ role: "dialog",
292
+ style: floatingStyle,
293
+ children: [
294
+ /* @__PURE__ */ jsx(SaturationBoard, { hue: h, s, v, onChange: handleBoard }),
295
+ /* @__PURE__ */ jsx(HueSlider, { hue: h, onChange: handleHue }),
296
+ /* @__PURE__ */ jsxs("div", { className: "cp-row", children: [
297
+ /* @__PURE__ */ jsx("span", { className: "cp-swatch sm", style: { background: current } }),
298
+ /* @__PURE__ */ jsx(
299
+ "input",
300
+ {
301
+ className: "cp-input",
302
+ value: inputText,
303
+ onChange: (e) => setInputText(e.target.value),
304
+ onBlur: handleInputBlur,
305
+ onKeyDown: handleInputKey,
306
+ spellCheck: false
307
+ }
308
+ )
309
+ ] }),
310
+ presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "cp-presets", children: presets.map((p) => /* @__PURE__ */ jsx(
311
+ "button",
312
+ {
313
+ type: "button",
314
+ className: `cp-preset ${current === normalizeHex(p) ? "active" : ""}`,
315
+ style: { background: p },
316
+ onClick: () => commit(p, true),
317
+ "aria-label": p
318
+ },
319
+ p
320
+ )) })
321
+ ]
322
+ }
323
+ ),
324
+ document.body
325
+ )
326
+ ]
327
+ }
328
+ );
329
+ }
330
+ );
331
+ ColorPicker.displayName = "ColorPicker";
332
+
333
+ export { ColorPicker };
334
+ //# sourceMappingURL=chunk-RPD2OIIP.js.map
335
+ //# sourceMappingURL=chunk-RPD2OIIP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ColorPicker/ColorPicker.tsx"],"names":[],"mappings":"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","file":"chunk-RPD2OIIP.js","sourcesContent":["import \"../../styles/tokens.css\";\nimport \"../../styles/shared.css\";\nimport \"./ColorPicker.css\";\nimport * as React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { useFloating } from \"../../utils/useFloating\";\n\n/* ============================================================================\n * Color conversion helpers\n * ========================================================================== */\n\ntype RGB = [number, number, number];\ntype HSV = [number, number, number];\n\nconst clamp = (n: number, lo: number, hi: number) => Math.min(Math.max(n, lo), hi);\n\nfunction normalizeHex(input: string): string | null {\n const s = input.trim().replace(/^#/, \"\");\n if (!/^([\\da-f]{3}|[\\da-f]{6})$/i.test(s)) return null;\n const full = s.length === 3 ? s.split(\"\").map((c) => c + c).join(\"\") : s;\n return \"#\" + full.toLowerCase();\n}\n\nfunction hexToRgb(hex: string): RGB | null {\n const n = normalizeHex(hex);\n if (!n) return null;\n const int = parseInt(n.slice(1), 16);\n return [(int >> 16) & 255, (int >> 8) & 255, int & 255];\n}\n\nfunction rgbToHex(r: number, g: number, b: number): string {\n const to = (x: number) => {\n const h = clamp(Math.round(x), 0, 255).toString(16);\n return h.length === 1 ? \"0\" + h : h;\n };\n return \"#\" + to(r) + to(g) + to(b);\n}\n\nfunction rgbToHsv(r: number, g: number, b: number): HSV {\n const R = r / 255;\n const G = g / 255;\n const B = b / 255;\n const max = Math.max(R, G, B);\n const min = Math.min(R, G, B);\n const d = max - min;\n let h = 0;\n if (d !== 0) {\n if (max === R) h = ((G - B) / d) % 6;\n else if (max === G) h = (B - R) / d + 2;\n else h = (R - G) / d + 4;\n h *= 60;\n if (h < 0) h += 360;\n }\n const s = max === 0 ? 0 : (d / max) * 100;\n const v = max * 100;\n return [h, s, v];\n}\n\nfunction hsvToRgb(h: number, s: number, v: number): RGB {\n const S = s / 100;\n const V = v / 100;\n const c = V * S;\n const hh = (h % 360) / 60;\n const x = c * (1 - Math.abs((hh % 2) - 1));\n const m = V - c;\n let r = 0;\n let g = 0;\n let b = 0;\n if (hh < 1) [r, g, b] = [c, x, 0];\n else if (hh < 2) [r, g, b] = [x, c, 0];\n else if (hh < 3) [r, g, b] = [0, c, x];\n else if (hh < 4) [r, g, b] = [0, x, c];\n else if (hh < 5) [r, g, b] = [x, 0, c];\n else [r, g, b] = [c, 0, x];\n return [(r + m) * 255, (g + m) * 255, (b + m) * 255];\n}\n\nconst hexToHsv = (hex: string): HSV | null => {\n const rgb = hexToRgb(hex);\n return rgb ? rgbToHsv(...rgb) : null;\n};\n\nconst hsvToHex = (h: number, s: number, v: number): string => rgbToHex(...hsvToRgb(h, s, v));\n\n/* ============================================================================\n * Public API\n * ========================================================================== */\n\nexport interface ColorPickerProps {\n /** Controlled hex color (e.g. \"#ff6b6b\"). */\n value?: string;\n /** Initial hex when uncontrolled. */\n defaultValue?: string;\n /** Fires on every pixel of drag / input edit. */\n onChange?: (hex: string) => void;\n /** Fires once when a drag / input / preset commit finishes. */\n onChangeComplete?: (hex: string) => void;\n /** Disable the trigger. */\n disabled?: boolean;\n /** Size of the swatch trigger. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Where the panel appears relative to the trigger. */\n placement?: \"top\" | \"bottom\" | \"left\" | \"right\";\n /** Hex preset chips below the panel. */\n presets?: string[];\n /** Show the current hex next to the swatch. */\n showText?: boolean;\n /** Custom trigger; defaults to a swatch chip. */\n children?: React.ReactNode;\n /** Controlled open state. */\n open?: boolean;\n /** Initial open state when uncontrolled. */\n defaultOpen?: boolean;\n /** Called when open state changes. */\n onOpenChange?: (open: boolean) => void;\n className?: string;\n style?: React.CSSProperties;\n}\n\n/* ============================================================================\n * Internals\n * ========================================================================== */\n\nconst DEFAULT_PRESETS = [\n \"#ff6b6b\",\n \"#ffa94d\",\n \"#ffd43b\",\n \"#51cf66\",\n \"#22b8cf\",\n \"#339af0\",\n \"#845ef7\",\n \"#f06595\",\n \"#868e96\",\n \"#212529\",\n];\n\ninterface BoardProps {\n hue: number;\n s: number;\n v: number;\n onChange: (s: number, v: number, done: boolean) => void;\n}\n\nconst SaturationBoard: React.FC<BoardProps> = ({ hue, s, v, onChange }) => {\n const ref = React.useRef<HTMLDivElement>(null);\n\n const compute = (clientX: number, clientY: number) => {\n const el = ref.current;\n if (!el) return { s, v };\n const rect = el.getBoundingClientRect();\n const ns = clamp(((clientX - rect.left) / rect.width) * 100, 0, 100);\n const nv = clamp(100 - ((clientY - rect.top) / rect.height) * 100, 0, 100);\n return { s: ns, v: nv };\n };\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = ref.current;\n if (!el) return;\n el.setPointerCapture(e.pointerId);\n const first = compute(e.clientX, e.clientY);\n onChange(first.s, first.v, false);\n\n const move = (ev: PointerEvent) => {\n const c = compute(ev.clientX, ev.clientY);\n onChange(c.s, c.v, false);\n };\n const up = (ev: PointerEvent) => {\n const c = compute(ev.clientX, ev.clientY);\n onChange(c.s, c.v, true);\n el.releasePointerCapture(e.pointerId);\n el.removeEventListener(\"pointermove\", move);\n el.removeEventListener(\"pointerup\", up);\n el.removeEventListener(\"pointercancel\", up);\n };\n el.addEventListener(\"pointermove\", move);\n el.addEventListener(\"pointerup\", up);\n el.addEventListener(\"pointercancel\", up);\n };\n\n return (\n <div\n ref={ref}\n className=\"cp-board\"\n style={{ background: `hsl(${hue}, 100%, 50%)` }}\n onPointerDown={handlePointerDown}\n >\n <div className=\"cp-board-white\" />\n <div className=\"cp-board-black\" />\n <div\n className=\"cp-board-thumb\"\n style={{ left: `${s}%`, top: `${100 - v}%` }}\n />\n </div>\n );\n};\n\ninterface HueProps {\n hue: number;\n onChange: (h: number, done: boolean) => void;\n}\n\nconst HueSlider: React.FC<HueProps> = ({ hue, onChange }) => {\n const ref = React.useRef<HTMLDivElement>(null);\n\n const compute = (clientX: number) => {\n const el = ref.current;\n if (!el) return hue;\n const rect = el.getBoundingClientRect();\n return clamp(((clientX - rect.left) / rect.width) * 360, 0, 360);\n };\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n const el = ref.current;\n if (!el) return;\n el.setPointerCapture(e.pointerId);\n onChange(compute(e.clientX), false);\n const move = (ev: PointerEvent) => onChange(compute(ev.clientX), false);\n const up = (ev: PointerEvent) => {\n onChange(compute(ev.clientX), true);\n el.releasePointerCapture(e.pointerId);\n el.removeEventListener(\"pointermove\", move);\n el.removeEventListener(\"pointerup\", up);\n el.removeEventListener(\"pointercancel\", up);\n };\n el.addEventListener(\"pointermove\", move);\n el.addEventListener(\"pointerup\", up);\n el.addEventListener(\"pointercancel\", up);\n };\n\n return (\n <div ref={ref} className=\"cp-hue\" onPointerDown={handlePointerDown}>\n <div\n className=\"cp-hue-thumb\"\n style={{ left: `${(hue / 360) * 100}%` }}\n />\n </div>\n );\n};\n\n/* ============================================================================\n * Main component\n * ========================================================================== */\n\n/**\n * `ColorPicker` — neumorphic color picker with HSV panel, hue slider,\n * hex input and optional preset palette.\n *\n * @example\n * <ColorPicker defaultValue=\"#845ef7\" onChange={setColor} />\n */\nexport const ColorPicker = React.forwardRef<HTMLButtonElement, ColorPickerProps>(\n (props, ref) => {\n const {\n value,\n defaultValue = \"#845ef7\",\n onChange,\n onChangeComplete,\n disabled,\n size = \"md\",\n placement = \"bottom\",\n presets = DEFAULT_PRESETS,\n showText = false,\n children,\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n className = \"\",\n style,\n } = props;\n\n const isControlled = value != null;\n const [internal, setInternal] = React.useState(\n normalizeHex(defaultValue) ?? \"#845ef7\"\n );\n const current = normalizeHex((isControlled ? value : internal) ?? \"\") ?? \"#845ef7\";\n\n const isOpenControlled = openProp != null;\n const [openState, setOpenState] = React.useState(defaultOpen);\n const open = isOpenControlled ? !!openProp : openState;\n const setOpen = (next: boolean) => {\n if (!isOpenControlled) setOpenState(next);\n onOpenChange?.(next);\n };\n\n const [inputText, setInputText] = React.useState(current);\n React.useEffect(() => setInputText(current), [current]);\n\n const { triggerRef, floatingStyle } = useFloating<HTMLButtonElement>({\n open,\n placement,\n panelWidth: 256,\n panelHeight: 300,\n });\n const panelRef = React.useRef<HTMLDivElement>(null);\n React.useImperativeHandle(ref, () => triggerRef.current as HTMLButtonElement);\n\n React.useEffect(() => {\n if (!open) return;\n const onDown = (e: MouseEvent) => {\n const t = e.target as Node;\n if (triggerRef.current?.contains(t)) return;\n if (panelRef.current?.contains(t)) return;\n setOpen(false);\n };\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"mousedown\", onDown);\n document.addEventListener(\"keydown\", onKey);\n return () => {\n document.removeEventListener(\"mousedown\", onDown);\n document.removeEventListener(\"keydown\", onKey);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n const commit = (hex: string, done: boolean) => {\n const n = normalizeHex(hex);\n if (!n) return;\n if (!isControlled) setInternal(n);\n onChange?.(n);\n if (done) onChangeComplete?.(n);\n };\n\n const hsv = hexToHsv(current) ?? [0, 100, 100];\n const [h, s, v] = hsv;\n\n const handleBoard = (ns: number, nv: number, done: boolean) => {\n commit(hsvToHex(h, ns, nv), done);\n };\n const handleHue = (nh: number, done: boolean) => {\n commit(hsvToHex(nh, s, v), done);\n };\n\n const handleInputBlur = () => {\n const n = normalizeHex(inputText);\n if (n) commit(n, true);\n else setInputText(current);\n };\n\n const handleInputKey = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n (e.target as HTMLInputElement).blur();\n }\n };\n\n return (\n <div\n className={`cp ${placement} ${open ? \"open\" : \"\"} ${className}`}\n style={style}\n >\n {children ? (\n <button\n type=\"button\"\n ref={triggerRef}\n className=\"cp-custom-trigger\"\n disabled={disabled}\n onClick={() => !disabled && setOpen(!open)}\n >\n {children}\n </button>\n ) : (\n <button\n type=\"button\"\n ref={triggerRef}\n className={`cp-trigger ${size}`}\n disabled={disabled}\n onClick={() => !disabled && setOpen(!open)}\n aria-label={`选择颜色 (当前 ${current})`}\n >\n <span className=\"cp-swatch\" style={{ background: current }} />\n {showText && <span className=\"cp-text\">{current}</span>}\n </button>\n )}\n\n {open && !disabled && typeof document !== \"undefined\" &&\n createPortal(\n <div\n ref={panelRef}\n className=\"cp-panel\"\n role=\"dialog\"\n style={floatingStyle}\n >\n <SaturationBoard hue={h} s={s} v={v} onChange={handleBoard} />\n <HueSlider hue={h} onChange={handleHue} />\n <div className=\"cp-row\">\n <span className=\"cp-swatch sm\" style={{ background: current }} />\n <input\n className=\"cp-input\"\n value={inputText}\n onChange={(e) => setInputText(e.target.value)}\n onBlur={handleInputBlur}\n onKeyDown={handleInputKey}\n spellCheck={false}\n />\n </div>\n {presets.length > 0 && (\n <div className=\"cp-presets\">\n {presets.map((p) => (\n <button\n key={p}\n type=\"button\"\n className={`cp-preset ${current === normalizeHex(p) ? \"active\" : \"\"}`}\n style={{ background: p }}\n onClick={() => commit(p, true)}\n aria-label={p}\n />\n ))}\n </div>\n )}\n </div>,\n document.body\n )}\n </div>\n );\n }\n);\nColorPicker.displayName = \"ColorPicker\";\n"]}
@@ -0,0 +1,131 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ function _interopNamespace(e) {
6
+ if (e && e.__esModule) return e;
7
+ var n = Object.create(null);
8
+ if (e) {
9
+ Object.keys(e).forEach(function (k) {
10
+ if (k !== 'default') {
11
+ var d = Object.getOwnPropertyDescriptor(e, k);
12
+ Object.defineProperty(n, k, d.get ? d : {
13
+ enumerable: true,
14
+ get: function () { return e[k]; }
15
+ });
16
+ }
17
+ });
18
+ }
19
+ n.default = e;
20
+ return Object.freeze(n);
21
+ }
22
+
23
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
24
+
25
+ // src/utils/useFloating.ts
26
+ function useFloating(opts) {
27
+ const triggerRef = React__namespace.useRef(null);
28
+ const preferred = opts.placement ?? "bottom";
29
+ const gap = opts.gap ?? 8;
30
+ const panelW = opts.panelWidth ?? 240;
31
+ const panelH = opts.panelHeight ?? 300;
32
+ const doShift = opts.shift !== false;
33
+ const doFlip = opts.flip !== false;
34
+ const matchW = !!opts.matchTriggerWidth;
35
+ const align = opts.alignCross ?? "start";
36
+ const open = opts.open;
37
+ const [state, setState] = React__namespace.useState({ top: 0, left: 0, placement: preferred });
38
+ React__namespace.useLayoutEffect(() => {
39
+ if (!open) return;
40
+ const update = () => {
41
+ const el = triggerRef.current;
42
+ if (!el) return;
43
+ const rect = el.getBoundingClientRect();
44
+ const w = matchW ? rect.width : panelW;
45
+ const h = panelH;
46
+ const vw = window.innerWidth;
47
+ const vh = window.innerHeight;
48
+ const MARGIN = 8;
49
+ const place = (p) => {
50
+ switch (p) {
51
+ case "top":
52
+ return { top: rect.top - gap - h, left: rect.left };
53
+ case "right":
54
+ return { top: rect.top, left: rect.right + gap };
55
+ case "left":
56
+ return { top: rect.top, left: rect.left - gap - w };
57
+ case "bottom":
58
+ default:
59
+ return { top: rect.bottom + gap, left: rect.left };
60
+ }
61
+ };
62
+ const fits = (p, c) => {
63
+ if (p === "bottom") return c.top + h <= vh - MARGIN;
64
+ if (p === "top") return c.top >= MARGIN;
65
+ if (p === "right") return c.left + w <= vw - MARGIN;
66
+ if (p === "left") return c.left >= MARGIN;
67
+ return true;
68
+ };
69
+ let resolved = preferred;
70
+ let coords = place(resolved);
71
+ if (doFlip && !fits(resolved, coords)) {
72
+ const opp = {
73
+ top: "bottom",
74
+ bottom: "top",
75
+ left: "right",
76
+ right: "left"
77
+ };
78
+ const alt = opp[resolved];
79
+ const altCoords = place(alt);
80
+ if (fits(alt, altCoords)) {
81
+ resolved = alt;
82
+ coords = altCoords;
83
+ }
84
+ }
85
+ if (align !== "start") {
86
+ if (resolved === "top" || resolved === "bottom") {
87
+ coords.left = align === "center" ? rect.left + rect.width / 2 : rect.right;
88
+ } else {
89
+ coords.top = align === "center" ? rect.top + rect.height / 2 : rect.bottom;
90
+ }
91
+ } else if (doShift) {
92
+ if (resolved === "bottom" || resolved === "top") {
93
+ coords.left = Math.max(MARGIN, Math.min(coords.left, vw - w - MARGIN));
94
+ } else {
95
+ coords.top = Math.max(MARGIN, Math.min(coords.top, vh - h - MARGIN));
96
+ }
97
+ }
98
+ setState({
99
+ top: coords.top,
100
+ left: coords.left,
101
+ width: matchW ? rect.width : void 0,
102
+ placement: resolved
103
+ });
104
+ };
105
+ update();
106
+ window.addEventListener("scroll", update, true);
107
+ window.addEventListener("resize", update);
108
+ return () => {
109
+ window.removeEventListener("scroll", update, true);
110
+ window.removeEventListener("resize", update);
111
+ };
112
+ }, [open, preferred, gap, panelW, panelH, doShift, doFlip, matchW]);
113
+ let transform;
114
+ if (align !== "start") {
115
+ const cross = state.placement === "top" || state.placement === "bottom" ? "X" : "Y";
116
+ const percent = align === "center" ? "-50%" : "-100%";
117
+ transform = `translate${cross}(${percent})`;
118
+ }
119
+ const floatingStyle = {
120
+ position: "fixed",
121
+ top: state.top,
122
+ left: state.left,
123
+ ...state.width != null ? { width: state.width } : {},
124
+ ...transform ? { transform } : {}
125
+ };
126
+ return { triggerRef, floatingStyle, placement: state.placement };
127
+ }
128
+
129
+ exports.useFloating = useFloating;
130
+ //# sourceMappingURL=chunk-RZ2E3XEU.cjs.map
131
+ //# sourceMappingURL=chunk-RZ2E3XEU.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/useFloating.ts"],"names":["React"],"mappings":"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","file":"chunk-RZ2E3XEU.cjs","sourcesContent":["import * as React from \"react\";\n\nexport type Placement = \"top\" | \"bottom\" | \"left\" | \"right\";\n\nexport interface UseFloatingOptions {\n /** Whether the floating element is currently visible. */\n open: boolean;\n /** Preferred placement relative to the trigger. Default `\"bottom\"`. */\n placement?: Placement;\n /** Distance between trigger and panel in px. Default 8. */\n gap?: number;\n /** Estimated panel width, used for flip / shift math. Ignored when `matchTriggerWidth`. */\n panelWidth?: number;\n /** Estimated panel height, used for flip / shift math. */\n panelHeight?: number;\n /** Keep the panel inside the viewport horizontally / vertically. Default true. */\n shift?: boolean;\n /** Flip to the opposite side if the preferred side would overflow. Default true. */\n flip?: boolean;\n /** Make the panel width track the trigger width (used by Select / Cascader). */\n matchTriggerWidth?: boolean;\n /**\n * Cross-axis alignment of the panel relative to the trigger.\n * - `\"start\"` (default) — panel's leading edge lines up with trigger's leading edge.\n * - `\"center\"` — panel is centered on the trigger (uses a CSS transform).\n * - `\"end\"` — panel's trailing edge lines up with trigger's trailing edge.\n *\n * `shift` is ignored for non-`\"start\"` alignments to avoid tugging against the\n * caller's translate.\n */\n alignCross?: \"start\" | \"center\" | \"end\";\n}\n\nexport interface UseFloatingResult<T extends HTMLElement> {\n /** Attach this to the trigger element. */\n triggerRef: React.RefObject<T>;\n /** Spread this onto the panel element. Already contains `position: fixed` + coords. */\n floatingStyle: React.CSSProperties;\n /** Resolved placement after flip logic — useful for arrow direction. */\n placement: Placement;\n}\n\n/**\n * Minimal floating-element positioning hook used by Tooltip / Popover / Select /\n * Cascader / ColorPicker. Designed to be paired with `createPortal(document.body)`\n * so overflow clipping from ancestors becomes a non-issue.\n *\n * Not a general-purpose `@floating-ui` replacement — it only covers flip + shift\n * relative to the viewport, which is what Lumina's overlays need.\n */\nexport function useFloating<T extends HTMLElement = HTMLElement>(\n opts: UseFloatingOptions\n): UseFloatingResult<T> {\n const triggerRef = React.useRef<T>(null);\n const preferred = opts.placement ?? \"bottom\";\n const gap = opts.gap ?? 8;\n const panelW = opts.panelWidth ?? 240;\n const panelH = opts.panelHeight ?? 300;\n const doShift = opts.shift !== false;\n const doFlip = opts.flip !== false;\n const matchW = !!opts.matchTriggerWidth;\n const align = opts.alignCross ?? \"start\";\n const open = opts.open;\n\n const [state, setState] = React.useState<{\n top: number;\n left: number;\n width?: number;\n placement: Placement;\n }>({ top: 0, left: 0, placement: preferred });\n\n React.useLayoutEffect(() => {\n if (!open) return;\n const update = () => {\n const el = triggerRef.current;\n if (!el) return;\n const rect = el.getBoundingClientRect();\n const w = matchW ? rect.width : panelW;\n const h = panelH;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const MARGIN = 8;\n\n const place = (p: Placement) => {\n switch (p) {\n case \"top\":\n return { top: rect.top - gap - h, left: rect.left };\n case \"right\":\n return { top: rect.top, left: rect.right + gap };\n case \"left\":\n return { top: rect.top, left: rect.left - gap - w };\n case \"bottom\":\n default:\n return { top: rect.bottom + gap, left: rect.left };\n }\n };\n\n const fits = (p: Placement, c: { top: number; left: number }) => {\n if (p === \"bottom\") return c.top + h <= vh - MARGIN;\n if (p === \"top\") return c.top >= MARGIN;\n if (p === \"right\") return c.left + w <= vw - MARGIN;\n if (p === \"left\") return c.left >= MARGIN;\n return true;\n };\n\n let resolved: Placement = preferred;\n let coords = place(resolved);\n\n if (doFlip && !fits(resolved, coords)) {\n const opp: Record<Placement, Placement> = {\n top: \"bottom\",\n bottom: \"top\",\n left: \"right\",\n right: \"left\",\n };\n const alt = opp[resolved];\n const altCoords = place(alt);\n if (fits(alt, altCoords)) {\n resolved = alt;\n coords = altCoords;\n }\n }\n\n // Cross-axis alignment replaces the cross coordinate with the trigger\n // midpoint / far edge; the paired CSS transform then visually aligns.\n if (align !== \"start\") {\n if (resolved === \"top\" || resolved === \"bottom\") {\n coords.left =\n align === \"center\" ? rect.left + rect.width / 2 : rect.right;\n } else {\n coords.top =\n align === \"center\" ? rect.top + rect.height / 2 : rect.bottom;\n }\n } else if (doShift) {\n if (resolved === \"bottom\" || resolved === \"top\") {\n coords.left = Math.max(MARGIN, Math.min(coords.left, vw - w - MARGIN));\n } else {\n coords.top = Math.max(MARGIN, Math.min(coords.top, vh - h - MARGIN));\n }\n }\n\n setState({\n top: coords.top,\n left: coords.left,\n width: matchW ? rect.width : undefined,\n placement: resolved,\n });\n };\n\n update();\n window.addEventListener(\"scroll\", update, true);\n window.addEventListener(\"resize\", update);\n return () => {\n window.removeEventListener(\"scroll\", update, true);\n window.removeEventListener(\"resize\", update);\n };\n }, [open, preferred, gap, panelW, panelH, doShift, doFlip, matchW]);\n\n let transform: string | undefined;\n if (align !== \"start\") {\n const cross = state.placement === \"top\" || state.placement === \"bottom\" ? \"X\" : \"Y\";\n const percent = align === \"center\" ? \"-50%\" : \"-100%\";\n transform = `translate${cross}(${percent})`;\n }\n\n const floatingStyle: React.CSSProperties = {\n position: \"fixed\",\n top: state.top,\n left: state.left,\n ...(state.width != null ? { width: state.width } : {}),\n ...(transform ? { transform } : {}),\n };\n\n return { triggerRef, floatingStyle, placement: state.placement };\n}\n"]}
@@ -1,10 +1,12 @@
1
1
  'use strict';
2
2
 
3
+ var chunkRZ2E3XEU_cjs = require('./chunk-RZ2E3XEU.cjs');
3
4
  var chunkYVO7XO4W_cjs = require('./chunk-YVO7XO4W.cjs');
4
5
  require('./tokens-HWQ7KWPG.css');
5
6
  require('./shared-NJHRNLRH.css');
6
- require('./Cascader-TO2QMSLJ.css');
7
+ require('./Cascader-DTRTTXC2.css');
7
8
  var React = require('react');
9
+ var reactDom = require('react-dom');
8
10
  var jsxRuntime = require('react/jsx-runtime');
9
11
 
10
12
  function _interopNamespace(e) {
@@ -41,10 +43,19 @@ var Cascader = ({
41
43
  const cur = isControlled ? value : inner;
42
44
  const [open, setOpen] = React__namespace.useState(false);
43
45
  const [path, setPath] = React__namespace.useState(cur);
44
- const ref = React__namespace.useRef(null);
46
+ const panelRef = React__namespace.useRef(null);
47
+ const { triggerRef: ref, floatingStyle } = chunkRZ2E3XEU_cjs.useFloating({
48
+ open,
49
+ placement: "bottom",
50
+ panelWidth: 520,
51
+ panelHeight: 260
52
+ });
45
53
  React__namespace.useEffect(() => {
46
54
  const h = (e) => {
47
- if (ref.current && !ref.current.contains(e.target)) setOpen(false);
55
+ const t = e.target;
56
+ if (ref.current?.contains(t)) return;
57
+ if (panelRef.current?.contains(t)) return;
58
+ setOpen(false);
48
59
  };
49
60
  document.addEventListener("mousedown", h);
50
61
  return () => document.removeEventListener("mousedown", h);
@@ -96,28 +107,31 @@ var Cascader = ({
96
107
  ]
97
108
  }
98
109
  ),
99
- open && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cascader-panel", children: columns.map((col, depth) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cascader-col", children: col.map((o) => {
100
- const isActive = path[depth] === o.value;
101
- const hasChildren = !!(o.children && o.children.length);
102
- return /* @__PURE__ */ jsxRuntime.jsxs(
103
- "button",
104
- {
105
- type: "button",
106
- className: `cascader-item ${isActive ? "active" : ""}`,
107
- disabled: o.disabled,
108
- onClick: () => pick(depth, o.value, hasChildren),
109
- children: [
110
- o.icon && /* @__PURE__ */ jsxRuntime.jsx(chunkYVO7XO4W_cjs.Icon, { name: o.icon, size: 13 }),
111
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: o.label }),
112
- hasChildren && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "chev", children: /* @__PURE__ */ jsxRuntime.jsx(chunkYVO7XO4W_cjs.Icon, { name: "chevRight", size: 12 }) })
113
- ]
114
- },
115
- o.value
116
- );
117
- }) }, depth)) })
110
+ open && typeof document !== "undefined" && reactDom.createPortal(
111
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: panelRef, className: "cascader-panel", style: floatingStyle, children: columns.map((col, depth) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "cascader-col", children: col.map((o) => {
112
+ const isActive = path[depth] === o.value;
113
+ const hasChildren = !!(o.children && o.children.length);
114
+ return /* @__PURE__ */ jsxRuntime.jsxs(
115
+ "button",
116
+ {
117
+ type: "button",
118
+ className: `cascader-item ${isActive ? "active" : ""}`,
119
+ disabled: o.disabled,
120
+ onClick: () => pick(depth, o.value, hasChildren),
121
+ children: [
122
+ o.icon && /* @__PURE__ */ jsxRuntime.jsx(chunkYVO7XO4W_cjs.Icon, { name: o.icon, size: 13 }),
123
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: o.label }),
124
+ hasChildren && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "chev", children: /* @__PURE__ */ jsxRuntime.jsx(chunkYVO7XO4W_cjs.Icon, { name: "chevRight", size: 12 }) })
125
+ ]
126
+ },
127
+ o.value
128
+ );
129
+ }) }, depth)) }),
130
+ document.body
131
+ )
118
132
  ] });
119
133
  };
120
134
 
121
135
  exports.Cascader = Cascader;
122
- //# sourceMappingURL=chunk-ZXM247EM.cjs.map
123
- //# sourceMappingURL=chunk-ZXM247EM.cjs.map
136
+ //# sourceMappingURL=chunk-TWBJCFEJ.cjs.map
137
+ //# sourceMappingURL=chunk-TWBJCFEJ.cjs.map