@carbon/utilities 0.24.0 → 0.25.0-rc.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.
|
@@ -31,7 +31,12 @@ interface DraggableProps {
|
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Makes a given element draggable using a handle element.
|
|
34
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
12
|
-
*
|
|
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
|
-
* @
|
|
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
|
-
*
|
|
12
|
-
*
|
|
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
|
-
* @
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
51
|
+
if (accumulated + size <= available && (!maxVisibleItems || visibleItems.length < maxVisibleItems)) {
|
|
48
52
|
visibleItems.push(items[i]);
|
|
49
53
|
accumulated += size;
|
|
50
|
-
} else
|
|
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)
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
@@ -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
|
-
|
|
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
|
-
*
|
|
13
|
-
*
|
|
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
|
-
* @
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
52
|
+
if (accumulated + size <= available && (!maxVisibleItems || visibleItems.length < maxVisibleItems)) {
|
|
49
53
|
visibleItems.push(items[i]);
|
|
50
54
|
accumulated += size;
|
|
51
|
-
} else
|
|
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)
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
4
|
+
"version": "0.25.0-rc.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"module": "es/index.js",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"@ibm/telemetry-js": "^1.6.1",
|
|
67
67
|
"@internationalized/number": "^3.6.1"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "e848b98936051ac0026fb83551c91bfe603c589c"
|
|
70
70
|
}
|