@bmsuisse/ui 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3369,7 +3369,9 @@ function Stepper({
3369
3369
  navLabel = "Steps",
3370
3370
  newLabel = "New",
3371
3371
  scrollTestId = "stepper-scroll",
3372
- newTestId
3372
+ newTestId,
3373
+ minWidth,
3374
+ className
3373
3375
  }) {
3374
3376
  const stepRefs = useRef8(/* @__PURE__ */ new Map());
3375
3377
  useEffect8(() => {
@@ -3380,69 +3382,76 @@ function Stepper({
3380
3382
  // onNew is pinned outside the horizontally-scrolling region below (a sibling of
3381
3383
  // it, not a child) so its own edge never scrolls off-screen along with the
3382
3384
  // later steps once the scroller's min-width doesn't fit the viewport.
3383
- /* @__PURE__ */ jsxs30("div", { className: "flex w-full shrink-0 items-center gap-2", children: [
3385
+ /* @__PURE__ */ jsxs30("div", { className: cn("flex w-full shrink-0 items-center gap-2", className), children: [
3384
3386
  /* @__PURE__ */ jsx48("nav", { "aria-label": navLabel, className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx48(
3385
3387
  "div",
3386
3388
  {
3387
3389
  "data-testid": scrollTestId,
3388
3390
  className: "flex w-full items-center gap-0 overflow-x-auto px-2 py-1",
3389
- children: /* @__PURE__ */ jsx48("ol", { className: "flex min-w-[700px] flex-1 items-start", children: steps.map(({ n, label, phase }, i) => {
3390
- const done = step > n;
3391
- const active = step === n;
3392
- const navigable = n <= maxStep && n !== step;
3393
- const last = i === steps.length - 1;
3394
- return /* @__PURE__ */ jsxs30("li", { className: cn("flex items-start", !last && "flex-1"), children: [
3395
- /* @__PURE__ */ jsxs30(
3396
- "button",
3397
- {
3398
- ref: (element) => {
3399
- if (element) stepRefs.current.set(n, element);
3400
- else stepRefs.current.delete(n);
3401
- },
3402
- "data-testid": `step-${n}`,
3403
- "aria-disabled": !navigable,
3404
- "aria-current": active ? "step" : void 0,
3405
- onClick: () => navigable && onNavigate(n),
3406
- className: cn(
3407
- "flex min-w-[68px] flex-col items-center gap-0.5 transition-opacity",
3408
- navigable ? "cursor-pointer hover:opacity-80" : "cursor-default"
3409
- ),
3410
- children: [
3411
- /* @__PURE__ */ jsx48(
3412
- "div",
3413
- {
3414
- className: cn(
3415
- "flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-[11px] font-bold transition-colors",
3416
- done ? "bg-primary/15 text-primary" : active ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"
3391
+ children: /* @__PURE__ */ jsx48(
3392
+ "ol",
3393
+ {
3394
+ className: cn("flex flex-1 items-start", minWidth === void 0 && "min-w-fit"),
3395
+ style: minWidth === void 0 ? void 0 : { minWidth },
3396
+ children: steps.map(({ n, label, phase }, i) => {
3397
+ const done = step > n;
3398
+ const active = step === n;
3399
+ const navigable = n <= maxStep && n !== step;
3400
+ const last = i === steps.length - 1;
3401
+ return /* @__PURE__ */ jsxs30("li", { className: cn("flex items-start", !last && "flex-1"), children: [
3402
+ /* @__PURE__ */ jsxs30(
3403
+ "button",
3404
+ {
3405
+ ref: (element) => {
3406
+ if (element) stepRefs.current.set(n, element);
3407
+ else stepRefs.current.delete(n);
3408
+ },
3409
+ "data-testid": `step-${n}`,
3410
+ "aria-disabled": !navigable,
3411
+ "aria-current": active ? "step" : void 0,
3412
+ onClick: () => navigable && onNavigate(n),
3413
+ className: cn(
3414
+ "flex min-w-[68px] flex-col items-center gap-0.5 transition-opacity",
3415
+ navigable ? "cursor-pointer hover:opacity-80" : "cursor-default"
3416
+ ),
3417
+ children: [
3418
+ /* @__PURE__ */ jsx48(
3419
+ "div",
3420
+ {
3421
+ className: cn(
3422
+ "flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-[11px] font-bold transition-colors",
3423
+ done ? "bg-primary/15 text-primary" : active ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"
3424
+ ),
3425
+ children: done ? /* @__PURE__ */ jsx48(CheckIcon5, { className: "h-3 w-3" }) : n
3426
+ }
3417
3427
  ),
3418
- children: done ? /* @__PURE__ */ jsx48(CheckIcon5, { className: "h-3 w-3" }) : n
3419
- }
3420
- ),
3421
- /* @__PURE__ */ jsx48(
3422
- "span",
3423
- {
3424
- className: cn(
3425
- "text-center whitespace-nowrap transition-colors",
3426
- active ? "text-[12px] font-semibold text-foreground" : done ? "text-[12px] font-medium text-primary" : "text-[12px] font-medium text-muted-foreground"
3428
+ /* @__PURE__ */ jsx48(
3429
+ "span",
3430
+ {
3431
+ className: cn(
3432
+ "text-center whitespace-nowrap transition-colors",
3433
+ active ? "text-[12px] font-semibold text-foreground" : done ? "text-[12px] font-medium text-primary" : "text-[12px] font-medium text-muted-foreground"
3434
+ ),
3435
+ children: label
3436
+ }
3427
3437
  ),
3428
- children: label
3429
- }
3430
- ),
3431
- /* @__PURE__ */ jsx48("span", { className: "text-[9px] tracking-[0.5px] text-muted-foreground/50 uppercase", children: phase })
3432
- ]
3433
- }
3434
- ),
3435
- !last && /* @__PURE__ */ jsx48(
3436
- "div",
3437
- {
3438
- className: cn(
3439
- "mx-1.5 mt-3.5 h-px flex-1 transition-colors",
3440
- done ? "bg-primary" : "bg-border"
3438
+ phase && /* @__PURE__ */ jsx48("span", { className: "text-[9px] tracking-[0.5px] text-muted-foreground/50 uppercase", children: phase })
3439
+ ]
3440
+ }
3441
+ ),
3442
+ !last && /* @__PURE__ */ jsx48(
3443
+ "div",
3444
+ {
3445
+ className: cn(
3446
+ "mx-1.5 mt-3.5 h-px flex-1 transition-colors",
3447
+ done ? "bg-primary" : "bg-border"
3448
+ )
3449
+ }
3441
3450
  )
3442
- }
3443
- )
3444
- ] }, n);
3445
- }) })
3451
+ ] }, n);
3452
+ })
3453
+ }
3454
+ )
3446
3455
  }
3447
3456
  ) }),
3448
3457
  onNew && /* @__PURE__ */ jsxs30(
@@ -3462,11 +3471,717 @@ function Stepper({
3462
3471
  );
3463
3472
  }
3464
3473
 
3474
+ // src/patterns/empty-state/EmptyState.tsx
3475
+ import { FunnelIcon } from "@heroicons/react/24/outline";
3476
+ import { jsx as jsx49, jsxs as jsxs31 } from "react/jsx-runtime";
3477
+ var EmptyState = ({
3478
+ title,
3479
+ description,
3480
+ icon: Icon2,
3481
+ action,
3482
+ size = "md",
3483
+ fill = false,
3484
+ className,
3485
+ ...props
3486
+ }) => {
3487
+ const sm = size === "sm";
3488
+ return /* @__PURE__ */ jsxs31(
3489
+ "div",
3490
+ {
3491
+ "data-testid": "empty-state",
3492
+ className: cn(
3493
+ "flex flex-col items-center text-center",
3494
+ sm ? "gap-1 px-4 py-4" : "gap-1.5 px-6 py-8",
3495
+ fill && "min-h-0 flex-1 justify-center",
3496
+ className
3497
+ ),
3498
+ ...props,
3499
+ children: [
3500
+ Icon2 ? /* @__PURE__ */ jsx49(
3501
+ "div",
3502
+ {
3503
+ className: cn(
3504
+ "mb-1 flex items-center justify-center rounded-full bg-muted",
3505
+ sm ? "h-8 w-8" : "h-12 w-12"
3506
+ ),
3507
+ children: /* @__PURE__ */ jsx49(Icon2, { "aria-hidden": "true", className: cn("text-muted-foreground", sm ? "h-4 w-4" : "h-6 w-6") })
3508
+ }
3509
+ ) : null,
3510
+ /* @__PURE__ */ jsx49("p", { className: cn("font-semibold text-foreground", sm ? "text-xs" : "text-sm"), children: title }),
3511
+ description ? /* @__PURE__ */ jsx49("p", { className: cn("max-w-prose text-muted-foreground", sm ? "text-xs" : "text-sm"), children: description }) : null,
3512
+ action ? /* @__PURE__ */ jsx49("div", { className: "mt-2 flex justify-center gap-2", children: action }) : null
3513
+ ]
3514
+ }
3515
+ );
3516
+ };
3517
+ var defaultFilteredEmptyStateLabels = {
3518
+ title: "No results",
3519
+ description: "Nothing matches the current search or filters.",
3520
+ reset: "Reset filters"
3521
+ };
3522
+ var FilteredEmptyState = ({
3523
+ onReset,
3524
+ labels,
3525
+ icon = FunnelIcon,
3526
+ size,
3527
+ ...props
3528
+ }) => {
3529
+ const l = { ...defaultFilteredEmptyStateLabels, ...labels };
3530
+ const rootTestId = props["data-testid"];
3531
+ return /* @__PURE__ */ jsx49(
3532
+ EmptyState,
3533
+ {
3534
+ icon,
3535
+ size,
3536
+ title: l.title,
3537
+ description: l.description,
3538
+ action: /* @__PURE__ */ jsx49(
3539
+ Button,
3540
+ {
3541
+ type: "button",
3542
+ variant: "outline",
3543
+ size: size === "sm" ? "xs" : "sm",
3544
+ onClick: onReset,
3545
+ "data-testid": typeof rootTestId === "string" ? `${rootTestId}-reset` : void 0,
3546
+ children: l.reset
3547
+ }
3548
+ ),
3549
+ ...props
3550
+ }
3551
+ );
3552
+ };
3553
+
3554
+ // src/patterns/toast/toastStore.ts
3555
+ var DEFAULT_TOAST_DURATION = { info: 4e3, success: 4e3, warning: 4e3, error: 8e3 };
3556
+ var MAX_TOASTS = 3;
3557
+ var TOAST_EXIT_MS = 150;
3558
+ var toasts = [];
3559
+ var nextId = 1;
3560
+ var listeners = /* @__PURE__ */ new Set();
3561
+ var emit = (next) => {
3562
+ toasts = next;
3563
+ for (const l of listeners) l();
3564
+ };
3565
+ var subscribeToasts = (listener) => {
3566
+ listeners.add(listener);
3567
+ return () => listeners.delete(listener);
3568
+ };
3569
+ var getToasts = () => toasts;
3570
+ var EMPTY = [];
3571
+ var getServerToasts = () => EMPTY;
3572
+ var remove = (id) => emit(toasts.filter((t) => t.id !== id));
3573
+ function dismissToast(id) {
3574
+ const targets = toasts.filter((t) => !t.leaving && (id === void 0 || t.id === id));
3575
+ if (targets.length === 0) return;
3576
+ const ids = new Set(targets.map((t) => t.id));
3577
+ emit(toasts.map((t) => ids.has(t.id) ? { ...t, leaving: true } : t));
3578
+ setTimeout(() => {
3579
+ for (const i of ids) remove(i);
3580
+ }, TOAST_EXIT_MS);
3581
+ }
3582
+ function show(message, options = {}) {
3583
+ const id = nextId++;
3584
+ const tone = options.tone ?? "info";
3585
+ const item = {
3586
+ id,
3587
+ message,
3588
+ description: options.description,
3589
+ tone,
3590
+ action: options.action,
3591
+ duration: options.duration,
3592
+ leaving: false
3593
+ };
3594
+ const active = toasts.filter((t) => !t.leaving);
3595
+ if (active.length >= MAX_TOASTS) {
3596
+ const victim = active.find((t) => t.duration !== Infinity) ?? active[0];
3597
+ if (victim) dismissToast(victim.id);
3598
+ }
3599
+ emit([...toasts, item]);
3600
+ return id;
3601
+ }
3602
+ var toast = Object.assign(show, {
3603
+ info: (message, options) => show(message, { ...options, tone: "info" }),
3604
+ success: (message, options) => show(message, { ...options, tone: "success" }),
3605
+ warning: (message, options) => show(message, { ...options, tone: "warning" }),
3606
+ error: (message, options) => show(message, { ...options, tone: "error" }),
3607
+ dismiss: dismissToast
3608
+ });
3609
+ function resetToasts() {
3610
+ emit([]);
3611
+ }
3612
+
3613
+ // src/patterns/toast/Toaster.tsx
3614
+ import {
3615
+ CheckCircleIcon as CheckCircleIcon2,
3616
+ ExclamationTriangleIcon as ExclamationTriangleIcon6,
3617
+ InformationCircleIcon as InformationCircleIcon2,
3618
+ XCircleIcon,
3619
+ XMarkIcon as XMarkIcon6
3620
+ } from "@heroicons/react/24/outline";
3621
+ import { useEffect as useEffect9, useRef as useRef9, useState as useState16, useSyncExternalStore } from "react";
3622
+ import { jsx as jsx50, jsxs as jsxs32 } from "react/jsx-runtime";
3623
+ var defaultToasterLabels = {
3624
+ region: "Notifications",
3625
+ dismiss: "Dismiss"
3626
+ };
3627
+ var positionClass = {
3628
+ "bottom-center": "bottom-4 items-center pb-[env(safe-area-inset-bottom)]",
3629
+ "bottom-left": "bottom-4 items-start pb-[env(safe-area-inset-bottom)]",
3630
+ "bottom-right": "bottom-4 items-end pb-[env(safe-area-inset-bottom)]",
3631
+ "top-center": "top-4 items-center pt-[env(safe-area-inset-top)]",
3632
+ "top-left": "top-4 items-start pt-[env(safe-area-inset-top)]",
3633
+ "top-right": "top-4 items-end pt-[env(safe-area-inset-top)]"
3634
+ };
3635
+ var toneIcon = {
3636
+ info: InformationCircleIcon2,
3637
+ success: CheckCircleIcon2,
3638
+ warning: ExclamationTriangleIcon6,
3639
+ error: XCircleIcon
3640
+ };
3641
+ var toneIconClass = {
3642
+ info: "text-sky-600 dark:text-sky-400",
3643
+ success: "text-emerald-600 dark:text-emerald-400",
3644
+ warning: "text-amber-600 dark:text-amber-400",
3645
+ error: "text-destructive"
3646
+ };
3647
+ var Toaster = ({ position = "bottom-center", duration, labels, className }) => {
3648
+ const toasts2 = useSyncExternalStore(subscribeToasts, getToasts, getServerToasts);
3649
+ const l = { ...defaultToasterLabels, ...labels };
3650
+ const top = position.startsWith("top");
3651
+ return /* @__PURE__ */ jsx50(
3652
+ "section",
3653
+ {
3654
+ "aria-label": l.region,
3655
+ "aria-live": "polite",
3656
+ className: cn(
3657
+ "pointer-events-none fixed inset-x-0 z-[100] flex gap-2 px-4",
3658
+ top ? "flex-col-reverse" : "flex-col",
3659
+ positionClass[position],
3660
+ className
3661
+ ),
3662
+ children: toasts2.map((t) => /* @__PURE__ */ jsx50(ToastCard, { toast: t, duration: resolveDuration(t, duration), dismissLabel: l.dismiss }, t.id))
3663
+ }
3664
+ );
3665
+ };
3666
+ var resolveDuration = (t, fallback) => t.duration ?? (typeof fallback === "number" ? fallback : fallback?.[t.tone] ?? DEFAULT_TOAST_DURATION[t.tone]);
3667
+ var ToastCard = ({
3668
+ toast: toast2,
3669
+ duration,
3670
+ dismissLabel
3671
+ }) => {
3672
+ const [entered, setEntered] = useState16(false);
3673
+ const [hovered, setHovered] = useState16(false);
3674
+ const [focused, setFocused] = useState16(false);
3675
+ const paused = hovered || focused;
3676
+ const bar = useRef9(null);
3677
+ const Icon2 = toneIcon[toast2.tone];
3678
+ const timed = Number.isFinite(duration) && duration > 0;
3679
+ useEffect9(() => {
3680
+ const raf = requestAnimationFrame(() => setEntered(true));
3681
+ return () => cancelAnimationFrame(raf);
3682
+ }, []);
3683
+ const remaining = useRef9(duration);
3684
+ const animRef = useRef9(null);
3685
+ useEffect9(() => {
3686
+ if (!timed || toast2.leaving) return;
3687
+ const el = bar.current;
3688
+ if (el && typeof el.animate === "function") {
3689
+ const anim = el.animate([{ transform: "scaleX(1)" }, { transform: "scaleX(0)" }], {
3690
+ duration,
3691
+ fill: "forwards"
3692
+ });
3693
+ anim.onfinish = () => dismissToast(toast2.id);
3694
+ animRef.current = anim;
3695
+ return () => {
3696
+ anim.onfinish = null;
3697
+ anim.cancel();
3698
+ animRef.current = null;
3699
+ };
3700
+ }
3701
+ return void 0;
3702
+ }, [timed, duration, toast2.id, toast2.leaving]);
3703
+ useEffect9(() => {
3704
+ if (!timed || toast2.leaving) return;
3705
+ if (animRef.current) {
3706
+ if (paused) animRef.current.pause();
3707
+ else animRef.current.play();
3708
+ return;
3709
+ }
3710
+ if (paused) return;
3711
+ const started = Date.now();
3712
+ const handle = setTimeout(() => dismissToast(toast2.id), remaining.current);
3713
+ return () => {
3714
+ clearTimeout(handle);
3715
+ remaining.current -= Date.now() - started;
3716
+ };
3717
+ }, [paused, timed, toast2.id, toast2.leaving]);
3718
+ const shown = entered && !toast2.leaving;
3719
+ return /* @__PURE__ */ jsxs32(
3720
+ "div",
3721
+ {
3722
+ role: toast2.tone === "error" ? "alert" : void 0,
3723
+ "data-testid": "toast",
3724
+ "data-tone": toast2.tone,
3725
+ "data-state": toast2.leaving ? "closed" : "open",
3726
+ onPointerEnter: (e) => {
3727
+ if (e.pointerType === "mouse") setHovered(true);
3728
+ },
3729
+ onPointerLeave: () => setHovered(false),
3730
+ onFocus: () => setFocused(true),
3731
+ onBlur: (e) => {
3732
+ if (!e.currentTarget.contains(e.relatedTarget)) setFocused(false);
3733
+ },
3734
+ className: cn(
3735
+ "pointer-events-auto relative flex w-full max-w-sm items-start gap-2 overflow-hidden rounded-lg border border-border bg-card px-3 py-2.5 text-sm text-card-foreground shadow-lg transition-[opacity,transform] duration-150 ease-out motion-reduce:transition-none",
3736
+ shown ? "translate-y-0 opacity-100" : "translate-y-2 opacity-0",
3737
+ toast2.leaving && "pointer-events-none"
3738
+ ),
3739
+ children: [
3740
+ /* @__PURE__ */ jsx50(Icon2, { "aria-hidden": "true", className: cn("mt-0.5 h-4 w-4 shrink-0", toneIconClass[toast2.tone]) }),
3741
+ /* @__PURE__ */ jsxs32("div", { className: "min-w-0 flex-1", children: [
3742
+ /* @__PURE__ */ jsx50("p", { className: "font-medium", children: toast2.message }),
3743
+ toast2.description ? /* @__PURE__ */ jsx50("p", { className: "mt-0.5 text-xs text-muted-foreground", children: toast2.description }) : null
3744
+ ] }),
3745
+ toast2.action ? /* @__PURE__ */ jsx50(
3746
+ "button",
3747
+ {
3748
+ type: "button",
3749
+ "data-testid": "toast-action",
3750
+ onClick: () => {
3751
+ if (toast2.leaving) return;
3752
+ toast2.action?.onClick();
3753
+ dismissToast(toast2.id);
3754
+ },
3755
+ className: "shrink-0 rounded-sm px-1.5 py-0.5 font-semibold text-foreground underline-offset-2 hover:bg-accent hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
3756
+ children: toast2.action.label
3757
+ }
3758
+ ) : null,
3759
+ /* @__PURE__ */ jsx50(
3760
+ "button",
3761
+ {
3762
+ type: "button",
3763
+ "aria-label": dismissLabel,
3764
+ onClick: () => dismissToast(toast2.id),
3765
+ className: "grid h-5 w-5 shrink-0 place-items-center rounded-sm text-muted-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
3766
+ children: /* @__PURE__ */ jsx50(XMarkIcon6, { "aria-hidden": "true", className: "h-3.5 w-3.5" })
3767
+ }
3768
+ ),
3769
+ timed && !toast2.leaving ? /* @__PURE__ */ jsx50(
3770
+ "span",
3771
+ {
3772
+ ref: bar,
3773
+ "aria-hidden": "true",
3774
+ "data-testid": "toast-progress",
3775
+ className: "absolute inset-x-0 bottom-0 h-0.5 origin-left bg-foreground/25 motion-reduce:opacity-0"
3776
+ }
3777
+ ) : null
3778
+ ]
3779
+ }
3780
+ );
3781
+ };
3782
+
3783
+ // src/patterns/date-input/DateInput.tsx
3784
+ import { CalendarDaysIcon } from "@heroicons/react/24/outline";
3785
+ import { forwardRef as forwardRef20, useEffect as useEffect11, useId as useId3, useImperativeHandle, useRef as useRef11, useState as useState18 } from "react";
3786
+
3787
+ // src/lib/dateField.ts
3788
+ var layoutCache = /* @__PURE__ */ new Map();
3789
+ function layoutOf(locale) {
3790
+ const cached = layoutCache.get(locale);
3791
+ if (cached) return cached;
3792
+ const parts = new Intl.DateTimeFormat(locale, { day: "2-digit", month: "2-digit", year: "numeric" }).formatToParts(
3793
+ new Date(2001, 1, 3)
3794
+ );
3795
+ const order = parts.filter((p) => p.type === "day" || p.type === "month" || p.type === "year").map((p) => p.type);
3796
+ const separator = parts.find((p) => p.type === "literal")?.value.trim() || ".";
3797
+ const layout = { order, separator };
3798
+ layoutCache.set(locale, layout);
3799
+ return layout;
3800
+ }
3801
+ var WORD = { day: "dd", month: "mm", year: "yyyy" };
3802
+ function datePlaceholder(locale) {
3803
+ const { order, separator } = layoutOf(locale);
3804
+ return order.map((part) => WORD[part]).join(separator);
3805
+ }
3806
+ var pad = (n, width) => String(n).padStart(width, "0");
3807
+ function formatIsoDay(iso, locale) {
3808
+ const match = /^(\d{4})-(\d{2})-(\d{2})(?:[T ].*)?$/.exec(iso);
3809
+ if (!match) return "";
3810
+ const { order, separator } = layoutOf(locale);
3811
+ const [, year = "", month = "", day = ""] = match;
3812
+ const value = { year, month, day };
3813
+ return order.map((part) => value[part]).join(separator);
3814
+ }
3815
+ var isRealDay = (year, month, day) => {
3816
+ const date = new Date(year, month - 1, day);
3817
+ return date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
3818
+ };
3819
+ var TWO_DIGIT_YEAR_LOOKAHEAD = 20;
3820
+ function expandYear(raw) {
3821
+ const n = Number(raw);
3822
+ if (raw.length > 2) return n;
3823
+ const now = (/* @__PURE__ */ new Date()).getFullYear();
3824
+ const century = Math.floor(now / 100) * 100;
3825
+ return century + n > now + TWO_DIGIT_YEAR_LOOKAHEAD ? century - 100 + n : century + n;
3826
+ }
3827
+ function splitDigits(digits, order) {
3828
+ if (digits.length !== 6 && digits.length !== 8) return null;
3829
+ const width = { day: 2, month: 2, year: digits.length - 4 };
3830
+ const out = [];
3831
+ let at = 0;
3832
+ for (const part of order) {
3833
+ out.push(digits.slice(at, at + width[part]));
3834
+ at += width[part];
3835
+ }
3836
+ return out;
3837
+ }
3838
+ function parseIsoDay(text, locale) {
3839
+ const trimmed = text.trim().replace(/\.$/, "");
3840
+ const iso = /^(\d{4})-(\d{1,2})-(\d{1,2})(?:[T ].*)?$/.exec(trimmed);
3841
+ let year;
3842
+ let month;
3843
+ let day;
3844
+ if (iso) {
3845
+ [year, month, day] = [Number(iso[1]), Number(iso[2]), Number(iso[3])];
3846
+ } else {
3847
+ const { order } = layoutOf(locale);
3848
+ const typed = /^(\d{1,4})[./\-\s]+(\d{1,2})[./\-\s]+(\d{1,4})$/.exec(trimmed);
3849
+ const raw = typed ? [typed[1] ?? "", typed[2] ?? "", typed[3] ?? ""] : /^\d+$/.test(trimmed) ? splitDigits(trimmed, order) : null;
3850
+ if (!raw) return null;
3851
+ const at = (part) => raw[order.indexOf(part)] ?? "";
3852
+ year = expandYear(at("year"));
3853
+ month = Number(at("month"));
3854
+ day = Number(at("day"));
3855
+ }
3856
+ if (year < 1e3 || year > 9999 || !isRealDay(year, month, day)) return null;
3857
+ return `${pad(year, 4)}-${pad(month, 2)}-${pad(day, 2)}`;
3858
+ }
3859
+ function toLocalIsoDay(d) {
3860
+ return `${pad(d.getFullYear(), 4)}-${pad(d.getMonth() + 1, 2)}-${pad(d.getDate(), 2)}`;
3861
+ }
3862
+ var daysInMonth = (year, month) => new Date(year, month, 0).getDate();
3863
+ function shiftIsoDay(iso, by) {
3864
+ const match = /^(\d{4})-(\d{2})-(\d{2})/.exec(iso);
3865
+ if (!match) return iso;
3866
+ const year = Number(match[1]);
3867
+ const month = Number(match[2]);
3868
+ const day = Number(match[3]);
3869
+ const total = year * 12 + (month - 1) + (by.months ?? 0);
3870
+ const nextYear = Math.floor(total / 12);
3871
+ const nextMonth = total % 12 + 1;
3872
+ const moved = new Date(nextYear, nextMonth - 1, Math.min(day, daysInMonth(nextYear, nextMonth)) + (by.days ?? 0));
3873
+ const result = moved.getFullYear();
3874
+ return result < 1e3 || result > 9999 ? iso : toLocalIsoDay(moved);
3875
+ }
3876
+
3877
+ // src/patterns/date-input/NativeDateInput.tsx
3878
+ import { forwardRef as forwardRef19, useEffect as useEffect10, useId as useId2, useRef as useRef10, useState as useState17 } from "react";
3879
+
3880
+ // src/patterns/date-input/shared.tsx
3881
+ import { useSyncExternalStore as useSyncExternalStore2 } from "react";
3882
+ import { jsx as jsx51 } from "react/jsx-runtime";
3883
+ var defaultDateInputLabels = {
3884
+ invalid: "Enter a valid date",
3885
+ outOfRange: "Date is out of range",
3886
+ openCalendar: "Choose date"
3887
+ };
3888
+ var toDay = (iso) => iso?.slice(0, 10) ?? "";
3889
+ var COARSE = "(pointer: coarse)";
3890
+ var subscribeCoarse = (listener) => {
3891
+ const mq = typeof window !== "undefined" ? window.matchMedia?.(COARSE) : void 0;
3892
+ mq?.addEventListener("change", listener);
3893
+ return () => mq?.removeEventListener("change", listener);
3894
+ };
3895
+ var isCoarse = () => typeof window !== "undefined" && !!window.matchMedia?.(COARSE).matches;
3896
+ var useCoarsePointer = () => useSyncExternalStore2(subscribeCoarse, isCoarse, () => false);
3897
+ var errorMessage = (error, l) => error === "invalid" ? l.invalid : error === "range" ? l.outOfRange : "";
3898
+ var DateInputMessage = ({ id, message }) => /* @__PURE__ */ jsx51("p", { id, role: "alert", className: "mt-1 text-xs text-destructive", children: message });
3899
+ var invalidClass = "aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive";
3900
+
3901
+ // src/patterns/date-input/NativeDateInput.tsx
3902
+ import { jsx as jsx52, jsxs as jsxs33 } from "react/jsx-runtime";
3903
+ var NativeDateInput = forwardRef19(
3904
+ ({
3905
+ value,
3906
+ onValueChange,
3907
+ onInvalidChange,
3908
+ locale: _locale,
3909
+ native: _native,
3910
+ min,
3911
+ max,
3912
+ showError = true,
3913
+ labels,
3914
+ onBlur,
3915
+ placeholder: _placeholder,
3916
+ className,
3917
+ name,
3918
+ ...props
3919
+ }, ref) => {
3920
+ const l = { ...defaultDateInputLabels, ...labels };
3921
+ const minDay = toDay(min);
3922
+ const maxDay = toDay(max);
3923
+ const [raw, setRaw] = useState17(toDay(value));
3924
+ const [error, setErrorState] = useState17(null);
3925
+ const errorRef = useRef10(null);
3926
+ const messageId = useId2();
3927
+ const setError = (next) => {
3928
+ if (errorRef.current === next) return;
3929
+ errorRef.current = next;
3930
+ setErrorState(next);
3931
+ onInvalidChange?.(next != null, next ?? void 0);
3932
+ };
3933
+ useEffect10(() => {
3934
+ setRaw(toDay(value));
3935
+ setError(null);
3936
+ }, [value]);
3937
+ const message = errorMessage(error, l);
3938
+ const showMessage = showError && message !== "";
3939
+ const describedBy = [props["aria-describedby"], showMessage ? messageId : void 0].filter(Boolean).join(" ") || void 0;
3940
+ return /* @__PURE__ */ jsxs33("div", { className, children: [
3941
+ /* @__PURE__ */ jsx52(
3942
+ Input,
3943
+ {
3944
+ ref,
3945
+ ...props,
3946
+ className: invalidClass,
3947
+ type: "date",
3948
+ min: minDay || void 0,
3949
+ max: maxDay || void 0,
3950
+ value: raw,
3951
+ "aria-invalid": error != null || props["aria-invalid"] || void 0,
3952
+ "aria-describedby": describedBy,
3953
+ onChange: (e) => {
3954
+ const el = e.currentTarget;
3955
+ const next = el.value;
3956
+ setRaw(next);
3957
+ if (el.validity.badInput) {
3958
+ setError(null);
3959
+ return;
3960
+ }
3961
+ if (next && (minDay && next < minDay || maxDay && next > maxDay)) {
3962
+ setError("range");
3963
+ return;
3964
+ }
3965
+ setError(null);
3966
+ if (next !== toDay(value)) onValueChange(next);
3967
+ },
3968
+ onBlur: (e) => {
3969
+ if (e.currentTarget.validity.badInput) setError("invalid");
3970
+ onBlur?.(e);
3971
+ }
3972
+ }
3973
+ ),
3974
+ showMessage ? /* @__PURE__ */ jsx52(DateInputMessage, { id: messageId, message }) : null,
3975
+ name ? /* @__PURE__ */ jsx52("input", { type: "hidden", name, value: toDay(value) }) : null
3976
+ ] });
3977
+ }
3978
+ );
3979
+ NativeDateInput.displayName = "NativeDateInput";
3980
+
3981
+ // src/patterns/date-input/DateInput.tsx
3982
+ import { Fragment as Fragment6, jsx as jsx53, jsxs as jsxs34 } from "react/jsx-runtime";
3983
+ function check(text, locale, min, max) {
3984
+ if (!text.trim()) return null;
3985
+ const iso = parseIsoDay(text, locale);
3986
+ if (iso == null) return "invalid";
3987
+ if (min && iso < min || max && iso > max) return "range";
3988
+ return null;
3989
+ }
3990
+ var DateInput = forwardRef20((props, ref) => {
3991
+ const coarse = useCoarsePointer();
3992
+ const useNative = props.native === "always" || props.native !== "never" && coarse;
3993
+ return useNative ? /* @__PURE__ */ jsx53(NativeDateInput, { ref, ...props }) : /* @__PURE__ */ jsx53(TypedDateInput, { ref, ...props });
3994
+ });
3995
+ DateInput.displayName = "DateInput";
3996
+ var TypedDateInput = forwardRef20(
3997
+ ({
3998
+ value,
3999
+ onValueChange,
4000
+ onInvalidChange,
4001
+ locale = "de-CH",
4002
+ min,
4003
+ max,
4004
+ showError = true,
4005
+ labels,
4006
+ onBlur,
4007
+ onKeyDown,
4008
+ onFocus,
4009
+ placeholder,
4010
+ className,
4011
+ name,
4012
+ disabled,
4013
+ readOnly,
4014
+ native: _native,
4015
+ ...props
4016
+ }, ref) => {
4017
+ const l = { ...defaultDateInputLabels, ...labels };
4018
+ const minDay = toDay(min);
4019
+ const maxDay = toDay(max);
4020
+ const [text, setText] = useState18(() => formatIsoDay(value, locale));
4021
+ const [error, setErrorState] = useState18(null);
4022
+ const dirty = useRef11(false);
4023
+ const focused = useRef11(false);
4024
+ const inputRef = useRef11(null);
4025
+ const pickerRef = useRef11(null);
4026
+ const messageId = useId3();
4027
+ useImperativeHandle(ref, () => inputRef.current);
4028
+ const errorRef = useRef11(null);
4029
+ const setError = (next) => {
4030
+ if (errorRef.current === next) return;
4031
+ errorRef.current = next;
4032
+ setErrorState(next);
4033
+ onInvalidChange?.(next != null, next ?? void 0);
4034
+ };
4035
+ useEffect11(() => {
4036
+ if (focused.current && dirty.current) return;
4037
+ setText(formatIsoDay(value, locale));
4038
+ setError(null);
4039
+ }, [value, locale]);
4040
+ const live = check(text, locale, minDay, maxDay);
4041
+ const liveMessage = live === "invalid" ? l.invalid : live === "range" ? l.outOfRange : "";
4042
+ useEffect11(() => {
4043
+ inputRef.current?.setCustomValidity(liveMessage);
4044
+ }, [liveMessage]);
4045
+ const commitIso = (iso) => {
4046
+ setText(formatIsoDay(iso, locale));
4047
+ setError(null);
4048
+ if (iso !== value.slice(0, 10)) onValueChange(iso);
4049
+ };
4050
+ const commit = () => {
4051
+ if (!dirty.current) return;
4052
+ dirty.current = false;
4053
+ if (!text.trim()) {
4054
+ setError(null);
4055
+ if (value) onValueChange("");
4056
+ return;
4057
+ }
4058
+ const problem = check(text, locale, minDay, maxDay);
4059
+ setError(problem);
4060
+ if (problem) return;
4061
+ commitIso(parseIsoDay(text, locale));
4062
+ };
4063
+ const step = (key, shift) => {
4064
+ const by = key === "ArrowUp" ? { days: 1 } : key === "ArrowDown" ? { days: -1 } : key === "PageUp" ? { months: shift ? 12 : 1 } : key === "PageDown" ? { months: shift ? -12 : -1 } : null;
4065
+ if (!by) return null;
4066
+ const base = parseIsoDay(text, locale) ?? (toDay(value) || toLocalIsoDay(/* @__PURE__ */ new Date()));
4067
+ let next = text.trim() || value ? shiftIsoDay(base, by) : base;
4068
+ if (minDay && next < minDay) next = minDay;
4069
+ if (maxDay && next > maxDay) next = maxDay;
4070
+ return next;
4071
+ };
4072
+ const openPicker = () => {
4073
+ const el = pickerRef.current;
4074
+ if (!el) return;
4075
+ try {
4076
+ el.showPicker();
4077
+ } catch {
4078
+ el.click();
4079
+ }
4080
+ };
4081
+ const message = errorMessage(error, l);
4082
+ const showMessage = showError && message !== "";
4083
+ const pickable = !disabled && !readOnly;
4084
+ const describedBy = [props["aria-describedby"], showMessage ? messageId : void 0].filter(Boolean).join(" ") || void 0;
4085
+ return /* @__PURE__ */ jsxs34("div", { className, children: [
4086
+ /* @__PURE__ */ jsxs34("div", { className: "relative", children: [
4087
+ /* @__PURE__ */ jsx53(
4088
+ Input,
4089
+ {
4090
+ ref: inputRef,
4091
+ ...props,
4092
+ disabled,
4093
+ readOnly,
4094
+ className: cn(invalidClass, pickable && "pr-9"),
4095
+ type: "text",
4096
+ autoComplete: "off",
4097
+ value: text,
4098
+ placeholder: placeholder ?? datePlaceholder(locale),
4099
+ "aria-invalid": error != null || props["aria-invalid"] || void 0,
4100
+ "aria-describedby": describedBy,
4101
+ onChange: (e) => {
4102
+ dirty.current = true;
4103
+ setText(e.target.value);
4104
+ setError(null);
4105
+ },
4106
+ onFocus: (e) => {
4107
+ focused.current = true;
4108
+ onFocus?.(e);
4109
+ },
4110
+ onBlur: (e) => {
4111
+ focused.current = false;
4112
+ commit();
4113
+ onBlur?.(e);
4114
+ },
4115
+ onKeyDown: (e) => {
4116
+ onKeyDown?.(e);
4117
+ if (e.defaultPrevented) return;
4118
+ if (e.key === "Enter") commit();
4119
+ else if (!readOnly && !disabled) {
4120
+ if (e.key === "ArrowDown" && e.altKey) {
4121
+ e.preventDefault();
4122
+ openPicker();
4123
+ } else if (!e.altKey && !e.ctrlKey && !e.metaKey) {
4124
+ const next = step(e.key, e.shiftKey);
4125
+ if (next) {
4126
+ e.preventDefault();
4127
+ dirty.current = false;
4128
+ commitIso(next);
4129
+ }
4130
+ }
4131
+ }
4132
+ }
4133
+ }
4134
+ ),
4135
+ pickable ? /* @__PURE__ */ jsxs34(Fragment6, { children: [
4136
+ /* @__PURE__ */ jsx53(
4137
+ "button",
4138
+ {
4139
+ type: "button",
4140
+ "aria-label": l.openCalendar,
4141
+ onClick: openPicker,
4142
+ className: "absolute inset-y-0 right-0 grid w-9 place-items-center rounded-r-md text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
4143
+ children: /* @__PURE__ */ jsx53(CalendarDaysIcon, { "aria-hidden": "true", className: "h-4 w-4" })
4144
+ }
4145
+ ),
4146
+ /* @__PURE__ */ jsx53(
4147
+ "input",
4148
+ {
4149
+ ref: pickerRef,
4150
+ type: "date",
4151
+ tabIndex: -1,
4152
+ "aria-hidden": "true",
4153
+ form: "bmsui-date-input-picker",
4154
+ "data-testid": "date-input-picker",
4155
+ min: minDay || void 0,
4156
+ max: maxDay || void 0,
4157
+ value: toDay(value),
4158
+ onChange: (e) => {
4159
+ const iso = e.target.value;
4160
+ dirty.current = false;
4161
+ if (iso) commitIso(iso);
4162
+ else {
4163
+ setText("");
4164
+ setError(null);
4165
+ if (value) onValueChange("");
4166
+ }
4167
+ },
4168
+ className: "pointer-events-none absolute inset-0 h-full w-full opacity-0"
4169
+ }
4170
+ )
4171
+ ] }) : null
4172
+ ] }),
4173
+ showMessage ? /* @__PURE__ */ jsx53(DateInputMessage, { id: messageId, message }) : null,
4174
+ name ? /* @__PURE__ */ jsx53("input", { type: "hidden", name, value: toDay(value) }) : null
4175
+ ] });
4176
+ }
4177
+ );
4178
+ TypedDateInput.displayName = "TypedDateInput";
4179
+
3465
4180
  // src/patterns/animated-brand/AnimatedBrand.tsx
3466
4181
  import {
3467
- useEffect as useEffect9,
3468
- useRef as useRef9,
3469
- useState as useState16
4182
+ useEffect as useEffect12,
4183
+ useRef as useRef12,
4184
+ useState as useState19
3470
4185
  } from "react";
3471
4186
 
3472
4187
  // src/patterns/animated-brand/brandMotion.ts
@@ -3860,7 +4575,7 @@ function playBrandMotion(p, name, onComplete) {
3860
4575
  }
3861
4576
 
3862
4577
  // src/patterns/animated-brand/AnimatedBrand.tsx
3863
- import { jsx as jsx49, jsxs as jsxs31 } from "react/jsx-runtime";
4578
+ import { jsx as jsx54, jsxs as jsxs35 } from "react/jsx-runtime";
3864
4579
  var absolute = {
3865
4580
  position: "absolute",
3866
4581
  borderRadius: "50%",
@@ -3891,17 +4606,17 @@ function AnimatedBrand({
3891
4606
  className,
3892
4607
  style
3893
4608
  }) {
3894
- const ref = useRef9(null);
3895
- const completion = useRef9(onComplete);
3896
- const [segmented, setSegmented] = useState16(null);
3897
- useEffect9(() => {
4609
+ const ref = useRef12(null);
4610
+ const completion = useRef12(onComplete);
4611
+ const [segmented, setSegmented] = useState19(null);
4612
+ useEffect12(() => {
3898
4613
  const letters2 = typeof Intl.Segmenter === "function" ? Array.from(new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(product), ({ segment }) => segment) : product ? [product] : [];
3899
4614
  setSegmented({ product, letters: letters2 });
3900
4615
  }, [product]);
3901
- useEffect9(() => {
4616
+ useEffect12(() => {
3902
4617
  completion.current = onComplete;
3903
4618
  }, [onComplete]);
3904
- useEffect9(() => {
4619
+ useEffect12(() => {
3905
4620
  const element = ref.current;
3906
4621
  if (!element || !autoPlay || segmented?.product !== product) return;
3907
4622
  let disposed = false;
@@ -3948,13 +4663,13 @@ function AnimatedBrand({
3948
4663
  color: textColor,
3949
4664
  ...style
3950
4665
  };
3951
- return /* @__PURE__ */ jsx49(
4666
+ return /* @__PURE__ */ jsx54(
3952
4667
  "span",
3953
4668
  {
3954
4669
  ref,
3955
4670
  className,
3956
4671
  style: wrapperStyle,
3957
- children: /* @__PURE__ */ jsxs31(
4672
+ children: /* @__PURE__ */ jsxs35(
3958
4673
  "span",
3959
4674
  {
3960
4675
  "data-logo-part": "logo",
@@ -3972,7 +4687,7 @@ function AnimatedBrand({
3972
4687
  userSelect: "none"
3973
4688
  },
3974
4689
  children: [
3975
- /* @__PURE__ */ jsxs31(
4690
+ /* @__PURE__ */ jsxs35(
3976
4691
  "span",
3977
4692
  {
3978
4693
  "data-logo-part": "mark",
@@ -3986,7 +4701,7 @@ function AnimatedBrand({
3986
4701
  marginRight: tail ? ".04em" : 0
3987
4702
  },
3988
4703
  children: [
3989
- /* @__PURE__ */ jsx49(
4704
+ /* @__PURE__ */ jsx54(
3990
4705
  "span",
3991
4706
  {
3992
4707
  "data-logo-part": "ring",
@@ -3998,7 +4713,7 @@ function AnimatedBrand({
3998
4713
  }
3999
4714
  }
4000
4715
  ),
4001
- /* @__PURE__ */ jsx49(
4716
+ /* @__PURE__ */ jsx54(
4002
4717
  "span",
4003
4718
  {
4004
4719
  "data-logo-part": "core",
@@ -4011,7 +4726,7 @@ function AnimatedBrand({
4011
4726
  }
4012
4727
  }
4013
4728
  ),
4014
- /* @__PURE__ */ jsx49(
4729
+ /* @__PURE__ */ jsx54(
4015
4730
  "span",
4016
4731
  {
4017
4732
  "data-logo-part": "trail",
@@ -4029,7 +4744,7 @@ function AnimatedBrand({
4029
4744
  }
4030
4745
  }
4031
4746
  ),
4032
- [0, 1].map((id) => /* @__PURE__ */ jsx49(
4747
+ [0, 1].map((id) => /* @__PURE__ */ jsx54(
4033
4748
  "span",
4034
4749
  {
4035
4750
  "data-logo-part": "echo",
@@ -4042,7 +4757,7 @@ function AnimatedBrand({
4042
4757
  },
4043
4758
  id
4044
4759
  )),
4045
- Array.from({ length: 8 }, (_, id) => /* @__PURE__ */ jsx49(
4760
+ Array.from({ length: 8 }, (_, id) => /* @__PURE__ */ jsx54(
4046
4761
  "span",
4047
4762
  {
4048
4763
  "data-logo-part": "particle",
@@ -4057,7 +4772,7 @@ function AnimatedBrand({
4057
4772
  },
4058
4773
  id
4059
4774
  )),
4060
- /* @__PURE__ */ jsx49(
4775
+ /* @__PURE__ */ jsx54(
4061
4776
  "span",
4062
4777
  {
4063
4778
  "data-logo-part": "bead",
@@ -4067,7 +4782,7 @@ function AnimatedBrand({
4067
4782
  ]
4068
4783
  }
4069
4784
  ),
4070
- /* @__PURE__ */ jsxs31(
4785
+ /* @__PURE__ */ jsxs35(
4071
4786
  "span",
4072
4787
  {
4073
4788
  "data-logo-part": "tail",
@@ -4078,7 +4793,7 @@ function AnimatedBrand({
4078
4793
  whiteSpace: "pre"
4079
4794
  },
4080
4795
  children: [
4081
- letters.map((letter, index) => /* @__PURE__ */ jsx49(
4796
+ letters.map((letter, index) => /* @__PURE__ */ jsx54(
4082
4797
  "span",
4083
4798
  {
4084
4799
  "data-brand-letter": "",
@@ -4087,7 +4802,7 @@ function AnimatedBrand({
4087
4802
  },
4088
4803
  `${index}-${letter}`
4089
4804
  )),
4090
- /* @__PURE__ */ jsx49(
4805
+ /* @__PURE__ */ jsx54(
4091
4806
  "span",
4092
4807
  {
4093
4808
  "data-brand-baseline": "",
@@ -4127,6 +4842,7 @@ export {
4127
4842
  Checkbox,
4128
4843
  Combobox,
4129
4844
  ConfirmDialog,
4845
+ DateInput,
4130
4846
  Dialog,
4131
4847
  DialogActions,
4132
4848
  DialogBody,
@@ -4152,7 +4868,9 @@ export {
4152
4868
  DropdownMenuSubContent,
4153
4869
  DropdownMenuSubTrigger,
4154
4870
  DropdownMenuTrigger,
4871
+ EmptyState,
4155
4872
  ErrorState,
4873
+ FilteredEmptyState,
4156
4874
  FormField,
4157
4875
  FormModal,
4158
4876
  InlineError,
@@ -4162,6 +4880,7 @@ export {
4162
4880
  LoadingOverlay,
4163
4881
  LoadingSpinner,
4164
4882
  LoadingState,
4883
+ MAX_TOASTS,
4165
4884
  Modal,
4166
4885
  NavGroup,
4167
4886
  NavItem,
@@ -4215,6 +4934,7 @@ export {
4215
4934
  TabsTrigger,
4216
4935
  TagCombobox,
4217
4936
  Textarea,
4937
+ Toaster,
4218
4938
  Tooltip,
4219
4939
  TooltipContent,
4220
4940
  TooltipProvider,
@@ -4224,13 +4944,23 @@ export {
4224
4944
  badgeVariants,
4225
4945
  buttonVariants,
4226
4946
  cn,
4947
+ datePlaceholder,
4948
+ defaultDateInputLabels,
4227
4949
  defaultErrorStateLabels,
4950
+ defaultFilteredEmptyStateLabels,
4951
+ defaultToasterLabels,
4228
4952
  describeSpeechError,
4953
+ formatIsoDay,
4229
4954
  getConfirmButtonPlacement,
4230
4955
  isWindowsPlatform,
4231
4956
  loadingSpinnerIconVariants,
4957
+ parseIsoDay,
4958
+ resetToasts,
4232
4959
  sheetVariants,
4960
+ shiftIsoDay,
4233
4961
  toErrorInfo,
4962
+ toLocalIsoDay,
4963
+ toast,
4234
4964
  useDelayedFlag,
4235
4965
  useMediaQuery,
4236
4966
  useSidebarCollapsed,