@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.cjs CHANGED
@@ -2569,7 +2569,22 @@ var Button = react.forwardRef(
2569
2569
  trailingElements
2570
2570
  ] });
2571
2571
  const safeHref = sanitizeHref(href);
2572
- const buttonEl = safeHref && !disabled ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: safeHref, className: classes, "data-react-fancy-button": "", "data-react-fancy-action": "", children: content }) : /* @__PURE__ */ jsxRuntime.jsx(
2572
+ const buttonEl = safeHref && !disabled ? (
2573
+ // Anchor mode forwards the same rest props as the <button> branch so
2574
+ // onClick / target / rel / ref / ARIA / data-* reach the <a> (issue #7).
2575
+ /* @__PURE__ */ jsxRuntime.jsx(
2576
+ "a",
2577
+ {
2578
+ ref,
2579
+ href: safeHref,
2580
+ className: classes,
2581
+ "data-react-fancy-button": "",
2582
+ "data-react-fancy-action": "",
2583
+ ...props,
2584
+ children: content
2585
+ }
2586
+ )
2587
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
2573
2588
  "button",
2574
2589
  {
2575
2590
  ref,
@@ -3064,6 +3079,44 @@ function InputWrapper({
3064
3079
  hasInsideSuffix && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute right-3 z-10 text-zinc-400 dark:text-zinc-500", children: suffix })
3065
3080
  ] });
3066
3081
  }
3082
+ var FieldModeContext = react.createContext(null);
3083
+ function useFieldMode(explicit) {
3084
+ const ctx = react.useContext(FieldModeContext);
3085
+ return explicit ?? ctx?.mode ?? "edit";
3086
+ }
3087
+ function isEmpty(value) {
3088
+ return value === null || value === void 0 || value === "";
3089
+ }
3090
+ function DisplayValue({
3091
+ children,
3092
+ size = "md",
3093
+ leading,
3094
+ trailing,
3095
+ empty = "\u2014",
3096
+ className
3097
+ }) {
3098
+ const empties = isEmpty(children);
3099
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3100
+ "div",
3101
+ {
3102
+ "data-react-fancy-display": "",
3103
+ "data-mode": "view",
3104
+ className: cn(
3105
+ "flex w-full items-center gap-2 text-zinc-900 dark:text-zinc-100",
3106
+ inputSizeClasses[size],
3107
+ // Strip the editable box look — keep only the size/padding rhythm.
3108
+ "border-0 bg-transparent px-0",
3109
+ empties && "text-zinc-400 dark:text-zinc-500",
3110
+ className
3111
+ ),
3112
+ children: [
3113
+ leading && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400 dark:text-zinc-500", children: leading }),
3114
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: empties ? empty : children }),
3115
+ trailing && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400 dark:text-zinc-500", children: trailing })
3116
+ ]
3117
+ }
3118
+ );
3119
+ }
3067
3120
  var Input = react.forwardRef(
3068
3121
  ({
3069
3122
  type = "text",
@@ -3082,13 +3135,15 @@ var Input = react.forwardRef(
3082
3135
  suffix,
3083
3136
  prefixPosition,
3084
3137
  suffixPosition,
3138
+ mode,
3085
3139
  onValueChange,
3086
3140
  onChange,
3087
3141
  ...props
3088
3142
  }, ref) => {
3089
3143
  const autoId = react.useId();
3090
3144
  const inputId = id ?? autoId;
3091
- const input = /* @__PURE__ */ jsxRuntime.jsx(
3145
+ const resolvedMode = useFieldMode(mode);
3146
+ const input = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, leading: leading ?? prefix, trailing: trailing ?? suffix, children: type === "password" ? props.value ? "\u2022\u2022\u2022\u2022\u2022\u2022" : "" : props.value }) : /* @__PURE__ */ jsxRuntime.jsx(
3092
3147
  InputWrapper,
3093
3148
  {
3094
3149
  prefix,
@@ -3163,6 +3218,7 @@ var Textarea = react.forwardRef(
3163
3218
  suffix,
3164
3219
  prefixPosition: _prefixPosition,
3165
3220
  suffixPosition: _suffixPosition,
3221
+ mode,
3166
3222
  onValueChange,
3167
3223
  onChange,
3168
3224
  value,
@@ -3172,6 +3228,7 @@ var Textarea = react.forwardRef(
3172
3228
  const autoId = react.useId();
3173
3229
  const textareaId = id ?? autoId;
3174
3230
  const internalRef = react.useRef(null);
3231
+ const resolvedMode = useFieldMode(mode);
3175
3232
  react.useEffect(() => {
3176
3233
  const el = internalRef.current;
3177
3234
  if (!autoResize || !el) return;
@@ -3181,7 +3238,7 @@ var Textarea = react.forwardRef(
3181
3238
  const maxHeight = maxRows ? maxRows * lineHeight : Infinity;
3182
3239
  el.style.height = `${Math.min(Math.max(el.scrollHeight, minHeight), maxHeight)}px`;
3183
3240
  }, [autoResize, minRows, maxRows, value, defaultValue]);
3184
- const textarea = /* @__PURE__ */ jsxRuntime.jsx(
3241
+ const textarea = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, className: "whitespace-pre-wrap", children: value ?? defaultValue }) : /* @__PURE__ */ jsxRuntime.jsx(
3185
3242
  InputWrapper,
3186
3243
  {
3187
3244
  prefix,
@@ -3453,6 +3510,7 @@ var NativeSelect = react.forwardRef(
3453
3510
  suffix,
3454
3511
  prefixPosition,
3455
3512
  suffixPosition,
3513
+ mode,
3456
3514
  onValueChange,
3457
3515
  onChange,
3458
3516
  value,
@@ -3461,6 +3519,27 @@ var NativeSelect = react.forwardRef(
3461
3519
  }, ref) => {
3462
3520
  const autoId = react.useId();
3463
3521
  const selectId = id ?? autoId;
3522
+ const resolvedMode = useFieldMode(mode);
3523
+ if (resolvedMode === "view") {
3524
+ const current = value ?? defaultValue;
3525
+ const opt = flattenOptions(list).map((o) => resolveOption(o)).find((o) => o.value === current);
3526
+ const display = /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, leading: prefix, trailing: suffix, children: opt?.label ?? current });
3527
+ if (label || error || description) {
3528
+ return /* @__PURE__ */ jsxRuntime.jsx(
3529
+ Field,
3530
+ {
3531
+ label,
3532
+ description,
3533
+ error,
3534
+ required,
3535
+ htmlFor: selectId,
3536
+ size,
3537
+ children: display
3538
+ }
3539
+ );
3540
+ }
3541
+ return display;
3542
+ }
3464
3543
  const isControlled = value !== void 0;
3465
3544
  const resolvedDefault = !isControlled && defaultValue === void 0 && placeholder ? "" : defaultValue;
3466
3545
  const select = /* @__PURE__ */ jsxRuntime.jsx(
@@ -3549,11 +3628,13 @@ var ListboxSelect = react.forwardRef(
3549
3628
  createLabel = "Create",
3550
3629
  selectedSuffix = "selected",
3551
3630
  indicator = "check",
3631
+ mode,
3552
3632
  value: controlledSingleValue,
3553
3633
  defaultValue: defaultSingleValue
3554
3634
  }, _ref) => {
3555
3635
  const autoId = react.useId();
3556
3636
  const selectId = id ?? autoId;
3637
+ const resolvedMode = useFieldMode(mode);
3557
3638
  const textInputEnabled = searchable || creatable;
3558
3639
  const [open, setOpen] = react.useState(false);
3559
3640
  const [search2, setSearch] = react.useState("");
@@ -3680,6 +3761,27 @@ var ListboxSelect = react.forwardRef(
3680
3761
  }
3681
3762
  }
3682
3763
  };
3764
+ if (resolvedMode === "view") {
3765
+ const labels = multiple ? currentMulti.map(
3766
+ (v) => resolvedOptions.find((o) => o.value === v)?.label ?? v
3767
+ ) : currentSingle ? [resolvedOptions.find((o) => o.value === currentSingle)?.label ?? currentSingle] : [];
3768
+ const display = /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, children: labels.join(", ") });
3769
+ if (label || error || description) {
3770
+ return /* @__PURE__ */ jsxRuntime.jsx(
3771
+ Field,
3772
+ {
3773
+ label,
3774
+ description,
3775
+ error,
3776
+ required,
3777
+ htmlFor: selectId,
3778
+ size,
3779
+ children: display
3780
+ }
3781
+ );
3782
+ }
3783
+ return display;
3784
+ }
3683
3785
  const trigger = /* @__PURE__ */ jsxRuntime.jsxs(
3684
3786
  "button",
3685
3787
  {
@@ -3855,11 +3957,13 @@ var Checkbox = react.forwardRef(
3855
3957
  checked: controlledChecked,
3856
3958
  defaultChecked = false,
3857
3959
  onCheckedChange,
3858
- indeterminate
3960
+ indeterminate,
3961
+ mode
3859
3962
  }, ref) => {
3860
3963
  const autoId = react.useId();
3861
3964
  const checkboxId = id ?? autoId;
3862
3965
  const internalRef = react.useRef(null);
3966
+ const resolvedMode = useFieldMode(mode);
3863
3967
  const [checked, setChecked] = useControllableState(
3864
3968
  controlledChecked,
3865
3969
  defaultChecked,
@@ -3878,8 +3982,21 @@ var Checkbox = react.forwardRef(
3878
3982
  lg: "h-5 w-5",
3879
3983
  xl: "h-6 w-6"
3880
3984
  }[size];
3985
+ const glyph = indeterminate ? "\u2014" : checked ? "\u2713" : "\u2715";
3881
3986
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-checkbox": "", className: cn("flex items-start gap-2", className), children: [
3882
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
3987
+ resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(
3988
+ "span",
3989
+ {
3990
+ "data-react-fancy-display": "",
3991
+ "data-mode": "view",
3992
+ className: cn(
3993
+ "flex shrink-0 items-center justify-center text-zinc-700 dark:text-zinc-200",
3994
+ sizeClasses6
3995
+ ),
3996
+ "aria-hidden": "true",
3997
+ children: glyph
3998
+ }
3999
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
3883
4000
  "input",
3884
4001
  {
3885
4002
  ref: (node) => {
@@ -3941,9 +4058,11 @@ function CheckboxGroup({
3941
4058
  value: controlledValue,
3942
4059
  defaultValue = [],
3943
4060
  onValueChange,
3944
- orientation = "vertical"
4061
+ orientation = "vertical",
4062
+ mode
3945
4063
  }) {
3946
4064
  const groupId = react.useId();
4065
+ const resolvedMode = useFieldMode(mode);
3947
4066
  const [value, setValue] = useControllableState(
3948
4067
  controlledValue,
3949
4068
  defaultValue,
@@ -3960,7 +4079,7 @@ function CheckboxGroup({
3960
4079
  lg: "h-5 w-5",
3961
4080
  xl: "h-6 w-6"
3962
4081
  }[size];
3963
- const content = /* @__PURE__ */ jsxRuntime.jsx(
4082
+ const content = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, children: list.map(resolveOption).filter((o) => value.includes(o.value)).map((o) => o.label).join(", ") }) : /* @__PURE__ */ jsxRuntime.jsx(
3964
4083
  "div",
3965
4084
  {
3966
4085
  "data-react-fancy-checkbox-group": "",
@@ -4040,10 +4159,12 @@ function RadioGroup({
4040
4159
  value: controlledValue,
4041
4160
  defaultValue,
4042
4161
  onValueChange,
4043
- orientation = "vertical"
4162
+ orientation = "vertical",
4163
+ mode
4044
4164
  }) {
4045
4165
  const groupId = react.useId();
4046
4166
  const radioName = name ?? groupId;
4167
+ const resolvedMode = useFieldMode(mode);
4047
4168
  const [value, setValue] = useControllableState(
4048
4169
  controlledValue,
4049
4170
  defaultValue,
@@ -4056,7 +4177,7 @@ function RadioGroup({
4056
4177
  lg: "h-5 w-5",
4057
4178
  xl: "h-6 w-6"
4058
4179
  }[size];
4059
- const content = /* @__PURE__ */ jsxRuntime.jsx(
4180
+ const content = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, children: list.map(resolveOption).find((o) => o.value === value)?.label }) : /* @__PURE__ */ jsxRuntime.jsx(
4060
4181
  "div",
4061
4182
  {
4062
4183
  "data-react-fancy-radio-group": "",
@@ -4164,10 +4285,12 @@ var Switch = react.forwardRef(
4164
4285
  checked: controlledChecked,
4165
4286
  defaultChecked = false,
4166
4287
  onCheckedChange,
4167
- color = "blue"
4288
+ color = "blue",
4289
+ mode
4168
4290
  }, ref) => {
4169
4291
  const autoId = react.useId();
4170
4292
  const switchId = id ?? autoId;
4293
+ const resolvedMode = useFieldMode(mode);
4171
4294
  const [checked, setChecked] = useControllableState(
4172
4295
  controlledChecked,
4173
4296
  defaultChecked,
@@ -4195,7 +4318,15 @@ var Switch = react.forwardRef(
4195
4318
  xl: "translate-x-6"
4196
4319
  }[size];
4197
4320
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-switch": "", className: cn("flex items-start gap-2", className), children: [
4198
- /* @__PURE__ */ jsxRuntime.jsx(
4321
+ resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(
4322
+ "span",
4323
+ {
4324
+ "data-react-fancy-display": "",
4325
+ "data-mode": "view",
4326
+ className: "text-sm font-medium text-zinc-700 dark:text-zinc-200",
4327
+ children: checked ? "On" : "Off"
4328
+ }
4329
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
4199
4330
  "button",
4200
4331
  {
4201
4332
  ref,
@@ -4309,15 +4440,17 @@ var SingleSlider = react.forwardRef(
4309
4440
  marks,
4310
4441
  prefix,
4311
4442
  suffix,
4443
+ mode,
4312
4444
  ...rest
4313
4445
  }, ref) => {
4314
4446
  const singleProps = rest;
4447
+ const resolvedMode = useFieldMode(mode);
4315
4448
  const [value, setValue] = useControllableState(
4316
4449
  singleProps.value,
4317
4450
  singleProps.defaultValue ?? min,
4318
4451
  singleProps.onValueChange
4319
4452
  );
4320
- const slider = /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-slider": "", className: cn("flex flex-col gap-1", className), children: [
4453
+ const slider = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, className, children: `${prefix ?? ""}${value}${suffix ?? ""}` }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-slider": "", className: cn("flex flex-col gap-1", className), children: [
4321
4454
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
4322
4455
  /* @__PURE__ */ jsxRuntime.jsx(
4323
4456
  "input",
@@ -4379,9 +4512,11 @@ var RangeSlider = react.forwardRef(
4379
4512
  marks,
4380
4513
  prefix,
4381
4514
  suffix,
4515
+ mode,
4382
4516
  ...rest
4383
4517
  }, ref) => {
4384
4518
  const rangeProps = rest;
4519
+ const resolvedMode = useFieldMode(mode);
4385
4520
  const [value, setValue] = useControllableState(
4386
4521
  rangeProps.value,
4387
4522
  rangeProps.defaultValue ?? [min, max],
@@ -4395,7 +4530,7 @@ var RangeSlider = react.forwardRef(
4395
4530
  };
4396
4531
  const leftPercent = (value[0] - min) / (max - min) * 100;
4397
4532
  const rightPercent = (value[1] - min) / (max - min) * 100;
4398
- const slider = /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-slider": "", className: cn("flex flex-col gap-1", className), children: [
4533
+ const slider = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, className, children: `${prefix ?? ""}${value[0]}${suffix ?? ""}\u2013${prefix ?? ""}${value[1]}${suffix ?? ""}` }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-slider": "", className: cn("flex flex-col gap-1", className), children: [
4399
4534
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
4400
4535
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
4401
4536
  /* @__PURE__ */ jsxRuntime.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" }),
@@ -4497,10 +4632,12 @@ function MultiSwitch({
4497
4632
  value: controlledValue,
4498
4633
  defaultValue,
4499
4634
  onValueChange,
4500
- linear
4635
+ linear,
4636
+ mode
4501
4637
  }) {
4502
4638
  const resolvedOptions = list.map(resolveOption);
4503
4639
  const fallback = defaultValue ?? resolvedOptions[0]?.value;
4640
+ const resolvedMode = useFieldMode(mode);
4504
4641
  const [value, setValue] = useControllableState(controlledValue, fallback, onValueChange);
4505
4642
  const containerRef = react.useRef(null);
4506
4643
  const itemRefs = react.useRef([]);
@@ -4525,7 +4662,7 @@ function MultiSwitch({
4525
4662
  react.useEffect(() => {
4526
4663
  updateIndicator();
4527
4664
  }, [updateIndicator]);
4528
- const control = /* @__PURE__ */ jsxRuntime.jsxs(
4665
+ const control = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, children: resolvedOptions.find((o) => o.value === value)?.label }) : /* @__PURE__ */ jsxRuntime.jsxs(
4529
4666
  "div",
4530
4667
  {
4531
4668
  ref: containerRef,
@@ -4588,6 +4725,22 @@ function MultiSwitch({
4588
4725
  return control;
4589
4726
  }
4590
4727
  MultiSwitch.displayName = "MultiSwitch";
4728
+ function formatDateValue(iso, includeTime) {
4729
+ if (!iso) return "";
4730
+ const date = new Date(iso);
4731
+ if (Number.isNaN(date.getTime())) return iso;
4732
+ return includeTime ? date.toLocaleString(void 0, {
4733
+ year: "numeric",
4734
+ month: "short",
4735
+ day: "numeric",
4736
+ hour: "2-digit",
4737
+ minute: "2-digit"
4738
+ }) : date.toLocaleDateString(void 0, {
4739
+ year: "numeric",
4740
+ month: "short",
4741
+ day: "numeric"
4742
+ });
4743
+ }
4591
4744
  var DatePicker = react.forwardRef(
4592
4745
  (props, ref) => {
4593
4746
  const {
@@ -4654,17 +4807,20 @@ var SingleDatePicker = react.forwardRef(
4654
4807
  name,
4655
4808
  min,
4656
4809
  max,
4810
+ includeTime,
4811
+ mode,
4657
4812
  inputType,
4658
4813
  inputClasses,
4659
4814
  ...rest
4660
4815
  }, ref) => {
4661
4816
  const singleProps = rest;
4817
+ const resolvedMode = useFieldMode(mode);
4662
4818
  const [value, setValue] = useControllableState(
4663
4819
  singleProps.value,
4664
4820
  singleProps.defaultValue ?? "",
4665
4821
  singleProps.onValueChange
4666
4822
  );
4667
- const input = /* @__PURE__ */ jsxRuntime.jsx(
4823
+ const input = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, className, children: formatDateValue(value, includeTime) }) : /* @__PURE__ */ jsxRuntime.jsx(
4668
4824
  "input",
4669
4825
  {
4670
4826
  "data-react-fancy-date-picker": "",
@@ -4712,17 +4868,20 @@ var RangeDatePicker = react.forwardRef(
4712
4868
  name,
4713
4869
  min,
4714
4870
  max,
4871
+ includeTime,
4872
+ mode,
4715
4873
  inputType,
4716
4874
  inputClasses,
4717
4875
  ...rest
4718
4876
  }, ref) => {
4719
4877
  const rangeProps = rest;
4878
+ const resolvedMode = useFieldMode(mode);
4720
4879
  const [value, setValue] = useControllableState(
4721
4880
  rangeProps.value,
4722
4881
  rangeProps.defaultValue ?? ["", ""],
4723
4882
  rangeProps.onValueChange
4724
4883
  );
4725
- const input = /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-date-picker": "", className: cn("flex items-center gap-2", className), children: [
4884
+ const input = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, className, children: value[0] || value[1] ? `${formatDateValue(value[0], includeTime)} \u2013 ${formatDateValue(value[1], includeTime)}` : "" }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-date-picker": "", className: cn("flex items-center gap-2", className), children: [
4726
4885
  /* @__PURE__ */ jsxRuntime.jsx(
4727
4886
  "input",
4728
4887
  {
@@ -4772,6 +4931,13 @@ var RangeDatePicker = react.forwardRef(
4772
4931
  }
4773
4932
  );
4774
4933
  RangeDatePicker.displayName = "RangeDatePicker";
4934
+ function FormProvider({ mode = "edit", children }) {
4935
+ const value = react.useMemo(() => ({ mode }), [mode]);
4936
+ return /* @__PURE__ */ jsxRuntime.jsx(FieldModeContext.Provider, { value, children });
4937
+ }
4938
+ function Form({ mode, children, ...formProps }) {
4939
+ return /* @__PURE__ */ jsxRuntime.jsx(FormProvider, { mode, children: /* @__PURE__ */ jsxRuntime.jsx("form", { "data-react-fancy-form": "", ...formProps, children }) });
4940
+ }
4775
4941
  var CarouselContext = react.createContext(null);
4776
4942
  CarouselContext.displayName = "CarouselContext";
4777
4943
  function useCarousel() {
@@ -5111,13 +5277,15 @@ var ColorPicker = react.forwardRef(
5111
5277
  size = "md",
5112
5278
  variant = "outline",
5113
5279
  disabled = false,
5114
- className
5280
+ className,
5281
+ mode
5115
5282
  }, ref) => {
5116
5283
  const [color, setColor] = useControllableState(
5117
5284
  value,
5118
5285
  defaultValue,
5119
5286
  onChange
5120
5287
  );
5288
+ const resolvedMode = useFieldMode(mode);
5121
5289
  const inputRef = react.useRef(null);
5122
5290
  const datalistId = react.useId();
5123
5291
  const handleChange = (e) => {
@@ -5128,6 +5296,42 @@ var ColorPicker = react.forwardRef(
5128
5296
  inputRef.current?.click();
5129
5297
  }
5130
5298
  };
5299
+ if (resolvedMode === "view") {
5300
+ return /* @__PURE__ */ jsxRuntime.jsxs(
5301
+ "div",
5302
+ {
5303
+ ref,
5304
+ "data-react-fancy-color-picker": "",
5305
+ "data-mode": "view",
5306
+ className: cn("inline-flex items-center gap-2", className),
5307
+ children: [
5308
+ /* @__PURE__ */ jsxRuntime.jsx(
5309
+ "span",
5310
+ {
5311
+ className: cn(
5312
+ "shrink-0 rounded-full",
5313
+ SWATCH_SIZES[size],
5314
+ variant === "outline" && "ring-1 ring-zinc-300 dark:ring-zinc-600"
5315
+ ),
5316
+ style: { backgroundColor: color },
5317
+ "aria-label": `Color: ${color}`
5318
+ }
5319
+ ),
5320
+ /* @__PURE__ */ jsxRuntime.jsx(
5321
+ "span",
5322
+ {
5323
+ className: cn(
5324
+ "select-all font-mono uppercase",
5325
+ TEXT_SIZES[size],
5326
+ "text-zinc-700 dark:text-zinc-300"
5327
+ ),
5328
+ children: color.toUpperCase()
5329
+ }
5330
+ )
5331
+ ]
5332
+ }
5333
+ );
5334
+ }
5131
5335
  return /* @__PURE__ */ jsxRuntime.jsxs(
5132
5336
  "div",
5133
5337
  {
@@ -6017,6 +6221,14 @@ var Badge = react.forwardRef(
6017
6221
  }
6018
6222
  );
6019
6223
  Badge.displayName = "Badge";
6224
+ var glowColors = {
6225
+ on: "#a855f7",
6226
+ // violet — neutral
6227
+ xp: "#22c55e",
6228
+ // green
6229
+ achievement: "#f59e0b"
6230
+ // amber
6231
+ };
6020
6232
  var containerSizeClasses = {
6021
6233
  xs: "h-6 w-6",
6022
6234
  sm: "h-8 w-8",
@@ -6051,8 +6263,10 @@ var Avatar = react.forwardRef(
6051
6263
  fallback,
6052
6264
  size = "md",
6053
6265
  status,
6266
+ glow,
6054
6267
  className
6055
6268
  }, ref) => {
6269
+ const glowKey = glow === true ? "on" : glow || null;
6056
6270
  return /* @__PURE__ */ jsxRuntime.jsxs(
6057
6271
  "div",
6058
6272
  {
@@ -6065,6 +6279,15 @@ var Avatar = react.forwardRef(
6065
6279
  className
6066
6280
  ),
6067
6281
  children: [
6282
+ glowKey && /* @__PURE__ */ jsxRuntime.jsx(
6283
+ "span",
6284
+ {
6285
+ "aria-hidden": true,
6286
+ "data-react-fancy-avatar-glow": glowKey,
6287
+ className: "fancy-avatar-glow",
6288
+ style: { "--fancy-glow": glowColors[glowKey] }
6289
+ }
6290
+ ),
6068
6291
  src ? /* @__PURE__ */ jsxRuntime.jsx(
6069
6292
  "img",
6070
6293
  {
@@ -8855,13 +9078,15 @@ var Autocomplete = react.forwardRef(
8855
9078
  loading = false,
8856
9079
  emptyMessage = "No results found.",
8857
9080
  disabled = false,
8858
- className
9081
+ className,
9082
+ mode
8859
9083
  }, ref) {
8860
9084
  const [value, setValue] = useControllableState(
8861
9085
  controlledValue,
8862
9086
  defaultValue,
8863
9087
  onChange
8864
9088
  );
9089
+ const resolvedMode = useFieldMode(mode);
8865
9090
  const [query, setQuery] = react.useState(value);
8866
9091
  const [open, setOpen] = react.useState(false);
8867
9092
  const [activeIndex, setActiveIndex] = react.useState(-1);
@@ -8914,6 +9139,23 @@ var Autocomplete = react.forwardRef(
8914
9139
  if (item && !item.disabled) select(item.value);
8915
9140
  }
8916
9141
  };
9142
+ if (resolvedMode === "view") {
9143
+ const matched = options.find((o) => o.value === value);
9144
+ return /* @__PURE__ */ jsxRuntime.jsx(
9145
+ "div",
9146
+ {
9147
+ "data-react-fancy-autocomplete": "",
9148
+ "data-mode": "view",
9149
+ ref: wrapperRef,
9150
+ className: cn(
9151
+ "text-sm text-zinc-900 dark:text-zinc-100",
9152
+ !value && "text-zinc-400 dark:text-zinc-500",
9153
+ className
9154
+ ),
9155
+ children: matched?.label ?? value ?? "\u2014"
9156
+ }
9157
+ );
9158
+ }
8917
9159
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-autocomplete": "", ref: wrapperRef, className: cn("relative", className), children: [
8918
9160
  /* @__PURE__ */ jsxRuntime.jsx(
8919
9161
  "input",
@@ -9086,13 +9328,15 @@ var OtpInput = react.forwardRef(
9086
9328
  onChange,
9087
9329
  disabled = false,
9088
9330
  autoFocus = false,
9089
- className
9331
+ className,
9332
+ mode
9090
9333
  }, ref) {
9091
9334
  const [value, setValue] = useControllableState(
9092
9335
  controlledValue,
9093
9336
  "",
9094
9337
  onChange
9095
9338
  );
9339
+ const resolvedMode = useFieldMode(mode);
9096
9340
  const inputsRef = react.useRef([]);
9097
9341
  const focusInput = react.useCallback(
9098
9342
  (index) => {
@@ -9146,6 +9390,21 @@ var OtpInput = react.forwardRef(
9146
9390
  },
9147
9391
  [length, setValue, focusInput]
9148
9392
  );
9393
+ if (resolvedMode === "view") {
9394
+ return /* @__PURE__ */ jsxRuntime.jsx(
9395
+ "div",
9396
+ {
9397
+ "data-react-fancy-otp-input": "",
9398
+ "data-mode": "view",
9399
+ ref,
9400
+ className: cn(
9401
+ "font-mono text-lg tracking-[0.4em] text-zinc-900 dark:text-zinc-100",
9402
+ className
9403
+ ),
9404
+ children: value || "\u2014"
9405
+ }
9406
+ );
9407
+ }
9149
9408
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-react-fancy-otp-input": "", ref, className: cn("flex gap-2", className), children: Array.from({ length }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx(
9150
9409
  "input",
9151
9410
  {
@@ -9360,16 +9619,34 @@ var TimePicker = react.forwardRef(
9360
9619
  format = "12h",
9361
9620
  minuteStep = 1,
9362
9621
  disabled = false,
9363
- className
9622
+ className,
9623
+ mode
9364
9624
  }, ref) {
9365
9625
  const [value, setValue] = useControllableState(
9366
9626
  controlledValue,
9367
9627
  defaultValue,
9368
9628
  onChange
9369
9629
  );
9630
+ const resolvedMode = useFieldMode(mode);
9370
9631
  const { hours: h24, minutes } = parseTime(value);
9371
9632
  const isPM = h24 >= 12;
9372
9633
  const displayHour = format === "12h" ? h24 % 12 || 12 : h24;
9634
+ if (resolvedMode === "view") {
9635
+ const formatted = format === "12h" ? `${pad(displayHour)}:${pad(minutes)} ${isPM ? "PM" : "AM"}` : `${pad(displayHour)}:${pad(minutes)}`;
9636
+ return /* @__PURE__ */ jsxRuntime.jsx(
9637
+ "div",
9638
+ {
9639
+ "data-react-fancy-time-picker": "",
9640
+ "data-mode": "view",
9641
+ ref,
9642
+ className: cn(
9643
+ "text-sm font-medium tabular-nums text-zinc-900 dark:text-zinc-100",
9644
+ className
9645
+ ),
9646
+ children: formatted
9647
+ }
9648
+ );
9649
+ }
9373
9650
  const updateTime = react.useCallback(
9374
9651
  (hours, mins) => {
9375
9652
  setValue(`${pad(hours)}:${pad(mins)}`);
@@ -13715,6 +13992,7 @@ exports.Composer = Composer;
13715
13992
  exports.ContentRenderer = ContentRenderer;
13716
13993
  exports.ContextMenu = ContextMenu;
13717
13994
  exports.DatePicker = DatePicker;
13995
+ exports.DisplayValue = DisplayValue;
13718
13996
  exports.Dropdown = Dropdown;
13719
13997
  exports.EMOJI_CATEGORY_ORDER = EMOJI_CATEGORY_ORDER;
13720
13998
  exports.EMOJI_DATA = EMOJI_DATA;
@@ -13724,7 +14002,10 @@ exports.Emoji = Emoji;
13724
14002
  exports.EmojiSelect = EmojiSelect;
13725
14003
  exports.FauxClient = FauxClient;
13726
14004
  exports.Field = Field;
14005
+ exports.FieldModeContext = FieldModeContext;
13727
14006
  exports.FileUpload = FileUpload;
14007
+ exports.Form = Form;
14008
+ exports.FormProvider = FormProvider;
13728
14009
  exports.Heading = Heading;
13729
14010
  exports.Icon = Icon;
13730
14011
  exports.Input = Input;
@@ -13794,6 +14075,7 @@ exports.useControllableState = useControllableState;
13794
14075
  exports.useDropdown = useDropdown;
13795
14076
  exports.useEditor = useEditor;
13796
14077
  exports.useEscapeKey = useEscapeKey;
14078
+ exports.useFieldMode = useFieldMode;
13797
14079
  exports.useFileUpload = useFileUpload;
13798
14080
  exports.useFloatingPosition = useFloatingPosition;
13799
14081
  exports.useFocusTrap = useFocusTrap;