@webdevarif/dashui 0.3.5 → 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.mjs CHANGED
@@ -3165,7 +3165,7 @@ function PostSidebarSection({
3165
3165
  }
3166
3166
 
3167
3167
  // src/components/ui/hsl-color-input.tsx
3168
- import { useState as useState8, useEffect as useEffect6, useCallback as useCallback2 } from "react";
3168
+ import { useState as useState8, useRef as useRef5, useEffect as useEffect6, useCallback as useCallback2 } from "react";
3169
3169
  import Color2 from "color";
3170
3170
  import * as Popover2 from "@radix-ui/react-popover";
3171
3171
 
@@ -3207,6 +3207,7 @@ var ColorPicker = ({
3207
3207
  const [saturation, setSaturationState] = useState7(initial.saturationl());
3208
3208
  const [lightness, setLightnessState] = useState7(initial.lightness());
3209
3209
  const [alpha, setAlphaState] = useState7(initial.alpha() * 100);
3210
+ const [mode, setMode] = useState7("HEX");
3210
3211
  const notifyRef = useRef4(onChange);
3211
3212
  useEffect5(() => {
3212
3213
  notifyRef.current = onChange;
@@ -3231,7 +3232,7 @@ var ColorPicker = ({
3231
3232
  setAlphaState(a);
3232
3233
  notify(hue, saturation, lightness, a);
3233
3234
  }, [hue, saturation, lightness, notify]);
3234
- return /* @__PURE__ */ jsx49(ColorPickerContext.Provider, { value: { hue, saturation, lightness, alpha, setHue, setSaturation, setLightness, setAlpha }, children: /* @__PURE__ */ jsx49("div", { className: cn("flex flex-col gap-3", className), ...props, children }) });
3235
+ return /* @__PURE__ */ jsx49(ColorPickerContext.Provider, { value: { hue, saturation, lightness, alpha, setHue, setSaturation, setLightness, setAlpha, mode, setMode }, children: /* @__PURE__ */ jsx49("div", { className: cn("flex flex-col gap-3", className), ...props, children }) });
3235
3236
  };
3236
3237
  var ColorPickerSelection = memo(({ className, ...props }) => {
3237
3238
  const containerRef = useRef4(null);
@@ -3379,10 +3380,54 @@ var ColorPickerEyeDropper = ({ className, ...props }) => {
3379
3380
  }
3380
3381
  );
3381
3382
  };
3383
+ var ColorPickerOutput = ({ className, ...props }) => {
3384
+ const { mode, setMode } = useColorPicker();
3385
+ return /* @__PURE__ */ jsx49(
3386
+ "select",
3387
+ {
3388
+ value: mode,
3389
+ onChange: (e) => setMode(e.target.value),
3390
+ className: cn(
3391
+ "h-7 bg-white/5 border border-white/10 rounded-md text-xs text-white/60 px-1.5 outline-none",
3392
+ "hover:border-white/20 focus:border-white/30 cursor-pointer shrink-0",
3393
+ className
3394
+ ),
3395
+ children: ["HEX", "HSL", "RGB"].map((f) => /* @__PURE__ */ jsx49("option", { value: f, className: "bg-[#1a1c2e]", children: f }, f))
3396
+ }
3397
+ );
3398
+ };
3399
+ var ColorPickerFormat = ({ className, ...props }) => {
3400
+ const { hue, saturation, lightness, alpha, mode } = useColorPicker();
3401
+ let displayValue = "";
3402
+ try {
3403
+ const c = Color.hsl(hue, saturation, lightness).alpha(alpha / 100);
3404
+ if (mode === "HEX") displayValue = c.hex();
3405
+ else if (mode === "HSL") displayValue = `${Math.round(hue)} ${Math.round(saturation)}% ${Math.round(lightness)}%`;
3406
+ else if (mode === "RGB") {
3407
+ const rgb = c.rgb().array().map(Math.round);
3408
+ displayValue = `${rgb[0]}, ${rgb[1]}, ${rgb[2]}`;
3409
+ }
3410
+ } catch {
3411
+ displayValue = "";
3412
+ }
3413
+ return /* @__PURE__ */ jsx49(
3414
+ "input",
3415
+ {
3416
+ readOnly: true,
3417
+ type: "text",
3418
+ value: displayValue,
3419
+ className: cn(
3420
+ "flex-1 h-7 bg-white/5 border border-white/10 rounded-md px-2 text-xs text-white/50 font-mono outline-none",
3421
+ className
3422
+ ),
3423
+ ...props
3424
+ }
3425
+ );
3426
+ };
3382
3427
 
3383
3428
  // src/components/ui/hsl-color-input.tsx
3384
3429
  import { jsx as jsx50, jsxs as jsxs34 } from "react/jsx-runtime";
3385
- function hslStringToHex(hsl) {
3430
+ function hslToHex(hsl) {
3386
3431
  if (!hsl) return "#000000";
3387
3432
  try {
3388
3433
  const parts = hsl.trim().split(/\s+/);
@@ -3394,13 +3439,10 @@ function hslStringToHex(hsl) {
3394
3439
  return "#000000";
3395
3440
  }
3396
3441
  }
3397
- function hexToHslString(hex) {
3442
+ function hexToHsl(hex) {
3398
3443
  try {
3399
- const c = Color2(hex);
3400
- const h = Math.round(c.hue());
3401
- const s = Math.round(c.saturationl());
3402
- const l = Math.round(c.lightness());
3403
- return `${h} ${s}% ${l}%`;
3444
+ const c = Color2(hex.startsWith("#") ? hex : `#${hex}`);
3445
+ return `${Math.round(c.hue())} ${Math.round(c.saturationl())}% ${Math.round(c.lightness())}%`;
3404
3446
  } catch {
3405
3447
  return "0 0% 0%";
3406
3448
  }
@@ -3408,88 +3450,93 @@ function hexToHslString(hex) {
3408
3450
  function ColorReader({ onHexChange }) {
3409
3451
  const { hue, saturation, lightness, alpha } = useColorPicker();
3410
3452
  useEffect6(() => {
3411
- const hex = Color2.hsl(hue, saturation, lightness).alpha(alpha / 100).hex();
3412
- onHexChange(hex);
3453
+ try {
3454
+ const hex = Color2.hsl(hue, saturation, lightness).alpha(alpha / 100).hex();
3455
+ onHexChange(hex);
3456
+ } catch {
3457
+ }
3413
3458
  }, [hue, saturation, lightness, alpha, onHexChange]);
3414
3459
  return null;
3415
3460
  }
3416
3461
  function HslColorInput({ value, onChange, className, inputClassName, disabled }) {
3417
3462
  const [open, setOpen] = useState8(false);
3418
- const [inputVal, setInputVal] = useState8(value);
3419
- useEffect6(() => {
3420
- setInputVal(value);
3421
- }, [value]);
3422
- const hexValue = hslStringToHex(value);
3463
+ const hexValue = hslToHex(value);
3423
3464
  const cssColor = value ? `hsl(${value})` : "transparent";
3424
- const handlePickerHex = useCallback2((hex) => {
3425
- const hsl = hexToHslString(hex);
3426
- setInputVal(hsl);
3427
- onChange(hsl);
3465
+ const pendingHexRef = useRef5(hexValue);
3466
+ const onChangeRef = useRef5(onChange);
3467
+ useEffect6(() => {
3468
+ onChangeRef.current = onChange;
3428
3469
  }, [onChange]);
3429
- return /* @__PURE__ */ jsxs34("div", { className: cn("flex items-center gap-1.5", className), children: [
3430
- /* @__PURE__ */ jsxs34(Popover2.Root, { open, onOpenChange: disabled ? void 0 : setOpen, children: [
3431
- /* @__PURE__ */ jsx50(Popover2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx50(
3432
- "button",
3433
- {
3434
- type: "button",
3435
- disabled,
3436
- className: cn(
3437
- "w-5 h-5 rounded border border-white/10 shrink-0 transition-all",
3438
- "hover:scale-110 hover:border-white/30 focus:outline-none",
3439
- disabled && "opacity-50 cursor-not-allowed"
3440
- ),
3441
- style: { background: cssColor },
3442
- "aria-label": "Pick color"
3443
- }
3444
- ) }),
3445
- /* @__PURE__ */ jsx50(Popover2.Portal, { children: /* @__PURE__ */ jsx50(
3446
- Popover2.Content,
3447
- {
3448
- sideOffset: 8,
3449
- align: "start",
3450
- className: cn(
3451
- "z-[9999] rounded-xl shadow-2xl p-3 w-[220px]",
3452
- "bg-[#1a1c2e] border border-white/10",
3453
- "focus:outline-none"
3454
- ),
3455
- onInteractOutside: () => setOpen(false),
3456
- children: open && /* @__PURE__ */ jsxs34(ColorPicker, { defaultValue: hexValue, children: [
3457
- /* @__PURE__ */ jsx50(ColorReader, { onHexChange: handlePickerHex }),
3458
- /* @__PURE__ */ jsx50(ColorPickerSelection, { className: "h-36 rounded-lg" }),
3459
- /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2", children: [
3460
- /* @__PURE__ */ jsx50(ColorPickerEyeDropper, {}),
3461
- /* @__PURE__ */ jsxs34("div", { className: "flex flex-col gap-1.5 flex-1", children: [
3462
- /* @__PURE__ */ jsx50(ColorPickerHue, {}),
3463
- /* @__PURE__ */ jsx50(ColorPickerAlpha, {})
3464
- ] })
3465
- ] }),
3466
- /* @__PURE__ */ jsx50(ColorPickerHexOutput, {})
3467
- ] })
3468
- }
3469
- ) })
3470
- ] }),
3471
- /* @__PURE__ */ jsx50(
3472
- "input",
3470
+ useEffect6(() => {
3471
+ if (open) pendingHexRef.current = hexValue;
3472
+ }, [open, hexValue]);
3473
+ const handleHexChange = useCallback2((hex) => {
3474
+ pendingHexRef.current = hex;
3475
+ }, []);
3476
+ const handleOpenChange = useCallback2((newOpen) => {
3477
+ if (!newOpen && open) {
3478
+ const pending = pendingHexRef.current;
3479
+ if (pending && pending !== hexValue) {
3480
+ onChangeRef.current(hexToHsl(pending));
3481
+ }
3482
+ }
3483
+ setOpen(newOpen);
3484
+ }, [open, hexValue]);
3485
+ return /* @__PURE__ */ jsxs34(Popover2.Root, { open, onOpenChange: disabled ? void 0 : handleOpenChange, children: [
3486
+ /* @__PURE__ */ jsx50(Popover2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs34(
3487
+ "button",
3473
3488
  {
3474
- type: "text",
3475
- value: inputVal,
3476
- onChange: (e) => {
3477
- setInputVal(e.target.value);
3478
- if (/^\d+(\.\d+)?\s+\d+(\.\d+)?%\s+\d+(\.\d+)?%$/.test(e.target.value.trim())) {
3479
- onChange(e.target.value.trim());
3480
- }
3481
- },
3482
- onBlur: () => setInputVal(value),
3489
+ type: "button",
3483
3490
  disabled,
3484
- placeholder: "H S% L%",
3485
3491
  className: cn(
3486
- "w-28 bg-white/5 border border-white/10 rounded px-1.5 py-0.5",
3487
- "text-xs text-white/70 font-mono outline-none focus:border-white/30",
3488
- "placeholder:text-white/20 disabled:opacity-50",
3489
- inputClassName
3490
- )
3492
+ "flex items-center gap-2 px-2 py-1 rounded-lg border border-white/10",
3493
+ "bg-white/5 hover:border-white/20 hover:bg-white/[0.08] transition-colors",
3494
+ "text-xs text-white/60 font-mono min-w-[7.5rem] justify-start",
3495
+ "focus:outline-none focus:border-white/30",
3496
+ disabled && "opacity-50 cursor-not-allowed",
3497
+ className
3498
+ ),
3499
+ "aria-label": "Pick color",
3500
+ children: [
3501
+ /* @__PURE__ */ jsx50(
3502
+ "span",
3503
+ {
3504
+ className: "w-4 h-4 rounded-full border border-white/20 shrink-0 inline-block",
3505
+ style: { background: cssColor }
3506
+ }
3507
+ ),
3508
+ /* @__PURE__ */ jsx50("span", { children: hexValue.toUpperCase() })
3509
+ ]
3491
3510
  }
3492
- )
3511
+ ) }),
3512
+ /* @__PURE__ */ jsx50(Popover2.Portal, { children: /* @__PURE__ */ jsx50(
3513
+ Popover2.Content,
3514
+ {
3515
+ sideOffset: 6,
3516
+ align: "start",
3517
+ className: cn(
3518
+ "z-[9999] rounded-xl shadow-2xl p-3 w-[14rem]",
3519
+ "bg-[#0f1117] border border-white/10",
3520
+ "focus:outline-none"
3521
+ ),
3522
+ onInteractOutside: () => handleOpenChange(false),
3523
+ children: open && /* @__PURE__ */ jsxs34(ColorPicker, { defaultValue: hexValue, className: "gap-2.5", children: [
3524
+ /* @__PURE__ */ jsx50(ColorReader, { onHexChange: handleHexChange }),
3525
+ /* @__PURE__ */ jsx50(ColorPickerSelection, { className: "h-32 w-full rounded-lg" }),
3526
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-3", children: [
3527
+ /* @__PURE__ */ jsx50(ColorPickerEyeDropper, {}),
3528
+ /* @__PURE__ */ jsxs34("div", { className: "flex flex-col gap-1.5 flex-1", children: [
3529
+ /* @__PURE__ */ jsx50(ColorPickerHue, {}),
3530
+ /* @__PURE__ */ jsx50(ColorPickerAlpha, {})
3531
+ ] })
3532
+ ] }),
3533
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-1.5", children: [
3534
+ /* @__PURE__ */ jsx50(ColorPickerOutput, {}),
3535
+ /* @__PURE__ */ jsx50(ColorPickerFormat, {})
3536
+ ] })
3537
+ ] }, hexValue)
3538
+ }
3539
+ ) })
3493
3540
  ] });
3494
3541
  }
3495
3542
 
@@ -3856,8 +3903,10 @@ export {
3856
3903
  ColorPicker,
3857
3904
  ColorPickerAlpha,
3858
3905
  ColorPickerEyeDropper,
3906
+ ColorPickerFormat,
3859
3907
  ColorPickerHexOutput,
3860
3908
  ColorPickerHue,
3909
+ ColorPickerOutput,
3861
3910
  ColorPickerSelection,
3862
3911
  ConfirmDialog,
3863
3912
  DashboardLayout,