@carbon/utilities 0.24.0 → 0.25.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.
@@ -147,7 +147,14 @@ declare global {
147
147
  }): PlainYearMonth;
148
148
  compare(one: PlainYearMonth, two: PlainYearMonth): number;
149
149
  }
150
- const PlainYearMonth: PlainYearMonthConstructor;
150
+ /**
151
+ * Usages of `var` and `namespace`, instead of const, are intentional. TS 6
152
+ * ships built-in types for the Temporal API in `lib.esnext.temporal.d.ts`
153
+ * using these forms. Declaration merging only works when the shapes match.
154
+ * Matching them prevents collisions and tsc errors for TS 6 consumers,
155
+ * and for TS 5 consumers nothing changes, they still get these types
156
+ */
157
+ var PlainYearMonth: PlainYearMonthConstructor;
151
158
  interface PlainDateConstructor {
152
159
  from(item: string | {
153
160
  year: number;
@@ -156,11 +163,10 @@ declare global {
156
163
  }): PlainDate;
157
164
  compare(one: PlainDate, two: PlainDate): number;
158
165
  }
159
- const PlainDate: PlainDateConstructor;
160
- interface Now {
161
- plainDateISO(): PlainDate;
166
+ var PlainDate: PlainDateConstructor;
167
+ namespace Now {
168
+ function plainDateISO(): PlainDate;
162
169
  }
163
- const Now: Now;
164
170
  }
165
171
  }
166
172
  /**
@@ -946,48 +952,5 @@ declare function parseDateString(dateString: string, format: string): Temporal.P
946
952
  * @returns True if Temporal API is available
947
953
  */
948
954
  declare function isTemporalAvailable(): boolean;
949
- /**
950
- * Get a fallback date handler if Temporal is not available
951
- * This provides a migration path for browsers without Temporal support
952
- */
953
- declare function getDateHandler(): {
954
- type: "temporal";
955
- toISOString: typeof plainDateToISOString;
956
- fromISOString: typeof parseISOToPlainDate;
957
- compare: typeof comparePlainDates;
958
- format: typeof formatPlainDate;
959
- isInRange: typeof isDateInRange;
960
- } | {
961
- type: "date";
962
- /**
963
- *
964
- * @param {Temporal.PlainDate} date - The date to convert
965
- */
966
- toISOString: (date: Date) => string;
967
- /**
968
- *
969
- * @param {string} str - The ISO string to parse
970
- */
971
- fromISOString: (str: string) => Date | null;
972
- /**
973
- *
974
- * @param {Temporal.PlainDate} d1 - First date
975
- * @param {Temporal.PlainDate} d2 - Second date
976
- */
977
- compare: (d1: Date, d2: Date) => number;
978
- /**
979
- *
980
- * @param {Temporal.PlainDate} date - The date to format
981
- * @param {string} format - The format string
982
- */
983
- format: (date: Date, format: string) => string;
984
- /**
985
- *
986
- * @param {Temporal.PlainDate} date - The date to check
987
- * @param {Temporal.PlainDate | null} min - Minimum date
988
- * @param {Temporal.PlainDate | null} max - Maximum date
989
- */
990
- isInRange: (date: Date, min: Date | null, max: Date | null) => boolean;
991
- };
992
955
  //#endregion
993
- export { type CalendarDay, type ClickOutsideConfig, ClickOutsideHandler, type DatePickerContext, DatePickerEvent, type DatePickerEvent$1 as DatePickerEventType, type DatePickerMode, DatePickerState, DatePickerStateMachine, type DateSelectPayload, type FocusRestoreTarget, type InputFocusPayload, type InputType, type KeyboardEventInfo, type KeyboardEventResult, type KeyboardPayload, type SideEffect, type StateAction, type StateConfig, type StateGuard, type StateTransition, type TransitionListener, type TransitionMap, type ValidationErrorPayload, type ValueChangePayload, actions, addDays, addMonths, areDatesEqual, checkGuard, comparePlainDates, dateToPlainDate, daysBetween, effects, executeAction, executeEffect, formatPlainDate, generateCalendarGrid, getAction, getDateHandler, getEffect, getFullDateLabel, getGuard, getMonthEnd, getMonthStart, getMonthYearLabel, getToday, getWeekdayLabels, guards, isDateInRange, isFuture, isPast, isSingleMode, isTemporalAvailable, isToday, mapKeyboardToStateMachineEvent, parseDateString, parseDateToPlainDate, parseISOToPlainDate, plainDateToDate, plainDateToISOString };
956
+ export { type CalendarDay, type ClickOutsideConfig, ClickOutsideHandler, type DatePickerContext, DatePickerEvent, type DatePickerEvent$1 as DatePickerEventType, type DatePickerMode, DatePickerState, DatePickerStateMachine, type DateSelectPayload, type FocusRestoreTarget, type InputFocusPayload, type InputType, type KeyboardEventInfo, type KeyboardEventResult, type KeyboardPayload, type SideEffect, type StateAction, type StateConfig, type StateGuard, type StateTransition, type TransitionListener, type TransitionMap, type ValidationErrorPayload, type ValueChangePayload, actions, addDays, addMonths, areDatesEqual, checkGuard, comparePlainDates, dateToPlainDate, daysBetween, effects, executeAction, executeEffect, formatPlainDate, generateCalendarGrid, getAction, getEffect, getFullDateLabel, getGuard, getMonthEnd, getMonthStart, getMonthYearLabel, getToday, getWeekdayLabels, guards, isDateInRange, isFuture, isPast, isSingleMode, isTemporalAvailable, isToday, mapKeyboardToStateMachineEvent, parseDateString, parseDateToPlainDate, parseISOToPlainDate, plainDateToDate, plainDateToISOString };
@@ -1,3 +1,4 @@
1
+ import "temporal-polyfill/global";
1
2
  //#region src/date-picker/primitives/states.ts
2
3
  /**
3
4
  * Copyright IBM Corp. 2026
@@ -357,64 +358,6 @@ function parseDateString(dateString, format) {
357
358
  function isTemporalAvailable() {
358
359
  return typeof Temporal !== "undefined" && typeof Temporal.PlainDate !== "undefined";
359
360
  }
360
- /**
361
- * Get a fallback date handler if Temporal is not available
362
- * This provides a migration path for browsers without Temporal support
363
- */
364
- function getDateHandler() {
365
- if (isTemporalAvailable()) return {
366
- type: "temporal",
367
- toISOString: plainDateToISOString,
368
- fromISOString: parseISOToPlainDate,
369
- compare: comparePlainDates,
370
- format: formatPlainDate,
371
- isInRange: isDateInRange
372
- };
373
- return {
374
- type: "date",
375
- /**
376
- *
377
- * @param {Temporal.PlainDate} date - The date to convert
378
- */
379
- toISOString: (date) => date.toISOString().split("T")[0],
380
- /**
381
- *
382
- * @param {string} str - The ISO string to parse
383
- */
384
- fromISOString: (str) => {
385
- const date = new Date(str);
386
- return isNaN(date.getTime()) ? null : date;
387
- },
388
- /**
389
- *
390
- * @param {Temporal.PlainDate} d1 - First date
391
- * @param {Temporal.PlainDate} d2 - Second date
392
- */
393
- compare: (d1, d2) => d1.getTime() - d2.getTime(),
394
- /**
395
- *
396
- * @param {Temporal.PlainDate} date - The date to format
397
- * @param {string} format - The format string
398
- */
399
- format: (date, format) => {
400
- const year = date.getFullYear().toString();
401
- const month = (date.getMonth() + 1).toString().padStart(2, "0");
402
- const day = date.getDate().toString().padStart(2, "0");
403
- return format.replace("Y", year).replace("m", month).replace("d", day);
404
- },
405
- /**
406
- *
407
- * @param {Temporal.PlainDate} date - The date to check
408
- * @param {Temporal.PlainDate | null} min - Minimum date
409
- * @param {Temporal.PlainDate | null} max - Maximum date
410
- */
411
- isInRange: (date, min, max) => {
412
- if (min && date < min) return false;
413
- if (max && date > max) return false;
414
- return true;
415
- }
416
- };
417
- }
418
361
  //#endregion
419
362
  //#region src/date-picker/primitives/guards.ts
420
363
  /**
@@ -2012,4 +1955,4 @@ function getWeekdayLabels(locale = "en", weekStartsOn = 0) {
2012
1955
  return labels;
2013
1956
  }
2014
1957
  //#endregion
2015
- export { ClickOutsideHandler, DatePickerEvent, DatePickerState, DatePickerStateMachine, actions, addDays, addMonths, areDatesEqual, checkGuard, comparePlainDates, dateToPlainDate, daysBetween, effects, executeAction, executeEffect, formatPlainDate, generateCalendarGrid, getAction, getDateHandler, getEffect, getFullDateLabel, getGuard, getMonthEnd, getMonthStart, getMonthYearLabel, getToday, getWeekdayLabels, guards, isDateInRange, isFuture, isPast, isSingleMode, isTemporalAvailable, isToday, mapKeyboardToStateMachineEvent, parseDateString, parseDateToPlainDate, parseISOToPlainDate, plainDateToDate, plainDateToISOString };
1958
+ export { ClickOutsideHandler, DatePickerEvent, DatePickerState, DatePickerStateMachine, actions, addDays, addMonths, areDatesEqual, checkGuard, comparePlainDates, dateToPlainDate, daysBetween, effects, executeAction, executeEffect, formatPlainDate, generateCalendarGrid, getAction, getEffect, getFullDateLabel, getGuard, getMonthEnd, getMonthStart, getMonthYearLabel, getToday, getWeekdayLabels, guards, isDateInRange, isFuture, isPast, isSingleMode, isTemporalAvailable, isToday, mapKeyboardToStateMachineEvent, parseDateString, parseDateToPlainDate, parseISOToPlainDate, plainDateToDate, plainDateToISOString };
@@ -31,7 +31,12 @@ interface DraggableProps {
31
31
  }
32
32
  /**
33
33
  * Makes a given element draggable using a handle element.
34
- *@param draggable - object which accepts el and optional attributes handle,focusableInHandle,dragStep and shiftDragStep
34
+ * @param {object} draggable - Configuration object for draggable behavior
35
+ * @param {HTMLElement} draggable.el - The element to make draggable
36
+ * @param {HTMLElement} [draggable.dragHandle] - Optional handle element for dragging
37
+ * @param {boolean} [draggable.focusableDragHandle] - Whether the drag handle should be focusable
38
+ * @param {number} [draggable.dragStep] - Step size for keyboard dragging (default: 10)
39
+ * @param {number} [draggable.shiftDragStep] - Step size for keyboard dragging with Shift key (default: 50)
35
40
  */
36
41
  declare const makeDraggable: ({
37
42
  el,
@@ -1,7 +1,12 @@
1
1
  //#region src/makeDraggable/makeDraggable.ts
2
2
  /**
3
3
  * Makes a given element draggable using a handle element.
4
- *@param draggable - object which accepts el and optional attributes handle,focusableInHandle,dragStep and shiftDragStep
4
+ * @param {object} draggable - Configuration object for draggable behavior
5
+ * @param {HTMLElement} draggable.el - The element to make draggable
6
+ * @param {HTMLElement} [draggable.dragHandle] - Optional handle element for dragging
7
+ * @param {boolean} [draggable.focusableDragHandle] - Whether the drag handle should be focusable
8
+ * @param {number} [draggable.dragStep] - Step size for keyboard dragging (default: 10)
9
+ * @param {number} [draggable.shiftDragStep] - Step size for keyboard dragging with Shift key (default: 50)
5
10
  */
6
11
  const makeDraggable = ({ el, dragHandle, focusableDragHandle, dragStep, shiftDragStep }) => {
7
12
  if (dragHandle) {
@@ -60,7 +65,8 @@ const makeDraggable = ({ el, dragHandle, focusableDragHandle, dragStep, shiftDra
60
65
  el.dispatchEvent(new CustomEvent(type, eventInit));
61
66
  };
62
67
  const onKeyDown = (e) => {
63
- if (e.key === "Enter") {
68
+ if (e.key === "Enter" || e.key === " ") {
69
+ e.preventDefault();
64
70
  isDragging = !isDragging;
65
71
  if (isDragging) {
66
72
  syncTransformState();
@@ -71,24 +77,42 @@ const makeDraggable = ({ el, dragHandle, focusableDragHandle, dragStep, shiftDra
71
77
  const distance = e.shiftKey ? shiftDragStep ?? 32 : dragStep ?? 8;
72
78
  switch (e.key) {
73
79
  case "Enter":
74
- case " ":
75
- e.preventDefault();
76
- break;
80
+ case " ": break;
77
81
  case "ArrowLeft":
82
+ e.preventDefault();
78
83
  currentX -= distance;
79
84
  applyTransform(currentX, currentY);
85
+ dispatch("dragmove", {
86
+ direction: "left",
87
+ distance
88
+ });
80
89
  break;
81
90
  case "ArrowRight":
91
+ e.preventDefault();
82
92
  currentX += distance;
83
93
  applyTransform(currentX, currentY);
94
+ dispatch("dragmove", {
95
+ direction: "right",
96
+ distance
97
+ });
84
98
  break;
85
99
  case "ArrowUp":
100
+ e.preventDefault();
86
101
  currentY -= distance;
87
102
  applyTransform(currentX, currentY);
103
+ dispatch("dragmove", {
104
+ direction: "up",
105
+ distance
106
+ });
88
107
  break;
89
108
  case "ArrowDown":
109
+ e.preventDefault();
90
110
  currentY += distance;
91
111
  applyTransform(currentX, currentY);
112
+ dispatch("dragmove", {
113
+ direction: "down",
114
+ distance
115
+ });
92
116
  break;
93
117
  }
94
118
  };
@@ -8,15 +8,16 @@
8
8
  /**
9
9
  * Calculates the size (width or height) of a given HTML element.
10
10
  *
11
- * This function performs an expensive calculation by temporarily changing the
12
- * display style of the element if it is not currently visible. It then uses
13
- * `getBoundingClientRect` to retrieve the size of the element.
11
+ * Temporarily sets `display` if the element is not currently visible so hidden
12
+ * items can still be measured. Adds margin and an optional `gap`.
14
13
  *
15
- * @param el - The HTML element whose size is to be calculated.
14
+ * @param el - The HTML element whose size is to be calculated. Returns 0 if
15
+ * `null` or `undefined` is passed.
16
16
  * @param dimension - The dimension to measure ('width' or 'height').
17
- * @returns The size of the element in pixels. Returns 0 if the element is not provided.
17
+ * @param gap - Optional gap (in px) to add to each item's size, representing the `column-gap` (width) or `row-gap` (height) of the parent container.
18
+ * @returns The size of the element in pixels, or 0 if no element is provided.
18
19
  */
19
- declare function getSize(el: HTMLElement | undefined, dimension: 'width' | 'height'): number;
20
+ declare function getSize(el: HTMLElement | null | undefined, dimension: 'width' | 'height', gap?: number): number;
20
21
  /**
21
22
  * Options for updating the overflow handler.
22
23
  * Determines which items should be visible and which should be hidden
@@ -43,6 +44,10 @@ interface UpdateOverflowHandlerOptions {
43
44
  onChange: (visibleItems: HTMLElement[], hiddenItems: HTMLElement[]) => void;
44
45
  /** An array of previously hidden items to compare against the new hidden items. */
45
46
  previousHiddenItems?: HTMLElement[];
47
+ /** Pixels to reserve from the container's available space, causing overflow to trigger earlier. */
48
+ offsetValue?: number;
49
+ /** The gap (in px) between items, representing `column-gap` (width) or `row-gap` (height) of the container. */
50
+ gap?: number;
46
51
  }
47
52
  /**
48
53
  * Updates the overflow handler by determining which items should be visible and which should be hidden.
@@ -60,7 +65,9 @@ declare function updateOverflowHandler({
60
65
  maxVisibleItems,
61
66
  dimension,
62
67
  onChange,
63
- previousHiddenItems
68
+ previousHiddenItems,
69
+ offsetValue,
70
+ gap
64
71
  }: UpdateOverflowHandlerOptions): HTMLElement[];
65
72
  /**
66
73
  * Options for initializing an overflow handler.
@@ -84,6 +91,16 @@ interface OverflowHandlerOptions {
84
91
  * The dimension to consider for overflow calculations. Defaults to 'width'.
85
92
  */
86
93
  dimension?: 'width' | 'height';
94
+ /**
95
+ * Pixels to reserve from the container's available space, causing overflow to
96
+ * trigger earlier. Useful when an element within the container (e.g. a "show
97
+ * more" button) needs guaranteed room.
98
+ */
99
+ offsetValue?: number;
100
+ /**
101
+ * The gap (in px) between items in the container's flex/grid layout.
102
+ */
103
+ gap?: number;
87
104
  }
88
105
  /**
89
106
  * Represents an instance of an overflow handler.
@@ -98,7 +115,9 @@ declare function createOverflowHandler({
98
115
  container,
99
116
  maxVisibleItems,
100
117
  onChange,
101
- dimension
118
+ dimension,
119
+ offsetValue,
120
+ gap
102
121
  }: OverflowHandlerOptions): OverflowHandler;
103
122
  //#endregion
104
123
  export { OverflowHandler, OverflowHandlerOptions, UpdateOverflowHandlerOptions, createOverflowHandler, getSize, updateOverflowHandler };
@@ -8,21 +8,23 @@
8
8
  /**
9
9
  * Calculates the size (width or height) of a given HTML element.
10
10
  *
11
- * This function performs an expensive calculation by temporarily changing the
12
- * display style of the element if it is not currently visible. It then uses
13
- * `getBoundingClientRect` to retrieve the size of the element.
11
+ * Temporarily sets `display` if the element is not currently visible so hidden
12
+ * items can still be measured. Adds margin and an optional `gap`.
14
13
  *
15
- * @param el - The HTML element whose size is to be calculated.
14
+ * @param el - The HTML element whose size is to be calculated. Returns 0 if
15
+ * `null` or `undefined` is passed.
16
16
  * @param dimension - The dimension to measure ('width' or 'height').
17
- * @returns The size of the element in pixels. Returns 0 if the element is not provided.
17
+ * @param gap - Optional gap (in px) to add to each item's size, representing the `column-gap` (width) or `row-gap` (height) of the parent container.
18
+ * @returns The size of the element in pixels, or 0 if no element is provided.
18
19
  */
19
- function getSize(el, dimension) {
20
+ function getSize(el, dimension, gap = 0) {
20
21
  if (!el) return 0;
21
22
  const originalDisplay = el.style.display;
22
- if (!el.offsetParent && getComputedStyle(el).display === "none") el.style.display = "inline-block";
23
+ const styles = getComputedStyle(el);
24
+ if (!el.offsetParent && styles.display === "none") el.style.display = "inline-block";
23
25
  const size = el.getBoundingClientRect()[dimension];
24
26
  el.style.display = originalDisplay;
25
- return size;
27
+ return size + (dimension === "width" ? (parseFloat(styles.marginLeft) || 0) + (parseFloat(styles.marginRight) || 0) : (parseFloat(styles.marginTop) || 0) + (parseFloat(styles.marginBottom) || 0)) + gap;
26
28
  }
27
29
  /**
28
30
  * Updates the overflow handler by determining which items should be visible and which should be hidden.
@@ -30,64 +32,80 @@ function getSize(el, dimension) {
30
32
  * @param options - Configuration options for updating the overflow handler.
31
33
  * @returns An array of hidden items after the update.
32
34
  */
33
- function updateOverflowHandler({ container, items, offset, sizes, fixedSizes, offsetSize, maxVisibleItems, dimension, onChange, previousHiddenItems = [] }) {
35
+ function updateOverflowHandler({ container, items, offset, sizes, fixedSizes, offsetSize, maxVisibleItems, dimension, onChange, previousHiddenItems = [], offsetValue = 0, gap = 0 }) {
34
36
  const containerSize = dimension === "width" ? container.clientWidth : container.clientHeight;
35
37
  let visibleItems = [];
36
38
  let hiddenItems = [];
37
39
  const totalSize = sizes.reduce((sum, size) => sum + size, 0);
38
40
  const totalFixedSize = fixedSizes.reduce((sum, size) => sum + size, 0);
39
- if (totalSize + totalFixedSize <= containerSize) {
41
+ const trailingGap = sizes.length + fixedSizes.length > 0 ? gap : 0;
42
+ if (totalSize + totalFixedSize - trailingGap <= containerSize - offsetValue) {
40
43
  visibleItems = maxVisibleItems ? items.slice(0, maxVisibleItems) : [...items];
41
44
  hiddenItems = maxVisibleItems ? items.slice(maxVisibleItems) : [];
42
45
  } else {
43
- const available = containerSize - offsetSize;
46
+ const available = containerSize - offsetSize - totalFixedSize - offsetValue + gap;
44
47
  let accumulated = 0;
48
+ let breakIndex = items.length;
45
49
  for (let i = 0; i < items.length; i++) {
46
50
  const size = sizes[i];
47
- if (accumulated + size + totalFixedSize <= available && (!maxVisibleItems || visibleItems.length < maxVisibleItems)) {
51
+ if (accumulated + size <= available && (!maxVisibleItems || visibleItems.length < maxVisibleItems)) {
48
52
  visibleItems.push(items[i]);
49
53
  accumulated += size;
50
- } else hiddenItems.push(items[i]);
54
+ } else {
55
+ breakIndex = i;
56
+ break;
57
+ }
51
58
  }
59
+ hiddenItems = items.slice(breakIndex);
52
60
  }
53
- if (previousHiddenItems.length === hiddenItems.length && previousHiddenItems.every((item, index) => item === hiddenItems[index])) return previousHiddenItems;
54
61
  visibleItems.forEach((item) => item.removeAttribute("data-hidden"));
55
62
  hiddenItems.forEach((item) => item.setAttribute("data-hidden", ""));
56
63
  if (offset) offset.toggleAttribute("data-hidden", hiddenItems.length === 0);
64
+ if (previousHiddenItems.length === hiddenItems.length && previousHiddenItems.every((item, index) => item === hiddenItems[index])) return previousHiddenItems;
57
65
  onChange(visibleItems, hiddenItems);
58
66
  return hiddenItems;
59
67
  }
60
- function createOverflowHandler({ container, maxVisibleItems, onChange, dimension = "width" }) {
68
+ function createOverflowHandler({ container, maxVisibleItems, onChange, dimension = "width", offsetValue, gap }) {
61
69
  if (!(container instanceof HTMLElement)) throw new Error("container must be an HTMLElement");
62
70
  if (typeof onChange !== "function") throw new Error("onChange must be a function");
63
71
  if (maxVisibleItems !== void 0 && (!Number.isInteger(maxVisibleItems) || maxVisibleItems <= 0)) throw new Error("maxVisibleItems must be a positive integer");
64
- const children = Array.from(container.children).filter((item) => item instanceof HTMLElement);
72
+ const children = Array.from(container.children);
65
73
  const offset = children.find((item) => item.hasAttribute("data-offset"));
66
74
  const fixedItems = children.filter((item) => item.hasAttribute("data-fixed"));
67
75
  const items = children.filter((item) => item !== offset && !fixedItems.includes(item));
68
- const fixedSizes = fixedItems.map((item) => getSize(item, dimension));
69
- const sizes = items.map((item) => getSize(item, dimension));
70
- const offsetSize = getSize(offset, dimension);
71
76
  let previousHiddenItems = [];
72
- function update() {
77
+ let rafId;
78
+ let disconnected = false;
79
+ const update = () => {
80
+ if (disconnected) return;
81
+ rafId = void 0;
73
82
  previousHiddenItems = updateOverflowHandler({
74
83
  container,
75
84
  items,
76
85
  offset,
77
- sizes,
78
- fixedSizes,
79
- offsetSize,
86
+ sizes: items.map((item) => getSize(item, dimension, gap)),
87
+ fixedSizes: fixedItems.map((item) => getSize(item, dimension, gap)),
88
+ offsetSize: getSize(offset, dimension, gap),
80
89
  maxVisibleItems,
81
90
  dimension,
82
91
  onChange,
83
- previousHiddenItems
92
+ previousHiddenItems,
93
+ offsetValue,
94
+ gap
84
95
  });
85
- }
86
- const resizeObserver = new ResizeObserver(() => requestAnimationFrame(update));
96
+ };
97
+ const scheduleUpdate = () => {
98
+ if (disconnected || rafId !== void 0) return;
99
+ rafId = requestAnimationFrame(update);
100
+ };
101
+ const resizeObserver = new ResizeObserver(scheduleUpdate);
87
102
  resizeObserver.observe(container);
88
- requestAnimationFrame(update);
103
+ scheduleUpdate();
104
+ document.fonts?.ready?.then(scheduleUpdate);
89
105
  return { disconnect() {
106
+ disconnected = true;
90
107
  resizeObserver.disconnect();
108
+ if (rafId !== void 0) cancelAnimationFrame(rafId);
91
109
  } };
92
110
  }
93
111
  //#endregion
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("temporal-polyfill/global");
2
3
  //#region src/date-picker/primitives/states.ts
3
4
  /**
4
5
  * Copyright IBM Corp. 2026
@@ -358,64 +359,6 @@ function parseDateString(dateString, format) {
358
359
  function isTemporalAvailable() {
359
360
  return typeof Temporal !== "undefined" && typeof Temporal.PlainDate !== "undefined";
360
361
  }
361
- /**
362
- * Get a fallback date handler if Temporal is not available
363
- * This provides a migration path for browsers without Temporal support
364
- */
365
- function getDateHandler() {
366
- if (isTemporalAvailable()) return {
367
- type: "temporal",
368
- toISOString: plainDateToISOString,
369
- fromISOString: parseISOToPlainDate,
370
- compare: comparePlainDates,
371
- format: formatPlainDate,
372
- isInRange: isDateInRange
373
- };
374
- return {
375
- type: "date",
376
- /**
377
- *
378
- * @param {Temporal.PlainDate} date - The date to convert
379
- */
380
- toISOString: (date) => date.toISOString().split("T")[0],
381
- /**
382
- *
383
- * @param {string} str - The ISO string to parse
384
- */
385
- fromISOString: (str) => {
386
- const date = new Date(str);
387
- return isNaN(date.getTime()) ? null : date;
388
- },
389
- /**
390
- *
391
- * @param {Temporal.PlainDate} d1 - First date
392
- * @param {Temporal.PlainDate} d2 - Second date
393
- */
394
- compare: (d1, d2) => d1.getTime() - d2.getTime(),
395
- /**
396
- *
397
- * @param {Temporal.PlainDate} date - The date to format
398
- * @param {string} format - The format string
399
- */
400
- format: (date, format) => {
401
- const year = date.getFullYear().toString();
402
- const month = (date.getMonth() + 1).toString().padStart(2, "0");
403
- const day = date.getDate().toString().padStart(2, "0");
404
- return format.replace("Y", year).replace("m", month).replace("d", day);
405
- },
406
- /**
407
- *
408
- * @param {Temporal.PlainDate} date - The date to check
409
- * @param {Temporal.PlainDate | null} min - Minimum date
410
- * @param {Temporal.PlainDate | null} max - Maximum date
411
- */
412
- isInRange: (date, min, max) => {
413
- if (min && date < min) return false;
414
- if (max && date > max) return false;
415
- return true;
416
- }
417
- };
418
- }
419
362
  //#endregion
420
363
  //#region src/date-picker/primitives/guards.ts
421
364
  /**
@@ -2013,6 +1956,33 @@ function getWeekdayLabels(locale = "en", weekStartsOn = 0) {
2013
1956
  return labels;
2014
1957
  }
2015
1958
  //#endregion
1959
+ //#region src/date-picker/index.ts
1960
+ /**
1961
+ * Copyright IBM Corp. 2026
1962
+ *
1963
+ * This source code is licensed under the Apache-2.0 license found in the
1964
+ * LICENSE file in the root directory of this source tree.
1965
+ */
1966
+ /**
1967
+ * @internal
1968
+ * This module is for internal use by @carbon/react and @carbon/web-components only.
1969
+ * It is not part of the public @carbon/utilities API.
1970
+ *
1971
+ * Import from source path:
1972
+ * import { ... } from '@carbon/utilities/src/date-picker';
1973
+ */
1974
+ /**
1975
+ * The primitives below are built on Temporal, which is still unevenly shipped:
1976
+ * no version of Safari implements it, and Chrome/Edge only gained it in 144.
1977
+ * Every `Temporal.*` reference in this module tree is a bare global, so on those engines
1978
+ * the first access — `Temporal.Now.plainDateISO()` on the calendar-open transition
1979
+ * throws a ReferenceError and the calendar never opens.
1980
+
1981
+ * `temporal-polyfill/global` installs `globalThis.Temporal` only when the engine
1982
+ * does not already provide it, so a native implementation always wins. It is
1983
+ * imported first so the global exists before any primitive can reach for it.
1984
+ */
1985
+ //#endregion
2016
1986
  exports.ClickOutsideHandler = ClickOutsideHandler;
2017
1987
  exports.DatePickerEvent = DatePickerEvent;
2018
1988
  exports.DatePickerState = DatePickerState;
@@ -2031,7 +2001,6 @@ exports.executeEffect = executeEffect;
2031
2001
  exports.formatPlainDate = formatPlainDate;
2032
2002
  exports.generateCalendarGrid = generateCalendarGrid;
2033
2003
  exports.getAction = getAction;
2034
- exports.getDateHandler = getDateHandler;
2035
2004
  exports.getEffect = getEffect;
2036
2005
  exports.getFullDateLabel = getFullDateLabel;
2037
2006
  exports.getGuard = getGuard;
@@ -2,7 +2,12 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/makeDraggable/makeDraggable.ts
3
3
  /**
4
4
  * Makes a given element draggable using a handle element.
5
- *@param draggable - object which accepts el and optional attributes handle,focusableInHandle,dragStep and shiftDragStep
5
+ * @param {object} draggable - Configuration object for draggable behavior
6
+ * @param {HTMLElement} draggable.el - The element to make draggable
7
+ * @param {HTMLElement} [draggable.dragHandle] - Optional handle element for dragging
8
+ * @param {boolean} [draggable.focusableDragHandle] - Whether the drag handle should be focusable
9
+ * @param {number} [draggable.dragStep] - Step size for keyboard dragging (default: 10)
10
+ * @param {number} [draggable.shiftDragStep] - Step size for keyboard dragging with Shift key (default: 50)
6
11
  */
7
12
  const makeDraggable = ({ el, dragHandle, focusableDragHandle, dragStep, shiftDragStep }) => {
8
13
  if (dragHandle) {
@@ -61,7 +66,8 @@ const makeDraggable = ({ el, dragHandle, focusableDragHandle, dragStep, shiftDra
61
66
  el.dispatchEvent(new CustomEvent(type, eventInit));
62
67
  };
63
68
  const onKeyDown = (e) => {
64
- if (e.key === "Enter") {
69
+ if (e.key === "Enter" || e.key === " ") {
70
+ e.preventDefault();
65
71
  isDragging = !isDragging;
66
72
  if (isDragging) {
67
73
  syncTransformState();
@@ -72,24 +78,42 @@ const makeDraggable = ({ el, dragHandle, focusableDragHandle, dragStep, shiftDra
72
78
  const distance = e.shiftKey ? shiftDragStep ?? 32 : dragStep ?? 8;
73
79
  switch (e.key) {
74
80
  case "Enter":
75
- case " ":
76
- e.preventDefault();
77
- break;
81
+ case " ": break;
78
82
  case "ArrowLeft":
83
+ e.preventDefault();
79
84
  currentX -= distance;
80
85
  applyTransform(currentX, currentY);
86
+ dispatch("dragmove", {
87
+ direction: "left",
88
+ distance
89
+ });
81
90
  break;
82
91
  case "ArrowRight":
92
+ e.preventDefault();
83
93
  currentX += distance;
84
94
  applyTransform(currentX, currentY);
95
+ dispatch("dragmove", {
96
+ direction: "right",
97
+ distance
98
+ });
85
99
  break;
86
100
  case "ArrowUp":
101
+ e.preventDefault();
87
102
  currentY -= distance;
88
103
  applyTransform(currentX, currentY);
104
+ dispatch("dragmove", {
105
+ direction: "up",
106
+ distance
107
+ });
89
108
  break;
90
109
  case "ArrowDown":
110
+ e.preventDefault();
91
111
  currentY += distance;
92
112
  applyTransform(currentX, currentY);
113
+ dispatch("dragmove", {
114
+ direction: "down",
115
+ distance
116
+ });
93
117
  break;
94
118
  }
95
119
  };
@@ -9,21 +9,23 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
9
9
  /**
10
10
  * Calculates the size (width or height) of a given HTML element.
11
11
  *
12
- * This function performs an expensive calculation by temporarily changing the
13
- * display style of the element if it is not currently visible. It then uses
14
- * `getBoundingClientRect` to retrieve the size of the element.
12
+ * Temporarily sets `display` if the element is not currently visible so hidden
13
+ * items can still be measured. Adds margin and an optional `gap`.
15
14
  *
16
- * @param el - The HTML element whose size is to be calculated.
15
+ * @param el - The HTML element whose size is to be calculated. Returns 0 if
16
+ * `null` or `undefined` is passed.
17
17
  * @param dimension - The dimension to measure ('width' or 'height').
18
- * @returns The size of the element in pixels. Returns 0 if the element is not provided.
18
+ * @param gap - Optional gap (in px) to add to each item's size, representing the `column-gap` (width) or `row-gap` (height) of the parent container.
19
+ * @returns The size of the element in pixels, or 0 if no element is provided.
19
20
  */
20
- function getSize(el, dimension) {
21
+ function getSize(el, dimension, gap = 0) {
21
22
  if (!el) return 0;
22
23
  const originalDisplay = el.style.display;
23
- if (!el.offsetParent && getComputedStyle(el).display === "none") el.style.display = "inline-block";
24
+ const styles = getComputedStyle(el);
25
+ if (!el.offsetParent && styles.display === "none") el.style.display = "inline-block";
24
26
  const size = el.getBoundingClientRect()[dimension];
25
27
  el.style.display = originalDisplay;
26
- return size;
28
+ return size + (dimension === "width" ? (parseFloat(styles.marginLeft) || 0) + (parseFloat(styles.marginRight) || 0) : (parseFloat(styles.marginTop) || 0) + (parseFloat(styles.marginBottom) || 0)) + gap;
27
29
  }
28
30
  /**
29
31
  * Updates the overflow handler by determining which items should be visible and which should be hidden.
@@ -31,64 +33,80 @@ function getSize(el, dimension) {
31
33
  * @param options - Configuration options for updating the overflow handler.
32
34
  * @returns An array of hidden items after the update.
33
35
  */
34
- function updateOverflowHandler({ container, items, offset, sizes, fixedSizes, offsetSize, maxVisibleItems, dimension, onChange, previousHiddenItems = [] }) {
36
+ function updateOverflowHandler({ container, items, offset, sizes, fixedSizes, offsetSize, maxVisibleItems, dimension, onChange, previousHiddenItems = [], offsetValue = 0, gap = 0 }) {
35
37
  const containerSize = dimension === "width" ? container.clientWidth : container.clientHeight;
36
38
  let visibleItems = [];
37
39
  let hiddenItems = [];
38
40
  const totalSize = sizes.reduce((sum, size) => sum + size, 0);
39
41
  const totalFixedSize = fixedSizes.reduce((sum, size) => sum + size, 0);
40
- if (totalSize + totalFixedSize <= containerSize) {
42
+ const trailingGap = sizes.length + fixedSizes.length > 0 ? gap : 0;
43
+ if (totalSize + totalFixedSize - trailingGap <= containerSize - offsetValue) {
41
44
  visibleItems = maxVisibleItems ? items.slice(0, maxVisibleItems) : [...items];
42
45
  hiddenItems = maxVisibleItems ? items.slice(maxVisibleItems) : [];
43
46
  } else {
44
- const available = containerSize - offsetSize;
47
+ const available = containerSize - offsetSize - totalFixedSize - offsetValue + gap;
45
48
  let accumulated = 0;
49
+ let breakIndex = items.length;
46
50
  for (let i = 0; i < items.length; i++) {
47
51
  const size = sizes[i];
48
- if (accumulated + size + totalFixedSize <= available && (!maxVisibleItems || visibleItems.length < maxVisibleItems)) {
52
+ if (accumulated + size <= available && (!maxVisibleItems || visibleItems.length < maxVisibleItems)) {
49
53
  visibleItems.push(items[i]);
50
54
  accumulated += size;
51
- } else hiddenItems.push(items[i]);
55
+ } else {
56
+ breakIndex = i;
57
+ break;
58
+ }
52
59
  }
60
+ hiddenItems = items.slice(breakIndex);
53
61
  }
54
- if (previousHiddenItems.length === hiddenItems.length && previousHiddenItems.every((item, index) => item === hiddenItems[index])) return previousHiddenItems;
55
62
  visibleItems.forEach((item) => item.removeAttribute("data-hidden"));
56
63
  hiddenItems.forEach((item) => item.setAttribute("data-hidden", ""));
57
64
  if (offset) offset.toggleAttribute("data-hidden", hiddenItems.length === 0);
65
+ if (previousHiddenItems.length === hiddenItems.length && previousHiddenItems.every((item, index) => item === hiddenItems[index])) return previousHiddenItems;
58
66
  onChange(visibleItems, hiddenItems);
59
67
  return hiddenItems;
60
68
  }
61
- function createOverflowHandler({ container, maxVisibleItems, onChange, dimension = "width" }) {
69
+ function createOverflowHandler({ container, maxVisibleItems, onChange, dimension = "width", offsetValue, gap }) {
62
70
  if (!(container instanceof HTMLElement)) throw new Error("container must be an HTMLElement");
63
71
  if (typeof onChange !== "function") throw new Error("onChange must be a function");
64
72
  if (maxVisibleItems !== void 0 && (!Number.isInteger(maxVisibleItems) || maxVisibleItems <= 0)) throw new Error("maxVisibleItems must be a positive integer");
65
- const children = Array.from(container.children).filter((item) => item instanceof HTMLElement);
73
+ const children = Array.from(container.children);
66
74
  const offset = children.find((item) => item.hasAttribute("data-offset"));
67
75
  const fixedItems = children.filter((item) => item.hasAttribute("data-fixed"));
68
76
  const items = children.filter((item) => item !== offset && !fixedItems.includes(item));
69
- const fixedSizes = fixedItems.map((item) => getSize(item, dimension));
70
- const sizes = items.map((item) => getSize(item, dimension));
71
- const offsetSize = getSize(offset, dimension);
72
77
  let previousHiddenItems = [];
73
- function update() {
78
+ let rafId;
79
+ let disconnected = false;
80
+ const update = () => {
81
+ if (disconnected) return;
82
+ rafId = void 0;
74
83
  previousHiddenItems = updateOverflowHandler({
75
84
  container,
76
85
  items,
77
86
  offset,
78
- sizes,
79
- fixedSizes,
80
- offsetSize,
87
+ sizes: items.map((item) => getSize(item, dimension, gap)),
88
+ fixedSizes: fixedItems.map((item) => getSize(item, dimension, gap)),
89
+ offsetSize: getSize(offset, dimension, gap),
81
90
  maxVisibleItems,
82
91
  dimension,
83
92
  onChange,
84
- previousHiddenItems
93
+ previousHiddenItems,
94
+ offsetValue,
95
+ gap
85
96
  });
86
- }
87
- const resizeObserver = new ResizeObserver(() => requestAnimationFrame(update));
97
+ };
98
+ const scheduleUpdate = () => {
99
+ if (disconnected || rafId !== void 0) return;
100
+ rafId = requestAnimationFrame(update);
101
+ };
102
+ const resizeObserver = new ResizeObserver(scheduleUpdate);
88
103
  resizeObserver.observe(container);
89
- requestAnimationFrame(update);
104
+ scheduleUpdate();
105
+ document.fonts?.ready?.then(scheduleUpdate);
90
106
  return { disconnect() {
107
+ disconnected = true;
91
108
  resizeObserver.disconnect();
109
+ if (rafId !== void 0) cancelAnimationFrame(rafId);
92
110
  } };
93
111
  }
94
112
  //#endregion
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@carbon/utilities",
3
3
  "description": "Utilities and helpers to drive consistency across software products using the Carbon Design System",
4
- "version": "0.24.0",
4
+ "version": "0.25.0",
5
5
  "license": "Apache-2.0",
6
6
  "main": "lib/index.js",
7
7
  "module": "es/index.js",
@@ -22,7 +22,9 @@
22
22
  "sideEffects": [
23
23
  "*.scss",
24
24
  "./index.scss",
25
- "./scss/**"
25
+ "./scss/**",
26
+ "./es/date-picker/index.js",
27
+ "./lib/date-picker/index.js"
26
28
  ],
27
29
  "exports": {
28
30
  ".": {
@@ -64,7 +66,8 @@
64
66
  },
65
67
  "dependencies": {
66
68
  "@ibm/telemetry-js": "^1.6.1",
67
- "@internationalized/number": "^3.6.1"
69
+ "@internationalized/number": "^3.6.1",
70
+ "temporal-polyfill": "^1.0.4"
68
71
  },
69
- "gitHead": "188d23202ec1092322dee92cf0df9d9958224ae4"
72
+ "gitHead": "7518c84ffd00f22434fe19d83119692c12fccb2f"
70
73
  }