@aviala-design/spiral 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4175,7 +4175,7 @@ function ColorPickerInputs({
4175
4175
  }
4176
4176
  ) : null,
4177
4177
  format === "hex" ? /* @__PURE__ */ jsxs19("div", { className: "aviala-color-picker-field", children: [
4178
- /* @__PURE__ */ jsx26("span", { className: "aviala-color-picker-field__badge-area", children: /* @__PURE__ */ jsx26(Badge, { children: "#" }) }),
4178
+ /* @__PURE__ */ jsx26("span", { className: "aviala-color-picker-field__badge-area", children: /* @__PURE__ */ jsx26(Badge, { style: "normal", children: "#" }) }),
4179
4179
  /* @__PURE__ */ jsx26(
4180
4180
  "input",
4181
4181
  {
@@ -4214,7 +4214,7 @@ function ColorPickerInputs({
4214
4214
  onKeyDown: (e) => e.key === "Enter" && commitAlpha()
4215
4215
  }
4216
4216
  ),
4217
- /* @__PURE__ */ jsx26("span", { className: "aviala-color-picker-field__badge-area", children: /* @__PURE__ */ jsx26(Badge, { children: "%" }) })
4217
+ /* @__PURE__ */ jsx26("span", { className: "aviala-color-picker-field__badge-area", children: /* @__PURE__ */ jsx26(Badge, { style: "normal", children: "%" }) })
4218
4218
  ] }),
4219
4219
  /* @__PURE__ */ jsxs19(
4220
4220
  Select,
@@ -4749,6 +4749,7 @@ function Cascader({
4749
4749
  const isValueControlled = valueProp !== void 0;
4750
4750
  const open = isOpenControlled ? openProp : internalOpen;
4751
4751
  const selectedPath = isValueControlled ? valueProp ?? [] : internalValue;
4752
+ const wasOpenRef = useRef7(open);
4752
4753
  useEffect5(() => {
4753
4754
  const markWindowBlur = () => {
4754
4755
  windowBlurCloseRef.current = true;
@@ -4757,10 +4758,20 @@ function Cascader({
4757
4758
  return () => window.removeEventListener("blur", markWindowBlur, true);
4758
4759
  }, []);
4759
4760
  useEffect5(() => {
4760
- if (open) {
4761
- setActivePath(selectedPath.length > 0 ? selectedPath.slice(0, -1) : []);
4761
+ const justOpened = open && !wasOpenRef.current;
4762
+ wasOpenRef.current = open;
4763
+ if (!justOpened) return;
4764
+ if (selectedPath.length === 0) {
4765
+ setActivePath([]);
4766
+ return;
4767
+ }
4768
+ const selectedOption = findOptionPath(options, selectedPath);
4769
+ if (selectedOption?.children?.length) {
4770
+ setActivePath(selectedPath);
4771
+ return;
4762
4772
  }
4763
- }, [open, selectedPath]);
4773
+ setActivePath(selectedPath.slice(0, -1));
4774
+ }, [open, options, selectedPath]);
4764
4775
  useEffect5(() => {
4765
4776
  if (!open) {
4766
4777
  pointerDownCloseRef.current = false;
@@ -6054,12 +6065,19 @@ function DatePicker(props) {
6054
6065
  setActivePanel("date");
6055
6066
  return;
6056
6067
  }
6068
+ setFocusedDay((current) => {
6069
+ if (current) return current;
6070
+ if (mode === "single" && singleValue) return startOfDay(singleValue);
6071
+ const rangeAnchor = mode === "range" ? rangeValue.from ?? rangeValue.to : void 0;
6072
+ if (rangeAnchor) return startOfDay(rangeAnchor);
6073
+ return startOfDay(/* @__PURE__ */ new Date());
6074
+ });
6057
6075
  const markPointerDown = () => {
6058
6076
  pointerDownCloseRef.current = true;
6059
6077
  };
6060
6078
  document.addEventListener("pointerdown", markPointerDown, true);
6061
6079
  return () => document.removeEventListener("pointerdown", markPointerDown, true);
6062
- }, [open]);
6080
+ }, [mode, open, rangeValue.from, rangeValue.to, singleValue]);
6063
6081
  const handleOpenChange = useCallback12(
6064
6082
  (nextOpen) => {
6065
6083
  if (disabled && nextOpen) return;
@@ -6160,19 +6178,21 @@ function DatePicker(props) {
6160
6178
  ]
6161
6179
  );
6162
6180
  const selectDate = useCallback12(
6163
- (date) => {
6181
+ (date, options) => {
6164
6182
  if (disabled || isDateDisabled(date, minDate, maxDate)) return;
6165
6183
  const day = startOfDay(date);
6166
6184
  setFocusedDay(day);
6167
6185
  if (!isSameMonth(day, viewMonth)) {
6168
6186
  setViewMonth(new Date(day.getFullYear(), day.getMonth(), 1));
6169
6187
  }
6188
+ const switchToTime = options?.switchToTime ?? enableTime;
6189
+ const shouldClose = options?.close ?? !enableTime;
6170
6190
  if (mode === "single") {
6171
6191
  const next = enableTime ? applyTimeToDate(day, timeValue.hours, timeValue.minutes) : day;
6172
6192
  commitSingle(next);
6173
- if (enableTime) {
6193
+ if (switchToTime) {
6174
6194
  setActivePanel("time");
6175
- } else {
6195
+ } else if (shouldClose) {
6176
6196
  handleOpenChange(false);
6177
6197
  }
6178
6198
  return;
@@ -6188,9 +6208,9 @@ function DatePicker(props) {
6188
6208
  if (isSameDay(day, currentFrom)) {
6189
6209
  commitRange({ from: withTime(day), to: withTime(day) });
6190
6210
  setRangeDraftFrom(void 0);
6191
- if (enableTime) {
6211
+ if (switchToTime) {
6192
6212
  setActivePanel("time");
6193
- } else {
6213
+ } else if (shouldClose) {
6194
6214
  handleOpenChange(false);
6195
6215
  }
6196
6216
  return;
@@ -6201,9 +6221,9 @@ function DatePicker(props) {
6201
6221
  to: normalized.to ? withTime(normalized.to) : void 0
6202
6222
  });
6203
6223
  setRangeDraftFrom(void 0);
6204
- if (enableTime) {
6224
+ if (switchToTime) {
6205
6225
  setActivePanel("time");
6206
- } else {
6226
+ } else if (shouldClose) {
6207
6227
  handleOpenChange(false);
6208
6228
  }
6209
6229
  },
@@ -6609,7 +6629,7 @@ function DatePickerPanelFooter() {
6609
6629
  if (!enableTime) return null;
6610
6630
  const panelValue = activePanel === "time" ? "time" : "date";
6611
6631
  const isRangeMode = mode === "range";
6612
- return /* @__PURE__ */ jsxs28(
6632
+ return /* @__PURE__ */ jsx37("div", { className: "aviala-datepicker-footer-wrap", children: /* @__PURE__ */ jsxs28(
6613
6633
  SegmentatorGroup,
6614
6634
  {
6615
6635
  value: panelValue,
@@ -6640,7 +6660,7 @@ function DatePickerPanelFooter() {
6640
6660
  )
6641
6661
  ]
6642
6662
  }
6643
- );
6663
+ ) });
6644
6664
  }
6645
6665
  function monthDiff(from, to) {
6646
6666
  return (to.getFullYear() - from.getFullYear()) * 12 + (to.getMonth() - from.getMonth());
@@ -6668,6 +6688,8 @@ function DatePickerCalendar({ className }) {
6668
6688
  const today = useMemo7(() => startOfDay(/* @__PURE__ */ new Date()), []);
6669
6689
  const days = useMemo7(() => getCalendarDays(viewMonth), [viewMonth]);
6670
6690
  const prevViewMonthRef = useRef9(viewMonth);
6691
+ const dayGridRef = useRef9(null);
6692
+ const pendingDayFocusRef = useRef9(false);
6671
6693
  const [monthSlide, setMonthSlide] = useState11(null);
6672
6694
  const isMonthPanel = activePanel === "month";
6673
6695
  const isTimePanel = activePanel === "time" && enableTime;
@@ -6724,40 +6746,40 @@ function DatePickerCalendar({ className }) {
6724
6746
  outgoingMonth: previous
6725
6747
  });
6726
6748
  }, [contentView, panel, viewMonth]);
6749
+ useLayoutEffect5(() => {
6750
+ if (!pendingDayFocusRef.current || !focusedDay) return;
6751
+ const grid = dayGridRef.current;
6752
+ if (!grid) return;
6753
+ const target = grid.querySelector(
6754
+ `button[data-day="${formatIsoDate(focusedDay)}"]`
6755
+ );
6756
+ if (!target || target.disabled) return;
6757
+ pendingDayFocusRef.current = false;
6758
+ target.focus();
6759
+ }, [focusedDay, days, monthSlide]);
6727
6760
  const outgoingDays = useMemo7(
6728
6761
  () => monthSlide ? getCalendarDays(monthSlide.outgoingMonth) : null,
6729
6762
  [monthSlide]
6730
6763
  );
6731
6764
  const handleDayKeyDown = (event, date) => {
6732
- let next = null;
6765
+ let deltaDays = 0;
6733
6766
  switch (event.key) {
6734
6767
  case "ArrowLeft":
6735
- next = new Date(date);
6736
- next.setDate(next.getDate() - 1);
6768
+ deltaDays = -1;
6737
6769
  break;
6738
6770
  case "ArrowRight":
6739
- next = new Date(date);
6740
- next.setDate(next.getDate() + 1);
6771
+ deltaDays = 1;
6741
6772
  break;
6742
6773
  case "ArrowUp":
6743
- next = new Date(date);
6744
- next.setDate(next.getDate() - 7);
6774
+ deltaDays = -7;
6745
6775
  break;
6746
6776
  case "ArrowDown":
6747
- next = new Date(date);
6748
- next.setDate(next.getDate() + 7);
6777
+ deltaDays = 7;
6749
6778
  break;
6750
6779
  case "Home":
6751
- next = new Date(date.getFullYear(), date.getMonth(), 1);
6752
- break;
6753
6780
  case "End":
6754
- next = new Date(date.getFullYear(), date.getMonth() + 1, 0);
6755
- break;
6756
6781
  case "PageUp":
6757
- next = addMonths(date, event.shiftKey ? -12 : -1);
6758
- break;
6759
6782
  case "PageDown":
6760
- next = addMonths(date, event.shiftKey ? 12 : 1);
6761
6783
  break;
6762
6784
  case "Enter":
6763
6785
  case " ":
@@ -6768,8 +6790,31 @@ function DatePickerCalendar({ className }) {
6768
6790
  return;
6769
6791
  }
6770
6792
  event.preventDefault();
6771
- if (!next) return;
6793
+ let next;
6794
+ if (event.key === "Home") {
6795
+ next = new Date(date.getFullYear(), date.getMonth(), 1);
6796
+ } else if (event.key === "End") {
6797
+ next = new Date(date.getFullYear(), date.getMonth() + 1, 0);
6798
+ } else if (event.key === "PageUp") {
6799
+ next = addMonths(date, event.shiftKey ? -12 : -1);
6800
+ } else if (event.key === "PageDown") {
6801
+ next = addMonths(date, event.shiftKey ? 12 : 1);
6802
+ } else {
6803
+ next = new Date(date);
6804
+ next.setDate(next.getDate() + deltaDays);
6805
+ let guard = 0;
6806
+ while (isDateDisabled(next, minDate, maxDate) && guard < 366) {
6807
+ next.setDate(next.getDate() + (deltaDays > 0 ? 1 : -1));
6808
+ guard += 1;
6809
+ }
6810
+ }
6772
6811
  const normalized = startOfDay(next);
6812
+ if (isDateDisabled(normalized, minDate, maxDate)) return;
6813
+ pendingDayFocusRef.current = true;
6814
+ if (mode === "single") {
6815
+ selectDate(normalized, { close: false, switchToTime: false });
6816
+ return;
6817
+ }
6773
6818
  setFocusedDay(normalized);
6774
6819
  if (!isSameMonth(normalized, viewMonth)) {
6775
6820
  setViewMonth(new Date(normalized.getFullYear(), normalized.getMonth(), 1));
@@ -6823,6 +6868,7 @@ function DatePickerCalendar({ className }) {
6823
6868
  /* @__PURE__ */ jsx37(
6824
6869
  "div",
6825
6870
  {
6871
+ ref: dayGridRef,
6826
6872
  className: "aviala-datepicker-calendar__grid",
6827
6873
  role: "grid",
6828
6874
  "aria-labelledby": `${calendarId}-label`,
@@ -6842,11 +6888,13 @@ function DatePickerCalendar({ className }) {
6842
6888
  const isToday = isSameDay(day, today);
6843
6889
  const dayDisabled = isDateDisabled(day, minDate, maxDate);
6844
6890
  const focused = focusedDay ? isSameDay(day, focusedDay) : false;
6891
+ const dayKey = formatIsoDate(day);
6845
6892
  return /* @__PURE__ */ jsxs28(
6846
6893
  "button",
6847
6894
  {
6848
6895
  type: "button",
6849
6896
  role: "gridcell",
6897
+ "data-day": dayKey,
6850
6898
  tabIndex: focused || !focusedDay && isToday ? 0 : -1,
6851
6899
  className: "aviala-datepicker-day aviala-focus-ring",
6852
6900
  "data-outside": outside ? "true" : void 0,
@@ -6876,7 +6924,7 @@ function DatePickerCalendar({ className }) {
6876
6924
  isToday ? /* @__PURE__ */ jsx37("span", { className: "aviala-datepicker-day__today-dot", "aria-hidden": true }) : null
6877
6925
  ]
6878
6926
  },
6879
- day.toISOString()
6927
+ dayKey
6880
6928
  );
6881
6929
  })
6882
6930
  },
@@ -7557,21 +7605,27 @@ var ModalContent = forwardRef30(
7557
7605
  onOpenAutoFocus,
7558
7606
  ...props
7559
7607
  }, ref) => {
7560
- const content = /* @__PURE__ */ jsxs32(Fragment6, { children: [
7561
- showOverlay ? /* @__PURE__ */ jsx42(ModalOverlay, {}) : null,
7562
- /* @__PURE__ */ jsx42(
7563
- DialogPrimitive.Content,
7564
- {
7565
- ref,
7566
- className: cn(modalContentVariants({ size }), className),
7567
- onOpenAutoFocus,
7568
- ...props,
7569
- children: /* @__PURE__ */ jsx42("div", { className: "aviala-modal-content__surface", children })
7570
- }
7571
- )
7608
+ const overlay = showOverlay ? /* @__PURE__ */ jsx42(ModalOverlay, {}) : null;
7609
+ const panel = /* @__PURE__ */ jsx42(
7610
+ DialogPrimitive.Content,
7611
+ {
7612
+ ref,
7613
+ className: cn(modalContentVariants({ size }), className),
7614
+ onOpenAutoFocus,
7615
+ ...props,
7616
+ children: /* @__PURE__ */ jsx42("div", { className: "aviala-modal-content__surface", children })
7617
+ }
7618
+ );
7619
+ if (!portalled) {
7620
+ return /* @__PURE__ */ jsxs32(Fragment6, { children: [
7621
+ overlay,
7622
+ panel
7623
+ ] });
7624
+ }
7625
+ return /* @__PURE__ */ jsxs32(DialogPrimitive.Portal, { children: [
7626
+ overlay,
7627
+ panel
7572
7628
  ] });
7573
- if (!portalled) return content;
7574
- return /* @__PURE__ */ jsx42(DialogPrimitive.Portal, { children: content });
7575
7629
  }
7576
7630
  );
7577
7631
  ModalContent.displayName = DialogPrimitive.Content.displayName;
@@ -7588,9 +7642,9 @@ var ModalHeader = forwardRef30(
7588
7642
  showIcon ? renderModalIcon(icon) : null,
7589
7643
  /* @__PURE__ */ jsx42("div", { className: "aviala-modal__header-main", children }),
7590
7644
  showClose ? /* @__PURE__ */ jsx42(DialogPrimitive.Close, { asChild: true, children: /* @__PURE__ */ jsx42(
7591
- Link,
7645
+ Button,
7592
7646
  {
7593
- level: "text",
7647
+ type: "button",
7594
7648
  mode: "noBackgroundCustom",
7595
7649
  iconOnly: true,
7596
7650
  "aria-label": closeLabel,