@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.
Files changed (62) hide show
  1. package/dist/css/badge.css +3 -3
  2. package/dist/css/content.css +9 -11
  3. package/dist/css/form.css +36 -22
  4. package/dist/css/message.css +4 -0
  5. package/dist/css/popover.css +3 -0
  6. package/dist/css/reset.css +176 -56
  7. package/dist/css/splitter.css +3 -3
  8. package/dist/css/tooltip.css +8 -0
  9. package/dist/js/attributable.full.js +48 -0
  10. package/dist/js/attributable.js +30 -45
  11. package/dist/js/floatable.full.js +413 -0
  12. package/dist/js/floatable.js +259 -132
  13. package/dist/js/focus-trap/embedded.full.js +351 -0
  14. package/dist/js/focus-trap/embedded.js +131 -131
  15. package/dist/js/focus-trap/standalone.full.js +402 -0
  16. package/dist/js/focus-trap/standalone.js +4 -4
  17. package/dist/js/index.js +4 -5
  18. package/dist/js/oui.full.js +1596 -0
  19. package/dist/js/popover.full.js +822 -0
  20. package/dist/js/popover.js +83 -156
  21. package/dist/js/splitter.full.js +605 -0
  22. package/dist/js/splitter.js +279 -200
  23. package/dist/js/tooltip.full.js +679 -0
  24. package/dist/js/tooltip.js +159 -144
  25. package/package.json +31 -59
  26. package/src/css/content.scss +1 -2
  27. package/src/css/form.scss +12 -4
  28. package/src/css/message.scss +3 -0
  29. package/src/css/mixins.scss +7 -0
  30. package/src/css/popover.scss +4 -0
  31. package/src/css/reset.scss +180 -54
  32. package/src/css/splitter.scss +3 -3
  33. package/src/css/tooltip.scss +8 -0
  34. package/src/js/floatable.ts +458 -124
  35. package/src/js/focus-trap/embedded.ts +149 -64
  36. package/src/js/focus-trap/standalone.ts +4 -4
  37. package/src/js/index.ts +1 -0
  38. package/src/js/popover.ts +51 -114
  39. package/src/js/splitter.ts +346 -109
  40. package/src/js/tooltip.ts +157 -63
  41. package/types/floatable.d.ts +19 -7
  42. package/types/focus-trap/embedded.d.ts +18 -5
  43. package/types/index.d.ts +1 -0
  44. package/types/popover.d.ts +2 -0
  45. package/types/splitter.d.ts +13 -1
  46. package/types/tooltip.d.ts +2 -1
  47. package/dist/js/attributable.cjs +0 -51
  48. package/dist/js/floatable.cjs +0 -134
  49. package/dist/js/focus-trap/embedded.cjs +0 -150
  50. package/dist/js/focus-trap/standalone.cjs +0 -8
  51. package/dist/js/index.cjs +0 -6
  52. package/dist/js/popover.cjs +0 -160
  53. package/dist/js/splitter.cjs +0 -211
  54. package/dist/js/tooltip.cjs +0 -160
  55. package/types/attributable.d.cts +0 -5
  56. package/types/floatable.d.cts +0 -16
  57. package/types/focus-trap/embedded.d.cts +0 -15
  58. package/types/focus-trap/standalone.d.cts +0 -3
  59. package/types/index.d.cts +0 -14
  60. package/types/popover.d.cts +0 -14
  61. package/types/splitter.d.cts +0 -10
  62. package/types/tooltip.d.cts +0 -3
@@ -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
- 'oui-splitter': OuiSplitterElement;
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
- #splitter: Splitter;
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('oui-splitter must have exactly two panels.');
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
- if (this.#splitter.types.auto) {
35
- observer.observe(this);
36
- }
74
+ this.#splitter.updateConnections(1);
37
75
  }
38
76
 
39
77
  disconnectedCallback(): void {
40
- if (this.#splitter.types.auto) {
41
- observer.unobserve(this);
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
- flex: Flex = {
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: 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
- mapped.set(element, this);
73
- mapped.set(this.handle, this);
134
+ this.updateOrientation();
135
+ this.updateValues();
136
+ }
137
+
138
+ updateConnections(add: 0 | 1): void {
139
+ const method = METHODS_CONNECT[add];
74
140
 
75
- setSize(this, this.flex.value);
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('oui-splitter-horizontal', '');
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.tabIndex = 0;
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.setAttribute('oui-splitter-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 getFlex(splitter: Splitter, value: number): number {
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 clamp(fraction, 0.1, 0.9);
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 onEnd(reset: boolean): void {
147
- if (splitter != null) {
148
- splitter.handle.removeAttribute('oui-splitter-active');
149
- splitter.separator.removeAttribute('oui-splitter-active');
257
+ function getValue(
258
+ element: HTMLElement,
259
+ name: string,
260
+ defaultValue: number,
261
+ ): number {
262
+ const value = element.getAttribute(name);
150
263
 
151
- if (reset) {
152
- setSize(splitter, splitter.flex.previous);
153
- } else {
154
- splitter.flex.previous = splitter.flex.value;
155
- }
264
+ if (isNullableOrWhitespace(value)) {
265
+ return defaultValue;
156
266
  }
157
267
 
158
- splitter = undefined;
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
- case event.key === 'Escape':
168
- onEnd(true);
169
- break;
270
+ if (Number.isNaN(parsed)) {
271
+ return defaultValue;
272
+ }
170
273
 
171
- default:
172
- break;
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 onMousedown(event: Event): void {
177
- splitter = mapped.get(
178
- findAncestor(
179
- event.target as never,
180
- '[oui-splitter-handle]',
181
- ) as HTMLSpanElement,
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
- if (splitter == null) {
185
- return;
186
- }
291
+ const value = getContained(
292
+ values.min,
293
+ getValue(element, 'size', values.now.current),
294
+ values.max,
295
+ );
187
296
 
188
- splitter.handle.setAttribute('oui-splitter-active', '');
189
- splitter.separator.setAttribute('oui-splitter-active', '');
297
+ values.now.current = value;
298
+ values.now.previous = value;
190
299
 
191
- splitter.rectangle = splitter.element.getBoundingClientRect();
300
+ return values;
192
301
  }
193
302
 
194
- function onMousemove(event: MouseEvent): void {
303
+ function onEnd(reset: boolean): void {
195
304
  if (splitter == null) {
196
305
  return;
197
306
  }
198
307
 
199
- const position = getPosition(event);
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
- setSize(splitter, splitter.flex.value);
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 onMouseup(): void {
212
- if (splitter != null) {
213
- onEnd(false);
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 = mapped.get(
338
+ const splitter = MAPPED_ELEMENTS.get(
219
339
  findAncestor(
220
340
  event.target as never,
221
- '[oui-splitter-handle]',
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
- if (absoluteKeys.has(event.key)) {
230
- setSize(splitter, event.key === 'End' ? 0.9 : 0.1, true);
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
- (splitter.types.horizontal && !horizontalKeys.has(event.key)) ||
237
- (!splitter.types.horizontal && !verticalKeys.has(event.key))
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 modifier = negativeKeys.has(event.key) ? -1 : 1;
364
+ const offset = KEYS_NEGATIVE.has(event.key) ? -1 : 1;
243
365
 
244
- setSize(splitter, splitter.flex.value + modifier * 0.05, true);
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 = mapped.get(entry.target as HTMLElement);
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('oui-splitter-horizontal', '');
397
+ splitter.element.setAttribute(ATTRIBUTE_HORIZONTAL, '');
268
398
  } else {
269
- splitter.element.removeAttribute('oui-splitter-horizontal');
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.flex.value = size;
478
+ splitter.values.now.current = size;
279
479
 
280
480
  if (previous) {
281
- splitter.flex.previous = size;
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 absoluteKeys = new Set(['End', 'Home']);
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 horizontalKeys = new Set(['ArrowDown', 'ArrowUp']);
507
+ const KEYS_VERTICAL: Set<string> = new Set(['ArrowLeft', 'ArrowRight']);
292
508
 
293
- const mapped = new WeakMap<HTMLElement, Splitter>();
509
+ const KEYS_ALL: Set<string> = new Set([
510
+ ...KEYS_ABSOLUTE,
511
+ ...KEYS_HORIZONTAL,
512
+ ...KEYS_VERTICAL,
513
+ ]);
294
514
 
295
- const observer = new ResizeObserver(onObservation);
515
+ const MAPPED_ELEMENTS: WeakMap<HTMLElement, Splitter> = new WeakMap();
296
516
 
297
- const negativeKeys = new Set(['ArrowLeft', 'ArrowUp']);
517
+ const METHODS_CONNECT = ['delete', 'set'] as const;
298
518
 
299
- const verticalKeys = new Set(['ArrowLeft', 'ArrowRight']);
519
+ const METHODS_OBSERVE = ['unobserve', 'observe'] as const;
300
520
 
301
- const allKeys = new Set([...absoluteKeys, ...horizontalKeys, ...verticalKeys]);
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('oui-splitter', OuiSplitterElement);
547
+ customElements.define(SELECTOR, OuiSplitterElement);
310
548
 
311
549
  on(document, 'keydown', onKeydown);
312
-
313
- on(document, 'mousedown', onMousedown);
314
-
315
- on(document, 'mousemove', onMousemove);
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});