@alpic-ai/ui 1.170.0 → 1.171.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.
Files changed (37) hide show
  1. package/dist/components/alert.d.mts +1 -1
  2. package/dist/components/avatar.d.mts +1 -1
  3. package/dist/components/badge.d.mts +1 -1
  4. package/dist/components/bar-chart.mjs +1 -1
  5. package/dist/components/button.d.mts +2 -2
  6. package/dist/components/editable.d.mts +101 -0
  7. package/dist/components/editable.mjs +509 -0
  8. package/dist/components/form.d.mts +10 -8
  9. package/dist/components/form.mjs +18 -8
  10. package/dist/components/input.d.mts +3 -1
  11. package/dist/components/input.mjs +5 -3
  12. package/dist/components/sidebar.d.mts +1 -1
  13. package/dist/components/skeleton.d.mts +1 -1
  14. package/dist/components/spinner.d.mts +1 -1
  15. package/dist/components/status-dot.d.mts +1 -1
  16. package/dist/components/tabs.d.mts +1 -1
  17. package/dist/components/toggle-group.d.mts +1 -1
  18. package/dist/components/visually-hidden-input.d.mts +12 -0
  19. package/dist/components/visually-hidden-input.mjs +109 -0
  20. package/dist/hooks/use-as-ref.d.mts +5 -0
  21. package/dist/hooks/use-as-ref.mjs +12 -0
  22. package/dist/hooks/use-isomorphic-layout-effect.d.mts +5 -0
  23. package/dist/hooks/use-isomorphic-layout-effect.mjs +5 -0
  24. package/dist/hooks/use-lazy-ref.d.mts +6 -0
  25. package/dist/hooks/use-lazy-ref.mjs +9 -0
  26. package/dist/lib/compose-refs.mjs +23 -0
  27. package/package.json +8 -12
  28. package/src/components/bar-chart.tsx +1 -1
  29. package/src/components/editable.tsx +871 -0
  30. package/src/components/form.tsx +16 -6
  31. package/src/components/input.tsx +8 -0
  32. package/src/components/visually-hidden-input.tsx +148 -0
  33. package/src/hooks/use-as-ref.ts +15 -0
  34. package/src/hooks/use-isomorphic-layout-effect.ts +5 -0
  35. package/src/hooks/use-lazy-ref.ts +13 -0
  36. package/src/lib/compose-refs.ts +38 -0
  37. package/src/stories/input.stories.tsx +3 -0
@@ -2,7 +2,7 @@ import { VariantProps } from "class-variance-authority";
2
2
  import * as React$1 from "react";
3
3
  //#region src/components/alert.d.ts
4
4
  declare const alertVariants: (props?: ({
5
- variant?: "default" | "destructive" | "warning" | "success" | null | undefined;
5
+ variant?: "default" | "destructive" | "success" | "warning" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  interface AlertProps extends React$1.HTMLAttributes<HTMLDivElement>, VariantProps<typeof alertVariants> {}
8
8
  declare function Alert({ className, variant, ...props }: AlertProps): React$1.JSX.Element;
@@ -3,7 +3,7 @@ import * as React$1 from "react";
3
3
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
4
4
  //#region src/components/avatar.d.ts
5
5
  declare const avatarVariants: (props?: ({
6
- size?: "sm" | "lg" | "xs" | "md" | "xl" | null | undefined;
6
+ size?: "sm" | "lg" | "md" | "xl" | "xs" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
8
  type AvatarSize = NonNullable<VariantProps<typeof avatarVariants>["size"]>;
9
9
  type AvatarStatus = "online";
@@ -1,7 +1,7 @@
1
1
  import { VariantProps } from "class-variance-authority";
2
2
  //#region src/components/badge.d.ts
3
3
  declare const badgeVariants: (props?: ({
4
- variant?: "warning" | "success" | "secondary" | "primary" | "error" | null | undefined;
4
+ variant?: "primary" | "secondary" | "success" | "warning" | "error" | null | undefined;
5
5
  size?: "sm" | "md" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  interface BadgeProps extends React.ComponentProps<"span">, VariantProps<typeof badgeVariants> {}
@@ -89,7 +89,7 @@ function BarChart({ data, index, series, variant = "stacked", legend = false, le
89
89
  "data-slot": "bar-chart",
90
90
  className: cn("flex w-full flex-col gap-3", "[&_.recharts-surface]:outline-none [&_.recharts-wrapper]:outline-none", className),
91
91
  children: [/* @__PURE__ */ jsx("div", {
92
- className: "w-full",
92
+ className: cn("w-full", bare && !loading && !isEmpty && "border-border border-b"),
93
93
  style: { height },
94
94
  children: loading ? /* @__PURE__ */ jsx(Skeleton, { className: "h-full w-full rounded-lg" }) : isEmpty ? /* @__PURE__ */ jsx("div", {
95
95
  className: "flex h-full items-center justify-center rounded-lg border border-border border-dashed font-mono text-quaternary-foreground text-text-xs",
@@ -2,8 +2,8 @@ import { VariantProps } from "class-variance-authority";
2
2
  import * as React$1 from "react";
3
3
  //#region src/components/button.d.ts
4
4
  declare const buttonVariants: (props?: ({
5
- variant?: "destructive" | "secondary" | "primary" | "tertiary" | "link" | "link-muted" | "cta" | null | undefined;
6
- size?: "default" | "icon" | "icon-rounded" | "pill" | null | undefined;
5
+ variant?: "destructive" | "primary" | "secondary" | "link" | "tertiary" | "link-muted" | "cta" | null | undefined;
6
+ size?: "default" | "pill" | "icon" | "icon-rounded" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
8
  interface ButtonProps extends React$1.ComponentProps<"button">, VariantProps<typeof buttonVariants> {
9
9
  asChild?: boolean;
@@ -0,0 +1,101 @@
1
+ import * as React$1 from "react";
2
+ //#region src/components/editable.d.ts
3
+ type Direction = "ltr" | "rtl";
4
+ interface DivProps extends React$1.ComponentProps<"div"> {
5
+ asChild?: boolean;
6
+ }
7
+ interface StoreState {
8
+ value: string;
9
+ editing: boolean;
10
+ }
11
+ interface Store {
12
+ subscribe: (callback: () => void) => () => void;
13
+ getState: () => StoreState;
14
+ setState: <K extends keyof StoreState>(key: K, value: StoreState[K]) => void;
15
+ notify: () => void;
16
+ }
17
+ declare function useStore<T>(selector: (state: StoreState) => T, ogStore?: Store | null): T;
18
+ interface EditableContextValue {
19
+ rootId: string;
20
+ inputId: string;
21
+ labelId: string;
22
+ defaultValue: string;
23
+ onCancel: () => void;
24
+ onEdit: () => void;
25
+ onSubmit: (value: string) => void;
26
+ onEnterKeyDown?: (event: KeyboardEvent) => void;
27
+ onEscapeKeyDown?: (event: KeyboardEvent) => void;
28
+ dir?: Direction;
29
+ maxLength?: number;
30
+ placeholder?: string;
31
+ triggerMode: "click" | "dblclick" | "focus";
32
+ autosize: boolean;
33
+ multiline: boolean;
34
+ disabled?: boolean;
35
+ readOnly?: boolean;
36
+ required?: boolean;
37
+ invalid?: boolean;
38
+ }
39
+ interface EditableProps extends Omit<DivProps, "onSubmit"> {
40
+ id?: string;
41
+ defaultValue?: string;
42
+ value?: string;
43
+ onValueChange?: (value: string) => void;
44
+ defaultEditing?: boolean;
45
+ editing?: boolean;
46
+ onEditingChange?: (editing: boolean) => void;
47
+ onCancel?: () => void;
48
+ onEdit?: () => void;
49
+ onSubmit?: (value: string) => void;
50
+ onEscapeKeyDown?: (event: KeyboardEvent) => void;
51
+ onEnterKeyDown?: (event: KeyboardEvent) => void;
52
+ dir?: Direction;
53
+ maxLength?: number;
54
+ name?: string;
55
+ placeholder?: string;
56
+ triggerMode?: EditableContextValue["triggerMode"];
57
+ autosize?: boolean;
58
+ multiline?: boolean;
59
+ disabled?: boolean;
60
+ readOnly?: boolean;
61
+ required?: boolean;
62
+ invalid?: boolean;
63
+ }
64
+ declare function Editable(props: EditableProps): React$1.JSX.Element;
65
+ interface EditableLabelProps extends React$1.ComponentProps<"label"> {
66
+ asChild?: boolean;
67
+ }
68
+ declare function EditableLabel(props: EditableLabelProps): React$1.JSX.Element;
69
+ interface EditableAreaProps extends React$1.ComponentProps<"div"> {
70
+ asChild?: boolean;
71
+ }
72
+ declare function EditableArea(props: EditableAreaProps): React$1.JSX.Element;
73
+ interface EditablePreviewProps extends React$1.ComponentProps<"div"> {
74
+ asChild?: boolean;
75
+ }
76
+ declare function EditablePreview(props: EditablePreviewProps): React$1.JSX.Element | null;
77
+ interface EditableInputProps extends React$1.ComponentProps<"input"> {
78
+ asChild?: boolean;
79
+ maxLength?: number;
80
+ }
81
+ declare function EditableInput(props: EditableInputProps): React$1.JSX.Element | null;
82
+ interface EditableTriggerProps extends React$1.ComponentProps<"button"> {
83
+ asChild?: boolean;
84
+ forceMount?: boolean;
85
+ }
86
+ declare function EditableTrigger(props: EditableTriggerProps): React$1.JSX.Element | null;
87
+ interface EditableToolbarProps extends React$1.ComponentProps<"div"> {
88
+ asChild?: boolean;
89
+ orientation?: "horizontal" | "vertical";
90
+ }
91
+ declare function EditableToolbar(props: EditableToolbarProps): React$1.JSX.Element;
92
+ interface EditableCancelProps extends React$1.ComponentProps<"button"> {
93
+ asChild?: boolean;
94
+ }
95
+ declare function EditableCancel(props: EditableCancelProps): React$1.JSX.Element | null;
96
+ interface EditableSubmitProps extends React$1.ComponentProps<"button"> {
97
+ asChild?: boolean;
98
+ }
99
+ declare function EditableSubmit(props: EditableSubmitProps): React$1.JSX.Element | null;
100
+ //#endregion
101
+ export { Editable, EditableArea, EditableCancel, EditableInput, EditableLabel, EditablePreview, type EditableProps, EditableSubmit, EditableToolbar, EditableTrigger, useStore as useEditable };
@@ -0,0 +1,509 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.mjs";
3
+ import { useIsomorphicLayoutEffect } from "../hooks/use-isomorphic-layout-effect.mjs";
4
+ import { useAsRef } from "../hooks/use-as-ref.mjs";
5
+ import { useLazyRef } from "../hooks/use-lazy-ref.mjs";
6
+ import { useComposedRefs } from "../lib/compose-refs.mjs";
7
+ import { VisuallyHiddenInput } from "./visually-hidden-input.mjs";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import * as React$1 from "react";
10
+ import { Slot } from "@radix-ui/react-slot";
11
+ //#region src/components/editable.tsx
12
+ const ROOT_NAME = "Editable";
13
+ const LABEL_NAME = "EditableLabel";
14
+ const AREA_NAME = "EditableArea";
15
+ const PREVIEW_NAME = "EditablePreview";
16
+ const INPUT_NAME = "EditableInput";
17
+ const TRIGGER_NAME = "EditableTrigger";
18
+ const TOOLBAR_NAME = "EditableToolbar";
19
+ const CANCEL_NAME = "EditableCancel";
20
+ const SUBMIT_NAME = "EditableSubmit";
21
+ const StoreContext = React$1.createContext(null);
22
+ function useStoreContext(consumerName) {
23
+ const context = React$1.useContext(StoreContext);
24
+ if (!context) throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
25
+ return context;
26
+ }
27
+ function useStore(selector, ogStore) {
28
+ const contextStore = React$1.useContext(StoreContext);
29
+ const store = ogStore ?? contextStore;
30
+ if (!store) throw new Error(`\`useStore\` must be used within \`${ROOT_NAME}\``);
31
+ const getSnapshot = React$1.useCallback(() => selector(store.getState()), [store, selector]);
32
+ return React$1.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
33
+ }
34
+ const EditableContext = React$1.createContext(null);
35
+ function useEditableContext(consumerName) {
36
+ const context = React$1.useContext(EditableContext);
37
+ if (!context) throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
38
+ return context;
39
+ }
40
+ function Editable(props) {
41
+ const { value: valueProp, defaultValue = "", defaultEditing, editing: editingProp, onValueChange, onEditingChange, onCancel: onCancelProp, onEdit: onEditProp, onSubmit: onSubmitProp, onEscapeKeyDown, onEnterKeyDown, dir: dirProp, maxLength, name, placeholder, triggerMode = "click", asChild, autosize = false, multiline = false, disabled, required, readOnly, invalid, className, id, ref, ...rootProps } = props;
42
+ const instanceId = React$1.useId();
43
+ const rootId = id ?? instanceId;
44
+ const inputId = React$1.useId();
45
+ const labelId = React$1.useId();
46
+ const dir = dirProp ?? "ltr";
47
+ const previousValueRef = React$1.useRef(defaultValue);
48
+ const [formTrigger, setFormTrigger] = React$1.useState(null);
49
+ const composedRef = useComposedRefs(ref, (node) => setFormTrigger(node));
50
+ const isFormControl = formTrigger ? !!formTrigger.closest("form") : true;
51
+ const listenersRef = useLazyRef(() => /* @__PURE__ */ new Set());
52
+ const stateRef = useLazyRef(() => ({
53
+ value: valueProp ?? defaultValue,
54
+ editing: editingProp ?? defaultEditing ?? false
55
+ }));
56
+ const propsRef = useAsRef({
57
+ onValueChange,
58
+ onEditingChange,
59
+ onCancel: onCancelProp,
60
+ onEdit: onEditProp,
61
+ onSubmit: onSubmitProp,
62
+ onEscapeKeyDown,
63
+ onEnterKeyDown
64
+ });
65
+ const store = React$1.useMemo(() => {
66
+ return {
67
+ subscribe: (cb) => {
68
+ listenersRef.current.add(cb);
69
+ return () => listenersRef.current.delete(cb);
70
+ },
71
+ getState: () => stateRef.current,
72
+ setState: (key, value) => {
73
+ if (Object.is(stateRef.current[key], value)) return;
74
+ if (key === "value" && typeof value === "string") {
75
+ stateRef.current.value = value;
76
+ propsRef.current.onValueChange?.(value);
77
+ } else if (key === "editing" && typeof value === "boolean") {
78
+ stateRef.current.editing = value;
79
+ propsRef.current.onEditingChange?.(value);
80
+ } else stateRef.current[key] = value;
81
+ store.notify();
82
+ },
83
+ notify: () => {
84
+ for (const cb of listenersRef.current) cb();
85
+ }
86
+ };
87
+ }, [
88
+ listenersRef,
89
+ stateRef,
90
+ propsRef
91
+ ]);
92
+ const value = useStore((state) => state.value, store);
93
+ useIsomorphicLayoutEffect(() => {
94
+ if (valueProp !== void 0) store.setState("value", valueProp);
95
+ }, [valueProp]);
96
+ useIsomorphicLayoutEffect(() => {
97
+ if (editingProp !== void 0) store.setState("editing", editingProp);
98
+ }, [editingProp]);
99
+ const onCancel = React$1.useCallback(() => {
100
+ const prevValue = previousValueRef.current;
101
+ store.setState("value", prevValue);
102
+ store.setState("editing", false);
103
+ propsRef.current.onCancel?.();
104
+ }, [store, propsRef]);
105
+ const onEdit = React$1.useCallback(() => {
106
+ const currentValue = store.getState().value;
107
+ previousValueRef.current = currentValue;
108
+ store.setState("editing", true);
109
+ propsRef.current.onEdit?.();
110
+ }, [store, propsRef]);
111
+ const onSubmit = React$1.useCallback((newValue) => {
112
+ store.setState("value", newValue);
113
+ store.setState("editing", false);
114
+ propsRef.current.onSubmit?.(newValue);
115
+ }, [store, propsRef]);
116
+ const contextValue = React$1.useMemo(() => ({
117
+ rootId,
118
+ inputId,
119
+ labelId,
120
+ defaultValue,
121
+ onSubmit,
122
+ onEdit,
123
+ onCancel,
124
+ onEscapeKeyDown,
125
+ onEnterKeyDown,
126
+ dir,
127
+ maxLength,
128
+ placeholder,
129
+ triggerMode,
130
+ autosize,
131
+ multiline,
132
+ disabled,
133
+ readOnly,
134
+ required,
135
+ invalid
136
+ }), [
137
+ rootId,
138
+ inputId,
139
+ labelId,
140
+ defaultValue,
141
+ onSubmit,
142
+ onCancel,
143
+ onEdit,
144
+ onEscapeKeyDown,
145
+ onEnterKeyDown,
146
+ dir,
147
+ maxLength,
148
+ placeholder,
149
+ triggerMode,
150
+ autosize,
151
+ multiline,
152
+ disabled,
153
+ required,
154
+ readOnly,
155
+ invalid
156
+ ]);
157
+ const RootPrimitive = asChild ? Slot : "div";
158
+ return /* @__PURE__ */ jsx(StoreContext.Provider, {
159
+ value: store,
160
+ children: /* @__PURE__ */ jsxs(EditableContext.Provider, {
161
+ value: contextValue,
162
+ children: [/* @__PURE__ */ jsx(RootPrimitive, {
163
+ "data-slot": "editable",
164
+ ...rootProps,
165
+ id,
166
+ ref: composedRef,
167
+ className: cn("flex min-w-0 flex-col gap-2", className)
168
+ }), isFormControl && /* @__PURE__ */ jsx(VisuallyHiddenInput, {
169
+ type: "hidden",
170
+ control: formTrigger,
171
+ name,
172
+ value,
173
+ disabled,
174
+ readOnly,
175
+ required
176
+ })]
177
+ })
178
+ });
179
+ }
180
+ function EditableLabel(props) {
181
+ const { asChild, className, children, ref, ...labelProps } = props;
182
+ const context = useEditableContext(LABEL_NAME);
183
+ return /* @__PURE__ */ jsx(asChild ? Slot : "label", {
184
+ "data-disabled": context.disabled ? "" : void 0,
185
+ "data-invalid": context.invalid ? "" : void 0,
186
+ "data-required": context.required ? "" : void 0,
187
+ "data-slot": "editable-label",
188
+ ...labelProps,
189
+ ref,
190
+ id: context.labelId,
191
+ htmlFor: context.inputId,
192
+ className: cn("text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70 data-required:after:ml-0.5 data-required:after:text-destructive data-required:after:content-['*']", className),
193
+ children
194
+ });
195
+ }
196
+ function EditableArea(props) {
197
+ const { asChild, className, ref, ...areaProps } = props;
198
+ const context = useEditableContext(AREA_NAME);
199
+ const editing = useStore((state) => state.editing);
200
+ return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
201
+ role: "group",
202
+ "data-disabled": context.disabled ? "" : void 0,
203
+ "data-editing": editing ? "" : void 0,
204
+ "data-slot": "editable-area",
205
+ dir: context.dir,
206
+ ...areaProps,
207
+ ref,
208
+ className: cn("relative inline-block min-w-0 data-disabled:cursor-not-allowed data-disabled:opacity-50", className)
209
+ });
210
+ }
211
+ function EditablePreview(props) {
212
+ const { onClick: onClickProp, onDoubleClick: onDoubleClickProp, onFocus: onFocusProp, onKeyDown: onKeyDownProp, asChild, className, ref, ...previewProps } = props;
213
+ const context = useEditableContext(PREVIEW_NAME);
214
+ const value = useStore((state) => state.value);
215
+ const editing = useStore((state) => state.editing);
216
+ const propsRef = useAsRef({
217
+ onClick: onClickProp,
218
+ onDoubleClick: onDoubleClickProp,
219
+ onFocus: onFocusProp,
220
+ onKeyDown: onKeyDownProp
221
+ });
222
+ const onTrigger = React$1.useCallback(() => {
223
+ if (context.disabled || context.readOnly) return;
224
+ context.onEdit();
225
+ }, [
226
+ context.onEdit,
227
+ context.disabled,
228
+ context.readOnly
229
+ ]);
230
+ const onClick = React$1.useCallback((event) => {
231
+ propsRef.current.onClick?.(event);
232
+ if (event.defaultPrevented || context.triggerMode !== "click") return;
233
+ onTrigger();
234
+ }, [
235
+ propsRef,
236
+ onTrigger,
237
+ context.triggerMode
238
+ ]);
239
+ const onDoubleClick = React$1.useCallback((event) => {
240
+ propsRef.current.onDoubleClick?.(event);
241
+ if (event.defaultPrevented || context.triggerMode !== "dblclick") return;
242
+ onTrigger();
243
+ }, [
244
+ propsRef,
245
+ onTrigger,
246
+ context.triggerMode
247
+ ]);
248
+ const onFocus = React$1.useCallback((event) => {
249
+ propsRef.current.onFocus?.(event);
250
+ if (event.defaultPrevented || context.triggerMode !== "focus") return;
251
+ onTrigger();
252
+ }, [
253
+ propsRef,
254
+ onTrigger,
255
+ context.triggerMode
256
+ ]);
257
+ const onKeyDown = React$1.useCallback((event) => {
258
+ propsRef.current.onKeyDown?.(event);
259
+ if (event.defaultPrevented) return;
260
+ if (event.key === "Enter") {
261
+ const nativeEvent = event.nativeEvent;
262
+ if (context.onEnterKeyDown) {
263
+ context.onEnterKeyDown(nativeEvent);
264
+ if (nativeEvent.defaultPrevented) return;
265
+ }
266
+ onTrigger();
267
+ }
268
+ }, [
269
+ propsRef,
270
+ onTrigger,
271
+ context.onEnterKeyDown
272
+ ]);
273
+ const PreviewPrimitive = asChild ? Slot : "div";
274
+ if (editing || context.readOnly) return null;
275
+ return /* @__PURE__ */ jsx(PreviewPrimitive, {
276
+ role: "button",
277
+ "aria-disabled": context.disabled || context.readOnly,
278
+ "data-empty": !value ? "" : void 0,
279
+ "data-disabled": context.disabled ? "" : void 0,
280
+ "data-readonly": context.readOnly ? "" : void 0,
281
+ "data-slot": "editable-preview",
282
+ tabIndex: context.disabled || context.readOnly ? void 0 : 0,
283
+ ...previewProps,
284
+ ref,
285
+ onClick,
286
+ onDoubleClick,
287
+ onFocus,
288
+ onKeyDown,
289
+ className: cn("cursor-text whitespace-pre-wrap rounded-sm border border-transparent px-1.5 py-1 transition-colors hover:bg-muted focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-hidden data-disabled:cursor-not-allowed data-disabled:opacity-50 data-empty:text-muted-foreground/60 data-empty:italic data-readonly:cursor-default data-readonly:hover:bg-transparent", className),
290
+ children: value || context.placeholder
291
+ });
292
+ }
293
+ function EditableInput(props) {
294
+ const { onBlur: onBlurProp, onChange: onChangeProp, onKeyDown: onKeyDownProp, asChild, className, disabled, readOnly, required, maxLength, ref, ...inputProps } = props;
295
+ const context = useEditableContext(INPUT_NAME);
296
+ const store = useStoreContext(INPUT_NAME);
297
+ const value = useStore((state) => state.value);
298
+ const editing = useStore((state) => state.editing);
299
+ const inputRef = React$1.useRef(null);
300
+ const composedRef = useComposedRefs(ref, inputRef);
301
+ const propsRef = useAsRef({
302
+ onBlur: onBlurProp,
303
+ onChange: onChangeProp,
304
+ onKeyDown: onKeyDownProp
305
+ });
306
+ const isDisabled = disabled || context.disabled;
307
+ const isReadOnly = readOnly || context.readOnly;
308
+ const isRequired = required || context.required;
309
+ const onAutosize = React$1.useCallback((target) => {
310
+ if (!context.autosize) return;
311
+ const { borderTopWidth, borderBottomWidth, borderLeftWidth, borderRightWidth } = getComputedStyle(target);
312
+ if (target instanceof HTMLTextAreaElement) {
313
+ target.style.height = "0";
314
+ target.style.height = `${target.scrollHeight + Number.parseFloat(borderTopWidth) + Number.parseFloat(borderBottomWidth)}px`;
315
+ } else {
316
+ target.style.width = "0";
317
+ target.style.width = `${target.scrollWidth + Number.parseFloat(borderLeftWidth) + Number.parseFloat(borderRightWidth)}px`;
318
+ }
319
+ }, [context.autosize]);
320
+ const onBlur = React$1.useCallback((event) => {
321
+ if (isDisabled || isReadOnly) return;
322
+ propsRef.current.onBlur?.(event);
323
+ if (event.defaultPrevented) return;
324
+ const relatedTarget = event.relatedTarget;
325
+ if (!(relatedTarget instanceof HTMLElement && (relatedTarget.closest(`[data-slot="editable-trigger"]`) || relatedTarget.closest(`[data-slot="editable-cancel"]`)))) context.onSubmit(value);
326
+ }, [
327
+ value,
328
+ context.onSubmit,
329
+ propsRef,
330
+ isDisabled,
331
+ isReadOnly
332
+ ]);
333
+ const onChange = React$1.useCallback((event) => {
334
+ if (isDisabled || isReadOnly) return;
335
+ propsRef.current.onChange?.(event);
336
+ if (event.defaultPrevented) return;
337
+ store.setState("value", event.target.value);
338
+ onAutosize(event.target);
339
+ }, [
340
+ store,
341
+ propsRef,
342
+ onAutosize,
343
+ isDisabled,
344
+ isReadOnly
345
+ ]);
346
+ const onKeyDown = React$1.useCallback((event) => {
347
+ if (isDisabled || isReadOnly) return;
348
+ propsRef.current.onKeyDown?.(event);
349
+ if (event.defaultPrevented) return;
350
+ if (event.key === "Escape") {
351
+ const nativeEvent = event.nativeEvent;
352
+ if (context.onEscapeKeyDown) {
353
+ context.onEscapeKeyDown(nativeEvent);
354
+ if (nativeEvent.defaultPrevented) return;
355
+ }
356
+ context.onCancel();
357
+ } else if (event.key === "Enter" && !context.multiline) {
358
+ event.preventDefault();
359
+ context.onSubmit(value);
360
+ }
361
+ }, [
362
+ value,
363
+ context.onSubmit,
364
+ context.onCancel,
365
+ context.onEscapeKeyDown,
366
+ context.multiline,
367
+ propsRef,
368
+ isDisabled,
369
+ isReadOnly
370
+ ]);
371
+ useIsomorphicLayoutEffect(() => {
372
+ if (!editing || isDisabled || isReadOnly || !inputRef.current) return;
373
+ const frameId = window.requestAnimationFrame(() => {
374
+ if (!inputRef.current) return;
375
+ inputRef.current.focus();
376
+ inputRef.current.select();
377
+ onAutosize(inputRef.current);
378
+ });
379
+ return () => {
380
+ window.cancelAnimationFrame(frameId);
381
+ };
382
+ }, [
383
+ editing,
384
+ onAutosize,
385
+ isDisabled,
386
+ isReadOnly
387
+ ]);
388
+ const InputPrimitive = asChild ? Slot : "input";
389
+ if (!editing && !isReadOnly) return null;
390
+ return /* @__PURE__ */ jsx(InputPrimitive, {
391
+ "aria-required": isRequired,
392
+ "aria-invalid": context.invalid,
393
+ "data-slot": "editable-input",
394
+ dir: context.dir,
395
+ disabled: isDisabled,
396
+ readOnly: isReadOnly,
397
+ required: isRequired,
398
+ ...inputProps,
399
+ id: context.inputId,
400
+ "aria-labelledby": context.labelId,
401
+ ref: composedRef,
402
+ maxLength: maxLength ?? context.maxLength,
403
+ placeholder: context.placeholder,
404
+ value,
405
+ onBlur,
406
+ onChange,
407
+ onKeyDown,
408
+ className: cn("flex rounded-sm border border-input bg-transparent px-1.5 py-1 shadow-xs transition-colors placeholder:text-muted-foreground/60 placeholder:italic focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50", context.autosize && !context.multiline ? "w-auto" : "w-full", className)
409
+ });
410
+ }
411
+ function EditableTrigger(props) {
412
+ const { asChild, forceMount = false, ref, ...triggerProps } = props;
413
+ const context = useEditableContext(TRIGGER_NAME);
414
+ const editing = useStore((state) => state.editing);
415
+ const onTrigger = React$1.useCallback(() => {
416
+ if (context.disabled || context.readOnly) return;
417
+ context.onEdit();
418
+ }, [
419
+ context.disabled,
420
+ context.readOnly,
421
+ context.onEdit
422
+ ]);
423
+ const TriggerPrimitive = asChild ? Slot : "button";
424
+ if (!forceMount && (editing || context.readOnly)) return null;
425
+ return /* @__PURE__ */ jsx(TriggerPrimitive, {
426
+ type: "button",
427
+ "aria-controls": context.rootId,
428
+ "aria-disabled": context.disabled || context.readOnly,
429
+ "data-disabled": context.disabled ? "" : void 0,
430
+ "data-readonly": context.readOnly ? "" : void 0,
431
+ "data-slot": "editable-trigger",
432
+ ...triggerProps,
433
+ ref,
434
+ onClick: context.triggerMode === "click" ? onTrigger : void 0,
435
+ onDoubleClick: context.triggerMode === "dblclick" ? onTrigger : void 0
436
+ });
437
+ }
438
+ function EditableToolbar(props) {
439
+ const { asChild, className, orientation = "horizontal", ref, ...toolbarProps } = props;
440
+ const context = useEditableContext(TOOLBAR_NAME);
441
+ return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
442
+ role: "toolbar",
443
+ "aria-controls": context.rootId,
444
+ "aria-orientation": orientation,
445
+ "data-slot": "editable-toolbar",
446
+ dir: context.dir,
447
+ ...toolbarProps,
448
+ ref,
449
+ className: cn("flex items-center gap-2", orientation === "vertical" && "flex-col", className)
450
+ });
451
+ }
452
+ function EditableCancel(props) {
453
+ const { onClick: onClickProp, asChild, ref, ...cancelProps } = props;
454
+ const context = useEditableContext(CANCEL_NAME);
455
+ const editing = useStore((state) => state.editing);
456
+ const propsRef = useAsRef({ onClick: onClickProp });
457
+ const onClick = React$1.useCallback((event) => {
458
+ if (context.disabled || context.readOnly) return;
459
+ propsRef.current.onClick?.(event);
460
+ if (event.defaultPrevented) return;
461
+ context.onCancel();
462
+ }, [
463
+ propsRef,
464
+ context.onCancel,
465
+ context.disabled,
466
+ context.readOnly
467
+ ]);
468
+ const CancelPrimitive = asChild ? Slot : "button";
469
+ if (!editing && !context.readOnly) return null;
470
+ return /* @__PURE__ */ jsx(CancelPrimitive, {
471
+ type: "button",
472
+ "aria-controls": context.rootId,
473
+ "data-slot": "editable-cancel",
474
+ ...cancelProps,
475
+ onClick,
476
+ ref
477
+ });
478
+ }
479
+ function EditableSubmit(props) {
480
+ const { onClick: onClickProp, asChild, ref, ...submitProps } = props;
481
+ const context = useEditableContext(SUBMIT_NAME);
482
+ const value = useStore((state) => state.value);
483
+ const editing = useStore((state) => state.editing);
484
+ const propsRef = useAsRef({ onClick: onClickProp });
485
+ const onClick = React$1.useCallback((event) => {
486
+ if (context.disabled || context.readOnly) return;
487
+ propsRef.current.onClick?.(event);
488
+ if (event.defaultPrevented) return;
489
+ context.onSubmit(value);
490
+ }, [
491
+ propsRef,
492
+ context.onSubmit,
493
+ value,
494
+ context.disabled,
495
+ context.readOnly
496
+ ]);
497
+ const SubmitPrimitive = asChild ? Slot : "button";
498
+ if (!editing && !context.readOnly) return null;
499
+ return /* @__PURE__ */ jsx(SubmitPrimitive, {
500
+ type: "button",
501
+ "aria-controls": context.rootId,
502
+ "data-slot": "editable-submit",
503
+ ...submitProps,
504
+ ref,
505
+ onClick
506
+ });
507
+ }
508
+ //#endregion
509
+ export { Editable, EditableArea, EditableCancel, EditableInput, EditableLabel, EditablePreview, EditableSubmit, EditableToolbar, EditableTrigger, useStore as useEditable };