@bizapps/design-system-testing 1.0.11 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.cjs CHANGED
@@ -8,13 +8,15 @@ var tailwindMerge = require('tailwind-merge');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
9
  var react = require('react');
10
10
  var radixUi = require('radix-ui');
11
- var reactDayPicker = require('react-day-picker');
12
11
  var dateFns = require('date-fns');
13
12
  var useEmblaCarousel = require('embla-carousel-react');
14
- var react$1 = require('motion/react');
13
+ var libphonenumberJs = require('libphonenumber-js');
15
14
  var cmdk = require('cmdk');
15
+ var countryFlags = require('country-flag-icons/react/3x2');
16
+ var react$1 = require('motion/react');
16
17
  var reactDropzone = require('react-dropzone');
17
18
  var Color = require('color');
19
+ var reactDayPicker = require('react-day-picker');
18
20
  var react$2 = require('@schedule-x/react');
19
21
  var calendar = require('@schedule-x/calendar');
20
22
  var eventsService = require('@schedule-x/events-service');
@@ -28,7 +30,26 @@ var reactTable = require('@tanstack/react-table');
28
30
 
29
31
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
30
32
 
33
+ function _interopNamespace(e) {
34
+ if (e && e.__esModule) return e;
35
+ var n = Object.create(null);
36
+ if (e) {
37
+ Object.keys(e).forEach(function (k) {
38
+ if (k !== 'default') {
39
+ var d = Object.getOwnPropertyDescriptor(e, k);
40
+ Object.defineProperty(n, k, d.get ? d : {
41
+ enumerable: true,
42
+ get: function () { return e[k]; }
43
+ });
44
+ }
45
+ });
46
+ }
47
+ n.default = e;
48
+ return Object.freeze(n);
49
+ }
50
+
31
51
  var useEmblaCarousel__default = /*#__PURE__*/_interopDefault(useEmblaCarousel);
52
+ var countryFlags__namespace = /*#__PURE__*/_interopNamespace(countryFlags);
32
53
  var Color__default = /*#__PURE__*/_interopDefault(Color);
33
54
 
34
55
  // src/components/ui/Alert/alert.tsx
@@ -457,174 +478,6 @@ function Button({
457
478
  }
458
479
  );
459
480
  }
460
- function Calendar({
461
- className,
462
- classNames,
463
- showOutsideDays = true,
464
- captionLayout = "dropdown",
465
- buttonVariant = "ghost",
466
- locale,
467
- formatters,
468
- components,
469
- fromYear,
470
- toYear,
471
- ...props
472
- }) {
473
- const defaultClassNames = reactDayPicker.getDefaultClassNames();
474
- return /* @__PURE__ */ jsxRuntime.jsx(
475
- reactDayPicker.DayPicker,
476
- {
477
- showOutsideDays,
478
- className: cn(
479
- "group/calendar bg-background p-3 font-sans [--cell-radius:var(--radius-md)] [--cell-size:--spacing(7)] in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent",
480
- String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
481
- String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
482
- className
483
- ),
484
- captionLayout,
485
- startMonth: new Date(fromYear ?? 1900, 0),
486
- endMonth: new Date(toYear ?? 2100, 11),
487
- locale,
488
- formatters: {
489
- formatMonthDropdown: (date) => date.toLocaleString(locale?.code, { month: "short" }),
490
- ...formatters
491
- },
492
- classNames: {
493
- root: cn("w-fit", defaultClassNames.root),
494
- months: cn("relative flex flex-col gap-3 md:flex-row", defaultClassNames.months),
495
- month: cn("flex w-full flex-col gap-3", defaultClassNames.month),
496
- nav: cn(
497
- "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-2",
498
- defaultClassNames.nav
499
- ),
500
- button_previous: cn(
501
- buttonVariants({ variant: buttonVariant }),
502
- "size-7 p-0 select-none opacity-50 aria-disabled:opacity-30 transition-opacity duration-150 hover:opacity-100",
503
- defaultClassNames.button_previous
504
- ),
505
- button_next: cn(
506
- buttonVariants({ variant: buttonVariant }),
507
- "size-7 p-0 select-none opacity-50 aria-disabled:opacity-30 transition-opacity duration-150 hover:opacity-100",
508
- defaultClassNames.button_next
509
- ),
510
- month_caption: cn(
511
- "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size) tracking-tight",
512
- defaultClassNames.month_caption
513
- ),
514
- dropdowns: cn(
515
- "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-semibold",
516
- defaultClassNames.dropdowns
517
- ),
518
- dropdown_root: cn(
519
- "relative rounded-(--cell-radius)",
520
- defaultClassNames.dropdown_root
521
- ),
522
- dropdown: cn("absolute inset-0 bg-popover opacity-0", defaultClassNames.dropdown),
523
- caption_label: cn(
524
- "font-semibold select-none",
525
- captionLayout === "label" ? "text-sm" : "flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
526
- defaultClassNames.caption_label
527
- ),
528
- weekdays: cn("flex gap-1", defaultClassNames.weekdays),
529
- weekday: cn(
530
- "flex-1 rounded-(--cell-radius) text-[0.75rem] font-semibold text-muted-foreground/70 select-none tracking-wide",
531
- defaultClassNames.weekday
532
- ),
533
- week: cn("mt-2 flex w-full gap-1", defaultClassNames.week),
534
- week_number_header: cn(
535
- "w-(--cell-size) select-none",
536
- defaultClassNames.week_number_header
537
- ),
538
- week_number: cn(
539
- "text-[0.75rem] text-muted-foreground/50 select-none",
540
- defaultClassNames.week_number
541
- ),
542
- day: cn(
543
- "group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)",
544
- props.showWeekNumber ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)" : "[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)",
545
- defaultClassNames.day
546
- ),
547
- range_start: cn(
548
- "relative isolate z-0 rounded-l-md bg-primary/8 after:absolute after:inset-y-0 after:right-0 after:w-3 after:bg-primary/8",
549
- defaultClassNames.range_start
550
- ),
551
- range_middle: cn("rounded-none bg-primary/8", defaultClassNames.range_middle),
552
- range_end: cn(
553
- "relative isolate z-0 rounded-r-md bg-primary/8 after:absolute after:inset-y-0 after:left-0 after:w-3 after:bg-primary/8",
554
- defaultClassNames.range_end
555
- ),
556
- today: cn("rounded-md bg-accent text-accent-foreground", defaultClassNames.today),
557
- outside: cn(
558
- "text-muted-foreground/50 aria-selected:text-muted-foreground/50",
559
- defaultClassNames.outside
560
- ),
561
- disabled: cn("text-muted-foreground/40 opacity-50", defaultClassNames.disabled),
562
- hidden: cn("invisible", defaultClassNames.hidden),
563
- ...classNames
564
- },
565
- components: {
566
- Root: ({ className: className2, rootRef, ...props2 }) => {
567
- return /* @__PURE__ */ jsxRuntime.jsx(
568
- "div",
569
- {
570
- "data-slot": "calendar",
571
- ref: rootRef,
572
- className: cn(className2),
573
- ...props2
574
- }
575
- );
576
- },
577
- Chevron: ({ className: className2, orientation, ...props2 }) => {
578
- if (orientation === "left") {
579
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeftIcon, { className: cn("size-4", className2), ...props2 });
580
- }
581
- if (orientation === "right") {
582
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, { className: cn("size-4", className2), ...props2 });
583
- }
584
- return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: cn("size-4", className2), ...props2 });
585
- },
586
- DayButton: ({ ...props2 }) => /* @__PURE__ */ jsxRuntime.jsx(CalendarDayButton, { locale, ...props2 }),
587
- WeekNumber: ({ children, ...props2 }) => {
588
- return /* @__PURE__ */ jsxRuntime.jsx("td", { ...props2, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-(--cell-size) items-center justify-center text-center", children }) });
589
- },
590
- ...components
591
- },
592
- ...props
593
- }
594
- );
595
- }
596
- function CalendarDayButton({
597
- className,
598
- day,
599
- modifiers,
600
- locale,
601
- ...props
602
- }) {
603
- const defaultClassNames = reactDayPicker.getDefaultClassNames();
604
- const ref = react.useRef(null);
605
- react.useEffect(() => {
606
- if (modifiers.focused) ref.current?.focus();
607
- }, [modifiers.focused]);
608
- return /* @__PURE__ */ jsxRuntime.jsx(
609
- Button,
610
- {
611
- ref,
612
- variant: "ghost",
613
- size: "icon-sm",
614
- "data-day": day.date.toLocaleDateString(locale?.code),
615
- "data-selected-single": modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle,
616
- "data-range-start": modifiers.range_start,
617
- "data-range-end": modifiers.range_end,
618
- "data-range-middle": modifiers.range_middle,
619
- className: cn(
620
- "group-data-[focused=true]/day:ring-primary/40 data-[range-end=true]:!bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:!bg-primary/8 data-[range-middle=true]:text-foreground data-[range-start=true]:!bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:!bg-primary data-[selected-single=true]:text-primary-foreground relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 !rounded-md border-0 !bg-transparent leading-none font-normal transition-colors duration-150 group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:rounded-md group-data-[focused=true]/day:ring-[2px] hover:!bg-transparent data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[selected-single=true]:rounded-md [&>span]:text-xs [&>span]:font-medium [&>span]:opacity-75",
621
- defaultClassNames.day,
622
- className
623
- ),
624
- ...props
625
- }
626
- );
627
- }
628
481
  function useControllableState({
629
482
  prop,
630
483
  defaultProp,
@@ -1110,6 +963,22 @@ function Input({ className, type, ...props }) {
1110
963
  }
1111
964
  );
1112
965
  }
966
+ function Label({ className, ...props }) {
967
+ return /* @__PURE__ */ jsxRuntime.jsx(
968
+ radixUi.Label.Root,
969
+ {
970
+ "data-slot": "label",
971
+ className: cn(
972
+ "text-foreground text-sm leading-6 font-medium transition-colors select-none",
973
+ "group-has-disabled/field:cursor-not-allowed group-has-disabled/field:opacity-50",
974
+ "peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
975
+ "aria-invalid:text-destructive dark:aria-invalid:text-destructive/90",
976
+ className
977
+ ),
978
+ ...props
979
+ }
980
+ );
981
+ }
1113
982
 
1114
983
  // src/utils/urlSecurity.ts
1115
984
  var SAFE_HREF_PROTOCOLS = /* @__PURE__ */ new Set(["https:", "http:", "mailto:", "tel:"]);
@@ -1191,15 +1060,412 @@ function Link({
1191
1060
  truncate ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 overflow-hidden text-ellipsis whitespace-nowrap", children }) : children,
1192
1061
  isExternal && !disabled && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1193
1062
  /* @__PURE__ */ jsxRuntime.jsx(
1194
- lucideReact.ExternalLinkIcon,
1063
+ lucideReact.ExternalLinkIcon,
1064
+ {
1065
+ "aria-hidden": "true",
1066
+ size: externalIconSize,
1067
+ className: "shrink-0"
1068
+ }
1069
+ ),
1070
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "(opens in new tab)" })
1071
+ ] })
1072
+ ]
1073
+ }
1074
+ );
1075
+ }
1076
+ function validatePhone(value) {
1077
+ if (!value) {
1078
+ return { isValid: false };
1079
+ }
1080
+ if (libphonenumberJs.isValidPhoneNumber(value)) {
1081
+ return { isValid: true };
1082
+ }
1083
+ return { isValid: false, problem: libphonenumberJs.validatePhoneNumberLength(value) ?? "INVALID" };
1084
+ }
1085
+ function Popover({ ...props }) {
1086
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Popover.Root, { "data-slot": "popover", ...props });
1087
+ }
1088
+ function PopoverTrigger({ ...props }) {
1089
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
1090
+ }
1091
+ function PopoverContent({
1092
+ className,
1093
+ align = "center",
1094
+ sideOffset = 4,
1095
+ container,
1096
+ ...props
1097
+ }) {
1098
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Popover.Portal, { container, children: /* @__PURE__ */ jsxRuntime.jsx(
1099
+ radixUi.Popover.Content,
1100
+ {
1101
+ "data-slot": "popover-content",
1102
+ align,
1103
+ sideOffset,
1104
+ className: cn(
1105
+ "bg-popover text-popover-foreground ring-foreground/5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 z-50 flex w-72 origin-(--radix-popover-content-transform-origin) flex-col gap-1 rounded-3xl p-4 text-sm shadow-lg ring-1 outline-hidden duration-100",
1106
+ className
1107
+ ),
1108
+ ...props
1109
+ }
1110
+ ) });
1111
+ }
1112
+ function PopoverAnchor({ ...props }) {
1113
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Popover.Anchor, { "data-slot": "popover-anchor", ...props });
1114
+ }
1115
+ function PopoverHeader({ className, ...props }) {
1116
+ return /* @__PURE__ */ jsxRuntime.jsx(
1117
+ "div",
1118
+ {
1119
+ "data-slot": "popover-header",
1120
+ className: cn("flex flex-col gap-1 text-sm", className),
1121
+ ...props
1122
+ }
1123
+ );
1124
+ }
1125
+ function PopoverTitle({ className, ...props }) {
1126
+ return /* @__PURE__ */ jsxRuntime.jsx(
1127
+ "div",
1128
+ {
1129
+ "data-slot": "popover-title",
1130
+ className: cn("text-base font-medium", className),
1131
+ ...props
1132
+ }
1133
+ );
1134
+ }
1135
+ function PopoverDescription({ className, ...props }) {
1136
+ return /* @__PURE__ */ jsxRuntime.jsx(
1137
+ "p",
1138
+ {
1139
+ "data-slot": "popover-description",
1140
+ className: cn("text-muted-foreground", className),
1141
+ ...props
1142
+ }
1143
+ );
1144
+ }
1145
+ function stripLeadingDialCode(raw, dialCode) {
1146
+ if (!raw.startsWith("+")) {
1147
+ return raw.replace(/\D/g, "");
1148
+ }
1149
+ const parsed = libphonenumberJs.parsePhoneNumberFromString(raw);
1150
+ if (parsed) {
1151
+ return parsed.nationalNumber;
1152
+ }
1153
+ const digits = raw.replace(/\D/g, "");
1154
+ const code = dialCode.replace(/\D/g, "");
1155
+ return code && digits.startsWith(code) ? digits.length > code.length ? digits.slice(code.length) : "" : digits;
1156
+ }
1157
+ var flagByCode = countryFlags__namespace;
1158
+ function CountryFlag({
1159
+ code,
1160
+ flagUrl,
1161
+ className
1162
+ }) {
1163
+ const isoCode = (code || "").toUpperCase();
1164
+ const FlagComponent = flagByCode[isoCode];
1165
+ const flag = flagUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: flagUrl, alt: "", "aria-hidden": "true", className: "size-full object-cover" }) : FlagComponent ? /* @__PURE__ */ jsxRuntime.jsx(FlagComponent, { "aria-hidden": "true", className: "size-full" }) : null;
1166
+ return /* @__PURE__ */ jsxRuntime.jsx(
1167
+ "span",
1168
+ {
1169
+ "data-slot": "phone-field-country-flag",
1170
+ "data-country": isoCode || void 0,
1171
+ "data-fallback": flag ? void 0 : "true",
1172
+ "aria-hidden": "true",
1173
+ className: cn(
1174
+ "size-4 shrink-0 overflow-hidden rounded-[2px]",
1175
+ !flag && "bg-muted rounded-full",
1176
+ className
1177
+ ),
1178
+ children: flag
1179
+ }
1180
+ );
1181
+ }
1182
+ function PhoneField({
1183
+ countries,
1184
+ value,
1185
+ onValueChange,
1186
+ onValidityChange,
1187
+ defaultCountry,
1188
+ placeholder = "Phone number",
1189
+ disabled = false,
1190
+ className,
1191
+ container,
1192
+ name,
1193
+ ...inputProps
1194
+ }) {
1195
+ const [open, setOpen] = react.useState(false);
1196
+ const [pickedCode, setPickedCode] = react.useState(
1197
+ (defaultCountry ?? countries[0]?.code)?.toUpperCase()
1198
+ );
1199
+ const [internalValue, setInternalValue] = react.useState("");
1200
+ const listRef = react.useRef(null);
1201
+ const inputRef = react.useRef(null);
1202
+ const caretRef = react.useRef(null);
1203
+ const lastValidityRef = react.useRef(null);
1204
+ const listId = `${react.useId()}-countries-list`;
1205
+ const isControlled = value !== void 0;
1206
+ const currentValue = isControlled ? value : internalValue;
1207
+ const parsed = currentValue ? libphonenumberJs.parsePhoneNumberFromString(currentValue) : void 0;
1208
+ const parsedCountry = parsed?.country;
1209
+ const parsedCallingCode = parsed?.countryCallingCode;
1210
+ const countryInList = parsedCountry !== void 0 && countries.some((country) => country.code.toUpperCase() === parsedCountry);
1211
+ const callingCodeInList = parsedCallingCode !== void 0 && countries.some(
1212
+ (country) => country.dialCode.replace(/\D/g, "") === parsedCallingCode
1213
+ );
1214
+ const pickedCountry = pickedCode ? countries.find((country) => country.code.toUpperCase() === pickedCode.toUpperCase()) : void 0;
1215
+ const pickMatchesValue = pickedCountry !== void 0 && pickedCountry.dialCode.replace(/\D/g, "") === parsedCallingCode;
1216
+ const representedCode = countryInList ? parsedCountry : pickMatchesValue ? pickedCountry.code : callingCodeInList ? countries.find(
1217
+ (country) => country.dialCode.replace(/\D/g, "") === parsedCallingCode
1218
+ )?.code : void 0;
1219
+ const selectedCode = representedCode ?? pickedCode ?? defaultCountry ?? countries[0]?.code;
1220
+ const selectedCountry = countries.find(
1221
+ (country) => country.code.toUpperCase() === selectedCode?.toUpperCase()
1222
+ ) ?? countries[0];
1223
+ const dialCode = selectedCountry ? selectedCountry.dialCode.replace(/\D/g, "") : "";
1224
+ const emitDialCode = parsedCallingCode ?? dialCode;
1225
+ const nationalDigits = parsed ? parsed.nationalNumber : currentValue ? stripLeadingDialCode(currentValue, dialCode) : "";
1226
+ const canFormat = selectedCountry !== void 0 && (!parsed || countryInList || callingCodeInList);
1227
+ const inputValue = selectedCountry && canFormat && nationalDigits ? new libphonenumberJs.AsYouType((selectedCountry.code || "").toUpperCase()).input(
1228
+ nationalDigits
1229
+ ) : nationalDigits;
1230
+ const isInvalid = inputProps["aria-invalid"] === true || inputProps["aria-invalid"] === "true";
1231
+ const { isValid, problem } = validatePhone(currentValue);
1232
+ react.useEffect(() => {
1233
+ const last = lastValidityRef.current;
1234
+ if (last && last.isValid === isValid && last.problem === problem) {
1235
+ return;
1236
+ }
1237
+ lastValidityRef.current = { isValid, problem };
1238
+ onValidityChange?.({ isValid, problem });
1239
+ }, [isValid, problem, onValidityChange]);
1240
+ react.useLayoutEffect(() => {
1241
+ const input = inputRef.current;
1242
+ const caret = caretRef.current;
1243
+ if (!input || !caret || document.activeElement !== input) {
1244
+ return;
1245
+ }
1246
+ const digitsBefore = caret.raw.slice(0, caret.start).replace(/\D/g, "").length;
1247
+ let position = 0;
1248
+ if (digitsBefore > 0) {
1249
+ let digitsSeen = 0;
1250
+ for (let i = 0; i < inputValue.length; i++) {
1251
+ if (/\d/.test(inputValue[i])) {
1252
+ digitsSeen += 1;
1253
+ }
1254
+ position = i + 1;
1255
+ if (digitsSeen >= digitsBefore) {
1256
+ break;
1257
+ }
1258
+ }
1259
+ }
1260
+ input.setSelectionRange(position, position + (caret.end - caret.start));
1261
+ caretRef.current = null;
1262
+ }, [inputValue]);
1263
+ const handleSearchChange = () => {
1264
+ requestAnimationFrame(() => listRef.current?.scrollTo({ top: 0 }));
1265
+ };
1266
+ function handleCountrySelect(code) {
1267
+ setPickedCode(code);
1268
+ setOpen(false);
1269
+ const nextCountry = countries.find(
1270
+ (country) => country.code.toUpperCase() === code.toUpperCase()
1271
+ );
1272
+ if (nextCountry && nationalDigits) {
1273
+ const next = `+${nextCountry.dialCode.replace(/\D/g, "")}${nationalDigits}`;
1274
+ onValueChange?.(next);
1275
+ if (!isControlled) {
1276
+ setInternalValue(next);
1277
+ }
1278
+ }
1279
+ }
1280
+ function deriveFromE164(e164) {
1281
+ const parsed2 = libphonenumberJs.parsePhoneNumberFromString(e164);
1282
+ if (!parsed2?.nationalNumber) {
1283
+ return void 0;
1284
+ }
1285
+ const countryMatch = parsed2.country ? countries.find((country) => country.code.toUpperCase() === parsed2.country) : void 0;
1286
+ const nextPickedCode = countryMatch ? countryMatch.code : parsed2.countryCallingCode ? countries.find(
1287
+ (country) => country.dialCode.replace(/\D/g, "") === parsed2.countryCallingCode
1288
+ )?.code : void 0;
1289
+ return {
1290
+ nationalNumber: parsed2.nationalNumber,
1291
+ emitCode: parsed2.countryCallingCode,
1292
+ nextPickedCode
1293
+ };
1294
+ }
1295
+ function handleInputChange(raw, nativeEvent) {
1296
+ const input = inputRef.current;
1297
+ if (input) {
1298
+ caretRef.current = {
1299
+ raw,
1300
+ start: input.selectionStart ?? raw.length,
1301
+ end: input.selectionEnd ?? raw.length
1302
+ };
1303
+ }
1304
+ if (!selectedCountry) return;
1305
+ let national = stripLeadingDialCode(raw, dialCode);
1306
+ let emitCode = emitDialCode;
1307
+ let nextPickedCode;
1308
+ const plusIndex = raw.indexOf("+");
1309
+ if (plusIndex === 0) {
1310
+ const derived = deriveFromE164(raw);
1311
+ if (derived) {
1312
+ emitCode = derived.emitCode || emitDialCode;
1313
+ nextPickedCode = derived.nextPickedCode;
1314
+ } else if (nativeEvent?.inputType === "insertFromPaste") {
1315
+ national = "";
1316
+ }
1317
+ } else if (plusIndex > 0) {
1318
+ const pasted = nativeEvent?.inputType === "insertFromPaste" && nativeEvent.data?.startsWith("+") ? nativeEvent.data : void 0;
1319
+ if (pasted) {
1320
+ const derived = deriveFromE164(pasted);
1321
+ const prefixDigits = raw.slice(0, plusIndex).replace(/\D/g, "");
1322
+ const suffixDigits = raw.slice(plusIndex + pasted.length).replace(/\D/g, "");
1323
+ if (derived) {
1324
+ national = prefixDigits + derived.nationalNumber + suffixDigits;
1325
+ emitCode = derived.emitCode || emitDialCode;
1326
+ nextPickedCode = derived.nextPickedCode;
1327
+ } else {
1328
+ national = prefixDigits + suffixDigits;
1329
+ }
1330
+ }
1331
+ }
1332
+ const next = national ? `+${emitCode}${national}` : "";
1333
+ const grew = national.replace(/\D/g, "").length > nationalDigits.length;
1334
+ const isPaste = nativeEvent?.inputType === "insertFromPaste";
1335
+ if (grew && !isPaste && libphonenumberJs.validatePhoneNumberLength(next) === "TOO_LONG") {
1336
+ if (input) {
1337
+ const caret = Math.max(0, (input.selectionStart ?? inputValue.length) - 1);
1338
+ input.value = inputValue;
1339
+ input.setSelectionRange(caret, caret);
1340
+ }
1341
+ caretRef.current = null;
1342
+ return;
1343
+ }
1344
+ if (nextPickedCode) {
1345
+ setPickedCode(nextPickedCode);
1346
+ }
1347
+ onValueChange?.(next);
1348
+ if (!isControlled) {
1349
+ setInternalValue(next);
1350
+ }
1351
+ }
1352
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1353
+ "div",
1354
+ {
1355
+ "data-slot": "phone-field",
1356
+ "data-invalid": isInvalid || void 0,
1357
+ className: cn(
1358
+ "border-input flex h-9 w-full min-w-0 items-center overflow-hidden rounded-md border bg-transparent shadow-xs transition-[color,box-shadow]",
1359
+ "focus-within:border-ring focus-within:ring-ring/30 focus-within:ring-3",
1360
+ "data-[invalid=true]:border-destructive data-[invalid=true]:ring-destructive/20 data-[invalid=true]:ring-3",
1361
+ "dark:data-[invalid=true]:border-destructive/50 dark:data-[invalid=true]:ring-destructive/40",
1362
+ className
1363
+ ),
1364
+ children: [
1365
+ /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
1366
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
1367
+ "button",
1368
+ {
1369
+ type: "button",
1370
+ "data-slot": "phone-field-country-select",
1371
+ disabled,
1372
+ "aria-expanded": open,
1373
+ "aria-haspopup": "listbox",
1374
+ "aria-controls": open ? listId : void 0,
1375
+ "aria-label": selectedCountry ? `${selectedCountry.name} ${selectedCountry.dialCode}` : void 0,
1376
+ className: cn(
1377
+ "flex h-full shrink-0 cursor-pointer items-center gap-1.5 border-r border-input px-2.5 text-sm font-medium outline-none select-none",
1378
+ "hover:bg-muted",
1379
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
1380
+ ),
1381
+ children: selectedCountry && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1382
+ /* @__PURE__ */ jsxRuntime.jsx(
1383
+ CountryFlag,
1384
+ {
1385
+ code: selectedCountry.code,
1386
+ flagUrl: selectedCountry.flagUrl
1387
+ }
1388
+ ),
1389
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: selectedCountry.dialCode }),
1390
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDownIcon, { size: 14, className: "text-muted-foreground shrink-0" })
1391
+ ] })
1392
+ }
1393
+ ) }),
1394
+ /* @__PURE__ */ jsxRuntime.jsx(
1395
+ PopoverContent,
1195
1396
  {
1196
- "aria-hidden": "true",
1197
- size: externalIconSize,
1198
- className: "shrink-0"
1397
+ className: "w-72 rounded-xl p-0",
1398
+ align: "start",
1399
+ container,
1400
+ children: /* @__PURE__ */ jsxRuntime.jsxs(cmdk.Command, { className: "rounded-xl", label: "Search countries", children: [
1401
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-border flex items-center gap-2 border-b px-3", children: [
1402
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SearchIcon, { size: 14, className: "text-muted-foreground shrink-0" }),
1403
+ /* @__PURE__ */ jsxRuntime.jsx(
1404
+ cmdk.Command.Input,
1405
+ {
1406
+ placeholder: "Search country...",
1407
+ onValueChange: handleSearchChange,
1408
+ className: "placeholder:text-muted-foreground flex h-9 w-full bg-transparent py-2 text-sm outline-none"
1409
+ }
1410
+ )
1411
+ ] }),
1412
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: listId, children: /* @__PURE__ */ jsxRuntime.jsxs(cmdk.Command.List, { ref: listRef, className: "max-h-56 overflow-y-auto p-1", children: [
1413
+ /* @__PURE__ */ jsxRuntime.jsx(cmdk.Command.Empty, { className: "text-muted-foreground py-4 text-center text-sm", children: "No country found." }),
1414
+ countries.map((country) => /* @__PURE__ */ jsxRuntime.jsxs(
1415
+ cmdk.Command.Item,
1416
+ {
1417
+ value: country.code,
1418
+ keywords: [country.name, country.dialCode],
1419
+ "data-slot": "phone-field-country-item",
1420
+ onSelect: () => handleCountrySelect(country.code),
1421
+ className: cn(
1422
+ "flex cursor-pointer items-center justify-between gap-2 rounded-md px-2 py-1.5 text-sm outline-none select-none",
1423
+ "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground",
1424
+ "hover:bg-accent hover:text-accent-foreground"
1425
+ ),
1426
+ children: [
1427
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [
1428
+ /* @__PURE__ */ jsxRuntime.jsx(CountryFlag, { code: country.code, flagUrl: country.flagUrl }),
1429
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: country.name })
1430
+ ] }),
1431
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
1432
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground tabular-nums", children: country.dialCode }),
1433
+ selectedCode?.toUpperCase() === country.code.toUpperCase() && /* @__PURE__ */ jsxRuntime.jsx(
1434
+ lucideReact.CheckIcon,
1435
+ {
1436
+ size: 14,
1437
+ className: "text-[var(--color-main-blue-primary)] shrink-0"
1438
+ }
1439
+ )
1440
+ ] })
1441
+ ]
1442
+ },
1443
+ country.code
1444
+ ))
1445
+ ] }) })
1446
+ ] })
1199
1447
  }
1200
- ),
1201
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "(opens in new tab)" })
1202
- ] })
1448
+ )
1449
+ ] }),
1450
+ /* @__PURE__ */ jsxRuntime.jsx(
1451
+ Input,
1452
+ {
1453
+ ref: inputRef,
1454
+ ...inputProps,
1455
+ "data-slot": "phone-field-input",
1456
+ type: "tel",
1457
+ value: inputValue,
1458
+ onChange: (event) => handleInputChange(event.target.value, event.nativeEvent),
1459
+ placeholder,
1460
+ disabled,
1461
+ autoComplete: inputProps.autoComplete ?? "tel",
1462
+ className: cn(
1463
+ "h-full flex-1 rounded-none border-0 bg-transparent shadow-none",
1464
+ "px-3 focus-visible:border-transparent focus-visible:ring-0"
1465
+ )
1466
+ }
1467
+ ),
1468
+ name !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: currentValue, "data-slot": "phone-field-hidden-input" })
1203
1469
  ]
1204
1470
  }
1205
1471
  );
@@ -1434,31 +1700,37 @@ function SelectContent({
1434
1700
  className,
1435
1701
  children,
1436
1702
  position = "popper",
1703
+ maxHeight,
1704
+ style,
1437
1705
  ...props
1438
1706
  }) {
1707
+ const resolvedMaxHeight = typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight;
1439
1708
  return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Select.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1440
1709
  radixUi.Select.Content,
1441
1710
  {
1442
1711
  "data-slot": "select-content",
1443
1712
  className: cn(
1444
- "border-border bg-popover text-popover-foreground relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
1713
+ "border-border bg-popover text-popover-foreground relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-hidden rounded-md border shadow-md",
1445
1714
  "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
1446
1715
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
1447
1716
  "data-[side=bottom]:translate-y-1 data-[side=top]:-translate-y-1",
1448
- position === "popper" && "w-[--radix-select-trigger-width]",
1717
+ position === "popper" && "w-(--radix-select-trigger-width)",
1449
1718
  className
1450
1719
  ),
1451
1720
  position,
1721
+ style: {
1722
+ ...resolvedMaxHeight ? {
1723
+ maxHeight: `min(${resolvedMaxHeight}, var(--radix-select-content-available-height))`
1724
+ } : null,
1725
+ ...style
1726
+ },
1452
1727
  ...props,
1453
1728
  children: [
1454
1729
  /* @__PURE__ */ jsxRuntime.jsx(SelectScrollUpButton, {}),
1455
1730
  /* @__PURE__ */ jsxRuntime.jsx(
1456
1731
  radixUi.Select.Viewport,
1457
1732
  {
1458
- className: cn(
1459
- "p-1",
1460
- position === "popper" && "h-[--radix-select-trigger-height]"
1461
- ),
1733
+ className: cn("scroll-my-1 p-1", position === "popper" && "w-full"),
1462
1734
  children
1463
1735
  }
1464
1736
  ),
@@ -1585,7 +1857,7 @@ var progressVariants = classVarianceAuthority.cva("relative flex w-full items-ce
1585
1857
  size: "md"
1586
1858
  }
1587
1859
  });
1588
- var progressIndicatorVariants = classVarianceAuthority.cva("size-full flex-1 transition-all", {
1860
+ var progressIndicatorVariants = classVarianceAuthority.cva("size-full flex-1 transition-all rounded-[5px]", {
1589
1861
  variants: {
1590
1862
  variant: {
1591
1863
  default: "bg-[var(--color-main-blue-primary)]",
@@ -1750,7 +2022,8 @@ var ease = {
1750
2022
  smooth: [0.4, 0, 0.2, 1],
1751
2023
  enter: [0, 0, 0.2, 1],
1752
2024
  exit: [0.4, 0, 1, 1],
1753
- linear: [0, 0, 1, 1]
2025
+ linear: [0, 0, 1, 1],
2026
+ drawer: [0.22, 1, 0.36, 1]
1754
2027
  };
1755
2028
  var spring = {
1756
2029
  gentle: { type: "spring", stiffness: 260, damping: 28 },
@@ -1794,6 +2067,15 @@ var transition = {
1794
2067
  card: {
1795
2068
  duration: duration.fast,
1796
2069
  ease: ease.smooth
2070
+ },
2071
+ // Drawer / slide panel — smooth enter, fast exit
2072
+ drawer: {
2073
+ duration: 0.3,
2074
+ ease: ease.drawer
2075
+ },
2076
+ drawerExit: {
2077
+ duration: 0.2,
2078
+ ease: ease.exit
1797
2079
  }
1798
2080
  };
1799
2081
  var fadeIn = {
@@ -2258,65 +2540,6 @@ function TooltipContent({
2258
2540
  }
2259
2541
  ) });
2260
2542
  }
2261
- function Popover({ ...props }) {
2262
- return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Popover.Root, { "data-slot": "popover", ...props });
2263
- }
2264
- function PopoverTrigger({ ...props }) {
2265
- return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Popover.Trigger, { "data-slot": "popover-trigger", ...props });
2266
- }
2267
- function PopoverContent({
2268
- className,
2269
- align = "center",
2270
- sideOffset = 4,
2271
- ...props
2272
- }) {
2273
- return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Popover.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
2274
- radixUi.Popover.Content,
2275
- {
2276
- "data-slot": "popover-content",
2277
- align,
2278
- sideOffset,
2279
- className: cn(
2280
- "bg-popover text-popover-foreground ring-foreground/5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 z-50 flex w-72 origin-(--radix-popover-content-transform-origin) flex-col gap-1 rounded-3xl p-4 text-sm shadow-lg ring-1 outline-hidden duration-100",
2281
- className
2282
- ),
2283
- ...props
2284
- }
2285
- ) });
2286
- }
2287
- function PopoverAnchor({ ...props }) {
2288
- return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Popover.Anchor, { "data-slot": "popover-anchor", ...props });
2289
- }
2290
- function PopoverHeader({ className, ...props }) {
2291
- return /* @__PURE__ */ jsxRuntime.jsx(
2292
- "div",
2293
- {
2294
- "data-slot": "popover-header",
2295
- className: cn("flex flex-col gap-1 text-sm", className),
2296
- ...props
2297
- }
2298
- );
2299
- }
2300
- function PopoverTitle({ className, ...props }) {
2301
- return /* @__PURE__ */ jsxRuntime.jsx(
2302
- "div",
2303
- {
2304
- "data-slot": "popover-title",
2305
- className: cn("text-base font-medium", className),
2306
- ...props
2307
- }
2308
- );
2309
- }
2310
- function PopoverDescription({ className, ...props }) {
2311
- return /* @__PURE__ */ jsxRuntime.jsx(
2312
- "p",
2313
- {
2314
- "data-slot": "popover-description",
2315
- className: cn("text-muted-foreground", className),
2316
- ...props
2317
- }
2318
- );
2319
- }
2320
2543
  var TEXT_SIZES = [12, 14, 16, 18, 20, 24, 28, 32, 40, 48];
2321
2544
  var TEXT_WEIGHTS = [100, 200, 300, 400, 500, 700, 800, 900];
2322
2545
  function Text({
@@ -2371,7 +2594,7 @@ function DialogTrigger({ ...props }) {
2371
2594
  }
2372
2595
  function DialogPortal({ children, ...props }) {
2373
2596
  const isOpen = react.useContext(DialogContext);
2374
- return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Portal, { "data-slot": "dialog-portal", forceMount: true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(react$1.AnimatePresence, { mode: "wait", children: isOpen && children }) });
2597
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Portal, { "data-slot": "dialog-portal", forceMount: true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(react$1.AnimatePresence, { mode: "sync", children: isOpen && children }) });
2375
2598
  }
2376
2599
  function DialogClose({ ...props }) {
2377
2600
  return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Close, { "data-slot": "dialog-close", ...props });
@@ -2398,7 +2621,7 @@ function DialogContent({
2398
2621
  ...props
2399
2622
  }) {
2400
2623
  return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
2401
- /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
2624
+ /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}, "dialog-overlay"),
2402
2625
  /* @__PURE__ */ jsxRuntime.jsx(
2403
2626
  radixUi.Dialog.Content,
2404
2627
  {
@@ -2435,7 +2658,8 @@ function DialogContent({
2435
2658
  ]
2436
2659
  }
2437
2660
  )
2438
- }
2661
+ },
2662
+ "dialog-content"
2439
2663
  )
2440
2664
  ] });
2441
2665
  }
@@ -2538,7 +2762,7 @@ function AlertDialogPortal({
2538
2762
  ...props
2539
2763
  }) {
2540
2764
  const isOpen = react.useContext(AlertDialogContext);
2541
- return /* @__PURE__ */ jsxRuntime.jsx(radixUi.AlertDialog.Portal, { "data-slot": "alert-dialog-portal", forceMount: true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(react$1.AnimatePresence, { mode: "wait", children: isOpen && children }) });
2765
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.AlertDialog.Portal, { "data-slot": "alert-dialog-portal", forceMount: true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(react$1.AnimatePresence, { mode: "sync", children: isOpen && children }) });
2542
2766
  }
2543
2767
  function AlertDialogOverlay({
2544
2768
  className,
@@ -2580,7 +2804,8 @@ function AlertDialogContent({
2580
2804
  AlertDialogOverlay,
2581
2805
  {
2582
2806
  className: cn(variant === "dark-glass" && "bg-primary/60 backdrop-blur-md")
2583
- }
2807
+ },
2808
+ "alert-dialog-overlay"
2584
2809
  ),
2585
2810
  /* @__PURE__ */ jsxRuntime.jsx(
2586
2811
  radixUi.AlertDialog.Content,
@@ -2614,7 +2839,8 @@ function AlertDialogContent({
2614
2839
  ]
2615
2840
  }
2616
2841
  )
2617
- }
2842
+ },
2843
+ "alert-dialog-content"
2618
2844
  )
2619
2845
  ] });
2620
2846
  }
@@ -2775,6 +3001,17 @@ function AccordionContent({
2775
3001
  }
2776
3002
  );
2777
3003
  }
3004
+ function createMatchFilter(mode) {
3005
+ return (value, search, keywords = []) => {
3006
+ const query = search.toLowerCase().trim();
3007
+ if (!query) return 1;
3008
+ const haystacks = [value, ...keywords].map((s) => s.toLowerCase());
3009
+ const matched = mode === "substring" ? haystacks.some((h) => h.includes(query)) : haystacks.some(
3010
+ (h) => h.startsWith(query) || h.split(/\s+/).some((word) => word.startsWith(query))
3011
+ );
3012
+ return matched ? 1 : 0;
3013
+ };
3014
+ }
2778
3015
  function Combobox({
2779
3016
  options,
2780
3017
  value,
@@ -2783,10 +3020,17 @@ function Combobox({
2783
3020
  searchPlaceholder = "Search...",
2784
3021
  emptyMessage = "No results found.",
2785
3022
  disabled = false,
2786
- className
3023
+ className,
3024
+ container,
3025
+ matchMode = "fuzzy"
2787
3026
  }) {
2788
3027
  const [open, setOpen] = react.useState(false);
3028
+ const listRef = react.useRef(null);
2789
3029
  const selected = options.find((opt) => opt.value === value);
3030
+ const filter = matchMode === "fuzzy" ? void 0 : createMatchFilter(matchMode);
3031
+ const handleSearchChange = () => {
3032
+ requestAnimationFrame(() => listRef.current?.scrollTo({ top: 0 }));
3033
+ };
2790
3034
  return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
2791
3035
  /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
2792
3036
  Button,
@@ -2806,18 +3050,19 @@ function Combobox({
2806
3050
  ]
2807
3051
  }
2808
3052
  ) }),
2809
- /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-64 rounded-lg p-0", align: "start", children: /* @__PURE__ */ jsxRuntime.jsxs(cmdk.Command, { className: "rounded-lg", children: [
3053
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-64 rounded-lg p-0", align: "start", container, children: /* @__PURE__ */ jsxRuntime.jsxs(cmdk.Command, { className: "rounded-lg", filter, children: [
2810
3054
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-border flex items-center gap-2 border-b px-3", children: [
2811
3055
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SearchIcon, { size: 14, className: "text-muted-foreground shrink-0" }),
2812
3056
  /* @__PURE__ */ jsxRuntime.jsx(
2813
3057
  cmdk.Command.Input,
2814
3058
  {
2815
3059
  placeholder: searchPlaceholder,
3060
+ onValueChange: handleSearchChange,
2816
3061
  className: "placeholder:text-muted-foreground flex h-9 w-full bg-transparent py-2 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50"
2817
3062
  }
2818
3063
  )
2819
3064
  ] }),
2820
- /* @__PURE__ */ jsxRuntime.jsxs(cmdk.Command.List, { className: "max-h-56 overflow-y-auto p-1", children: [
3065
+ /* @__PURE__ */ jsxRuntime.jsxs(cmdk.Command.List, { ref: listRef, className: "max-h-56 overflow-y-auto p-1", children: [
2821
3066
  /* @__PURE__ */ jsxRuntime.jsx(cmdk.Command.Empty, { className: "text-muted-foreground py-4 text-center text-sm", children: emptyMessage }),
2822
3067
  options.map((option) => /* @__PURE__ */ jsxRuntime.jsxs(
2823
3068
  cmdk.Command.Item,
@@ -4082,92 +4327,325 @@ var ColorPickerFormat = ({ className, ...props }) => {
4082
4327
  "relative flex w-full items-center gap-1 -space-x-px rounded-md",
4083
4328
  className
4084
4329
  ),
4085
- ...props,
4086
- children: [
4087
- /* @__PURE__ */ jsxRuntime.jsx(
4088
- Input2,
4089
- {
4090
- className: "bg-muted h-8 w-[5rem] rounded-md px-2 text-xs",
4091
- readOnly: true,
4092
- type: "text",
4093
- value: displayHex
4094
- }
4095
- ),
4096
- /* @__PURE__ */ jsxRuntime.jsx(PercentageInput, { value: alpha, onChange: setAlpha })
4097
- ]
4098
- }
4099
- );
4100
- }
4101
- if (mode === "css") {
4102
- const rgb = color.rgb().array().map((value) => Math.round(value));
4103
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full rounded-md", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsx(
4104
- Input2,
4105
- {
4106
- className: "bg-muted h-8 w-full rounded-md px-2 text-xs shadow-none",
4107
- readOnly: true,
4108
- type: "text",
4109
- value: `rgba(${rgb.join(", ")}, ${alpha}%)`,
4110
- ...props
4111
- }
4112
- ) });
4113
- }
4114
- return null;
4115
- };
4116
- var ColorPickerPresets = ({ colors, className, ...props }) => {
4117
- const { hue, saturation, lightness, alpha, setHue, setSaturation, setLightness, setAlpha } = useColorPicker();
4118
- const currentHex = Color__default.default.hsl(hue, saturation, lightness, alpha / 100).hex();
4119
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-wrap gap-1.5", className), ...props, children: colors.map((hex) => {
4120
- const isActive = Color__default.default(hex).hex().toUpperCase() === currentHex.toUpperCase();
4121
- return /* @__PURE__ */ jsxRuntime.jsx(
4122
- "button",
4123
- {
4124
- type: "button",
4125
- className: cn(
4126
- "size-5 cursor-pointer rounded-[3px] border transition-all",
4127
- "hover:scale-110 hover:shadow-md",
4128
- isActive && "ring-ring ring-offset-background ring-2 ring-offset-1"
4330
+ ...props,
4331
+ children: [
4332
+ /* @__PURE__ */ jsxRuntime.jsx(
4333
+ Input2,
4334
+ {
4335
+ className: "bg-muted h-8 w-[5rem] rounded-md px-2 text-xs",
4336
+ readOnly: true,
4337
+ type: "text",
4338
+ value: displayHex
4339
+ }
4340
+ ),
4341
+ /* @__PURE__ */ jsxRuntime.jsx(PercentageInput, { value: alpha, onChange: setAlpha })
4342
+ ]
4343
+ }
4344
+ );
4345
+ }
4346
+ if (mode === "css") {
4347
+ const rgb = color.rgb().array().map((value) => Math.round(value));
4348
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full rounded-md", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsx(
4349
+ Input2,
4350
+ {
4351
+ className: "bg-muted h-8 w-full rounded-md px-2 text-xs shadow-none",
4352
+ readOnly: true,
4353
+ type: "text",
4354
+ value: `rgba(${rgb.join(", ")}, ${alpha}%)`,
4355
+ ...props
4356
+ }
4357
+ ) });
4358
+ }
4359
+ return null;
4360
+ };
4361
+ var ColorPickerPresets = ({ colors, className, ...props }) => {
4362
+ const { hue, saturation, lightness, alpha, setHue, setSaturation, setLightness, setAlpha } = useColorPicker();
4363
+ const currentHex = Color__default.default.hsl(hue, saturation, lightness, alpha / 100).hex();
4364
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-wrap gap-1.5", className), ...props, children: colors.map((hex) => {
4365
+ const isActive = Color__default.default(hex).hex().toUpperCase() === currentHex.toUpperCase();
4366
+ return /* @__PURE__ */ jsxRuntime.jsx(
4367
+ "button",
4368
+ {
4369
+ type: "button",
4370
+ className: cn(
4371
+ "size-5 cursor-pointer rounded-[3px] border transition-all",
4372
+ "hover:scale-110 hover:shadow-md",
4373
+ isActive && "ring-ring ring-offset-background ring-2 ring-offset-1"
4374
+ ),
4375
+ style: { backgroundColor: hex },
4376
+ onClick: () => {
4377
+ const color = Color__default.default(hex);
4378
+ const [h, s, l] = color.hsl().array();
4379
+ setHue(h);
4380
+ setSaturation(s);
4381
+ setLightness(l);
4382
+ setAlpha(100);
4383
+ },
4384
+ "aria-label": hex,
4385
+ title: hex
4386
+ },
4387
+ hex
4388
+ );
4389
+ }) });
4390
+ };
4391
+ ColorPickerPresets.displayName = "ColorPickerPresets";
4392
+ function Calendar({
4393
+ className,
4394
+ classNames,
4395
+ modifiersClassNames,
4396
+ showOutsideDays = true,
4397
+ captionLayout = "dropdown",
4398
+ buttonVariant = "ghost",
4399
+ locale,
4400
+ formatters,
4401
+ components,
4402
+ fromYear,
4403
+ toYear,
4404
+ ...props
4405
+ }) {
4406
+ const defaultClassNames = reactDayPicker.getDefaultClassNames();
4407
+ const resolvedComponents = react.useMemo(
4408
+ () => ({
4409
+ Root: ({ className: className2, rootRef, ...rootProps }) => {
4410
+ return /* @__PURE__ */ jsxRuntime.jsx(
4411
+ "div",
4412
+ {
4413
+ "data-slot": "calendar",
4414
+ ref: rootRef,
4415
+ className: cn(className2),
4416
+ ...rootProps
4417
+ }
4418
+ );
4419
+ },
4420
+ Chevron: ({ className: className2, orientation, ...chevronProps }) => {
4421
+ if (orientation === "left") {
4422
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeftIcon, { className: cn("size-4", className2), ...chevronProps });
4423
+ }
4424
+ if (orientation === "right") {
4425
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, { className: cn("size-4", className2), ...chevronProps });
4426
+ }
4427
+ return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: cn("size-4", className2), ...chevronProps });
4428
+ },
4429
+ DayButton: (dayButtonProps) => /* @__PURE__ */ jsxRuntime.jsx(CalendarDayButton, { locale, ...dayButtonProps }),
4430
+ WeekNumber: ({ children, ...weekNumberProps }) => {
4431
+ return /* @__PURE__ */ jsxRuntime.jsx("td", { ...weekNumberProps, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-(--cell-size) items-center justify-center text-center", children }) });
4432
+ },
4433
+ ...components
4434
+ }),
4435
+ [locale, components]
4436
+ );
4437
+ return /* @__PURE__ */ jsxRuntime.jsx(
4438
+ reactDayPicker.DayPicker,
4439
+ {
4440
+ showOutsideDays,
4441
+ className: cn(
4442
+ "group/calendar bg-background p-3 font-sans [--cell-radius:var(--radius-md)] [--cell-size:--spacing(7)] in-data-[slot=card-content]:bg-transparent in-data-[slot=popover-content]:bg-transparent",
4443
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
4444
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
4445
+ className
4446
+ ),
4447
+ captionLayout,
4448
+ startMonth: new Date(fromYear ?? 1900, 0),
4449
+ endMonth: new Date(toYear ?? 2100, 11),
4450
+ locale,
4451
+ formatters: {
4452
+ formatMonthDropdown: (date) => date.toLocaleString(locale?.code, { month: "short" }),
4453
+ ...formatters
4454
+ },
4455
+ classNames: {
4456
+ root: cn("w-fit", defaultClassNames.root),
4457
+ months: cn("relative flex flex-col gap-3 md:flex-row", defaultClassNames.months),
4458
+ month: cn("flex w-full flex-col gap-3", defaultClassNames.month),
4459
+ nav: cn(
4460
+ "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-2",
4461
+ defaultClassNames.nav
4462
+ ),
4463
+ button_previous: cn(
4464
+ buttonVariants({ variant: buttonVariant }),
4465
+ "size-7 p-0 select-none opacity-50 aria-disabled:opacity-30 transition-opacity duration-150 hover:opacity-100",
4466
+ defaultClassNames.button_previous
4467
+ ),
4468
+ button_next: cn(
4469
+ buttonVariants({ variant: buttonVariant }),
4470
+ "size-7 p-0 select-none opacity-50 aria-disabled:opacity-30 transition-opacity duration-150 hover:opacity-100",
4471
+ defaultClassNames.button_next
4472
+ ),
4473
+ month_caption: cn(
4474
+ "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size) tracking-tight",
4475
+ defaultClassNames.month_caption
4476
+ ),
4477
+ dropdowns: cn(
4478
+ "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-semibold",
4479
+ defaultClassNames.dropdowns
4480
+ ),
4481
+ dropdown_root: cn(
4482
+ "relative rounded-(--cell-radius)",
4483
+ defaultClassNames.dropdown_root
4484
+ ),
4485
+ dropdown: cn("absolute inset-0 bg-popover opacity-0", defaultClassNames.dropdown),
4486
+ caption_label: cn(
4487
+ "font-semibold select-none",
4488
+ captionLayout === "label" ? "text-sm" : "flex items-center gap-1 rounded-(--cell-radius) text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
4489
+ defaultClassNames.caption_label
4490
+ ),
4491
+ weekdays: cn("flex gap-1", defaultClassNames.weekdays),
4492
+ weekday: cn(
4493
+ "flex-1 rounded-(--cell-radius) text-[0.75rem] font-semibold text-muted-foreground/70 select-none tracking-wide",
4494
+ defaultClassNames.weekday
4495
+ ),
4496
+ week: cn("mt-2 flex w-full gap-1", defaultClassNames.week),
4497
+ week_number_header: cn(
4498
+ "w-(--cell-size) select-none",
4499
+ defaultClassNames.week_number_header
4500
+ ),
4501
+ week_number: cn(
4502
+ "text-[0.75rem] text-muted-foreground/50 select-none",
4503
+ defaultClassNames.week_number
4504
+ ),
4505
+ day: cn(
4506
+ "group/day relative aspect-square h-full w-full rounded-(--cell-radius) p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)",
4507
+ props.showWeekNumber ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)" : "[&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)",
4508
+ defaultClassNames.day
4509
+ ),
4510
+ range_start: cn(
4511
+ "relative isolate z-0 rounded-l-md bg-primary/8 after:absolute after:inset-y-0 after:right-0 after:w-3 after:bg-primary/8",
4512
+ defaultClassNames.range_start
4129
4513
  ),
4130
- style: { backgroundColor: hex },
4131
- onClick: () => {
4132
- const color = Color__default.default(hex);
4133
- const [h, s, l] = color.hsl().array();
4134
- setHue(h);
4135
- setSaturation(s);
4136
- setLightness(l);
4137
- setAlpha(100);
4138
- },
4139
- "aria-label": hex,
4140
- title: hex
4514
+ range_middle: cn("rounded-none bg-primary/8", defaultClassNames.range_middle),
4515
+ range_end: cn(
4516
+ "relative isolate z-0 rounded-r-md bg-primary/8 after:absolute after:inset-y-0 after:left-0 after:w-3 after:bg-primary/8",
4517
+ defaultClassNames.range_end
4518
+ ),
4519
+ today: cn("rounded-md bg-accent text-accent-foreground", defaultClassNames.today),
4520
+ outside: cn(
4521
+ "text-muted-foreground/50 aria-selected:text-muted-foreground/50",
4522
+ defaultClassNames.outside
4523
+ ),
4524
+ disabled: cn("text-muted-foreground/40 opacity-50", defaultClassNames.disabled),
4525
+ hidden: cn("invisible", defaultClassNames.hidden),
4526
+ ...classNames
4141
4527
  },
4142
- hex
4143
- );
4144
- }) });
4145
- };
4146
- ColorPickerPresets.displayName = "ColorPickerPresets";
4147
- function DatePicker({
4148
- mode = "single",
4149
- selected,
4150
- onSelect,
4151
- placeholder = "Pick a date",
4152
- disabled = false,
4528
+ modifiersClassNames: {
4529
+ preview_start: "relative isolate z-0 rounded-l-md bg-primary/8 after:absolute after:inset-y-0 after:right-0 after:w-3 after:bg-primary/8",
4530
+ preview_middle: "rounded-none bg-primary/8",
4531
+ preview_end: "relative isolate z-0 rounded-r-md bg-primary/8 after:absolute after:inset-y-0 after:left-0 after:w-3 after:bg-primary/8",
4532
+ ...modifiersClassNames
4533
+ },
4534
+ components: resolvedComponents,
4535
+ ...props
4536
+ }
4537
+ );
4538
+ }
4539
+ function CalendarDayButton({
4153
4540
  className,
4154
- fromDate,
4155
- toDate
4541
+ day,
4542
+ modifiers,
4543
+ locale,
4544
+ ...props
4156
4545
  }) {
4546
+ const defaultClassNames = reactDayPicker.getDefaultClassNames();
4547
+ const ref = react.useRef(null);
4548
+ react.useEffect(() => {
4549
+ if (modifiers.focused) ref.current?.focus();
4550
+ }, [modifiers.focused]);
4551
+ const isPreviewEdge = Boolean(
4552
+ (modifiers.preview_start || modifiers.preview_end) && !modifiers.selected
4553
+ );
4554
+ return /* @__PURE__ */ jsxRuntime.jsx(
4555
+ Button,
4556
+ {
4557
+ ref,
4558
+ variant: "ghost",
4559
+ size: "icon-sm",
4560
+ "data-day": day.date.toLocaleDateString(locale?.code),
4561
+ "data-selected-single": modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle,
4562
+ "data-range-start": modifiers.range_start,
4563
+ "data-range-end": modifiers.range_end,
4564
+ "data-range-middle": modifiers.range_middle,
4565
+ "data-preview-middle": Boolean(modifiers.preview_middle),
4566
+ "data-preview-edge": isPreviewEdge,
4567
+ className: cn(
4568
+ "group-data-[focused=true]/day:ring-primary/40 data-[preview-edge=true]:ring-primary/50 data-[preview-edge=true]:text-primary data-[preview-middle=true]:text-primary data-[range-end=true]:!bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:!bg-primary/8 data-[range-middle=true]:text-foreground data-[range-start=true]:!bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:!bg-primary data-[selected-single=true]:text-primary-foreground relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 !rounded-md border-0 !bg-transparent leading-none font-normal transition-colors duration-150 group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:rounded-md group-data-[focused=true]/day:ring-[2px] hover:!bg-transparent data-[preview-edge=true]:rounded-md data-[preview-edge=true]:font-medium data-[preview-edge=true]:ring-[2px] data-[preview-middle=true]:font-medium data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[selected-single=true]:rounded-md [&>span]:text-xs [&>span]:font-medium [&>span]:opacity-75",
4569
+ defaultClassNames.day,
4570
+ className
4571
+ ),
4572
+ ...props
4573
+ }
4574
+ );
4575
+ }
4576
+ function DatePicker(props) {
4577
+ const {
4578
+ placeholder = "Pick a date",
4579
+ disabled = false,
4580
+ className,
4581
+ fromDate,
4582
+ toDate,
4583
+ numberOfMonths = 1
4584
+ } = props;
4157
4585
  const [open, setOpen] = react.useState(false);
4586
+ const [awaitingRangeEnd, setAwaitingRangeEnd] = react.useState(false);
4587
+ const [previewDate, setPreviewDate] = react.useState(void 0);
4158
4588
  const label = react.useMemo(() => {
4159
- if (mode === "range") {
4160
- const range = selected;
4161
- if (range?.from && range?.to)
4162
- return `${dateFns.format(range.from, "MMM d, yyyy")} \u2013 ${dateFns.format(range.to, "MMM d, yyyy")}`;
4163
- if (range?.from) return `${dateFns.format(range.from, "MMM d, yyyy")} \u2013 \u2026`;
4164
- return placeholder;
4165
- }
4166
- const date = selected;
4167
- return date ? dateFns.format(date, "MMM d, yyyy") : placeholder;
4168
- }, [mode, selected, placeholder]);
4169
- const hasValue = mode === "range" ? !!selected?.from : !!selected;
4170
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: setOpen, children: [
4589
+ if (props.mode === "range") {
4590
+ const range = props.selected;
4591
+ if (!range?.from) return placeholder;
4592
+ if (!range.to) return `${dateFns.format(range.from, "MMM d, yyyy")} \u2013 \u2026`;
4593
+ return `${dateFns.format(range.from, "MMM d, yyyy")} \u2013 ${dateFns.format(range.to, "MMM d, yyyy")}`;
4594
+ }
4595
+ return props.selected ? dateFns.format(props.selected, "MMM d, yyyy") : placeholder;
4596
+ }, [props.mode, props.selected, placeholder]);
4597
+ const handleOpenChange = (nextOpen) => {
4598
+ setOpen(nextOpen);
4599
+ if (!nextOpen) {
4600
+ setAwaitingRangeEnd(false);
4601
+ setPreviewDate(void 0);
4602
+ }
4603
+ };
4604
+ const handleRangeSelect = (range, triggerDate) => {
4605
+ if (props.mode !== "range") return;
4606
+ const emit = props.onSelect;
4607
+ if (!awaitingRangeEnd) {
4608
+ setAwaitingRangeEnd(true);
4609
+ emit?.({ from: triggerDate, to: void 0 });
4610
+ return;
4611
+ }
4612
+ emit?.(range);
4613
+ if (!range?.from || !range.to) {
4614
+ setAwaitingRangeEnd(!!range?.from);
4615
+ return;
4616
+ }
4617
+ setAwaitingRangeEnd(false);
4618
+ setPreviewDate(void 0);
4619
+ setOpen(false);
4620
+ };
4621
+ const rangeFrom = props.mode === "range" ? props.selected?.from : void 0;
4622
+ const previewModifiers = react.useMemo(() => {
4623
+ if (!awaitingRangeEnd || !rangeFrom || !previewDate) return void 0;
4624
+ if (dateFns.isSameDay(rangeFrom, previewDate)) return void 0;
4625
+ const [start, end] = previewDate < rangeFrom ? [previewDate, rangeFrom] : [rangeFrom, previewDate];
4626
+ return {
4627
+ preview_start: start,
4628
+ preview_middle: { after: start, before: end },
4629
+ preview_end: end
4630
+ };
4631
+ }, [awaitingRangeEnd, rangeFrom, previewDate]);
4632
+ const handleDayPreview = (day, dayModifiers) => {
4633
+ if (!awaitingRangeEnd) return;
4634
+ if (dayModifiers.disabled || dayModifiers.hidden) return;
4635
+ setPreviewDate((current) => current && dateFns.isSameDay(current, day) ? current : day);
4636
+ };
4637
+ const dateConstraints = react.useMemo(() => {
4638
+ const disabledMatchers = [];
4639
+ if (fromDate) disabledMatchers.push({ before: fromDate });
4640
+ if (toDate) disabledMatchers.push({ after: toDate });
4641
+ return {
4642
+ ...disabledMatchers.length > 0 && { disabled: disabledMatchers },
4643
+ ...fromDate && { startMonth: fromDate },
4644
+ ...toDate && { endMonth: toDate }
4645
+ };
4646
+ }, [fromDate, toDate]);
4647
+ const hasValue = props.mode === "range" ? !!props.selected?.from : !!props.selected;
4648
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
4171
4649
  /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
4172
4650
  Button,
4173
4651
  {
@@ -4185,36 +4663,36 @@ function DatePicker({
4185
4663
  ]
4186
4664
  }
4187
4665
  ) }),
4188
- /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { "data-slot": "date-picker-content", className: "w-auto p-0", align: "start", children: mode === "range" ? /* @__PURE__ */ jsxRuntime.jsx(
4189
- Calendar,
4190
- {
4191
- ...{
4666
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { "data-slot": "date-picker-content", className: "w-auto p-0", align: "start", children: props.mode === "range" ? (
4667
+ // Clearing the preview on the wrapper instead of per day
4668
+ // avoids the blank frame `onDayMouseLeave` would cause when
4669
+ // the pointer travels from one day to the next.
4670
+ /* @__PURE__ */ jsxRuntime.jsx("div", { onMouseLeave: () => setPreviewDate(void 0), children: /* @__PURE__ */ jsxRuntime.jsx(
4671
+ Calendar,
4672
+ {
4192
4673
  mode: "range",
4193
- selected,
4194
- onSelect: (range) => {
4195
- onSelect?.(range);
4196
- if (range?.to) setOpen(false);
4197
- },
4198
- fromDate,
4199
- toDate,
4200
- numberOfMonths: 2,
4201
- initialFocus: true
4674
+ selected: props.selected,
4675
+ onSelect: handleRangeSelect,
4676
+ modifiers: previewModifiers,
4677
+ onDayMouseEnter: handleDayPreview,
4678
+ onDayFocus: handleDayPreview,
4679
+ numberOfMonths,
4680
+ autoFocus: true,
4681
+ ...dateConstraints
4202
4682
  }
4203
- }
4683
+ ) })
4204
4684
  ) : /* @__PURE__ */ jsxRuntime.jsx(
4205
4685
  Calendar,
4206
4686
  {
4207
- ...{
4208
- mode: "single",
4209
- selected,
4210
- onSelect: (date) => {
4211
- onSelect?.(date);
4212
- setOpen(false);
4213
- },
4214
- fromDate,
4215
- toDate,
4216
- initialFocus: true
4217
- }
4687
+ mode: "single",
4688
+ selected: props.selected,
4689
+ onSelect: (date) => {
4690
+ props.onSelect?.(date);
4691
+ setOpen(false);
4692
+ },
4693
+ numberOfMonths,
4694
+ autoFocus: true,
4695
+ ...dateConstraints
4218
4696
  }
4219
4697
  ) })
4220
4698
  ] });
@@ -4339,6 +4817,7 @@ var Navbar = react.forwardRef(
4339
4817
  notifications,
4340
4818
  avatarSrc,
4341
4819
  avatarFallback,
4820
+ showUtilityBar = true,
4342
4821
  onNavLinkClick,
4343
4822
  onSearchClick,
4344
4823
  onHelpClick,
@@ -4410,7 +4889,7 @@ var Navbar = react.forwardRef(
4410
4889
  ] }),
4411
4890
  /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "ml-auto flex h-full items-center", children: navigationLinks.map((link, i) => /* @__PURE__ */ jsxRuntime.jsx(NavLinkItem, { link, onNavLinkClick }, i)) })
4412
4891
  ] }) }),
4413
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-background border-border border-b px-4 md:px-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex h-9 max-w-screen-2xl items-center justify-between", children: [
4892
+ showUtilityBar && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-background border-border border-b px-4 md:px-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex h-9 max-w-screen-2xl items-center justify-between", children: [
4414
4893
  /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "flex items-center", children: utilityLinks.map((link, i) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
4415
4894
  i > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-border mx-3 select-none", children: "|" }),
4416
4895
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -4655,6 +5134,8 @@ function NavigationMenuIndicator({
4655
5134
  }
4656
5135
  );
4657
5136
  }
5137
+
5138
+ // src/components/authorization/policy.ts
4658
5139
  function matchPermission(pattern, permission) {
4659
5140
  if (pattern === "*") return true;
4660
5141
  if (pattern === permission) return true;
@@ -4670,41 +5151,46 @@ function matchesAny(permissionSet, permission) {
4670
5151
  }
4671
5152
  return false;
4672
5153
  }
5154
+ function can(permissionSet, perms, mode = "any") {
5155
+ const list = Array.isArray(perms) ? perms : [perms];
5156
+ if (list.length === 0) return false;
5157
+ if (permissionSet.has("*")) return true;
5158
+ if (mode === "all") {
5159
+ return list.every((p) => matchesAny(permissionSet, p));
5160
+ }
5161
+ return list.some((p) => matchesAny(permissionSet, p));
5162
+ }
4673
5163
  var AbilityContext = react.createContext(void 0);
4674
5164
  AbilityContext.displayName = "AbilityContext";
4675
5165
  function AbilityProvider({ children, permissions }) {
4676
5166
  const [permissionSet, setPermissionSet] = react.useState(
4677
5167
  () => new Set(permissions ?? [])
4678
5168
  );
4679
- const can = react.useCallback(
4680
- (perms, mode = "any") => {
4681
- const list = Array.isArray(perms) ? perms : [perms];
4682
- if (list.length === 0) return false;
4683
- if (permissionSet.has("*")) return true;
4684
- if (mode === "all") {
4685
- return list.every((p) => matchesAny(permissionSet, p));
4686
- }
4687
- return list.some((p) => matchesAny(permissionSet, p));
4688
- },
5169
+ const [imperativelyResolved, setImperativelyResolved] = react.useState(false);
5170
+ const status = permissions !== void 0 || imperativelyResolved ? "ready" : "loading";
5171
+ const can2 = react.useCallback(
5172
+ (perms, mode = "any") => can(permissionSet, perms, mode),
4689
5173
  [permissionSet]
4690
5174
  );
4691
5175
  const setAbilities = react.useCallback((perms) => {
4692
5176
  setPermissionSet(new Set(perms));
5177
+ setImperativelyResolved(true);
4693
5178
  }, []);
4694
5179
  const clearAbilities = react.useCallback(() => {
4695
5180
  setPermissionSet(/* @__PURE__ */ new Set());
5181
+ setImperativelyResolved(true);
4696
5182
  }, []);
4697
- const syncedKey = react.useRef(permissions ? permissions.join("|") : null);
5183
+ const permissionKey = permissions === void 0 ? null : [...permissions].sort().join("|");
5184
+ const syncedKey = react.useRef(permissionKey);
4698
5185
  react.useEffect(() => {
4699
- if (permissions === void 0) return;
4700
- const key = permissions.join("|");
4701
- if (key === syncedKey.current) return;
4702
- syncedKey.current = key;
5186
+ if (permissionKey === null) return;
5187
+ if (permissionKey === syncedKey.current) return;
5188
+ syncedKey.current = permissionKey;
4703
5189
  setPermissionSet(new Set(permissions));
4704
- }, [permissions]);
5190
+ }, [permissionKey, permissions]);
4705
5191
  const value = react.useMemo(
4706
- () => ({ can, setAbilities, clearAbilities }),
4707
- [can, setAbilities, clearAbilities]
5192
+ () => ({ can: can2, setAbilities, clearAbilities, status }),
5193
+ [can2, setAbilities, clearAbilities, status]
4708
5194
  );
4709
5195
  return /* @__PURE__ */ jsxRuntime.jsx(AbilityContext.Provider, { value, children });
4710
5196
  }
@@ -4716,36 +5202,194 @@ function useAbility() {
4716
5202
  return context;
4717
5203
  }
4718
5204
  function useCan(permissions, mode = "any") {
4719
- const { can } = useAbility();
4720
- return can(permissions, mode);
5205
+ const { can: can2 } = useAbility();
5206
+ return can2(permissions, mode);
5207
+ }
5208
+ function useAbilityStatus() {
5209
+ return useAbility().status;
5210
+ }
5211
+
5212
+ // src/components/authorization/permissions.generated.ts
5213
+ var KNOWN_PERMISSIONS = [];
5214
+
5215
+ // src/components/authorization/permission-catalog.ts
5216
+ var CATALOG = new Set(KNOWN_PERMISSIONS);
5217
+ var warned = /* @__PURE__ */ new Set();
5218
+ function warnUnknownPermission(permission) {
5219
+ if (process.env.NODE_ENV === "production") return;
5220
+ if (CATALOG.size === 0) return;
5221
+ const requested = Array.isArray(permission) ? permission : [permission];
5222
+ for (const entry of requested) {
5223
+ if (entry.includes("*")) continue;
5224
+ if (CATALOG.has(entry) || warned.has(entry)) continue;
5225
+ warned.add(entry);
5226
+ console.warn(
5227
+ `[Can] Unknown permission "${entry}". It is not in the generated permission catalog. Check for a typo, or regenerate the catalog with \`pnpm generate-permissions\`.`
5228
+ );
5229
+ }
5230
+ }
5231
+ var FOCUS_TRAVERSAL_KEYS = /* @__PURE__ */ new Set(["Tab", "Escape"]);
5232
+ function blockInteraction(event) {
5233
+ event.preventDefault();
5234
+ event.stopPropagation();
5235
+ }
5236
+ function blockNonTraversalKey(event) {
5237
+ if (!FOCUS_TRAVERSAL_KEYS.has(event.key)) blockInteraction(event);
5238
+ }
5239
+ var warnedRenderPropMisuse = /* @__PURE__ */ new Set();
5240
+ function warnRenderPropVoidsProps(voided) {
5241
+ if (process.env.NODE_ENV === "production") return;
5242
+ if (voided.length === 0) return;
5243
+ const key = voided.join(",");
5244
+ if (warnedRenderPropMisuse.has(key)) return;
5245
+ warnedRenderPropMisuse.add(key);
5246
+ console.warn(
5247
+ `[Can] \`children\` is a function, so ${voided.map((prop) => `\`${prop}\``).join(", ")} ${voided.length === 1 ? "is" : "are"} ignored. A render prop owns every state: read \`allowed\` and \`status\` and render the disabled, loading and denied cases yourself, or pass an element instead of a function.`
5248
+ );
5249
+ }
5250
+ function disableElement(child) {
5251
+ return react.cloneElement(child, {
5252
+ "aria-disabled": "true",
5253
+ className: cn(child.props.className, "cursor-not-allowed opacity-50"),
5254
+ onClickCapture: blockInteraction,
5255
+ onKeyDownCapture: blockNonTraversalKey,
5256
+ onKeyUpCapture: blockNonTraversalKey,
5257
+ onPointerDownCapture: blockInteraction,
5258
+ onMouseDownCapture: blockInteraction
5259
+ });
5260
+ }
5261
+ function InteractionFirewall({ children }) {
5262
+ return /* @__PURE__ */ jsxRuntime.jsx(
5263
+ "span",
5264
+ {
5265
+ "data-slot": "can-blocked",
5266
+ className: "contents",
5267
+ onClickCapture: blockInteraction,
5268
+ onPointerDownCapture: blockInteraction,
5269
+ onMouseDownCapture: blockInteraction,
5270
+ onKeyDownCapture: blockNonTraversalKey,
5271
+ onKeyUpCapture: blockNonTraversalKey,
5272
+ children
5273
+ }
5274
+ );
5275
+ }
5276
+ function DisabledSubtree({
5277
+ children,
5278
+ className,
5279
+ ...props
5280
+ }) {
5281
+ const { "data-slot": _incomingDataSlot, ...restProps } = props;
5282
+ return /* @__PURE__ */ jsxRuntime.jsx(
5283
+ "span",
5284
+ {
5285
+ "data-slot": "can-disabled",
5286
+ "aria-disabled": "true",
5287
+ className: cn(
5288
+ "inline-flex cursor-not-allowed opacity-50",
5289
+ "*:pointer-events-none",
5290
+ className
5291
+ ),
5292
+ onClickCapture: blockInteraction,
5293
+ onPointerDownCapture: blockInteraction,
5294
+ onMouseDownCapture: blockInteraction,
5295
+ onKeyDownCapture: blockNonTraversalKey,
5296
+ onKeyUpCapture: blockNonTraversalKey,
5297
+ ...restProps,
5298
+ children
5299
+ }
5300
+ );
4721
5301
  }
4722
- function Can({ permission, mode = "any", negate = false, fallback = null, children }) {
4723
- const { can } = useAbility();
4724
- const hasPermission = can(permission, mode);
5302
+ function Can({
5303
+ permission,
5304
+ mode = "any",
5305
+ negate = false,
5306
+ behavior = "hide",
5307
+ reason = null,
5308
+ fallback = null,
5309
+ loading,
5310
+ children
5311
+ }) {
5312
+ warnUnknownPermission(permission);
5313
+ const { can: can2, status } = useAbility();
5314
+ const hasPermission = status === "ready" && can2(permission, mode);
4725
5315
  const show = negate ? !hasPermission : hasPermission;
4726
5316
  if (typeof children === "function") {
4727
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children(show) });
5317
+ warnRenderPropVoidsProps([
5318
+ ...behavior === "disable" ? ["behavior='disable'"] : [],
5319
+ ...reason !== null ? ["reason"] : [],
5320
+ ...fallback !== null ? ["fallback"] : [],
5321
+ ...loading !== void 0 ? ["loading"] : []
5322
+ ]);
5323
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children({ allowed: show, status }) });
5324
+ }
5325
+ if (status === "loading" && loading !== void 0) {
5326
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loading });
4728
5327
  }
4729
- return show ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
5328
+ if (show) {
5329
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
5330
+ }
5331
+ if (behavior === "disable") {
5332
+ if (react.isValidElement(children) && children.type !== react.Fragment) {
5333
+ const disabledChild = disableElement(children);
5334
+ if (reason === null) {
5335
+ return /* @__PURE__ */ jsxRuntime.jsx(InteractionFirewall, { children: disabledChild });
5336
+ }
5337
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
5338
+ /* @__PURE__ */ jsxRuntime.jsx(InteractionFirewall, { children: /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: disabledChild }) }),
5339
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: reason })
5340
+ ] });
5341
+ }
5342
+ if (reason === null) {
5343
+ return /* @__PURE__ */ jsxRuntime.jsx(DisabledSubtree, { children });
5344
+ }
5345
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
5346
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(DisabledSubtree, { children }) }),
5347
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: reason })
5348
+ ] });
5349
+ }
5350
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
4730
5351
  }
4731
5352
  Can.displayName = "Can";
4732
- function CanNot({ permission, mode = "any", fallback = null, children }) {
4733
- return /* @__PURE__ */ jsxRuntime.jsx(Can, { permission, mode, negate: true, fallback, children });
5353
+ function CanNot({
5354
+ permission,
5355
+ mode = "any",
5356
+ behavior = "hide",
5357
+ reason = null,
5358
+ fallback = null,
5359
+ loading,
5360
+ children
5361
+ }) {
5362
+ return /* @__PURE__ */ jsxRuntime.jsx(
5363
+ Can,
5364
+ {
5365
+ permission,
5366
+ mode,
5367
+ negate: true,
5368
+ behavior,
5369
+ reason,
5370
+ fallback,
5371
+ loading,
5372
+ children
5373
+ }
5374
+ );
4734
5375
  }
4735
5376
  CanNot.displayName = "CanNot";
4736
- var MOBILE_BREAKPOINT = 768;
4737
- function useIsMobile() {
4738
- const [isMobile, setIsMobile] = react.useState(void 0);
5377
+ function useMediaQuery(query) {
5378
+ const [matches, setMatches] = react.useState(false);
4739
5379
  react.useEffect(() => {
4740
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
4741
- const onChange = () => {
4742
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
4743
- };
4744
- mql.addEventListener("change", onChange);
4745
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
4746
- return () => mql.removeEventListener("change", onChange);
4747
- }, []);
4748
- return !!isMobile;
5380
+ if (typeof window === "undefined") return;
5381
+ const mql = window.matchMedia(query);
5382
+ setMatches(mql.matches);
5383
+ const handler = (e) => setMatches(e.matches);
5384
+ mql.addEventListener("change", handler);
5385
+ return () => mql.removeEventListener("change", handler);
5386
+ }, [query]);
5387
+ return matches;
5388
+ }
5389
+
5390
+ // src/hooks/use-mobile.ts
5391
+ function useIsMobile() {
5392
+ return useMediaQuery("(max-width: 767px)");
4749
5393
  }
4750
5394
  function Sheet({ ...props }) {
4751
5395
  return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Root, { "data-slot": "sheet", ...props });
@@ -4938,6 +5582,39 @@ function SidebarProvider({
4938
5582
  }
4939
5583
  ) });
4940
5584
  }
5585
+ function SidebarResizeHandle() {
5586
+ const dragRef = react.useRef(null);
5587
+ return /* @__PURE__ */ jsxRuntime.jsx(
5588
+ "div",
5589
+ {
5590
+ "data-slot": "sidebar-resize-handle",
5591
+ className: "absolute inset-y-0 right-0 w-1 cursor-col-resize opacity-0 transition-opacity hover:opacity-100 hover:bg-sidebar-border group-data-[state=collapsed]:hidden",
5592
+ onPointerDown: (e) => {
5593
+ e.preventDefault();
5594
+ const wrapper = e.currentTarget.closest('[data-slot="sidebar-wrapper"]');
5595
+ if (!wrapper) return;
5596
+ const container = e.currentTarget.closest('[data-slot="sidebar-container"]');
5597
+ const gap = container?.parentElement?.querySelector('[data-slot="sidebar-gap"]') ?? null;
5598
+ const currentWidth = container ? parseFloat(getComputedStyle(container).width) : 256;
5599
+ if (container) container.style.transition = "none";
5600
+ if (gap) gap.style.transition = "none";
5601
+ dragRef.current = { startX: e.clientX, startWidth: currentWidth, wrapper, container: container ?? null, gap };
5602
+ e.currentTarget.setPointerCapture(e.pointerId);
5603
+ },
5604
+ onPointerMove: (e) => {
5605
+ if (!dragRef.current) return;
5606
+ const { startX, startWidth, wrapper } = dragRef.current;
5607
+ const newWidth = Math.max(160, Math.min(480, startWidth + (e.clientX - startX)));
5608
+ wrapper.style.setProperty("--sidebar-width", `${newWidth}px`);
5609
+ },
5610
+ onPointerUp: () => {
5611
+ if (dragRef.current?.container) dragRef.current.container.style.transition = "";
5612
+ if (dragRef.current?.gap) dragRef.current.gap.style.transition = "";
5613
+ dragRef.current = null;
5614
+ }
5615
+ }
5616
+ );
5617
+ }
4941
5618
  function Sidebar({
4942
5619
  side = "left",
4943
5620
  variant = "sidebar",
@@ -5008,7 +5685,7 @@ function Sidebar({
5008
5685
  )
5009
5686
  }
5010
5687
  ),
5011
- /* @__PURE__ */ jsxRuntime.jsx(
5688
+ /* @__PURE__ */ jsxRuntime.jsxs(
5012
5689
  "div",
5013
5690
  {
5014
5691
  "data-slot": "sidebar-container",
@@ -5020,15 +5697,18 @@ function Sidebar({
5020
5697
  className
5021
5698
  ),
5022
5699
  ...props,
5023
- children: /* @__PURE__ */ jsxRuntime.jsx(
5024
- "div",
5025
- {
5026
- "data-sidebar": "sidebar",
5027
- "data-slot": "sidebar-inner",
5028
- className: "bg-sidebar group-data-[variant=floating]:ring-sidebar-border flex size-full flex-col group-data-[variant=floating]:rounded-2xl group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1",
5029
- children
5030
- }
5031
- )
5700
+ children: [
5701
+ /* @__PURE__ */ jsxRuntime.jsx(
5702
+ "div",
5703
+ {
5704
+ "data-sidebar": "sidebar",
5705
+ "data-slot": "sidebar-inner",
5706
+ className: "bg-sidebar group-data-[variant=floating]:ring-sidebar-border flex size-full flex-col group-data-[variant=floating]:rounded-2xl group-data-[variant=floating]:shadow-sm group-data-[variant=floating]:ring-1",
5707
+ children
5708
+ }
5709
+ ),
5710
+ /* @__PURE__ */ jsxRuntime.jsx(SidebarResizeHandle, {})
5711
+ ]
5032
5712
  }
5033
5713
  )
5034
5714
  ]
@@ -5145,7 +5825,7 @@ function SidebarContent({ className, ...props }) {
5145
5825
  "data-slot": "sidebar-content",
5146
5826
  "data-sidebar": "content",
5147
5827
  className: cn(
5148
- "no-scrollbar flex min-h-0 flex-1 flex-col gap-2 overflow-auto [--radius:var(--radius-xl)] group-data-[collapsible=icon]:overflow-hidden",
5828
+ "no-scrollbar flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto overflow-x-hidden [--radius:var(--radius-xl)] group-data-[collapsible=icon]:overflow-hidden",
5149
5829
  className
5150
5830
  ),
5151
5831
  ...props
@@ -5440,6 +6120,7 @@ function AppShell({
5440
6120
  onItemClick,
5441
6121
  brandName = "Total Portal",
5442
6122
  showHeader = true,
6123
+ header,
5443
6124
  open,
5444
6125
  onOpenChange,
5445
6126
  defaultOpen,
@@ -5460,7 +6141,7 @@ function AppShell({
5460
6141
  /* @__PURE__ */ jsxRuntime.jsx(SidebarTrigger, { variant: "ghost", className: "size-8 shrink-0" }),
5461
6142
  /* @__PURE__ */ jsxRuntime.jsx(SidebarBrand, { brandName })
5462
6143
  ] }),
5463
- /* @__PURE__ */ jsxRuntime.jsx(SidebarContent, { children: /* @__PURE__ */ jsxRuntime.jsx(SidebarGroup, { children: /* @__PURE__ */ jsxRuntime.jsx(SidebarGroupContent, { children: /* @__PURE__ */ jsxRuntime.jsx(SidebarMenu, { children: items.map((item) => {
6144
+ /* @__PURE__ */ jsxRuntime.jsx(SidebarContent, { className: "overflow-x:hidden", children: /* @__PURE__ */ jsxRuntime.jsx(SidebarGroup, { children: /* @__PURE__ */ jsxRuntime.jsx(SidebarGroupContent, { children: /* @__PURE__ */ jsxRuntime.jsx(SidebarMenu, { children: items.map((item) => {
5464
6145
  const menuItem = /* @__PURE__ */ jsxRuntime.jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxRuntime.jsxs(
5465
6146
  SidebarMenuButton,
5466
6147
  {
@@ -5489,7 +6170,7 @@ function AppShell({
5489
6170
  }) }) }) }) })
5490
6171
  ] }),
5491
6172
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
5492
- showHeader ? /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex h-14 items-center gap-2 border-b px-4", children: [
6173
+ header ? header : showHeader ? /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex h-14 items-center gap-2 border-b px-4", children: [
5493
6174
  /* @__PURE__ */ jsxRuntime.jsx(SidebarTrigger, { variant: "ghost", className: "size-8 shrink-0 md:hidden" }),
5494
6175
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: brandName })
5495
6176
  ] }) : /* @__PURE__ */ jsxRuntime.jsx(SidebarTrigger, { variant: "ghost", className: "size-8 shrink-0 md:hidden" }),
@@ -6103,14 +6784,9 @@ var eventCalendarStyles = `
6103
6784
  font-weight: 600;
6104
6785
  }
6105
6786
 
6106
- /* \u2500\u2500 Event modal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
6787
+ /* \u2500\u2500 Event modal \u2014 hidden; replaced by TCCE Popover in event-calendar.tsx \u2500\u2500 */
6107
6788
  .sx-tcce .sx__event-modal {
6108
- border-radius: var(--border-radius-article, 0.875rem);
6109
- border: 1px solid var(--color-border);
6110
- font-size: 13px;
6111
- min-width: 220px;
6112
- max-width: 300px;
6113
- background: var(--color-background);
6789
+ display: none !important;
6114
6790
  }
6115
6791
  .sx-tcce .sx__event-modal__title {
6116
6792
  font-size: 14px;
@@ -6255,8 +6931,43 @@ function useEventCalendar({
6255
6931
  return () => unsubscribe?.();
6256
6932
  }, []);
6257
6933
  return {
6258
- calendarApp: calendarApp.current
6934
+ calendarApp: calendarApp.current,
6935
+ eventModal: eventModal$1.current
6936
+ };
6937
+ }
6938
+ var EVENT_COLOR = {
6939
+ default: "#22205f",
6940
+ primary: "#22205f",
6941
+ success: "#00a824",
6942
+ warning: "#c8a23b",
6943
+ danger: "#ea3a3d"
6944
+ };
6945
+ function getFixedAnchorRect(el) {
6946
+ const rect = el.getBoundingClientRect();
6947
+ let ancestor = el.parentElement;
6948
+ while (ancestor && ancestor !== document.documentElement) {
6949
+ if (window.getComputedStyle(ancestor).transform !== "none") {
6950
+ const cb = ancestor.getBoundingClientRect();
6951
+ return new DOMRect(rect.left - cb.left, rect.top - cb.top, rect.width, rect.height);
6952
+ }
6953
+ ancestor = ancestor.parentElement;
6954
+ }
6955
+ return rect;
6956
+ }
6957
+ function formatEventTime(start, end) {
6958
+ const isAllDay = start.length === 10;
6959
+ if (isAllDay) {
6960
+ const date = /* @__PURE__ */ new Date(`${start}T00:00:00`);
6961
+ return date.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
6962
+ }
6963
+ const fmt = (s) => {
6964
+ const [, time] = s.split(" ");
6965
+ const [h, m] = time.split(":").map(Number);
6966
+ const ampm = h >= 12 ? "PM" : "AM";
6967
+ const hour = h % 12 || 12;
6968
+ return `${hour}:${m.toString().padStart(2, "0")} ${ampm}`;
6259
6969
  };
6970
+ return `${fmt(start)} \u2013 ${fmt(end)}`;
6260
6971
  }
6261
6972
  function EventCalendar({
6262
6973
  events,
@@ -6269,26 +6980,116 @@ function EventCalendar({
6269
6980
  className
6270
6981
  }) {
6271
6982
  const [currentView, setCurrentView] = react.useState(defaultView);
6983
+ const [selectedEvent, setSelectedEvent] = react.useState(null);
6984
+ const [anchorRect, setAnchorRect] = react.useState(null);
6985
+ const clickedEventElRef = react.useRef(false);
6272
6986
  const handleViewChange = react.useCallback(
6273
6987
  (view) => {
6274
6988
  setCurrentView(view);
6275
6989
  onViewChange?.(view);
6276
6990
  },
6277
- [onViewChange]
6991
+ [onViewChange]
6992
+ );
6993
+ const handleEventClick = react.useCallback(
6994
+ (event) => {
6995
+ setSelectedEvent(event);
6996
+ onEventClick?.(event);
6997
+ },
6998
+ [onEventClick]
6999
+ );
7000
+ const { calendarApp, eventModal } = useEventCalendar({
7001
+ events,
7002
+ defaultView,
7003
+ defaultDate,
7004
+ locale,
7005
+ onEventClick: handleEventClick,
7006
+ onEventCreate,
7007
+ onViewChange: handleViewChange
7008
+ });
7009
+ react.useEffect(() => {
7010
+ const unsub = eventModal.calendarEventElement.subscribe((el) => {
7011
+ if (!el) {
7012
+ if (clickedEventElRef.current) {
7013
+ clickedEventElRef.current = false;
7014
+ } else {
7015
+ setSelectedEvent(null);
7016
+ setAnchorRect(null);
7017
+ }
7018
+ } else {
7019
+ setAnchorRect(getFixedAnchorRect(el));
7020
+ }
7021
+ });
7022
+ return unsub;
7023
+ }, [eventModal]);
7024
+ const handlePopoverOpenChange = react.useCallback(
7025
+ (open) => {
7026
+ if (!open) {
7027
+ eventModal.close();
7028
+ setSelectedEvent(null);
7029
+ setAnchorRect(null);
7030
+ }
7031
+ },
7032
+ [eventModal]
6278
7033
  );
6279
- const { calendarApp } = useEventCalendar({
6280
- events,
6281
- defaultView,
6282
- defaultDate,
6283
- locale,
6284
- onEventClick,
6285
- onEventCreate,
6286
- onViewChange: handleViewChange
6287
- });
6288
7034
  const contextValue = react.useMemo(() => ({ currentView }), [currentView]);
6289
7035
  return /* @__PURE__ */ jsxRuntime.jsxs(EventCalendarContext.Provider, { value: contextValue, children: [
6290
7036
  /* @__PURE__ */ jsxRuntime.jsx("style", { href: "tcce-event-calendar", precedence: "default", children: eventCalendarStyles }),
6291
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "event-calendar", className: cn("sx-tcce w-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(react$2.ScheduleXCalendar, { calendarApp: calendarApp ?? null }) })
7037
+ /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: !!selectedEvent && !!anchorRect, onOpenChange: handlePopoverOpenChange, children: [
7038
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "event-calendar", className: cn("sx-tcce w-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(react$2.ScheduleXCalendar, { calendarApp: calendarApp ?? null }) }),
7039
+ anchorRect && /* @__PURE__ */ jsxRuntime.jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
7040
+ "span",
7041
+ {
7042
+ style: {
7043
+ position: "fixed",
7044
+ top: anchorRect.top,
7045
+ left: anchorRect.left,
7046
+ width: anchorRect.width,
7047
+ height: anchorRect.height,
7048
+ pointerEvents: "none"
7049
+ }
7050
+ }
7051
+ ) }),
7052
+ /* @__PURE__ */ jsxRuntime.jsx(
7053
+ PopoverContent,
7054
+ {
7055
+ side: "right",
7056
+ align: "start",
7057
+ className: "w-65 gap-2",
7058
+ onPointerDownOutside: (e) => {
7059
+ const target = e.target;
7060
+ const isEventEl = target.closest(
7061
+ ".sx__month-grid-event, .sx__time-grid-event, .sx__month-agenda-event"
7062
+ );
7063
+ if (isEventEl) {
7064
+ e.preventDefault();
7065
+ clickedEventElRef.current = true;
7066
+ }
7067
+ },
7068
+ children: selectedEvent && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7069
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
7070
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7071
+ /* @__PURE__ */ jsxRuntime.jsx(
7072
+ "span",
7073
+ {
7074
+ className: "size-2 shrink-0 rounded-full",
7075
+ style: {
7076
+ backgroundColor: EVENT_COLOR[selectedEvent.color ?? "default"]
7077
+ }
7078
+ }
7079
+ ),
7080
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-heading text-sm font-semibold leading-tight", children: selectedEvent.title })
7081
+ ] }),
7082
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Edit event", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { size: 14 }) })
7083
+ ] }),
7084
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
7085
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { size: 13, className: "shrink-0" }),
7086
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatEventTime(selectedEvent.start, selectedEvent.end) })
7087
+ ] }),
7088
+ selectedEvent.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: selectedEvent.description })
7089
+ ] })
7090
+ }
7091
+ )
7092
+ ] })
6292
7093
  ] });
6293
7094
  }
6294
7095
  function useAppForm(schema, options) {
@@ -6367,7 +7168,7 @@ function TableHead({ className, ...props }) {
6367
7168
  {
6368
7169
  "data-slot": "table-head",
6369
7170
  className: cn(
6370
- "text-foreground has([role=checkbox])]:pr-0 h-12 px-3 text-left align-middle font-medium whitespace-nowrap",
7171
+ "text-foreground has-[[role=checkbox]]:pr-0 h-12 px-3 text-left align-middle font-medium whitespace-nowrap",
6371
7172
  className
6372
7173
  ),
6373
7174
  ...props
@@ -6380,7 +7181,7 @@ function TableCell({ className, ...props }) {
6380
7181
  {
6381
7182
  "data-slot": "table-cell",
6382
7183
  className: cn(
6383
- "has([role=checkbox])]:pr-0 p-3 align-middle whitespace-nowrap",
7184
+ "has-[[role=checkbox]]:pr-0 p-3 align-middle whitespace-nowrap",
6384
7185
  className
6385
7186
  ),
6386
7187
  ...props
@@ -6630,18 +7431,6 @@ function TablePaginationBase({
6630
7431
  );
6631
7432
  }
6632
7433
  var TablePagination = react.memo(TablePaginationBase);
6633
- function useMediaQuery(query) {
6634
- const [matches, setMatches] = react.useState(false);
6635
- react.useEffect(() => {
6636
- if (typeof window === "undefined") return;
6637
- const mql = window.matchMedia(query);
6638
- setMatches(mql.matches);
6639
- const handler = (e) => setMatches(e.matches);
6640
- mql.addEventListener("change", handler);
6641
- return () => mql.removeEventListener("change", handler);
6642
- }, [query]);
6643
- return matches;
6644
- }
6645
7434
  var TableContext = react.createContext(null);
6646
7435
  function useTableContext() {
6647
7436
  const ctx = react.useContext(TableContext);
@@ -6653,6 +7442,13 @@ function useTableContext() {
6653
7442
  function useTableContextSafe() {
6654
7443
  return react.useContext(TableContext);
6655
7444
  }
7445
+
7446
+ // src/components/compounds/Table/cell-size-class.ts
7447
+ var cellSizeClass = {
7448
+ sm: "px-3 py-1.5 text-xs",
7449
+ md: "px-5 py-2.5 text-sm",
7450
+ lg: "px-6 py-3 text-sm"
7451
+ };
6656
7452
  var cardPadding = {
6657
7453
  sm: "p-3",
6658
7454
  md: "p-4",
@@ -6990,6 +7786,9 @@ function DataTableHeaderCell({ header }) {
6990
7786
  },
6991
7787
  className: cn(
6992
7788
  "bg-primary text-primary-foreground",
7789
+ // Same density padding as the body cells: without it the header
7790
+ // label and the cell value below it sit at different offsets.
7791
+ cellSizeClass[meta.size ?? tableSize],
6993
7792
  canResize && "relative",
6994
7793
  meta.align === "center" && "text-center",
6995
7794
  meta.align === "right" && "text-right",
@@ -7379,11 +8178,6 @@ function useTablePersistence({
7379
8178
  persistDensity
7380
8179
  };
7381
8180
  }
7382
- var cellSizeClass = {
7383
- sm: "px-1 py-0 text-xs",
7384
- md: "px-5 py-2.5 text-sm",
7385
- lg: "px-6 py-3 text-sm"
7386
- };
7387
8181
  function resolveClassName(value, row) {
7388
8182
  return typeof value === "function" ? value(row) : value;
7389
8183
  }
@@ -7424,6 +8218,13 @@ function DataTableCell({
7424
8218
  }
7425
8219
  );
7426
8220
  }
8221
+ var INTERACTIVE_CELL_CONTENT = 'button, a, input, select, textarea, [role="button"], [role="checkbox"], [role="menuitem"], [role="link"]';
8222
+ function isInteractiveCellEvent(event) {
8223
+ const target = event.target;
8224
+ if (!(target instanceof Element)) return false;
8225
+ const match = target.closest(INTERACTIVE_CELL_CONTENT);
8226
+ return match !== null && match !== event.currentTarget;
8227
+ }
7427
8228
  function DataTableRow({ row, classNames }) {
7428
8229
  const { onRowClick, variant } = useTableContext();
7429
8230
  const clickable = Boolean(onRowClick);
@@ -7436,12 +8237,15 @@ function DataTableRow({ row, classNames }) {
7436
8237
  "data-clickable": clickable || void 0,
7437
8238
  role: clickable ? "button" : void 0,
7438
8239
  tabIndex: clickable ? 0 : void 0,
7439
- onClick: clickable ? () => onRowClick?.(row.original) : void 0,
8240
+ onClick: clickable ? (e) => {
8241
+ if (isInteractiveCellEvent(e)) return;
8242
+ onRowClick?.(row.original);
8243
+ } : void 0,
7440
8244
  onKeyDown: clickable ? (e) => {
7441
- if (e.key === "Enter" || e.key === " ") {
7442
- e.preventDefault();
7443
- onRowClick?.(row.original);
7444
- }
8245
+ if (e.key !== "Enter" && e.key !== " ") return;
8246
+ if (isInteractiveCellEvent(e)) return;
8247
+ e.preventDefault();
8248
+ onRowClick?.(row.original);
7445
8249
  } : void 0,
7446
8250
  className: cn("hover:bg-muted", clickable && "cursor-pointer", rowClassName),
7447
8251
  children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsxRuntime.jsx(DataTableCell, { cell, cellClassName }, cell.id))
@@ -8042,7 +8846,7 @@ function DataTableFooter({ pagination, selectedCount, className }) {
8042
8846
  className: cn("flex items-center justify-between border-t px-4 py-2", className),
8043
8847
  children: [
8044
8848
  selectedCount != null && selectedCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-live": "polite", className: "text-muted-foreground text-xs", children: `${selectedCount} row${selectedCount > 1 ? "s" : ""} selected` }),
8045
- /* @__PURE__ */ jsxRuntime.jsx(TablePagination, { ...pagination })
8849
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto", children: /* @__PURE__ */ jsxRuntime.jsx(TablePagination, { ...pagination }) })
8046
8850
  ]
8047
8851
  }
8048
8852
  );
@@ -8151,18 +8955,21 @@ function DataTableSearch({
8151
8955
  debounce = 300
8152
8956
  }) {
8153
8957
  const ctx = useTableContextSafe();
8154
- const [inputValue, setInputValue] = react.useState("");
8155
8958
  const globalFilter = ctx?.globalFilter;
8156
8959
  const setGlobalFilter = ctx?.setGlobalFilter;
8960
+ const committedValue = globalFilter ?? "";
8961
+ const [inputValue, setInputValue] = react.useState(committedValue);
8157
8962
  react.useEffect(() => {
8158
- if (globalFilter === "") setInputValue("");
8963
+ if (globalFilter === void 0) return;
8964
+ setInputValue(globalFilter);
8159
8965
  }, [globalFilter]);
8160
8966
  react.useEffect(() => {
8967
+ if (inputValue === committedValue) return;
8161
8968
  const timer = setTimeout(() => {
8162
8969
  setGlobalFilter?.(inputValue);
8163
8970
  }, debounce);
8164
8971
  return () => clearTimeout(timer);
8165
- }, [inputValue, debounce, setGlobalFilter]);
8972
+ }, [inputValue, committedValue, debounce, setGlobalFilter]);
8166
8973
  const handleClear = () => {
8167
8974
  setInputValue("");
8168
8975
  setGlobalFilter?.("");
@@ -8183,7 +8990,13 @@ function DataTableSearch({
8183
8990
  onChange: (e) => setInputValue(e.target.value),
8184
8991
  placeholder,
8185
8992
  "aria-label": placeholder,
8186
- className: "h-8 w-48 pr-8 pl-8 text-sm"
8993
+ className: cn(
8994
+ "h-8 w-48 pr-9 pl-9 text-sm",
8995
+ "[&::-webkit-search-cancel-button]:appearance-none",
8996
+ "[&::-webkit-search-decoration]:appearance-none",
8997
+ "[&::-webkit-search-results-button]:appearance-none",
8998
+ "[&::-webkit-search-results-decoration]:appearance-none"
8999
+ )
8187
9000
  }
8188
9001
  ),
8189
9002
  inputValue && /* @__PURE__ */ jsxRuntime.jsx(
@@ -8193,12 +9006,382 @@ function DataTableSearch({
8193
9006
  size: "icon-sm",
8194
9007
  onClick: handleClear,
8195
9008
  "aria-label": "Clear search",
8196
- className: "text-muted-foreground hover:text-foreground absolute right-0.5 size-6",
9009
+ className: "text-muted-foreground hover:text-foreground absolute top-1/2 right-1.5 size-6 -translate-y-1/2",
8197
9010
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3.5", "aria-hidden": "true" })
8198
9011
  }
8199
9012
  )
8200
9013
  ] });
8201
9014
  }
9015
+ function BottomNav({ items, className }) {
9016
+ return /* @__PURE__ */ jsxRuntime.jsx(
9017
+ "nav",
9018
+ {
9019
+ "data-slot": "bottom-nav",
9020
+ className: cn(
9021
+ "fixed bottom-0 left-0 right-0 z-50 mx-4 mb-4 rounded-2xl bg-background shadow-[0_-4px_20px_rgba(0,0,0,0.08)]",
9022
+ className
9023
+ ),
9024
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-20 items-center justify-around px-4", children: items.map(({ label, href, icon, isActive, onClick }) => /* @__PURE__ */ jsxRuntime.jsxs(
9025
+ "a",
9026
+ {
9027
+ href,
9028
+ onClick,
9029
+ "data-slot": "bottom-nav-item",
9030
+ className: cn(
9031
+ "group flex flex-col items-center gap-0 transition-colors",
9032
+ isActive ? "text-primary" : "text-muted-foreground"
9033
+ ),
9034
+ children: [
9035
+ /* @__PURE__ */ jsxRuntime.jsxs(
9036
+ "span",
9037
+ {
9038
+ className: cn(
9039
+ "flex h-12 items-center justify-center rounded-2xl transition-all",
9040
+ isActive ? "flex-col gap-0.5 bg-primary/10 px-4" : "w-12 group-hover:bg-muted group-active:bg-primary/10"
9041
+ ),
9042
+ children: [
9043
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-6 w-6 shrink-0", children: icon }),
9044
+ isActive && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold leading-none", children: label })
9045
+ ]
9046
+ }
9047
+ ),
9048
+ /* @__PURE__ */ jsxRuntime.jsx(
9049
+ "span",
9050
+ {
9051
+ className: cn(
9052
+ "text-[10px] font-medium",
9053
+ isActive ? "invisible" : "visible"
9054
+ ),
9055
+ children: label
9056
+ }
9057
+ ),
9058
+ /* @__PURE__ */ jsxRuntime.jsx(
9059
+ "span",
9060
+ {
9061
+ className: cn(
9062
+ "h-1 w-5 rounded-full transition-all",
9063
+ isActive ? "bg-primary" : "bg-transparent"
9064
+ )
9065
+ }
9066
+ )
9067
+ ]
9068
+ },
9069
+ href
9070
+ )) })
9071
+ }
9072
+ );
9073
+ }
9074
+ var BottomNavTabsContext = react.createContext(null);
9075
+ function useBottomNavTabsContext() {
9076
+ const ctx = react.useContext(BottomNavTabsContext);
9077
+ if (!ctx) throw new Error("BottomNavTabsList must be inside BottomNavTabs");
9078
+ return ctx;
9079
+ }
9080
+ function BottomNavTabs({
9081
+ defaultValue,
9082
+ value: controlledValue,
9083
+ onValueChange,
9084
+ ...props
9085
+ }) {
9086
+ const [internalValue, setInternalValue] = react.useState(controlledValue ?? defaultValue ?? "");
9087
+ const activeValue = controlledValue ?? internalValue;
9088
+ const listId = react.useId();
9089
+ const handleValueChange = (v) => {
9090
+ if (controlledValue === void 0) setInternalValue(v);
9091
+ onValueChange?.(v);
9092
+ };
9093
+ return /* @__PURE__ */ jsxRuntime.jsx(BottomNavTabsContext.Provider, { value: { activeValue, listId }, children: /* @__PURE__ */ jsxRuntime.jsx(
9094
+ radixUi.Tabs.Root,
9095
+ {
9096
+ "data-slot": "bottom-nav-tabs",
9097
+ value: activeValue,
9098
+ onValueChange: handleValueChange,
9099
+ ...props
9100
+ }
9101
+ ) });
9102
+ }
9103
+ function BottomNavTabsContent({
9104
+ className,
9105
+ ...props
9106
+ }) {
9107
+ return /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { className: cn("pb-28", className), ...props });
9108
+ }
9109
+ function BottomNavTabsList({ items, className }) {
9110
+ const { activeValue, listId } = useBottomNavTabsContext();
9111
+ return /* @__PURE__ */ jsxRuntime.jsx(
9112
+ "nav",
9113
+ {
9114
+ "data-slot": "bottom-nav-tabs-list",
9115
+ className: cn(
9116
+ "fixed bottom-0 left-0 right-0 z-50 mx-6 max-w- mb-4 rounded-2xl bg-background shadow-[0_-4px_20px_rgba(0,0,0,0.08)]",
9117
+ className
9118
+ ),
9119
+ children: /* @__PURE__ */ jsxRuntime.jsx(radixUi.Tabs.List, { className: "flex h-20 items-center justify-around px-4", children: items.map(({ value, label, icon, activeIcon }) => {
9120
+ const isActive = value === activeValue;
9121
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9122
+ radixUi.Tabs.Trigger,
9123
+ {
9124
+ value,
9125
+ "data-slot": "bottom-nav-tabs-trigger",
9126
+ className: cn(
9127
+ "group flex flex-col items-center transition-colors",
9128
+ "data-[state=active]:text-primary data-[state=inactive]:text-muted-foreground",
9129
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:rounded-2xl"
9130
+ ),
9131
+ children: [
9132
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-15 w-16 flex-col items-center justify-center gap-1.5", children: [
9133
+ /* @__PURE__ */ jsxRuntime.jsx(react$1.AnimatePresence, { initial: false, children: isActive && /* @__PURE__ */ jsxRuntime.jsx(
9134
+ react$1.motion.span,
9135
+ {
9136
+ layoutId: `${listId}-pill`,
9137
+ className: "absolute inset-0 rounded-2xl bg-primary/10",
9138
+ transition: spring.snappy
9139
+ }
9140
+ ) }),
9141
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10 h-6 w-6", children: isActive ? activeIcon ?? icon : icon }),
9142
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10 text-[10px] font-medium leading-none", children: label })
9143
+ ] }),
9144
+ /* @__PURE__ */ jsxRuntime.jsx(
9145
+ "span",
9146
+ {
9147
+ className: cn(
9148
+ "mt-1 h-1 w-6 rounded-full transition-colors",
9149
+ isActive ? "bg-primary" : "bg-transparent"
9150
+ )
9151
+ }
9152
+ )
9153
+ ]
9154
+ },
9155
+ value
9156
+ );
9157
+ }) })
9158
+ }
9159
+ );
9160
+ }
9161
+ var DrawerContext = react.createContext({ isOpen: false, modal: true });
9162
+ function Drawer({ children, open, onOpenChange, modal = true, ...props }) {
9163
+ const [internalOpen, setInternalOpen] = react.useState(props.defaultOpen ?? false);
9164
+ const isOpen = open !== void 0 ? open : internalOpen;
9165
+ return /* @__PURE__ */ jsxRuntime.jsx(DrawerContext.Provider, { value: { isOpen, modal }, children: /* @__PURE__ */ jsxRuntime.jsx(
9166
+ radixUi.Dialog.Root,
9167
+ {
9168
+ "data-slot": "drawer",
9169
+ modal,
9170
+ ...props,
9171
+ open: isOpen,
9172
+ onOpenChange: (v) => {
9173
+ setInternalOpen(v);
9174
+ onOpenChange?.(v);
9175
+ },
9176
+ children
9177
+ }
9178
+ ) });
9179
+ }
9180
+ function DrawerTrigger({ ...props }) {
9181
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Trigger, { "data-slot": "drawer-trigger", ...props });
9182
+ }
9183
+ function DrawerClose({ ...props }) {
9184
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Close, { "data-slot": "drawer-close", ...props });
9185
+ }
9186
+ function DrawerPortal({ children, ...props }) {
9187
+ const { isOpen } = react.useContext(DrawerContext);
9188
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Portal, { forceMount: true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(react$1.AnimatePresence, { mode: "sync", children: isOpen && children }) });
9189
+ }
9190
+ function DrawerOverlay({ className, ...props }) {
9191
+ return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Overlay, { "data-slot": "drawer-overlay", asChild: true, forceMount: true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx(
9192
+ react$1.motion.div,
9193
+ {
9194
+ className: cn(
9195
+ "fixed inset-0 isolate z-50 bg-black/30 supports-backdrop-filter:backdrop-blur-sm",
9196
+ className
9197
+ ),
9198
+ initial: { opacity: 0 },
9199
+ animate: { opacity: 1 },
9200
+ exit: { opacity: 0 },
9201
+ transition: { duration: duration.normal, ease: ease.smooth }
9202
+ }
9203
+ ) });
9204
+ }
9205
+ var sizeClasses = {
9206
+ sm: "w-64",
9207
+ md: "w-80",
9208
+ lg: "w-96",
9209
+ xl: "w-[30rem]",
9210
+ full: "w-screen"
9211
+ };
9212
+ function DrawerContent({
9213
+ className,
9214
+ children,
9215
+ side = "right",
9216
+ size = "md",
9217
+ showCloseButton = true,
9218
+ resizable = false,
9219
+ ...props
9220
+ }) {
9221
+ const isHorizontal = side === "left" || side === "right";
9222
+ const xInitial = side === "right" ? "100%" : side === "left" ? "-100%" : 0;
9223
+ const yInitial = side === "bottom" ? "100%" : side === "top" ? "-100%" : 0;
9224
+ const dragRef = react.useRef(null);
9225
+ const { modal } = react.useContext(DrawerContext);
9226
+ return /* @__PURE__ */ jsxRuntime.jsxs(DrawerPortal, { children: [
9227
+ modal && /* @__PURE__ */ jsxRuntime.jsx(DrawerOverlay, {}, "drawer-overlay"),
9228
+ /* @__PURE__ */ jsxRuntime.jsx(
9229
+ radixUi.Dialog.Content,
9230
+ {
9231
+ "data-slot": "drawer-content",
9232
+ "data-side": side,
9233
+ asChild: true,
9234
+ forceMount: true,
9235
+ className: cn(
9236
+ "fixed z-50 flex flex-col bg-popover text-popover-foreground shadow-xl outline-none",
9237
+ side === "left" && "inset-y-0 left-0",
9238
+ side === "right" && "inset-y-0 right-0",
9239
+ side === "top" && "inset-x-0 top-0",
9240
+ side === "bottom" && "inset-x-0 bottom-0",
9241
+ isHorizontal && sizeClasses[size],
9242
+ !isHorizontal && "h-auto min-h-40",
9243
+ className
9244
+ ),
9245
+ ...props,
9246
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
9247
+ react$1.motion.div,
9248
+ {
9249
+ className: cn("flex flex-col", isHorizontal && "h-full"),
9250
+ initial: { x: xInitial, y: yInitial, opacity: 0 },
9251
+ animate: { x: 0, y: 0, opacity: 1, transition: transition.drawer },
9252
+ exit: { x: xInitial, y: yInitial, opacity: 0, transition: transition.drawerExit },
9253
+ children: [
9254
+ children,
9255
+ showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Close, { "data-slot": "drawer-close", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
9256
+ Button,
9257
+ {
9258
+ variant: "ghost",
9259
+ className: "absolute top-4 right-4",
9260
+ size: "icon-sm",
9261
+ children: [
9262
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, {}),
9263
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
9264
+ ]
9265
+ }
9266
+ ) }),
9267
+ resizable && /* @__PURE__ */ jsxRuntime.jsx(
9268
+ "div",
9269
+ {
9270
+ "data-slot": "drawer-resize-handle",
9271
+ className: cn(
9272
+ "absolute opacity-0 transition-opacity hover:opacity-100 hover:bg-border",
9273
+ side === "right" && "inset-y-0 left-0 w-1 cursor-col-resize",
9274
+ side === "left" && "inset-y-0 right-0 w-1 cursor-col-resize",
9275
+ side === "top" && "inset-x-0 bottom-0 h-1 cursor-row-resize",
9276
+ side === "bottom" && "inset-x-0 top-0 h-1 cursor-row-resize"
9277
+ ),
9278
+ onPointerDown: (e) => {
9279
+ e.preventDefault();
9280
+ const content = e.currentTarget.parentElement;
9281
+ if (!content) return;
9282
+ const startSize = isHorizontal ? parseFloat(getComputedStyle(content).width) : parseFloat(getComputedStyle(content).height);
9283
+ content.style.transition = "none";
9284
+ dragRef.current = {
9285
+ startPos: isHorizontal ? e.clientX : e.clientY,
9286
+ startSize,
9287
+ content
9288
+ };
9289
+ e.currentTarget.setPointerCapture(e.pointerId);
9290
+ },
9291
+ onPointerMove: (e) => {
9292
+ if (!dragRef.current) return;
9293
+ const { startPos, startSize, content } = dragRef.current;
9294
+ const delta = (isHorizontal ? e.clientX : e.clientY) - startPos;
9295
+ let newSize;
9296
+ if (side === "right") {
9297
+ newSize = Math.max(160, Math.min(window.innerWidth * 0.9, startSize - delta));
9298
+ } else if (side === "left") {
9299
+ newSize = Math.max(160, Math.min(window.innerWidth * 0.9, startSize + delta));
9300
+ } else if (side === "bottom") {
9301
+ newSize = Math.max(80, Math.min(window.innerHeight * 0.9, startSize - delta));
9302
+ } else {
9303
+ newSize = Math.max(80, Math.min(window.innerHeight * 0.9, startSize + delta));
9304
+ }
9305
+ content.style[isHorizontal ? "width" : "height"] = `${newSize}px`;
9306
+ },
9307
+ onPointerUp: () => {
9308
+ if (dragRef.current?.content) {
9309
+ dragRef.current.content.style.transition = "";
9310
+ }
9311
+ dragRef.current = null;
9312
+ },
9313
+ onPointerCancel: () => {
9314
+ if (dragRef.current?.content) {
9315
+ dragRef.current.content.style.transition = "";
9316
+ }
9317
+ dragRef.current = null;
9318
+ }
9319
+ }
9320
+ )
9321
+ ]
9322
+ }
9323
+ )
9324
+ },
9325
+ "drawer-content"
9326
+ )
9327
+ ] });
9328
+ }
9329
+ function DrawerHeader({ className, ...props }) {
9330
+ return /* @__PURE__ */ jsxRuntime.jsx(
9331
+ "div",
9332
+ {
9333
+ "data-slot": "drawer-header",
9334
+ className: cn("flex shrink-0 flex-col gap-1.5 p-6", className),
9335
+ ...props
9336
+ }
9337
+ );
9338
+ }
9339
+ function DrawerBody({ className, ...props }) {
9340
+ return /* @__PURE__ */ jsxRuntime.jsx(
9341
+ "div",
9342
+ {
9343
+ "data-slot": "drawer-body",
9344
+ className: cn("flex-1 overflow-y-auto px-6 pb-6", className),
9345
+ ...props
9346
+ }
9347
+ );
9348
+ }
9349
+ function DrawerFooter({ className, ...props }) {
9350
+ return /* @__PURE__ */ jsxRuntime.jsx(
9351
+ "div",
9352
+ {
9353
+ "data-slot": "drawer-footer",
9354
+ className: cn(
9355
+ "border-border mt-auto flex shrink-0 flex-wrap items-center justify-end gap-2 border-t px-6 py-4",
9356
+ className
9357
+ ),
9358
+ ...props
9359
+ }
9360
+ );
9361
+ }
9362
+ function DrawerTitle({ className, ...props }) {
9363
+ return /* @__PURE__ */ jsxRuntime.jsx(
9364
+ radixUi.Dialog.Title,
9365
+ {
9366
+ "data-slot": "drawer-title",
9367
+ className: cn("font-heading text-base leading-none font-semibold", className),
9368
+ ...props
9369
+ }
9370
+ );
9371
+ }
9372
+ function DrawerDescription({
9373
+ className,
9374
+ ...props
9375
+ }) {
9376
+ return /* @__PURE__ */ jsxRuntime.jsx(
9377
+ radixUi.Dialog.Description,
9378
+ {
9379
+ "data-slot": "drawer-description",
9380
+ className: cn("text-sm text-muted-foreground", className),
9381
+ ...props
9382
+ }
9383
+ );
9384
+ }
8202
9385
  function TCCEProvider({
8203
9386
  children,
8204
9387
  permissions,
@@ -8248,6 +9431,10 @@ exports.AvatarGroup = AvatarGroup;
8248
9431
  exports.AvatarGroupCount = AvatarGroupCount;
8249
9432
  exports.AvatarImage = AvatarImage;
8250
9433
  exports.Badge = Badge2;
9434
+ exports.BottomNav = BottomNav;
9435
+ exports.BottomNavTabs = BottomNavTabs;
9436
+ exports.BottomNavTabsContent = BottomNavTabsContent;
9437
+ exports.BottomNavTabsList = BottomNavTabsList;
8251
9438
  exports.Breadcrumb = Breadcrumb;
8252
9439
  exports.BreadcrumbEllipsis = BreadcrumbEllipsis;
8253
9440
  exports.BreadcrumbItem = BreadcrumbItem;
@@ -8256,8 +9443,6 @@ exports.BreadcrumbList = BreadcrumbList;
8256
9443
  exports.BreadcrumbPage = BreadcrumbPage;
8257
9444
  exports.BreadcrumbSeparator = BreadcrumbSeparator;
8258
9445
  exports.Button = Button;
8259
- exports.Calendar = Calendar;
8260
- exports.CalendarDayButton = CalendarDayButton;
8261
9446
  exports.Can = Can;
8262
9447
  exports.CanNot = CanNot;
8263
9448
  exports.Card = Card;
@@ -8303,6 +9488,17 @@ exports.DialogOverlay = DialogOverlay;
8303
9488
  exports.DialogPortal = DialogPortal;
8304
9489
  exports.DialogTitle = DialogTitle;
8305
9490
  exports.DialogTrigger = DialogTrigger;
9491
+ exports.Drawer = Drawer;
9492
+ exports.DrawerBody = DrawerBody;
9493
+ exports.DrawerClose = DrawerClose;
9494
+ exports.DrawerContent = DrawerContent;
9495
+ exports.DrawerDescription = DrawerDescription;
9496
+ exports.DrawerFooter = DrawerFooter;
9497
+ exports.DrawerHeader = DrawerHeader;
9498
+ exports.DrawerOverlay = DrawerOverlay;
9499
+ exports.DrawerPortal = DrawerPortal;
9500
+ exports.DrawerTitle = DrawerTitle;
9501
+ exports.DrawerTrigger = DrawerTrigger;
8306
9502
  exports.DropdownMenu = DropdownMenu;
8307
9503
  exports.DropdownMenuCheckboxItem = DropdownMenuCheckboxItem;
8308
9504
  exports.DropdownMenuContent = DropdownMenuContent;
@@ -8345,6 +9541,8 @@ exports.ItemHeader = ItemHeader;
8345
9541
  exports.ItemMedia = ItemMedia;
8346
9542
  exports.ItemSeparator = ItemSeparator;
8347
9543
  exports.ItemTitle = ItemTitle;
9544
+ exports.KNOWN_PERMISSIONS = KNOWN_PERMISSIONS;
9545
+ exports.Label = Label;
8348
9546
  exports.Link = Link;
8349
9547
  exports.Logo = Logo;
8350
9548
  exports.MiniCalendar = MiniCalendar;
@@ -8367,6 +9565,7 @@ exports.PaginationItem = PaginationItem;
8367
9565
  exports.PaginationLink = PaginationLink;
8368
9566
  exports.PaginationNext = PaginationNext;
8369
9567
  exports.PaginationPrevious = PaginationPrevious;
9568
+ exports.PhoneField = PhoneField;
8370
9569
  exports.PinInput = PinInput;
8371
9570
  exports.Popover = Popover;
8372
9571
  exports.PopoverAnchor = PopoverAnchor;
@@ -8503,6 +9702,7 @@ exports.toggleVariants = toggleVariants;
8503
9702
  exports.tooltipContentVariants = tooltipContentVariants;
8504
9703
  exports.transition = transition;
8505
9704
  exports.useAbility = useAbility;
9705
+ exports.useAbilityStatus = useAbilityStatus;
8506
9706
  exports.useAppForm = useAppForm;
8507
9707
  exports.useCan = useCan;
8508
9708
  exports.useCarousel = useCarousel;
@@ -8517,5 +9717,6 @@ exports.useTableSizing = useTableSizing;
8517
9717
  exports.useTableSorting = useTableSorting;
8518
9718
  exports.useTableVisibility = useTableVisibility;
8519
9719
  exports.useToast = useToast;
9720
+ exports.validatePhone = validatePhone;
8520
9721
  //# sourceMappingURL=main.cjs.map
8521
9722
  //# sourceMappingURL=main.cjs.map