@sveltia/ui 0.70.1 → 0.70.3
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.
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
disabled = false,
|
|
37
37
|
label = '',
|
|
38
38
|
labelDir = undefined,
|
|
39
|
-
|
|
39
|
+
// The popup flips to the other side by itself when the submenu wouldn’t fit on this one
|
|
40
|
+
popupPosition = 'right-top',
|
|
40
41
|
children: _children,
|
|
41
42
|
startIcon: _startIcon,
|
|
42
43
|
endIcon: _endIcon,
|
|
@@ -325,6 +325,13 @@ class Popup {
|
|
|
325
325
|
|
|
326
326
|
const topMargin = intersectionRect.top - 8;
|
|
327
327
|
const bottomMargin = rootBounds.height - intersectionRect.bottom - 8;
|
|
328
|
+
// A popup that opens beside its anchor is aligned with one of the anchor’s edges and extends
|
|
329
|
+
// across it, so its room is measured from that edge, not from the opposite one a dropdown
|
|
330
|
+
// hangs off
|
|
331
|
+
const leftMargin = intersectionRect.left - 8;
|
|
332
|
+
const rightMargin = rootBounds.width - intersectionRect.right - 8;
|
|
333
|
+
const downwardMargin = rootBounds.height - intersectionRect.top - 8;
|
|
334
|
+
const upwardMargin = intersectionRect.bottom - 8;
|
|
328
335
|
let { position } = this;
|
|
329
336
|
let height;
|
|
330
337
|
|
|
@@ -345,7 +352,6 @@ class Popup {
|
|
|
345
352
|
}
|
|
346
353
|
|
|
347
354
|
// Alter the position if the space is limited
|
|
348
|
-
// @todo Handle more overflow cases
|
|
349
355
|
if (position.startsWith('bottom-')) {
|
|
350
356
|
if (contentHeight > bottomMargin) {
|
|
351
357
|
if (topMargin > bottomMargin) {
|
|
@@ -357,6 +363,31 @@ class Popup {
|
|
|
357
363
|
}
|
|
358
364
|
}
|
|
359
365
|
|
|
366
|
+
// Only a popup that opens beside its anchor carries a `-top`/`-bottom` suffix, and it grows
|
|
367
|
+
// away from the edge it’s aligned with: down from the anchor’s top, or up from its bottom. It
|
|
368
|
+
// gets the same treatment as the dropdown above — align with the other edge when the content
|
|
369
|
+
// doesn’t fit and that edge has more room, and cap it either way, so a long submenu scrolls
|
|
370
|
+
// instead of running past the viewport
|
|
371
|
+
if (position.endsWith('-top')) {
|
|
372
|
+
if (contentHeight > downwardMargin) {
|
|
373
|
+
if (upwardMargin > downwardMargin) {
|
|
374
|
+
position = /** @type {PopupPosition} */ (position.replace('-top', '-bottom'));
|
|
375
|
+
height = upwardMargin;
|
|
376
|
+
} else {
|
|
377
|
+
height = downwardMargin;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
} else if (position.endsWith('-bottom')) {
|
|
381
|
+
if (contentHeight > upwardMargin) {
|
|
382
|
+
if (downwardMargin > upwardMargin) {
|
|
383
|
+
position = /** @type {PopupPosition} */ (position.replace('-bottom', '-top'));
|
|
384
|
+
height = downwardMargin;
|
|
385
|
+
} else {
|
|
386
|
+
height = upwardMargin;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
360
391
|
// If the popup overflows the viewport, change the position
|
|
361
392
|
if (position.endsWith('-left')) {
|
|
362
393
|
if (intersectionRect.left + contentWidth > rootBounds.width - 8) {
|
|
@@ -370,6 +401,20 @@ class Popup {
|
|
|
370
401
|
}
|
|
371
402
|
}
|
|
372
403
|
|
|
404
|
+
// The two checks above align a dropdown that opens below or above its anchor, so neither
|
|
405
|
+
// covers a popup that opens beside one — a submenu — running off the edge it opens towards.
|
|
406
|
+
// That gets the same treatment as the vertical flip above: switch to the other side, but only
|
|
407
|
+
// when it has more room, so a submenu with nowhere to go stays where the caller put it
|
|
408
|
+
if (position.startsWith('right-')) {
|
|
409
|
+
if (contentWidth > rightMargin && leftMargin > rightMargin) {
|
|
410
|
+
position = /** @type {PopupPosition} */ (position.replace('right-', 'left-'));
|
|
411
|
+
}
|
|
412
|
+
} else if (position.startsWith('left-')) {
|
|
413
|
+
if (contentWidth > leftMargin && rightMargin > leftMargin) {
|
|
414
|
+
position = /** @type {PopupPosition} */ (position.replace('left-', 'right-'));
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
373
418
|
const top = position.startsWith('bottom-')
|
|
374
419
|
? `${Math.round(intersectionRect.bottom)}px`
|
|
375
420
|
: position.endsWith('-top')
|
|
@@ -398,9 +443,15 @@ class Popup {
|
|
|
398
443
|
inset: [top, right, bottom, left].join(' '),
|
|
399
444
|
zIndex: 1000,
|
|
400
445
|
minWidth: `${Math.round(intersectionRect.width)}px`,
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
446
|
+
// A popup opening beside the anchor is capped by the room on that side, not by the width the
|
|
447
|
+
// anchor’s own edges leave, which is what the two dropdown cases below measure
|
|
448
|
+
maxWidth: position.startsWith('right-')
|
|
449
|
+
? `${Math.round(rightMargin)}px`
|
|
450
|
+
: position.startsWith('left-')
|
|
451
|
+
? `${Math.round(leftMargin)}px`
|
|
452
|
+
: position.endsWith('-left')
|
|
453
|
+
? `${Math.round(rootBounds.width - intersectionRect.left - 8)}px`
|
|
454
|
+
: `${Math.round(intersectionRect.right - 8)}px`,
|
|
404
455
|
// `undefined` removes the `max-height` the popup is given, letting it take its natural size
|
|
405
456
|
// again. `auto` would look equivalent but isn’t a valid `max-height`, so the browser would
|
|
406
457
|
// drop it and leave whatever limit was applied last in place.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltia/ui",
|
|
3
|
-
"version": "0.70.
|
|
3
|
+
"version": "0.70.3",
|
|
4
4
|
"description": "A collection of Svelte components and utilities for building user interfaces.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"eslint-config-airbnb-extended": "^3.2.0",
|
|
63
63
|
"eslint-config-prettier": "^10.1.8",
|
|
64
64
|
"eslint-plugin-import": "^2.32.0",
|
|
65
|
-
"eslint-plugin-jsdoc": "^64.3.
|
|
65
|
+
"eslint-plugin-jsdoc": "^64.3.6",
|
|
66
66
|
"eslint-plugin-package-json": "^1.8.0",
|
|
67
67
|
"eslint-plugin-svelte": "^3.23.0",
|
|
68
68
|
"globals": "^17.12.0",
|