@oscarpalmer/oui 0.24.0 → 0.26.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/{tooltip.css → floatable.css} +59 -24
- package/dist/css/reset.css +17 -0
- package/dist/js/dialog.d.mts +38 -0
- package/dist/js/dialog.mjs +92 -0
- package/dist/js/embedded-CHK82Uh5.d.mts +76 -0
- package/dist/js/embedded-ai6cqURc.d.mts +68 -0
- package/dist/js/floatable/embedded.d.mts +2 -0
- package/dist/js/floatable/embedded.mjs +157 -0
- package/dist/js/floatable/standalone.d.mts +2 -0
- package/dist/js/floatable/standalone.mjs +2 -0
- package/dist/js/focus-trap/embedded.d.mts +2 -26
- package/dist/js/focus-trap/embedded.mjs +158 -80
- package/dist/js/focus-trap/standalone.d.mts +2 -1
- package/dist/js/focus-trap/standalone.mjs +3 -3
- package/dist/js/index.d.mts +6 -3
- package/dist/js/index.mjs +9 -5
- package/dist/js/internal/draggable.d.mts +2 -2
- package/dist/js/internal/draggable.mjs +3 -3
- package/dist/js/{movable-BKFgoaOl.d.mts → movable-dNqBctx3.d.mts} +16 -16
- package/dist/js/movable.d.mts +2 -2
- package/dist/js/movable.mjs +4 -4
- package/dist/js/popover.d.mts +38 -1
- package/dist/js/popover.mjs +83 -44
- package/dist/js/sortable.d.mts +2 -2
- package/dist/js/sortable.mjs +5 -5
- package/dist/js/splitter.mjs +49 -48
- package/dist/js/toolbar.d.mts +1 -0
- package/dist/js/toolbar.mjs +107 -0
- package/dist/js/tooltip.d.mts +27 -1
- package/dist/js/tooltip.mjs +85 -49
- package/package.json +14 -2
- package/src/css/{tooltip.scss → floatable.scss} +47 -5
- package/src/css/mixins.scss +0 -2
- package/src/css/reset.scss +17 -0
- package/src/js/dialog.ts +188 -0
- package/src/js/floatable/embedded.ts +323 -0
- package/src/js/floatable/standalone.ts +1 -0
- package/src/js/focus-trap/embedded.ts +219 -93
- package/src/js/focus-trap/standalone.ts +4 -2
- package/src/js/index.ts +6 -4
- package/src/js/internal/draggable.ts +20 -20
- package/src/js/movable.ts +17 -17
- package/src/js/popover.ts +143 -61
- package/src/js/sortable.ts +26 -26
- package/src/js/splitter.ts +98 -96
- package/src/js/toolbar.ts +214 -0
- package/src/js/tooltip.ts +138 -54
- package/dist/css/popover.css +0 -30
- package/dist/js/floatable.d.mts +0 -59
- package/dist/js/floatable.mjs +0 -130
- package/src/css/popover.scss +0 -10
- package/src/js/floatable.ts +0 -237
|
@@ -1,118 +1,239 @@
|
|
|
1
|
+
import {isPlainObject} from '@oscarpalmer/atoms/is';
|
|
1
2
|
import {clamp} from '@oscarpalmer/atoms/number';
|
|
2
3
|
import {on} from '@oscarpalmer/toretto/event';
|
|
3
4
|
import {findAncestor} from '@oscarpalmer/toretto/find';
|
|
4
5
|
import {getFocusable} from '@oscarpalmer/toretto/focusable';
|
|
6
|
+
import {isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
disabled = false;
|
|
8
|
+
// #region Types
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
export class OuiFocusTrap {
|
|
11
|
+
#destroyed = false;
|
|
12
|
+
#tabIndex: number;
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
embedded: boolean;
|
|
14
|
+
readonly #state: OuiFocusTrapState;
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Is focused maintained within the _FocusTrap_ when clicking outside of it?
|
|
18
|
+
*/
|
|
15
19
|
get contain(): boolean {
|
|
16
|
-
return this.element.hasAttribute(
|
|
20
|
+
return this.#state.element.hasAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN);
|
|
17
21
|
}
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Should focus be maintained within the _FocusTrap_ when clicking outside of it?
|
|
25
|
+
*/
|
|
26
|
+
set contain(value: boolean) {
|
|
27
|
+
if (value === true) {
|
|
28
|
+
this.#state.element.setAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN, '');
|
|
29
|
+
} else if (value === false) {
|
|
30
|
+
this.#state.element.removeAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN);
|
|
31
|
+
}
|
|
21
32
|
}
|
|
22
33
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Is the _FocusTrap_ disabled?
|
|
36
|
+
*/
|
|
37
|
+
get disabled(): boolean {
|
|
38
|
+
return this.#state.disabled;
|
|
39
|
+
}
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Should the _FocusTrap_ be disabled?
|
|
43
|
+
*/
|
|
44
|
+
set disabled(value: boolean) {
|
|
45
|
+
if (value === true) {
|
|
46
|
+
this.disable();
|
|
47
|
+
} else if (value === false) {
|
|
48
|
+
this.enable();
|
|
31
49
|
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Is focus allowed to escape when pressing _Escape_ within the _FocusTrap_?
|
|
54
|
+
*/
|
|
55
|
+
get noescape(): boolean {
|
|
56
|
+
return this.#state.element.hasAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE);
|
|
57
|
+
}
|
|
32
58
|
|
|
33
|
-
|
|
34
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Should the _FocusTrap_ allow focus to escape when pressing _Escape_?
|
|
61
|
+
*/
|
|
62
|
+
set noescape(value: boolean) {
|
|
63
|
+
if (value === true) {
|
|
64
|
+
this.#state.element.setAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE, '');
|
|
65
|
+
} else if (value === false) {
|
|
66
|
+
this.#state.element.removeAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE);
|
|
35
67
|
}
|
|
36
68
|
}
|
|
37
69
|
|
|
38
|
-
|
|
39
|
-
|
|
70
|
+
constructor(state: OuiFocusTrapState) {
|
|
71
|
+
this.#state = state;
|
|
72
|
+
this.#tabIndex = state.element.tabIndex;
|
|
73
|
+
|
|
74
|
+
state.element.tabIndex = -1;
|
|
75
|
+
|
|
76
|
+
state.element.setAttribute(ATTRIBUTE_FOCUSTRAP, '');
|
|
77
|
+
|
|
78
|
+
this.contain = state.options.contain;
|
|
79
|
+
this.noescape = state.options.noescape;
|
|
80
|
+
|
|
81
|
+
states.set(this, state);
|
|
40
82
|
}
|
|
41
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Destroys the _FocusTrap_
|
|
86
|
+
*/
|
|
42
87
|
destroy(): void {
|
|
43
|
-
this
|
|
88
|
+
if (this.#destroyed) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.#destroyed = true;
|
|
93
|
+
|
|
94
|
+
disabled.delete(this);
|
|
95
|
+
instances.delete(this.#state.element);
|
|
96
|
+
states.delete(this);
|
|
97
|
+
|
|
98
|
+
this.#state.element.tabIndex = this.#tabIndex;
|
|
99
|
+
|
|
100
|
+
this.#state.element.removeAttribute(ATTRIBUTE_FOCUSTRAP);
|
|
101
|
+
this.#state.element.removeAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN);
|
|
102
|
+
this.#state.element.removeAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE);
|
|
103
|
+
|
|
104
|
+
this.#state.element = undefined as never;
|
|
44
105
|
}
|
|
45
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Disables the _FocusTrap_
|
|
109
|
+
*/
|
|
46
110
|
disable(): void {
|
|
47
|
-
if (!(this.disabled || this.noescape)) {
|
|
48
|
-
setDisabled(this, true);
|
|
111
|
+
if (!this.#destroyed && !(this.disabled || this.#state.options.noescape)) {
|
|
112
|
+
setDisabled(this, this.#state, true);
|
|
49
113
|
}
|
|
50
114
|
}
|
|
51
115
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Enables the _FocusTrap_
|
|
118
|
+
*/
|
|
56
119
|
enable(): void {
|
|
57
|
-
if (this.disabled) {
|
|
58
|
-
setDisabled(this, false);
|
|
120
|
+
if (!this.#destroyed && this.disabled) {
|
|
121
|
+
setDisabled(this, this.#state, false);
|
|
59
122
|
}
|
|
60
123
|
}
|
|
61
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Focuses the _FocusTrap_
|
|
127
|
+
*
|
|
128
|
+
* @param last When `true`, focuses the last focusable element within the _FocusTrap_ instead of the first
|
|
129
|
+
*/
|
|
62
130
|
focus(last: boolean): void {
|
|
63
|
-
|
|
131
|
+
if (!this.#destroyed && !this.disabled) {
|
|
132
|
+
tabToTrap(this, getFocusable(this.#state.element), this.#state.element, last ? -1 : 0);
|
|
133
|
+
}
|
|
64
134
|
}
|
|
65
135
|
}
|
|
66
136
|
|
|
67
|
-
type
|
|
68
|
-
|
|
137
|
+
type OuiFocusTrapOptions = {
|
|
138
|
+
/**
|
|
139
|
+
* Should focus be maintained within the _FocusTrap_ when clicking outside of it?
|
|
140
|
+
*/
|
|
141
|
+
contain?: boolean;
|
|
142
|
+
/**
|
|
143
|
+
* Should the _FocusTrap_ allow focus to escape when pressing _Escape_?
|
|
144
|
+
*/
|
|
145
|
+
noescape?: boolean;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
type OuiFocusTrapState = {
|
|
149
|
+
disabled: boolean;
|
|
150
|
+
element: HTMLElement;
|
|
151
|
+
options: Required<OuiFocusTrapOptions>;
|
|
69
152
|
};
|
|
70
153
|
|
|
71
|
-
//
|
|
154
|
+
// #endregion
|
|
155
|
+
|
|
156
|
+
// #region Functions
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Creates _(or retrieves)_ a _FocusTrap_ for an element
|
|
160
|
+
*
|
|
161
|
+
* @param element Element to trap focus within
|
|
162
|
+
* @param options _FocusTrap_ options
|
|
163
|
+
* @returns _FocusTrap_ instance
|
|
164
|
+
*/
|
|
165
|
+
export function createFocusTrap(element: HTMLElement, options?: OuiFocusTrapOptions): OuiFocusTrap {
|
|
166
|
+
if (!isHTMLOrSVGElement(element)) {
|
|
167
|
+
throw new TypeError(MESSAGE);
|
|
168
|
+
}
|
|
72
169
|
|
|
73
|
-
|
|
74
|
-
let focusTrap = FOCUSTRAPS_ALL.get(element);
|
|
170
|
+
let instance = instances.get(element);
|
|
75
171
|
|
|
76
|
-
if (
|
|
77
|
-
|
|
172
|
+
if (instance == null) {
|
|
173
|
+
instance = new OuiFocusTrap(getState(element, options));
|
|
78
174
|
|
|
79
|
-
|
|
175
|
+
instances.set(element, instance);
|
|
80
176
|
}
|
|
81
177
|
|
|
82
|
-
return
|
|
178
|
+
return instance;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function getOptions(
|
|
182
|
+
element: HTMLElement,
|
|
183
|
+
input?: OuiFocusTrapOptions,
|
|
184
|
+
): Required<OuiFocusTrapOptions> {
|
|
185
|
+
const options = isPlainObject(input) ? input : {};
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
contain:
|
|
189
|
+
typeof options.contain === 'boolean'
|
|
190
|
+
? options.contain
|
|
191
|
+
: element.hasAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN),
|
|
192
|
+
noescape:
|
|
193
|
+
typeof options.noescape === 'boolean'
|
|
194
|
+
? options.noescape
|
|
195
|
+
: element.hasAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function getState(element: HTMLElement, options?: OuiFocusTrapOptions): OuiFocusTrapState {
|
|
200
|
+
return {
|
|
201
|
+
element,
|
|
202
|
+
disabled: false,
|
|
203
|
+
options: getOptions(element, options),
|
|
204
|
+
};
|
|
83
205
|
}
|
|
84
206
|
|
|
85
207
|
function onEscape(event: KeyboardEvent): void {
|
|
86
|
-
let element = findAncestor(event,
|
|
208
|
+
let element = findAncestor(event, SELECTOR) as HTMLElement;
|
|
87
209
|
|
|
88
|
-
let
|
|
210
|
+
let instance = instances.get(element);
|
|
211
|
+
let state = states.get(instance!);
|
|
89
212
|
|
|
90
|
-
if (element == null ||
|
|
213
|
+
if (element == null || instance == null || state == null) {
|
|
91
214
|
return;
|
|
92
215
|
}
|
|
93
216
|
|
|
94
|
-
while (
|
|
95
|
-
element = findAncestor(
|
|
96
|
-
focusTrap.element.parentElement as HTMLElement,
|
|
97
|
-
ATTRIBUTE_SELECTOR,
|
|
98
|
-
) as HTMLElement;
|
|
217
|
+
while (state.disabled) {
|
|
218
|
+
element = findAncestor(state.element.parentElement as HTMLElement, SELECTOR) as HTMLElement;
|
|
99
219
|
|
|
100
|
-
|
|
220
|
+
instance = instances.get(element);
|
|
221
|
+
state = states.get(instance!);
|
|
101
222
|
|
|
102
|
-
if (element == null ||
|
|
223
|
+
if (element == null || instance == null || state == null) {
|
|
103
224
|
return;
|
|
104
225
|
}
|
|
105
226
|
|
|
106
|
-
if (!
|
|
227
|
+
if (!state.disabled) {
|
|
107
228
|
break;
|
|
108
229
|
}
|
|
109
230
|
}
|
|
110
231
|
|
|
111
|
-
|
|
232
|
+
instance?.disable();
|
|
112
233
|
}
|
|
113
234
|
|
|
114
235
|
function onFocusIn(event: Event): void {
|
|
115
|
-
const focusTrap =
|
|
236
|
+
const focusTrap = instances.get(findAncestor(event, SELECTOR) as HTMLElement);
|
|
116
237
|
|
|
117
238
|
lastTarget = focusTrap == null ? undefined : (event.target as HTMLElement);
|
|
118
239
|
}
|
|
@@ -133,38 +254,40 @@ function onKeydown(event: KeyboardEvent): void {
|
|
|
133
254
|
}
|
|
134
255
|
|
|
135
256
|
function onPointerdown(event: MouseEvent | TouchEvent): void {
|
|
136
|
-
const
|
|
137
|
-
const
|
|
257
|
+
const last = findAncestor(lastTarget as HTMLElement, SELECTOR) as HTMLElement;
|
|
258
|
+
const next = findAncestor(event, SELECTOR) as HTMLElement;
|
|
138
259
|
|
|
139
|
-
if (
|
|
140
|
-
if (
|
|
260
|
+
if (last != null && next !== last) {
|
|
261
|
+
if (states.get(instances.get(last)!)?.options.contain ?? false) {
|
|
141
262
|
event.preventDefault();
|
|
142
263
|
|
|
143
264
|
lastTarget?.focus();
|
|
144
265
|
}
|
|
145
266
|
}
|
|
146
267
|
|
|
147
|
-
if (
|
|
268
|
+
if (disabled.size === 0) {
|
|
148
269
|
return;
|
|
149
270
|
}
|
|
150
271
|
|
|
151
|
-
for (const focusTrap of
|
|
152
|
-
|
|
272
|
+
for (const focusTrap of disabled) {
|
|
273
|
+
const state = states.get(focusTrap);
|
|
274
|
+
|
|
275
|
+
if (state != null && state.element !== next) {
|
|
153
276
|
focusTrap.enable();
|
|
154
277
|
}
|
|
155
278
|
}
|
|
156
279
|
}
|
|
157
280
|
|
|
158
281
|
function onTab(event: KeyboardEvent): void {
|
|
159
|
-
const element = findAncestor(event,
|
|
282
|
+
const element = findAncestor(event, SELECTOR) as HTMLElement;
|
|
160
283
|
|
|
161
|
-
const
|
|
284
|
+
const instance = instances.get(element);
|
|
162
285
|
|
|
163
|
-
if (
|
|
286
|
+
if (instance == null) {
|
|
164
287
|
return;
|
|
165
288
|
}
|
|
166
289
|
|
|
167
|
-
if (!
|
|
290
|
+
if (!instance.disabled) {
|
|
168
291
|
event.preventDefault();
|
|
169
292
|
}
|
|
170
293
|
|
|
@@ -173,37 +296,30 @@ function onTab(event: KeyboardEvent): void {
|
|
|
173
296
|
const index = elements.indexOf(event.target as HTMLElement);
|
|
174
297
|
|
|
175
298
|
if (index === -1 || elements.length === 0) {
|
|
176
|
-
tabToTrap(
|
|
299
|
+
tabToTrap(instance, elements, element);
|
|
177
300
|
} else {
|
|
178
|
-
tabToElement(
|
|
301
|
+
tabToElement(instance, elements, index, event.shiftKey ? -1 : 1);
|
|
179
302
|
}
|
|
180
303
|
}
|
|
181
304
|
|
|
182
305
|
export function removeFocusTrap(element: HTMLElement): void {
|
|
183
|
-
|
|
184
|
-
FOCUSTRAPS_ALL.delete(element);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function setConnected(focusTrap: FocusTrap, value: boolean): void {
|
|
188
|
-
if (!focusTrap.embedded || focusTrap.connected === value) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
306
|
+
instances.get(element)?.destroy();
|
|
191
307
|
|
|
192
|
-
|
|
308
|
+
instances.delete(element);
|
|
193
309
|
}
|
|
194
310
|
|
|
195
|
-
function setDisabled(focusTrap:
|
|
196
|
-
|
|
311
|
+
function setDisabled(focusTrap: OuiFocusTrap, state: OuiFocusTrapState, value: boolean): void {
|
|
312
|
+
state.disabled = value;
|
|
197
313
|
|
|
198
314
|
if (value) {
|
|
199
|
-
|
|
315
|
+
disabled.add(focusTrap);
|
|
200
316
|
} else {
|
|
201
|
-
|
|
317
|
+
disabled.delete(focusTrap);
|
|
202
318
|
}
|
|
203
319
|
}
|
|
204
320
|
|
|
205
321
|
function tabToElement(
|
|
206
|
-
|
|
322
|
+
instance: OuiFocusTrap,
|
|
207
323
|
elements: Element[],
|
|
208
324
|
index: number,
|
|
209
325
|
modifier: number,
|
|
@@ -211,18 +327,18 @@ function tabToElement(
|
|
|
211
327
|
const {length} = elements;
|
|
212
328
|
const next = clamp(index + modifier, 0, length - 1, true);
|
|
213
329
|
|
|
214
|
-
if (
|
|
330
|
+
if (instance.disabled) {
|
|
215
331
|
if ((index === length - 1 && next === 0) || (index === 0 && next === length - 1)) {
|
|
216
332
|
lastTarget = undefined;
|
|
217
333
|
|
|
218
|
-
|
|
334
|
+
instance.enable();
|
|
219
335
|
}
|
|
220
336
|
|
|
221
337
|
return;
|
|
222
338
|
}
|
|
223
339
|
|
|
224
340
|
const element = elements[next] as HTMLElement;
|
|
225
|
-
const elementFocusTrap =
|
|
341
|
+
const elementFocusTrap = instances.get(element);
|
|
226
342
|
|
|
227
343
|
if (elementFocusTrap != null) {
|
|
228
344
|
elementFocusTrap.focus(modifier === -1);
|
|
@@ -234,15 +350,15 @@ function tabToElement(
|
|
|
234
350
|
}
|
|
235
351
|
|
|
236
352
|
function tabToTrap(
|
|
237
|
-
|
|
353
|
+
instance: OuiFocusTrap,
|
|
238
354
|
elements: Element[],
|
|
239
355
|
element: HTMLElement,
|
|
240
356
|
index?: number,
|
|
241
357
|
): void {
|
|
242
|
-
if (
|
|
358
|
+
if (instance.disabled) {
|
|
243
359
|
lastTarget = undefined;
|
|
244
360
|
|
|
245
|
-
|
|
361
|
+
instance.enable();
|
|
246
362
|
} else {
|
|
247
363
|
const next = elements.length === 0 ? element : elements.at(index ?? 0);
|
|
248
364
|
|
|
@@ -252,30 +368,40 @@ function tabToTrap(
|
|
|
252
368
|
}
|
|
253
369
|
}
|
|
254
370
|
|
|
255
|
-
//
|
|
371
|
+
// #endregion
|
|
256
372
|
|
|
257
|
-
|
|
373
|
+
// #region Variables
|
|
258
374
|
|
|
259
|
-
const
|
|
375
|
+
export const ATTRIBUTE_FOCUSTRAP = 'oui-focus-trap';
|
|
376
|
+
|
|
377
|
+
export const ATTRIBUTE_FOCUSTRAP_CONTAIN = `${ATTRIBUTE_FOCUSTRAP}-contain`;
|
|
378
|
+
|
|
379
|
+
export const ATTRIBUTE_FOCUSTRAP_NOESCAPE = `${ATTRIBUTE_FOCUSTRAP}-noescape`;
|
|
260
380
|
|
|
261
381
|
const EVENT_OPTIONS: AddEventListenerOptions = {
|
|
262
382
|
capture: true,
|
|
263
383
|
passive: false,
|
|
264
384
|
};
|
|
265
385
|
|
|
266
|
-
|
|
386
|
+
const MESSAGE = 'Element must be an HTMLElement or SVGElement';
|
|
387
|
+
|
|
388
|
+
const SELECTOR = `[${ATTRIBUTE_FOCUSTRAP}]`;
|
|
267
389
|
|
|
268
|
-
|
|
390
|
+
const disabled = new Set<OuiFocusTrap>();
|
|
269
391
|
|
|
270
|
-
const
|
|
392
|
+
const instances = new WeakMap<HTMLElement, OuiFocusTrap>();
|
|
271
393
|
|
|
272
|
-
const
|
|
394
|
+
const states = new WeakMap<OuiFocusTrap, OuiFocusTrapState>();
|
|
273
395
|
|
|
274
396
|
let lastTarget: HTMLElement | undefined;
|
|
275
397
|
|
|
276
|
-
//
|
|
398
|
+
// #endregion
|
|
399
|
+
|
|
400
|
+
// #region Initialization
|
|
277
401
|
|
|
278
402
|
on(document, 'focusin', onFocusIn, EVENT_OPTIONS);
|
|
279
403
|
on(document, 'keydown', onKeydown, EVENT_OPTIONS);
|
|
280
404
|
on(document, 'mousedown', onPointerdown, EVENT_OPTIONS);
|
|
281
405
|
on(document, 'touchstart', onPointerdown, EVENT_OPTIONS);
|
|
406
|
+
|
|
407
|
+
// #endregion
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {attributable} from '../internal/attributable';
|
|
2
|
-
import {createFocusTrap,
|
|
2
|
+
import {ATTRIBUTE_FOCUSTRAP, createFocusTrap, removeFocusTrap, type OuiFocusTrap} from './embedded';
|
|
3
3
|
|
|
4
|
-
attributable(
|
|
4
|
+
attributable(ATTRIBUTE_FOCUSTRAP, createFocusTrap, removeFocusTrap);
|
|
5
|
+
|
|
6
|
+
export {createFocusTrap, type OuiFocusTrap};
|
package/src/js/index.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import './focus-trap/standalone';
|
|
2
1
|
import './movable';
|
|
3
|
-
import './popover';
|
|
4
2
|
import './sortable';
|
|
3
|
+
import './toolbar';
|
|
5
4
|
|
|
6
|
-
export
|
|
5
|
+
export * from './dialog';
|
|
6
|
+
export * from './floatable/standalone';
|
|
7
|
+
export * from './focus-trap/standalone';
|
|
8
|
+
export * from './popover';
|
|
7
9
|
export * from './splitter';
|
|
8
|
-
export
|
|
10
|
+
export * from './tooltip';
|
|
@@ -4,14 +4,14 @@ import {getPosition, on} from '@oscarpalmer/toretto/event';
|
|
|
4
4
|
import {findAncestor} from '@oscarpalmer/toretto/find';
|
|
5
5
|
import {toggleStyles} from '@oscarpalmer/toretto/style';
|
|
6
6
|
import supportsTouch from '@oscarpalmer/toretto/touch';
|
|
7
|
-
import type {
|
|
8
|
-
import type {
|
|
7
|
+
import type {OuiMovable} from '../movable';
|
|
8
|
+
import type {OuiSortable} from '../sortable';
|
|
9
9
|
|
|
10
10
|
// #region Types
|
|
11
11
|
|
|
12
12
|
type Direction = 'horizontal' | 'vertical' | 'x' | 'y';
|
|
13
13
|
|
|
14
|
-
export abstract class
|
|
14
|
+
export abstract class OuiDraggable {
|
|
15
15
|
container: HTMLElement | undefined;
|
|
16
16
|
|
|
17
17
|
hasHandles: boolean | undefined;
|
|
@@ -45,25 +45,25 @@ export abstract class Draggable {
|
|
|
45
45
|
type DragBegin = (
|
|
46
46
|
event: MouseEvent | TouchEvent,
|
|
47
47
|
state: DraggableState,
|
|
48
|
-
draggable:
|
|
48
|
+
draggable: OuiDraggable,
|
|
49
49
|
element: HTMLElement,
|
|
50
50
|
handle: HTMLElement,
|
|
51
51
|
position: EventPosition,
|
|
52
52
|
) => void;
|
|
53
53
|
|
|
54
|
-
type DragCancel = (state: DraggableState, draggable:
|
|
54
|
+
type DragCancel = (state: DraggableState, draggable: OuiDraggable) => void;
|
|
55
55
|
|
|
56
56
|
type DragEnd = (
|
|
57
57
|
event: MouseEvent | TouchEvent,
|
|
58
58
|
state: DraggableState,
|
|
59
|
-
draggable:
|
|
59
|
+
draggable: OuiDraggable,
|
|
60
60
|
reset: () => void,
|
|
61
61
|
) => void;
|
|
62
62
|
|
|
63
63
|
type DragMove = (
|
|
64
64
|
event: MouseEvent | TouchEvent,
|
|
65
65
|
state: DraggableState,
|
|
66
|
-
draggable:
|
|
66
|
+
draggable: OuiDraggable,
|
|
67
67
|
position: DragMovePosition,
|
|
68
68
|
) => PlainObject | undefined;
|
|
69
69
|
|
|
@@ -81,8 +81,8 @@ export type DraggableBound<
|
|
|
81
81
|
};
|
|
82
82
|
|
|
83
83
|
type DraggableInstances = {
|
|
84
|
-
movable?:
|
|
85
|
-
sortable?:
|
|
84
|
+
movable?: OuiMovable;
|
|
85
|
+
sortable?: OuiSortable;
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
type DraggableOptions = {
|
|
@@ -94,25 +94,25 @@ type DraggableOptions = {
|
|
|
94
94
|
|
|
95
95
|
type DraggableOptionsContainer = {
|
|
96
96
|
attribute: string;
|
|
97
|
-
map: Map<HTMLElement, Set<
|
|
97
|
+
map: Map<HTMLElement, Set<OuiDraggable>>;
|
|
98
98
|
onDestroy?: DraggableOptionsContainerOnDestroy;
|
|
99
99
|
onInitialize?: DraggableOptionsContainerOnInitialize;
|
|
100
100
|
};
|
|
101
101
|
|
|
102
102
|
type DraggableOptionsContainerOnDestroy = (
|
|
103
|
-
draggable:
|
|
103
|
+
draggable: OuiDraggable,
|
|
104
104
|
container: HTMLElement,
|
|
105
105
|
empty: boolean,
|
|
106
106
|
) => void;
|
|
107
107
|
|
|
108
|
-
type DraggableOptionsContainerOnInitialize = (draggable:
|
|
108
|
+
type DraggableOptionsContainerOnInitialize = (draggable: OuiDraggable) => void;
|
|
109
109
|
|
|
110
110
|
type DraggableOptionsDirection = {
|
|
111
111
|
attribute: string;
|
|
112
112
|
onAfter?: DraggableOptionsDirectionOnAfter;
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
-
type DraggableOptionsDirectionOnAfter = (draggable:
|
|
115
|
+
type DraggableOptionsDirectionOnAfter = (draggable: OuiDraggable) => void;
|
|
116
116
|
|
|
117
117
|
type DraggableOptionsDrag = {
|
|
118
118
|
onBegin: DragBegin;
|
|
@@ -128,14 +128,14 @@ type DraggableOptionsPosition = {
|
|
|
128
128
|
|
|
129
129
|
type DraggableOptionsPositionGetOffset = (
|
|
130
130
|
state: DraggableState,
|
|
131
|
-
draggable:
|
|
131
|
+
draggable: OuiDraggable,
|
|
132
132
|
element: HTMLElement,
|
|
133
133
|
position: EventPosition,
|
|
134
134
|
) => EventPosition;
|
|
135
135
|
|
|
136
136
|
type DraggableOptionsPositionGetOriginal = (
|
|
137
137
|
state: DraggableState,
|
|
138
|
-
draggable:
|
|
138
|
+
draggable: OuiDraggable,
|
|
139
139
|
position: EventPosition,
|
|
140
140
|
) => EventPosition;
|
|
141
141
|
|
|
@@ -178,7 +178,7 @@ function getHandle(event: Event, isMovable: boolean): HTMLElement | null {
|
|
|
178
178
|
) as HTMLElement;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
function getNextPosition(draggable:
|
|
181
|
+
function getNextPosition(draggable: OuiDraggable, position: EventPosition): EventPosition {
|
|
182
182
|
let x = state.original?.x ?? 0;
|
|
183
183
|
let y = state.original?.y ?? 0;
|
|
184
184
|
|
|
@@ -394,7 +394,7 @@ function reset(): void {
|
|
|
394
394
|
styleToggler.remove();
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
function setContainer(draggable:
|
|
397
|
+
function setContainer(draggable: OuiDraggable, options: DraggableOptions): void {
|
|
398
398
|
const selector = draggable.element.getAttribute(options.container.attribute);
|
|
399
399
|
|
|
400
400
|
if (typeof selector !== 'string') {
|
|
@@ -420,7 +420,7 @@ function setContainer(draggable: Draggable, options: DraggableOptions): void {
|
|
|
420
420
|
options.container.onInitialize?.(draggable);
|
|
421
421
|
}
|
|
422
422
|
|
|
423
|
-
function setDirection(draggable:
|
|
423
|
+
function setDirection(draggable: OuiDraggable, options: DraggableOptions): void {
|
|
424
424
|
const direction = draggable.element.getAttribute(options.direction.attribute);
|
|
425
425
|
|
|
426
426
|
if (horizontals.has(direction as Direction)) {
|
|
@@ -432,7 +432,7 @@ function setDirection(draggable: Draggable, options: DraggableOptions): void {
|
|
|
432
432
|
options.direction.onAfter?.(draggable);
|
|
433
433
|
}
|
|
434
434
|
|
|
435
|
-
function unsetContainer(draggable:
|
|
435
|
+
function unsetContainer(draggable: OuiDraggable, options: DraggableOptions): void {
|
|
436
436
|
const {container} = draggable;
|
|
437
437
|
|
|
438
438
|
if (container == null) {
|
|
@@ -499,7 +499,7 @@ const styleToggler = toggleStyles(document.body, {
|
|
|
499
499
|
|
|
500
500
|
const verticals = new Set<Direction>(['vertical', 'y']);
|
|
501
501
|
|
|
502
|
-
let current:
|
|
502
|
+
let current: OuiMovable | OuiSortable | undefined;
|
|
503
503
|
|
|
504
504
|
// #endregion
|
|
505
505
|
|