@fluentui/priority-overflow 0.0.0-nightly-20220511-0419.1
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.json +26 -0
- package/CHANGELOG.md +14 -0
- package/LICENSE +15 -0
- package/README.md +5 -0
- package/dist/index.d.ts +109 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/lib/debounce.js +21 -0
- package/lib/debounce.js.map +1 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/lib/overflowManager.js +213 -0
- package/lib/overflowManager.js.map +1 -0
- package/lib/priorityQueue.js +111 -0
- package/lib/priorityQueue.js.map +1 -0
- package/lib/types.js +2 -0
- package/lib/types.js.map +1 -0
- package/lib-commonjs/debounce.js +30 -0
- package/lib-commonjs/debounce.js.map +1 -0
- package/lib-commonjs/index.js +16 -0
- package/lib-commonjs/index.js.map +1 -0
- package/lib-commonjs/overflowManager.js +224 -0
- package/lib-commonjs/overflowManager.js.map +1 -0
- package/lib-commonjs/priorityQueue.js +120 -0
- package/lib-commonjs/priorityQueue.js.map +1 -0
- package/lib-commonjs/types.js +6 -0
- package/lib-commonjs/types.js.map +1 -0
- package/package.json +40 -0
package/CHANGELOG.json
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"name": "@fluentui/priority-overflow",
|
3
|
+
"entries": [
|
4
|
+
{
|
5
|
+
"date": "Wed, 11 May 2022 04:31:11 GMT",
|
6
|
+
"tag": "@fluentui/priority-overflow_v0.0.0-nightly-20220511-0419.1",
|
7
|
+
"version": "0.0.0-nightly-20220511-0419.1",
|
8
|
+
"comments": {
|
9
|
+
"prerelease": [
|
10
|
+
{
|
11
|
+
"author": "email not defined",
|
12
|
+
"package": "@fluentui/priority-overflow",
|
13
|
+
"commit": "not available",
|
14
|
+
"comment": "Release nightly v9"
|
15
|
+
},
|
16
|
+
{
|
17
|
+
"author": "lingfangao@hotmail.com",
|
18
|
+
"package": "@fluentui/priority-overflow",
|
19
|
+
"commit": "4ae08d6ecf85ac29593ddc2abb23f8a073711b38",
|
20
|
+
"comment": "feat: Initial beta release"
|
21
|
+
}
|
22
|
+
]
|
23
|
+
}
|
24
|
+
}
|
25
|
+
]
|
26
|
+
}
|
package/CHANGELOG.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Change Log - @fluentui/priority-overflow
|
2
|
+
|
3
|
+
This log was last generated on Wed, 11 May 2022 04:31:11 GMT and should not be manually modified.
|
4
|
+
|
5
|
+
<!-- Start content -->
|
6
|
+
|
7
|
+
## [0.0.0-nightly-20220511-0419.1](https://github.com/microsoft/fluentui/tree/@fluentui/priority-overflow_v0.0.0-nightly-20220511-0419.1)
|
8
|
+
|
9
|
+
Wed, 11 May 2022 04:31:11 GMT
|
10
|
+
|
11
|
+
### Changes
|
12
|
+
|
13
|
+
- Release nightly v9 ([commit](https://github.com/microsoft/fluentui/commit/not available) by email not defined)
|
14
|
+
- feat: Initial beta release ([PR #22913](https://github.com/microsoft/fluentui/pull/22913) by lingfangao@hotmail.com)
|
package/LICENSE
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
@fluentui/priority-overflow
|
2
|
+
|
3
|
+
Copyright (c) Microsoft Corporation
|
4
|
+
|
5
|
+
All rights reserved.
|
6
|
+
|
7
|
+
MIT License
|
8
|
+
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
14
|
+
|
15
|
+
Note: Usage of the fonts and icons referenced in Fluent UI React is subject to the terms listed at https://aka.ms/fluentui-assets-license
|
package/README.md
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
# @fluentui/priority-overflow
|
2
|
+
|
3
|
+
**Priority Overflow components for [Fluent UI React](https://developer.microsoft.com/en-us/fluentui)**
|
4
|
+
|
5
|
+
These are not production-ready components and **should never be used in product**. This space is useful for testing new components whose APIs might change before final release.
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
/**
|
2
|
+
* @returns overflow manager instance
|
3
|
+
*/
|
4
|
+
export declare function createOverflowManager(): OverflowManager;
|
5
|
+
|
6
|
+
export declare interface ObserveOptions {
|
7
|
+
/**
|
8
|
+
* Padding (in px) at the end of the container before overflow occurs
|
9
|
+
* Useful to account for extra elements (i.e. dropdown menu)
|
10
|
+
* or to account for any kinds of margins between items which are hard to measure with JS
|
11
|
+
* @default 10
|
12
|
+
*/
|
13
|
+
padding?: number;
|
14
|
+
/**
|
15
|
+
* Direction where items are removed when overflow occurs
|
16
|
+
* @default end
|
17
|
+
*/
|
18
|
+
overflowDirection?: OverflowDirection;
|
19
|
+
/**
|
20
|
+
* Horizontal or vertical overflow
|
21
|
+
* @default horizontal
|
22
|
+
*/
|
23
|
+
overflowAxis?: OverflowAxis;
|
24
|
+
/**
|
25
|
+
* The minimum number of visible items
|
26
|
+
*/
|
27
|
+
minimumVisible?: number;
|
28
|
+
/**
|
29
|
+
* Callback when item visibility is updated
|
30
|
+
*/
|
31
|
+
onUpdateItemVisibility: OnUpdateItemVisibility;
|
32
|
+
/**
|
33
|
+
* Callback when item visibility is updated
|
34
|
+
*/
|
35
|
+
onUpdateOverflow: OnUpdateOverflow;
|
36
|
+
}
|
37
|
+
|
38
|
+
export declare type OnUpdateItemVisibility = (data: OnUpdateItemVisibilityPayload) => void;
|
39
|
+
|
40
|
+
export declare interface OnUpdateItemVisibilityPayload {
|
41
|
+
item: OverflowItemEntry;
|
42
|
+
visible: boolean;
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* signature similar to standard event listeners, but typed to handle the custom event
|
47
|
+
*/
|
48
|
+
export declare type OnUpdateOverflow = (data: OverflowEventPayload) => void;
|
49
|
+
|
50
|
+
export declare type OverflowAxis = 'horizontal' | 'vertical';
|
51
|
+
|
52
|
+
export declare type OverflowDirection = 'start' | 'end';
|
53
|
+
|
54
|
+
/**
|
55
|
+
* Payload of the custom DOM event for overflow updates
|
56
|
+
*/
|
57
|
+
export declare interface OverflowEventPayload {
|
58
|
+
visibleItems: OverflowItemEntry[];
|
59
|
+
invisibleItems: OverflowItemEntry[];
|
60
|
+
groupVisibility: Record<string, OverflowGroupState>;
|
61
|
+
}
|
62
|
+
|
63
|
+
export declare type OverflowGroupState = 'visible' | 'hidden' | 'overflow';
|
64
|
+
|
65
|
+
export declare interface OverflowItemEntry {
|
66
|
+
/**
|
67
|
+
* HTML element that will be disappear when overflowed
|
68
|
+
*/
|
69
|
+
element: HTMLElement;
|
70
|
+
/**
|
71
|
+
* Lower priority items are invisible first when the container is overflowed
|
72
|
+
* @default 0
|
73
|
+
*/
|
74
|
+
priority: number;
|
75
|
+
/**
|
76
|
+
* Specific id, used to track visibility and provide updates to consumers
|
77
|
+
*/
|
78
|
+
id: string;
|
79
|
+
groupId?: string;
|
80
|
+
}
|
81
|
+
|
82
|
+
export declare interface OverflowManager {
|
83
|
+
/**
|
84
|
+
* Starts observing the container and managing the overflow state
|
85
|
+
*/
|
86
|
+
observe: (container: HTMLElement, options: ObserveOptions) => void;
|
87
|
+
/**
|
88
|
+
* Stops observing the container
|
89
|
+
*/
|
90
|
+
disconnect: () => void;
|
91
|
+
/**
|
92
|
+
* Add overflow items
|
93
|
+
*/
|
94
|
+
addItem: (items: OverflowItemEntry) => void;
|
95
|
+
/**
|
96
|
+
* Remove overflow item
|
97
|
+
*/
|
98
|
+
removeItem: (itemId: string) => void;
|
99
|
+
/**
|
100
|
+
* Manually update the overflow, updates are batched and async
|
101
|
+
*/
|
102
|
+
update: () => void;
|
103
|
+
/**
|
104
|
+
* Manually update the overflow sync
|
105
|
+
*/
|
106
|
+
forceUpdate: () => void;
|
107
|
+
}
|
108
|
+
|
109
|
+
export { }
|
@@ -0,0 +1,11 @@
|
|
1
|
+
// This file is read by tools that parse documentation comments conforming to the TSDoc standard.
|
2
|
+
// It should be published with your NPM package. It should not be tracked by Git.
|
3
|
+
{
|
4
|
+
"tsdocVersion": "0.12",
|
5
|
+
"toolPackages": [
|
6
|
+
{
|
7
|
+
"packageName": "@microsoft/api-extractor",
|
8
|
+
"packageVersion": "7.18.1"
|
9
|
+
}
|
10
|
+
]
|
11
|
+
}
|
package/lib/debounce.js
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
/**
|
2
|
+
* Microtask debouncer
|
3
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide
|
4
|
+
* @param fn - Function to debounce
|
5
|
+
* @returns debounced function
|
6
|
+
*/
|
7
|
+
export function debounce(fn) {
|
8
|
+
let pending;
|
9
|
+
return () => {
|
10
|
+
if (!pending) {
|
11
|
+
pending = true;
|
12
|
+
queueMicrotask(() => {
|
13
|
+
// Need to set pending to `false` before the debounced function is run.
|
14
|
+
// React can actually interrupt the function while it's running!
|
15
|
+
pending = false;
|
16
|
+
fn();
|
17
|
+
});
|
18
|
+
}
|
19
|
+
};
|
20
|
+
}
|
21
|
+
//# sourceMappingURL=debounce.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["debounce.ts"],"names":[],"mappings":"AAAA;;;;;AAKG;AACH,OAAM,SAAU,QAAV,CAAmB,EAAnB,EAA+B;AACnC,MAAI,OAAJ;AACA,SAAO,MAAK;AACV,QAAI,CAAC,OAAL,EAAc;AACZ,MAAA,OAAO,GAAG,IAAV;AACA,MAAA,cAAc,CAAC,MAAK;AAClB;AACA;AACA,QAAA,OAAO,GAAG,KAAV;AACA,QAAA,EAAE;AACH,OALa,CAAd;AAMD;AACF,GAVD;AAWD","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"],"sourceRoot":"../src/"}
|
package/lib/index.js
ADDED
package/lib/index.js.map
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"../src/","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC","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"]}
|
@@ -0,0 +1,213 @@
|
|
1
|
+
import { debounce } from './debounce';
|
2
|
+
import { createPriorityQueue } from './priorityQueue';
|
3
|
+
/**
|
4
|
+
* @returns overflow manager instance
|
5
|
+
*/
|
6
|
+
|
7
|
+
export function createOverflowManager() {
|
8
|
+
let container;
|
9
|
+
const options = {
|
10
|
+
padding: 10,
|
11
|
+
overflowAxis: 'horizontal',
|
12
|
+
overflowDirection: 'end',
|
13
|
+
minimumVisible: 0,
|
14
|
+
onUpdateItemVisibility: () => undefined,
|
15
|
+
onUpdateOverflow: () => undefined
|
16
|
+
};
|
17
|
+
const overflowItems = {};
|
18
|
+
const overflowGroups = {};
|
19
|
+
const resizeObserver = new ResizeObserver(entries => {
|
20
|
+
if (!entries[0] || !container) {
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
|
24
|
+
update();
|
25
|
+
});
|
26
|
+
const invisibleItemQueue = createPriorityQueue((a, b) => {
|
27
|
+
const itemA = overflowItems[a];
|
28
|
+
const itemB = overflowItems[b]; // Higher priority at the top of the queue
|
29
|
+
|
30
|
+
const priority = itemB.priority - itemA.priority;
|
31
|
+
|
32
|
+
if (priority !== 0) {
|
33
|
+
return priority;
|
34
|
+
}
|
35
|
+
|
36
|
+
const positionStatusBit = options.overflowDirection === 'end' ? Node.DOCUMENT_POSITION_FOLLOWING : Node.DOCUMENT_POSITION_PRECEDING; // equal priority, use DOM order
|
37
|
+
// eslint-disable-next-line no-bitwise
|
38
|
+
|
39
|
+
return itemA.element.compareDocumentPosition(itemB.element) & positionStatusBit ? -1 : 1;
|
40
|
+
});
|
41
|
+
const visibleItemQueue = createPriorityQueue((a, b) => {
|
42
|
+
const itemA = overflowItems[a];
|
43
|
+
const itemB = overflowItems[b]; // Lower priority at the top of the queue
|
44
|
+
|
45
|
+
const priority = itemA.priority - itemB.priority;
|
46
|
+
|
47
|
+
if (priority !== 0) {
|
48
|
+
return priority;
|
49
|
+
}
|
50
|
+
|
51
|
+
const positionStatusBit = options.overflowDirection === 'end' ? Node.DOCUMENT_POSITION_PRECEDING : Node.DOCUMENT_POSITION_FOLLOWING; // equal priority, use DOM order
|
52
|
+
// eslint-disable-next-line no-bitwise
|
53
|
+
|
54
|
+
return itemA.element.compareDocumentPosition(itemB.element) & positionStatusBit ? -1 : 1;
|
55
|
+
});
|
56
|
+
|
57
|
+
const getOffsetSize = el => {
|
58
|
+
return options.overflowAxis === 'horizontal' ? el.offsetWidth : el.offsetHeight;
|
59
|
+
};
|
60
|
+
|
61
|
+
const makeItemVisible = () => {
|
62
|
+
const nextVisible = invisibleItemQueue.dequeue();
|
63
|
+
visibleItemQueue.enqueue(nextVisible);
|
64
|
+
const item = overflowItems[nextVisible];
|
65
|
+
options.onUpdateItemVisibility({
|
66
|
+
item,
|
67
|
+
visible: true
|
68
|
+
});
|
69
|
+
|
70
|
+
if (item.groupId) {
|
71
|
+
overflowGroups[item.groupId].invisibleItemIds.delete(item.id);
|
72
|
+
overflowGroups[item.groupId].visibleItemIds.add(item.id);
|
73
|
+
}
|
74
|
+
|
75
|
+
return getOffsetSize(item.element);
|
76
|
+
};
|
77
|
+
|
78
|
+
const makeItemInvisible = () => {
|
79
|
+
const nextInvisible = visibleItemQueue.dequeue();
|
80
|
+
invisibleItemQueue.enqueue(nextInvisible);
|
81
|
+
const item = overflowItems[nextInvisible];
|
82
|
+
const width = getOffsetSize(item.element);
|
83
|
+
options.onUpdateItemVisibility({
|
84
|
+
item,
|
85
|
+
visible: false
|
86
|
+
});
|
87
|
+
|
88
|
+
if (item.groupId) {
|
89
|
+
overflowGroups[item.groupId].visibleItemIds.delete(item.id);
|
90
|
+
overflowGroups[item.groupId].invisibleItemIds.add(item.id);
|
91
|
+
}
|
92
|
+
|
93
|
+
return width;
|
94
|
+
};
|
95
|
+
|
96
|
+
const dispatchOverflowUpdate = () => {
|
97
|
+
const visibleItemIds = visibleItemQueue.all();
|
98
|
+
const invisibleItemIds = invisibleItemQueue.all();
|
99
|
+
const visibleItems = visibleItemIds.map(itemId => overflowItems[itemId]);
|
100
|
+
const invisibleItems = invisibleItemIds.map(itemId => overflowItems[itemId]);
|
101
|
+
const groupVisibility = {};
|
102
|
+
Object.entries(overflowGroups).forEach(([groupId, groupState]) => {
|
103
|
+
if (groupState.invisibleItemIds.size && groupState.visibleItemIds.size) {
|
104
|
+
groupVisibility[groupId] = 'overflow';
|
105
|
+
} else if (groupState.visibleItemIds.size === 0) {
|
106
|
+
groupVisibility[groupId] = 'hidden';
|
107
|
+
} else {
|
108
|
+
groupVisibility[groupId] = 'visible';
|
109
|
+
}
|
110
|
+
});
|
111
|
+
options.onUpdateOverflow({
|
112
|
+
visibleItems,
|
113
|
+
invisibleItems,
|
114
|
+
groupVisibility
|
115
|
+
});
|
116
|
+
};
|
117
|
+
|
118
|
+
const processOverflowItems = availableSize => {
|
119
|
+
if (!container) {
|
120
|
+
return;
|
121
|
+
} // Snapshot of the visible/invisible state to compare for updates
|
122
|
+
|
123
|
+
|
124
|
+
const visibleTop = visibleItemQueue.peek();
|
125
|
+
const invisibleTop = invisibleItemQueue.peek();
|
126
|
+
const visibleItemIds = visibleItemQueue.all();
|
127
|
+
let currentWidth = visibleItemIds.reduce((sum, visibleItemId) => {
|
128
|
+
const child = overflowItems[visibleItemId].element;
|
129
|
+
return sum + getOffsetSize(child);
|
130
|
+
}, 0); // Add items until available width is filled
|
131
|
+
|
132
|
+
while (currentWidth < availableSize && invisibleItemQueue.size() > 0) {
|
133
|
+
currentWidth += makeItemVisible();
|
134
|
+
} // Remove items until there's no more overlap
|
135
|
+
|
136
|
+
|
137
|
+
while (currentWidth > availableSize && visibleItemQueue.size() > 0) {
|
138
|
+
if (visibleItemQueue.size() === options.minimumVisible) {
|
139
|
+
break;
|
140
|
+
}
|
141
|
+
|
142
|
+
currentWidth -= makeItemInvisible();
|
143
|
+
} // only update when the state of visible/invisible items has changed
|
144
|
+
|
145
|
+
|
146
|
+
if (visibleItemQueue.peek() !== visibleTop || invisibleItemQueue.peek() !== invisibleTop) {
|
147
|
+
dispatchOverflowUpdate();
|
148
|
+
}
|
149
|
+
};
|
150
|
+
|
151
|
+
const forceUpdate = () => {
|
152
|
+
if (!container) {
|
153
|
+
return;
|
154
|
+
}
|
155
|
+
|
156
|
+
const availableSize = getOffsetSize(container) - options.padding;
|
157
|
+
processOverflowItems(availableSize);
|
158
|
+
};
|
159
|
+
|
160
|
+
const update = debounce(forceUpdate);
|
161
|
+
|
162
|
+
const observe = (observedContainer, userOptions) => {
|
163
|
+
Object.assign(options, userOptions);
|
164
|
+
container = observedContainer;
|
165
|
+
resizeObserver.observe(container);
|
166
|
+
};
|
167
|
+
|
168
|
+
const disconnect = () => {
|
169
|
+
resizeObserver.disconnect();
|
170
|
+
};
|
171
|
+
|
172
|
+
const addItem = item => {
|
173
|
+
overflowItems[item.id] = item;
|
174
|
+
visibleItemQueue.enqueue(item.id);
|
175
|
+
|
176
|
+
if (item.groupId) {
|
177
|
+
if (!overflowGroups[item.groupId]) {
|
178
|
+
overflowGroups[item.groupId] = {
|
179
|
+
visibleItemIds: new Set(),
|
180
|
+
invisibleItemIds: new Set()
|
181
|
+
};
|
182
|
+
}
|
183
|
+
|
184
|
+
overflowGroups[item.groupId].visibleItemIds.add(item.id);
|
185
|
+
}
|
186
|
+
|
187
|
+
update();
|
188
|
+
};
|
189
|
+
|
190
|
+
const removeItem = itemId => {
|
191
|
+
const item = overflowItems[itemId];
|
192
|
+
visibleItemQueue.remove(itemId);
|
193
|
+
invisibleItemQueue.remove(itemId);
|
194
|
+
|
195
|
+
if (item.groupId) {
|
196
|
+
overflowGroups[item.groupId].visibleItemIds.delete(item.id);
|
197
|
+
overflowGroups[item.groupId].invisibleItemIds.delete(item.id);
|
198
|
+
}
|
199
|
+
|
200
|
+
delete overflowItems[itemId];
|
201
|
+
update();
|
202
|
+
};
|
203
|
+
|
204
|
+
return {
|
205
|
+
addItem,
|
206
|
+
disconnect,
|
207
|
+
forceUpdate,
|
208
|
+
observe,
|
209
|
+
removeItem,
|
210
|
+
update
|
211
|
+
};
|
212
|
+
}
|
213
|
+
//# sourceMappingURL=overflowManager.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["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 * @returns overflow manager instance\n */\nexport function createOverflowManager(): OverflowManager {\n let container: HTMLElement | undefined;\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 // 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\n while (currentWidth < availableSize && invisibleItemQueue.size() > 0) {\n currentWidth += makeItemVisible();\n }\n // Remove items until there's no more overlap\n while (currentWidth > availableSize && visibleItemQueue.size() > 0) {\n if (visibleItemQueue.size() === options.minimumVisible) {\n break;\n }\n currentWidth -= 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 container = observedContainer;\n resizeObserver.observe(container);\n };\n\n const disconnect: OverflowManager['disconnect'] = () => {\n resizeObserver.disconnect();\n };\n\n const addItem: OverflowManager['addItem'] = item => {\n overflowItems[item.id] = item;\n visibleItemQueue.enqueue(item.id);\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 removeItem: OverflowManager['removeItem'] = itemId => {\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 };\n}\n"],"sourceRoot":"../src/"}
|
@@ -0,0 +1,111 @@
|
|
1
|
+
/**
|
2
|
+
* @param compare - comparison function for items
|
3
|
+
* @returns Priority queue implemented with a min heap
|
4
|
+
*/
|
5
|
+
export function createPriorityQueue(compare) {
|
6
|
+
const arr = [];
|
7
|
+
let size = 0;
|
8
|
+
|
9
|
+
const left = i => {
|
10
|
+
return 2 * i + 1;
|
11
|
+
};
|
12
|
+
|
13
|
+
const right = i => {
|
14
|
+
return 2 * i + 2;
|
15
|
+
};
|
16
|
+
|
17
|
+
const parent = i => {
|
18
|
+
return Math.floor((i - 1) / 2);
|
19
|
+
};
|
20
|
+
|
21
|
+
const swap = (a, b) => {
|
22
|
+
const tmp = arr[a];
|
23
|
+
arr[a] = arr[b];
|
24
|
+
arr[b] = tmp;
|
25
|
+
};
|
26
|
+
|
27
|
+
const heapify = i => {
|
28
|
+
let smallest = i;
|
29
|
+
const l = left(i);
|
30
|
+
const r = right(i);
|
31
|
+
|
32
|
+
if (l < size && compare(arr[l], arr[smallest]) < 0) {
|
33
|
+
smallest = l;
|
34
|
+
}
|
35
|
+
|
36
|
+
if (r < size && compare(arr[r], arr[smallest]) < 0) {
|
37
|
+
smallest = r;
|
38
|
+
}
|
39
|
+
|
40
|
+
if (smallest !== i) {
|
41
|
+
swap(smallest, i);
|
42
|
+
heapify(smallest);
|
43
|
+
}
|
44
|
+
};
|
45
|
+
|
46
|
+
const dequeue = () => {
|
47
|
+
if (size === 0) {
|
48
|
+
throw new Error('Priority queue empty');
|
49
|
+
}
|
50
|
+
|
51
|
+
const res = arr[0];
|
52
|
+
arr[0] = arr[--size];
|
53
|
+
heapify(0);
|
54
|
+
return res;
|
55
|
+
};
|
56
|
+
|
57
|
+
const peek = () => {
|
58
|
+
if (size === 0) {
|
59
|
+
return null;
|
60
|
+
}
|
61
|
+
|
62
|
+
return arr[0];
|
63
|
+
};
|
64
|
+
|
65
|
+
const enqueue = item => {
|
66
|
+
arr[size++] = item;
|
67
|
+
let i = size - 1;
|
68
|
+
let p = parent(i);
|
69
|
+
|
70
|
+
while (i > 0 && compare(arr[p], arr[i]) > 0) {
|
71
|
+
swap(p, i);
|
72
|
+
i = p;
|
73
|
+
p = parent(i);
|
74
|
+
}
|
75
|
+
};
|
76
|
+
|
77
|
+
const contains = item => {
|
78
|
+
return arr.indexOf(item) >= 0;
|
79
|
+
};
|
80
|
+
|
81
|
+
const remove = item => {
|
82
|
+
const i = arr.indexOf(item);
|
83
|
+
|
84
|
+
if (i === -1) {
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
|
88
|
+
arr[i] = arr[--size];
|
89
|
+
heapify(i);
|
90
|
+
};
|
91
|
+
|
92
|
+
const clear = () => {
|
93
|
+
size = 0;
|
94
|
+
};
|
95
|
+
|
96
|
+
const all = () => {
|
97
|
+
return arr.slice(0, size);
|
98
|
+
};
|
99
|
+
|
100
|
+
return {
|
101
|
+
all,
|
102
|
+
clear,
|
103
|
+
contains,
|
104
|
+
dequeue,
|
105
|
+
enqueue,
|
106
|
+
peek,
|
107
|
+
remove,
|
108
|
+
size: () => size
|
109
|
+
};
|
110
|
+
}
|
111
|
+
//# sourceMappingURL=priorityQueue.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["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 return arr.indexOf(item) >= 0;\n };\n\n const remove = (item: T) => {\n const i = arr.indexOf(item);\n\n if (i === -1) {\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"],"sourceRoot":"../src/"}
|
package/lib/types.js
ADDED
package/lib/types.js.map
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"../src/","sources":["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\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"]}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.debounce = void 0;
|
7
|
+
/**
|
8
|
+
* Microtask debouncer
|
9
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide
|
10
|
+
* @param fn - Function to debounce
|
11
|
+
* @returns debounced function
|
12
|
+
*/
|
13
|
+
|
14
|
+
function debounce(fn) {
|
15
|
+
let pending;
|
16
|
+
return () => {
|
17
|
+
if (!pending) {
|
18
|
+
pending = true;
|
19
|
+
queueMicrotask(() => {
|
20
|
+
// Need to set pending to `false` before the debounced function is run.
|
21
|
+
// React can actually interrupt the function while it's running!
|
22
|
+
pending = false;
|
23
|
+
fn();
|
24
|
+
});
|
25
|
+
}
|
26
|
+
};
|
27
|
+
}
|
28
|
+
|
29
|
+
exports.debounce = debounce;
|
30
|
+
//# sourceMappingURL=debounce.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["debounce.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;AAKG;;AACH,SAAgB,QAAhB,CAAyB,EAAzB,EAAqC;AACnC,MAAI,OAAJ;AACA,SAAO,MAAK;AACV,QAAI,CAAC,OAAL,EAAc;AACZ,MAAA,OAAO,GAAG,IAAV;AACA,MAAA,cAAc,CAAC,MAAK;AAClB;AACA;AACA,QAAA,OAAO,GAAG,KAAV;AACA,QAAA,EAAE;AACH,OALa,CAAd;AAMD;AACF,GAVD;AAWD;;AAbD,OAAA,CAAA,QAAA,GAAA,QAAA","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"],"sourceRoot":"../src/"}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.createOverflowManager = void 0;
|
7
|
+
|
8
|
+
var overflowManager_1 = /*#__PURE__*/require("./overflowManager");
|
9
|
+
|
10
|
+
Object.defineProperty(exports, "createOverflowManager", {
|
11
|
+
enumerable: true,
|
12
|
+
get: function () {
|
13
|
+
return overflowManager_1.createOverflowManager;
|
14
|
+
}
|
15
|
+
});
|
16
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["index.ts"],"names":[],"mappings":";;;;;;;AAAA,IAAA,iBAAA,gBAAA,OAAA,CAAA,mBAAA,CAAA;;AAAS,MAAA,CAAA,cAAA,CAAA,OAAA,EAAA,uBAAA,EAAA;AAAA,EAAA,UAAA,EAAA,IAAA;AAAA,EAAA,GAAA,EAAA,YAAA;AAAA,WAAA,iBAAA,CAAA,qBAAA;AAAqB;AAArB,CAAA","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"],"sourceRoot":"../src/"}
|
@@ -0,0 +1,224 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.createOverflowManager = void 0;
|
7
|
+
|
8
|
+
const debounce_1 = /*#__PURE__*/require("./debounce");
|
9
|
+
|
10
|
+
const priorityQueue_1 = /*#__PURE__*/require("./priorityQueue");
|
11
|
+
/**
|
12
|
+
* @returns overflow manager instance
|
13
|
+
*/
|
14
|
+
|
15
|
+
|
16
|
+
function createOverflowManager() {
|
17
|
+
let container;
|
18
|
+
const options = {
|
19
|
+
padding: 10,
|
20
|
+
overflowAxis: 'horizontal',
|
21
|
+
overflowDirection: 'end',
|
22
|
+
minimumVisible: 0,
|
23
|
+
onUpdateItemVisibility: () => undefined,
|
24
|
+
onUpdateOverflow: () => undefined
|
25
|
+
};
|
26
|
+
const overflowItems = {};
|
27
|
+
const overflowGroups = {};
|
28
|
+
const resizeObserver = new ResizeObserver(entries => {
|
29
|
+
if (!entries[0] || !container) {
|
30
|
+
return;
|
31
|
+
}
|
32
|
+
|
33
|
+
update();
|
34
|
+
});
|
35
|
+
const invisibleItemQueue = priorityQueue_1.createPriorityQueue((a, b) => {
|
36
|
+
const itemA = overflowItems[a];
|
37
|
+
const itemB = overflowItems[b]; // Higher priority at the top of the queue
|
38
|
+
|
39
|
+
const priority = itemB.priority - itemA.priority;
|
40
|
+
|
41
|
+
if (priority !== 0) {
|
42
|
+
return priority;
|
43
|
+
}
|
44
|
+
|
45
|
+
const positionStatusBit = options.overflowDirection === 'end' ? Node.DOCUMENT_POSITION_FOLLOWING : Node.DOCUMENT_POSITION_PRECEDING; // equal priority, use DOM order
|
46
|
+
// eslint-disable-next-line no-bitwise
|
47
|
+
|
48
|
+
return itemA.element.compareDocumentPosition(itemB.element) & positionStatusBit ? -1 : 1;
|
49
|
+
});
|
50
|
+
const visibleItemQueue = priorityQueue_1.createPriorityQueue((a, b) => {
|
51
|
+
const itemA = overflowItems[a];
|
52
|
+
const itemB = overflowItems[b]; // Lower priority at the top of the queue
|
53
|
+
|
54
|
+
const priority = itemA.priority - itemB.priority;
|
55
|
+
|
56
|
+
if (priority !== 0) {
|
57
|
+
return priority;
|
58
|
+
}
|
59
|
+
|
60
|
+
const positionStatusBit = options.overflowDirection === 'end' ? Node.DOCUMENT_POSITION_PRECEDING : Node.DOCUMENT_POSITION_FOLLOWING; // equal priority, use DOM order
|
61
|
+
// eslint-disable-next-line no-bitwise
|
62
|
+
|
63
|
+
return itemA.element.compareDocumentPosition(itemB.element) & positionStatusBit ? -1 : 1;
|
64
|
+
});
|
65
|
+
|
66
|
+
const getOffsetSize = el => {
|
67
|
+
return options.overflowAxis === 'horizontal' ? el.offsetWidth : el.offsetHeight;
|
68
|
+
};
|
69
|
+
|
70
|
+
const makeItemVisible = () => {
|
71
|
+
const nextVisible = invisibleItemQueue.dequeue();
|
72
|
+
visibleItemQueue.enqueue(nextVisible);
|
73
|
+
const item = overflowItems[nextVisible];
|
74
|
+
options.onUpdateItemVisibility({
|
75
|
+
item,
|
76
|
+
visible: true
|
77
|
+
});
|
78
|
+
|
79
|
+
if (item.groupId) {
|
80
|
+
overflowGroups[item.groupId].invisibleItemIds.delete(item.id);
|
81
|
+
overflowGroups[item.groupId].visibleItemIds.add(item.id);
|
82
|
+
}
|
83
|
+
|
84
|
+
return getOffsetSize(item.element);
|
85
|
+
};
|
86
|
+
|
87
|
+
const makeItemInvisible = () => {
|
88
|
+
const nextInvisible = visibleItemQueue.dequeue();
|
89
|
+
invisibleItemQueue.enqueue(nextInvisible);
|
90
|
+
const item = overflowItems[nextInvisible];
|
91
|
+
const width = getOffsetSize(item.element);
|
92
|
+
options.onUpdateItemVisibility({
|
93
|
+
item,
|
94
|
+
visible: false
|
95
|
+
});
|
96
|
+
|
97
|
+
if (item.groupId) {
|
98
|
+
overflowGroups[item.groupId].visibleItemIds.delete(item.id);
|
99
|
+
overflowGroups[item.groupId].invisibleItemIds.add(item.id);
|
100
|
+
}
|
101
|
+
|
102
|
+
return width;
|
103
|
+
};
|
104
|
+
|
105
|
+
const dispatchOverflowUpdate = () => {
|
106
|
+
const visibleItemIds = visibleItemQueue.all();
|
107
|
+
const invisibleItemIds = invisibleItemQueue.all();
|
108
|
+
const visibleItems = visibleItemIds.map(itemId => overflowItems[itemId]);
|
109
|
+
const invisibleItems = invisibleItemIds.map(itemId => overflowItems[itemId]);
|
110
|
+
const groupVisibility = {};
|
111
|
+
Object.entries(overflowGroups).forEach(([groupId, groupState]) => {
|
112
|
+
if (groupState.invisibleItemIds.size && groupState.visibleItemIds.size) {
|
113
|
+
groupVisibility[groupId] = 'overflow';
|
114
|
+
} else if (groupState.visibleItemIds.size === 0) {
|
115
|
+
groupVisibility[groupId] = 'hidden';
|
116
|
+
} else {
|
117
|
+
groupVisibility[groupId] = 'visible';
|
118
|
+
}
|
119
|
+
});
|
120
|
+
options.onUpdateOverflow({
|
121
|
+
visibleItems,
|
122
|
+
invisibleItems,
|
123
|
+
groupVisibility
|
124
|
+
});
|
125
|
+
};
|
126
|
+
|
127
|
+
const processOverflowItems = availableSize => {
|
128
|
+
if (!container) {
|
129
|
+
return;
|
130
|
+
} // Snapshot of the visible/invisible state to compare for updates
|
131
|
+
|
132
|
+
|
133
|
+
const visibleTop = visibleItemQueue.peek();
|
134
|
+
const invisibleTop = invisibleItemQueue.peek();
|
135
|
+
const visibleItemIds = visibleItemQueue.all();
|
136
|
+
let currentWidth = visibleItemIds.reduce((sum, visibleItemId) => {
|
137
|
+
const child = overflowItems[visibleItemId].element;
|
138
|
+
return sum + getOffsetSize(child);
|
139
|
+
}, 0); // Add items until available width is filled
|
140
|
+
|
141
|
+
while (currentWidth < availableSize && invisibleItemQueue.size() > 0) {
|
142
|
+
currentWidth += makeItemVisible();
|
143
|
+
} // Remove items until there's no more overlap
|
144
|
+
|
145
|
+
|
146
|
+
while (currentWidth > availableSize && visibleItemQueue.size() > 0) {
|
147
|
+
if (visibleItemQueue.size() === options.minimumVisible) {
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
|
151
|
+
currentWidth -= makeItemInvisible();
|
152
|
+
} // only update when the state of visible/invisible items has changed
|
153
|
+
|
154
|
+
|
155
|
+
if (visibleItemQueue.peek() !== visibleTop || invisibleItemQueue.peek() !== invisibleTop) {
|
156
|
+
dispatchOverflowUpdate();
|
157
|
+
}
|
158
|
+
};
|
159
|
+
|
160
|
+
const forceUpdate = () => {
|
161
|
+
if (!container) {
|
162
|
+
return;
|
163
|
+
}
|
164
|
+
|
165
|
+
const availableSize = getOffsetSize(container) - options.padding;
|
166
|
+
processOverflowItems(availableSize);
|
167
|
+
};
|
168
|
+
|
169
|
+
const update = debounce_1.debounce(forceUpdate);
|
170
|
+
|
171
|
+
const observe = (observedContainer, userOptions) => {
|
172
|
+
Object.assign(options, userOptions);
|
173
|
+
container = observedContainer;
|
174
|
+
resizeObserver.observe(container);
|
175
|
+
};
|
176
|
+
|
177
|
+
const disconnect = () => {
|
178
|
+
resizeObserver.disconnect();
|
179
|
+
};
|
180
|
+
|
181
|
+
const addItem = item => {
|
182
|
+
overflowItems[item.id] = item;
|
183
|
+
visibleItemQueue.enqueue(item.id);
|
184
|
+
|
185
|
+
if (item.groupId) {
|
186
|
+
if (!overflowGroups[item.groupId]) {
|
187
|
+
overflowGroups[item.groupId] = {
|
188
|
+
visibleItemIds: new Set(),
|
189
|
+
invisibleItemIds: new Set()
|
190
|
+
};
|
191
|
+
}
|
192
|
+
|
193
|
+
overflowGroups[item.groupId].visibleItemIds.add(item.id);
|
194
|
+
}
|
195
|
+
|
196
|
+
update();
|
197
|
+
};
|
198
|
+
|
199
|
+
const removeItem = itemId => {
|
200
|
+
const item = overflowItems[itemId];
|
201
|
+
visibleItemQueue.remove(itemId);
|
202
|
+
invisibleItemQueue.remove(itemId);
|
203
|
+
|
204
|
+
if (item.groupId) {
|
205
|
+
overflowGroups[item.groupId].visibleItemIds.delete(item.id);
|
206
|
+
overflowGroups[item.groupId].invisibleItemIds.delete(item.id);
|
207
|
+
}
|
208
|
+
|
209
|
+
delete overflowItems[itemId];
|
210
|
+
update();
|
211
|
+
};
|
212
|
+
|
213
|
+
return {
|
214
|
+
addItem,
|
215
|
+
disconnect,
|
216
|
+
forceUpdate,
|
217
|
+
observe,
|
218
|
+
removeItem,
|
219
|
+
update
|
220
|
+
};
|
221
|
+
}
|
222
|
+
|
223
|
+
exports.createOverflowManager = createOverflowManager;
|
224
|
+
//# sourceMappingURL=overflowManager.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["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 * @returns overflow manager instance\n */\nexport function createOverflowManager(): OverflowManager {\n let container: HTMLElement | undefined;\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 // 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\n while (currentWidth < availableSize && invisibleItemQueue.size() > 0) {\n currentWidth += makeItemVisible();\n }\n // Remove items until there's no more overlap\n while (currentWidth > availableSize && visibleItemQueue.size() > 0) {\n if (visibleItemQueue.size() === options.minimumVisible) {\n break;\n }\n currentWidth -= 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 container = observedContainer;\n resizeObserver.observe(container);\n };\n\n const disconnect: OverflowManager['disconnect'] = () => {\n resizeObserver.disconnect();\n };\n\n const addItem: OverflowManager['addItem'] = item => {\n overflowItems[item.id] = item;\n visibleItemQueue.enqueue(item.id);\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 removeItem: OverflowManager['removeItem'] = itemId => {\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 };\n}\n"],"sourceRoot":"../src/"}
|
@@ -0,0 +1,120 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.createPriorityQueue = void 0;
|
7
|
+
/**
|
8
|
+
* @param compare - comparison function for items
|
9
|
+
* @returns Priority queue implemented with a min heap
|
10
|
+
*/
|
11
|
+
|
12
|
+
function createPriorityQueue(compare) {
|
13
|
+
const arr = [];
|
14
|
+
let size = 0;
|
15
|
+
|
16
|
+
const left = i => {
|
17
|
+
return 2 * i + 1;
|
18
|
+
};
|
19
|
+
|
20
|
+
const right = i => {
|
21
|
+
return 2 * i + 2;
|
22
|
+
};
|
23
|
+
|
24
|
+
const parent = i => {
|
25
|
+
return Math.floor((i - 1) / 2);
|
26
|
+
};
|
27
|
+
|
28
|
+
const swap = (a, b) => {
|
29
|
+
const tmp = arr[a];
|
30
|
+
arr[a] = arr[b];
|
31
|
+
arr[b] = tmp;
|
32
|
+
};
|
33
|
+
|
34
|
+
const heapify = i => {
|
35
|
+
let smallest = i;
|
36
|
+
const l = left(i);
|
37
|
+
const r = right(i);
|
38
|
+
|
39
|
+
if (l < size && compare(arr[l], arr[smallest]) < 0) {
|
40
|
+
smallest = l;
|
41
|
+
}
|
42
|
+
|
43
|
+
if (r < size && compare(arr[r], arr[smallest]) < 0) {
|
44
|
+
smallest = r;
|
45
|
+
}
|
46
|
+
|
47
|
+
if (smallest !== i) {
|
48
|
+
swap(smallest, i);
|
49
|
+
heapify(smallest);
|
50
|
+
}
|
51
|
+
};
|
52
|
+
|
53
|
+
const dequeue = () => {
|
54
|
+
if (size === 0) {
|
55
|
+
throw new Error('Priority queue empty');
|
56
|
+
}
|
57
|
+
|
58
|
+
const res = arr[0];
|
59
|
+
arr[0] = arr[--size];
|
60
|
+
heapify(0);
|
61
|
+
return res;
|
62
|
+
};
|
63
|
+
|
64
|
+
const peek = () => {
|
65
|
+
if (size === 0) {
|
66
|
+
return null;
|
67
|
+
}
|
68
|
+
|
69
|
+
return arr[0];
|
70
|
+
};
|
71
|
+
|
72
|
+
const enqueue = item => {
|
73
|
+
arr[size++] = item;
|
74
|
+
let i = size - 1;
|
75
|
+
let p = parent(i);
|
76
|
+
|
77
|
+
while (i > 0 && compare(arr[p], arr[i]) > 0) {
|
78
|
+
swap(p, i);
|
79
|
+
i = p;
|
80
|
+
p = parent(i);
|
81
|
+
}
|
82
|
+
};
|
83
|
+
|
84
|
+
const contains = item => {
|
85
|
+
return arr.indexOf(item) >= 0;
|
86
|
+
};
|
87
|
+
|
88
|
+
const remove = item => {
|
89
|
+
const i = arr.indexOf(item);
|
90
|
+
|
91
|
+
if (i === -1) {
|
92
|
+
return;
|
93
|
+
}
|
94
|
+
|
95
|
+
arr[i] = arr[--size];
|
96
|
+
heapify(i);
|
97
|
+
};
|
98
|
+
|
99
|
+
const clear = () => {
|
100
|
+
size = 0;
|
101
|
+
};
|
102
|
+
|
103
|
+
const all = () => {
|
104
|
+
return arr.slice(0, size);
|
105
|
+
};
|
106
|
+
|
107
|
+
return {
|
108
|
+
all,
|
109
|
+
clear,
|
110
|
+
contains,
|
111
|
+
dequeue,
|
112
|
+
enqueue,
|
113
|
+
peek,
|
114
|
+
remove,
|
115
|
+
size: () => size
|
116
|
+
};
|
117
|
+
}
|
118
|
+
|
119
|
+
exports.createPriorityQueue = createPriorityQueue;
|
120
|
+
//# sourceMappingURL=priorityQueue.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["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 return arr.indexOf(item) >= 0;\n };\n\n const remove = (item: T) => {\n const i = arr.indexOf(item);\n\n if (i === -1) {\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"],"sourceRoot":"../src/"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","sourceRoot":"../src/"}
|
package/package.json
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
{
|
2
|
+
"name": "@fluentui/priority-overflow",
|
3
|
+
"version": "0.0.0-nightly-20220511-0419.1",
|
4
|
+
"description": "Vanilla JS utilities to implement overflow menus",
|
5
|
+
"main": "lib-commonjs/index.js",
|
6
|
+
"module": "lib/index.js",
|
7
|
+
"typings": "dist/index.d.ts",
|
8
|
+
"sideEffects": false,
|
9
|
+
"repository": {
|
10
|
+
"type": "git",
|
11
|
+
"url": "https://github.com/microsoft/fluentui"
|
12
|
+
},
|
13
|
+
"license": "MIT",
|
14
|
+
"scripts": {
|
15
|
+
"build": "just-scripts build",
|
16
|
+
"bundle-size": "bundle-size measure",
|
17
|
+
"clean": "just-scripts clean",
|
18
|
+
"code-style": "just-scripts code-style",
|
19
|
+
"just": "just-scripts",
|
20
|
+
"lint": "just-scripts lint",
|
21
|
+
"test": "jest --passWithNoTests",
|
22
|
+
"docs": "api-extractor run --config=config/api-extractor.local.json --local",
|
23
|
+
"build:local": "tsc -p ./tsconfig.lib.json --module esnext --emitDeclarationOnly && node ../../../scripts/typescript/normalize-import --output ./dist/packages/react-components/priority-overflow/src && yarn docs",
|
24
|
+
"type-check": "tsc -b tsconfig.json"
|
25
|
+
},
|
26
|
+
"devDependencies": {
|
27
|
+
"@fluentui/eslint-plugin": "*",
|
28
|
+
"@fluentui/scripts": "^1.0.0"
|
29
|
+
},
|
30
|
+
"dependencies": {
|
31
|
+
"tslib": "^2.1.0"
|
32
|
+
},
|
33
|
+
"beachball": {
|
34
|
+
"disallowedChangeTypes": [
|
35
|
+
"major",
|
36
|
+
"minor",
|
37
|
+
"patch"
|
38
|
+
]
|
39
|
+
}
|
40
|
+
}
|