@bigtablet/design-system 2.4.0 → 2.4.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,6 +1,6 @@
1
1
  "use client";
2
2
  import './index.css';
3
- import * as React5 from 'react';
3
+ import * as React4 from 'react';
4
4
  import { createContext, useContext, useState, useCallback } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -107,6 +107,15 @@ var colors = {
107
107
  }
108
108
  };
109
109
 
110
+ // src/styles/elevation/index.ts
111
+ var elevation = {
112
+ level1: "0 1px 1px -1px rgba(0, 0, 0, 0.20), 0 3px 3px 0px rgba(0, 0, 0, 0.12)",
113
+ level2: "0 2px 2px -2px rgba(0, 0, 0, 0.20), 0 6px 6px 0px rgba(0, 0, 0, 0.12)",
114
+ level3: "0 3px 3px -3px rgba(0, 0, 0, 0.20), 0 9px 9px 0px rgba(0, 0, 0, 0.12)",
115
+ level4: "0 5px 5px -5px rgba(0, 0, 0, 0.20), 0 15px 15px 0px rgba(0, 0, 0, 0.12)",
116
+ level5: "0 8px 10px -5px rgba(0, 0, 0, 0.20), 0 20px 20px 0px rgba(0, 0, 0, 0.12)"
117
+ };
118
+
110
119
  // src/styles/motion/index.ts
111
120
  var motion = {
112
121
  transition: {
@@ -147,15 +156,6 @@ var radius = {
147
156
  full: "9999px"
148
157
  };
149
158
 
150
- // src/styles/elevation/index.ts
151
- var elevation = {
152
- level1: "0 1px 1px -1px rgba(0, 0, 0, 0.20), 0 3px 3px 0px rgba(0, 0, 0, 0.12)",
153
- level2: "0 2px 2px -2px rgba(0, 0, 0, 0.20), 0 6px 6px 0px rgba(0, 0, 0, 0.12)",
154
- level3: "0 3px 3px -3px rgba(0, 0, 0, 0.20), 0 9px 9px 0px rgba(0, 0, 0, 0.12)",
155
- level4: "0 5px 5px -5px rgba(0, 0, 0, 0.20), 0 15px 15px 0px rgba(0, 0, 0, 0.12)",
156
- level5: "0 8px 10px -5px rgba(0, 0, 0, 0.20), 0 20px 20px 0px rgba(0, 0, 0, 0.12)"
157
- };
158
-
159
159
  // src/styles/spacing/index.ts
160
160
  var spacing = {
161
161
  "0": "0px",
@@ -485,8 +485,8 @@ var FOCUSABLE_SELECTORS = [
485
485
  '[tabindex]:not([tabindex="-1"])'
486
486
  ].join(", ");
487
487
  function useFocusTrap(containerRef, isActive) {
488
- const previousActiveElement = React5.useRef(null);
489
- React5.useEffect(() => {
488
+ const previousActiveElement = React4.useRef(null);
489
+ React4.useEffect(() => {
490
490
  if (!isActive) return;
491
491
  const container = containerRef.current;
492
492
  if (!container) return;
@@ -591,43 +591,46 @@ var AlertModal = ({
591
591
  onCancel,
592
592
  onClose
593
593
  }) => {
594
- const panelRef = React5.useRef(null);
595
- const titleId = React5.useId();
596
- const messageId = React5.useId();
594
+ const panelRef = React4.useRef(null);
595
+ const titleId = React4.useId();
596
+ const messageId = React4.useId();
597
597
  useFocusTrap(panelRef, true);
598
598
  const modalClassName = cn("alert_modal", `alert_variant_${variant}`);
599
599
  const actionsClassName = cn("alert_actions", `alert_actions_${actionsAlign}`);
600
- return /* @__PURE__ */ jsx(
601
- "div",
602
- {
603
- className: "alert_overlay",
604
- role: "presentation",
605
- onClick: onClose,
606
- onKeyDown: (e) => e.key === "Escape" && onClose(),
607
- children: /* @__PURE__ */ jsxs(
608
- "div",
609
- {
610
- ref: panelRef,
611
- className: modalClassName,
612
- onClick: (e) => e.stopPropagation(),
613
- onKeyDown: (e) => {
614
- if (e.key !== "Escape") e.stopPropagation();
615
- },
616
- role: "alertdialog",
617
- "aria-modal": "true",
618
- "aria-labelledby": titleId,
619
- "aria-describedby": messageId,
620
- children: [
621
- title && /* @__PURE__ */ jsx("div", { className: "alert_title", id: titleId, children: title }),
622
- message && /* @__PURE__ */ jsx("div", { className: "alert_message", id: messageId, children: message }),
623
- /* @__PURE__ */ jsxs("div", { className: actionsClassName, children: [
624
- showCancel && /* @__PURE__ */ jsx("button", { type: "button", className: "alert_button alert_button_cancel", onClick: onCancel, children: cancelText }),
625
- /* @__PURE__ */ jsx("button", { type: "button", className: "alert_button alert_button_confirm", onClick: onConfirm, children: confirmText })
626
- ] })
627
- ]
628
- }
629
- )
630
- }
600
+ return (
601
+ // biome-ignore lint/a11y/noStaticElementInteractions: modal overlay pattern — clickable backdrop without role=button (focus is trapped on the panel inside)
602
+ /* @__PURE__ */ jsx(
603
+ "div",
604
+ {
605
+ className: "alert_overlay",
606
+ role: "presentation",
607
+ onClick: onClose,
608
+ onKeyDown: (e) => e.key === "Escape" && onClose(),
609
+ children: /* @__PURE__ */ jsxs(
610
+ "div",
611
+ {
612
+ ref: panelRef,
613
+ className: modalClassName,
614
+ onClick: (e) => e.stopPropagation(),
615
+ onKeyDown: (e) => {
616
+ if (e.key !== "Escape") e.stopPropagation();
617
+ },
618
+ role: "alertdialog",
619
+ "aria-modal": "true",
620
+ "aria-labelledby": titleId,
621
+ "aria-describedby": messageId,
622
+ children: [
623
+ title && /* @__PURE__ */ jsx("div", { className: "alert_title", id: titleId, children: title }),
624
+ message && /* @__PURE__ */ jsx("div", { className: "alert_message", id: messageId, children: message }),
625
+ /* @__PURE__ */ jsxs("div", { className: actionsClassName, children: [
626
+ showCancel && /* @__PURE__ */ jsx("button", { type: "button", className: "alert_button alert_button_cancel", onClick: onCancel, children: cancelText }),
627
+ /* @__PURE__ */ jsx("button", { type: "button", className: "alert_button alert_button_confirm", onClick: onConfirm, children: confirmText })
628
+ ] })
629
+ ]
630
+ }
631
+ )
632
+ }
633
+ )
631
634
  );
632
635
  };
633
636
  var Button = ({
@@ -685,12 +688,12 @@ var Checkbox = ({
685
688
  ref,
686
689
  ...props
687
690
  }) => {
688
- const inputRef = React5.useRef(null);
689
- React5.useImperativeHandle(
691
+ const inputRef = React4.useRef(null);
692
+ React4.useImperativeHandle(
690
693
  ref,
691
694
  () => inputRef.current
692
695
  );
693
- React5.useEffect(() => {
696
+ React4.useEffect(() => {
694
697
  if (!inputRef.current) return;
695
698
  inputRef.current.indeterminate = Boolean(indeterminate);
696
699
  }, [indeterminate]);
@@ -701,26 +704,57 @@ var Checkbox = ({
701
704
  className
702
705
  );
703
706
  return /* @__PURE__ */ jsxs("label", { className: rootClassName, children: [
704
- /* @__PURE__ */ jsx(
705
- "input",
706
- {
707
- ref: inputRef,
708
- type: "checkbox",
709
- className: "checkbox_input",
710
- ...props
711
- }
712
- ),
707
+ /* @__PURE__ */ jsx("input", { ref: inputRef, type: "checkbox", className: "checkbox_input", ...props }),
713
708
  /* @__PURE__ */ jsx("span", { className: "checkbox_state_layer", "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { className: "checkbox_icon" }) }),
714
709
  label ? /* @__PURE__ */ jsx("span", { className: "checkbox_label", children: label }) : null
715
710
  ] });
716
711
  };
717
712
  Checkbox.displayName = "Checkbox";
718
- var CheckIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "4 10 8 14 16 6" }) });
719
- var CloseIcon = () => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
720
- /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "14", y2: "14" }),
721
- /* @__PURE__ */ jsx("line", { x1: "14", y1: "6", x2: "6", y2: "14" })
722
- ] });
723
- var ChevronDownIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("polyline", { points: "5 8 10 13 15 8" }) });
713
+ var CheckIcon = () => /* @__PURE__ */ jsx(
714
+ "svg",
715
+ {
716
+ viewBox: "0 0 20 20",
717
+ fill: "none",
718
+ stroke: "currentColor",
719
+ strokeWidth: 2,
720
+ strokeLinecap: "round",
721
+ strokeLinejoin: "round",
722
+ "aria-hidden": "true",
723
+ focusable: "false",
724
+ children: /* @__PURE__ */ jsx("polyline", { points: "4 10 8 14 16 6" })
725
+ }
726
+ );
727
+ var CloseIcon = () => /* @__PURE__ */ jsxs(
728
+ "svg",
729
+ {
730
+ viewBox: "0 0 20 20",
731
+ fill: "none",
732
+ stroke: "currentColor",
733
+ strokeWidth: 2,
734
+ strokeLinecap: "round",
735
+ strokeLinejoin: "round",
736
+ "aria-hidden": "true",
737
+ focusable: "false",
738
+ children: [
739
+ /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "14", y2: "14" }),
740
+ /* @__PURE__ */ jsx("line", { x1: "14", y1: "6", x2: "6", y2: "14" })
741
+ ]
742
+ }
743
+ );
744
+ var ChevronDownIcon = () => /* @__PURE__ */ jsx(
745
+ "svg",
746
+ {
747
+ viewBox: "0 0 20 20",
748
+ fill: "none",
749
+ stroke: "currentColor",
750
+ strokeWidth: 2,
751
+ strokeLinecap: "round",
752
+ strokeLinejoin: "round",
753
+ "aria-hidden": "true",
754
+ focusable: "false",
755
+ children: /* @__PURE__ */ jsx("polyline", { points: "5 8 10 13 15 8" })
756
+ }
757
+ );
724
758
  var Chip = ({
725
759
  type = "basic",
726
760
  label,
@@ -818,22 +852,22 @@ var Dropdown = ({
818
852
  fullWidth,
819
853
  className
820
854
  }) => {
821
- const internalId = React5.useId();
855
+ const internalId = React4.useId();
822
856
  const dropdownId = id ?? internalId;
823
857
  const isControlled = value !== void 0;
824
- const [internalValue, setInternalValue] = React5.useState(defaultValue);
858
+ const [internalValue, setInternalValue] = React4.useState(defaultValue);
825
859
  const currentValue = isControlled ? value ?? null : internalValue;
826
- const [isOpen, setIsOpen] = React5.useState(false);
827
- const [activeIndex, setActiveIndex] = React5.useState(-1);
828
- const [dropUp, setDropUp] = React5.useState(false);
829
- const wrapperRef = React5.useRef(null);
830
- const controlRef = React5.useRef(null);
831
- const currentOption = React5.useMemo(
860
+ const [isOpen, setIsOpen] = React4.useState(false);
861
+ const [activeIndex, setActiveIndex] = React4.useState(-1);
862
+ const [dropUp, setDropUp] = React4.useState(false);
863
+ const wrapperRef = React4.useRef(null);
864
+ const controlRef = React4.useRef(null);
865
+ const currentOption = React4.useMemo(
832
866
  () => options.find((o) => o.value === currentValue) ?? null,
833
867
  [options, currentValue]
834
868
  );
835
869
  const isLabelVisible = isOpen || !!currentOption;
836
- const setValue = React5.useCallback(
870
+ const setValue = React4.useCallback(
837
871
  (next) => {
838
872
  const option = options.find((o) => o.value === next) ?? null;
839
873
  if (!isControlled) setInternalValue(next);
@@ -841,7 +875,7 @@ var Dropdown = ({
841
875
  },
842
876
  [isControlled, onChange, options]
843
877
  );
844
- React5.useEffect(() => {
878
+ React4.useEffect(() => {
845
879
  const handleOutsideClick = (e) => {
846
880
  if (!wrapperRef.current?.contains(e.target)) {
847
881
  setIsOpen(false);
@@ -912,14 +946,17 @@ var Dropdown = ({
912
946
  break;
913
947
  }
914
948
  };
915
- React5.useEffect(() => {
949
+ React4.useEffect(() => {
916
950
  if (!isOpen) return;
917
951
  const idx = options.findIndex((o) => o.value === currentValue && !o.disabled);
918
952
  setActiveIndex(
919
- idx >= 0 ? idx : Math.max(0, options.findIndex((o) => !o.disabled))
953
+ idx >= 0 ? idx : Math.max(
954
+ 0,
955
+ options.findIndex((o) => !o.disabled)
956
+ )
920
957
  );
921
958
  }, [isOpen, options, currentValue]);
922
- React5.useLayoutEffect(() => {
959
+ React4.useLayoutEffect(() => {
923
960
  if (!isOpen || !controlRef.current) return;
924
961
  const rect = controlRef.current.getBoundingClientRect();
925
962
  const listHeight = Math.min(options.length * 56, 288);
@@ -938,14 +975,7 @@ var Dropdown = ({
938
975
  style: fullWidth ? { width: "100%" } : void 0,
939
976
  children: [
940
977
  /* @__PURE__ */ jsxs("div", { className: fieldsetClassName, children: [
941
- label && /* @__PURE__ */ jsx(
942
- "span",
943
- {
944
- className: cn("dropdown_label", { is_visible: isLabelVisible }),
945
- "aria-hidden": "true",
946
- children: label
947
- }
948
- ),
978
+ label && /* @__PURE__ */ jsx("span", { className: cn("dropdown_label", { is_visible: isLabelVisible }), "aria-hidden": "true", children: label }),
949
979
  /* @__PURE__ */ jsxs(
950
980
  "button",
951
981
  {
@@ -967,49 +997,41 @@ var Dropdown = ({
967
997
  }
968
998
  )
969
999
  ] }),
970
- isOpen && /* @__PURE__ */ jsx(
971
- "div",
972
- {
973
- id: `${dropdownId}_listbox`,
974
- role: "listbox",
975
- className: listClassName,
976
- children: options.map((opt, i) => {
977
- const selected = currentValue === opt.value;
978
- const active = i === activeIndex;
979
- return /* @__PURE__ */ jsxs(React5.Fragment, { children: [
980
- /* @__PURE__ */ jsxs(
981
- "div",
982
- {
983
- role: "option",
984
- tabIndex: -1,
985
- "aria-selected": selected,
986
- "aria-disabled": opt.disabled ? true : void 0,
987
- className: cn("dropdown_option", {
988
- is_selected: selected,
989
- is_active: active,
990
- is_disabled: opt.disabled
991
- }),
992
- onMouseEnter: () => !opt.disabled && setActiveIndex(i),
993
- onClick: () => {
994
- if (opt.disabled) return;
995
- setValue(opt.value);
996
- setIsOpen(false);
997
- },
998
- children: [
999
- opt.leadingIcon && /* @__PURE__ */ jsx("span", { className: "dropdown_option_icon", children: opt.leadingIcon }),
1000
- /* @__PURE__ */ jsxs("span", { className: "dropdown_option_content", children: [
1001
- /* @__PURE__ */ jsx("span", { className: "dropdown_option_label", children: opt.label }),
1002
- opt.supportingText && /* @__PURE__ */ jsx("span", { className: "dropdown_option_supporting", children: opt.supportingText })
1003
- ] }),
1004
- (selected || opt.trailingIcon) && /* @__PURE__ */ jsx("span", { className: "dropdown_option_trailing", children: opt.trailingIcon ?? /* @__PURE__ */ jsx(Check, { size: 16, "aria-hidden": "true" }) })
1005
- ]
1006
- }
1007
- ),
1008
- opt.showDivider && /* @__PURE__ */ jsx("div", { className: "dropdown_option_divider", role: "separator" })
1009
- ] }, opt.value);
1010
- })
1011
- }
1012
- )
1000
+ isOpen && /* @__PURE__ */ jsx("div", { id: `${dropdownId}_listbox`, role: "listbox", className: listClassName, children: options.map((opt, i) => {
1001
+ const selected = currentValue === opt.value;
1002
+ const active = i === activeIndex;
1003
+ return /* @__PURE__ */ jsxs(React4.Fragment, { children: [
1004
+ /* @__PURE__ */ jsxs(
1005
+ "div",
1006
+ {
1007
+ role: "option",
1008
+ tabIndex: -1,
1009
+ "aria-selected": selected,
1010
+ "aria-disabled": opt.disabled ? true : void 0,
1011
+ className: cn("dropdown_option", {
1012
+ is_selected: selected,
1013
+ is_active: active,
1014
+ is_disabled: opt.disabled
1015
+ }),
1016
+ onMouseEnter: () => !opt.disabled && setActiveIndex(i),
1017
+ onClick: () => {
1018
+ if (opt.disabled) return;
1019
+ setValue(opt.value);
1020
+ setIsOpen(false);
1021
+ },
1022
+ children: [
1023
+ opt.leadingIcon && /* @__PURE__ */ jsx("span", { className: "dropdown_option_icon", children: opt.leadingIcon }),
1024
+ /* @__PURE__ */ jsxs("span", { className: "dropdown_option_content", children: [
1025
+ /* @__PURE__ */ jsx("span", { className: "dropdown_option_label", children: opt.label }),
1026
+ opt.supportingText && /* @__PURE__ */ jsx("span", { className: "dropdown_option_supporting", children: opt.supportingText })
1027
+ ] }),
1028
+ (selected || opt.trailingIcon) && /* @__PURE__ */ jsx("span", { className: "dropdown_option_trailing", children: opt.trailingIcon ?? /* @__PURE__ */ jsx(Check, { size: 16, "aria-hidden": "true" }) })
1029
+ ]
1030
+ }
1031
+ ),
1032
+ opt.showDivider && /* @__PURE__ */ jsx("hr", { className: "dropdown_option_divider" })
1033
+ ] }, opt.value);
1034
+ }) })
1013
1035
  ]
1014
1036
  }
1015
1037
  );
@@ -1036,9 +1058,9 @@ var DatePicker = ({
1036
1058
  minDateSrFormat = "Minimum date: {date}",
1037
1059
  selectableRangeUntilTodaySrText = "Selectable up to today"
1038
1060
  }) => {
1039
- const groupId = React5.useId();
1040
- const constraintId = React5.useId();
1041
- const { todayYear, todayMonth, todayDay } = React5.useMemo(() => {
1061
+ const groupId = React4.useId();
1062
+ const constraintId = React4.useId();
1063
+ const { todayYear, todayMonth, todayDay } = React4.useMemo(() => {
1042
1064
  const now = /* @__PURE__ */ new Date();
1043
1065
  return {
1044
1066
  todayYear: now.getFullYear(),
@@ -1047,7 +1069,7 @@ var DatePicker = ({
1047
1069
  };
1048
1070
  }, []);
1049
1071
  const endYear = endYearProp ?? todayYear + 10;
1050
- const parsed = React5.useMemo(() => {
1072
+ const parsed = React4.useMemo(() => {
1051
1073
  if (!value) return { year: 0, month: 0, day: 0 };
1052
1074
  const [y, m, d] = value.split("-").map(Number);
1053
1075
  return {
@@ -1056,7 +1078,7 @@ var DatePicker = ({
1056
1078
  day: d || 0
1057
1079
  };
1058
1080
  }, [value]);
1059
- const min = React5.useMemo(() => {
1081
+ const min = React4.useMemo(() => {
1060
1082
  if (!minDate) return { year: 0, month: 0, day: 0 };
1061
1083
  const [y, m, d] = minDate.split("-").map(Number);
1062
1084
  return {
@@ -1069,11 +1091,14 @@ var DatePicker = ({
1069
1091
  const maxYear = selectableRange === "until-today" ? todayYear : endYear;
1070
1092
  const minMonth = min.year > 0 && year === min.year ? Math.min(12, Math.max(1, min.month)) : 1;
1071
1093
  const maxMonth = selectableRange === "until-today" && year === todayYear ? todayMonth : 12;
1072
- const minDay = Math.min(31, Math.max(
1073
- 1,
1074
- min.year > 0 && min.month > 0 && year === min.year && month === min.month ? min.day : 1
1075
- ));
1076
- const maxDay = React5.useMemo(() => {
1094
+ const minDay = Math.min(
1095
+ 31,
1096
+ Math.max(
1097
+ 1,
1098
+ min.year > 0 && min.month > 0 && year === min.year && month === min.month ? min.day : 1
1099
+ )
1100
+ );
1101
+ const maxDay = React4.useMemo(() => {
1077
1102
  if (!year || !month) return 31;
1078
1103
  const daysInMonth = getDaysInMonth(year, month);
1079
1104
  if (selectableRange === "until-today" && year === todayYear && month === todayMonth) {
@@ -1081,28 +1106,28 @@ var DatePicker = ({
1081
1106
  }
1082
1107
  return daysInMonth;
1083
1108
  }, [year, month, selectableRange, todayYear, todayMonth, todayDay]);
1084
- const yearOptions = React5.useMemo(
1109
+ const yearOptions = React4.useMemo(
1085
1110
  () => range(startYear, maxYear).map((y) => ({
1086
1111
  value: String(y),
1087
1112
  label: String(y)
1088
1113
  })),
1089
1114
  [startYear, maxYear]
1090
1115
  );
1091
- const monthOptions = React5.useMemo(
1116
+ const monthOptions = React4.useMemo(
1092
1117
  () => range(minMonth, Math.max(minMonth, maxMonth)).map((m) => ({
1093
1118
  value: String(m),
1094
1119
  label: pad(m)
1095
1120
  })),
1096
1121
  [minMonth, maxMonth]
1097
1122
  );
1098
- const dayOptions = React5.useMemo(
1123
+ const dayOptions = React4.useMemo(
1099
1124
  () => range(minDay, Math.max(minDay, maxDay)).map((d) => ({
1100
1125
  value: String(d),
1101
1126
  label: pad(d)
1102
1127
  })),
1103
1128
  [minDay, maxDay]
1104
1129
  );
1105
- const emit = React5.useCallback(
1130
+ const emit = React4.useCallback(
1106
1131
  (yy, mm, dd) => {
1107
1132
  if (mode === "year-month") {
1108
1133
  onChange(`${yy}-${pad(mm)}`);
@@ -1113,7 +1138,7 @@ var DatePicker = ({
1113
1138
  },
1114
1139
  [mode, onChange]
1115
1140
  );
1116
- const handleYearChange = React5.useCallback(
1141
+ const handleYearChange = React4.useCallback(
1117
1142
  (raw) => {
1118
1143
  if (!raw) return;
1119
1144
  const newYear = Number(raw);
@@ -1130,14 +1155,14 @@ var DatePicker = ({
1130
1155
  },
1131
1156
  [month, day, min.year, min.month, selectableRange, todayYear, todayMonth, emit]
1132
1157
  );
1133
- const handleMonthChange = React5.useCallback(
1158
+ const handleMonthChange = React4.useCallback(
1134
1159
  (raw) => {
1135
1160
  if (!raw || !year) return;
1136
1161
  emit(year, Number(raw), day || void 0);
1137
1162
  },
1138
1163
  [year, day, emit]
1139
1164
  );
1140
- const handleDayChange = React5.useCallback(
1165
+ const handleDayChange = React4.useCallback(
1141
1166
  (raw) => {
1142
1167
  if (!raw || !year || !month) return;
1143
1168
  emit(year, month, Number(raw));
@@ -1151,8 +1176,7 @@ var DatePicker = ({
1151
1176
  });
1152
1177
  const constraintParts = [];
1153
1178
  if (minDate) constraintParts.push(minDateSrFormat.replace("{date}", minDate));
1154
- if (selectableRange === "until-today")
1155
- constraintParts.push(selectableRangeUntilTodaySrText);
1179
+ if (selectableRange === "until-today") constraintParts.push(selectableRangeUntilTodaySrText);
1156
1180
  const constraintDesc = constraintParts.join(". ");
1157
1181
  return /* @__PURE__ */ jsxs("div", { className: rootClassName, style: containerStyle, children: [
1158
1182
  label && /* @__PURE__ */ jsx("span", { className: "date_picker_label", id: groupId, children: label }),
@@ -1209,29 +1233,12 @@ var DatePicker = ({
1209
1233
  )
1210
1234
  ] });
1211
1235
  };
1212
- var Divider = ({
1213
- weight = "standard",
1214
- className,
1215
- ...props
1216
- }) => {
1217
- const dividerClassName = cn(
1218
- "divider",
1219
- `divider_weight_${weight}`,
1220
- className
1221
- );
1236
+ var Divider = ({ weight = "standard", className, ...props }) => {
1237
+ const dividerClassName = cn("divider", `divider_weight_${weight}`, className);
1222
1238
  return /* @__PURE__ */ jsx("hr", { className: dividerClassName, ...props });
1223
1239
  };
1224
- var FAB = ({
1225
- variant = "primary",
1226
- icon,
1227
- className,
1228
- ...props
1229
- }) => {
1230
- const fabClassName = cn(
1231
- "fab",
1232
- `fab_variant_${variant}`,
1233
- className
1234
- );
1240
+ var FAB = ({ variant = "primary", icon, className, ...props }) => {
1241
+ const fabClassName = cn("fab", `fab_variant_${variant}`, className);
1235
1242
  return /* @__PURE__ */ jsx("button", { className: fabClassName, ...props, children: /* @__PURE__ */ jsx("span", { className: "fab_icon", "aria-hidden": "true", children: icon }) });
1236
1243
  };
1237
1244
  var FileInput = ({
@@ -1243,14 +1250,16 @@ var FileInput = ({
1243
1250
  disabled,
1244
1251
  ...props
1245
1252
  }) => {
1246
- const inputId = React5.useId();
1247
- const helperId = React5.useId();
1248
- const [previewUrls, setPreviewUrls] = React5.useState([]);
1253
+ const inputId = React4.useId();
1254
+ const helperId = React4.useId();
1255
+ const [previewUrls, setPreviewUrls] = React4.useState([]);
1249
1256
  const handleChange = (e) => {
1250
1257
  const files = e.currentTarget.files;
1251
1258
  onFiles?.(files);
1252
1259
  if (preview && files) {
1253
- previewUrls.forEach((url) => URL.revokeObjectURL(url));
1260
+ for (const url of previewUrls) {
1261
+ URL.revokeObjectURL(url);
1262
+ }
1254
1263
  const urls = [];
1255
1264
  for (let i = 0; i < files.length; i++) {
1256
1265
  if (files[i].type.startsWith("image/")) {
@@ -1259,13 +1268,17 @@ var FileInput = ({
1259
1268
  }
1260
1269
  setPreviewUrls(urls);
1261
1270
  } else {
1262
- previewUrls.forEach((url) => URL.revokeObjectURL(url));
1271
+ for (const url of previewUrls) {
1272
+ URL.revokeObjectURL(url);
1273
+ }
1263
1274
  setPreviewUrls([]);
1264
1275
  }
1265
1276
  };
1266
- React5.useEffect(() => {
1277
+ React4.useEffect(() => {
1267
1278
  return () => {
1268
- previewUrls.forEach((url) => URL.revokeObjectURL(url));
1279
+ for (const url of previewUrls) {
1280
+ URL.revokeObjectURL(url);
1281
+ }
1269
1282
  };
1270
1283
  }, [previewUrls]);
1271
1284
  const rootClassName = cn("file_input", disabled && "file_input_disabled", className);
@@ -1284,7 +1297,10 @@ var FileInput = ({
1284
1297
  ),
1285
1298
  /* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "file_input_label", children: label }),
1286
1299
  supportingText && /* @__PURE__ */ jsx("span", { id: helperId, className: "file_input_helper", children: supportingText }),
1287
- previewUrls.length > 0 && /* @__PURE__ */ jsx("div", { className: "file_input_preview", children: previewUrls.map((url) => /* @__PURE__ */ jsx("img", { src: url, alt: "", className: "file_input_preview_img" }, url)) })
1300
+ previewUrls.length > 0 && /* @__PURE__ */ jsx("div", { className: "file_input_preview", children: previewUrls.map((url) => (
1301
+ // biome-ignore lint/performance/noImgElement: framework-agnostic DS — host app should swap with next/image if needed
1302
+ /* @__PURE__ */ jsx("img", { src: url, alt: "", className: "file_input_preview_img" }, url)
1303
+ )) })
1288
1304
  ] });
1289
1305
  };
1290
1306
 
@@ -1923,13 +1939,7 @@ var LinearProgress = ({
1923
1939
  "aria-valuemin": 0,
1924
1940
  "aria-valuemax": totalSteps,
1925
1941
  ...props,
1926
- children: /* @__PURE__ */ jsx(
1927
- "div",
1928
- {
1929
- className: "linear_progress_indicator",
1930
- style: { width: `${percent}%` }
1931
- }
1932
- )
1942
+ children: /* @__PURE__ */ jsx("div", { className: "linear_progress_indicator", style: { width: `${percent}%` } })
1933
1943
  }
1934
1944
  );
1935
1945
  };
@@ -1953,32 +1963,114 @@ var ListItem = ({
1953
1963
  onClick && "list_item_interactive",
1954
1964
  className
1955
1965
  );
1966
+ return (
1967
+ // biome-ignore lint/a11y/noStaticElementInteractions: optional interactive list item — role=button + tabIndex set conditionally based on onClick
1968
+ /* @__PURE__ */ jsx(
1969
+ "div",
1970
+ {
1971
+ className: rootClassName,
1972
+ onClick: disabled ? void 0 : onClick,
1973
+ onKeyDown: (e) => {
1974
+ if (disabled || !onClick) return;
1975
+ if (e.key === "Enter" || e.key === " ") {
1976
+ e.preventDefault();
1977
+ onClick(e);
1978
+ }
1979
+ },
1980
+ role: onClick ? "button" : void 0,
1981
+ tabIndex: onClick && !disabled ? 0 : void 0,
1982
+ "aria-disabled": disabled || void 0,
1983
+ ...props,
1984
+ children: /* @__PURE__ */ jsxs("div", { className: "list_item_state_layer", children: [
1985
+ leadingElement && /* @__PURE__ */ jsx("div", { className: "list_item_leading", children: leadingElement }),
1986
+ /* @__PURE__ */ jsxs("div", { className: "list_item_content", children: [
1987
+ overline && /* @__PURE__ */ jsx("span", { className: "list_item_overline", children: overline }),
1988
+ /* @__PURE__ */ jsx("span", { className: "list_item_label", children: label }),
1989
+ supportingText && /* @__PURE__ */ jsx("span", { className: "list_item_supporting", children: supportingText }),
1990
+ metadata && /* @__PURE__ */ jsx("span", { className: "list_item_metadata", children: metadata })
1991
+ ] }),
1992
+ trailingElement && /* @__PURE__ */ jsx("div", { className: "list_item_trailing", children: trailingElement })
1993
+ ] })
1994
+ }
1995
+ )
1996
+ );
1997
+ };
1998
+ var Modal = ({
1999
+ open,
2000
+ onClose,
2001
+ closeOnOverlay = true,
2002
+ width = 520,
2003
+ title,
2004
+ children,
2005
+ className,
2006
+ ariaLabel,
2007
+ ...props
2008
+ }) => {
2009
+ const panelRef = React4.useRef(null);
2010
+ const titleId = React4.useId();
2011
+ useFocusTrap(panelRef, open);
2012
+ const handleEscape = React4.useEffectEvent((e) => {
2013
+ if (e.key === "Escape") onClose?.();
2014
+ });
2015
+ React4.useEffect(() => {
2016
+ if (!open) return;
2017
+ document.addEventListener("keydown", handleEscape);
2018
+ return () => document.removeEventListener("keydown", handleEscape);
2019
+ }, [open]);
2020
+ React4.useEffect(() => {
2021
+ if (!open) return;
2022
+ const body = document.body;
2023
+ const openModals = parseInt(body.dataset.openModals || "0", 10);
2024
+ if (openModals === 0) {
2025
+ body.dataset.originalOverflow = window.getComputedStyle(body).overflow;
2026
+ body.style.overflow = "hidden";
2027
+ }
2028
+ body.dataset.openModals = String(openModals + 1);
2029
+ return () => {
2030
+ const currentOpenModals = parseInt(body.dataset.openModals || "1", 10);
2031
+ const nextOpenModals = currentOpenModals - 1;
2032
+ if (nextOpenModals === 0) {
2033
+ body.style.overflow = body.dataset.originalOverflow || "";
2034
+ delete body.dataset.openModals;
2035
+ delete body.dataset.originalOverflow;
2036
+ } else {
2037
+ body.dataset.openModals = String(nextOpenModals);
2038
+ }
2039
+ };
2040
+ }, [open]);
2041
+ if (!open) return null;
2042
+ const panelClassName = cn("modal_panel", className);
2043
+ const hasTitle = !!title;
1956
2044
  return /* @__PURE__ */ jsx(
1957
2045
  "div",
1958
2046
  {
1959
- className: rootClassName,
1960
- onClick: disabled ? void 0 : onClick,
2047
+ className: "modal",
2048
+ role: "dialog",
2049
+ "aria-modal": "true",
2050
+ "aria-labelledby": hasTitle && !ariaLabel ? titleId : void 0,
2051
+ "aria-label": !hasTitle ? ariaLabel ?? "Dialog" : ariaLabel,
2052
+ onClick: () => closeOnOverlay && onClose?.(),
1961
2053
  onKeyDown: (e) => {
1962
- if (disabled || !onClick) return;
1963
- if (e.key === "Enter" || e.key === " ") {
1964
- e.preventDefault();
1965
- onClick(e);
1966
- }
2054
+ if (e.key === "Escape") onClose?.();
1967
2055
  },
1968
- role: onClick ? "button" : void 0,
1969
- tabIndex: onClick && !disabled ? 0 : void 0,
1970
- "aria-disabled": disabled || void 0,
1971
- ...props,
1972
- children: /* @__PURE__ */ jsxs("div", { className: "list_item_state_layer", children: [
1973
- leadingElement && /* @__PURE__ */ jsx("div", { className: "list_item_leading", children: leadingElement }),
1974
- /* @__PURE__ */ jsxs("div", { className: "list_item_content", children: [
1975
- overline && /* @__PURE__ */ jsx("span", { className: "list_item_overline", children: overline }),
1976
- /* @__PURE__ */ jsx("span", { className: "list_item_label", children: label }),
1977
- supportingText && /* @__PURE__ */ jsx("span", { className: "list_item_supporting", children: supportingText }),
1978
- metadata && /* @__PURE__ */ jsx("span", { className: "list_item_metadata", children: metadata })
1979
- ] }),
1980
- trailingElement && /* @__PURE__ */ jsx("div", { className: "list_item_trailing", children: trailingElement })
1981
- ] })
2056
+ children: /* @__PURE__ */ jsxs(
2057
+ "div",
2058
+ {
2059
+ ref: panelRef,
2060
+ className: panelClassName,
2061
+ style: { width },
2062
+ role: "document",
2063
+ onClick: (e) => e.stopPropagation(),
2064
+ onKeyDown: (e) => {
2065
+ if (e.key !== "Escape") e.stopPropagation();
2066
+ },
2067
+ ...props,
2068
+ children: [
2069
+ title && /* @__PURE__ */ jsx("div", { id: titleId, className: "modal_header", children: title }),
2070
+ /* @__PURE__ */ jsx("div", { className: "modal_body", children })
2071
+ ]
2072
+ }
2073
+ )
1982
2074
  }
1983
2075
  );
1984
2076
  };
@@ -1993,8 +2085,11 @@ var OtpInput = ({
1993
2085
  ariaLabel = "OTP \uC785\uB825",
1994
2086
  className
1995
2087
  }) => {
1996
- const inputsRef = React5.useRef([]);
1997
- const digits = React5.useMemo(() => {
2088
+ const inputsRef = React4.useRef([]);
2089
+ React4.useEffect(() => {
2090
+ if (autoFocus) inputsRef.current[0]?.focus();
2091
+ }, [autoFocus]);
2092
+ const digits = React4.useMemo(() => {
1998
2093
  const arr = value.split("").slice(0, length);
1999
2094
  while (arr.length < length) arr.push("");
2000
2095
  return arr;
@@ -2016,7 +2111,7 @@ var OtpInput = ({
2016
2111
  }
2017
2112
  };
2018
2113
  const handleFocus = (index) => {
2019
- const firstEmpty = digits.findIndex((d) => d === "");
2114
+ const firstEmpty = digits.indexOf("");
2020
2115
  if (firstEmpty !== -1 && firstEmpty < index) {
2021
2116
  focusInput(firstEmpty);
2022
2117
  }
@@ -2057,116 +2152,39 @@ var OtpInput = ({
2057
2152
  focusInput(nextIndex);
2058
2153
  };
2059
2154
  const rootClassName = cn("otp_input", className);
2060
- return /* @__PURE__ */ jsxs("div", { className: rootClassName, role: "group", "aria-label": ariaLabel, children: [
2061
- /* @__PURE__ */ jsx("div", { className: "otp_input_boxes", children: digits.map((digit, i) => /* @__PURE__ */ jsx(
2062
- "input",
2063
- {
2064
- ref: (el) => {
2065
- inputsRef.current[i] = el;
2066
- },
2067
- type: "text",
2068
- inputMode: "numeric",
2069
- pattern: "\\d*",
2070
- maxLength: 1,
2071
- value: digit,
2072
- onChange: (e) => handleChange(i, e),
2073
- onFocus: () => handleFocus(i),
2074
- onKeyDown: (e) => handleKeyDown(i, e),
2075
- onPaste: handlePaste,
2076
- disabled,
2077
- autoFocus: autoFocus && i === 0,
2078
- "aria-label": `${i + 1}\uBC88\uC9F8 \uC790\uB9AC`,
2079
- className: cn(
2080
- "otp_input_box",
2081
- error && "otp_input_box_error",
2082
- disabled && "otp_input_box_disabled"
2083
- )
2084
- },
2085
- i
2086
- )) }),
2087
- supportingText && /* @__PURE__ */ jsx("span", { className: cn("otp_input_supporting", error && "otp_input_supporting_error"), children: supportingText })
2088
- ] });
2089
- };
2090
- OtpInput.displayName = "OtpInput";
2091
- var Modal = ({
2092
- open,
2093
- onClose,
2094
- closeOnOverlay = true,
2095
- width = 520,
2096
- title,
2097
- children,
2098
- className,
2099
- ariaLabel,
2100
- ...props
2101
- }) => {
2102
- const panelRef = React5.useRef(null);
2103
- const titleId = React5.useId();
2104
- useFocusTrap(panelRef, open);
2105
- const handleEscape = React5.useEffectEvent((e) => {
2106
- if (e.key === "Escape") onClose?.();
2107
- });
2108
- React5.useEffect(() => {
2109
- if (!open) return;
2110
- document.addEventListener("keydown", handleEscape);
2111
- return () => document.removeEventListener("keydown", handleEscape);
2112
- }, [open]);
2113
- React5.useEffect(() => {
2114
- if (!open) return;
2115
- const body = document.body;
2116
- const openModals = parseInt(body.dataset.openModals || "0", 10);
2117
- if (openModals === 0) {
2118
- body.dataset.originalOverflow = window.getComputedStyle(body).overflow;
2119
- body.style.overflow = "hidden";
2120
- }
2121
- body.dataset.openModals = String(openModals + 1);
2122
- return () => {
2123
- const currentOpenModals = parseInt(body.dataset.openModals || "1", 10);
2124
- const nextOpenModals = currentOpenModals - 1;
2125
- if (nextOpenModals === 0) {
2126
- body.style.overflow = body.dataset.originalOverflow || "";
2127
- delete body.dataset.openModals;
2128
- delete body.dataset.originalOverflow;
2129
- } else {
2130
- body.dataset.openModals = String(nextOpenModals);
2131
- }
2132
- };
2133
- }, [open]);
2134
- if (!open) return null;
2135
- const panelClassName = cn("modal_panel", className);
2136
- const hasTitle = !!title;
2137
- return /* @__PURE__ */ jsx(
2138
- "div",
2139
- {
2140
- className: "modal",
2141
- role: "dialog",
2142
- "aria-modal": "true",
2143
- "aria-labelledby": hasTitle && !ariaLabel ? titleId : void 0,
2144
- "aria-label": !hasTitle ? ariaLabel ?? "Dialog" : ariaLabel,
2145
- onClick: () => closeOnOverlay && onClose?.(),
2146
- onKeyDown: (e) => {
2147
- if (e.key === "Escape") onClose?.();
2148
- },
2149
- children: /* @__PURE__ */ jsxs(
2150
- "div",
2155
+ return (
2156
+ // biome-ignore lint/a11y/useSemanticElements: <fieldset> would force border/legend styles; role=group is the WAI-ARIA equivalent for OTP grouping
2157
+ /* @__PURE__ */ jsxs("div", { className: rootClassName, role: "group", "aria-label": ariaLabel, children: [
2158
+ /* @__PURE__ */ jsx("div", { className: "otp_input_boxes", children: digits.map((digit, i) => /* @__PURE__ */ jsx(
2159
+ "input",
2151
2160
  {
2152
- ref: panelRef,
2153
- className: panelClassName,
2154
- style: { width },
2155
- role: "document",
2156
- onClick: (e) => e.stopPropagation(),
2157
- onKeyDown: (e) => {
2158
- if (e.key !== "Escape") e.stopPropagation();
2161
+ ref: (el) => {
2162
+ inputsRef.current[i] = el;
2159
2163
  },
2160
- ...props,
2161
- children: [
2162
- title && /* @__PURE__ */ jsx("div", { id: titleId, className: "modal_header", children: title }),
2163
- /* @__PURE__ */ jsx("div", { className: "modal_body", children })
2164
- ]
2165
- }
2166
- )
2167
- }
2164
+ type: "text",
2165
+ inputMode: "numeric",
2166
+ pattern: "\\d*",
2167
+ maxLength: 1,
2168
+ value: digit,
2169
+ onChange: (e) => handleChange(i, e),
2170
+ onFocus: () => handleFocus(i),
2171
+ onKeyDown: (e) => handleKeyDown(i, e),
2172
+ onPaste: handlePaste,
2173
+ disabled,
2174
+ "aria-label": `${i + 1}\uBC88\uC9F8 \uC790\uB9AC`,
2175
+ className: cn(
2176
+ "otp_input_box",
2177
+ error && "otp_input_box_error",
2178
+ disabled && "otp_input_box_disabled"
2179
+ )
2180
+ },
2181
+ i
2182
+ )) }),
2183
+ supportingText && /* @__PURE__ */ jsx("span", { className: cn("otp_input_supporting", error && "otp_input_supporting_error"), children: supportingText })
2184
+ ] })
2168
2185
  );
2169
2186
  };
2187
+ OtpInput.displayName = "OtpInput";
2170
2188
  var range2 = (start, end) => {
2171
2189
  const out = [];
2172
2190
  for (let i = start; i <= end; i += 1) out.push(i);
@@ -2205,7 +2223,7 @@ var Pagination = ({
2205
2223
  }) => {
2206
2224
  const prevDisabled = page <= 1;
2207
2225
  const nextDisabled = page >= totalPages;
2208
- const items = React5.useMemo(() => getPaginationItems(page, totalPages), [page, totalPages]);
2226
+ const items = React4.useMemo(() => getPaginationItems(page, totalPages), [page, totalPages]);
2209
2227
  return /* @__PURE__ */ jsxs("nav", { className: "pagination", "aria-label": "Pagination", children: [
2210
2228
  /* @__PURE__ */ jsx(
2211
2229
  "button",
@@ -2220,7 +2238,9 @@ var Pagination = ({
2220
2238
  ),
2221
2239
  /* @__PURE__ */ jsx("ul", { className: "pagination_pages", children: items.map((it, idx) => {
2222
2240
  if (it === "ellipsis") {
2223
- return /* @__PURE__ */ jsx("li", { className: "pagination_ellipsis", "aria-hidden": "true", children: "\u2026" }, `e-${idx}`);
2241
+ const prev = items[idx - 1];
2242
+ const next = items[idx + 1];
2243
+ return /* @__PURE__ */ jsx("li", { className: "pagination_ellipsis", "aria-hidden": "true", children: "\u2026" }, `e-${prev}-${next}`);
2224
2244
  }
2225
2245
  const isActive = it === page;
2226
2246
  const buttonClassName = cn("pagination_page_button", { pagination_active: isActive });
@@ -2249,7 +2269,12 @@ var Pagination = ({
2249
2269
  ] });
2250
2270
  };
2251
2271
  var Radio = ({ label, size = "md", className, ref, ...props }) => {
2252
- const rootClassName = cn("radio", `radio_size_${size}`, props.disabled && "radio_disabled", className);
2272
+ const rootClassName = cn(
2273
+ "radio",
2274
+ `radio_size_${size}`,
2275
+ props.disabled && "radio_disabled",
2276
+ className
2277
+ );
2253
2278
  return /* @__PURE__ */ jsxs("label", { className: rootClassName, children: [
2254
2279
  /* @__PURE__ */ jsx("input", { ref, type: "radio", className: "radio_input", ...props }),
2255
2280
  /* @__PURE__ */ jsx("span", { className: "radio_state_layer", "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { className: "radio_dot" }) }),
@@ -2268,49 +2293,6 @@ var Spinner = ({ size = 24, ariaLabel = "Loading" }) => {
2268
2293
  }
2269
2294
  );
2270
2295
  };
2271
- var Toggle = ({
2272
- checked,
2273
- defaultChecked,
2274
- onChange,
2275
- size = "sm",
2276
- disabled,
2277
- className,
2278
- ariaLabel,
2279
- ref,
2280
- ...props
2281
- }) => {
2282
- const isControlled = checked !== void 0;
2283
- const [innerChecked, setInnerChecked] = React5.useState(!!defaultChecked);
2284
- const isOn = isControlled ? !!checked : innerChecked;
2285
- const handleToggle = () => {
2286
- if (disabled) return;
2287
- const next = !isOn;
2288
- if (!isControlled) setInnerChecked(next);
2289
- onChange?.(next);
2290
- };
2291
- const rootClassName = cn(
2292
- "toggle",
2293
- `toggle_size_${size}`,
2294
- { toggle_on: isOn, toggle_disabled: disabled },
2295
- className
2296
- );
2297
- return /* @__PURE__ */ jsx(
2298
- "button",
2299
- {
2300
- ref,
2301
- type: "button",
2302
- role: "switch",
2303
- "aria-checked": isOn,
2304
- "aria-label": ariaLabel,
2305
- disabled,
2306
- onClick: handleToggle,
2307
- className: rootClassName,
2308
- ...props,
2309
- children: /* @__PURE__ */ jsx("span", { className: "toggle_thumb" })
2310
- }
2311
- );
2312
- };
2313
- Toggle.displayName = "Toggle";
2314
2296
  var ClearIcon = () => /* @__PURE__ */ jsx(Icon, { name: "close", size: 20 });
2315
2297
  var TextField = ({
2316
2298
  id,
@@ -2331,21 +2313,21 @@ var TextField = ({
2331
2313
  ref,
2332
2314
  ...props
2333
2315
  }) => {
2334
- const generatedId = React5.useId();
2316
+ const generatedId = React4.useId();
2335
2317
  const inputId = id ?? generatedId;
2336
2318
  const helperId = supportingText ? `${inputId}-help` : void 0;
2337
2319
  const isControlled = value !== void 0;
2338
2320
  const applyTransform = (nextValue) => transformValue ? transformValue(nextValue) : nextValue;
2339
- const [innerValue, setInnerValue] = React5.useState(
2321
+ const [innerValue, setInnerValue] = React4.useState(
2340
2322
  () => applyTransform(value ?? defaultValue ?? "")
2341
2323
  );
2342
- const isComposingRef = React5.useRef(false);
2343
- React5.useEffect(() => {
2324
+ const isComposingRef = React4.useRef(false);
2325
+ React4.useEffect(() => {
2344
2326
  if (!isControlled) return;
2345
2327
  const nextValue = value ?? "";
2346
2328
  setInnerValue(transformValue ? transformValue(nextValue) : nextValue);
2347
2329
  }, [isControlled, value, transformValue]);
2348
- const handleClear = React5.useCallback(() => {
2330
+ const handleClear = React4.useCallback(() => {
2349
2331
  setInnerValue("");
2350
2332
  onChangeAction?.("");
2351
2333
  }, [onChangeAction]);
@@ -2357,54 +2339,54 @@ var TextField = ({
2357
2339
  props.disabled && "text_field_disabled",
2358
2340
  className
2359
2341
  );
2360
- const resolvedTrailing = clearable && innerValue ? /* @__PURE__ */ jsx(
2361
- "button",
2362
- {
2363
- type: "button",
2364
- className: "text_field_clear",
2365
- onClick: handleClear,
2366
- "aria-label": "Clear",
2367
- children: /* @__PURE__ */ jsx(ClearIcon, {})
2368
- }
2369
- ) : trailingIcon ? /* @__PURE__ */ jsx("span", { className: "text_field_icon", "aria-hidden": "true", children: trailingIcon }) : null;
2342
+ const resolvedTrailing = clearable && innerValue ? /* @__PURE__ */ jsx("button", { type: "button", className: "text_field_clear", onClick: handleClear, "aria-label": "Clear", children: /* @__PURE__ */ jsx(ClearIcon, {}) }) : trailingIcon ? /* @__PURE__ */ jsx("span", { className: "text_field_icon", "aria-hidden": "true", children: trailingIcon }) : null;
2370
2343
  return /* @__PURE__ */ jsxs("div", { className: rootClassName, children: [
2371
2344
  /* @__PURE__ */ jsxs("fieldset", { className: "text_field_container", children: [
2372
2345
  label && showLabel && /* @__PURE__ */ jsx("legend", { className: "text_field_label", children: /* @__PURE__ */ jsx("label", { htmlFor: inputId, children: label }) }),
2373
2346
  /* @__PURE__ */ jsxs("div", { className: "text_field_inner", children: [
2374
2347
  leadingIcon && /* @__PURE__ */ jsx("span", { className: "text_field_icon", "aria-hidden": "true", children: leadingIcon }),
2375
- /* @__PURE__ */ jsx("div", { className: cn("text_field_input_wrap", resolvedTrailing && "text_field_input_wrap_no_pad_right"), children: /* @__PURE__ */ jsx(
2376
- "input",
2348
+ /* @__PURE__ */ jsx(
2349
+ "div",
2377
2350
  {
2378
- id: inputId,
2379
- ref,
2380
- className: "text_field_input",
2381
- "aria-invalid": !!error,
2382
- "aria-describedby": helperId,
2383
- "aria-label": !showLabel ? label : void 0,
2384
- ...props,
2385
- value: innerValue,
2386
- onCompositionStart: () => {
2387
- isComposingRef.current = true;
2388
- },
2389
- onCompositionEnd: (event) => {
2390
- isComposingRef.current = false;
2391
- const rawValue = event.currentTarget.value;
2392
- const nextValue = applyTransform(rawValue);
2393
- setInnerValue(nextValue);
2394
- onChangeAction?.(nextValue);
2395
- },
2396
- onChange: (event) => {
2397
- const rawValue = event.target.value;
2398
- if (isComposingRef.current) {
2399
- setInnerValue(rawValue);
2400
- return;
2351
+ className: cn(
2352
+ "text_field_input_wrap",
2353
+ resolvedTrailing && "text_field_input_wrap_no_pad_right"
2354
+ ),
2355
+ children: /* @__PURE__ */ jsx(
2356
+ "input",
2357
+ {
2358
+ id: inputId,
2359
+ ref,
2360
+ className: "text_field_input",
2361
+ "aria-invalid": !!error,
2362
+ "aria-describedby": helperId,
2363
+ "aria-label": !showLabel ? label : void 0,
2364
+ ...props,
2365
+ value: innerValue,
2366
+ onCompositionStart: () => {
2367
+ isComposingRef.current = true;
2368
+ },
2369
+ onCompositionEnd: (event) => {
2370
+ isComposingRef.current = false;
2371
+ const rawValue = event.currentTarget.value;
2372
+ const nextValue = applyTransform(rawValue);
2373
+ setInnerValue(nextValue);
2374
+ onChangeAction?.(nextValue);
2375
+ },
2376
+ onChange: (event) => {
2377
+ const rawValue = event.target.value;
2378
+ if (isComposingRef.current) {
2379
+ setInnerValue(rawValue);
2380
+ return;
2381
+ }
2382
+ const nextValue = applyTransform(rawValue);
2383
+ setInnerValue(nextValue);
2384
+ onChangeAction?.(nextValue);
2385
+ }
2401
2386
  }
2402
- const nextValue = applyTransform(rawValue);
2403
- setInnerValue(nextValue);
2404
- onChangeAction?.(nextValue);
2405
- }
2387
+ )
2406
2388
  }
2407
- ) }),
2389
+ ),
2408
2390
  resolvedTrailing
2409
2391
  ] })
2410
2392
  ] }),
@@ -2412,7 +2394,7 @@ var TextField = ({
2412
2394
  ] });
2413
2395
  };
2414
2396
  TextField.displayName = "TextField";
2415
- var ToastContext = React5.createContext(null);
2397
+ var ToastContext = React4.createContext(null);
2416
2398
  var VARIANT_ICONS = {
2417
2399
  success: /* @__PURE__ */ jsx(CheckCircle2, { size: 18 }),
2418
2400
  error: /* @__PURE__ */ jsx(XCircle, { size: 18 }),
@@ -2421,9 +2403,9 @@ var VARIANT_ICONS = {
2421
2403
  default: /* @__PURE__ */ jsx(Bell, { size: 18 })
2422
2404
  };
2423
2405
  var ToastItemComponent = ({ item, onRemove, closeAriaLabel }) => {
2424
- const [exiting, setExiting] = React5.useState(false);
2425
- const closingRef = React5.useRef(false);
2426
- const close = React5.useCallback(() => {
2406
+ const [exiting, setExiting] = React4.useState(false);
2407
+ const closingRef = React4.useRef(false);
2408
+ const close = React4.useCallback(() => {
2427
2409
  if (closingRef.current) return;
2428
2410
  closingRef.current = true;
2429
2411
  setExiting(true);
@@ -2450,24 +2432,25 @@ var ToastProvider = ({
2450
2432
  maxCount = 5,
2451
2433
  closeAriaLabel = "Close"
2452
2434
  }) => {
2453
- const [toasts, setToasts] = React5.useState([]);
2454
- const [isMounted, setIsMounted] = React5.useState(false);
2455
- React5.useEffect(() => {
2435
+ const [toasts, setToasts] = React4.useState([]);
2436
+ const [isMounted, setIsMounted] = React4.useState(false);
2437
+ React4.useEffect(() => {
2456
2438
  setIsMounted(true);
2457
2439
  }, []);
2458
- const addToast = React5.useCallback(
2440
+ const addToast = React4.useCallback(
2459
2441
  (message, variant, duration = 3e3) => {
2460
2442
  const id = crypto.randomUUID();
2461
2443
  setToasts((prev) => [{ id, message, variant, duration }, ...prev].slice(0, maxCount));
2462
2444
  },
2463
2445
  [maxCount]
2464
2446
  );
2465
- const removeToast = React5.useCallback((id) => {
2447
+ const removeToast = React4.useCallback((id) => {
2466
2448
  setToasts((prev) => prev.filter((t) => t.id !== id));
2467
2449
  }, []);
2468
2450
  return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: { addToast }, children: [
2469
2451
  children,
2470
2452
  isMounted && createPortal(
2453
+ // biome-ignore lint/a11y/useSemanticElements: <section> would create unwanted nesting in portal; role=region is the WAI-ARIA equivalent for live announcements
2471
2454
  /* @__PURE__ */ jsx(
2472
2455
  "div",
2473
2456
  {
@@ -2509,6 +2492,49 @@ var useToast = () => {
2509
2492
  message: (message, duration) => ctx.addToast(message, "default", duration)
2510
2493
  };
2511
2494
  };
2495
+ var Toggle = ({
2496
+ checked,
2497
+ defaultChecked,
2498
+ onChange,
2499
+ size = "sm",
2500
+ disabled,
2501
+ className,
2502
+ ariaLabel,
2503
+ ref,
2504
+ ...props
2505
+ }) => {
2506
+ const isControlled = checked !== void 0;
2507
+ const [innerChecked, setInnerChecked] = React4.useState(!!defaultChecked);
2508
+ const isOn = isControlled ? !!checked : innerChecked;
2509
+ const handleToggle = () => {
2510
+ if (disabled) return;
2511
+ const next = !isOn;
2512
+ if (!isControlled) setInnerChecked(next);
2513
+ onChange?.(next);
2514
+ };
2515
+ const rootClassName = cn(
2516
+ "toggle",
2517
+ `toggle_size_${size}`,
2518
+ { toggle_on: isOn, toggle_disabled: disabled },
2519
+ className
2520
+ );
2521
+ return /* @__PURE__ */ jsx(
2522
+ "button",
2523
+ {
2524
+ ref,
2525
+ type: "button",
2526
+ role: "switch",
2527
+ "aria-checked": isOn,
2528
+ "aria-label": ariaLabel,
2529
+ disabled,
2530
+ onClick: handleToggle,
2531
+ className: rootClassName,
2532
+ ...props,
2533
+ children: /* @__PURE__ */ jsx("span", { className: "toggle_thumb" })
2534
+ }
2535
+ );
2536
+ };
2537
+ Toggle.displayName = "Toggle";
2512
2538
  var TopLoading = ({
2513
2539
  progress,
2514
2540
  color,