@north-light/crouter 0.3.198 → 0.3.200

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 (316) hide show
  1. package/dist/api/client.d.ts +18 -18
  2. package/dist/api/client.js +29 -37
  3. package/dist/api/dto/broker-ops.d.ts +3 -1
  4. package/dist/api/dto/broker.d.ts +13 -2
  5. package/dist/api/dto/broker.js +4 -4
  6. package/dist/api/dto/human.d.ts +6 -5
  7. package/dist/api/dto/inbox.d.ts +81 -34
  8. package/dist/api/dto/nodes.d.ts +8 -2
  9. package/dist/api/dto/profiles.d.ts +23 -0
  10. package/dist/api/dto/profiles.js +2 -2
  11. package/dist/api/dto/worktree.d.ts +3 -5
  12. package/dist/api/routes.d.ts +3 -5
  13. package/dist/api/routes.js +4 -6
  14. package/dist/builtin-memory/00-runtime-base.md +6 -6
  15. package/dist/builtin-memory/01-spine/01-no-manager.md +1 -1
  16. package/dist/builtin-memory/02-lifecycle/00-terminal.md +3 -3
  17. package/dist/builtin-memory/04-orchestration-kernel.md +6 -6
  18. package/dist/builtin-memory/05-kinds/design/00-base.md +1 -1
  19. package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +2 -2
  20. package/dist/builtin-memory/05-kinds/review/00-base.md +2 -2
  21. package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +1 -1
  22. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +1 -1
  23. package/dist/builtin-memory/insights/capture.md +2 -2
  24. package/dist/builtin-memory/insights/init.md +3 -3
  25. package/dist/builtin-memory/internal/INDEX.md +1 -1
  26. package/dist/builtin-memory/internal/memory-loading.md +1 -1
  27. package/dist/builtin-memory/internal/nodes-and-canvas.md +2 -2
  28. package/dist/builtin-memory/internal/plugins.md +59 -2
  29. package/dist/builtin-memory/internal/storage-tiers.md +3 -1
  30. package/dist/builtin-memory/spec/roadmap.md +2 -2
  31. package/dist/builtin-memory/testing.md +1 -1
  32. package/dist/clients/attach/chrome/bash-jobs.js +3 -3
  33. package/dist/clients/attach/render/chat-view.d.ts +26 -1
  34. package/dist/clients/attach/render/chat-view.js +61 -11
  35. package/dist/clients/attach/render/page-block.d.ts +34 -0
  36. package/dist/clients/attach/render/page-block.js +226 -0
  37. package/dist/clients/attach/session/whip.d.ts +2 -0
  38. package/dist/clients/attach/session/whip.js +2 -0
  39. package/dist/clients/attach/viewer.js +1419 -993
  40. package/dist/clients/conversation/projection.js +18 -3
  41. package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +9 -6
  42. package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +13 -21
  43. package/dist/clients/inbox/controller.js +10 -16
  44. package/dist/clients/inbox/page-adapter.d.ts +1 -3
  45. package/dist/clients/inbox/page-adapter.js +3 -4
  46. package/dist/clients/inbox/resolve.d.ts +1 -1
  47. package/dist/clients/inbox/resolve.js +3 -3
  48. package/dist/clients/inbox/review/document-surface.js +3 -1
  49. package/dist/clients/inbox/review/state.d.ts +2 -1
  50. package/dist/clients/inbox/review/state.js +5 -16
  51. package/dist/clients/inbox/tui/input.js +37 -19
  52. package/dist/clients/inbox/tui/panel.js +5 -31
  53. package/dist/clients/inbox/tui/render.d.ts +11 -0
  54. package/dist/clients/inbox/tui/render.js +71 -27
  55. package/dist/clients/inbox/tui/slots.d.ts +3 -1
  56. package/dist/clients/inbox/tui/slots.js +16 -12
  57. package/dist/clients/inbox/tui/types.d.ts +2 -7
  58. package/dist/clients/inbox/tui.js +2 -2
  59. package/dist/commands/__tests__/human.test.js +71 -114
  60. package/dist/commands/__tests__/node-message.test.js +14 -0
  61. package/dist/commands/attention.js +4 -4
  62. package/dist/commands/canvas-snapshot.js +1 -1
  63. package/dist/commands/canvas.js +1 -1
  64. package/dist/commands/dashboard.js +1 -1
  65. package/dist/commands/human/{html.d.ts → components.d.ts} +1 -1
  66. package/dist/commands/human/components.js +77 -0
  67. package/dist/commands/human/feedback.d.ts +2 -0
  68. package/dist/commands/human/feedback.js +108 -0
  69. package/dist/commands/human/prompts.d.ts +13 -5
  70. package/dist/commands/human/prompts.js +160 -97
  71. package/dist/commands/human/queue.js +57 -88
  72. package/dist/commands/human/shared.d.ts +2 -12
  73. package/dist/commands/human/shared.js +17 -11
  74. package/dist/commands/human.js +29 -21
  75. package/dist/commands/memory/origin.js +2 -2
  76. package/dist/commands/node/bash.js +4 -4
  77. package/dist/commands/node/inspect.js +3 -3
  78. package/dist/commands/node/lifecycle.js +1 -1
  79. package/dist/commands/node/message.js +2 -2
  80. package/dist/commands/node-worktree.js +8 -8
  81. package/dist/commands/pkg/browse.js +1 -1
  82. package/dist/commands/pkg/plugin-manage.js +129 -10
  83. package/dist/commands/profile/delete.js +41 -15
  84. package/dist/commands/profile.js +1 -1
  85. package/dist/commands/push.js +1 -1
  86. package/dist/commands/surface/node/focus.js +29 -14
  87. package/dist/commands/surface-edit.js +3 -3
  88. package/dist/commands/surface-inbox.d.ts +2 -0
  89. package/dist/commands/{human/inbox.js → surface-inbox.js} +14 -18
  90. package/dist/commands/surface.js +2 -1
  91. package/dist/commands/sys/doctor.js +60 -3
  92. package/dist/commands/sys/feedback.js +79 -25
  93. package/dist/commands/sys/settings.js +1 -1
  94. package/dist/core/__tests__/cron-broker-capacity.test.js +1 -1
  95. package/dist/core/__tests__/extension-abort.test.js +5 -2
  96. package/dist/core/__tests__/fixtures/fake-engine.d.ts +13 -2
  97. package/dist/core/__tests__/fixtures/fake-engine.js +47 -3
  98. package/dist/core/__tests__/helpers/harness.js +17 -55
  99. package/dist/core/__tests__/human-cancel-guard.test.js +31 -10
  100. package/dist/core/__tests__/human-deliver.test.js +31 -26
  101. package/dist/core/__tests__/human-node-not-supervised.test.js +1 -1
  102. package/dist/core/__tests__/plugin-page-components.test.js +157 -0
  103. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +4 -5
  104. package/dist/core/__tests__/seam/dormancy-release.test.js +40 -0
  105. package/dist/core/__tests__/serial/flagship-lifecycle.test.js +2 -2
  106. package/dist/core/__tests__/serial/human-deliver-e2e.test.js +12 -6
  107. package/dist/core/__tests__/serial/live-mutation.test.js +1 -1
  108. package/dist/core/__tests__/serial/tmux-surface.test.js +4 -2
  109. package/dist/core/__tests__/serial/worktree.test.js +24 -198
  110. package/dist/core/__tests__/session-cycles.test.js +22 -0
  111. package/dist/core/__tests__/stop-guard.test.js +4 -4
  112. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +19 -4
  113. package/dist/core/bash-jobs.d.ts +6 -0
  114. package/dist/core/bash-jobs.js +10 -0
  115. package/dist/core/canvas/__tests__/attention.test.js +8 -5
  116. package/dist/core/canvas/__tests__/render-remote.test.js +5 -5
  117. package/dist/core/canvas/attention.js +8 -6
  118. package/dist/core/canvas/browse/model.d.ts +8 -2
  119. package/dist/core/canvas/browse/model.js +11 -4
  120. package/dist/core/canvas/canvas.d.ts +7 -0
  121. package/dist/core/canvas/canvas.js +37 -0
  122. package/dist/core/canvas/crons.d.ts +9 -0
  123. package/dist/core/canvas/crons.js +51 -0
  124. package/dist/core/canvas/node-order.d.ts +22 -1
  125. package/dist/core/canvas/node-order.js +26 -1
  126. package/dist/core/canvas/render-source.d.ts +5 -0
  127. package/dist/core/canvas/render-source.js +1 -0
  128. package/dist/core/canvas/types.d.ts +9 -3
  129. package/dist/core/command-plugins/bundle.d.ts +6 -1
  130. package/dist/core/command-plugins/bundle.js +26 -13
  131. package/dist/core/command.js +2 -1
  132. package/dist/core/config.d.ts +47 -1
  133. package/dist/core/config.js +137 -4
  134. package/dist/core/help.js +1 -1
  135. package/dist/core/human/__tests__/page-catalog.test.js +4 -0
  136. package/dist/core/human/__tests__/page-tickets.test.js +65 -52
  137. package/dist/core/human/__tests__/page.test.js +56 -98
  138. package/dist/core/human/__tests__/serial/inbox-core.test.js +6 -6
  139. package/dist/core/human/answer-text.js +3 -3
  140. package/dist/core/human/answer.d.ts +6 -4
  141. package/dist/core/human/answer.js +4 -10
  142. package/dist/core/human/component-docs.d.ts +11 -7
  143. package/dist/core/human/component-docs.js +361 -88
  144. package/dist/core/human/convention.d.ts +17 -3
  145. package/dist/core/human/convention.js +36 -5
  146. package/dist/core/human/feedback-companion.d.ts +20 -0
  147. package/dist/core/human/feedback-companion.js +98 -0
  148. package/dist/core/human/feedback.d.ts +65 -0
  149. package/dist/core/human/feedback.js +116 -0
  150. package/dist/core/human/page-catalog.d.ts +40 -5
  151. package/dist/core/human/page-catalog.js +102 -30
  152. package/dist/core/human/page-errors.d.ts +4 -0
  153. package/dist/core/human/page-errors.js +7 -0
  154. package/dist/core/human/page-eval.d.ts +20 -0
  155. package/dist/core/human/page-eval.js +123 -0
  156. package/dist/core/human/page-schema.d.ts +23 -191
  157. package/dist/core/human/page-schema.js +60 -89
  158. package/dist/core/human/page-synth.d.ts +1 -1
  159. package/dist/core/human/page-synth.js +15 -18
  160. package/dist/core/human/page.d.ts +12 -27
  161. package/dist/core/human/page.js +142 -474
  162. package/dist/core/human/root.d.ts +6 -2
  163. package/dist/core/human/root.js +12 -4
  164. package/dist/core/human/scan.d.ts +3 -4
  165. package/dist/core/human/scan.js +16 -15
  166. package/dist/core/human/summary.d.ts +1 -2
  167. package/dist/core/human/summary.js +2 -2
  168. package/dist/core/human/tickets.d.ts +20 -14
  169. package/dist/core/human/tickets.js +91 -31
  170. package/dist/core/human/types.d.ts +10 -2
  171. package/dist/core/preview-registry.js +8 -10
  172. package/dist/core/profiles/default-binding.d.ts +4 -0
  173. package/dist/core/profiles/default-binding.js +24 -0
  174. package/dist/core/profiles/deletion-reservation.d.ts +8 -0
  175. package/dist/core/profiles/deletion-reservation.js +38 -0
  176. package/dist/core/profiles/manifest.d.ts +3 -0
  177. package/dist/core/profiles/manifest.js +12 -0
  178. package/dist/core/profiles/select.js +2 -2
  179. package/dist/core/review/realize.js +3 -3
  180. package/dist/core/review/store.d.ts +6 -0
  181. package/dist/core/review/store.js +31 -0
  182. package/dist/core/runtime/bearings.d.ts +0 -4
  183. package/dist/core/runtime/bearings.js +4 -62
  184. package/dist/core/runtime/bin-contributions.d.ts +44 -0
  185. package/dist/core/runtime/bin-contributions.js +186 -0
  186. package/dist/core/runtime/broker/client-registry.d.ts +4 -0
  187. package/dist/core/runtime/broker/client-registry.js +13 -1
  188. package/dist/core/runtime/broker/extension-abort.d.ts +1 -1
  189. package/dist/core/runtime/broker/extension-abort.js +4 -2
  190. package/dist/core/runtime/broker/fault-retry.js +4 -0
  191. package/dist/core/runtime/broker/frame-dispatch.d.ts +3 -1
  192. package/dist/core/runtime/broker/frame-dispatch.js +5 -6
  193. package/dist/core/runtime/broker/read-ops.d.ts +1 -1
  194. package/dist/core/runtime/broker/read-ops.js +2 -2
  195. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  196. package/dist/core/runtime/broker/rebind.js +6 -1
  197. package/dist/core/runtime/broker-extension-render.js +19 -0
  198. package/dist/core/runtime/broker-protocol.d.ts +14 -0
  199. package/dist/core/runtime/broker.d.ts +1 -1
  200. package/dist/core/runtime/broker.js +17 -6
  201. package/dist/core/runtime/front-door-env.d.ts +5 -0
  202. package/dist/core/runtime/front-door-env.js +16 -0
  203. package/dist/core/runtime/front-door.d.ts +1 -5
  204. package/dist/core/runtime/front-door.js +2 -5
  205. package/dist/core/runtime/host.d.ts +1 -1
  206. package/dist/core/runtime/invocation.d.ts +6 -0
  207. package/dist/core/runtime/invocation.js +10 -0
  208. package/dist/core/runtime/kickoff.js +34 -0
  209. package/dist/core/runtime/launch.d.ts +2 -6
  210. package/dist/core/runtime/node-read.js +4 -1
  211. package/dist/core/runtime/nodes.js +2 -0
  212. package/dist/core/runtime/promote.d.ts +1 -0
  213. package/dist/core/runtime/promote.js +3 -1
  214. package/dist/core/runtime/session-cycles.d.ts +6 -0
  215. package/dist/core/runtime/session-cycles.js +15 -1
  216. package/dist/core/runtime/session-visibility.d.ts +17 -8
  217. package/dist/core/runtime/session-visibility.js +19 -10
  218. package/dist/core/runtime/spawn-env.d.ts +9 -1
  219. package/dist/core/runtime/spawn-env.js +62 -2
  220. package/dist/core/runtime/stop-guard.d.ts +2 -2
  221. package/dist/core/runtime/stop-guard.js +2 -2
  222. package/dist/core/runtime/stop-signals.d.ts +1 -1
  223. package/dist/core/runtime/stop-signals.js +2 -2
  224. package/dist/core/runtime/tmux-bindings.js +1 -1
  225. package/dist/core/session-model/session-state.d.ts +4 -3
  226. package/dist/core/session-model/session-state.js +14 -1
  227. package/dist/core/user-settings.d.ts +21 -2
  228. package/dist/core/user-settings.js +32 -11
  229. package/dist/core/worktree.d.ts +15 -45
  230. package/dist/core/worktree.js +59 -261
  231. package/dist/daemon/api/__tests__/seam/profile-delete.test.d.ts +1 -0
  232. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +386 -0
  233. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  234. package/dist/daemon/api/handlers/broker-ops.js +9 -5
  235. package/dist/daemon/api/handlers/feedback-comments.d.ts +2 -0
  236. package/dist/daemon/api/handlers/feedback-comments.js +207 -0
  237. package/dist/daemon/api/handlers/human.js +24 -20
  238. package/dist/daemon/api/handlers/inbox.d.ts +10 -0
  239. package/dist/daemon/api/handlers/inbox.js +39 -115
  240. package/dist/daemon/api/handlers/profiles.js +11 -29
  241. package/dist/daemon/api/map.d.ts +6 -1
  242. package/dist/daemon/api/map.js +23 -0
  243. package/dist/daemon/api/server.js +3 -1
  244. package/dist/daemon/companion-retire.d.ts +2 -0
  245. package/dist/daemon/companion-retire.js +33 -0
  246. package/dist/daemon/cron-run.js +14 -16
  247. package/dist/daemon/human/finish.d.ts +12 -7
  248. package/dist/daemon/human/finish.js +101 -38
  249. package/dist/daemon/human/sweep.js +5 -1
  250. package/dist/daemon/profile-delete.d.ts +7 -0
  251. package/dist/daemon/profile-delete.js +306 -0
  252. package/dist/daemon/reconcilers/broker-supervision.js +3 -1
  253. package/dist/daemon/review/deliver.js +3 -3
  254. package/dist/daemon/review/finish.d.ts +0 -2
  255. package/dist/daemon/review/finish.js +1 -29
  256. package/dist/pi-extensions/__tests__/canvas-bash-valve.test.js +56 -1
  257. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +4 -4
  258. package/dist/pi-extensions/canvas-bash-valve.js +19 -5
  259. package/dist/pi-extensions/canvas-inbox-watcher.js +1 -1
  260. package/dist/pi-extensions/canvas-review-boundary.d.ts +4 -0
  261. package/dist/pi-extensions/canvas-review-boundary.js +18 -9
  262. package/dist/pi-extensions/canvas-stophook.js +4 -4
  263. package/dist/shared/generated-context.js +2 -2
  264. package/dist/types.d.ts +44 -2
  265. package/dist/types.js +7 -2
  266. package/package.json +6 -5
  267. package/runtime.lock.json +5 -33
  268. package/dist/builtin-memory/init.md +0 -38
  269. package/dist/builtin-memory/plan.md +0 -19
  270. package/dist/builtin-memory/spec.md +0 -19
  271. package/dist/commands/human/doc.d.ts +0 -2
  272. package/dist/commands/human/doc.js +0 -91
  273. package/dist/commands/human/html.js +0 -81
  274. package/dist/commands/human/inbox.d.ts +0 -2
  275. package/dist/core/human/__tests__/html-markdown.test.js +0 -52
  276. package/dist/core/human/__tests__/page-render.test.js +0 -66
  277. package/dist/core/human/html-markdown.d.ts +0 -3
  278. package/dist/core/human/html-markdown.js +0 -288
  279. package/dist/core/human/page-render.d.ts +0 -4
  280. package/dist/core/human/page-render.js +0 -105
  281. package/dist/pages/bundle.css +0 -1
  282. package/dist/pages/bundle.js +0 -1778
  283. package/dist/pages/comments.d.ts +0 -72
  284. package/dist/pages/comments.js +0 -176
  285. package/dist/pages/controls.d.ts +0 -98
  286. package/dist/pages/controls.js +0 -261
  287. package/dist/pages/elements/cards.d.ts +0 -28
  288. package/dist/pages/elements/cards.js +0 -915
  289. package/dist/pages/elements/chart.d.ts +0 -23
  290. package/dist/pages/elements/chart.js +0 -664
  291. package/dist/pages/elements/options.d.ts +0 -30
  292. package/dist/pages/elements/options.js +0 -742
  293. package/dist/pages/elements/pages.d.ts +0 -30
  294. package/dist/pages/elements/pages.js +0 -377
  295. package/dist/pages/elements/slot.d.ts +0 -26
  296. package/dist/pages/elements/slot.js +0 -112
  297. package/dist/pages/elements/table.d.ts +0 -36
  298. package/dist/pages/elements/table.js +0 -1043
  299. package/dist/pages/elements/text.d.ts +0 -31
  300. package/dist/pages/elements/text.js +0 -1175
  301. package/dist/pages/entry.d.ts +0 -8
  302. package/dist/pages/entry.js +0 -8
  303. package/dist/pages/host.d.ts +0 -134
  304. package/dist/pages/host.js +0 -165
  305. package/dist/pages/readonly.d.ts +0 -24
  306. package/dist/pages/readonly.js +0 -31
  307. package/dist/pages/register.d.ts +0 -2
  308. package/dist/pages/register.js +0 -3
  309. package/dist/pages/responses.d.ts +0 -37
  310. package/dist/pages/responses.js +0 -56
  311. package/dist/pages/slot-config.d.ts +0 -36
  312. package/dist/pages/slot-config.js +0 -50
  313. package/dist/pages/types.d.ts +0 -98
  314. package/dist/pages/types.js +0 -23
  315. /package/dist/{core/human/__tests__/html-markdown.test.d.ts → commands/__tests__/node-message.test.d.ts} +0 -0
  316. /package/dist/core/{human/__tests__/page-render.test.d.ts → __tests__/plugin-page-components.test.d.ts} +0 -0
@@ -1,72 +0,0 @@
1
- /**
2
- * Comment list algebra, shared by every element in the bundle so commenting is one
3
- * behaviour and not five near-identical ones.
4
- *
5
- * The editing model is **one comment per anchor**: an option, a row, a column, a card or a
6
- * range holds at most one comment, and re-commenting edits it. The response type still
7
- * carries a list with ids, because a `range` anchor on a long document naturally grows
8
- * several and the contract should not have to change when it does.
9
- *
10
- * Every function here is pure over the array it is given — elements hold their own comment
11
- * list in local state, replace it with the returned one, and hand the whole response to
12
- * `respond()`.
13
- */
14
- import type { Comment, CommentAnchor } from './types.js';
15
- /**
16
- * Whether this slot can record a comment at all.
17
- *
18
- * Comments ride the slot's response: `respond(slotId, …)` is the only way one leaves the
19
- * frame, so a slot with no `slot-id` has nowhere to put it. That is a real page shape — a
20
- * table with no row or column selection is display-only and the renderer gives it no id
21
- * (`isResponseBearingSlot`), and a hand-authored html page can omit the attribute on any
22
- * element — and it used to render the full comment affordance anyway: the trigger opened, the
23
- * box took the words, Save closed it, and the comment was dropped on the floor. An affordance
24
- * that cannot keep what it accepts should not be drawn, so the elements build no comment UI
25
- * when this is false.
26
- */
27
- export declare function canRecordComments(slotId: string | undefined): boolean;
28
- /** A stable string identity for an anchor, used to find and key comments. */
29
- export declare function anchorKey(anchor: CommentAnchor): string;
30
- /** The comment on `anchor`, if the user has left one. */
31
- export declare function findComment(comments: Comment[], anchor: CommentAnchor): Comment | undefined;
32
- /**
33
- * Write a comment at `anchor`, replacing any comment already there. Empty or whitespace-only
34
- * text removes it — clearing the box is how you delete, so the popover never needs a separate
35
- * destructive path for "I changed my mind". An edit keeps the existing comment's id, so the
36
- * response is stable across retyping.
37
- */
38
- export declare function setComment(comments: Comment[], anchor: CommentAnchor, text: string): Comment[];
39
- /**
40
- * Take over a comment list the host saved earlier (`savedResponse`), as this element's own
41
- * local state. Malformed entries are dropped rather than thrown on — hydration must never be
42
- * the reason a page fails to render — and the one-comment-per-anchor rule is re-imposed.
43
- *
44
- * Adopting also advances the id counter past every `cN` id taken from the saved list, so a
45
- * comment written after a reopen cannot be minted with an id a saved comment already holds.
46
- */
47
- export declare function adoptComments(value: unknown): Comment[];
48
- /**
49
- * Comment ids are frame-local: the host does not mint them, and nothing downstream keys off
50
- * their value — `validatePageResponses` only requires a non-empty string. One counter is
51
- * shared by every element in the bundle, so ids are unique across a whole page and stay
52
- * legible in a response the human reads.
53
- */
54
- export declare function newCommentId(): string;
55
- /**
56
- * The quoted region as a composer shows it back: what you selected, at a glance, in about two
57
- * lines however much you selected.
58
- *
59
- * A range anchor carries the selection verbatim, and a selection is as long as the person made
60
- * it — a whole paragraph is a normal thing to comment on. Rendered verbatim that quote pushed
61
- * the box and the save button off the bottom of the popover, so the thing being written could
62
- * not be seen while writing it. The preview keeps both ends — the beginning says what was
63
- * selected and the end says where it stopped, which is exactly what a person checks — and
64
- * elides the middle. Line breaks collapse, because a preview is one run of text and a quote
65
- * that keeps its paragraph shape is the blowout again in another form.
66
- *
67
- * The comment itself is still anchored to the full range: this is what is shown, never what is
68
- * stored.
69
- */
70
- export declare function quotePreview(quote: string): string;
71
- /** A short, human label for what a comment is attached to. */
72
- export declare function anchorLabel(anchor: CommentAnchor): string;
@@ -1,176 +0,0 @@
1
- /**
2
- * Comment list algebra, shared by every element in the bundle so commenting is one
3
- * behaviour and not five near-identical ones.
4
- *
5
- * The editing model is **one comment per anchor**: an option, a row, a column, a card or a
6
- * range holds at most one comment, and re-commenting edits it. The response type still
7
- * carries a list with ids, because a `range` anchor on a long document naturally grows
8
- * several and the contract should not have to change when it does.
9
- *
10
- * Every function here is pure over the array it is given — elements hold their own comment
11
- * list in local state, replace it with the returned one, and hand the whole response to
12
- * `respond()`.
13
- */
14
- /**
15
- * Whether this slot can record a comment at all.
16
- *
17
- * Comments ride the slot's response: `respond(slotId, …)` is the only way one leaves the
18
- * frame, so a slot with no `slot-id` has nowhere to put it. That is a real page shape — a
19
- * table with no row or column selection is display-only and the renderer gives it no id
20
- * (`isResponseBearingSlot`), and a hand-authored html page can omit the attribute on any
21
- * element — and it used to render the full comment affordance anyway: the trigger opened, the
22
- * box took the words, Save closed it, and the comment was dropped on the floor. An affordance
23
- * that cannot keep what it accepts should not be drawn, so the elements build no comment UI
24
- * when this is false.
25
- */
26
- export function canRecordComments(slotId) {
27
- return slotId !== undefined;
28
- }
29
- /** A stable string identity for an anchor, used to find and key comments. */
30
- export function anchorKey(anchor) {
31
- switch (anchor.kind) {
32
- case 'whole':
33
- return 'whole';
34
- case 'option':
35
- return `option:${anchor.optionId}`;
36
- case 'row':
37
- return `row:${anchor.rowId}`;
38
- case 'column':
39
- return `column:${anchor.columnId}`;
40
- case 'card':
41
- return `card:${anchor.cardId}`;
42
- case 'range':
43
- return `range:${anchor.start}:${anchor.end}`;
44
- }
45
- }
46
- /** The comment on `anchor`, if the user has left one. */
47
- export function findComment(comments, anchor) {
48
- const key = anchorKey(anchor);
49
- return comments.find((comment) => anchorKey(comment.anchor) === key);
50
- }
51
- /**
52
- * Write a comment at `anchor`, replacing any comment already there. Empty or whitespace-only
53
- * text removes it — clearing the box is how you delete, so the popover never needs a separate
54
- * destructive path for "I changed my mind". An edit keeps the existing comment's id, so the
55
- * response is stable across retyping.
56
- */
57
- export function setComment(comments, anchor, text) {
58
- const key = anchorKey(anchor);
59
- const rest = comments.filter((comment) => anchorKey(comment.anchor) !== key);
60
- const trimmed = text.trim();
61
- if (trimmed === '')
62
- return rest;
63
- const existing = comments.find((comment) => anchorKey(comment.anchor) === key);
64
- return [...rest, { id: existing?.id ?? newCommentId(), anchor, text: trimmed }];
65
- }
66
- let counter = 0;
67
- /** Whether a value read back from a host is a comment anchor this bundle understands. */
68
- function isAnchor(value) {
69
- if (typeof value !== 'object' || value === null)
70
- return false;
71
- const anchor = value;
72
- switch (anchor.kind) {
73
- case 'whole':
74
- return true;
75
- case 'option':
76
- return typeof anchor.optionId === 'string';
77
- case 'row':
78
- return typeof anchor.rowId === 'string';
79
- case 'column':
80
- return typeof anchor.columnId === 'string';
81
- case 'card':
82
- return typeof anchor.cardId === 'string';
83
- case 'range':
84
- return typeof anchor.start === 'number' && typeof anchor.end === 'number' && typeof anchor.quote === 'string';
85
- default:
86
- return false;
87
- }
88
- }
89
- /**
90
- * Take over a comment list the host saved earlier (`savedResponse`), as this element's own
91
- * local state. Malformed entries are dropped rather than thrown on — hydration must never be
92
- * the reason a page fails to render — and the one-comment-per-anchor rule is re-imposed.
93
- *
94
- * Adopting also advances the id counter past every `cN` id taken from the saved list, so a
95
- * comment written after a reopen cannot be minted with an id a saved comment already holds.
96
- */
97
- export function adoptComments(value) {
98
- if (!Array.isArray(value))
99
- return [];
100
- const adopted = [];
101
- for (const entry of value) {
102
- if (typeof entry !== 'object' || entry === null)
103
- continue;
104
- const { id, anchor, text } = entry;
105
- if (typeof id !== 'string' || id === '')
106
- continue;
107
- if (typeof text !== 'string' || text.trim() === '')
108
- continue;
109
- if (!isAnchor(anchor))
110
- continue;
111
- if (findComment(adopted, anchor) !== undefined)
112
- continue;
113
- adopted.push({ id, anchor: { ...anchor }, text });
114
- const minted = /^c(\d+)$/.exec(id);
115
- if (minted !== null)
116
- counter = Math.max(counter, Number(minted[1]));
117
- }
118
- return adopted;
119
- }
120
- /**
121
- * Comment ids are frame-local: the host does not mint them, and nothing downstream keys off
122
- * their value — `validatePageResponses` only requires a non-empty string. One counter is
123
- * shared by every element in the bundle, so ids are unique across a whole page and stay
124
- * legible in a response the human reads.
125
- */
126
- export function newCommentId() {
127
- counter += 1;
128
- return `c${counter}`;
129
- }
130
- /** How much of a quoted region a preview shows before it is worth eliding. Two lines in a
131
- * 20em popover at the quote's own size, which is the whole budget the composer can spare. */
132
- const QUOTE_BUDGET = 84;
133
- const QUOTE_HEAD = 48;
134
- const QUOTE_TAIL = 30;
135
- /** Drop a trailing part-word, so a head cut lands between words rather than inside one. */
136
- function headWords(text) {
137
- const cut = text.lastIndexOf(' ');
138
- return (cut > 0 && cut >= text.length - 12 ? text.slice(0, cut) : text).trimEnd();
139
- }
140
- /** Drop a leading part-word, the same way, at the other end of the elision. */
141
- function tailWords(text) {
142
- const cut = text.indexOf(' ');
143
- return (cut !== -1 && cut < 12 ? text.slice(cut + 1) : text).trimStart();
144
- }
145
- /**
146
- * The quoted region as a composer shows it back: what you selected, at a glance, in about two
147
- * lines however much you selected.
148
- *
149
- * A range anchor carries the selection verbatim, and a selection is as long as the person made
150
- * it — a whole paragraph is a normal thing to comment on. Rendered verbatim that quote pushed
151
- * the box and the save button off the bottom of the popover, so the thing being written could
152
- * not be seen while writing it. The preview keeps both ends — the beginning says what was
153
- * selected and the end says where it stopped, which is exactly what a person checks — and
154
- * elides the middle. Line breaks collapse, because a preview is one run of text and a quote
155
- * that keeps its paragraph shape is the blowout again in another form.
156
- *
157
- * The comment itself is still anchored to the full range: this is what is shown, never what is
158
- * stored.
159
- */
160
- export function quotePreview(quote) {
161
- const flat = quote.replace(/\s+/gu, ' ').trim();
162
- if (flat.length <= QUOTE_BUDGET)
163
- return flat;
164
- return `${headWords(flat.slice(0, QUOTE_HEAD))} \u2026 ${tailWords(flat.slice(-QUOTE_TAIL))}`;
165
- }
166
- /** A short, human label for what a comment is attached to. */
167
- export function anchorLabel(anchor) {
168
- switch (anchor.kind) {
169
- case 'whole':
170
- return 'this';
171
- case 'range':
172
- return `\u201c${anchor.quote}\u201d`;
173
- default:
174
- return anchorKey(anchor);
175
- }
176
- }
@@ -1,98 +0,0 @@
1
- /**
2
- * The shared control paint: the one focus treatment every focusable thing in the page bundle
3
- * wears, the one radio and checkbox recipe every element draws with, and the one writing-box
4
- * recipe every textarea and text field wears.
5
- *
6
- * All three exist for the same reason — a control that differs element to element reads as
7
- * foreign, and the host's kit draws each of them exactly one way.
8
- *
9
- * A page frame is a bare document rendered beside a host's own UI, and the host's controls are
10
- * drawn ones — a bordered box with an accent fill and a tick, a ring with a dot. A native UA
11
- * control cannot be made to look like that: `accent-color` only tints the UA's own drawing, so
12
- * the frame's radios kept the platform's shape, size, checked treatment and focus ring while
13
- * everything around them wore the host's. They read as foreign, because they were.
14
- *
15
- * So the controls are drawn here instead, out of the same `--crtr-*` tokens the rest of the
16
- * bundle spends. They stay real `<input type="radio">` / `<input type="checkbox">` elements —
17
- * the label association, the arrow-key behaviour of a native radio group, Space, the `change`
18
- * event and every `target.type` check keep working exactly as before. Only the paint moved.
19
- *
20
- * The mark is a `::before` on the input, which is why `display: inline-grid` is on the control:
21
- * an `appearance: none` input has no UA-drawn glyph left and no content of its own, so the grid
22
- * exists purely to centre the one pseudo-element in it.
23
- *
24
- * ## This module is the `--crtr-control-*` family
25
- *
26
- * Every value these three recipes paint with is read through a named component token, so a
27
- * host restyles the bundle's controls without touching crtr — custom properties inherit
28
- * through shadow roots, which is the whole mechanism. The short version of the layering rule
29
- * is:
30
- *
31
- * var(--crtr-<element>-<knob>, var(--crtr-control-<part>-<knob>, <kit default>))
32
- *
33
- * The element layer is the optional `{ scope }` first argument each function takes. A call
34
- * that passes `{ scope: 'text-editor' }` gets `--crtr-text-editor-padding` laid over the
35
- * family's `--crtr-control-writing-padding`; a call that passes no scope reads the family
36
- * token alone. Every default stays inline here — the family tokens are deliberately NOT
37
- * declared in `bundle.css`, because an undeclared token is what lets the fallback chain carry
38
- * the kit default all the way down.
39
- *
40
- * The innermost fallback of each chain is a theme token read with a CSS system colour behind
41
- * it, because these rules live in the element's own shadow root and therefore apply even when
42
- * `bundle.css` — where the whole `--crtr-*` theme map is declared — never loaded. That way an
43
- * unstyled frame still shows a control with a visible box, a visible mark and a visible focus
44
- * ring rather than a blank square.
45
- */
46
- /**
47
- * The element-level token layer a call site lays over the shared family.
48
- *
49
- * `scope` is the `--crtr-`-suffix an element claims for these particular controls, so
50
- * `{ scope: 'text-editor' }` mints `--crtr-text-editor-<knob>`. It is the element's name plus
51
- * the anatomy part it is styling, and it is the element's to choose: the family part name
52
- * (`writing`, `box`, `radio`, `checkbox`, `focus`, `mark`) describes the shared recipe, while
53
- * the scope describes the thing on the page a person is looking at.
54
- */
55
- export interface TokenScope {
56
- readonly scope: string;
57
- }
58
- /**
59
- * The focus treatment bound to the selectors of things that are neither a writing box nor a
60
- * drawn control — every button in the bundle. `writingBoxStyle` and `controlStyle` already
61
- * carry it, so they do not need this.
62
- *
63
- * The ring is outset paint, so a button close enough to the edge of the page frame to have the
64
- * ring clipped needs a gutter around it, the way `<crtr-text>`'s writing surface does.
65
- */
66
- export declare function focusRingStyle(...selectors: readonly string[]): string;
67
- export declare function focusRingStyle(scope: TokenScope, ...selectors: readonly string[]): string;
68
- /**
69
- * The one writing-box recipe — every `<textarea>` and single-line `<input type="text">` the
70
- * bundle puts in front of a person paints with this.
71
- *
72
- * It is the host kit's own field, translated token for token from
73
- * `apps/gateway/components/ui/textarea.tsx` — which the kit's `input.tsx` matches declaration
74
- * for declaration, because in the kit a one-line field and a writing surface are the same
75
- * control at two heights: text at the body size and body weight (`font: inherit`, which against
76
- * `--crtr-font-size` is the kit's `md:text-sm`), `px-3 py-2`, a hairline border at the small
77
- * radius, the faintest fill against the page, `shadow-xs`, and the shared focus ring.
78
- *
79
- * Before this existed each element wrote its own comment box, and they had drifted: three
80
- * different paddings, two different fills, and an `outline` focus ring where the kit uses a
81
- * border-plus-ring. A comment box has to read as the same thing wherever a person meets it, so
82
- * the recipe is shared rather than repeated — and `<crtr-text>`'s one-line field and its
83
- * textarea are one call with two selectors, so they cannot drift apart again.
84
- *
85
- * Sizing that belongs to one box — how tall it starts, whether it may be dragged taller — stays
86
- * in the element's own rule, which follows this block and wins at equal specificity.
87
- */
88
- export declare function writingBoxStyle(...selectors: readonly string[]): string;
89
- export declare function writingBoxStyle(scope: TokenScope, ...selectors: readonly string[]): string;
90
- /**
91
- * The recipe, bound to the `part` selectors an element gives its controls.
92
- *
93
- * The result is interpolated into that element's shadow-root stylesheet. Anything an element
94
- * owns rather than shares — where the control sits against its label — stays in the element's
95
- * own rule, which follows this block and therefore wins at equal specificity.
96
- */
97
- export declare function controlStyle(...selectors: readonly string[]): string;
98
- export declare function controlStyle(scope: TokenScope, ...selectors: readonly string[]): string;
@@ -1,261 +0,0 @@
1
- /**
2
- * The shared control paint: the one focus treatment every focusable thing in the page bundle
3
- * wears, the one radio and checkbox recipe every element draws with, and the one writing-box
4
- * recipe every textarea and text field wears.
5
- *
6
- * All three exist for the same reason — a control that differs element to element reads as
7
- * foreign, and the host's kit draws each of them exactly one way.
8
- *
9
- * A page frame is a bare document rendered beside a host's own UI, and the host's controls are
10
- * drawn ones — a bordered box with an accent fill and a tick, a ring with a dot. A native UA
11
- * control cannot be made to look like that: `accent-color` only tints the UA's own drawing, so
12
- * the frame's radios kept the platform's shape, size, checked treatment and focus ring while
13
- * everything around them wore the host's. They read as foreign, because they were.
14
- *
15
- * So the controls are drawn here instead, out of the same `--crtr-*` tokens the rest of the
16
- * bundle spends. They stay real `<input type="radio">` / `<input type="checkbox">` elements —
17
- * the label association, the arrow-key behaviour of a native radio group, Space, the `change`
18
- * event and every `target.type` check keep working exactly as before. Only the paint moved.
19
- *
20
- * The mark is a `::before` on the input, which is why `display: inline-grid` is on the control:
21
- * an `appearance: none` input has no UA-drawn glyph left and no content of its own, so the grid
22
- * exists purely to centre the one pseudo-element in it.
23
- *
24
- * ## This module is the `--crtr-control-*` family
25
- *
26
- * Every value these three recipes paint with is read through a named component token, so a
27
- * host restyles the bundle's controls without touching crtr — custom properties inherit
28
- * through shadow roots, which is the whole mechanism. The short version of the layering rule
29
- * is:
30
- *
31
- * var(--crtr-<element>-<knob>, var(--crtr-control-<part>-<knob>, <kit default>))
32
- *
33
- * The element layer is the optional `{ scope }` first argument each function takes. A call
34
- * that passes `{ scope: 'text-editor' }` gets `--crtr-text-editor-padding` laid over the
35
- * family's `--crtr-control-writing-padding`; a call that passes no scope reads the family
36
- * token alone. Every default stays inline here — the family tokens are deliberately NOT
37
- * declared in `bundle.css`, because an undeclared token is what lets the fallback chain carry
38
- * the kit default all the way down.
39
- *
40
- * The innermost fallback of each chain is a theme token read with a CSS system colour behind
41
- * it, because these rules live in the element's own shadow root and therefore apply even when
42
- * `bundle.css` — where the whole `--crtr-*` theme map is declared — never loaded. That way an
43
- * unstyled frame still shows a control with a visible box, a visible mark and a visible focus
44
- * ring rather than a blank square.
45
- */
46
- /** Lucide's `check`, as a mask. Colour comes from the pseudo-element, so the paint is opaque
47
- * black and the geometry — including the 2-unit round-capped stroke — is the kit's own. */
48
- const CHECK_MASK = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E\")";
49
- /** Lucide's `minus` — the glyph a partial selection wears, so "some" cannot read as "none". */
50
- const MINUS_MASK = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3C/svg%3E\")";
51
- /** The selector list, each entry suffixed and joined the way a CSS rule wants it. */
52
- function each(selectors, suffix = '') {
53
- return selectors.map((selector) => `${selector}${suffix}`).join(',\n ');
54
- }
55
- /**
56
- * Splits the optional leading scope off a variadic selector list.
57
- *
58
- * The scope is a leading argument rather than a trailing options object because the selector
59
- * list is variadic and reads as one thought; an element file's call stays a single line either
60
- * way.
61
- */
62
- function split(args) {
63
- const first = args[0];
64
- if (typeof first === 'object')
65
- return [first.scope, args.slice(1)];
66
- return [null, args];
67
- }
68
- /**
69
- * A chain builder for one family part: given a knob name and the kit's current value for it,
70
- * it returns the `var()` chain a declaration is written through.
71
- *
72
- * `elementPart` is what the element layer prefixes the knob with. It is empty only for the one
73
- * family per call that owns the plain knob names, and set on every other family sharing that
74
- * call — two families that both spend `fill` or `mark-color` would otherwise collapse onto a
75
- * single element token, and overriding the box's fill would repaint the mark inside it.
76
- */
77
- function chain(scope, familyPrefix, elementPart) {
78
- return (name, fallback) => {
79
- const family = `var(--crtr-${familyPrefix}-${name}, ${fallback})`;
80
- if (scope === null)
81
- return family;
82
- const element = elementPart === '' ? `${scope}-${name}` : `${scope}-${elementPart}-${name}`;
83
- return `var(--crtr-${element}, ${family})`;
84
- };
85
- }
86
- /**
87
- * The one focus treatment, and the only one the bundle draws.
88
- *
89
- * It is the kit's, verbatim: the border takes the focus colour and a soft ring sits just
90
- * outside it — `focus-visible:border-aurora-cyan/60 focus-visible:ring-aurora-cyan/25
91
- * focus-visible:ring-[3px]`, which `apps/gateway/components/ui/{input,textarea,button,
92
- * checkbox}.tsx` all carry identically. A UA `outline` is never it; every element in this
93
- * bundle wrote its own `outline: 2px solid` before this existed, so a focused button and the
94
- * focused field under it drew two visibly different rings.
95
- *
96
- * It is one declaration block rather than a ring plus a resting elevation, so a missing shadow
97
- * token can never take the ring down with it.
98
- *
99
- * The ring width is a flat three pixels on every focusable thing the kit draws — a button, a
100
- * field, a checkbox — so its default is in `rem` rather than `em`: an `em` ring would come out
101
- * a different thickness on a button set at `0.875em` than on the field beside it, which is the
102
- * drift this module exists to remove.
103
- *
104
- * A focusable region that is not a control — a scrolling thread, a table body, a prose block —
105
- * is deliberately NOT in this family. Those run the full width of the frame the host gives the
106
- * page, so a ring painted outside them is clipped and draws three sides of a rectangle; they
107
- * keep an inset `outline` and say so at the rule.
108
- */
109
- function focusRing(scope) {
110
- const focus = chain(scope, 'control-focus', 'focus');
111
- const width = focus('ring-width', '0.1875rem');
112
- const color = focus('ring-color', 'color-mix(in srgb, var(--crtr-color-focus, CanvasText) 25%, transparent)');
113
- return `
114
- outline: ${focus('outline', 'none')};
115
- border-color: ${focus('border-color', 'color-mix(in srgb, var(--crtr-color-focus, CanvasText) 60%, transparent)')};
116
- box-shadow: ${focus('ring', `0 0 0 ${width}\n ${color}`)};`;
117
- }
118
- export function focusRingStyle(...args) {
119
- const [scope, selectors] = split(args);
120
- return `
121
- ${each(selectors, ':focus-visible')} {${focusRing(scope)}
122
- }
123
- `;
124
- }
125
- export function writingBoxStyle(...args) {
126
- const [scope, selectors] = split(args);
127
- const box = chain(scope, 'control-writing', '');
128
- const any = chain(scope, 'control', '');
129
- const motion = any('transition', '120ms ease');
130
- return `
131
- ${each(selectors)} {
132
- /* Block, not the UA's inline-block: a full-width field on its own line would otherwise sit
133
- in a line box and carry a descender's worth of dead space under it. */
134
- display: block;
135
- box-sizing: border-box;
136
- width: 100%;
137
- padding: ${box('padding', 'var(--crtr-space-2) var(--crtr-space-3)')};
138
- color: ${box('text-color', 'var(--crtr-color-text, CanvasText)')};
139
- font: ${box('font', 'inherit')};
140
- line-height: ${box('line-height', 'var(--crtr-line-height, 1.5)')};
141
- background: ${box('fill', 'color-mix(in srgb, var(--crtr-color-text, CanvasText) 2%, var(--crtr-color-background, Canvas))')};
142
- border: ${box('border-width', '1px')} ${box('border-style', 'solid')} ${box('border-color', 'var(--crtr-color-border, CanvasText)')};
143
- border-radius: ${box('radius', 'var(--crtr-radius-small)')};
144
- box-shadow: ${box('shadow', 'var(--crtr-shadow)')};
145
- transition: border-color ${motion}, box-shadow ${motion};
146
- }
147
-
148
- ${each(selectors, '::placeholder')} {
149
- color: ${box('placeholder-color', 'var(--crtr-color-text-muted, GrayText)')};
150
- }
151
-
152
- ${each(selectors, ':focus-visible')} {${focusRing(scope)}
153
- }
154
-
155
- /* A page that can no longer take an answer keeps its text selectable and copyable, and drops
156
- the affordances that say it could still be rewritten. */
157
- ${each(selectors, ':read-only')} {
158
- background: ${box('readonly-fill', 'var(--crtr-color-surface, Canvas)')};
159
- box-shadow: ${box('readonly-shadow', 'none')};
160
- resize: none;
161
- }
162
- `;
163
- }
164
- export function controlStyle(...args) {
165
- const [scope, selectors] = split(args);
166
- const box = chain(scope, 'control-box', '');
167
- const mark = chain(scope, 'control-mark', 'mark');
168
- const radio = chain(scope, 'control-radio', 'radio');
169
- const check = chain(scope, 'control-checkbox', 'checkbox');
170
- const any = chain(scope, 'control', '');
171
- const motion = any('transition', '120ms ease');
172
- return `
173
- ${each(selectors)} {
174
- /* The box tracks the host's font token like every other size in the bundle. The kit's
175
- control is 16px against 14px text; these ratios are that pair, kept proportional. */
176
- --control-box: ${box('size', '1.125em')};
177
- appearance: none;
178
- -webkit-appearance: none;
179
- box-sizing: border-box;
180
- display: inline-grid;
181
- place-content: center;
182
- flex: none;
183
- width: var(--control-box);
184
- height: var(--control-box);
185
- margin: 0;
186
- padding: 0;
187
- vertical-align: middle;
188
- /* Transparent rather than the background token, so an empty control on a selected row
189
- carries that row's tint the way the kit's does. */
190
- background: ${box('fill', 'transparent')};
191
- border: ${box('border-width', '1px')} ${box('border-style', 'solid')} ${box('border-color', 'var(--crtr-color-border, CanvasText)')};
192
- border-radius: ${box('radius', 'calc(var(--control-box) * 0.25)')};
193
- box-shadow: ${box('shadow', 'var(--crtr-shadow)')};
194
- cursor: pointer;
195
- transition: background-color ${motion}, border-color ${motion}, box-shadow ${motion};
196
- }
197
-
198
- ${each(selectors, '[type="radio"]')} {
199
- border-radius: ${radio('radius', '50%')};
200
- }
201
-
202
- /* The mark. It is always present and always centred; selecting scales it in, which is the
203
- state change the kit animates too. */
204
- ${each(selectors, '::before')} {
205
- content: "";
206
- background: ${mark('fill', 'currentColor')};
207
- transform: scale(0);
208
- transition: transform ${motion};
209
- }
210
-
211
- ${each(selectors, ':checked::before')},
212
- ${each(selectors, ':indeterminate::before')} {
213
- transform: scale(1);
214
- }
215
-
216
- /* A radio keeps its own surface and marks itself with a dot in the accent; a checkbox fills
217
- with the accent and carries the tick in the accent's contrast colour. */
218
- ${each(selectors, '[type="radio"]::before')} {
219
- width: ${radio('mark-size', 'calc(var(--control-box) * 0.5)')};
220
- height: ${radio('mark-size', 'calc(var(--control-box) * 0.5)')};
221
- border-radius: ${radio('mark-radius', '50%')};
222
- color: ${radio('mark-color', 'var(--crtr-color-accent, CanvasText)')};
223
- }
224
-
225
- ${each(selectors, '[type="radio"]:checked')} {
226
- border-color: ${radio('checked-border-color', 'var(--crtr-color-accent, CanvasText)')};
227
- }
228
-
229
- ${each(selectors, '[type="checkbox"]::before')} {
230
- width: ${check('mark-size', 'calc(var(--control-box) * 0.875)')};
231
- height: ${check('mark-size', 'calc(var(--control-box) * 0.875)')};
232
- color: ${check('mark-color', 'var(--crtr-color-accent-contrast, Canvas)')};
233
- -webkit-mask: ${check('mark-image', CHECK_MASK)} ${check('mark-layout', 'center / contain no-repeat')};
234
- mask: ${check('mark-image', CHECK_MASK)} ${check('mark-layout', 'center / contain no-repeat')};
235
- }
236
-
237
- ${each(selectors, '[type="checkbox"]:indeterminate::before')} {
238
- -webkit-mask-image: ${check('indeterminate-mark-image', MINUS_MASK)};
239
- mask-image: ${check('indeterminate-mark-image', MINUS_MASK)};
240
- }
241
-
242
- ${each(selectors, '[type="checkbox"]:checked')},
243
- ${each(selectors, '[type="checkbox"]:indeterminate')} {
244
- background: ${check('checked-fill', 'var(--crtr-color-accent, CanvasText)')};
245
- border-color: ${check('checked-border-color', 'var(--crtr-color-accent, CanvasText)')};
246
- }
247
-
248
- /* The bundle's one focus treatment. The box scales with the font token, but the ring does
249
- not: the kit's is a flat three pixels on a checkbox and on the field beside it alike. */
250
- ${each(selectors, '[type]:focus-visible')} {${focusRing(scope)}
251
- }
252
-
253
- /* A page that can no longer take an answer keeps its selection legible — the mark stays the
254
- accent, only dimmed — and drops every affordance that says it could still be changed. */
255
- ${each(selectors, ':disabled')} {
256
- opacity: ${any('disabled-opacity', '0.5')};
257
- box-shadow: ${any('disabled-shadow', 'none')};
258
- cursor: default;
259
- }
260
- `;
261
- }
@@ -1,28 +0,0 @@
1
- /**
2
- * `<crtr-cards>` — the choice `options` makes, when each candidate has enough body to
3
- * deserve its own surface: a meeting slot, a vendor, a search result.
4
- *
5
- * This is a port of the agent interaction kit's `cards` component, not a new design. The
6
- * selection treatment is the kit's selectable-surface recipe — a hairline surface that
7
- * answers the pointer and goes accent-toned once chosen — carrying the kit's selection
8
- * control and the kit's comment affordance. Navigation is the kit's classic list grammar
9
- * (`j`/`k` move, `x` selects, `c` comments), so a card grid, an option list and a table
10
- * are all driven the same way.
11
- *
12
- * Data arrives inline as `cards`. The element never touches the network: a page source file
13
- * is read and embedded once at submit, before this element renders.
14
- *
15
- * ## Every value here is a `--crtr-cards-*` token
16
- *
17
- * The card surface, its heading, its tag, the comment affordance and the three notice states
18
- * are all painted through `var(--crtr-cards-<part>-<knob>, <kit default>)`, so a host restyles
19
- * this element by setting properties on the document root — custom properties inherit into
20
- * shadow roots, which is the whole mechanism. The shared control, writing-box and focus
21
- * recipes carry their own element layer through the `{ scope }` each call passes, so the
22
- * card's radio reads `--crtr-cards-control-*` over the family's `--crtr-control-box-*`.
23
- *
24
- * Defaults stay inline at the rule that spends them and no `--crtr-cards-*` token is ever
25
- * declared: an unset token is what carries the kit default down the chain, which is why an
26
- * unstyled page renders exactly as it did before any of this existed.
27
- */
28
- export {};