@signal9/era-ui 30.2.1 → 30.2.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.
- package/CHANGELOG.md +6 -0
- package/dist/ui/alert-dialog/alert-dialog-root.svelte +4 -1
- package/dist/ui/context-menu/context-menu-root.svelte +4 -1
- package/dist/ui/dialog/dialog-root.svelte +7 -1
- package/dist/ui/dropdown-menu/dropdown-menu-root.svelte +4 -1
- package/dist/ui/link-preview/link-preview-root.svelte +4 -1
- package/dist/ui/menubar/menubar-root.svelte +1 -1
- package/dist/ui/provider/axis-relay.svelte.d.ts +1 -1
- package/dist/ui/provider/axis-relay.svelte.js +28 -2
- package/dist/ui/tooltip/tooltip-root.svelte +4 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [30.2.2](https://github.com/sig-nine/era-ui/compare/v30.2.1...v30.2.2) (2026-08-16)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* **provider:** portalled content keeps its axes with no trigger rendered ([ed15a44](https://github.com/sig-nine/era-ui/commit/ed15a445eccafa582907e4bf08d9735edd9140cf))
|
|
6
|
+
|
|
1
7
|
## [30.2.1](https://github.com/sig-nine/era-ui/compare/v30.2.0...v30.2.1) (2026-08-16)
|
|
2
8
|
|
|
3
9
|
### Bug Fixes
|
|
@@ -23,8 +23,11 @@
|
|
|
23
23
|
|
|
24
24
|
// Capture on OPEN, not on mount: bits-ui mounts content eagerly and toggles
|
|
25
25
|
// it, so a mount-time read runs once at page load and never again.
|
|
26
|
+
// activeElement is the FALLBACK anchor, used only when no Trigger rendered —
|
|
27
|
+
// see AxisRelay.refresh(). It is read here, at the instant `open` turns true,
|
|
28
|
+
// because bits-ui moves focus into the panel a moment later.
|
|
26
29
|
$effect(() => {
|
|
27
|
-
if (open) relay.refresh();
|
|
30
|
+
if (open) relay.refresh(document.activeElement);
|
|
28
31
|
});
|
|
29
32
|
</script>
|
|
30
33
|
|
|
@@ -23,8 +23,11 @@
|
|
|
23
23
|
|
|
24
24
|
// Capture on OPEN, not on mount: bits-ui mounts content eagerly and toggles
|
|
25
25
|
// it, so a mount-time read runs once at page load and never again.
|
|
26
|
+
// activeElement is the FALLBACK anchor, used only when no Trigger rendered —
|
|
27
|
+
// see AxisRelay.refresh(). It is read here, at the instant `open` turns true,
|
|
28
|
+
// because bits-ui moves focus into the panel a moment later.
|
|
26
29
|
$effect(() => {
|
|
27
|
-
if (open) relay.refresh();
|
|
30
|
+
if (open) relay.refresh(document.activeElement);
|
|
28
31
|
});
|
|
29
32
|
</script>
|
|
30
33
|
|
|
@@ -32,9 +32,15 @@
|
|
|
32
32
|
* before a consumer has scoped anything, and never again. Reading when `open`
|
|
33
33
|
* turns true is the moment the answer is actually needed, and it re-reads on
|
|
34
34
|
* every open, so an axis that changed in between is picked up.
|
|
35
|
+
*
|
|
36
|
+
* `document.activeElement` is the FALLBACK anchor, used only when no Trigger
|
|
37
|
+
* rendered — see AxisRelay.refresh() for why that case exists and what it
|
|
38
|
+
* costs. It is read HERE, at the instant `open` turns true, because bits-ui
|
|
39
|
+
* moves focus into the panel a moment later and the answer would be the
|
|
40
|
+
* panel itself.
|
|
35
41
|
*/
|
|
36
42
|
$effect(() => {
|
|
37
|
-
if (open) relay.refresh();
|
|
43
|
+
if (open) relay.refresh(document.activeElement);
|
|
38
44
|
});
|
|
39
45
|
</script>
|
|
40
46
|
|
|
@@ -23,8 +23,11 @@
|
|
|
23
23
|
|
|
24
24
|
// Capture on OPEN, not on mount: bits-ui mounts content eagerly and toggles
|
|
25
25
|
// it, so a mount-time read runs once at page load and never again.
|
|
26
|
+
// activeElement is the FALLBACK anchor, used only when no Trigger rendered —
|
|
27
|
+
// see AxisRelay.refresh(). It is read here, at the instant `open` turns true,
|
|
28
|
+
// because bits-ui moves focus into the panel a moment later.
|
|
26
29
|
$effect(() => {
|
|
27
|
-
if (open) relay.refresh();
|
|
30
|
+
if (open) relay.refresh(document.activeElement);
|
|
28
31
|
});
|
|
29
32
|
</script>
|
|
30
33
|
|
|
@@ -23,8 +23,11 @@
|
|
|
23
23
|
|
|
24
24
|
// Capture on OPEN, not on mount: bits-ui mounts content eagerly and toggles
|
|
25
25
|
// it, so a mount-time read runs once at page load and never again.
|
|
26
|
+
// activeElement is the FALLBACK anchor, used only when no Trigger rendered —
|
|
27
|
+
// see AxisRelay.refresh(). It is read here, at the instant `open` turns true,
|
|
28
|
+
// because bits-ui moves focus into the panel a moment later.
|
|
26
29
|
$effect(() => {
|
|
27
|
-
if (open) relay.refresh();
|
|
30
|
+
if (open) relay.refresh(document.activeElement);
|
|
28
31
|
});
|
|
29
32
|
</script>
|
|
30
33
|
|
|
@@ -20,7 +20,7 @@ export declare class AxisRelay {
|
|
|
20
20
|
* without touching surface, and closest() answers each question separately,
|
|
21
21
|
* which is what makes the axes orthogonal in the first place.
|
|
22
22
|
*/
|
|
23
|
-
refresh(): void;
|
|
23
|
+
refresh(fallback?: Element | null): void;
|
|
24
24
|
/** The class string portalled content should carry. */
|
|
25
25
|
get schemeClass(): string;
|
|
26
26
|
}
|
|
@@ -64,8 +64,34 @@ export class AxisRelay {
|
|
|
64
64
|
* without touching surface, and closest() answers each question separately,
|
|
65
65
|
* which is what makes the axes orthogonal in the first place.
|
|
66
66
|
*/
|
|
67
|
-
refresh() {
|
|
68
|
-
|
|
67
|
+
refresh(fallback) {
|
|
68
|
+
/*
|
|
69
|
+
* NO TRIGGER, NO ANCHOR — the gap this fallback closes.
|
|
70
|
+
*
|
|
71
|
+
* A dialog driven purely by `bind:open` renders no Trigger, so there is
|
|
72
|
+
* no node left in the subtree to read from and the content inherited
|
|
73
|
+
* from :root. That is not an edge case: driving a confirm dialog from
|
|
74
|
+
* state is the ordinary way to write one, and it is why a consumer went
|
|
75
|
+
* on restating `data-font` on every Dialog.Content long after the relay
|
|
76
|
+
* was supposed to have made that unnecessary. Measured before this: a
|
|
77
|
+
* dialog opened from a button inside a `data-font="serif"` section came
|
|
78
|
+
* up with data-font null and font-family monospace.
|
|
79
|
+
*
|
|
80
|
+
* The fallback is WHERE THE USER WAS when it opened — document.
|
|
81
|
+
* activeElement, passed in by the Root at the instant `open` turns
|
|
82
|
+
* true, before bits-ui moves focus into the panel. A state-driven
|
|
83
|
+
* dialog is nearly always opened by something the user just clicked,
|
|
84
|
+
* and that something sits exactly where the dialog logically belongs.
|
|
85
|
+
*
|
|
86
|
+
* <body> is not an anchor: with nothing focused there is nothing to
|
|
87
|
+
* learn, and reading from it would just re-derive :root the long way.
|
|
88
|
+
* A dialog opened by a timer while focus is elsewhere therefore keeps
|
|
89
|
+
* the old behaviour rather than picking up an unrelated subtree.
|
|
90
|
+
*/
|
|
91
|
+
const el = this.#anchor ??
|
|
92
|
+
(fallback && fallback !== document.body && fallback !== document.documentElement
|
|
93
|
+
? fallback
|
|
94
|
+
: null);
|
|
69
95
|
if (!el?.closest)
|
|
70
96
|
return;
|
|
71
97
|
// The reading itself lives in axes-at.ts, runes-free, because the notes
|
|
@@ -23,8 +23,11 @@
|
|
|
23
23
|
|
|
24
24
|
// Capture on OPEN, not on mount: bits-ui mounts content eagerly and toggles
|
|
25
25
|
// it, so a mount-time read runs once at page load and never again.
|
|
26
|
+
// activeElement is the FALLBACK anchor, used only when no Trigger rendered —
|
|
27
|
+
// see AxisRelay.refresh(). It is read here, at the instant `open` turns true,
|
|
28
|
+
// because bits-ui moves focus into the panel a moment later.
|
|
26
29
|
$effect(() => {
|
|
27
|
-
if (open) relay.refresh();
|
|
30
|
+
if (open) relay.refresh(document.activeElement);
|
|
28
31
|
});
|
|
29
32
|
</script>
|
|
30
33
|
|