@schukai/monster 4.129.1 → 4.129.2

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 (25) hide show
  1. package/package.json +1 -1
  2. package/source/components/content/stylesheet/camera-capture.mjs +1 -1
  3. package/source/components/content/stylesheet/copy.mjs +1 -1
  4. package/source/components/content/viewer/stylesheet/message.mjs +1 -1
  5. package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +1 -1
  6. package/source/components/form/message-state-button.mjs +2 -1
  7. package/source/components/form/popper-button.mjs +51 -9
  8. package/source/components/form/select.mjs +76 -14
  9. package/source/components/form/style/context-error.pcss +15 -0
  10. package/source/components/form/style/context-help.pcss +13 -1
  11. package/source/components/form/stylesheet/button-bar.mjs +1 -1
  12. package/source/components/form/stylesheet/confirm-button.mjs +1 -1
  13. package/source/components/form/stylesheet/context-error.mjs +1 -1
  14. package/source/components/form/stylesheet/context-help.mjs +1 -1
  15. package/source/components/form/stylesheet/digits.mjs +1 -1
  16. package/source/components/form/stylesheet/field-set.mjs +1 -1
  17. package/source/components/form/stylesheet/login.mjs +1 -1
  18. package/source/components/form/stylesheet/message-state-button.mjs +13 -6
  19. package/source/components/form/stylesheet/popper-button.mjs +13 -6
  20. package/source/components/form/stylesheet/select.mjs +1 -1
  21. package/source/components/form/util/floating-ui.mjs +808 -168
  22. package/source/components/layout/popper.mjs +68 -15
  23. package/source/components/layout/stylesheet/popper.mjs +13 -6
  24. package/source/components/style/floating-ui.css +57 -1
  25. package/source/components/stylesheet/floating-ui.mjs +13 -6
@@ -16,7 +16,6 @@ import {
16
16
  arrow,
17
17
  autoPlacement,
18
18
  autoUpdate,
19
- detectOverflow,
20
19
  computePosition,
21
20
  offset,
22
21
  flip,
@@ -24,11 +23,21 @@ import {
24
23
  shift,
25
24
  } from "@floating-ui/dom";
26
25
  import { Processing } from "../../../util/processing.mjs";
27
- import { getDocument } from "../../../dom/util.mjs";
28
26
  import { isString, isArray, isObject, isFunction } from "../../../types/is.mjs";
29
27
  import { hide } from "@popperjs/core";
30
28
 
31
- export { positionPopper };
29
+ export {
30
+ canUseNativePositionedPopper,
31
+ closePositionedPopper,
32
+ isPositionedPopperOpen,
33
+ openPositionedPopper,
34
+ positionPopper,
35
+ };
36
+
37
+ const autoUpdateCleanupMap = new WeakMap();
38
+ const nativeArrowSyncFrameMap = new WeakMap();
39
+ const anchorNameMap = new WeakMap();
40
+ let anchorNameCounter = 0;
32
41
 
33
42
  /**
34
43
  * @private
@@ -38,191 +47,822 @@ export { positionPopper };
38
47
  * @return {Promise|*}
39
48
  */
40
49
  function positionPopper(controlElement, popperElement, options) {
41
- const body = getDocument().body;
50
+ const config = normalizePopperConfig(options);
42
51
 
43
52
  return new Processing(() => {
44
- const arrowElement = controlElement.querySelector(
53
+ if (canUseNativePositionedPopper(controlElement, popperElement, config)) {
54
+ prepareNativePopover(controlElement, popperElement, config);
55
+ startAutoUpdate(controlElement, popperElement, () => {
56
+ syncNativePopover(controlElement, popperElement, config);
57
+ });
58
+ syncNativePopover(controlElement, popperElement, config);
59
+ return;
60
+ }
61
+
62
+ teardownNativePopover(popperElement);
63
+ popperElement.style.removeProperty("visibility");
64
+ popperElement.style.display = "block";
65
+
66
+ const arrowElement = popperElement.querySelector(
45
67
  "[data-monster-role=arrow]",
46
68
  );
69
+ const floatingMiddleware = [...config.floatingMiddleware];
70
+ if (
71
+ arrowElement instanceof HTMLElement &&
72
+ config.middlewareTokens.includes("arrow")
73
+ ) {
74
+ floatingMiddleware.push(arrow({ element: arrowElement }));
75
+ }
47
76
 
48
- const config = Object.assign(
49
- {},
50
- {
51
- placement: "top",
52
- },
53
- options,
54
- );
77
+ startAutoUpdate(controlElement, popperElement, () => {
78
+ computePosition(
79
+ controlElement,
80
+ popperElement,
81
+ Object.assign({}, config, {
82
+ middleware: floatingMiddleware,
83
+ }),
84
+ ).then(({ x, y, placement, middlewareData }) => {
85
+ Object.assign(popperElement.style, {
86
+ top: "0",
87
+ left: "0",
88
+ transform: `translate(${roundByDPR(x)}px,${roundByDPR(y)}px)`,
89
+ });
90
+
91
+ if (middlewareData.arrow) {
92
+ applyFloatingArrowStyles(
93
+ arrowElement,
94
+ placement,
95
+ middlewareData.arrow,
96
+ );
97
+ }
98
+ });
99
+ });
100
+ }).run();
101
+ }
102
+
103
+ function openPositionedPopper(controlElement, popperElement, options) {
104
+ const config = normalizePopperConfig(options);
105
+
106
+ if (canUseNativePositionedPopper(controlElement, popperElement, config)) {
107
+ prepareNativePopover(controlElement, popperElement, config);
108
+ popperElement.style.removeProperty("transform");
109
+ if (!matchesPopoverOpen(popperElement)) {
110
+ popperElement.showPopover();
111
+ }
112
+ return;
113
+ }
114
+
115
+ teardownNativePopover(popperElement);
116
+ popperElement.style.display = "block";
117
+ }
118
+
119
+ function closePositionedPopper(popperElement) {
120
+ stopAutoUpdate(popperElement);
121
+ cancelScheduledNativeArrowSync(popperElement);
122
+
123
+ if (isNativePopoverElement(popperElement)) {
124
+ if (matchesPopoverOpen(popperElement)) {
125
+ popperElement.hidePopover();
126
+ }
127
+ popperElement.style.display = "none";
128
+ popperElement.style.removeProperty("visibility");
129
+ popperElement.style.removeProperty("transform");
130
+ return;
131
+ }
132
+
133
+ popperElement.style.display = "none";
134
+ }
135
+
136
+ function isPositionedPopperOpen(popperElement) {
137
+ if (isNativePopoverElement(popperElement)) {
138
+ return matchesPopoverOpen(popperElement);
139
+ }
140
+
141
+ return popperElement.style.display === "block";
142
+ }
143
+
144
+ function canUseNativePositionedPopper(controlElement, popperElement, options) {
145
+ if (!(controlElement instanceof HTMLElement)) {
146
+ return false;
147
+ }
148
+
149
+ if (!(popperElement instanceof HTMLElement)) {
150
+ return false;
151
+ }
152
+
153
+ if (options?.engine !== "native") {
154
+ return false;
155
+ }
156
+
157
+ if (!("showPopover" in HTMLElement.prototype)) {
158
+ return false;
159
+ }
160
+
161
+ if (typeof CSS === "undefined") {
162
+ return false;
163
+ }
164
+
165
+ return (
166
+ CSS.supports("anchor-name: --monster-popper-anchor") &&
167
+ CSS.supports("position-anchor: --monster-popper-anchor") &&
168
+ CSS.supports("top: anchor(bottom)")
169
+ );
170
+ }
171
+
172
+ function normalizePopperConfig(options) {
173
+ const config = Object.assign(
174
+ {},
175
+ {
176
+ placement: "top",
177
+ engine: "native",
178
+ },
179
+ options,
180
+ );
181
+
182
+ config.middleware = normalizeMiddleware(config);
183
+ config.middlewareTokens = config.middleware.filter((line) => isString(line));
184
+ config.floatingMiddleware = buildFloatingMiddleware(
185
+ config.middleware,
186
+ config.placement,
187
+ );
188
+
189
+ return config;
190
+ }
191
+
192
+ function normalizeMiddleware(config) {
193
+ const middleware = config?.["middleware"];
194
+ if (isArray(middleware)) {
195
+ return [...middleware];
196
+ }
197
+
198
+ if (isString(middleware)) {
199
+ return middleware.split(",").filter((line) => line.trim().length > 0);
200
+ }
201
+
202
+ return [];
203
+ }
55
204
 
56
- const middleware = config?.["middleware"];
57
- if (!isArray(middleware)) {
58
- if (isString(middleware)) {
59
- config["middleware"] = middleware.split(",").filter((line) => {
60
- return line.trim().length > 0;
205
+ function buildFloatingMiddleware(middleware, placement) {
206
+ const result = [...middleware];
207
+
208
+ for (const key in result) {
209
+ const line = result[key];
210
+ if (isFunction(line) || isObject(line)) {
211
+ continue;
212
+ }
213
+
214
+ if (!isString(line)) {
215
+ throw new Error(
216
+ `Middleware must be a string, a function or an object. Got ${typeof line}`,
217
+ );
218
+ }
219
+
220
+ const kv = line.split(":");
221
+ const fn = kv.shift();
222
+
223
+ switch (fn) {
224
+ case "flip":
225
+ result[key] = flip();
226
+ break;
227
+ case "shift":
228
+ result[key] = shift();
229
+ break;
230
+ case "autoPlacement":
231
+ let defaultAllowedPlacements = ["top", "bottom", "left", "right"];
232
+
233
+ const defPlacement = kv?.shift();
234
+ if (isString(defPlacement) && defPlacement.trim().length > 0) {
235
+ defaultAllowedPlacements = defPlacement
236
+ .split(",")
237
+ .filter((entry) => entry.trim().length > 0);
238
+ }
239
+
240
+ if (defaultAllowedPlacements.includes(placement)) {
241
+ defaultAllowedPlacements.splice(
242
+ defaultAllowedPlacements.indexOf(placement),
243
+ 1,
244
+ );
245
+ }
246
+ defaultAllowedPlacements.unshift(placement);
247
+
248
+ result[key] = autoPlacement({
249
+ crossAxis: true,
250
+ autoAlignment: true,
251
+ allowedPlacements: defaultAllowedPlacements,
61
252
  });
62
- } else {
63
- config["middleware"] = [];
64
- }
253
+ break;
254
+ case "arrow":
255
+ result[key] = null;
256
+ break;
257
+ case "size":
258
+ result[key] = size({
259
+ apply({ availableWidth, availableHeight, elements }) {
260
+ Object.assign(elements.floating.style, {
261
+ boxSizing: "border-box",
262
+ maxWidth: `${availableWidth}px`,
263
+ maxHeight: `${availableHeight}px`,
264
+ });
265
+ },
266
+ });
267
+ break;
268
+ case "offset":
269
+ result[key] = offset(parseInt(kv?.shift()) || 10);
270
+ break;
271
+ case "hide":
272
+ result[key] = hide();
273
+ break;
274
+ default:
275
+ throw new Error(`Unknown function: ${fn}`);
65
276
  }
277
+ }
66
278
 
67
- for (const key in middleware) {
68
- const line = middleware[key];
69
- if (isFunction(line)) {
70
- continue;
71
- }
279
+ return result.filter(Boolean);
280
+ }
281
+
282
+ function startAutoUpdate(controlElement, popperElement, callback) {
283
+ stopAutoUpdate(popperElement);
284
+ autoUpdateCleanupMap.set(
285
+ popperElement,
286
+ autoUpdate(controlElement, popperElement, callback),
287
+ );
288
+ }
289
+
290
+ function stopAutoUpdate(popperElement) {
291
+ const cleanup = autoUpdateCleanupMap.get(popperElement);
292
+ if (typeof cleanup === "function") {
293
+ cleanup();
294
+ }
295
+ autoUpdateCleanupMap.delete(popperElement);
296
+ }
297
+
298
+ function scheduleNativeArrowSync(controlElement, popperElement) {
299
+ cancelScheduledNativeArrowSync(popperElement);
300
+
301
+ const frameState = {
302
+ outer: 0,
303
+ inner: 0,
304
+ };
305
+
306
+ frameState.outer = requestAnimationFrame(() => {
307
+ frameState.inner = requestAnimationFrame(() => {
308
+ nativeArrowSyncFrameMap.delete(popperElement);
72
309
 
73
- if (isObject(line)) {
74
- continue;
310
+ if (
311
+ !(controlElement instanceof HTMLElement) ||
312
+ !(popperElement instanceof HTMLElement) ||
313
+ !isNativePopoverElement(popperElement)
314
+ ) {
315
+ return;
75
316
  }
76
317
 
77
- if (!isString(line)) {
78
- throw new Error(
79
- `Middleware must be a string, a function or an object. Got ${typeof line}`,
80
- );
318
+ if (
319
+ !matchesPopoverOpen(popperElement) &&
320
+ popperElement.style.display !== "block"
321
+ ) {
322
+ return;
81
323
  }
82
324
 
83
- const kv = line.split(":");
84
- const fn = kv.shift();
85
-
86
- switch (fn) {
87
- case "flip":
88
- config["middleware"][key] = flip();
89
- break;
90
- case "shift":
91
- config["middleware"][key] = shift();
92
- break;
93
- case "autoPlacement":
94
- let defaultAllowedPlacements = ["top", "bottom", "left", "right"];
95
-
96
- const defPlacement = kv?.shift();
97
- if (isString(defPlacement) && defPlacement.trim().length > 0) {
98
- defaultAllowedPlacements = defPlacement
99
- .split(",")
100
- .filter((line) => {
101
- return line.trim().length > 0;
102
- });
103
- }
104
-
105
- if (defaultAllowedPlacements.includes(config.placement)) {
106
- defaultAllowedPlacements.splice(
107
- defaultAllowedPlacements.indexOf(config.placement),
108
- 1,
109
- );
110
- }
111
- defaultAllowedPlacements.unshift(config.placement);
112
-
113
- config["middleware"][key] = autoPlacement({
114
- crossAxis: true,
115
- autoAlignment: true,
116
- allowedPlacements: defaultAllowedPlacements,
117
- });
118
-
119
- break;
120
- case "arrow":
121
- if (arrowElement) {
122
- config["middleware"][key] = arrow({ element: arrowElement });
123
- }
124
- break;
125
- case "size":
126
- config["middleware"][key] = size({
127
- apply({ availableWidth, availableHeight, elements }) {
128
- Object.assign(elements.floating.style, {
129
- boxSizing: "border-box",
130
- maxWidth: `${availableWidth}px`,
131
- maxHeight: `${availableHeight}px`,
132
- });
133
- },
134
- });
135
- break;
136
- case "offset":
137
- const o = kv?.shift();
138
- config["middleware"][key] = offset(parseInt(o) || 10);
139
- break;
140
- case "hide":
141
- config["middleware"][key] = hide();
142
- break;
325
+ syncNativeArrow(controlElement, popperElement);
326
+ });
327
+ });
328
+
329
+ nativeArrowSyncFrameMap.set(popperElement, frameState);
330
+ }
331
+
332
+ function cancelScheduledNativeArrowSync(popperElement) {
333
+ const frameState = nativeArrowSyncFrameMap.get(popperElement);
334
+ if (!frameState) {
335
+ return;
336
+ }
337
+
338
+ if (frameState.outer) {
339
+ cancelAnimationFrame(frameState.outer);
340
+ }
341
+
342
+ if (frameState.inner) {
343
+ cancelAnimationFrame(frameState.inner);
344
+ }
345
+
346
+ nativeArrowSyncFrameMap.delete(popperElement);
347
+ }
348
+
349
+ function prepareNativePopover(controlElement, popperElement, config) {
350
+ const anchorName = getAnchorName(controlElement);
351
+ popperElement.dataset.monsterPopperEngine = "native";
352
+ popperElement.setAttribute("popover", "manual");
353
+ controlElement.style.setProperty("anchor-name", anchorName);
354
+ popperElement.style.setProperty("position-anchor", anchorName);
355
+ popperElement.style.setProperty("inset", "auto");
356
+ popperElement.style.setProperty("margin", "0");
357
+ popperElement.style.setProperty("overflow", "visible");
358
+ popperElement.style.display = "block";
359
+ popperElement.style.removeProperty("transform");
360
+ applyNativeTryFallbacks(popperElement, config);
361
+ }
362
+
363
+ function teardownNativePopover(popperElement) {
364
+ if (!isNativePopoverElement(popperElement)) {
365
+ return;
366
+ }
367
+
368
+ if (matchesPopoverOpen(popperElement)) {
369
+ popperElement.hidePopover();
370
+ }
371
+
372
+ cancelScheduledNativeArrowSync(popperElement);
373
+ delete popperElement.dataset.monsterPopperEngine;
374
+ popperElement.removeAttribute("popover");
375
+ popperElement.style.removeProperty("position-anchor");
376
+ popperElement.style.removeProperty("position-area");
377
+ popperElement.style.removeProperty("inset-area");
378
+ popperElement.style.removeProperty("position-try");
379
+ popperElement.style.removeProperty("position-try-fallbacks");
380
+ popperElement.style.removeProperty("margin");
381
+ popperElement.style.removeProperty("margin-top");
382
+ popperElement.style.removeProperty("margin-right");
383
+ popperElement.style.removeProperty("margin-bottom");
384
+ popperElement.style.removeProperty("margin-left");
385
+ popperElement.style.removeProperty("inset");
386
+ popperElement.style.removeProperty("overflow");
387
+ popperElement.style.removeProperty("--monster-popper-control-width");
388
+ popperElement.style.removeProperty("--monster-popper-control-height");
389
+ }
390
+
391
+ function syncNativePopover(controlElement, popperElement, config) {
392
+ const controlRect = controlElement.getBoundingClientRect();
393
+ const placement = resolvePlacement(config.placement);
394
+ const offsetValue = resolveOffset(config.middlewareTokens);
395
+
396
+ popperElement.style.setProperty(
397
+ "--monster-popper-control-width",
398
+ `${Math.round(controlRect.width)}px`,
399
+ );
400
+ popperElement.style.setProperty(
401
+ "--monster-popper-control-height",
402
+ `${Math.round(controlRect.height)}px`,
403
+ );
404
+
405
+ applyNativePlacementStyles(popperElement, placement, offsetValue);
406
+ popperElement.style.removeProperty("visibility");
407
+ syncNativeArrow(controlElement, popperElement);
408
+ scheduleNativeArrowSync(controlElement, popperElement);
409
+ }
410
+
411
+ function resolvePlacement(value) {
412
+ if (!isString(value) || value.trim().length === 0) {
413
+ return { side: "top", align: "center" };
414
+ }
415
+
416
+ const [rawSide, rawAlign] = value.split("-");
417
+ const side = rawSide === "auto" ? "top" : rawSide;
418
+ const align =
419
+ rawAlign === "start" || rawAlign === "end" ? rawAlign : "center";
420
+
421
+ if (!["top", "bottom", "left", "right"].includes(side)) {
422
+ return { side: "top", align: "center" };
423
+ }
424
+
425
+ return { side, align };
426
+ }
427
+
428
+ function resolveOffset(middleware) {
429
+ if (!isArray(middleware)) {
430
+ return 10;
431
+ }
432
+
433
+ for (const entry of middleware) {
434
+ if (!isString(entry) || !entry.startsWith("offset")) {
435
+ continue;
436
+ }
437
+
438
+ const [, rawValue] = entry.split(":");
439
+ const parsed = parseInt(rawValue);
440
+ if (Number.isFinite(parsed)) {
441
+ return parsed;
442
+ }
443
+ }
444
+
445
+ return 10;
446
+ }
447
+
448
+ function applyNativePlacementStyles(
449
+ popperElement,
450
+ { side, align },
451
+ offsetValue,
452
+ ) {
453
+ if (supportsNativePositionArea()) {
454
+ applyNativePositionAreaStyles(popperElement, { side, align }, offsetValue);
455
+ return;
456
+ }
457
+
458
+ popperElement.style.removeProperty("position-area");
459
+ popperElement.style.removeProperty("inset-area");
460
+ popperElement.style.removeProperty("margin-top");
461
+ popperElement.style.removeProperty("margin-right");
462
+ popperElement.style.removeProperty("margin-bottom");
463
+ popperElement.style.removeProperty("margin-left");
464
+ popperElement.style.removeProperty("top");
465
+ popperElement.style.removeProperty("right");
466
+ popperElement.style.removeProperty("bottom");
467
+ popperElement.style.removeProperty("left");
468
+
469
+ switch (side) {
470
+ case "bottom":
471
+ popperElement.style.setProperty(
472
+ "top",
473
+ `calc(anchor(bottom) + ${offsetValue}px)`,
474
+ );
475
+ applyHorizontalAlignment(popperElement, align);
476
+ break;
477
+ case "left":
478
+ popperElement.style.setProperty(
479
+ "left",
480
+ `calc(anchor(left) - 100% - ${offsetValue}px)`,
481
+ );
482
+ applyVerticalAlignment(popperElement, align);
483
+ break;
484
+ case "right":
485
+ popperElement.style.setProperty(
486
+ "left",
487
+ `calc(anchor(right) + ${offsetValue}px)`,
488
+ );
489
+ applyVerticalAlignment(popperElement, align);
490
+ break;
491
+ case "top":
492
+ default:
493
+ popperElement.style.setProperty(
494
+ "top",
495
+ `calc(anchor(top) - 100% - ${offsetValue}px)`,
496
+ );
497
+ applyHorizontalAlignment(popperElement, align);
498
+ break;
499
+ }
500
+ }
501
+
502
+ function applyNativePositionAreaStyles(
503
+ popperElement,
504
+ { side, align },
505
+ offsetValue,
506
+ ) {
507
+ const positionArea = resolveNativePositionArea({ side, align });
508
+
509
+ popperElement.style.removeProperty("top");
510
+ popperElement.style.removeProperty("right");
511
+ popperElement.style.removeProperty("bottom");
512
+ popperElement.style.removeProperty("left");
513
+ popperElement.style.setProperty("position-area", positionArea);
514
+ popperElement.style.setProperty("inset-area", positionArea);
515
+ popperElement.style.setProperty("margin-top", "0px");
516
+ popperElement.style.setProperty("margin-right", "0px");
517
+ popperElement.style.setProperty("margin-bottom", "0px");
518
+ popperElement.style.setProperty("margin-left", "0px");
519
+
520
+ switch (side) {
521
+ case "bottom":
522
+ popperElement.style.setProperty("margin-top", `${offsetValue}px`);
523
+ break;
524
+ case "left":
525
+ popperElement.style.setProperty("margin-right", `${offsetValue}px`);
526
+ break;
527
+ case "right":
528
+ popperElement.style.setProperty("margin-left", `${offsetValue}px`);
529
+ break;
530
+ case "top":
531
+ default:
532
+ popperElement.style.setProperty("margin-bottom", `${offsetValue}px`);
533
+ break;
534
+ }
535
+ }
536
+
537
+ function resolveNativePositionArea({ side, align }) {
538
+ switch (side) {
539
+ case "bottom":
540
+ switch (align) {
541
+ case "end":
542
+ return "bottom span-left";
543
+ case "center":
544
+ return "bottom center";
545
+ case "start":
143
546
  default:
144
- throw new Error(`Unknown function: ${fn}`);
547
+ return "bottom span-right";
145
548
  }
146
- }
549
+ case "left":
550
+ switch (align) {
551
+ case "end":
552
+ return "left span-top";
553
+ case "center":
554
+ return "left center";
555
+ case "start":
556
+ default:
557
+ return "left span-bottom";
558
+ }
559
+ case "right":
560
+ switch (align) {
561
+ case "end":
562
+ return "right span-top";
563
+ case "center":
564
+ return "right center";
565
+ case "start":
566
+ default:
567
+ return "right span-bottom";
568
+ }
569
+ case "top":
570
+ default:
571
+ switch (align) {
572
+ case "end":
573
+ return "top span-left";
574
+ case "center":
575
+ return "top center";
576
+ case "start":
577
+ default:
578
+ return "top span-right";
579
+ }
580
+ }
581
+ }
147
582
 
148
- popperElement.style.removeProperty("visibility");
149
- popperElement.style.display = "block";
583
+ function supportsNativePositionArea() {
584
+ if (typeof CSS === "undefined") {
585
+ return false;
586
+ }
587
+
588
+ return (
589
+ CSS.supports("position-area: bottom center") ||
590
+ CSS.supports("inset-area: bottom center")
591
+ );
592
+ }
593
+
594
+ function applyHorizontalAlignment(popperElement, align) {
595
+ switch (align) {
596
+ case "end":
597
+ popperElement.style.setProperty("left", "calc(anchor(right) - 100%)");
598
+ break;
599
+ case "center":
600
+ popperElement.style.setProperty(
601
+ "left",
602
+ "calc(anchor(left) + (var(--monster-popper-control-width) - 100%) / 2)",
603
+ );
604
+ break;
605
+ case "start":
606
+ default:
607
+ popperElement.style.setProperty("left", "anchor(left)");
608
+ break;
609
+ }
610
+ }
150
611
 
151
- autoUpdate(controlElement, popperElement, () => {
152
- computePosition(controlElement, popperElement, config).then(
153
- ({ x, y, placement, middlewareData }) => {
154
- Object.assign(popperElement.style, {
155
- top: "0",
156
- left: "0",
157
- transform: `translate(${roundByDPR(x)}px,${roundByDPR(y)}px)`,
158
- });
159
-
160
- if (middlewareData.arrow) {
161
- const side = placement.split("-")[0];
162
-
163
- const staticSide = {
164
- top: "bottom",
165
- right: "left",
166
- bottom: "top",
167
- left: "right",
168
- }[side];
169
-
170
- // monster-border-width = + 4 (2*2) (should come from css)
171
- const arrowLen = arrowElement.offsetWidth + 4;
172
-
173
- const borderStyle = {
174
- borderLeft: "transparent",
175
- borderRight: "transparent",
176
- borderBottom: "transparent",
177
- borderTop: "transparent",
178
- };
179
-
180
- const defaultBorder =
181
- "var(--monster-border-width) var(--monster-border-style) var(--monster-bg-color-primary-4)";
182
-
183
- switch (side) {
184
- case "top":
185
- borderStyle.borderRight = defaultBorder;
186
- borderStyle.borderBottom = defaultBorder;
187
- break;
188
-
189
- case "bottom":
190
- borderStyle.borderTop = defaultBorder;
191
- borderStyle.borderLeft = defaultBorder;
192
- break;
193
-
194
- case "left":
195
- borderStyle.borderRight = defaultBorder;
196
- borderStyle.borderTop = defaultBorder;
197
- break;
198
-
199
- case "right":
200
- borderStyle.borderBottom = defaultBorder;
201
- borderStyle.borderLeft = defaultBorder;
202
- break;
203
- }
204
-
205
- const { x, y } = middlewareData.arrow;
206
-
207
- Object.assign(
208
- arrowElement.style,
209
- {
210
- left: x != null ? `${x}px` : "",
211
- top: y != null ? `${y}px` : "",
212
- // Ensure the static side gets unset when
213
- // flipping to other placements' axes.
214
- right: "",
215
- bottom: "",
216
- [staticSide]: `${-arrowLen / 2}px`,
217
- transform: "rotate(45deg)",
218
- },
219
- borderStyle,
220
- );
221
- }
222
- },
612
+ function applyVerticalAlignment(popperElement, align) {
613
+ switch (align) {
614
+ case "end":
615
+ popperElement.style.setProperty("top", "calc(anchor(bottom) - 100%)");
616
+ break;
617
+ case "center":
618
+ popperElement.style.setProperty(
619
+ "top",
620
+ "calc(anchor(top) + (var(--monster-popper-control-height) - 100%) / 2)",
223
621
  );
622
+ break;
623
+ case "start":
624
+ default:
625
+ popperElement.style.setProperty("top", "anchor(top)");
626
+ break;
627
+ }
628
+ }
629
+
630
+ function applyNativeTryFallbacks(popperElement, config) {
631
+ const middleware = config.middlewareTokens || [];
632
+ const placement = resolvePlacement(config.placement);
633
+ let fallbacks = "";
634
+
635
+ if (
636
+ middleware.some(
637
+ (entry) => isString(entry) && entry.startsWith("autoPlacement"),
638
+ )
639
+ ) {
640
+ fallbacks =
641
+ placement.side === "left" || placement.side === "right"
642
+ ? "flip-inline, flip-block"
643
+ : "flip-block, flip-inline";
644
+ } else if (middleware.includes("flip")) {
645
+ fallbacks =
646
+ placement.side === "left" || placement.side === "right"
647
+ ? "flip-inline"
648
+ : "flip-block";
649
+ }
650
+
651
+ if (fallbacks.length === 0) {
652
+ popperElement.style.removeProperty("position-try");
653
+ popperElement.style.removeProperty("position-try-fallbacks");
654
+ return;
655
+ }
656
+
657
+ popperElement.style.setProperty("position-try", fallbacks);
658
+ popperElement.style.setProperty("position-try-fallbacks", fallbacks);
659
+ }
660
+
661
+ function syncNativeArrow(controlElement, popperElement) {
662
+ const arrowElement = popperElement.querySelector("[data-monster-role=arrow]");
663
+
664
+ if (!(arrowElement instanceof HTMLElement)) {
665
+ return;
666
+ }
667
+
668
+ const controlRect = controlElement.getBoundingClientRect();
669
+ const popperRect = popperElement.getBoundingClientRect();
670
+ const arrowHalf = arrowElement.offsetWidth / 2;
671
+
672
+ if (arrowHalf === 0) {
673
+ return;
674
+ }
675
+
676
+ const side = resolveArrowSide(controlRect, popperRect);
677
+ const staticSide = side;
678
+ const defaultBorder =
679
+ "var(--monster-border-width) var(--monster-border-style) var(--monster-bg-color-primary-4)";
680
+ const borderStyle = {
681
+ borderLeft: "transparent",
682
+ borderRight: "transparent",
683
+ borderBottom: "transparent",
684
+ borderTop: "transparent",
685
+ };
686
+
687
+ switch (side) {
688
+ case "top":
689
+ borderStyle.borderTop = defaultBorder;
690
+ borderStyle.borderLeft = defaultBorder;
691
+ break;
692
+ case "bottom":
693
+ borderStyle.borderRight = defaultBorder;
694
+ borderStyle.borderBottom = defaultBorder;
695
+ break;
696
+ case "left":
697
+ borderStyle.borderLeft = defaultBorder;
698
+ borderStyle.borderBottom = defaultBorder;
699
+ break;
700
+ case "right":
701
+ borderStyle.borderTop = defaultBorder;
702
+ borderStyle.borderRight = defaultBorder;
703
+ break;
704
+ }
705
+
706
+ const arrowOffset = resolveArrowOffset(
707
+ side,
708
+ controlRect,
709
+ popperRect,
710
+ arrowHalf,
711
+ );
712
+ const arrowLen = arrowElement.offsetWidth + 4;
713
+
714
+ Object.assign(
715
+ arrowElement.style,
716
+ {
717
+ left: side === "top" || side === "bottom" ? `${arrowOffset}px` : "",
718
+ top: side === "left" || side === "right" ? `${arrowOffset}px` : "",
719
+ right: "",
720
+ bottom: "",
721
+ [staticSide]: `${-arrowLen / 2}px`,
722
+ transform: "rotate(45deg)",
723
+ },
724
+ borderStyle,
725
+ );
726
+ }
727
+
728
+ function resolveArrowSide(controlRect, popperRect) {
729
+ const triggerCenterX = controlRect.left + controlRect.width / 2;
730
+ const triggerCenterY = controlRect.top + controlRect.height / 2;
731
+ const candidates = [];
732
+
733
+ if (triggerCenterY <= popperRect.top) {
734
+ candidates.push({
735
+ side: "top",
736
+ distance: popperRect.top - triggerCenterY,
224
737
  });
225
- }).run();
738
+ }
739
+
740
+ if (triggerCenterY >= popperRect.bottom) {
741
+ candidates.push({
742
+ side: "bottom",
743
+ distance: triggerCenterY - popperRect.bottom,
744
+ });
745
+ }
746
+
747
+ if (triggerCenterX <= popperRect.left) {
748
+ candidates.push({
749
+ side: "left",
750
+ distance: popperRect.left - triggerCenterX,
751
+ });
752
+ }
753
+
754
+ if (triggerCenterX >= popperRect.right) {
755
+ candidates.push({
756
+ side: "right",
757
+ distance: triggerCenterX - popperRect.right,
758
+ });
759
+ }
760
+
761
+ if (candidates.length === 0) {
762
+ return "top";
763
+ }
764
+
765
+ candidates.sort((a, b) => a.distance - b.distance);
766
+ return candidates[0].side;
767
+ }
768
+
769
+ function resolveArrowOffset(side, controlRect, popperRect, arrowHalf) {
770
+ if (side === "top" || side === "bottom") {
771
+ return clamp(
772
+ controlRect.left + controlRect.width / 2 - popperRect.left - arrowHalf,
773
+ 0,
774
+ Math.max(0, popperRect.width - arrowHalf * 2),
775
+ );
776
+ }
777
+
778
+ return clamp(
779
+ controlRect.top + controlRect.height / 2 - popperRect.top - arrowHalf,
780
+ 0,
781
+ Math.max(0, popperRect.height - arrowHalf * 2),
782
+ );
783
+ }
784
+
785
+ function applyFloatingArrowStyles(arrowElement, placement, arrowData) {
786
+ if (!(arrowElement instanceof HTMLElement)) {
787
+ return;
788
+ }
789
+
790
+ const side = placement.split("-")[0];
791
+ const staticSide = {
792
+ top: "bottom",
793
+ right: "left",
794
+ bottom: "top",
795
+ left: "right",
796
+ }[side];
797
+ const arrowLen = arrowElement.offsetWidth + 4;
798
+ const borderStyle = {
799
+ borderLeft: "transparent",
800
+ borderRight: "transparent",
801
+ borderBottom: "transparent",
802
+ borderTop: "transparent",
803
+ };
804
+ const defaultBorder =
805
+ "var(--monster-border-width) var(--monster-border-style) var(--monster-bg-color-primary-4)";
806
+
807
+ switch (side) {
808
+ case "top":
809
+ borderStyle.borderRight = defaultBorder;
810
+ borderStyle.borderBottom = defaultBorder;
811
+ break;
812
+ case "bottom":
813
+ borderStyle.borderTop = defaultBorder;
814
+ borderStyle.borderLeft = defaultBorder;
815
+ break;
816
+ case "left":
817
+ borderStyle.borderRight = defaultBorder;
818
+ borderStyle.borderTop = defaultBorder;
819
+ break;
820
+ case "right":
821
+ borderStyle.borderBottom = defaultBorder;
822
+ borderStyle.borderLeft = defaultBorder;
823
+ break;
824
+ }
825
+
826
+ Object.assign(
827
+ arrowElement.style,
828
+ {
829
+ left: arrowData.x != null ? `${arrowData.x}px` : "",
830
+ top: arrowData.y != null ? `${arrowData.y}px` : "",
831
+ right: "",
832
+ bottom: "",
833
+ [staticSide]: `${-arrowLen / 2}px`,
834
+ transform: "rotate(45deg)",
835
+ },
836
+ borderStyle,
837
+ );
838
+ }
839
+
840
+ function getAnchorName(controlElement) {
841
+ if (!anchorNameMap.has(controlElement)) {
842
+ anchorNameCounter += 1;
843
+ anchorNameMap.set(
844
+ controlElement,
845
+ `--monster-popper-anchor-${anchorNameCounter}`,
846
+ );
847
+ }
848
+
849
+ return anchorNameMap.get(controlElement);
850
+ }
851
+
852
+ function isNativePopoverElement(popperElement) {
853
+ return popperElement?.dataset?.monsterPopperEngine === "native";
854
+ }
855
+
856
+ function matchesPopoverOpen(popperElement) {
857
+ try {
858
+ return popperElement.matches(":popover-open");
859
+ } catch (e) {
860
+ return false;
861
+ }
862
+ }
863
+
864
+ function clamp(value, min, max) {
865
+ return Math.min(Math.max(value, min), max);
226
866
  }
227
867
 
228
868
  function roundByDPR(value) {