@oscarpalmer/oui 0.19.0 → 0.21.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/a11y.css +0 -1
- package/dist/css/form.css +0 -1
- package/dist/css/popover.css +22 -0
- package/dist/css/reset.css +8 -8
- package/dist/css/table.css +1 -1
- package/dist/css/tooltip.css +43 -0
- package/dist/js/focus-trap/embedded.d.mts +26 -0
- package/dist/js/focus-trap/{embedded.js → embedded.mjs} +11 -9
- package/dist/js/focus-trap/standalone.d.mts +1 -0
- package/dist/js/focus-trap/{standalone.js → standalone.mjs} +5 -2
- package/dist/js/index.d.mts +4 -0
- package/dist/js/index.mjs +7 -0
- package/dist/js/internal/attributable.d.mts +4 -0
- package/dist/js/{attributable.full.js → internal/attributable.mjs} +8 -1
- package/dist/js/internal/draggable.d.mts +2 -0
- package/dist/js/internal/draggable.mjs +212 -0
- package/dist/js/internal/floatable.d.mts +26 -0
- package/dist/js/{floatable.js → internal/floatable.mjs} +73 -50
- package/dist/js/movable-BEo2LbUI.d.mts +101 -0
- package/dist/js/movable.d.mts +2 -0
- package/dist/js/movable.mjs +152 -0
- package/dist/js/popover.d.mts +20 -0
- package/dist/js/{popover.js → popover.mjs} +10 -8
- package/dist/js/sortable.d.mts +2 -0
- package/dist/js/sortable.mjs +243 -0
- package/dist/js/splitter.d.mts +25 -0
- package/dist/js/{splitter.js → splitter.mjs} +62 -60
- package/dist/js/tooltip.d.mts +4 -0
- package/dist/js/{tooltip.js → tooltip.mjs} +22 -20
- package/package.json +66 -69
- package/src/css/mixins.scss +30 -1
- package/src/css/popover.scss +6 -1
- package/src/css/reset.scss +4 -4
- package/src/css/table.scss +1 -1
- package/src/css/tooltip.scss +55 -1
- package/src/js/focus-trap/embedded.ts +4 -10
- package/src/js/focus-trap/standalone.ts +1 -1
- package/src/js/index.ts +3 -1
- package/src/js/{attributable.ts → internal/attributable.ts} +11 -1
- package/src/js/internal/draggable.ts +515 -0
- package/src/js/{floatable.ts → internal/floatable.ts} +141 -63
- package/src/js/movable.ts +260 -0
- package/src/js/popover.ts +1 -1
- package/src/js/sortable.ts +467 -0
- package/src/js/splitter.ts +3 -9
- package/src/js/tooltip.ts +11 -9
- package/dist/js/attributable.js +0 -36
- package/dist/js/floatable.full.js +0 -398
- package/dist/js/focus-trap/embedded.full.js +0 -408
- package/dist/js/focus-trap/standalone.full.js +0 -447
- package/dist/js/index.js +0 -5
- package/dist/js/oui.full.js +0 -1573
- package/dist/js/popover.full.js +0 -760
- package/dist/js/splitter.full.js +0 -769
- package/dist/js/tooltip.full.js +0 -613
- package/types/attributable.d.ts +0 -1
- package/types/floatable.d.ts +0 -24
- package/types/focus-trap/embedded.d.ts +0 -24
- package/types/focus-trap/standalone.d.ts +0 -1
- package/types/index.d.ts +0 -4
- package/types/popover.d.ts +0 -17
- package/types/splitter.d.ts +0 -23
- package/types/tooltip.d.ts +0 -2
|
@@ -91,7 +91,6 @@ export class Floatable {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
type FloatableWindow = Window & {
|
|
94
|
-
// biome-ignore lint/style/useNamingConvention: Non-standard name to avoid conflicts
|
|
95
94
|
_oscarpalmer_oui_floatable: State;
|
|
96
95
|
};
|
|
97
96
|
|
|
@@ -159,7 +158,7 @@ function closeAbove(element: HTMLElement): void {
|
|
|
159
158
|
}
|
|
160
159
|
|
|
161
160
|
while (index < state.order.length - 1) {
|
|
162
|
-
|
|
161
|
+
state.order.pop()?.toggle(false, true);
|
|
163
162
|
}
|
|
164
163
|
}
|
|
165
164
|
|
|
@@ -171,14 +170,14 @@ function closeAll(): void {
|
|
|
171
170
|
state?.active.clear();
|
|
172
171
|
|
|
173
172
|
for (const floatable of floatables) {
|
|
174
|
-
|
|
173
|
+
floatable.toggle(false, true);
|
|
175
174
|
}
|
|
176
175
|
}
|
|
177
176
|
|
|
178
177
|
function closeNonInteractive(state: State): void {
|
|
179
178
|
for (const floatable of state.active) {
|
|
180
179
|
if (!floatable.options.interactive) {
|
|
181
|
-
|
|
180
|
+
floatable.toggle(false);
|
|
182
181
|
}
|
|
183
182
|
}
|
|
184
183
|
}
|
|
@@ -193,78 +192,157 @@ export function deactivate(floatable: Floatable): void {
|
|
|
193
192
|
floatable.options.onAfter?.(false);
|
|
194
193
|
}
|
|
195
194
|
|
|
195
|
+
function getAttribute(
|
|
196
|
+
position: Position,
|
|
197
|
+
anchor: DOMRect,
|
|
198
|
+
top: number,
|
|
199
|
+
left: number,
|
|
200
|
+
): Position | undefined {
|
|
201
|
+
switch (position) {
|
|
202
|
+
case 'horizontal':
|
|
203
|
+
case 'horizontal-bottom':
|
|
204
|
+
case 'horizontal-top':
|
|
205
|
+
return position.replace('horizontal', left >= anchor.right ? 'right' : 'left') as Position;
|
|
206
|
+
|
|
207
|
+
case 'vertical':
|
|
208
|
+
case 'vertical-end':
|
|
209
|
+
case 'vertical-start':
|
|
210
|
+
return position.replace('vertical', top >= anchor.bottom ? 'bottom' : 'top') as Position;
|
|
211
|
+
|
|
212
|
+
default:
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function getMargin(): number {
|
|
218
|
+
try {
|
|
219
|
+
const fontsize = parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
220
|
+
|
|
221
|
+
if (Number.isNaN(fontsize)) {
|
|
222
|
+
return 5;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const margin = fontsize / 2;
|
|
226
|
+
|
|
227
|
+
return margin < 5 ? 5 : margin;
|
|
228
|
+
} catch {
|
|
229
|
+
return 5;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
196
233
|
function getState(): State {
|
|
197
234
|
return (window as unknown as FloatableWindow)._oscarpalmer_oui_floatable;
|
|
198
235
|
}
|
|
199
236
|
|
|
200
|
-
function getX(anchor: DOMRect, content: DOMRect, position: Position): number {
|
|
201
|
-
if (position
|
|
202
|
-
const
|
|
237
|
+
function getX(anchor: DOMRect, content: DOMRect, position: Position, margin: number): number {
|
|
238
|
+
if (position === 'above' || position === 'below' || position === 'vertical') {
|
|
239
|
+
const center = anchor.left + anchor.width / 2;
|
|
240
|
+
const width = content.width / 2;
|
|
203
241
|
|
|
204
|
-
|
|
205
|
-
|
|
242
|
+
if (center + width + margin >= document.body.clientWidth) {
|
|
243
|
+
return document.body.clientWidth - content.width - margin / 2;
|
|
244
|
+
}
|
|
206
245
|
|
|
207
|
-
|
|
208
|
-
|
|
246
|
+
if (center - width - margin <= 0) {
|
|
247
|
+
return margin / 2;
|
|
248
|
+
}
|
|
209
249
|
|
|
210
|
-
return
|
|
250
|
+
return center - width;
|
|
211
251
|
}
|
|
212
252
|
|
|
213
|
-
if (position.startsWith(
|
|
253
|
+
if (position.startsWith('end')) {
|
|
214
254
|
return anchor.right;
|
|
215
255
|
}
|
|
216
256
|
|
|
217
|
-
if (position.startsWith(
|
|
257
|
+
if (position.startsWith('start')) {
|
|
218
258
|
return anchor.left - content.width;
|
|
219
259
|
}
|
|
220
260
|
|
|
221
|
-
if (position.
|
|
222
|
-
|
|
223
|
-
|
|
261
|
+
if (position.endsWith('end')) {
|
|
262
|
+
return anchor.right - content.width - margin <= 0 ? margin / 2 : anchor.right - content.width;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (position.endsWith('start')) {
|
|
266
|
+
if (anchor.left + content.width + margin >= document.body.clientWidth) {
|
|
267
|
+
return document.body.clientWidth - content.width - margin / 2;
|
|
224
268
|
}
|
|
225
269
|
|
|
226
|
-
return anchor.left -
|
|
270
|
+
return anchor.left - margin <= 0 ? margin / 2 : anchor.left;
|
|
227
271
|
}
|
|
228
272
|
|
|
229
|
-
|
|
273
|
+
if (!position.startsWith('horizontal')) {
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (anchor.right + content.width + margin >= document.body.clientWidth) {
|
|
278
|
+
return anchor.left - content.width;
|
|
279
|
+
}
|
|
230
280
|
|
|
231
|
-
return
|
|
281
|
+
return anchor.right;
|
|
232
282
|
}
|
|
233
283
|
|
|
234
|
-
function getY(
|
|
235
|
-
|
|
284
|
+
function getY(
|
|
285
|
+
anchor: DOMRect,
|
|
286
|
+
content: DOMRect,
|
|
287
|
+
position: Position,
|
|
288
|
+
margin: number,
|
|
289
|
+
preferAbove: boolean,
|
|
290
|
+
): number {
|
|
291
|
+
if (position === 'end' || position === 'start' || position === 'horizontal') {
|
|
292
|
+
const center = anchor.top + anchor.height / 2;
|
|
293
|
+
const height = content.height / 2;
|
|
294
|
+
|
|
295
|
+
if (center + height + margin >= document.body.clientHeight) {
|
|
296
|
+
return document.body.clientHeight - content.height - margin / 2;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (center - height - margin <= 0) {
|
|
300
|
+
return margin / 2;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return center - height;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (position.startsWith('above')) {
|
|
236
307
|
return anchor.top - content.height;
|
|
237
308
|
}
|
|
238
309
|
|
|
239
|
-
if (position.startsWith(
|
|
310
|
+
if (position.startsWith('below')) {
|
|
240
311
|
return anchor.bottom;
|
|
241
312
|
}
|
|
242
313
|
|
|
243
|
-
if (position.endsWith(
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
314
|
+
if (position.endsWith('bottom')) {
|
|
315
|
+
return anchor.bottom - content.height - margin <= 0
|
|
316
|
+
? margin / 2
|
|
317
|
+
: anchor.bottom - content.height;
|
|
247
318
|
}
|
|
248
319
|
|
|
249
|
-
if (position.endsWith(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
320
|
+
if (position.endsWith('top')) {
|
|
321
|
+
return anchor.top + content.height + margin >= document.body.clientHeight
|
|
322
|
+
? document.body.clientHeight - content.height - margin
|
|
323
|
+
: anchor.top;
|
|
253
324
|
}
|
|
254
325
|
|
|
255
|
-
if (position.startsWith(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
326
|
+
if (!position.startsWith('vertical')) {
|
|
327
|
+
return 0;
|
|
328
|
+
}
|
|
259
329
|
|
|
260
|
-
|
|
330
|
+
if (preferAbove) {
|
|
331
|
+
if (
|
|
332
|
+
anchor.top - content.height - margin <= 0 &&
|
|
333
|
+
anchor.bottom + content.height + margin <= document.body.clientHeight
|
|
334
|
+
) {
|
|
261
335
|
return anchor.bottom;
|
|
262
336
|
}
|
|
263
337
|
|
|
264
338
|
return anchor.top - content.height;
|
|
265
339
|
}
|
|
266
340
|
|
|
267
|
-
|
|
341
|
+
if (anchor.bottom + content.height + margin >= document.body.clientHeight) {
|
|
342
|
+
return anchor.top - content.height;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return anchor.bottom;
|
|
268
346
|
}
|
|
269
347
|
|
|
270
348
|
function initialize(floatable: Floatable): void {
|
|
@@ -294,7 +372,7 @@ function isDisabled(element: HTMLElement): boolean {
|
|
|
294
372
|
}
|
|
295
373
|
|
|
296
374
|
function onClick(event: PointerEvent): void {
|
|
297
|
-
const related = findAncestor(event
|
|
375
|
+
const related = findAncestor(event, SELECTOR_ALL);
|
|
298
376
|
|
|
299
377
|
if (!(related instanceof HTMLElement)) {
|
|
300
378
|
closeAll();
|
|
@@ -318,7 +396,7 @@ function onKeyDown(event: KeyboardEvent): void {
|
|
|
318
396
|
|
|
319
397
|
closeNonInteractive(state);
|
|
320
398
|
|
|
321
|
-
const related = findAncestor(event
|
|
399
|
+
const related = findAncestor(event, SELECTOR_CONTENT);
|
|
322
400
|
|
|
323
401
|
if (!(related instanceof HTMLElement)) {
|
|
324
402
|
return;
|
|
@@ -329,8 +407,24 @@ function onKeyDown(event: KeyboardEvent): void {
|
|
|
329
407
|
const floatable = state.mapped.get(related);
|
|
330
408
|
|
|
331
409
|
if (floatable != null) {
|
|
332
|
-
|
|
410
|
+
floatable.toggle(false);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function setAttribute(
|
|
415
|
+
position: Position,
|
|
416
|
+
anchor: DOMRect,
|
|
417
|
+
floater: HTMLElement,
|
|
418
|
+
top: number,
|
|
419
|
+
left: number,
|
|
420
|
+
): void {
|
|
421
|
+
let actual: Position | undefined;
|
|
422
|
+
|
|
423
|
+
if (/^(horizontal|vertical)/.test(position)) {
|
|
424
|
+
actual = getAttribute(position, anchor, top, left);
|
|
333
425
|
}
|
|
426
|
+
|
|
427
|
+
floater.setAttribute('position', actual ?? position);
|
|
334
428
|
}
|
|
335
429
|
|
|
336
430
|
function stop(floatable: Floatable): void {
|
|
@@ -359,7 +453,7 @@ function toggle(anchor: HTMLElement): void {
|
|
|
359
453
|
closeAbove(content as HTMLElement);
|
|
360
454
|
}
|
|
361
455
|
|
|
362
|
-
|
|
456
|
+
floatable.toggle(!active);
|
|
363
457
|
}
|
|
364
458
|
|
|
365
459
|
function updatePosition(floatable: Floatable): void {
|
|
@@ -372,6 +466,8 @@ function updatePosition(floatable: Floatable): void {
|
|
|
372
466
|
position = floatable.options.defaultPosition;
|
|
373
467
|
}
|
|
374
468
|
|
|
469
|
+
const margin = getMargin();
|
|
470
|
+
|
|
375
471
|
let previousAnchor: DOMRect;
|
|
376
472
|
let previousContent: DOMRect;
|
|
377
473
|
|
|
@@ -404,8 +500,10 @@ function updatePosition(floatable: Floatable): void {
|
|
|
404
500
|
previousAnchor = anchor;
|
|
405
501
|
previousContent = content;
|
|
406
502
|
|
|
407
|
-
const left = getX(anchor, content, position);
|
|
408
|
-
const top = getY(anchor, content, position, floatable.options.preferAbove);
|
|
503
|
+
const left = getX(anchor, content, position, margin);
|
|
504
|
+
const top = getY(anchor, content, position, margin, floatable.options.preferAbove);
|
|
505
|
+
|
|
506
|
+
setAttribute(position, anchor, floatable.options.content, top, left);
|
|
409
507
|
|
|
410
508
|
if (top + content.height > window.innerHeight) {
|
|
411
509
|
floatable.options.content.style.height = `${window.innerHeight - top}px`;
|
|
@@ -442,26 +540,6 @@ const ATTRIBUTE_CONTENT = 'oui-floatable-content';
|
|
|
442
540
|
|
|
443
541
|
const INSERT_AFTEREND = 'afterend';
|
|
444
542
|
|
|
445
|
-
const POSITION_ABOVE = 'above';
|
|
446
|
-
|
|
447
|
-
const POSITION_BELOW = 'below';
|
|
448
|
-
|
|
449
|
-
const POSITION_BOTTOM = 'bottom';
|
|
450
|
-
|
|
451
|
-
const POSITION_END = 'end';
|
|
452
|
-
|
|
453
|
-
const POSITION_HORIZONTAL = 'horizontal';
|
|
454
|
-
|
|
455
|
-
const POSITION_START = 'start';
|
|
456
|
-
|
|
457
|
-
const POSITION_SUFFIX_END = '-end';
|
|
458
|
-
|
|
459
|
-
const POSITION_SUFFIX_START = '-start';
|
|
460
|
-
|
|
461
|
-
const POSITION_TOP = 'top';
|
|
462
|
-
|
|
463
|
-
const POSITION_VERTICAL = 'vertical';
|
|
464
|
-
|
|
465
543
|
const POSITIONS: Set<Position> = new Set([
|
|
466
544
|
'above',
|
|
467
545
|
'above-end',
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import type {EventPosition, PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
|
+
import {getPosition, on} from '@oscarpalmer/toretto/event';
|
|
3
|
+
import {attributable} from './internal/attributable';
|
|
4
|
+
import {
|
|
5
|
+
addDraggable,
|
|
6
|
+
Draggable,
|
|
7
|
+
removeDraggable,
|
|
8
|
+
type DraggableBound,
|
|
9
|
+
type DraggableState,
|
|
10
|
+
type DragMovePosition,
|
|
11
|
+
} from './internal/draggable';
|
|
12
|
+
|
|
13
|
+
// #region Types
|
|
14
|
+
|
|
15
|
+
export class Movable extends Draggable {
|
|
16
|
+
inset: string;
|
|
17
|
+
|
|
18
|
+
moved = false;
|
|
19
|
+
|
|
20
|
+
offset: Partial<EventPosition> | undefined;
|
|
21
|
+
|
|
22
|
+
position: string;
|
|
23
|
+
|
|
24
|
+
get dragged(): HTMLElement {
|
|
25
|
+
return this.element;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get origin(): HTMLElement | undefined {
|
|
29
|
+
return this.element;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
constructor(element: HTMLElement) {
|
|
33
|
+
super('move', element, {
|
|
34
|
+
container: {
|
|
35
|
+
attribute: ATTRIBUTE_CONTAINER,
|
|
36
|
+
map: CONTAINERS,
|
|
37
|
+
onDestroy: destroyContainer,
|
|
38
|
+
onInitialize: initializeContainer,
|
|
39
|
+
},
|
|
40
|
+
direction: {
|
|
41
|
+
attribute: ATTRIBUTE_DIRECTION,
|
|
42
|
+
onAfter: afterDirection,
|
|
43
|
+
},
|
|
44
|
+
drag: {
|
|
45
|
+
onBegin,
|
|
46
|
+
onCancel,
|
|
47
|
+
onEnd,
|
|
48
|
+
onMove,
|
|
49
|
+
},
|
|
50
|
+
position: {
|
|
51
|
+
getOffset: getOffsetPosition,
|
|
52
|
+
getOriginal: getOriginalPosition,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this.hasHandles = element.querySelector(SELECTOR_HANDLE) != null;
|
|
57
|
+
|
|
58
|
+
this.inset = element.style.inset;
|
|
59
|
+
this.position = element.style.position;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
override destroy(): void {
|
|
63
|
+
super.destroy();
|
|
64
|
+
|
|
65
|
+
MOVED.delete(this);
|
|
66
|
+
|
|
67
|
+
this.element.style.inset = this.inset;
|
|
68
|
+
this.element.style.position = this.position;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// #endregion
|
|
73
|
+
|
|
74
|
+
// #region Functions
|
|
75
|
+
|
|
76
|
+
function afterDirection(draggable: Draggable): void {
|
|
77
|
+
const container = draggable.container?.getBoundingClientRect();
|
|
78
|
+
|
|
79
|
+
if (container != null) {
|
|
80
|
+
setOffset(draggable as Movable, container);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function destroyContainer(_: Draggable, container: HTMLElement, empty: boolean): void {
|
|
85
|
+
if (empty) {
|
|
86
|
+
resizer.unobserve(container);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getOffsetPosition(
|
|
91
|
+
state: DraggableState,
|
|
92
|
+
_: Draggable,
|
|
93
|
+
__: HTMLElement,
|
|
94
|
+
position: EventPosition,
|
|
95
|
+
): EventPosition {
|
|
96
|
+
return {
|
|
97
|
+
x: position.x - (state.element?.rectangle.left ?? 0),
|
|
98
|
+
y: position.y - (state.element?.rectangle.top ?? 0),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function getOriginalPosition(state: DraggableState): EventPosition {
|
|
103
|
+
return {
|
|
104
|
+
x: state.element?.rectangle.left ?? 0,
|
|
105
|
+
y: state.element?.rectangle.top ?? 0,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function initializeContainer(draggable: Draggable): void {
|
|
110
|
+
resizer.observe(draggable.container!);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function onBegin(): void {}
|
|
114
|
+
|
|
115
|
+
function onCancel(state: DraggableState, draggable: Draggable): void {
|
|
116
|
+
const movable = draggable as Movable;
|
|
117
|
+
|
|
118
|
+
const {element, inset, moved, position} = movable;
|
|
119
|
+
const {x, y} = state.original ?? {x: 0, y: 0};
|
|
120
|
+
|
|
121
|
+
if (moved) {
|
|
122
|
+
element.style.inset = `${y}px auto auto ${x}px`;
|
|
123
|
+
} else {
|
|
124
|
+
element.style.position = position;
|
|
125
|
+
element.style.inset = inset;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function onEnd(
|
|
130
|
+
event: MouseEvent | TouchEvent,
|
|
131
|
+
state: DraggableState,
|
|
132
|
+
draggable: Draggable,
|
|
133
|
+
reset: () => void,
|
|
134
|
+
): void {
|
|
135
|
+
const movable = draggable as Movable;
|
|
136
|
+
|
|
137
|
+
if (!movable.moved) {
|
|
138
|
+
movable.moved = true;
|
|
139
|
+
|
|
140
|
+
if (movable.container != null) {
|
|
141
|
+
MOVED.add(movable);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const container = movable.container?.getBoundingClientRect();
|
|
146
|
+
|
|
147
|
+
if (container != null) {
|
|
148
|
+
setOffset(movable, container);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const end = new CustomEvent(EVENT_END, {
|
|
152
|
+
detail: {
|
|
153
|
+
from: {...state.original},
|
|
154
|
+
to: getPosition(event),
|
|
155
|
+
},
|
|
156
|
+
cancelable: true,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
movable.element.dispatchEvent(end);
|
|
160
|
+
|
|
161
|
+
setTimeout(() => {
|
|
162
|
+
if (end.defaultPrevented) {
|
|
163
|
+
onCancel(state, draggable);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
reset();
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function onMove(
|
|
171
|
+
_: MouseEvent | TouchEvent,
|
|
172
|
+
state: DraggableState,
|
|
173
|
+
__: Draggable,
|
|
174
|
+
position: DragMovePosition,
|
|
175
|
+
): PlainObject | undefined {
|
|
176
|
+
return {
|
|
177
|
+
from: {...state.original},
|
|
178
|
+
to: {...position.calculated},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function onResize(entries: ResizeObserverEntry[]): void {
|
|
183
|
+
const {length} = entries;
|
|
184
|
+
|
|
185
|
+
for (let index = 0; index < length; index += 1) {
|
|
186
|
+
const entry = entries[index];
|
|
187
|
+
const set = CONTAINERS.get(entry.target as HTMLElement);
|
|
188
|
+
|
|
189
|
+
if (set == null) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
for (const movable of set) {
|
|
194
|
+
reposition(movable);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function onScroll(): void {
|
|
200
|
+
for (const moved of MOVED) {
|
|
201
|
+
reposition(moved);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function reposition(movable: Movable): void {
|
|
206
|
+
if (!movable.moved || movable.container == null) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const container = movable.container.getBoundingClientRect();
|
|
211
|
+
|
|
212
|
+
const x = container.left + (movable.offset?.x ?? 0);
|
|
213
|
+
const y = container.top + (movable.offset?.y ?? 0);
|
|
214
|
+
|
|
215
|
+
movable.element.style.inset = `${y}px auto auto ${x}px`;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function setOffset(movable: Movable, container: DOMRect): void {
|
|
219
|
+
movable.offset = {};
|
|
220
|
+
|
|
221
|
+
const element = movable.element.getBoundingClientRect();
|
|
222
|
+
|
|
223
|
+
movable.offset.y = element.top - container.top;
|
|
224
|
+
movable.offset.x = element.left - container.left;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// #endregion
|
|
228
|
+
|
|
229
|
+
// #region Variables
|
|
230
|
+
|
|
231
|
+
const ATTRIBUTE = 'oui-movable';
|
|
232
|
+
|
|
233
|
+
const ATTRIBUTE_CONTAINER = `${ATTRIBUTE}-container`;
|
|
234
|
+
|
|
235
|
+
const ATTRIBUTE_DIRECTION = `${ATTRIBUTE}-direction`;
|
|
236
|
+
|
|
237
|
+
const CONTAINERS = new Map<HTMLElement, Set<Movable>>();
|
|
238
|
+
|
|
239
|
+
const EVENT_END = 'move:end';
|
|
240
|
+
|
|
241
|
+
const MOVED = new Set<Movable>();
|
|
242
|
+
|
|
243
|
+
const SELECTOR_HANDLE = `[${ATTRIBUTE}-handle]`;
|
|
244
|
+
|
|
245
|
+
const bound: DraggableBound = {
|
|
246
|
+
constructor: Movable,
|
|
247
|
+
property: 'movable',
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const resizer = new ResizeObserver(onResize);
|
|
251
|
+
|
|
252
|
+
// #endregion
|
|
253
|
+
|
|
254
|
+
// #region Initialization
|
|
255
|
+
|
|
256
|
+
attributable(ATTRIBUTE, addDraggable.bind(bound), removeDraggable.bind(bound));
|
|
257
|
+
|
|
258
|
+
on(document, 'scroll', onScroll);
|
|
259
|
+
|
|
260
|
+
// #endregion
|
package/src/js/popover.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
2
|
import {getFocusable} from '@oscarpalmer/toretto/focusable';
|
|
3
|
-
import {Floatable} from './floatable';
|
|
3
|
+
import {Floatable} from './internal/floatable';
|
|
4
4
|
import {createFocusTrap, type FocusTrap} from './focus-trap/embedded';
|
|
5
5
|
|
|
6
6
|
declare global {
|