@crewlethq/ui 0.35.1 → 0.37.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 (176) hide show
  1. package/README.md +90 -1
  2. package/dist/AgentHandoffPanel/AgentHandoffPanel.d.ts +99 -0
  3. package/dist/AgentHandoffPanel/index.d.ts +3 -0
  4. package/dist/AgentHandoffPanel/index.js +16 -0
  5. package/dist/AgentHandoffPanel-JWSW62GU.css +151 -0
  6. package/dist/ArrangeFrame/index.js +1 -1
  7. package/dist/{ArrangeFrame-3PLZAG22.css → ArrangeFrame-QXOQTFAH.css} +22 -5
  8. package/dist/ArrangeList/index.js +4 -3
  9. package/dist/ArtifactAccess/ArtifactAccess.d.ts +40 -0
  10. package/dist/ArtifactAccess/index.d.ts +3 -0
  11. package/dist/ArtifactAccess/index.js +2 -0
  12. package/dist/ArtifactAccess-Y53ZTRFS.css +31 -0
  13. package/dist/ArtifactBar/ArtifactBar.d.ts +2 -1
  14. package/dist/ArtifactBar/index.js +2 -2
  15. package/dist/{ArtifactBar-HV5AT4RG.css → ArtifactBar-FWPBBKQ5.css} +8 -0
  16. package/dist/ArtifactCard/ArtifactCard.d.ts +1 -6
  17. package/dist/ArtifactCard/index.d.ts +2 -1
  18. package/dist/ArtifactCard/index.js +4 -3
  19. package/dist/ArtifactCover/index.js +3 -2
  20. package/dist/ArtifactKindIllustration/ArtifactKindIllustration.d.ts +16 -7
  21. package/dist/ArtifactKindIllustration/index.js +1 -1
  22. package/dist/{ArtifactKindIllustration-5FPRJQ3P.css → ArtifactKindIllustration-KLFL7KBG.css} +37 -1
  23. package/dist/ArtifactMakeRow/ArtifactMakeRow.d.ts +39 -0
  24. package/dist/ArtifactMakeRow/index.d.ts +4 -0
  25. package/dist/ArtifactMakeRow/index.js +4 -0
  26. package/dist/ArtifactMakeRow-XBA2MPSY.css +167 -0
  27. package/dist/ArtifactNameCell/ArtifactNameCell.d.ts +37 -0
  28. package/dist/ArtifactNameCell/index.d.ts +4 -0
  29. package/dist/ArtifactNameCell/index.js +4 -0
  30. package/dist/ArtifactNameCell-RTVP4LO4.css +104 -0
  31. package/dist/ArtifactPanel/ArtifactPanel.d.ts +8 -1
  32. package/dist/ArtifactPanel/index.js +1 -1
  33. package/dist/{ArtifactPanel-HW3SU7CP.css → ArtifactPanel-KKUUIPEU.css} +9 -0
  34. package/dist/AuthLayout/index.js +2 -2
  35. package/dist/AvatarPicker/index.js +2 -2
  36. package/dist/Canvas/index.js +2 -2
  37. package/dist/CanvasBoard/CanvasBoard.d.ts +27 -13
  38. package/dist/CanvasBoard/index.d.ts +1 -1
  39. package/dist/CanvasBoard/index.js +4 -4
  40. package/dist/{CanvasBoard-5NNSKY6A.css → CanvasBoard-TS4P356F.css} +13 -6
  41. package/dist/CanvasToolbar/index.js +3 -3
  42. package/dist/Card/index.js +1 -1
  43. package/dist/{Card-KJOYHDTJ.css → Card-QOVASQNU.css} +17 -12
  44. package/dist/Checkbox/index.js +3 -2
  45. package/dist/ChoiceButtons/index.js +1 -1
  46. package/dist/{ChoiceButtons-DJ5EOGUA.css → ChoiceButtons-FLIFXFFS.css} +10 -0
  47. package/dist/ChoiceList/index.js +1 -1
  48. package/dist/{ChoiceList-RBL7FNQL.css → ChoiceList-EA2W6MOS.css} +36 -5
  49. package/dist/Combobox/index.js +3 -2
  50. package/dist/CommandPalette/index.js +3 -2
  51. package/dist/CommentThread/index.js +6 -5
  52. package/dist/Composer/Composer.d.ts +4 -0
  53. package/dist/Composer/index.js +3 -2
  54. package/dist/{Composer-ABGJIAIR.css → Composer-PXITWNEK.css} +26 -15
  55. package/dist/ConfirmField/index.js +3 -2
  56. package/dist/DataTable/index.js +4 -3
  57. package/dist/DataView/index.js +7 -6
  58. package/dist/DatasetSource/DatasetSource.d.ts +4 -0
  59. package/dist/DatasetSource/index.js +1 -1
  60. package/dist/{DatasetSource-XFPZBRXL.css → DatasetSource-SMGX4PS5.css} +38 -4
  61. package/dist/DateTimePicker/index.js +2 -1
  62. package/dist/{DateTimePicker-HG2KQXQ6.css → DateTimePicker-2IVTKFV2.css} +15 -2
  63. package/dist/DocTabsEditor/index.js +3 -2
  64. package/dist/Document/Document.d.ts +15 -3
  65. package/dist/Document/index.js +2 -1
  66. package/dist/{Document-JUGCSQ4L.css → Document-YFWTWXJP.css} +34 -2
  67. package/dist/{Editor-BVQHBF7L.js → Editor-HORWMUM3.js} +2 -1
  68. package/dist/FilterChip/index.js +1 -1
  69. package/dist/{FilterChip-EZ4QMW4E.css → FilterChip-VL33P3JL.css} +5 -1
  70. package/dist/Input/index.js +2 -1
  71. package/dist/{Input-GBZSFXLU.css → Input-ABGOFENS.css} +46 -10
  72. package/dist/LayersList/index.js +1 -1
  73. package/dist/{LayersList-NQZEIPZB.css → LayersList-TBNF4XGL.css} +16 -3
  74. package/dist/LinkInterstitial/index.js +2 -2
  75. package/dist/ListInput/index.js +3 -2
  76. package/dist/LivePreview/LivePreview.d.ts +120 -28
  77. package/dist/LivePreview/budget.d.ts +64 -20
  78. package/dist/LivePreview/index.d.ts +6 -4
  79. package/dist/LivePreview/index.js +1 -1
  80. package/dist/LivePreview/stills.d.ts +57 -0
  81. package/dist/LivePreview-BROGKR4N.css +113 -0
  82. package/dist/PresenterView/index.js +2 -2
  83. package/dist/PrincipalPicker/index.js +4 -3
  84. package/dist/RichEditor/index.js +1 -1
  85. package/dist/Select/index.js +2 -1
  86. package/dist/{Select-A54YS5EP.css → Select-W3CHTZXP.css} +18 -2
  87. package/dist/ShareDialog/index.js +3 -2
  88. package/dist/SheetColumnEditor/index.js +6 -5
  89. package/dist/SheetGrid/index.js +3 -3
  90. package/dist/SlideCompare/index.js +2 -2
  91. package/dist/SlideFilmstrip/index.js +2 -2
  92. package/dist/{SlideFilmstrip-4ITZLMO4.css → SlideFilmstrip-PAT7P4OG.css} +26 -7
  93. package/dist/SlideGrid/index.js +2 -2
  94. package/dist/{SlideGrid-S4LTJ4UU.css → SlideGrid-FJA33DV4.css} +11 -1
  95. package/dist/SlideStage/index.js +1 -1
  96. package/dist/{SlideStage-S2FISF4C.css → SlideStage-ZTTEQSS2.css} +4 -2
  97. package/dist/SourceEditor/index.js +2 -1
  98. package/dist/{SourceEditor-G2C3STPX.css → SourceEditor-QAYE2JS6.css} +19 -12
  99. package/dist/Switcher/index.js +4 -3
  100. package/dist/TagsInput/index.js +2 -1
  101. package/dist/{TagsInput-XMXTI5Q4.css → TagsInput-7EGBBXHS.css} +7 -1
  102. package/dist/ThemeGallery/index.js +1 -1
  103. package/dist/{ThemeGallery-HSUKBDWY.css → ThemeGallery-X35Y25EX.css} +26 -5
  104. package/dist/TimeWindowPicker/index.js +4 -3
  105. package/dist/{TimeWindowPicker-T763GLXH.css → TimeWindowPicker-DEFDV77Z.css} +15 -2
  106. package/dist/TreeCanvas/index.js +3 -3
  107. package/dist/VersionTimeline/index.js +2 -2
  108. package/dist/{chunk-V43UVX4H.js → chunk-27GD7LVR.js} +1 -1
  109. package/dist/{chunk-6JVRY5DQ.js → chunk-44WJLPQS.js} +2 -2
  110. package/dist/{chunk-ONL54WMH.js → chunk-46RL3E54.js} +1 -1
  111. package/dist/{chunk-UHJQDFKQ.js → chunk-4ZJLOKSS.js} +1 -1
  112. package/dist/{chunk-ACA27MZH.js → chunk-5QXRI35B.js} +1 -1
  113. package/dist/{chunk-LL5AFXU7.js → chunk-5RT5O4JR.js} +1 -1
  114. package/dist/{chunk-GMU6SQ6B.js → chunk-66NGUD5S.js} +2 -2
  115. package/dist/{chunk-3Y56GQPM.js → chunk-7VAUGG6B.js} +1 -1
  116. package/dist/{chunk-2CQLNML5.js → chunk-AOLCZDZ6.js} +3 -1
  117. package/dist/{chunk-NKZCJRKO.js → chunk-APDKUGSH.js} +2 -2
  118. package/dist/chunk-BGLKLXL3.js +29 -0
  119. package/dist/{chunk-Z6VW6CXX.js → chunk-BIQDJOJZ.js} +1 -1
  120. package/dist/{chunk-YSJC7AZC.js → chunk-BWOIUOO3.js} +1 -1
  121. package/dist/{chunk-PI7HKLIT.js → chunk-D7GNNID2.js} +3 -1
  122. package/dist/chunk-EAKC24BW.js +51 -0
  123. package/dist/{chunk-CCLNGVCM.js → chunk-EARDAJQY.js} +1 -1
  124. package/dist/chunk-EOQFPZEE.js +138 -0
  125. package/dist/{chunk-THROPJZC.js → chunk-F23N4MVU.js} +1 -1
  126. package/dist/{chunk-J6YZ4IYV.js → chunk-FG4O64DV.js} +3 -3
  127. package/dist/{chunk-E35CMI5D.js → chunk-FHHYXZSP.js} +31 -13
  128. package/dist/{chunk-AYB6AYNH.js → chunk-GMLAKNFY.js} +1 -1
  129. package/dist/{chunk-ZB5O3ELS.js → chunk-GRYZ5EP3.js} +4 -2
  130. package/dist/{chunk-QFNWMWWY.js → chunk-GS7ZTHPF.js} +4 -4
  131. package/dist/{chunk-ILAEBSLJ.js → chunk-H5NOLRGH.js} +2 -2
  132. package/dist/{chunk-W3UVOZKL.js → chunk-IPAU6FLH.js} +6 -2
  133. package/dist/{chunk-6QFAK2WV.js → chunk-IUYUS2SO.js} +4 -1
  134. package/dist/{chunk-22CQQDFW.js → chunk-JML75PGJ.js} +1 -1
  135. package/dist/{chunk-AXBRWRGV.js → chunk-JQLS3MZB.js} +1 -1
  136. package/dist/{chunk-FGYET26P.js → chunk-KJW2AS57.js} +1 -1
  137. package/dist/{chunk-QIXMNOBD.js → chunk-KYZMN6I6.js} +2 -2
  138. package/dist/{chunk-73A7D5CE.js → chunk-L4WZSVMT.js} +3 -1
  139. package/dist/{chunk-ULPL26BU.js → chunk-N5SKHIAP.js} +1 -1
  140. package/dist/{chunk-LV4APO72.js → chunk-NQGPD6NX.js} +1 -1
  141. package/dist/{chunk-7UYONN6K.js → chunk-OHA6WSAG.js} +6 -11
  142. package/dist/chunk-P5VGSVWG.js +39 -0
  143. package/dist/chunk-P6WFZDKS.js +111 -0
  144. package/dist/{chunk-CPEPST4S.js → chunk-PJIPUEJ3.js} +1 -1
  145. package/dist/{chunk-QS4ZGTEU.js → chunk-PPFX6GRK.js} +1 -1
  146. package/dist/{chunk-7DZDSSJS.js → chunk-RH2NCQBZ.js} +5 -4
  147. package/dist/{chunk-3VD3G3IL.js → chunk-T5RQGI6O.js} +1 -1
  148. package/dist/{chunk-F2KY4RLI.js → chunk-TVRBQMIX.js} +5 -3
  149. package/dist/{chunk-W7QBBKUE.js → chunk-UBZDYOCA.js} +7 -3
  150. package/dist/{chunk-QEFHYUCY.js → chunk-UWGUKMBK.js} +1 -1
  151. package/dist/{chunk-5YLON2PW.js → chunk-UYZZV4DZ.js} +1 -1
  152. package/dist/{chunk-BQ7AKL2N.js → chunk-VKKUGZ3G.js} +3 -1
  153. package/dist/{chunk-DEJHAOC5.js → chunk-WMXAX6VA.js} +1 -1
  154. package/dist/{chunk-VDPJGP4Q.js → chunk-WX2NIG4G.js} +1 -1
  155. package/dist/chunk-WYKWXRJ4.js +456 -0
  156. package/dist/{chunk-ZU3DUXD2.js → chunk-WZGYIVYH.js} +1 -1
  157. package/dist/{chunk-HUVG2FFT.js → chunk-Y5BD4MTE.js} +4 -2
  158. package/dist/chunk-YSGLEHND.js +56 -0
  159. package/dist/generated/index.d.ts +4 -0
  160. package/dist/generated/index.js +105 -100
  161. package/dist/index.js +105 -100
  162. package/dist/styles.css +1036 -163
  163. package/dist/utils/focusModality.d.ts +41 -0
  164. package/dist/utils/index.d.ts +2 -0
  165. package/dist/utils/index.js +2 -1
  166. package/package.json +3 -3
  167. package/dist/LivePreview-SRO7KHO4.css +0 -65
  168. package/dist/chunk-KF6YGL4B.js +0 -160
  169. package/dist/chunk-TYKQ33CL.js +0 -35
  170. package/dist/{chunk-3P4Y5RX6.js → chunk-4BYHAOHH.js} +1 -1
  171. package/dist/{chunk-KD2IRYCT.js → chunk-5WDXPHEW.js} +1 -1
  172. package/dist/{chunk-OSFA5ROT.js → chunk-FEJANUZK.js} +0 -0
  173. package/dist/{chunk-FJJHD73S.js → chunk-GYBDPCRC.js} +1 -1
  174. package/dist/{chunk-VHZ3AXJD.js → chunk-NQCY44B3.js} +1 -1
  175. package/dist/{chunk-3WCNHYXE.js → chunk-PNNYVN52.js} +0 -0
  176. package/dist/{chunk-FF5OZV77.js → chunk-W3HYWD63.js} +2 -2
package/README.md CHANGED
@@ -54,7 +54,7 @@ import { Button } from '@crewlethq/ui/Button'; // 8 KB of CSS, not 182 KB
54
54
  | Arranging a page | `ArrangeBoard`, `ArrangeGrid`, `ArrangeFrame` (with `useGridResize`), `ArrangeGroup`, `ArrangeList`, and the reorder hooks under them (`useReorder`, `useReorderLists`, `moveKey`) |
55
55
  | Application shell | `AppShell` with `AppShell.Rail`, `AppShell.Topbar`, `AppShell.AccountRow` and `useAppShell`, `AuthLayout`, `SidebarNav` and `NavItem`, `BrandLockup`, `SearchTrigger`, `PageHeader`, `Toolbar`, `Stack`, `Inline`, `Spacer`, `AutoGrid`, `ErrorBoundary`, `useShortcut`, `useFullscreen`, `useIdle`, `useMediaMatch` |
56
56
  | 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 |
57
- | 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) |
57
+ | 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 |
58
58
  | 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) |
59
59
  | Presence | `PresenceStack`, `PresenceRing` and `presenceHueClass`, `CursorFlag`, `LiveCursor`, `FollowBanner`, `PeopleRail` (with `peopleRailKey`), and `PresenceModel` (the roster order, one entry per person, the session hues from `PRESENCE_HUES`, with no React in it) |
60
60
  | Presentations | `SlideStage` (a slide laid out at 1920 by 1080 and scaled to its box, with `SLIDE_WIDTH` and `SLIDE_HEIGHT`), `useSlideKeys` (the keys a show and a clicker send), `SlideNav` (Previous, the position and Next, with `SLIDE_NAV_LABELS`), `SlideFilmstrip`, `SlideGrid`, `SlideCompare` (with `SLIDE_COMPARE_LABELS`), `PresenterView` (with `formatStopwatch`) |
@@ -204,6 +204,95 @@ places:
204
204
  - A surface that pans or zooms dispatches `LAYER_REPOSITION_EVENT` on its host
205
205
  when the content beneath it moves, and every panel anchored inside follows.
206
206
 
207
+ ## Changes in 0.37.0
208
+
209
+ ### An artifact list with an identity
210
+
211
+ **`ArtifactNameCell` names an artifact in a list.** The kind's glyph on the kind's tint (the Make row's tile at a list's size, so a doc started from the tray is found in the list by the same mark in the same colour), the title, and under it the kind's word and the artifact's description (`detail`) on one quiet line, each cut on one line with the whole of it on hover. The kind is printed, so a list needs no Type column of its own. Under the pointer the row's ground moves and the mark's hairline takes the kind's hue; nothing lifts. `pinned` draws and says a pin, and `trashed` draws the mark without its tint. Every word is in `labels`.
212
+
213
+ **`ArtifactAccessLabel` says who can open an artifact** as its glyph and a word: Private, Shared or Company (`ARTIFACT_ACCESS_LABELS`), or the caller's own `label` and `title`. Access is a fact about reach, never a status, so it takes no colour: the word is a step stronger where others can open it. The glyphs are `ArtifactAccessGlyph`, which `ArtifactCard` now draws its access with too, and the `ArtifactAccess` type has moved to this module (the card's subpath still exports it).
214
+
215
+ ### Previews
216
+
217
+ **`PreviewScale` fills a box with `fit="fill"`.** The content covers the box edge to edge, centred across and held at the top, wherever that leaves at most a fifth of it outside the box (`PREVIEW_FILL_MAX_CUT`), and is contained whole otherwise. A design's laptop board (16:10) in a gallery card (16:9) was contained, which left an empty strip down each side of the card; filled, it reaches both sides and loses a tenth of its foot. A phone's board is still shown whole. `PreviewFit` names the three fits.
218
+
219
+ ### Wording
220
+
221
+ **The gallery's tray is "Start a new artifact"** in the stories, the tests and the notes on `ArtifactMakeRow` and `ArtifactKindTile`, where it was "Make something new".
222
+
223
+ ## Changes in 0.36.0
224
+
225
+ ### New on a create page and in the gallery
226
+
227
+ **`AgentHandoffPanel` hands the work to an agent beside what is being made.** A create page is the direct way to make something; asking an agent is a panel at its side rather than a mode that swaps the page for a form, so a person can lay out a slide, ask, and lay out another. It is an `ArtifactPanel` (titled "Ask an agent"), so inside an `ArtifactWorkspace` it is a column where there is room, a drawer over the page's end where there is not, and the screen on a phone. Top to bottom: an `intro` line, the brief (a `Composer` with its visible `briefLabel`, `briefPlaceholder`, `briefHelper` and `briefMaxLength`), `starters` offered as one-press chips while the brief is empty (`onStarter`), the kind's own fields (`children`), **Who builds it** (`agent`, the host's picker), **Goes with it** (`carried`: what the reader already made, each with an icon, a label and a detail) with the task exactly as it is filed behind a disclosure (`task`), and **What happens next** (`steps`, a `Timeline`). A `notice` (a refusal) sits above the commit. The commit is the panel's foot (`send`: its label, the chosen agent's picture as `media`, `busy` and `disabledReason`), always in reach however far the panel scrolls; a held send says why in words beside the button as well as in its tooltip, and the picture is hidden from the button's name. Command+Enter from any field in the panel sends, and the press is answered there, so a page-wide shortcut behind the panel never also fires. Every heading and label is in `labels` (`AGENT_HANDOFF_LABELS`).
228
+
229
+ **An artifact panel takes a `footer`** (`ArtifactPanel`): what stays under the body however far it scrolls, on a hairline at the panel's foot and outside the scrolling body, such as a hand-off's Send. A panel without one is unchanged.
230
+
231
+ **`ArtifactMakeRow` is the gallery's Make something new row, a quiet tray rather than a row of pictures.** Each kind is its glyph on the kind's own tint, its name and a few words on what it is for (`detail`), the whole item one link named by the kind with the words as its description; with `disabledReason` an item stays a focusable stop that says why it cannot start one. The tray is Crewlet's dotted field in a hairline ring, and an item lifts off it as a card under the pointer while nothing inside it moves. It lays itself out by its own width: under 560px three across in two lines, each mark over its name; from 560px the six in one line, still mark over name, so a long name is never cut; from 920px the mark beside the name with what the kind is for under it. At 1440 the row is 52px tall where the tiles were 166px. `ArtifactKindTile` stays, for a create page's starting points.
232
+
233
+ ### Chosen options and focus
234
+
235
+ **A chosen option is calm, and the focus ring is the one accent line on a page.** Two tokens name what a chosen option draws: `--color-border-selected`, the accent at 0.6 (the full accent in a high-contrast theme), so a tint mixed toward its ground, and `--color-surface-selected`, the soft fill. Every component that marks a pick takes them, at one pixel, and pairs them with a mark of its own that clears 3:1, so the state never rests on the tint:
236
+
237
+ - `ThemeGallery`: the chosen card's edge is the selected edge over the selected fill, and a check stands beside its name. It was a full accent border.
238
+ - `SlideFilmstrip` and `SlideGrid`: the slide being edited keeps its one-pixel edge in the selected edge, with the selected fill as a 3px band outside it, and its number in the accent ink. It was a 2px ring in the full accent, the focus ring's weight and colour.
239
+ - `DatasetSource`: an open source is one card. The selected edge rings the whole entry, its preview included, over the selected fill on its summary, which is the card's head; the preview is a well under it on the inset ground, parted from the head by one line in the same edge, so the settings and figures it shows read as the entry's own rather than as loose items of the rail. It was the full accent around the summary alone. Selected without a preview it is the selected edge and fill around the summary; closed, it is unchanged.
240
+ - `ChoiceList` and `LayersList`: the picked row stands on the selected fill. A layer used to take the accent rail of a current row (the outline's heading, the page in the rail), which beside a canvas read as a second selection; the rail's room is kept, and forced colours draw it in `Highlight`.
241
+ - `SlideFilmstrip`'s focus ring grows outward from the thumbnail's edge. It sat on the inset offset, inside the thumbnail, where a dark slide swallowed it and tabbing through the strip showed nothing.
242
+ - `Card`: a chosen card (`selected`) takes the selected edge over the selected fill, laid over its own surface. It was the full accent border under `--shadow-selection`, a second 2px accent ring.
243
+ - `ArtifactKindTile`: a tile that is a button takes `selected` (announced as a pressed button): the selected edge on its frame over the selected fill, and a check beside its name. Its ground no longer draws a tinted inner line, which with the frame's edge and the focus ring read as three nested rings; the frame is the tile's one edge.
244
+ - `ArrangeFrame`: the block under the pointer, or holding focus in one of its fields, takes the selected edge; the block itself in keyboard focus takes a 2px focus ring (it was one pixel); a picked or resizing block keeps one crisp pixel of the accent.
245
+ - `FilterChip`: a pressed chip stands on the selected fill, keeping its lighter line and the accent ink.
246
+ - `ChoiceList`: the radio is drawn rather than the platform's, an empty ring on the control boundary until chosen and an accent dot when it is, because the platform's dark radio filled every unchosen answer with a grey disc that read as a second choice; forced colours hand it back to the platform. A tag ("Suggested") is set in the tertiary ink, no longer a second accent mark on the chosen row.
247
+ - `SlideFilmstrip`'s thumbnails take the strong line at rest and its hover step under the pointer: on the dark page the plain hairline left a strip of dark slides with no edges.
248
+ - `CanvasBoard`: hover is one screen pixel of the selected edge, and a pick one crisp pixel of the full accent with its four corners. It was two pixels, so a picked board and the live board ([data-active], which keeps the 2px focus ring) read alike.
249
+
250
+ **A field rings at 2px for the keyboard and at its own hairline for a pointer.** `trackFocusModality` (and `useFocusModality`, exported with `FOCUS_MODALITY_ATTRIBUTE`) writes `data-crewlet-focus="keyboard" | "pointer"` on the root: Tab, or any key pressed outside a text-entry control, is the keyboard, a pointer press is the pointer, and typing in a field is neither. Every field (`Input`, `Textarea`, `Select` and its search box, `TagsInput`, `DateTimePicker`, `TimeWindowPicker`, `Composer`, `DocumentTitleField`) starts it while mounted, and an application may call `trackFocusModality()` at boot so the first key a reader presses is seen before any field mounts. A boxed field's ring is now 2px in `--color-focus` over its boundary, the area WCAG 2.2's focus appearance asks of a keyboard indicator, and where a pointer put the caret it narrows to one pixel in `--color-border-selected`, so a page that focuses its first field on load no longer rings it in the focus colour before anybody has touched a key. A refused field keeps its danger colour under either. A document that tracks nothing keeps the 2px ring. `Input.test.tsx` holds every boxed ring to one narrowing rule. `SourceEditor` rings as a field does too, in place of its accent border and soft halo.
251
+
252
+ **`Composer` rings as a field does.** Its box takes the field ring above, keyed on the field so tabbing onto the send action shows that button's ring. It used to recolour its border to the accent and lay a 2px soft halo outside it: two highlights for one state.
253
+
254
+ **A composer's footer is drawn only with something in it** (`Composer`). With no send shortcut, counter or actions there is no strip under the field, and a footer holding only the shortcut's hint goes on a phone, where the hint is not drawn, instead of leaving an empty strip. A footer with actions or a counter stays on every width.
255
+
256
+ ### Titles
257
+
258
+ **`DocumentTitleField` wraps.** It is a textarea of one row that grows with the title, so a long title, or a long example in its placeholder, wraps on a phone as the title it becomes does, where the input it replaced cut it mid-word. It is still one line of text: Enter inserts nothing (its keydown reaches the caller and the page as an input's does, and in a form with a submit button it submits, as an input's Enter does), a pasted, dropped or autofilled line break becomes a space before `onChange` reads the value, and it is named to assistive technology as a single-line field (`aria-multiline="false"`). It forwards a ref to the textarea. A caller that typed its handlers or ref for `HTMLInputElement` types them for `HTMLTextAreaElement`.
259
+
260
+ **`DocumentTitleField` underlines in a tint for a pointer and in two focus pixels for the keyboard.** The line along its foot is one pixel (the hairline under the pointer, the selected edge once a click has put the caret in it), and two pixels in the focus colour for the keyboard, drawn as the border and a shadow under it with a transparent outline that forced colours paint. The padding takes the pixel the border no longer reserves, so the title sits where it did. A page that focuses its title on load no longer draws a 2px accent bar under it before anybody has touched anything.
261
+
262
+ ### Live previews
263
+
264
+ **A live preview is a snapshot: rendered once, then a still copy with nothing live behind it** (`LivePreview`). Scrolling a gallery up and down tore every card down as it left and drew it again from its stand-in as it came back, so the kind's drawing flickered over content the reader had just seen, and every redraw read its data again. Now the content renders once, out of sight behind the stand-in; when it calls `useLivePreview().ready()` and the page's fonts have loaded, what it drew is copied (its DOM, cloned: a canvas as an image of what it drew, and nothing that would load again, such as a frame, a video or an embedded object), the copy fades in over the stand-in, which is hidden only once the fade is done (fading both at once showed a double exposure), and the content is unmounted in the same commit. From then on the preview holds no React tree, query, subscription, observer of its own or timer, and it never reads, polls or redraws again; nothing inside a copy animates. A copy laid out at `width` is rescaled when its box changes size by one ResizeObserver the provider shares; one with no `width` is drawn again only if its box changes size. A render that has not drawn within `LIVE_PREVIEW_RENDER_MS` (15 seconds, past the ten a framed page is given to answer) gives up and keeps its stand-in.
265
+
266
+ **A snapshot is kept by key for the provider's life** (`snapshot`, new). Previews under one `LivePreviewBudgetProvider` with the same key share one copy, so a card mounted again (a filter, a change of shape, a page of results) shows it at once with nothing read or rendered, and no fade. A key names a version of the content: a new key is a new snapshot, and a provider mounted afresh (the page loaded again) takes new ones. The provider keeps up to `LIVE_PREVIEW_STILLS_KEPT` copies (200, four pages of a listing at fifty; `kept` changes it), the one used longest ago dropped first. A preview that failed is remembered under its key too. `createLivePreviewStills` is the store, exported for a host that measures.
267
+
268
+ **A frame is kept, not copied** (`frame`). A page in a frame lives in another document, which nothing can clone and a clone of the frame would load again, so a framed preview keeps its frame once drawn and fades it in. Kept frames are capped apart (`LIVE_PREVIEW_MAX_FRAMES`, twelve, the pages a design's canvas runs at once): one the reader has left is parked, and taken back only when a frame coming near needs its place, the one left longest ago first; one on screen is never taken back for another.
269
+
270
+ **The budget bounds renders at once, six by default** (`LIVE_PREVIEW_MAX`, from twelve). A slot is held only while content renders, and given to the next box the moment the content says it has drawn, so six is enough for any gallery: six is the number of connections a browser opens to one host over HTTP/1.1, which is how a preview's reads reach their server, so a seventh render would only queue behind them. `LivePreviewBudgetProvider` takes `maxFrames` and `kept` beside `max`.
271
+
272
+ **A preview starts a screen ahead** (`LIVE_PREVIEW_MARGIN`, `'100% 0px'`, from `'200px 0px'`). A snapshot costs nothing once taken, so drawing a screen ahead in each direction is paid once and lets a reader scrolling at any pace meet every card already drawn.
273
+
274
+ Measured on a gallery of 44 cards at 1440 by 900, scrolling down and back at reading pace, in flings, then to the foot and twice over again, against 0.36.0's earlier preview (a parked slot and a still copy only on reclaim): visible cards drawn again after they had drawn stayed at 0; cards seen before their first draw fell from 18 samples to 0 (from about 50 to 0 with the CPU slowed fourfold); teardowns of a drawn card fell from 93 to 0; requests and socket questions after every card had drawn fell from 7 and 2 to none, and over the whole visit from 106 and 27 to 57 and 12, every board, dataset and sheet read exactly once; long tasks at fourfold slowdown fell from about 40 (2.4 seconds in all) to 2 (150 milliseconds); the heap after the visit from 15.1 to 13.7 MB and the document's nodes from 6,356 to 5,994. The first screen draws within about 15 milliseconds of the time it took before (about 70 with the CPU slowed fourfold).
275
+
276
+ **A preview's margin is measured against its scroll container.** The observer was rooted at the window, and a page that scrolls inside a frame clips its content at the frame's edge, so `rootMargin` never applied and every card started drawing only once it was on screen. It now observes against the nearest ancestor that scrolls.
277
+
278
+ **`createLivePreviewBudget().request` answers a slot** (`LivePreviewSlot`: `release`, `drawn`, `park` and `resume`) in place of a give-back function, and takes the holder's `reclaim` and whether it is a `frame`. `drawn()` ends a render: it gives a page's slot back for good and keeps a frame among the frames. A host that called the answer to give a slot back calls `release()`.
279
+
280
+ ### Artifact kit
281
+
282
+ **A kit sheet reads the page's capabilities again once the runtime's handshake lands** (`@crewlethq/artifact-kit`: `<crewlet-sheet>`, `mountSheet`). Before the handshake the runtime answers `capabilities.has` from what the origin told it as the page loaded, and from the handshake on the host's word is the authority. The sheet read the answer once, when it was first drawn, and kept it, so a sheet drawn on one answer and handed another by the handshake kept the first: a page whose host said `db` at the handshake could still show "This sheet cannot load" for good. The sheet now reads the declaration again when `ready` resolves, its subscriptions following what it reads, and says a page has no datastore only once the handshake has said so; before then it draws nothing. `mountSheet` and the element still wait for the handshake before they draw, so a page sees no change unless a host's handshake disagrees with what its page loaded with.
283
+
284
+ ### Smaller fixes
285
+
286
+ **A framed slide keeps its edge on the dark theme** (`SlideStage` with `framed`). The slide's outline takes `--color-border-strong` rather than `--color-border-default`. On the dark theme the default border is a step off the page, so a dark slide (most themes are dark) on a dark page drew no edge and read as a hole in the page; the strong border is the third step of the ramp and clears the page in both themes. Hosts that recolour the outline for a marked stage are unchanged.
287
+
288
+ **An artifact bar's status is quiet by default** (`ArtifactBar`'s `status`). Plain words handed to it ("Creating…", "25 words", "4 slides · Nightshade") are drawn in the compact step and the secondary ink, with tabular figures, as `EditingStatus` draws itself, rather than at the bar title's size and ink. A host that styled its own status span for this can drop the span; one that wants a stronger status passes an element with its own colour.
289
+
290
+ **An option with a detail starts at its top** (`ChoiceButtons`). Laid out as tiles by a host's grid, the options in one row stretch to the tallest, and centred text set a label with a one-line detail lower than its neighbour with a two-line one. An option that has a detail now aligns its label, detail and mark to its top edge, so every label in a row starts on one line. An option without a detail, and a column of options, look as they did.
291
+
292
+ **A narrow board keeps a readable name** (`CanvasBoard`). A name with too little room above its board is shortened to at least three letters and an ellipsis; a board narrower than that is called by its number in the design ("3"), and only a board narrower than a digit goes unnamed. A shortened name or a number carries the whole name as a tooltip, and the board's region is still named in full. The name row counts the room the move handle and the open control take, so a touch screen's open control no longer cuts the name to nothing. `boardName(title, position, room)` is that rule, and `BOARD_NAME_MIN_CHARS` the letters it keeps. `boardRoom(width, height)` now answers the placeholder's `lines` alone, and `BOARD_TITLE_MIN_WIDTH` is gone: a host that read `boardRoom(...).title` asks `boardName` instead.
293
+
294
+ Beyond what is named above (a `DocumentTitleField` handler or ref typed for a textarea, a budget's `request` answering a slot, and `boardRoom(...).title` read through `boardName`), a host has nothing else to change. A host stylesheet that drew its own chosen state in `--color-brand-accent` can take the two selected tokens in its place, and one that drew a title underline of its own can follow `DocumentTitleField`.
295
+
207
296
  ## Changes in 0.35.1
208
297
 
209
298
  **A column given another type keeps only what every type has** (`SheetColumnEditor`, and `retypeColumn` in the sheet model). Its field, name, width, freezing, read-only flag and Required stay, and so does its length cap between text and long text, which both read it. Every other setting belongs to the old type and is dropped: a number's bounds, decimals and format, a choice's options, a date's time of day. The column is built up from what is kept rather than pared down from the old one, so a setting a type adds later is dropped without the editor having to name it. Before, a date's time of day and a text's length cap rode along, unseen, into a type that ignores them, and came back if the old type was picked again. A host that relied on a setting surviving a type change sets it again on the column it is handed.
@@ -0,0 +1,99 @@
1
+ import { type ReactNode, type Ref } from 'react';
2
+ /** One thing that goes to the agent with the brief: the draft, the slides laid out, the board. */
3
+ export interface AgentHandoffItem {
4
+ key: string;
5
+ /** A small glyph before the words. */
6
+ icon?: ReactNode;
7
+ /** What it is, in a line: "Your draft", "4 slides in Nightshade". */
8
+ label: ReactNode;
9
+ /** A second, quieter line: how much of it, or what the agent does with it. */
10
+ detail?: ReactNode;
11
+ }
12
+ /** A brief to start from, offered while the brief is empty. */
13
+ export interface AgentHandoffStarter {
14
+ key: string;
15
+ /** Its name on the chip: "Incident review". */
16
+ label: string;
17
+ }
18
+ /** The panel's commit: the press that files the work. */
19
+ export interface AgentHandoffSend {
20
+ /** Its words: "Ask SRE Lead". */
21
+ label: string;
22
+ /** Drawn before the words and hidden from the name: the chosen agent's character. */
23
+ media?: ReactNode;
24
+ onSend: () => void;
25
+ /** Unavailable, and why. Said on the button and, in words, beside it. */
26
+ disabledReason?: string | undefined;
27
+ /** Filing the work now. */
28
+ busy?: boolean | undefined;
29
+ }
30
+ export interface AgentHandoffLabels {
31
+ title: string;
32
+ brief: string;
33
+ starters: string;
34
+ agent: string;
35
+ carried: string;
36
+ task: string;
37
+ next: string;
38
+ step: string;
39
+ }
40
+ export declare const AGENT_HANDOFF_LABELS: AgentHandoffLabels;
41
+ export interface AgentHandoffPanelProps {
42
+ onClose: () => void;
43
+ /** A glyph before the title: the one on the control that opened the panel. */
44
+ icon?: ReactNode;
45
+ /** See [ArtifactPanel]: false for a panel that is open on arrival. */
46
+ focusOnOpen?: boolean | undefined;
47
+ /** A line under the title saying what the panel does, in the kind's words. */
48
+ intro?: ReactNode;
49
+ brief: string;
50
+ onBriefChange: (brief: string) => void;
51
+ /** The brief field's visible name, asked as a question where that reads better. */
52
+ briefLabel?: string | undefined;
53
+ briefPlaceholder?: string | undefined;
54
+ /** Under the field: what a good brief says. */
55
+ briefHelper?: ReactNode;
56
+ briefMaxLength?: number | undefined;
57
+ briefRef?: Ref<HTMLTextAreaElement> | undefined;
58
+ /** Briefs to start from, drawn while the brief is empty. */
59
+ starters?: readonly AgentHandoffStarter[] | undefined;
60
+ onStarter?: ((key: string) => void) | undefined;
61
+ /** The kind's own fields, under the brief: what a page may do, references. */
62
+ children?: ReactNode;
63
+ /** Who builds it: the host's agent picker, and the project it files in. */
64
+ agent: ReactNode;
65
+ /** What goes to the agent with the brief, so nothing the reader made is lost. */
66
+ carried?: readonly AgentHandoffItem[] | undefined;
67
+ /** The task exactly as it is filed, behind a disclosure. */
68
+ task?: {
69
+ title: string;
70
+ body: string;
71
+ } | undefined;
72
+ /** What happens after the press, step by step. */
73
+ steps?: readonly ReactNode[] | undefined;
74
+ /** A refusal or a warning, said above the commit. */
75
+ notice?: ReactNode;
76
+ send: AgentHandoffSend;
77
+ labels?: Partial<AgentHandoffLabels> | undefined;
78
+ className?: string | undefined;
79
+ }
80
+ /**
81
+ * Handing the work to an agent, at the side of what the reader is making.
82
+ *
83
+ * A PANEL, NOT A MODE. The page beside it is the direct way to make the thing,
84
+ * and stays live and editable while the brief is written, so a person can lay
85
+ * out a slide, then ask, then lay out another. What they made goes with the
86
+ * brief (`carried`), and the panel says so, so moving between the two ways
87
+ * loses nothing. Built on [ArtifactPanel], so it is a column where there is
88
+ * room, a drawer over the page's end where there is not, and the screen on a
89
+ * phone, exactly as an open artifact's panels are.
90
+ *
91
+ * THE BRIEF FIRST, as every agent composer puts it: the field the reader came
92
+ * to fill, with briefs to start from while it is empty. Then who builds it,
93
+ * what goes with it, the task as it is filed and what happens next, so nothing
94
+ * about the ask is hidden. The commit sits in the panel's foot, always in
95
+ * reach, with the chosen agent's character beside its words; Command+Enter
96
+ * anywhere in the panel presses it. A send that is held says why in words
97
+ * beside it, not only in the button's tooltip.
98
+ */
99
+ export declare function AgentHandoffPanel({ onClose, icon, focusOnOpen, intro, brief, onBriefChange, briefLabel, briefPlaceholder, briefHelper, briefMaxLength, briefRef, starters, onStarter, children, agent, carried, task, steps, notice, send, labels, className, }: AgentHandoffPanelProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './AgentHandoffPanel.css';
2
+ export { AGENT_HANDOFF_LABELS, AgentHandoffPanel } from './AgentHandoffPanel.js';
3
+ export type { AgentHandoffItem, AgentHandoffLabels, AgentHandoffPanelProps, AgentHandoffSend, AgentHandoffStarter, } from './AgentHandoffPanel.js';
@@ -0,0 +1,16 @@
1
+ export { AGENT_HANDOFF_LABELS, AgentHandoffPanel } from '../chunk-EOQFPZEE.js';
2
+ import '../chunk-AUQPBL4O.js';
3
+ import '../chunk-3TFDQLW3.js';
4
+ import '../chunk-MICH6QSJ.js';
5
+ import '../chunk-RH2NCQBZ.js';
6
+ import '../chunk-Y5BD4MTE.js';
7
+ import '../chunk-IUYUS2SO.js';
8
+ import '../chunk-YSGLEHND.js';
9
+ import '../chunk-SMBKXWML.js';
10
+ import '../chunk-FZVJDJFN.js';
11
+ import '../chunk-BHHIIK3M.js';
12
+ import '../chunk-PQADV6P6.js';
13
+ import '../chunk-OG6CL3EB.js';
14
+ import '../chunk-4FQT6ZAY.js';
15
+ import '../chunk-BZFWDIV6.js';
16
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,151 @@
1
+ /*
2
+ * Handing work to an agent, at the side of what is being made. The panel is
3
+ * an ArtifactPanel; this is its inside: the brief, its starters, the agent,
4
+ * what goes with it and the steps after, on one rhythm, and the commit in the
5
+ * panel's foot.
6
+ *
7
+ * ONE STEP BETWEEN SECTIONS (spacing-6) and one inside them (spacing-2): the
8
+ * brief and its helper read as one block, the next question as the next.
9
+ */
10
+
11
+ .crewlet-agent-handoff__body {
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: var(--spacing-6);
15
+ min-width: 0;
16
+ }
17
+
18
+ .crewlet-agent-handoff__intro {
19
+ margin: 0;
20
+ color: var(--color-text-secondary);
21
+ font-size: var(--font-size-sm);
22
+ line-height: var(--font-line-height-normal);
23
+ }
24
+
25
+ .crewlet-agent-handoff__brief {
26
+ display: flex;
27
+ flex-direction: column;
28
+ gap: var(--spacing-2);
29
+ min-width: 0;
30
+ }
31
+
32
+ /* THE BRIEF'S NAME is a section's name, at a section heading's size, since
33
+ it heads the panel's first question. */
34
+ .crewlet-agent-handoff__label {
35
+ color: var(--color-text-primary);
36
+ font-size: var(--font-size-sm);
37
+ font-weight: var(--font-weight-semibold);
38
+ line-height: var(--font-line-height-snug);
39
+ }
40
+
41
+ .crewlet-agent-handoff__helper {
42
+ margin: 0;
43
+ color: var(--color-text-tertiary);
44
+ font-size: var(--font-size-xs);
45
+ line-height: var(--font-line-height-normal);
46
+ }
47
+
48
+ .crewlet-agent-handoff__starters {
49
+ display: flex;
50
+ flex-wrap: wrap;
51
+ gap: var(--spacing-2);
52
+ }
53
+
54
+ .crewlet-agent-handoff__section {
55
+ min-width: 0;
56
+ }
57
+
58
+ .crewlet-agent-handoff__carried {
59
+ display: flex;
60
+ flex-direction: column;
61
+ gap: var(--spacing-1);
62
+ margin: 0 0 var(--spacing-2);
63
+ padding: 0;
64
+ list-style: none;
65
+ }
66
+
67
+ .crewlet-agent-handoff__item {
68
+ display: flex;
69
+ align-items: flex-start;
70
+ gap: var(--spacing-2);
71
+ padding: var(--spacing-2) var(--spacing-3);
72
+ border-radius: var(--radius-md);
73
+ background: var(--color-surface-subtle);
74
+ }
75
+
76
+ .crewlet-agent-handoff__item-icon {
77
+ display: inline-flex;
78
+ flex: none;
79
+ /* On the first line's centre, whatever the glyph's own box. */
80
+ margin-top: 1px;
81
+ color: var(--color-text-tertiary);
82
+ }
83
+
84
+ .crewlet-agent-handoff__item-words {
85
+ display: flex;
86
+ flex-direction: column;
87
+ gap: 2px;
88
+ min-width: 0;
89
+ }
90
+
91
+ .crewlet-agent-handoff__item-label {
92
+ overflow-wrap: anywhere;
93
+ color: var(--color-text-primary);
94
+ font-size: var(--font-size-sm);
95
+ line-height: var(--font-line-height-snug);
96
+ }
97
+
98
+ .crewlet-agent-handoff__item-detail {
99
+ overflow-wrap: anywhere;
100
+ color: var(--color-text-tertiary);
101
+ font-size: var(--font-size-xs);
102
+ line-height: var(--font-line-height-normal);
103
+ }
104
+
105
+ .crewlet-agent-handoff__task {
106
+ display: flex;
107
+ flex-direction: column;
108
+ gap: var(--spacing-2);
109
+ padding-top: var(--spacing-2);
110
+ }
111
+
112
+ .crewlet-agent-handoff__task-title {
113
+ margin: 0;
114
+ color: var(--color-text-primary);
115
+ font-size: var(--font-size-sm);
116
+ font-weight: var(--font-weight-medium);
117
+ }
118
+
119
+ /* THE BODY AS SENT, wrapped rather than scrolled sideways: a reader checks it
120
+ line by line, and a panel's width is narrower than its longest line. */
121
+ .crewlet-agent-handoff__task-body {
122
+ max-height: 16rem;
123
+ margin: 0;
124
+ overflow: auto;
125
+ padding: var(--spacing-2) var(--spacing-3);
126
+ border-radius: var(--radius-md);
127
+ background: var(--color-surface-inset);
128
+ color: var(--color-text-secondary);
129
+ font-family: var(--font-family-mono);
130
+ font-size: var(--font-size-xs);
131
+ line-height: var(--font-line-height-normal);
132
+ white-space: pre-wrap;
133
+ overflow-wrap: anywhere;
134
+ }
135
+
136
+ .crewlet-agent-handoff__foot {
137
+ display: flex;
138
+ flex-direction: column;
139
+ gap: var(--spacing-2);
140
+ }
141
+
142
+ .crewlet-agent-handoff__media {
143
+ display: inline-flex;
144
+ }
145
+
146
+ .crewlet-agent-handoff__reason {
147
+ margin: 0;
148
+ color: var(--color-text-tertiary);
149
+ font-size: var(--font-size-xs);
150
+ line-height: var(--font-line-height-normal);
151
+ }
@@ -1,4 +1,4 @@
1
- export { ArrangeFrame, useGridResize } from '../chunk-DEJHAOC5.js';
1
+ export { ArrangeFrame, useGridResize } from '../chunk-WMXAX6VA.js';
2
2
  import '../chunk-RSAQOKH3.js';
3
3
  import '../chunk-4FQT6ZAY.js';
4
4
  import '../chunk-BZFWDIV6.js';
@@ -59,9 +59,8 @@
59
59
 
60
60
  /*
61
61
  * THE ONE RING, over the block's own edge, on the innermost block the
62
- * pointer or the focus is in. A hairline drawn exactly over the block's own
63
- * 1px border, so the border turns to the accent rather than a second, heavier
64
- * line appearing around it.
62
+ * pointer or the focus is in. Drawn exactly over the block's own 1px border,
63
+ * so the border changes colour rather than a second line appearing around it.
65
64
  *
66
65
  * IT IS A LAYER OF ITS OWN, above the content. An outline is painted with the
67
66
  * block, under any content that is positioned or scrolls (a card with a fixed
@@ -78,14 +77,32 @@
78
77
  border-radius: inherit;
79
78
  pointer-events: none;
80
79
  }
81
- .crewlet-arrange-frame.is-editing:is(:hover, :focus-visible, :has(:focus-visible)):not(
80
+ /*
81
+ * THREE STRENGTHS ON THE ONE LAYER. The innermost block under the pointer, or
82
+ * holding the focus in one of its fields, takes the selected edge, the accent
83
+ * mixed toward the page: it says where the reader is working, and in the full
84
+ * accent a caret in a cell's field drew a frame in the focus ring's own hue
85
+ * round the whole block. The block ITSELF in keyboard focus takes the focus
86
+ * ring, two pixels in the focus colour, the area a keyboard indicator needs.
87
+ * A picked or resizing block takes one crisp pixel of the full accent, as a
88
+ * picked board on a canvas does, its handles saying the rest.
89
+ */
90
+ .crewlet-arrange-frame.is-editing:is(:hover, :has(:focus-visible)):not(:focus-visible, .is-selected, .is-resizing):not(
82
91
  :has(.crewlet-arrange-frame:is(:hover, :focus-visible, :has(:focus-visible)))
83
- )::after,
92
+ )::after {
93
+ border-color: var(--color-border-selected);
94
+ }
95
+
84
96
  .crewlet-arrange-frame.is-selected::after,
85
97
  .crewlet-arrange-frame.is-resizing::after {
86
98
  border-color: var(--color-brand-accent);
87
99
  }
88
100
 
101
+ .crewlet-arrange-frame.is-editing:focus-visible::after {
102
+ border-width: 2px;
103
+ border-color: var(--color-focus);
104
+ }
105
+
89
106
  /* A block with no surface of its own takes its ring a step outside it. */
90
107
  .crewlet-arrange-frame.is-bare {
91
108
  --crewlet-arrange-frame-radius: var(--radius-md);
@@ -1,8 +1,9 @@
1
- export { ArrangeList, DEFAULT_ARRANGE_LABELS } from '../chunk-V43UVX4H.js';
1
+ export { ArrangeList, DEFAULT_ARRANGE_LABELS } from '../chunk-27GD7LVR.js';
2
2
  import '../chunk-A722MUNR.js';
3
3
  import '../chunk-XJ2QEBMM.js';
4
- import '../chunk-CPEPST4S.js';
5
- import '../chunk-6QFAK2WV.js';
4
+ import '../chunk-PJIPUEJ3.js';
5
+ import '../chunk-IUYUS2SO.js';
6
+ import '../chunk-YSGLEHND.js';
6
7
  import '../chunk-PQADV6P6.js';
7
8
  import '../chunk-RSAQOKH3.js';
8
9
  import '../chunk-4FQT6ZAY.js';
@@ -0,0 +1,40 @@
1
+ import { type GlyphSize } from '@crewlethq/icons/glyphs';
2
+ /**
3
+ * Who can open an artifact: only its owner (and those they shared it with by
4
+ * name, which the owner alone sees), people it is shared with, or the whole
5
+ * company.
6
+ */
7
+ export type ArtifactAccess = 'private' | 'shared' | 'company';
8
+ /** Every access, from the narrowest to the widest. */
9
+ export declare const ARTIFACT_ACCESSES: readonly ["private", "shared", "company"];
10
+ /**
11
+ * What each access is called where there is room for a word: a list's column,
12
+ * a card's hover text. Short, because a column of them is read down.
13
+ */
14
+ export declare const ARTIFACT_ACCESS_LABELS: Readonly<Record<ArtifactAccess, string>>;
15
+ /**
16
+ * The glyph an access is drawn with, wherever it is drawn: a lock, people or
17
+ * the company's building. Decorative: whatever draws it says the word too,
18
+ * printed or for assistive technology.
19
+ */
20
+ export declare function ArtifactAccessGlyph({ access, size }: {
21
+ access: ArtifactAccess;
22
+ size?: GlyphSize | undefined;
23
+ }): import("react").JSX.Element;
24
+ export interface ArtifactAccessLabelProps {
25
+ access: ArtifactAccess;
26
+ /** The word printed beside the glyph. The design system's short word by default. */
27
+ label?: string | undefined;
28
+ /** The hover text, where the word is not the whole story: "Shared with 3 people". */
29
+ title?: string | undefined;
30
+ className?: string | undefined;
31
+ }
32
+ /**
33
+ * Who can open an artifact, as a glyph and its word: a list's Access column.
34
+ *
35
+ * QUIET FOR PRIVATE, A STEP UP FOR SHARED. The glyph is the tertiary step,
36
+ * and an artifact others can open prints its word a step stronger than one
37
+ * nobody else sees, so a column read down picks out what is shared without
38
+ * a hue: access is a fact about reach, never a status, and takes no colour.
39
+ */
40
+ export declare function ArtifactAccessLabel({ access, label, title, className }: ArtifactAccessLabelProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './ArtifactAccess.css';
2
+ export { ARTIFACT_ACCESSES, ARTIFACT_ACCESS_LABELS, ArtifactAccessGlyph, ArtifactAccessLabel } from './ArtifactAccess.js';
3
+ export type { ArtifactAccess, ArtifactAccessLabelProps } from './ArtifactAccess.js';
@@ -0,0 +1,2 @@
1
+ export { ARTIFACT_ACCESSES, ARTIFACT_ACCESS_LABELS, ArtifactAccessGlyph, ArtifactAccessLabel } from '../chunk-BGLKLXL3.js';
2
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,31 @@
1
+ /*
2
+ * An artifact's access as a glyph and its word. No colour of its own: the
3
+ * glyph is the tertiary step and the word the secondary, one step stronger
4
+ * where others can open it.
5
+ */
6
+
7
+ .crewlet-artifact-access {
8
+ display: inline-flex;
9
+ align-items: center;
10
+ gap: calc(var(--spacing-1) * 1.5);
11
+ min-width: 0;
12
+ max-width: 100%;
13
+ color: var(--color-text-tertiary);
14
+ }
15
+
16
+ .crewlet-artifact-access__glyph {
17
+ display: inline-flex;
18
+ flex: none;
19
+ }
20
+
21
+ .crewlet-artifact-access__word {
22
+ min-width: 0;
23
+ overflow: hidden;
24
+ text-overflow: ellipsis;
25
+ white-space: nowrap;
26
+ }
27
+
28
+ .crewlet-artifact-access--shared,
29
+ .crewlet-artifact-access--company {
30
+ color: var(--color-text-secondary);
31
+ }
@@ -100,7 +100,8 @@ export interface ArtifactBarProps {
100
100
  presence?: ReactNode;
101
101
  /**
102
102
  * What the kind is doing now, said before its tools: an `EditingStatus`
103
- * while a doc is edited. Never folded away; a status that has words to
103
+ * while a doc is edited, or plain words ("Creating…"), which the bar draws
104
+ * in its quiet small step. Never folded away; a status that has words to
104
105
  * spare folds them itself.
105
106
  */
106
107
  status?: ReactNode;
@@ -1,12 +1,12 @@
1
- export { ARTIFACT_BAR_LABELS, ArtifactBar, ArtifactVersionChip } from '../chunk-NKZCJRKO.js';
1
+ export { ARTIFACT_BAR_LABELS, ArtifactBar, ArtifactVersionChip } from '../chunk-APDKUGSH.js';
2
2
  import '../chunk-WKEPORNM.js';
3
- import '../chunk-SMBKXWML.js';
4
3
  import '../chunk-6ZJ3N7QI.js';
5
4
  import '../chunk-CCAXYHQS.js';
6
5
  import '../chunk-VL6CUNSX.js';
7
6
  import '../chunk-RKKO7QHH.js';
8
7
  import '../chunk-ILDNJHRU.js';
9
8
  import '../chunk-CE2THTQR.js';
9
+ import '../chunk-SMBKXWML.js';
10
10
  import '../chunk-BHHIIK3M.js';
11
11
  import '../chunk-BUVCV3WI.js';
12
12
  import '../chunk-OMV5W53A.js';
@@ -198,11 +198,19 @@
198
198
  margin-inline-start: var(--spacing-1);
199
199
  }
200
200
 
201
+ /* THE STATUS IS QUIET by default, in the bar's small step and the secondary
202
+ ink that `EditingStatus` takes, so a host that hands it words ("Creating…",
203
+ "25 words") draws them as the open artifact draws its own, never at the
204
+ title's weight. Its figures are tabular, so a count does not jitter. */
201
205
  .crewlet-artifact-bar__status {
202
206
  display: inline-flex;
203
207
  align-items: center;
204
208
  min-width: 0;
205
209
  margin-inline-end: var(--spacing-2);
210
+ color: var(--color-text-secondary);
211
+ font-size: var(--font-size-compact);
212
+ font-variant-numeric: tabular-nums;
213
+ white-space: nowrap;
206
214
  }
207
215
 
208
216
  .crewlet-artifact-bar__presence {
@@ -1,4 +1,5 @@
1
1
  import { type ReactNode } from 'react';
2
+ import { type ArtifactAccess } from '../ArtifactAccess/index.js';
2
3
  import { type ArtifactKind } from '../ArtifactKindGlyph/index.js';
3
4
  import { type AvatarStackMember } from '../Avatar/index.js';
4
5
  import { type Principal } from '../Principal/index.js';
@@ -14,12 +15,6 @@ import { type TimeValue } from '../RelativeTime/index.js';
14
15
  export declare function ArtifactPreviewGlyph({ kind }: {
15
16
  kind: ArtifactKind;
16
17
  }): import("react").JSX.Element;
17
- /**
18
- * Who can open an artifact, as its card says it: only its owner (and those
19
- * they shared it with by name, which the owner alone sees), people it is
20
- * shared with, or the whole company.
21
- */
22
- export type ArtifactAccess = 'private' | 'shared' | 'company';
23
18
  export type ArtifactCardSize = 'card' | 'compact';
24
19
  export interface ArtifactCardLabels {
25
20
  kinds: Record<ArtifactKind, string>;
@@ -1,6 +1,7 @@
1
1
  import '../ArtifactKindIllustration/ArtifactKinds.css';
2
2
  import './ArtifactCard.css';
3
3
  export { ArtifactCard, ArtifactCardSkeleton, ArtifactPreviewGlyph } from './ArtifactCard.js';
4
- export type { ArtifactAccess, ArtifactCardLabels, ArtifactCardProps, ArtifactCardSize } from './ArtifactCard.js';
4
+ export type { ArtifactCardLabels, ArtifactCardProps, ArtifactCardSize } from './ArtifactCard.js';
5
5
  export { ARTIFACT_KINDS, ArtifactKindGlyph } from '../ArtifactKindGlyph/index.js';
6
6
  export type { ArtifactKind } from '../ArtifactKindGlyph/index.js';
7
+ export type { ArtifactAccess } from '../ArtifactAccess/index.js';