@poodle64/ui 2026.9.4 → 2026.9.5

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
@@ -1164,4 +1164,18 @@ non-zero and naming the field on any difference.
1164
1164
 
1165
1165
  1. Change a component; bump `version` in `package.json` (CalVer).
1166
1166
  2. `pnpm build`, which runs `svelte-package` then `publint` (package.json/exports sanity).
1167
- 3. Commit, tag `ui-v<version>`, push the tag; CI publishes to public npm.
1167
+ 3. Commit, tag `ui-v<version>`, push the tag.
1168
+ 4. `.github/workflows/publish.yaml` runs on that push and should publish via
1169
+ npm OIDC trusted publishing: check it with
1170
+ `gh run list --workflow=publish.yaml`. As of 2026.9.4 every run since
1171
+ `ui-v2026.9.2` fails at the `npm publish` step with
1172
+ `E404 Not Found - PUT .../@poodle64%2fui` (an OIDC/trusted-publisher
1173
+ binding issue, since `Build and test package` passes first). Until that
1174
+ is diagnosed and fixed, publish manually from `packages/ui/`:
1175
+ ```bash
1176
+ printf '//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}\n' > .npmrc
1177
+ signet exec --identity huginn-claude --broker https://portcullis.godswood.au \
1178
+ --credential npm-publish-token --env-var NODE_AUTH_TOKEN -- npm publish
1179
+ rm -f .npmrc
1180
+ ```
1181
+ Confirm with `npm view @poodle64/ui version`.
@@ -575,7 +575,19 @@
575
575
  {@render brandLockup(true)}
576
576
  </span>
577
577
 
578
- {#if context}{@render context()}{/if}
578
+ <!-- `min-w-0` is what lets a leading `context` snippet (a workspace
579
+ switcher, a breadcrumb) actually shrink under crowding — a flex
580
+ item's automatic `min-width: auto` otherwise floors it at its own
581
+ min-content size, so with search, actions and identity all also
582
+ competing for the bar the FIRST thing to run out of room was
583
+ whichever trailing control happened to sit last in source order
584
+ (theme, identity) — pushed edge-to-edge past the header's own
585
+ right edge and, with no horizontal scroll on the bar, permanently
586
+ unreachable rather than merely cramped (design-system#111). The
587
+ wordmark and the search button already carry their own shrink
588
+ behaviour (hiding text, going icon-only); `context` is the one
589
+ leading slot that never had to. -->
590
+ {#if context}<div class="min-w-0">{@render context()}</div>{/if}
579
591
 
580
592
  {#if onSearch && searchPlacement === 'leading'}
581
593
  {@render searchButton(
package/dist/styles.css CHANGED
@@ -624,6 +624,15 @@
624
624
  .ds-nav {
625
625
  --ds-nav-ink: var(--ds-nav-chrome-ink, var(--foreground));
626
626
  --ds-nav-ink-muted: var(--ds-nav-chrome-ink-muted, var(--muted-foreground));
627
+ /* Specified rather than left `visible` (the default): `overflow-y: auto`
628
+ otherwise forces the computed value of an unspecified overflow-x to
629
+ `auto` too (CSSOM's "if one axis is visible and the other is not, the
630
+ visible one becomes auto" rule), so a row wider than the nav — a long
631
+ label, a wide badge — got its own sideways scrollbar inside the drawer.
632
+ The drawer scrolls vertically only; a row that doesn't fit truncates
633
+ (`.ds-nav-item`'s label already carries `.truncate`) rather than
634
+ growing a second scroll axis on top of the menu's own (design-system#111). */
635
+ overflow-x: hidden;
627
636
  }
628
637
 
629
638
  .ds-shell-rail,
@@ -847,6 +856,21 @@
847
856
  padding-inline: 0;
848
857
  }
849
858
 
859
+ /* A hard ceiling on the whole shell, in the one unit that names the actual
860
+ drawn surface rather than a percentage of an ancestor. `.ds-shell` is
861
+ already `flex` with `overflow-hidden` in the component markup, which
862
+ clips an ordinary descendant that outgrows it — but a `position: fixed`
863
+ descendant (the open drawer, below) is excused from an ancestor's
864
+ `overflow: hidden` by definition, fixed positioning escapes every
865
+ clipping ancestor that is not itself a containing block for fixed
866
+ elements, and `.ds-shell` is not one. This is the backstop for that
867
+ whole class of leak: whatever grows past the shell's own box, on
868
+ whichever descendant, the SHELL still cannot be asked to draw wider than
869
+ the viewport it is actually in (design-system#111). */
870
+ .ds-shell {
871
+ max-width: 100dvw;
872
+ }
873
+
850
874
  /* The rail is ONE element in two states, not two elements (see the comment in
851
875
  app-shell.svelte): below md it is hidden until `data-drawer` turns it into
852
876
  an overlay; at md and up it is the permanent column and `data-drawer` means
@@ -871,16 +895,35 @@
871
895
  the last nav row at its bottom sit exactly where a notch or a home
872
896
  indicator gesture bar would cover them. The rail's own sticky state
873
897
  never needs this — it starts below the page's own top edge in normal
874
- flow, not against the physical screen edge. */
898
+ flow, not against the physical screen edge.
899
+
900
+ The width is a `min()` against the true viewport (`100dvw`, less the
901
+ left inset a landscape notch carves out of it) rather than the old
902
+ `max-width: 82vw` — `vw` is the LAYOUT viewport, which on a phone stays
903
+ the largest size the page could ever occupy whether or not the browser
904
+ chrome is actually showing, while `dvw` is the viewport the page is
905
+ ACTUALLY drawn into right now. The two rarely disagree on width the way
906
+ `vh`/`dvh` disagree on height, but disagreeing on principle was already
907
+ enough to make this the one place on the drawer that named the wrong
908
+ viewport (design-system#111): every other rule the drawer carries reads
909
+ `dvh`/`env(safe-area-inset-*)`, so `82vw` was the one dimension still
910
+ trusting a unit this component elsewhere treats as untrustworthy on a
911
+ phone. `min()` over `--ds-shell-rail-width` keeps the drawer at its
912
+ ordinary width on anything bigger than a narrow phone, and only the
913
+ viewport term binds below that — so the drawer can never be asked to be
914
+ wider than the screen it is drawn on, at any width, by construction
915
+ rather than by testing every content shape that could have pushed it
916
+ there. */
875
917
  .ds-shell-rail[data-drawer='true'] {
876
918
  display: flex;
877
919
  position: fixed;
878
920
  inset-block: 0;
879
921
  left: 0;
880
922
  z-index: 50;
881
- max-width: 82vw;
923
+ width: min(var(--ds-shell-rail-width), 82dvw, 100dvw - env(safe-area-inset-left, 0px));
882
924
  padding-top: env(safe-area-inset-top);
883
925
  padding-bottom: env(safe-area-inset-bottom);
926
+ padding-left: env(safe-area-inset-left);
884
927
  box-shadow:
885
928
  0 10px 15px -3px oklch(0 0 0 / 0.1),
886
929
  0 4px 6px -4px oklch(0 0 0 / 0.1);
@@ -896,9 +939,10 @@
896
939
  .ds-shell-rail[data-drawer='true'] {
897
940
  position: sticky;
898
941
  z-index: auto;
899
- max-width: none;
942
+ width: var(--ds-shell-rail-width);
900
943
  padding-top: 0;
901
944
  padding-bottom: 0;
945
+ padding-left: 0;
902
946
  box-shadow: none;
903
947
  animation: none;
904
948
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poodle64/ui",
3
- "version": "2026.9.4",
3
+ "version": "2026.9.5",
4
4
  "description": "Household shared component layer: shadcn-svelte primitives (bits-ui) plus the composed page chrome every app builds its routes from, restyled by each app's @poodle64/design-tokens alias layer. One fix reaches every app.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "meta": {
3
3
  "package": "@poodle64/ui",
4
- "version": "2026.9.4",
4
+ "version": "2026.9.5",
5
5
  "generatedBy": "scripts/generate-registry.mjs",
6
6
  "source": "scripts/situations.json + package source (DO NOT EDIT the outputs by hand)",
7
7
  "componentCount": 56,
@@ -1,7 +1,7 @@
1
1
  # @poodle64/ui — situation → component map
2
2
 
3
3
  <!-- GENERATED by scripts/generate-registry.mjs from scripts/situations.json + package source. DO NOT EDIT. -->
4
- Generated from `@poodle64/ui@2026.9.4`. 56 components, 15 situations.
4
+ Generated from `@poodle64/ui@2026.9.5`. 56 components, 15 situations.
5
5
 
6
6
  **Read this before writing a `<div>`.** Find the SITUATION you are in below, then compose the component named for it — do not hand-build it from raw `Card` or utility classes. Import is `import { Name } from '<import path>'`. Props marked `?` are optional. This map is the retrieval step the [`frontend-design` skill] makes mandatory; the [CHI 2026 study] measured composing-from-a-registry at 95% design-system compliance against 71% for writing the CSS from a prose style guide.
7
7