@particle-academy/react-fancy 4.4.6 → 4.5.0

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
@@ -2567,7 +2567,22 @@ var Button = forwardRef(
2567
2567
  trailingElements
2568
2568
  ] });
2569
2569
  const safeHref = sanitizeHref(href);
2570
- const buttonEl = safeHref && !disabled ? /* @__PURE__ */ jsx("a", { href: safeHref, className: classes, "data-react-fancy-button": "", "data-react-fancy-action": "", children: content }) : /* @__PURE__ */ jsx(
2570
+ const buttonEl = safeHref && !disabled ? (
2571
+ // Anchor mode forwards the same rest props as the <button> branch so
2572
+ // onClick / target / rel / ref / ARIA / data-* reach the <a> (issue #7).
2573
+ /* @__PURE__ */ jsx(
2574
+ "a",
2575
+ {
2576
+ ref,
2577
+ href: safeHref,
2578
+ className: classes,
2579
+ "data-react-fancy-button": "",
2580
+ "data-react-fancy-action": "",
2581
+ ...props,
2582
+ children: content
2583
+ }
2584
+ )
2585
+ ) : /* @__PURE__ */ jsx(
2571
2586
  "button",
2572
2587
  {
2573
2588
  ref,
@@ -3062,6 +3077,44 @@ function InputWrapper({
3062
3077
  hasInsideSuffix && /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-3 z-10 text-zinc-400 dark:text-zinc-500", children: suffix })
3063
3078
  ] });
3064
3079
  }
3080
+ var FieldModeContext = createContext(null);
3081
+ function useFieldMode(explicit) {
3082
+ const ctx = useContext(FieldModeContext);
3083
+ return explicit ?? ctx?.mode ?? "edit";
3084
+ }
3085
+ function isEmpty(value) {
3086
+ return value === null || value === void 0 || value === "";
3087
+ }
3088
+ function DisplayValue({
3089
+ children,
3090
+ size = "md",
3091
+ leading,
3092
+ trailing,
3093
+ empty = "\u2014",
3094
+ className
3095
+ }) {
3096
+ const empties = isEmpty(children);
3097
+ return /* @__PURE__ */ jsxs(
3098
+ "div",
3099
+ {
3100
+ "data-react-fancy-display": "",
3101
+ "data-mode": "view",
3102
+ className: cn(
3103
+ "flex w-full items-center gap-2 text-zinc-900 dark:text-zinc-100",
3104
+ inputSizeClasses[size],
3105
+ // Strip the editable box look — keep only the size/padding rhythm.
3106
+ "border-0 bg-transparent px-0",
3107
+ empties && "text-zinc-400 dark:text-zinc-500",
3108
+ className
3109
+ ),
3110
+ children: [
3111
+ leading && /* @__PURE__ */ jsx("span", { className: "text-zinc-400 dark:text-zinc-500", children: leading }),
3112
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: empties ? empty : children }),
3113
+ trailing && /* @__PURE__ */ jsx("span", { className: "text-zinc-400 dark:text-zinc-500", children: trailing })
3114
+ ]
3115
+ }
3116
+ );
3117
+ }
3065
3118
  var Input = forwardRef(
3066
3119
  ({
3067
3120
  type = "text",
@@ -3080,13 +3133,15 @@ var Input = forwardRef(
3080
3133
  suffix,
3081
3134
  prefixPosition,
3082
3135
  suffixPosition,
3136
+ mode,
3083
3137
  onValueChange,
3084
3138
  onChange,
3085
3139
  ...props
3086
3140
  }, ref) => {
3087
3141
  const autoId = useId();
3088
3142
  const inputId = id ?? autoId;
3089
- const input = /* @__PURE__ */ jsx(
3143
+ const resolvedMode = useFieldMode(mode);
3144
+ const input = resolvedMode === "view" ? /* @__PURE__ */ jsx(DisplayValue, { size, leading: leading ?? prefix, trailing: trailing ?? suffix, children: type === "password" ? props.value ? "\u2022\u2022\u2022\u2022\u2022\u2022" : "" : props.value }) : /* @__PURE__ */ jsx(
3090
3145
  InputWrapper,
3091
3146
  {
3092
3147
  prefix,
@@ -3161,6 +3216,7 @@ var Textarea = forwardRef(
3161
3216
  suffix,
3162
3217
  prefixPosition: _prefixPosition,
3163
3218
  suffixPosition: _suffixPosition,
3219
+ mode,
3164
3220
  onValueChange,
3165
3221
  onChange,
3166
3222
  value,
@@ -3170,6 +3226,7 @@ var Textarea = forwardRef(
3170
3226
  const autoId = useId();
3171
3227
  const textareaId = id ?? autoId;
3172
3228
  const internalRef = useRef(null);
3229
+ const resolvedMode = useFieldMode(mode);
3173
3230
  useEffect(() => {
3174
3231
  const el = internalRef.current;
3175
3232
  if (!autoResize || !el) return;
@@ -3179,7 +3236,7 @@ var Textarea = forwardRef(
3179
3236
  const maxHeight = maxRows ? maxRows * lineHeight : Infinity;
3180
3237
  el.style.height = `${Math.min(Math.max(el.scrollHeight, minHeight), maxHeight)}px`;
3181
3238
  }, [autoResize, minRows, maxRows, value, defaultValue]);
3182
- const textarea = /* @__PURE__ */ jsx(
3239
+ const textarea = resolvedMode === "view" ? /* @__PURE__ */ jsx(DisplayValue, { size, className: "whitespace-pre-wrap", children: value ?? defaultValue }) : /* @__PURE__ */ jsx(
3183
3240
  InputWrapper,
3184
3241
  {
3185
3242
  prefix,
@@ -3451,6 +3508,7 @@ var NativeSelect = forwardRef(
3451
3508
  suffix,
3452
3509
  prefixPosition,
3453
3510
  suffixPosition,
3511
+ mode,
3454
3512
  onValueChange,
3455
3513
  onChange,
3456
3514
  value,
@@ -3459,6 +3517,27 @@ var NativeSelect = forwardRef(
3459
3517
  }, ref) => {
3460
3518
  const autoId = useId();
3461
3519
  const selectId = id ?? autoId;
3520
+ const resolvedMode = useFieldMode(mode);
3521
+ if (resolvedMode === "view") {
3522
+ const current = value ?? defaultValue;
3523
+ const opt = flattenOptions(list).map((o) => resolveOption(o)).find((o) => o.value === current);
3524
+ const display = /* @__PURE__ */ jsx(DisplayValue, { size, leading: prefix, trailing: suffix, children: opt?.label ?? current });
3525
+ if (label || error || description) {
3526
+ return /* @__PURE__ */ jsx(
3527
+ Field,
3528
+ {
3529
+ label,
3530
+ description,
3531
+ error,
3532
+ required,
3533
+ htmlFor: selectId,
3534
+ size,
3535
+ children: display
3536
+ }
3537
+ );
3538
+ }
3539
+ return display;
3540
+ }
3462
3541
  const isControlled = value !== void 0;
3463
3542
  const resolvedDefault = !isControlled && defaultValue === void 0 && placeholder ? "" : defaultValue;
3464
3543
  const select = /* @__PURE__ */ jsx(
@@ -3547,11 +3626,13 @@ var ListboxSelect = forwardRef(
3547
3626
  createLabel = "Create",
3548
3627
  selectedSuffix = "selected",
3549
3628
  indicator = "check",
3629
+ mode,
3550
3630
  value: controlledSingleValue,
3551
3631
  defaultValue: defaultSingleValue
3552
3632
  }, _ref) => {
3553
3633
  const autoId = useId();
3554
3634
  const selectId = id ?? autoId;
3635
+ const resolvedMode = useFieldMode(mode);
3555
3636
  const textInputEnabled = searchable || creatable;
3556
3637
  const [open, setOpen] = useState(false);
3557
3638
  const [search2, setSearch] = useState("");
@@ -3678,6 +3759,27 @@ var ListboxSelect = forwardRef(
3678
3759
  }
3679
3760
  }
3680
3761
  };
3762
+ if (resolvedMode === "view") {
3763
+ const labels = multiple ? currentMulti.map(
3764
+ (v) => resolvedOptions.find((o) => o.value === v)?.label ?? v
3765
+ ) : currentSingle ? [resolvedOptions.find((o) => o.value === currentSingle)?.label ?? currentSingle] : [];
3766
+ const display = /* @__PURE__ */ jsx(DisplayValue, { size, children: labels.join(", ") });
3767
+ if (label || error || description) {
3768
+ return /* @__PURE__ */ jsx(
3769
+ Field,
3770
+ {
3771
+ label,
3772
+ description,
3773
+ error,
3774
+ required,
3775
+ htmlFor: selectId,
3776
+ size,
3777
+ children: display
3778
+ }
3779
+ );
3780
+ }
3781
+ return display;
3782
+ }
3681
3783
  const trigger = /* @__PURE__ */ jsxs(
3682
3784
  "button",
3683
3785
  {
@@ -3853,11 +3955,13 @@ var Checkbox = forwardRef(
3853
3955
  checked: controlledChecked,
3854
3956
  defaultChecked = false,
3855
3957
  onCheckedChange,
3856
- indeterminate
3958
+ indeterminate,
3959
+ mode
3857
3960
  }, ref) => {
3858
3961
  const autoId = useId();
3859
3962
  const checkboxId = id ?? autoId;
3860
3963
  const internalRef = useRef(null);
3964
+ const resolvedMode = useFieldMode(mode);
3861
3965
  const [checked, setChecked] = useControllableState(
3862
3966
  controlledChecked,
3863
3967
  defaultChecked,
@@ -3876,8 +3980,21 @@ var Checkbox = forwardRef(
3876
3980
  lg: "h-5 w-5",
3877
3981
  xl: "h-6 w-6"
3878
3982
  }[size];
3983
+ const glyph = indeterminate ? "\u2014" : checked ? "\u2713" : "\u2715";
3879
3984
  return /* @__PURE__ */ jsxs("div", { "data-react-fancy-checkbox": "", className: cn("flex items-start gap-2", className), children: [
3880
- /* @__PURE__ */ jsx("div", { className: "relative flex items-center", children: /* @__PURE__ */ jsx(
3985
+ resolvedMode === "view" ? /* @__PURE__ */ jsx(
3986
+ "span",
3987
+ {
3988
+ "data-react-fancy-display": "",
3989
+ "data-mode": "view",
3990
+ className: cn(
3991
+ "flex shrink-0 items-center justify-center text-zinc-700 dark:text-zinc-200",
3992
+ sizeClasses6
3993
+ ),
3994
+ "aria-hidden": "true",
3995
+ children: glyph
3996
+ }
3997
+ ) : /* @__PURE__ */ jsx("div", { className: "relative flex items-center", children: /* @__PURE__ */ jsx(
3881
3998
  "input",
3882
3999
  {
3883
4000
  ref: (node) => {
@@ -3939,9 +4056,11 @@ function CheckboxGroup({
3939
4056
  value: controlledValue,
3940
4057
  defaultValue = [],
3941
4058
  onValueChange,
3942
- orientation = "vertical"
4059
+ orientation = "vertical",
4060
+ mode
3943
4061
  }) {
3944
4062
  const groupId = useId();
4063
+ const resolvedMode = useFieldMode(mode);
3945
4064
  const [value, setValue] = useControllableState(
3946
4065
  controlledValue,
3947
4066
  defaultValue,
@@ -3958,7 +4077,7 @@ function CheckboxGroup({
3958
4077
  lg: "h-5 w-5",
3959
4078
  xl: "h-6 w-6"
3960
4079
  }[size];
3961
- const content = /* @__PURE__ */ jsx(
4080
+ const content = resolvedMode === "view" ? /* @__PURE__ */ jsx(DisplayValue, { size, children: list.map(resolveOption).filter((o) => value.includes(o.value)).map((o) => o.label).join(", ") }) : /* @__PURE__ */ jsx(
3962
4081
  "div",
3963
4082
  {
3964
4083
  "data-react-fancy-checkbox-group": "",
@@ -4038,10 +4157,12 @@ function RadioGroup({
4038
4157
  value: controlledValue,
4039
4158
  defaultValue,
4040
4159
  onValueChange,
4041
- orientation = "vertical"
4160
+ orientation = "vertical",
4161
+ mode
4042
4162
  }) {
4043
4163
  const groupId = useId();
4044
4164
  const radioName = name ?? groupId;
4165
+ const resolvedMode = useFieldMode(mode);
4045
4166
  const [value, setValue] = useControllableState(
4046
4167
  controlledValue,
4047
4168
  defaultValue,
@@ -4054,7 +4175,7 @@ function RadioGroup({
4054
4175
  lg: "h-5 w-5",
4055
4176
  xl: "h-6 w-6"
4056
4177
  }[size];
4057
- const content = /* @__PURE__ */ jsx(
4178
+ const content = resolvedMode === "view" ? /* @__PURE__ */ jsx(DisplayValue, { size, children: list.map(resolveOption).find((o) => o.value === value)?.label }) : /* @__PURE__ */ jsx(
4058
4179
  "div",
4059
4180
  {
4060
4181
  "data-react-fancy-radio-group": "",
@@ -4162,10 +4283,12 @@ var Switch = forwardRef(
4162
4283
  checked: controlledChecked,
4163
4284
  defaultChecked = false,
4164
4285
  onCheckedChange,
4165
- color = "blue"
4286
+ color = "blue",
4287
+ mode
4166
4288
  }, ref) => {
4167
4289
  const autoId = useId();
4168
4290
  const switchId = id ?? autoId;
4291
+ const resolvedMode = useFieldMode(mode);
4169
4292
  const [checked, setChecked] = useControllableState(
4170
4293
  controlledChecked,
4171
4294
  defaultChecked,
@@ -4193,7 +4316,15 @@ var Switch = forwardRef(
4193
4316
  xl: "translate-x-6"
4194
4317
  }[size];
4195
4318
  return /* @__PURE__ */ jsxs("div", { "data-react-fancy-switch": "", className: cn("flex items-start gap-2", className), children: [
4196
- /* @__PURE__ */ jsx(
4319
+ resolvedMode === "view" ? /* @__PURE__ */ jsx(
4320
+ "span",
4321
+ {
4322
+ "data-react-fancy-display": "",
4323
+ "data-mode": "view",
4324
+ className: "text-sm font-medium text-zinc-700 dark:text-zinc-200",
4325
+ children: checked ? "On" : "Off"
4326
+ }
4327
+ ) : /* @__PURE__ */ jsx(
4197
4328
  "button",
4198
4329
  {
4199
4330
  ref,
@@ -4307,15 +4438,17 @@ var SingleSlider = forwardRef(
4307
4438
  marks,
4308
4439
  prefix,
4309
4440
  suffix,
4441
+ mode,
4310
4442
  ...rest
4311
4443
  }, ref) => {
4312
4444
  const singleProps = rest;
4445
+ const resolvedMode = useFieldMode(mode);
4313
4446
  const [value, setValue] = useControllableState(
4314
4447
  singleProps.value,
4315
4448
  singleProps.defaultValue ?? min,
4316
4449
  singleProps.onValueChange
4317
4450
  );
4318
- const slider = /* @__PURE__ */ jsxs("div", { "data-react-fancy-slider": "", className: cn("flex flex-col gap-1", className), children: [
4451
+ const slider = resolvedMode === "view" ? /* @__PURE__ */ jsx(DisplayValue, { size, className, children: `${prefix ?? ""}${value}${suffix ?? ""}` }) : /* @__PURE__ */ jsxs("div", { "data-react-fancy-slider": "", className: cn("flex flex-col gap-1", className), children: [
4319
4452
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
4320
4453
  /* @__PURE__ */ jsx(
4321
4454
  "input",
@@ -4377,9 +4510,11 @@ var RangeSlider = forwardRef(
4377
4510
  marks,
4378
4511
  prefix,
4379
4512
  suffix,
4513
+ mode,
4380
4514
  ...rest
4381
4515
  }, ref) => {
4382
4516
  const rangeProps = rest;
4517
+ const resolvedMode = useFieldMode(mode);
4383
4518
  const [value, setValue] = useControllableState(
4384
4519
  rangeProps.value,
4385
4520
  rangeProps.defaultValue ?? [min, max],
@@ -4393,7 +4528,7 @@ var RangeSlider = forwardRef(
4393
4528
  };
4394
4529
  const leftPercent = (value[0] - min) / (max - min) * 100;
4395
4530
  const rightPercent = (value[1] - min) / (max - min) * 100;
4396
- const slider = /* @__PURE__ */ jsxs("div", { "data-react-fancy-slider": "", className: cn("flex flex-col gap-1", className), children: [
4531
+ const slider = resolvedMode === "view" ? /* @__PURE__ */ jsx(DisplayValue, { size, className, children: `${prefix ?? ""}${value[0]}${suffix ?? ""}\u2013${prefix ?? ""}${value[1]}${suffix ?? ""}` }) : /* @__PURE__ */ jsxs("div", { "data-react-fancy-slider": "", className: cn("flex flex-col gap-1", className), children: [
4397
4532
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
4398
4533
  /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
4399
4534
  /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute top-1/2 h-1.5 w-full -translate-y-1/2 rounded-full bg-zinc-200 dark:bg-zinc-700" }),
@@ -4495,10 +4630,12 @@ function MultiSwitch({
4495
4630
  value: controlledValue,
4496
4631
  defaultValue,
4497
4632
  onValueChange,
4498
- linear
4633
+ linear,
4634
+ mode
4499
4635
  }) {
4500
4636
  const resolvedOptions = list.map(resolveOption);
4501
4637
  const fallback = defaultValue ?? resolvedOptions[0]?.value;
4638
+ const resolvedMode = useFieldMode(mode);
4502
4639
  const [value, setValue] = useControllableState(controlledValue, fallback, onValueChange);
4503
4640
  const containerRef = useRef(null);
4504
4641
  const itemRefs = useRef([]);
@@ -4523,7 +4660,7 @@ function MultiSwitch({
4523
4660
  useEffect(() => {
4524
4661
  updateIndicator();
4525
4662
  }, [updateIndicator]);
4526
- const control = /* @__PURE__ */ jsxs(
4663
+ const control = resolvedMode === "view" ? /* @__PURE__ */ jsx(DisplayValue, { size, children: resolvedOptions.find((o) => o.value === value)?.label }) : /* @__PURE__ */ jsxs(
4527
4664
  "div",
4528
4665
  {
4529
4666
  ref: containerRef,
@@ -4586,6 +4723,22 @@ function MultiSwitch({
4586
4723
  return control;
4587
4724
  }
4588
4725
  MultiSwitch.displayName = "MultiSwitch";
4726
+ function formatDateValue(iso, includeTime) {
4727
+ if (!iso) return "";
4728
+ const date = new Date(iso);
4729
+ if (Number.isNaN(date.getTime())) return iso;
4730
+ return includeTime ? date.toLocaleString(void 0, {
4731
+ year: "numeric",
4732
+ month: "short",
4733
+ day: "numeric",
4734
+ hour: "2-digit",
4735
+ minute: "2-digit"
4736
+ }) : date.toLocaleDateString(void 0, {
4737
+ year: "numeric",
4738
+ month: "short",
4739
+ day: "numeric"
4740
+ });
4741
+ }
4589
4742
  var DatePicker = forwardRef(
4590
4743
  (props, ref) => {
4591
4744
  const {
@@ -4652,17 +4805,20 @@ var SingleDatePicker = forwardRef(
4652
4805
  name,
4653
4806
  min,
4654
4807
  max,
4808
+ includeTime,
4809
+ mode,
4655
4810
  inputType,
4656
4811
  inputClasses,
4657
4812
  ...rest
4658
4813
  }, ref) => {
4659
4814
  const singleProps = rest;
4815
+ const resolvedMode = useFieldMode(mode);
4660
4816
  const [value, setValue] = useControllableState(
4661
4817
  singleProps.value,
4662
4818
  singleProps.defaultValue ?? "",
4663
4819
  singleProps.onValueChange
4664
4820
  );
4665
- const input = /* @__PURE__ */ jsx(
4821
+ const input = resolvedMode === "view" ? /* @__PURE__ */ jsx(DisplayValue, { size, className, children: formatDateValue(value, includeTime) }) : /* @__PURE__ */ jsx(
4666
4822
  "input",
4667
4823
  {
4668
4824
  "data-react-fancy-date-picker": "",
@@ -4710,17 +4866,20 @@ var RangeDatePicker = forwardRef(
4710
4866
  name,
4711
4867
  min,
4712
4868
  max,
4869
+ includeTime,
4870
+ mode,
4713
4871
  inputType,
4714
4872
  inputClasses,
4715
4873
  ...rest
4716
4874
  }, ref) => {
4717
4875
  const rangeProps = rest;
4876
+ const resolvedMode = useFieldMode(mode);
4718
4877
  const [value, setValue] = useControllableState(
4719
4878
  rangeProps.value,
4720
4879
  rangeProps.defaultValue ?? ["", ""],
4721
4880
  rangeProps.onValueChange
4722
4881
  );
4723
- const input = /* @__PURE__ */ jsxs("div", { "data-react-fancy-date-picker": "", className: cn("flex items-center gap-2", className), children: [
4882
+ const input = resolvedMode === "view" ? /* @__PURE__ */ jsx(DisplayValue, { size, className, children: value[0] || value[1] ? `${formatDateValue(value[0], includeTime)} \u2013 ${formatDateValue(value[1], includeTime)}` : "" }) : /* @__PURE__ */ jsxs("div", { "data-react-fancy-date-picker": "", className: cn("flex items-center gap-2", className), children: [
4724
4883
  /* @__PURE__ */ jsx(
4725
4884
  "input",
4726
4885
  {
@@ -4770,6 +4929,13 @@ var RangeDatePicker = forwardRef(
4770
4929
  }
4771
4930
  );
4772
4931
  RangeDatePicker.displayName = "RangeDatePicker";
4932
+ function FormProvider({ mode = "edit", children }) {
4933
+ const value = useMemo(() => ({ mode }), [mode]);
4934
+ return /* @__PURE__ */ jsx(FieldModeContext.Provider, { value, children });
4935
+ }
4936
+ function Form({ mode, children, ...formProps }) {
4937
+ return /* @__PURE__ */ jsx(FormProvider, { mode, children: /* @__PURE__ */ jsx("form", { "data-react-fancy-form": "", ...formProps, children }) });
4938
+ }
4773
4939
  var CarouselContext = createContext(null);
4774
4940
  CarouselContext.displayName = "CarouselContext";
4775
4941
  function useCarousel() {
@@ -5109,13 +5275,15 @@ var ColorPicker = forwardRef(
5109
5275
  size = "md",
5110
5276
  variant = "outline",
5111
5277
  disabled = false,
5112
- className
5278
+ className,
5279
+ mode
5113
5280
  }, ref) => {
5114
5281
  const [color, setColor] = useControllableState(
5115
5282
  value,
5116
5283
  defaultValue,
5117
5284
  onChange
5118
5285
  );
5286
+ const resolvedMode = useFieldMode(mode);
5119
5287
  const inputRef = useRef(null);
5120
5288
  const datalistId = useId();
5121
5289
  const handleChange = (e) => {
@@ -5126,6 +5294,42 @@ var ColorPicker = forwardRef(
5126
5294
  inputRef.current?.click();
5127
5295
  }
5128
5296
  };
5297
+ if (resolvedMode === "view") {
5298
+ return /* @__PURE__ */ jsxs(
5299
+ "div",
5300
+ {
5301
+ ref,
5302
+ "data-react-fancy-color-picker": "",
5303
+ "data-mode": "view",
5304
+ className: cn("inline-flex items-center gap-2", className),
5305
+ children: [
5306
+ /* @__PURE__ */ jsx(
5307
+ "span",
5308
+ {
5309
+ className: cn(
5310
+ "shrink-0 rounded-full",
5311
+ SWATCH_SIZES[size],
5312
+ variant === "outline" && "ring-1 ring-zinc-300 dark:ring-zinc-600"
5313
+ ),
5314
+ style: { backgroundColor: color },
5315
+ "aria-label": `Color: ${color}`
5316
+ }
5317
+ ),
5318
+ /* @__PURE__ */ jsx(
5319
+ "span",
5320
+ {
5321
+ className: cn(
5322
+ "select-all font-mono uppercase",
5323
+ TEXT_SIZES[size],
5324
+ "text-zinc-700 dark:text-zinc-300"
5325
+ ),
5326
+ children: color.toUpperCase()
5327
+ }
5328
+ )
5329
+ ]
5330
+ }
5331
+ );
5332
+ }
5129
5333
  return /* @__PURE__ */ jsxs(
5130
5334
  "div",
5131
5335
  {
@@ -6015,6 +6219,14 @@ var Badge = forwardRef(
6015
6219
  }
6016
6220
  );
6017
6221
  Badge.displayName = "Badge";
6222
+ var glowColors = {
6223
+ on: "#a855f7",
6224
+ // violet — neutral
6225
+ xp: "#22c55e",
6226
+ // green
6227
+ achievement: "#f59e0b"
6228
+ // amber
6229
+ };
6018
6230
  var containerSizeClasses = {
6019
6231
  xs: "h-6 w-6",
6020
6232
  sm: "h-8 w-8",
@@ -6049,8 +6261,10 @@ var Avatar = forwardRef(
6049
6261
  fallback,
6050
6262
  size = "md",
6051
6263
  status,
6264
+ glow,
6052
6265
  className
6053
6266
  }, ref) => {
6267
+ const glowKey = glow === true ? "on" : glow || null;
6054
6268
  return /* @__PURE__ */ jsxs(
6055
6269
  "div",
6056
6270
  {
@@ -6063,6 +6277,15 @@ var Avatar = forwardRef(
6063
6277
  className
6064
6278
  ),
6065
6279
  children: [
6280
+ glowKey && /* @__PURE__ */ jsx(
6281
+ "span",
6282
+ {
6283
+ "aria-hidden": true,
6284
+ "data-react-fancy-avatar-glow": glowKey,
6285
+ className: "fancy-avatar-glow",
6286
+ style: { "--fancy-glow": glowColors[glowKey] }
6287
+ }
6288
+ ),
6066
6289
  src ? /* @__PURE__ */ jsx(
6067
6290
  "img",
6068
6291
  {
@@ -8853,13 +9076,15 @@ var Autocomplete = forwardRef(
8853
9076
  loading = false,
8854
9077
  emptyMessage = "No results found.",
8855
9078
  disabled = false,
8856
- className
9079
+ className,
9080
+ mode
8857
9081
  }, ref) {
8858
9082
  const [value, setValue] = useControllableState(
8859
9083
  controlledValue,
8860
9084
  defaultValue,
8861
9085
  onChange
8862
9086
  );
9087
+ const resolvedMode = useFieldMode(mode);
8863
9088
  const [query, setQuery] = useState(value);
8864
9089
  const [open, setOpen] = useState(false);
8865
9090
  const [activeIndex, setActiveIndex] = useState(-1);
@@ -8912,6 +9137,23 @@ var Autocomplete = forwardRef(
8912
9137
  if (item && !item.disabled) select(item.value);
8913
9138
  }
8914
9139
  };
9140
+ if (resolvedMode === "view") {
9141
+ const matched = options.find((o) => o.value === value);
9142
+ return /* @__PURE__ */ jsx(
9143
+ "div",
9144
+ {
9145
+ "data-react-fancy-autocomplete": "",
9146
+ "data-mode": "view",
9147
+ ref: wrapperRef,
9148
+ className: cn(
9149
+ "text-sm text-zinc-900 dark:text-zinc-100",
9150
+ !value && "text-zinc-400 dark:text-zinc-500",
9151
+ className
9152
+ ),
9153
+ children: matched?.label ?? value ?? "\u2014"
9154
+ }
9155
+ );
9156
+ }
8915
9157
  return /* @__PURE__ */ jsxs("div", { "data-react-fancy-autocomplete": "", ref: wrapperRef, className: cn("relative", className), children: [
8916
9158
  /* @__PURE__ */ jsx(
8917
9159
  "input",
@@ -9084,13 +9326,15 @@ var OtpInput = forwardRef(
9084
9326
  onChange,
9085
9327
  disabled = false,
9086
9328
  autoFocus = false,
9087
- className
9329
+ className,
9330
+ mode
9088
9331
  }, ref) {
9089
9332
  const [value, setValue] = useControllableState(
9090
9333
  controlledValue,
9091
9334
  "",
9092
9335
  onChange
9093
9336
  );
9337
+ const resolvedMode = useFieldMode(mode);
9094
9338
  const inputsRef = useRef([]);
9095
9339
  const focusInput = useCallback(
9096
9340
  (index) => {
@@ -9144,6 +9388,21 @@ var OtpInput = forwardRef(
9144
9388
  },
9145
9389
  [length, setValue, focusInput]
9146
9390
  );
9391
+ if (resolvedMode === "view") {
9392
+ return /* @__PURE__ */ jsx(
9393
+ "div",
9394
+ {
9395
+ "data-react-fancy-otp-input": "",
9396
+ "data-mode": "view",
9397
+ ref,
9398
+ className: cn(
9399
+ "font-mono text-lg tracking-[0.4em] text-zinc-900 dark:text-zinc-100",
9400
+ className
9401
+ ),
9402
+ children: value || "\u2014"
9403
+ }
9404
+ );
9405
+ }
9147
9406
  return /* @__PURE__ */ jsx("div", { "data-react-fancy-otp-input": "", ref, className: cn("flex gap-2", className), children: Array.from({ length }, (_, i) => /* @__PURE__ */ jsx(
9148
9407
  "input",
9149
9408
  {
@@ -9358,16 +9617,34 @@ var TimePicker = forwardRef(
9358
9617
  format = "12h",
9359
9618
  minuteStep = 1,
9360
9619
  disabled = false,
9361
- className
9620
+ className,
9621
+ mode
9362
9622
  }, ref) {
9363
9623
  const [value, setValue] = useControllableState(
9364
9624
  controlledValue,
9365
9625
  defaultValue,
9366
9626
  onChange
9367
9627
  );
9628
+ const resolvedMode = useFieldMode(mode);
9368
9629
  const { hours: h24, minutes } = parseTime(value);
9369
9630
  const isPM = h24 >= 12;
9370
9631
  const displayHour = format === "12h" ? h24 % 12 || 12 : h24;
9632
+ if (resolvedMode === "view") {
9633
+ const formatted = format === "12h" ? `${pad(displayHour)}:${pad(minutes)} ${isPM ? "PM" : "AM"}` : `${pad(displayHour)}:${pad(minutes)}`;
9634
+ return /* @__PURE__ */ jsx(
9635
+ "div",
9636
+ {
9637
+ "data-react-fancy-time-picker": "",
9638
+ "data-mode": "view",
9639
+ ref,
9640
+ className: cn(
9641
+ "text-sm font-medium tabular-nums text-zinc-900 dark:text-zinc-100",
9642
+ className
9643
+ ),
9644
+ children: formatted
9645
+ }
9646
+ );
9647
+ }
9371
9648
  const updateTime = useCallback(
9372
9649
  (hours, mins) => {
9373
9650
  setValue(`${pad(hours)}:${pad(mins)}`);
@@ -13687,6 +13964,6 @@ function caretRect(ta, start, end) {
13687
13964
  return { x, y };
13688
13965
  }
13689
13966
 
13690
- export { Accordion, AccordionPanel, AccordionPanelContent, AccordionPanelSection, AccordionPanelTrigger, Action, Autocomplete, Avatar, Badge, Brand, Breadcrumbs, Button, Calendar, Callout, Card, Carousel, Chart, ChatDrawer, Checkbox, CheckboxGroup, ColorPicker, Command, Composer, ContentRenderer, ContextMenu, DatePicker, Dropdown, EMOJI_CATEGORY_ORDER, EMOJI_DATA, EMOJI_ENTRIES, Editor, Emoji, EmojiSelect, FauxClient, Field, FileUpload, Heading, Icon, Input, InputTag, Kanban, MagicWand, Menu2 as Menu, MobileMenu, Modal, MoodMeter, MultiSwitch, Navbar, OtpInput, Pagination, Pillbox, Popover, Portal, Profile, Progress, PromptInput, RadioGroup, ReasonTag, SKIN_TONES, Select, Separator, Sidebar, Skeleton, Slider, StickyNote, Switch, Table, Tabs, Text, Textarea, TimeGrid, TimePicker, Timeline, Toast, Tooltip, TreeNav, applyTone, cn, configureIcons, contentEditableAdapter, controlledAdapter, find, hasSkinTones, inputAdapter, registerExtension, registerExtensions, registerIconSet, registerIcons, resolve, sanitizeHref, sanitizeHtml, search, skinTones, textareaAdapter, useAccordion, useAccordionPanel, useAccordionSection, useAnimation, useCarousel, useCommand, useContextMenu, useControllableState, useDropdown, useEditor, useEscapeKey, useFileUpload, useFloatingPosition, useFocusTrap, useId12 as useId, useKanban, useMenu, useMobileMenu, useModal, useNavbar, useNodeRegistry, useOutsideClick, usePanZoom, usePopover, useSidebar, useTabs, useToast, useTreeNav };
13967
+ export { Accordion, AccordionPanel, AccordionPanelContent, AccordionPanelSection, AccordionPanelTrigger, Action, Autocomplete, Avatar, Badge, Brand, Breadcrumbs, Button, Calendar, Callout, Card, Carousel, Chart, ChatDrawer, Checkbox, CheckboxGroup, ColorPicker, Command, Composer, ContentRenderer, ContextMenu, DatePicker, DisplayValue, Dropdown, EMOJI_CATEGORY_ORDER, EMOJI_DATA, EMOJI_ENTRIES, Editor, Emoji, EmojiSelect, FauxClient, Field, FieldModeContext, FileUpload, Form, FormProvider, Heading, Icon, Input, InputTag, Kanban, MagicWand, Menu2 as Menu, MobileMenu, Modal, MoodMeter, MultiSwitch, Navbar, OtpInput, Pagination, Pillbox, Popover, Portal, Profile, Progress, PromptInput, RadioGroup, ReasonTag, SKIN_TONES, Select, Separator, Sidebar, Skeleton, Slider, StickyNote, Switch, Table, Tabs, Text, Textarea, TimeGrid, TimePicker, Timeline, Toast, Tooltip, TreeNav, applyTone, cn, configureIcons, contentEditableAdapter, controlledAdapter, find, hasSkinTones, inputAdapter, registerExtension, registerExtensions, registerIconSet, registerIcons, resolve, sanitizeHref, sanitizeHtml, search, skinTones, textareaAdapter, useAccordion, useAccordionPanel, useAccordionSection, useAnimation, useCarousel, useCommand, useContextMenu, useControllableState, useDropdown, useEditor, useEscapeKey, useFieldMode, useFileUpload, useFloatingPosition, useFocusTrap, useId12 as useId, useKanban, useMenu, useMobileMenu, useModal, useNavbar, useNodeRegistry, useOutsideClick, usePanZoom, usePopover, useSidebar, useTabs, useToast, useTreeNav };
13691
13968
  //# sourceMappingURL=index.js.map
13692
13969
  //# sourceMappingURL=index.js.map