@arkcit/react-ui 0.3.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.
@@ -0,0 +1,2113 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
32
+
33
+ // src/components/shared/patterns/forms/engine/syntheticEvents.ts
34
+ var createFormFieldChangeEvent = (name, value) => ({
35
+ target: {
36
+ name,
37
+ value
38
+ }
39
+ });
40
+
41
+ // src/components/shared/primitives/data-entry/Checkbox/Checkbox.tsx
42
+ import { forwardRef } from "react";
43
+ import { jsx } from "react/jsx-runtime";
44
+ var Checkbox = forwardRef(
45
+ (_a, ref) => {
46
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
47
+ return /* @__PURE__ */ jsx(
48
+ "input",
49
+ __spreadValues({
50
+ ref,
51
+ type: "checkbox",
52
+ className: `h-4 w-4 rounded border border-border-strong text-primary focus-visible:ring-2 focus-visible:ring-primary/30 disabled:opacity-50 disabled:cursor-not-allowed ${className != null ? className : ""}`
53
+ }, props)
54
+ );
55
+ }
56
+ );
57
+ Checkbox.displayName = "Checkbox";
58
+ var Checkbox_default = Checkbox;
59
+
60
+ // src/components/shared/patterns/forms/FormField/fields/CheckboxField/CheckboxField.tsx
61
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
62
+ var CheckboxField = ({
63
+ field,
64
+ value,
65
+ error,
66
+ errorId,
67
+ onChange
68
+ }) => {
69
+ const checked = Boolean(value);
70
+ const emit = (next) => {
71
+ onChange(createFormFieldChangeEvent(field.name, next));
72
+ };
73
+ return /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 cursor-pointer select-none py-1", children: [
74
+ /* @__PURE__ */ jsx2(
75
+ Checkbox_default,
76
+ {
77
+ id: field.name,
78
+ name: field.name,
79
+ checked,
80
+ onChange: (e) => emit(e.target.checked),
81
+ "aria-invalid": Boolean(error),
82
+ "aria-describedby": errorId,
83
+ className: `cursor-pointer ${error ? "border-danger" : "border-border-strong"}`
84
+ }
85
+ ),
86
+ /* @__PURE__ */ jsxs("span", { className: "text-foreground", children: [
87
+ field.label,
88
+ " ",
89
+ field.required && "*"
90
+ ] }),
91
+ error && !errorId && /* @__PURE__ */ jsx2("p", { className: "text-sm text-danger", children: error })
92
+ ] });
93
+ };
94
+ var CheckboxField_default = CheckboxField;
95
+
96
+ // src/components/shared/patterns/forms/FormField/fields/CheckboxField/index.tsx
97
+ var CheckboxField_default2 = CheckboxField_default;
98
+
99
+ // src/components/shared/patterns/forms/FormField/fields/CheckboxSearchField/CheckboxSearchField.tsx
100
+ import React4 from "react";
101
+ import { ChevronDown } from "lucide-react";
102
+
103
+ // src/components/shared/primitives/data-entry/Input/Input.tsx
104
+ import { forwardRef as forwardRef2 } from "react";
105
+
106
+ // src/components/shared/utils/cx.ts
107
+ var cx = (...classes) => classes.filter(Boolean).join(" ");
108
+
109
+ // src/components/shared/primitives/data-entry/Input/Input.tsx
110
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
111
+ var SIZE_CLASSES = {
112
+ xs: "h-7 px-2 text-xs",
113
+ sm: "h-8 px-3 text-sm",
114
+ md: "h-10 px-3 text-sm",
115
+ lg: "h-11 px-4 text-base"
116
+ };
117
+ var INTENT_CLASSES = {
118
+ primary: "focus-visible:border-primary",
119
+ secondary: "focus-visible:border-secondary",
120
+ success: "focus-visible:border-success",
121
+ warning: "focus-visible:border-warning",
122
+ danger: "focus-visible:border-danger",
123
+ info: "focus-visible:border-info",
124
+ neutral: "focus-visible:border-primary"
125
+ };
126
+ var Input = forwardRef2(
127
+ (_a, ref) => {
128
+ var _b = _a, {
129
+ className,
130
+ type = "text",
131
+ intent = "neutral",
132
+ size = "md",
133
+ rightIcon: RightIcon,
134
+ rightIconClassName
135
+ } = _b, props = __objRest(_b, [
136
+ "className",
137
+ "type",
138
+ "intent",
139
+ "size",
140
+ "rightIcon",
141
+ "rightIconClassName"
142
+ ]);
143
+ const isInvalid = props["aria-invalid"] === true || props["aria-invalid"] === "true";
144
+ return /* @__PURE__ */ jsxs2("div", { className: "relative w-full", children: [
145
+ /* @__PURE__ */ jsx3(
146
+ "input",
147
+ __spreadValues({
148
+ ref,
149
+ type,
150
+ className: cx(
151
+ "w-full rounded-md border bg-background text-foreground outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed",
152
+ SIZE_CLASSES[size],
153
+ isInvalid ? "border-danger focus-visible:border-danger" : "border-border-strong",
154
+ !isInvalid && INTENT_CLASSES[intent],
155
+ RightIcon && "pr-10",
156
+ className
157
+ )
158
+ }, props)
159
+ ),
160
+ RightIcon ? /* @__PURE__ */ jsx3("span", { className: "pointer-events-none absolute inset-y-0 right-3 flex items-center text-muted-foreground", children: /* @__PURE__ */ jsx3(
161
+ RightIcon,
162
+ {
163
+ "aria-hidden": "true",
164
+ className: cx("h-4 w-4", rightIconClassName)
165
+ }
166
+ ) }) : null
167
+ ] });
168
+ }
169
+ );
170
+ Input.displayName = "Input";
171
+ var Input_default = Input;
172
+
173
+ // src/components/shared/primitives/misc/Tag/Tag.tsx
174
+ import { X } from "lucide-react";
175
+
176
+ // src/components/shared/utils/renderBindableNode.tsx
177
+ import React3 from "react";
178
+ import { jsx as jsx4 } from "react/jsx-runtime";
179
+ var MISSING_TRANSLATION_FALLBACK = "Lorem ipsum dolor sit amet. (fallback)";
180
+ var MISSING_REF_FALLBACK = "Lorem ipsum dolor sit amet. (fallback)";
181
+ var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
182
+ var renderBindableNode = (value) => {
183
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value == null) {
184
+ return value;
185
+ }
186
+ if (Array.isArray(value)) {
187
+ return value.map((item, index) => /* @__PURE__ */ jsx4(React3.Fragment, { children: renderBindableNode(item) }, `bindable-node-${index}`));
188
+ }
189
+ if (React3.isValidElement(value)) return value;
190
+ if (isPlainObject(value)) {
191
+ if (typeof value.$t === "string") return MISSING_TRANSLATION_FALLBACK;
192
+ if (typeof value.$ref === "string") return MISSING_REF_FALLBACK;
193
+ if ("children" in value) {
194
+ return renderBindableNode(value.children);
195
+ }
196
+ try {
197
+ return JSON.stringify(value);
198
+ } catch (e) {
199
+ return String(value);
200
+ }
201
+ }
202
+ return String(value);
203
+ };
204
+
205
+ // src/components/shared/primitives/misc/Tag/Tag.tsx
206
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
207
+ var SIZE_CLASSES2 = {
208
+ sm: "h-6 px-2 text-xs",
209
+ md: "h-7 px-2.5 text-sm"
210
+ };
211
+ var VARIANT_CLASSES = {
212
+ solid: {
213
+ primary: "bg-primary text-primary-foreground border border-primary",
214
+ secondary: "bg-secondary text-secondary-foreground border border-secondary",
215
+ success: "bg-success text-success-foreground border border-success",
216
+ warning: "bg-warning text-warning-foreground border border-warning",
217
+ danger: "bg-danger text-danger-foreground border border-danger",
218
+ info: "bg-info text-info-foreground border border-info",
219
+ neutral: "bg-foreground text-background border border-foreground"
220
+ },
221
+ soft: {
222
+ primary: "bg-primary-soft text-primary-soft-foreground border border-transparent",
223
+ secondary: "bg-secondary-soft text-secondary-soft-foreground border border-transparent",
224
+ success: "bg-success-soft text-success-soft-foreground border border-transparent",
225
+ warning: "bg-warning-soft text-warning-soft-foreground border border-transparent",
226
+ danger: "bg-danger-soft text-danger-soft-foreground border border-transparent",
227
+ info: "bg-info-soft text-info-soft-foreground border border-transparent",
228
+ neutral: "bg-surface text-foreground border border-transparent"
229
+ },
230
+ outline: {
231
+ primary: "bg-background text-primary border border-primary",
232
+ secondary: "bg-background text-secondary border border-secondary",
233
+ success: "bg-background text-success border border-success",
234
+ warning: "bg-background text-warning border border-warning",
235
+ danger: "bg-background text-danger border border-danger",
236
+ info: "bg-background text-info border border-info",
237
+ neutral: "bg-background text-foreground border border-border-strong"
238
+ },
239
+ ghost: {
240
+ primary: "bg-transparent text-ghost-primary-foreground border border-transparent hover:bg-ghost-primary-hover",
241
+ secondary: "bg-transparent text-ghost-secondary-foreground border border-transparent hover:bg-ghost-secondary-hover",
242
+ success: "bg-transparent text-ghost-success-foreground border border-transparent hover:bg-ghost-success-hover",
243
+ warning: "bg-transparent text-ghost-warning-foreground border border-transparent hover:bg-ghost-warning-hover",
244
+ danger: "bg-transparent text-ghost-danger-foreground border border-transparent hover:bg-ghost-danger-hover",
245
+ info: "bg-transparent text-ghost-info-foreground border border-transparent hover:bg-ghost-info-hover",
246
+ neutral: "bg-transparent text-ghost-foreground border border-transparent hover:bg-ghost-hover"
247
+ },
248
+ glass: {
249
+ primary: "bg-primary/20 text-primary-soft-foreground border border-glass-border shadow-glass",
250
+ secondary: "bg-secondary/20 text-secondary-soft-foreground border border-glass-border shadow-glass",
251
+ success: "bg-success/20 text-success-soft-foreground border border-glass-border shadow-glass",
252
+ warning: "bg-warning/20 text-warning-soft-foreground border border-glass-border shadow-glass",
253
+ danger: "bg-danger/20 text-danger-soft-foreground border border-glass-border shadow-glass",
254
+ info: "bg-info/20 text-info-soft-foreground border border-glass-border shadow-glass",
255
+ neutral: "bg-glass-bg text-foreground border border-glass-border shadow-glass"
256
+ }
257
+ };
258
+ var Tag = (_a) => {
259
+ var _b = _a, {
260
+ children,
261
+ onRemove,
262
+ intent = "neutral",
263
+ variant = "soft",
264
+ size = "sm",
265
+ disabled = false,
266
+ className
267
+ } = _b, props = __objRest(_b, [
268
+ "children",
269
+ "onRemove",
270
+ "intent",
271
+ "variant",
272
+ "size",
273
+ "disabled",
274
+ "className"
275
+ ]);
276
+ return /* @__PURE__ */ jsxs3(
277
+ "span",
278
+ __spreadProps(__spreadValues({
279
+ className: cx(
280
+ "inline-flex items-center gap-1 rounded-md font-medium transition-colors",
281
+ SIZE_CLASSES2[size],
282
+ VARIANT_CLASSES[variant][intent],
283
+ disabled && "opacity-50",
284
+ className
285
+ )
286
+ }, props), {
287
+ children: [
288
+ /* @__PURE__ */ jsx5("span", { className: "truncate", children: renderBindableNode(children) }),
289
+ onRemove ? /* @__PURE__ */ jsx5(
290
+ "button",
291
+ {
292
+ type: "button",
293
+ onClick: onRemove,
294
+ disabled,
295
+ "aria-label": "Remove tag",
296
+ className: "inline-flex h-4 w-4 items-center justify-center rounded-sm hover:bg-black/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed",
297
+ children: /* @__PURE__ */ jsx5(X, { className: "h-3 w-3", "aria-hidden": "true" })
298
+ }
299
+ ) : null
300
+ ]
301
+ })
302
+ );
303
+ };
304
+ var Tag_default = Tag;
305
+
306
+ // src/components/shared/hooks/events/useEventListener.ts
307
+ import { useEffect, useRef } from "react";
308
+ function useEventListener(event, handler, options) {
309
+ const handlerRef = useRef(handler);
310
+ useEffect(() => {
311
+ handlerRef.current = handler;
312
+ }, [handler]);
313
+ useEffect(() => {
314
+ if (typeof window === "undefined") return;
315
+ const listener = (e) => handlerRef.current(e);
316
+ window.addEventListener(event, listener, options);
317
+ return () => {
318
+ window.removeEventListener(event, listener, options);
319
+ };
320
+ }, [event, options]);
321
+ }
322
+ var useEventListener_default = useEventListener;
323
+
324
+ // src/components/shared/hooks/events/useOnClickOutside.ts
325
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
326
+ function useOnClickOutside(ref, handler) {
327
+ const handlerRef = useRef2(handler);
328
+ useEffect2(() => {
329
+ handlerRef.current = handler;
330
+ }, [handler]);
331
+ useEffect2(() => {
332
+ if (typeof document === "undefined") return;
333
+ const listener = (event) => {
334
+ const el = ref.current;
335
+ if (!el || el.contains(event.target)) return;
336
+ handlerRef.current(event);
337
+ };
338
+ document.addEventListener("mousedown", listener);
339
+ document.addEventListener("touchstart", listener);
340
+ return () => {
341
+ document.removeEventListener("mousedown", listener);
342
+ document.removeEventListener("touchstart", listener);
343
+ };
344
+ }, [ref]);
345
+ }
346
+ var useOnClickOutside_default = useOnClickOutside;
347
+
348
+ // src/components/shared/patterns/forms/FormField/fields/CheckboxSearchField/CheckboxSearchField.tsx
349
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
350
+ var CheckboxSearchField = ({
351
+ field,
352
+ value,
353
+ error,
354
+ errorId,
355
+ onChange,
356
+ dict
357
+ }) => {
358
+ var _a, _b;
359
+ const selected = Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
360
+ const [search, setSearch] = React4.useState("");
361
+ const [open, setOpen] = React4.useState(false);
362
+ const containerRef = React4.useRef(null);
363
+ const filtered = (_b = (_a = field.options) == null ? void 0 : _a.filter(
364
+ (opt) => opt.label.toLowerCase().includes(search.toLowerCase())
365
+ )) != null ? _b : [];
366
+ const emit = (next) => {
367
+ onChange(createFormFieldChangeEvent(field.name, next));
368
+ };
369
+ const toggle = (val) => {
370
+ const next = selected.includes(val) ? selected.filter((v) => v !== val) : [...selected, val];
371
+ emit(next);
372
+ };
373
+ const removeTag = (tag) => {
374
+ const next = selected.filter((t) => t !== tag);
375
+ emit(next);
376
+ };
377
+ useOnClickOutside_default(containerRef, () => {
378
+ setOpen(false);
379
+ });
380
+ return /* @__PURE__ */ jsxs4("div", { ref: containerRef, className: "flex flex-col gap-2 relative", children: [
381
+ /* @__PURE__ */ jsx6(
382
+ Input_default,
383
+ {
384
+ id: field.name,
385
+ type: "text",
386
+ className: "cursor-pointer placeholder:text-muted-foreground",
387
+ rightIcon: ChevronDown,
388
+ rightIconClassName: cx(
389
+ "h-5 w-5 [stroke-width:2.5] transition-transform duration-200 ease-out",
390
+ open && "rotate-180"
391
+ ),
392
+ placeholder: dict.search,
393
+ value: search,
394
+ onChange: (e) => setSearch(e.target.value),
395
+ onFocus: () => setOpen(true),
396
+ onClick: () => setOpen(true),
397
+ "aria-invalid": Boolean(error),
398
+ "aria-describedby": errorId,
399
+ "aria-expanded": open
400
+ }
401
+ ),
402
+ open && /* @__PURE__ */ jsxs4(
403
+ "div",
404
+ {
405
+ role: "listbox",
406
+ "aria-label": field.label,
407
+ className: "absolute left-0 right-0 top-full z-10 mt-1 max-h-60 overflow-y-auto rounded-lg border border-border bg-background p-2 shadow-lg",
408
+ children: [
409
+ filtered.length === 0 && /* @__PURE__ */ jsx6("div", { className: "px-2 py-1 text-sm text-muted-foreground", children: dict.noResultToShow }),
410
+ filtered.map((opt) => {
411
+ const val = opt.value.toString();
412
+ const checked = selected.includes(val);
413
+ return /* @__PURE__ */ jsxs4(
414
+ "label",
415
+ {
416
+ className: "flex cursor-pointer select-none items-center gap-2 rounded px-2 py-1 hover:bg-surface-hover",
417
+ children: [
418
+ /* @__PURE__ */ jsx6(
419
+ Checkbox_default,
420
+ {
421
+ checked,
422
+ onChange: () => toggle(val),
423
+ className: "cursor-pointer"
424
+ }
425
+ ),
426
+ /* @__PURE__ */ jsx6("span", { children: opt.label })
427
+ ]
428
+ },
429
+ val
430
+ );
431
+ })
432
+ ]
433
+ }
434
+ ),
435
+ /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap gap-2 mt-1", children: selected.map((tag) => {
436
+ var _a2, _b2;
437
+ const opt = (_a2 = field.options) == null ? void 0 : _a2.find((o) => o.value.toString() === tag);
438
+ return /* @__PURE__ */ jsx6(
439
+ Tag_default,
440
+ {
441
+ intent: "primary",
442
+ variant: "soft",
443
+ onRemove: () => removeTag(tag),
444
+ children: (_b2 = opt == null ? void 0 : opt.label) != null ? _b2 : tag
445
+ },
446
+ tag
447
+ );
448
+ }) })
449
+ ] });
450
+ };
451
+ var CheckboxSearchField_default = CheckboxSearchField;
452
+
453
+ // src/components/shared/patterns/forms/FormField/fields/CheckboxSearchField/index.tsx
454
+ var CheckboxSearchField_default2 = CheckboxSearchField_default;
455
+
456
+ // src/helpers/forms/index.ts
457
+ var getSafeValue = (value) => {
458
+ if (value === null || value === void 0) return "";
459
+ if (typeof value === "boolean") return value ? "true" : "false";
460
+ if (Array.isArray(value)) {
461
+ return value.every((item) => typeof item === "string") ? value : void 0;
462
+ }
463
+ return value;
464
+ };
465
+
466
+ // src/components/shared/patterns/forms/FormField/fields/ColorField/ColorField.tsx
467
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
468
+ var ColorField = ({
469
+ field,
470
+ value,
471
+ error,
472
+ errorId,
473
+ onChange
474
+ }) => {
475
+ var _a;
476
+ return /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-4", children: [
477
+ /* @__PURE__ */ jsx7(
478
+ "input",
479
+ {
480
+ id: field.name,
481
+ type: "color",
482
+ name: field.name,
483
+ value: getSafeValue(value) || "#000000",
484
+ onChange,
485
+ "aria-invalid": Boolean(error),
486
+ "aria-describedby": errorId,
487
+ className: `h-10 w-12 cursor-pointer rounded-md border p-1 ${error ? "border-danger" : "border-border-strong"}`
488
+ }
489
+ ),
490
+ /* @__PURE__ */ jsx7(
491
+ "input",
492
+ {
493
+ type: "text",
494
+ name: field.name,
495
+ value: getSafeValue(value),
496
+ onChange,
497
+ placeholder: (_a = field.placeholder) != null ? _a : "#rrggbb",
498
+ "aria-invalid": Boolean(error),
499
+ "aria-describedby": errorId,
500
+ className: `w-full flex-1 rounded-lg border px-3 py-2 focus:outline-none focus:ring-2 ${error ? "border-danger focus:ring-danger/40" : "border-border-strong focus:ring-ring"}`
501
+ }
502
+ )
503
+ ] });
504
+ };
505
+ var ColorField_default = ColorField;
506
+
507
+ // src/components/shared/patterns/forms/FormField/fields/ColorField/index.tsx
508
+ var ColorField_default2 = ColorField_default;
509
+
510
+ // src/components/shared/patterns/forms/selection/Combobox/Combobox.tsx
511
+ import { useEffect as useEffect3, useId, useMemo, useRef as useRef3, useState } from "react";
512
+ import { Check, ChevronDown as ChevronDown2, Loader2 } from "lucide-react";
513
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
514
+ var sizeClasses = {
515
+ sm: "min-h-9 px-3 text-sm",
516
+ md: "min-h-10 px-3 text-sm",
517
+ lg: "min-h-11 px-4 text-base"
518
+ };
519
+ var variantClasses = {
520
+ solid: "bg-surface border-border text-foreground",
521
+ outline: "bg-background border-border-strong text-foreground",
522
+ ghost: "bg-transparent border-transparent text-foreground hover:bg-surface",
523
+ soft: "bg-surface border-transparent text-foreground",
524
+ glass: "bg-glass-bg border-glass-border text-foreground shadow-glass backdrop-blur-md"
525
+ };
526
+ var intentClasses = {
527
+ primary: "focus-within:border-primary",
528
+ secondary: "focus-within:border-secondary",
529
+ success: "focus-within:border-success",
530
+ warning: "focus-within:border-warning",
531
+ danger: "focus-within:border-danger",
532
+ info: "focus-within:border-info"
533
+ };
534
+ var defaultFilter = (option, query) => option.label.toLowerCase().includes(query.toLowerCase());
535
+ var valuesEqual = (a, b) => Object.is(a, b);
536
+ var Combobox = ({
537
+ options,
538
+ value = null,
539
+ onChange,
540
+ values = [],
541
+ onChangeMany,
542
+ multiple = false,
543
+ placeholder = "Select...",
544
+ disabled = false,
545
+ loading = false,
546
+ search = true,
547
+ query,
548
+ onQueryChange,
549
+ filterFn = defaultFilter,
550
+ closeOnSelect,
551
+ maxSelected,
552
+ size = "md",
553
+ intent = "primary",
554
+ variant = "outline",
555
+ label,
556
+ hint,
557
+ error,
558
+ className,
559
+ inputClassName,
560
+ menuClassName,
561
+ renderOption,
562
+ renderValue,
563
+ "aria-label": ariaLabel,
564
+ id,
565
+ name
566
+ }) => {
567
+ const internalId = useId();
568
+ const inputId = id != null ? id : `combobox-${internalId}`;
569
+ const listboxId = `${inputId}-listbox`;
570
+ const wrapperRef = useRef3(null);
571
+ const inputRef = useRef3(null);
572
+ const [open, setOpen] = useState(false);
573
+ const [activeIndex, setActiveIndex] = useState(0);
574
+ const [internalQuery, setInternalQuery] = useState("");
575
+ const isControlledQuery = typeof query === "string";
576
+ const currentQuery = isControlledQuery ? query : internalQuery;
577
+ const isInvalid = Boolean(error);
578
+ const shouldCloseOnSelect = closeOnSelect != null ? closeOnSelect : multiple ? false : true;
579
+ const selectedValues = multiple ? values : value == null ? [] : [value];
580
+ const filteredOptions = useMemo(
581
+ () => options.filter(
582
+ (option) => currentQuery.trim() ? filterFn(option, currentQuery) : true
583
+ ),
584
+ [currentQuery, filterFn, options]
585
+ );
586
+ const currentSingleLabel = useMemo(() => {
587
+ if (multiple || value == null) return "";
588
+ const option = options.find((item) => valuesEqual(item.value, value));
589
+ if (!option) return "";
590
+ return renderValue ? renderValue(option.value) : option.label;
591
+ }, [multiple, options, renderValue, value]);
592
+ const inputValue = useMemo(() => {
593
+ if (multiple) return currentQuery;
594
+ if (!search) return currentSingleLabel;
595
+ return open ? currentQuery : currentQuery || currentSingleLabel;
596
+ }, [currentQuery, currentSingleLabel, multiple, open, search]);
597
+ useEffect3(() => {
598
+ if (!open) return;
599
+ const onClickOutside = (event) => {
600
+ var _a;
601
+ if (!((_a = wrapperRef.current) == null ? void 0 : _a.contains(event.target))) {
602
+ setOpen(false);
603
+ }
604
+ };
605
+ document.addEventListener("mousedown", onClickOutside);
606
+ return () => document.removeEventListener("mousedown", onClickOutside);
607
+ }, [open]);
608
+ const updateQuery = (nextQuery) => {
609
+ if (!isControlledQuery) setInternalQuery(nextQuery);
610
+ onQueryChange == null ? void 0 : onQueryChange(nextQuery);
611
+ };
612
+ const isSelected = (option) => selectedValues.some((item) => valuesEqual(item, option.value));
613
+ const commitSingle = (next) => {
614
+ onChange == null ? void 0 : onChange(next);
615
+ };
616
+ const commitMany = (next) => {
617
+ onChangeMany == null ? void 0 : onChangeMany(next);
618
+ };
619
+ const selectOption = (option) => {
620
+ if (option.disabled) return;
621
+ if (multiple) {
622
+ const exists = isSelected(option);
623
+ if (exists) {
624
+ commitMany(values.filter((item) => !valuesEqual(item, option.value)));
625
+ } else {
626
+ if (typeof maxSelected === "number" && values.length >= maxSelected)
627
+ return;
628
+ commitMany([...values, option.value]);
629
+ }
630
+ } else {
631
+ commitSingle(option.value);
632
+ if (search) updateQuery("");
633
+ }
634
+ if (shouldCloseOnSelect) {
635
+ setOpen(false);
636
+ }
637
+ };
638
+ return /* @__PURE__ */ jsxs6("div", { className: cx("relative w-full", className), ref: wrapperRef, children: [
639
+ label ? /* @__PURE__ */ jsx8(
640
+ "label",
641
+ {
642
+ htmlFor: inputId,
643
+ className: "mb-1 block text-sm font-medium text-foreground",
644
+ children: label
645
+ }
646
+ ) : null,
647
+ /* @__PURE__ */ jsxs6(
648
+ "div",
649
+ {
650
+ className: cx(
651
+ "rounded-md border transition-colors focus-within:ring-2 focus-within:ring-ring",
652
+ sizeClasses[size],
653
+ variantClasses[variant],
654
+ intentClasses[intent],
655
+ isInvalid && "border-danger focus-within:border-danger",
656
+ disabled && "cursor-not-allowed opacity-60"
657
+ ),
658
+ children: [
659
+ multiple && values.length > 0 ? /* @__PURE__ */ jsx8("div", { className: "flex flex-wrap gap-1 px-2 pb-1 pt-2", children: values.map((selected, index) => {
660
+ var _a;
661
+ const option = options.find(
662
+ (item) => valuesEqual(item.value, selected)
663
+ );
664
+ return /* @__PURE__ */ jsx8(
665
+ Tag_default,
666
+ {
667
+ size: "sm",
668
+ onRemove: () => commitMany(
669
+ values.filter((item) => !valuesEqual(item, selected))
670
+ ),
671
+ children: (_a = option == null ? void 0 : option.label) != null ? _a : String(selected)
672
+ },
673
+ `${String(selected)}-${index}`
674
+ );
675
+ }) }) : null,
676
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 py-0.5", children: [
677
+ /* @__PURE__ */ jsx8(
678
+ "input",
679
+ {
680
+ ref: inputRef,
681
+ id: inputId,
682
+ name,
683
+ value: inputValue,
684
+ onFocus: () => {
685
+ if (!disabled) setOpen(true);
686
+ },
687
+ onClick: () => {
688
+ if (!disabled) setOpen(true);
689
+ },
690
+ onChange: (event) => {
691
+ if (!search && !multiple) return;
692
+ updateQuery(event.target.value);
693
+ setOpen(true);
694
+ setActiveIndex(0);
695
+ },
696
+ onKeyDown: (event) => {
697
+ if (disabled) return;
698
+ if (event.key === "ArrowDown") {
699
+ event.preventDefault();
700
+ setOpen(true);
701
+ setActiveIndex(
702
+ (prev) => Math.min(filteredOptions.length - 1, prev + 1)
703
+ );
704
+ } else if (event.key === "ArrowUp") {
705
+ event.preventDefault();
706
+ setOpen(true);
707
+ setActiveIndex((prev) => Math.max(0, prev - 1));
708
+ } else if (event.key === "Enter") {
709
+ event.preventDefault();
710
+ if (!open) {
711
+ setOpen(true);
712
+ return;
713
+ }
714
+ const option = filteredOptions[activeIndex];
715
+ if (option) selectOption(option);
716
+ } else if (event.key === "Escape") {
717
+ setOpen(false);
718
+ } else if (event.key === "Backspace" && multiple && !currentQuery && values.length > 0) {
719
+ commitMany(values.slice(0, -1));
720
+ } else if (event.key === "Tab") {
721
+ setOpen(false);
722
+ }
723
+ },
724
+ placeholder: multiple && values.length > 0 ? "" : placeholder,
725
+ role: "combobox",
726
+ "aria-expanded": open,
727
+ "aria-controls": listboxId,
728
+ "aria-autocomplete": "list",
729
+ "aria-label": ariaLabel,
730
+ "aria-invalid": isInvalid,
731
+ disabled,
732
+ className: cx(
733
+ "h-8 w-full bg-transparent py-0 text-foreground outline-none placeholder:text-muted-foreground",
734
+ inputClassName
735
+ )
736
+ }
737
+ ),
738
+ loading ? /* @__PURE__ */ jsx8(
739
+ Loader2,
740
+ {
741
+ className: "h-4 w-4 animate-spin text-muted-foreground",
742
+ "aria-hidden": "true"
743
+ }
744
+ ) : null,
745
+ /* @__PURE__ */ jsx8("span", { className: "inline-flex h-8 shrink-0 items-center justify-center", children: /* @__PURE__ */ jsx8(
746
+ ChevronDown2,
747
+ {
748
+ strokeWidth: 2.5,
749
+ className: cx(
750
+ "h-5 w-5 text-muted-foreground transition-transform duration-200 ease-out",
751
+ open && "rotate-180"
752
+ ),
753
+ "aria-hidden": "true"
754
+ }
755
+ ) })
756
+ ] })
757
+ ]
758
+ }
759
+ ),
760
+ open ? /* @__PURE__ */ jsx8(
761
+ "ul",
762
+ {
763
+ id: listboxId,
764
+ role: "listbox",
765
+ "aria-multiselectable": multiple || void 0,
766
+ className: cx(
767
+ "absolute left-0 right-0 top-full z-20 mt-1 max-h-60 overflow-y-auto rounded-md border border-border bg-background p-1 shadow-md",
768
+ menuClassName
769
+ ),
770
+ children: loading ? /* @__PURE__ */ jsx8("li", { className: "px-3 py-2 text-sm text-muted-foreground", children: "Loading..." }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsx8("li", { className: "px-3 py-2 text-sm text-muted-foreground", children: "No results" }) : filteredOptions.map((option, index) => {
771
+ const selected = isSelected(option);
772
+ const active = index === activeIndex;
773
+ return /* @__PURE__ */ jsx8(
774
+ "li",
775
+ {
776
+ role: "option",
777
+ "aria-selected": selected,
778
+ children: /* @__PURE__ */ jsxs6(
779
+ "button",
780
+ {
781
+ type: "button",
782
+ disabled: option.disabled,
783
+ onMouseEnter: () => setActiveIndex(index),
784
+ onClick: () => selectOption(option),
785
+ className: cx(
786
+ "flex w-full items-center justify-between rounded px-3 py-2 text-sm",
787
+ active ? "bg-surface" : "hover:bg-surface",
788
+ option.disabled && "cursor-not-allowed opacity-50"
789
+ ),
790
+ children: [
791
+ renderOption ? renderOption(option, { selected, active }) : /* @__PURE__ */ jsx8("span", { className: "text-foreground", children: option.label }),
792
+ selected ? /* @__PURE__ */ jsx8(
793
+ Check,
794
+ {
795
+ className: "h-4 w-4 text-primary",
796
+ "aria-hidden": "true"
797
+ }
798
+ ) : null
799
+ ]
800
+ }
801
+ )
802
+ },
803
+ `${String(option.value)}-${index}`
804
+ );
805
+ })
806
+ }
807
+ ) : null,
808
+ hint && !error ? /* @__PURE__ */ jsx8("p", { className: "mt-1 text-xs text-muted-foreground", children: hint }) : null,
809
+ error ? /* @__PURE__ */ jsx8("p", { className: "mt-1 text-xs text-danger", children: error }) : null
810
+ ] });
811
+ };
812
+ var Combobox_default = Combobox;
813
+
814
+ // src/components/shared/patterns/forms/FormField/fields/ComboboxField/ComboboxField.tsx
815
+ import { jsx as jsx9 } from "react/jsx-runtime";
816
+ var ComboboxField = ({
817
+ field,
818
+ value,
819
+ error,
820
+ onChange
821
+ }) => {
822
+ var _a, _b;
823
+ const isMultiple = Boolean(field.multiple);
824
+ const options = ((_a = field.options) != null ? _a : []).map((option) => ({
825
+ value: String(option.value),
826
+ label: option.label
827
+ }));
828
+ const emitChange = (nextValue) => {
829
+ const normalizedValue = nextValue == null ? "" : Array.isArray(nextValue) ? nextValue : String(nextValue);
830
+ onChange(createFormFieldChangeEvent(field.name, normalizedValue));
831
+ };
832
+ return /* @__PURE__ */ jsx9(
833
+ Combobox_default,
834
+ {
835
+ id: field.name,
836
+ name: field.name,
837
+ options,
838
+ multiple: isMultiple,
839
+ values: isMultiple ? value != null ? value : [] : [],
840
+ value: !isMultiple ? value != null ? value : null : null,
841
+ onChange: (next) => emitChange(next),
842
+ onChangeMany: (next) => emitChange(next),
843
+ placeholder: (_b = field.placeholder) != null ? _b : "Select...",
844
+ intent: error ? "danger" : "primary",
845
+ error,
846
+ inputClassName: "cursor-pointer",
847
+ "aria-label": field.label
848
+ }
849
+ );
850
+ };
851
+ var ComboboxField_default = ComboboxField;
852
+
853
+ // src/components/shared/patterns/forms/FormField/fields/DatePickerField/DatePickerField.tsx
854
+ import React7, { useEffect as useEffect5, useMemo as useMemo2, useState as useState3 } from "react";
855
+
856
+ // src/components/shared/primitives/actions/Button/Button.tsx
857
+ import { forwardRef as forwardRef3 } from "react";
858
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
859
+ var BASE_CLASSES = "relative inline-flex items-center justify-center overflow-hidden rounded-lg font-semibold cursor-pointer transition-all focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed";
860
+ var SIZE_CLASSES3 = {
861
+ xs: "h-7 px-2 text-xs",
862
+ sm: "h-8 px-3 text-sm",
863
+ md: "h-10 px-4 text-sm",
864
+ lg: "h-11 px-5 text-base"
865
+ };
866
+ var SOLID_INTENT_CLASSES = {
867
+ primary: "bg-primary text-primary-foreground border border-primary hover:bg-primary-hover hover:border-primary-hover",
868
+ secondary: "bg-secondary text-secondary-foreground border border-secondary hover:bg-secondary-hover hover:border-secondary-hover",
869
+ success: "bg-success text-success-foreground border border-success hover:bg-success-hover hover:border-success-hover",
870
+ warning: "bg-warning text-warning-foreground border border-warning hover:bg-warning-hover hover:border-warning-hover",
871
+ danger: "bg-danger text-danger-foreground border border-danger hover:bg-danger-hover hover:border-danger-hover",
872
+ info: "bg-info text-info-foreground border border-info hover:bg-info-hover hover:border-info-hover",
873
+ neutral: "bg-foreground text-background border border-foreground hover:opacity-90"
874
+ };
875
+ var OUTLINE_INTENT_CLASSES = {
876
+ primary: "bg-background text-primary border border-primary hover:bg-primary hover:text-primary-foreground",
877
+ secondary: "bg-background text-secondary border border-secondary hover:bg-secondary hover:text-secondary-foreground",
878
+ success: "bg-background text-success border border-success hover:bg-success hover:text-success-foreground",
879
+ warning: "bg-background text-warning border border-warning hover:bg-warning hover:text-warning-foreground",
880
+ danger: "bg-background text-danger border border-danger hover:bg-danger hover:text-danger-foreground",
881
+ info: "bg-background text-info border border-info hover:bg-info hover:text-info-foreground",
882
+ neutral: "bg-background text-foreground border border-border-strong hover:bg-surface"
883
+ };
884
+ var SOFT_INTENT_CLASSES = {
885
+ primary: "bg-primary-soft text-primary-soft-foreground border border-transparent hover:bg-primary-soft",
886
+ secondary: "bg-secondary-soft text-secondary-soft-foreground border border-transparent hover:bg-secondary-soft",
887
+ success: "bg-success-soft text-success-soft-foreground border border-transparent hover:bg-success-soft",
888
+ warning: "bg-warning-soft text-warning-soft-foreground border border-transparent hover:bg-warning-soft",
889
+ danger: "bg-danger-soft text-danger-soft-foreground border border-transparent hover:bg-danger-soft",
890
+ info: "bg-info-soft text-info-soft-foreground border border-transparent hover:bg-info-soft",
891
+ neutral: "bg-surface text-foreground border border-transparent hover:bg-surface-hover"
892
+ };
893
+ var GHOST_INTENT_CLASSES = {
894
+ primary: "bg-transparent text-ghost-primary-foreground border border-transparent hover:bg-ghost-primary-hover",
895
+ secondary: "bg-transparent text-ghost-secondary-foreground border border-transparent hover:bg-ghost-secondary-hover",
896
+ success: "bg-transparent text-ghost-success-foreground border border-transparent hover:bg-ghost-success-hover",
897
+ warning: "bg-transparent text-ghost-warning-foreground border border-transparent hover:bg-ghost-warning-hover",
898
+ danger: "bg-transparent text-ghost-danger-foreground border border-transparent hover:bg-ghost-danger-hover",
899
+ info: "bg-transparent text-ghost-info-foreground border border-transparent hover:bg-ghost-info-hover",
900
+ neutral: "bg-ghost text-ghost-foreground border border-ghost hover:bg-ghost-hover"
901
+ };
902
+ var GLASS_INTENT_CLASSES = {
903
+ primary: "bg-primary/20 text-primary-soft-foreground border border-glass-border hover:bg-primary/30",
904
+ secondary: "bg-secondary/20 text-secondary-soft-foreground border border-glass-border hover:bg-secondary/30",
905
+ success: "bg-success/20 text-success-soft-foreground border border-glass-border hover:bg-success/30",
906
+ warning: "bg-warning/20 text-warning-soft-foreground border border-glass-border hover:bg-warning/30",
907
+ danger: "bg-danger/20 text-danger-soft-foreground border border-glass-border hover:bg-danger/30",
908
+ info: "bg-info/20 text-info-soft-foreground border border-glass-border hover:bg-info/30",
909
+ neutral: "bg-glass-bg text-foreground border border-glass-border hover:border-glass-highlight"
910
+ };
911
+ var GLASS_LAYER_CLASSES = "before:pointer-events-none before:absolute before:inset-0 before:rounded-[inherit] before:bg-glass-highlight before:opacity-25";
912
+ var VARIANT_BY_KIND = {
913
+ solid: SOLID_INTENT_CLASSES,
914
+ outline: OUTLINE_INTENT_CLASSES,
915
+ ghost: GHOST_INTENT_CLASSES,
916
+ soft: SOFT_INTENT_CLASSES,
917
+ glass: GLASS_INTENT_CLASSES,
918
+ "reverse-primary": OUTLINE_INTENT_CLASSES,
919
+ "reverse-secondary": OUTLINE_INTENT_CLASSES
920
+ };
921
+ var resolveVariant = (intent, variant) => {
922
+ const safeVariant = variant != null ? variant : "solid";
923
+ if (safeVariant === "reverse-primary") {
924
+ return { intent: "primary", variant: "outline" };
925
+ }
926
+ if (safeVariant === "reverse-secondary") {
927
+ return { intent: "secondary", variant: "outline" };
928
+ }
929
+ return { intent, variant: safeVariant };
930
+ };
931
+ var Button = forwardRef3(
932
+ (_a, ref) => {
933
+ var _b = _a, {
934
+ type = "button",
935
+ intent = "primary",
936
+ variant = "solid",
937
+ size = "md",
938
+ loading = false,
939
+ disabled,
940
+ className,
941
+ children
942
+ } = _b, props = __objRest(_b, [
943
+ "type",
944
+ "intent",
945
+ "variant",
946
+ "size",
947
+ "loading",
948
+ "disabled",
949
+ "className",
950
+ "children"
951
+ ]);
952
+ const resolved = resolveVariant(intent, variant);
953
+ const isDisabled = disabled || loading;
954
+ return /* @__PURE__ */ jsx10(
955
+ "button",
956
+ __spreadProps(__spreadValues({
957
+ ref,
958
+ type,
959
+ className: cx(
960
+ BASE_CLASSES,
961
+ SIZE_CLASSES3[size],
962
+ VARIANT_BY_KIND[resolved.variant][resolved.intent],
963
+ resolved.variant === "glass" && GLASS_LAYER_CLASSES,
964
+ className
965
+ ),
966
+ disabled: isDisabled,
967
+ "aria-busy": loading || void 0
968
+ }, props), {
969
+ children: /* @__PURE__ */ jsxs7("span", { className: "relative inline-flex items-center gap-2 leading-none", children: [
970
+ loading && /* @__PURE__ */ jsx10(
971
+ "span",
972
+ {
973
+ className: "h-3.5 w-3.5 animate-spin rounded-full border-2 border-current border-r-transparent",
974
+ "aria-hidden": "true"
975
+ }
976
+ ),
977
+ renderBindableNode(children)
978
+ ] })
979
+ })
980
+ );
981
+ }
982
+ );
983
+ Button.displayName = "Button";
984
+ var Button_default = Button;
985
+
986
+ // src/components/shared/primitives/actions/Button/index.tsx
987
+ var Button_default2 = Button_default;
988
+
989
+ // src/components/shared/overlays/modals/Popin/Popin.tsx
990
+ import { X as X2 } from "lucide-react";
991
+ import {
992
+ useEffect as useEffect4,
993
+ useId as useId2,
994
+ useRef as useRef4,
995
+ useState as useState2
996
+ } from "react";
997
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
998
+ var MAX_SIZE_MAP = {
999
+ sm: "24rem",
1000
+ md: "28rem",
1001
+ lg: "32rem",
1002
+ xl: "36rem",
1003
+ "2xl": "42rem",
1004
+ full: "100vw"
1005
+ };
1006
+ var Popin = ({
1007
+ displayedPopin,
1008
+ children,
1009
+ setDisplayedPopin,
1010
+ title,
1011
+ closeText,
1012
+ hasCloseAvailability = true,
1013
+ closeOnOutsideClick = true,
1014
+ maxSize = "2xl",
1015
+ actionText,
1016
+ onAction,
1017
+ requireScrollToEnableAction = false
1018
+ }) => {
1019
+ const rawCloseOnOutsideClick = closeOnOutsideClick;
1020
+ const normalizedCloseOnOutsideClick = typeof rawCloseOnOutsideClick === "string" ? rawCloseOnOutsideClick.toLowerCase() !== "false" : Boolean(rawCloseOnOutsideClick);
1021
+ const titleId = useId2();
1022
+ const scrollRef = useRef4(null);
1023
+ const [hasScrolledToBottom, setHasScrolledToBottom] = useState2(
1024
+ !requireScrollToEnableAction
1025
+ );
1026
+ useEventListener_default("keydown", (event) => {
1027
+ if (!displayedPopin || !hasCloseAvailability) return;
1028
+ if (event.key === "Escape") {
1029
+ event.preventDefault();
1030
+ setDisplayedPopin(false);
1031
+ }
1032
+ });
1033
+ useEffect4(() => {
1034
+ var _a;
1035
+ if (!displayedPopin) return;
1036
+ setHasScrolledToBottom(!requireScrollToEnableAction);
1037
+ (_a = scrollRef.current) == null ? void 0 : _a.scrollTo({ top: 0 });
1038
+ if (requireScrollToEnableAction) {
1039
+ queueMicrotask(() => {
1040
+ const el = scrollRef.current;
1041
+ if (!el) return;
1042
+ const noScrollNeeded = el.scrollHeight <= el.clientHeight + 1;
1043
+ if (noScrollNeeded) {
1044
+ setHasScrolledToBottom(true);
1045
+ }
1046
+ });
1047
+ }
1048
+ }, [displayedPopin, requireScrollToEnableAction]);
1049
+ const handleScroll = () => {
1050
+ if (!requireScrollToEnableAction) return;
1051
+ const el = scrollRef.current;
1052
+ if (!el) return;
1053
+ const isBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 4;
1054
+ if (isBottom) setHasScrolledToBottom(true);
1055
+ };
1056
+ if (!displayedPopin) return null;
1057
+ const dialogStyle = {
1058
+ maxWidth: maxSize === "full" ? "calc(100vw - 2rem)" : `min(${MAX_SIZE_MAP[maxSize]}, calc(100vw - 2rem))`
1059
+ };
1060
+ return /* @__PURE__ */ jsxs8("div", { className: "fixed inset-0 z-[9999] flex items-center justify-center px-4", children: [
1061
+ /* @__PURE__ */ jsx11(
1062
+ "div",
1063
+ {
1064
+ className: "absolute inset-0 bg-foreground/40 opacity-50",
1065
+ onMouseDown: (event) => {
1066
+ event.preventDefault();
1067
+ event.stopPropagation();
1068
+ },
1069
+ onClick: (event) => {
1070
+ event.preventDefault();
1071
+ event.stopPropagation();
1072
+ if (hasCloseAvailability && normalizedCloseOnOutsideClick) {
1073
+ setDisplayedPopin(false);
1074
+ }
1075
+ }
1076
+ }
1077
+ ),
1078
+ /* @__PURE__ */ jsxs8(
1079
+ "div",
1080
+ {
1081
+ role: "dialog",
1082
+ "aria-modal": "true",
1083
+ "aria-labelledby": titleId,
1084
+ className: "relative z-10 flex w-fit max-h-[72vh] max-w-full min-w-0 flex-col rounded border-2 border-border bg-surface-hover sm:max-h-[85vh]",
1085
+ style: dialogStyle,
1086
+ onClick: (event) => event.stopPropagation(),
1087
+ children: [
1088
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between gap-3 border-b border-border px-6 py-4", children: [
1089
+ /* @__PURE__ */ jsx11(
1090
+ "h3",
1091
+ {
1092
+ id: titleId,
1093
+ className: "min-w-0 flex-1 break-words text-lg font-semibold text-primary",
1094
+ children: title
1095
+ }
1096
+ ),
1097
+ hasCloseAvailability && /* @__PURE__ */ jsx11(
1098
+ Button_default2,
1099
+ {
1100
+ type: "button",
1101
+ variant: "reverse-primary",
1102
+ onClick: () => setDisplayedPopin(false),
1103
+ "aria-label": typeof closeText === "string" ? closeText : "Close",
1104
+ className: "bg-transparent border-0 p-0 focus-visible:ring-offset-0",
1105
+ children: /* @__PURE__ */ jsx11(X2, { size: 20, "aria-hidden": "true" })
1106
+ }
1107
+ )
1108
+ ] }),
1109
+ /* @__PURE__ */ jsx11(
1110
+ "div",
1111
+ {
1112
+ ref: scrollRef,
1113
+ onScroll: handleScroll,
1114
+ className: "min-h-0 overflow-x-auto overflow-y-auto break-words px-6 py-4",
1115
+ children
1116
+ }
1117
+ ),
1118
+ actionText && /* @__PURE__ */ jsx11("div", { className: "flex justify-end px-6 py-4 border-t border-border bg-surface-hover", children: /* @__PURE__ */ jsx11(
1119
+ Button_default2,
1120
+ {
1121
+ onClick: onAction,
1122
+ disabled: requireScrollToEnableAction && !hasScrolledToBottom || !onAction,
1123
+ children: actionText
1124
+ }
1125
+ ) })
1126
+ ]
1127
+ }
1128
+ )
1129
+ ] });
1130
+ };
1131
+ var Popin_default = Popin;
1132
+
1133
+ // src/components/shared/overlays/modals/Popin/index.ts
1134
+ var Popin_default2 = Popin_default;
1135
+
1136
+ // src/components/shared/patterns/forms/FormField/fields/DatePickerField/DatePickerField.tsx
1137
+ import { Fragment, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1138
+ var ITEM_HEIGHT = 42;
1139
+ var WheelPickerColumn = ({
1140
+ label,
1141
+ items,
1142
+ selectedValue,
1143
+ onChange
1144
+ }) => {
1145
+ const wheelRef = React7.useRef(null);
1146
+ useEffect5(() => {
1147
+ const index = items.findIndex((item) => item.value === selectedValue);
1148
+ if (index < 0 || !wheelRef.current) return;
1149
+ wheelRef.current.scrollTo({
1150
+ top: index * ITEM_HEIGHT,
1151
+ behavior: "smooth"
1152
+ });
1153
+ }, [items, selectedValue]);
1154
+ return /* @__PURE__ */ jsxs9("div", { className: "min-w-20 flex flex-col gap-1", children: [
1155
+ /* @__PURE__ */ jsx12("p", { className: "text-xs font-semibold text-foreground", children: label }),
1156
+ /* @__PURE__ */ jsxs9("div", { className: "relative", children: [
1157
+ /* @__PURE__ */ jsx12("div", { className: "pointer-events-none absolute left-0 right-0 top-1/2 z-10 h-10 -translate-y-1/2 rounded border border-primary/30 bg-primary/5" }),
1158
+ /* @__PURE__ */ jsx12(
1159
+ "div",
1160
+ {
1161
+ ref: wheelRef,
1162
+ role: "listbox",
1163
+ "aria-label": `${label} wheel picker`,
1164
+ className: "h-52 overflow-y-auto rounded border border-border bg-background snap-y snap-mandatory",
1165
+ onScroll: (event) => {
1166
+ const target = event.currentTarget;
1167
+ const index = Math.round(target.scrollTop / ITEM_HEIGHT);
1168
+ const clampedIndex = Math.max(0, Math.min(items.length - 1, index));
1169
+ const next = items[clampedIndex];
1170
+ if (next && next.value !== selectedValue) {
1171
+ onChange(next.value);
1172
+ }
1173
+ },
1174
+ children: items.map((item) => /* @__PURE__ */ jsx12(
1175
+ "button",
1176
+ {
1177
+ type: "button",
1178
+ role: "option",
1179
+ "aria-selected": item.value === selectedValue,
1180
+ className: `flex h-10 w-full snap-start items-center justify-center text-sm ${item.value === selectedValue ? "font-semibold text-primary" : "text-muted-foreground"}`,
1181
+ onClick: () => onChange(item.value),
1182
+ children: item.label
1183
+ },
1184
+ `${label}-${item.value}`
1185
+ ))
1186
+ }
1187
+ )
1188
+ ] })
1189
+ ] });
1190
+ };
1191
+ var DatePickerField = ({
1192
+ field,
1193
+ value,
1194
+ error,
1195
+ errorId,
1196
+ onChange
1197
+ }) => {
1198
+ var _a;
1199
+ const safeValue = String((_a = getSafeValue(value)) != null ? _a : "");
1200
+ const [isMobilePicker, setIsMobilePicker] = useState3(false);
1201
+ const [isPopinOpen, setIsPopinOpen] = useState3(false);
1202
+ const today = useMemo2(() => /* @__PURE__ */ new Date(), []);
1203
+ const defaultYear = today.getFullYear();
1204
+ const [selectedYear, setSelectedYear] = useState3(defaultYear);
1205
+ const [selectedMonth, setSelectedMonth] = useState3(today.getMonth() + 1);
1206
+ const [selectedDay, setSelectedDay] = useState3(today.getDate());
1207
+ useEffect5(() => {
1208
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
1209
+ return;
1210
+ }
1211
+ const media = window.matchMedia("(max-width: 768px), (pointer: coarse)");
1212
+ const update = () => setIsMobilePicker(media.matches);
1213
+ update();
1214
+ media.addEventListener("change", update);
1215
+ return () => media.removeEventListener("change", update);
1216
+ }, []);
1217
+ const parseDate = (dateString) => {
1218
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dateString);
1219
+ if (!match) return null;
1220
+ return {
1221
+ year: Number(match[1]),
1222
+ month: Number(match[2]),
1223
+ day: Number(match[3])
1224
+ };
1225
+ };
1226
+ const daysInSelectedMonth = new Date(
1227
+ selectedYear,
1228
+ selectedMonth,
1229
+ 0
1230
+ ).getDate();
1231
+ const years = useMemo2(() => {
1232
+ const start = defaultYear - 100;
1233
+ const end = defaultYear + 20;
1234
+ return Array.from({ length: end - start + 1 }, (_, index) => start + index);
1235
+ }, [defaultYear]);
1236
+ const days = useMemo2(
1237
+ () => Array.from({ length: daysInSelectedMonth }, (_, index) => index + 1),
1238
+ [daysInSelectedMonth]
1239
+ );
1240
+ const formattedValue = useMemo2(() => {
1241
+ const parsed = parseDate(safeValue);
1242
+ if (!parsed) return safeValue;
1243
+ return `${String(parsed.day).padStart(2, "0")}/${String(parsed.month).padStart(2, "0")}/${parsed.year}`;
1244
+ }, [safeValue]);
1245
+ const openMobilePicker = () => {
1246
+ const parsed = parseDate(safeValue);
1247
+ if (parsed) {
1248
+ setSelectedYear(parsed.year);
1249
+ setSelectedMonth(parsed.month);
1250
+ setSelectedDay(parsed.day);
1251
+ }
1252
+ setIsPopinOpen(true);
1253
+ };
1254
+ const emitDate = (nextValue) => {
1255
+ onChange(createFormFieldChangeEvent(field.name, nextValue));
1256
+ };
1257
+ const applyMobilePicker = () => {
1258
+ const safeDay = Math.min(selectedDay, daysInSelectedMonth);
1259
+ const isoDate = `${selectedYear}-${String(selectedMonth).padStart(2, "0")}-${String(safeDay).padStart(2, "0")}`;
1260
+ emitDate(isoDate);
1261
+ setIsPopinOpen(false);
1262
+ };
1263
+ if (isMobilePicker) {
1264
+ return /* @__PURE__ */ jsxs9(Fragment, { children: [
1265
+ /* @__PURE__ */ jsx12(
1266
+ "button",
1267
+ {
1268
+ type: "button",
1269
+ onClick: openMobilePicker,
1270
+ className: `mt-1 w-full rounded-md border bg-background px-3 py-2 text-left text-sm outline-none focus-visible:ring-2 ${error ? "border-danger focus-visible:ring-danger/40" : "border-border-strong focus-visible:ring-ring"}`,
1271
+ "aria-invalid": Boolean(error),
1272
+ "aria-describedby": errorId,
1273
+ children: formattedValue || field.placeholder || "Select a date"
1274
+ }
1275
+ ),
1276
+ /* @__PURE__ */ jsx12(
1277
+ Popin_default2,
1278
+ {
1279
+ displayedPopin: isPopinOpen,
1280
+ setDisplayedPopin: setIsPopinOpen,
1281
+ title: field.label,
1282
+ closeText: "Close date picker",
1283
+ actionText: "Apply",
1284
+ onAction: applyMobilePicker,
1285
+ maxSize: "full",
1286
+ children: /* @__PURE__ */ jsxs9("div", { className: "flex gap-3 overflow-x-auto", children: [
1287
+ /* @__PURE__ */ jsx12(
1288
+ WheelPickerColumn,
1289
+ {
1290
+ label: "Day",
1291
+ items: days.map((day) => ({
1292
+ value: day,
1293
+ label: String(day).padStart(2, "0")
1294
+ })),
1295
+ selectedValue: selectedDay,
1296
+ onChange: setSelectedDay
1297
+ }
1298
+ ),
1299
+ /* @__PURE__ */ jsx12(
1300
+ WheelPickerColumn,
1301
+ {
1302
+ label: "Month",
1303
+ items: Array.from({ length: 12 }, (_, index) => ({
1304
+ value: index + 1,
1305
+ label: String(index + 1).padStart(2, "0")
1306
+ })),
1307
+ selectedValue: selectedMonth,
1308
+ onChange: setSelectedMonth
1309
+ }
1310
+ ),
1311
+ /* @__PURE__ */ jsx12(
1312
+ WheelPickerColumn,
1313
+ {
1314
+ label: "Year",
1315
+ items: years.map((year) => ({
1316
+ value: year,
1317
+ label: String(year)
1318
+ })),
1319
+ selectedValue: selectedYear,
1320
+ onChange: setSelectedYear
1321
+ }
1322
+ )
1323
+ ] })
1324
+ }
1325
+ )
1326
+ ] });
1327
+ }
1328
+ return /* @__PURE__ */ jsx12(
1329
+ Input_default,
1330
+ {
1331
+ id: field.name,
1332
+ type: "date",
1333
+ name: field.name,
1334
+ value: safeValue,
1335
+ onChange,
1336
+ "aria-invalid": Boolean(error),
1337
+ "aria-describedby": errorId,
1338
+ intent: error ? "danger" : "neutral",
1339
+ className: "mt-1"
1340
+ }
1341
+ );
1342
+ };
1343
+ var DatePickerField_default = DatePickerField;
1344
+
1345
+ // src/components/shared/patterns/forms/FormField/fields/DatePickerField/index.tsx
1346
+ var DatePickerField_default2 = DatePickerField_default;
1347
+
1348
+ // src/components/shared/media/upload/fields/FileUpload/FileUpload.tsx
1349
+ import { useEffect as useEffect6, useId as useId3, useMemo as useMemo3, useState as useState4 } from "react";
1350
+ import { Upload, X as X3 } from "lucide-react";
1351
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1352
+ var VARIANT_CLASSES2 = {
1353
+ solid: {
1354
+ primary: "bg-primary-soft border-primary text-primary-soft-foreground",
1355
+ secondary: "bg-secondary-soft border-secondary text-secondary-soft-foreground",
1356
+ success: "bg-success-soft border-success text-success-soft-foreground",
1357
+ warning: "bg-warning-soft border-warning text-warning-soft-foreground",
1358
+ danger: "bg-danger-soft border-danger text-danger-soft-foreground",
1359
+ info: "bg-info-soft border-info text-info-soft-foreground",
1360
+ neutral: "bg-surface border-border text-foreground"
1361
+ },
1362
+ outline: {
1363
+ primary: "bg-background border-primary text-primary",
1364
+ secondary: "bg-background border-secondary text-secondary",
1365
+ success: "bg-background border-success text-success",
1366
+ warning: "bg-background border-warning text-warning",
1367
+ danger: "bg-background border-danger text-danger",
1368
+ info: "bg-background border-info text-info",
1369
+ neutral: "bg-background border-border text-foreground"
1370
+ },
1371
+ ghost: {
1372
+ primary: "bg-transparent border-transparent text-ghost-primary-foreground hover:bg-ghost-primary-hover",
1373
+ secondary: "bg-transparent border-transparent text-ghost-secondary-foreground hover:bg-ghost-secondary-hover",
1374
+ success: "bg-transparent border-transparent text-ghost-success-foreground hover:bg-ghost-success-hover",
1375
+ warning: "bg-transparent border-transparent text-ghost-warning-foreground hover:bg-ghost-warning-hover",
1376
+ danger: "bg-transparent border-transparent text-ghost-danger-foreground hover:bg-ghost-danger-hover",
1377
+ info: "bg-transparent border-transparent text-ghost-info-foreground hover:bg-ghost-info-hover",
1378
+ neutral: "bg-transparent border-transparent text-ghost-foreground hover:bg-ghost-hover"
1379
+ },
1380
+ soft: {
1381
+ primary: "bg-primary-soft border-transparent text-primary-soft-foreground",
1382
+ secondary: "bg-secondary-soft border-transparent text-secondary-soft-foreground",
1383
+ success: "bg-success-soft border-transparent text-success-soft-foreground",
1384
+ warning: "bg-warning-soft border-transparent text-warning-soft-foreground",
1385
+ danger: "bg-danger-soft border-transparent text-danger-soft-foreground",
1386
+ info: "bg-info-soft border-transparent text-info-soft-foreground",
1387
+ neutral: "bg-surface border-transparent text-foreground"
1388
+ },
1389
+ glass: {
1390
+ primary: "bg-primary/20 border-glass-border text-primary-soft-foreground shadow-glass",
1391
+ secondary: "bg-secondary/20 border-glass-border text-secondary-soft-foreground shadow-glass",
1392
+ success: "bg-success/20 border-glass-border text-success-soft-foreground shadow-glass",
1393
+ warning: "bg-warning/20 border-glass-border text-warning-soft-foreground shadow-glass",
1394
+ danger: "bg-danger/20 border-glass-border text-danger-soft-foreground shadow-glass",
1395
+ info: "bg-info/20 border-glass-border text-info-soft-foreground shadow-glass",
1396
+ neutral: "bg-glass-bg border-glass-border text-foreground shadow-glass"
1397
+ }
1398
+ };
1399
+ var matchesAccept = (file, accept) => {
1400
+ if (!accept) return true;
1401
+ const accepted = accept.split(",").map((item) => item.trim().toLowerCase());
1402
+ const fileType = file.type.toLowerCase();
1403
+ const fileName = file.name.toLowerCase();
1404
+ return accepted.some((rule) => {
1405
+ if (rule.startsWith(".")) return fileName.endsWith(rule);
1406
+ if (rule.endsWith("/*")) return fileType.startsWith(rule.slice(0, -1));
1407
+ return fileType === rule;
1408
+ });
1409
+ };
1410
+ var getPreviewKind = (file) => {
1411
+ if (file.type.startsWith("image/")) return "image";
1412
+ if (file.type.startsWith("video/")) return "video";
1413
+ return null;
1414
+ };
1415
+ var createPreviewUrl = (file) => {
1416
+ if (typeof URL === "undefined" || typeof URL.createObjectURL !== "function") return null;
1417
+ return URL.createObjectURL(file);
1418
+ };
1419
+ var revokePreviewUrl = (url) => {
1420
+ if (!url) return;
1421
+ if (typeof URL === "undefined" || typeof URL.revokeObjectURL !== "function") return;
1422
+ URL.revokeObjectURL(url);
1423
+ };
1424
+ var FileUpload = ({
1425
+ value,
1426
+ onChange,
1427
+ multiple = true,
1428
+ accept,
1429
+ maxFiles,
1430
+ maxSizeBytes,
1431
+ disabled = false,
1432
+ renderFile,
1433
+ onReject,
1434
+ intent = "neutral",
1435
+ variant = "outline",
1436
+ className
1437
+ }) => {
1438
+ var _a;
1439
+ const inputId = useId3();
1440
+ const files = useMemo3(() => value != null ? value : [], [value]);
1441
+ const [dragActive, setDragActive] = useState4(false);
1442
+ const [previewOpen, setPreviewOpen] = useState4(false);
1443
+ const [activePreview, setActivePreview] = useState4(null);
1444
+ const previews = useMemo3(
1445
+ () => files.map((file) => {
1446
+ const kind = getPreviewKind(file);
1447
+ return {
1448
+ file,
1449
+ kind,
1450
+ url: kind ? createPreviewUrl(file) : null
1451
+ };
1452
+ }),
1453
+ [files]
1454
+ );
1455
+ useEffect6(
1456
+ () => () => {
1457
+ previews.forEach((preview) => {
1458
+ revokePreviewUrl(preview.url);
1459
+ });
1460
+ },
1461
+ [previews]
1462
+ );
1463
+ const normalizeFiles = (incomingFiles) => {
1464
+ const next = [];
1465
+ for (const file of incomingFiles) {
1466
+ if (!matchesAccept(file, accept)) {
1467
+ onReject == null ? void 0 : onReject({ type: "accept", file });
1468
+ continue;
1469
+ }
1470
+ if (typeof maxSizeBytes === "number" && file.size > maxSizeBytes) {
1471
+ onReject == null ? void 0 : onReject({ type: "maxSize", file });
1472
+ continue;
1473
+ }
1474
+ next.push(file);
1475
+ }
1476
+ const merged = multiple ? [...files, ...next] : next.slice(0, 1);
1477
+ if (typeof maxFiles === "number" && merged.length > maxFiles) {
1478
+ onReject == null ? void 0 : onReject({ type: "maxFiles" });
1479
+ return merged.slice(0, maxFiles);
1480
+ }
1481
+ return merged;
1482
+ };
1483
+ const commitFiles = (incomingFiles) => {
1484
+ const normalized = normalizeFiles(incomingFiles);
1485
+ onChange(normalized);
1486
+ };
1487
+ return /* @__PURE__ */ jsxs10("div", { className: cx("space-y-3", className), children: [
1488
+ /* @__PURE__ */ jsxs10(
1489
+ "label",
1490
+ {
1491
+ htmlFor: inputId,
1492
+ onDragOver: (event) => {
1493
+ event.preventDefault();
1494
+ if (!disabled) setDragActive(true);
1495
+ },
1496
+ onDragLeave: () => setDragActive(false),
1497
+ onDrop: (event) => {
1498
+ event.preventDefault();
1499
+ setDragActive(false);
1500
+ if (disabled) return;
1501
+ const dropped = Array.from(event.dataTransfer.files);
1502
+ if (dropped.length) commitFiles(dropped);
1503
+ },
1504
+ className: cx(
1505
+ "flex min-h-28 cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed p-4 text-center transition-colors",
1506
+ VARIANT_CLASSES2[variant][intent],
1507
+ dragActive && "border-primary bg-primary-soft",
1508
+ disabled && "cursor-not-allowed opacity-60"
1509
+ ),
1510
+ children: [
1511
+ /* @__PURE__ */ jsx13(Upload, { className: "h-5 w-5", "aria-hidden": "true" }),
1512
+ /* @__PURE__ */ jsx13("span", { className: "text-sm font-medium text-foreground", children: "Drop files here or click to upload" }),
1513
+ /* @__PURE__ */ jsxs10("span", { className: "text-xs text-muted-foreground", children: [
1514
+ accept ? `Accepted: ${accept}` : "All file types",
1515
+ "."
1516
+ ] })
1517
+ ]
1518
+ }
1519
+ ),
1520
+ /* @__PURE__ */ jsx13(
1521
+ "input",
1522
+ {
1523
+ id: inputId,
1524
+ type: "file",
1525
+ accept,
1526
+ multiple,
1527
+ disabled,
1528
+ className: "sr-only",
1529
+ onChange: (event) => {
1530
+ var _a2;
1531
+ const selected = Array.from((_a2 = event.target.files) != null ? _a2 : []);
1532
+ if (selected.length) commitFiles(selected);
1533
+ event.currentTarget.value = "";
1534
+ }
1535
+ }
1536
+ ),
1537
+ files.length > 0 ? /* @__PURE__ */ jsx13("div", { className: "flex flex-wrap justify-center gap-3", children: previews.map(({ file, kind, url }, index) => /* @__PURE__ */ jsxs10(
1538
+ "div",
1539
+ {
1540
+ className: "w-full max-w-64 rounded-lg border border-border bg-surface p-3",
1541
+ children: [
1542
+ /* @__PURE__ */ jsxs10("div", { className: "flex justify-center", children: [
1543
+ kind === "image" && url ? /* @__PURE__ */ jsx13(
1544
+ "button",
1545
+ {
1546
+ type: "button",
1547
+ className: "w-full cursor-pointer rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1548
+ "aria-label": `Open preview ${file.name}`,
1549
+ onClick: () => {
1550
+ setActivePreview({ name: file.name, kind: "image", url });
1551
+ setPreviewOpen(true);
1552
+ },
1553
+ children: /* @__PURE__ */ jsx13(
1554
+ "img",
1555
+ {
1556
+ src: url,
1557
+ alt: file.name,
1558
+ className: "h-28 w-full rounded object-cover"
1559
+ }
1560
+ )
1561
+ }
1562
+ ) : null,
1563
+ kind === "video" && url ? /* @__PURE__ */ jsx13(
1564
+ "button",
1565
+ {
1566
+ type: "button",
1567
+ className: "w-full cursor-pointer rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1568
+ "aria-label": `Open preview ${file.name}`,
1569
+ onClick: () => {
1570
+ setActivePreview({ name: file.name, kind: "video", url });
1571
+ setPreviewOpen(true);
1572
+ },
1573
+ children: /* @__PURE__ */ jsx13(
1574
+ "video",
1575
+ {
1576
+ src: url,
1577
+ className: "h-28 w-full rounded object-cover",
1578
+ muted: true,
1579
+ preload: "metadata",
1580
+ "aria-label": `Preview ${file.name}`
1581
+ }
1582
+ )
1583
+ }
1584
+ ) : null,
1585
+ !kind ? /* @__PURE__ */ jsx13("div", { className: "flex h-28 w-full items-center justify-center rounded bg-muted text-xs text-muted-foreground", children: "No preview" }) : null
1586
+ ] }),
1587
+ /* @__PURE__ */ jsxs10("div", { className: "mt-2 flex items-center gap-2", children: [
1588
+ /* @__PURE__ */ jsx13("div", { className: "min-w-0 flex-1 rounded-md border border-border bg-background px-2 py-1 text-center text-sm", children: /* @__PURE__ */ jsx13("span", { className: "block truncate", children: renderFile ? renderFile(file) : file.name }) }),
1589
+ /* @__PURE__ */ jsx13(
1590
+ "button",
1591
+ {
1592
+ type: "button",
1593
+ "aria-label": `Remove ${file.name}`,
1594
+ onClick: () => onChange(files.filter((_, fileIndex) => fileIndex !== index)),
1595
+ className: "shrink-0 rounded p-1 text-muted-foreground hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1596
+ children: /* @__PURE__ */ jsx13(X3, { className: "h-4 w-4", "aria-hidden": "true" })
1597
+ }
1598
+ )
1599
+ ] })
1600
+ ]
1601
+ },
1602
+ `${file.name}-${file.size}-${index}`
1603
+ )) }) : null,
1604
+ /* @__PURE__ */ jsx13(
1605
+ Popin_default2,
1606
+ {
1607
+ displayedPopin: previewOpen,
1608
+ setDisplayedPopin: setPreviewOpen,
1609
+ title: (_a = activePreview == null ? void 0 : activePreview.name) != null ? _a : "Media preview",
1610
+ closeText: "Close preview",
1611
+ maxSize: "xl",
1612
+ children: /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-center", children: [
1613
+ (activePreview == null ? void 0 : activePreview.kind) === "image" ? /* @__PURE__ */ jsx13(
1614
+ "img",
1615
+ {
1616
+ src: activePreview.url,
1617
+ alt: activePreview.name,
1618
+ className: "max-h-[70vh] w-auto max-w-full rounded object-contain"
1619
+ }
1620
+ ) : null,
1621
+ (activePreview == null ? void 0 : activePreview.kind) === "video" ? /* @__PURE__ */ jsx13(
1622
+ "video",
1623
+ {
1624
+ src: activePreview.url,
1625
+ className: "max-h-[70vh] w-auto max-w-full rounded",
1626
+ controls: true,
1627
+ autoPlay: true,
1628
+ muted: true
1629
+ }
1630
+ ) : null
1631
+ ] })
1632
+ }
1633
+ )
1634
+ ] });
1635
+ };
1636
+ var FileUpload_default = FileUpload;
1637
+
1638
+ // src/components/shared/patterns/forms/FormField/fields/FileUploadField/FileUploadField.tsx
1639
+ import { jsx as jsx14 } from "react/jsx-runtime";
1640
+ var FileUploadField = ({
1641
+ field,
1642
+ value,
1643
+ onChange
1644
+ }) => {
1645
+ var _a;
1646
+ const safeField = field != null ? field : {};
1647
+ const fieldName = typeof safeField.name === "string" && safeField.name.trim() ? safeField.name : "fileUpload";
1648
+ const files = Array.isArray(value) ? value : [];
1649
+ return /* @__PURE__ */ jsx14(
1650
+ FileUpload_default,
1651
+ {
1652
+ value: files,
1653
+ onChange: (nextFiles) => onChange(createFormFieldChangeEvent(fieldName, nextFiles)),
1654
+ multiple: (_a = safeField.multiple) != null ? _a : true,
1655
+ accept: safeField.accept,
1656
+ maxFiles: safeField.maxFiles,
1657
+ maxSizeBytes: safeField.maxSizeBytes
1658
+ }
1659
+ );
1660
+ };
1661
+ var FileUploadField_default = FileUploadField;
1662
+
1663
+ // src/components/shared/primitives/data-entry/Select/Select.tsx
1664
+ import { forwardRef as forwardRef4, useState as useState5 } from "react";
1665
+ import { ChevronDown as ChevronDown3 } from "lucide-react";
1666
+ import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1667
+ var SIZE_CLASSES4 = {
1668
+ xs: "h-7 px-2 text-xs",
1669
+ sm: "h-8 px-3 text-sm",
1670
+ md: "h-10 px-3 text-sm",
1671
+ lg: "h-11 px-4 text-base"
1672
+ };
1673
+ var INTENT_CLASSES2 = {
1674
+ primary: "focus-visible:border-primary",
1675
+ secondary: "focus-visible:border-secondary",
1676
+ success: "focus-visible:border-success",
1677
+ warning: "focus-visible:border-warning",
1678
+ danger: "focus-visible:border-danger",
1679
+ info: "focus-visible:border-info",
1680
+ neutral: "focus-visible:border-primary"
1681
+ };
1682
+ var Select = forwardRef4(
1683
+ (_a, ref) => {
1684
+ var _b = _a, { className, children, intent = "neutral", size = "md" } = _b, props = __objRest(_b, ["className", "children", "intent", "size"]);
1685
+ const isInvalid = props["aria-invalid"] === true || props["aria-invalid"] === "true";
1686
+ const [isFocused, setIsFocused] = useState5(false);
1687
+ return /* @__PURE__ */ jsxs11("div", { className: "relative w-full", children: [
1688
+ /* @__PURE__ */ jsx15(
1689
+ "select",
1690
+ __spreadProps(__spreadValues({
1691
+ ref,
1692
+ className: cx(
1693
+ "w-full appearance-none rounded-md border bg-background pr-10 text-foreground outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
1694
+ SIZE_CLASSES4[size],
1695
+ isInvalid ? "border-danger focus-visible:border-danger" : "border-border-strong",
1696
+ !isInvalid && INTENT_CLASSES2[intent],
1697
+ className
1698
+ ),
1699
+ onFocus: (event) => {
1700
+ var _a2;
1701
+ setIsFocused(true);
1702
+ (_a2 = props.onFocus) == null ? void 0 : _a2.call(props, event);
1703
+ },
1704
+ onBlur: (event) => {
1705
+ var _a2;
1706
+ setIsFocused(false);
1707
+ (_a2 = props.onBlur) == null ? void 0 : _a2.call(props, event);
1708
+ }
1709
+ }, props), {
1710
+ children
1711
+ })
1712
+ ),
1713
+ /* @__PURE__ */ jsx15("span", { className: "pointer-events-none absolute inset-y-0 right-3 flex items-center text-muted-foreground", children: /* @__PURE__ */ jsx15(
1714
+ ChevronDown3,
1715
+ {
1716
+ "aria-hidden": "true",
1717
+ strokeWidth: 2.5,
1718
+ className: cx(
1719
+ "h-5 w-5 transition-transform duration-200 ease-out",
1720
+ isFocused && "rotate-180"
1721
+ )
1722
+ }
1723
+ ) })
1724
+ ] });
1725
+ }
1726
+ );
1727
+ Select.displayName = "Select";
1728
+ var Select_default = Select;
1729
+
1730
+ // src/components/shared/patterns/forms/FormField/fields/SelectField/SelectField.tsx
1731
+ import { jsx as jsx16 } from "react/jsx-runtime";
1732
+ var SelectField = ({ field, value, error, errorId, onChange }) => {
1733
+ var _a;
1734
+ return /* @__PURE__ */ jsx16(
1735
+ Select_default,
1736
+ {
1737
+ id: field.name,
1738
+ name: field.name,
1739
+ value,
1740
+ onChange,
1741
+ "aria-invalid": Boolean(error),
1742
+ "aria-describedby": errorId,
1743
+ intent: error ? "danger" : "neutral",
1744
+ className: "mt-1 cursor-pointer",
1745
+ children: (_a = field.options) == null ? void 0 : _a.map((opt) => /* @__PURE__ */ jsx16("option", { value: opt.value, children: opt.label }, opt.value))
1746
+ }
1747
+ );
1748
+ };
1749
+ var SelectField_default = SelectField;
1750
+
1751
+ // src/components/shared/patterns/forms/FormField/fields/SelectField/index.tsx
1752
+ var SelectField_default2 = SelectField_default;
1753
+
1754
+ // src/components/shared/primitives/data-entry/Slider/Slider.tsx
1755
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
1756
+ var SIZE_CLASSES5 = {
1757
+ sm: "h-1.5",
1758
+ md: "h-2",
1759
+ lg: "h-2.5"
1760
+ };
1761
+ var INTENT_CLASSES3 = {
1762
+ primary: "accent-primary",
1763
+ secondary: "accent-secondary",
1764
+ success: "accent-success",
1765
+ warning: "accent-warning",
1766
+ danger: "accent-danger",
1767
+ info: "accent-info",
1768
+ neutral: "accent-primary"
1769
+ };
1770
+ var Slider = (_a) => {
1771
+ var _b = _a, {
1772
+ value,
1773
+ onChange,
1774
+ min = 0,
1775
+ max = 100,
1776
+ step = 1,
1777
+ disabled = false,
1778
+ showValue = false,
1779
+ formatValue,
1780
+ intent = "primary",
1781
+ size = "md",
1782
+ className
1783
+ } = _b, props = __objRest(_b, [
1784
+ "value",
1785
+ "onChange",
1786
+ "min",
1787
+ "max",
1788
+ "step",
1789
+ "disabled",
1790
+ "showValue",
1791
+ "formatValue",
1792
+ "intent",
1793
+ "size",
1794
+ "className"
1795
+ ]);
1796
+ return /* @__PURE__ */ jsxs12("div", { className: cx("flex items-center gap-3", className), children: [
1797
+ /* @__PURE__ */ jsx17(
1798
+ "input",
1799
+ __spreadValues({
1800
+ type: "range",
1801
+ value,
1802
+ min,
1803
+ max,
1804
+ step,
1805
+ disabled,
1806
+ onChange: (event) => onChange(Number(event.target.value)),
1807
+ className: cx(
1808
+ "w-full cursor-pointer rounded-lg bg-surface shadow-none disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
1809
+ SIZE_CLASSES5[size],
1810
+ INTENT_CLASSES3[intent]
1811
+ )
1812
+ }, props)
1813
+ ),
1814
+ showValue ? /* @__PURE__ */ jsx17("span", { className: "min-w-10 text-right text-xs font-medium text-muted-foreground", children: formatValue ? formatValue(value) : value }) : null
1815
+ ] });
1816
+ };
1817
+ var Slider_default = Slider;
1818
+
1819
+ // src/components/shared/patterns/forms/FormField/fields/SliderField/SliderField.tsx
1820
+ import { jsx as jsx18 } from "react/jsx-runtime";
1821
+ var SliderField = ({ field, value, onChange }) => {
1822
+ var _a, _b, _c, _d, _e;
1823
+ const numericValue = typeof value === "number" ? value : typeof value === "string" && value !== "" ? Number(value) : (_a = field.min) != null ? _a : 0;
1824
+ return /* @__PURE__ */ jsx18(
1825
+ Slider_default,
1826
+ {
1827
+ id: field.name,
1828
+ name: field.name,
1829
+ value: Number.isFinite(numericValue) ? numericValue : (_b = field.min) != null ? _b : 0,
1830
+ min: (_c = field.min) != null ? _c : 0,
1831
+ max: (_d = field.max) != null ? _d : 100,
1832
+ step: (_e = field.step) != null ? _e : 1,
1833
+ showValue: true,
1834
+ onChange: (next) => onChange(createFormFieldChangeEvent(field.name, next)),
1835
+ "aria-label": field.label
1836
+ }
1837
+ );
1838
+ };
1839
+ var SliderField_default = SliderField;
1840
+
1841
+ // src/components/shared/primitives/data-entry/Switch/Switch.tsx
1842
+ import { jsx as jsx19 } from "react/jsx-runtime";
1843
+ var Switch = (_a) => {
1844
+ var _b = _a, {
1845
+ checked,
1846
+ onChange,
1847
+ disabled = false,
1848
+ label,
1849
+ className,
1850
+ onKeyDown,
1851
+ "aria-label": ariaLabel
1852
+ } = _b, props = __objRest(_b, [
1853
+ "checked",
1854
+ "onChange",
1855
+ "disabled",
1856
+ "label",
1857
+ "className",
1858
+ "onKeyDown",
1859
+ "aria-label"
1860
+ ]);
1861
+ const handleToggle = () => {
1862
+ if (disabled) return;
1863
+ onChange(!checked);
1864
+ };
1865
+ const handleKeyDown = (event) => {
1866
+ onKeyDown == null ? void 0 : onKeyDown(event);
1867
+ if (event.defaultPrevented || disabled) return;
1868
+ if (event.key === " " || event.key === "Enter") {
1869
+ event.preventDefault();
1870
+ onChange(!checked);
1871
+ }
1872
+ };
1873
+ return /* @__PURE__ */ jsx19(
1874
+ "button",
1875
+ __spreadProps(__spreadValues({
1876
+ type: "button",
1877
+ role: "switch",
1878
+ "aria-checked": checked,
1879
+ "aria-label": ariaLabel != null ? ariaLabel : label,
1880
+ disabled,
1881
+ onClick: handleToggle,
1882
+ onKeyDown: handleKeyDown,
1883
+ className: `relative inline-flex h-6 w-11 cursor-pointer items-center rounded-full border transition-colors shadow-sm disabled:opacity-50 disabled:cursor-not-allowed ${checked ? "border-primary-foreground/40 bg-primary-hover" : "border-border-strong bg-border-strong"} ${className != null ? className : ""}`
1884
+ }, props), {
1885
+ children: /* @__PURE__ */ jsx19(
1886
+ "span",
1887
+ {
1888
+ className: `inline-block h-4 w-4 transform rounded-full transition-transform ${checked ? "translate-x-6 bg-primary-foreground" : "translate-x-1 bg-background"}`
1889
+ }
1890
+ )
1891
+ })
1892
+ );
1893
+ };
1894
+ var Switch_default = Switch;
1895
+
1896
+ // src/components/shared/patterns/forms/FormField/fields/SwitchField/SwitchField.tsx
1897
+ import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
1898
+ var SwitchField = ({
1899
+ field,
1900
+ value,
1901
+ error,
1902
+ errorId,
1903
+ onChange
1904
+ }) => {
1905
+ const checked = Boolean(value);
1906
+ const emit = (next) => {
1907
+ onChange(createFormFieldChangeEvent(field.name, next));
1908
+ };
1909
+ return /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-3 py-1", children: [
1910
+ /* @__PURE__ */ jsx20(
1911
+ Switch_default,
1912
+ {
1913
+ checked,
1914
+ onChange: emit,
1915
+ label: field.label,
1916
+ "aria-describedby": errorId,
1917
+ "aria-invalid": Boolean(error)
1918
+ }
1919
+ ),
1920
+ /* @__PURE__ */ jsxs13("span", { className: "text-foreground", children: [
1921
+ field.label,
1922
+ " ",
1923
+ field.required && "*"
1924
+ ] }),
1925
+ error && !errorId && /* @__PURE__ */ jsx20("p", { className: "text-sm text-danger", children: error })
1926
+ ] });
1927
+ };
1928
+ var SwitchField_default = SwitchField;
1929
+
1930
+ // src/components/shared/patterns/forms/FormField/fields/SwitchField/index.tsx
1931
+ var SwitchField_default2 = SwitchField_default;
1932
+
1933
+ // src/components/shared/patterns/forms/FormField/fields/TagsField/TagsField.tsx
1934
+ import React10 from "react";
1935
+ import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
1936
+ var TagsField = ({ field, value, error, errorId, onChange }) => {
1937
+ var _a;
1938
+ const [tagToAdd, setTagToAdd] = React10.useState("");
1939
+ const tags = Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
1940
+ const addTag = () => {
1941
+ if (!tagToAdd || tags.includes(tagToAdd)) return;
1942
+ onChange(createFormFieldChangeEvent(field.name, [...tags, tagToAdd]));
1943
+ setTagToAdd("");
1944
+ };
1945
+ const removeTag = (tag) => {
1946
+ onChange(createFormFieldChangeEvent(field.name, tags.filter((t) => t !== tag)));
1947
+ };
1948
+ return /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-2", children: [
1949
+ /* @__PURE__ */ jsxs14("div", { className: "flex gap-2", children: [
1950
+ /* @__PURE__ */ jsxs14(
1951
+ Select_default,
1952
+ {
1953
+ id: field.name,
1954
+ className: "flex-1 cursor-pointer placeholder:text-muted-foreground",
1955
+ value: tagToAdd,
1956
+ onChange: (e) => setTagToAdd(e.target.value),
1957
+ "aria-invalid": Boolean(error),
1958
+ "aria-describedby": errorId,
1959
+ intent: error ? "danger" : "neutral",
1960
+ children: [
1961
+ /* @__PURE__ */ jsx21("option", { value: "", children: "\u2014" }),
1962
+ (_a = field.options) == null ? void 0 : _a.map((opt) => /* @__PURE__ */ jsx21("option", { value: opt.value, children: opt.label }, opt.value))
1963
+ ]
1964
+ }
1965
+ ),
1966
+ /* @__PURE__ */ jsx21(
1967
+ Button_default2,
1968
+ {
1969
+ intent: "primary",
1970
+ variant: "solid",
1971
+ type: "button",
1972
+ onClick: addTag,
1973
+ className: "px-3 py-2",
1974
+ children: "+"
1975
+ }
1976
+ )
1977
+ ] }),
1978
+ /* @__PURE__ */ jsx21("div", { className: "flex flex-wrap gap-2 mt-1", children: tags.map((tag) => {
1979
+ var _a2, _b, _c;
1980
+ return /* @__PURE__ */ jsx21(
1981
+ Tag_default,
1982
+ {
1983
+ intent: "primary",
1984
+ variant: "soft",
1985
+ onRemove: () => removeTag(tag),
1986
+ children: (_c = (_b = (_a2 = field.options) == null ? void 0 : _a2.find((option) => String(option.value) === tag)) == null ? void 0 : _b.label) != null ? _c : tag
1987
+ },
1988
+ tag
1989
+ );
1990
+ }) })
1991
+ ] });
1992
+ };
1993
+ var TagsField_default = TagsField;
1994
+
1995
+ // src/components/shared/patterns/forms/FormField/fields/TagsField/index.tsx
1996
+ var TagsField_default2 = TagsField_default;
1997
+
1998
+ // src/components/shared/primitives/data-entry/Textarea/Textarea.tsx
1999
+ import { forwardRef as forwardRef5 } from "react";
2000
+ import { jsx as jsx22 } from "react/jsx-runtime";
2001
+ var SIZE_CLASSES6 = {
2002
+ xs: "px-2 py-1 text-xs",
2003
+ sm: "px-3 py-1.5 text-sm",
2004
+ md: "px-3 py-2 text-sm",
2005
+ lg: "px-4 py-2.5 text-base"
2006
+ };
2007
+ var INTENT_CLASSES4 = {
2008
+ primary: "focus-visible:border-primary",
2009
+ secondary: "focus-visible:border-secondary",
2010
+ success: "focus-visible:border-success",
2011
+ warning: "focus-visible:border-warning",
2012
+ danger: "focus-visible:border-danger",
2013
+ info: "focus-visible:border-info",
2014
+ neutral: "focus-visible:border-primary"
2015
+ };
2016
+ var Textarea = forwardRef5(
2017
+ (_a, ref) => {
2018
+ var _b = _a, { className, intent = "neutral", size = "md" } = _b, props = __objRest(_b, ["className", "intent", "size"]);
2019
+ const isInvalid = props["aria-invalid"] === true || props["aria-invalid"] === "true";
2020
+ return /* @__PURE__ */ jsx22(
2021
+ "textarea",
2022
+ __spreadValues({
2023
+ ref,
2024
+ className: cx(
2025
+ "w-full rounded-md border bg-background text-foreground outline-none transition-colors focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 disabled:cursor-not-allowed",
2026
+ SIZE_CLASSES6[size],
2027
+ isInvalid ? "border-danger focus-visible:border-danger" : "border-border-strong",
2028
+ !isInvalid && INTENT_CLASSES4[intent],
2029
+ className
2030
+ )
2031
+ }, props)
2032
+ );
2033
+ }
2034
+ );
2035
+ Textarea.displayName = "Textarea";
2036
+ var Textarea_default = Textarea;
2037
+
2038
+ // src/components/shared/patterns/forms/FormField/fields/TextAreaField/TextAreaField.tsx
2039
+ import { jsx as jsx23 } from "react/jsx-runtime";
2040
+ var TextareaField = ({
2041
+ field,
2042
+ value,
2043
+ error,
2044
+ errorId,
2045
+ onChange
2046
+ }) => {
2047
+ return /* @__PURE__ */ jsx23(
2048
+ Textarea_default,
2049
+ {
2050
+ id: field.name,
2051
+ name: field.name,
2052
+ value: getSafeValue(value),
2053
+ placeholder: field.placeholder,
2054
+ rows: 3,
2055
+ onChange,
2056
+ "aria-invalid": Boolean(error),
2057
+ "aria-describedby": errorId,
2058
+ intent: error ? "danger" : "neutral",
2059
+ className: "mt-1"
2060
+ }
2061
+ );
2062
+ };
2063
+ var TextAreaField_default = TextareaField;
2064
+
2065
+ // src/components/shared/patterns/forms/FormField/fields/TextAreaField/index.tsx
2066
+ var TextAreaField_default2 = TextAreaField_default;
2067
+
2068
+ // src/components/shared/patterns/forms/FormField/fields/TextField/TextField.tsx
2069
+ import { jsx as jsx24 } from "react/jsx-runtime";
2070
+ var TextField = ({
2071
+ field,
2072
+ value,
2073
+ error,
2074
+ errorId,
2075
+ onChange
2076
+ }) => {
2077
+ return /* @__PURE__ */ jsx24(
2078
+ Input_default,
2079
+ {
2080
+ id: field.name,
2081
+ type: field.type === "number" /* NUMBER */ ? "number" : "text",
2082
+ name: field.name,
2083
+ value: getSafeValue(value),
2084
+ placeholder: field.placeholder,
2085
+ required: field.required,
2086
+ pattern: field.pattern,
2087
+ onChange,
2088
+ "aria-invalid": Boolean(error),
2089
+ "aria-describedby": errorId,
2090
+ intent: error ? "danger" : "neutral",
2091
+ className: "mt-1"
2092
+ }
2093
+ );
2094
+ };
2095
+ var TextField_default = TextField;
2096
+
2097
+ // src/components/shared/patterns/forms/FormField/fields/TextField/index.tsx
2098
+ var TextField_default2 = TextField_default;
2099
+ export {
2100
+ CheckboxField_default2 as CheckboxField,
2101
+ CheckboxSearchField_default2 as CheckboxSearchField,
2102
+ ColorField_default2 as ColorField,
2103
+ ComboboxField_default as ComboboxField,
2104
+ DatePickerField_default2 as DatePickerField,
2105
+ FileUploadField_default as FileUploadField,
2106
+ SelectField_default2 as SelectField,
2107
+ SliderField_default as SliderField,
2108
+ SwitchField_default2 as SwitchField,
2109
+ TagsField_default2 as TagField,
2110
+ TagsField_default2 as TagsField,
2111
+ TextAreaField_default2 as TextAreaField,
2112
+ TextField_default2 as TextField
2113
+ };