@fluentui/priority-overflow 9.0.0-rc.1 → 9.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/CHANGELOG.json +67 -1
- package/CHANGELOG.md +20 -2
- package/lib/debounce.js.map +1 -1
- package/lib/overflowManager.js +21 -57
- package/lib/overflowManager.js.map +1 -1
- package/lib/priorityQueue.js +0 -21
- package/lib/priorityQueue.js.map +1 -1
- package/lib-amd/debounce.js +27 -0
- package/lib-amd/debounce.js.map +1 -0
- package/lib-amd/index.js +7 -0
- package/lib-amd/index.js.map +1 -0
- package/lib-amd/overflowManager.js +208 -0
- package/lib-amd/overflowManager.js.map +1 -0
- package/lib-amd/priorityQueue.js +97 -0
- package/lib-amd/priorityQueue.js.map +1 -0
- package/lib-amd/types.js +5 -0
- package/lib-amd/types.js.map +1 -0
- package/lib-commonjs/debounce.js +0 -2
- package/lib-commonjs/debounce.js.map +1 -1
- package/lib-commonjs/index.js +0 -2
- package/lib-commonjs/index.js.map +1 -1
- package/lib-commonjs/overflowManager.js +21 -61
- package/lib-commonjs/overflowManager.js.map +1 -1
- package/lib-commonjs/priorityQueue.js +0 -23
- package/lib-commonjs/priorityQueue.js.map +1 -1
- package/lib-commonjs/types.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
define(["require", "exports", "./debounce", "./priorityQueue"], function (require, exports, debounce_1, priorityQueue_1) {
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.createOverflowManager = void 0;
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
* @returns overflow manager instance
|
|
8
|
+
*/
|
|
9
|
+
function createOverflowManager() {
|
|
10
|
+
var container;
|
|
11
|
+
var overflowMenu;
|
|
12
|
+
var observing = false;
|
|
13
|
+
var options = {
|
|
14
|
+
padding: 10,
|
|
15
|
+
overflowAxis: 'horizontal',
|
|
16
|
+
overflowDirection: 'end',
|
|
17
|
+
minimumVisible: 0,
|
|
18
|
+
onUpdateItemVisibility: function () { return undefined; },
|
|
19
|
+
onUpdateOverflow: function () { return undefined; },
|
|
20
|
+
};
|
|
21
|
+
var overflowItems = {};
|
|
22
|
+
var overflowGroups = {};
|
|
23
|
+
var resizeObserver = new ResizeObserver(function (entries) {
|
|
24
|
+
if (!entries[0] || !container) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
update();
|
|
28
|
+
});
|
|
29
|
+
var invisibleItemQueue = priorityQueue_1.createPriorityQueue(function (a, b) {
|
|
30
|
+
var itemA = overflowItems[a];
|
|
31
|
+
var itemB = overflowItems[b];
|
|
32
|
+
// Higher priority at the top of the queue
|
|
33
|
+
var priority = itemB.priority - itemA.priority;
|
|
34
|
+
if (priority !== 0) {
|
|
35
|
+
return priority;
|
|
36
|
+
}
|
|
37
|
+
var positionStatusBit = options.overflowDirection === 'end' ? Node.DOCUMENT_POSITION_FOLLOWING : Node.DOCUMENT_POSITION_PRECEDING;
|
|
38
|
+
// equal priority, use DOM order
|
|
39
|
+
// eslint-disable-next-line no-bitwise
|
|
40
|
+
return itemA.element.compareDocumentPosition(itemB.element) & positionStatusBit ? -1 : 1;
|
|
41
|
+
});
|
|
42
|
+
var visibleItemQueue = priorityQueue_1.createPriorityQueue(function (a, b) {
|
|
43
|
+
var itemA = overflowItems[a];
|
|
44
|
+
var itemB = overflowItems[b];
|
|
45
|
+
// Lower priority at the top of the queue
|
|
46
|
+
var priority = itemA.priority - itemB.priority;
|
|
47
|
+
if (priority !== 0) {
|
|
48
|
+
return priority;
|
|
49
|
+
}
|
|
50
|
+
var positionStatusBit = options.overflowDirection === 'end' ? Node.DOCUMENT_POSITION_PRECEDING : Node.DOCUMENT_POSITION_FOLLOWING;
|
|
51
|
+
// equal priority, use DOM order
|
|
52
|
+
// eslint-disable-next-line no-bitwise
|
|
53
|
+
return itemA.element.compareDocumentPosition(itemB.element) & positionStatusBit ? -1 : 1;
|
|
54
|
+
});
|
|
55
|
+
var getOffsetSize = function (el) {
|
|
56
|
+
return options.overflowAxis === 'horizontal' ? el.offsetWidth : el.offsetHeight;
|
|
57
|
+
};
|
|
58
|
+
var makeItemVisible = function () {
|
|
59
|
+
var nextVisible = invisibleItemQueue.dequeue();
|
|
60
|
+
visibleItemQueue.enqueue(nextVisible);
|
|
61
|
+
var item = overflowItems[nextVisible];
|
|
62
|
+
options.onUpdateItemVisibility({ item: item, visible: true });
|
|
63
|
+
if (item.groupId) {
|
|
64
|
+
overflowGroups[item.groupId].invisibleItemIds.delete(item.id);
|
|
65
|
+
overflowGroups[item.groupId].visibleItemIds.add(item.id);
|
|
66
|
+
}
|
|
67
|
+
return getOffsetSize(item.element);
|
|
68
|
+
};
|
|
69
|
+
var makeItemInvisible = function () {
|
|
70
|
+
var nextInvisible = visibleItemQueue.dequeue();
|
|
71
|
+
invisibleItemQueue.enqueue(nextInvisible);
|
|
72
|
+
var item = overflowItems[nextInvisible];
|
|
73
|
+
var width = getOffsetSize(item.element);
|
|
74
|
+
options.onUpdateItemVisibility({ item: item, visible: false });
|
|
75
|
+
if (item.groupId) {
|
|
76
|
+
overflowGroups[item.groupId].visibleItemIds.delete(item.id);
|
|
77
|
+
overflowGroups[item.groupId].invisibleItemIds.add(item.id);
|
|
78
|
+
}
|
|
79
|
+
return width;
|
|
80
|
+
};
|
|
81
|
+
var dispatchOverflowUpdate = function () {
|
|
82
|
+
var visibleItemIds = visibleItemQueue.all();
|
|
83
|
+
var invisibleItemIds = invisibleItemQueue.all();
|
|
84
|
+
var visibleItems = visibleItemIds.map(function (itemId) { return overflowItems[itemId]; });
|
|
85
|
+
var invisibleItems = invisibleItemIds.map(function (itemId) { return overflowItems[itemId]; });
|
|
86
|
+
var groupVisibility = {};
|
|
87
|
+
Object.entries(overflowGroups).forEach(function (_a) {
|
|
88
|
+
var groupId = _a[0], groupState = _a[1];
|
|
89
|
+
if (groupState.invisibleItemIds.size && groupState.visibleItemIds.size) {
|
|
90
|
+
groupVisibility[groupId] = 'overflow';
|
|
91
|
+
}
|
|
92
|
+
else if (groupState.visibleItemIds.size === 0) {
|
|
93
|
+
groupVisibility[groupId] = 'hidden';
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
groupVisibility[groupId] = 'visible';
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
options.onUpdateOverflow({ visibleItems: visibleItems, invisibleItems: invisibleItems, groupVisibility: groupVisibility });
|
|
100
|
+
};
|
|
101
|
+
var processOverflowItems = function (availableSize) {
|
|
102
|
+
if (!container) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
var overflowMenuOffset = overflowMenu ? getOffsetSize(overflowMenu) : 0;
|
|
106
|
+
// Snapshot of the visible/invisible state to compare for updates
|
|
107
|
+
var visibleTop = visibleItemQueue.peek();
|
|
108
|
+
var invisibleTop = invisibleItemQueue.peek();
|
|
109
|
+
var visibleItemIds = visibleItemQueue.all();
|
|
110
|
+
var currentWidth = visibleItemIds.reduce(function (sum, visibleItemId) {
|
|
111
|
+
var child = overflowItems[visibleItemId].element;
|
|
112
|
+
return sum + getOffsetSize(child);
|
|
113
|
+
}, 0);
|
|
114
|
+
// Add items until available width is filled - can result in overflow
|
|
115
|
+
while (currentWidth < availableSize && invisibleItemQueue.size() > 0) {
|
|
116
|
+
currentWidth += makeItemVisible();
|
|
117
|
+
}
|
|
118
|
+
// Remove items until there's no more overflow
|
|
119
|
+
while (currentWidth > availableSize && visibleItemQueue.size() > 0) {
|
|
120
|
+
if (visibleItemQueue.size() <= options.minimumVisible) {
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
currentWidth -= makeItemInvisible();
|
|
124
|
+
}
|
|
125
|
+
// make sure the overflow menu can fit
|
|
126
|
+
if (visibleItemQueue.size() > options.minimumVisible &&
|
|
127
|
+
invisibleItemQueue.size() > 0 &&
|
|
128
|
+
currentWidth + overflowMenuOffset > availableSize) {
|
|
129
|
+
makeItemInvisible();
|
|
130
|
+
}
|
|
131
|
+
// only update when the state of visible/invisible items has changed
|
|
132
|
+
if (visibleItemQueue.peek() !== visibleTop || invisibleItemQueue.peek() !== invisibleTop) {
|
|
133
|
+
dispatchOverflowUpdate();
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
var forceUpdate = function () {
|
|
137
|
+
if (!container) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
var availableSize = getOffsetSize(container) - options.padding;
|
|
141
|
+
processOverflowItems(availableSize);
|
|
142
|
+
};
|
|
143
|
+
var update = debounce_1.debounce(forceUpdate);
|
|
144
|
+
var observe = function (observedContainer, userOptions) {
|
|
145
|
+
Object.assign(options, userOptions);
|
|
146
|
+
observing = true;
|
|
147
|
+
Object.values(overflowItems).forEach(function (item) { return visibleItemQueue.enqueue(item.id); });
|
|
148
|
+
container = observedContainer;
|
|
149
|
+
resizeObserver.observe(container);
|
|
150
|
+
};
|
|
151
|
+
var disconnect = function () {
|
|
152
|
+
observing = false;
|
|
153
|
+
resizeObserver.disconnect();
|
|
154
|
+
};
|
|
155
|
+
var addItem = function (item) {
|
|
156
|
+
if (overflowItems[item.id]) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
overflowItems[item.id] = item;
|
|
160
|
+
// some options can affect priority which are only set on `observe`
|
|
161
|
+
if (observing) {
|
|
162
|
+
visibleItemQueue.enqueue(item.id);
|
|
163
|
+
}
|
|
164
|
+
if (item.groupId) {
|
|
165
|
+
if (!overflowGroups[item.groupId]) {
|
|
166
|
+
overflowGroups[item.groupId] = {
|
|
167
|
+
visibleItemIds: new Set(),
|
|
168
|
+
invisibleItemIds: new Set(),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
overflowGroups[item.groupId].visibleItemIds.add(item.id);
|
|
172
|
+
}
|
|
173
|
+
update();
|
|
174
|
+
};
|
|
175
|
+
var addOverflowMenu = function (el) {
|
|
176
|
+
overflowMenu = el;
|
|
177
|
+
};
|
|
178
|
+
var removeOverflowMenu = function () {
|
|
179
|
+
overflowMenu = undefined;
|
|
180
|
+
};
|
|
181
|
+
var removeItem = function (itemId) {
|
|
182
|
+
if (!overflowItems[itemId]) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
var item = overflowItems[itemId];
|
|
186
|
+
visibleItemQueue.remove(itemId);
|
|
187
|
+
invisibleItemQueue.remove(itemId);
|
|
188
|
+
if (item.groupId) {
|
|
189
|
+
overflowGroups[item.groupId].visibleItemIds.delete(item.id);
|
|
190
|
+
overflowGroups[item.groupId].invisibleItemIds.delete(item.id);
|
|
191
|
+
}
|
|
192
|
+
delete overflowItems[itemId];
|
|
193
|
+
update();
|
|
194
|
+
};
|
|
195
|
+
return {
|
|
196
|
+
addItem: addItem,
|
|
197
|
+
disconnect: disconnect,
|
|
198
|
+
forceUpdate: forceUpdate,
|
|
199
|
+
observe: observe,
|
|
200
|
+
removeItem: removeItem,
|
|
201
|
+
update: update,
|
|
202
|
+
addOverflowMenu: addOverflowMenu,
|
|
203
|
+
removeOverflowMenu: removeOverflowMenu,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
exports.createOverflowManager = createOverflowManager;
|
|
207
|
+
});
|
|
208
|
+
//# sourceMappingURL=overflowManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overflowManager.js","sourceRoot":"","sources":["../../../../../../../packages/react-components/priority-overflow/src/overflowManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { debounce } from './debounce';\nimport { createPriorityQueue } from './priorityQueue';\nimport type { OverflowGroupState, OverflowItemEntry, OverflowManager, ObserveOptions } from './types';\n\n/**\n * @internal\n * @returns overflow manager instance\n */\nexport function createOverflowManager(): OverflowManager {\n let container: HTMLElement | undefined;\n let overflowMenu: HTMLElement | undefined;\n let observing = false;\n const options: Required<ObserveOptions> = {\n padding: 10,\n overflowAxis: 'horizontal',\n overflowDirection: 'end',\n minimumVisible: 0,\n onUpdateItemVisibility: () => undefined,\n onUpdateOverflow: () => undefined,\n };\n\n const overflowItems: Record<string, OverflowItemEntry> = {};\n const overflowGroups: Record<string, { visibleItemIds: Set<string>; invisibleItemIds: Set<string> }> = {};\n const resizeObserver = new ResizeObserver(entries => {\n if (!entries[0] || !container) {\n return;\n }\n\n update();\n });\n\n const invisibleItemQueue = createPriorityQueue<string>((a, b) => {\n const itemA = overflowItems[a];\n const itemB = overflowItems[b];\n // Higher priority at the top of the queue\n const priority = itemB.priority - itemA.priority;\n if (priority !== 0) {\n return priority;\n }\n\n const positionStatusBit =\n options.overflowDirection === 'end' ? Node.DOCUMENT_POSITION_FOLLOWING : Node.DOCUMENT_POSITION_PRECEDING;\n\n // equal priority, use DOM order\n // eslint-disable-next-line no-bitwise\n return itemA.element.compareDocumentPosition(itemB.element) & positionStatusBit ? -1 : 1;\n });\n\n const visibleItemQueue = createPriorityQueue<string>((a, b) => {\n const itemA = overflowItems[a];\n const itemB = overflowItems[b];\n // Lower priority at the top of the queue\n const priority = itemA.priority - itemB.priority;\n\n if (priority !== 0) {\n return priority;\n }\n\n const positionStatusBit =\n options.overflowDirection === 'end' ? Node.DOCUMENT_POSITION_PRECEDING : Node.DOCUMENT_POSITION_FOLLOWING;\n\n // equal priority, use DOM order\n // eslint-disable-next-line no-bitwise\n return itemA.element.compareDocumentPosition(itemB.element) & positionStatusBit ? -1 : 1;\n });\n\n const getOffsetSize = (el: HTMLElement) => {\n return options.overflowAxis === 'horizontal' ? el.offsetWidth : el.offsetHeight;\n };\n\n const makeItemVisible = () => {\n const nextVisible = invisibleItemQueue.dequeue();\n visibleItemQueue.enqueue(nextVisible);\n\n const item = overflowItems[nextVisible];\n options.onUpdateItemVisibility({ item, visible: true });\n if (item.groupId) {\n overflowGroups[item.groupId].invisibleItemIds.delete(item.id);\n overflowGroups[item.groupId].visibleItemIds.add(item.id);\n }\n\n return getOffsetSize(item.element);\n };\n\n const makeItemInvisible = () => {\n const nextInvisible = visibleItemQueue.dequeue();\n invisibleItemQueue.enqueue(nextInvisible);\n\n const item = overflowItems[nextInvisible];\n const width = getOffsetSize(item.element);\n options.onUpdateItemVisibility({ item, visible: false });\n if (item.groupId) {\n overflowGroups[item.groupId].visibleItemIds.delete(item.id);\n overflowGroups[item.groupId].invisibleItemIds.add(item.id);\n }\n\n return width;\n };\n\n const dispatchOverflowUpdate = () => {\n const visibleItemIds = visibleItemQueue.all();\n const invisibleItemIds = invisibleItemQueue.all();\n\n const visibleItems = visibleItemIds.map(itemId => overflowItems[itemId]);\n const invisibleItems = invisibleItemIds.map(itemId => overflowItems[itemId]);\n\n const groupVisibility: Record<string, OverflowGroupState> = {};\n Object.entries(overflowGroups).forEach(([groupId, groupState]) => {\n if (groupState.invisibleItemIds.size && groupState.visibleItemIds.size) {\n groupVisibility[groupId] = 'overflow';\n } else if (groupState.visibleItemIds.size === 0) {\n groupVisibility[groupId] = 'hidden';\n } else {\n groupVisibility[groupId] = 'visible';\n }\n });\n\n options.onUpdateOverflow({ visibleItems, invisibleItems, groupVisibility });\n };\n\n const processOverflowItems = (availableSize: number) => {\n if (!container) {\n return;\n }\n\n const overflowMenuOffset = overflowMenu ? getOffsetSize(overflowMenu) : 0;\n\n // Snapshot of the visible/invisible state to compare for updates\n const visibleTop = visibleItemQueue.peek();\n const invisibleTop = invisibleItemQueue.peek();\n\n const visibleItemIds = visibleItemQueue.all();\n let currentWidth = visibleItemIds.reduce((sum, visibleItemId) => {\n const child = overflowItems[visibleItemId].element;\n return sum + getOffsetSize(child);\n }, 0);\n\n // Add items until available width is filled - can result in overflow\n while (currentWidth < availableSize && invisibleItemQueue.size() > 0) {\n currentWidth += makeItemVisible();\n }\n\n // Remove items until there's no more overflow\n while (currentWidth > availableSize && visibleItemQueue.size() > 0) {\n if (visibleItemQueue.size() <= options.minimumVisible) {\n break;\n }\n currentWidth -= makeItemInvisible();\n }\n\n // make sure the overflow menu can fit\n if (\n visibleItemQueue.size() > options.minimumVisible &&\n invisibleItemQueue.size() > 0 &&\n currentWidth + overflowMenuOffset > availableSize\n ) {\n makeItemInvisible();\n }\n\n // only update when the state of visible/invisible items has changed\n if (visibleItemQueue.peek() !== visibleTop || invisibleItemQueue.peek() !== invisibleTop) {\n dispatchOverflowUpdate();\n }\n };\n\n const forceUpdate: OverflowManager['forceUpdate'] = () => {\n if (!container) {\n return;\n }\n\n const availableSize = getOffsetSize(container) - options.padding;\n processOverflowItems(availableSize);\n };\n\n const update: OverflowManager['update'] = debounce(forceUpdate);\n\n const observe: OverflowManager['observe'] = (observedContainer, userOptions) => {\n Object.assign(options, userOptions);\n observing = true;\n Object.values(overflowItems).forEach(item => visibleItemQueue.enqueue(item.id));\n\n container = observedContainer;\n resizeObserver.observe(container);\n };\n\n const disconnect: OverflowManager['disconnect'] = () => {\n observing = false;\n resizeObserver.disconnect();\n };\n\n const addItem: OverflowManager['addItem'] = item => {\n if (overflowItems[item.id]) {\n return;\n }\n\n overflowItems[item.id] = item;\n\n // some options can affect priority which are only set on `observe`\n if (observing) {\n visibleItemQueue.enqueue(item.id);\n }\n\n if (item.groupId) {\n if (!overflowGroups[item.groupId]) {\n overflowGroups[item.groupId] = {\n visibleItemIds: new Set<string>(),\n invisibleItemIds: new Set<string>(),\n };\n }\n\n overflowGroups[item.groupId].visibleItemIds.add(item.id);\n }\n\n update();\n };\n\n const addOverflowMenu: OverflowManager['addOverflowMenu'] = el => {\n overflowMenu = el;\n };\n\n const removeOverflowMenu: OverflowManager['removeOverflowMenu'] = () => {\n overflowMenu = undefined;\n };\n\n const removeItem: OverflowManager['removeItem'] = itemId => {\n if (!overflowItems[itemId]) {\n return;\n }\n\n const item = overflowItems[itemId];\n visibleItemQueue.remove(itemId);\n invisibleItemQueue.remove(itemId);\n\n if (item.groupId) {\n overflowGroups[item.groupId].visibleItemIds.delete(item.id);\n overflowGroups[item.groupId].invisibleItemIds.delete(item.id);\n }\n\n delete overflowItems[itemId];\n update();\n };\n\n return {\n addItem,\n disconnect,\n forceUpdate,\n observe,\n removeItem,\n update,\n addOverflowMenu,\n removeOverflowMenu,\n };\n}\n"]}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
define(["require", "exports"], function (require, exports) {
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.createPriorityQueue = void 0;
|
|
5
|
+
/**
|
|
6
|
+
* @param compare - comparison function for items
|
|
7
|
+
* @returns Priority queue implemented with a min heap
|
|
8
|
+
*/
|
|
9
|
+
function createPriorityQueue(compare) {
|
|
10
|
+
var arr = [];
|
|
11
|
+
var size = 0;
|
|
12
|
+
var left = function (i) {
|
|
13
|
+
return 2 * i + 1;
|
|
14
|
+
};
|
|
15
|
+
var right = function (i) {
|
|
16
|
+
return 2 * i + 2;
|
|
17
|
+
};
|
|
18
|
+
var parent = function (i) {
|
|
19
|
+
return Math.floor((i - 1) / 2);
|
|
20
|
+
};
|
|
21
|
+
var swap = function (a, b) {
|
|
22
|
+
var tmp = arr[a];
|
|
23
|
+
arr[a] = arr[b];
|
|
24
|
+
arr[b] = tmp;
|
|
25
|
+
};
|
|
26
|
+
var heapify = function (i) {
|
|
27
|
+
var smallest = i;
|
|
28
|
+
var l = left(i);
|
|
29
|
+
var r = right(i);
|
|
30
|
+
if (l < size && compare(arr[l], arr[smallest]) < 0) {
|
|
31
|
+
smallest = l;
|
|
32
|
+
}
|
|
33
|
+
if (r < size && compare(arr[r], arr[smallest]) < 0) {
|
|
34
|
+
smallest = r;
|
|
35
|
+
}
|
|
36
|
+
if (smallest !== i) {
|
|
37
|
+
swap(smallest, i);
|
|
38
|
+
heapify(smallest);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var dequeue = function () {
|
|
42
|
+
if (size === 0) {
|
|
43
|
+
throw new Error('Priority queue empty');
|
|
44
|
+
}
|
|
45
|
+
var res = arr[0];
|
|
46
|
+
arr[0] = arr[--size];
|
|
47
|
+
heapify(0);
|
|
48
|
+
return res;
|
|
49
|
+
};
|
|
50
|
+
var peek = function () {
|
|
51
|
+
if (size === 0) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
return arr[0];
|
|
55
|
+
};
|
|
56
|
+
var enqueue = function (item) {
|
|
57
|
+
arr[size++] = item;
|
|
58
|
+
var i = size - 1;
|
|
59
|
+
var p = parent(i);
|
|
60
|
+
while (i > 0 && compare(arr[p], arr[i]) > 0) {
|
|
61
|
+
swap(p, i);
|
|
62
|
+
i = p;
|
|
63
|
+
p = parent(i);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var contains = function (item) {
|
|
67
|
+
var index = arr.indexOf(item);
|
|
68
|
+
return index >= 0 && index < size;
|
|
69
|
+
};
|
|
70
|
+
var remove = function (item) {
|
|
71
|
+
var i = arr.indexOf(item);
|
|
72
|
+
if (i === -1 || i >= size) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
arr[i] = arr[--size];
|
|
76
|
+
heapify(i);
|
|
77
|
+
};
|
|
78
|
+
var clear = function () {
|
|
79
|
+
size = 0;
|
|
80
|
+
};
|
|
81
|
+
var all = function () {
|
|
82
|
+
return arr.slice(0, size);
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
all: all,
|
|
86
|
+
clear: clear,
|
|
87
|
+
contains: contains,
|
|
88
|
+
dequeue: dequeue,
|
|
89
|
+
enqueue: enqueue,
|
|
90
|
+
peek: peek,
|
|
91
|
+
remove: remove,
|
|
92
|
+
size: function () { return size; },
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
exports.createPriorityQueue = createPriorityQueue;
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=priorityQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"priorityQueue.js","sourceRoot":"","sources":["../../../../../../../packages/react-components/priority-overflow/src/priorityQueue.ts"],"names":[],"mappings":"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","sourcesContent":["export type PriorityQueueCompareFn<T> = (a: T, b: T) => number;\n\nexport interface PriorityQueue<T> {\n all: () => T[];\n clear: () => void;\n contains: (item: T) => boolean;\n dequeue: () => T;\n enqueue: (item: T) => void;\n peek: () => T | null;\n remove: (item: T) => void;\n size: () => number;\n}\n\n/**\n * @param compare - comparison function for items\n * @returns Priority queue implemented with a min heap\n */\nexport function createPriorityQueue<T>(compare: PriorityQueueCompareFn<T>): PriorityQueue<T> {\n const arr: T[] = [];\n let size = 0;\n\n const left = (i: number) => {\n return 2 * i + 1;\n };\n\n const right = (i: number) => {\n return 2 * i + 2;\n };\n\n const parent = (i: number) => {\n return Math.floor((i - 1) / 2);\n };\n\n const swap = (a: number, b: number) => {\n const tmp = arr[a];\n arr[a] = arr[b];\n arr[b] = tmp;\n };\n\n const heapify = (i: number) => {\n let smallest = i;\n const l = left(i);\n const r = right(i);\n\n if (l < size && compare(arr[l], arr[smallest]) < 0) {\n smallest = l;\n }\n\n if (r < size && compare(arr[r], arr[smallest]) < 0) {\n smallest = r;\n }\n\n if (smallest !== i) {\n swap(smallest, i);\n heapify(smallest);\n }\n };\n\n const dequeue = () => {\n if (size === 0) {\n throw new Error('Priority queue empty');\n }\n\n const res = arr[0];\n arr[0] = arr[--size];\n heapify(0);\n\n return res;\n };\n\n const peek = () => {\n if (size === 0) {\n return null;\n }\n\n return arr[0];\n };\n\n const enqueue = (item: T) => {\n arr[size++] = item;\n let i = size - 1;\n let p = parent(i);\n while (i > 0 && compare(arr[p], arr[i]) > 0) {\n swap(p, i);\n i = p;\n p = parent(i);\n }\n };\n\n const contains = (item: T) => {\n const index = arr.indexOf(item);\n return index >= 0 && index < size;\n };\n\n const remove = (item: T) => {\n const i = arr.indexOf(item);\n\n if (i === -1 || i >= size) {\n return;\n }\n\n arr[i] = arr[--size];\n heapify(i);\n };\n\n const clear = () => {\n size = 0;\n };\n\n const all = () => {\n return arr.slice(0, size);\n };\n\n return {\n all,\n clear,\n contains,\n dequeue,\n enqueue,\n peek,\n remove,\n size: () => size,\n };\n}\n"]}
|
package/lib-amd/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../packages/react-components/priority-overflow/src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type OverflowDirection = 'start' | 'end';\nexport type OverflowAxis = 'horizontal' | 'vertical';\nexport type OverflowGroupState = 'visible' | 'hidden' | 'overflow';\nexport interface OverflowItemEntry {\n /**\n * HTML element that will be disappear when overflowed\n */\n element: HTMLElement;\n /**\n * Lower priority items are invisible first when the container is overflowed\n * @default 0\n */\n priority: number;\n /**\n * Specific id, used to track visibility and provide updates to consumers\n */\n id: string;\n\n groupId?: string;\n}\n\n/**\n * signature similar to standard event listeners, but typed to handle the custom event\n */\nexport type OnUpdateOverflow = (data: OverflowEventPayload) => void;\n\nexport type OnUpdateItemVisibility = (data: OnUpdateItemVisibilityPayload) => void;\n\n/**\n * Payload of the custom DOM event for overflow updates\n */\nexport interface OverflowEventPayload {\n visibleItems: OverflowItemEntry[];\n invisibleItems: OverflowItemEntry[];\n groupVisibility: Record<string, OverflowGroupState>;\n}\n\nexport interface OnUpdateItemVisibilityPayload {\n item: OverflowItemEntry;\n visible: boolean;\n}\n\nexport interface ObserveOptions {\n /**\n * Padding (in px) at the end of the container before overflow occurs\n * Useful to account for extra elements (i.e. dropdown menu)\n * or to account for any kinds of margins between items which are hard to measure with JS\n * @default 10\n */\n padding?: number;\n /**\n * Direction where items are removed when overflow occurs\n * @default end\n */\n overflowDirection?: OverflowDirection;\n\n /**\n * Horizontal or vertical overflow\n * @default horizontal\n */\n overflowAxis?: OverflowAxis;\n\n /**\n * The minimum number of visible items\n */\n minimumVisible?: number;\n\n /**\n * Callback when item visibility is updated\n */\n onUpdateItemVisibility: OnUpdateItemVisibility;\n\n /**\n * Callback when item visibility is updated\n */\n onUpdateOverflow: OnUpdateOverflow;\n}\n\n/**\n * @internal\n */\nexport interface OverflowManager {\n /**\n * Starts observing the container and managing the overflow state\n */\n observe: (container: HTMLElement, options: ObserveOptions) => void;\n /**\n * Stops observing the container\n */\n disconnect: () => void;\n /**\n * Add overflow items\n */\n addItem: (items: OverflowItemEntry) => void;\n /**\n * Remove overflow item\n */\n removeItem: (itemId: string) => void;\n /**\n * Manually update the overflow, updates are batched and async\n */\n update: () => void;\n /**\n * Manually update the overflow sync\n */\n forceUpdate: () => void;\n\n /**\n * Adds an element that opens an overflow menu. This is used to calculate\n * available space and check if additional items need to overflow\n */\n addOverflowMenu: (element: HTMLElement) => void;\n\n /**\n * Unsets the overflow menu element\n */\n removeOverflowMenu: () => void;\n}\n"]}
|
package/lib-commonjs/debounce.js
CHANGED
|
@@ -10,7 +10,6 @@ exports.debounce = void 0;
|
|
|
10
10
|
* @param fn - Function to debounce
|
|
11
11
|
* @returns debounced function
|
|
12
12
|
*/
|
|
13
|
-
|
|
14
13
|
function debounce(fn) {
|
|
15
14
|
let pending;
|
|
16
15
|
return () => {
|
|
@@ -25,6 +24,5 @@ function debounce(fn) {
|
|
|
25
24
|
}
|
|
26
25
|
};
|
|
27
26
|
}
|
|
28
|
-
|
|
29
27
|
exports.debounce = debounce;
|
|
30
28
|
//# sourceMappingURL=debounce.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"mappings":";;;;;;AAAA;;;;;;AAMA,SAAgBA,QAAQ,CAACC,EAAY;EACnC,IAAIC,OAAgB;EACpB,OAAO,MAAK;IACV,IAAI,CAACA,OAAO,EAAE;MACZA,OAAO,GAAG,IAAI;MACdC,cAAc,CAAC,MAAK;QAClB;QACA;QACAD,OAAO,GAAG,KAAK;QACfD,EAAE,EAAE;MACN,CAAC,CAAC;;EAEN,CAAC;AACH;AAbAG","names":["debounce","fn","pending","queueMicrotask","exports"],"sourceRoot":"../src/","sources":["packages/react-components/priority-overflow/src/debounce.ts"],"sourcesContent":["/**\n * Microtask debouncer\n * https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide\n * @param fn - Function to debounce\n * @returns debounced function\n */\nexport function debounce(fn: Function) {\n let pending: boolean;\n return () => {\n if (!pending) {\n pending = true;\n queueMicrotask(() => {\n // Need to set pending to `false` before the debounced function is run.\n // React can actually interrupt the function while it's running!\n pending = false;\n fn();\n });\n }\n };\n}\n"]}
|
package/lib-commonjs/index.js
CHANGED
|
@@ -4,9 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.createOverflowManager = void 0;
|
|
7
|
-
|
|
8
7
|
var overflowManager_1 = /*#__PURE__*/require("./overflowManager");
|
|
9
|
-
|
|
10
8
|
Object.defineProperty(exports, "createOverflowManager", {
|
|
11
9
|
enumerable: true,
|
|
12
10
|
get: function () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["packages/react-components/priority-overflow/src/index.ts"],"
|
|
1
|
+
{"version":3,"mappings":";;;;;;AAAA;AAASA;EAAAC;EAAAC;IAAA,8CAAqB;EAAA;AAAA","names":["Object","enumerable","get"],"sourceRoot":"../src/","sources":["packages/react-components/priority-overflow/src/index.ts"],"sourcesContent":["export { createOverflowManager } from './overflowManager';\nexport type {\n ObserveOptions,\n OnUpdateItemVisibility,\n OnUpdateItemVisibilityPayload,\n OnUpdateOverflow,\n OverflowAxis,\n OverflowDirection,\n OverflowEventPayload,\n OverflowGroupState,\n OverflowItemEntry,\n OverflowManager,\n} from './types';\n"]}
|
|
@@ -4,16 +4,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.createOverflowManager = void 0;
|
|
7
|
-
|
|
8
7
|
const debounce_1 = /*#__PURE__*/require("./debounce");
|
|
9
|
-
|
|
10
8
|
const priorityQueue_1 = /*#__PURE__*/require("./priorityQueue");
|
|
11
9
|
/**
|
|
12
10
|
* @internal
|
|
13
11
|
* @returns overflow manager instance
|
|
14
12
|
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
13
|
function createOverflowManager() {
|
|
18
14
|
let container;
|
|
19
15
|
let overflowMenu;
|
|
@@ -32,44 +28,37 @@ function createOverflowManager() {
|
|
|
32
28
|
if (!entries[0] || !container) {
|
|
33
29
|
return;
|
|
34
30
|
}
|
|
35
|
-
|
|
36
31
|
update();
|
|
37
32
|
});
|
|
38
33
|
const invisibleItemQueue = priorityQueue_1.createPriorityQueue((a, b) => {
|
|
39
34
|
const itemA = overflowItems[a];
|
|
40
|
-
const itemB = overflowItems[b];
|
|
41
|
-
|
|
35
|
+
const itemB = overflowItems[b];
|
|
36
|
+
// Higher priority at the top of the queue
|
|
42
37
|
const priority = itemB.priority - itemA.priority;
|
|
43
|
-
|
|
44
38
|
if (priority !== 0) {
|
|
45
39
|
return priority;
|
|
46
40
|
}
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
const positionStatusBit = options.overflowDirection === 'end' ? Node.DOCUMENT_POSITION_FOLLOWING : Node.DOCUMENT_POSITION_PRECEDING;
|
|
42
|
+
// equal priority, use DOM order
|
|
49
43
|
// eslint-disable-next-line no-bitwise
|
|
50
|
-
|
|
51
44
|
return itemA.element.compareDocumentPosition(itemB.element) & positionStatusBit ? -1 : 1;
|
|
52
45
|
});
|
|
53
46
|
const visibleItemQueue = priorityQueue_1.createPriorityQueue((a, b) => {
|
|
54
47
|
const itemA = overflowItems[a];
|
|
55
|
-
const itemB = overflowItems[b];
|
|
56
|
-
|
|
48
|
+
const itemB = overflowItems[b];
|
|
49
|
+
// Lower priority at the top of the queue
|
|
57
50
|
const priority = itemA.priority - itemB.priority;
|
|
58
|
-
|
|
59
51
|
if (priority !== 0) {
|
|
60
52
|
return priority;
|
|
61
53
|
}
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
const positionStatusBit = options.overflowDirection === 'end' ? Node.DOCUMENT_POSITION_PRECEDING : Node.DOCUMENT_POSITION_FOLLOWING;
|
|
55
|
+
// equal priority, use DOM order
|
|
64
56
|
// eslint-disable-next-line no-bitwise
|
|
65
|
-
|
|
66
57
|
return itemA.element.compareDocumentPosition(itemB.element) & positionStatusBit ? -1 : 1;
|
|
67
58
|
});
|
|
68
|
-
|
|
69
59
|
const getOffsetSize = el => {
|
|
70
60
|
return options.overflowAxis === 'horizontal' ? el.offsetWidth : el.offsetHeight;
|
|
71
61
|
};
|
|
72
|
-
|
|
73
62
|
const makeItemVisible = () => {
|
|
74
63
|
const nextVisible = invisibleItemQueue.dequeue();
|
|
75
64
|
visibleItemQueue.enqueue(nextVisible);
|
|
@@ -78,15 +67,12 @@ function createOverflowManager() {
|
|
|
78
67
|
item,
|
|
79
68
|
visible: true
|
|
80
69
|
});
|
|
81
|
-
|
|
82
70
|
if (item.groupId) {
|
|
83
71
|
overflowGroups[item.groupId].invisibleItemIds.delete(item.id);
|
|
84
72
|
overflowGroups[item.groupId].visibleItemIds.add(item.id);
|
|
85
73
|
}
|
|
86
|
-
|
|
87
74
|
return getOffsetSize(item.element);
|
|
88
75
|
};
|
|
89
|
-
|
|
90
76
|
const makeItemInvisible = () => {
|
|
91
77
|
const nextInvisible = visibleItemQueue.dequeue();
|
|
92
78
|
invisibleItemQueue.enqueue(nextInvisible);
|
|
@@ -96,15 +82,12 @@ function createOverflowManager() {
|
|
|
96
82
|
item,
|
|
97
83
|
visible: false
|
|
98
84
|
});
|
|
99
|
-
|
|
100
85
|
if (item.groupId) {
|
|
101
86
|
overflowGroups[item.groupId].visibleItemIds.delete(item.id);
|
|
102
87
|
overflowGroups[item.groupId].invisibleItemIds.add(item.id);
|
|
103
88
|
}
|
|
104
|
-
|
|
105
89
|
return width;
|
|
106
90
|
};
|
|
107
|
-
|
|
108
91
|
const dispatchOverflowUpdate = () => {
|
|
109
92
|
const visibleItemIds = visibleItemQueue.all();
|
|
110
93
|
const invisibleItemIds = invisibleItemQueue.all();
|
|
@@ -126,56 +109,47 @@ function createOverflowManager() {
|
|
|
126
109
|
groupVisibility
|
|
127
110
|
});
|
|
128
111
|
};
|
|
129
|
-
|
|
130
112
|
const processOverflowItems = availableSize => {
|
|
131
113
|
if (!container) {
|
|
132
114
|
return;
|
|
133
115
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
116
|
+
const overflowMenuOffset = overflowMenu ? getOffsetSize(overflowMenu) : 0;
|
|
117
|
+
// Snapshot of the visible/invisible state to compare for updates
|
|
137
118
|
const visibleTop = visibleItemQueue.peek();
|
|
138
119
|
const invisibleTop = invisibleItemQueue.peek();
|
|
139
120
|
const visibleItemIds = visibleItemQueue.all();
|
|
140
121
|
let currentWidth = visibleItemIds.reduce((sum, visibleItemId) => {
|
|
141
122
|
const child = overflowItems[visibleItemId].element;
|
|
142
123
|
return sum + getOffsetSize(child);
|
|
143
|
-
}, 0);
|
|
144
|
-
|
|
124
|
+
}, 0);
|
|
125
|
+
// Add items until available width is filled - can result in overflow
|
|
145
126
|
while (currentWidth < availableSize && invisibleItemQueue.size() > 0) {
|
|
146
127
|
currentWidth += makeItemVisible();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
128
|
+
}
|
|
129
|
+
// Remove items until there's no more overflow
|
|
150
130
|
while (currentWidth > availableSize && visibleItemQueue.size() > 0) {
|
|
151
|
-
if (visibleItemQueue.size()
|
|
131
|
+
if (visibleItemQueue.size() <= options.minimumVisible) {
|
|
152
132
|
break;
|
|
153
133
|
}
|
|
154
|
-
|
|
155
134
|
currentWidth -= makeItemInvisible();
|
|
156
135
|
}
|
|
157
|
-
|
|
158
|
-
if (invisibleItemQueue.size() > 0 && currentWidth + overflowMenuOffset > availableSize) {
|
|
136
|
+
// make sure the overflow menu can fit
|
|
137
|
+
if (visibleItemQueue.size() > options.minimumVisible && invisibleItemQueue.size() > 0 && currentWidth + overflowMenuOffset > availableSize) {
|
|
159
138
|
makeItemInvisible();
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
139
|
+
}
|
|
140
|
+
// only update when the state of visible/invisible items has changed
|
|
163
141
|
if (visibleItemQueue.peek() !== visibleTop || invisibleItemQueue.peek() !== invisibleTop) {
|
|
164
142
|
dispatchOverflowUpdate();
|
|
165
143
|
}
|
|
166
144
|
};
|
|
167
|
-
|
|
168
145
|
const forceUpdate = () => {
|
|
169
146
|
if (!container) {
|
|
170
147
|
return;
|
|
171
148
|
}
|
|
172
|
-
|
|
173
149
|
const availableSize = getOffsetSize(container) - options.padding;
|
|
174
150
|
processOverflowItems(availableSize);
|
|
175
151
|
};
|
|
176
|
-
|
|
177
152
|
const update = debounce_1.debounce(forceUpdate);
|
|
178
|
-
|
|
179
153
|
const observe = (observedContainer, userOptions) => {
|
|
180
154
|
Object.assign(options, userOptions);
|
|
181
155
|
observing = true;
|
|
@@ -183,23 +157,19 @@ function createOverflowManager() {
|
|
|
183
157
|
container = observedContainer;
|
|
184
158
|
resizeObserver.observe(container);
|
|
185
159
|
};
|
|
186
|
-
|
|
187
160
|
const disconnect = () => {
|
|
188
161
|
observing = false;
|
|
189
162
|
resizeObserver.disconnect();
|
|
190
163
|
};
|
|
191
|
-
|
|
192
164
|
const addItem = item => {
|
|
193
165
|
if (overflowItems[item.id]) {
|
|
194
166
|
return;
|
|
195
167
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
168
|
+
overflowItems[item.id] = item;
|
|
169
|
+
// some options can affect priority which are only set on `observe`
|
|
199
170
|
if (observing) {
|
|
200
171
|
visibleItemQueue.enqueue(item.id);
|
|
201
172
|
}
|
|
202
|
-
|
|
203
173
|
if (item.groupId) {
|
|
204
174
|
if (!overflowGroups[item.groupId]) {
|
|
205
175
|
overflowGroups[item.groupId] = {
|
|
@@ -207,39 +177,30 @@ function createOverflowManager() {
|
|
|
207
177
|
invisibleItemIds: new Set()
|
|
208
178
|
};
|
|
209
179
|
}
|
|
210
|
-
|
|
211
180
|
overflowGroups[item.groupId].visibleItemIds.add(item.id);
|
|
212
181
|
}
|
|
213
|
-
|
|
214
182
|
update();
|
|
215
183
|
};
|
|
216
|
-
|
|
217
184
|
const addOverflowMenu = el => {
|
|
218
185
|
overflowMenu = el;
|
|
219
186
|
};
|
|
220
|
-
|
|
221
187
|
const removeOverflowMenu = () => {
|
|
222
188
|
overflowMenu = undefined;
|
|
223
189
|
};
|
|
224
|
-
|
|
225
190
|
const removeItem = itemId => {
|
|
226
191
|
if (!overflowItems[itemId]) {
|
|
227
192
|
return;
|
|
228
193
|
}
|
|
229
|
-
|
|
230
194
|
const item = overflowItems[itemId];
|
|
231
195
|
visibleItemQueue.remove(itemId);
|
|
232
196
|
invisibleItemQueue.remove(itemId);
|
|
233
|
-
|
|
234
197
|
if (item.groupId) {
|
|
235
198
|
overflowGroups[item.groupId].visibleItemIds.delete(item.id);
|
|
236
199
|
overflowGroups[item.groupId].invisibleItemIds.delete(item.id);
|
|
237
200
|
}
|
|
238
|
-
|
|
239
201
|
delete overflowItems[itemId];
|
|
240
202
|
update();
|
|
241
203
|
};
|
|
242
|
-
|
|
243
204
|
return {
|
|
244
205
|
addItem,
|
|
245
206
|
disconnect,
|
|
@@ -251,6 +212,5 @@ function createOverflowManager() {
|
|
|
251
212
|
removeOverflowMenu
|
|
252
213
|
};
|
|
253
214
|
}
|
|
254
|
-
|
|
255
215
|
exports.createOverflowManager = createOverflowManager;
|
|
256
216
|
//# sourceMappingURL=overflowManager.js.map
|