@broberg/app-shell 0.22.0 → 0.22.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/README.md +9 -0
- package/css/app-shell.css +10 -2
- package/dist/preact.cjs +12 -9
- package/dist/preact.cjs.map +1 -1
- package/dist/preact.js +12 -9
- package/dist/preact.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -187,6 +187,15 @@ right-aligned before the chevron — «Type …… All ›», testid `<prefix>-a
|
|
|
187
187
|
The focus ring now shows only for keyboard use: after a mouse open the first item has focus but no ring; opening
|
|
188
188
|
with Enter from a keyboard-focused anchor, or any key in the menu, shows it. ↑↓/Enter/Escape are unchanged.
|
|
189
189
|
|
|
190
|
+
**0.22.1** — a long `value` no longer clips the label (F092.33, scout #2830): the value gives way first and
|
|
191
|
+
ellipses; the label only once the value is gone. The menu now sizes to its content between 240 and 320px
|
|
192
|
+
(`--bas-menu-min-width` / `--bas-menu-max-width`, never wider than the viewport − 16px) instead of a fixed 240px.
|
|
193
|
+
|
|
194
|
+
**0.22.2** — sidebar user menu (F092.34, scout #2855): when the menu is taller than the space above the button and
|
|
195
|
+
scrolls, only the middle scrolls — the head (name/e-mail) and «Log ud» stay pinned in view. «Log ud» now sits in its
|
|
196
|
+
own `.bas-menu__foot` block. The menu button shows a focus ring only for keyboard focus, also when the app has its
|
|
197
|
+
own global `button:focus` outline.
|
|
198
|
+
|
|
190
199
|
## 0.11.1 — the palette list floats over the menu (F001.25)
|
|
191
200
|
|
|
192
201
|
Christian 10/10: «Kunne denne ikke være en pop-over ting så dialogen ikke bliver
|
package/css/app-shell.css
CHANGED
|
@@ -158,6 +158,7 @@ button.bas-group__label:hover { color: var(--bas-group-label-color, var(--fg-mut
|
|
|
158
158
|
/* F092.32 — sized as tokens (scout's measurement of Claude Desktop at 1×). Not
|
|
159
159
|
declared here, only read with a fallback, so an app's :root value wins. */
|
|
160
160
|
.bas-rowmenu {
|
|
161
|
+
min-width: var(--bas-menu-min-width, 240px); max-width: min(var(--bas-menu-max-width, 320px), calc(100vw - 16px)); box-sizing: border-box;
|
|
161
162
|
z-index: 70; padding: var(--bas-menu-padding, 6px); outline: none; border-radius: var(--bas-menu-radius, 14px); background: var(--bg-card);
|
|
162
163
|
border: 1px solid var(--border); box-shadow: 0 12px 32px rgba(0, 0, 0, .22);
|
|
163
164
|
}
|
|
@@ -169,7 +170,8 @@ button.bas-group__label:hover { color: var(--bas-group-label-color, var(--fg-mut
|
|
|
169
170
|
/* Focus ring for keyboard use only; a mouse open shows the highlight alone. */
|
|
170
171
|
.bas-rowmenu__item:focus, .bas-rowmenu__back:focus { outline: none; }
|
|
171
172
|
.bas-rowmenu.is-kbd .bas-rowmenu__item:focus, .bas-rowmenu.is-kbd .bas-rowmenu__back:focus { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
172
|
-
.
|
|
173
|
+
/* F092.33 — the value gives way first; the label only once the value is gone. */
|
|
174
|
+
.bas-rowmenu__value { flex: 0 1000 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg-muted); }
|
|
173
175
|
.bas-rowmenu__sep { height: 1px; margin: 6px 4px; background: var(--border); }
|
|
174
176
|
.bas-rowmenu__back { color: var(--fg-muted); font-weight: 500; border-bottom: 1px solid var(--border); border-radius: 0; margin-bottom: 4px; }
|
|
175
177
|
.bas-rowmenu__item.is-active, .bas-rowmenu__item:hover, .bas-rowmenu__back:hover { background: var(--hover); }
|
|
@@ -177,7 +179,7 @@ button.bas-group__label:hover { color: var(--bas-group-label-color, var(--fg-mut
|
|
|
177
179
|
.bas-rowmenu__item.is-danger { color: var(--danger); }
|
|
178
180
|
.bas-rowmenu__item.is-armed { background: var(--danger-soft, var(--hover)); font-weight: 500; }
|
|
179
181
|
.bas-rowmenu__icon { display: inline-flex; color: var(--fg-subtle); }
|
|
180
|
-
.bas-rowmenu__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
182
|
+
.bas-rowmenu__label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
181
183
|
.bas-rowmenu__kbd { font-family: var(--font-mono, ui-monospace, monospace); font-size: calc(11px * var(--bas-font-scale, 1)); color: var(--fg-subtle); }
|
|
182
184
|
.bas-rowmenu__form { display: flex; gap: 6px; padding: 4px; }
|
|
183
185
|
.bas-rowmenu__input { flex: 1; min-width: 0; padding: 6px 8px; border: 1px solid var(--border); border-radius: calc(var(--bas-radius) - 2px); background: var(--bg-sunk); color: var(--fg); font: inherit; font-size: calc(13px * var(--bas-font-scale, 1)); }
|
|
@@ -342,6 +344,9 @@ button.bas-group__label:hover { color: var(--bas-group-label-color, var(--fg-mut
|
|
|
342
344
|
transition: background var(--bas-dur) var(--bas-ease);
|
|
343
345
|
}
|
|
344
346
|
.bas-userbtn:hover, .bas-userbtn.is-open { background: var(--active); }
|
|
347
|
+
/* F092.34 — a ring for keyboard focus only; beats an app's global button:focus rule by specificity. */
|
|
348
|
+
.bas-userbtn:focus:not(:focus-visible) { outline: none; }
|
|
349
|
+
.bas-userbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
345
350
|
.bas-userbtn__name { font-size: calc(13px * var(--bas-font-scale, 1)); font-weight: 500; }
|
|
346
351
|
.bas-avatar { border-radius: 50%; object-fit: cover; flex: none; }
|
|
347
352
|
.bas-avatar--initials {
|
|
@@ -549,6 +554,9 @@ button.bas-group__label:hover { color: var(--bas-group-label-color, var(--fg-mut
|
|
|
549
554
|
.bas-sidebar.is-railed .bas-userbtn.is-sidebar { justify-content: center; padding: 6px 0; }
|
|
550
555
|
/* Positioned as position:fixed from the button by the component (the sidebar clips overflow). */
|
|
551
556
|
.bas-menu.is-up { top: auto; right: auto; max-width: none; overflow-y: auto; }
|
|
557
|
+
/* F092.34 — when the sidebar menu scrolls, only the middle does: the head and «Log ud» stay in view. */
|
|
558
|
+
.bas-menu.is-up > .bas-menu__who { position: sticky; top: 0; z-index: 1; background: var(--bg-card); }
|
|
559
|
+
.bas-menu.is-up > .bas-menu__foot { position: sticky; bottom: 0; z-index: 1; background: var(--bg-card); }
|
|
552
560
|
.bas-menu__sub { font-size: calc(12px * var(--bas-font-scale, 1)); color: var(--fg-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
553
561
|
/* F092.27 — the organisation line (menu top only). */
|
|
554
562
|
.bas-menu__org { display: flex; align-items: center; gap: 6px; margin-top: 4px; font-size: calc(13px * var(--bas-font-scale, 1)); color: var(--fg-muted); min-width: 0; }
|
package/dist/preact.cjs
CHANGED
|
@@ -578,7 +578,7 @@ function ItemActionsMenu(props) {
|
|
|
578
578
|
hooks.useLayoutEffect(() => {
|
|
579
579
|
const r = props.anchor.getBoundingClientRect();
|
|
580
580
|
const vw = window.innerWidth, vh = window.innerHeight, m = 8;
|
|
581
|
-
const w = Math.min(240, vw - 2 * m);
|
|
581
|
+
const w = Math.min(Math.max(240, menu.current?.offsetWidth ?? 0), vw - 2 * m);
|
|
582
582
|
const h = menu.current?.offsetHeight ?? 0;
|
|
583
583
|
const start = props.placement === "up-start";
|
|
584
584
|
const left = Math.max(m, Math.min(start ? r.left : r.right - w, vw - w - m));
|
|
@@ -586,7 +586,7 @@ function ItemActionsMenu(props) {
|
|
|
586
586
|
const fitsAbove = r.top - 4 - h >= m;
|
|
587
587
|
const below = start ? !fitsAbove : props.placement === "down" || fitsBelow || !fitsAbove;
|
|
588
588
|
const top = below ? Math.min(r.bottom + 4, vh - m - h) : r.top - 4 - h;
|
|
589
|
-
setPos({ position: "fixed", left: `${left}px`, top: `${Math.max(m, top)}px
|
|
589
|
+
setPos({ position: "fixed", left: `${left}px`, top: `${Math.max(m, top)}px` });
|
|
590
590
|
}, [stack.length]);
|
|
591
591
|
hooks.useLayoutEffect(() => {
|
|
592
592
|
if (!pos) return;
|
|
@@ -670,7 +670,7 @@ function ItemActionsMenu(props) {
|
|
|
670
670
|
tabIndex: -1,
|
|
671
671
|
"aria-label": view.kind === "list" && view.title ? view.title : props.label,
|
|
672
672
|
"data-testid": `${pre}-menu`,
|
|
673
|
-
style: pos ?? { position: "fixed", visibility: "hidden" },
|
|
673
|
+
style: pos ?? { position: "fixed", left: "0px", top: "0px", visibility: "hidden" },
|
|
674
674
|
onKeyDown,
|
|
675
675
|
children: [
|
|
676
676
|
stack.length > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", class: "bas-rowmenu__back", "data-testid": `${pre}-back`, "aria-label": t.back, onClick: back, children: [
|
|
@@ -1484,13 +1484,16 @@ function UserMenu(p) {
|
|
|
1484
1484
|
] })
|
|
1485
1485
|
] }) })
|
|
1486
1486
|
] }) : null,
|
|
1487
|
-
p.onSignOut ?
|
|
1488
|
-
|
|
1489
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
1490
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1491
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1487
|
+
p.onSignOut ? (
|
|
1488
|
+
// F092.34 — its own block, so the sidebar menu can pin it to the bottom while the middle scrolls.
|
|
1489
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { class: "bas-menu__foot", children: [
|
|
1490
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { class: "bas-sep" }),
|
|
1491
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", class: "bas-mi is-danger", role: "menuitem", "data-testid": "topbar-sign-out", disabled: busy, onClick: () => void signOut(), children: [
|
|
1492
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconLogOut, {}),
|
|
1493
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t.signOut })
|
|
1494
|
+
] })
|
|
1492
1495
|
] })
|
|
1493
|
-
|
|
1496
|
+
) : null
|
|
1494
1497
|
] }) : null
|
|
1495
1498
|
] });
|
|
1496
1499
|
}
|