@the-portland-company/shell 0.11.1 → 0.11.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,36 @@
1
+ ## 0.11.3 — 2026-07-20
2
+
3
+ ### Fixed (native — token contract + client boundary)
4
+
5
+ - **Native chrome now has a real semantic token layer.** The `./native`
6
+ components (NavTopBar / NavSidebar / NavTabStrip / NavAppShell) reference
7
+ `--background`, `--foreground`, `--muted`, `--panel`, `--panel-elevated`,
8
+ `--line`, `--shadow-soft` directly as `var(--x)`, but chrome.css never defined
9
+ them for light mode and only emitted `--foreground`/`--muted`/`--background`
10
+ inside `.dark` as ShadCN **HSL channel triplets** (`210 40% 98%`) meant for
11
+ `hsl(var(--x))` — invalid when used as a full color, so out-of-the-box the
12
+ native chrome had no surface/border and broken text. `gen:tokens` now emits
13
+ these seven names as **full colors in both `:root` (light, aliased to the
14
+ canonical `--topbar-*`/`--surface-*`/`--sidebar-border`/`--shadow-lg` tokens)
15
+ and `.dark` (from the Specs `darkMode.*` values wrapped in `hsl()`)**. Note
16
+ `--muted` maps to muted-*foreground* because native uses it as secondary text.
17
+ Apps consuming `./native` no longer need an app-side var bridge in globals.css.
18
+ - **`"use client"` is now emitted on `dist/native.{js,cjs}`** (prepended
19
+ post-build, since esbuild strips a source/banner directive). Next.js App
20
+ Router apps can import the native chrome into Server Components without a
21
+ manual client-boundary wrapper. Ignored (harmless) by Vite/Chakra consumers.
22
+
23
+ ## 0.11.2 — 2026-07-20
24
+
25
+ ### Added (native — per-slot Brand glyphs)
26
+
27
+ - **`NavTopBarAction` gains an optional `slot`** so the native top-bar action
28
+ icons source their glyph by name from `--topbar-icon-<slot>` (Brand API),
29
+ matching the Chakra `<TopBarIcon>`; button size/color/hover and the cluster
30
+ gap now resolve the universal `--topbar-icon-*` tokens with the previous
31
+ literals as fallbacks. Shared slot contract extracted to
32
+ `src/lib/topbarIconSlot.ts` (framework-agnostic, no Chakra import).
33
+
1
34
  ## 0.11.1 — 2026-07-20
2
35
 
3
36
  ### Fixed (packaging — native install)
package/dist/chrome.css CHANGED
@@ -240,6 +240,19 @@
240
240
  --mode-input-border-color: #E63946;
241
241
  --mode-input-hover-border-color: #C42E3A;
242
242
  --mode-input-focus-shadow-color: #E63946;
243
+
244
+ /* Native chrome semantic layer — shell-owned aliases over the
245
+ canonical tokens above, consumed by the ./native export
246
+ (NavTopBar / NavSidebar / NavTabStrip / NavAppShell). These are the
247
+ full-color names those components reference directly as var(--x);
248
+ the .dark block overrides them with dark values. */
249
+ --background: var(--surface-1);
250
+ --foreground: var(--topbar-title-color);
251
+ --muted: var(--topbar-breadcrumb-color);
252
+ --panel: var(--topbar-bg);
253
+ --panel-elevated: var(--surface-1);
254
+ --line: var(--sidebar-border);
255
+ --shadow-soft: var(--shadow-lg);
243
256
  }
244
257
  .dark {
245
258
  --background: 222.2 84% 4.9%;
@@ -261,4 +274,11 @@
261
274
  --border: 217.2 32.6% 17.5%;
262
275
  --input: 217.2 32.6% 17.5%;
263
276
  --ring: 212.7 26.8% 83.9%;
277
+ --background: hsl(222.2 84% 4.9%);
278
+ --foreground: hsl(210 40% 98%);
279
+ --muted: hsl(215 20.2% 65.1%);
280
+ --panel: hsl(222.2 84% 4.9%);
281
+ --panel-elevated: hsl(217.2 32.6% 17.5%);
282
+ --line: hsl(217.2 32.6% 17.5%);
283
+ --shadow-soft: 0 4px 16px rgba(0, 0, 0, 0.5);
264
284
  }
@@ -0,0 +1,25 @@
1
+ import { useState, useEffect } from 'react';
2
+
3
+ // src/lib/topbarIconSlot.ts
4
+ function useTopBarIconSlotGlyph(slot) {
5
+ const [name, setName] = useState(null);
6
+ useEffect(() => {
7
+ if (typeof window === "undefined") return;
8
+ const read = () => {
9
+ const raw = window.getComputedStyle(document.documentElement).getPropertyValue(`--topbar-icon-${slot}`).trim().replace(/^['"]|['"]$/g, "");
10
+ setName(raw.length > 0 ? raw : null);
11
+ };
12
+ read();
13
+ const observer = new MutationObserver(read);
14
+ observer.observe(document.head, { childList: true, subtree: true });
15
+ return () => observer.disconnect();
16
+ }, [slot]);
17
+ return name;
18
+ }
19
+ function brandIconSrc(name, basePath = "/brand/icons/") {
20
+ return `${basePath}${name}.svg`;
21
+ }
22
+
23
+ export { brandIconSrc, useTopBarIconSlotGlyph };
24
+ //# sourceMappingURL=chunk-VTGRJ4HV.js.map
25
+ //# sourceMappingURL=chunk-VTGRJ4HV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/topbarIconSlot.ts"],"names":[],"mappings":";;;AA6BO,SAAS,uBAAuB,IAAA,EAAqC;AAC1E,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAwB,IAAI,CAAA;AAEpD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAEnC,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,MAAM,GAAA,GAAM,MAAA,CACT,gBAAA,CAAiB,QAAA,CAAS,eAAe,CAAA,CACzC,gBAAA,CAAiB,CAAA,cAAA,EAAiB,IAAI,EAAE,CAAA,CACxC,IAAA,EAAK,CAEL,OAAA,CAAQ,gBAAgB,EAAE,CAAA;AAC7B,MAAA,OAAA,CAAQ,GAAA,CAAI,MAAA,GAAS,CAAA,GAAI,GAAA,GAAM,IAAI,CAAA;AAAA,IACrC,CAAA;AAEA,IAAA,IAAA,EAAK;AAEL,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,IAAI,CAAA;AAC1C,IAAA,QAAA,CAAS,OAAA,CAAQ,SAAS,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AAClE,IAAA,OAAO,MAAM,SAAS,UAAA,EAAW;AAAA,EACnC,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,YAAA,CAAa,IAAA,EAAc,QAAA,GAAW,eAAA,EAAiB;AACrE,EAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,EAAG,IAAI,CAAA,IAAA,CAAA;AAC3B","file":"chunk-VTGRJ4HV.js","sourcesContent":["import { useEffect, useState } from 'react'\n\n/**\n * The six canonical top-bar action slots (Reference/Global-Rules v9 → top-bar\n * icons). Each slot's GLYPH is unique and comes from the Brand API\n * `topbarIcons.items.*` tokens, exposed as `--topbar-icon-<slot>` CSS vars\n * whose value is the brand-icon NAME. Every OTHER property — size, gap, color,\n * hover, selected — is universal across all six slots.\n */\nexport type TopBarIconSlot =\n | 'comms-fuel'\n | 'apps'\n | 'notifications'\n | 'alerts'\n | 'support'\n | 'dark-mode'\n\n/**\n * Reads the glyph NAME for a slot from its `--topbar-icon-<slot>` CSS var.\n *\n * Runs in an effect because the Brand stylesheet is appended to <head> at\n * runtime (Global Rules forbids baking it into the build), so the var is not\n * resolvable during SSR or the first synchronous render. The MutationObserver\n * re-reads once the stylesheet lands so the glyph upgrades from the caller's\n * fallback without a reload.\n *\n * Returns null when the slot has no Brand glyph — callers render their own\n * fallback icon in that case.\n */\nexport function useTopBarIconSlotGlyph(slot: TopBarIconSlot): string | null {\n const [name, setName] = useState<string | null>(null)\n\n useEffect(() => {\n if (typeof window === 'undefined') return\n\n const read = () => {\n const raw = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(`--topbar-icon-${slot}`)\n .trim()\n // Brand may emit the name quoted (e.g. \"bell\"); strip the quotes.\n .replace(/^['\"]|['\"]$/g, '')\n setName(raw.length > 0 ? raw : null)\n }\n\n read()\n\n const observer = new MutationObserver(read)\n observer.observe(document.head, { childList: true, subtree: true })\n return () => observer.disconnect()\n }, [slot])\n\n return name\n}\n\n/** Path to a brand-icon SVG in the consuming app's public dir. */\nexport function brandIconSrc(name: string, basePath = '/brand/icons/') {\n return `${basePath}${name}.svg`\n}\n"]}
package/dist/index.cjs CHANGED
@@ -2655,7 +2655,7 @@ function AppLayout({
2655
2655
  overlaySlot
2656
2656
  ] });
2657
2657
  }
2658
- function useSlotGlyphName(slot) {
2658
+ function useTopBarIconSlotGlyph(slot) {
2659
2659
  const [name, setName] = react$1.useState(null);
2660
2660
  react$1.useEffect(() => {
2661
2661
  if (typeof window === "undefined") return;
@@ -2672,7 +2672,7 @@ function useSlotGlyphName(slot) {
2672
2672
  }
2673
2673
  var TopBarIcon = react$1.forwardRef(
2674
2674
  function TopBarIcon2({ slot, fallbackIcon, isSelected, ...rest }, ref) {
2675
- const glyphName = useSlotGlyphName(slot);
2675
+ const glyphName = useTopBarIconSlotGlyph(slot);
2676
2676
  const icon = glyphName ? /* @__PURE__ */ jsxRuntime.jsx(
2677
2677
  BrandIcon,
2678
2678
  {