@particle-academy/react-fancy 4.5.0 → 4.7.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
@@ -2106,6 +2106,17 @@ function applyTone(char, tone) {
2106
2106
  // src/components/Icon/icon-config.ts
2107
2107
  var registry = /* @__PURE__ */ new Map();
2108
2108
  var defaultSetName = "lucide";
2109
+ var addenda = [];
2110
+ function registerIconAddendum(set) {
2111
+ if (!addenda.includes(set)) addenda.push(set);
2112
+ }
2113
+ function resolveFromAddenda(name) {
2114
+ for (const set of addenda) {
2115
+ const hit = set.resolve(name);
2116
+ if (hit) return hit;
2117
+ }
2118
+ return null;
2119
+ }
2109
2120
  function kebabToPascal(str) {
2110
2121
  return str.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
2111
2122
  }
@@ -2169,6 +2180,8 @@ function resolveIcon(name, setName) {
2169
2180
  const set = registry.get(resolvedSet);
2170
2181
  const registered = set ? set.resolve(name) : null;
2171
2182
  if (registered) return registered;
2183
+ const fromAddenda = resolveFromAddenda(name);
2184
+ if (fromAddenda) return fromAddenda;
2172
2185
  if (resolvedSet === "lucide") return resolveFromLucide(name);
2173
2186
  return null;
2174
2187
  }
@@ -3093,19 +3106,33 @@ function DisplayValue({
3093
3106
  leading,
3094
3107
  trailing,
3095
3108
  empty = "\u2014",
3109
+ interactive,
3110
+ onActivate,
3096
3111
  className
3097
3112
  }) {
3098
3113
  const empties = isEmpty(children);
3114
+ const onKeyDown = interactive ? (e) => {
3115
+ if (e.key === "Enter" || e.key === " ") {
3116
+ e.preventDefault();
3117
+ onActivate?.();
3118
+ }
3119
+ } : void 0;
3099
3120
  return /* @__PURE__ */ jsxRuntime.jsxs(
3100
3121
  "div",
3101
3122
  {
3102
3123
  "data-react-fancy-display": "",
3103
3124
  "data-mode": "view",
3125
+ role: interactive ? "button" : void 0,
3126
+ tabIndex: interactive ? 0 : void 0,
3127
+ title: interactive ? "Click to edit" : void 0,
3128
+ onClick: interactive ? onActivate : void 0,
3129
+ onKeyDown,
3104
3130
  className: cn(
3105
3131
  "flex w-full items-center gap-2 text-zinc-900 dark:text-zinc-100",
3106
3132
  inputSizeClasses[size],
3107
3133
  // Strip the editable box look — keep only the size/padding rhythm.
3108
3134
  "border-0 bg-transparent px-0",
3135
+ interactive && "-mx-2 cursor-text rounded-md px-2 outline-none transition-colors hover:bg-zinc-100 focus-visible:ring-2 focus-visible:ring-blue-500/40 dark:hover:bg-zinc-800",
3109
3136
  empties && "text-zinc-400 dark:text-zinc-500",
3110
3137
  className
3111
3138
  ),
@@ -3117,6 +3144,16 @@ function DisplayValue({
3117
3144
  }
3118
3145
  );
3119
3146
  }
3147
+ function useInlineEdit(mode, disabled) {
3148
+ const [editing, setEditing] = react.useState(false);
3149
+ const interactive = mode === "view" && !disabled;
3150
+ const showControl = mode !== "view" || interactive && editing;
3151
+ const enterEdit = react.useCallback(() => {
3152
+ if (interactive) setEditing(true);
3153
+ }, [interactive]);
3154
+ const exitEdit = react.useCallback(() => setEditing(false), []);
3155
+ return { showControl, interactive, enterEdit, exitEdit };
3156
+ }
3120
3157
  var Input = react.forwardRef(
3121
3158
  ({
3122
3159
  type = "text",
@@ -3143,7 +3180,18 @@ var Input = react.forwardRef(
3143
3180
  const autoId = react.useId();
3144
3181
  const inputId = id ?? autoId;
3145
3182
  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(
3183
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
3184
+ const input = !showControl ? /* @__PURE__ */ jsxRuntime.jsx(
3185
+ DisplayValue,
3186
+ {
3187
+ size,
3188
+ interactive,
3189
+ onActivate: enterEdit,
3190
+ leading: leading ?? prefix,
3191
+ trailing: trailing ?? suffix,
3192
+ children: type === "password" ? props.value ? "\u2022\u2022\u2022\u2022\u2022\u2022" : "" : props.value
3193
+ }
3194
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
3147
3195
  InputWrapper,
3148
3196
  {
3149
3197
  prefix,
@@ -3175,7 +3223,12 @@ var Input = react.forwardRef(
3175
3223
  onChange?.(e);
3176
3224
  onValueChange?.(e.target.value);
3177
3225
  },
3178
- ...props
3226
+ ...props,
3227
+ autoFocus: interactive || props.autoFocus,
3228
+ onBlur: (e) => {
3229
+ props.onBlur?.(e);
3230
+ if (interactive) exitEdit();
3231
+ }
3179
3232
  }
3180
3233
  ),
3181
3234
  trailing && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute right-3 text-zinc-400 dark:text-zinc-500", children: trailing })
@@ -3229,6 +3282,7 @@ var Textarea = react.forwardRef(
3229
3282
  const textareaId = id ?? autoId;
3230
3283
  const internalRef = react.useRef(null);
3231
3284
  const resolvedMode = useFieldMode(mode);
3285
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
3232
3286
  react.useEffect(() => {
3233
3287
  const el = internalRef.current;
3234
3288
  if (!autoResize || !el) return;
@@ -3238,7 +3292,16 @@ var Textarea = react.forwardRef(
3238
3292
  const maxHeight = maxRows ? maxRows * lineHeight : Infinity;
3239
3293
  el.style.height = `${Math.min(Math.max(el.scrollHeight, minHeight), maxHeight)}px`;
3240
3294
  }, [autoResize, minRows, maxRows, value, defaultValue]);
3241
- const textarea = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, className: "whitespace-pre-wrap", children: value ?? defaultValue }) : /* @__PURE__ */ jsxRuntime.jsx(
3295
+ const textarea = !showControl ? /* @__PURE__ */ jsxRuntime.jsx(
3296
+ DisplayValue,
3297
+ {
3298
+ size,
3299
+ className: "whitespace-pre-wrap",
3300
+ interactive,
3301
+ onActivate: enterEdit,
3302
+ children: value ?? defaultValue
3303
+ }
3304
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
3242
3305
  InputWrapper,
3243
3306
  {
3244
3307
  prefix,
@@ -3277,7 +3340,12 @@ var Textarea = react.forwardRef(
3277
3340
  onChange?.(e);
3278
3341
  onValueChange?.(e.target.value);
3279
3342
  },
3280
- ...props
3343
+ ...props,
3344
+ autoFocus: interactive || props.autoFocus,
3345
+ onBlur: (e) => {
3346
+ props.onBlur?.(e);
3347
+ if (interactive) exitEdit();
3348
+ }
3281
3349
  }
3282
3350
  )
3283
3351
  }
@@ -3520,10 +3588,21 @@ var NativeSelect = react.forwardRef(
3520
3588
  const autoId = react.useId();
3521
3589
  const selectId = id ?? autoId;
3522
3590
  const resolvedMode = useFieldMode(mode);
3523
- if (resolvedMode === "view") {
3591
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
3592
+ if (!showControl) {
3524
3593
  const current = value ?? defaultValue;
3525
3594
  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 });
3595
+ const display = /* @__PURE__ */ jsxRuntime.jsx(
3596
+ DisplayValue,
3597
+ {
3598
+ size,
3599
+ leading: prefix,
3600
+ trailing: suffix,
3601
+ interactive,
3602
+ onActivate: enterEdit,
3603
+ children: opt?.label ?? current
3604
+ }
3605
+ );
3527
3606
  if (label || error || description) {
3528
3607
  return /* @__PURE__ */ jsxRuntime.jsx(
3529
3608
  Field,
@@ -3574,6 +3653,11 @@ var NativeSelect = react.forwardRef(
3574
3653
  },
3575
3654
  ...props,
3576
3655
  ...isControlled ? { value } : { defaultValue: resolvedDefault },
3656
+ autoFocus: interactive || props.autoFocus,
3657
+ onBlur: (e) => {
3658
+ props.onBlur?.(e);
3659
+ if (interactive) exitEdit();
3660
+ },
3577
3661
  children: [
3578
3662
  placeholder && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: placeholder }),
3579
3663
  list.map(
@@ -3635,6 +3719,7 @@ var ListboxSelect = react.forwardRef(
3635
3719
  const autoId = react.useId();
3636
3720
  const selectId = id ?? autoId;
3637
3721
  const resolvedMode = useFieldMode(mode);
3722
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
3638
3723
  const textInputEnabled = searchable || creatable;
3639
3724
  const [open, setOpen] = react.useState(false);
3640
3725
  const [search2, setSearch] = react.useState("");
@@ -3761,11 +3846,11 @@ var ListboxSelect = react.forwardRef(
3761
3846
  }
3762
3847
  }
3763
3848
  };
3764
- if (resolvedMode === "view") {
3849
+ if (!showControl) {
3765
3850
  const labels = multiple ? currentMulti.map(
3766
3851
  (v) => resolvedOptions.find((o) => o.value === v)?.label ?? v
3767
3852
  ) : currentSingle ? [resolvedOptions.find((o) => o.value === currentSingle)?.label ?? currentSingle] : [];
3768
- const display = /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, children: labels.join(", ") });
3853
+ const display = /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, interactive, onActivate: enterEdit, children: labels.join(", ") });
3769
3854
  if (label || error || description) {
3770
3855
  return /* @__PURE__ */ jsxRuntime.jsx(
3771
3856
  Field,
@@ -3789,6 +3874,7 @@ var ListboxSelect = react.forwardRef(
3789
3874
  type: "button",
3790
3875
  id: selectId,
3791
3876
  disabled,
3877
+ autoFocus: interactive,
3792
3878
  onClick: () => setOpen((o) => !o),
3793
3879
  onKeyDown: handleKeyDown,
3794
3880
  role: "combobox",
@@ -3910,10 +3996,21 @@ var ListboxSelect = react.forwardRef(
3910
3996
  ]
3911
3997
  }
3912
3998
  ) });
3913
- const content = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
3914
- trigger,
3915
- dropdown
3916
- ] });
3999
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(
4000
+ "div",
4001
+ {
4002
+ className: "relative",
4003
+ onBlur: (e) => {
4004
+ if (interactive && !open && !e.currentTarget.contains(e.relatedTarget)) {
4005
+ exitEdit();
4006
+ }
4007
+ },
4008
+ children: [
4009
+ trigger,
4010
+ dropdown
4011
+ ]
4012
+ }
4013
+ );
3917
4014
  if (label || error || description) {
3918
4015
  return /* @__PURE__ */ jsxRuntime.jsx(
3919
4016
  Field,
@@ -3964,6 +4061,7 @@ var Checkbox = react.forwardRef(
3964
4061
  const checkboxId = id ?? autoId;
3965
4062
  const internalRef = react.useRef(null);
3966
4063
  const resolvedMode = useFieldMode(mode);
4064
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
3967
4065
  const [checked, setChecked] = useControllableState(
3968
4066
  controlledChecked,
3969
4067
  defaultChecked,
@@ -3984,16 +4082,27 @@ var Checkbox = react.forwardRef(
3984
4082
  }[size];
3985
4083
  const glyph = indeterminate ? "\u2014" : checked ? "\u2713" : "\u2715";
3986
4084
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-checkbox": "", className: cn("flex items-start gap-2", className), children: [
3987
- resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(
4085
+ !showControl ? /* @__PURE__ */ jsxRuntime.jsx(
3988
4086
  "span",
3989
4087
  {
3990
4088
  "data-react-fancy-display": "",
3991
4089
  "data-mode": "view",
4090
+ role: interactive ? "button" : void 0,
4091
+ tabIndex: interactive ? 0 : void 0,
4092
+ title: interactive ? "Click to edit" : void 0,
4093
+ onClick: interactive ? enterEdit : void 0,
4094
+ onKeyDown: interactive ? (e) => {
4095
+ if (e.key === "Enter" || e.key === " ") {
4096
+ e.preventDefault();
4097
+ enterEdit();
4098
+ }
4099
+ } : void 0,
3992
4100
  className: cn(
3993
4101
  "flex shrink-0 items-center justify-center text-zinc-700 dark:text-zinc-200",
3994
- sizeClasses6
4102
+ sizeClasses6,
4103
+ interactive && "cursor-pointer rounded outline-none transition-colors hover:text-zinc-900 focus-visible:ring-2 focus-visible:ring-blue-500/40 dark:hover:text-white"
3995
4104
  ),
3996
- "aria-hidden": "true",
4105
+ "aria-hidden": interactive ? void 0 : "true",
3997
4106
  children: glyph
3998
4107
  }
3999
4108
  ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -4013,6 +4122,10 @@ var Checkbox = react.forwardRef(
4013
4122
  disabled,
4014
4123
  required,
4015
4124
  checked,
4125
+ autoFocus: interactive,
4126
+ onBlur: () => {
4127
+ if (interactive) exitEdit();
4128
+ },
4016
4129
  onChange: (e) => setChecked(e.target.checked),
4017
4130
  className: cn(
4018
4131
  sizeClasses6,
@@ -4063,6 +4176,7 @@ function CheckboxGroup({
4063
4176
  }) {
4064
4177
  const groupId = react.useId();
4065
4178
  const resolvedMode = useFieldMode(mode);
4179
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
4066
4180
  const [value, setValue] = useControllableState(
4067
4181
  controlledValue,
4068
4182
  defaultValue,
@@ -4079,10 +4193,13 @@ function CheckboxGroup({
4079
4193
  lg: "h-5 w-5",
4080
4194
  xl: "h-6 w-6"
4081
4195
  }[size];
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(
4196
+ const content = !showControl ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, interactive, onActivate: enterEdit, children: list.map(resolveOption).filter((o) => value.includes(o.value)).map((o) => o.label).join(", ") }) : /* @__PURE__ */ jsxRuntime.jsx(
4083
4197
  "div",
4084
4198
  {
4085
4199
  "data-react-fancy-checkbox-group": "",
4200
+ onBlur: (e) => {
4201
+ if (interactive && !e.currentTarget.contains(e.relatedTarget)) exitEdit();
4202
+ },
4086
4203
  className: cn(
4087
4204
  "flex gap-3",
4088
4205
  orientation === "vertical" ? "flex-col" : "flex-row flex-wrap",
@@ -4102,6 +4219,7 @@ function CheckboxGroup({
4102
4219
  value: String(resolved.value),
4103
4220
  checked: isChecked,
4104
4221
  disabled: disabled || resolved.disabled,
4222
+ autoFocus: interactive && index === 0,
4105
4223
  onChange: () => handleToggle(resolved.value),
4106
4224
  className: cn(
4107
4225
  sizeClasses6,
@@ -4165,6 +4283,7 @@ function RadioGroup({
4165
4283
  const groupId = react.useId();
4166
4284
  const radioName = name ?? groupId;
4167
4285
  const resolvedMode = useFieldMode(mode);
4286
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
4168
4287
  const [value, setValue] = useControllableState(
4169
4288
  controlledValue,
4170
4289
  defaultValue,
@@ -4177,11 +4296,15 @@ function RadioGroup({
4177
4296
  lg: "h-5 w-5",
4178
4297
  xl: "h-6 w-6"
4179
4298
  }[size];
4180
- const content = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, children: list.map(resolveOption).find((o) => o.value === value)?.label }) : /* @__PURE__ */ jsxRuntime.jsx(
4299
+ const selectedIndex = list.map(resolveOption).findIndex((o) => o.value === value);
4300
+ const content = !showControl ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, interactive, onActivate: enterEdit, children: list.map(resolveOption).find((o) => o.value === value)?.label }) : /* @__PURE__ */ jsxRuntime.jsx(
4181
4301
  "div",
4182
4302
  {
4183
4303
  "data-react-fancy-radio-group": "",
4184
4304
  role: "radiogroup",
4305
+ onBlur: (e) => {
4306
+ if (interactive && !e.currentTarget.contains(e.relatedTarget)) exitEdit();
4307
+ },
4185
4308
  className: cn(
4186
4309
  "flex gap-3",
4187
4310
  orientation === "vertical" ? "flex-col" : "flex-row flex-wrap",
@@ -4191,6 +4314,7 @@ function RadioGroup({
4191
4314
  const resolved = resolveOption(option);
4192
4315
  const optionId = `${groupId}-${index}`;
4193
4316
  const isSelected = value === resolved.value;
4317
+ const shouldAutoFocus = interactive && (selectedIndex === -1 ? index === 0 : isSelected);
4194
4318
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
4195
4319
  /* @__PURE__ */ jsxRuntime.jsx(
4196
4320
  "input",
@@ -4201,6 +4325,7 @@ function RadioGroup({
4201
4325
  value: String(resolved.value),
4202
4326
  checked: isSelected,
4203
4327
  disabled: disabled || resolved.disabled,
4328
+ autoFocus: shouldAutoFocus,
4204
4329
  onChange: () => setValue(resolved.value),
4205
4330
  className: cn(
4206
4331
  sizeClasses6,
@@ -4291,6 +4416,7 @@ var Switch = react.forwardRef(
4291
4416
  const autoId = react.useId();
4292
4417
  const switchId = id ?? autoId;
4293
4418
  const resolvedMode = useFieldMode(mode);
4419
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
4294
4420
  const [checked, setChecked] = useControllableState(
4295
4421
  controlledChecked,
4296
4422
  defaultChecked,
@@ -4318,12 +4444,25 @@ var Switch = react.forwardRef(
4318
4444
  xl: "translate-x-6"
4319
4445
  }[size];
4320
4446
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-switch": "", className: cn("flex items-start gap-2", className), children: [
4321
- resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(
4447
+ !showControl ? /* @__PURE__ */ jsxRuntime.jsx(
4322
4448
  "span",
4323
4449
  {
4324
4450
  "data-react-fancy-display": "",
4325
4451
  "data-mode": "view",
4326
- className: "text-sm font-medium text-zinc-700 dark:text-zinc-200",
4452
+ role: interactive ? "button" : void 0,
4453
+ tabIndex: interactive ? 0 : void 0,
4454
+ title: interactive ? "Click to edit" : void 0,
4455
+ onClick: interactive ? enterEdit : void 0,
4456
+ onKeyDown: interactive ? (e) => {
4457
+ if (e.key === "Enter" || e.key === " ") {
4458
+ e.preventDefault();
4459
+ enterEdit();
4460
+ }
4461
+ } : void 0,
4462
+ className: cn(
4463
+ "text-sm font-medium text-zinc-700 dark:text-zinc-200",
4464
+ interactive && "cursor-pointer rounded-md outline-none transition-colors hover:text-zinc-900 focus-visible:ring-2 focus-visible:ring-blue-500/40 dark:hover:text-white"
4465
+ ),
4327
4466
  children: checked ? "On" : "Off"
4328
4467
  }
4329
4468
  ) : /* @__PURE__ */ jsxRuntime.jsx(
@@ -4335,6 +4474,10 @@ var Switch = react.forwardRef(
4335
4474
  role: "switch",
4336
4475
  "aria-checked": checked,
4337
4476
  disabled,
4477
+ autoFocus: interactive,
4478
+ onBlur: () => {
4479
+ if (interactive) exitEdit();
4480
+ },
4338
4481
  onClick: () => setChecked(!checked),
4339
4482
  className: cn(
4340
4483
  "relative inline-flex shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/40 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
@@ -4445,12 +4588,22 @@ var SingleSlider = react.forwardRef(
4445
4588
  }, ref) => {
4446
4589
  const singleProps = rest;
4447
4590
  const resolvedMode = useFieldMode(mode);
4591
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
4448
4592
  const [value, setValue] = useControllableState(
4449
4593
  singleProps.value,
4450
4594
  singleProps.defaultValue ?? min,
4451
4595
  singleProps.onValueChange
4452
4596
  );
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: [
4597
+ const slider = !showControl ? /* @__PURE__ */ jsxRuntime.jsx(
4598
+ DisplayValue,
4599
+ {
4600
+ size,
4601
+ className,
4602
+ interactive,
4603
+ onActivate: enterEdit,
4604
+ children: `${prefix ?? ""}${value}${suffix ?? ""}`
4605
+ }
4606
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-slider": "", className: cn("flex flex-col gap-1", className), children: [
4454
4607
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
4455
4608
  /* @__PURE__ */ jsxRuntime.jsx(
4456
4609
  "input",
@@ -4464,6 +4617,10 @@ var SingleSlider = react.forwardRef(
4464
4617
  step,
4465
4618
  value,
4466
4619
  disabled,
4620
+ autoFocus: interactive,
4621
+ onBlur: () => {
4622
+ if (interactive) exitEdit();
4623
+ },
4467
4624
  onChange: (e) => setValue(Number(e.target.value)),
4468
4625
  className: cn(
4469
4626
  "w-full cursor-pointer accent-blue-600 disabled:cursor-not-allowed disabled:opacity-50",
@@ -4517,6 +4674,7 @@ var RangeSlider = react.forwardRef(
4517
4674
  }, ref) => {
4518
4675
  const rangeProps = rest;
4519
4676
  const resolvedMode = useFieldMode(mode);
4677
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
4520
4678
  const [value, setValue] = useControllableState(
4521
4679
  rangeProps.value,
4522
4680
  rangeProps.defaultValue ?? [min, max],
@@ -4530,61 +4688,81 @@ var RangeSlider = react.forwardRef(
4530
4688
  };
4531
4689
  const leftPercent = (value[0] - min) / (max - min) * 100;
4532
4690
  const rightPercent = (value[1] - min) / (max - min) * 100;
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: [
4534
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
4535
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
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" }),
4537
- /* @__PURE__ */ jsxRuntime.jsx(
4538
- "div",
4539
- {
4540
- className: "pointer-events-none absolute top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-blue-500",
4541
- style: { left: `${leftPercent}%`, width: `${rightPercent - leftPercent}%` }
4542
- }
4543
- ),
4544
- /* @__PURE__ */ jsxRuntime.jsx(
4545
- "input",
4546
- {
4547
- ref,
4548
- type: "range",
4549
- min,
4550
- max,
4551
- step,
4552
- value: value[0],
4553
- disabled,
4554
- onChange: (e) => handleMin(Number(e.target.value)),
4555
- className: cn(
4556
- "pointer-events-none absolute w-full cursor-pointer appearance-none bg-transparent [&::-webkit-slider-thumb]:pointer-events-auto [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-600 [&::-webkit-slider-thumb]:shadow",
4557
- dirtyRingClasses(dirty)
4558
- )
4559
- }
4560
- ),
4561
- /* @__PURE__ */ jsxRuntime.jsx(
4562
- "input",
4563
- {
4564
- type: "range",
4565
- min,
4566
- max,
4567
- step,
4568
- value: value[1],
4569
- disabled,
4570
- onChange: (e) => handleMax(Number(e.target.value)),
4571
- className: "pointer-events-none absolute w-full cursor-pointer appearance-none bg-transparent [&::-webkit-slider-thumb]:pointer-events-auto [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-600 [&::-webkit-slider-thumb]:shadow"
4572
- }
4573
- ),
4574
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6" })
4575
- ] }),
4576
- showValue && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-[6ch] shrink-0 whitespace-nowrap text-right text-sm font-medium text-zinc-700 dark:text-zinc-300", children: [
4577
- prefix,
4578
- value[0],
4579
- suffix,
4580
- "\u2013",
4581
- prefix,
4582
- value[1],
4583
- suffix
4584
- ] })
4585
- ] }),
4586
- marks && marks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(SliderMarks, { marks, min, max })
4587
- ] });
4691
+ const slider = !showControl ? /* @__PURE__ */ jsxRuntime.jsx(
4692
+ DisplayValue,
4693
+ {
4694
+ size,
4695
+ className,
4696
+ interactive,
4697
+ onActivate: enterEdit,
4698
+ children: `${prefix ?? ""}${value[0]}${suffix ?? ""}\u2013${prefix ?? ""}${value[1]}${suffix ?? ""}`
4699
+ }
4700
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
4701
+ "div",
4702
+ {
4703
+ "data-react-fancy-slider": "",
4704
+ className: cn("flex flex-col gap-1", className),
4705
+ onBlur: (e) => {
4706
+ if (interactive && !e.currentTarget.contains(e.relatedTarget)) exitEdit();
4707
+ },
4708
+ children: [
4709
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
4710
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
4711
+ /* @__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" }),
4712
+ /* @__PURE__ */ jsxRuntime.jsx(
4713
+ "div",
4714
+ {
4715
+ className: "pointer-events-none absolute top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-blue-500",
4716
+ style: { left: `${leftPercent}%`, width: `${rightPercent - leftPercent}%` }
4717
+ }
4718
+ ),
4719
+ /* @__PURE__ */ jsxRuntime.jsx(
4720
+ "input",
4721
+ {
4722
+ ref,
4723
+ type: "range",
4724
+ min,
4725
+ max,
4726
+ step,
4727
+ value: value[0],
4728
+ disabled,
4729
+ autoFocus: interactive,
4730
+ onChange: (e) => handleMin(Number(e.target.value)),
4731
+ className: cn(
4732
+ "pointer-events-none absolute w-full cursor-pointer appearance-none bg-transparent [&::-webkit-slider-thumb]:pointer-events-auto [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-600 [&::-webkit-slider-thumb]:shadow",
4733
+ dirtyRingClasses(dirty)
4734
+ )
4735
+ }
4736
+ ),
4737
+ /* @__PURE__ */ jsxRuntime.jsx(
4738
+ "input",
4739
+ {
4740
+ type: "range",
4741
+ min,
4742
+ max,
4743
+ step,
4744
+ value: value[1],
4745
+ disabled,
4746
+ onChange: (e) => handleMax(Number(e.target.value)),
4747
+ className: "pointer-events-none absolute w-full cursor-pointer appearance-none bg-transparent [&::-webkit-slider-thumb]:pointer-events-auto [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-600 [&::-webkit-slider-thumb]:shadow"
4748
+ }
4749
+ ),
4750
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6" })
4751
+ ] }),
4752
+ showValue && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-[6ch] shrink-0 whitespace-nowrap text-right text-sm font-medium text-zinc-700 dark:text-zinc-300", children: [
4753
+ prefix,
4754
+ value[0],
4755
+ suffix,
4756
+ "\u2013",
4757
+ prefix,
4758
+ value[1],
4759
+ suffix
4760
+ ] })
4761
+ ] }),
4762
+ marks && marks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(SliderMarks, { marks, min, max })
4763
+ ]
4764
+ }
4765
+ );
4588
4766
  if (label || error || description) {
4589
4767
  return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, description, error, required, htmlFor: id, size, children: slider });
4590
4768
  }
@@ -4638,6 +4816,7 @@ function MultiSwitch({
4638
4816
  const resolvedOptions = list.map(resolveOption);
4639
4817
  const fallback = defaultValue ?? resolvedOptions[0]?.value;
4640
4818
  const resolvedMode = useFieldMode(mode);
4819
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
4641
4820
  const [value, setValue] = useControllableState(controlledValue, fallback, onValueChange);
4642
4821
  const containerRef = react.useRef(null);
4643
4822
  const itemRefs = react.useRef([]);
@@ -4662,13 +4841,16 @@ function MultiSwitch({
4662
4841
  react.useEffect(() => {
4663
4842
  updateIndicator();
4664
4843
  }, [updateIndicator]);
4665
- const control = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, children: resolvedOptions.find((o) => o.value === value)?.label }) : /* @__PURE__ */ jsxRuntime.jsxs(
4844
+ const control = !showControl ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, interactive, onActivate: enterEdit, children: resolvedOptions.find((o) => o.value === value)?.label }) : /* @__PURE__ */ jsxRuntime.jsxs(
4666
4845
  "div",
4667
4846
  {
4668
4847
  ref: containerRef,
4669
4848
  "data-react-fancy-multi-switch": "",
4670
4849
  role: "radiogroup",
4671
4850
  id,
4851
+ onBlur: (e) => {
4852
+ if (interactive && !e.currentTarget.contains(e.relatedTarget)) exitEdit();
4853
+ },
4672
4854
  className: cn(
4673
4855
  "relative inline-flex rounded-lg border border-zinc-300 bg-zinc-100 dark:border-zinc-700 dark:bg-zinc-800",
4674
4856
  dirty && "ring-2 ring-amber-400/50",
@@ -4696,6 +4878,7 @@ function MultiSwitch({
4696
4878
  role: "radio",
4697
4879
  "aria-checked": isSelected,
4698
4880
  disabled: disabled || option.disabled,
4881
+ autoFocus: interactive && (selectedIndex === -1 ? index === 0 : isSelected),
4699
4882
  onClick: () => {
4700
4883
  if (linear) {
4701
4884
  const nextIndex = (selectedIndex + 1) % resolvedOptions.length;
@@ -4815,12 +4998,22 @@ var SingleDatePicker = react.forwardRef(
4815
4998
  }, ref) => {
4816
4999
  const singleProps = rest;
4817
5000
  const resolvedMode = useFieldMode(mode);
5001
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
4818
5002
  const [value, setValue] = useControllableState(
4819
5003
  singleProps.value,
4820
5004
  singleProps.defaultValue ?? "",
4821
5005
  singleProps.onValueChange
4822
5006
  );
4823
- const input = resolvedMode === "view" ? /* @__PURE__ */ jsxRuntime.jsx(DisplayValue, { size, className, children: formatDateValue(value, includeTime) }) : /* @__PURE__ */ jsxRuntime.jsx(
5007
+ const input = !showControl ? /* @__PURE__ */ jsxRuntime.jsx(
5008
+ DisplayValue,
5009
+ {
5010
+ size,
5011
+ className,
5012
+ interactive,
5013
+ onActivate: enterEdit,
5014
+ children: formatDateValue(value, includeTime)
5015
+ }
5016
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
4824
5017
  "input",
4825
5018
  {
4826
5019
  "data-react-fancy-date-picker": "",
@@ -4834,7 +5027,11 @@ var SingleDatePicker = react.forwardRef(
4834
5027
  disabled,
4835
5028
  required,
4836
5029
  onChange: (e) => setValue(e.target.value),
4837
- className: cn(inputClasses, className)
5030
+ className: cn(inputClasses, className),
5031
+ autoFocus: interactive,
5032
+ onBlur: () => {
5033
+ if (interactive) exitEdit();
5034
+ }
4838
5035
  }
4839
5036
  );
4840
5037
  if (label || error || description) {
@@ -4876,43 +5073,64 @@ var RangeDatePicker = react.forwardRef(
4876
5073
  }, ref) => {
4877
5074
  const rangeProps = rest;
4878
5075
  const resolvedMode = useFieldMode(mode);
5076
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
4879
5077
  const [value, setValue] = useControllableState(
4880
5078
  rangeProps.value,
4881
5079
  rangeProps.defaultValue ?? ["", ""],
4882
5080
  rangeProps.onValueChange
4883
5081
  );
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: [
4885
- /* @__PURE__ */ jsxRuntime.jsx(
4886
- "input",
4887
- {
4888
- ref,
4889
- id,
4890
- type: inputType,
4891
- name: name ? `${name}_start` : void 0,
4892
- min,
4893
- max: value[1] || max,
4894
- value: value[0],
4895
- disabled,
4896
- required,
4897
- onChange: (e) => setValue([e.target.value, value[1]]),
4898
- className: inputClasses
4899
- }
4900
- ),
4901
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "to" }),
4902
- /* @__PURE__ */ jsxRuntime.jsx(
4903
- "input",
4904
- {
4905
- type: inputType,
4906
- name: name ? `${name}_end` : void 0,
4907
- min: value[0] || min,
4908
- max,
4909
- value: value[1],
4910
- disabled,
4911
- onChange: (e) => setValue([value[0], e.target.value]),
4912
- className: inputClasses
4913
- }
4914
- )
4915
- ] });
5082
+ const input = !showControl ? /* @__PURE__ */ jsxRuntime.jsx(
5083
+ DisplayValue,
5084
+ {
5085
+ size,
5086
+ className,
5087
+ interactive,
5088
+ onActivate: enterEdit,
5089
+ children: value[0] || value[1] ? `${formatDateValue(value[0], includeTime)} \u2013 ${formatDateValue(value[1], includeTime)}` : ""
5090
+ }
5091
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
5092
+ "div",
5093
+ {
5094
+ "data-react-fancy-date-picker": "",
5095
+ className: cn("flex items-center gap-2", className),
5096
+ onBlur: (e) => {
5097
+ if (interactive && !e.currentTarget.contains(e.relatedTarget)) exitEdit();
5098
+ },
5099
+ children: [
5100
+ /* @__PURE__ */ jsxRuntime.jsx(
5101
+ "input",
5102
+ {
5103
+ ref,
5104
+ id,
5105
+ type: inputType,
5106
+ name: name ? `${name}_start` : void 0,
5107
+ min,
5108
+ max: value[1] || max,
5109
+ value: value[0],
5110
+ disabled,
5111
+ required,
5112
+ onChange: (e) => setValue([e.target.value, value[1]]),
5113
+ className: inputClasses,
5114
+ autoFocus: interactive
5115
+ }
5116
+ ),
5117
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: "to" }),
5118
+ /* @__PURE__ */ jsxRuntime.jsx(
5119
+ "input",
5120
+ {
5121
+ type: inputType,
5122
+ name: name ? `${name}_end` : void 0,
5123
+ min: value[0] || min,
5124
+ max,
5125
+ value: value[1],
5126
+ disabled,
5127
+ onChange: (e) => setValue([value[0], e.target.value]),
5128
+ className: inputClasses
5129
+ }
5130
+ )
5131
+ ]
5132
+ }
5133
+ );
4916
5134
  if (label || error || description) {
4917
5135
  return /* @__PURE__ */ jsxRuntime.jsx(
4918
5136
  Field,
@@ -5286,6 +5504,7 @@ var ColorPicker = react.forwardRef(
5286
5504
  onChange
5287
5505
  );
5288
5506
  const resolvedMode = useFieldMode(mode);
5507
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
5289
5508
  const inputRef = react.useRef(null);
5290
5509
  const datalistId = react.useId();
5291
5510
  const handleChange = (e) => {
@@ -5296,14 +5515,28 @@ var ColorPicker = react.forwardRef(
5296
5515
  inputRef.current?.click();
5297
5516
  }
5298
5517
  };
5299
- if (resolvedMode === "view") {
5518
+ if (!showControl) {
5300
5519
  return /* @__PURE__ */ jsxRuntime.jsxs(
5301
5520
  "div",
5302
5521
  {
5303
5522
  ref,
5304
5523
  "data-react-fancy-color-picker": "",
5305
5524
  "data-mode": "view",
5306
- className: cn("inline-flex items-center gap-2", className),
5525
+ role: interactive ? "button" : void 0,
5526
+ tabIndex: interactive ? 0 : void 0,
5527
+ title: interactive ? "Click to edit" : void 0,
5528
+ onClick: interactive ? enterEdit : void 0,
5529
+ onKeyDown: interactive ? (e) => {
5530
+ if (e.key === "Enter" || e.key === " ") {
5531
+ e.preventDefault();
5532
+ enterEdit();
5533
+ }
5534
+ } : void 0,
5535
+ className: cn(
5536
+ "inline-flex items-center gap-2",
5537
+ interactive && "cursor-pointer rounded-md outline-none transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-blue-500/40",
5538
+ className
5539
+ ),
5307
5540
  children: [
5308
5541
  /* @__PURE__ */ jsxRuntime.jsx(
5309
5542
  "span",
@@ -5338,12 +5571,16 @@ var ColorPicker = react.forwardRef(
5338
5571
  ref,
5339
5572
  "data-react-fancy-color-picker": "",
5340
5573
  className: cn("inline-flex items-center gap-2", className),
5574
+ onBlur: (e) => {
5575
+ if (interactive && !e.currentTarget.contains(e.relatedTarget)) exitEdit();
5576
+ },
5341
5577
  children: [
5342
5578
  /* @__PURE__ */ jsxRuntime.jsx(
5343
5579
  "button",
5344
5580
  {
5345
5581
  type: "button",
5346
5582
  disabled,
5583
+ autoFocus: interactive,
5347
5584
  onClick: handleSwatchClick,
5348
5585
  className: cn(
5349
5586
  "relative shrink-0 rounded-full transition-shadow",
@@ -9087,6 +9324,7 @@ var Autocomplete = react.forwardRef(
9087
9324
  onChange
9088
9325
  );
9089
9326
  const resolvedMode = useFieldMode(mode);
9327
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
9090
9328
  const [query, setQuery] = react.useState(value);
9091
9329
  const [open, setOpen] = react.useState(false);
9092
9330
  const [activeIndex, setActiveIndex] = react.useState(-1);
@@ -9139,7 +9377,7 @@ var Autocomplete = react.forwardRef(
9139
9377
  if (item && !item.disabled) select(item.value);
9140
9378
  }
9141
9379
  };
9142
- if (resolvedMode === "view") {
9380
+ if (!showControl) {
9143
9381
  const matched = options.find((o) => o.value === value);
9144
9382
  return /* @__PURE__ */ jsxRuntime.jsx(
9145
9383
  "div",
@@ -9147,72 +9385,97 @@ var Autocomplete = react.forwardRef(
9147
9385
  "data-react-fancy-autocomplete": "",
9148
9386
  "data-mode": "view",
9149
9387
  ref: wrapperRef,
9388
+ role: interactive ? "button" : void 0,
9389
+ tabIndex: interactive ? 0 : void 0,
9390
+ title: interactive ? "Click to edit" : void 0,
9391
+ onClick: interactive ? enterEdit : void 0,
9392
+ onKeyDown: interactive ? (e) => {
9393
+ if (e.key === "Enter" || e.key === " ") {
9394
+ e.preventDefault();
9395
+ enterEdit();
9396
+ }
9397
+ } : void 0,
9150
9398
  className: cn(
9151
9399
  "text-sm text-zinc-900 dark:text-zinc-100",
9152
9400
  !value && "text-zinc-400 dark:text-zinc-500",
9401
+ interactive && "cursor-pointer rounded-md outline-none transition-colors hover:bg-zinc-100 focus-visible:ring-2 focus-visible:ring-blue-500/40 dark:hover:bg-zinc-800",
9153
9402
  className
9154
9403
  ),
9155
9404
  children: matched?.label ?? value ?? "\u2014"
9156
9405
  }
9157
9406
  );
9158
9407
  }
9159
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-react-fancy-autocomplete": "", ref: wrapperRef, className: cn("relative", className), children: [
9160
- /* @__PURE__ */ jsxRuntime.jsx(
9161
- "input",
9162
- {
9163
- ref: (node) => {
9164
- anchorRef.current = node;
9165
- if (typeof ref === "function") ref(node);
9166
- else if (ref) ref.current = node;
9167
- },
9168
- type: "text",
9169
- value: query,
9170
- onChange: (e) => {
9171
- setQuery(e.target.value);
9172
- setOpen(true);
9173
- setActiveIndex(-1);
9174
- },
9175
- onFocus: () => setOpen(true),
9176
- onKeyDown: handleKeyDown,
9177
- placeholder,
9178
- disabled,
9179
- role: "combobox",
9180
- "aria-expanded": open,
9181
- "aria-autocomplete": "list",
9182
- className: "w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-900 placeholder:text-zinc-400 outline-none transition-[border-color,box-shadow] duration-150 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/40 dark:border-zinc-700 dark:bg-[#1e1e24] dark:text-zinc-100 dark:placeholder:text-zinc-500 dark:focus:border-blue-400 dark:focus:ring-blue-400/20"
9183
- }
9184
- ),
9185
- open && /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
9186
- "div",
9187
- {
9188
- ref: listRef,
9189
- role: "listbox",
9190
- className: "fixed z-50 max-h-60 min-w-[8rem] overflow-y-auto rounded-xl border border-zinc-200 bg-white p-1 shadow-lg dark:border-zinc-700 dark:bg-zinc-900 dark:shadow-zinc-950/50 fancy-scale-in",
9191
- style: {
9192
- left: position.x,
9193
- top: position.y,
9194
- width: anchorRef.current?.offsetWidth
9195
- },
9196
- children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-zinc-400", children: "Loading..." }) : filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-zinc-400", children: emptyMessage }) : filtered.map((option, i) => /* @__PURE__ */ jsxRuntime.jsx(
9197
- "button",
9408
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9409
+ "div",
9410
+ {
9411
+ "data-react-fancy-autocomplete": "",
9412
+ ref: wrapperRef,
9413
+ className: cn("relative", className),
9414
+ onBlur: (e) => {
9415
+ if (interactive && !open && !e.currentTarget.contains(e.relatedTarget)) {
9416
+ exitEdit();
9417
+ }
9418
+ },
9419
+ children: [
9420
+ /* @__PURE__ */ jsxRuntime.jsx(
9421
+ "input",
9198
9422
  {
9199
- type: "button",
9200
- role: "option",
9201
- "aria-selected": i === activeIndex,
9202
- disabled: option.disabled,
9203
- onClick: () => select(option.value),
9204
- className: cn(
9205
- "flex w-full items-center rounded-lg px-3 py-2 text-left text-sm text-zinc-700 transition-colors dark:text-zinc-200",
9206
- i === activeIndex ? "bg-zinc-100 dark:bg-zinc-800" : "hover:bg-zinc-50 dark:hover:bg-zinc-800/50",
9207
- option.disabled && "cursor-not-allowed opacity-50"
9208
- ),
9209
- children: /* @__PURE__ */ jsxRuntime.jsx(HighlightMatch, { text: option.label, query })
9210
- },
9211
- option.value
9212
- ))
9213
- }
9214
- ) })
9215
- ] });
9423
+ ref: (node) => {
9424
+ anchorRef.current = node;
9425
+ if (typeof ref === "function") ref(node);
9426
+ else if (ref) ref.current = node;
9427
+ },
9428
+ type: "text",
9429
+ value: query,
9430
+ onChange: (e) => {
9431
+ setQuery(e.target.value);
9432
+ setOpen(true);
9433
+ setActiveIndex(-1);
9434
+ },
9435
+ onFocus: () => setOpen(true),
9436
+ onKeyDown: handleKeyDown,
9437
+ placeholder,
9438
+ disabled,
9439
+ autoFocus: interactive,
9440
+ role: "combobox",
9441
+ "aria-expanded": open,
9442
+ "aria-autocomplete": "list",
9443
+ className: "w-full rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm text-zinc-900 placeholder:text-zinc-400 outline-none transition-[border-color,box-shadow] duration-150 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/40 dark:border-zinc-700 dark:bg-[#1e1e24] dark:text-zinc-100 dark:placeholder:text-zinc-500 dark:focus:border-blue-400 dark:focus:ring-blue-400/20"
9444
+ }
9445
+ ),
9446
+ open && /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
9447
+ "div",
9448
+ {
9449
+ ref: listRef,
9450
+ role: "listbox",
9451
+ className: "fixed z-50 max-h-60 min-w-[8rem] overflow-y-auto rounded-xl border border-zinc-200 bg-white p-1 shadow-lg dark:border-zinc-700 dark:bg-zinc-900 dark:shadow-zinc-950/50 fancy-scale-in",
9452
+ style: {
9453
+ left: position.x,
9454
+ top: position.y,
9455
+ width: anchorRef.current?.offsetWidth
9456
+ },
9457
+ children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-zinc-400", children: "Loading..." }) : filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-zinc-400", children: emptyMessage }) : filtered.map((option, i) => /* @__PURE__ */ jsxRuntime.jsx(
9458
+ "button",
9459
+ {
9460
+ type: "button",
9461
+ role: "option",
9462
+ "aria-selected": i === activeIndex,
9463
+ disabled: option.disabled,
9464
+ onClick: () => select(option.value),
9465
+ className: cn(
9466
+ "flex w-full items-center rounded-lg px-3 py-2 text-left text-sm text-zinc-700 transition-colors dark:text-zinc-200",
9467
+ i === activeIndex ? "bg-zinc-100 dark:bg-zinc-800" : "hover:bg-zinc-50 dark:hover:bg-zinc-800/50",
9468
+ option.disabled && "cursor-not-allowed opacity-50"
9469
+ ),
9470
+ children: /* @__PURE__ */ jsxRuntime.jsx(HighlightMatch, { text: option.label, query })
9471
+ },
9472
+ option.value
9473
+ ))
9474
+ }
9475
+ ) })
9476
+ ]
9477
+ }
9478
+ );
9216
9479
  }
9217
9480
  );
9218
9481
  function HighlightMatch({ text, query }) {
@@ -9337,6 +9600,7 @@ var OtpInput = react.forwardRef(
9337
9600
  onChange
9338
9601
  );
9339
9602
  const resolvedMode = useFieldMode(mode);
9603
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
9340
9604
  const inputsRef = react.useRef([]);
9341
9605
  const focusInput = react.useCallback(
9342
9606
  (index) => {
@@ -9390,42 +9654,64 @@ var OtpInput = react.forwardRef(
9390
9654
  },
9391
9655
  [length, setValue, focusInput]
9392
9656
  );
9393
- if (resolvedMode === "view") {
9657
+ if (!showControl) {
9394
9658
  return /* @__PURE__ */ jsxRuntime.jsx(
9395
9659
  "div",
9396
9660
  {
9397
9661
  "data-react-fancy-otp-input": "",
9398
9662
  "data-mode": "view",
9399
9663
  ref,
9664
+ role: interactive ? "button" : void 0,
9665
+ tabIndex: interactive ? 0 : void 0,
9666
+ title: interactive ? "Click to edit" : void 0,
9667
+ onClick: interactive ? enterEdit : void 0,
9668
+ onKeyDown: interactive ? (e) => {
9669
+ if (e.key === "Enter" || e.key === " ") {
9670
+ e.preventDefault();
9671
+ enterEdit();
9672
+ }
9673
+ } : void 0,
9400
9674
  className: cn(
9401
9675
  "font-mono text-lg tracking-[0.4em] text-zinc-900 dark:text-zinc-100",
9676
+ interactive && "cursor-pointer rounded-md outline-none transition-opacity hover:opacity-80 focus-visible:ring-2 focus-visible:ring-blue-500/40",
9402
9677
  className
9403
9678
  ),
9404
9679
  children: value || "\u2014"
9405
9680
  }
9406
9681
  );
9407
9682
  }
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(
9409
- "input",
9683
+ return /* @__PURE__ */ jsxRuntime.jsx(
9684
+ "div",
9410
9685
  {
9411
- ref: (el) => {
9412
- inputsRef.current[i] = el;
9686
+ "data-react-fancy-otp-input": "",
9687
+ ref,
9688
+ className: cn("flex gap-2", className),
9689
+ onBlur: (e) => {
9690
+ if (interactive && !e.currentTarget.contains(e.relatedTarget)) exitEdit();
9413
9691
  },
9414
- type: "text",
9415
- inputMode: "numeric",
9416
- maxLength: 1,
9417
- value: value[i] ?? "",
9418
- onChange: (e) => handleChange(i, e.target.value),
9419
- onKeyDown: (e) => handleKeyDown(i, e),
9420
- onPaste: handlePaste,
9421
- onFocus: (e) => e.target.select(),
9422
- disabled,
9423
- autoFocus: autoFocus && i === 0,
9424
- className: "h-12 w-10 rounded-lg border border-zinc-200 bg-white text-center text-lg font-medium text-zinc-900 outline-none transition-[border-color,box-shadow] duration-150 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/40 dark:border-zinc-700 dark:bg-[#1e1e24] dark:text-zinc-100 dark:focus:border-blue-400 dark:focus:ring-blue-400/20",
9425
- "aria-label": `Digit ${i + 1}`
9426
- },
9427
- i
9428
- )) });
9692
+ children: Array.from({ length }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx(
9693
+ "input",
9694
+ {
9695
+ ref: (el) => {
9696
+ inputsRef.current[i] = el;
9697
+ },
9698
+ type: "text",
9699
+ inputMode: "numeric",
9700
+ maxLength: 1,
9701
+ value: value[i] ?? "",
9702
+ onChange: (e) => handleChange(i, e.target.value),
9703
+ onKeyDown: (e) => handleKeyDown(i, e),
9704
+ onPaste: handlePaste,
9705
+ onFocus: (e) => e.target.select(),
9706
+ disabled,
9707
+ autoFocus: (autoFocus || interactive) && i === 0,
9708
+ className: "h-12 w-10 rounded-lg border border-zinc-200 bg-white text-center text-lg font-medium text-zinc-900 outline-none transition-[border-color,box-shadow] duration-150 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/40 dark:border-zinc-700 dark:bg-[#1e1e24] dark:text-zinc-100 dark:focus:border-blue-400 dark:focus:ring-blue-400/20",
9709
+ "aria-label": `Digit ${i + 1}`
9710
+ },
9711
+ i
9712
+ ))
9713
+ }
9714
+ );
9429
9715
  }
9430
9716
  );
9431
9717
  OtpInput.displayName = "OtpInput";
@@ -9628,10 +9914,11 @@ var TimePicker = react.forwardRef(
9628
9914
  onChange
9629
9915
  );
9630
9916
  const resolvedMode = useFieldMode(mode);
9917
+ const { showControl, interactive, enterEdit, exitEdit } = useInlineEdit(resolvedMode, disabled);
9631
9918
  const { hours: h24, minutes } = parseTime(value);
9632
9919
  const isPM = h24 >= 12;
9633
9920
  const displayHour = format === "12h" ? h24 % 12 || 12 : h24;
9634
- if (resolvedMode === "view") {
9921
+ if (!showControl) {
9635
9922
  const formatted = format === "12h" ? `${pad(displayHour)}:${pad(minutes)} ${isPM ? "PM" : "AM"}` : `${pad(displayHour)}:${pad(minutes)}`;
9636
9923
  return /* @__PURE__ */ jsxRuntime.jsx(
9637
9924
  "div",
@@ -9639,8 +9926,19 @@ var TimePicker = react.forwardRef(
9639
9926
  "data-react-fancy-time-picker": "",
9640
9927
  "data-mode": "view",
9641
9928
  ref,
9929
+ role: interactive ? "button" : void 0,
9930
+ tabIndex: interactive ? 0 : void 0,
9931
+ title: interactive ? "Click to edit" : void 0,
9932
+ onClick: interactive ? enterEdit : void 0,
9933
+ onKeyDown: interactive ? (e) => {
9934
+ if (e.key === "Enter" || e.key === " ") {
9935
+ e.preventDefault();
9936
+ enterEdit();
9937
+ }
9938
+ } : void 0,
9642
9939
  className: cn(
9643
9940
  "text-sm font-medium tabular-nums text-zinc-900 dark:text-zinc-100",
9941
+ interactive && "cursor-pointer rounded-md outline-none transition-colors hover:bg-zinc-100 focus-visible:ring-2 focus-visible:ring-blue-500/40 dark:hover:bg-zinc-800",
9644
9942
  className
9645
9943
  ),
9646
9944
  children: formatted
@@ -9677,6 +9975,9 @@ var TimePicker = react.forwardRef(
9677
9975
  {
9678
9976
  "data-react-fancy-time-picker": "",
9679
9977
  ref,
9978
+ onBlur: (e) => {
9979
+ if (interactive && !e.currentTarget.contains(e.relatedTarget)) exitEdit();
9980
+ },
9680
9981
  className: cn(
9681
9982
  "inline-flex items-center gap-1 rounded-lg border border-zinc-200 bg-white p-2 dark:border-zinc-700 dark:bg-zinc-900",
9682
9983
  disabled && "opacity-50",
@@ -9684,7 +9985,7 @@ var TimePicker = react.forwardRef(
9684
9985
  ),
9685
9986
  children: [
9686
9987
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [
9687
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => changeHour(1), disabled, className: spinBtnClass, "aria-label": "Increase hour", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { size: 14 }) }),
9988
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", autoFocus: interactive, onClick: () => changeHour(1), disabled, className: spinBtnClass, "aria-label": "Increase hour", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { size: 14 }) }),
9688
9989
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: displayClass, children: pad(displayHour) }),
9689
9990
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => changeHour(-1), disabled, className: spinBtnClass, "aria-label": "Decrease hour", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { size: 14 }) })
9690
9991
  ] }),
@@ -14056,6 +14357,7 @@ exports.hasSkinTones = hasSkinTones;
14056
14357
  exports.inputAdapter = inputAdapter;
14057
14358
  exports.registerExtension = registerExtension;
14058
14359
  exports.registerExtensions = registerExtensions;
14360
+ exports.registerIconAddendum = registerIconAddendum;
14059
14361
  exports.registerIconSet = registerIconSet;
14060
14362
  exports.registerIcons = registerIcons;
14061
14363
  exports.resolve = resolve;