@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
@@ -0,0 +1,328 @@
1
+ import type {EventPosition, PlainObject} from '@oscarpalmer/atoms/models';
2
+ import {getPosition, on} from '@oscarpalmer/toretto/event';
3
+ import {isHTMLOrSVGElement} from '@oscarpalmer/toretto/is';
4
+ import {attributable} from '../internal/attributable';
5
+ import {
6
+ addDraggable,
7
+ getDraggableStates,
8
+ OuiDraggable,
9
+ removeDraggable,
10
+ type CreateOuiDraggableOptions,
11
+ type OuiDraggableBound,
12
+ type OuiDraggableGlobals,
13
+ type OuiDraggableItem,
14
+ type OuiDraggableState,
15
+ type OuiDragMovePosition,
16
+ } from '../internal/draggable';
17
+
18
+ // #region Types
19
+
20
+ export class OuiMovable extends OuiDraggable<OuiMovableState> {
21
+ #element: HTMLElement;
22
+
23
+ #style: OuiMovableStyle;
24
+
25
+ constructor(element: HTMLElement, options?: CreateOuiDraggableOptions) {
26
+ const style = {
27
+ inset: element.style.inset,
28
+ position: element.style.position,
29
+ };
30
+
31
+ super(
32
+ 'movable',
33
+ 'move',
34
+ ATTRIBUTE_MOVABLE,
35
+ element,
36
+ {
37
+ container: {
38
+ attribute: ATTRIBUTE_CONTAINER,
39
+ map: CONTAINERS,
40
+ onDestroy: destroyContainer,
41
+ onInitialize: initializeContainer,
42
+ },
43
+ direction: {
44
+ attribute: ATTRIBUTE_DIRECTION,
45
+ onAfter: afterDirection,
46
+ },
47
+ drag: {
48
+ onBegin,
49
+ onCancel,
50
+ onEnd,
51
+ onMove,
52
+ },
53
+ input: options,
54
+ position: {
55
+ getOffset: getOffsetPosition,
56
+ getOriginal: getOriginalPosition,
57
+ },
58
+ getDragged() {
59
+ return element;
60
+ },
61
+ getOrigin() {
62
+ return element;
63
+ },
64
+ },
65
+ {
66
+ style,
67
+ hasHandles: element.querySelector(SELECTOR_HANDLE) != null,
68
+ moved: false,
69
+ },
70
+ );
71
+
72
+ this.#element = element;
73
+
74
+ this.#style = style;
75
+ }
76
+
77
+ /**
78
+ * Destroys the _Movable_
79
+ */
80
+ override destroy(): void {
81
+ MOVED.delete(this);
82
+
83
+ this.#element.style.inset = this.#style.inset;
84
+ this.#element.style.position = this.#style.position;
85
+
86
+ this.#element = undefined as never;
87
+ this.#style = undefined as never;
88
+
89
+ super.destroy();
90
+ }
91
+ }
92
+
93
+ type OuiMovableState = {
94
+ hasHandles?: boolean;
95
+ moved: boolean;
96
+ offset?: Partial<EventPosition>;
97
+ style: OuiMovableStyle;
98
+ };
99
+
100
+ type OuiMovableStyle = {
101
+ inset: string;
102
+ position: string;
103
+ };
104
+
105
+ // #endregion
106
+
107
+ // #region Functions
108
+
109
+ function afterDirection(item: OuiDraggableItem): void {
110
+ const container = item.state.container?.getBoundingClientRect();
111
+
112
+ if (container != null) {
113
+ setOffset(item.state as OuiDraggableState & OuiMovableState, container);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Creates _(or retrieves)_ a _OuiMovable_ instance for an element
119
+ *
120
+ * @param element Element to make movable
121
+ * @returns _OuiMovable_ instance
122
+ */
123
+ export function createMovable(
124
+ element: HTMLElement,
125
+ options?: CreateOuiDraggableOptions,
126
+ ): OuiMovable {
127
+ if (!isHTMLOrSVGElement(element)) {
128
+ throw new TypeError(MESSAGE);
129
+ }
130
+
131
+ return addMovable(element, options) as OuiMovable;
132
+ }
133
+
134
+ function destroyContainer(_: unknown, container: HTMLElement, empty: boolean): void {
135
+ if (empty) {
136
+ resizer.unobserve(container);
137
+ }
138
+ }
139
+
140
+ function getOffsetPosition(
141
+ globals: OuiDraggableGlobals,
142
+ _: OuiDraggableItem,
143
+ __: HTMLElement,
144
+ position: EventPosition,
145
+ ): EventPosition {
146
+ return {
147
+ x: position.x - (globals.element?.rectangle.left ?? 0),
148
+ y: position.y - (globals.element?.rectangle.top ?? 0),
149
+ };
150
+ }
151
+
152
+ function getOriginalPosition(globals: OuiDraggableGlobals): EventPosition {
153
+ return {
154
+ x: globals.element?.rectangle.left ?? 0,
155
+ y: globals.element?.rectangle.top ?? 0,
156
+ };
157
+ }
158
+
159
+ function initializeContainer(item: OuiDraggableItem): void {
160
+ resizer.observe(item.state.container!);
161
+ }
162
+
163
+ function onBegin(): void {}
164
+
165
+ function onCancel(globals: OuiDraggableGlobals, item: OuiDraggableItem): void {
166
+ const {element, moved, style} = item.state as OuiDraggableState & OuiMovableState;
167
+
168
+ const {x, y} = globals.original ?? {x: 0, y: 0};
169
+
170
+ if (moved) {
171
+ element.style.inset = `${y}px auto auto ${x}px`;
172
+ } else {
173
+ element.style.position = style.position;
174
+ element.style.inset = style.inset;
175
+ }
176
+
177
+ element.removeAttribute(ATTRIBUTE_MOVING);
178
+ }
179
+
180
+ function onEnd(
181
+ event: MouseEvent | TouchEvent,
182
+ globals: OuiDraggableGlobals,
183
+ item: OuiDraggableItem,
184
+ reset: () => void,
185
+ ): void {
186
+ const movable = item.instance as OuiMovable;
187
+ const state = item.state as OuiDraggableState & OuiMovableState;
188
+
189
+ state.element.removeAttribute(ATTRIBUTE_MOVING);
190
+
191
+ if (!state.moved) {
192
+ state.moved = true;
193
+
194
+ if (state.container != null) {
195
+ MOVED.add(movable);
196
+ }
197
+ }
198
+
199
+ const container = state.container?.getBoundingClientRect();
200
+
201
+ if (container != null) {
202
+ setOffset(state, container);
203
+ }
204
+
205
+ const end = new CustomEvent(EVENT_END, {
206
+ detail: {
207
+ from: {...globals.original},
208
+ to: getPosition(event),
209
+ },
210
+ cancelable: true,
211
+ });
212
+
213
+ state.element.dispatchEvent(end);
214
+
215
+ setTimeout(() => {
216
+ if (end.defaultPrevented) {
217
+ onCancel(globals, item);
218
+ }
219
+
220
+ reset();
221
+ });
222
+ }
223
+
224
+ function onMove(
225
+ _: MouseEvent | TouchEvent,
226
+ globals: OuiDraggableGlobals,
227
+ __: OuiDraggableItem,
228
+ position: OuiDragMovePosition,
229
+ ): PlainObject | undefined {
230
+ globals.element?.node.setAttribute(ATTRIBUTE_MOVING, '');
231
+
232
+ return {
233
+ from: {...globals.original},
234
+ to: {...position.calculated},
235
+ };
236
+ }
237
+
238
+ function onResize(entries: ResizeObserverEntry[]): void {
239
+ const {length} = entries;
240
+
241
+ for (let index = 0; index < length; index += 1) {
242
+ const entry = entries[index];
243
+ const set = CONTAINERS.get(entry.target as HTMLElement);
244
+
245
+ if (set == null) {
246
+ continue;
247
+ }
248
+
249
+ for (const movable of set) {
250
+ reposition(movable);
251
+ }
252
+ }
253
+ }
254
+
255
+ function onScroll(): void {
256
+ for (const moved of MOVED) {
257
+ reposition(moved);
258
+ }
259
+ }
260
+
261
+ function reposition(movable: OuiMovable): void {
262
+ const state = getDraggableStates(movable.element)?.movable as OuiDraggableState & OuiMovableState;
263
+
264
+ if (state == null || !state.moved || state.container == null) {
265
+ return;
266
+ }
267
+
268
+ const container = state.container.getBoundingClientRect();
269
+
270
+ const x = container.left + (state.offset?.x ?? 0);
271
+ const y = container.top + (state.offset?.y ?? 0);
272
+
273
+ state.element.style.inset = `${y}px auto auto ${x}px`;
274
+ }
275
+
276
+ function setOffset(state: OuiDraggableState & OuiMovableState, container: DOMRect): void {
277
+ state.offset = {};
278
+
279
+ const element = state.element.getBoundingClientRect();
280
+
281
+ state.offset.y = element.top - container.top;
282
+ state.offset.x = element.left - container.left;
283
+ }
284
+
285
+ // #endregion
286
+
287
+ // #region Variables
288
+
289
+ export const ATTRIBUTE_MOVABLE = 'oui-movable';
290
+
291
+ const ATTRIBUTE_CONTAINER = `${ATTRIBUTE_MOVABLE}-container`;
292
+
293
+ const ATTRIBUTE_DIRECTION = `${ATTRIBUTE_MOVABLE}-direction`;
294
+
295
+ export const ATTRIBUTE_MOVABLE_HANDLE = `${ATTRIBUTE_MOVABLE}-handle`;
296
+
297
+ const ATTRIBUTE_MOVING = `${ATTRIBUTE_MOVABLE}-moving`;
298
+
299
+ const CONTAINERS = new Map<HTMLElement, Set<OuiMovable>>();
300
+
301
+ const EVENT_END = 'move:end';
302
+
303
+ const MESSAGE = 'The element must be an instance of HTMLElement or SVGElement';
304
+
305
+ const MOVED = new Set<OuiMovable>();
306
+
307
+ const SELECTOR_HANDLE = `[${ATTRIBUTE_MOVABLE_HANDLE}]`;
308
+
309
+ const bound: OuiDraggableBound = {
310
+ constructor: OuiMovable,
311
+ property: 'movable',
312
+ };
313
+
314
+ const resizer = new ResizeObserver(onResize);
315
+
316
+ const addMovable = addDraggable.bind(bound);
317
+
318
+ const removeMovable = removeDraggable.bind(bound);
319
+
320
+ // #endregion
321
+
322
+ // #region Initialization
323
+
324
+ on(document, 'scroll', onScroll);
325
+
326
+ attributable(ATTRIBUTE_MOVABLE, addMovable, removeMovable);
327
+
328
+ // #endregion
@@ -0,0 +1,2 @@
1
+ export type {CreateOuiDraggableOptions as CreateOuiMovableOptions} from '../internal/draggable';
2
+ export {createMovable, type OuiMovable} from './movable.embedded';
package/src/js/popover.ts CHANGED
@@ -7,8 +7,8 @@ import {
7
7
  getOnBeforeToggleListener,
8
8
  type OuiFloatable,
9
9
  type OuiFloatableOptions,
10
- } from './floatable/embedded';
11
- import {createFocusTrap, type OuiFocusTrap} from './focus-trap/embedded';
10
+ } from './floatable/floatable.embedded';
11
+ import {createFocusTrap, type OuiFocusTrap} from './focus-trap/focus-trap.embedded';
12
12
  import {attributable} from './internal/attributable';
13
13
 
14
14
  // #region Types
@@ -23,6 +23,14 @@ class OuiPopover {
23
23
  return this.#state.content.checkVisibility();
24
24
  }
25
25
 
26
+ set open(value: boolean) {
27
+ if (value === true) {
28
+ this.show();
29
+ } else if (value === false) {
30
+ this.hide();
31
+ }
32
+ }
33
+
26
34
  constructor(state: OuiPopoverState) {
27
35
  this.#state = state;
28
36
 
@@ -169,6 +177,7 @@ const TRUE = 'true';
169
177
  const options: OuiFloatableOptions = {
170
178
  attribute: `${ATTRIBUTE}position`,
171
179
  position: 'below-start',
180
+ reusable: false,
172
181
  };
173
182
 
174
183
  const states = new WeakMap<HTMLElement, OuiPopoverState>();