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