@conscia-labs/design-system 0.2.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/LICENSE +21 -0
- package/README.md +488 -0
- package/dist/card-DqFHjLjm.d.ts +22 -0
- package/dist/chunk-5MGPU2JE.js +1764 -0
- package/dist/chunk-5MGPU2JE.js.map +1 -0
- package/dist/chunk-CU3OXBFI.js +664 -0
- package/dist/chunk-CU3OXBFI.js.map +1 -0
- package/dist/chunk-D5LYROOM.js +15 -0
- package/dist/chunk-D5LYROOM.js.map +1 -0
- package/dist/chunk-JU5DQXFC.js +11 -0
- package/dist/chunk-JU5DQXFC.js.map +1 -0
- package/dist/chunk-OX4SN5WX.js +1 -0
- package/dist/chunk-OX4SN5WX.js.map +1 -0
- package/dist/chunk-YHPZ5CQU.js +937 -0
- package/dist/chunk-YHPZ5CQU.js.map +1 -0
- package/dist/foundation/index.d.ts +7 -0
- package/dist/foundation/index.js +12 -0
- package/dist/foundation/index.js.map +1 -0
- package/dist/foundation.css +432 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +355 -0
- package/dist/index.js.map +1 -0
- package/dist/patterns/index.d.ts +317 -0
- package/dist/patterns/index.js +109 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/primitives/index.d.ts +239 -0
- package/dist/primitives/index.js +244 -0
- package/dist/primitives/index.js.map +1 -0
- package/dist/standalone.css +2 -0
- package/dist/styles.css +432 -0
- package/dist/tailwind.css +8 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +150 -0
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Button,
|
|
3
|
+
Card,
|
|
4
|
+
CardContent,
|
|
5
|
+
CardDescription,
|
|
6
|
+
CardHeader,
|
|
7
|
+
CardTitle,
|
|
8
|
+
Checkbox,
|
|
9
|
+
Select,
|
|
10
|
+
SelectContent,
|
|
11
|
+
SelectGroup,
|
|
12
|
+
SelectItem,
|
|
13
|
+
SelectTrigger,
|
|
14
|
+
SelectValue,
|
|
15
|
+
Table,
|
|
16
|
+
TableBody,
|
|
17
|
+
TableCell,
|
|
18
|
+
TableHead,
|
|
19
|
+
TableHeader,
|
|
20
|
+
TableRow
|
|
21
|
+
} from "./chunk-YHPZ5CQU.js";
|
|
22
|
+
import {
|
|
23
|
+
cn
|
|
24
|
+
} from "./chunk-JU5DQXFC.js";
|
|
25
|
+
|
|
26
|
+
// src/primitives/alert.tsx
|
|
27
|
+
import { cva } from "class-variance-authority";
|
|
28
|
+
import { jsx } from "react/jsx-runtime";
|
|
29
|
+
var alertVariants = cva(
|
|
30
|
+
"relative grid w-full grid-cols-[auto_1fr] items-start gap-x-3 rounded-[var(--ds-radius-surface)] border px-4 py-3.5 text-sm [&>svg]:mt-0.5 [&>svg]:size-5",
|
|
31
|
+
{
|
|
32
|
+
variants: {
|
|
33
|
+
variant: {
|
|
34
|
+
default: "border-border-default bg-card text-foreground",
|
|
35
|
+
information: "border-information-border bg-information-background text-information-foreground",
|
|
36
|
+
success: "border-success-border bg-success-background text-success-foreground",
|
|
37
|
+
warning: "border-warning-border bg-warning-background text-warning-foreground",
|
|
38
|
+
danger: "border-danger-border bg-danger-background text-danger-foreground"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
defaultVariants: {
|
|
42
|
+
variant: "default"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
function Alert({
|
|
47
|
+
className,
|
|
48
|
+
variant,
|
|
49
|
+
...props
|
|
50
|
+
}) {
|
|
51
|
+
return /* @__PURE__ */ jsx(
|
|
52
|
+
"div",
|
|
53
|
+
{
|
|
54
|
+
"data-slot": "alert",
|
|
55
|
+
className: cn(alertVariants({ variant }), className),
|
|
56
|
+
...props
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
function AlertTitle({ className, ...props }) {
|
|
61
|
+
return /* @__PURE__ */ jsx(
|
|
62
|
+
"div",
|
|
63
|
+
{
|
|
64
|
+
"data-slot": "alert-title",
|
|
65
|
+
className: cn("font-medium leading-5", className),
|
|
66
|
+
...props
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
function AlertDescription({ className, ...props }) {
|
|
71
|
+
return /* @__PURE__ */ jsx(
|
|
72
|
+
"div",
|
|
73
|
+
{
|
|
74
|
+
"data-slot": "alert-description",
|
|
75
|
+
className: cn("col-start-2 mt-0.5 text-sm leading-5 opacity-80", className),
|
|
76
|
+
...props
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/primitives/avatar.tsx
|
|
82
|
+
import * as AvatarPrimitive from "@radix-ui/react-avatar";
|
|
83
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
84
|
+
function Avatar({
|
|
85
|
+
className,
|
|
86
|
+
...props
|
|
87
|
+
}) {
|
|
88
|
+
return /* @__PURE__ */ jsx2(
|
|
89
|
+
AvatarPrimitive.Root,
|
|
90
|
+
{
|
|
91
|
+
"data-slot": "avatar",
|
|
92
|
+
className: cn("relative flex size-8 shrink-0 overflow-hidden rounded-full", className),
|
|
93
|
+
...props
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
function AvatarImage({
|
|
98
|
+
className,
|
|
99
|
+
...props
|
|
100
|
+
}) {
|
|
101
|
+
return /* @__PURE__ */ jsx2(
|
|
102
|
+
AvatarPrimitive.Image,
|
|
103
|
+
{
|
|
104
|
+
"data-slot": "avatar-image",
|
|
105
|
+
className: cn("aspect-square size-full", className),
|
|
106
|
+
...props
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
function AvatarFallback({
|
|
111
|
+
className,
|
|
112
|
+
...props
|
|
113
|
+
}) {
|
|
114
|
+
return /* @__PURE__ */ jsx2(
|
|
115
|
+
AvatarPrimitive.Fallback,
|
|
116
|
+
{
|
|
117
|
+
"data-slot": "avatar-fallback",
|
|
118
|
+
className: cn("flex size-full items-center justify-center rounded-full bg-surface-muted text-xs font-medium text-muted-foreground", className),
|
|
119
|
+
...props
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/primitives/badge.tsx
|
|
125
|
+
import { cva as cva2 } from "class-variance-authority";
|
|
126
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
127
|
+
var badgeVariants = cva2(
|
|
128
|
+
"inline-flex items-center rounded-md border px-1.5 py-0.5 text-[var(--ds-metadata)] font-medium leading-4 transition-colors",
|
|
129
|
+
{
|
|
130
|
+
variants: {
|
|
131
|
+
variant: {
|
|
132
|
+
default: "border-primary bg-primary text-primary-foreground",
|
|
133
|
+
accent: "border-selection-border bg-selection-background text-selection-foreground",
|
|
134
|
+
secondary: "border-neutral-border bg-neutral-background text-neutral-foreground",
|
|
135
|
+
neutral: "border-neutral-border bg-neutral-background text-neutral-foreground",
|
|
136
|
+
outline: "border-border-default text-foreground",
|
|
137
|
+
information: "border-information-border bg-information-background text-information-foreground",
|
|
138
|
+
info: "border-information-border bg-information-background text-information-foreground",
|
|
139
|
+
success: "border-success-border bg-success-background text-success-foreground",
|
|
140
|
+
warning: "border-warning-border bg-warning-background text-warning-foreground",
|
|
141
|
+
danger: "border-danger-border bg-danger-background text-danger-foreground",
|
|
142
|
+
destructive: "border-danger-border bg-danger-background text-danger-foreground"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
defaultVariants: {
|
|
146
|
+
variant: "neutral"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
function Badge({
|
|
151
|
+
className,
|
|
152
|
+
variant,
|
|
153
|
+
...props
|
|
154
|
+
}) {
|
|
155
|
+
return /* @__PURE__ */ jsx3("span", { "data-slot": "badge", className: cn(badgeVariants({ variant, className })), ...props });
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/primitives/input.tsx
|
|
159
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
160
|
+
function Input({ className, type, ...props }) {
|
|
161
|
+
return /* @__PURE__ */ jsx4(
|
|
162
|
+
"input",
|
|
163
|
+
{
|
|
164
|
+
type,
|
|
165
|
+
"data-slot": "input",
|
|
166
|
+
className: cn(
|
|
167
|
+
"border-input bg-card flex h-[var(--ds-field-control-height)] w-full min-w-0 rounded-[var(--ds-field-control-radius)] border px-[var(--ds-field-control-padding-x)] py-2 text-base shadow-none transition-colors outline-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
168
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
169
|
+
"aria-invalid:border-danger aria-invalid:ring-danger/20 dark:aria-invalid:ring-danger/40",
|
|
170
|
+
className
|
|
171
|
+
),
|
|
172
|
+
...props
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/primitives/switch.tsx
|
|
178
|
+
import * as SwitchPrimitive from "@radix-ui/react-switch";
|
|
179
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
180
|
+
function Switch({
|
|
181
|
+
className,
|
|
182
|
+
size = "default",
|
|
183
|
+
...props
|
|
184
|
+
}) {
|
|
185
|
+
return /* @__PURE__ */ jsx5(
|
|
186
|
+
SwitchPrimitive.Root,
|
|
187
|
+
{
|
|
188
|
+
"data-slot": "switch",
|
|
189
|
+
"data-size": size,
|
|
190
|
+
className: cn(
|
|
191
|
+
"peer group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80",
|
|
192
|
+
className
|
|
193
|
+
),
|
|
194
|
+
...props,
|
|
195
|
+
children: /* @__PURE__ */ jsx5(
|
|
196
|
+
SwitchPrimitive.Thumb,
|
|
197
|
+
{
|
|
198
|
+
"data-slot": "switch-thumb",
|
|
199
|
+
className: "pointer-events-none block rounded-full bg-background ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground"
|
|
200
|
+
}
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/primitives/textarea.tsx
|
|
207
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
208
|
+
function Textarea({ className, ...props }) {
|
|
209
|
+
return /* @__PURE__ */ jsx6(
|
|
210
|
+
"textarea",
|
|
211
|
+
{
|
|
212
|
+
"data-slot": "textarea",
|
|
213
|
+
className: cn("min-h-28 w-full rounded-[var(--ds-field-control-radius)] border border-input bg-card px-[var(--ds-field-control-padding-x)] py-3 text-sm outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50", className),
|
|
214
|
+
...props
|
|
215
|
+
}
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/primitives/compat.tsx
|
|
220
|
+
import { jsx as jsx7, jsxs } from "react/jsx-runtime";
|
|
221
|
+
var ConsciaButton = Button;
|
|
222
|
+
function ConsciaIconButton({
|
|
223
|
+
size = "icon",
|
|
224
|
+
...props
|
|
225
|
+
}) {
|
|
226
|
+
return /* @__PURE__ */ jsx7(Button, { size, ...props });
|
|
227
|
+
}
|
|
228
|
+
var ConsciaCard = Card;
|
|
229
|
+
var ConsciaCardContent = CardContent;
|
|
230
|
+
var ConsciaCardDescription = CardDescription;
|
|
231
|
+
function ConsciaCardHeader({
|
|
232
|
+
actionRight,
|
|
233
|
+
className,
|
|
234
|
+
children,
|
|
235
|
+
...props
|
|
236
|
+
}) {
|
|
237
|
+
if (!actionRight) {
|
|
238
|
+
return /* @__PURE__ */ jsx7(CardHeader, { className, ...props, children });
|
|
239
|
+
}
|
|
240
|
+
return /* @__PURE__ */ jsxs(
|
|
241
|
+
CardHeader,
|
|
242
|
+
{
|
|
243
|
+
className: cn(
|
|
244
|
+
"grid grid-cols-[minmax(0,1fr)_auto] items-start gap-4",
|
|
245
|
+
className
|
|
246
|
+
),
|
|
247
|
+
...props,
|
|
248
|
+
children: [
|
|
249
|
+
/* @__PURE__ */ jsx7("div", { className: "grid gap-2", children }),
|
|
250
|
+
/* @__PURE__ */ jsx7("div", { className: "justify-self-end", children: actionRight })
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
var ConsciaCardTitle = CardTitle;
|
|
256
|
+
var ConsciaCheckbox = Checkbox;
|
|
257
|
+
var ConsciaInput = Input;
|
|
258
|
+
var ConsciaSwitch = Switch;
|
|
259
|
+
var ConsciaTextarea = Textarea;
|
|
260
|
+
var ConsciaSelect = Select;
|
|
261
|
+
var ConsciaSelectContent = SelectContent;
|
|
262
|
+
var ConsciaSelectGroup = SelectGroup;
|
|
263
|
+
var ConsciaSelectItem = SelectItem;
|
|
264
|
+
var ConsciaSelectTrigger = SelectTrigger;
|
|
265
|
+
var ConsciaSelectValue = SelectValue;
|
|
266
|
+
var ConsciaTable = Table;
|
|
267
|
+
var ConsciaTableBody = TableBody;
|
|
268
|
+
var ConsciaTableCell = TableCell;
|
|
269
|
+
var ConsciaTableHeader = TableHeader;
|
|
270
|
+
var ConsciaTableHead = TableHead;
|
|
271
|
+
var ConsciaTableRow = TableRow;
|
|
272
|
+
|
|
273
|
+
// src/primitives/field.tsx
|
|
274
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
275
|
+
function Field({
|
|
276
|
+
className,
|
|
277
|
+
...props
|
|
278
|
+
}) {
|
|
279
|
+
return /* @__PURE__ */ jsx8(
|
|
280
|
+
"div",
|
|
281
|
+
{
|
|
282
|
+
"data-slot": "field",
|
|
283
|
+
className: cn("grid gap-[var(--ds-field-label-gap)]", className),
|
|
284
|
+
...props
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
function FieldGroup({
|
|
289
|
+
className,
|
|
290
|
+
...props
|
|
291
|
+
}) {
|
|
292
|
+
return /* @__PURE__ */ jsx8(
|
|
293
|
+
"div",
|
|
294
|
+
{
|
|
295
|
+
"data-slot": "field-group",
|
|
296
|
+
className: cn("grid gap-[var(--ds-field-gap)]", className),
|
|
297
|
+
...props
|
|
298
|
+
}
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
function FieldLabel({
|
|
302
|
+
className,
|
|
303
|
+
...props
|
|
304
|
+
}) {
|
|
305
|
+
return /* @__PURE__ */ jsx8(
|
|
306
|
+
"label",
|
|
307
|
+
{
|
|
308
|
+
"data-slot": "field-label",
|
|
309
|
+
className: cn("text-[length:var(--ds-field-label-size)] font-medium leading-[var(--ds-field-label-line-height)] text-foreground", className),
|
|
310
|
+
...props
|
|
311
|
+
}
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
function FieldDescription({
|
|
315
|
+
className,
|
|
316
|
+
...props
|
|
317
|
+
}) {
|
|
318
|
+
return /* @__PURE__ */ jsx8(
|
|
319
|
+
"p",
|
|
320
|
+
{
|
|
321
|
+
"data-slot": "field-description",
|
|
322
|
+
className: cn("mt-[var(--ds-field-message-gap)] text-[var(--ds-metadata)] text-muted-foreground", className),
|
|
323
|
+
...props
|
|
324
|
+
}
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
function FieldError({
|
|
328
|
+
className,
|
|
329
|
+
...props
|
|
330
|
+
}) {
|
|
331
|
+
return /* @__PURE__ */ jsx8(
|
|
332
|
+
"p",
|
|
333
|
+
{
|
|
334
|
+
"data-slot": "field-error",
|
|
335
|
+
className: cn("mt-[var(--ds-field-message-gap)] text-[var(--ds-metadata)] font-medium text-danger-foreground", className),
|
|
336
|
+
...props
|
|
337
|
+
}
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// src/primitives/form-select.tsx
|
|
342
|
+
import * as React from "react";
|
|
343
|
+
import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
344
|
+
var emptyValue = "__conscia_empty_select_value__";
|
|
345
|
+
function toSelectValue(value) {
|
|
346
|
+
if (value === void 0) {
|
|
347
|
+
return void 0;
|
|
348
|
+
}
|
|
349
|
+
return value === "" ? emptyValue : value;
|
|
350
|
+
}
|
|
351
|
+
function fromSelectValue(value) {
|
|
352
|
+
return value === emptyValue ? "" : value;
|
|
353
|
+
}
|
|
354
|
+
function FormSelect({
|
|
355
|
+
name,
|
|
356
|
+
id,
|
|
357
|
+
value,
|
|
358
|
+
defaultValue,
|
|
359
|
+
required,
|
|
360
|
+
disabled,
|
|
361
|
+
placeholder,
|
|
362
|
+
options,
|
|
363
|
+
className,
|
|
364
|
+
triggerClassName,
|
|
365
|
+
contentClassName,
|
|
366
|
+
onValueChange,
|
|
367
|
+
onClick,
|
|
368
|
+
"aria-label": ariaLabel
|
|
369
|
+
}) {
|
|
370
|
+
const [internalValue, setInternalValue] = React.useState(defaultValue ?? "");
|
|
371
|
+
const currentValue = value ?? internalValue;
|
|
372
|
+
function handleValueChange(nextValue) {
|
|
373
|
+
const actualValue = fromSelectValue(nextValue);
|
|
374
|
+
if (value === void 0) {
|
|
375
|
+
setInternalValue(actualValue);
|
|
376
|
+
}
|
|
377
|
+
onValueChange?.(actualValue);
|
|
378
|
+
}
|
|
379
|
+
return /* @__PURE__ */ jsx9("div", { className: cn("min-w-0", className), onClick, children: /* @__PURE__ */ jsxs2(
|
|
380
|
+
Select,
|
|
381
|
+
{
|
|
382
|
+
name,
|
|
383
|
+
value: toSelectValue(currentValue),
|
|
384
|
+
required,
|
|
385
|
+
disabled,
|
|
386
|
+
onValueChange: handleValueChange,
|
|
387
|
+
children: [
|
|
388
|
+
/* @__PURE__ */ jsx9(SelectTrigger, { id, "aria-label": ariaLabel, className: triggerClassName, children: /* @__PURE__ */ jsx9(SelectValue, { placeholder }) }),
|
|
389
|
+
/* @__PURE__ */ jsx9(SelectContent, { className: contentClassName, children: /* @__PURE__ */ jsx9(SelectGroup, { children: options.map((option) => /* @__PURE__ */ jsx9(
|
|
390
|
+
SelectItem,
|
|
391
|
+
{
|
|
392
|
+
value: toSelectValue(option.value) ?? emptyValue,
|
|
393
|
+
disabled: option.disabled,
|
|
394
|
+
children: option.label
|
|
395
|
+
},
|
|
396
|
+
option.value
|
|
397
|
+
)) }) })
|
|
398
|
+
]
|
|
399
|
+
}
|
|
400
|
+
) });
|
|
401
|
+
}
|
|
402
|
+
var ConsciaFormSelect = FormSelect;
|
|
403
|
+
|
|
404
|
+
// src/primitives/label.tsx
|
|
405
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
406
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
407
|
+
function Label({
|
|
408
|
+
className,
|
|
409
|
+
...props
|
|
410
|
+
}) {
|
|
411
|
+
return /* @__PURE__ */ jsx10(
|
|
412
|
+
LabelPrimitive.Root,
|
|
413
|
+
{
|
|
414
|
+
"data-slot": "label",
|
|
415
|
+
className: cn(
|
|
416
|
+
"flex items-center gap-2 text-[length:var(--ds-field-label-size)] font-medium leading-[var(--ds-field-label-line-height)] text-foreground select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
417
|
+
className
|
|
418
|
+
),
|
|
419
|
+
...props
|
|
420
|
+
}
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// src/primitives/searchable-select.tsx
|
|
425
|
+
import * as React2 from "react";
|
|
426
|
+
import { Check, ChevronsUpDown, Search, X } from "lucide-react";
|
|
427
|
+
import { jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
428
|
+
function SearchableSelect({
|
|
429
|
+
id,
|
|
430
|
+
name,
|
|
431
|
+
value = "",
|
|
432
|
+
options,
|
|
433
|
+
onValueChange,
|
|
434
|
+
placeholder = "Select an option",
|
|
435
|
+
searchPlaceholder = "Search...",
|
|
436
|
+
emptyMessage = "No matching options.",
|
|
437
|
+
disabled = false,
|
|
438
|
+
clearable = false,
|
|
439
|
+
clearLabel = "Clear selection",
|
|
440
|
+
optionsLabel,
|
|
441
|
+
className,
|
|
442
|
+
"aria-label": ariaLabel
|
|
443
|
+
}) {
|
|
444
|
+
const generatedId = React2.useId();
|
|
445
|
+
const listboxId = `${id ?? generatedId}-listbox`;
|
|
446
|
+
const rootRef = React2.useRef(null);
|
|
447
|
+
const activeOptionRef = React2.useRef(null);
|
|
448
|
+
const [open, setOpen] = React2.useState(false);
|
|
449
|
+
const [search, setSearch] = React2.useState("");
|
|
450
|
+
const [activeIndex, setActiveIndex] = React2.useState(0);
|
|
451
|
+
const selected = options.find((option) => option.value === value);
|
|
452
|
+
const normalizedSearch = search.trim().toLowerCase();
|
|
453
|
+
const filteredOptions = normalizedSearch ? options.filter(
|
|
454
|
+
(option) => [option.label, option.description, ...option.keywords ?? []].filter(Boolean).join(" ").toLowerCase().includes(normalizedSearch)
|
|
455
|
+
) : options;
|
|
456
|
+
const enabledIndexes = filteredOptions.reduce((indexes, option, index) => {
|
|
457
|
+
if (!option.disabled) {
|
|
458
|
+
indexes.push(index);
|
|
459
|
+
}
|
|
460
|
+
return indexes;
|
|
461
|
+
}, []);
|
|
462
|
+
const resolvedActiveIndex = enabledIndexes.includes(activeIndex) ? activeIndex : enabledIndexes[0] ?? -1;
|
|
463
|
+
React2.useEffect(() => {
|
|
464
|
+
if (!open) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
function closeWhenOutside(event) {
|
|
468
|
+
if (!rootRef.current?.contains(event.target)) {
|
|
469
|
+
setOpen(false);
|
|
470
|
+
setSearch("");
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
document.addEventListener("pointerdown", closeWhenOutside);
|
|
474
|
+
return () => document.removeEventListener("pointerdown", closeWhenOutside);
|
|
475
|
+
}, [open]);
|
|
476
|
+
React2.useEffect(() => {
|
|
477
|
+
if (open) {
|
|
478
|
+
activeOptionRef.current?.scrollIntoView({ block: "nearest" });
|
|
479
|
+
}
|
|
480
|
+
}, [open, resolvedActiveIndex]);
|
|
481
|
+
function select(option) {
|
|
482
|
+
if (option.disabled) {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
onValueChange(option.value);
|
|
486
|
+
setSearch("");
|
|
487
|
+
setOpen(false);
|
|
488
|
+
}
|
|
489
|
+
function onKeyDown(event) {
|
|
490
|
+
if (event.key === "ArrowDown") {
|
|
491
|
+
event.preventDefault();
|
|
492
|
+
setOpen(true);
|
|
493
|
+
setActiveIndex((current) => {
|
|
494
|
+
const position = enabledIndexes.indexOf(current);
|
|
495
|
+
return enabledIndexes[Math.min(enabledIndexes.length - 1, position + 1)] ?? -1;
|
|
496
|
+
});
|
|
497
|
+
} else if (event.key === "ArrowUp") {
|
|
498
|
+
event.preventDefault();
|
|
499
|
+
setOpen(true);
|
|
500
|
+
setActiveIndex((current) => {
|
|
501
|
+
const position = enabledIndexes.indexOf(current);
|
|
502
|
+
return enabledIndexes[Math.max(0, position === -1 ? 0 : position - 1)] ?? -1;
|
|
503
|
+
});
|
|
504
|
+
} else if (event.key === "Home") {
|
|
505
|
+
event.preventDefault();
|
|
506
|
+
setOpen(true);
|
|
507
|
+
setActiveIndex(enabledIndexes[0] ?? -1);
|
|
508
|
+
} else if (event.key === "End") {
|
|
509
|
+
event.preventDefault();
|
|
510
|
+
setOpen(true);
|
|
511
|
+
setActiveIndex(enabledIndexes.at(-1) ?? -1);
|
|
512
|
+
} else if (event.key === "Enter" && open && filteredOptions[resolvedActiveIndex]) {
|
|
513
|
+
event.preventDefault();
|
|
514
|
+
select(filteredOptions[resolvedActiveIndex]);
|
|
515
|
+
} else if (event.key === "Escape") {
|
|
516
|
+
setOpen(false);
|
|
517
|
+
setSearch("");
|
|
518
|
+
} else if (event.key === "Tab") {
|
|
519
|
+
setOpen(false);
|
|
520
|
+
setSearch("");
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return /* @__PURE__ */ jsxs3("div", { ref: rootRef, "data-slot": "searchable-select", className: cn("relative min-w-0", className), children: [
|
|
524
|
+
name ? /* @__PURE__ */ jsx11("input", { type: "hidden", name, value }) : null,
|
|
525
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
526
|
+
/* @__PURE__ */ jsx11(Search, { className: "pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground", "aria-hidden": "true" }),
|
|
527
|
+
/* @__PURE__ */ jsx11(
|
|
528
|
+
Input,
|
|
529
|
+
{
|
|
530
|
+
id,
|
|
531
|
+
role: "combobox",
|
|
532
|
+
"aria-label": ariaLabel,
|
|
533
|
+
"aria-autocomplete": "list",
|
|
534
|
+
"aria-expanded": open,
|
|
535
|
+
"aria-controls": open ? listboxId : void 0,
|
|
536
|
+
"aria-activedescendant": open && filteredOptions[resolvedActiveIndex] ? `${listboxId}-${resolvedActiveIndex}` : void 0,
|
|
537
|
+
autoComplete: "off",
|
|
538
|
+
className: "px-9",
|
|
539
|
+
disabled,
|
|
540
|
+
placeholder: open ? searchPlaceholder : placeholder,
|
|
541
|
+
value: open ? search : selected?.label ?? "",
|
|
542
|
+
onFocus: (event) => {
|
|
543
|
+
setOpen(true);
|
|
544
|
+
setSearch("");
|
|
545
|
+
event.currentTarget.select();
|
|
546
|
+
},
|
|
547
|
+
onClick: () => {
|
|
548
|
+
if (!open) {
|
|
549
|
+
setOpen(true);
|
|
550
|
+
setSearch("");
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
onChange: (event) => {
|
|
554
|
+
setSearch(event.target.value);
|
|
555
|
+
setOpen(true);
|
|
556
|
+
setActiveIndex(0);
|
|
557
|
+
},
|
|
558
|
+
onKeyDown
|
|
559
|
+
}
|
|
560
|
+
),
|
|
561
|
+
clearable && value ? /* @__PURE__ */ jsx11(
|
|
562
|
+
Button,
|
|
563
|
+
{
|
|
564
|
+
type: "button",
|
|
565
|
+
variant: "ghost",
|
|
566
|
+
size: "icon",
|
|
567
|
+
disabled,
|
|
568
|
+
className: "absolute right-8 top-1/2 -translate-y-1/2",
|
|
569
|
+
"aria-label": clearLabel,
|
|
570
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
571
|
+
onClick: () => {
|
|
572
|
+
onValueChange("");
|
|
573
|
+
setSearch("");
|
|
574
|
+
},
|
|
575
|
+
children: /* @__PURE__ */ jsx11(X, {})
|
|
576
|
+
}
|
|
577
|
+
) : null,
|
|
578
|
+
/* @__PURE__ */ jsx11(ChevronsUpDown, { className: "pointer-events-none absolute right-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground", "aria-hidden": "true" })
|
|
579
|
+
] }),
|
|
580
|
+
open ? /* @__PURE__ */ jsx11(
|
|
581
|
+
"div",
|
|
582
|
+
{
|
|
583
|
+
id: listboxId,
|
|
584
|
+
role: "listbox",
|
|
585
|
+
"aria-label": optionsLabel ?? (ariaLabel ? `${ariaLabel} options` : "Options"),
|
|
586
|
+
className: "absolute z-50 mt-1 max-h-72 w-full overflow-y-auto rounded-md border border-border-subtle bg-popover p-1 text-popover-foreground shadow-md",
|
|
587
|
+
children: filteredOptions.length ? filteredOptions.map((option, index) => /* @__PURE__ */ jsxs3(
|
|
588
|
+
"button",
|
|
589
|
+
{
|
|
590
|
+
id: `${listboxId}-${index}`,
|
|
591
|
+
type: "button",
|
|
592
|
+
role: "option",
|
|
593
|
+
"aria-selected": option.value === value,
|
|
594
|
+
"aria-disabled": option.disabled || void 0,
|
|
595
|
+
disabled: option.disabled,
|
|
596
|
+
tabIndex: -1,
|
|
597
|
+
ref: index === resolvedActiveIndex ? activeOptionRef : void 0,
|
|
598
|
+
"data-active": index === resolvedActiveIndex,
|
|
599
|
+
className: "flex w-full items-center gap-3 rounded-sm px-3 py-2 text-left text-[length:var(--ds-menu-item-size)] outline-none hover:bg-surface-muted focus-visible:bg-surface-muted data-[active=true]:bg-surface-muted disabled:pointer-events-none disabled:opacity-50",
|
|
600
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
601
|
+
onMouseEnter: () => setActiveIndex(index),
|
|
602
|
+
onClick: () => select(option),
|
|
603
|
+
children: [
|
|
604
|
+
/* @__PURE__ */ jsxs3("span", { className: "grid min-w-0 flex-1 gap-0.5", children: [
|
|
605
|
+
/* @__PURE__ */ jsx11("span", { className: "truncate font-medium", children: option.label }),
|
|
606
|
+
option.description ? /* @__PURE__ */ jsx11("span", { className: "truncate text-[length:var(--ds-menu-label-size)] text-muted-foreground", children: option.description }) : null
|
|
607
|
+
] }),
|
|
608
|
+
option.value === value ? /* @__PURE__ */ jsx11(Check, { className: "size-4 shrink-0 text-success-foreground", "aria-hidden": "true" }) : null
|
|
609
|
+
]
|
|
610
|
+
},
|
|
611
|
+
option.value
|
|
612
|
+
)) : /* @__PURE__ */ jsx11("p", { className: "px-3 py-6 text-center text-[length:var(--ds-menu-item-size)] text-muted-foreground", children: emptyMessage })
|
|
613
|
+
}
|
|
614
|
+
) : null
|
|
615
|
+
] });
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
export {
|
|
619
|
+
alertVariants,
|
|
620
|
+
Alert,
|
|
621
|
+
AlertTitle,
|
|
622
|
+
AlertDescription,
|
|
623
|
+
Avatar,
|
|
624
|
+
AvatarImage,
|
|
625
|
+
AvatarFallback,
|
|
626
|
+
badgeVariants,
|
|
627
|
+
Badge,
|
|
628
|
+
Input,
|
|
629
|
+
Switch,
|
|
630
|
+
Textarea,
|
|
631
|
+
ConsciaButton,
|
|
632
|
+
ConsciaIconButton,
|
|
633
|
+
ConsciaCard,
|
|
634
|
+
ConsciaCardContent,
|
|
635
|
+
ConsciaCardDescription,
|
|
636
|
+
ConsciaCardHeader,
|
|
637
|
+
ConsciaCardTitle,
|
|
638
|
+
ConsciaCheckbox,
|
|
639
|
+
ConsciaInput,
|
|
640
|
+
ConsciaSwitch,
|
|
641
|
+
ConsciaTextarea,
|
|
642
|
+
ConsciaSelect,
|
|
643
|
+
ConsciaSelectContent,
|
|
644
|
+
ConsciaSelectGroup,
|
|
645
|
+
ConsciaSelectItem,
|
|
646
|
+
ConsciaSelectTrigger,
|
|
647
|
+
ConsciaSelectValue,
|
|
648
|
+
ConsciaTable,
|
|
649
|
+
ConsciaTableBody,
|
|
650
|
+
ConsciaTableCell,
|
|
651
|
+
ConsciaTableHeader,
|
|
652
|
+
ConsciaTableHead,
|
|
653
|
+
ConsciaTableRow,
|
|
654
|
+
Field,
|
|
655
|
+
FieldGroup,
|
|
656
|
+
FieldLabel,
|
|
657
|
+
FieldDescription,
|
|
658
|
+
FieldError,
|
|
659
|
+
FormSelect,
|
|
660
|
+
ConsciaFormSelect,
|
|
661
|
+
Label,
|
|
662
|
+
SearchableSelect
|
|
663
|
+
};
|
|
664
|
+
//# sourceMappingURL=chunk-CU3OXBFI.js.map
|