@broberg/app-shell 0.7.1 → 0.8.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/README.md CHANGED
@@ -53,6 +53,18 @@ the user menu reads and writes theme, palette, surfaces and backdrop through it.
53
53
  | `TenantSwitcher` | The user's own organisations, the active one marked, switching through the app's route (0.7.1). |
54
54
  | `AnalyticsPage` | The app's own visitors, page views, page views per day and most visited pages, from Upmetrics (0.6.0). |
55
55
 
56
+ ## 0.8.0 — TenantSwitcher on a phone (F029.10, found by appkit's pilot)
57
+
58
+ - **The menu stays on screen.** It is anchored to the switcher, which sits among
59
+ your actions rather than at the edge, so at 393 px it ran off the right side.
60
+ It is now measured when it opens and shifted back inside, 16 px from the edge.
61
+ - **Changed output: no raw role.** Roles are your app's words, so the switcher
62
+ cannot translate them, and a bare «member» in a Danish UI is worse than nothing.
63
+ Pass `roleLabel={(role) => …}` to show them; without it, other rows show no role.
64
+ The active row still says «aktiv», and a suspended one still says so.
65
+ - **On a phone the switcher takes at most 40% of the width**, and the organisation
66
+ name is cut with «…» before the page title is.
67
+
56
68
  ## 0.7.1 — TenantSwitcher: the user's own organisations (F029.10)
57
69
 
58
70
  0.7.0 was tagged but never reached npm: the secret gate stopped it on a test fixture key, now listed in `.gitleaksignore`.
package/css/app-shell.css CHANGED
@@ -382,7 +382,9 @@
382
382
  .bas-tenant__btn:hover, .bas-tenant__btn.is-open { background: var(--active); }
383
383
  .bas-tenant__btn::after { content: "▾"; font-size: 10px; color: var(--fg-muted); flex: none; }
384
384
  .bas-tenant__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 500; }
385
- .bas-tenant__menu { left: 0; right: auto; }
385
+ .bas-tenant__menu { left: 0; right: auto; max-width: calc(100vw - 32px); }
386
+ /* phone: the org name gives way before the page title does */
387
+ @media (max-width: 767px) { .bas-tenant { max-width: 40vw; } }
386
388
  .bas-tenant__item { justify-content: space-between; }
387
389
  .bas-tenant__item.is-active { font-weight: 600; }
388
390
  .bas-tenant__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
package/dist/preact.cjs CHANGED
@@ -1352,7 +1352,8 @@ function AnalyticsSeries({ data, t, locale, num }) {
1352
1352
  ] })
1353
1353
  ] });
1354
1354
  }
1355
- function TenantSwitcher({ lang, activeSlug, adapter, onSwitch }) {
1355
+ var EDGE = 16;
1356
+ function TenantSwitcher({ lang, activeSlug, adapter, onSwitch, roleLabel }) {
1356
1357
  const t = TEXT[lang];
1357
1358
  const api = hooks.useMemo(() => adapter ?? createFetchTenantAdapter(), [adapter]);
1358
1359
  const [rows, setRows] = hooks.useState(null);
@@ -1361,6 +1362,18 @@ function TenantSwitcher({ lang, activeSlug, adapter, onSwitch }) {
1361
1362
  const [busy, setBusy] = hooks.useState(null);
1362
1363
  const [switchFailed, setSwitchFailed] = hooks.useState(false);
1363
1364
  const root = hooks.useRef(null);
1365
+ const menu = hooks.useRef(null);
1366
+ hooks.useLayoutEffect(() => {
1367
+ const el = menu.current;
1368
+ if (!open || !el) return;
1369
+ el.style.transform = "";
1370
+ const r = el.getBoundingClientRect();
1371
+ const vw = document.documentElement.clientWidth || window.innerWidth;
1372
+ let dx = 0;
1373
+ if (r.right > vw - EDGE) dx = vw - EDGE - r.right;
1374
+ if (r.left + dx < EDGE) dx = EDGE - r.left;
1375
+ if (dx !== 0) el.style.transform = `translateX(${Math.round(dx)}px)`;
1376
+ }, [open, rows, loadFailed, switchFailed]);
1364
1377
  const load = () => {
1365
1378
  setLoadFailed(false);
1366
1379
  api.load().then(setRows, () => setLoadFailed(true));
@@ -1411,7 +1424,7 @@ function TenantSwitcher({ lang, activeSlug, adapter, onSwitch }) {
1411
1424
  children: /* @__PURE__ */ jsxRuntime.jsx("span", { class: "bas-tenant__label", "data-testid": "tenant-switcher-label", children: label })
1412
1425
  }
1413
1426
  ),
1414
- open ? /* @__PURE__ */ jsxRuntime.jsxs("div", { class: "bas-menu bas-tenant__menu", role: "menu", "data-testid": "tenant-switcher-menu", children: [
1427
+ open ? /* @__PURE__ */ jsxRuntime.jsxs("div", { class: "bas-menu bas-tenant__menu", ref: menu, role: "menu", "data-testid": "tenant-switcher-menu", children: [
1415
1428
  loadFailed ? /* @__PURE__ */ jsxRuntime.jsxs("div", { class: "bas-tenant__note", role: "alert", "data-testid": "tenant-switcher-load-error", children: [
1416
1429
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: t.tenantLoadFailed }),
1417
1430
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", class: "bas-mi", onClick: load, "data-testid": "tenant-switcher-retry", children: t.tenantRetry })
@@ -1432,7 +1445,7 @@ function TenantSwitcher({ lang, activeSlug, adapter, onSwitch }) {
1432
1445
  "data-testid": `tenant-switcher-item-${r.tenant.slug}`,
1433
1446
  children: [
1434
1447
  /* @__PURE__ */ jsxRuntime.jsx("span", { class: "bas-tenant__name", children: r.tenant.name }),
1435
- /* @__PURE__ */ jsxRuntime.jsx("span", { class: "bas-tenant__role", children: suspended ? t.tenantSuspended : isActive ? t.tenantActive : r.role })
1448
+ suspended || isActive || roleLabel ? /* @__PURE__ */ jsxRuntime.jsx("span", { class: "bas-tenant__role", "data-testid": `tenant-switcher-role-${r.tenant.slug}`, children: suspended ? t.tenantSuspended : isActive ? t.tenantActive : roleLabel(r.role) }) : null
1436
1449
  ]
1437
1450
  },
1438
1451
  r.tenant.id