@openleaf-editor/ui 0.1.0-beta.2 → 0.1.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -0
- package/dist/block-type.d.ts +5 -0
- package/dist/block-type.d.ts.map +1 -0
- package/dist/block-type.js +133 -0
- package/dist/block-type.js.map +1 -0
- package/dist/content-css.d.ts +18 -0
- package/dist/content-css.d.ts.map +1 -1
- package/dist/content-css.js +231 -16
- package/dist/content-css.js.map +1 -1
- package/dist/css.d.ts +23 -0
- package/dist/css.d.ts.map +1 -0
- package/dist/css.js +846 -0
- package/dist/css.js.map +1 -0
- package/dist/dialog.d.ts +93 -0
- package/dist/dialog.d.ts.map +1 -1
- package/dist/dialog.js +414 -86
- package/dist/dialog.js.map +1 -1
- package/dist/floating.d.ts +4 -0
- package/dist/floating.d.ts.map +1 -1
- package/dist/floating.js +50 -2
- package/dist/floating.js.map +1 -1
- package/dist/help.d.ts +1 -1
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +29 -5
- package/dist/help.js.map +1 -1
- package/dist/i18n.d.ts +8 -0
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +32 -7
- package/dist/i18n.js.map +1 -1
- package/dist/icons.d.ts +7 -1
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +6 -2
- package/dist/icons.js.map +1 -1
- package/dist/index.d.ts +10 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/items.d.ts +0 -1
- package/dist/items.d.ts.map +1 -1
- package/dist/items.js +211 -20
- package/dist/items.js.map +1 -1
- package/dist/live.d.ts +42 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +83 -0
- package/dist/live.js.map +1 -0
- package/dist/menu.d.ts +31 -2
- package/dist/menu.d.ts.map +1 -1
- package/dist/menu.js +163 -23
- package/dist/menu.js.map +1 -1
- package/dist/openleaf.css +147 -12
- package/dist/overflow.d.ts +47 -4
- package/dist/overflow.d.ts.map +1 -1
- package/dist/overflow.js +338 -83
- package/dist/overflow.js.map +1 -1
- package/dist/registry.d.ts +72 -18
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +7 -6
- package/dist/registry.js.map +1 -1
- package/dist/skins.d.ts.map +1 -1
- package/dist/skins.js +48 -14
- package/dist/skins.js.map +1 -1
- package/dist/styles.d.ts +61 -1
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +77 -637
- package/dist/styles.js.map +1 -1
- package/dist/testing.d.ts +3 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +3 -0
- package/dist/testing.js.map +1 -0
- package/dist/toolbar.d.ts +71 -12
- package/dist/toolbar.d.ts.map +1 -1
- package/dist/toolbar.js +410 -166
- package/dist/toolbar.js.map +1 -1
- package/dist/upload.d.ts +32 -7
- package/dist/upload.d.ts.map +1 -1
- package/dist/upload.js +64 -8
- package/dist/upload.js.map +1 -1
- package/package.json +17 -3
package/dist/overflow.d.ts
CHANGED
|
@@ -1,17 +1,60 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Collapse overflowing toolbar groups into a "More"
|
|
2
|
+
* Collapse overflowing toolbar groups into a "More" panel.
|
|
3
3
|
*
|
|
4
4
|
* Wrapping is the default for a reason: a control that moved behind a click is
|
|
5
5
|
* a control the author does not have. Overflow is therefore opt-in. When it is
|
|
6
|
-
* on, groups that do not fit the current width are
|
|
7
|
-
* offered in a
|
|
6
|
+
* on, groups that do not fit the current width are moved out of the bar and
|
|
7
|
+
* offered in a panel at the end, so a narrow CMS sidebar still has every item
|
|
8
8
|
* without a two-row bar.
|
|
9
|
+
*
|
|
10
|
+
* ## Why the real controls move rather than being cloned
|
|
11
|
+
*
|
|
12
|
+
* The first implementation cloned each control into a `role="menu"`. Cloning a
|
|
13
|
+
* live control produces a listener-free copy that has to forward every
|
|
14
|
+
* interaction back to an original it can only find by id, duplicates that id
|
|
15
|
+
* and the accessible name, and goes stale the moment the caret moves -- three
|
|
16
|
+
* bugs that only exist because there were two of everything. Moving the group
|
|
17
|
+
* node itself has none of them: the control in the panel IS the control, so it
|
|
18
|
+
* carries its own listeners, its own state and its own accessible name, and
|
|
19
|
+
* nothing can drift.
|
|
20
|
+
*
|
|
21
|
+
* ## The keyboard pattern
|
|
22
|
+
*
|
|
23
|
+
* The panel is a vertical `role="toolbar"`, not a `role="menu"`: a menu owns a
|
|
24
|
+
* content model of `menuitem` children, and a `<select>` is not one -- the
|
|
25
|
+
* default bar has four. So the panel is the same widget as the bar it came
|
|
26
|
+
* from, turned ninety degrees, and it keeps the same contract: one tab stop,
|
|
27
|
+
* arrow keys to move, Home/End to the ends, Escape back to the trigger. Tab
|
|
28
|
+
* closes, because a panel a keyboard user can walk out of and leave open is the
|
|
29
|
+
* failure mode of every hand-rolled popup.
|
|
30
|
+
*
|
|
31
|
+
* Up/Down are taken from a `<select>` inside the panel the same way Left/Right
|
|
32
|
+
* are taken from one in the bar; Alt+Down still opens its list, and typeahead
|
|
33
|
+
* still selects. Home/End are left to the select, which uses them for its own
|
|
34
|
+
* first and last option.
|
|
9
35
|
*/
|
|
10
36
|
export declare class ToolbarOverflow {
|
|
11
37
|
#private;
|
|
12
|
-
constructor(toolbar: HTMLElement, host: HTMLElement, doc: Document);
|
|
38
|
+
constructor(toolbar: HTMLElement, host: HTMLElement, doc: Document, onLayout?: () => void);
|
|
39
|
+
/** Re-home the trigger after the toolbar rebuilt its children. */
|
|
13
40
|
reattach(): void;
|
|
14
41
|
destroy(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Lay the bar out without stealing focus.
|
|
44
|
+
*
|
|
45
|
+
* `#reflow` moves real controls -- the trigger included -- between the bar and
|
|
46
|
+
* the panel, and `appendChild` of an already-connected node is a removal
|
|
47
|
+
* followed by an insertion. Every engine resets focus to the body when a
|
|
48
|
+
* focused element is moved that way (chromium, firefox and webkit alike; it is
|
|
49
|
+
* not a WebKit quirk, WebKit just loses the race more often on a loaded
|
|
50
|
+
* machine). A ResizeObserver fires whenever the bar changes size -- a font
|
|
51
|
+
* finishing, `--openleaf-button-size` changing density, a CMS sidebar
|
|
52
|
+
* animating open -- so a keyboard user standing on More could have the button
|
|
53
|
+
* pulled out from under them between focusing it and pressing Enter, and the
|
|
54
|
+
* Enter went to the document.
|
|
55
|
+
*
|
|
56
|
+
* So the layout records what it is about to move focus off, and puts it back.
|
|
57
|
+
*/
|
|
15
58
|
layout(): void;
|
|
16
59
|
}
|
|
17
60
|
//# sourceMappingURL=overflow.d.ts.map
|
package/dist/overflow.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overflow.d.ts","sourceRoot":"","sources":["../src/overflow.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"overflow.d.ts","sourceRoot":"","sources":["../src/overflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAUH,qBAAa,eAAe;;gBAuBd,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,MAAM,IAAI;IA+CzF,kEAAkE;IAClE,QAAQ,IAAI,IAAI;IAiChB,OAAO,IAAI,IAAI;IAgBf;;;;;;;;;;;;;;;OAeG;IACH,MAAM,IAAI,IAAI;CAsOf"}
|
package/dist/overflow.js
CHANGED
|
@@ -1,135 +1,390 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Collapse overflowing toolbar groups into a "More"
|
|
2
|
+
* Collapse overflowing toolbar groups into a "More" panel.
|
|
3
3
|
*
|
|
4
4
|
* Wrapping is the default for a reason: a control that moved behind a click is
|
|
5
5
|
* a control the author does not have. Overflow is therefore opt-in. When it is
|
|
6
|
-
* on, groups that do not fit the current width are
|
|
7
|
-
* offered in a
|
|
6
|
+
* on, groups that do not fit the current width are moved out of the bar and
|
|
7
|
+
* offered in a panel at the end, so a narrow CMS sidebar still has every item
|
|
8
8
|
* without a two-row bar.
|
|
9
|
+
*
|
|
10
|
+
* ## Why the real controls move rather than being cloned
|
|
11
|
+
*
|
|
12
|
+
* The first implementation cloned each control into a `role="menu"`. Cloning a
|
|
13
|
+
* live control produces a listener-free copy that has to forward every
|
|
14
|
+
* interaction back to an original it can only find by id, duplicates that id
|
|
15
|
+
* and the accessible name, and goes stale the moment the caret moves -- three
|
|
16
|
+
* bugs that only exist because there were two of everything. Moving the group
|
|
17
|
+
* node itself has none of them: the control in the panel IS the control, so it
|
|
18
|
+
* carries its own listeners, its own state and its own accessible name, and
|
|
19
|
+
* nothing can drift.
|
|
20
|
+
*
|
|
21
|
+
* ## The keyboard pattern
|
|
22
|
+
*
|
|
23
|
+
* The panel is a vertical `role="toolbar"`, not a `role="menu"`: a menu owns a
|
|
24
|
+
* content model of `menuitem` children, and a `<select>` is not one -- the
|
|
25
|
+
* default bar has four. So the panel is the same widget as the bar it came
|
|
26
|
+
* from, turned ninety degrees, and it keeps the same contract: one tab stop,
|
|
27
|
+
* arrow keys to move, Home/End to the ends, Escape back to the trigger. Tab
|
|
28
|
+
* closes, because a panel a keyboard user can walk out of and leave open is the
|
|
29
|
+
* failure mode of every hand-rolled popup.
|
|
30
|
+
*
|
|
31
|
+
* Up/Down are taken from a `<select>` inside the panel the same way Left/Right
|
|
32
|
+
* are taken from one in the bar; Alt+Down still opens its list, and typeahead
|
|
33
|
+
* still selects. Home/End are left to the select, which uses them for its own
|
|
34
|
+
* first and last option.
|
|
9
35
|
*/
|
|
10
36
|
import { t } from './i18n.js';
|
|
11
37
|
import { iconElement } from './icons.js';
|
|
38
|
+
/** Focusable controls, matching what the toolbar's own roving walks. */
|
|
39
|
+
const FOCUSABLE = 'button.ol-btn, select.ol-select';
|
|
40
|
+
let panelCounter = 0;
|
|
12
41
|
export class ToolbarOverflow {
|
|
13
42
|
#toolbar;
|
|
14
43
|
#host;
|
|
44
|
+
#doc;
|
|
15
45
|
#more;
|
|
16
|
-
#
|
|
46
|
+
#panel;
|
|
17
47
|
#observer = null;
|
|
18
|
-
|
|
48
|
+
#onLayout;
|
|
49
|
+
/**
|
|
50
|
+
* A pending coalesced layout.
|
|
51
|
+
*
|
|
52
|
+
* A ResizeObserver fires once per observed element, so a ten-group bar paid
|
|
53
|
+
* for ten layouts in one frame. One rAF collapses them, and the frame is
|
|
54
|
+
* cancelled on destroy so a queued layout cannot run against a torn-down bar.
|
|
55
|
+
*/
|
|
56
|
+
#frame = null;
|
|
57
|
+
/**
|
|
58
|
+
* A layout that arrived while the panel was open, and the guard that keeps
|
|
59
|
+
* `#close` from re-entering the reflow that called it.
|
|
60
|
+
*/
|
|
61
|
+
#deferred = false;
|
|
62
|
+
#reflowing = false;
|
|
63
|
+
constructor(toolbar, host, doc, onLayout) {
|
|
19
64
|
this.#toolbar = toolbar;
|
|
20
65
|
this.#host = host;
|
|
66
|
+
this.#doc = doc;
|
|
67
|
+
this.#onLayout = onLayout;
|
|
21
68
|
toolbar.classList.add('ol-toolbar--overflow');
|
|
69
|
+
this.#panel = doc.createElement('div');
|
|
70
|
+
this.#panel.className = 'ol-menu ol-overflow-menu';
|
|
71
|
+
this.#panel.id = `ol-overflow-${(panelCounter += 1)}`;
|
|
72
|
+
this.#panel.setAttribute('role', 'toolbar');
|
|
73
|
+
this.#panel.setAttribute('aria-orientation', 'vertical');
|
|
74
|
+
this.#panel.setAttribute('aria-label', t('More formatting'));
|
|
75
|
+
this.#panel.hidden = true;
|
|
76
|
+
this.#panel.addEventListener('keydown', this.#onKeydown);
|
|
22
77
|
this.#more = doc.createElement('button');
|
|
23
78
|
this.#more.type = 'button';
|
|
24
79
|
this.#more.className = 'ol-btn ol-overflow-more';
|
|
25
80
|
this.#more.setAttribute('aria-label', t('More'));
|
|
26
|
-
|
|
81
|
+
// Not `aria-haspopup`: none of its values describes a toolbar, and "true"
|
|
82
|
+
// means menu, which is what this deliberately is not. Expanded plus a
|
|
83
|
+
// pointer at the panel is the honest relationship.
|
|
27
84
|
this.#more.setAttribute('aria-expanded', 'false');
|
|
85
|
+
this.#more.setAttribute('aria-controls', this.#panel.id);
|
|
28
86
|
this.#more.hidden = true;
|
|
29
87
|
this.#more.appendChild(iconElement('more', doc));
|
|
30
|
-
this.#
|
|
31
|
-
this.#menu.className = 'ol-menu ol-overflow-menu';
|
|
32
|
-
this.#menu.setAttribute('role', 'menu');
|
|
33
|
-
this.#menu.hidden = true;
|
|
88
|
+
this.#more.addEventListener('mousedown', (event) => event.preventDefault());
|
|
34
89
|
this.#more.addEventListener('click', () => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
90
|
+
if (this.#panel.hidden)
|
|
91
|
+
this.#open();
|
|
92
|
+
else
|
|
93
|
+
this.#close(true);
|
|
38
94
|
});
|
|
39
|
-
|
|
95
|
+
// Immediately after the bar, never at the end of the editor: appended to the
|
|
96
|
+
// host it landed after the editable region, so Tab from More walked into the
|
|
97
|
+
// content and the panel could only be reached by going backwards.
|
|
98
|
+
if (toolbar.parentNode)
|
|
99
|
+
toolbar.after(this.#panel);
|
|
100
|
+
else
|
|
101
|
+
host.appendChild(this.#panel);
|
|
40
102
|
toolbar.appendChild(this.#more);
|
|
41
103
|
if (typeof ResizeObserver !== 'undefined') {
|
|
42
|
-
this.#observer = new ResizeObserver(() => this
|
|
104
|
+
this.#observer = new ResizeObserver(() => this.#schedule());
|
|
43
105
|
this.#observer.observe(toolbar);
|
|
44
106
|
}
|
|
45
107
|
this.layout();
|
|
46
108
|
}
|
|
109
|
+
/** Re-home the trigger after the toolbar rebuilt its children. */
|
|
47
110
|
reattach() {
|
|
111
|
+
// Closed first: the panel is about to be emptied, and an open panel would
|
|
112
|
+
// both defer the layout below and leave the author holding an empty one.
|
|
113
|
+
this.#deferred = false;
|
|
114
|
+
this.#close();
|
|
115
|
+
// The groups in the panel belong to the render that was just thrown away.
|
|
116
|
+
// Restoring them would put two of every control in the bar.
|
|
117
|
+
this.#panel.replaceChildren();
|
|
48
118
|
if (!this.#more.isConnected)
|
|
49
119
|
this.#toolbar.appendChild(this.#more);
|
|
50
120
|
this.layout();
|
|
51
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Coalesce resize notifications into one layout per frame.
|
|
124
|
+
*
|
|
125
|
+
* The observer watches the very element `layout` resizes, so an unthrottled
|
|
126
|
+
* callback fed itself: hiding a group changes the bar's size, which notifies
|
|
127
|
+
* the observer, which lays out again. A frame is the right budget for work
|
|
128
|
+
* whose only purpose is deciding what the next paint shows.
|
|
129
|
+
*/
|
|
130
|
+
#schedule() {
|
|
131
|
+
if (this.#frame !== null)
|
|
132
|
+
return;
|
|
133
|
+
const win = this.#toolbar.ownerDocument.defaultView;
|
|
134
|
+
if (!win?.requestAnimationFrame) {
|
|
135
|
+
this.layout();
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this.#frame = win.requestAnimationFrame(() => {
|
|
139
|
+
this.#frame = null;
|
|
140
|
+
this.layout();
|
|
141
|
+
});
|
|
142
|
+
}
|
|
52
143
|
destroy() {
|
|
144
|
+
// A queued frame outlives destroy() and would lay out a torn-down bar.
|
|
145
|
+
if (this.#frame !== null) {
|
|
146
|
+
this.#toolbar.ownerDocument.defaultView?.cancelAnimationFrame(this.#frame);
|
|
147
|
+
this.#frame = null;
|
|
148
|
+
}
|
|
53
149
|
this.#observer?.disconnect();
|
|
150
|
+
// Dropped before the close, or the close would lay out a bar being torn down.
|
|
151
|
+
this.#deferred = false;
|
|
152
|
+
this.#close();
|
|
153
|
+
this.#restore();
|
|
54
154
|
this.#more.remove();
|
|
55
|
-
this.#
|
|
155
|
+
this.#panel.remove();
|
|
56
156
|
this.#toolbar.classList.remove('ol-toolbar--overflow');
|
|
57
|
-
for (const group of this.#groups())
|
|
58
|
-
group.hidden = false;
|
|
59
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Lay the bar out without stealing focus.
|
|
160
|
+
*
|
|
161
|
+
* `#reflow` moves real controls -- the trigger included -- between the bar and
|
|
162
|
+
* the panel, and `appendChild` of an already-connected node is a removal
|
|
163
|
+
* followed by an insertion. Every engine resets focus to the body when a
|
|
164
|
+
* focused element is moved that way (chromium, firefox and webkit alike; it is
|
|
165
|
+
* not a WebKit quirk, WebKit just loses the race more often on a loaded
|
|
166
|
+
* machine). A ResizeObserver fires whenever the bar changes size -- a font
|
|
167
|
+
* finishing, `--openleaf-button-size` changing density, a CMS sidebar
|
|
168
|
+
* animating open -- so a keyboard user standing on More could have the button
|
|
169
|
+
* pulled out from under them between focusing it and pressing Enter, and the
|
|
170
|
+
* Enter went to the document.
|
|
171
|
+
*
|
|
172
|
+
* So the layout records what it is about to move focus off, and puts it back.
|
|
173
|
+
*/
|
|
60
174
|
layout() {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (
|
|
175
|
+
// Never reflow under an open panel. Measuring means putting every group
|
|
176
|
+
// back in the bar, which means closing the panel the author is reading --
|
|
177
|
+
// so a ResizeObserver pass that lands just after they opened it took it
|
|
178
|
+
// away again, along with the focus inside it. A real viewport resize still
|
|
179
|
+
// closes the panel through `#onViewportChange`, and that close runs the
|
|
180
|
+
// deferred layout immediately; a font or a density change simply waits
|
|
181
|
+
// until the author is done with the panel.
|
|
182
|
+
if (!this.#panel.hidden) {
|
|
183
|
+
this.#deferred = true;
|
|
69
184
|
return;
|
|
70
|
-
const overflowing = [];
|
|
71
|
-
for (let i = groups.length - 1; i >= 0; i -= 1) {
|
|
72
|
-
const fits = this.#toolbar.scrollWidth <= budget + 1;
|
|
73
|
-
if (fits)
|
|
74
|
-
break;
|
|
75
|
-
const group = groups[i];
|
|
76
|
-
if (!group)
|
|
77
|
-
break;
|
|
78
|
-
group.hidden = true;
|
|
79
|
-
overflowing.unshift(group);
|
|
80
185
|
}
|
|
81
|
-
|
|
186
|
+
const active = this.#doc.activeElement;
|
|
187
|
+
const held = active instanceof HTMLElement &&
|
|
188
|
+
(this.#toolbar.contains(active) || this.#panel.contains(active))
|
|
189
|
+
? active
|
|
190
|
+
: null;
|
|
191
|
+
this.#reflowing = true;
|
|
192
|
+
try {
|
|
193
|
+
this.#reflow();
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
this.#reflowing = false;
|
|
197
|
+
}
|
|
198
|
+
if (!held || this.#doc.activeElement === held)
|
|
82
199
|
return;
|
|
200
|
+
// A control the reflow pushed into the panel cannot hold focus: the panel is
|
|
201
|
+
// hidden by now. The trigger is where the panel's own Escape sends focus, so
|
|
202
|
+
// it is the honest destination for a control that just went behind it.
|
|
203
|
+
const target = held.isConnected && !this.#panel.contains(held) ? held : this.#more;
|
|
204
|
+
if (!target.hidden && target.isConnected)
|
|
205
|
+
target.focus();
|
|
206
|
+
}
|
|
207
|
+
#reflow() {
|
|
208
|
+
this.#restore();
|
|
209
|
+
// Revealed BEFORE the reads, not after the compute. The trigger takes a
|
|
210
|
+
// width and a gap in the row the moment it is shown, and it cannot be
|
|
211
|
+
// measured while hidden -- `display: none` reports 0. Showing it here means
|
|
212
|
+
// its footprint is inside the same `scrollWidth` as everything else, so the
|
|
213
|
+
// arithmetic needs no second measurement and no second layout pass.
|
|
214
|
+
//
|
|
215
|
+
// Measured every time rather than cached: the width follows
|
|
216
|
+
// `--openleaf-button-size`, which a skin or an integrator token changes at
|
|
217
|
+
// runtime (compact is 28px, the default 32px, coarse-pointer 40px), so a
|
|
218
|
+
// value pinned at first layout goes quietly wrong on the next density
|
|
219
|
+
// change.
|
|
83
220
|
this.#more.hidden = false;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
221
|
+
this.#close();
|
|
222
|
+
// READ. Every measurement is taken here, while the bar is fully expanded,
|
|
223
|
+
// because a width read after a style write forces the browser to lay the
|
|
224
|
+
// whole bar out again. The old loop alternated the two once per group, so a
|
|
225
|
+
// ten-group bar paid for ten layouts -- from a ResizeObserver watching the
|
|
226
|
+
// element it was resizing.
|
|
227
|
+
const budget = this.#toolbar.clientWidth;
|
|
228
|
+
const groups = this.#groups();
|
|
229
|
+
const total = this.#toolbar.scrollWidth;
|
|
230
|
+
const widths = groups.map((group) => group.offsetWidth);
|
|
231
|
+
const moreWidth = this.#more.offsetWidth;
|
|
232
|
+
const gap = Number.parseFloat(this.#toolbar.ownerDocument.defaultView?.getComputedStyle(this.#toolbar).columnGap ?? '') || 0;
|
|
233
|
+
if (budget === 0) {
|
|
234
|
+
this.#more.hidden = true;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
// COMPUTE. In overflow mode the bar is a nowrap flex row with one uniform
|
|
238
|
+
// gap, so moving the last k groups out takes exactly their widths and k
|
|
239
|
+
// gaps off the scroll width. Nothing has to be re-measured between them.
|
|
240
|
+
//
|
|
241
|
+
// The trigger's footprint has to come back OUT to answer "does this bar
|
|
242
|
+
// overflow at all", because a bar that fits never shows one -- and charging
|
|
243
|
+
// it for a button it will not show would collapse a group for nothing.
|
|
244
|
+
const trigger = moreWidth > 0 ? moreWidth + gap : 0;
|
|
245
|
+
if (total - trigger <= budget + 1) {
|
|
246
|
+
this.#more.hidden = true;
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
// Past here the trigger stays, so `total` -- which already includes it -- is
|
|
250
|
+
// the right starting point. Leaving it out is what let a bar stay
|
|
251
|
+
// overflowing by roughly the width of the More button: the groups fit, then
|
|
252
|
+
// revealing the trigger pushed the row back over its budget, and it
|
|
253
|
+
// converged only on the next ResizeObserver pass, with a visible flash in
|
|
254
|
+
// between.
|
|
255
|
+
let used = total;
|
|
256
|
+
let count = 0;
|
|
257
|
+
while (used > budget + 1 && count < groups.length) {
|
|
258
|
+
used -= (widths[groups.length - 1 - count] ?? 0) + gap;
|
|
259
|
+
count += 1;
|
|
260
|
+
}
|
|
261
|
+
if (count === 0) {
|
|
262
|
+
this.#more.hidden = true;
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
// WRITE. Backwards, inserted at the front, so the panel keeps the bar's
|
|
266
|
+
// order. The controls themselves move -- they are not cloned -- which is
|
|
267
|
+
// what makes the panel operable rather than a picture of the bar.
|
|
268
|
+
for (let i = groups.length - 1; i >= groups.length - count; i -= 1) {
|
|
269
|
+
const group = groups[i];
|
|
270
|
+
if (group)
|
|
271
|
+
this.#panel.insertBefore(group, this.#panel.firstChild);
|
|
272
|
+
}
|
|
273
|
+
// The trigger is already visible -- revealed before the reads, above. And
|
|
274
|
+
// there are no separator elements to hide: the divider is a border on the
|
|
275
|
+
// group, so a group that moved into the panel takes its own rule with it
|
|
276
|
+
// and cannot leave one stranded at the end of the bar.
|
|
277
|
+
this.#onLayout?.();
|
|
128
278
|
void this.#host;
|
|
129
279
|
}
|
|
130
|
-
|
|
131
|
-
|
|
280
|
+
/* -------------------------------------------------------------- *
|
|
281
|
+
* Open, close, and the keyboard
|
|
282
|
+
* -------------------------------------------------------------- */
|
|
283
|
+
#open() {
|
|
284
|
+
this.#panel.hidden = false;
|
|
285
|
+
this.#more.setAttribute('aria-expanded', 'true');
|
|
286
|
+
this.#position();
|
|
287
|
+
this.#doc.addEventListener('pointerdown', this.#onPointerDown, true);
|
|
288
|
+
this.#doc.defaultView?.addEventListener('scroll', this.#onViewportChange, true);
|
|
289
|
+
this.#doc.defaultView?.addEventListener('resize', this.#onViewportChange);
|
|
290
|
+
this.#focus(0);
|
|
291
|
+
}
|
|
292
|
+
#close(returnFocus = false) {
|
|
293
|
+
if (this.#panel.hidden)
|
|
294
|
+
return;
|
|
295
|
+
this.#panel.hidden = true;
|
|
132
296
|
this.#more.setAttribute('aria-expanded', 'false');
|
|
297
|
+
this.#doc.removeEventListener('pointerdown', this.#onPointerDown, true);
|
|
298
|
+
this.#doc.defaultView?.removeEventListener('scroll', this.#onViewportChange, true);
|
|
299
|
+
this.#doc.defaultView?.removeEventListener('resize', this.#onViewportChange);
|
|
300
|
+
if (returnFocus)
|
|
301
|
+
this.#more.focus();
|
|
302
|
+
// The reflow's own `#close` must not turn round and call it again.
|
|
303
|
+
if (this.#deferred && !this.#reflowing) {
|
|
304
|
+
this.#deferred = false;
|
|
305
|
+
this.layout();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Under the trigger, in viewport coordinates and clamped to it.
|
|
310
|
+
*
|
|
311
|
+
* Fixed rather than absolute because the bar may sit inside a host with
|
|
312
|
+
* `overflow: hidden`, which is the case the whole feature exists for.
|
|
313
|
+
*/
|
|
314
|
+
#position() {
|
|
315
|
+
const rect = this.#more.getBoundingClientRect();
|
|
316
|
+
const box = this.#panel.getBoundingClientRect();
|
|
317
|
+
const view = this.#doc.defaultView;
|
|
318
|
+
const width = view?.innerWidth ?? 0;
|
|
319
|
+
const height = view?.innerHeight ?? 0;
|
|
320
|
+
const below = rect.bottom + 4;
|
|
321
|
+
const top = below + box.height > height ? Math.max(4, rect.top - box.height - 4) : below;
|
|
322
|
+
this.#panel.style.position = 'fixed';
|
|
323
|
+
this.#panel.style.left = `${Math.round(Math.max(4, Math.min(rect.left, width - box.width - 4)))}px`;
|
|
324
|
+
this.#panel.style.top = `${Math.round(top)}px`;
|
|
325
|
+
}
|
|
326
|
+
#focusables() {
|
|
327
|
+
return [...this.#panel.querySelectorAll(FOCUSABLE)];
|
|
328
|
+
}
|
|
329
|
+
#focus(index) {
|
|
330
|
+
const items = this.#focusables();
|
|
331
|
+
if (items.length === 0)
|
|
332
|
+
return;
|
|
333
|
+
const next = items[(index + items.length) % items.length];
|
|
334
|
+
for (const item of items)
|
|
335
|
+
item.tabIndex = item === next ? 0 : -1;
|
|
336
|
+
next?.focus();
|
|
337
|
+
}
|
|
338
|
+
#onKeydown = (event) => {
|
|
339
|
+
const target = event.target;
|
|
340
|
+
if (event.key === 'Escape' || event.key === 'Tab') {
|
|
341
|
+
event.preventDefault();
|
|
342
|
+
this.#close(true);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const items = this.#focusables();
|
|
346
|
+
const index = items.indexOf(target);
|
|
347
|
+
if (index < 0)
|
|
348
|
+
return;
|
|
349
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
350
|
+
// Alt+Down is how a keyboard user opens a native select's list.
|
|
351
|
+
if (event.altKey)
|
|
352
|
+
return;
|
|
353
|
+
event.preventDefault();
|
|
354
|
+
this.#focus(index + (event.key === 'ArrowDown' ? 1 : -1));
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (event.key === 'Home' || event.key === 'End') {
|
|
358
|
+
// Left to the select, which uses them for its own first and last option.
|
|
359
|
+
if (target?.tagName === 'SELECT')
|
|
360
|
+
return;
|
|
361
|
+
event.preventDefault();
|
|
362
|
+
this.#focus(event.key === 'Home' ? 0 : items.length - 1);
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
#onPointerDown = (event) => {
|
|
366
|
+
const target = event.target;
|
|
367
|
+
if (!(target instanceof Node))
|
|
368
|
+
return;
|
|
369
|
+
if (this.#panel.contains(target) || this.#more.contains(target))
|
|
370
|
+
return;
|
|
371
|
+
this.#close();
|
|
372
|
+
};
|
|
373
|
+
#onViewportChange = () => this.#close();
|
|
374
|
+
/* -------------------------------------------------------------- *
|
|
375
|
+
* Moving groups back and forth
|
|
376
|
+
* -------------------------------------------------------------- */
|
|
377
|
+
#restore() {
|
|
378
|
+
for (const group of [...this.#panel.children])
|
|
379
|
+
this.#toolbar.appendChild(group);
|
|
380
|
+
// Overflow always takes a suffix of the groups, so appending in panel order
|
|
381
|
+
// puts them back where they were. The trigger stays last -- but only if it
|
|
382
|
+
// is not already there. An unconditional `appendChild` re-inserts it on
|
|
383
|
+
// every pass, and a re-insertion is what drops focus, so the steady-state
|
|
384
|
+
// layout of a bar that fits now moves nothing at all.
|
|
385
|
+
if (this.#more.isConnected && this.#toolbar.lastElementChild !== this.#more) {
|
|
386
|
+
this.#toolbar.appendChild(this.#more);
|
|
387
|
+
}
|
|
133
388
|
}
|
|
134
389
|
#groups() {
|
|
135
390
|
return [...this.#toolbar.querySelectorAll(':scope > .ol-group')];
|
package/dist/overflow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overflow.js","sourceRoot":"","sources":["../src/overflow.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"overflow.js","sourceRoot":"","sources":["../src/overflow.ts"],"names":[],"mappings":"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"}
|