@mond-design-system/react 1.0.0-alpha.0 → 1.0.0-alpha.2

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.cjs CHANGED
@@ -214,7 +214,7 @@ function Button({
214
214
  ...own,
215
215
  ...rest,
216
216
  children: [
217
- loading ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: SPINNER_PX[size] }) : iconLeft,
217
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: SPINNER_PX[size], label: "", "aria-hidden": "true" }) : iconLeft,
218
218
  children,
219
219
  !loading && iconRight
220
220
  ]
@@ -313,6 +313,661 @@ function Badge({ tone = "neutral", className, ...rest }) {
313
313
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx(Badge_default.badge, Badge_default[`tone-${tone}`], className), ...rest });
314
314
  }
315
315
 
316
+ // src/components/Chip/Chip.module.css
317
+ var Chip_default = {
318
+ chip: "Chip_chip",
319
+ "variant-soft": "Chip_variant-soft",
320
+ "variant-outline": "Chip_variant-outline",
321
+ selected: "Chip_selected",
322
+ interactive: "Chip_interactive",
323
+ disabled: "Chip_disabled"
324
+ };
325
+ function Chip({
326
+ children,
327
+ variant = "soft",
328
+ selected,
329
+ icon,
330
+ onClick,
331
+ disabled = false,
332
+ className,
333
+ ...rest
334
+ }) {
335
+ const interactive = typeof onClick === "function";
336
+ const shared = {
337
+ className: cx(
338
+ Chip_default.chip,
339
+ Chip_default[`variant-${variant}`],
340
+ selected && Chip_default.selected,
341
+ interactive && !disabled && Chip_default.interactive,
342
+ disabled && Chip_default.disabled,
343
+ className
344
+ ),
345
+ ...rest
346
+ };
347
+ const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
348
+ icon,
349
+ children
350
+ ] });
351
+ return interactive ? /* @__PURE__ */ jsxRuntime.jsx(
352
+ "button",
353
+ {
354
+ type: "button",
355
+ onClick,
356
+ disabled,
357
+ "aria-pressed": selected === void 0 ? void 0 : selected,
358
+ ...shared,
359
+ children: content
360
+ }
361
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { ...shared, children: content });
362
+ }
363
+
364
+ // src/components/Chip/ChipGroup.module.css
365
+ var ChipGroup_default = {
366
+ group: "ChipGroup_group",
367
+ "gap-hairline": "ChipGroup_gap-hairline",
368
+ "gap-tight": "ChipGroup_gap-tight",
369
+ "gap-base": "ChipGroup_gap-base"
370
+ };
371
+ function ChipGroup({ children, gap = "tight", className, ...rest }) {
372
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx(ChipGroup_default.group, ChipGroup_default[`gap-${gap}`], className), ...rest, children });
373
+ }
374
+
375
+ // src/components/Chip/ChipBar.module.css
376
+ var ChipBar_default = {
377
+ bar: "ChipBar_bar",
378
+ "gap-hairline": "ChipBar_gap-hairline",
379
+ "gap-tight": "ChipBar_gap-tight",
380
+ "gap-base": "ChipBar_gap-base",
381
+ bordered: "ChipBar_bordered",
382
+ fade: "ChipBar_fade",
383
+ item: "ChipBar_item"
384
+ };
385
+ function ChipBar({
386
+ children,
387
+ gap = "tight",
388
+ bordered = false,
389
+ fade = true,
390
+ className,
391
+ ...rest
392
+ }) {
393
+ return /* @__PURE__ */ jsxRuntime.jsx(
394
+ "div",
395
+ {
396
+ className: cx(ChipBar_default.bar, ChipBar_default[`gap-${gap}`], bordered && ChipBar_default.bordered, fade && ChipBar_default.fade, className),
397
+ ...rest,
398
+ children: react.Children.map(children, (child) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: ChipBar_default.item, children: child }))
399
+ }
400
+ );
401
+ }
402
+
403
+ // src/components/CountButton/CountButton.module.css
404
+ var CountButton_default = {
405
+ button: "CountButton_button",
406
+ "tone-accent": "CountButton_tone-accent",
407
+ "tone-danger": "CountButton_tone-danger",
408
+ glyph: "CountButton_glyph"
409
+ };
410
+ var SPINNER_PX2 = 20;
411
+ function CountButton({
412
+ icon,
413
+ label,
414
+ active,
415
+ tone = "accent",
416
+ disabled = false,
417
+ loading = false,
418
+ className,
419
+ children,
420
+ ...rest
421
+ }) {
422
+ const isToggle = active !== void 0;
423
+ return /* @__PURE__ */ jsxRuntime.jsxs(
424
+ "button",
425
+ {
426
+ type: "button",
427
+ disabled: disabled || loading,
428
+ "aria-label": label,
429
+ "aria-pressed": isToggle ? active : void 0,
430
+ "aria-busy": loading || void 0,
431
+ className: cx(CountButton_default.button, active && CountButton_default[`tone-${tone}`], className),
432
+ ...rest,
433
+ children: [
434
+ loading ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: SPINNER_PX2, label: "", "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: CountButton_default.glyph, children: icon }),
435
+ children != null ? /* @__PURE__ */ jsxRuntime.jsx("span", { children }) : null
436
+ ]
437
+ }
438
+ );
439
+ }
440
+
441
+ // src/components/Field/Field.module.css
442
+ var Field_default = {
443
+ field: "Field_field",
444
+ label: "Field_label",
445
+ required: "Field_required",
446
+ message: "Field_message",
447
+ error: "Field_error"
448
+ };
449
+ var FieldContext = react.createContext(null);
450
+ function useFieldContext() {
451
+ return react.useContext(FieldContext);
452
+ }
453
+ function Field({ label, children, hint, error, required = false, className }) {
454
+ const id = react.useId();
455
+ const messageId = `${id}-message`;
456
+ const message = error ?? hint;
457
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx(Field_default.field, className), children: [
458
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: Field_default.label, htmlFor: id, children: [
459
+ label,
460
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: Field_default.required, "aria-hidden": "true", children: "*" })
461
+ ] }),
462
+ /* @__PURE__ */ jsxRuntime.jsx(
463
+ FieldContext.Provider,
464
+ {
465
+ value: { id, describedBy: message ? messageId : void 0, invalid: error !== void 0 },
466
+ children
467
+ }
468
+ ),
469
+ message && /* @__PURE__ */ jsxRuntime.jsx("span", { id: messageId, className: cx(Field_default.message, error !== void 0 && Field_default.error), children: message })
470
+ ] });
471
+ }
472
+
473
+ // src/components/Select/Select.module.css
474
+ var Select_default = {
475
+ wrap: "Select_wrap",
476
+ select: "Select_select",
477
+ "size-sm": "Select_size-sm",
478
+ "size-md": "Select_size-md",
479
+ "size-lg": "Select_size-lg",
480
+ chevron: "Select_chevron"
481
+ };
482
+ function Select({ size = "md", className, children, ...rest }) {
483
+ const field = useFieldContext();
484
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: Select_default.wrap, children: [
485
+ /* @__PURE__ */ jsxRuntime.jsx(
486
+ "select",
487
+ {
488
+ id: rest.id ?? field?.id,
489
+ "aria-describedby": rest["aria-describedby"] ?? field?.describedBy,
490
+ "aria-invalid": rest["aria-invalid"] ?? (field?.invalid || void 0),
491
+ className: cx(Select_default.select, Select_default[`size-${size}`], className),
492
+ ...rest,
493
+ children
494
+ }
495
+ ),
496
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", className: Select_default.chevron, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 6l4 4 4-4", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) })
497
+ ] });
498
+ }
499
+ var OverlayHistoryContext = react.createContext(null);
500
+
501
+ // src/hooks/useOverlay.ts
502
+ var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
503
+ function useOverlay(options) {
504
+ const ref = react.useRef(null);
505
+ const { open, onClose } = options;
506
+ const close = react.useRef(onClose);
507
+ react.useEffect(() => {
508
+ close.current = onClose;
509
+ }, [onClose]);
510
+ const overlayHistory = react.useContext(OverlayHistoryContext);
511
+ react.useEffect(() => {
512
+ if (!open || !overlayHistory) return;
513
+ return overlayHistory.register(() => close.current());
514
+ }, [open, overlayHistory]);
515
+ react.useEffect(() => {
516
+ if (!open) return;
517
+ const panel = ref.current;
518
+ const previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
519
+ panel?.focus();
520
+ const onKeyDown = (event) => {
521
+ if (event.key === "Escape") {
522
+ event.stopPropagation();
523
+ close.current();
524
+ return;
525
+ }
526
+ if (event.key !== "Tab" || !panel) return;
527
+ const focusable = [...panel.querySelectorAll(FOCUSABLE)];
528
+ if (focusable.length === 0) {
529
+ event.preventDefault();
530
+ panel.focus();
531
+ return;
532
+ }
533
+ const first = focusable[0];
534
+ const last = focusable[focusable.length - 1];
535
+ const active = document.activeElement;
536
+ if (event.shiftKey && (active === first || active === panel)) {
537
+ event.preventDefault();
538
+ last?.focus();
539
+ } else if (!event.shiftKey && active === last) {
540
+ event.preventDefault();
541
+ first?.focus();
542
+ }
543
+ };
544
+ document.addEventListener("keydown", onKeyDown);
545
+ const bodyOverflow = document.body.style.overflow;
546
+ document.body.style.overflow = "hidden";
547
+ return () => {
548
+ document.removeEventListener("keydown", onKeyDown);
549
+ document.body.style.overflow = bodyOverflow;
550
+ previous?.focus();
551
+ };
552
+ }, [open]);
553
+ return ref;
554
+ }
555
+ function usePresence(open, durationMs) {
556
+ const [mounted, setMounted] = react.useState(open);
557
+ if (open && !mounted) setMounted(true);
558
+ react.useEffect(() => {
559
+ if (open) return;
560
+ const timer = setTimeout(() => setMounted(false), durationMs);
561
+ return () => clearTimeout(timer);
562
+ }, [open, durationMs]);
563
+ return { mounted: open || mounted, visible: open };
564
+ }
565
+
566
+ // src/components/Overlay/Overlay.module.css
567
+ var Overlay_default = {
568
+ scrim: "Overlay_scrim",
569
+ "variant-modal": "Overlay_variant-modal",
570
+ "variant-sheet": "Overlay_variant-sheet"
571
+ };
572
+ var OVERLAY_EXIT_MS = 200;
573
+ function Overlay({ open, onClose, label, variant, closeOnScrimClick, panelClassName, children }) {
574
+ const { mounted, visible } = usePresence(open, OVERLAY_EXIT_MS);
575
+ const ref = useOverlay({ open, onClose });
576
+ if (!mounted) return null;
577
+ return reactDom.createPortal(
578
+ /* @__PURE__ */ jsxRuntime.jsx(
579
+ "div",
580
+ {
581
+ className: cx(Overlay_default.scrim, Overlay_default[`variant-${variant}`]),
582
+ "data-open": visible || void 0,
583
+ "data-testid": "mds-scrim",
584
+ onClick: closeOnScrimClick ? onClose : void 0,
585
+ children: /* @__PURE__ */ jsxRuntime.jsx(
586
+ "div",
587
+ {
588
+ ref,
589
+ role: "dialog",
590
+ "aria-modal": "true",
591
+ "aria-label": label,
592
+ tabIndex: -1,
593
+ className: panelClassName,
594
+ "data-open": visible || void 0,
595
+ onClick: (event) => event.stopPropagation(),
596
+ children
597
+ }
598
+ )
599
+ }
600
+ ),
601
+ document.body
602
+ );
603
+ }
604
+
605
+ // src/components/Sheet/Sheet.module.css
606
+ var Sheet_default = {
607
+ panel: "Sheet_panel",
608
+ header: "Sheet_header",
609
+ body: "Sheet_body",
610
+ footer: "Sheet_footer"
611
+ };
612
+ function Sheet({ open, onClose, label, closeOnScrimClick = true, children }) {
613
+ return /* @__PURE__ */ jsxRuntime.jsx(
614
+ Overlay,
615
+ {
616
+ open,
617
+ onClose,
618
+ label,
619
+ variant: "sheet",
620
+ closeOnScrimClick,
621
+ panelClassName: Sheet_default.panel,
622
+ children
623
+ }
624
+ );
625
+ }
626
+ function SheetHeader({ children }) {
627
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: Sheet_default.header, children });
628
+ }
629
+ function SheetBody({ children }) {
630
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: Sheet_default.body, children });
631
+ }
632
+ function SheetFooter({ children }) {
633
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: Sheet_default.footer, children });
634
+ }
635
+
636
+ // src/components/DateTimePicker/DateTimePicker.module.css
637
+ var DateTimePicker_default = {
638
+ trigger: "DateTimePicker_trigger",
639
+ hasValue: "DateTimePicker_hasValue",
640
+ triggerLabel: "DateTimePicker_triggerLabel",
641
+ glyph: "DateTimePicker_glyph",
642
+ timeRow: "DateTimePicker_timeRow",
643
+ grow: "DateTimePicker_grow",
644
+ meridiem: "DateTimePicker_meridiem",
645
+ colon: "DateTimePicker_colon",
646
+ calendarHeader: "DateTimePicker_calendarHeader",
647
+ monthLabel: "DateTimePicker_monthLabel",
648
+ weekdays: "DateTimePicker_weekdays",
649
+ weekday: "DateTimePicker_weekday",
650
+ grid: "DateTimePicker_grid",
651
+ day: "DateTimePicker_day",
652
+ today: "DateTimePicker_today",
653
+ selected: "DateTimePicker_selected",
654
+ outside: "DateTimePicker_outside"
655
+ };
656
+ var DEFAULT_LABELS = {
657
+ dialog: "Pick date and time",
658
+ previousMonth: "Previous month",
659
+ nextMonth: "Next month",
660
+ today: "Today",
661
+ done: "Done",
662
+ hour: "Hour",
663
+ minute: "Minutes",
664
+ dayPeriod: "AM/PM"
665
+ };
666
+ function localeData(locale) {
667
+ const resolved = new Intl.DateTimeFormat(locale).resolvedOptions().locale;
668
+ const intlLocale = new Intl.Locale(resolved);
669
+ const weekInfo = intlLocale.getWeekInfo?.() ?? intlLocale.weekInfo;
670
+ const firstDay = (weekInfo?.firstDay ?? 1) % 7;
671
+ const weekdayFmt = new Intl.DateTimeFormat(resolved, { weekday: "short", timeZone: "UTC" });
672
+ const weekdays = Array.from(
673
+ { length: 7 },
674
+ (_, i) => weekdayFmt.format(new Date(Date.UTC(2021, 7, 1 + (firstDay + i) % 7)))
675
+ );
676
+ const hourFmt = new Intl.DateTimeFormat(resolved, { hour: "numeric" });
677
+ const { hourCycle } = hourFmt.resolvedOptions();
678
+ const hour12 = hourCycle === "h11" || hourCycle === "h12";
679
+ const periodOf = (hour) => new Intl.DateTimeFormat(resolved, { hour: "numeric", hour12: true }).formatToParts(new Date(2021, 0, 1, hour)).find((part) => part.type === "dayPeriod")?.value ?? (hour < 12 ? "AM" : "PM");
680
+ return {
681
+ firstDay,
682
+ weekdays,
683
+ hour12,
684
+ dayPeriods: [periodOf(9), periodOf(21)],
685
+ monthTitle: new Intl.DateTimeFormat(resolved, { month: "long", year: "numeric" }),
686
+ dayLabel: new Intl.DateTimeFormat(resolved, { month: "long", day: "numeric", year: "numeric" }),
687
+ full: new Intl.DateTimeFormat(resolved, {
688
+ weekday: "short",
689
+ month: "short",
690
+ day: "numeric",
691
+ hour: "numeric",
692
+ minute: "2-digit"
693
+ })
694
+ };
695
+ }
696
+ function startOfDay(d) {
697
+ return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
698
+ }
699
+ function snapMinutes(d, step) {
700
+ const out = new Date(d);
701
+ out.setMinutes(Math.round(out.getMinutes() / step) * step, 0, 0);
702
+ return out;
703
+ }
704
+ function addDays(d, n) {
705
+ const o = new Date(d);
706
+ o.setDate(o.getDate() + n);
707
+ return o;
708
+ }
709
+ function addMonths(d, n) {
710
+ const o = new Date(d);
711
+ o.setMonth(o.getMonth() + n);
712
+ return o;
713
+ }
714
+ function minuteOptions(step) {
715
+ const s = Math.max(1, Math.min(60, Math.floor(step)));
716
+ return Array.from({ length: Math.floor(60 / s) }, (_, i) => i * s);
717
+ }
718
+ function pad2(n) {
719
+ return String(n).padStart(2, "0");
720
+ }
721
+ var chevronLeft = /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", className: DateTimePicker_default.glyph, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 3l-5 5 5 5", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) });
722
+ var chevronRight = /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", className: DateTimePicker_default.glyph, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 3l5 5-5 5", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) });
723
+ var calendarGlyph = /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", className: DateTimePicker_default.glyph, children: [
724
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2.5", y: "3.5", width: "11", height: "10", rx: "1.5", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }),
725
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2.5 6.5h11M5.5 2v2.5M10.5 2v2.5", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
726
+ ] });
727
+ var clockGlyph = /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", className: DateTimePicker_default.glyph, children: [
728
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8", cy: "8", r: "5.75", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }),
729
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 5v3.25l2 1.5", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
730
+ ] });
731
+ function DateTimePicker({
732
+ value,
733
+ onChange,
734
+ placeholder = "Select date & time",
735
+ min,
736
+ minuteStep = 5,
737
+ disabled = false,
738
+ id,
739
+ "aria-label": ariaLabel,
740
+ locale,
741
+ labels
742
+ }) {
743
+ const text = { ...DEFAULT_LABELS, ...labels };
744
+ const intl = react.useMemo(() => localeData(locale), [locale]);
745
+ const [open, setOpen] = react.useState(false);
746
+ const [draft, setDraft] = react.useState(() => /* @__PURE__ */ new Date());
747
+ const [view, setView] = react.useState(() => {
748
+ const d = /* @__PURE__ */ new Date();
749
+ return { y: d.getFullYear(), m: d.getMonth() };
750
+ });
751
+ const [focusedDay, setFocusedDay] = react.useState(() => /* @__PURE__ */ new Date());
752
+ const dayRefs = react.useRef(/* @__PURE__ */ new Map());
753
+ const pendingFocusRef = react.useRef(false);
754
+ const minDate = min ? new Date(min) : /* @__PURE__ */ new Date();
755
+ const minStart = startOfDay(minDate);
756
+ function openPicker() {
757
+ const base = snapMinutes(value ? new Date(value) : /* @__PURE__ */ new Date(), minuteStep);
758
+ setDraft(base);
759
+ const start = startOfDay(base) >= minStart ? base : new Date(minStart);
760
+ setView({ y: start.getFullYear(), m: start.getMonth() });
761
+ setFocusedDay(start);
762
+ setOpen(true);
763
+ }
764
+ react.useEffect(() => {
765
+ if (!pendingFocusRef.current) return;
766
+ pendingFocusRef.current = false;
767
+ dayRefs.current.get(startOfDay(focusedDay))?.focus();
768
+ }, [focusedDay, view]);
769
+ const h24 = draft.getHours();
770
+ const h12 = h24 % 12 || 12;
771
+ const isPM = h24 >= 12;
772
+ function setHour(v) {
773
+ const nd = new Date(draft);
774
+ nd.setHours(intl.hour12 ? Number(v) % 12 + (isPM ? 12 : 0) : Number(v));
775
+ setDraft(nd);
776
+ }
777
+ function setMinute(v) {
778
+ const nd = new Date(draft);
779
+ nd.setMinutes(Number(v), 0, 0);
780
+ setDraft(nd);
781
+ }
782
+ function setMeridiem(v) {
783
+ const nd = new Date(draft);
784
+ nd.setHours(h12 % 12 + (v === "pm" ? 12 : 0));
785
+ setDraft(nd);
786
+ }
787
+ function pickDay(day) {
788
+ const nd = new Date(draft);
789
+ nd.setFullYear(view.y, view.m, day);
790
+ setDraft(nd);
791
+ }
792
+ function firstFocusableInView(y, m) {
793
+ const monthStart = new Date(y, m, 1);
794
+ return startOfDay(monthStart) >= minStart ? monthStart : new Date(minStart);
795
+ }
796
+ function shiftMonth(delta) {
797
+ let m = view.m + delta;
798
+ let y = view.y;
799
+ if (m < 0) {
800
+ m = 11;
801
+ y -= 1;
802
+ }
803
+ if (m > 11) {
804
+ m = 0;
805
+ y += 1;
806
+ }
807
+ setView({ y, m });
808
+ setFocusedDay(firstFocusableInView(y, m));
809
+ }
810
+ function goToday() {
811
+ const t = /* @__PURE__ */ new Date();
812
+ setView({ y: t.getFullYear(), m: t.getMonth() });
813
+ setFocusedDay(startOfDay(t) >= minStart ? t : new Date(minStart));
814
+ }
815
+ function focusDate(next) {
816
+ if (startOfDay(next) < minStart) return;
817
+ pendingFocusRef.current = true;
818
+ if (next.getMonth() !== view.m || next.getFullYear() !== view.y) {
819
+ setView({ y: next.getFullYear(), m: next.getMonth() });
820
+ }
821
+ setFocusedDay(next);
822
+ }
823
+ function onDayKeyDown(e, cell) {
824
+ const weekOffset = (cell.getDay() - intl.firstDay + 7) % 7;
825
+ switch (e.key) {
826
+ case "ArrowLeft":
827
+ e.preventDefault();
828
+ focusDate(addDays(cell, -1));
829
+ break;
830
+ case "ArrowRight":
831
+ e.preventDefault();
832
+ focusDate(addDays(cell, 1));
833
+ break;
834
+ case "ArrowUp":
835
+ e.preventDefault();
836
+ focusDate(addDays(cell, -7));
837
+ break;
838
+ case "ArrowDown":
839
+ e.preventDefault();
840
+ focusDate(addDays(cell, 7));
841
+ break;
842
+ case "Home":
843
+ e.preventDefault();
844
+ focusDate(addDays(cell, -weekOffset));
845
+ break;
846
+ case "End":
847
+ e.preventDefault();
848
+ focusDate(addDays(cell, 6 - weekOffset));
849
+ break;
850
+ case "PageUp":
851
+ e.preventDefault();
852
+ focusDate(addMonths(cell, -1));
853
+ break;
854
+ case "PageDown":
855
+ e.preventDefault();
856
+ focusDate(addMonths(cell, 1));
857
+ break;
858
+ case "Enter":
859
+ case " ":
860
+ e.preventDefault();
861
+ pickDay(cell.getDate());
862
+ break;
863
+ }
864
+ }
865
+ function confirm() {
866
+ onChange(draft.toISOString());
867
+ setOpen(false);
868
+ }
869
+ const first = new Date(view.y, view.m, 1);
870
+ const startWeekday = (first.getDay() - intl.firstDay + 7) % 7;
871
+ const daysInMonth = new Date(view.y, view.m + 1, 0).getDate();
872
+ const prevDisabled = view.y < minDate.getFullYear() || view.y === minDate.getFullYear() && view.m <= minDate.getMonth();
873
+ const todayStart = startOfDay(/* @__PURE__ */ new Date());
874
+ const draftStart = startOfDay(draft);
875
+ const spanCells = Math.ceil((startWeekday + daysInMonth) / 7) * 7;
876
+ const dayCells = Array.from({ length: spanCells }, (_, i) => {
877
+ const cell = new Date(view.y, view.m, 1 - startWeekday + i);
878
+ const inMonth = cell.getMonth() === view.m && cell.getFullYear() === view.y;
879
+ const cellStart = cell.getTime();
880
+ const isDisabled = !inMonth || cellStart < minStart;
881
+ const isSelected = inMonth && cellStart === draftStart;
882
+ const isToday = inMonth && cellStart === todayStart;
883
+ const isFocusTarget = inMonth && !isDisabled && cellStart === startOfDay(focusedDay);
884
+ return /* @__PURE__ */ jsxRuntime.jsx(
885
+ "button",
886
+ {
887
+ type: "button",
888
+ disabled: isDisabled,
889
+ tabIndex: isFocusTarget ? 0 : -1,
890
+ ref: inMonth && !isDisabled ? (el) => {
891
+ if (el) dayRefs.current.set(cellStart, el);
892
+ else dayRefs.current.delete(cellStart);
893
+ } : void 0,
894
+ "aria-hidden": inMonth ? void 0 : true,
895
+ "aria-label": intl.dayLabel.format(cell),
896
+ "aria-pressed": isSelected,
897
+ onClick: inMonth ? () => pickDay(cell.getDate()) : void 0,
898
+ onKeyDown: inMonth && !isDisabled ? (e) => onDayKeyDown(e, cell) : void 0,
899
+ className: cx(DateTimePicker_default.day, isToday && DateTimePicker_default.today, isSelected && DateTimePicker_default.selected, !inMonth && DateTimePicker_default.outside),
900
+ children: cell.getDate()
901
+ },
902
+ `c-${i}`
903
+ );
904
+ });
905
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
906
+ /* @__PURE__ */ jsxRuntime.jsxs(
907
+ "button",
908
+ {
909
+ id,
910
+ type: "button",
911
+ disabled,
912
+ "aria-haspopup": "dialog",
913
+ "aria-expanded": open,
914
+ "aria-label": ariaLabel ? `${ariaLabel}: ${value ? intl.full.format(new Date(value)) : placeholder}` : void 0,
915
+ onClick: openPicker,
916
+ className: cx(DateTimePicker_default.trigger, value && DateTimePicker_default.hasValue),
917
+ children: [
918
+ calendarGlyph,
919
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: DateTimePicker_default.triggerLabel, children: value ? intl.full.format(new Date(value)) : placeholder })
920
+ ]
921
+ }
922
+ ),
923
+ /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onClose: () => setOpen(false), label: ariaLabel ?? text.dialog, children: [
924
+ /* @__PURE__ */ jsxRuntime.jsx(SheetHeader, { children: intl.full.format(draft) }),
925
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetBody, { children: [
926
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: DateTimePicker_default.timeRow, children: [
927
+ clockGlyph,
928
+ intl.hour12 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
929
+ /* @__PURE__ */ jsxRuntime.jsx(Select, { "aria-label": text.hour, value: String(h12), onChange: (e) => setHour(e.target.value), className: DateTimePicker_default.grow, children: Array.from({ length: 12 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(i + 1), children: i + 1 }, i + 1)) }),
930
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: DateTimePicker_default.colon, "aria-hidden": "true", children: ":" }),
931
+ /* @__PURE__ */ jsxRuntime.jsx(Select, { "aria-label": text.minute, value: String(draft.getMinutes()), onChange: (e) => setMinute(e.target.value), className: DateTimePicker_default.grow, children: minuteOptions(minuteStep).map((m) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(m), children: pad2(m) }, m)) }),
932
+ /* @__PURE__ */ jsxRuntime.jsxs(Select, { "aria-label": text.dayPeriod, value: isPM ? "pm" : "am", onChange: (e) => setMeridiem(e.target.value), className: DateTimePicker_default.meridiem, children: [
933
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "am", children: intl.dayPeriods[0] }),
934
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "pm", children: intl.dayPeriods[1] })
935
+ ] })
936
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
937
+ /* @__PURE__ */ jsxRuntime.jsx(Select, { "aria-label": text.hour, value: String(h24), onChange: (e) => setHour(e.target.value), className: DateTimePicker_default.grow, children: Array.from({ length: 24 }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(i), children: pad2(i) }, i)) }),
938
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: DateTimePicker_default.colon, "aria-hidden": "true", children: ":" }),
939
+ /* @__PURE__ */ jsxRuntime.jsx(Select, { "aria-label": text.minute, value: String(draft.getMinutes()), onChange: (e) => setMinute(e.target.value), className: DateTimePicker_default.grow, children: minuteOptions(minuteStep).map((m) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(m), children: pad2(m) }, m)) })
940
+ ] })
941
+ ] }),
942
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": intl.monthTitle.format(first), children: [
943
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: DateTimePicker_default.calendarHeader, children: [
944
+ /* @__PURE__ */ jsxRuntime.jsx(
945
+ Button,
946
+ {
947
+ iconOnly: true,
948
+ "aria-label": text.previousMonth,
949
+ variant: "ghost",
950
+ size: "sm",
951
+ disabled: prevDisabled,
952
+ onClick: () => shiftMonth(-1),
953
+ children: chevronLeft
954
+ }
955
+ ),
956
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: DateTimePicker_default.monthLabel, children: intl.monthTitle.format(first) }),
957
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { iconOnly: true, "aria-label": text.nextMonth, variant: "ghost", size: "sm", onClick: () => shiftMonth(1), children: chevronRight })
958
+ ] }),
959
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: DateTimePicker_default.weekdays, children: intl.weekdays.map((w, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: DateTimePicker_default.weekday, children: w }, `wd-${i}`)) }),
960
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: DateTimePicker_default.grid, children: dayCells })
961
+ ] })
962
+ ] }),
963
+ /* @__PURE__ */ jsxRuntime.jsxs(SheetFooter, { children: [
964
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", onClick: goToday, children: text.today }),
965
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: confirm, children: text.done })
966
+ ] })
967
+ ] })
968
+ ] });
969
+ }
970
+
316
971
  // src/components/Tag/Tag.module.css
317
972
  var Tag_default = {
318
973
  tag: "Tag_tag",
@@ -416,38 +1071,6 @@ function ProgressBar({
416
1071
  );
417
1072
  }
418
1073
 
419
- // src/components/Field/Field.module.css
420
- var Field_default = {
421
- field: "Field_field",
422
- label: "Field_label",
423
- required: "Field_required",
424
- message: "Field_message",
425
- error: "Field_error"
426
- };
427
- var FieldContext = react.createContext(null);
428
- function useFieldContext() {
429
- return react.useContext(FieldContext);
430
- }
431
- function Field({ label, children, hint, error, required = false, className }) {
432
- const id = react.useId();
433
- const messageId = `${id}-message`;
434
- const message = error ?? hint;
435
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx(Field_default.field, className), children: [
436
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: Field_default.label, htmlFor: id, children: [
437
- label,
438
- required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: Field_default.required, "aria-hidden": "true", children: "*" })
439
- ] }),
440
- /* @__PURE__ */ jsxRuntime.jsx(
441
- FieldContext.Provider,
442
- {
443
- value: { id, describedBy: message ? messageId : void 0, invalid: error !== void 0 },
444
- children
445
- }
446
- ),
447
- message && /* @__PURE__ */ jsxRuntime.jsx("span", { id: messageId, className: cx(Field_default.message, error !== void 0 && Field_default.error), children: message })
448
- ] });
449
- }
450
-
451
1074
  // src/components/Input/Input.module.css
452
1075
  var Input_default = {
453
1076
  input: "Input_input",
@@ -540,33 +1163,6 @@ function Textarea({ rows = 3, showCount = false, className, ...rest }) {
540
1163
  ] });
541
1164
  }
542
1165
 
543
- // src/components/Select/Select.module.css
544
- var Select_default = {
545
- wrap: "Select_wrap",
546
- select: "Select_select",
547
- "size-sm": "Select_size-sm",
548
- "size-md": "Select_size-md",
549
- "size-lg": "Select_size-lg",
550
- chevron: "Select_chevron"
551
- };
552
- function Select({ size = "md", className, children, ...rest }) {
553
- const field = useFieldContext();
554
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: Select_default.wrap, children: [
555
- /* @__PURE__ */ jsxRuntime.jsx(
556
- "select",
557
- {
558
- id: rest.id ?? field?.id,
559
- "aria-describedby": rest["aria-describedby"] ?? field?.describedBy,
560
- "aria-invalid": rest["aria-invalid"] ?? (field?.invalid || void 0),
561
- className: cx(Select_default.select, Select_default[`size-${size}`], className),
562
- ...rest,
563
- children
564
- }
565
- ),
566
- /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", className: Select_default.chevron, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 6l4 4 4-4", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) })
567
- ] });
568
- }
569
-
570
1166
  // src/components/Checkbox/Checkbox.module.css
571
1167
  var Checkbox_default = {
572
1168
  root: "Checkbox_root",
@@ -986,103 +1582,6 @@ function CardBody({ className, ...rest }) {
986
1582
  function CardFooter({ className, ...rest }) {
987
1583
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx(Card_default.footer, className), ...rest });
988
1584
  }
989
- var FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
990
- function useOverlay(options) {
991
- const ref = react.useRef(null);
992
- const { open, onClose } = options;
993
- const close = react.useRef(onClose);
994
- react.useEffect(() => {
995
- close.current = onClose;
996
- }, [onClose]);
997
- react.useEffect(() => {
998
- if (!open) return;
999
- const panel = ref.current;
1000
- const previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
1001
- panel?.focus();
1002
- const onKeyDown = (event) => {
1003
- if (event.key === "Escape") {
1004
- event.stopPropagation();
1005
- close.current();
1006
- return;
1007
- }
1008
- if (event.key !== "Tab" || !panel) return;
1009
- const focusable = [...panel.querySelectorAll(FOCUSABLE)];
1010
- if (focusable.length === 0) {
1011
- event.preventDefault();
1012
- panel.focus();
1013
- return;
1014
- }
1015
- const first = focusable[0];
1016
- const last = focusable[focusable.length - 1];
1017
- const active = document.activeElement;
1018
- if (event.shiftKey && (active === first || active === panel)) {
1019
- event.preventDefault();
1020
- last?.focus();
1021
- } else if (!event.shiftKey && active === last) {
1022
- event.preventDefault();
1023
- first?.focus();
1024
- }
1025
- };
1026
- document.addEventListener("keydown", onKeyDown);
1027
- const bodyOverflow = document.body.style.overflow;
1028
- document.body.style.overflow = "hidden";
1029
- return () => {
1030
- document.removeEventListener("keydown", onKeyDown);
1031
- document.body.style.overflow = bodyOverflow;
1032
- previous?.focus();
1033
- };
1034
- }, [open]);
1035
- return ref;
1036
- }
1037
- function usePresence(open, durationMs) {
1038
- const [mounted, setMounted] = react.useState(open);
1039
- if (open && !mounted) setMounted(true);
1040
- react.useEffect(() => {
1041
- if (open) return;
1042
- const timer = setTimeout(() => setMounted(false), durationMs);
1043
- return () => clearTimeout(timer);
1044
- }, [open, durationMs]);
1045
- return { mounted: open || mounted, visible: open };
1046
- }
1047
-
1048
- // src/components/Overlay/Overlay.module.css
1049
- var Overlay_default = {
1050
- scrim: "Overlay_scrim",
1051
- "variant-modal": "Overlay_variant-modal",
1052
- "variant-sheet": "Overlay_variant-sheet"
1053
- };
1054
- var OVERLAY_EXIT_MS = 200;
1055
- function Overlay({ open, onClose, label, variant, closeOnScrimClick, panelClassName, children }) {
1056
- const { mounted, visible } = usePresence(open, OVERLAY_EXIT_MS);
1057
- const ref = useOverlay({ open, onClose });
1058
- if (!mounted) return null;
1059
- return reactDom.createPortal(
1060
- /* @__PURE__ */ jsxRuntime.jsx(
1061
- "div",
1062
- {
1063
- className: cx(Overlay_default.scrim, Overlay_default[`variant-${variant}`]),
1064
- "data-open": visible || void 0,
1065
- "data-testid": "mds-scrim",
1066
- onClick: closeOnScrimClick ? onClose : void 0,
1067
- children: /* @__PURE__ */ jsxRuntime.jsx(
1068
- "div",
1069
- {
1070
- ref,
1071
- role: "dialog",
1072
- "aria-modal": "true",
1073
- "aria-label": label,
1074
- tabIndex: -1,
1075
- className: panelClassName,
1076
- "data-open": visible || void 0,
1077
- onClick: (event) => event.stopPropagation(),
1078
- children
1079
- }
1080
- )
1081
- }
1082
- ),
1083
- document.body
1084
- );
1085
- }
1086
1585
 
1087
1586
  // src/components/Modal/Modal.module.css
1088
1587
  var Modal_default = {
@@ -1115,37 +1614,6 @@ function ModalFooter({ children }) {
1115
1614
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: Modal_default.footer, children });
1116
1615
  }
1117
1616
 
1118
- // src/components/Sheet/Sheet.module.css
1119
- var Sheet_default = {
1120
- panel: "Sheet_panel",
1121
- header: "Sheet_header",
1122
- body: "Sheet_body",
1123
- footer: "Sheet_footer"
1124
- };
1125
- function Sheet({ open, onClose, label, closeOnScrimClick = true, children }) {
1126
- return /* @__PURE__ */ jsxRuntime.jsx(
1127
- Overlay,
1128
- {
1129
- open,
1130
- onClose,
1131
- label,
1132
- variant: "sheet",
1133
- closeOnScrimClick,
1134
- panelClassName: Sheet_default.panel,
1135
- children
1136
- }
1137
- );
1138
- }
1139
- function SheetHeader({ children }) {
1140
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: Sheet_default.header, children });
1141
- }
1142
- function SheetBody({ children }) {
1143
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: Sheet_default.body, children });
1144
- }
1145
- function SheetFooter({ children }) {
1146
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: Sheet_default.footer, children });
1147
- }
1148
-
1149
1617
  // src/components/ConfirmDialog/ConfirmDialog.module.css
1150
1618
  var ConfirmDialog_default = {
1151
1619
  description: "ConfirmDialog_description"
@@ -1253,8 +1721,13 @@ exports.CardBody = CardBody;
1253
1721
  exports.CardFooter = CardFooter;
1254
1722
  exports.CardHeader = CardHeader;
1255
1723
  exports.Checkbox = Checkbox;
1724
+ exports.Chip = Chip;
1725
+ exports.ChipBar = ChipBar;
1726
+ exports.ChipGroup = ChipGroup;
1256
1727
  exports.ConfirmDialog = ConfirmDialog;
1257
1728
  exports.Container = Container;
1729
+ exports.CountButton = CountButton;
1730
+ exports.DateTimePicker = DateTimePicker;
1258
1731
  exports.Divider = Divider;
1259
1732
  exports.EmptyState = EmptyState;
1260
1733
  exports.Field = Field;
@@ -1270,6 +1743,7 @@ exports.Modal = Modal;
1270
1743
  exports.ModalBody = ModalBody;
1271
1744
  exports.ModalFooter = ModalFooter;
1272
1745
  exports.ModalHeader = ModalHeader;
1746
+ exports.OverlayHistoryContext = OverlayHistoryContext;
1273
1747
  exports.PasswordInput = PasswordInput;
1274
1748
  exports.ProgressBar = ProgressBar;
1275
1749
  exports.Radio = Radio;