@fluentui/priority-overflow 9.0.0-rc.1 → 9.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|