@oscarpalmer/oui 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/css/badge.css +3 -3
- package/dist/css/content.css +9 -11
- package/dist/css/form.css +36 -22
- package/dist/css/message.css +4 -0
- package/dist/css/popover.css +3 -0
- package/dist/css/reset.css +176 -56
- package/dist/css/splitter.css +3 -3
- package/dist/css/tooltip.css +8 -0
- package/dist/js/attributable.full.js +48 -0
- package/dist/js/attributable.js +30 -45
- package/dist/js/floatable.full.js +413 -0
- package/dist/js/floatable.js +259 -132
- package/dist/js/focus-trap/embedded.full.js +351 -0
- package/dist/js/focus-trap/embedded.js +131 -131
- package/dist/js/focus-trap/standalone.full.js +402 -0
- package/dist/js/focus-trap/standalone.js +4 -4
- package/dist/js/index.js +4 -5
- package/dist/js/oui.full.js +1596 -0
- package/dist/js/popover.full.js +822 -0
- package/dist/js/popover.js +83 -156
- package/dist/js/splitter.full.js +605 -0
- package/dist/js/splitter.js +279 -200
- package/dist/js/tooltip.full.js +679 -0
- package/dist/js/tooltip.js +159 -144
- package/package.json +31 -59
- package/src/css/content.scss +1 -2
- package/src/css/form.scss +12 -4
- package/src/css/message.scss +3 -0
- package/src/css/mixins.scss +7 -0
- package/src/css/popover.scss +4 -0
- package/src/css/reset.scss +180 -54
- package/src/css/splitter.scss +3 -3
- package/src/css/tooltip.scss +8 -0
- package/src/js/floatable.ts +458 -124
- package/src/js/focus-trap/embedded.ts +149 -64
- package/src/js/focus-trap/standalone.ts +4 -4
- package/src/js/index.ts +1 -0
- package/src/js/popover.ts +51 -114
- package/src/js/splitter.ts +346 -109
- package/src/js/tooltip.ts +157 -63
- package/types/floatable.d.ts +19 -7
- package/types/focus-trap/embedded.d.ts +18 -5
- package/types/index.d.ts +1 -0
- package/types/popover.d.ts +2 -0
- package/types/splitter.d.ts +13 -1
- package/types/tooltip.d.ts +2 -1
- package/dist/js/attributable.cjs +0 -51
- package/dist/js/floatable.cjs +0 -134
- package/dist/js/focus-trap/embedded.cjs +0 -150
- package/dist/js/focus-trap/standalone.cjs +0 -8
- package/dist/js/index.cjs +0 -6
- package/dist/js/popover.cjs +0 -160
- package/dist/js/splitter.cjs +0 -211
- package/dist/js/tooltip.cjs +0 -160
- package/types/attributable.d.cts +0 -5
- package/types/floatable.d.cts +0 -16
- package/types/focus-trap/embedded.d.cts +0 -15
- package/types/focus-trap/standalone.d.cts +0 -3
- package/types/index.d.cts +0 -14
- package/types/popover.d.cts +0 -14
- package/types/splitter.d.cts +0 -10
- package/types/tooltip.d.cts +0 -3
package/src/js/splitter.ts
CHANGED
|
@@ -1,20 +1,58 @@
|
|
|
1
|
+
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import {round} from '@oscarpalmer/atoms/math';
|
|
1
3
|
import {clamp} from '@oscarpalmer/atoms/number';
|
|
2
4
|
import {getPosition, on} from '@oscarpalmer/toretto/event';
|
|
3
5
|
import {findAncestor} from '@oscarpalmer/toretto/find';
|
|
6
|
+
import {type StyleToggler, toggleStyles} from '@oscarpalmer/toretto/style';
|
|
7
|
+
import supportsTouch from '@oscarpalmer/toretto/touch';
|
|
4
8
|
|
|
5
9
|
declare global {
|
|
10
|
+
// biome-ignore lint/nursery/useConsistentTypeDefinitions: Extending builtins to allow custom element type help
|
|
6
11
|
interface HTMLElementTagNameMap {
|
|
7
|
-
|
|
12
|
+
[SELECTOR]: OuiSplitterElement;
|
|
8
13
|
}
|
|
9
14
|
}
|
|
10
15
|
|
|
11
|
-
type Flex = {
|
|
12
|
-
previous: number;
|
|
13
|
-
value: number;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
16
|
export class OuiSplitterElement extends HTMLElement {
|
|
17
|
-
|
|
17
|
+
static readonly observedAttributes = ['max', 'min', 'size', 'type'];
|
|
18
|
+
|
|
19
|
+
readonly #splitter: Splitter;
|
|
20
|
+
|
|
21
|
+
// Getters and setters
|
|
22
|
+
|
|
23
|
+
get max(): number {
|
|
24
|
+
return this.#splitter.values.max;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
set max(value: number) {
|
|
28
|
+
this.setAttribute('max', String(value));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get min(): number {
|
|
32
|
+
return this.#splitter.values.min;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
set min(value: number) {
|
|
36
|
+
this.setAttribute('min', String(value));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get size(): number {
|
|
40
|
+
return this.#splitter.values.now.current;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
set size(value: number) {
|
|
44
|
+
this.setAttribute('size', String(value));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get type(): string {
|
|
48
|
+
return this.getAttribute('type') ?? 'vertical';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
set type(value: string) {
|
|
52
|
+
this.setAttribute('type', value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Constructor
|
|
18
56
|
|
|
19
57
|
constructor() {
|
|
20
58
|
super();
|
|
@@ -24,61 +62,116 @@ export class OuiSplitterElement extends HTMLElement {
|
|
|
24
62
|
);
|
|
25
63
|
|
|
26
64
|
if (panels.length !== 2) {
|
|
27
|
-
throw new Error(
|
|
65
|
+
throw new Error(`${SELECTOR} must have exactly two panels.`);
|
|
28
66
|
}
|
|
29
67
|
|
|
30
68
|
this.#splitter = new Splitter(this, panels);
|
|
31
69
|
}
|
|
32
70
|
|
|
71
|
+
// Methods
|
|
72
|
+
|
|
33
73
|
connectedCallback(): void {
|
|
34
|
-
|
|
35
|
-
observer.observe(this);
|
|
36
|
-
}
|
|
74
|
+
this.#splitter.updateConnections(1);
|
|
37
75
|
}
|
|
38
76
|
|
|
39
77
|
disconnectedCallback(): void {
|
|
40
|
-
|
|
41
|
-
|
|
78
|
+
this.#splitter.updateConnections(0);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
attributeChangedCallback(name: string): void {
|
|
82
|
+
switch (name) {
|
|
83
|
+
case 'max':
|
|
84
|
+
case 'min':
|
|
85
|
+
case 'size':
|
|
86
|
+
this.#splitter.updateValues();
|
|
87
|
+
break;
|
|
88
|
+
|
|
89
|
+
case 'type':
|
|
90
|
+
this.#splitter.updateOrientation();
|
|
91
|
+
break;
|
|
92
|
+
|
|
93
|
+
default:
|
|
94
|
+
break;
|
|
42
95
|
}
|
|
43
96
|
}
|
|
44
97
|
}
|
|
45
98
|
|
|
99
|
+
let index = 0;
|
|
100
|
+
|
|
46
101
|
class Splitter {
|
|
47
|
-
|
|
48
|
-
previous: 0.5,
|
|
49
|
-
value: 0.5,
|
|
50
|
-
};
|
|
102
|
+
element: OuiSplitterElement;
|
|
51
103
|
|
|
52
104
|
handle: HTMLSpanElement;
|
|
53
105
|
|
|
106
|
+
panels: HTMLElement[];
|
|
107
|
+
|
|
54
108
|
rectangle: DOMRect;
|
|
55
109
|
|
|
56
110
|
separator: HTMLDivElement;
|
|
57
111
|
|
|
58
|
-
types
|
|
112
|
+
types!: Types;
|
|
113
|
+
|
|
114
|
+
values: Values;
|
|
115
|
+
|
|
116
|
+
constructor(element: OuiSplitterElement, panels: HTMLElement[]) {
|
|
117
|
+
this.element = element;
|
|
118
|
+
this.panels = panels;
|
|
119
|
+
|
|
120
|
+
if (isNullableOrWhitespace(element.id)) {
|
|
121
|
+
element.id = `oui_splitter_${++index}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.values = getValues(element);
|
|
59
125
|
|
|
60
|
-
constructor(
|
|
61
|
-
public element: OuiSplitterElement,
|
|
62
|
-
public panels: HTMLElement[],
|
|
63
|
-
) {
|
|
64
126
|
this.handle = createHandle();
|
|
65
127
|
this.rectangle = element.getBoundingClientRect();
|
|
66
|
-
this.separator = createSeparator();
|
|
128
|
+
this.separator = createSeparator(this);
|
|
67
129
|
|
|
68
130
|
this.separator.append(this.handle);
|
|
69
131
|
|
|
70
132
|
panels[0].insertAdjacentElement('afterend', this.separator);
|
|
71
133
|
|
|
72
|
-
|
|
73
|
-
|
|
134
|
+
this.updateOrientation();
|
|
135
|
+
this.updateValues();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
updateConnections(add: 0 | 1): void {
|
|
139
|
+
const method = METHODS_CONNECT[add];
|
|
74
140
|
|
|
75
|
-
|
|
141
|
+
MAPPED_ELEMENTS[method](this.element, this);
|
|
142
|
+
MAPPED_ELEMENTS[method](this.handle, this);
|
|
143
|
+
MAPPED_ELEMENTS[method](this.separator, this);
|
|
76
144
|
|
|
145
|
+
if (this.types.auto) {
|
|
146
|
+
RESIZE_OBSERVER[METHODS_OBSERVE[add]](this.element);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
updateOrientation(): void {
|
|
77
151
|
this.types = getTypes(this);
|
|
78
152
|
|
|
153
|
+
if (this.types.auto) {
|
|
154
|
+
RESIZE_OBSERVER.observe(this.element);
|
|
155
|
+
} else {
|
|
156
|
+
RESIZE_OBSERVER.unobserve(this.element);
|
|
157
|
+
}
|
|
158
|
+
|
|
79
159
|
if (this.types.horizontal) {
|
|
80
|
-
this.element.setAttribute(
|
|
160
|
+
this.element.setAttribute(ATTRIBUTE_HORIZONTAL, '');
|
|
161
|
+
} else {
|
|
162
|
+
this.element.removeAttribute(ATTRIBUTE_HORIZONTAL);
|
|
81
163
|
}
|
|
164
|
+
|
|
165
|
+
setAriaOrientation(this);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
updateValues(): void {
|
|
169
|
+
this.values = getValues(this.element);
|
|
170
|
+
|
|
171
|
+
requestAnimationFrame(() => {
|
|
172
|
+
setSize(this, this.values.now.current);
|
|
173
|
+
setAriaValue(this);
|
|
174
|
+
});
|
|
82
175
|
}
|
|
83
176
|
}
|
|
84
177
|
|
|
@@ -87,35 +180,53 @@ type Types = {
|
|
|
87
180
|
horizontal: boolean;
|
|
88
181
|
};
|
|
89
182
|
|
|
183
|
+
type Values = {
|
|
184
|
+
max: number;
|
|
185
|
+
min: number;
|
|
186
|
+
now: ValuesNow;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
type ValuesNow = {
|
|
190
|
+
current: number;
|
|
191
|
+
previous: number;
|
|
192
|
+
};
|
|
193
|
+
|
|
90
194
|
//
|
|
91
195
|
|
|
92
196
|
function createHandle(): HTMLSpanElement {
|
|
93
197
|
const handle = document.createElement('span');
|
|
94
198
|
|
|
95
|
-
handle.
|
|
96
|
-
|
|
97
|
-
handle.setAttribute('aria-label', 'Resize panels');
|
|
98
|
-
handle.setAttribute('oui-splitter-handle', '');
|
|
199
|
+
handle.setAttribute('aria-hidden', 'true');
|
|
200
|
+
handle.setAttribute(ATTRIBUTE_HANDLE, '');
|
|
99
201
|
|
|
100
202
|
return handle;
|
|
101
203
|
}
|
|
102
204
|
|
|
103
|
-
function createSeparator(): HTMLDivElement {
|
|
205
|
+
function createSeparator(splitter: Splitter): HTMLDivElement {
|
|
104
206
|
const separator = document.createElement('div');
|
|
105
207
|
|
|
106
|
-
separator.
|
|
208
|
+
separator.role = 'separator';
|
|
209
|
+
separator.tabIndex = 0;
|
|
210
|
+
|
|
211
|
+
separator.setAttribute('aria-controls', splitter.element.id);
|
|
212
|
+
separator.setAttribute('aria-label', 'Resize panels');
|
|
213
|
+
separator.setAttribute(ATTRIBUTE_SEPARATOR, '');
|
|
107
214
|
|
|
108
215
|
return separator;
|
|
109
216
|
}
|
|
110
217
|
|
|
111
|
-
function
|
|
218
|
+
function getContained(min: number, value: number, max: number): number {
|
|
219
|
+
return round(clamp(value, min, max), VALUE_DECIMALS);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function getSize(splitter: Splitter, value: number): number {
|
|
112
223
|
const {height, left, top, width} = splitter.rectangle;
|
|
113
224
|
|
|
114
225
|
const offset = value - (splitter.types.horizontal ? top : left);
|
|
115
226
|
|
|
116
227
|
const fraction = offset / (splitter.types.horizontal ? height : width);
|
|
117
228
|
|
|
118
|
-
return
|
|
229
|
+
return getContained(splitter.values.min, fraction, splitter.values.max);
|
|
119
230
|
}
|
|
120
231
|
|
|
121
232
|
function getTypes(splitter: Splitter, width?: number, height?: number): Types {
|
|
@@ -143,82 +254,91 @@ function getTypes(splitter: Splitter, width?: number, height?: number): Types {
|
|
|
143
254
|
};
|
|
144
255
|
}
|
|
145
256
|
|
|
146
|
-
function
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
257
|
+
function getValue(
|
|
258
|
+
element: HTMLElement,
|
|
259
|
+
name: string,
|
|
260
|
+
defaultValue: number,
|
|
261
|
+
): number {
|
|
262
|
+
const value = element.getAttribute(name);
|
|
150
263
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
} else {
|
|
154
|
-
splitter.flex.previous = splitter.flex.value;
|
|
155
|
-
}
|
|
264
|
+
if (isNullableOrWhitespace(value)) {
|
|
265
|
+
return defaultValue;
|
|
156
266
|
}
|
|
157
267
|
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function onKeydown(event: KeyboardEvent): void {
|
|
162
|
-
switch (true) {
|
|
163
|
-
case allKeys.has(event.key):
|
|
164
|
-
onNavigate(event);
|
|
165
|
-
break;
|
|
268
|
+
const parsed = Number.parseFloat(value);
|
|
166
269
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
270
|
+
if (Number.isNaN(parsed)) {
|
|
271
|
+
return defaultValue;
|
|
272
|
+
}
|
|
170
273
|
|
|
171
|
-
|
|
172
|
-
|
|
274
|
+
if (parsed < 0) {
|
|
275
|
+
return defaultValue;
|
|
173
276
|
}
|
|
277
|
+
|
|
278
|
+
return parsed > 1 ? parsed / NAVIGATION_MAXIMUM_TOTAL : parsed;
|
|
174
279
|
}
|
|
175
280
|
|
|
176
|
-
function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
281
|
+
function getValues(element: OuiSplitterElement): Values {
|
|
282
|
+
const values: Values = {
|
|
283
|
+
max: getValue(element, 'max', NAVIGATION_MAXIMUM_PERCENTAGE),
|
|
284
|
+
min: getValue(element, 'min', NAVIGATION_MINIMUM_PERCENTAGE),
|
|
285
|
+
now: {
|
|
286
|
+
current: 0.5,
|
|
287
|
+
previous: 0.5,
|
|
288
|
+
},
|
|
289
|
+
};
|
|
183
290
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
291
|
+
const value = getContained(
|
|
292
|
+
values.min,
|
|
293
|
+
getValue(element, 'size', values.now.current),
|
|
294
|
+
values.max,
|
|
295
|
+
);
|
|
187
296
|
|
|
188
|
-
|
|
189
|
-
|
|
297
|
+
values.now.current = value;
|
|
298
|
+
values.now.previous = value;
|
|
190
299
|
|
|
191
|
-
|
|
300
|
+
return values;
|
|
192
301
|
}
|
|
193
302
|
|
|
194
|
-
function
|
|
303
|
+
function onEnd(reset: boolean): void {
|
|
195
304
|
if (splitter == null) {
|
|
196
305
|
return;
|
|
197
306
|
}
|
|
198
307
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (position != null) {
|
|
202
|
-
splitter.flex.value = getFlex(
|
|
203
|
-
splitter,
|
|
204
|
-
splitter.types.horizontal ? position.y : position.x,
|
|
205
|
-
);
|
|
308
|
+
splitter.handle.removeAttribute(ATTRIBUTE_ACTIVE);
|
|
309
|
+
splitter.separator.removeAttribute(ATTRIBUTE_ACTIVE);
|
|
206
310
|
|
|
207
|
-
|
|
311
|
+
if (reset) {
|
|
312
|
+
setSize(splitter, splitter.values.now.previous);
|
|
313
|
+
} else {
|
|
314
|
+
splitter.values.now.previous = splitter.values.now.current;
|
|
208
315
|
}
|
|
316
|
+
|
|
317
|
+
splitter = undefined;
|
|
318
|
+
|
|
319
|
+
STYLING_TOGGLER.remove();
|
|
209
320
|
}
|
|
210
321
|
|
|
211
|
-
function
|
|
212
|
-
|
|
213
|
-
|
|
322
|
+
function onKeydown(event: KeyboardEvent): void {
|
|
323
|
+
switch (true) {
|
|
324
|
+
case KEYS_ALL.has(event.key):
|
|
325
|
+
onNavigate(event);
|
|
326
|
+
break;
|
|
327
|
+
|
|
328
|
+
case event.key === 'Escape':
|
|
329
|
+
onEnd(true);
|
|
330
|
+
break;
|
|
331
|
+
|
|
332
|
+
default:
|
|
333
|
+
break;
|
|
214
334
|
}
|
|
215
335
|
}
|
|
216
336
|
|
|
217
337
|
function onNavigate(event: KeyboardEvent): void {
|
|
218
|
-
const splitter =
|
|
338
|
+
const splitter = MAPPED_ELEMENTS.get(
|
|
219
339
|
findAncestor(
|
|
220
340
|
event.target as never,
|
|
221
|
-
'[oui-splitter-
|
|
341
|
+
'[oui-splitter-separator]',
|
|
222
342
|
) as HTMLSpanElement,
|
|
223
343
|
);
|
|
224
344
|
|
|
@@ -226,22 +346,32 @@ function onNavigate(event: KeyboardEvent): void {
|
|
|
226
346
|
return;
|
|
227
347
|
}
|
|
228
348
|
|
|
229
|
-
|
|
230
|
-
|
|
349
|
+
const {types, values} = splitter;
|
|
350
|
+
|
|
351
|
+
if (KEYS_ABSOLUTE.has(event.key)) {
|
|
352
|
+
setSize(splitter, event.key === 'End' ? values.max : values.min, true);
|
|
231
353
|
|
|
232
354
|
return;
|
|
233
355
|
}
|
|
234
356
|
|
|
235
357
|
if (
|
|
236
|
-
(
|
|
237
|
-
(
|
|
358
|
+
(types.horizontal && !KEYS_HORIZONTAL.has(event.key)) ||
|
|
359
|
+
!(types.horizontal || KEYS_VERTICAL.has(event.key))
|
|
238
360
|
) {
|
|
239
361
|
return;
|
|
240
362
|
}
|
|
241
363
|
|
|
242
|
-
const
|
|
364
|
+
const offset = KEYS_NEGATIVE.has(event.key) ? -1 : 1;
|
|
243
365
|
|
|
244
|
-
setSize(
|
|
366
|
+
setSize(
|
|
367
|
+
splitter,
|
|
368
|
+
getContained(
|
|
369
|
+
values.min,
|
|
370
|
+
values.now.current + offset * NAVIGATION_MODIFIER,
|
|
371
|
+
values.max,
|
|
372
|
+
),
|
|
373
|
+
true,
|
|
374
|
+
);
|
|
245
375
|
}
|
|
246
376
|
|
|
247
377
|
function onObservation(entries: ResizeObserverEntry[]): void {
|
|
@@ -251,7 +381,7 @@ function onObservation(entries: ResizeObserverEntry[]): void {
|
|
|
251
381
|
|
|
252
382
|
frame = requestAnimationFrame(() => {
|
|
253
383
|
for (const entry of entries) {
|
|
254
|
-
const splitter =
|
|
384
|
+
const splitter = MAPPED_ELEMENTS.get(entry.target as HTMLElement);
|
|
255
385
|
|
|
256
386
|
if (splitter == null) {
|
|
257
387
|
return;
|
|
@@ -264,41 +394,149 @@ function onObservation(entries: ResizeObserverEntry[]): void {
|
|
|
264
394
|
);
|
|
265
395
|
|
|
266
396
|
if (splitter.types.horizontal) {
|
|
267
|
-
splitter.element.setAttribute(
|
|
397
|
+
splitter.element.setAttribute(ATTRIBUTE_HORIZONTAL, '');
|
|
268
398
|
} else {
|
|
269
|
-
splitter.element.removeAttribute(
|
|
399
|
+
splitter.element.removeAttribute(ATTRIBUTE_HORIZONTAL);
|
|
270
400
|
}
|
|
401
|
+
|
|
402
|
+
setAriaOrientation(splitter);
|
|
271
403
|
}
|
|
272
404
|
|
|
273
405
|
frame = undefined;
|
|
274
406
|
});
|
|
275
407
|
}
|
|
276
408
|
|
|
409
|
+
function onPointerdown(event: Event): void {
|
|
410
|
+
if (
|
|
411
|
+
(event.type === 'mousedown' && supportsTouch.value) ||
|
|
412
|
+
(event.type === 'touchstart' && !supportsTouch.value)
|
|
413
|
+
) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
splitter = MAPPED_ELEMENTS.get(
|
|
418
|
+
findAncestor(event.target as never, SELECTOR_HANDLE) as HTMLSpanElement,
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
if (splitter == null) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (supportsTouch.value) {
|
|
426
|
+
event.preventDefault();
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
splitter.handle.setAttribute(ATTRIBUTE_ACTIVE, '');
|
|
430
|
+
splitter.separator.setAttribute(ATTRIBUTE_ACTIVE, '');
|
|
431
|
+
|
|
432
|
+
splitter.rectangle = splitter.element.getBoundingClientRect();
|
|
433
|
+
|
|
434
|
+
STYLING_TOGGLER.set();
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function onPointermove(event: MouseEvent): void {
|
|
438
|
+
if (splitter == null) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const position = getPosition(event);
|
|
443
|
+
|
|
444
|
+
if (position != null) {
|
|
445
|
+
splitter.values.now.current = getSize(
|
|
446
|
+
splitter,
|
|
447
|
+
splitter.types.horizontal ? position.y : position.x,
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
setSize(splitter, splitter.values.now.current);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function onPointerup(): void {
|
|
455
|
+
if (splitter != null) {
|
|
456
|
+
onEnd(false);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function setAriaOrientation(splitter: Splitter): void {
|
|
461
|
+
splitter.separator.setAttribute(
|
|
462
|
+
'aria-orientation',
|
|
463
|
+
splitter.types.horizontal ? 'horizontal' : 'vertical',
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function setAriaValue(splitter: Splitter): void {
|
|
468
|
+
splitter.separator.setAttribute('aria-valuemax', String(splitter.values.max));
|
|
469
|
+
splitter.separator.setAttribute('aria-valuemin', String(splitter.values.min));
|
|
470
|
+
|
|
471
|
+
splitter.separator.setAttribute(
|
|
472
|
+
'aria-valuenow',
|
|
473
|
+
String(splitter.values.now.current),
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
|
|
277
477
|
function setSize(splitter: Splitter, size: number, previous?: boolean): void {
|
|
278
|
-
splitter.
|
|
478
|
+
splitter.values.now.current = size;
|
|
279
479
|
|
|
280
480
|
if (previous) {
|
|
281
|
-
splitter.
|
|
481
|
+
splitter.values.now.previous = size;
|
|
282
482
|
}
|
|
283
483
|
|
|
284
484
|
splitter.element.style.setProperty('--oui-splitter-size', `${size}`);
|
|
485
|
+
|
|
486
|
+
setAriaValue(splitter);
|
|
285
487
|
}
|
|
286
488
|
|
|
287
489
|
//
|
|
288
490
|
|
|
289
|
-
const
|
|
491
|
+
const SELECTOR = 'oui-splitter';
|
|
492
|
+
|
|
493
|
+
const ATTRIBUTE_ACTIVE = `${SELECTOR}-active`;
|
|
494
|
+
|
|
495
|
+
const ATTRIBUTE_HANDLE = `${SELECTOR}-handle`;
|
|
496
|
+
|
|
497
|
+
const ATTRIBUTE_HORIZONTAL = `${SELECTOR}-horizontal`;
|
|
498
|
+
|
|
499
|
+
const ATTRIBUTE_SEPARATOR = `${SELECTOR}-separator`;
|
|
500
|
+
|
|
501
|
+
const KEYS_ABSOLUTE: Set<string> = new Set(['End', 'Home']);
|
|
502
|
+
|
|
503
|
+
const KEYS_HORIZONTAL: Set<string> = new Set(['ArrowDown', 'ArrowUp']);
|
|
504
|
+
|
|
505
|
+
const KEYS_NEGATIVE: Set<string> = new Set(['ArrowLeft', 'ArrowUp']);
|
|
290
506
|
|
|
291
|
-
const
|
|
507
|
+
const KEYS_VERTICAL: Set<string> = new Set(['ArrowLeft', 'ArrowRight']);
|
|
292
508
|
|
|
293
|
-
const
|
|
509
|
+
const KEYS_ALL: Set<string> = new Set([
|
|
510
|
+
...KEYS_ABSOLUTE,
|
|
511
|
+
...KEYS_HORIZONTAL,
|
|
512
|
+
...KEYS_VERTICAL,
|
|
513
|
+
]);
|
|
294
514
|
|
|
295
|
-
const
|
|
515
|
+
const MAPPED_ELEMENTS: WeakMap<HTMLElement, Splitter> = new WeakMap();
|
|
296
516
|
|
|
297
|
-
const
|
|
517
|
+
const METHODS_CONNECT = ['delete', 'set'] as const;
|
|
298
518
|
|
|
299
|
-
const
|
|
519
|
+
const METHODS_OBSERVE = ['unobserve', 'observe'] as const;
|
|
300
520
|
|
|
301
|
-
const
|
|
521
|
+
const NAVIGATION_MAXIMUM_PERCENTAGE = 0.9;
|
|
522
|
+
|
|
523
|
+
const NAVIGATION_MAXIMUM_TOTAL = 100;
|
|
524
|
+
|
|
525
|
+
const NAVIGATION_MINIMUM_PERCENTAGE = 0.1;
|
|
526
|
+
|
|
527
|
+
const NAVIGATION_MODIFIER = 0.05;
|
|
528
|
+
|
|
529
|
+
const RESIZE_OBSERVER: ResizeObserver = new ResizeObserver(onObservation);
|
|
530
|
+
|
|
531
|
+
const SELECTOR_HANDLE = `[${ATTRIBUTE_HANDLE}]`;
|
|
532
|
+
|
|
533
|
+
const STYLING_TOGGLER: StyleToggler = toggleStyles(document.body, {
|
|
534
|
+
touchAction: 'none',
|
|
535
|
+
userSelect: 'none',
|
|
536
|
+
webkitUserSelect: 'none',
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
const VALUE_DECIMALS = 6;
|
|
302
540
|
|
|
303
541
|
let frame: DOMHighResTimeStamp | undefined;
|
|
304
542
|
|
|
@@ -306,12 +544,11 @@ let splitter: Splitter | undefined;
|
|
|
306
544
|
|
|
307
545
|
//
|
|
308
546
|
|
|
309
|
-
customElements.define(
|
|
547
|
+
customElements.define(SELECTOR, OuiSplitterElement);
|
|
310
548
|
|
|
311
549
|
on(document, 'keydown', onKeydown);
|
|
312
|
-
|
|
313
|
-
on(document, '
|
|
314
|
-
|
|
315
|
-
on(document, '
|
|
316
|
-
|
|
317
|
-
on(document, 'mouseup', onMouseup);
|
|
550
|
+
on(document, 'mousedown', onPointerdown);
|
|
551
|
+
on(document, 'pointermove', onPointermove);
|
|
552
|
+
on(document, 'pointerup', onPointerup);
|
|
553
|
+
on(document, 'touchcancel', onPointerup, {passive: false});
|
|
554
|
+
on(document, 'touchstart', onPointerdown, {passive: false});
|