@nexub/react 7.3.0 → 7.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.
Files changed (38) hide show
  1. package/accessibility.json +1 -1
  2. package/dist/components/Avatar/Avatar.d.ts +3 -0
  3. package/dist/components/Avatar/Avatar.js +28 -5
  4. package/dist/components/Avatar/index.d.ts +1 -1
  5. package/dist/components/Button/Button.d.ts +2 -1
  6. package/dist/components/Button/Button.js +37 -7
  7. package/dist/components/Combobox/Combobox.d.ts +6 -9
  8. package/dist/components/Combobox/Combobox.js +30 -9
  9. package/dist/components/DataTable/DataTable.d.ts +5 -1
  10. package/dist/components/DataTable/DataTable.js +6 -2
  11. package/dist/components/DatePicker/DatePicker.d.ts +16 -1
  12. package/dist/components/DatePicker/DatePicker.js +100 -26
  13. package/dist/components/FileUpload/FileUpload.js +86 -32
  14. package/dist/components/Input/Input.d.ts +6 -0
  15. package/dist/components/Input/Input.js +47 -5
  16. package/dist/components/Progress/Progress.d.ts +4 -0
  17. package/dist/components/Progress/Progress.js +73 -20
  18. package/dist/components/Select/Select.d.ts +18 -3
  19. package/dist/components/Select/Select.js +170 -71
  20. package/dist/components/Skeleton/Skeleton.d.ts +9 -0
  21. package/dist/components/Skeleton/Skeleton.js +18 -1
  22. package/dist/components/Skeleton/index.d.ts +2 -2
  23. package/dist/components/Skeleton/index.js +2 -1
  24. package/dist/components/Slider/Slider.d.ts +10 -0
  25. package/dist/components/Slider/Slider.js +48 -3
  26. package/dist/components/Slider/index.d.ts +1 -1
  27. package/dist/components/Switch/Switch.d.ts +6 -0
  28. package/dist/components/Switch/Switch.js +29 -2
  29. package/dist/components/Toast/Toaster.js +68 -23
  30. package/dist/components/Toast/index.d.ts +1 -1
  31. package/dist/components/Toast/useToast.d.ts +18 -1
  32. package/dist/components/Toast/useToast.js +14 -0
  33. package/dist/hooks/useAsyncAction.d.ts +27 -0
  34. package/dist/hooks/useAsyncAction.js +36 -0
  35. package/dist/index.d.ts +7 -4
  36. package/dist/index.js +4 -1
  37. package/dist/styles.css +1 -1
  38. package/package.json +6 -6
@@ -5,6 +5,7 @@ import { Upload, X } from "@nexub/icons";
5
5
  import { cn } from "../../utils/cn.js";
6
6
  import { useLocale, useNexubMessages } from "../NexubProvider/NexubProvider.js";
7
7
  import { Progress } from "../Progress/Progress.js";
8
+ import { SPRING_MS } from "../Motion/useMotion.js";
8
9
  function formatFileSize(bytes, locale) {
9
10
  const [value, unit] = bytes < 1024 ? [bytes, "byte"] : bytes < 1024 * 1024 ? [bytes / 1024, "kilobyte"] : [bytes / (1024 * 1024), "megabyte"];
10
11
  return new Intl.NumberFormat(locale, { style: "unit", unit, unitDisplay: "short", maximumFractionDigits: 1 }).format(value);
@@ -27,7 +28,7 @@ function useFileUpload() {
27
28
  return ctx;
28
29
  }
29
30
  const Root = React.forwardRef(
30
- ({ className, accept, maxFiles, maxSize, onFilesChange, onReject, validate, children, ...props }, ref) => {
31
+ ({ className, accept, maxFiles, maxSize, onFilesChange, onReject, validate, onPaste, children, ...props }, ref) => {
31
32
  const [files, setFiles] = React.useState([]);
32
33
  const [rejections, setRejections] = React.useState([]);
33
34
  const [isDragging, setIsDragging] = React.useState(false);
@@ -65,7 +66,22 @@ const Root = React.forwardRef(
65
66
  () => ({ accept, maxFiles, maxSize, onFilesChange, files, rejections, addFiles, removeFile, isDragging, setIsDragging }),
66
67
  [accept, maxFiles, maxSize, onFilesChange, files, rejections, addFiles, removeFile, isDragging, setIsDragging]
67
68
  );
68
- return /* @__PURE__ */ jsx(FileUploadContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { ref, className: cn("flex flex-col gap-4", className), ...props, children }) });
69
+ return /* @__PURE__ */ jsx(FileUploadContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
70
+ "div",
71
+ {
72
+ ref,
73
+ className: cn("flex flex-col gap-4", className),
74
+ onPaste: (e) => {
75
+ onPaste?.(e);
76
+ const pasted = Array.from(e.clipboardData?.files ?? []);
77
+ if (e.defaultPrevented || !pasted.length) return;
78
+ e.preventDefault();
79
+ addFiles(pasted);
80
+ },
81
+ ...props,
82
+ children
83
+ }
84
+ ) });
69
85
  }
70
86
  );
71
87
  Root.displayName = "FileUpload.Root";
@@ -140,7 +156,7 @@ const List = React.forwardRef(
140
156
  ({ className, ...props }, ref) => {
141
157
  const { files } = useFileUpload();
142
158
  if (files.length === 0) return null;
143
- return /* @__PURE__ */ jsx("ul", { ref, className: cn("flex flex-col gap-2", className), ...props });
159
+ return /* @__PURE__ */ jsx("ul", { ref, className: cn("flex flex-col", className), ...props });
144
160
  }
145
161
  );
146
162
  List.displayName = "FileUpload.List";
@@ -149,40 +165,78 @@ const Item = React.forwardRef(({ className, index, progress, onCancel, error, ..
149
165
  const messages = useNexubMessages();
150
166
  const { locale } = useLocale();
151
167
  const file = files[index];
168
+ const [exiting, setExiting] = React.useState(null);
169
+ const [entered, setEntered] = React.useState(false);
170
+ const [thumb, setThumb] = React.useState();
171
+ React.useEffect(() => {
172
+ if (!file?.type.startsWith("image/") || typeof URL.createObjectURL !== "function") return;
173
+ const url = URL.createObjectURL(file);
174
+ setThumb(url);
175
+ return () => {
176
+ URL.revokeObjectURL(url);
177
+ setThumb(void 0);
178
+ };
179
+ }, [file]);
180
+ const isExiting = !!file && exiting === file;
181
+ React.useEffect(() => {
182
+ if (!isExiting) return;
183
+ const t = setTimeout(() => removeFile(index), SPRING_MS.effects.default + 50);
184
+ return () => clearTimeout(t);
185
+ }, [isExiting, index, removeFile]);
152
186
  if (!file) return null;
153
187
  const uploading = progress !== void 0 && progress < 100;
154
188
  const percent = Math.round(Math.max(0, Math.min(100, progress ?? 0)));
155
- return /* @__PURE__ */ jsxs(
156
- "li",
157
- {
158
- ref,
159
- className: cn(
160
- "flex items-center justify-between gap-3 rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface)] p-3",
161
- className
162
- ),
163
- ...props,
164
- children: [
165
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
166
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-[var(--color-on-surface)]", children: file.name }),
167
- /* @__PURE__ */ jsxs("p", { className: "text-xs text-[var(--color-on-surface-muted)]", children: [
168
- formatFileSize(file.size, locale),
169
- uploading && ` \xB7 ${percent}%`
170
- ] }),
171
- uploading && /* @__PURE__ */ jsx(Progress, { value: percent, size: "sm", className: "mt-1.5", "aria-label": messages.uploadProgress(file.name, percent) }),
172
- error && /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-1 text-xs text-[var(--color-error)]", children: error })
173
- ] }),
174
- /* @__PURE__ */ jsx(
175
- "button",
189
+ return (
190
+ // nx-list-item: grows in on add, collapses out on remove (grid rows, spring tokens).
191
+ /* @__PURE__ */ jsx(
192
+ "li",
193
+ {
194
+ ref,
195
+ className: "nx-list-item",
196
+ "data-state": isExiting ? "exit" : entered ? void 0 : "enter",
197
+ onAnimationEnd: (e) => {
198
+ if (e.target !== e.currentTarget) return;
199
+ if (isExiting) removeFile(index);
200
+ else setEntered(true);
201
+ },
202
+ ...props,
203
+ children: /* @__PURE__ */ jsx("div", { className: "nx-list-item-inner", children: /* @__PURE__ */ jsx("div", { className: "[li:not(:last-child)>.nx-list-item-inner>&]:pb-2", children: /* @__PURE__ */ jsxs(
204
+ "div",
176
205
  {
177
- type: "button",
178
- onClick: () => uploading && onCancel ? onCancel() : removeFile(index),
179
- "aria-label": uploading && onCancel ? messages.cancelUpload(file.name) : messages.removeFile(file.name),
180
- className: "nx-state-layer shrink-0 rounded-full p-1 text-[var(--color-on-surface-muted)] hover:text-[var(--color-on-surface)] transition-colors",
181
- children: /* @__PURE__ */ jsx(X, { size: "sm", "aria-hidden": "true" })
206
+ className: cn(
207
+ "flex items-center justify-between gap-3 rounded-shape-container border border-[var(--color-outline-variant)] bg-[var(--color-surface)] p-3",
208
+ className
209
+ ),
210
+ children: [
211
+ thumb && /* @__PURE__ */ jsx("img", { src: thumb, alt: "", className: "h-10 w-10 shrink-0 rounded-shape-min object-cover" }),
212
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
213
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-[var(--color-on-surface)]", children: file.name }),
214
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-[var(--color-on-surface-muted)]", children: [
215
+ formatFileSize(file.size, locale),
216
+ uploading && ` \xB7 ${percent}%`
217
+ ] }),
218
+ uploading && /* @__PURE__ */ jsx(Progress, { value: percent, size: "sm", className: "mt-1.5", "aria-label": messages.uploadProgress(file.name, percent) }),
219
+ error && /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-1 text-xs text-[var(--color-error)]", children: error })
220
+ ] }),
221
+ /* @__PURE__ */ jsx(
222
+ "button",
223
+ {
224
+ type: "button",
225
+ onClick: () => {
226
+ if (uploading && onCancel) return onCancel();
227
+ setEntered(true);
228
+ setExiting(file);
229
+ },
230
+ "aria-label": uploading && onCancel ? messages.cancelUpload(file.name) : messages.removeFile(file.name),
231
+ className: "nx-state-layer shrink-0 rounded-full p-1 text-[var(--color-on-surface-muted)] hover:text-[var(--color-on-surface)] transition-colors",
232
+ children: /* @__PURE__ */ jsx(X, { size: "sm", "aria-hidden": "true" })
233
+ }
234
+ )
235
+ ]
182
236
  }
183
- )
184
- ]
185
- }
237
+ ) }) })
238
+ }
239
+ )
186
240
  );
187
241
  });
188
242
  Item.displayName = "FileUpload.Item";
@@ -17,5 +17,11 @@ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
17
17
  leadingIcon?: React.ReactNode;
18
18
  trailingIcon?: React.ReactNode;
19
19
  wrapperClassName?: string;
20
+ /** Shows a clear button while there is a value. Clearing fires `onChange` with "". */
21
+ clearable?: boolean;
22
+ /** Shows a "12/80" counter; needs `maxLength`. Announced politely near the limit. */
23
+ showCount?: boolean;
24
+ /** Spinner in the trailing slot and `aria-busy` on the input. */
25
+ loading?: boolean;
20
26
  }
21
27
  export declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
@@ -1,8 +1,14 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
3
  import * as React from "react";
4
+ import { X } from "@nexub/icons";
3
5
  import { cva } from "class-variance-authority";
4
6
  import { cn } from "../../utils/cn.js";
5
7
  import { field, fieldDisabledWithin, fieldFocusWithin, fieldInvalid } from "../../utils/control.js";
8
+ import { useMergedRefs } from "../../hooks/useMergedRefs.js";
9
+ import { useNexubMessages } from "../NexubProvider/NexubProvider.js";
10
+ import { IconButton } from "../IconButton/IconButton.js";
11
+ import { Spinner } from "../Spinner/Spinner.js";
6
12
  const inputVariants = cva(
7
13
  [
8
14
  // The wrapper owns ALL focus styling (border + ring). Strip every possible
@@ -67,6 +73,7 @@ const addonVariants = cva(
67
73
  }
68
74
  }
69
75
  );
76
+ const nearLimit = (length, max) => length >= max - Math.max(1, Math.ceil(max * 0.1));
70
77
  const Input = React.forwardRef(
71
78
  ({
72
79
  className,
@@ -78,26 +85,61 @@ const Input = React.forwardRef(
78
85
  trailingIcon,
79
86
  wrapperClassName,
80
87
  disabled,
88
+ clearable,
89
+ showCount,
90
+ loading,
81
91
  ...props
82
92
  }, ref) => {
83
93
  const hasAddon = Boolean(leadingAddon ?? trailingAddon);
94
+ const messages = useNexubMessages();
95
+ const innerRef = React.useRef(null);
96
+ const mergedRef = useMergedRefs(ref, innerRef);
97
+ const countId = React.useId();
98
+ const [uncontrolledLength, setLength] = React.useState(String(props.defaultValue ?? "").length);
99
+ const length = props.value !== void 0 && props.value !== null ? String(props.value).length : uncontrolledLength;
100
+ const max = props.maxLength;
101
+ const counting = Boolean(showCount && max !== void 0 && max >= 0);
102
+ const handleChange = (e) => {
103
+ setLength(e.target.value.length);
104
+ props.onChange?.(e);
105
+ };
106
+ const clear = () => {
107
+ const el = innerRef.current;
108
+ if (!el) return;
109
+ Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set?.call(el, "");
110
+ el.dispatchEvent(new Event("input", { bubbles: true }));
111
+ el.focus();
112
+ };
84
113
  const inputEl = /* @__PURE__ */ jsx(
85
114
  "input",
86
115
  {
87
- ref,
88
116
  className: cn(inputVariants({ size }), className),
89
117
  "aria-invalid": invalid ?? void 0,
118
+ "aria-busy": loading || void 0,
90
119
  disabled,
91
- ...props
120
+ ...props,
121
+ "aria-describedby": [props["aria-describedby"], counting && countId].filter(Boolean).join(" ") || void 0,
122
+ onChange: handleChange,
123
+ ref: mergedRef
92
124
  }
93
125
  );
126
+ const showClear = clearable && length > 0 && !disabled && !props.readOnly;
127
+ const trailing = /* @__PURE__ */ jsxs(Fragment, { children: [
128
+ counting && /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-label-sm tabular-nums text-[var(--color-on-surface-muted)]", children: [
129
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: `${length}/${max}` }),
130
+ /* @__PURE__ */ jsx("span", { id: countId, className: "sr-only", "aria-live": nearLimit(length, max) ? "polite" : "off", children: messages.characterCount(length, max) })
131
+ ] }),
132
+ loading && /* @__PURE__ */ jsx(Spinner, { size: "sm", className: "shrink-0" }),
133
+ showClear && /* @__PURE__ */ jsx(IconButton, { size: "xs", label: messages.clear, onClick: clear, className: "-me-1.5", children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4", "aria-hidden": "true" }) }),
134
+ trailingIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--color-on-surface-variant)]", children: trailingIcon })
135
+ ] });
94
136
  if (hasAddon) {
95
137
  return /* @__PURE__ */ jsxs("div", { className: cn("flex w-full overflow-hidden", field, fieldFocusWithin, invalid && fieldInvalid), children: [
96
138
  leadingAddon && /* @__PURE__ */ jsx("span", { className: cn(addonVariants({ side: "leading" })), children: leadingAddon }),
97
139
  /* @__PURE__ */ jsxs("div", { className: cn(inputWrapperVariants({ size, invalid }), "rounded-none border-0 shadow-none focus-within:shadow-none", wrapperClassName), children: [
98
140
  leadingIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--color-on-surface-variant)]", children: leadingIcon }),
99
141
  inputEl,
100
- trailingIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--color-on-surface-variant)]", children: trailingIcon })
142
+ trailing
101
143
  ] }),
102
144
  trailingAddon && /* @__PURE__ */ jsx("span", { className: cn(addonVariants({ side: "trailing" })), children: trailingAddon })
103
145
  ] });
@@ -105,7 +147,7 @@ const Input = React.forwardRef(
105
147
  return /* @__PURE__ */ jsxs("div", { className: cn(inputWrapperVariants({ size, invalid }), wrapperClassName), children: [
106
148
  leadingIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--color-on-surface-variant)]", children: leadingIcon }),
107
149
  inputEl,
108
- trailingIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[var(--color-on-surface-variant)]", children: trailingIcon })
150
+ trailing
109
151
  ] });
110
152
  }
111
153
  );
@@ -13,5 +13,9 @@ export interface ProgressProps extends Omit<React.HTMLAttributes<HTMLDivElement>
13
13
  max?: number;
14
14
  tone?: ToneValue;
15
15
  animated?: boolean;
16
+ /** `circular` draws a ring; same value/max/indeterminate semantics. @default 'linear' */
17
+ variant?: 'linear' | 'circular';
18
+ /** Linear only: splits the bar into N equal steps, filled up to the value. */
19
+ segments?: number;
16
20
  }
17
21
  export declare const Progress: React.ForwardRefExoticComponent<ProgressProps & React.RefAttributes<HTMLDivElement>>;
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { cva } from "class-variance-authority";
5
5
  import { cn } from "../../utils/cn.js";
@@ -43,6 +43,18 @@ const progressFillVariants = cva(
43
43
  }
44
44
  }
45
45
  );
46
+ const ringTone = {
47
+ neutral: "stroke-[var(--color-outline)]",
48
+ info: "stroke-[var(--color-info)]",
49
+ success: "stroke-[var(--color-success)]",
50
+ warning: "stroke-[var(--color-warning)]",
51
+ danger: "stroke-[var(--color-error)]",
52
+ leap: "stroke-[var(--color-leap)]",
53
+ bookub: "stroke-[var(--color-bookub)]",
54
+ payub: "stroke-[var(--color-payub)]",
55
+ founderub: "stroke-[var(--color-founderub)]"
56
+ };
57
+ const ringSize = { sm: "size-6", md: "size-10", lg: "size-16" };
46
58
  const Progress = React.forwardRef(
47
59
  ({
48
60
  className,
@@ -51,6 +63,8 @@ const Progress = React.forwardRef(
51
63
  value,
52
64
  max = 100,
53
65
  animated = false,
66
+ variant = "linear",
67
+ segments,
54
68
  ...props
55
69
  }, ref) => {
56
70
  const isIndeterminate = value === void 0 || value === null;
@@ -60,31 +74,70 @@ const Progress = React.forwardRef(
60
74
  useIsomorphicLayoutEffect(() => {
61
75
  fillRef.current?.style.setProperty("width", `${percentage}%`);
62
76
  }, [percentage]);
63
- return /* @__PURE__ */ jsx(
64
- "div",
65
- {
66
- ref,
67
- role: "progressbar",
68
- "aria-valuenow": isIndeterminate ? void 0 : clampedValue,
69
- "aria-valuemin": 0,
70
- "aria-valuemax": max,
71
- className: cn(progressTrackVariants({ size }), className),
72
- ...props,
73
- children: /* @__PURE__ */ jsx(
74
- "div",
77
+ const aria = {
78
+ role: "progressbar",
79
+ "aria-valuenow": isIndeterminate ? void 0 : clampedValue,
80
+ "aria-valuemin": 0,
81
+ "aria-valuemax": max
82
+ };
83
+ if (variant === "circular") {
84
+ return /* @__PURE__ */ jsx("div", { ref, ...aria, className: cn("inline-flex", ringSize[size ?? "md"], className), ...props, children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 36 36", className: cn("size-full -rotate-90", isIndeterminate && "animate-spin motion-reduce:animate-none"), "aria-hidden": "true", children: [
85
+ /* @__PURE__ */ jsx("circle", { cx: "18", cy: "18", r: "15", fill: "none", strokeWidth: "4", className: "stroke-[var(--color-surface-container-high)]" }),
86
+ /* @__PURE__ */ jsx(
87
+ "circle",
75
88
  {
76
- className: cn(
77
- progressFillVariants({ tone }),
78
- animated && "animate-pulse",
79
- isIndeterminate && "animate-[nx-progress-indeterminate_1.4s_ease-in-out_infinite]"
80
- ),
81
- ref: fillRef,
89
+ cx: "18",
90
+ cy: "18",
91
+ r: "15",
92
+ fill: "none",
93
+ strokeWidth: "4",
94
+ strokeLinecap: "round",
95
+ pathLength: 100,
96
+ strokeDasharray: `${isIndeterminate ? 25 : percentage} 100`,
97
+ className: cn("transition-all duration-spatial-default ease-spatial-default", ringTone[tone]),
82
98
  "data-part": "fill",
83
99
  "data-indeterminate": isIndeterminate || void 0
84
100
  }
85
101
  )
102
+ ] }) });
103
+ }
104
+ if (segments && segments > 0 && !isIndeterminate) {
105
+ const filled = Math.round(percentage / 100 * segments);
106
+ return /* @__PURE__ */ jsx(
107
+ "div",
108
+ {
109
+ ref,
110
+ ...aria,
111
+ className: cn(progressTrackVariants({ size }), "flex gap-1 bg-transparent", className),
112
+ ...props,
113
+ children: Array.from({ length: segments }, (_, i) => /* @__PURE__ */ jsx(
114
+ "div",
115
+ {
116
+ "data-part": "segment",
117
+ "data-filled": i < filled || void 0,
118
+ className: cn(
119
+ "flex-1",
120
+ i < filled ? progressFillVariants({ tone }) : "rounded-full bg-[var(--color-surface-container-high)]"
121
+ )
122
+ },
123
+ i
124
+ ))
125
+ }
126
+ );
127
+ }
128
+ return /* @__PURE__ */ jsx("div", { ref, ...aria, className: cn(progressTrackVariants({ size }), className), ...props, children: /* @__PURE__ */ jsx(
129
+ "div",
130
+ {
131
+ className: cn(
132
+ progressFillVariants({ tone }),
133
+ animated && "animate-pulse",
134
+ isIndeterminate && "animate-[nx-progress-indeterminate_1.4s_ease-in-out_infinite]"
135
+ ),
136
+ ref: fillRef,
137
+ "data-part": "fill",
138
+ "data-indeterminate": isIndeterminate || void 0
86
139
  }
87
- );
140
+ ) });
88
141
  }
89
142
  );
90
143
  Progress.displayName = "Progress";
@@ -1,7 +1,22 @@
1
1
  import * as React from 'react';
2
2
  import * as RadixSelect from '@radix-ui/react-select';
3
+ export interface SelectRootProps extends RadixSelect.SelectProps {
4
+ /** Shows a clear button on the Trigger while there is a value; clearing calls `onValueChange('')` and shows the placeholder. */
5
+ clearable?: boolean;
6
+ }
7
+ export interface SelectContentProps extends RadixSelect.SelectContentProps {
8
+ /** A filter field at the top; items whose text (or `textValue`) doesn't match are hidden. Typing on an item moves to the field. */
9
+ searchable?: boolean;
10
+ }
11
+ export interface SelectItemProps extends RadixSelect.SelectItemProps {
12
+ /** A secondary line under the label: the option's accessible description, not part of its name. */
13
+ description?: React.ReactNode;
14
+ }
3
15
  export declare const Select: {
4
- Root: React.FC<RadixSelect.SelectProps>;
16
+ Root: {
17
+ ({ clearable, value, defaultValue, onValueChange, onOpenChange, ...props }: SelectRootProps): React.JSX.Element;
18
+ displayName: string;
19
+ };
5
20
  Group: React.ForwardRefExoticComponent<RadixSelect.SelectGroupProps & React.RefAttributes<HTMLDivElement>>;
6
21
  Value: React.ForwardRefExoticComponent<RadixSelect.SelectValueProps & React.RefAttributes<HTMLSpanElement>>;
7
22
  Trigger: React.ForwardRefExoticComponent<RadixSelect.SelectTriggerProps & {
@@ -9,8 +24,8 @@ export declare const Select: {
9
24
  } & React.RefAttributes<HTMLButtonElement>>;
10
25
  ScrollUpButton: React.ForwardRefExoticComponent<RadixSelect.SelectScrollUpButtonProps & React.RefAttributes<HTMLDivElement>>;
11
26
  ScrollDownButton: React.ForwardRefExoticComponent<RadixSelect.SelectScrollDownButtonProps & React.RefAttributes<HTMLDivElement>>;
12
- Content: React.ForwardRefExoticComponent<RadixSelect.SelectContentProps & React.RefAttributes<HTMLDivElement>>;
27
+ Content: React.ForwardRefExoticComponent<SelectContentProps & React.RefAttributes<HTMLDivElement>>;
13
28
  Label: React.ForwardRefExoticComponent<RadixSelect.SelectLabelProps & React.RefAttributes<HTMLDivElement>>;
14
- Item: React.ForwardRefExoticComponent<RadixSelect.SelectItemProps & React.RefAttributes<HTMLDivElement>>;
29
+ Item: React.ForwardRefExoticComponent<SelectItemProps & React.RefAttributes<HTMLDivElement>>;
15
30
  Separator: React.ForwardRefExoticComponent<RadixSelect.SelectSeparatorProps & React.RefAttributes<HTMLDivElement>>;
16
31
  };