@erclx/canon 5.25.0 → 5.27.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 (315) hide show
  1. package/README.md +4 -3
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/SKILL.md +2 -0
  4. package/claude/skills/auto-ship/SKILL.md +3 -11
  5. package/claude/skills/auto-ship/references/review-findings.md +20 -0
  6. package/claude/skills/backlog-triage/SKILL.md +2 -0
  7. package/claude/skills/bash-cli-script/SKILL.md +2 -0
  8. package/claude/skills/build-in-slices/SKILL.md +2 -0
  9. package/claude/skills/canon-cli/SKILL.md +2 -0
  10. package/claude/skills/canon-feedback/SKILL.md +2 -0
  11. package/claude/skills/canon-feedback-triage/SKILL.md +2 -0
  12. package/claude/skills/canon-operator/SKILL.md +2 -0
  13. package/claude/skills/canon-rollout/SKILL.md +3 -11
  14. package/claude/skills/canon-rollout/references/failure-recovery.md +20 -0
  15. package/claude/skills/canvas/SKILL.md +14 -1
  16. package/claude/skills/ci-workflow/SKILL.md +2 -0
  17. package/claude/skills/code-craft/SKILL.md +2 -0
  18. package/claude/skills/codebase-layout/SKILL.md +2 -0
  19. package/claude/skills/context-fold/REQUIREMENT.md +6 -2
  20. package/claude/skills/context-fold/SKILL.md +9 -21
  21. package/claude/skills/context-fold/references/anchor-sweep.md +2 -2
  22. package/claude/skills/context-fold/references/completion-report.md +26 -0
  23. package/claude/skills/create-rule/SKILL.md +2 -0
  24. package/claude/skills/create-skill/SKILL.md +2 -0
  25. package/claude/skills/create-standard/SKILL.md +2 -0
  26. package/claude/skills/decision-escalate/SKILL.md +2 -0
  27. package/claude/skills/deploy-app/SKILL.md +2 -0
  28. package/claude/skills/deprecation-migration/SKILL.md +2 -0
  29. package/claude/skills/design-extract/SKILL.md +2 -0
  30. package/claude/skills/design-taste/REQUIREMENT.md +1 -1
  31. package/claude/skills/design-taste/SKILL.md +6 -2
  32. package/claude/skills/design-taste/references/adopted.md +40 -0
  33. package/claude/skills/design-taste/references/kinds.md +1 -1
  34. package/claude/skills/design-taste/references/systems.md +1 -7
  35. package/claude/skills/design-taste/references/tells.md +2 -24
  36. package/claude/skills/docs-sync/REQUIREMENT.md +2 -1
  37. package/claude/skills/docs-sync/SKILL.md +2 -0
  38. package/claude/skills/document-health/REQUIREMENT.md +2 -0
  39. package/claude/skills/document-health/SKILL.md +23 -0
  40. package/claude/skills/document-health/references/axes.md +12 -0
  41. package/claude/skills/draft-and-pick/SKILL.md +3 -1
  42. package/claude/skills/draft-doc/SKILL.md +2 -0
  43. package/claude/skills/draft-doc/references/wiki.md +1 -1
  44. package/claude/skills/draft-figure/SKILL.md +2 -0
  45. package/claude/skills/draft-identity/SKILL.md +3 -1
  46. package/claude/skills/draft-ready/SKILL.md +2 -0
  47. package/claude/skills/draft-screencast/SKILL.md +11 -7
  48. package/claude/skills/draft-slides/REQUIREMENT.md +17 -12
  49. package/claude/skills/draft-slides/SKILL.md +33 -20
  50. package/claude/skills/git-branch/SKILL.md +2 -0
  51. package/claude/skills/git-commit/SKILL.md +2 -0
  52. package/claude/skills/git-followup/SKILL.md +2 -0
  53. package/claude/skills/git-issue/SKILL.md +2 -0
  54. package/claude/skills/git-issue/references/issue.md +10 -0
  55. package/claude/skills/git-pr/SKILL.md +2 -0
  56. package/claude/skills/git-pr/references/evidence.md +14 -6
  57. package/claude/skills/git-pr/references/labels.md +12 -0
  58. package/claude/skills/git-ship/SKILL.md +2 -0
  59. package/claude/skills/git-split/SKILL.md +21 -8
  60. package/claude/skills/git-stage/SKILL.md +2 -0
  61. package/claude/skills/git-worktree/SKILL.md +2 -0
  62. package/claude/skills/index-lookup/SKILL.md +2 -0
  63. package/claude/skills/markdown-propose/SKILL.md +2 -0
  64. package/claude/skills/markdown-propose/references/format.md +9 -0
  65. package/claude/skills/memory-capture/SKILL.md +2 -0
  66. package/claude/skills/memory-review/SKILL.md +2 -0
  67. package/claude/skills/memory-review/references/later-phases.md +7 -0
  68. package/claude/skills/plan-feature/SKILL.md +2 -0
  69. package/claude/skills/plan-groundwork/SKILL.md +2 -0
  70. package/claude/skills/plan-intake/SKILL.md +2 -0
  71. package/claude/skills/plan-intake-answer/SKILL.md +2 -0
  72. package/claude/skills/project-commands/SKILL.md +2 -0
  73. package/claude/skills/read-frames/SKILL.md +2 -0
  74. package/claude/skills/record-screencast/SKILL.md +2 -0
  75. package/claude/skills/repo-metadata/SKILL.md +2 -0
  76. package/claude/skills/restate-plainly/SKILL.md +2 -0
  77. package/claude/skills/review-address/SKILL.md +3 -7
  78. package/claude/skills/review-address/references/post-review-findings.md +16 -0
  79. package/claude/skills/review-branch/SKILL.md +2 -0
  80. package/claude/skills/review-craft/SKILL.md +2 -0
  81. package/claude/skills/review-craft/references/ui.md +2 -2
  82. package/claude/skills/review-pr/SKILL.md +4 -8
  83. package/claude/skills/review-pr/references/body-variants.md +52 -0
  84. package/claude/skills/review-pr/references/key-changes.md +16 -0
  85. package/claude/skills/review-pr/references/post.md +15 -43
  86. package/claude/skills/review-ui/SKILL.md +3 -1
  87. package/claude/skills/review-ui/references/post.md +4 -2
  88. package/claude/skills/role-orchestrator/SKILL.md +5 -14
  89. package/claude/skills/role-orchestrator/references/orchestrator-cloud-launch.md +8 -0
  90. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +13 -0
  91. package/claude/skills/role-orchestrator/references/orchestrator-handback.md +1 -1
  92. package/claude/skills/role-orchestrator/references/orchestrator-inbound.md +23 -0
  93. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +5 -33
  94. package/claude/skills/role-orchestrator/references/orchestrator-poll.md +1 -21
  95. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +1 -1
  96. package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +38 -0
  97. package/claude/skills/role-orchestrator/references/orchestrator-watch.md +26 -0
  98. package/claude/skills/role-planner/SKILL.md +2 -0
  99. package/claude/skills/role-reviewer/REQUIREMENT.md +1 -1
  100. package/claude/skills/role-reviewer/SKILL.md +2 -0
  101. package/claude/skills/role-worker/SKILL.md +2 -0
  102. package/claude/skills/search-craft/REQUIREMENT.md +1 -1
  103. package/claude/skills/search-craft/SKILL.md +5 -1
  104. package/claude/skills/search-craft/references/adopted.md +30 -0
  105. package/claude/skills/seed-sync/SKILL.md +2 -0
  106. package/claude/skills/session-compact/SKILL.md +2 -0
  107. package/claude/skills/session-map/SKILL.md +2 -0
  108. package/claude/skills/session-relay/SKILL.md +2 -0
  109. package/claude/skills/session-resume/SKILL.md +2 -0
  110. package/claude/skills/session-worktree/SKILL.md +3 -11
  111. package/claude/skills/session-worktree/references/install-command.md +20 -0
  112. package/claude/skills/sketch-design/SKILL.md +2 -0
  113. package/claude/skills/systematic-debugging/SKILL.md +2 -0
  114. package/claude/skills/target-check/SKILL.md +2 -0
  115. package/claude/skills/target-setup/SKILL.md +2 -0
  116. package/claude/skills/target-setup/references/detect.md +8 -0
  117. package/claude/skills/target-setup/references/indexes.md +13 -0
  118. package/claude/skills/target-setup/references/verify.md +8 -0
  119. package/claude/skills/task-board/SKILL.md +2 -0
  120. package/claude/skills/teach-workspace/SKILL.md +5 -15
  121. package/claude/skills/teach-workspace/references/lesson-build.md +75 -0
  122. package/claude/skills/teach-workspace/references/lesson-craft.md +13 -69
  123. package/claude/skills/teach-workspace/references/revisit.md +22 -0
  124. package/claude/skills/test-craft/SKILL.md +2 -0
  125. package/claude/skills/test-first/SKILL.md +4 -0
  126. package/claude/skills/test-first/references/adopted.md +36 -0
  127. package/claude/skills/ui-checklist/SKILL.md +2 -0
  128. package/claude/skills/ux-audit/SKILL.md +2 -0
  129. package/claude/skills/ux-measure/SKILL.md +2 -0
  130. package/claude/skills/ux-walkthrough/SKILL.md +2 -0
  131. package/claude/skills/video-craft/SKILL.md +2 -0
  132. package/claude/skills/write-human/SKILL.md +3 -1
  133. package/claude/skills/write-human/references/machine-tells.md +13 -0
  134. package/claude/skills/youtube-transcripts/SKILL.md +2 -0
  135. package/docs/agents/canvas.md +24 -6
  136. package/docs/agents/capture.md +6 -6
  137. package/docs/agents/commands.md +5 -5
  138. package/docs/agents/index.md +5 -5
  139. package/docs/agents/install-and-sync.md +7 -0
  140. package/docs/agents/key-changes.md +1 -1
  141. package/docs/agents/pr-evidence.md +38 -15
  142. package/docs/agents/pr-local.md +19 -13
  143. package/docs/agents/pr-preview.md +44 -21
  144. package/docs/agents/records-stale.md +22 -9
  145. package/docs/agents/records.md +1 -1
  146. package/docs/agents/sandbox.md +29 -5
  147. package/docs/agents/scripting.md +8 -1
  148. package/docs/agents/skills-audit.md +11 -3
  149. package/docs/agents/slides.md +15 -3
  150. package/docs/workflow/ai-workflow.md +1 -1
  151. package/docs/workflow/index.md +1 -0
  152. package/docs/workflow/operating-model.md +5 -6
  153. package/docs/workflow/parallel-features.md +23 -2
  154. package/docs/workflow/skill-map-on-request.md +42 -0
  155. package/docs/workflow/skill-map.md +3 -34
  156. package/docs/workflow/zshrc-aliases.md +1 -1
  157. package/package.json +1 -1
  158. package/scripts/core/regen-hero.ts +1 -1
  159. package/scripts/lib/sandbox-git.sh +1 -9
  160. package/scripts/lib/sandbox-path.sh +6 -162
  161. package/scripts/sandbox-hook.sh +99 -0
  162. package/src/audits/run.ts +1 -1
  163. package/src/canvas/address.ts +12 -3
  164. package/src/canvas/capture.ts +1 -9
  165. package/src/canvas/client/inspector/align-grid.tsx +162 -0
  166. package/src/canvas/client/inspector/color-field.tsx +398 -0
  167. package/src/canvas/client/inspector/color-inputs.tsx +139 -0
  168. package/src/canvas/client/inspector/color-picker.tsx +668 -0
  169. package/src/canvas/client/inspector/color-space.ts +240 -0
  170. package/src/canvas/client/inspector/field.tsx +5 -1
  171. package/src/canvas/client/inspector/fields.css +547 -17
  172. package/src/canvas/client/inspector/size-field.tsx +69 -0
  173. package/src/canvas/client/inspector/values.ts +166 -1
  174. package/src/canvas/client/inspector.tsx +236 -73
  175. package/src/canvas/client/selection.tsx +197 -0
  176. package/src/canvas/client/shell.css +104 -12
  177. package/src/canvas/client/state.ts +69 -9
  178. package/src/canvas/client/surface.tsx +147 -22
  179. package/src/canvas/content.ts +50 -1
  180. package/src/canvas/edit.ts +37 -4
  181. package/src/canvas/editing.ts +203 -0
  182. package/src/canvas/global.d.ts +15 -0
  183. package/src/canvas/server.ts +149 -12
  184. package/src/canvas/tokens.ts +59 -17
  185. package/src/capture/render.ts +45 -7
  186. package/src/capture/sources.ts +43 -0
  187. package/src/census/count.ts +2 -2
  188. package/src/claude/cases/workflow.ts +5 -0
  189. package/src/claude/seeds.ts +2 -2
  190. package/src/claude/skills-audit.ts +96 -14
  191. package/src/claude/skills-drift.ts +1 -1
  192. package/src/claude/skills-families.ts +36 -0
  193. package/src/claude/skills-list.ts +76 -15
  194. package/src/commands/audits.ts +2 -2
  195. package/src/commands/canvas.ts +179 -2
  196. package/src/commands/claude.ts +94 -11
  197. package/src/commands/design.ts +142 -2
  198. package/src/commands/feedback.ts +3 -3
  199. package/src/commands/gov.ts +1 -1
  200. package/src/commands/hooks.ts +1 -1
  201. package/src/commands/indexes.ts +1 -1
  202. package/src/commands/init.ts +1 -1
  203. package/src/commands/intake.ts +1 -1
  204. package/src/commands/migrate.ts +1 -1
  205. package/src/commands/pr.ts +105 -58
  206. package/src/commands/records.ts +89 -7
  207. package/src/commands/repo.ts +1 -1
  208. package/src/commands/sandbox.ts +103 -11
  209. package/src/commands/sessions.ts +1 -1
  210. package/src/commands/slides.ts +31 -77
  211. package/src/commands/sync.ts +1 -1
  212. package/src/commands/tasks.ts +2 -2
  213. package/src/commands/teach.ts +1 -1
  214. package/src/commands/transcripts.ts +1 -1
  215. package/src/commands/worktrees.ts +1 -1
  216. package/src/comments/scan.ts +1 -1
  217. package/src/comments/trend.ts +1 -1
  218. package/src/context/audit.ts +1 -1
  219. package/src/context/citations.ts +1 -1
  220. package/src/context/classify/extract.ts +2 -2
  221. package/src/design/project-fonts.ts +392 -0
  222. package/src/design/tokens.ts +2 -18
  223. package/src/docs/read.ts +1 -1
  224. package/src/{github.ts → feedback/github.ts} +2 -2
  225. package/src/{client-commands.ts → gate/client-commands.ts} +1 -1
  226. package/src/gate/measures.ts +53 -13
  227. package/src/gate/sequencer.ts +1 -1
  228. package/src/gate/stages.ts +9 -0
  229. package/src/{git-files.ts → git/files.ts} +2 -2
  230. package/src/{git-ignore.ts → git/ignore.ts} +1 -1
  231. package/src/{worktree.ts → git/worktree.ts} +1 -1
  232. package/src/gov/citations.ts +2 -2
  233. package/src/gov/install.ts +1 -1
  234. package/src/gov/payload.ts +1 -1
  235. package/src/gov/superseded.ts +3 -3
  236. package/src/gov/test-order.ts +2 -2
  237. package/src/help.ts +1 -1
  238. package/src/hooks/post-merge.ts +1 -1
  239. package/src/indexes/walk.ts +1 -1
  240. package/src/labels/audit.ts +1 -1
  241. package/src/markdown/ceiling.ts +1 -1
  242. package/src/markdown/files.ts +1 -1
  243. package/src/migrate/apply.ts +1 -1
  244. package/src/pr/bijection.ts +1 -1
  245. package/src/pr/evidence.ts +96 -43
  246. package/src/pr/local.ts +16 -10
  247. package/src/pr/preview.ts +78 -2
  248. package/src/record-root.ts +1 -0
  249. package/src/records/backup.ts +2 -1
  250. package/src/records/push-guard.ts +1 -1
  251. package/src/records/stale-canonical.ts +146 -0
  252. package/src/records/stale.ts +1 -1
  253. package/src/sandbox/headless/dispatch.ts +264 -0
  254. package/src/sandbox/headless/run.ts +653 -0
  255. package/src/sandbox/headless/watch.ts +145 -0
  256. package/src/sandbox/hooks.ts +128 -0
  257. package/src/sandbox/provision.ts +607 -0
  258. package/src/sandbox/tree.ts +99 -4
  259. package/src/secrets/marker.ts +2 -2
  260. package/src/secrets/scan.ts +2 -2
  261. package/src/sessions/claim.ts +1 -1
  262. package/src/sessions/resolve.ts +1 -1
  263. package/src/sessions/transfer/bundle.ts +1 -1
  264. package/src/shipped/references.ts +2 -2
  265. package/src/slides/convert/export.ts +2 -16
  266. package/src/slides/decks.ts +110 -0
  267. package/src/slides/package/fonts.ts +6 -2
  268. package/src/standards/audit.ts +2 -2
  269. package/src/standards/read.ts +1 -1
  270. package/src/sync/check.ts +2 -2
  271. package/src/sync/engine.ts +2 -2
  272. package/src/sync/git.ts +1 -1
  273. package/src/sync/history.ts +1 -1
  274. package/src/sync/reverse.ts +1 -1
  275. package/src/sync/seeds-report.ts +1 -1
  276. package/src/sync/target.ts +1 -1
  277. package/src/sync/workflow.ts +1 -1
  278. package/src/targets/pulls.ts +2 -2
  279. package/src/targets/sweep.ts +2 -2
  280. package/src/tasks/answers.ts +1 -1
  281. package/src/tasks/archive.ts +1 -1
  282. package/src/tasks/reach.ts +1 -1
  283. package/src/tasks/trunk.ts +1 -1
  284. package/src/teach/nav.ts +1 -1
  285. package/src/tooling/inject.ts +2 -2
  286. package/src/tooling/subfolder.ts +1 -1
  287. package/src/web/readme-citations.ts +2 -2
  288. package/src/worktrees/bare-flag.ts +1 -1
  289. package/src/worktrees/reclaim.ts +2 -2
  290. package/src/worktrees/remove.ts +1 -1
  291. package/standards/architecture.md +1 -0
  292. package/standards/canvas.md +3 -2
  293. package/standards/requirements.md +2 -0
  294. package/standards/skill-practice.md +2 -1
  295. package/standards/skill.md +2 -0
  296. package/standards/wiki.md +12 -3
  297. package/tooling/base/configs/.github/workflows/pr-local-preview.yml +2 -2
  298. package/scripts/lib/sandbox-dispatch.sh +0 -190
  299. package/scripts/manage-sandbox.sh +0 -472
  300. package/src/slides/layouts.ts +0 -478
  301. package/src/slides/parse.ts +0 -84
  302. package/src/slides/render.ts +0 -110
  303. package/src/slides/styles.ts +0 -96
  304. /package/claude/skills/write-human/references/{source-material.md → adopted.md} +0 -0
  305. /package/src/{commands/feedback-format.ts → feedback/body.ts} +0 -0
  306. /package/src/{github-format.ts → feedback/github-format.ts} +0 -0
  307. /package/src/{git-base.ts → git/base.ts} +0 -0
  308. /package/src/{git-env.ts → git/env.ts} +0 -0
  309. /package/src/{frontmatter.ts → markdown/frontmatter.ts} +0 -0
  310. /package/src/{binary.ts → sweep/binary.ts} +0 -0
  311. /package/src/{exempt-marker.ts → sweep/exempt-marker.ts} +0 -0
  312. /package/src/{copy.ts → sync/copy.ts} +0 -0
  313. /package/src/{target.ts → targets/validate.ts} +0 -0
  314. /package/src/{paths.ts → tasks/paths.ts} +0 -0
  315. /package/src/{seed-marker.ts → tooling/seed-marker.ts} +0 -0
@@ -108,44 +108,574 @@
108
108
  flex: 1;
109
109
  }
110
110
 
111
- .token-picker {
111
+ .raw {
112
112
  flex: none;
113
- width: 4.5rem;
114
- min-height: 24px;
115
- padding: 2px var(--space-xs);
113
+ color: var(--color-text-secondary);
114
+ cursor: help;
115
+ }
116
+
117
+ .text-excerpt {
118
+ margin: var(--space-xs) 0 0;
119
+ color: var(--color-text-body);
120
+ overflow: hidden;
121
+ text-overflow: ellipsis;
122
+ white-space: nowrap;
123
+ }
124
+
125
+ .saved {
126
+ margin-left: var(--space-sm);
127
+ color: var(--color-success);
128
+ font-weight: 400;
129
+ }
130
+
131
+ /* An icon in a section's header lane or beside a field, square at row height. */
132
+ .section-icon {
133
+ flex: none;
134
+ display: grid;
135
+ place-items: center;
136
+ width: 24px;
137
+ height: 24px;
138
+ padding: 0;
139
+ border: 0;
140
+ border-radius: var(--radius-action);
141
+ background: transparent;
142
+ color: var(--color-muted);
143
+ cursor: pointer;
144
+ }
145
+
146
+ .section-icon:hover,
147
+ .section-icon[aria-pressed='true'] {
148
+ background: var(--color-surface);
149
+ color: var(--color-text);
150
+ }
151
+
152
+ .section-icon:disabled {
153
+ opacity: 0.5;
154
+ cursor: not-allowed;
155
+ }
156
+
157
+ .section-icon svg {
158
+ width: 14px;
159
+ height: 14px;
160
+ fill: none;
161
+ stroke: currentColor;
162
+ stroke-width: 1.5;
163
+ stroke-linecap: round;
164
+ stroke-linejoin: round;
165
+ }
166
+
167
+ /* The alignment grid on the left, the direction and wrap stacked beside it. */
168
+ .flex-layout {
169
+ display: grid;
170
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
171
+ gap: var(--space-xs);
172
+ align-items: start;
173
+ }
174
+
175
+ .flex-layout-side {
176
+ display: flex;
177
+ align-items: center;
178
+ gap: var(--space-xs);
179
+ min-width: 0;
180
+ }
181
+
182
+ .flex-layout-side .glyph-field {
183
+ flex: 1;
184
+ }
185
+
186
+ .align-grid {
187
+ display: grid;
188
+ grid-template-columns: repeat(3, 1fr);
189
+ grid-template-rows: repeat(3, 24px);
190
+ padding: 2px;
116
191
  border: 1px solid var(--color-border);
117
192
  border-radius: var(--radius-action);
118
193
  background: var(--color-surface);
194
+ }
195
+
196
+ .align-cell {
197
+ display: grid;
198
+ place-items: center;
199
+ min-width: 0;
200
+ padding: 0;
201
+ border: 0;
202
+ border-radius: var(--radius-action);
203
+ background: transparent;
204
+ color: var(--color-muted);
205
+ cursor: pointer;
206
+ }
207
+
208
+ .align-cell:hover {
119
209
  color: var(--color-text);
120
- font: inherit;
210
+ }
211
+
212
+ .align-cell:disabled {
213
+ opacity: 0.5;
214
+ cursor: not-allowed;
215
+ }
216
+
217
+ .align-dot {
218
+ width: 3px;
219
+ height: 3px;
220
+ border-radius: 50%;
221
+ background: currentColor;
222
+ }
223
+
224
+ .align-cell[aria-checked='true'] {
225
+ color: var(--color-accent);
226
+ }
227
+
228
+ .align-cell[aria-checked='true'] .align-dot {
229
+ width: 10px;
230
+ height: 10px;
231
+ border-radius: 2px;
232
+ }
233
+
234
+ /*
235
+ * A size's mode menu trails its number. The select is transparent over the
236
+ * chevron, so the platform's own list opens and the field keeps one height.
237
+ */
238
+ .size-mode {
239
+ position: relative;
240
+ flex: none;
241
+ display: grid;
242
+ place-items: center;
243
+ width: 24px;
244
+ height: 22px;
245
+ border-radius: var(--radius-action);
246
+ color: var(--color-muted);
247
+ }
248
+
249
+ .size-mode:hover,
250
+ .size-mode:focus-within {
251
+ color: var(--color-text);
252
+ background: var(--color-chrome);
253
+ }
254
+
255
+ .size-mode-select {
256
+ position: absolute;
257
+ inset: 0;
258
+ width: 100%;
259
+ height: 100%;
260
+ opacity: 0;
121
261
  cursor: pointer;
122
262
  }
123
263
 
124
- .token-picker:hover {
125
- border-color: var(--color-muted);
264
+ .size-mode-select:disabled {
265
+ cursor: not-allowed;
126
266
  }
127
267
 
128
- .token-picker:disabled {
268
+ .size-mode:has(.size-mode-select:disabled) {
269
+ opacity: 0.5;
270
+ }
271
+
272
+ /* The select is invisible, so the project ring draws on the lane holding it. */
273
+ .size-mode:has(.size-mode-select:focus-visible) {
274
+ outline: 2px solid var(--color-accent);
275
+ outline-offset: 0;
276
+ }
277
+
278
+ .size-mode-chevron {
279
+ width: 12px;
280
+ height: 12px;
281
+ fill: none;
282
+ stroke: currentColor;
283
+ stroke-width: 1.5;
284
+ }
285
+
286
+ /*
287
+ * A color is one field: a swatch leading in the glyph's lane, the hex, and the
288
+ * opacity right-aligned, with the tokens and the eyedropper trailing the row.
289
+ */
290
+ .color-field {
291
+ min-width: 0;
292
+ }
293
+
294
+ .swatch {
295
+ flex: none;
296
+ display: grid;
297
+ place-items: center;
298
+ width: 1.75rem;
299
+ min-height: 22px;
300
+ padding: 0;
301
+ border: 0;
302
+ background: transparent;
303
+ cursor: pointer;
304
+ }
305
+
306
+ .swatch:disabled {
129
307
  opacity: 0.5;
130
308
  cursor: not-allowed;
131
309
  }
132
310
 
133
- .raw {
311
+ /*
312
+ * The paint is the top layer over a checker, so an opacity below full reads
313
+ * as one. `--paint` carries the color, since a background color sits under
314
+ * every image layer and the checker would cover it.
315
+ */
316
+ .swatch-paint {
317
+ --paint: transparent;
134
318
  flex: none;
319
+ width: 12px;
320
+ height: 12px;
321
+ border: 1px solid var(--color-border);
322
+ border-radius: 2px;
323
+ background-image:
324
+ linear-gradient(var(--paint), var(--paint)),
325
+ linear-gradient(45deg, var(--color-border) 25%, transparent 25%),
326
+ linear-gradient(-45deg, var(--color-border) 25%, transparent 25%),
327
+ linear-gradient(45deg, transparent 75%, var(--color-border) 75%),
328
+ linear-gradient(-45deg, transparent 75%, var(--color-border) 75%);
329
+ background-size:
330
+ auto,
331
+ 6px 6px,
332
+ 6px 6px,
333
+ 6px 6px,
334
+ 6px 6px;
335
+ background-position:
336
+ 0 0,
337
+ 0 0,
338
+ 0 3px,
339
+ 3px -3px,
340
+ -3px 0;
341
+ }
342
+
343
+ .swatch:hover .swatch-paint {
344
+ border-color: var(--color-muted);
345
+ }
346
+
347
+ /* No fill draws a slash rather than a color. */
348
+ .swatch.is-none .swatch-paint {
349
+ background-image: linear-gradient(
350
+ to top right,
351
+ transparent calc(50% - 1px),
352
+ var(--color-muted) calc(50% - 1px),
353
+ var(--color-muted) calc(50% + 1px),
354
+ transparent calc(50% + 1px)
355
+ );
356
+ background-size: auto;
357
+ }
358
+
359
+ .color-field .glyph-field-input {
360
+ text-transform: uppercase;
361
+ }
362
+
363
+ /* Only a hex reads in capitals. A value the picker cannot read stays as written. */
364
+ .color-field .glyph-field-input::placeholder,
365
+ .color-field .glyph-field-input.is-text {
366
+ text-transform: none;
367
+ }
368
+
369
+ /* A token name is a name, so it keeps its own case. */
370
+ .color-field .glyph-field-input.is-token {
371
+ flex: 0 1 auto;
372
+ margin-right: auto;
373
+ padding: 0 var(--space-xs);
374
+ border-radius: var(--radius-action);
375
+ background: var(--color-background);
376
+ text-transform: none;
377
+ }
378
+
379
+ .color-opacity {
380
+ flex: none;
381
+ width: 2.25rem;
382
+ padding: 2px 0;
383
+ border: 0;
384
+ background: transparent;
385
+ color: var(--color-text);
386
+ font: inherit;
387
+ font-variant-numeric: tabular-nums;
388
+ text-align: right;
389
+ }
390
+
391
+ .color-opacity:disabled {
392
+ color: var(--color-muted);
393
+ cursor: not-allowed;
394
+ }
395
+
396
+ .color-percent {
397
+ flex: none;
398
+ padding-right: var(--space-xs);
399
+ color: var(--color-muted);
400
+ user-select: none;
401
+ }
402
+
403
+ /*
404
+ * The picker and the token list float beside the panel, in the top layer
405
+ * where the browser has one. The panel scrolls and clips, so neither sits in
406
+ * its flow. The script places each at fixed coordinates inside the window, and
407
+ * the caps below hold a window too small for the whole picker.
408
+ */
409
+ .color-popover {
410
+ position: fixed;
411
+ inset: auto;
412
+ z-index: 10;
413
+ max-width: calc(100vw - 16px);
414
+ max-height: calc(100vh - 16px);
415
+ margin: 0;
416
+ padding: var(--space-sm);
417
+ overflow: auto;
418
+ border: 1px solid var(--color-border);
419
+ border-radius: var(--radius-panel);
420
+ background: var(--color-chrome);
421
+ color: var(--color-text);
422
+ box-shadow: 0 8px 24px rgb(0 0 0 / 0.35);
423
+ }
424
+
425
+ .color-popover.is-tokens {
426
+ width: 14rem;
427
+ padding: var(--space-xs);
428
+ }
429
+
430
+ .picker {
431
+ --picker-hue: red;
432
+ --picker-solid: transparent;
433
+ display: grid;
434
+ grid-template-columns: 14rem 14px 14px 13rem;
435
+ gap: var(--space-sm);
436
+ align-items: stretch;
437
+ }
438
+
439
+ /*
440
+ * The area draws white to the hue left to right, then black over it bottom
441
+ * to top, so a point reads as saturation across and brightness up.
442
+ */
443
+ .picker-area {
444
+ position: relative;
445
+ aspect-ratio: 1;
446
+ border-radius: var(--radius-action);
447
+ background:
448
+ linear-gradient(to top, #000, transparent),
449
+ linear-gradient(to right, #fff, var(--picker-hue));
450
+ cursor: crosshair;
451
+ touch-action: none;
452
+ }
453
+
454
+ .picker-thumb {
455
+ position: absolute;
456
+ width: 12px;
457
+ height: 12px;
458
+ border: 2px solid #fff;
459
+ border-radius: 50%;
460
+ box-shadow: 0 0 0 1px rgb(0 0 0 / 0.5);
461
+ transform: translate(-50%, -50%);
462
+ pointer-events: none;
463
+ }
464
+
465
+ .picker-slider {
466
+ appearance: none;
467
+ width: 14px;
468
+ height: 100%;
469
+ margin: 0;
470
+ border-radius: var(--radius-action);
471
+ writing-mode: vertical-lr;
472
+ cursor: pointer;
473
+ }
474
+
475
+ /* Hue runs red at the top through the wheel and back to red at the foot. */
476
+ .picker-hue {
477
+ background: linear-gradient(
478
+ to bottom,
479
+ #f00,
480
+ #ff0 17%,
481
+ #0f0 33%,
482
+ #0ff 50%,
483
+ #00f 67%,
484
+ #f0f 83%,
485
+ #f00
486
+ );
487
+ }
488
+
489
+ /* Alpha runs opaque at the top to clear at the foot, over a checker. */
490
+ .picker-alpha {
491
+ direction: rtl;
492
+ background-image:
493
+ linear-gradient(to bottom, var(--picker-solid), transparent),
494
+ linear-gradient(45deg, var(--color-border) 25%, transparent 25%),
495
+ linear-gradient(-45deg, var(--color-border) 25%, transparent 25%),
496
+ linear-gradient(45deg, transparent 75%, var(--color-border) 75%),
497
+ linear-gradient(-45deg, transparent 75%, var(--color-border) 75%);
498
+ background-size:
499
+ auto,
500
+ 8px 8px,
501
+ 8px 8px,
502
+ 8px 8px,
503
+ 8px 8px;
504
+ background-position:
505
+ 0 0,
506
+ 0 0,
507
+ 0 4px,
508
+ 4px -4px,
509
+ -4px 0;
510
+ }
511
+
512
+ .picker-slider::-webkit-slider-thumb {
513
+ appearance: none;
514
+ width: 14px;
515
+ height: 6px;
516
+ border: 2px solid #fff;
517
+ border-radius: 2px;
518
+ box-shadow: 0 0 0 1px rgb(0 0 0 / 0.5);
519
+ }
520
+
521
+ .picker-slider::-moz-range-thumb {
522
+ width: 10px;
523
+ height: 2px;
524
+ border: 2px solid #fff;
525
+ border-radius: 2px;
526
+ background: transparent;
527
+ box-shadow: 0 0 0 1px rgb(0 0 0 / 0.5);
528
+ }
529
+
530
+ .picker-side {
531
+ display: flex;
532
+ flex-direction: column;
533
+ gap: var(--space-xs);
534
+ min-width: 0;
535
+ }
536
+
537
+ .picker-compare {
538
+ display: grid;
539
+ grid-template-columns: 1fr 1fr;
540
+ height: 3.5rem;
541
+ overflow: hidden;
542
+ border: 1px solid var(--color-border);
543
+ border-radius: var(--radius-action);
544
+ }
545
+
546
+ /* Each half paints over the checker, so an alpha below full reads as one. */
547
+ .picker-previous,
548
+ .picker-new {
549
+ --paint: transparent;
550
+ padding: 0;
551
+ border: 0;
552
+ background-image:
553
+ linear-gradient(var(--paint), var(--paint)),
554
+ linear-gradient(45deg, var(--color-border) 25%, transparent 25%),
555
+ linear-gradient(-45deg, var(--color-border) 25%, transparent 25%),
556
+ linear-gradient(45deg, transparent 75%, var(--color-border) 75%),
557
+ linear-gradient(-45deg, transparent 75%, var(--color-border) 75%);
558
+ background-size:
559
+ auto,
560
+ 8px 8px,
561
+ 8px 8px,
562
+ 8px 8px,
563
+ 8px 8px;
564
+ background-position:
565
+ 0 0,
566
+ 0 0,
567
+ 0 4px,
568
+ 4px -4px,
569
+ -4px 0;
570
+ }
571
+
572
+ .picker-previous {
573
+ cursor: pointer;
574
+ }
575
+
576
+ .picker-compare-labels {
577
+ display: grid;
578
+ grid-template-columns: 1fr 1fr;
135
579
  color: var(--color-text-secondary);
136
- cursor: help;
580
+ text-align: center;
137
581
  }
138
582
 
139
- .text-excerpt {
140
- margin: var(--space-xs) 0 0;
141
- color: var(--color-text-body);
583
+ .picker-row {
584
+ display: grid;
585
+ grid-template-columns: repeat(3, minmax(0, 1fr));
586
+ gap: 1px;
587
+ overflow: hidden;
588
+ border-radius: var(--radius-action);
589
+ }
590
+
591
+ .picker-channel {
592
+ display: flex;
593
+ flex-direction: column;
594
+ align-items: stretch;
595
+ min-width: 0;
596
+ }
597
+
598
+ .picker-number {
599
+ min-width: 0;
600
+ min-height: 24px;
601
+ padding: 2px var(--space-xs);
602
+ border: 0;
603
+ background: var(--color-surface);
604
+ color: var(--color-text);
605
+ font: inherit;
606
+ font-variant-numeric: tabular-nums;
607
+ text-align: center;
608
+ }
609
+
610
+ .picker-letter {
611
+ color: var(--color-muted);
612
+ font-size: 0.75em;
613
+ text-align: center;
614
+ user-select: none;
615
+ }
616
+
617
+ .token-list {
618
+ max-height: 12rem;
619
+ margin: 0;
620
+ padding: 0;
621
+ overflow-y: auto;
622
+ list-style: none;
623
+ }
624
+
625
+ .token-option {
626
+ display: flex;
627
+ align-items: center;
628
+ gap: var(--space-xs);
629
+ min-height: 24px;
630
+ padding: 0 var(--space-xs);
631
+ border-radius: var(--radius-action);
632
+ cursor: pointer;
633
+ }
634
+
635
+ .token-option:hover,
636
+ .token-option.is-active {
637
+ background: var(--color-surface);
638
+ }
639
+
640
+ .token-option[aria-selected='true'] .token-name {
641
+ color: var(--color-accent);
642
+ }
643
+
644
+ .token-name {
645
+ min-width: 0;
142
646
  overflow: hidden;
143
647
  text-overflow: ellipsis;
144
648
  white-space: nowrap;
145
649
  }
146
650
 
147
- .saved {
148
- margin-left: var(--space-sm);
149
- color: var(--color-success);
150
- font-weight: 400;
651
+ /* A trailing icon on the color row, square at the row's height. */
652
+ .color-icon {
653
+ flex: none;
654
+ display: grid;
655
+ place-items: center;
656
+ width: 24px;
657
+ height: 24px;
658
+ padding: 0;
659
+ border: 0;
660
+ border-radius: var(--radius-action);
661
+ background: transparent;
662
+ color: var(--color-muted);
663
+ cursor: pointer;
664
+ }
665
+
666
+ .color-icon:hover,
667
+ .color-icon[aria-expanded='true'] {
668
+ background: var(--color-surface);
669
+ color: var(--color-text);
670
+ }
671
+
672
+ .color-icon:disabled {
673
+ opacity: 0.5;
674
+ cursor: not-allowed;
675
+ }
676
+
677
+ .color-icon svg {
678
+ width: 14px;
679
+ height: 14px;
680
+ fill: currentColor;
151
681
  }
@@ -0,0 +1,69 @@
1
+ /** @jsxImportSource preact */
2
+ import type { JSX } from 'preact'
3
+ import { Field, type Scrub } from '@/canvas/client/inspector/field'
4
+
5
+ /** The modes a size takes besides a number, by the name the field shows. */
6
+ const MODES = ['Fill', 'Fit'] as const
7
+
8
+ interface SizeFieldProps {
9
+ readonly label: string
10
+ readonly glyph: string
11
+ /** The value as the panel shows it, a mode name or a number. */
12
+ readonly initial: string
13
+ readonly isBusy: boolean
14
+ /** Takes a typed number or a picked mode name, each as shown. */
15
+ readonly onCommit: (value: string) => void
16
+ readonly scrub?: Scrub
17
+ }
18
+
19
+ /**
20
+ * A size that takes a number or a mode. The chevron is a native select, so
21
+ * its list opens above the panel's clipping and answers the keyboard as the
22
+ * platform does, and typing a number replaces the mode.
23
+ */
24
+ export function SizeField({
25
+ label,
26
+ glyph,
27
+ initial,
28
+ isBusy,
29
+ onCommit,
30
+ scrub,
31
+ }: SizeFieldProps): JSX.Element {
32
+ const mode = (MODES as readonly string[]).includes(initial) ? initial : ''
33
+ return (
34
+ <Field
35
+ label={label}
36
+ glyph={glyph}
37
+ initial={initial}
38
+ isBusy={isBusy}
39
+ onCommit={onCommit}
40
+ scrub={scrub}
41
+ trailing={
42
+ <span class="size-mode">
43
+ <select
44
+ class="size-mode-select"
45
+ aria-label={`${label} mode`}
46
+ value={mode}
47
+ disabled={isBusy}
48
+ onChange={(event) => {
49
+ const picked = event.currentTarget.value
50
+ if (picked && picked !== mode) onCommit(picked)
51
+ }}
52
+ >
53
+ <option value="" disabled hidden>
54
+ Fixed
55
+ </option>
56
+ {MODES.map((name) => (
57
+ <option key={name} value={name}>
58
+ {name}
59
+ </option>
60
+ ))}
61
+ </select>
62
+ <svg class="size-mode-chevron" viewBox="0 0 16 16" aria-hidden="true">
63
+ <path d="M4.5 6.5 8 10l3.5-3.5" />
64
+ </svg>
65
+ </span>
66
+ }
67
+ />
68
+ )
69
+ }