@webdevarif/dashui 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -49,6 +49,14 @@ __export(index_exports, {
49
49
  CardHeader: () => CardHeader,
50
50
  CardTitle: () => CardTitle,
51
51
  Checkbox: () => Checkbox,
52
+ ColorPicker: () => ColorPicker,
53
+ ColorPickerAlpha: () => ColorPickerAlpha,
54
+ ColorPickerEyeDropper: () => ColorPickerEyeDropper,
55
+ ColorPickerFormat: () => ColorPickerFormat,
56
+ ColorPickerHexOutput: () => ColorPickerHexOutput,
57
+ ColorPickerHue: () => ColorPickerHue,
58
+ ColorPickerOutput: () => ColorPickerOutput,
59
+ ColorPickerSelection: () => ColorPickerSelection,
52
60
  ConfirmDialog: () => ConfirmDialog,
53
61
  DashboardLayout: () => DashboardLayout,
54
62
  DataTable: () => DataTable,
@@ -135,6 +143,7 @@ __export(index_exports, {
135
143
  badgeVariants: () => badgeVariants,
136
144
  buttonVariants: () => buttonVariants,
137
145
  cn: () => cn,
146
+ useColorPicker: () => useColorPicker,
138
147
  useDisclosure: () => useDisclosure,
139
148
  usePagination: () => usePagination,
140
149
  useTheme: () => import_next_themes2.useTheme
@@ -3308,137 +3317,376 @@ function PostSidebarSection({
3308
3317
  }
3309
3318
 
3310
3319
  // src/components/ui/hsl-color-input.tsx
3320
+ var import_react2 = require("react");
3321
+ var import_color2 = __toESM(require("color"));
3322
+ var Popover2 = __toESM(require("@radix-ui/react-popover"));
3323
+
3324
+ // src/components/ui/color-picker.tsx
3325
+ var import_color = __toESM(require("color"));
3311
3326
  var import_react = require("react");
3312
- var import_react_dom = require("react-dom");
3313
- var import_react_colorful = require("react-colorful");
3327
+ var Slider = __toESM(require("@radix-ui/react-slider"));
3314
3328
  var import_jsx_runtime49 = require("react/jsx-runtime");
3315
- function parseHsl(value) {
3316
- if (!value) return { h: 0, s: 0, l: 0 };
3317
- const parts = value.trim().split(/\s+/);
3318
- return {
3319
- h: parseFloat(parts[0]) || 0,
3320
- s: parseFloat(parts[1]) || 0,
3321
- l: parseFloat(parts[2]) || 0
3322
- };
3323
- }
3324
- function formatHsl(c) {
3325
- return `${Math.round(c.h)} ${Math.round(c.s)}% ${Math.round(c.l)}%`;
3326
- }
3327
- function HslColorInput({ value, onChange, className, inputClassName, disabled }) {
3328
- const [open, setOpen] = (0, import_react.useState)(false);
3329
- const [pos, setPos] = (0, import_react.useState)({ top: 0, left: 0 });
3330
- const [inputVal, setInputVal] = (0, import_react.useState)(value);
3331
- const [mounted, setMounted] = (0, import_react.useState)(false);
3332
- const triggerRef = (0, import_react.useRef)(null);
3333
- const pickerRef = (0, import_react.useRef)(null);
3334
- (0, import_react.useEffect)(() => {
3335
- setMounted(true);
3336
- }, []);
3329
+ var ColorPickerContext = (0, import_react.createContext)(void 0);
3330
+ var useColorPicker = () => {
3331
+ const ctx = (0, import_react.useContext)(ColorPickerContext);
3332
+ if (!ctx) throw new Error("useColorPicker must be used within ColorPicker");
3333
+ return ctx;
3334
+ };
3335
+ var ColorPicker = ({
3336
+ defaultValue = "#000000",
3337
+ onChange,
3338
+ className,
3339
+ children,
3340
+ ...props
3341
+ }) => {
3342
+ const initial = (() => {
3343
+ try {
3344
+ return (0, import_color.default)(defaultValue);
3345
+ } catch {
3346
+ return (0, import_color.default)("#000000");
3347
+ }
3348
+ })();
3349
+ const [hue, setHueState] = (0, import_react.useState)(initial.hue());
3350
+ const [saturation, setSaturationState] = (0, import_react.useState)(initial.saturationl());
3351
+ const [lightness, setLightnessState] = (0, import_react.useState)(initial.lightness());
3352
+ const [alpha, setAlphaState] = (0, import_react.useState)(initial.alpha() * 100);
3353
+ const [mode, setMode] = (0, import_react.useState)("HEX");
3354
+ const notifyRef = (0, import_react.useRef)(onChange);
3337
3355
  (0, import_react.useEffect)(() => {
3338
- setInputVal(value);
3339
- }, [value]);
3340
- const openPicker = (0, import_react.useCallback)(() => {
3341
- const rect = triggerRef.current?.getBoundingClientRect();
3342
- if (!rect) return;
3343
- const pickerW = 228;
3344
- let left = rect.left;
3345
- if (left + pickerW > window.innerWidth - 8) left = window.innerWidth - pickerW - 8;
3346
- setPos({ top: rect.bottom + 6, left: Math.max(8, left) });
3347
- setOpen(true);
3356
+ notifyRef.current = onChange;
3357
+ }, [onChange]);
3358
+ const notify = (0, import_react.useCallback)((h, s, l, a) => {
3359
+ const hex = import_color.default.hsl(h, s, l).alpha(a / 100).hexa();
3360
+ notifyRef.current?.(hex);
3348
3361
  }, []);
3362
+ const setHue = (0, import_react.useCallback)((h) => {
3363
+ setHueState(h);
3364
+ notify(h, saturation, lightness, alpha);
3365
+ }, [saturation, lightness, alpha, notify]);
3366
+ const setSaturation = (0, import_react.useCallback)((s) => {
3367
+ setSaturationState(s);
3368
+ notify(hue, s, lightness, alpha);
3369
+ }, [hue, lightness, alpha, notify]);
3370
+ const setLightness = (0, import_react.useCallback)((l) => {
3371
+ setLightnessState(l);
3372
+ notify(hue, saturation, l, alpha);
3373
+ }, [hue, saturation, alpha, notify]);
3374
+ const setAlpha = (0, import_react.useCallback)((a) => {
3375
+ setAlphaState(a);
3376
+ notify(hue, saturation, lightness, a);
3377
+ }, [hue, saturation, lightness, notify]);
3378
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ColorPickerContext.Provider, { value: { hue, saturation, lightness, alpha, setHue, setSaturation, setLightness, setAlpha, mode, setMode }, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: cn("flex flex-col gap-3", className), ...props, children }) });
3379
+ };
3380
+ var ColorPickerSelection = (0, import_react.memo)(({ className, ...props }) => {
3381
+ const containerRef = (0, import_react.useRef)(null);
3382
+ const [isDragging, setIsDragging] = (0, import_react.useState)(false);
3383
+ const [posX, setPosX] = (0, import_react.useState)(0);
3384
+ const [posY, setPosY] = (0, import_react.useState)(0);
3385
+ const { hue, setSaturation, setLightness } = useColorPicker();
3386
+ const bg = (0, import_react.useMemo)(
3387
+ () => `linear-gradient(0deg,rgba(0,0,0,1),rgba(0,0,0,0)),linear-gradient(90deg,rgba(255,255,255,1),rgba(255,255,255,0)),hsl(${hue},100%,50%)`,
3388
+ [hue]
3389
+ );
3390
+ const handleMove = (0, import_react.useCallback)((e) => {
3391
+ if (!isDragging || !containerRef.current) return;
3392
+ const rect = containerRef.current.getBoundingClientRect();
3393
+ const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
3394
+ const y = Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height));
3395
+ setPosX(x);
3396
+ setPosY(y);
3397
+ setSaturation(x * 100);
3398
+ const topL = x < 0.01 ? 100 : 50 + 50 * (1 - x);
3399
+ setLightness(topL * (1 - y));
3400
+ }, [isDragging, setSaturation, setLightness]);
3349
3401
  (0, import_react.useEffect)(() => {
3350
- if (!open) return;
3351
- const handler = (e) => {
3352
- const target = e.target;
3353
- if (pickerRef.current?.contains(target)) return;
3354
- if (triggerRef.current?.contains(target)) return;
3355
- setOpen(false);
3402
+ if (!isDragging) return;
3403
+ const up = () => setIsDragging(false);
3404
+ window.addEventListener("pointermove", handleMove);
3405
+ window.addEventListener("pointerup", up);
3406
+ return () => {
3407
+ window.removeEventListener("pointermove", handleMove);
3408
+ window.removeEventListener("pointerup", up);
3356
3409
  };
3357
- document.addEventListener("pointerdown", handler, true);
3358
- return () => document.removeEventListener("pointerdown", handler, true);
3359
- }, [open]);
3360
- const cssColor = value ? `hsl(${value})` : "transparent";
3361
- const picker = /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
3410
+ }, [isDragging, handleMove]);
3411
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3362
3412
  "div",
3363
3413
  {
3364
- ref: pickerRef,
3365
- style: { position: "fixed", top: pos.top, left: pos.left, zIndex: 9999 },
3366
- className: "bg-[#1a1c2e] border border-white/10 rounded-xl shadow-2xl p-3 flex flex-col gap-3",
3367
- onPointerDown: (e) => e.stopPropagation(),
3414
+ ref: containerRef,
3415
+ className: cn("relative w-full cursor-crosshair rounded-lg", className),
3416
+ style: { background: bg },
3417
+ onPointerDown: (e) => {
3418
+ e.preventDefault();
3419
+ setIsDragging(true);
3420
+ handleMove(e.nativeEvent);
3421
+ },
3422
+ ...props,
3423
+ children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3424
+ "div",
3425
+ {
3426
+ className: "pointer-events-none absolute h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white",
3427
+ style: {
3428
+ left: `${posX * 100}%`,
3429
+ top: `${posY * 100}%`,
3430
+ boxShadow: "0 0 0 1px rgba(0,0,0,0.6)"
3431
+ }
3432
+ }
3433
+ )
3434
+ }
3435
+ );
3436
+ });
3437
+ ColorPickerSelection.displayName = "ColorPickerSelection";
3438
+ var ColorPickerHue = ({ className, ...props }) => {
3439
+ const { hue, setHue } = useColorPicker();
3440
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
3441
+ Slider.Root,
3442
+ {
3443
+ className: cn("relative flex h-4 w-full touch-none items-center", className),
3444
+ max: 360,
3445
+ step: 1,
3446
+ value: [hue],
3447
+ onValueChange: ([h]) => setHue(h),
3448
+ ...props,
3449
+ children: [
3450
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Slider.Track, { className: "relative h-3 w-full grow rounded-full bg-[linear-gradient(90deg,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)]", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Slider.Range, { className: "absolute h-full" }) }),
3451
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Slider.Thumb, { className: "block h-4 w-4 rounded-full border-2 border-white shadow-md focus:outline-none", style: { boxShadow: "0 0 0 1px rgba(0,0,0,0.4)" } })
3452
+ ]
3453
+ }
3454
+ );
3455
+ };
3456
+ var ColorPickerAlpha = ({ className, ...props }) => {
3457
+ const { alpha, setAlpha, hue, saturation, lightness } = useColorPicker();
3458
+ const solidColor = `hsl(${hue},${saturation}%,${lightness}%)`;
3459
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
3460
+ Slider.Root,
3461
+ {
3462
+ className: cn("relative flex h-4 w-full touch-none items-center", className),
3463
+ max: 100,
3464
+ step: 1,
3465
+ value: [alpha],
3466
+ onValueChange: ([a]) => setAlpha(a),
3467
+ ...props,
3368
3468
  children: [
3369
3469
  /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3370
- import_react_colorful.HslColorPicker,
3470
+ Slider.Track,
3371
3471
  {
3372
- color: parseHsl(value),
3373
- onChange: (c) => {
3374
- const formatted = formatHsl(c);
3375
- setInputVal(formatted);
3376
- onChange(formatted);
3377
- }
3472
+ className: "relative h-3 w-full grow rounded-full",
3473
+ style: {
3474
+ backgroundImage: `linear-gradient(90deg, transparent, ${solidColor}), url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==")`
3475
+ },
3476
+ children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Slider.Range, { className: "absolute h-full" })
3378
3477
  }
3379
3478
  ),
3380
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "flex items-center gap-2 px-1", children: [
3381
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "w-5 h-5 rounded border border-white/10 shrink-0", style: { background: cssColor } }),
3382
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-mono text-white/40 flex-1 truncate", children: value || "none" }),
3383
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3384
- "button",
3385
- {
3386
- onClick: () => setOpen(false),
3387
- className: "text-white/30 hover:text-white/70 text-xs px-1.5 py-0.5 rounded hover:bg-white/5 transition-colors",
3388
- children: "Done"
3389
- }
3390
- )
3391
- ] })
3479
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Slider.Thumb, { className: "block h-4 w-4 rounded-full border-2 border-white shadow-md focus:outline-none", style: { boxShadow: "0 0 0 1px rgba(0,0,0,0.4)" } })
3392
3480
  ]
3393
3481
  }
3394
3482
  );
3395
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: cn("flex items-center gap-1.5", className), children: [
3396
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3483
+ };
3484
+ var ColorPickerHexOutput = ({ className, ...props }) => {
3485
+ const { hue, saturation, lightness, alpha } = useColorPicker();
3486
+ const hex = import_color.default.hsl(hue, saturation, lightness).alpha(alpha / 100).hex();
3487
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: cn("flex items-center gap-1.5 px-1", className), ...props, children: [
3488
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "w-5 h-5 rounded border border-white/20 shrink-0", style: { background: `hsl(${hue},${saturation}%,${lightness}%)` } }),
3489
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { className: "text-xs font-mono text-white/50 flex-1", children: hex })
3490
+ ] });
3491
+ };
3492
+ var ColorPickerEyeDropper = ({ className, ...props }) => {
3493
+ const { setHue, setSaturation, setLightness, setAlpha } = useColorPicker();
3494
+ const pick = async () => {
3495
+ try {
3496
+ const result = await new EyeDropper().open();
3497
+ const c = (0, import_color.default)(result.sRGBHex);
3498
+ setHue(c.hue());
3499
+ setSaturation(c.saturationl());
3500
+ setLightness(c.lightness());
3501
+ setAlpha(100);
3502
+ } catch {
3503
+ }
3504
+ };
3505
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3506
+ "button",
3507
+ {
3508
+ type: "button",
3509
+ onClick: pick,
3510
+ title: "Eye dropper",
3511
+ className: cn(
3512
+ "w-7 h-7 flex items-center justify-center rounded-md",
3513
+ "border border-white/10 text-white/40 hover:text-white/70 hover:border-white/25",
3514
+ "transition-colors shrink-0",
3515
+ className
3516
+ ),
3517
+ ...props,
3518
+ children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
3519
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M9.53 16.122a3 3 0 0 0-5.78 1.128 2.25 2.25 0 0 1-2.4 2.245 4.5 4.5 0 0 0 8.4-2.245c0-.399-.078-.78-.22-1.128Z" }),
3520
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "m13.5 10.5 2.25-2.25m0 0 2.25-2.25M15.75 8.25l2.25 2.25M15.75 8.25 13.5 6m4.5-1.5 1.5-1.5" }),
3521
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: "M6.75 7.5 10.5 4.5c.5-.375 1.25-.375 1.5 0l6.75 6.75c.375.5.375 1.25 0 1.5L15 16.5" })
3522
+ ] })
3523
+ }
3524
+ );
3525
+ };
3526
+ var ColorPickerOutput = ({ className, ...props }) => {
3527
+ const { mode, setMode } = useColorPicker();
3528
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3529
+ "select",
3530
+ {
3531
+ value: mode,
3532
+ onChange: (e) => setMode(e.target.value),
3533
+ className: cn(
3534
+ "h-7 bg-white/5 border border-white/10 rounded-md text-xs text-white/60 px-1.5 outline-none",
3535
+ "hover:border-white/20 focus:border-white/30 cursor-pointer shrink-0",
3536
+ className
3537
+ ),
3538
+ children: ["HEX", "HSL", "RGB"].map((f) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("option", { value: f, className: "bg-[#1a1c2e]", children: f }, f))
3539
+ }
3540
+ );
3541
+ };
3542
+ var ColorPickerFormat = ({ className, ...props }) => {
3543
+ const { hue, saturation, lightness, alpha, mode } = useColorPicker();
3544
+ let displayValue = "";
3545
+ try {
3546
+ const c = import_color.default.hsl(hue, saturation, lightness).alpha(alpha / 100);
3547
+ if (mode === "HEX") displayValue = c.hex();
3548
+ else if (mode === "HSL") displayValue = `${Math.round(hue)} ${Math.round(saturation)}% ${Math.round(lightness)}%`;
3549
+ else if (mode === "RGB") {
3550
+ const rgb = c.rgb().array().map(Math.round);
3551
+ displayValue = `${rgb[0]}, ${rgb[1]}, ${rgb[2]}`;
3552
+ }
3553
+ } catch {
3554
+ displayValue = "";
3555
+ }
3556
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3557
+ "input",
3558
+ {
3559
+ readOnly: true,
3560
+ type: "text",
3561
+ value: displayValue,
3562
+ className: cn(
3563
+ "flex-1 h-7 bg-white/5 border border-white/10 rounded-md px-2 text-xs text-white/50 font-mono outline-none",
3564
+ className
3565
+ ),
3566
+ ...props
3567
+ }
3568
+ );
3569
+ };
3570
+
3571
+ // src/components/ui/hsl-color-input.tsx
3572
+ var import_jsx_runtime50 = require("react/jsx-runtime");
3573
+ function hslToHex(hsl) {
3574
+ if (!hsl) return "#000000";
3575
+ try {
3576
+ const parts = hsl.trim().split(/\s+/);
3577
+ const h = parseFloat(parts[0]) || 0;
3578
+ const s = parseFloat(parts[1]) || 0;
3579
+ const l = parseFloat(parts[2]) || 0;
3580
+ return import_color2.default.hsl(h, s, l).hex();
3581
+ } catch {
3582
+ return "#000000";
3583
+ }
3584
+ }
3585
+ function hexToHsl(hex) {
3586
+ try {
3587
+ const c = (0, import_color2.default)(hex.startsWith("#") ? hex : `#${hex}`);
3588
+ return `${Math.round(c.hue())} ${Math.round(c.saturationl())}% ${Math.round(c.lightness())}%`;
3589
+ } catch {
3590
+ return "0 0% 0%";
3591
+ }
3592
+ }
3593
+ function ColorReader({ onHexChange }) {
3594
+ const { hue, saturation, lightness, alpha } = useColorPicker();
3595
+ (0, import_react2.useEffect)(() => {
3596
+ try {
3597
+ const hex = import_color2.default.hsl(hue, saturation, lightness).alpha(alpha / 100).hex();
3598
+ onHexChange(hex);
3599
+ } catch {
3600
+ }
3601
+ }, [hue, saturation, lightness, alpha, onHexChange]);
3602
+ return null;
3603
+ }
3604
+ function HslColorInput({ value, onChange, className, inputClassName, disabled }) {
3605
+ const [open, setOpen] = (0, import_react2.useState)(false);
3606
+ const hexValue = hslToHex(value);
3607
+ const cssColor = value ? `hsl(${value})` : "transparent";
3608
+ const pendingHexRef = (0, import_react2.useRef)(hexValue);
3609
+ const onChangeRef = (0, import_react2.useRef)(onChange);
3610
+ (0, import_react2.useEffect)(() => {
3611
+ onChangeRef.current = onChange;
3612
+ }, [onChange]);
3613
+ (0, import_react2.useEffect)(() => {
3614
+ if (open) pendingHexRef.current = hexValue;
3615
+ }, [open, hexValue]);
3616
+ const handleHexChange = (0, import_react2.useCallback)((hex) => {
3617
+ pendingHexRef.current = hex;
3618
+ }, []);
3619
+ const handleOpenChange = (0, import_react2.useCallback)((newOpen) => {
3620
+ if (!newOpen && open) {
3621
+ const pending = pendingHexRef.current;
3622
+ if (pending && pending !== hexValue) {
3623
+ onChangeRef.current(hexToHsl(pending));
3624
+ }
3625
+ }
3626
+ setOpen(newOpen);
3627
+ }, [open, hexValue]);
3628
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(Popover2.Root, { open, onOpenChange: disabled ? void 0 : handleOpenChange, children: [
3629
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Popover2.Trigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3397
3630
  "button",
3398
3631
  {
3399
- ref: triggerRef,
3400
3632
  type: "button",
3401
3633
  disabled,
3402
- onClick: () => open ? setOpen(false) : openPicker(),
3403
3634
  className: cn(
3404
- "w-5 h-5 rounded border border-white/10 shrink-0 transition-all",
3405
- "hover:scale-110 hover:border-white/30 focus:outline-none",
3406
- disabled && "opacity-50 cursor-not-allowed"
3635
+ "flex items-center gap-2 px-2 py-1 rounded-lg border border-white/10",
3636
+ "bg-white/5 hover:border-white/20 hover:bg-white/[0.08] transition-colors",
3637
+ "text-xs text-white/60 font-mono min-w-[7.5rem] justify-start",
3638
+ "focus:outline-none focus:border-white/30",
3639
+ disabled && "opacity-50 cursor-not-allowed",
3640
+ className
3407
3641
  ),
3408
- style: { background: cssColor },
3409
- "aria-label": "Pick color"
3642
+ "aria-label": "Pick color",
3643
+ children: [
3644
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3645
+ "span",
3646
+ {
3647
+ className: "w-4 h-4 rounded-full border border-white/20 shrink-0 inline-block",
3648
+ style: { background: cssColor }
3649
+ }
3650
+ ),
3651
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { children: hexValue.toUpperCase() })
3652
+ ]
3410
3653
  }
3411
- ),
3412
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
3413
- "input",
3654
+ ) }),
3655
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Popover2.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3656
+ Popover2.Content,
3414
3657
  {
3415
- type: "text",
3416
- value: inputVal,
3417
- onChange: (e) => {
3418
- setInputVal(e.target.value);
3419
- if (/^\d+(\.\d+)?\s+\d+(\.\d+)?%\s+\d+(\.\d+)?%$/.test(e.target.value.trim())) {
3420
- onChange(e.target.value.trim());
3421
- }
3422
- },
3423
- onBlur: () => setInputVal(value),
3424
- disabled,
3425
- placeholder: "H S% L%",
3658
+ sideOffset: 6,
3659
+ align: "start",
3426
3660
  className: cn(
3427
- "w-28 bg-white/5 border border-white/10 rounded px-1.5 py-0.5",
3428
- "text-xs text-white/70 font-mono outline-none focus:border-white/30",
3429
- "placeholder:text-white/20 disabled:opacity-50",
3430
- inputClassName
3431
- )
3661
+ "z-[9999] rounded-xl shadow-2xl p-3 w-[14rem]",
3662
+ "bg-[#0f1117] border border-white/10",
3663
+ "focus:outline-none"
3664
+ ),
3665
+ onInteractOutside: () => handleOpenChange(false),
3666
+ children: open && /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(ColorPicker, { defaultValue: hexValue, className: "gap-2.5", children: [
3667
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ColorReader, { onHexChange: handleHexChange }),
3668
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ColorPickerSelection, { className: "h-32 w-full rounded-lg" }),
3669
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "flex items-center gap-3", children: [
3670
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ColorPickerEyeDropper, {}),
3671
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "flex flex-col gap-1.5 flex-1", children: [
3672
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ColorPickerHue, {}),
3673
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ColorPickerAlpha, {})
3674
+ ] })
3675
+ ] }),
3676
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "flex items-center gap-1.5", children: [
3677
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ColorPickerOutput, {}),
3678
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ColorPickerFormat, {})
3679
+ ] })
3680
+ ] }, hexValue)
3432
3681
  }
3433
- ),
3434
- mounted && open && (0, import_react_dom.createPortal)(picker, document.body)
3682
+ ) })
3435
3683
  ] });
3436
3684
  }
3437
3685
 
3438
3686
  // src/hooks/index.ts
3439
- var import_react2 = require("react");
3687
+ var import_react3 = require("react");
3440
3688
  function useDisclosure(initial = false) {
3441
- const [isOpen, setIsOpen] = (0, import_react2.useState)(initial);
3689
+ const [isOpen, setIsOpen] = (0, import_react3.useState)(initial);
3442
3690
  return {
3443
3691
  isOpen,
3444
3692
  open: () => setIsOpen(true),
@@ -3448,15 +3696,15 @@ function useDisclosure(initial = false) {
3448
3696
  };
3449
3697
  }
3450
3698
  function usePagination(total, pageSize = 20) {
3451
- const [page, setPage] = (0, import_react2.useState)(1);
3699
+ const [page, setPage] = (0, import_react3.useState)(1);
3452
3700
  const totalPages = Math.ceil(total / pageSize);
3453
3701
  return { page, setPage, pageSize, total, totalPages };
3454
3702
  }
3455
3703
 
3456
3704
  // src/components/auth/AuthShell.tsx
3457
- var import_jsx_runtime50 = require("react/jsx-runtime");
3705
+ var import_jsx_runtime51 = require("react/jsx-runtime");
3458
3706
  function AuthShell({ children, pattern = "dots", maxWidth = "520px" }) {
3459
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
3707
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
3460
3708
  "div",
3461
3709
  {
3462
3710
  style: {
@@ -3471,7 +3719,7 @@ function AuthShell({ children, pattern = "dots", maxWidth = "520px" }) {
3471
3719
  overflow: "hidden"
3472
3720
  },
3473
3721
  children: [
3474
- pattern === "dots" && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3722
+ pattern === "dots" && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3475
3723
  "div",
3476
3724
  {
3477
3725
  "aria-hidden": true,
@@ -3485,7 +3733,7 @@ function AuthShell({ children, pattern = "dots", maxWidth = "520px" }) {
3485
3733
  }
3486
3734
  }
3487
3735
  ),
3488
- pattern === "grid" && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
3736
+ pattern === "grid" && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3489
3737
  "div",
3490
3738
  {
3491
3739
  "aria-hidden": true,
@@ -3499,16 +3747,16 @@ function AuthShell({ children, pattern = "dots", maxWidth = "520px" }) {
3499
3747
  }
3500
3748
  }
3501
3749
  ),
3502
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { style: { position: "relative", zIndex: 1, width: "100%", maxWidth }, children })
3750
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { style: { position: "relative", zIndex: 1, width: "100%", maxWidth }, children })
3503
3751
  ]
3504
3752
  }
3505
3753
  );
3506
3754
  }
3507
3755
 
3508
3756
  // src/components/auth/AuthCard.tsx
3509
- var import_jsx_runtime51 = require("react/jsx-runtime");
3757
+ var import_jsx_runtime52 = require("react/jsx-runtime");
3510
3758
  function AuthCard({ children, padding = "24px 28px" }) {
3511
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
3759
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3512
3760
  "div",
3513
3761
  {
3514
3762
  style: {
@@ -3525,10 +3773,10 @@ function AuthCard({ children, padding = "24px 28px" }) {
3525
3773
  }
3526
3774
 
3527
3775
  // src/components/auth/AuthLogo.tsx
3528
- var import_jsx_runtime52 = require("react/jsx-runtime");
3776
+ var import_jsx_runtime53 = require("react/jsx-runtime");
3529
3777
  function AuthLogo({ appName = "Builify CMS", letter = "B", imageUrl, size = 36 }) {
3530
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "10px", marginBottom: "28px" }, children: [
3531
- imageUrl ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3778
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "10px", marginBottom: "28px" }, children: [
3779
+ imageUrl ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3532
3780
  "img",
3533
3781
  {
3534
3782
  src: imageUrl,
@@ -3537,7 +3785,7 @@ function AuthLogo({ appName = "Builify CMS", letter = "B", imageUrl, size = 36 }
3537
3785
  height: size,
3538
3786
  style: { borderRadius: "calc(var(--radius, 0.5rem) * 1.2)", flexShrink: 0, display: "block" }
3539
3787
  }
3540
- ) : /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3788
+ ) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3541
3789
  "div",
3542
3790
  {
3543
3791
  style: {
@@ -3556,7 +3804,7 @@ function AuthLogo({ appName = "Builify CMS", letter = "B", imageUrl, size = 36 }
3556
3804
  children: letter
3557
3805
  }
3558
3806
  ),
3559
- /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
3807
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3560
3808
  "span",
3561
3809
  {
3562
3810
  style: {
@@ -3572,10 +3820,10 @@ function AuthLogo({ appName = "Builify CMS", letter = "B", imageUrl, size = 36 }
3572
3820
  }
3573
3821
 
3574
3822
  // src/components/auth/AuthHeader.tsx
3575
- var import_jsx_runtime53 = require("react/jsx-runtime");
3823
+ var import_jsx_runtime54 = require("react/jsx-runtime");
3576
3824
  function AuthHeader({ title, description }) {
3577
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { style: { marginBottom: "24px", textAlign: "center" }, children: [
3578
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3825
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { style: { marginBottom: "24px", textAlign: "center" }, children: [
3826
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3579
3827
  "h1",
3580
3828
  {
3581
3829
  style: {
@@ -3588,7 +3836,7 @@ function AuthHeader({ title, description }) {
3588
3836
  children: title
3589
3837
  }
3590
3838
  ),
3591
- description && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
3839
+ description && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3592
3840
  "p",
3593
3841
  {
3594
3842
  style: {
@@ -3604,12 +3852,12 @@ function AuthHeader({ title, description }) {
3604
3852
  }
3605
3853
 
3606
3854
  // src/components/auth/AuthField.tsx
3607
- var import_jsx_runtime54 = require("react/jsx-runtime");
3855
+ var import_jsx_runtime55 = require("react/jsx-runtime");
3608
3856
  function AuthField({ label, error, hint, rightLabel, id, ...props }) {
3609
3857
  const fieldId = id ?? label.toLowerCase().replace(/\s+/g, "-");
3610
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [
3611
- /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
3612
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3858
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [
3859
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
3860
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
3613
3861
  "label",
3614
3862
  {
3615
3863
  htmlFor: fieldId,
@@ -3621,9 +3869,9 @@ function AuthField({ label, error, hint, rightLabel, id, ...props }) {
3621
3869
  children: label
3622
3870
  }
3623
3871
  ),
3624
- rightLabel && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { style: { fontSize: "0.8125rem" }, children: rightLabel })
3872
+ rightLabel && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { style: { fontSize: "0.8125rem" }, children: rightLabel })
3625
3873
  ] }),
3626
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3874
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
3627
3875
  "input",
3628
3876
  {
3629
3877
  id: fieldId,
@@ -3653,13 +3901,13 @@ function AuthField({ label, error, hint, rightLabel, id, ...props }) {
3653
3901
  ...props
3654
3902
  }
3655
3903
  ),
3656
- error && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", { style: { fontSize: "0.8rem", color: "var(--destructive)", margin: 0 }, children: error }),
3657
- hint && !error && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", { style: { fontSize: "0.8rem", color: "var(--muted-foreground)", margin: 0 }, children: hint })
3904
+ error && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", { style: { fontSize: "0.8rem", color: "var(--destructive)", margin: 0 }, children: error }),
3905
+ hint && !error && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", { style: { fontSize: "0.8rem", color: "var(--muted-foreground)", margin: 0 }, children: hint })
3658
3906
  ] });
3659
3907
  }
3660
3908
 
3661
3909
  // src/components/auth/AuthButton.tsx
3662
- var import_jsx_runtime55 = require("react/jsx-runtime");
3910
+ var import_jsx_runtime56 = require("react/jsx-runtime");
3663
3911
  function AuthButton({
3664
3912
  loading,
3665
3913
  variant = "primary",
@@ -3702,7 +3950,7 @@ function AuthButton({
3702
3950
  color: "var(--foreground)"
3703
3951
  }
3704
3952
  };
3705
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
3953
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
3706
3954
  "button",
3707
3955
  {
3708
3956
  disabled: loading || disabled,
@@ -3714,8 +3962,8 @@ function AuthButton({
3714
3962
  e.currentTarget.style.filter = "none";
3715
3963
  },
3716
3964
  ...props,
3717
- children: loading ? /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_jsx_runtime55.Fragment, { children: [
3718
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(
3965
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
3966
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
3719
3967
  "span",
3720
3968
  {
3721
3969
  style: {
@@ -3736,19 +3984,19 @@ function AuthButton({
3736
3984
  }
3737
3985
 
3738
3986
  // src/components/auth/AuthDivider.tsx
3739
- var import_jsx_runtime56 = require("react/jsx-runtime");
3987
+ var import_jsx_runtime57 = require("react/jsx-runtime");
3740
3988
  function AuthDivider({ label = "or" }) {
3741
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "12px", margin: "20px 0" }, children: [
3742
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { style: { flex: 1, height: 1, background: "var(--border)" } }),
3743
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { style: { fontSize: "0.75rem", color: "var(--muted-foreground)", userSelect: "none" }, children: label }),
3744
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { style: { flex: 1, height: 1, background: "var(--border)" } })
3989
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "12px", margin: "20px 0" }, children: [
3990
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { style: { flex: 1, height: 1, background: "var(--border)" } }),
3991
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("span", { style: { fontSize: "0.75rem", color: "var(--muted-foreground)", userSelect: "none" }, children: label }),
3992
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)("div", { style: { flex: 1, height: 1, background: "var(--border)" } })
3745
3993
  ] });
3746
3994
  }
3747
3995
 
3748
3996
  // src/components/auth/AuthFootnote.tsx
3749
- var import_jsx_runtime57 = require("react/jsx-runtime");
3997
+ var import_jsx_runtime58 = require("react/jsx-runtime");
3750
3998
  function AuthFootnote({ text, linkText, linkHref }) {
3751
- return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("p", { style: {
3999
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("p", { style: {
3752
4000
  textAlign: "center",
3753
4001
  marginTop: "20px",
3754
4002
  fontSize: "0.8125rem",
@@ -3756,7 +4004,7 @@ function AuthFootnote({ text, linkText, linkHref }) {
3756
4004
  }, children: [
3757
4005
  text,
3758
4006
  " ",
3759
- /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
4007
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
3760
4008
  "a",
3761
4009
  {
3762
4010
  href: linkHref,
@@ -3796,6 +4044,14 @@ var import_next_themes2 = require("next-themes");
3796
4044
  CardHeader,
3797
4045
  CardTitle,
3798
4046
  Checkbox,
4047
+ ColorPicker,
4048
+ ColorPickerAlpha,
4049
+ ColorPickerEyeDropper,
4050
+ ColorPickerFormat,
4051
+ ColorPickerHexOutput,
4052
+ ColorPickerHue,
4053
+ ColorPickerOutput,
4054
+ ColorPickerSelection,
3799
4055
  ConfirmDialog,
3800
4056
  DashboardLayout,
3801
4057
  DataTable,
@@ -3882,6 +4138,7 @@ var import_next_themes2 = require("next-themes");
3882
4138
  badgeVariants,
3883
4139
  buttonVariants,
3884
4140
  cn,
4141
+ useColorPicker,
3885
4142
  useDisclosure,
3886
4143
  usePagination,
3887
4144
  useTheme