@oscarpalmer/oui 0.26.1 → 0.27.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/floatable.css +0 -2
- package/dist/css/message.css +1 -0
- package/dist/css/reset.css +1 -0
- package/dist/js/dialog.d.mts +2 -0
- package/dist/js/dialog.mjs +16 -1
- package/dist/js/draggable-zszaW1qS.d.mts +155 -0
- package/dist/js/floatable/floatable.embedded.d.mts +2 -0
- package/dist/js/floatable/{embedded.mjs → floatable.embedded.mjs} +16 -11
- package/dist/js/floatable/floatable.standalone.d.mts +2 -0
- package/dist/js/floatable/floatable.standalone.mjs +2 -0
- package/dist/js/{embedded-CSOh5njI.d.mts → floatable.embedded-YxGwzgbE.d.mts} +5 -2
- package/dist/js/focus-trap/focus-trap.embedded.d.mts +2 -0
- package/dist/js/focus-trap/{embedded.mjs → focus-trap.embedded.mjs} +17 -15
- package/dist/js/focus-trap/focus-trap.standalone.d.mts +2 -0
- package/dist/js/focus-trap/focus-trap.standalone.mjs +2 -0
- package/dist/js/{embedded-CHK82Uh5.d.mts → focus-trap.embedded-DR8NpZfr.d.mts} +18 -18
- package/dist/js/index.d.mts +4 -3
- package/dist/js/index.mjs +8 -7
- package/dist/js/internal/draggable.d.mts +2 -2
- package/dist/js/internal/draggable.mjs +146 -94
- package/dist/js/movable/movable.embedded.d.mts +2 -0
- package/dist/js/movable/movable.embedded.mjs +184 -0
- package/dist/js/movable/movable.standalone.d.mts +2 -0
- package/dist/js/movable/movable.standalone.mjs +2 -0
- package/dist/js/popover.d.mts +2 -2
- package/dist/js/popover.mjs +4 -3
- package/dist/js/sortable/sortable.embedded.d.mts +2 -0
- package/dist/js/{sortable.mjs → sortable/sortable.embedded.mjs} +88 -63
- package/dist/js/sortable/sortable.standalone.d.mts +2 -0
- package/dist/js/sortable/sortable.standalone.mjs +2 -0
- package/dist/js/splitter.mjs +5 -5
- package/dist/js/toolbar.mjs +6 -6
- package/dist/js/tooltip.d.mts +2 -2
- package/dist/js/tooltip.mjs +36 -33
- package/package.json +11 -11
- package/src/css/floatable.scss +0 -2
- package/src/css/message.scss +1 -0
- package/src/css/reset.scss +1 -0
- package/src/js/dialog.ts +31 -1
- package/src/js/floatable/{embedded.ts → floatable.embedded.ts} +18 -10
- package/src/js/floatable/floatable.standalone.ts +6 -0
- package/src/js/focus-trap/{embedded.ts → focus-trap.embedded.ts} +20 -17
- package/src/js/focus-trap/focus-trap.standalone.ts +1 -0
- package/src/js/index.ts +4 -4
- package/src/js/internal/draggable.ts +309 -168
- package/src/js/movable/movable.embedded.ts +328 -0
- package/src/js/movable/movable.standalone.ts +2 -0
- package/src/js/popover.ts +3 -2
- package/src/js/{sortable.ts → sortable/sortable.embedded.ts} +170 -103
- package/src/js/sortable/sortable.standalone.ts +2 -0
- package/src/js/tooltip.ts +49 -43
- package/dist/js/floatable/embedded.d.mts +0 -2
- package/dist/js/floatable/standalone.d.mts +0 -2
- package/dist/js/floatable/standalone.mjs +0 -2
- package/dist/js/focus-trap/embedded.d.mts +0 -2
- package/dist/js/focus-trap/standalone.d.mts +0 -2
- package/dist/js/focus-trap/standalone.mjs +0 -6
- package/dist/js/movable-dNqBctx3.d.mts +0 -101
- package/dist/js/movable.d.mts +0 -2
- package/dist/js/movable.mjs +0 -152
- package/dist/js/sortable.d.mts +0 -2
- package/src/js/floatable/standalone.ts +0 -1
- package/src/js/focus-trap/standalone.ts +0 -6
- package/src/js/movable.ts +0 -260
package/src/js/dialog.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {on} from '@oscarpalmer/toretto/event';
|
|
2
2
|
import type {RemovableEventListener} from '@oscarpalmer/toretto/models';
|
|
3
|
-
import {getOnBeforeToggleListener} from './floatable/embedded';
|
|
3
|
+
import {getOnBeforeToggleListener} from './floatable/floatable.embedded';
|
|
4
4
|
import {attributable} from './internal/attributable';
|
|
5
|
+
import {ATTRIBUTE_MOVABLE_HANDLE} from './movable/movable.embedded';
|
|
6
|
+
import {createMovable, type OuiMovable} from './movable/movable.standalone';
|
|
5
7
|
|
|
6
8
|
// #region Types
|
|
7
9
|
|
|
@@ -79,6 +81,7 @@ type OuiDialogState = {
|
|
|
79
81
|
element: HTMLDialogElement;
|
|
80
82
|
listeners: RemovableEventListener[];
|
|
81
83
|
modal: boolean;
|
|
84
|
+
movable?: OuiMovable;
|
|
82
85
|
};
|
|
83
86
|
|
|
84
87
|
// #endregion
|
|
@@ -120,6 +123,22 @@ function getDialog(element: HTMLDialogElement): OuiDialog | undefined {
|
|
|
120
123
|
return states.get(element)?.dialog;
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
function getMovable(element: HTMLDialogElement): OuiMovable | undefined {
|
|
127
|
+
const handles = element.querySelectorAll(SELECTOR_MOVER);
|
|
128
|
+
|
|
129
|
+
if (handles.length === 0) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (const handle of handles) {
|
|
134
|
+
handle.setAttribute(ATTRIBUTE_MOVABLE_HANDLE, '');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return createMovable(element, {
|
|
138
|
+
container: element.getAttribute(ATTRIBUTE_CONTAINER) ?? undefined,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
123
142
|
function getState(element: HTMLDialogElement): OuiDialogState {
|
|
124
143
|
const state: OuiDialogState = {
|
|
125
144
|
element,
|
|
@@ -136,9 +155,15 @@ function getState(element: HTMLDialogElement): OuiDialogState {
|
|
|
136
155
|
|
|
137
156
|
element.setAttribute(ARIA_MODAL, String(modal));
|
|
138
157
|
element.setAttribute(ATTRIBUTE_OPEN, '');
|
|
158
|
+
|
|
159
|
+
element.focus();
|
|
139
160
|
} else {
|
|
140
161
|
element.removeAttribute(ATTRIBUTE_OPEN);
|
|
141
162
|
element.setAttribute(ARIA_MODAL, String(state.modal));
|
|
163
|
+
|
|
164
|
+
element.style.inset = '';
|
|
165
|
+
element.style.position = '';
|
|
166
|
+
element.style.transform = '';
|
|
142
167
|
}
|
|
143
168
|
}),
|
|
144
169
|
],
|
|
@@ -146,6 +171,7 @@ function getState(element: HTMLDialogElement): OuiDialogState {
|
|
|
146
171
|
};
|
|
147
172
|
|
|
148
173
|
state.dialog = new OuiDialog(state);
|
|
174
|
+
state.movable = getMovable(element);
|
|
149
175
|
|
|
150
176
|
return state;
|
|
151
177
|
}
|
|
@@ -170,6 +196,8 @@ const ARIA_MODAL = 'aria-modal';
|
|
|
170
196
|
|
|
171
197
|
const ATTRIBUTE = 'oui-dialog';
|
|
172
198
|
|
|
199
|
+
const ATTRIBUTE_CONTAINER = `${ATTRIBUTE}-container`;
|
|
200
|
+
|
|
173
201
|
const ATTRIBUTE_OPEN = `${ATTRIBUTE}-open`;
|
|
174
202
|
|
|
175
203
|
const COMMAND_SHOW_MODAL = 'show-modal';
|
|
@@ -178,6 +206,8 @@ const EVENT_TOGGLE = 'toggle';
|
|
|
178
206
|
|
|
179
207
|
const MESSAGE = 'The element must be an instance of HTMLDialogElement';
|
|
180
208
|
|
|
209
|
+
const SELECTOR_MOVER = `[${ATTRIBUTE}-mover]`;
|
|
210
|
+
|
|
181
211
|
const SELECTOR_MODAL = ':modal';
|
|
182
212
|
|
|
183
213
|
const TRUE = 'true';
|
|
@@ -5,7 +5,7 @@ import type {RemovableEventListener} from '@oscarpalmer/toretto/models';
|
|
|
5
5
|
|
|
6
6
|
// #region Types
|
|
7
7
|
|
|
8
|
-
type CreateOuiFloatableOptions = {
|
|
8
|
+
export type CreateOuiFloatableOptions = {
|
|
9
9
|
/**
|
|
10
10
|
* Open the floatable when created? _(defaults to `true`)_
|
|
11
11
|
*/
|
|
@@ -50,10 +50,8 @@ export class OuiFloatable {
|
|
|
50
50
|
content.popover = 'manual';
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
anchor.style.anchorName = anchorName;
|
|
56
|
-
content.style.positionAnchor = anchorName;
|
|
53
|
+
anchor.style.anchorName = state.name;
|
|
54
|
+
content.style.positionAnchor = state.name;
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
/**
|
|
@@ -105,6 +103,7 @@ export class OuiFloatable {
|
|
|
105
103
|
export type OuiFloatableOptions = {
|
|
106
104
|
attribute?: string;
|
|
107
105
|
position: OuiFloatablePosition;
|
|
106
|
+
reusable: boolean;
|
|
108
107
|
};
|
|
109
108
|
|
|
110
109
|
export type OuiFloatablePosition =
|
|
@@ -124,6 +123,7 @@ export type OuiFloatablePosition =
|
|
|
124
123
|
type OuiFloatableState = {
|
|
125
124
|
anchor: HTMLElement;
|
|
126
125
|
content: HTMLElement;
|
|
126
|
+
name: string;
|
|
127
127
|
options: OuiFloatableOptions;
|
|
128
128
|
};
|
|
129
129
|
|
|
@@ -171,6 +171,7 @@ export function createFloatable(
|
|
|
171
171
|
content,
|
|
172
172
|
{
|
|
173
173
|
position,
|
|
174
|
+
reusable: false,
|
|
174
175
|
},
|
|
175
176
|
true,
|
|
176
177
|
);
|
|
@@ -194,12 +195,14 @@ function createInstance(
|
|
|
194
195
|
throw new TypeError(MESSAGE);
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
let floatable = instances.get(content);
|
|
198
|
+
let floatable = options.reusable ? undefined : instances.get(content);
|
|
198
199
|
|
|
199
200
|
if (floatable == null) {
|
|
200
201
|
floatable = new OuiFloatable(getState(anchor, content, options), standalone);
|
|
201
202
|
|
|
202
|
-
|
|
203
|
+
if (!options.reusable) {
|
|
204
|
+
instances.set(content, floatable);
|
|
205
|
+
}
|
|
203
206
|
}
|
|
204
207
|
|
|
205
208
|
return floatable;
|
|
@@ -212,7 +215,7 @@ export function getOnBeforeToggleListener(element: HTMLElement): RemovableEventL
|
|
|
212
215
|
event => {
|
|
213
216
|
const {newState, source} = event;
|
|
214
217
|
|
|
215
|
-
if (newState ===
|
|
218
|
+
if (newState === FLOATABLE_STATE_OPEN && source?.getAttribute(ARIA_DISABLED) === TRUE) {
|
|
216
219
|
event.preventDefault();
|
|
217
220
|
}
|
|
218
221
|
},
|
|
@@ -255,9 +258,12 @@ function getState(
|
|
|
255
258
|
content: HTMLElement,
|
|
256
259
|
options: OuiFloatableOptions,
|
|
257
260
|
): OuiFloatableState {
|
|
261
|
+
const name = getAnchorName(anchor);
|
|
262
|
+
|
|
258
263
|
const state: OuiFloatableState = {
|
|
259
264
|
anchor,
|
|
260
265
|
content,
|
|
266
|
+
name,
|
|
261
267
|
options,
|
|
262
268
|
};
|
|
263
269
|
|
|
@@ -266,6 +272,7 @@ function getState(
|
|
|
266
272
|
|
|
267
273
|
export function removeFloatable(content: HTMLElement): void {
|
|
268
274
|
instances.get(content)?.destroy();
|
|
275
|
+
|
|
269
276
|
instances.delete(content);
|
|
270
277
|
}
|
|
271
278
|
|
|
@@ -274,6 +281,7 @@ function setPosition(state: OuiFloatableState, override?: OuiFloatablePosition):
|
|
|
274
281
|
|
|
275
282
|
const area = AREAS[position];
|
|
276
283
|
|
|
284
|
+
state.content.style.positionAnchor = state.name;
|
|
277
285
|
state.content.style.positionArea = area;
|
|
278
286
|
|
|
279
287
|
state.content.setAttribute(ATTRIBUTE_POSITION, POSITIONS[area]);
|
|
@@ -306,14 +314,14 @@ const ATTRIBUTE_POSITION = 'oui-position';
|
|
|
306
314
|
|
|
307
315
|
const EVENT_BEFORE = 'beforetoggle';
|
|
308
316
|
|
|
317
|
+
export const FLOATABLE_STATE_OPEN = 'open';
|
|
318
|
+
|
|
309
319
|
const MESSAGE = 'Anchor and content must be an HTMLElement or SVGElement';
|
|
310
320
|
|
|
311
321
|
const POSITIONS = Object.fromEntries(
|
|
312
322
|
Object.entries(AREAS).map(([position, area]) => [area, position]),
|
|
313
323
|
) as Record<string, OuiFloatablePosition>;
|
|
314
324
|
|
|
315
|
-
const STATE_OPEN = 'open';
|
|
316
|
-
|
|
317
325
|
const TRUE = 'true';
|
|
318
326
|
|
|
319
327
|
const instances = new WeakMap<HTMLElement, OuiFloatable>();
|
|
@@ -4,6 +4,7 @@ import {on} from '@oscarpalmer/toretto/event';
|
|
|
4
4
|
import {findAncestor} from '@oscarpalmer/toretto/find';
|
|
5
5
|
import {getFocusable} from '@oscarpalmer/toretto/focusable';
|
|
6
6
|
import {isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
|
|
7
|
+
import {attributable} from '../internal/attributable';
|
|
7
8
|
|
|
8
9
|
// #region Types
|
|
9
10
|
|
|
@@ -14,14 +15,14 @@ export class OuiFocusTrap {
|
|
|
14
15
|
readonly #state: OuiFocusTrapState;
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
* Is focused maintained within the
|
|
18
|
+
* Is focused maintained within the _focus trap_ when clicking outside of it?
|
|
18
19
|
*/
|
|
19
20
|
get contain(): boolean {
|
|
20
21
|
return this.#state.element.hasAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
|
-
* Should focus be maintained within the
|
|
25
|
+
* Should focus be maintained within the _focus trap_ when clicking outside of it?
|
|
25
26
|
*/
|
|
26
27
|
set contain(value: boolean) {
|
|
27
28
|
if (value === true) {
|
|
@@ -32,14 +33,14 @@ export class OuiFocusTrap {
|
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
|
-
* Is the
|
|
36
|
+
* Is the _focus trap_ disabled?
|
|
36
37
|
*/
|
|
37
38
|
get disabled(): boolean {
|
|
38
39
|
return this.#state.disabled;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
|
-
* Should the
|
|
43
|
+
* Should the _focus trap_ be disabled?
|
|
43
44
|
*/
|
|
44
45
|
set disabled(value: boolean) {
|
|
45
46
|
if (value === true) {
|
|
@@ -50,14 +51,14 @@ export class OuiFocusTrap {
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
/**
|
|
53
|
-
* Is focus allowed to escape when pressing _Escape_ within the
|
|
54
|
+
* Is focus allowed to escape when pressing _Escape_ within the _focus trap_?
|
|
54
55
|
*/
|
|
55
56
|
get noescape(): boolean {
|
|
56
57
|
return this.#state.element.hasAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE);
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/**
|
|
60
|
-
* Should the
|
|
61
|
+
* Should the _focus trap_ allow focus to escape when pressing _Escape_?
|
|
61
62
|
*/
|
|
62
63
|
set noescape(value: boolean) {
|
|
63
64
|
if (value === true) {
|
|
@@ -82,7 +83,7 @@ export class OuiFocusTrap {
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
/**
|
|
85
|
-
* Destroys the
|
|
86
|
+
* Destroys the _focus trap_
|
|
86
87
|
*/
|
|
87
88
|
destroy(): void {
|
|
88
89
|
if (this.#destroyed) {
|
|
@@ -105,7 +106,7 @@ export class OuiFocusTrap {
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
/**
|
|
108
|
-
* Disables the
|
|
109
|
+
* Disables the _focus trap_
|
|
109
110
|
*/
|
|
110
111
|
disable(): void {
|
|
111
112
|
if (!this.#destroyed && !(this.disabled || this.#state.options.noescape)) {
|
|
@@ -114,7 +115,7 @@ export class OuiFocusTrap {
|
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
/**
|
|
117
|
-
* Enables the
|
|
118
|
+
* Enables the _focus trap_
|
|
118
119
|
*/
|
|
119
120
|
enable(): void {
|
|
120
121
|
if (!this.#destroyed && this.disabled) {
|
|
@@ -123,9 +124,9 @@ export class OuiFocusTrap {
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
/**
|
|
126
|
-
* Focuses the
|
|
127
|
+
* Focuses the _focus trap_
|
|
127
128
|
*
|
|
128
|
-
* @param last When `true`, focuses the last focusable element within the
|
|
129
|
+
* @param last When `true`, focuses the last focusable element within the _focus trap_ instead of the first
|
|
129
130
|
*/
|
|
130
131
|
focus(last: boolean): void {
|
|
131
132
|
if (!this.#destroyed && !this.disabled) {
|
|
@@ -134,13 +135,13 @@ export class OuiFocusTrap {
|
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
|
|
137
|
-
type OuiFocusTrapOptions = {
|
|
138
|
+
export type OuiFocusTrapOptions = {
|
|
138
139
|
/**
|
|
139
|
-
* Should focus be maintained within the
|
|
140
|
+
* Should focus be maintained within the _focus trap_ when clicking outside of it?
|
|
140
141
|
*/
|
|
141
142
|
contain?: boolean;
|
|
142
143
|
/**
|
|
143
|
-
* Should the
|
|
144
|
+
* Should the _focus trap_ allow focus to escape when pressing _Escape_?
|
|
144
145
|
*/
|
|
145
146
|
noescape?: boolean;
|
|
146
147
|
};
|
|
@@ -156,11 +157,11 @@ type OuiFocusTrapState = {
|
|
|
156
157
|
// #region Functions
|
|
157
158
|
|
|
158
159
|
/**
|
|
159
|
-
* Creates _(or retrieves)_ a
|
|
160
|
+
* Creates _(or retrieves)_ a _focus trap_ for an element
|
|
160
161
|
*
|
|
161
162
|
* @param element Element to trap focus within
|
|
162
|
-
* @param options
|
|
163
|
-
* @returns
|
|
163
|
+
* @param options _Focus trap_ options
|
|
164
|
+
* @returns _Focus trap_ instance
|
|
164
165
|
*/
|
|
165
166
|
export function createFocusTrap(element: HTMLElement, options?: OuiFocusTrapOptions): OuiFocusTrap {
|
|
166
167
|
if (!isHTMLOrSVGElement(element)) {
|
|
@@ -399,6 +400,8 @@ let lastTarget: HTMLElement | undefined;
|
|
|
399
400
|
|
|
400
401
|
// #region Initialization
|
|
401
402
|
|
|
403
|
+
attributable(ATTRIBUTE_FOCUSTRAP, createFocusTrap, removeFocusTrap);
|
|
404
|
+
|
|
402
405
|
on(document, 'focusin', onFocusIn, EVENT_OPTIONS);
|
|
403
406
|
on(document, 'keydown', onKeydown, EVENT_OPTIONS);
|
|
404
407
|
on(document, 'mousedown', onPointerdown, EVENT_OPTIONS);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {createFocusTrap, type OuiFocusTrap, type OuiFocusTrapOptions} from './focus-trap.embedded';
|
package/src/js/index.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import './
|
|
2
|
-
import './sortable';
|
|
1
|
+
import './sortable/sortable.embedded';
|
|
3
2
|
import './toolbar';
|
|
4
3
|
|
|
5
4
|
export * from './dialog';
|
|
6
|
-
export * from './floatable/standalone';
|
|
7
|
-
export * from './focus-trap/standalone';
|
|
5
|
+
export * from './floatable/floatable.standalone';
|
|
6
|
+
export * from './focus-trap/focus-trap.standalone';
|
|
7
|
+
export * from './movable/movable.standalone';
|
|
8
8
|
export * from './popover';
|
|
9
9
|
export * from './splitter';
|
|
10
10
|
export * from './tooltip';
|