@open-mercato/ui 0.6.4-develop.4178.1.aad9ddaa95 → 0.6.4-develop.4210.1.d412061cfe

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 (92) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +14 -0
  3. package/dist/backend/DataTable.js +28 -62
  4. package/dist/backend/DataTable.js.map +2 -2
  5. package/dist/backend/detail/AttachmentMetadataDialog.js +1 -1
  6. package/dist/backend/detail/AttachmentMetadataDialog.js.map +2 -2
  7. package/dist/primitives/activity-feed.js +196 -0
  8. package/dist/primitives/activity-feed.js.map +7 -0
  9. package/dist/primitives/avatar.js +140 -14
  10. package/dist/primitives/avatar.js.map +3 -3
  11. package/dist/primitives/badge.js +94 -5
  12. package/dist/primitives/badge.js.map +2 -2
  13. package/dist/primitives/button-group.js +52 -0
  14. package/dist/primitives/button-group.js.map +7 -0
  15. package/dist/primitives/color-picker.js +520 -0
  16. package/dist/primitives/color-picker.js.map +7 -0
  17. package/dist/primitives/command-menu.js +355 -0
  18. package/dist/primitives/command-menu.js.map +7 -0
  19. package/dist/primitives/dialog.js +210 -35
  20. package/dist/primitives/dialog.js.map +2 -2
  21. package/dist/primitives/drawer.js +219 -0
  22. package/dist/primitives/drawer.js.map +7 -0
  23. package/dist/primitives/notification-feed.js +213 -0
  24. package/dist/primitives/notification-feed.js.map +7 -0
  25. package/dist/primitives/notification.js +23 -2
  26. package/dist/primitives/notification.js.map +2 -2
  27. package/dist/primitives/pagination.js +245 -0
  28. package/dist/primitives/pagination.js.map +7 -0
  29. package/dist/primitives/progress.js +178 -5
  30. package/dist/primitives/progress.js.map +2 -2
  31. package/dist/primitives/rating.js +174 -0
  32. package/dist/primitives/rating.js.map +7 -0
  33. package/dist/primitives/scroll-area.js +82 -0
  34. package/dist/primitives/scroll-area.js.map +7 -0
  35. package/dist/primitives/segmented-control.js +101 -0
  36. package/dist/primitives/segmented-control.js.map +7 -0
  37. package/dist/primitives/separator.js +103 -4
  38. package/dist/primitives/separator.js.map +2 -2
  39. package/dist/primitives/slider.js +115 -0
  40. package/dist/primitives/slider.js.map +7 -0
  41. package/dist/primitives/step-indicator.js +187 -0
  42. package/dist/primitives/step-indicator.js.map +7 -0
  43. package/dist/primitives/table.js +102 -10
  44. package/dist/primitives/table.js.map +2 -2
  45. package/dist/primitives/tabs.js +122 -14
  46. package/dist/primitives/tabs.js.map +2 -2
  47. package/dist/primitives/time-picker.js +9 -11
  48. package/dist/primitives/time-picker.js.map +2 -2
  49. package/package.json +8 -4
  50. package/src/backend/DataTable.tsx +43 -60
  51. package/src/backend/detail/AttachmentMetadataDialog.tsx +1 -1
  52. package/src/primitives/__tests__/activity-feed.test.tsx +216 -0
  53. package/src/primitives/__tests__/avatar.test.tsx +131 -0
  54. package/src/primitives/__tests__/badge.test.tsx +189 -0
  55. package/src/primitives/__tests__/button-group.test.tsx +117 -0
  56. package/src/primitives/__tests__/color-picker.test.tsx +589 -0
  57. package/src/primitives/__tests__/command-menu.test.tsx +231 -0
  58. package/src/primitives/__tests__/dialog.test.tsx +290 -0
  59. package/src/primitives/__tests__/drawer.test.tsx +264 -0
  60. package/src/primitives/__tests__/notification-feed.test.tsx +303 -0
  61. package/src/primitives/__tests__/notification.test.tsx +102 -2
  62. package/src/primitives/__tests__/pagination.test.tsx +268 -0
  63. package/src/primitives/__tests__/progress.test.tsx +222 -0
  64. package/src/primitives/__tests__/rating.test.tsx +164 -0
  65. package/src/primitives/__tests__/scroll-area.test.tsx +109 -0
  66. package/src/primitives/__tests__/segmented-control.test.tsx +129 -0
  67. package/src/primitives/__tests__/separator.test.tsx +143 -0
  68. package/src/primitives/__tests__/slider.test.tsx +86 -0
  69. package/src/primitives/__tests__/step-indicator.test.tsx +205 -0
  70. package/src/primitives/__tests__/table.test.tsx +199 -0
  71. package/src/primitives/__tests__/tabs.test.tsx +139 -0
  72. package/src/primitives/activity-feed.tsx +326 -0
  73. package/src/primitives/avatar.tsx +225 -22
  74. package/src/primitives/badge.tsx +141 -6
  75. package/src/primitives/button-group.tsx +100 -0
  76. package/src/primitives/color-picker.tsx +693 -0
  77. package/src/primitives/command-menu.tsx +503 -0
  78. package/src/primitives/dialog.tsx +315 -51
  79. package/src/primitives/drawer.tsx +338 -0
  80. package/src/primitives/notification-feed.tsx +358 -0
  81. package/src/primitives/notification.tsx +42 -2
  82. package/src/primitives/pagination.tsx +376 -0
  83. package/src/primitives/progress.tsx +267 -6
  84. package/src/primitives/rating.tsx +245 -0
  85. package/src/primitives/scroll-area.tsx +169 -0
  86. package/src/primitives/segmented-control.tsx +162 -0
  87. package/src/primitives/separator.tsx +163 -3
  88. package/src/primitives/slider.tsx +160 -0
  89. package/src/primitives/step-indicator.tsx +287 -0
  90. package/src/primitives/table.tsx +142 -11
  91. package/src/primitives/tabs.tsx +174 -12
  92. package/src/primitives/time-picker.tsx +9 -11
@@ -0,0 +1,520 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
5
+ import { Pipette, Plus, Trash2 } from "lucide-react";
6
+ import { cva } from "class-variance-authority";
7
+ import { cn } from "@open-mercato/shared/lib/utils";
8
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
9
+ const COLOR_PICKER_DEFAULT_SWATCHES = [
10
+ "#71777C",
11
+ // Gray
12
+ "#6366F1",
13
+ // Blue (= DS OM accent-indigo)
14
+ "#F59E0B",
15
+ // Orange
16
+ "#EF4343",
17
+ // Red
18
+ "#22C55E",
19
+ // Green
20
+ "#F6B51E",
21
+ // Yellow (= Rating amber)
22
+ "#7D52F3",
23
+ // Purple
24
+ "#47C2FF",
25
+ // Sky
26
+ "#FB4BA3",
27
+ // Pink
28
+ "#22D3BB"
29
+ // Teal
30
+ ];
31
+ const HEX_PATTERN_3 = /^#?[0-9a-fA-F]{3}$/;
32
+ const HEX_PATTERN_6 = /^#?[0-9a-fA-F]{6}$/;
33
+ function normalizeHex(input) {
34
+ const trimmed = input.trim();
35
+ if (HEX_PATTERN_6.test(trimmed)) {
36
+ return ("#" + trimmed.replace(/^#/, "")).toUpperCase();
37
+ }
38
+ if (HEX_PATTERN_3.test(trimmed)) {
39
+ const stripped = trimmed.replace(/^#/, "");
40
+ return ("#" + stripped[0] + stripped[0] + stripped[1] + stripped[1] + stripped[2] + stripped[2]).toUpperCase();
41
+ }
42
+ return null;
43
+ }
44
+ function hexToRgb(hex) {
45
+ const normalized = normalizeHex(hex);
46
+ if (!normalized) return null;
47
+ const stripped = normalized.replace(/^#/, "");
48
+ return {
49
+ r: parseInt(stripped.slice(0, 2), 16),
50
+ g: parseInt(stripped.slice(2, 4), 16),
51
+ b: parseInt(stripped.slice(4, 6), 16)
52
+ };
53
+ }
54
+ function rgbToHsl(r, g, b) {
55
+ const rN = r / 255;
56
+ const gN = g / 255;
57
+ const bN = b / 255;
58
+ const max = Math.max(rN, gN, bN);
59
+ const min = Math.min(rN, gN, bN);
60
+ const delta = max - min;
61
+ let h = 0;
62
+ let s = 0;
63
+ const l = (max + min) / 2;
64
+ if (delta !== 0) {
65
+ s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min);
66
+ if (max === rN) h = (gN - bN) / delta + (gN < bN ? 6 : 0);
67
+ else if (max === gN) h = (bN - rN) / delta + 2;
68
+ else h = (rN - gN) / delta + 4;
69
+ h /= 6;
70
+ }
71
+ return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) };
72
+ }
73
+ function hslToRgb(h, s, l) {
74
+ const sN = s / 100;
75
+ const lN = l / 100;
76
+ const k = (n) => (n + h / 30) % 12;
77
+ const a = sN * Math.min(lN, 1 - lN);
78
+ const f = (n) => lN - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
79
+ return {
80
+ r: Math.round(255 * f(0)),
81
+ g: Math.round(255 * f(8)),
82
+ b: Math.round(255 * f(4))
83
+ };
84
+ }
85
+ function rgbToHex(r, g, b) {
86
+ return "#" + [r, g, b].map((v) => v.toString(16).padStart(2, "0")).join("").toUpperCase();
87
+ }
88
+ function hexToHueDegrees(hex) {
89
+ const rgb = hexToRgb(hex);
90
+ if (!rgb) return 0;
91
+ return rgbToHsl(rgb.r, rgb.g, rgb.b).h;
92
+ }
93
+ const triggerVariants = cva(
94
+ "inline-flex items-center gap-2 rounded-md border border-input bg-background px-2.5 py-1.5 text-sm shadow-xs outline-none transition-colors hover:bg-muted/40 focus-visible:shadow-focus disabled:cursor-not-allowed disabled:opacity-60",
95
+ {
96
+ variants: {
97
+ size: {
98
+ sm: "h-8",
99
+ default: "h-9"
100
+ }
101
+ },
102
+ defaultVariants: { size: "default" }
103
+ }
104
+ );
105
+ const swatchVariants = cva(
106
+ "inline-flex size-6 items-center justify-center rounded-full outline-none focus-visible:shadow-focus disabled:cursor-not-allowed disabled:opacity-50"
107
+ );
108
+ const swatchDotVariants = cva(
109
+ // Subtle hairline border keeps very-light / white swatches visible on
110
+ // a white popover background. The Figma `Color Dots [1.1]` ellipse
111
+ // does NOT carry a border by default (only on Selected, via an inset
112
+ // white stroke), but in practice palettes routinely include #FFFFFF
113
+ // and other near-white values that vanish without a 1px outline.
114
+ // We use `border-foreground/10` so the outline stays invisible on
115
+ // saturated colors and only "appears" on light values.
116
+ "inline-block size-4 rounded-full border border-foreground/10 transition-transform group-enabled/swatch:group-hover/swatch:scale-[0.875]",
117
+ {
118
+ variants: {
119
+ selected: {
120
+ true: "ring-2 ring-inset ring-background",
121
+ false: ""
122
+ }
123
+ },
124
+ defaultVariants: { selected: false }
125
+ }
126
+ );
127
+ const ColorPicker = React.forwardRef(
128
+ ({
129
+ className,
130
+ value,
131
+ onChange,
132
+ swatches: swatchesProp,
133
+ defaultSwatches,
134
+ persistKey,
135
+ onAddSwatch,
136
+ allowCustom = true,
137
+ size,
138
+ disabled,
139
+ enableEyedropper = true,
140
+ onRemoveColor,
141
+ onEditSavedColors,
142
+ showOpacity = false,
143
+ chooseLabel = "Choose color",
144
+ savedLabel = "Saved colors",
145
+ addLabel = "Add new color",
146
+ editLabel = "Edit",
147
+ removeAriaLabel = "Remove color",
148
+ ...props
149
+ }, ref) => {
150
+ const t = useT();
151
+ const normalizedValue = React.useMemo(() => normalizeHex(value) ?? value, [value]);
152
+ const [hexInput, setHexInput] = React.useState(normalizedValue);
153
+ const [hexError, setHexError] = React.useState(null);
154
+ const [open, setOpen] = React.useState(false);
155
+ const [eyedropperSupported, setEyedropperSupported] = React.useState(false);
156
+ const initialUncontrolled = React.useMemo(
157
+ () => [...defaultSwatches ?? COLOR_PICKER_DEFAULT_SWATCHES],
158
+ [defaultSwatches]
159
+ );
160
+ const [internalSwatches, setInternalSwatches] = React.useState(initialUncontrolled);
161
+ React.useEffect(() => {
162
+ if (!persistKey || typeof window === "undefined") return;
163
+ try {
164
+ const raw = window.localStorage.getItem(persistKey);
165
+ if (!raw) return;
166
+ const parsed = JSON.parse(raw);
167
+ if (Array.isArray(parsed) && parsed.every((c) => typeof c === "string" && normalizeHex(c) !== null)) {
168
+ setInternalSwatches(parsed.map((c) => normalizeHex(c)));
169
+ }
170
+ } catch {
171
+ }
172
+ }, [persistKey]);
173
+ const isControlled = swatchesProp !== void 0;
174
+ const effectiveSwatches = isControlled ? swatchesProp : internalSwatches;
175
+ const persistSwatches = React.useCallback(
176
+ (next) => {
177
+ if (!persistKey || typeof window === "undefined") return;
178
+ try {
179
+ window.localStorage.setItem(persistKey, JSON.stringify(next));
180
+ } catch {
181
+ }
182
+ },
183
+ [persistKey]
184
+ );
185
+ const handleAddSwatch = React.useCallback(
186
+ (color) => {
187
+ const normalized = normalizeHex(color) ?? color;
188
+ if (!isControlled) {
189
+ setInternalSwatches((prev) => {
190
+ if (prev.some((c) => c.toUpperCase() === normalized.toUpperCase())) return prev;
191
+ const next = [...prev, normalized];
192
+ persistSwatches(next);
193
+ return next;
194
+ });
195
+ }
196
+ onAddSwatch?.(normalized);
197
+ },
198
+ [isControlled, persistSwatches, onAddSwatch]
199
+ );
200
+ const handleRemoveColor = React.useCallback(
201
+ (color) => {
202
+ const normalized = normalizeHex(color) ?? color;
203
+ if (!isControlled) {
204
+ setInternalSwatches((prev) => {
205
+ const next = prev.filter((c) => c.toUpperCase() !== normalized.toUpperCase());
206
+ persistSwatches(next);
207
+ return next;
208
+ });
209
+ }
210
+ onRemoveColor?.(normalized);
211
+ },
212
+ [isControlled, persistSwatches, onRemoveColor]
213
+ );
214
+ const showAddButton = Boolean(onAddSwatch) || Boolean(persistKey);
215
+ const showRemoveButton = Boolean(onRemoveColor) || Boolean(persistKey);
216
+ React.useEffect(() => {
217
+ if (typeof window === "undefined") return;
218
+ setEyedropperSupported(typeof window.EyeDropper === "function");
219
+ }, []);
220
+ React.useEffect(() => {
221
+ if (!open) {
222
+ setHexInput(normalizedValue);
223
+ setHexError(null);
224
+ }
225
+ }, [normalizedValue, open]);
226
+ const commitHex = React.useCallback(
227
+ (raw) => {
228
+ const next = normalizeHex(raw);
229
+ if (next === null) {
230
+ setHexError(t("ui.colorPicker.error.invalidHex", "Invalid hex"));
231
+ return;
232
+ }
233
+ setHexError(null);
234
+ setHexInput(next);
235
+ if (next !== normalizedValue) onChange(next);
236
+ },
237
+ [normalizedValue, onChange, t]
238
+ );
239
+ const handleHueChange = React.useCallback(
240
+ (hueDeg) => {
241
+ const rgb = hslToRgb(hueDeg, 100, 50);
242
+ onChange(rgbToHex(rgb.r, rgb.g, rgb.b));
243
+ },
244
+ [onChange]
245
+ );
246
+ const handleEyedropper = React.useCallback(async () => {
247
+ if (!eyedropperSupported) return;
248
+ const Ctor = window.EyeDropper;
249
+ if (!Ctor) return;
250
+ try {
251
+ const dropper = new Ctor();
252
+ const result = await dropper.open();
253
+ if (result && typeof result.sRGBHex === "string") {
254
+ const next = normalizeHex(result.sRGBHex);
255
+ if (next) onChange(next);
256
+ }
257
+ } catch {
258
+ }
259
+ }, [eyedropperSupported, onChange]);
260
+ const currentHue = React.useMemo(() => hexToHueDegrees(normalizedValue), [normalizedValue]);
261
+ return /* @__PURE__ */ jsxs(PopoverPrimitive.Root, { open, onOpenChange: setOpen, children: [
262
+ /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
263
+ "button",
264
+ {
265
+ ref,
266
+ type: "button",
267
+ disabled,
268
+ "data-slot": "color-picker-trigger",
269
+ className: cn(triggerVariants({ size }), className),
270
+ ...props,
271
+ children: [
272
+ /* @__PURE__ */ jsx(
273
+ "span",
274
+ {
275
+ "data-slot": "color-picker-preview",
276
+ "aria-hidden": "true",
277
+ className: "inline-block size-4 shrink-0 rounded-full border border-border/30",
278
+ style: { backgroundColor: normalizedValue }
279
+ }
280
+ ),
281
+ /* @__PURE__ */ jsx("span", { className: "font-mono uppercase tracking-tight", children: normalizedValue })
282
+ ]
283
+ }
284
+ ) }),
285
+ /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
286
+ PopoverPrimitive.Content,
287
+ {
288
+ sideOffset: 6,
289
+ align: "start",
290
+ "data-slot": "color-picker-popover",
291
+ className: cn(
292
+ "z-popover w-80 rounded-xl border border-input bg-popover p-0 text-popover-foreground shadow-md outline-none",
293
+ "data-[state=open]:animate-in data-[state=closed]:animate-out",
294
+ "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
295
+ ),
296
+ children: [
297
+ /* @__PURE__ */ jsxs(
298
+ "div",
299
+ {
300
+ "data-slot": "color-picker-section-choose",
301
+ className: "space-y-2.5 px-5 pt-4 pb-5",
302
+ children: [
303
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
304
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: chooseLabel }),
305
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-xs uppercase tracking-tight text-muted-foreground/80", children: normalizedValue })
306
+ ] }),
307
+ /* @__PURE__ */ jsx(
308
+ "input",
309
+ {
310
+ type: "range",
311
+ min: 0,
312
+ max: 360,
313
+ step: 1,
314
+ value: currentHue,
315
+ disabled,
316
+ onChange: (event) => handleHueChange(Number(event.target.value)),
317
+ "data-slot": "color-picker-hue-slider",
318
+ "aria-label": `${chooseLabel} hue`,
319
+ className: cn(
320
+ "block h-3 w-full cursor-pointer appearance-none rounded-full outline-none",
321
+ // Native range styling. The track is the gradient itself.
322
+ "[background-image:linear-gradient(to_right,hsl(0,100%,50%),hsl(60,100%,50%),hsl(120,100%,50%),hsl(180,100%,50%),hsl(240,100%,50%),hsl(300,100%,50%),hsl(360,100%,50%))]",
323
+ // Thumb: small white pill with shadow per Figma.
324
+ "[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:size-3 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-background [&::-webkit-slider-thumb]:shadow-sm",
325
+ "[&::-moz-range-thumb]:size-3 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:bg-background [&::-moz-range-thumb]:shadow-sm",
326
+ "focus-visible:shadow-focus",
327
+ "disabled:cursor-not-allowed disabled:opacity-50"
328
+ )
329
+ }
330
+ )
331
+ ]
332
+ }
333
+ ),
334
+ /* @__PURE__ */ jsx("div", { className: "h-px w-full bg-border/60", "aria-hidden": "true" }),
335
+ allowCustom ? /* @__PURE__ */ jsxs(
336
+ "div",
337
+ {
338
+ "data-slot": "color-picker-section-input",
339
+ className: "flex w-full min-w-0 items-center gap-2.5 px-5 py-4",
340
+ children: [
341
+ /* @__PURE__ */ jsxs("div", { className: "flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-input bg-background px-2 shadow-xs", children: [
342
+ /* @__PURE__ */ jsx(
343
+ "span",
344
+ {
345
+ "aria-hidden": "true",
346
+ "data-slot": "color-picker-current-dot",
347
+ className: "inline-block size-4 shrink-0 rounded-full border border-foreground/10",
348
+ style: { backgroundColor: normalizedValue }
349
+ }
350
+ ),
351
+ /* @__PURE__ */ jsx(
352
+ "input",
353
+ {
354
+ type: "text",
355
+ "data-slot": "color-picker-hex",
356
+ value: hexInput,
357
+ onChange: (event) => {
358
+ setHexInput(event.target.value);
359
+ setHexError(null);
360
+ },
361
+ onBlur: (event) => commitHex(event.target.value),
362
+ onKeyDown: (event) => {
363
+ if (event.key === "Enter") {
364
+ event.preventDefault();
365
+ commitHex(event.currentTarget.value);
366
+ } else if (event.key === "Escape") {
367
+ event.preventDefault();
368
+ setHexInput(normalizedValue);
369
+ setHexError(null);
370
+ setOpen(false);
371
+ }
372
+ },
373
+ className: cn(
374
+ "h-full min-w-0 flex-1 bg-transparent font-mono text-sm uppercase tracking-tight outline-none",
375
+ "placeholder:text-muted-foreground",
376
+ hexError && "text-destructive"
377
+ )
378
+ }
379
+ ),
380
+ showOpacity ? /* @__PURE__ */ jsx(
381
+ "span",
382
+ {
383
+ "data-slot": "color-picker-opacity",
384
+ "aria-hidden": "true",
385
+ className: "shrink-0 font-mono text-xs text-muted-foreground tabular-nums",
386
+ children: "100%"
387
+ }
388
+ ) : null
389
+ ] }),
390
+ !showRemoveButton && enableEyedropper && eyedropperSupported ? /* @__PURE__ */ jsx(
391
+ "button",
392
+ {
393
+ type: "button",
394
+ onClick: handleEyedropper,
395
+ "data-slot": "color-picker-eyedropper",
396
+ "aria-label": t("ui.colorPicker.eyedropper.ariaLabel", "Pick color from screen"),
397
+ className: cn(
398
+ "inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-input bg-background text-muted-foreground shadow-xs transition-colors",
399
+ "hover:bg-muted/40 hover:text-foreground",
400
+ "focus-visible:shadow-focus focus-visible:outline-none"
401
+ ),
402
+ children: /* @__PURE__ */ jsx(Pipette, { "aria-hidden": "true", className: "size-4" })
403
+ }
404
+ ) : null,
405
+ showRemoveButton ? /* @__PURE__ */ jsx(
406
+ "button",
407
+ {
408
+ type: "button",
409
+ onClick: () => handleRemoveColor(normalizedValue),
410
+ "data-slot": "color-picker-remove",
411
+ "aria-label": removeAriaLabel,
412
+ className: cn(
413
+ "inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-input bg-background text-muted-foreground shadow-xs transition-colors",
414
+ "hover:bg-status-error-bg hover:text-status-error-text hover:border-status-error-border",
415
+ "focus-visible:shadow-focus focus-visible:outline-none"
416
+ ),
417
+ children: /* @__PURE__ */ jsx(Trash2, { "aria-hidden": "true", className: "size-4" })
418
+ }
419
+ ) : null
420
+ ]
421
+ }
422
+ ) : null,
423
+ hexError ? /* @__PURE__ */ jsx(
424
+ "p",
425
+ {
426
+ "data-slot": "color-picker-error",
427
+ className: "px-5 pb-3 -mt-2 text-xs text-status-error-text",
428
+ children: hexError
429
+ }
430
+ ) : null,
431
+ /* @__PURE__ */ jsx("div", { className: "h-px w-full bg-border/60", "aria-hidden": "true" }),
432
+ /* @__PURE__ */ jsxs("div", { "data-slot": "color-picker-section-saved", className: "px-5 pt-4 pb-5", children: [
433
+ /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center justify-between", children: [
434
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: savedLabel }),
435
+ onEditSavedColors ? /* @__PURE__ */ jsx(
436
+ "button",
437
+ {
438
+ type: "button",
439
+ onClick: () => onEditSavedColors(),
440
+ "data-slot": "color-picker-edit",
441
+ className: cn(
442
+ "text-sm font-medium text-accent-indigo outline-none transition-colors",
443
+ "hover:underline focus-visible:underline",
444
+ "focus-visible:shadow-focus rounded-sm"
445
+ ),
446
+ children: editLabel
447
+ }
448
+ ) : null
449
+ ] }),
450
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3", role: "radiogroup", children: effectiveSwatches.map((swatch) => {
451
+ const normalized = normalizeHex(swatch) ?? swatch;
452
+ const selected = normalized.toUpperCase() === normalizedValue.toUpperCase();
453
+ return /* @__PURE__ */ jsxs(
454
+ "button",
455
+ {
456
+ type: "button",
457
+ role: "radio",
458
+ "aria-checked": selected,
459
+ "aria-label": normalized,
460
+ "data-slot": "color-picker-swatch",
461
+ "data-state": selected ? "on" : "off",
462
+ className: cn(swatchVariants(), "group/swatch"),
463
+ onClick: () => {
464
+ onChange(normalized);
465
+ if (!allowCustom && !showAddButton) setOpen(false);
466
+ },
467
+ children: [
468
+ /* @__PURE__ */ jsx(
469
+ "span",
470
+ {
471
+ "aria-hidden": "true",
472
+ "data-slot": "color-picker-swatch-dot",
473
+ className: swatchDotVariants({ selected }),
474
+ style: { backgroundColor: normalized }
475
+ }
476
+ ),
477
+ selected ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Selected" }) : null
478
+ ]
479
+ },
480
+ normalized
481
+ );
482
+ }) })
483
+ ] }),
484
+ showAddButton ? /* @__PURE__ */ jsxs(Fragment, { children: [
485
+ /* @__PURE__ */ jsx("div", { className: "h-px w-full bg-border/60", "aria-hidden": "true" }),
486
+ /* @__PURE__ */ jsxs(
487
+ "button",
488
+ {
489
+ type: "button",
490
+ onClick: () => handleAddSwatch(normalizedValue),
491
+ "data-slot": "color-picker-add",
492
+ className: cn(
493
+ "flex w-full items-center gap-1.5 rounded-b-xl px-4 py-3.5 text-left text-sm text-muted-foreground outline-none transition-colors",
494
+ "hover:bg-muted/40 hover:text-foreground",
495
+ "focus-visible:shadow-focus focus-visible:outline-none"
496
+ ),
497
+ children: [
498
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": "true", className: "size-5 text-muted-foreground/70" }),
499
+ /* @__PURE__ */ jsx("span", { children: addLabel })
500
+ ]
501
+ }
502
+ )
503
+ ] }) : null,
504
+ /* @__PURE__ */ jsx(PopoverPrimitive.Arrow, { className: "fill-popover stroke-input" })
505
+ ]
506
+ }
507
+ ) })
508
+ ] });
509
+ }
510
+ );
511
+ ColorPicker.displayName = "ColorPicker";
512
+ export {
513
+ COLOR_PICKER_DEFAULT_SWATCHES,
514
+ ColorPicker,
515
+ swatchDotVariants as colorPickerSwatchDotVariants,
516
+ swatchVariants as colorPickerSwatchVariants,
517
+ triggerVariants as colorPickerTriggerVariants,
518
+ normalizeHex
519
+ };
520
+ //# sourceMappingURL=color-picker.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/primitives/color-picker.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport * as PopoverPrimitive from '@radix-ui/react-popover'\nimport { Pipette, Plus, Trash2 } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\n\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\n// Local types for the experimental EyeDropper API (no DOM lib coverage yet).\ninterface EyeDropperResult { sRGBHex: string }\ninterface EyeDropperAPI { open(): Promise<EyeDropperResult> }\ninterface WindowWithEyeDropper extends Window { EyeDropper?: new () => EyeDropperAPI }\n\n/**\n * Color picker per Figma `Color Picker` frame (DS Open Mercato\n * `167184:38583`, doc page `553:22078`). 4-section layout 316\u00D7334:\n *\n * 1. Choose Color \u2014 header row (\"Choose color\" label + hex preview\n * on the right) + a single pill hue slider\n * (gradient rainbow, draggable white thumb).\n * 2. Input \u2014 hex input field + eyedropper button (Sip).\n * 3. Saved Colors \u2014 title + row of swatch dots (24\u00D724, rounded-full).\n * 4. Action \u2014 \"+ Add new color\" footer button (optional).\n *\n * No 2D HSV spectrum, no opacity slider, no format dropdown \u2014 those\n * belong to a heavier picker layout that's not in this DS source.\n * Implementation is vanilla (no `react-colorful`): hue is a native\n * `<input type=\"range\">` styled as a gradient pill, hex \u2192 RGB \u2192 HSL\n * conversion done inline so we can keep dependencies minimal.\n *\n * ```tsx\n * const [color, setColor] = React.useState('#6366F1')\n *\n * // Basic\n * <ColorPicker value={color} onChange={setColor} />\n *\n * // Saved-colors editor (user can append the current color)\n * const [swatches, setSwatches] = React.useState<string[]>([])\n * <ColorPicker\n * value={color}\n * onChange={setColor}\n * swatches={swatches}\n * onAddSwatch={(c) => setSwatches([...swatches, c])}\n * />\n *\n * // Locked palette \u2014 no hex input, no add button\n * <ColorPicker\n * value={color}\n * onChange={setColor}\n * swatches={['#22C55E', '#F59E0B', '#EF4343']}\n * allowCustom={false}\n * />\n * ```\n */\n\n/**\n * Default swatch list anchored on the Figma `Color Dots [1.1]`\n * component set (DS OM `3365:22464`) \u2014 10 brand-curated colors that\n * also drive the Tag colors. Kept inline so the primitive ships with\n * a sensible default; consumers can override via `swatches`.\n */\nexport const COLOR_PICKER_DEFAULT_SWATCHES: readonly string[] = [\n '#71777C', // Gray\n '#6366F1', // Blue (= DS OM accent-indigo)\n '#F59E0B', // Orange\n '#EF4343', // Red\n '#22C55E', // Green\n '#F6B51E', // Yellow (= Rating amber)\n '#7D52F3', // Purple\n '#47C2FF', // Sky\n '#FB4BA3', // Pink\n '#22D3BB', // Teal\n]\n\nconst HEX_PATTERN_3 = /^#?[0-9a-fA-F]{3}$/\nconst HEX_PATTERN_6 = /^#?[0-9a-fA-F]{6}$/\n\nexport function normalizeHex(input: string): string | null {\n const trimmed = input.trim()\n if (HEX_PATTERN_6.test(trimmed)) {\n return ('#' + trimmed.replace(/^#/, '')).toUpperCase()\n }\n if (HEX_PATTERN_3.test(trimmed)) {\n const stripped = trimmed.replace(/^#/, '')\n return ('#' + stripped[0] + stripped[0] + stripped[1] + stripped[1] + stripped[2] + stripped[2]).toUpperCase()\n }\n return null\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n const normalized = normalizeHex(hex)\n if (!normalized) return null\n const stripped = normalized.replace(/^#/, '')\n return {\n r: parseInt(stripped.slice(0, 2), 16),\n g: parseInt(stripped.slice(2, 4), 16),\n b: parseInt(stripped.slice(4, 6), 16),\n }\n}\n\nfunction rgbToHsl(r: number, g: number, b: number): { h: number; s: number; l: number } {\n const rN = r / 255\n const gN = g / 255\n const bN = b / 255\n const max = Math.max(rN, gN, bN)\n const min = Math.min(rN, gN, bN)\n const delta = max - min\n let h = 0\n let s = 0\n const l = (max + min) / 2\n if (delta !== 0) {\n s = l > 0.5 ? delta / (2 - max - min) : delta / (max + min)\n if (max === rN) h = ((gN - bN) / delta + (gN < bN ? 6 : 0))\n else if (max === gN) h = (bN - rN) / delta + 2\n else h = (rN - gN) / delta + 4\n h /= 6\n }\n return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) }\n}\n\nfunction hslToRgb(h: number, s: number, l: number): { r: number; g: number; b: number } {\n const sN = s / 100\n const lN = l / 100\n const k = (n: number) => (n + h / 30) % 12\n const a = sN * Math.min(lN, 1 - lN)\n const f = (n: number) => lN - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)))\n return {\n r: Math.round(255 * f(0)),\n g: Math.round(255 * f(8)),\n b: Math.round(255 * f(4)),\n }\n}\n\nfunction rgbToHex(r: number, g: number, b: number): string {\n return (\n '#' +\n [r, g, b]\n .map((v) => v.toString(16).padStart(2, '0'))\n .join('')\n .toUpperCase()\n )\n}\n\n/**\n * Extract a pure-hue degree (0..360) from a hex color, ignoring its\n * saturation / lightness. Used to position the hue-slider thumb when\n * the controlled `value` changes via swatch click or hex input.\n */\nfunction hexToHueDegrees(hex: string): number {\n const rgb = hexToRgb(hex)\n if (!rgb) return 0\n return rgbToHsl(rgb.r, rgb.g, rgb.b).h\n}\n\nconst triggerVariants = cva(\n 'inline-flex items-center gap-2 rounded-md border border-input bg-background px-2.5 py-1.5 text-sm shadow-xs outline-none transition-colors ' +\n 'hover:bg-muted/40 ' +\n 'focus-visible:shadow-focus ' +\n 'disabled:cursor-not-allowed disabled:opacity-60',\n {\n variants: {\n size: {\n sm: 'h-8',\n default: 'h-9',\n },\n },\n defaultVariants: { size: 'default' },\n },\n)\n\nconst swatchVariants = cva(\n 'inline-flex size-6 items-center justify-center rounded-full outline-none ' +\n 'focus-visible:shadow-focus ' +\n 'disabled:cursor-not-allowed disabled:opacity-50',\n)\n\nconst swatchDotVariants = cva(\n // Subtle hairline border keeps very-light / white swatches visible on\n // a white popover background. The Figma `Color Dots [1.1]` ellipse\n // does NOT carry a border by default (only on Selected, via an inset\n // white stroke), but in practice palettes routinely include #FFFFFF\n // and other near-white values that vanish without a 1px outline.\n // We use `border-foreground/10` so the outline stays invisible on\n // saturated colors and only \"appears\" on light values.\n 'inline-block size-4 rounded-full border border-foreground/10 transition-transform ' +\n 'group-enabled/swatch:group-hover/swatch:scale-[0.875]',\n {\n variants: {\n selected: {\n true: 'ring-2 ring-inset ring-background',\n false: '',\n },\n },\n defaultVariants: { selected: false },\n },\n)\n\nexport type ColorPickerProps = Omit<\n React.HTMLAttributes<HTMLButtonElement>,\n 'value' | 'onChange'\n> &\n VariantProps<typeof triggerVariants> & {\n /** Current selected color, `#RRGGBB`. */\n value: string\n /** Fired when the user picks a swatch, drags the hue slider, or\n * commits a hex input. */\n onChange: (next: string) => void\n /** Optional palette (\"Saved colors\" row). When provided, the primitive\n * runs in **controlled mode** \u2014 the consumer owns the list. When\n * omitted (and `persistKey` is also absent) the primitive falls back\n * to `COLOR_PICKER_DEFAULT_SWATCHES` read-only. */\n swatches?: readonly string[]\n /** Initial palette for the uncontrolled / persisted mode. Used when\n * `swatches` is omitted. Defaults to `COLOR_PICKER_DEFAULT_SWATCHES`. */\n defaultSwatches?: readonly string[]\n /** When set, the primitive switches to **persisted mode**: hydrates\n * the swatch list from `localStorage[persistKey]` on mount, and\n * auto-saves after every `onAddSwatch` / `onRemoveColor`. Pair with\n * no `swatches` prop. The \"+ Add new color\" footer and trash button\n * render automatically when `persistKey` is provided (no need to\n * wire `onAddSwatch` / `onRemoveColor` callbacks for the buttons to\n * appear \u2014 they still fire as notification callbacks). */\n persistKey?: string\n /** Optional callback for the \"+ Add new color\" footer button. When\n * omitted, the button is hidden \u2014 unless `persistKey` is set, in\n * which case the primitive renders + handles the button itself. */\n onAddSwatch?: (next: string) => void\n /** Allow free-form hex input. Default `true`. */\n allowCustom?: boolean\n /** Block the popover when true; trigger dims. */\n disabled?: boolean\n /** Optional label for screen readers. */\n 'aria-label'?: string\n /** Show the eyedropper button in the input row. Default `true`. The\n * button auto-hides when `window.EyeDropper` is unavailable. */\n enableEyedropper?: boolean\n /** Optional callback. When provided, renders a trash icon button\n * after the hex container; click fires with the current value\n * (consumer decides whether to remove from `swatches`, clear the\n * field, or otherwise act). */\n onRemoveColor?: (current: string) => void\n /** Optional callback. When provided, renders an \"Edit\" link button\n * at the right of the \"Saved colors\" header. Click fires this\n * callback so the consumer can open a separate management UI. */\n onEditSavedColors?: () => void\n /** Show an opacity percentage badge inside the hex container.\n * Default `false`. v5 always shows 100% \u2014 surface kept for\n * forward-compatibility with an alpha-aware follow-up release. */\n showOpacity?: boolean\n /** Section title above the hue slider. Default `\"Choose color\"`. */\n chooseLabel?: string\n /** Section title above the swatch row. Default `\"Saved colors\"`. */\n savedLabel?: string\n /** Label for the \"+ Add new color\" footer. Default `\"Add new color\"`. */\n addLabel?: string\n /** Label for the \"Edit\" link in the saved-colors header. Default `\"Edit\"`. */\n editLabel?: string\n /** ARIA label for the trash button. Default `\"Remove color\"`. */\n removeAriaLabel?: string\n }\n\nexport const ColorPicker = React.forwardRef<HTMLButtonElement, ColorPickerProps>(\n (\n {\n className,\n value,\n onChange,\n swatches: swatchesProp,\n defaultSwatches,\n persistKey,\n onAddSwatch,\n allowCustom = true,\n size,\n disabled,\n enableEyedropper = true,\n onRemoveColor,\n onEditSavedColors,\n showOpacity = false,\n chooseLabel = 'Choose color',\n savedLabel = 'Saved colors',\n addLabel = 'Add new color',\n editLabel = 'Edit',\n removeAriaLabel = 'Remove color',\n ...props\n },\n ref,\n ) => {\n const t = useT()\n const normalizedValue = React.useMemo(() => normalizeHex(value) ?? value, [value])\n const [hexInput, setHexInput] = React.useState(normalizedValue)\n const [hexError, setHexError] = React.useState<string | null>(null)\n const [open, setOpen] = React.useState(false)\n const [eyedropperSupported, setEyedropperSupported] = React.useState(false)\n\n // Swatches state cascade:\n // 1. `swatches` prop \u2192 controlled, primitive never mutates the list.\n // 2. `persistKey` set \u2192 uncontrolled + auto-save to localStorage.\n // 3. otherwise \u2192 uncontrolled in-memory only (lost on remount).\n const initialUncontrolled = React.useMemo(\n () => [...(defaultSwatches ?? COLOR_PICKER_DEFAULT_SWATCHES)],\n [defaultSwatches],\n )\n const [internalSwatches, setInternalSwatches] = React.useState<string[]>(initialUncontrolled)\n\n // Hydrate from localStorage on mount when persistKey is set. We do this\n // in an effect (not initialState) so SSR rendering matches the initial\n // hydration pass \u2014 otherwise React warns about mismatched output.\n React.useEffect(() => {\n if (!persistKey || typeof window === 'undefined') return\n try {\n const raw = window.localStorage.getItem(persistKey)\n if (!raw) return\n const parsed = JSON.parse(raw)\n if (\n Array.isArray(parsed) &&\n parsed.every((c) => typeof c === 'string' && normalizeHex(c) !== null)\n ) {\n setInternalSwatches(parsed.map((c) => normalizeHex(c) as string))\n }\n } catch {\n // Corrupt JSON or storage disabled \u2014 fall through to the in-memory\n // default. No-op, no flash to user.\n }\n }, [persistKey])\n\n const isControlled = swatchesProp !== undefined\n const effectiveSwatches = isControlled ? swatchesProp! : internalSwatches\n\n const persistSwatches = React.useCallback(\n (next: string[]) => {\n if (!persistKey || typeof window === 'undefined') return\n try {\n window.localStorage.setItem(persistKey, JSON.stringify(next))\n } catch {\n // Storage quota exceeded or disabled \u2014 silent no-op.\n }\n },\n [persistKey],\n )\n\n const handleAddSwatch = React.useCallback(\n (color: string) => {\n const normalized = normalizeHex(color) ?? color\n if (!isControlled) {\n setInternalSwatches((prev) => {\n if (prev.some((c) => c.toUpperCase() === normalized.toUpperCase())) return prev\n const next = [...prev, normalized]\n persistSwatches(next)\n return next\n })\n }\n onAddSwatch?.(normalized)\n },\n [isControlled, persistSwatches, onAddSwatch],\n )\n\n const handleRemoveColor = React.useCallback(\n (color: string) => {\n const normalized = normalizeHex(color) ?? color\n if (!isControlled) {\n setInternalSwatches((prev) => {\n const next = prev.filter((c) => c.toUpperCase() !== normalized.toUpperCase())\n persistSwatches(next)\n return next\n })\n }\n onRemoveColor?.(normalized)\n },\n [isControlled, persistSwatches, onRemoveColor],\n )\n\n // Auto-render the add + trash buttons when persistKey is set, even if\n // the consumer omitted the callbacks. The primitive owns the list in\n // that mode, so the callbacks are purely \"notification\" channels.\n const showAddButton = Boolean(onAddSwatch) || Boolean(persistKey)\n const showRemoveButton = Boolean(onRemoveColor) || Boolean(persistKey)\n\n React.useEffect(() => {\n if (typeof window === 'undefined') return\n setEyedropperSupported(typeof (window as WindowWithEyeDropper).EyeDropper === 'function')\n }, [])\n\n React.useEffect(() => {\n if (!open) {\n setHexInput(normalizedValue)\n setHexError(null)\n }\n }, [normalizedValue, open])\n\n const commitHex = React.useCallback(\n (raw: string) => {\n const next = normalizeHex(raw)\n if (next === null) {\n setHexError(t('ui.colorPicker.error.invalidHex', 'Invalid hex'))\n return\n }\n setHexError(null)\n setHexInput(next)\n if (next !== normalizedValue) onChange(next)\n },\n [normalizedValue, onChange, t],\n )\n\n const handleHueChange = React.useCallback(\n (hueDeg: number) => {\n // Pure saturated color at the picked hue (s=100%, l=50%).\n const rgb = hslToRgb(hueDeg, 100, 50)\n onChange(rgbToHex(rgb.r, rgb.g, rgb.b))\n },\n [onChange],\n )\n\n const handleEyedropper = React.useCallback(async () => {\n if (!eyedropperSupported) return\n const Ctor = (window as WindowWithEyeDropper).EyeDropper\n if (!Ctor) return\n try {\n const dropper = new Ctor()\n const result = await dropper.open()\n if (result && typeof result.sRGBHex === 'string') {\n const next = normalizeHex(result.sRGBHex)\n if (next) onChange(next)\n }\n } catch {\n // User cancelled \u2014 no-op.\n }\n }, [eyedropperSupported, onChange])\n\n const currentHue = React.useMemo(() => hexToHueDegrees(normalizedValue), [normalizedValue])\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n <PopoverPrimitive.Trigger asChild>\n <button\n ref={ref}\n type=\"button\"\n disabled={disabled}\n data-slot=\"color-picker-trigger\"\n className={cn(triggerVariants({ size }), className)}\n {...props}\n >\n <span\n data-slot=\"color-picker-preview\"\n aria-hidden=\"true\"\n className=\"inline-block size-4 shrink-0 rounded-full border border-border/30\"\n style={{ backgroundColor: normalizedValue }}\n />\n <span className=\"font-mono uppercase tracking-tight\">{normalizedValue}</span>\n </button>\n </PopoverPrimitive.Trigger>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n sideOffset={6}\n align=\"start\"\n data-slot=\"color-picker-popover\"\n className={cn(\n 'z-popover w-80 rounded-xl border border-input bg-popover p-0 text-popover-foreground shadow-md outline-none',\n 'data-[state=open]:animate-in data-[state=closed]:animate-out',\n 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',\n )}\n >\n {/* Section 1 \u2014 Choose color */}\n <div\n data-slot=\"color-picker-section-choose\"\n className=\"space-y-2.5 px-5 pt-4 pb-5\"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">{chooseLabel}</span>\n <span className=\"font-mono text-xs uppercase tracking-tight text-muted-foreground/80\">\n {normalizedValue}\n </span>\n </div>\n <input\n type=\"range\"\n min={0}\n max={360}\n step={1}\n value={currentHue}\n disabled={disabled}\n onChange={(event) => handleHueChange(Number(event.target.value))}\n data-slot=\"color-picker-hue-slider\"\n aria-label={`${chooseLabel} hue`}\n className={cn(\n 'block h-3 w-full cursor-pointer appearance-none rounded-full outline-none',\n // Native range styling. The track is the gradient itself.\n '[background-image:linear-gradient(to_right,hsl(0,100%,50%),hsl(60,100%,50%),hsl(120,100%,50%),hsl(180,100%,50%),hsl(240,100%,50%),hsl(300,100%,50%),hsl(360,100%,50%))]',\n // Thumb: small white pill with shadow per Figma.\n '[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:size-3 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-background [&::-webkit-slider-thumb]:shadow-sm',\n '[&::-moz-range-thumb]:size-3 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:bg-background [&::-moz-range-thumb]:shadow-sm',\n 'focus-visible:shadow-focus',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n )}\n />\n </div>\n\n <div className=\"h-px w-full bg-border/60\" aria-hidden=\"true\" />\n\n {/* Section 2 \u2014 Hex input row.\n *\n * Layout matches Figma `Color Picker` frame 167184:38583 \u00A7 2:\n *\n * [\u25CF colored-bullet] [#HEX text] [opacity %?] (container)\n * [eyedropper]?\n * [trash]?\n *\n * The bullet, hex field, and optional opacity badge live\n * INSIDE the rounded container. Eyedropper + trash render\n * as separate icon buttons after the container.\n */}\n {allowCustom ? (\n <div\n data-slot=\"color-picker-section-input\"\n className=\"flex w-full min-w-0 items-center gap-2.5 px-5 py-4\"\n >\n <div className=\"flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-input bg-background px-2 shadow-xs\">\n <span\n aria-hidden=\"true\"\n data-slot=\"color-picker-current-dot\"\n className=\"inline-block size-4 shrink-0 rounded-full border border-foreground/10\"\n style={{ backgroundColor: normalizedValue }}\n />\n <input\n type=\"text\"\n data-slot=\"color-picker-hex\"\n value={hexInput}\n onChange={(event) => {\n setHexInput(event.target.value)\n setHexError(null)\n }}\n onBlur={(event) => commitHex(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault()\n commitHex(event.currentTarget.value)\n } else if (event.key === 'Escape') {\n event.preventDefault()\n setHexInput(normalizedValue)\n setHexError(null)\n setOpen(false)\n }\n }}\n className={cn(\n 'h-full min-w-0 flex-1 bg-transparent font-mono text-sm uppercase tracking-tight outline-none',\n 'placeholder:text-muted-foreground',\n hexError && 'text-destructive',\n )}\n />\n {showOpacity ? (\n <span\n data-slot=\"color-picker-opacity\"\n aria-hidden=\"true\"\n className=\"shrink-0 font-mono text-xs text-muted-foreground tabular-nums\"\n >\n 100%\n </span>\n ) : null}\n </div>\n {/* Eyedropper and trash are mutually exclusive \u2014 Figma\n * section 2 renders ONE button on the right (trash).\n * When the consumer wires `onRemoveColor`, the\n * eyedropper steps aside so we stay 1:1 with the\n * Figma layout. */}\n {!showRemoveButton && enableEyedropper && eyedropperSupported ? (\n <button\n type=\"button\"\n onClick={handleEyedropper}\n data-slot=\"color-picker-eyedropper\"\n aria-label={t('ui.colorPicker.eyedropper.ariaLabel', 'Pick color from screen')}\n className={cn(\n 'inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-input bg-background text-muted-foreground shadow-xs transition-colors',\n 'hover:bg-muted/40 hover:text-foreground',\n 'focus-visible:shadow-focus focus-visible:outline-none',\n )}\n >\n <Pipette aria-hidden=\"true\" className=\"size-4\" />\n </button>\n ) : null}\n {showRemoveButton ? (\n <button\n type=\"button\"\n onClick={() => handleRemoveColor(normalizedValue)}\n data-slot=\"color-picker-remove\"\n aria-label={removeAriaLabel}\n className={cn(\n 'inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-input bg-background text-muted-foreground shadow-xs transition-colors',\n 'hover:bg-status-error-bg hover:text-status-error-text hover:border-status-error-border',\n 'focus-visible:shadow-focus focus-visible:outline-none',\n )}\n >\n <Trash2 aria-hidden=\"true\" className=\"size-4\" />\n </button>\n ) : null}\n </div>\n ) : null}\n {hexError ? (\n <p\n data-slot=\"color-picker-error\"\n className=\"px-5 pb-3 -mt-2 text-xs text-status-error-text\"\n >\n {hexError}\n </p>\n ) : null}\n\n <div className=\"h-px w-full bg-border/60\" aria-hidden=\"true\" />\n\n {/* Section 3 \u2014 Saved colors */}\n <div data-slot=\"color-picker-section-saved\" className=\"px-5 pt-4 pb-5\">\n <div className=\"mb-3 flex items-center justify-between\">\n <span className=\"text-sm text-muted-foreground\">{savedLabel}</span>\n {onEditSavedColors ? (\n <button\n type=\"button\"\n onClick={() => onEditSavedColors()}\n data-slot=\"color-picker-edit\"\n className={cn(\n 'text-sm font-medium text-accent-indigo outline-none transition-colors',\n 'hover:underline focus-visible:underline',\n 'focus-visible:shadow-focus rounded-sm',\n )}\n >\n {editLabel}\n </button>\n ) : null}\n </div>\n <div className=\"flex flex-wrap gap-3\" role=\"radiogroup\">\n {effectiveSwatches.map((swatch) => {\n const normalized = normalizeHex(swatch) ?? swatch\n const selected = normalized.toUpperCase() === normalizedValue.toUpperCase()\n return (\n <button\n key={normalized}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n aria-label={normalized}\n data-slot=\"color-picker-swatch\"\n data-state={selected ? 'on' : 'off'}\n className={cn(swatchVariants(), 'group/swatch')}\n onClick={() => {\n onChange(normalized)\n if (!allowCustom && !showAddButton) setOpen(false)\n }}\n >\n <span\n aria-hidden=\"true\"\n data-slot=\"color-picker-swatch-dot\"\n className={swatchDotVariants({ selected })}\n style={{ backgroundColor: normalized }}\n />\n {selected ? <span className=\"sr-only\">Selected</span> : null}\n </button>\n )\n })}\n </div>\n </div>\n\n {/* Section 4 \u2014 Add new color (optional) */}\n {showAddButton ? (\n <>\n <div className=\"h-px w-full bg-border/60\" aria-hidden=\"true\" />\n <button\n type=\"button\"\n onClick={() => handleAddSwatch(normalizedValue)}\n data-slot=\"color-picker-add\"\n className={cn(\n 'flex w-full items-center gap-1.5 rounded-b-xl px-4 py-3.5 text-left text-sm text-muted-foreground outline-none transition-colors',\n 'hover:bg-muted/40 hover:text-foreground',\n 'focus-visible:shadow-focus focus-visible:outline-none',\n )}\n >\n <Plus aria-hidden=\"true\" className=\"size-5 text-muted-foreground/70\" />\n <span>{addLabel}</span>\n </button>\n </>\n ) : null}\n\n <PopoverPrimitive.Arrow className=\"fill-popover stroke-input\" />\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n )\n },\n)\nColorPicker.displayName = 'ColorPicker'\n\nexport {\n triggerVariants as colorPickerTriggerVariants,\n swatchVariants as colorPickerSwatchVariants,\n swatchDotVariants as colorPickerSwatchDotVariants,\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }