@oscarpalmer/oui 0.17.0 → 0.18.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/badge.css +3 -3
- package/dist/css/content.css +9 -11
- package/dist/css/form.css +36 -22
- package/dist/css/message.css +4 -0
- package/dist/css/reset.css +176 -56
- package/dist/css/tooltip.css +8 -0
- package/dist/js/attributable.full.js +48 -0
- package/dist/js/attributable.js +30 -45
- package/dist/js/floatable.full.js +413 -0
- package/dist/js/floatable.js +254 -169
- package/dist/js/focus-trap/embedded.full.js +351 -0
- package/dist/js/focus-trap/embedded.js +131 -131
- package/dist/js/focus-trap/standalone.full.js +402 -0
- package/dist/js/focus-trap/standalone.js +4 -4
- package/dist/js/index.js +4 -5
- package/dist/js/oui.full.js +1596 -0
- package/dist/js/popover.full.js +822 -0
- package/dist/js/popover.js +83 -162
- package/dist/js/splitter.full.js +605 -0
- package/dist/js/splitter.js +263 -245
- package/dist/js/tooltip.full.js +679 -0
- package/dist/js/tooltip.js +159 -150
- package/package.json +31 -59
- package/src/css/content.scss +1 -2
- package/src/css/form.scss +12 -4
- package/src/css/message.scss +3 -0
- package/src/css/mixins.scss +7 -0
- package/src/css/reset.scss +180 -54
- package/src/css/tooltip.scss +8 -0
- package/src/js/floatable.ts +380 -133
- package/src/js/focus-trap/embedded.ts +149 -64
- package/src/js/focus-trap/standalone.ts +4 -4
- package/src/js/index.ts +1 -0
- package/src/js/popover.ts +50 -120
- package/src/js/splitter.ts +250 -103
- package/src/js/tooltip.ts +155 -68
- package/types/floatable.d.ts +17 -10
- package/types/focus-trap/embedded.d.ts +18 -5
- package/types/index.d.ts +1 -0
- package/types/popover.d.ts +2 -0
- package/types/splitter.d.ts +13 -1
- package/types/tooltip.d.ts +2 -1
- package/dist/js/attributable.cjs +0 -51
- package/dist/js/floatable.cjs +0 -176
- package/dist/js/focus-trap/embedded.cjs +0 -150
- package/dist/js/focus-trap/standalone.cjs +0 -8
- package/dist/js/index.cjs +0 -6
- package/dist/js/popover.cjs +0 -166
- package/dist/js/splitter.cjs +0 -272
- package/dist/js/tooltip.cjs +0 -166
- package/types/attributable.d.cts +0 -5
- package/types/floatable.d.cts +0 -20
- package/types/focus-trap/embedded.d.cts +0 -15
- package/types/focus-trap/standalone.d.cts +0 -3
- package/types/index.d.cts +0 -14
- package/types/popover.d.cts +0 -14
- package/types/splitter.d.cts +0 -10
- package/types/tooltip.d.cts +0 -3
package/src/js/floatable.ts
CHANGED
|
@@ -1,31 +1,109 @@
|
|
|
1
|
+
import {on} from '@oscarpalmer/toretto/event';
|
|
2
|
+
import {findAncestor} from '@oscarpalmer/toretto/find';
|
|
3
|
+
|
|
1
4
|
export class Floatable {
|
|
2
|
-
|
|
5
|
+
active = false;
|
|
6
|
+
|
|
7
|
+
disabled = false;
|
|
8
|
+
|
|
9
|
+
frame: DOMHighResTimeStamp | undefined;
|
|
10
|
+
|
|
11
|
+
ignoreFocus = false;
|
|
12
|
+
|
|
13
|
+
constructor(readonly options: Options) {
|
|
14
|
+
initialize(this);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
destroy(): void {
|
|
18
|
+
stop(this);
|
|
19
|
+
|
|
20
|
+
const state = getState();
|
|
21
|
+
|
|
22
|
+
state?.active.delete(this);
|
|
23
|
+
state?.mapped.delete(this.options.anchor);
|
|
24
|
+
state?.mapped.delete(this.options.content);
|
|
25
|
+
|
|
26
|
+
this.options.anchor = undefined as never;
|
|
27
|
+
this.options.content = undefined as never;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
disable(): void {
|
|
31
|
+
if (this.disabled) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.disabled = true;
|
|
36
|
+
|
|
37
|
+
stop(this);
|
|
38
|
+
|
|
39
|
+
getState()?.active.delete(this);
|
|
40
|
+
}
|
|
3
41
|
|
|
4
|
-
|
|
42
|
+
enable(): void {
|
|
43
|
+
if (!this.disabled) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.disabled = false;
|
|
48
|
+
|
|
49
|
+
initialize(this);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
toggle(active: boolean, ignoreFocus?: boolean): void {
|
|
53
|
+
if (this.disabled || this.active === active) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const state = getState();
|
|
58
|
+
|
|
59
|
+
if (state == null) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
5
62
|
|
|
6
|
-
|
|
63
|
+
this.ignoreFocus = !active && (ignoreFocus ?? false);
|
|
7
64
|
|
|
8
|
-
|
|
65
|
+
stop(this);
|
|
9
66
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
readonly position: Position,
|
|
15
|
-
readonly preferAbove: boolean,
|
|
16
|
-
) {
|
|
17
|
-
setStyles(content);
|
|
67
|
+
if (active) {
|
|
68
|
+
state.active.add(this);
|
|
69
|
+
} else {
|
|
70
|
+
state.active.delete(this);
|
|
18
71
|
}
|
|
19
72
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
73
|
+
if (this.options.interactive) {
|
|
74
|
+
if (active) {
|
|
75
|
+
state.order.push(this);
|
|
76
|
+
} else {
|
|
77
|
+
const index = state.order.indexOf(this);
|
|
24
78
|
|
|
25
|
-
|
|
26
|
-
|
|
79
|
+
if (index > -1) {
|
|
80
|
+
state.order.splice(index, 1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (active) {
|
|
86
|
+
activate(this);
|
|
87
|
+
} else {
|
|
88
|
+
deactivate(this);
|
|
27
89
|
}
|
|
28
90
|
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
type FloatableWindow = Window & {
|
|
94
|
+
// biome-ignore lint/style/useNamingConvention: Non-standard name to avoid conflicts
|
|
95
|
+
_oscarpalmer_oui_floatable: State;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
type Options = {
|
|
99
|
+
anchor: HTMLElement;
|
|
100
|
+
content: HTMLElement;
|
|
101
|
+
defaultPosition: Position;
|
|
102
|
+
interactive: boolean;
|
|
103
|
+
positionAttribute: string;
|
|
104
|
+
preferAbove: boolean;
|
|
105
|
+
onAfter?: (active: boolean) => void;
|
|
106
|
+
};
|
|
29
107
|
|
|
30
108
|
type Position =
|
|
31
109
|
| 'above'
|
|
@@ -47,82 +125,117 @@ type Position =
|
|
|
47
125
|
| 'vertical-end'
|
|
48
126
|
| 'vertical-start';
|
|
49
127
|
|
|
128
|
+
type State = {
|
|
129
|
+
active: Set<Floatable>;
|
|
130
|
+
mapped: Map<HTMLElement, Floatable>;
|
|
131
|
+
order: Floatable[];
|
|
132
|
+
};
|
|
133
|
+
|
|
50
134
|
//
|
|
51
135
|
|
|
52
|
-
|
|
53
|
-
floatable
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
stop(floatable);
|
|
136
|
+
function activate(floatable: Floatable): void {
|
|
137
|
+
floatable.active = true;
|
|
138
|
+
|
|
139
|
+
document.body.append(floatable.options.content);
|
|
140
|
+
|
|
141
|
+
floatable.options.content.hidden = false;
|
|
59
142
|
|
|
60
|
-
|
|
143
|
+
updatePosition(floatable);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function closeAbove(element: HTMLElement): void {
|
|
147
|
+
const state = getState();
|
|
148
|
+
|
|
149
|
+
if (state == null) {
|
|
61
150
|
return;
|
|
62
151
|
}
|
|
63
152
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
153
|
+
const index = state.order.findIndex(
|
|
154
|
+
floatable =>
|
|
155
|
+
floatable.options.anchor === element ||
|
|
156
|
+
floatable.options.content === element,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
if (index === -1 || index === state.order.length - 1) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
while (index < state.order.length - 1) {
|
|
164
|
+
void state.order.pop()?.toggle(false, true);
|
|
70
165
|
}
|
|
71
166
|
}
|
|
72
167
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
active: Set<Floatable>,
|
|
76
|
-
order?: Floatable[],
|
|
77
|
-
time?: number,
|
|
78
|
-
): void {
|
|
79
|
-
stop(floatable);
|
|
168
|
+
function closeAll(): void {
|
|
169
|
+
const state = getState();
|
|
80
170
|
|
|
81
|
-
|
|
82
|
-
|
|
171
|
+
const floatables = [...(state?.active ?? [])];
|
|
172
|
+
|
|
173
|
+
state?.active.clear();
|
|
174
|
+
|
|
175
|
+
for (const floatable of floatables) {
|
|
176
|
+
void floatable.toggle(false, true);
|
|
83
177
|
}
|
|
178
|
+
}
|
|
84
179
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}, time);
|
|
180
|
+
function closeNonInteractive(state: State): void {
|
|
181
|
+
for (const floatable of state.active) {
|
|
182
|
+
if (!floatable.options.interactive) {
|
|
183
|
+
void floatable.toggle(false);
|
|
184
|
+
}
|
|
91
185
|
}
|
|
92
186
|
}
|
|
93
187
|
|
|
188
|
+
export function deactivate(floatable: Floatable): void {
|
|
189
|
+
floatable.active = false;
|
|
190
|
+
|
|
191
|
+
floatable.options.content.hidden = true;
|
|
192
|
+
|
|
193
|
+
floatable.options.anchor.insertAdjacentElement(
|
|
194
|
+
INSERT_AFTEREND,
|
|
195
|
+
floatable.options.content,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
floatable.options.onAfter?.(false);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function getState(): State {
|
|
202
|
+
return (window as unknown as FloatableWindow)._oscarpalmer_oui_floatable;
|
|
203
|
+
}
|
|
204
|
+
|
|
94
205
|
function getX(anchor: DOMRect, content: DOMRect, position: Position): number {
|
|
95
|
-
if (position.endsWith(
|
|
206
|
+
if (position.endsWith(POSITION_SUFFIX_END)) {
|
|
96
207
|
const end = anchor.right - content.width;
|
|
97
208
|
|
|
98
|
-
return end
|
|
209
|
+
return end < 0 ? 0 : end;
|
|
99
210
|
}
|
|
100
211
|
|
|
101
|
-
if (position.endsWith(
|
|
212
|
+
if (position.endsWith(POSITION_SUFFIX_START)) {
|
|
102
213
|
const start = anchor.left;
|
|
103
214
|
|
|
104
|
-
return start + content.width
|
|
105
|
-
? window.innerWidth - content.width
|
|
215
|
+
return start + content.width > window.innerWidth
|
|
216
|
+
? window.innerWidth - content.width
|
|
106
217
|
: start;
|
|
107
218
|
}
|
|
108
219
|
|
|
109
|
-
if (position.startsWith(
|
|
110
|
-
return anchor.right
|
|
220
|
+
if (position.startsWith(POSITION_END)) {
|
|
221
|
+
return anchor.right;
|
|
111
222
|
}
|
|
112
223
|
|
|
113
|
-
if (position.startsWith(
|
|
114
|
-
return anchor.left - content.width
|
|
224
|
+
if (position.startsWith(POSITION_START)) {
|
|
225
|
+
return anchor.left - content.width;
|
|
115
226
|
}
|
|
116
227
|
|
|
117
|
-
if (position.startsWith(
|
|
118
|
-
if (anchor.right + content.width
|
|
119
|
-
return anchor.right
|
|
228
|
+
if (position.startsWith(POSITION_HORIZONTAL)) {
|
|
229
|
+
if (anchor.right + content.width <= window.innerWidth) {
|
|
230
|
+
return anchor.right;
|
|
120
231
|
}
|
|
121
232
|
|
|
122
|
-
return anchor.left - content.width
|
|
233
|
+
return anchor.left - content.width;
|
|
123
234
|
}
|
|
124
235
|
|
|
125
|
-
|
|
236
|
+
const left = anchor.left + (anchor.width - content.width) / 2;
|
|
237
|
+
|
|
238
|
+
return left < 0 ? 0 : left;
|
|
126
239
|
}
|
|
127
240
|
|
|
128
241
|
function getY(
|
|
@@ -131,137 +244,243 @@ function getY(
|
|
|
131
244
|
position: Position,
|
|
132
245
|
preferAbove: boolean,
|
|
133
246
|
): number {
|
|
134
|
-
if (position.startsWith(
|
|
135
|
-
return anchor.top - content.height
|
|
247
|
+
if (position.startsWith(POSITION_ABOVE)) {
|
|
248
|
+
return anchor.top - content.height;
|
|
136
249
|
}
|
|
137
250
|
|
|
138
|
-
if (position.startsWith(
|
|
139
|
-
return anchor.bottom
|
|
251
|
+
if (position.startsWith(POSITION_BELOW)) {
|
|
252
|
+
return anchor.bottom;
|
|
140
253
|
}
|
|
141
254
|
|
|
142
|
-
if (position.endsWith(
|
|
255
|
+
if (position.endsWith(POSITION_BOTTOM)) {
|
|
143
256
|
const bottom = anchor.bottom - content.height;
|
|
144
257
|
|
|
145
|
-
return bottom
|
|
258
|
+
return bottom < 0 ? 0 : bottom;
|
|
146
259
|
}
|
|
147
260
|
|
|
148
|
-
if (position.endsWith(
|
|
261
|
+
if (position.endsWith(POSITION_TOP)) {
|
|
149
262
|
const top = anchor.top;
|
|
150
263
|
|
|
151
|
-
return top + content.height
|
|
152
|
-
? window.innerHeight - content.height
|
|
264
|
+
return top + content.height > window.innerHeight
|
|
265
|
+
? window.innerHeight - content.height
|
|
153
266
|
: top;
|
|
154
267
|
}
|
|
155
268
|
|
|
156
|
-
if (position.startsWith(
|
|
157
|
-
if (preferAbove && anchor.top - content.height
|
|
158
|
-
return anchor.top - content.height
|
|
269
|
+
if (position.startsWith(POSITION_VERTICAL)) {
|
|
270
|
+
if (preferAbove && anchor.top - content.height >= 0) {
|
|
271
|
+
return anchor.top - content.height;
|
|
159
272
|
}
|
|
160
273
|
|
|
161
|
-
if (anchor.bottom + content.height
|
|
162
|
-
return anchor.bottom
|
|
274
|
+
if (anchor.bottom + content.height <= document.body.clientHeight) {
|
|
275
|
+
return anchor.bottom;
|
|
163
276
|
}
|
|
164
277
|
|
|
165
|
-
return anchor.top - content.height
|
|
278
|
+
return anchor.top - content.height;
|
|
166
279
|
}
|
|
167
280
|
|
|
168
281
|
return anchor.top + (anchor.height - content.height) / 2;
|
|
169
282
|
}
|
|
170
283
|
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
)
|
|
176
|
-
|
|
284
|
+
function initialize(floatable: Floatable): void {
|
|
285
|
+
const {anchor, content, interactive} = floatable.options;
|
|
286
|
+
|
|
287
|
+
if (interactive) {
|
|
288
|
+
anchor.setAttribute(ATTRIBUTE_ANCHOR, '');
|
|
289
|
+
content.setAttribute(ATTRIBUTE_CONTENT, '');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
content.style.position = 'fixed';
|
|
293
|
+
content.style.inset = '0 auto auto 0';
|
|
294
|
+
content.style.zIndex = '10';
|
|
295
|
+
|
|
296
|
+
const state = getState();
|
|
297
|
+
|
|
298
|
+
state?.mapped.set(anchor, floatable);
|
|
299
|
+
state?.mapped.set(content, floatable);
|
|
300
|
+
}
|
|
177
301
|
|
|
178
|
-
|
|
302
|
+
function isDisabled(element: HTMLElement): boolean {
|
|
303
|
+
return (
|
|
304
|
+
(element as HTMLInputElement).disabled ||
|
|
305
|
+
(element as HTMLInputElement).readOnly ||
|
|
306
|
+
element.getAttribute('aria-disabled') === 'true'
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function onClick(event: PointerEvent): void {
|
|
311
|
+
const related = findAncestor(event.target as never, SELECTOR_ALL);
|
|
179
312
|
|
|
180
|
-
if (
|
|
181
|
-
|
|
313
|
+
if (!(related instanceof HTMLElement)) {
|
|
314
|
+
closeAll();
|
|
315
|
+
} else if (related.hasAttribute(ATTRIBUTE_CONTENT)) {
|
|
316
|
+
closeAbove(related);
|
|
317
|
+
} else if (!isDisabled(related)) {
|
|
318
|
+
toggle(related);
|
|
182
319
|
}
|
|
320
|
+
}
|
|
183
321
|
|
|
184
|
-
|
|
322
|
+
function onKeyDown(event: KeyboardEvent): void {
|
|
323
|
+
if (event.key !== 'Escape') {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const state = getState();
|
|
328
|
+
|
|
329
|
+
if (state == null || state.active.size === 0) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
185
332
|
|
|
186
|
-
|
|
333
|
+
closeNonInteractive(state);
|
|
187
334
|
|
|
188
|
-
|
|
335
|
+
const related = findAncestor(event.target as never, SELECTOR_CONTENT);
|
|
336
|
+
|
|
337
|
+
if (!(related instanceof HTMLElement)) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
closeAbove(related);
|
|
342
|
+
|
|
343
|
+
const floatable = state.mapped.get(related);
|
|
344
|
+
|
|
345
|
+
if (floatable != null) {
|
|
346
|
+
void floatable.toggle(false);
|
|
347
|
+
}
|
|
189
348
|
}
|
|
190
349
|
|
|
191
|
-
function
|
|
192
|
-
floatable
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
): void {
|
|
196
|
-
floatable.active = false;
|
|
350
|
+
function stop(floatable: Floatable): void {
|
|
351
|
+
if (floatable.frame != null) {
|
|
352
|
+
cancelAnimationFrame(floatable.frame);
|
|
353
|
+
}
|
|
197
354
|
|
|
198
|
-
|
|
355
|
+
floatable.frame = undefined;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function toggle(anchor: HTMLElement): void {
|
|
359
|
+
const floatable = getState()?.mapped.get(anchor);
|
|
199
360
|
|
|
200
|
-
|
|
361
|
+
if (floatable == null) {
|
|
362
|
+
closeAll();
|
|
201
363
|
|
|
202
|
-
|
|
203
|
-
order?.splice(index, 1);
|
|
364
|
+
return;
|
|
204
365
|
}
|
|
205
366
|
|
|
206
|
-
|
|
367
|
+
const active = Boolean(floatable.active);
|
|
368
|
+
const content = findAncestor(floatable.options.anchor, SELECTOR_CONTENT);
|
|
207
369
|
|
|
208
|
-
|
|
370
|
+
if (content == null) {
|
|
371
|
+
closeAll();
|
|
372
|
+
} else {
|
|
373
|
+
closeAbove(content as HTMLElement);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
void floatable.toggle(!active);
|
|
209
377
|
}
|
|
210
378
|
|
|
211
|
-
function
|
|
379
|
+
function updatePosition(floatable: Floatable): void {
|
|
212
380
|
let position: Position =
|
|
213
|
-
(floatable.anchor
|
|
214
|
-
|
|
381
|
+
(floatable.options.anchor
|
|
382
|
+
.getAttribute(floatable.options.positionAttribute)
|
|
383
|
+
?.trim() as Position) ?? floatable.options.defaultPosition;
|
|
215
384
|
|
|
216
|
-
if (!
|
|
217
|
-
position = floatable.
|
|
385
|
+
if (!POSITIONS.has(position as Position)) {
|
|
386
|
+
position = floatable.options.defaultPosition;
|
|
218
387
|
}
|
|
219
388
|
|
|
389
|
+
let previousAnchor: DOMRect;
|
|
390
|
+
let previousContent: DOMRect;
|
|
391
|
+
|
|
392
|
+
let calculated = false;
|
|
393
|
+
let runOnAfter = false;
|
|
394
|
+
|
|
220
395
|
function run(): void {
|
|
221
|
-
|
|
222
|
-
|
|
396
|
+
const anchor = floatable.options.anchor.getBoundingClientRect();
|
|
397
|
+
const content = floatable.options.content.getBoundingClientRect();
|
|
398
|
+
|
|
399
|
+
if (calculated) {
|
|
400
|
+
if (previousAnchor != null && previousContent != null) {
|
|
401
|
+
if (
|
|
402
|
+
PROPERTIES.every(
|
|
403
|
+
property => anchor[property] === previousAnchor[property],
|
|
404
|
+
) &&
|
|
405
|
+
PROPERTIES.every(
|
|
406
|
+
property => content[property] === previousContent[property],
|
|
407
|
+
)
|
|
408
|
+
) {
|
|
409
|
+
floatable.frame = requestAnimationFrame(run);
|
|
410
|
+
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
} else {
|
|
415
|
+
calculated = true;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
update(anchor, content);
|
|
419
|
+
}
|
|
223
420
|
|
|
224
|
-
|
|
225
|
-
|
|
421
|
+
function update(anchor: DOMRect, content: DOMRect): void {
|
|
422
|
+
previousAnchor = anchor;
|
|
423
|
+
previousContent = content;
|
|
226
424
|
|
|
227
|
-
|
|
425
|
+
const left = getX(anchor, content, position);
|
|
426
|
+
const top = getY(anchor, content, position, floatable.options.preferAbove);
|
|
228
427
|
|
|
229
|
-
|
|
428
|
+
if (top + content.height > window.innerHeight) {
|
|
429
|
+
floatable.options.content.style.height = `${window.innerHeight - top}px`;
|
|
430
|
+
} else {
|
|
431
|
+
floatable.options.content.style.height = '';
|
|
230
432
|
}
|
|
231
433
|
|
|
232
|
-
|
|
233
|
-
}
|
|
434
|
+
if (left + content.width > window.innerWidth) {
|
|
435
|
+
floatable.options.content.style.width = `${window.innerWidth - left}px`;
|
|
436
|
+
} else {
|
|
437
|
+
floatable.options.content.style.width = '';
|
|
438
|
+
}
|
|
234
439
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
content.style.inset = '0 auto auto 0';
|
|
238
|
-
content.style.zIndex = '10';
|
|
239
|
-
}
|
|
440
|
+
// floatable.options.content.style.inset = `${top}px auto auto ${left}px`;
|
|
441
|
+
floatable.options.content.style.transform = `translate3d(${left}px, ${top}px, 0)`;
|
|
240
442
|
|
|
241
|
-
|
|
242
|
-
if (floatable.frame != null) {
|
|
243
|
-
cancelAnimationFrame(floatable.frame);
|
|
244
|
-
}
|
|
443
|
+
floatable.frame = requestAnimationFrame(run);
|
|
245
444
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
445
|
+
if (!runOnAfter) {
|
|
446
|
+
runOnAfter = true;
|
|
249
447
|
|
|
250
|
-
|
|
251
|
-
|
|
448
|
+
floatable.options.onAfter?.(true);
|
|
449
|
+
}
|
|
252
450
|
}
|
|
253
451
|
|
|
254
|
-
floatable.
|
|
255
|
-
floatable.deactivate = undefined;
|
|
256
|
-
floatable.frame = undefined;
|
|
452
|
+
floatable.frame = requestAnimationFrame(run);
|
|
257
453
|
}
|
|
258
454
|
|
|
259
455
|
//
|
|
260
456
|
|
|
261
|
-
const
|
|
262
|
-
|
|
457
|
+
const ATTRIBUTE_ANCHOR = 'oui-floatable-anchor';
|
|
458
|
+
|
|
459
|
+
const ATTRIBUTE_CONTENT = 'oui-floatable-content';
|
|
460
|
+
|
|
461
|
+
const INSERT_AFTEREND = 'afterend';
|
|
462
|
+
|
|
463
|
+
const POSITION_ABOVE = 'above';
|
|
263
464
|
|
|
264
|
-
const
|
|
465
|
+
const POSITION_BELOW = 'below';
|
|
466
|
+
|
|
467
|
+
const POSITION_BOTTOM = 'bottom';
|
|
468
|
+
|
|
469
|
+
const POSITION_END = 'end';
|
|
470
|
+
|
|
471
|
+
const POSITION_HORIZONTAL = 'horizontal';
|
|
472
|
+
|
|
473
|
+
const POSITION_START = 'start';
|
|
474
|
+
|
|
475
|
+
const POSITION_SUFFIX_END = '-end';
|
|
476
|
+
|
|
477
|
+
const POSITION_SUFFIX_START = '-start';
|
|
478
|
+
|
|
479
|
+
const POSITION_TOP = 'top';
|
|
480
|
+
|
|
481
|
+
const POSITION_VERTICAL = 'vertical';
|
|
482
|
+
|
|
483
|
+
const POSITIONS: Set<Position> = new Set([
|
|
265
484
|
'above',
|
|
266
485
|
'above-end',
|
|
267
486
|
'above-start',
|
|
@@ -281,3 +500,31 @@ const positions = new Set<Position>([
|
|
|
281
500
|
'vertical-end',
|
|
282
501
|
'vertical-start',
|
|
283
502
|
]);
|
|
503
|
+
|
|
504
|
+
const PROPERTIES: (keyof DOMRect)[] = ['bottom', 'left', 'right', 'top'];
|
|
505
|
+
|
|
506
|
+
const SELECTOR_ALL = `[${ATTRIBUTE_ANCHOR}], [${ATTRIBUTE_CONTENT}]`;
|
|
507
|
+
|
|
508
|
+
const SELECTOR_CONTENT = `[${ATTRIBUTE_CONTENT}]`;
|
|
509
|
+
|
|
510
|
+
//
|
|
511
|
+
|
|
512
|
+
if ((window as unknown as FloatableWindow)._oscarpalmer_oui_floatable == null) {
|
|
513
|
+
Object.defineProperty(window, '_oscarpalmer_oui_floatable', {
|
|
514
|
+
enumerable: false,
|
|
515
|
+
value: {
|
|
516
|
+
active: new Set(),
|
|
517
|
+
mapped: new Map(),
|
|
518
|
+
order: [],
|
|
519
|
+
},
|
|
520
|
+
writable: false,
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
on(document, 'keydown', event => {
|
|
524
|
+
onKeyDown(event);
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
on(document, 'click', event => {
|
|
528
|
+
onClick(event);
|
|
529
|
+
});
|
|
530
|
+
}
|