@crewlethq/ui 0.82.0 → 0.83.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.
Files changed (139) hide show
  1. package/README.md +29 -1
  2. package/dist/AppShell/AccountRow.d.ts +6 -1
  3. package/dist/AppShell/AppShell.d.ts +15 -6
  4. package/dist/AppShell/index.d.ts +1 -1
  5. package/dist/AppShell/index.js +8 -5
  6. package/dist/AppShell/railMotion.d.ts +60 -0
  7. package/dist/AppShell/railShape.d.ts +5 -0
  8. package/dist/{AppShell-F7RID4P4.css → AppShell-U7D2MUUF.css} +177 -56
  9. package/dist/ArrangeList/index.js +3 -2
  10. package/dist/ArtifactBar/index.js +7 -5
  11. package/dist/ArtifactCard/index.js +2 -2
  12. package/dist/AuthLayout/index.js +3 -3
  13. package/dist/AvatarPicker/index.js +7 -6
  14. package/dist/BrandLockup/index.js +2 -2
  15. package/dist/Canvas/index.js +4 -2
  16. package/dist/CanvasBoard/index.js +6 -4
  17. package/dist/CanvasToolbar/index.js +5 -3
  18. package/dist/ChangeMark/index.js +4 -2
  19. package/dist/ChatThread/index.js +2 -2
  20. package/dist/CommandPalette/index.js +3 -2
  21. package/dist/CompactNav/index.js +2 -1
  22. package/dist/ContrastHelp/index.js +3 -2
  23. package/dist/DataGrid/index.js +2 -2
  24. package/dist/DataTable/index.js +4 -3
  25. package/dist/DataView/index.js +7 -6
  26. package/dist/DateTimePicker/index.js +3 -2
  27. package/dist/DeepWorkCard/index.js +2 -2
  28. package/dist/DocTabsEditor/index.js +5 -3
  29. package/dist/DockColumn/DockColumn.d.ts +68 -0
  30. package/dist/DockColumn/index.d.ts +3 -0
  31. package/dist/DockColumn/index.js +6 -0
  32. package/dist/DockColumn-SMJCXHS4.css +61 -0
  33. package/dist/{Editor-7EQWP3RN.js → Editor-5D5Z3LBQ.js} +3 -2
  34. package/dist/EmojiPicker/index.js +5 -3
  35. package/dist/FactList/index.js +4 -2
  36. package/dist/HuePicker/index.js +5 -4
  37. package/dist/LinkInterstitial/index.js +3 -2
  38. package/dist/ListInput/index.js +3 -2
  39. package/dist/MarkdownEditor/index.js +5 -4
  40. package/dist/MediaMatch/index.d.ts +1 -1
  41. package/dist/MediaMatch/index.js +1 -1
  42. package/dist/MediaMatch/useMediaMatch.d.ts +14 -0
  43. package/dist/Menu/index.js +2 -1
  44. package/dist/MergeConflicts/index.js +5 -4
  45. package/dist/MessageActions/index.js +6 -4
  46. package/dist/Modal/index.js +2 -1
  47. package/dist/OpenInAppCard/index.js +2 -2
  48. package/dist/Outline/index.js +2 -1
  49. package/dist/Popover/index.js +2 -1
  50. package/dist/Presence/index.d.ts +2 -0
  51. package/dist/Presence/index.js +4 -0
  52. package/dist/Presence/usePresence.d.ts +109 -0
  53. package/dist/ReactionBar/index.js +6 -4
  54. package/dist/RecordChip/index.js +3 -2
  55. package/dist/Reorder/index.js +2 -1
  56. package/dist/RichEditor/index.js +1 -1
  57. package/dist/SegmentedControl/index.js +4 -3
  58. package/dist/SetupWizard/index.js +2 -2
  59. package/dist/ShareDialog/index.js +4 -3
  60. package/dist/SheetColumnEditor/index.js +6 -5
  61. package/dist/SheetGrid/index.js +8 -6
  62. package/dist/SlideFilmstrip/index.js +5 -3
  63. package/dist/Switcher/index.js +5 -4
  64. package/dist/Tabs/index.js +3 -2
  65. package/dist/ThemeSwitcher/index.js +5 -4
  66. package/dist/TimeRangePicker/index.js +6 -5
  67. package/dist/TimeWindowPicker/index.js +3 -2
  68. package/dist/Tooltip/index.js +3 -1
  69. package/dist/TreeCanvas/index.js +6 -3
  70. package/dist/VersionCompare/index.js +5 -4
  71. package/dist/{chunk-KJR5X4II.js → chunk-22CU7V4J.js} +2 -2
  72. package/dist/{chunk-4RYELYWG.js → chunk-2SVQBQAD.js} +2 -2
  73. package/dist/{chunk-HQFOZJQ4.js → chunk-46FIBJCV.js} +4 -4
  74. package/dist/{chunk-LQRN2XZK.js → chunk-4DEKONVJ.js} +2 -2
  75. package/dist/chunk-5JPOFAVN.js +58 -0
  76. package/dist/{chunk-C7UHDM7Y.js → chunk-5V6GW6HK.js} +1 -1
  77. package/dist/{chunk-XGLMPPDW.js → chunk-7K6LVM5I.js} +1 -1
  78. package/dist/{chunk-FKAJBN6G.js → chunk-7M7WKYOV.js} +3 -3
  79. package/dist/{chunk-A5YKNRG6.js → chunk-7QCSISHM.js} +2 -1
  80. package/dist/{chunk-3QQIGMY3.js → chunk-7ZSEUO5Q.js} +6 -30
  81. package/dist/{chunk-57BFL323.js → chunk-ABRWL5FJ.js} +1 -1
  82. package/dist/{chunk-HFOTRZFU.js → chunk-AQNP3KQU.js} +2 -2
  83. package/dist/{chunk-N2T7Y5KR.js → chunk-AUSFKGKL.js} +1 -1
  84. package/dist/{chunk-GZVAZ3LL.js → chunk-AZYE7NR4.js} +1 -1
  85. package/dist/{chunk-6IOQWMYJ.js → chunk-BN5FEJL5.js} +1 -1
  86. package/dist/{chunk-MPVMB2DV.js → chunk-BVML4UVB.js} +3 -2
  87. package/dist/{chunk-XY4O2XMR.js → chunk-BXGBGYKH.js} +3 -3
  88. package/dist/{chunk-OAHRMR4U.js → chunk-C42XW5YP.js} +1 -1
  89. package/dist/{chunk-HA2PL7PA.js → chunk-DRFOTWJE.js} +1 -1
  90. package/dist/{chunk-SM4P2SHB.js → chunk-EC6EUIAD.js} +7 -4
  91. package/dist/{chunk-AMUXSJ2A.js → chunk-FPU7AA3X.js} +4 -15
  92. package/dist/{chunk-KLAVEJIO.js → chunk-GLKQHN7G.js} +1 -1
  93. package/dist/chunk-HTS5RJ7S.js +6 -0
  94. package/dist/{chunk-GP5TNTZH.js → chunk-ICE3D63E.js} +3 -5
  95. package/dist/{chunk-ISQANI6Q.js → chunk-JLOESTT2.js} +2 -1
  96. package/dist/{chunk-C75WZMXG.js → chunk-K6RWEQ6P.js} +1 -1
  97. package/dist/{chunk-GVPUCEWH.js → chunk-KXWJJWBD.js} +1 -1
  98. package/dist/chunk-L72URIHR.js +36 -0
  99. package/dist/{chunk-2TOGGCDM.js → chunk-LT44RL62.js} +2 -2
  100. package/dist/{chunk-HCUECVZ3.js → chunk-MVKUE4FI.js} +1 -1
  101. package/dist/{chunk-6YBBQAEM.js → chunk-MYAARF4Z.js} +1 -1
  102. package/dist/{chunk-SEKO6P3Y.js → chunk-NCUSI4ZU.js} +1 -1
  103. package/dist/chunk-PCAT2EFB.js +104 -0
  104. package/dist/{chunk-T4IEESXN.js → chunk-PGBKZSSQ.js} +87 -24
  105. package/dist/{chunk-TGCGLKD4.js → chunk-RBQRTGXX.js} +1 -1
  106. package/dist/{chunk-B3X4DHRB.js → chunk-RDIQB5ZE.js} +2 -2
  107. package/dist/{chunk-T7WESRZF.js → chunk-RO5JU6SN.js} +2 -2
  108. package/dist/{chunk-IUWP2LSE.js → chunk-SGMWLUYQ.js} +2 -2
  109. package/dist/{chunk-LSOR77RZ.js → chunk-SHH7UD5U.js} +1 -1
  110. package/dist/{chunk-JV6JM6W6.js → chunk-SNQ7PH3D.js} +1 -1
  111. package/dist/{chunk-MPYRC3GO.js → chunk-SPNTUQBV.js} +2 -2
  112. package/dist/{chunk-YM77TZ7Q.js → chunk-T3S3D4FC.js} +1 -1
  113. package/dist/{chunk-YOJAGKTS.js → chunk-TGGYSQRD.js} +3 -4
  114. package/dist/{chunk-2KJCUCVE.js → chunk-TQKQRS2J.js} +2 -2
  115. package/dist/{chunk-ONNXUS5Y.js → chunk-VB3FVKNI.js} +1 -1
  116. package/dist/{chunk-JHQGNFN3.js → chunk-VONEKR3J.js} +2 -2
  117. package/dist/{chunk-P6F3PE4V.js → chunk-WANKINXG.js} +2 -2
  118. package/dist/{chunk-PXLS6JKL.js → chunk-WMO722J2.js} +1 -1
  119. package/dist/{chunk-SYVQXMLO.js → chunk-XRWHDW6F.js} +4 -4
  120. package/dist/{chunk-WT3B76MG.js → chunk-XTJHMP3W.js} +1 -1
  121. package/dist/{chunk-RTPQDNW3.js → chunk-YJQXESOJ.js} +5 -1
  122. package/dist/{chunk-VGOWSOUA.js → chunk-YXKSUILG.js} +1 -1
  123. package/dist/{chunk-G6ZFSUIH.js → chunk-ZJVLGYE3.js} +2 -2
  124. package/dist/{chunk-BSAU7QRW.js → chunk-ZPTKAYJK.js} +1 -1
  125. package/dist/{chunk-XXDB6KPV.js → chunk-ZXXZESCD.js} +3 -4
  126. package/dist/generated/index.d.ts +2 -0
  127. package/dist/generated/index.js +97 -93
  128. package/dist/index.js +97 -93
  129. package/dist/styles.css +242 -57
  130. package/dist/utils/composedRef.d.ts +39 -0
  131. package/dist/utils/index.d.ts +2 -0
  132. package/dist/utils/index.js +3 -1
  133. package/dist/utils/tokenMs.d.ts +6 -0
  134. package/package.json +5 -5
  135. package/dist/{chunk-IYI6HWKN.js → chunk-CV2LU2T2.js} +1 -1
  136. package/dist/{chunk-FVZPSTL2.js → chunk-G4EHZHKM.js} +1 -1
  137. package/dist/{chunk-FEJANUZK.js → chunk-KBSD476L.js} +0 -0
  138. package/dist/{chunk-2H6YDUR5.js → chunk-QM3432PH.js} +1 -1
  139. /package/dist/{chunk-KLWWNV25.js → chunk-REEZQCML.js} +0 -0
package/README.md CHANGED
@@ -53,7 +53,7 @@ import { Button } from '@crewlethq/ui/Button'; // 8 KB of CSS, not 182 KB
53
53
  | Hooks and seams | `useModalLayer`, `usePopupLayer`, `LayerHost`, `useListbox`, `useOptionKeys`, `useHighlightRest` and `HIGHLIGHT_REST_MS`, `useClipboard`, `useDownload`, `downloadText`, `downloadBlob`, `safeFilename`, `toCsv`, `elementToPng` and `ElementToPngError`, `useOutcome`, `useAnnouncer`, `useNow`, `formatRelative`, `HeadingLevelProvider`, `cx`, the node hues (`NODE_HUES`, `NODE_HUE_NAMES`, `isNodeHue`) |
54
54
  | Layout | `Container`, `Section`, `Card`, `TileGrid`, `ListDetail`, `AsideLayout`, `Tabs`, `Accordion`, `Disclosure`, `Outline` (with `useActiveHeading` and `scrollToHeading`), `TreeGrid` |
55
55
  | Arranging a page | `ArrangeBoard`, `ArrangeGrid`, `ArrangeFrame` (with `useGridResize`), `ArrangeGroup`, `ArrangeList`, and the reorder hooks under them (`useReorder`, `useReorderLists`, `moveKey`) |
56
- | Application shell | `AppShell` with `AppShell.Rail`, the compact rail (`rail="compact"`, the one fold control from `onRailChange`, and `useAppShell().rail` to pick the shape) and `fill="flush"`, the `aside` track and the `peek` slot (`useAppShellAside`, `useAppShellPeek`), `AppShell.ResizeHandle` (also `ResizeHandle`) and `useStoredWidth`, `SidePanel` and `SidePanelFrame`, `PeekRail` and `PeekHost` (with `PeekNeighbours`, `usePeekNeighbours`, `usePeekStep`, `peekClickHandler`, `peekRowActivation`), `SectionFrame` (with `SectionFrame.Nav` and `SectionFrame.Body`), `LockedLabel`, `AppShell.Topbar`, `AppShell.AccountRow` and `useAppShell`, `AuthLayout`, `SidebarNav` and `NavItem` (with `dense` lists, `unread` and `muted` rows and `collapsible` groups), `CompactNav` with `CompactNavItem`, `CompactNavGroup` and `CompactNavSeparator` (the rail folded to its marks, fed from the same places), `DirectoryList`, `BrandLockup`, `SearchTrigger`, `PageHeader`, `Toolbar`, `Stack`, `Inline`, `Spacer`, `AutoGrid`, `ErrorBoundary`, `useShortcut`, `useFullscreen`, `useIdle`, `useMediaMatch` |
56
+ | Application shell | `AppShell` with `AppShell.Rail`, the compact rail (`rail="compact"`, the one fold control from `onRailChange`, and `useAppShell().rail` to pick the shape) and `fill="flush"`, the `aside` track and the `peek` slot (`useAppShellAside`, `useAppShellPeek`), `AppShell.ResizeHandle` (also `ResizeHandle`) and `useStoredWidth`, `SidePanel` and `SidePanelFrame`, `PeekRail` and `PeekHost` (with `PeekNeighbours`, `usePeekNeighbours`, `usePeekStep`, `peekClickHandler`, `peekRowActivation`), `SectionFrame` (with `SectionFrame.Nav` and `SectionFrame.Body`), `DockColumn` and `usePresence`, `LockedLabel`, `AppShell.Topbar`, `AppShell.AccountRow` and `useAppShell`, `AuthLayout`, `SidebarNav` and `NavItem` (with `dense` lists, `unread` and `muted` rows and `collapsible` groups), `CompactNav` with `CompactNavItem`, `CompactNavGroup` and `CompactNavSeparator` (the rail folded to its marks, fed from the same places), `DirectoryList`, `BrandLockup`, `SearchTrigger`, `PageHeader`, `Toolbar`, `Stack`, `Inline`, `Spacer`, `AutoGrid`, `ErrorBoundary`, `useShortcut`, `useFullscreen`, `useIdle`, `useMediaMatch` |
57
57
  | Preferences | `ThemeToggle`, `ThemeSwitcher`, `DensitySwitcher`, `ThemeGallery`, `ThemeSwatch`, `useThemePreference`, `useDensityPreference`, `useSystemTheme`, `resolveTheme`, `applyStoredPreferences`, and the framework-free `applyTheme`, `applyPalette`, `applyDensity` with `THEME_PREFERENCES`, `DENSITY_PREFERENCES` and their guards |
58
58
  | Artifacts | `SandboxedFrame` (with `SandboxedFramePlaceholder` and `SandboxedFrameNotice`), `LinkInterstitial` and `openExternal`, `VersionTimeline`, `ShareDialog` with the role ladder (`ARTIFACT_ROLES`, `SHAREABLE_ROLES`, `roleAtLeast`), `PrincipalPicker`, `Principal` and `PrincipalAvatar`, `ArtifactCard`, `ArtifactKindGlyph` and `ArtifactPreviewGlyph` (the preview a card draws with no cover, for a cover with nothing to draw), `ArtifactBar` and `ArtifactVersionChip` (an open artifact's one slim bar), `ArtifactPanel` and `ArtifactWorkspace` (the panels it opens beside or over the artifact), `CanvasBoard` (a design's artboards and notes on a `Canvas`, with the visibility budget `liveBoards`), `CanvasToolbar` (a canvas's tool palette, with `toolForKey`), `LayersList` (the list of a canvas's items beside it, marked by the canvas's selection), `CanvasSchematic` (a design's cover, drawn from its boards' frames), `AccessDeniedCard`, `ArtifactIcon` (with `artifactIconGlyph` and `ARTIFACT_ICON_WORDS`), the native gallery covers (`DocCover`, `SheetCover`, `DashboardCover`), `MergeConflicts`, the dashboard pieces (`WidgetFrame`, `DatasetSource` and `DatasetSourceList`), and `FrameProtocol` (the wire between a host page and an embedded artifact, with no React in it), `ArtifactNameCell` and `ArtifactAccessLabel` (with `ArtifactAccessGlyph`) for a list of artifacts |
59
59
  | Sheets | `SheetGrid`, the cells on their own (`CheckboxCell`, `TextCell`, `LongTextCell`, `NumberCell`, `SelectCell`, `MultiSelectCell`, `PersonCell`, `StatusCell`, `DateCell`, `UrlCell`, `RatingCell`, and `SheetCell` for any type), `ChangeMark`, and `SheetModel` (every rule a sheet is drawn from, with no React in it: values, parsing, the keyboard model, TSV, the pending edits of D23) |
@@ -205,6 +205,34 @@ places:
205
205
  - A surface that pans or zooms dispatches `LAYER_REPOSITION_EVENT` on its host
206
206
  when the content beneath it moves, and every panel anchored inside follows.
207
207
 
208
+ ## Changes in 0.83.0
209
+
210
+ ### The application rail
211
+
212
+ **The fold control is a plus and a minus in the rail's top left corner.** The chevron in the row under the rail's head is gone. In its place `AppShell` draws one control in the corner the head leaves empty, up and to the left of the brand's mark: a minus (`MinusGlyph`) while the rail is full, to make it smaller, and a plus (`PlusGlyph`) while it is compact, to open it. It is the same element in both shapes and never moves, so focus stays on it across a fold. It keeps its names ("Collapse the sidebar" and "Expand the sidebar", or `railFoldLabels`), `aria-controls`, `aria-keyshortcuts` and the keys in its tooltip, and now says `aria-expanded` (true while the rail is full). It stands at the target floor (`--size-target-min`, 24px) at every density, its ring is drawn inside its own box, and it is quiet until the rail is pointed at. Full, the search field keeps the nav's own columns, since nothing stands before it any more. Props are unchanged.
213
+
214
+ **The rail eases between its two shapes.** Its width moves on the slow step with the emphasized curve, the motion a `DockColumn` opens by, and what it holds keeps the width of the shape drawn, so the moving edge clips the rail's words rather than squeezing or rewrapping them, and the column under the edge never drifts. Folding, the full rail's middle, foot and status stay drawn and inert while its words fade out (focus inside them goes to the rail's first live control: the fold control, or the brand's link in the head, which stays live; with neither, the folded rail's first control once it is drawn), then the compact column fades in once the rail has moved; unfolding, the full rail is drawn at once and fades in while the edge uncovers it. The brand's mark and the fold control do not move or fade. Both shapes are a `usePresence` each, so the rail waits on the motion actually running on it, as a `DockColumn` does. `useAppShell().rail` reports the shape drawn, so it stays `full` until a fold has moved; the root's `data-rail-motion` (`fold`, `folded`, `unfold`, and `reverse` for a fold pressed again mid way, type `AppShellRailMotion`) names the phase under way. The words leave by a transition of their opacity, so a reversal brings them back from wherever their fade had reached rather than blinking them out and in; `usePresence` reports such a return as `returning`. Under reduced motion, and wherever nothing moves, the new shape is drawn at once. A change that arrives with the window crossing into the wide layout is drawn at once too. The rail's grid track is now `auto` and the rail takes `--crewlet-app-shell-rail` as its own width, which is still the one variable a host sets for a narrower rail. An aside column capped by the page's floor (`asideReserve`) now takes what the grid leaves it beside the rail's LIVE width, so it widens and narrows with the rail frame by frame, where a cap computed from the rail's variable jumped at both ends of a fold (story: `AppShellAside` Cap Follows A Folding Rail). While the rail moves the shell holds what it measures (the screen's width that `useScreenWidth` and `useScreenBelow` read, the scroller's gutter, the aside's width) and takes each once when the rail comes to rest, so no screen re-renders on every frame of a fold or changes shape mid way; a container query on the content column still follows every frame.
215
+
216
+ **In the compact rail the status has a row of its own under the brand's mark**, where the fold chevron stood, rather than at the top of the foot: the `AppShell.RailStatus` dot and count, centred, a small control step tall, before the places. It keeps its button, its name ("Engine serving, 2 alarms"), its popup attributes and its ref. A panel it opens now stands at the top of the rail, so open it below the status (`side="bottom"`) in both shapes. Full, it stays at the end of the head's line.
217
+
218
+ **The compact account face is centred on the tiles' line.** It took the full row's badge column and the step after it, which stood the face 4px left of the column's centre in a box 8px wider than the face. It now sits in a box of its own size, centred under the tiles. Hand the face at the tiles' height in the compact rail (`Avatar size="sm"`, 26px); the full row keeps `size="md"`.
219
+
220
+ **A place that waits on the reader takes the badge, whichever place it is.** `NavItem` and `CompactNavItem` draw a `badge` as the one filled accent pill, centred on the row's line and ending on the row's end inset, so a column of badges lines up down the rail; a `count` is the quiet figure. Nothing changed in how either is drawn: to show the reader's own work as the inbox is shown, pass `badge` rather than `count`. New stories: `AppShell` Fold Control In Both Shapes, `SidebarNav` Badges On The Rows About You, and `DockColumn` (Pinned Beside A Conversation, Unpinned, At The End).
221
+
222
+ ### Columns that ease open and shut
223
+
224
+ **`usePresence` is new**: something kept drawn while it leaves. `usePresence(shown, ref, { transitions, animations, instant })` answers `present` (draw it), `leaving` (drawn only to finish leaving: make it `inert`) and `entering` (shown again, never on the first draw, while its motion runs: the window a stylesheet scopes an entrance to). It waits only for the surface's OWN motion (`MotionOwnership`), as it is actually running (`getAnimations()`), never for a duration written in code: the transitions on `ref`'s element itself (by property; any, if `transitions` is left out) and the keyframes it names in `animations`, wherever they run under it. A motion something else inside it runs (a meter filling, a badge arriving), a paused one and an endless one (a pulse) are never waited for, a motion replaced mid way is waited out in its turn, a reopen on the way out cancels the wait, and no wait outlasts the motion's own remaining time and a margin (the fast step), so a tab hidden mid motion still settles. Under `prefers-reduced-motion: reduce`, where nothing runs, where the Web Animations API is missing, and for a change the host marks `instant`, it goes straight through in the same commit, before any paint. `afterMotion(element, done, owned)` and `runningMotion(element, owned)` are the same wait for a host with its own state, `tokenMs(motion.duration.fast)` turns a motion token into milliseconds (Tooltip and CompactNav each kept a copy), `releaseFocus(container, target)` takes focus out of something about to turn inert (to the host's `target`, or off it). The reader's motion preference is now asked through one spelling of the query, **`REDUCED_MOTION_QUERY`**, with **`prefersReducedMotion(view)`** for a read outside render, both beside `useMediaMatch`; `ChatThread`, `Outline`, `useReorder` and `TreeCanvas` use them where each kept a copy of the string. The ui-tests helper `apps/ui-tests/src/motion.ts` (`driveMotion`, `settleMotion`, `preferReducedMotion`) starts and ends motion by hand in jsdom.
225
+
226
+ **`DockColumn` is new**: a column a host docks beside its content and takes away again, such as a list of rooms pinned beside a conversation. It stands in the host's own `auto` grid track (or as a flex item that does not grow) and eases its width between none and its panel's (`width`, px or any length) on the slow step with the emphasized curve, so the content beside it resizes frame by frame rather than jumping. The panel keeps its own width and is held to the edge that faces the content, so it slides in from the outer edge, and on close it stays drawn and `inert` until the column has closed over it; opened again on the way out, it is live where it is. Closed from inside (an Unpin in its own head), focus goes to `focusOnClose`, the control that docks it again, and is never left in the panel. `side` (`start`, the default, or `end`) places it, `divider` (on by default) draws the hairline on the edge that faces the content, and `--crewlet-dock-column-ground` gives the panel a ground. It is a plain column, not a landmark: what it holds names itself. Under reduced motion it simply is or is not. Types: `DockColumnProps`, `DockColumnSide`.
227
+
228
+ ### React
229
+
230
+ **The package asks for React 19** (`react` and `react-dom` `>=19`, was `>=18`). The components already used what React 19 brought, `inert` as a boolean prop and `ref` as a plain prop of a function component and of an element (`ArrangeFrame`, `Tooltip`, `ListInput`, and now `DockColumn`, the folding rail and `Popover`), and under React 18 neither fails loudly: `inert` is dropped with a warning, so a panel on its way out stays focusable, and a ref read from props is undefined, so a trigger's own ref is lost. Every Crewlet application is on React 19. A suite holds the peer range to the source.
231
+
232
+ ### Refs
233
+
234
+ **A trigger keeps its own ref across re-renders.** `Tooltip` cloned its trigger with a new ref callback on every render, so React took the element away from the trigger's own ref and gave it back in each commit, and a layout effect earlier in the tree read null while the control stood in the document (a `DockColumn` handing focus to a tooltip-wrapped Pin control as it closed). `Tooltip`, `Popover`, `Menu`'s trigger props and `Modal`'s frame now join their refs with **`useComposedRef(...refs)`** (new, with **`composeRefs`** for code outside a component and **`attachRef`** for one ref), one callback for any number of refs that is the same callback while they are the same and releases each the way React would. `Popover` also keeps the ref its trigger carried, which it used to replace.
235
+
208
236
  ## Changes in 0.82.0
209
237
 
210
238
  ### A conversation's messages
@@ -13,6 +13,9 @@ export interface AccountRowProps {
13
13
  /**
14
14
  * The reader's badge, drawn decorative: the name beside it says who it is.
15
15
  * In a rail's foot the row is sized for a medium one (`size="md"`, 32px).
16
+ * In the compact rail the face stands among the compact places' tiles and
17
+ * takes their height, a small one (`size="sm"`, 26px), centred in the
18
+ * column as each tile is.
16
19
  */
17
20
  avatar: ReactNode;
18
21
  /** Who the reader is. */
@@ -73,6 +76,8 @@ export interface AccountRowProps {
73
76
  * IN THE COMPACT RAIL THE ROW IS THE READER'S FACE (`compact`): the same link
74
77
  * or menu button, holding the badge alone, named by the name and the detail
75
78
  * as the full row is, and showing them in a tooltip, since a face says who
76
- * it is only to somebody who already knows.
79
+ * it is only to somebody who already knows. The face is centred in the
80
+ * column on the line the tiles above it are centred on, and at their height
81
+ * when it is handed at the small step.
77
82
  */
78
83
  export declare function AccountRow({ avatar, name, detail, href, menu, current, title, linkSuffix, actions, compact: compactProp, className, }: AccountRowProps): import("react").JSX.Element;
@@ -63,6 +63,7 @@ import { type AppShellRailShape } from './railShape.js';
63
63
  export { useAppShellAside, useAppShellPeek } from './regions.js';
64
64
  export type { AppShellAsideShape, AppShellPeekShape, AppShellRegionValue } from './regions.js';
65
65
  export type { AppShellRailShape } from './railShape.js';
66
+ export type { AppShellRailMotion } from './railMotion.js';
66
67
  /** The aside's resting width, in px, where the host names none. */
67
68
  export declare const APP_SHELL_ASIDE_WIDTH = 420;
68
69
  /** How the reader resizes the aside while it is a column. */
@@ -97,6 +98,8 @@ interface AppShellContextValue {
97
98
  * The shape the rail is drawn in NOW: `compact` only where the host asked
98
99
  * for it and the layout is wide, `full` in the drawer and everywhere else,
99
100
  * so an application picks `CompactNav` or `SidebarNav` from this alone.
101
+ * While the rail folds it is still `full`, and it turns `compact` when the
102
+ * rail reaches the compact column (see `railMotion.ts`).
100
103
  */
101
104
  rail: AppShellRailShape;
102
105
  }
@@ -159,8 +162,10 @@ export interface AppShellProps extends Omit<HTMLAttributes<HTMLDivElement>, 'tit
159
162
  rail?: AppShellRailShape | undefined;
160
163
  /**
161
164
  * Called with the other shape when the reader presses the fold control.
162
- * Given, the shell draws THE fold control (never in the drawer); keeping the
163
- * choice, and binding a key to it, are the application's.
165
+ * Given, the shell draws THE fold control (never in the drawer): a minus in
166
+ * the rail's top left corner while it is full, and a plus in the same place
167
+ * while it is compact. Keeping the choice, and binding a key to it, are the
168
+ * application's.
164
169
  */
165
170
  onRailChange?: ((next: AppShellRailShape) => void) | undefined;
166
171
  /**
@@ -248,7 +253,8 @@ export interface AppShellRailProps {
248
253
  * A compact status at the end of the head's line, beside the name the head
249
254
  * carries: an `<AppShell.RailStatus>`, the application's own state in a
250
255
  * dot and a count. It takes its own width, so the name keeps the rest and
251
- * truncates there, and it stands in the drawer's head the same way.
256
+ * truncates there, and it stands in the drawer's head the same way. In the
257
+ * compact rail it has a row of its own under the head's mark.
252
258
  */
253
259
  status?: ReactNode;
254
260
  /**
@@ -268,9 +274,12 @@ export interface AppShellRailProps {
268
274
  * alone (the lockup shows its mark, over the column's centre, and keeps its
269
275
  * name as the link's name and title); the field is not drawn, because a
270
276
  * 76px column has no room for one and the application draws a Search tile
271
- * among its `CompactNav` places instead; and the status stands at the top of
272
- * the foot as its dot and count, since the head has no line left beside the
273
- * mark. The middle and the foot are drawn as the application gives them.
277
+ * among its `CompactNav` places instead; and the status stands in a row of
278
+ * its own under the mark, as its dot and count, since the head has no line
279
+ * left beside the mark. That row is the first thing under the head in the
280
+ * column, before the places, so the state a reader checks at a glance is
281
+ * where their eye starts. The middle and the foot are drawn as the
282
+ * application gives them.
274
283
  */
275
284
  export declare function AppShellRail({ header, search, status, footer, className, children }: AppShellRailProps): import("react").JSX.Element;
276
285
  /**
@@ -9,4 +9,4 @@ export { useScreenBelow, useScreenWidth } from './screenWidth.js';
9
9
  export type { StoredWidth, StoredWidthOptions, WidthStorage } from './storedWidth.js';
10
10
  export { AccountRow } from './AccountRow.js';
11
11
  export type { AccountRowMenu, AccountRowProps } from './AccountRow.js';
12
- export type { ActionRailRowProps, ActionRailStatusProps, AppShellAsideResize, AppShellAsideShape, AppShellContextValue, AppShellPeekShape, AppShellProps, AppShellRailShape, AppShellRailProps, AppShellRailRowProps, AppShellRailStatusProps, AppShellRegionValue, AppShellToggleProps, AppShellTopbarProps, RailRowCount, StaticRailRowProps, StaticRailStatusProps, } from './AppShell.js';
12
+ export type { ActionRailRowProps, ActionRailStatusProps, AppShellAsideResize, AppShellAsideShape, AppShellContextValue, AppShellPeekShape, AppShellProps, AppShellRailMotion, AppShellRailShape, AppShellRailProps, AppShellRailRowProps, AppShellRailStatusProps, AppShellRegionValue, AppShellToggleProps, AppShellTopbarProps, RailRowCount, StaticRailRowProps, StaticRailStatusProps, } from './AppShell.js';
@@ -1,8 +1,11 @@
1
- export { APP_SHELL_ASIDE_WIDTH, AccountRow, AppShell, AppShellRail, AppShellRailRow, AppShellRailStatus, AppShellToggle, AppShellTopbar, readStoredWidth, useAppShell, useScreenBelow, useScreenWidth, useStoredWidth } from '../chunk-T4IEESXN.js';
2
- import '../chunk-RTPQDNW3.js';
3
- import '../chunk-ISQANI6Q.js';
4
- import '../chunk-3QQIGMY3.js';
5
- import '../chunk-YOJAGKTS.js';
1
+ export { APP_SHELL_ASIDE_WIDTH, AccountRow, AppShell, AppShellRail, AppShellRailRow, AppShellRailStatus, AppShellToggle, AppShellTopbar, readStoredWidth, useAppShell, useScreenBelow, useScreenWidth, useStoredWidth } from '../chunk-PGBKZSSQ.js';
2
+ import '../chunk-PCAT2EFB.js';
3
+ import '../chunk-JLOESTT2.js';
4
+ import '../chunk-YJQXESOJ.js';
5
+ import '../chunk-7ZSEUO5Q.js';
6
+ import '../chunk-HTS5RJ7S.js';
7
+ import '../chunk-TGGYSQRD.js';
8
+ import '../chunk-L72URIHR.js';
6
9
  export { RESIZE_HANDLE_LARGE_STEP, RESIZE_HANDLE_STEP, ResizeHandle, clampSize, useAppShellAside, useAppShellPeek } from '../chunk-PIYJNCN7.js';
7
10
  import '../chunk-CMAZZY2I.js';
8
11
  import '../chunk-DGXZ635L.js';
@@ -0,0 +1,60 @@
1
+ /**
2
+ * How the rail moves between its two shapes.
3
+ *
4
+ * THE STYLESHEET MOVES IT, THIS DECIDES THE ORDER. The rail's width eases
5
+ * between the full rail and the compact column (AppShell.css), and its
6
+ * content is laid out at the width of the shape drawn, clipped by the moving
7
+ * edge, so nothing in it rewraps at a width it will never rest at. What the
8
+ * stylesheet cannot decide is WHEN the content changes shape, because the
9
+ * application draws a different tree for each one:
10
+ *
11
+ * - UNFOLDING, the full rail is drawn at once, and the moving edge uncovers
12
+ * it while its words fade in (`unfold`).
13
+ * - FOLDING, the full rail stays drawn, inert, while the edge narrows over it
14
+ * and its words fade out (`fold`), and the compact column is drawn once the
15
+ * rail's motion has ended, fading in (`folded`). Drawn at once instead, the
16
+ * column would replace the words before the reader saw them go.
17
+ *
18
+ * ONE MECHANISM FOR EVERY COLUMN THAT EASES. Both shapes are a `usePresence`
19
+ * each, waiting on the motion actually running on the rail, as a
20
+ * `DockColumn` waits on its own: no duration is written again here, nothing
21
+ * waits under reduced motion, and where nothing moves the new shape is drawn
22
+ * in the same commit, before any paint.
23
+ */
24
+ import { type RefObject } from 'react';
25
+ import type { AppShellRailShape } from './railShape.js';
26
+ /**
27
+ * Where a change of shape is: `fold` while the rail narrows over the full
28
+ * rail's fading words, `folded` while the compact column fades in after it,
29
+ * `unfold` while the rail widens and the full rail's words fade in, and
30
+ * `reverse` while a fold pressed again mid way widens the rail back and its
31
+ * words return from wherever their fade had reached.
32
+ */
33
+ export type AppShellRailMotion = 'fold' | 'folded' | 'unfold' | 'reverse';
34
+ /**
35
+ * The rail's own motion, which a change of shape waits for: its width, on the
36
+ * rail itself, and the keyframes its words arrive by (AppShell.css), wherever
37
+ * they run inside it. Named, so that nothing else moving inside the rail (a
38
+ * meter filling, a badge arriving, a paused animation) holds a fold. The
39
+ * words LEAVE by a transition of their opacity, which a reversal turns back
40
+ * from where it is, and the rail's width outlasts it.
41
+ */
42
+ export declare const RAIL_MOTION: {
43
+ readonly transitions: readonly ["width"];
44
+ readonly animations: readonly ["crewlet-app-shell-rail-unfold", "crewlet-app-shell-rail-settle"];
45
+ };
46
+ /**
47
+ * The shape to draw the rail's content in, the phase of the change under
48
+ * way, and whether the content drawn is only leaving (and so inert), for a
49
+ * rail whose chosen shape is `target`.
50
+ *
51
+ * `moves` is whether a change may animate at all: never in the drawer, where
52
+ * the rail is always the full list and a shape is not a width. A change that
53
+ * arrives WITH the window crossing into the wide layout does not animate
54
+ * either: the reader resized a window, they did not fold a rail.
55
+ */
56
+ export declare function useRailMotion(target: AppShellRailShape, moves: boolean, rail: RefObject<HTMLElement | null>): {
57
+ drawn: AppShellRailShape;
58
+ motion: AppShellRailMotion | null;
59
+ leaving: boolean;
60
+ };
@@ -15,3 +15,8 @@ export type AppShellRailShape = 'full' | 'compact';
15
15
  export declare const RailShapeContext: import("react").Context<AppShellRailShape>;
16
16
  /** The shape the rail around this component is drawn in now: `full` outside a shell, and in the drawer. */
17
17
  export declare function useRailShape(): AppShellRailShape;
18
+ /**
19
+ * Whether the rail's content is drawn only to finish leaving, while the rail
20
+ * folds over it (railMotion.ts): `AppShell.Rail` makes it inert then.
21
+ */
22
+ export declare const RailLeavingContext: import("react").Context<boolean>;
@@ -27,30 +27,40 @@
27
27
  --crewlet-app-shell-rail: var(--size-shell-rail);
28
28
  --crewlet-app-shell-topbar: var(--size-shell-topbar);
29
29
  /* What stands on the frame to the sheet's left: the rail's column, or
30
- nothing where there is no rail or the rail is a drawer. The aside's cap
31
- below subtracts it, so it is one name for both. */
30
+ nothing where there is no rail or the rail is a drawer. */
32
31
  --crewlet-app-shell-beside: var(--crewlet-app-shell-rail);
33
- /* THE ASIDE'S TRACK, while it is a column: the panel's width and the inset
34
- it is held off the window's edge by, capped so the sheet keeps the
35
- host's floor (`--crewlet-app-shell-aside-reserve`, the page's sheet with
36
- its own inset and hairlines). The host publishes both widths on this
37
- element; with no reserve the panel takes the width it was given. */
38
- --crewlet-app-shell-aside-track: calc(
39
- min(
40
- var(--crewlet-app-shell-aside),
41
- max(
42
- 0px,
43
- 100% - var(--crewlet-app-shell-beside) - var(--crewlet-app-shell-aside-reserve, 0px) - var(--size-shell-inset)
44
- )
45
- ) +
46
- var(--size-shell-inset)
32
+ /*
33
+ * THE ASIDE'S TRACK, while it is a column: the inset it is held off the
34
+ * window's edge by at least, and the panel's width and that inset at most.
35
+ * THE CAP IS THE GRID'S. The page's sheet takes the host's floor as its
36
+ * own track's minimum (`--crewlet-app-shell-aside-reserve`, the page's sheet
37
+ * with its own inset and hairlines), and the grid hands the aside what is
38
+ * left once the rail and that floor have theirs, up to its width. The rail's
39
+ * track is the rail's live width, so while the rail eases between its
40
+ * shapes the cap eases with it: a cap computed from the rail's VARIABLE
41
+ * named the shape drawn, and jumped at both ends of a fold. With no reserve
42
+ * the panel takes the width it was given, as far as the window holds it.
43
+ */
44
+ --crewlet-app-shell-aside-track: minmax(
45
+ var(--size-shell-inset),
46
+ calc(var(--crewlet-app-shell-aside) + var(--size-shell-inset))
47
+ );
48
+ /* The page's floor beside an aside column, never more than the window
49
+ leaves it: on a window too narrow for the floor, the page gives way rather
50
+ than the shell growing past the window's edge. */
51
+ --crewlet-app-shell-sheet-floor: min(
52
+ var(--crewlet-app-shell-aside-reserve, 0px),
53
+ max(0px, 100% - var(--crewlet-app-shell-beside) - var(--size-shell-inset))
47
54
  );
48
55
  /* Where the drawer's veil sits while it is open. The shell replaces it with
49
56
  the surface's own place in the layer band; this default only has to clear
50
57
  the page chrome for the moment before that lands. */
51
58
  --crewlet-app-shell-drawer-z: var(--z-index-overlay);
52
59
  display: grid;
53
- grid-template-columns: var(--crewlet-app-shell-rail) minmax(0, 1fr);
60
+ /* The rail's track is the rail's own width (`auto`), and the rail takes
61
+ `--crewlet-app-shell-rail` itself, so the track follows it while it eases
62
+ between its two shapes (see the rail's motion, below). */
63
+ grid-template-columns: auto minmax(0, 1fr);
54
64
  /* One row, the viewport's height less nothing: the sheet's own margin is
55
65
  what holds it off the frame's edges, and a row sized by its content would
56
66
  let a tall screen push the sheet's bottom edge off the window. */
@@ -89,11 +99,11 @@
89
99
  keeps its column and is only narrower, so nothing under the bar moves but
90
100
  its end edge. */
91
101
  .crewlet-app-shell[data-aside='column'] {
92
- grid-template-columns: var(--crewlet-app-shell-rail) minmax(0, 1fr) var(--crewlet-app-shell-aside-track);
102
+ grid-template-columns: auto minmax(var(--crewlet-app-shell-sheet-floor), 1fr) var(--crewlet-app-shell-aside-track);
93
103
  }
94
104
 
95
105
  .crewlet-app-shell--no-rail[data-aside='column'] {
96
- grid-template-columns: minmax(0, 1fr) var(--crewlet-app-shell-aside-track);
106
+ grid-template-columns: minmax(var(--crewlet-app-shell-sheet-floor), 1fr) var(--crewlet-app-shell-aside-track);
97
107
  }
98
108
 
99
109
  /* The skip link, drawn only while it holds focus, over everything. */
@@ -139,14 +149,25 @@
139
149
  position: relative;
140
150
  display: flex;
141
151
  flex-direction: column;
152
+ width: var(--crewlet-app-shell-rail);
142
153
  min-height: 0;
143
154
  min-width: 0;
155
+ /* THE MOVING EDGE CUTS WHAT IT PASSES. While the rail eases between its
156
+ shapes its content keeps the width of the shape drawn (below), and the
157
+ edge clips it rather than squeezing it. Across only: a ring or a badge
158
+ at a row's top or bottom is never cut. */
159
+ overflow-x: clip;
144
160
  background: var(--color-surface-frame);
161
+ transition: width var(--motion-duration-slow) var(--motion-easing-emphasized);
145
162
  }
146
163
 
164
+ /* THE CONTENT IS LAID OUT AT ITS SHAPE'S WIDTH, never at a width between the
165
+ two, so no word in the rail rewraps while it moves and nothing drifts with
166
+ the edge: the column stands still and the edge travels over it. */
147
167
  .crewlet-app-shell__rail-inner {
148
168
  display: flex;
149
169
  flex-direction: column;
170
+ width: var(--crewlet-app-shell-rail);
150
171
  min-height: 0;
151
172
  height: 100%;
152
173
  }
@@ -890,7 +911,7 @@
890
911
  }
891
912
 
892
913
  /*
893
- * THE COMPACT RAIL: the same track, narrowed to the compact column. One
914
+ * THE COMPACT RAIL: the same rail, narrowed to the compact column. One
894
915
  * variable is the rail's width for the grid, the aside's cap and the drawer
895
916
  * alike, so folding the rail is this one declaration. The shell writes the
896
917
  * attribute only where the layout is wide: the drawer under the step is
@@ -901,21 +922,29 @@
901
922
  }
902
923
 
903
924
  /*
904
- * THE FOLD CONTROL stands over the compact column's centre, in the row under
905
- * the head, in both shapes, so it never moves under the pointer that pressed
906
- * it. Quiet until the rail is pointed at: the tertiary ink, which holds 3:1
907
- * on the frame, then the secondary, and the ghost's own primary under the
908
- * pointer.
925
+ * THE FOLD CONTROL stands in the rail's top left corner, in both shapes, so
926
+ * it never moves under the pointer that pressed it: a minus while the rail is
927
+ * full and a plus while it is compact. The corner is the square the head
928
+ * leaves empty up and to the left of the brand's mark, and the control is the
929
+ * target floor (`--size-target-min`), so it ends short of the mark on the
930
+ * compact column's centre at every density.
931
+ *
932
+ * Quiet until the rail is pointed at: the tertiary ink, which holds 3:1 on
933
+ * the frame, then the secondary, and the ghost's own primary under the
934
+ * pointer. Its ring is drawn inside its own box, because the corner it
935
+ * stands in is the window's, and a ring outside it would be cut there.
909
936
  */
910
937
  .crewlet-app-shell__fold {
911
938
  position: absolute;
912
- top: calc(var(--size-shell-inset) + var(--crewlet-app-shell-topbar));
913
- left: calc((var(--size-shell-rail-compact) - var(--size-control-sm)) / 2);
939
+ top: 0;
940
+ left: 0;
914
941
  z-index: 1;
915
942
  display: inline-flex;
916
943
  }
917
944
 
918
945
  .crewlet-app-shell__fold > .crewlet-icon-btn {
946
+ width: var(--size-target-min);
947
+ height: var(--size-target-min);
919
948
  color: var(--color-text-tertiary);
920
949
  }
921
950
 
@@ -923,6 +952,10 @@
923
952
  color: var(--color-text-secondary);
924
953
  }
925
954
 
955
+ .crewlet-app-shell__fold > .crewlet-icon-btn:focus-visible {
956
+ outline-offset: var(--size-focus-ring-inset-offset);
957
+ }
958
+
926
959
  /*
927
960
  * THE MARK STANDS WHERE THE COMPACT RAIL'S DOES, in both shapes: centred over
928
961
  * the compact column, in the head. Full, the name follows it; compact, the
@@ -939,30 +972,16 @@
939
972
  }
940
973
 
941
974
  /*
942
- * FULL, THE FIELD STARTS AFTER THE FOLD CONTROL, a step off it, on the row
943
- * the control stands in. The field holds its place at the top of the rail's
944
- * middle while the rows scroll under it, on the frame's own ground, so the
945
- * control beside it is always beside it.
975
+ * COMPACT, THE STATUS HAS A ROW OF ITS OWN under the mark, a small control
976
+ * step tall, its dot and its count centred in the column: the first thing
977
+ * under the head, before the places, where the fold control stood before it
978
+ * moved to the corner.
946
979
  */
947
- /* The middle is a stacking context of its own, so the field pinned in it
948
- stands over the rows scrolling under it and the whole middle stands under
949
- the fold control, which is painted a step above the rail. */
950
- .crewlet-app-shell--foldable .crewlet-app-shell__rail-body {
951
- isolation: isolate;
952
- }
953
-
954
- .crewlet-app-shell--foldable[data-rail='full'] .crewlet-app-shell__rail-search {
955
- position: sticky;
956
- top: 0;
957
- z-index: 1;
958
- padding-left: calc((var(--size-shell-rail-compact) + var(--size-control-sm)) / 2 + var(--spacing-2));
959
- background: var(--color-surface-frame);
960
- }
961
-
962
- /* COMPACT, THE FOLD CONTROL HAS A ROW OF ITS OWN under the mark, which the
963
- head leaves room for, and the column of tiles starts under it. */
964
- .crewlet-app-shell--foldable[data-rail='compact'] .crewlet-app-shell__rail-head {
965
- margin-bottom: var(--size-control-sm);
980
+ .crewlet-app-shell[data-rail='compact'] .crewlet-app-shell__rail-inner > .crewlet-app-shell__rail-status {
981
+ justify-content: center;
982
+ min-width: 0;
983
+ min-height: var(--size-control-sm);
984
+ margin: 0;
966
985
  }
967
986
 
968
987
  .crewlet-app-shell[data-rail='compact'] .crewlet-app-shell__rail-body {
@@ -972,7 +991,7 @@
972
991
 
973
992
  /*
974
993
  * The compact foot: what the full foot holds, centred in the column, a step
975
- * apart: the status's dot, a Settings tile, the reader's face.
994
+ * apart: a Settings tile, the reader's face.
976
995
  */
977
996
  .crewlet-app-shell[data-rail='compact'] .crewlet-app-shell__rail-foot {
978
997
  align-items: center;
@@ -984,10 +1003,85 @@
984
1003
  align-self: stretch;
985
1004
  }
986
1005
 
987
- .crewlet-app-shell[data-rail='compact'] .crewlet-app-shell__rail-foot > .crewlet-app-shell__rail-status {
988
- justify-content: center;
989
- min-width: 0;
990
- margin: 0;
1006
+ /*
1007
+ * THE COMPACT FACE IS CENTRED ON THE TILES' LINE. It gives up the full row's
1008
+ * badge column and the step after it (above): kept, the step stood the face
1009
+ * 4px left of the column's centre, in a box 8px wider than the face, so the
1010
+ * face sat off the line every tile above it is centred on.
1011
+ */
1012
+ .crewlet-app-shell__rail-foot .crewlet-account-row--compact .crewlet-account-row__avatar {
1013
+ width: auto;
1014
+ margin-inline-end: 0;
1015
+ }
1016
+
1017
+ /*
1018
+ * THE RAIL'S MOTION (railMotion.ts). The rail's width eases between the two
1019
+ * shapes on the slow step with the emphasized curve, the motion a
1020
+ * `DockColumn` opens and closes by, so a column of the frame and a column of
1021
+ * a screen move as one. What the rail holds keeps the width of the shape
1022
+ * drawn, so the moving edge clips the words rather than squeezing them.
1023
+ *
1024
+ * FOLDING, the full rail stays drawn, inert, while the edge narrows to the
1025
+ * compact column, and its words fade out on the base step; the compact column
1026
+ * is drawn when the rail's motion has ended, and fades in on the fast step.
1027
+ * UNFOLDING, the full rail is drawn at once and fades in while the edge
1028
+ * uncovers it. The brand's mark and the fold control are in the same place in
1029
+ * both shapes, so neither fades.
1030
+ *
1031
+ * THE WORDS LEAVE BY A TRANSITION and arrive by keyframes. A fold takes their
1032
+ * opacity to nothing; a fold pressed again mid way (`reverse`) declares
1033
+ * nothing of its own, so the same transition takes the opacity back from
1034
+ * wherever it had reached. Faded out by keyframes instead, a reversal could
1035
+ * only start an entrance from nothing, and the words blinked out and back.
1036
+ * The transition is declared only while the rail moves, so nothing else that
1037
+ * sets these parts' opacity is eased.
1038
+ */
1039
+ .crewlet-app-shell[data-rail-motion='fold'] > .crewlet-app-shell__rail {
1040
+ width: var(--size-shell-rail-compact);
1041
+ }
1042
+
1043
+ /* Two names for one entrance, so an unfold pressed while the compact column
1044
+ is still arriving starts the full rail's entrance afresh. */
1045
+ @keyframes crewlet-app-shell-rail-unfold {
1046
+ from {
1047
+ opacity: 0;
1048
+ }
1049
+ }
1050
+
1051
+ @keyframes crewlet-app-shell-rail-settle {
1052
+ from {
1053
+ opacity: 0;
1054
+ }
1055
+ }
1056
+
1057
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-body,
1058
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-foot,
1059
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-status,
1060
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-head .crewlet-brand__name,
1061
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-head .crewlet-brand__context {
1062
+ transition: opacity var(--motion-duration-base) var(--motion-easing-out);
1063
+ }
1064
+
1065
+ .crewlet-app-shell[data-rail-motion='fold'] .crewlet-app-shell__rail-body,
1066
+ .crewlet-app-shell[data-rail-motion='fold'] .crewlet-app-shell__rail-foot,
1067
+ .crewlet-app-shell[data-rail-motion='fold'] .crewlet-app-shell__rail-status,
1068
+ .crewlet-app-shell[data-rail-motion='fold'] .crewlet-app-shell__rail-head .crewlet-brand__name,
1069
+ .crewlet-app-shell[data-rail-motion='fold'] .crewlet-app-shell__rail-head .crewlet-brand__context {
1070
+ opacity: 0;
1071
+ }
1072
+
1073
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-body,
1074
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-foot,
1075
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-status,
1076
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-head .crewlet-brand__name,
1077
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-head .crewlet-brand__context {
1078
+ animation: crewlet-app-shell-rail-unfold var(--motion-duration-slow) var(--motion-easing-out);
1079
+ }
1080
+
1081
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-body,
1082
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-foot,
1083
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-status {
1084
+ animation: crewlet-app-shell-rail-settle var(--motion-duration-fast) var(--motion-easing-out);
991
1085
  }
992
1086
 
993
1087
  @media (width < 1024px) {
@@ -1000,7 +1094,7 @@
1000
1094
  step is still a column; the rail is a drawer here and takes no track. */
1001
1095
  .crewlet-app-shell[data-aside='column'],
1002
1096
  .crewlet-app-shell--no-rail[data-aside='column'] {
1003
- grid-template-columns: minmax(0, 1fr) var(--crewlet-app-shell-aside-track);
1097
+ grid-template-columns: minmax(var(--crewlet-app-shell-sheet-floor), 1fr) var(--crewlet-app-shell-aside-track);
1004
1098
  }
1005
1099
 
1006
1100
  .crewlet-app-shell--no-rail {
@@ -1065,6 +1159,12 @@
1065
1159
  transition: transform var(--motion-duration-slow) var(--motion-easing-emphasized);
1066
1160
  }
1067
1161
 
1162
+ /* The drawer never changes shape, and on a window narrower than the rail
1163
+ it is the window's width: its content fills it rather than being cut. */
1164
+ .crewlet-app-shell__rail-inner {
1165
+ width: auto;
1166
+ }
1167
+
1068
1168
  .crewlet-app-shell__toggle {
1069
1169
  display: inline-flex;
1070
1170
  }
@@ -1099,6 +1199,27 @@
1099
1199
  .crewlet-app-shell__aside[data-shape='sheet'] {
1100
1200
  animation: none;
1101
1201
  }
1202
+
1203
+ /* Under reduced motion the shell draws the new shape at once
1204
+ (`usePresence`), so no phase starts; these hold even if one did. */
1205
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-body,
1206
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-foot,
1207
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-status,
1208
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-head .crewlet-brand__name,
1209
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-head .crewlet-brand__context {
1210
+ transition: none;
1211
+ }
1212
+
1213
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-body,
1214
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-foot,
1215
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-status,
1216
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-head .crewlet-brand__name,
1217
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-head .crewlet-brand__context,
1218
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-body,
1219
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-foot,
1220
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-status {
1221
+ animation: none;
1222
+ }
1102
1223
  }
1103
1224
 
1104
1225
  /* ── the account row ───────────────────────────────────────────────────── */
@@ -1,7 +1,8 @@
1
- export { ArrangeList, DEFAULT_ARRANGE_LABELS } from '../chunk-WT3B76MG.js';
1
+ export { ArrangeList, DEFAULT_ARRANGE_LABELS } from '../chunk-XTJHMP3W.js';
2
2
  import '../chunk-3XDT5ZWL.js';
3
- import '../chunk-MPVMB2DV.js';
3
+ import '../chunk-BVML4UVB.js';
4
4
  import '../chunk-YQ7Q52XU.js';
5
+ import '../chunk-YJQXESOJ.js';
5
6
  import '../chunk-O7N6W52M.js';
6
7
  import '../chunk-PGCLHYVP.js';
7
8
  import '../chunk-TUEM2XIW.js';
@@ -1,13 +1,15 @@
1
- export { ARTIFACT_BAR_LABELS, ArtifactBar, ArtifactVersionChip } from '../chunk-XY4O2XMR.js';
1
+ export { ARTIFACT_BAR_LABELS, ArtifactBar, ArtifactVersionChip } from '../chunk-BXGBGYKH.js';
2
2
  import '../chunk-36WK24AI.js';
3
- import '../chunk-GZVAZ3LL.js';
4
- import '../chunk-HCUECVZ3.js';
3
+ import '../chunk-AZYE7NR4.js';
4
+ import '../chunk-MVKUE4FI.js';
5
5
  import '../chunk-EGMQURBR.js';
6
6
  import '../chunk-CYQBDZ6M.js';
7
7
  import '../chunk-AVL52EME.js';
8
8
  import '../chunk-RSKW25Y5.js';
9
- import '../chunk-3QQIGMY3.js';
10
- import '../chunk-YOJAGKTS.js';
9
+ import '../chunk-7ZSEUO5Q.js';
10
+ import '../chunk-HTS5RJ7S.js';
11
+ import '../chunk-TGGYSQRD.js';
12
+ import '../chunk-L72URIHR.js';
11
13
  import '../chunk-CMAZZY2I.js';
12
14
  import '../chunk-DGXZ635L.js';
13
15
  import '../chunk-XSPCITPN.js';
@@ -1,4 +1,4 @@
1
- export { ArtifactCard, ArtifactCardSkeleton, ArtifactPreviewGlyph } from '../chunk-2H6YDUR5.js';
1
+ export { ArtifactCard, ArtifactCardSkeleton, ArtifactPreviewGlyph } from '../chunk-QM3432PH.js';
2
2
  import '../chunk-I4IUX3JF.js';
3
3
  import '../chunk-HF5L56YQ.js';
4
4
  import '../chunk-EJNJMHQG.js';
@@ -8,8 +8,8 @@ import '../chunk-AV2DXAEL.js';
8
8
  import '../chunk-IRONPJB4.js';
9
9
  import '../chunk-XZY6S3UC.js';
10
10
  import '../chunk-ZB3E2Z4Y.js';
11
- import '../chunk-DOY3KC6I.js';
12
11
  import '../chunk-YQ7Q52XU.js';
12
+ import '../chunk-DOY3KC6I.js';
13
13
  export { ARTIFACT_KINDS, ArtifactKindGlyph } from '../chunk-RSKW25Y5.js';
14
14
  import '../chunk-O7N6W52M.js';
15
15
  import '../chunk-PGCLHYVP.js';