@oscarpalmer/oui 0.26.0 → 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.
Files changed (66) hide show
  1. package/dist/css/floatable.css +0 -2
  2. package/dist/css/message.css +1 -0
  3. package/dist/css/reset.css +1 -0
  4. package/dist/js/dialog.d.mts +6 -0
  5. package/dist/js/dialog.mjs +23 -1
  6. package/dist/js/draggable-zszaW1qS.d.mts +155 -0
  7. package/dist/js/floatable/floatable.embedded.d.mts +2 -0
  8. package/dist/js/floatable/{embedded.mjs → floatable.embedded.mjs} +22 -17
  9. package/dist/js/floatable/floatable.standalone.d.mts +2 -0
  10. package/dist/js/floatable/floatable.standalone.mjs +2 -0
  11. package/dist/js/{embedded-ai6cqURc.d.mts → floatable.embedded-YxGwzgbE.d.mts} +13 -10
  12. package/dist/js/focus-trap/focus-trap.embedded.d.mts +2 -0
  13. package/dist/js/focus-trap/{embedded.mjs → focus-trap.embedded.mjs} +17 -15
  14. package/dist/js/focus-trap/focus-trap.standalone.d.mts +2 -0
  15. package/dist/js/focus-trap/focus-trap.standalone.mjs +2 -0
  16. package/dist/js/{embedded-CHK82Uh5.d.mts → focus-trap.embedded-DR8NpZfr.d.mts} +18 -18
  17. package/dist/js/index.d.mts +4 -3
  18. package/dist/js/index.mjs +8 -7
  19. package/dist/js/internal/draggable.d.mts +2 -2
  20. package/dist/js/internal/draggable.mjs +146 -94
  21. package/dist/js/movable/movable.embedded.d.mts +2 -0
  22. package/dist/js/movable/movable.embedded.mjs +184 -0
  23. package/dist/js/movable/movable.standalone.d.mts +2 -0
  24. package/dist/js/movable/movable.standalone.mjs +2 -0
  25. package/dist/js/popover.d.mts +3 -2
  26. package/dist/js/popover.mjs +8 -3
  27. package/dist/js/sortable/sortable.embedded.d.mts +2 -0
  28. package/dist/js/{sortable.mjs → sortable/sortable.embedded.mjs} +88 -63
  29. package/dist/js/sortable/sortable.standalone.d.mts +2 -0
  30. package/dist/js/sortable/sortable.standalone.mjs +2 -0
  31. package/dist/js/splitter.d.mts +24 -0
  32. package/dist/js/splitter.mjs +33 -9
  33. package/dist/js/toolbar.mjs +6 -6
  34. package/dist/js/tooltip.d.mts +12 -2
  35. package/dist/js/tooltip.mjs +49 -33
  36. package/package.json +11 -11
  37. package/src/css/floatable.scss +0 -2
  38. package/src/css/message.scss +1 -0
  39. package/src/css/reset.scss +1 -0
  40. package/src/js/dialog.ts +42 -1
  41. package/src/js/floatable/{embedded.ts → floatable.embedded.ts} +26 -18
  42. package/src/js/floatable/floatable.standalone.ts +6 -0
  43. package/src/js/focus-trap/{embedded.ts → focus-trap.embedded.ts} +20 -17
  44. package/src/js/focus-trap/focus-trap.standalone.ts +1 -0
  45. package/src/js/index.ts +4 -4
  46. package/src/js/internal/draggable.ts +309 -168
  47. package/src/js/movable/movable.embedded.ts +328 -0
  48. package/src/js/movable/movable.standalone.ts +2 -0
  49. package/src/js/popover.ts +11 -2
  50. package/src/js/{sortable.ts → sortable/sortable.embedded.ts} +170 -103
  51. package/src/js/sortable/sortable.standalone.ts +2 -0
  52. package/src/js/splitter.ts +28 -4
  53. package/src/js/tooltip.ts +66 -43
  54. package/dist/js/floatable/embedded.d.mts +0 -2
  55. package/dist/js/floatable/standalone.d.mts +0 -2
  56. package/dist/js/floatable/standalone.mjs +0 -2
  57. package/dist/js/focus-trap/embedded.d.mts +0 -2
  58. package/dist/js/focus-trap/standalone.d.mts +0 -2
  59. package/dist/js/focus-trap/standalone.mjs +0 -6
  60. package/dist/js/movable-dNqBctx3.d.mts +0 -101
  61. package/dist/js/movable.d.mts +0 -2
  62. package/dist/js/movable.mjs +0 -152
  63. package/dist/js/sortable.d.mts +0 -2
  64. package/src/js/floatable/standalone.ts +0 -1
  65. package/src/js/focus-trap/standalone.ts +0 -6
  66. package/src/js/movable.ts +0 -260
@@ -2,154 +2,230 @@ import type {EventPosition, PlainObject} from '@oscarpalmer/atoms/models';
2
2
  import {clamp} from '@oscarpalmer/atoms/number';
3
3
  import {getPosition, on} from '@oscarpalmer/toretto/event';
4
4
  import {findAncestor} from '@oscarpalmer/toretto/find';
5
- import {toggleStyles} from '@oscarpalmer/toretto/style';
5
+ import {toggleStyles, type StyleToggler} from '@oscarpalmer/toretto/style';
6
6
  import supportsTouch from '@oscarpalmer/toretto/touch';
7
- import type {OuiMovable} from '../movable';
8
- import type {OuiSortable} from '../sortable';
7
+ import type {OuiMovable} from '../movable/movable.embedded';
8
+ import type {OuiSortable} from '../sortable/sortable.embedded';
9
+ import {isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
9
10
 
10
11
  // #region Types
11
12
 
12
- type Direction = 'horizontal' | 'vertical' | 'x' | 'y';
13
-
14
- export abstract class OuiDraggable {
15
- container: HTMLElement | undefined;
13
+ export type CreateOuiDraggableOptions = {
14
+ /**
15
+ * Container to hold the draggable element and restrict its movement within. Can be `body`, `document`, `window`, a _CSS_ selector, or an element. _(If not provided, the draggable element will not have any constraints)_
16
+ */
17
+ container?: string | HTMLElement;
18
+ /**
19
+ * Direction in which the element can be dragged. _(If not provided, the element can be dragged in any direction)_
20
+ */
21
+ direction?: OuiDraggableDirection;
22
+ };
16
23
 
17
- hasHandles: boolean | undefined;
24
+ type OuiDraggableDirection = 'horizontal' | 'vertical' | 'x' | 'y';
18
25
 
19
- horizontal = true;
26
+ export abstract class OuiDraggable<ExtraState extends PlainObject = PlainObject> {
27
+ #destroyed = false;
20
28
 
21
- vertical = true;
29
+ #name: keyof OuiDraggableStates;
22
30
 
23
- abstract readonly dragged: HTMLElement;
31
+ readonly #state: OuiDraggableState & ExtraState;
24
32
 
25
- abstract origin: HTMLElement | undefined;
33
+ get element(): HTMLElement {
34
+ return this.#state.element;
35
+ }
26
36
 
27
37
  constructor(
28
- public prefix: string,
29
- public element: HTMLElement,
30
- public options: DraggableOptions,
38
+ name: keyof OuiDraggableStates,
39
+ event: string,
40
+ attribute: string,
41
+ element: HTMLElement,
42
+ options: OuiDraggableOptions<ExtraState>,
43
+ extras: ExtraState,
31
44
  ) {
32
- setContainer(this, options);
33
- setDirection(this, options);
45
+ this.#name = name;
46
+
47
+ this.#state = {
48
+ ...extras,
49
+ attribute,
50
+ element,
51
+ event,
52
+ options,
53
+ horizontal: true,
54
+ vertical: true,
55
+ styling: toggleStyles(element, styles),
56
+ } as OuiDraggableState & ExtraState;
57
+
58
+ const item = {
59
+ instance: this,
60
+ state: this.#state,
61
+ };
62
+
63
+ setContainer(item);
64
+ setDirection(item);
65
+
66
+ element.setAttribute(attribute, '');
67
+
68
+ let states = globals.states.get(element);
69
+
70
+ states ??= {};
71
+
72
+ states[this.#name] = this.#state;
73
+
74
+ globals.states.set(element, states);
34
75
  }
35
76
 
36
77
  destroy(): void {
37
- unsetContainer(this, this.options);
78
+ if (this.#destroyed) {
79
+ return;
80
+ }
81
+
82
+ this.#destroyed = true;
38
83
 
39
- this.container = undefined;
40
- this.element = undefined!;
41
- this.options = undefined!;
84
+ destroyInstance(this, this.#state);
42
85
  }
43
86
  }
44
87
 
45
- type DragBegin = (
88
+ type OuiDragBegin<State extends PlainObject = PlainObject> = (
46
89
  event: MouseEvent | TouchEvent,
47
- state: DraggableState,
48
- draggable: OuiDraggable,
90
+ globals: OuiDraggableGlobals,
91
+ item: OuiDraggableItem<State>,
49
92
  element: HTMLElement,
50
93
  handle: HTMLElement,
51
94
  position: EventPosition,
52
95
  ) => void;
53
96
 
54
- type DragCancel = (state: DraggableState, draggable: OuiDraggable) => void;
97
+ type OuiDragCancel<State extends PlainObject = PlainObject> = (
98
+ globals: OuiDraggableGlobals,
99
+ item: OuiDraggableItem<State>,
100
+ ) => void;
55
101
 
56
- type DragEnd = (
102
+ type OuiDragEnd<State extends PlainObject = PlainObject> = (
57
103
  event: MouseEvent | TouchEvent,
58
- state: DraggableState,
59
- draggable: OuiDraggable,
104
+ globals: OuiDraggableGlobals,
105
+ item: OuiDraggableItem<State>,
60
106
  reset: () => void,
61
107
  ) => void;
62
108
 
63
- type DragMove = (
109
+ type OuiDragMove<State extends PlainObject = PlainObject> = (
64
110
  event: MouseEvent | TouchEvent,
65
- state: DraggableState,
66
- draggable: OuiDraggable,
67
- position: DragMovePosition,
111
+ globals: OuiDraggableGlobals,
112
+ item: OuiDraggableItem<State>,
113
+ position: OuiDragMovePosition,
68
114
  ) => PlainObject | undefined;
69
115
 
70
- export type DragMovePosition = {
116
+ export type OuiDragMovePosition = {
71
117
  calculated: EventPosition;
72
118
  original: EventPosition;
73
119
  };
74
120
 
75
- export type DraggableBound<
76
- Property extends keyof DraggableInstances = keyof DraggableInstances,
77
- Instance extends DraggableInstances[Property] = DraggableInstances[Property],
121
+ export type OuiDraggableBound<
122
+ Property extends keyof OuiDraggableInstances = keyof OuiDraggableInstances,
123
+ Instance extends OuiDraggableInstances[Property] = OuiDraggableInstances[Property],
78
124
  > = {
79
- constructor: new (element: HTMLElement) => Instance;
125
+ constructor: new (element: HTMLElement, options?: CreateOuiDraggableOptions) => Instance;
80
126
  property: Property;
81
127
  };
82
128
 
83
- type DraggableInstances = {
129
+ export type OuiDraggableGlobals = {
130
+ container?: DOMRect;
131
+ element?: OuiDraggableGlobalsElement;
132
+ instances: WeakMap<HTMLElement, OuiDraggableInstances>;
133
+ offset?: EventPosition;
134
+ original?: EventPosition;
135
+ states: WeakMap<HTMLElement, OuiDraggableStates>;
136
+ };
137
+
138
+ type OuiDraggableGlobalsElement = {
139
+ node: HTMLElement;
140
+ rectangle: DOMRect;
141
+ };
142
+
143
+ type OuiDraggableInstances = {
84
144
  movable?: OuiMovable;
85
145
  sortable?: OuiSortable;
86
146
  };
87
147
 
88
- type DraggableOptions = {
89
- container: DraggableOptionsContainer;
90
- direction: DraggableOptionsDirection;
91
- drag: DraggableOptionsDrag;
92
- position: DraggableOptionsPosition;
148
+ export type OuiDraggableItem<ExtraState extends PlainObject = PlainObject> = {
149
+ instance: OuiDraggable<ExtraState>;
150
+ state: OuiDraggableState & ExtraState;
151
+ };
152
+
153
+ type OuiDraggableOptions<ExtraState extends PlainObject = PlainObject> = {
154
+ container: OuiDraggableOptionsContainer<ExtraState>;
155
+ direction: OuiDraggableOptionsDirection<ExtraState>;
156
+ drag: OuiDraggableOptionsDrag<ExtraState>;
157
+ input?: CreateOuiDraggableOptions;
158
+ position: OuiDraggableOptionsPosition<ExtraState>;
159
+ getDragged(): HTMLElement;
160
+ getOrigin(): HTMLElement | undefined;
93
161
  };
94
162
 
95
- type DraggableOptionsContainer = {
163
+ type OuiDraggableOptionsContainer<ExtraState extends PlainObject = PlainObject> = {
96
164
  attribute: string;
97
165
  map: Map<HTMLElement, Set<OuiDraggable>>;
98
- onDestroy?: DraggableOptionsContainerOnDestroy;
99
- onInitialize?: DraggableOptionsContainerOnInitialize;
166
+ onDestroy?: OuiDraggableOptionsContainerOnDestroy<ExtraState>;
167
+ onInitialize?: OuiDraggableOptionsContainerOnInitialize;
100
168
  };
101
169
 
102
- type DraggableOptionsContainerOnDestroy = (
103
- draggable: OuiDraggable,
170
+ type OuiDraggableOptionsContainerOnDestroy<ExtraState extends PlainObject = PlainObject> = (
171
+ item: OuiDraggableItem<ExtraState>,
104
172
  container: HTMLElement,
105
173
  empty: boolean,
106
174
  ) => void;
107
175
 
108
- type DraggableOptionsContainerOnInitialize = (draggable: OuiDraggable) => void;
176
+ type OuiDraggableOptionsContainerOnInitialize<ExtraState extends PlainObject = PlainObject> = (
177
+ item: OuiDraggableItem<ExtraState>,
178
+ ) => void;
109
179
 
110
- type DraggableOptionsDirection = {
180
+ type OuiDraggableOptionsDirection<ExtraState extends PlainObject = PlainObject> = {
111
181
  attribute: string;
112
- onAfter?: DraggableOptionsDirectionOnAfter;
182
+ onAfter?: OuiDraggableOptionsDirectionOnAfter<ExtraState>;
113
183
  };
114
184
 
115
- type DraggableOptionsDirectionOnAfter = (draggable: OuiDraggable) => void;
185
+ type OuiDraggableOptionsDirectionOnAfter<ExtraState extends PlainObject = PlainObject> = (
186
+ item: OuiDraggableItem<ExtraState>,
187
+ ) => void;
116
188
 
117
- type DraggableOptionsDrag = {
118
- onBegin: DragBegin;
119
- onCancel: DragCancel;
120
- onEnd: DragEnd;
121
- onMove: DragMove;
189
+ type OuiDraggableOptionsDrag<ExtraState extends PlainObject = PlainObject> = {
190
+ onBegin: OuiDragBegin<ExtraState>;
191
+ onCancel: OuiDragCancel<ExtraState>;
192
+ onEnd: OuiDragEnd<ExtraState>;
193
+ onMove: OuiDragMove<ExtraState>;
122
194
  };
123
195
 
124
- type DraggableOptionsPosition = {
125
- getOffset: DraggableOptionsPositionGetOffset;
126
- getOriginal: DraggableOptionsPositionGetOriginal;
196
+ type OuiDraggableOptionsPosition<ExtraState extends PlainObject = PlainObject> = {
197
+ getOffset: OuiDraggableOptionsPositionGetOffset<ExtraState>;
198
+ getOriginal: OuiDraggableOptionsPositionGetOriginal<ExtraState>;
127
199
  };
128
200
 
129
- type DraggableOptionsPositionGetOffset = (
130
- state: DraggableState,
131
- draggable: OuiDraggable,
201
+ type OuiDraggableOptionsPositionGetOffset<ExtraState extends PlainObject = PlainObject> = (
202
+ globals: OuiDraggableGlobals,
203
+ item: OuiDraggableItem<ExtraState>,
132
204
  element: HTMLElement,
133
205
  position: EventPosition,
134
206
  ) => EventPosition;
135
207
 
136
- type DraggableOptionsPositionGetOriginal = (
137
- state: DraggableState,
138
- draggable: OuiDraggable,
208
+ type OuiDraggableOptionsPositionGetOriginal<ExtraState extends PlainObject = PlainObject> = (
209
+ globals: OuiDraggableGlobals,
210
+ item: OuiDraggableItem<ExtraState>,
139
211
  position: EventPosition,
140
212
  ) => EventPosition;
141
213
 
142
- export type DraggableState = {
143
- container: DOMRect | undefined;
144
- element: DraggableStateElement | undefined;
145
- instances: WeakMap<HTMLElement, DraggableInstances>;
146
- offset: EventPosition | undefined;
147
- original: EventPosition | undefined;
214
+ export type OuiDraggableState = {
215
+ attribute: string;
216
+ container?: HTMLElement;
217
+ element: HTMLElement;
218
+ event: string;
219
+ hasHandles?: boolean;
220
+ horizontal: boolean;
221
+ options: OuiDraggableOptions;
222
+ styling: StyleToggler;
223
+ vertical: boolean;
148
224
  };
149
225
 
150
- type DraggableStateElement = {
151
- node: HTMLElement;
152
- rectangle: DOMRect;
226
+ type OuiDraggableStates = {
227
+ movable?: OuiDraggableState;
228
+ sortable?: OuiDraggableState;
153
229
  };
154
230
 
155
231
  // #endregion
@@ -157,18 +233,43 @@ type DraggableStateElement = {
157
233
  // #region Functions
158
234
 
159
235
  export function addDraggable<
160
- Property extends keyof DraggableInstances,
161
- Instance extends DraggableInstances[Property],
162
- >(this: DraggableBound<Property, Instance>, element: HTMLElement): void {
163
- let instances = state.instances.get(element);
236
+ Property extends keyof OuiDraggableInstances,
237
+ Instance extends OuiDraggableInstances[Property],
238
+ >(
239
+ this: OuiDraggableBound<Property, Instance>,
240
+ element: HTMLElement,
241
+ options?: CreateOuiDraggableOptions,
242
+ ): Instance {
243
+ let instances = globals.instances.get(element);
164
244
 
165
245
  if (instances == null) {
166
246
  instances = {};
167
247
 
168
- state.instances.set(element, instances);
248
+ globals.instances.set(element, instances);
169
249
  }
170
250
 
171
- instances[this.property] ??= new this.constructor(element);
251
+ instances[this.property] ??= new this.constructor(element, options);
252
+
253
+ return instances[this.property] as Instance;
254
+ }
255
+
256
+ function destroyInstance(instance: OuiDraggable, state: OuiDraggableState): void {
257
+ unsetContainer({
258
+ instance,
259
+ state,
260
+ });
261
+
262
+ state.element.removeAttribute(state.attribute);
263
+ state.styling.remove();
264
+
265
+ state.container = undefined;
266
+ state.element = undefined as never;
267
+ state.options = undefined as never;
268
+ state.styling = undefined as never;
269
+ }
270
+
271
+ export function getDraggableStates(element: HTMLElement): OuiDraggableStates | undefined {
272
+ return globals.states.get(element);
172
273
  }
173
274
 
174
275
  function getHandle(event: Event, isMovable: boolean): HTMLElement | null {
@@ -178,23 +279,31 @@ function getHandle(event: Event, isMovable: boolean): HTMLElement | null {
178
279
  ) as HTMLElement;
179
280
  }
180
281
 
181
- function getNextPosition(draggable: OuiDraggable, position: EventPosition): EventPosition {
182
- let x = state.original?.x ?? 0;
183
- let y = state.original?.y ?? 0;
282
+ function getNextPosition(item: OuiDraggableItem, position: EventPosition): EventPosition {
283
+ let x = globals.original?.x ?? 0;
284
+ let y = globals.original?.y ?? 0;
184
285
 
185
- if (draggable.horizontal) {
186
- x = position.x - (state.offset?.x ?? 0);
286
+ if (item.state.horizontal) {
287
+ x = position.x - (globals.offset?.x ?? 0);
187
288
 
188
- if (state.container != null && state.element != null) {
189
- x = clamp(x, state.container.left, state.container.right - state.element.rectangle.width);
289
+ if (globals.container != null && globals.element != null) {
290
+ x = clamp(
291
+ x,
292
+ globals.container.left,
293
+ globals.container.right - globals.element.rectangle.width,
294
+ );
190
295
  }
191
296
  }
192
297
 
193
- if (draggable.vertical) {
194
- y = position.y - (state.offset?.y ?? 0);
298
+ if (item.state.vertical) {
299
+ y = position.y - (globals.offset?.y ?? 0);
195
300
 
196
- if (state.container != null && state.element != null) {
197
- y = clamp(y, state.container.top, state.container.bottom - state.element.rectangle.height);
301
+ if (globals.container != null && globals.element != null) {
302
+ y = clamp(
303
+ y,
304
+ globals.container.top,
305
+ globals.container.bottom - globals.element.rectangle.height,
306
+ );
198
307
  }
199
308
  }
200
309
 
@@ -206,14 +315,12 @@ function onKeydown(event: KeyboardEvent): void {
206
315
  return;
207
316
  }
208
317
 
209
- const {origin} = current;
210
-
211
- current.options.drag.onCancel?.(state, current);
318
+ current.state.options.drag.onCancel?.(globals, current);
212
319
 
213
- current.element.dispatchEvent(
214
- new CustomEvent(`${current.prefix}:cancel`, {
320
+ current.state.element.dispatchEvent(
321
+ new CustomEvent(`${current.state.event}:cancel`, {
215
322
  detail: {
216
- element: origin,
323
+ element: current.state.options.getOrigin(),
217
324
  },
218
325
  }),
219
326
  );
@@ -235,17 +342,22 @@ function onPointerdown(event: MouseEvent | TouchEvent): void {
235
342
  }
236
343
 
237
344
  const container = findAncestor(event, SELECTOR)! as HTMLElement;
238
- const instances = state.instances.get(container!);
239
345
 
240
- if (instances == null) {
346
+ const instances = globals.instances.get(container!);
347
+ const states = globals.states.get(container);
348
+
349
+ if (instances == null || states == null) {
241
350
  return;
242
351
  }
243
352
 
244
353
  const isMovable = container.hasAttribute(ATTRIBUTE_MOVABLE);
245
354
 
246
- const instance = isMovable ? instances.movable : instances.sortable;
355
+ const item: OuiDraggableItem = {
356
+ instance: (isMovable ? instances.movable : instances.sortable) as OuiDraggable,
357
+ state: (isMovable ? states.movable : states.sortable) as OuiDraggableState,
358
+ };
247
359
 
248
- if (instance == null) {
360
+ if (item.instance == null || item.state == null) {
249
361
  return;
250
362
  }
251
363
 
@@ -265,9 +377,9 @@ function onPointerdown(event: MouseEvent | TouchEvent): void {
265
377
 
266
378
  let handle: HTMLElement | null = element;
267
379
 
268
- instance.hasHandles ??= element.querySelector(SELECTOR_SORTABLE_HANDLE) != null;
380
+ item.state.hasHandles ??= element.querySelector(SELECTOR_SORTABLE_HANDLE) != null;
269
381
 
270
- if (instance.hasHandles) {
382
+ if (item.state.hasHandles) {
271
383
  handle = getHandle(event, isMovable);
272
384
  }
273
385
 
@@ -275,50 +387,51 @@ function onPointerdown(event: MouseEvent | TouchEvent): void {
275
387
  return;
276
388
  }
277
389
 
278
- const {dragged} = instance;
279
-
390
+ const dragged = item.state.options.getDragged();
280
391
  const rectangle = dragged.getBoundingClientRect();
281
392
 
282
393
  const position = getPosition(event) ?? {x: 0, y: 0};
283
394
 
284
- current = instance;
395
+ current = item;
285
396
 
286
- state.container = instance.container?.getBoundingClientRect();
397
+ globals.container = item.state.container?.getBoundingClientRect();
287
398
 
288
- state.element = {
399
+ globals.element = {
289
400
  rectangle,
290
401
  node: dragged,
291
402
  };
292
403
 
293
- state.offset = instance.options.position.getOffset(state, instance, element, position);
294
- state.original = instance.options.position.getOriginal(state, instance, position);
404
+ globals.offset = item.state.options.position.getOffset(globals, item, element, position);
405
+ globals.original = item.state.options.position.getOriginal(globals, item, position);
295
406
 
296
- const begin = new CustomEvent(`${instance.prefix}:begin`, {
407
+ const begin = new CustomEvent(`${item.state.event}:begin`, {
297
408
  detail: {
298
409
  element,
299
- position: {...state.original},
410
+ position: {...globals.original},
300
411
  },
301
412
  cancelable: true,
302
413
  });
303
414
 
304
- instance.element.dispatchEvent(begin);
415
+ item.state.element.dispatchEvent(begin);
305
416
 
306
417
  setTimeout(() => {
307
418
  if (begin.defaultPrevented) {
308
- current?.options.drag.onCancel(state, instance);
419
+ item.state.options.drag.onCancel?.(globals, item);
309
420
 
310
421
  reset();
311
422
 
312
423
  return;
313
424
  }
314
425
 
315
- const next = getNextPosition(instance, position);
426
+ const next = getNextPosition(item, position);
316
427
 
317
428
  dragged.style.position = 'fixed';
318
429
  dragged.style.inset = `${next.y}px auto auto ${next.x}px`;
430
+ dragged.style.transform = 'translate3d(0, 0, 0)';
319
431
 
320
- instance.options.drag.onBegin(event, state, instance, element, handle, next);
432
+ item.state.options.drag.onBegin?.(event, globals, item, element, handle, next);
321
433
 
434
+ item.state.styling.set();
322
435
  styleToggler.set();
323
436
  });
324
437
  }
@@ -336,29 +449,29 @@ function onPointermove(event: MouseEvent | TouchEvent): void {
336
449
 
337
450
  const next = getNextPosition(current, position);
338
451
 
339
- if (state.element != null) {
340
- state.element.node.style.inset = `${next.y}px auto auto ${next.x}px`;
452
+ if (globals.element != null) {
453
+ globals.element.node.style.inset = `${next.y}px auto auto ${next.x}px`;
341
454
  }
342
455
 
343
- const detail = current.options.drag.onMove(event, state, current, {
456
+ const detail = current.state.options.drag.onMove(event, globals, current, {
344
457
  calculated: next,
345
458
  original: position,
346
459
  });
347
460
 
348
- current.element.dispatchEvent(
349
- new CustomEvent(`${current.prefix}:move`, {
461
+ current.state.element.dispatchEvent(
462
+ new CustomEvent(`${current.state.event}:move`, {
350
463
  detail,
351
464
  }),
352
465
  );
353
466
  }
354
467
 
355
468
  function onPointerup(event: MouseEvent | TouchEvent): void {
356
- current?.options.drag.onEnd?.(event, state, current, reset);
469
+ current?.state.options.drag.onEnd?.(event, globals, current, reset);
357
470
  }
358
471
 
359
472
  export function removeDraggable<
360
- Property extends keyof DraggableInstances,
361
- Instance extends DraggableInstances[Property],
473
+ Property extends keyof OuiDraggableInstances,
474
+ Instance extends OuiDraggableInstances[Property],
362
475
  >(
363
476
  this: {
364
477
  constructor: new (element: HTMLElement) => Instance;
@@ -368,92 +481,117 @@ export function removeDraggable<
368
481
  ): void {
369
482
  const {property} = this;
370
483
 
371
- const instances = state.instances.get(element);
484
+ removeInstance(globals.instances, property, element);
485
+ removeInstance(globals.states, property, element);
486
+ }
487
+
488
+ function removeInstance(
489
+ map: WeakMap<HTMLElement, OuiDraggableInstances | OuiDraggableStates>,
490
+ name: keyof OuiDraggableInstances | keyof OuiDraggableStates,
491
+ element: HTMLElement,
492
+ ): void {
493
+ const instances = map.get(element);
372
494
 
373
- if (instances == null || instances[property] == null) {
495
+ if (instances == null || instances[name] == null) {
374
496
  return;
375
497
  }
376
498
 
377
- instances[property]?.destroy();
499
+ if (typeof (instances[name] as OuiDraggable).destroy === 'function') {
500
+ (instances[name] as OuiDraggable).destroy();
501
+ }
378
502
 
379
- instances[property] = undefined;
503
+ instances[name] = undefined;
380
504
 
381
- if (instances[properties[property]] == null) {
382
- state.instances.delete(element);
505
+ if (instances[properties[name]] == null) {
506
+ map.delete(element);
383
507
  }
384
508
  }
385
509
 
386
510
  function reset(): void {
387
- current = undefined;
511
+ current?.state.styling.remove();
512
+ styleToggler.remove();
388
513
 
389
- state.container = undefined;
390
- state.element = undefined;
391
- state.offset = undefined;
392
- state.original = undefined;
514
+ current = undefined;
393
515
 
394
- styleToggler.remove();
516
+ globals.container = undefined;
517
+ globals.element = undefined;
518
+ globals.offset = undefined;
519
+ globals.original = undefined;
395
520
  }
396
521
 
397
- function setContainer(draggable: OuiDraggable, options: DraggableOptions): void {
398
- const selector = draggable.element.getAttribute(options.container.attribute);
522
+ function setContainer(item: OuiDraggableItem): void {
523
+ const {container} = item.state.options.input ?? {};
524
+
525
+ if (isHTMLOrSVGElement(container)) {
526
+ setContainerElement(item, container);
527
+
528
+ return;
529
+ }
530
+
531
+ const selector =
532
+ container ?? item.instance.element.getAttribute(item.state.options.container.attribute);
399
533
 
400
534
  if (typeof selector !== 'string') {
401
535
  return;
402
536
  }
403
537
 
404
- draggable.container = globals.has(selector)
405
- ? draggable.element.ownerDocument.body
538
+ const element = containers.has(selector)
539
+ ? item.state.element.ownerDocument.body
406
540
  : (document.querySelector(selector) ?? undefined);
407
541
 
408
- if (draggable.container == null) {
409
- return;
542
+ if (isHTMLOrSVGElement(element)) {
543
+ setContainerElement(item, element);
410
544
  }
545
+ }
546
+
547
+ function setContainerElement(item: OuiDraggableItem, element: HTMLElement): void {
548
+ item.state.container = element;
411
549
 
412
- const set = options.container.map.get(draggable.container);
550
+ const set = item.state.options.container.map.get(element);
413
551
 
414
552
  if (set == null) {
415
- options.container.map.set(draggable.container, new Set([draggable]));
553
+ item.state.options.container.map.set(element, new Set([item.instance]));
416
554
  } else {
417
- set.add(draggable);
555
+ set.add(item.instance);
418
556
  }
419
557
 
420
- options.container.onInitialize?.(draggable);
558
+ item.state.options.container.onInitialize?.(item);
421
559
  }
422
560
 
423
- function setDirection(draggable: OuiDraggable, options: DraggableOptions): void {
424
- const direction = draggable.element.getAttribute(options.direction.attribute);
561
+ function setDirection(item: OuiDraggableItem): void {
562
+ const direction = item.state.element.getAttribute(item.state.options.direction.attribute);
425
563
 
426
- if (horizontals.has(direction as Direction)) {
427
- draggable.vertical = false;
428
- } else if (verticals.has(direction as Direction)) {
429
- draggable.horizontal = false;
564
+ if (horizontals.has(direction as OuiDraggableDirection)) {
565
+ item.state.vertical = false;
566
+ } else if (verticals.has(direction as OuiDraggableDirection)) {
567
+ item.state.horizontal = false;
430
568
  }
431
569
 
432
- options.direction.onAfter?.(draggable);
570
+ item.state.options.direction.onAfter?.(item);
433
571
  }
434
572
 
435
- function unsetContainer(draggable: OuiDraggable, options: DraggableOptions): void {
436
- const {container} = draggable;
573
+ function unsetContainer(item: OuiDraggableItem): void {
574
+ const {container} = item.state;
437
575
 
438
576
  if (container == null) {
439
577
  return;
440
578
  }
441
579
 
442
- const set = options.container.map.get(container);
580
+ const set = item.state.options.container.map.get(container);
443
581
 
444
582
  let empty = false;
445
583
 
446
584
  if (set != null) {
447
- set.delete(draggable);
585
+ set.delete(item.instance);
448
586
 
449
587
  if (set.size === 0) {
450
588
  empty = true;
451
589
 
452
- options.container.map.delete(container);
590
+ item.state.options.container.map.delete(container);
453
591
  }
454
592
  }
455
593
 
456
- options.container.onDestroy?.(draggable, container, empty);
594
+ item.state.options.container.onDestroy?.(item, container, empty);
457
595
  }
458
596
 
459
597
  // #endregion
@@ -474,32 +612,35 @@ const SELECTOR_SORTABLE_HANDLE = `[${ATTRIBUTE_SORTABLE}-handle]`;
474
612
 
475
613
  const SELECTOR_SORTABLE_ITEM = `[${ATTRIBUTE_SORTABLE}] > *`;
476
614
 
477
- const globals = new Set<string>(['body', 'document', 'window']);
615
+ const containers = new Set<string>(['body', 'document', 'window']);
478
616
 
479
- const horizontals = new Set<Direction>(['horizontal', 'x']);
617
+ const horizontals = new Set<OuiDraggableDirection>(['horizontal', 'x']);
480
618
 
481
- const properties: Record<keyof DraggableInstances, keyof DraggableInstances> = {
619
+ const properties: Record<keyof OuiDraggableInstances, keyof OuiDraggableInstances> = {
482
620
  movable: 'sortable',
483
621
  sortable: 'movable',
484
622
  };
485
623
 
486
- const state: DraggableState = {
624
+ const globals: OuiDraggableGlobals = {
487
625
  container: undefined,
488
626
  element: undefined,
489
627
  instances: new WeakMap(),
490
628
  offset: undefined,
491
629
  original: undefined,
630
+ states: new WeakMap(),
492
631
  };
493
632
 
494
- const styleToggler = toggleStyles(document.body, {
633
+ const styles = {
495
634
  touchAction: 'none',
496
635
  userSelect: 'none',
497
636
  webkitUserSelect: 'none',
498
- });
637
+ };
638
+
639
+ const styleToggler = toggleStyles(document.body, styles);
499
640
 
500
- const verticals = new Set<Direction>(['vertical', 'y']);
641
+ const verticals = new Set<OuiDraggableDirection>(['vertical', 'y']);
501
642
 
502
- let current: OuiMovable | OuiSortable | undefined;
643
+ let current: OuiDraggableItem | undefined;
503
644
 
504
645
  // #endregion
505
646