@cardstack/boxel-cli 0.11.0-unstable.2 → 0.11.0-unstable.3

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 (106) hide show
  1. package/bundled-realms/pretui/components/agent-mark.gts +98 -0
  2. package/bundled-realms/pretui/components/agent-question.gts +340 -37
  3. package/bundled-realms/pretui/components/answer-footer.gts +249 -0
  4. package/bundled-realms/pretui/components/card-embed.gts +523 -0
  5. package/bundled-realms/pretui/components/card-pills.gts +725 -0
  6. package/bundled-realms/pretui/components/code-block.gts +87 -45
  7. package/bundled-realms/pretui/components/collapsed-turn.gts +133 -12
  8. package/bundled-realms/pretui/components/compaction-chip.gts +81 -67
  9. package/bundled-realms/pretui/components/composer-cap.gts +516 -0
  10. package/bundled-realms/pretui/components/context-ring.gts +108 -0
  11. package/bundled-realms/pretui/components/diff-block.gts +1002 -31
  12. package/bundled-realms/pretui/components/diff-stat.gts +102 -0
  13. package/bundled-realms/pretui/components/jump-chip.gts +86 -53
  14. package/bundled-realms/pretui/components/markdown-stream.gts +799 -0
  15. package/bundled-realms/pretui/components/markdown-surface.gts +71 -0
  16. package/bundled-realms/pretui/components/plan-mark.gts +147 -0
  17. package/bundled-realms/pretui/components/prose.gts +185 -8
  18. package/bundled-realms/pretui/components/prose.md +6 -8
  19. package/bundled-realms/pretui/components/quick-look.gts +377 -0
  20. package/bundled-realms/pretui/components/reactions.gts +136 -0
  21. package/bundled-realms/pretui/components/recommendation.gts +67 -36
  22. package/bundled-realms/pretui/components/result-card.gts +58 -22
  23. package/bundled-realms/pretui/components/segmented-control.gts +13 -8
  24. package/bundled-realms/pretui/components/session-prep.gts +12 -11
  25. package/bundled-realms/pretui/components/sliding-highlight.gts +8 -3
  26. package/bundled-realms/pretui/components/speaker-label.gts +132 -0
  27. package/bundled-realms/pretui/components/state-glyph.gts +121 -0
  28. package/bundled-realms/pretui/components/step-list.gts +62 -60
  29. package/bundled-realms/pretui/components/stick-to-bottom.gts +1150 -0
  30. package/bundled-realms/pretui/components/system-line.gts +143 -0
  31. package/bundled-realms/pretui/components/task-checklist.gts +184 -0
  32. package/bundled-realms/pretui/components/thinking.gts +63 -94
  33. package/bundled-realms/pretui/components/tool-change-table.gts +285 -0
  34. package/bundled-realms/pretui/components/tool-gate.gts +462 -0
  35. package/bundled-realms/pretui/components/tool-group.gts +920 -0
  36. package/bundled-realms/pretui/components/tool-icon.ts +64 -0
  37. package/bundled-realms/pretui/components/tool-meta.gts +82 -0
  38. package/bundled-realms/pretui/components/tool-plan.gts +197 -0
  39. package/bundled-realms/pretui/components/tool-row.gts +2087 -0
  40. package/bundled-realms/pretui/components/turn-changes.gts +227 -0
  41. package/bundled-realms/pretui/components/user-bubble.gts +575 -0
  42. package/bundled-realms/pretui/components/work-item.gts +185 -48
  43. package/bundled-realms/pretui/docs/scroll-anchoring-protocol.md +136 -0
  44. package/bundled-realms/pretui/internal/markdown-projection.ts +438 -0
  45. package/bundled-realms/pretui/internal/mount-queue.ts +79 -0
  46. package/bundled-realms/pretui/internal/tool-phrases.ts +168 -0
  47. package/bundled-realms/pretui/package.json +2 -1
  48. package/bundled-test-harness/assets/{ai-module-creation-test-beRNwH-e.js → ai-module-creation-test-B6FQKqIl.js} +1 -1
  49. package/bundled-test-harness/assets/{app-CtezUCip.js → app-KpPqdyX3.js} +4 -4
  50. package/bundled-test-harness/assets/{binary-upload-dedupe-test-bI8T0QLl.js → binary-upload-dedupe-test-DN00y1tM.js} +1 -1
  51. package/bundled-test-harness/assets/{can-invoke-test-DVaU_yRT.js → can-invoke-test-Bl-EUFM3.js} +1 -1
  52. package/bundled-test-harness/assets/{card-chooser-paging-test-DnxMnXKR.js → card-chooser-paging-test-BNuZRHX3.js} +1 -1
  53. package/bundled-test-harness/assets/{card-chooser-test-DUSnLr-u.js → card-chooser-test-wKfPOOT4.js} +1 -1
  54. package/bundled-test-harness/assets/{card-def-field-def-relationships-test-GBUr3tFK.js → card-def-field-def-relationships-test-CduQ6zan.js} +1 -1
  55. package/bundled-test-harness/assets/{card-delete-test-CQveO1VC.js → card-delete-test-DKxolj5o.js} +1 -1
  56. package/bundled-test-harness/assets/{check-correctness-test-D2M2p66N.js → check-correctness-test-B-kgHztp.js} +1 -1
  57. package/bundled-test-harness/assets/{codeblocks-test-AdolhdCA.js → codeblocks-test-BDD7qK_V.js} +1 -1
  58. package/bundled-test-harness/assets/{compaction-test-DvyAQq56.js → compaction-test-BweolkhG.js} +1 -1
  59. package/bundled-test-harness/assets/{container-DIF_9lZ9.css → container-B5B6u-xm.css} +29 -22
  60. package/bundled-test-harness/assets/{container-DvvqmNpg.js → container-BnJjIM6J.js} +9 -6
  61. package/bundled-test-harness/assets/{create-listing-modal-test-D95JfQab.js → create-listing-modal-test-FvcAKpIa.js} +1 -1
  62. package/bundled-test-harness/assets/{debug-message-test-BcNtj7Wr.js → debug-message-test-CJ18Evt7.js} +1 -1
  63. package/bundled-test-harness/assets/{externals-DCnB4XSS.js → externals-BWjhmCD4.js} +1 -1
  64. package/bundled-test-harness/assets/{fallback-banner-live-delete-test-5lnN1pv2.js → fallback-banner-live-delete-test-C2H3BrT-.js} +1 -1
  65. package/bundled-test-harness/assets/{fallback-banner-test-DFb_m_Kq.js → fallback-banner-test-C10aYjkj.js} +1 -1
  66. package/bundled-test-harness/assets/{fallback-models-test-p3YIwj1L.js → fallback-models-test-BxoPiaGF.js} +1 -1
  67. package/bundled-test-harness/assets/{file-attachment-test-CmyjNWRR.js → file-attachment-test-DeKyzYaz.js} +1 -1
  68. package/bundled-test-harness/assets/{general-test-CX-TFDuX.js → general-test-BewzrpoB.js} +1 -1
  69. package/bundled-test-harness/assets/{index-query-engine-test-CY2tAkot.js → index-query-engine-test-BtI8Y2LR.js} +1 -1
  70. package/bundled-test-harness/assets/{instance-filter-matcher-test-CMBTh8xn.js → instance-filter-matcher-test-BHXHGHjE.js} +1 -1
  71. package/bundled-test-harness/assets/{main-BOZbZVem.js → main-CqAHZ2kK.js} +1 -1
  72. package/bundled-test-harness/assets/{message-tool-test-CfjRSJvt.js → message-tool-test-NMaPJFsd.js} +1 -1
  73. package/bundled-test-harness/assets/{model-cost-tier-test-mZG84Uso.js → model-cost-tier-test-BgbfN2LH.js} +1 -1
  74. package/bundled-test-harness/assets/{operation-lowering-test-CHnjKSJb.js → operation-lowering-test-C4IaOjsA.js} +1 -1
  75. package/bundled-test-harness/assets/{operator-mode-card-chooser-test-KWS8lq16.js → operator-mode-card-chooser-test-Bwe47Rn7.js} +1 -1
  76. package/bundled-test-harness/assets/{operator-mode-links-test-CViFt0Ws.js → operator-mode-links-test-BU4jkC-B.js} +1 -1
  77. package/bundled-test-harness/assets/{operator-mode-test-D0gZM2yw.js → operator-mode-test-Bh0rGM9z.js} +1 -1
  78. package/bundled-test-harness/assets/{operator-mode-ui-test-CEvHJ9DS.js → operator-mode-ui-test-whgUw0ju.js} +1 -1
  79. package/bundled-test-harness/assets/{overlay-menu-items-test-Pw80RXsr.js → overlay-menu-items-test-Cwn1vr8q.js} +1 -1
  80. package/bundled-test-harness/assets/{past-sessions-test-CW0-Bjav.js → past-sessions-test-Bh24N-Kz.js} +1 -1
  81. package/bundled-test-harness/assets/{permission-checking-realm-test-D5uXQypS.js → permission-checking-realm-test-DKnnAy0f.js} +1 -1
  82. package/bundled-test-harness/assets/{realm-config-policy-standing-test-Btatheni.js → realm-config-policy-standing-test-DngdYypq.js} +1 -1
  83. package/bundled-test-harness/assets/{realm-config-routing-rule-edit-test-Dh5zW13o.js → realm-config-routing-rule-edit-test-_rkFU8SN.js} +1 -1
  84. package/bundled-test-harness/assets/{realm-config-settings-test-BJa8gv_C.js → realm-config-settings-test-CR9NH0Zn.js} +1 -1
  85. package/bundled-test-harness/assets/{reasoning-test-2Zp37cQB.js → reasoning-test-0lH10kRl.js} +1 -1
  86. package/bundled-test-harness/assets/{room-message-test-BsrON13e.js → room-message-test-C-PddE4Y.js} +1 -1
  87. package/bundled-test-harness/assets/{run-realm-code-BxktQf6R.js → run-realm-code-C8N7DtN-.js} +1 -1
  88. package/bundled-test-harness/assets/{run-realm-code-test-7grpTos-.js → run-realm-code-test-DBdp147q.js} +1 -1
  89. package/bundled-test-harness/assets/{schema-generation-test-CM9ggQji.js → schema-generation-test-CB1Hb7GQ.js} +1 -1
  90. package/bundled-test-harness/assets/{scrolling-test-BER00htB.js → scrolling-test-3PhVin8h.js} +1 -1
  91. package/bundled-test-harness/assets/{searchable-option-test-Ctf8r3HZ.js → searchable-option-test-BAdOiL4U.js} +1 -1
  92. package/bundled-test-harness/assets/{sending-test-BJGobs2E.js → sending-test-KSmu1tSJ.js} +1 -1
  93. package/bundled-test-harness/assets/{skills-test-GPOsHRN6.js → skills-test-D-dlcFpd.js} +1 -1
  94. package/bundled-test-harness/assets/{store-test-QvvHimzH.js → store-test-CEW7xQjZ.js} +1 -1
  95. package/bundled-test-harness/assets/{tests-DoTEpvcF.js → tests-QYqqa6nv.js} +47 -47
  96. package/bundled-test-harness/assets/{text-input-validator-test-CYYH2N0L.js → text-input-validator-test-D8iNOWep.js} +1 -1
  97. package/bundled-test-harness/assets/{to-device-streaming-test-Ctqa0bVp.js → to-device-streaming-test-trCX-505.js} +1 -1
  98. package/bundled-test-harness/assets/{token-usage-test-BQVbK3X0.js → token-usage-test-C6sULooH.js} +1 -1
  99. package/bundled-test-harness/assets/{tools-DU8Rc15s.js → tools-UJfD-_al.js} +1 -1
  100. package/bundled-test-harness/assets/{tools-test-B13yvEKE.js → tools-test-Brav31AV.js} +1 -1
  101. package/bundled-test-harness/assets/{worker-DHBEBihX.js → worker-9ph9_Lpv.js} +31 -26
  102. package/bundled-test-harness/index.html +8 -8
  103. package/bundled-test-harness/tests/index.html +8 -8
  104. package/bundled-types/host-app/lib/realm-runner/worker.ts +8 -51
  105. package/bundled-types/runtime-common/realm-runner-script.d.ts +3 -0
  106. package/package.json +1 -1
@@ -115,7 +115,12 @@ const GRAMMARS: Record<string, Rule[]> = {
115
115
  ['string', sticky('`(?:\\\\[\\s\\S]|[^`\\\\])*`')],
116
116
  ['string', sticky("'(?:\\\\.|[^'\\\\\\n])*'")],
117
117
  ['string', sticky('"(?:\\\\.|[^"\\\\\\n])*"')],
118
- ['number', sticky('0[xXbBoO][0-9a-fA-F_]+|\\d[\\d_]*(?:\\.\\d[\\d_]*)?(?:[eE][+-]?\\d+)?')],
118
+ [
119
+ 'number',
120
+ sticky(
121
+ '0[xXbBoO][0-9a-fA-F_]+|\\d[\\d_]*(?:\\.\\d[\\d_]*)?(?:[eE][+-]?\\d+)?',
122
+ ),
123
+ ],
119
124
  ['keyword', sticky('(?:' + TS_KEYWORDS + ')\\b')],
120
125
  ['name', sticky('[A-Za-z_$][\\w$]*(?=\\s*\\()')],
121
126
  ['name', sticky('[A-Z][\\w$]*')],
@@ -131,7 +136,7 @@ const GRAMMARS: Record<string, Rule[]> = {
131
136
  ],
132
137
  css: [
133
138
  ['comment', sticky('/\\*[\\s\\S]*?\\*/')],
134
- ['string', sticky("'(?:\\\\.|[^'\\\\\\n])*'|\"(?:\\\\.|[^\"\\\\\\n])*\"")],
139
+ ['string', sticky('\'(?:\\\\.|[^\'\\\\\\n])*\'|"(?:\\\\.|[^"\\\\\\n])*"')],
135
140
  ['keyword', sticky('@[\\w-]+')],
136
141
  ['name', sticky('--[\\w-]+')],
137
142
  ['number', sticky('#[0-9a-fA-F]{3,8}\\b|-?\\d*\\.?\\d+(?:%|[a-z]{1,4})?')],
@@ -154,7 +159,7 @@ const GRAMMARS: Record<string, Rule[]> = {
154
159
  ],
155
160
  shell: [
156
161
  ['comment', sticky('#[^\\n]*')],
157
- ['string', sticky("'[^'\\n]*'|\"(?:\\\\.|[^\"\\\\\\n])*\"")],
162
+ ['string', sticky('\'[^\'\\n]*\'|"(?:\\\\.|[^"\\\\\\n])*"')],
158
163
  ['name', sticky('\\$\\{?[\\w]+\\}?')],
159
164
  ['number', sticky('\\b\\d+\\b')],
160
165
  ['keyword', sticky('(?:' + SHELL_KEYWORDS + ')\\b')],
@@ -173,8 +178,18 @@ const GRAMMARS: Record<string, Rule[]> = {
173
178
  python: [
174
179
  ['comment', sticky('#[^\\n]*')],
175
180
  ['string', sticky('"""[\\s\\S]*?"""|\'\'\'[\\s\\S]*?\'\'\'')],
176
- ['string', sticky("[rbfu]{0,2}'(?:\\\\.|[^'\\\\\\n])*'|[rbfu]{0,2}\"(?:\\\\.|[^\"\\\\\\n])*\"")],
177
- ['number', sticky('0[xXbBoO][0-9a-fA-F_]+|\\d[\\d_]*(?:\\.\\d[\\d_]*)?(?:[eE][+-]?\\d+)?')],
181
+ [
182
+ 'string',
183
+ sticky(
184
+ '[rbfu]{0,2}\'(?:\\\\.|[^\'\\\\\\n])*\'|[rbfu]{0,2}"(?:\\\\.|[^"\\\\\\n])*"',
185
+ ),
186
+ ],
187
+ [
188
+ 'number',
189
+ sticky(
190
+ '0[xXbBoO][0-9a-fA-F_]+|\\d[\\d_]*(?:\\.\\d[\\d_]*)?(?:[eE][+-]?\\d+)?',
191
+ ),
192
+ ],
178
193
  ['keyword', sticky('(?:' + PY_KEYWORDS + ')\\b')],
179
194
  ['name', sticky('[A-Za-z_][\\w]*(?=\\s*\\()')],
180
195
  ['plain', sticky('[A-Za-z_][\\w]*')],
@@ -227,7 +242,9 @@ export function grammarFor(language: string | undefined): string | undefined {
227
242
 
228
243
  /** A language guessed from a filename. Used only when `@language` is absent —
229
244
  * an explicit language always wins over an extension. */
230
- export function languageForFilename(name: string | undefined): string | undefined {
245
+ export function languageForFilename(
246
+ name: string | undefined,
247
+ ): string | undefined {
231
248
  let match = /\.([a-z0-9]+)$/i.exec((name ?? '').trim());
232
249
  if (!match) {
233
250
  return undefined;
@@ -253,10 +270,7 @@ const CLASS_FOR: Record<CodeTokenKind, string> = {
253
270
  * and spaces is one span rather than thirty. With no grammar the whole input is
254
271
  * a single `plain` token, which is exactly what "no highlighting" should cost.
255
272
  */
256
- export function tokenizeCode(
257
- code: string,
258
- language?: string,
259
- ): CodeToken[] {
273
+ export function tokenizeCode(code: string, language?: string): CodeToken[] {
260
274
  let text = code ?? '';
261
275
  let key = grammarFor(language);
262
276
  if (!key) {
@@ -420,6 +434,9 @@ export interface CodeBlockSignature {
420
434
  highlight?: string | number[];
421
435
  /** soft-wrap long lines instead of scrolling sideways */
422
436
  wrap?: boolean;
437
+ /** 'compact': a slim header, the smallest data type size and tight
438
+ * padding, for code inside a transcript row. Default 'regular' */
439
+ density?: 'regular' | 'compact';
423
440
  /** scroll ceiling, in lines. The source this replaced had none, so a
424
441
  * five-hundred-line snippet rendered five hundred lines tall. */
425
442
  maxLines?: number;
@@ -549,7 +566,8 @@ export class CodeBlock extends Component<CodeBlockSignature> {
549
566
  * custom property so the gutter sizes itself; only a digit string ever
550
567
  * reaches the style attribute, and `cssStyle` validates that. */
551
568
  get gutterDigits(): number {
552
- let last = Math.max(1, Math.floor(this.args.startLine ?? 1)) +
569
+ let last =
570
+ Math.max(1, Math.floor(this.args.startLine ?? 1)) +
553
571
  Math.max(0, this.lineCount - 1);
554
572
  return Math.max(2, String(last).length);
555
573
  }
@@ -580,6 +598,7 @@ export class CodeBlock extends Component<CodeBlockSignature> {
580
598
  <figure
581
599
  class='pretui-code'
582
600
  data-wrap={{if @wrap 'true' 'false'}}
601
+ data-density={{if @density @density 'regular'}}
583
602
  data-gutter={{if this.showGutter 'true' 'false'}}
584
603
  style={{this.gutterStyle}}
585
604
  data-test-pretui-code
@@ -597,7 +616,8 @@ export class CodeBlock extends Component<CodeBlockSignature> {
597
616
  <CopyButton
598
617
  @text={{this.code}}
599
618
  @label='Copy the code'
600
- @variant='ghost'
619
+ @tone='neutral'
620
+ @appearance='plain'
601
621
  data-test-pretui-code-copy
602
622
  />
603
623
  </span>
@@ -626,7 +646,10 @@ export class CodeBlock extends Component<CodeBlockSignature> {
626
646
  data-clamped={{if this.clamped 'true' 'false'}}
627
647
  style={{if this.clamped this.clampStyle}}
628
648
  data-test-pretui-code-body
629
- ><code class='pretui-code-code'>{{#each this.lines key='key' as |line|}}<span
649
+ ><code class='pretui-code-code'>{{#each
650
+ this.lines key='key'
651
+ as |line|
652
+ }}<span
630
653
  class='pretui-code-line'
631
654
  data-marked={{if line.marked 'true' 'false'}}
632
655
  >{{#if this.showGutter}}<span
@@ -657,18 +680,40 @@ export class CodeBlock extends Component<CodeBlockSignature> {
657
680
  .pretui-code {
658
681
  margin: 0;
659
682
  display: grid;
660
- border-radius: var(--radius);
661
- background: var(--card);
683
+ border-radius: var(--boxel-border-radius);
684
+ background-color: var(--card);
685
+ color: var(--card-foreground);
662
686
  box-shadow: var(--pretui-shadow-card, 0 0 0 1px var(--border));
663
687
  overflow: hidden;
664
688
  container-type: inline-size;
665
689
  }
690
+ /* compact: code inside a row is a glance, not a read: small, short,
691
+ and scrolled */
692
+ .pretui-code[data-density='compact'] {
693
+ --pretui-code-size: var(--boxel-font-size-2xs);
694
+ --pretui-code-leading: 1.45;
695
+ }
696
+ .pretui-code[data-density='compact'] .pretui-code-head {
697
+ padding: var(--boxel-sp-6xs) var(--boxel-sp-2xs) var(--boxel-sp-6xs)
698
+ var(--boxel-sp-xs);
699
+ }
700
+ .pretui-code[data-density='compact'] .pretui-code-body {
701
+ padding-block: var(--boxel-sp-4xs);
702
+ }
703
+ .pretui-code[data-density='compact']
704
+ .pretui-code-body[data-clamped='true'] {
705
+ max-height: calc(
706
+ var(--pretui-code-max, 24) * var(--pretui-code-leading, 1.6) *
707
+ var(--pretui-code-size, var(--boxel-font-size-xs)) +
708
+ var(--boxel-sp-4xs) * 2
709
+ );
710
+ }
666
711
  .pretui-code-head {
667
712
  display: flex;
668
713
  align-items: center;
669
- gap: var(--space-3, 8px);
670
- padding: var(--space-2, 6px) var(--space-3, 8px);
671
- background: color-mix(
714
+ gap: var(--boxel-sp-xs);
715
+ padding: var(--boxel-sp-2xs) var(--boxel-sp-xs);
716
+ background-color: color-mix(
672
717
  in oklch,
673
718
  var(--foreground) 4%,
674
719
  var(--card)
@@ -682,12 +727,11 @@ export class CodeBlock extends Component<CodeBlockSignature> {
682
727
  text-overflow: ellipsis;
683
728
  white-space: nowrap;
684
729
  font-family: var(--font-mono);
685
- font-size: var(--text-ui-sm, 11.5px);
686
- color: var(--foreground);
730
+ font-size: var(--boxel-font-size-xs);
687
731
  }
688
732
  .pretui-code-count {
689
733
  flex: 0 0 auto;
690
- font-size: var(--text-ui-xs, 10.5px);
734
+ font-size: var(--boxel-font-size-2xs);
691
735
  font-variant-numeric: tabular-nums;
692
736
  color: var(--muted-foreground);
693
737
  }
@@ -697,26 +741,25 @@ export class CodeBlock extends Component<CodeBlockSignature> {
697
741
  }
698
742
  .pretui-code-caption {
699
743
  margin: 0;
700
- padding: var(--space-2, 6px) var(--space-3, 8px) 0;
701
- font-size: var(--text-ui-sm, 11.5px);
744
+ padding: var(--boxel-sp-2xs) var(--boxel-sp-xs) 0;
745
+ font-size: var(--boxel-font-size-xs);
702
746
  color: var(--muted-foreground);
703
747
  }
704
748
  .pretui-code-binary {
705
749
  margin: 0;
706
- padding: var(--space-4, 12px) var(--space-3, 8px);
707
- font-size: var(--text-ui-sm, 11.5px);
750
+ padding: var(--boxel-sp-sm) var(--boxel-sp-xs);
751
+ font-size: var(--boxel-font-size-xs);
708
752
  color: var(--muted-foreground);
709
753
  }
710
754
  .pretui-code-body {
711
755
  margin: 0;
712
- padding: var(--space-3, 8px) 0;
756
+ padding: var(--boxel-sp-xs) 0;
713
757
  overflow: auto;
714
758
  font-family: var(--font-mono);
715
- font-size: var(--pretui-code-size, 12px);
759
+ font-size: var(--pretui-code-size, var(--boxel-font-size-xs));
716
760
  line-height: var(--pretui-code-leading, 1.6);
717
761
  /* Law 8 — code is numerals as often as it is words. */
718
762
  font-variant-numeric: tabular-nums;
719
- color: var(--foreground);
720
763
  tab-size: var(--pretui-code-tab, 2);
721
764
  }
722
765
  /* The scroll ceiling. `--pretui-code-max` is a line COUNT set from the
@@ -725,7 +768,8 @@ export class CodeBlock extends Component<CodeBlockSignature> {
725
768
  .pretui-code-body[data-clamped='true'] {
726
769
  max-height: calc(
727
770
  var(--pretui-code-max, 24) * var(--pretui-code-leading, 1.6) *
728
- var(--pretui-code-size, 12px) + var(--space-3, 8px) * 2
771
+ var(--pretui-code-size, var(--boxel-font-size-xs)) +
772
+ var(--boxel-sp-xs) * 2
729
773
  );
730
774
  }
731
775
  .pretui-code-body:focus-visible {
@@ -734,12 +778,14 @@ export class CodeBlock extends Component<CodeBlockSignature> {
734
778
  }
735
779
  .pretui-code-code {
736
780
  display: block;
737
- font: inherit;
781
+ font-family: inherit;
782
+ font-size: inherit;
783
+ line-height: inherit;
738
784
  min-width: max-content;
739
785
  }
740
786
  .pretui-code-line {
741
787
  display: block;
742
- padding-inline: var(--space-3, 8px);
788
+ padding-inline: var(--boxel-sp-xs);
743
789
  /* A blank line is still a line. Without this an empty block collapses
744
790
  to nothing and the code silently loses its paragraphing. */
745
791
  min-height: calc(var(--pretui-code-leading, 1.6) * 1em);
@@ -747,7 +793,7 @@ export class CodeBlock extends Component<CodeBlockSignature> {
747
793
  /* The mark carries a SHAPE as well as a tint, so it
748
794
  survives greyscale and a colour-blind reader. */
749
795
  .pretui-code-line[data-marked='true'] {
750
- background: color-mix(
796
+ background-color: color-mix(
751
797
  in oklch,
752
798
  var(--primary) 10%,
753
799
  transparent
@@ -763,7 +809,7 @@ export class CodeBlock extends Component<CodeBlockSignature> {
763
809
  --pretui-code-gutter,
764
810
  calc(var(--pretui-code-digits, 2) * 1ch + 0.5ch)
765
811
  );
766
- margin-inline-end: var(--space-3, 8px);
812
+ margin-inline-end: var(--boxel-sp-xs);
767
813
  text-align: end;
768
814
  /* Not selectable, so dragging across the code does not drag the
769
815
  numbers into the clipboard with it. The prefix is not optional:
@@ -771,11 +817,7 @@ export class CodeBlock extends Component<CodeBlockSignature> {
771
817
  where a drag-select is most likely. */
772
818
  -webkit-user-select: none;
773
819
  user-select: none;
774
- color: color-mix(
775
- in oklch,
776
- var(--muted-foreground) 65%,
777
- transparent
778
- );
820
+ color: color-mix(in oklch, var(--muted-foreground) 65%, transparent);
779
821
  }
780
822
  .pretui-code-text {
781
823
  white-space: pre;
@@ -824,7 +866,7 @@ export class CodeBlock extends Component<CodeBlockSignature> {
824
866
  var(--foreground) 18%,
825
867
  var(--pretui-code-keyword, var(--chart-4))
826
868
  );
827
- font-weight: var(--weight-medium, 500);
869
+ font-weight: 500;
828
870
  }
829
871
  .pretui-code-name {
830
872
  color: color-mix(
@@ -844,22 +886,22 @@ export class CodeBlock extends Component<CodeBlockSignature> {
844
886
  appearance: none;
845
887
  border: 0;
846
888
  width: 100%;
847
- padding: var(--space-2, 6px);
848
- background: color-mix(
889
+ padding: var(--boxel-sp-2xs);
890
+ background-color: color-mix(
849
891
  in oklch,
850
892
  var(--foreground) 4%,
851
893
  var(--card)
852
894
  );
853
895
  box-shadow: inset 0 1px 0 var(--border);
854
- font: inherit;
855
- font-size: var(--text-ui-sm, 11.5px);
896
+ font-family: inherit;
897
+ font-size: var(--boxel-font-size-xs);
856
898
  color: var(--muted-foreground);
857
899
  cursor: pointer;
858
900
  transition: background-color 160ms
859
901
  var(--pretui-ease-snap, cubic-bezier(0.23, 1, 0.32, 1));
860
902
  }
861
903
  .pretui-code-more:hover {
862
- background: var(--hover, color-mix(in oklch, var(--foreground) 7%, var(--card)));
904
+ background-color: var(--hover);
863
905
  color: var(--foreground);
864
906
  }
865
907
  .pretui-code-more:active {
@@ -871,7 +913,7 @@ export class CodeBlock extends Component<CodeBlockSignature> {
871
913
  }
872
914
  @media (pointer: coarse) {
873
915
  .pretui-code-more {
874
- min-height: 44px;
916
+ min-height: 2.75rem;
875
917
  }
876
918
  }
877
919
  @media (prefers-reduced-motion: reduce) {
@@ -1,42 +1,163 @@
1
1
  // Pretui — CollapsedTurn: a settled conversation turn folded to a one-line receipt.
2
2
  import Component from '@glimmer/component';
3
+ import { StateGlyph } from './state-glyph';
3
4
  import { on } from '@ember/modifier';
4
5
 
5
6
  export interface CollapsedTurnSignature {
6
- Args: { summary: string; onExpand?: () => void };
7
+ Args: {
8
+ summary: string;
9
+ /** called when the reader presses the line */
10
+ onExpand?: () => void;
11
+ /** the line is a toggle: set while the turn's work is shown, so the
12
+ * line says it can fold again (aria-expanded, a turned chevron) */
13
+ expanded?: boolean;
14
+ /** the element the line shows and hides, for aria-controls */
15
+ controls?: string;
16
+ /** 'pill' (default): a capsule. 'row': a line on ToolRow's grid, its
17
+ * check in the disc column and its words on the row's text edge, so a
18
+ * folded turn reads as one more row in a transcript of rows */
19
+ variant?: 'pill' | 'row';
20
+ };
7
21
  Element: HTMLButtonElement;
8
22
  }
9
23
 
10
24
  // Settled history earns its quiet: a receipt of counts, not content.
11
25
  export class CollapsedTurn extends Component<CollapsedTurnSignature> {
12
26
  expand = () => this.args.onExpand?.();
27
+ get isToggle() {
28
+ return this.args.expanded !== undefined;
29
+ }
30
+ get expandedState() {
31
+ if (!this.isToggle) {
32
+ return undefined;
33
+ }
34
+ return this.args.expanded ? 'true' : 'false';
35
+ }
13
36
  <template>
14
- <button type='button' class='pretui-collapsed' data-test-pretui-collapsed-turn {{on 'click' this.expand}} ...attributes>
15
- <span class='pretui-collapsed-check'>✓</span>{{@summary}}
37
+ <button
38
+ type='button'
39
+ class='pretui-collapsed'
40
+ data-variant={{if @variant @variant 'pill'}}
41
+ aria-expanded={{this.expandedState}}
42
+ aria-controls={{@controls}}
43
+ {{on 'click' this.expand}}
44
+ data-test-pretui-collapsed-turn
45
+ ...attributes
46
+ >
47
+ <StateGlyph
48
+ class='pretui-collapsed-check'
49
+ @glyph='done'
50
+ data-test-pretui-collapsed-turn-check
51
+ />
52
+ <span
53
+ class='pretui-collapsed-summary'
54
+ data-test-pretui-collapsed-turn-summary
55
+ >{{@summary}}</span>
56
+ {{#if this.isToggle}}
57
+ <span
58
+ class='pretui-collapsed-chevron'
59
+ data-open={{if @expanded 'true'}}
60
+ aria-hidden='true'
61
+ data-test-pretui-collapsed-turn-chevron
62
+ ></span>
63
+ {{/if}}
16
64
  </button>
17
65
  <style scoped>
18
66
  @layer PretComponent {
19
67
  .pretui-collapsed {
20
68
  display: inline-flex;
21
69
  align-items: center;
22
- gap: 7px;
23
- height: 24px;
24
- padding: 0 calc(5px * var(--pretui-capsule-base, 1.35) + 12px * var(--pretui-radius-encroach, 0.35));
25
- border-radius: 12px;
70
+ gap: var(--boxel-sp-xs);
71
+ max-width: 100%;
72
+ min-height: 1.5rem;
73
+ padding: 0
74
+ calc(
75
+ 0.3125rem * var(--pretui-capsule-base, 1.35) +
76
+ var(--boxel-border-radius-sm) *
77
+ var(--pretui-radius-encroach, 0.35)
78
+ );
79
+ border-radius: var(--boxel-border-radius-sm);
26
80
  border: 0;
27
- background: var(--inset, var(--boxel-100));
81
+ background-color: var(--inset);
28
82
  box-shadow: var(--pretui-shadow-hairline, 0 0 0 1px var(--border));
29
- font: inherit;
30
- font-size: var(--text-ui-sm, 11.5px);
83
+ font-family: inherit;
84
+ font-size: var(--boxel-ui-label-font-size);
85
+ line-height: var(--boxel-ui-label-line-height);
31
86
  color: var(--muted-foreground);
32
87
  cursor: pointer;
33
88
  font-variant-numeric: tabular-nums;
89
+ text-align: start;
34
90
  }
35
91
  .pretui-collapsed:hover {
36
- background: var(--hover, var(--boxel-100));
92
+ background-color: var(--hover);
93
+ color: var(--foreground);
37
94
  }
95
+ .pretui-collapsed:focus-visible {
96
+ outline: 2px solid var(--ring);
97
+ outline-offset: 2px;
98
+ }
99
+ /* done is ink with a check, not green */
38
100
  .pretui-collapsed-check {
39
- color: var(--success, var(--boxel-success));
101
+ flex: none;
102
+ color: var(--foreground);
103
+ }
104
+ .pretui-collapsed-summary {
105
+ min-width: 0;
106
+ overflow: hidden;
107
+ text-overflow: ellipsis;
108
+ white-space: nowrap;
109
+ }
110
+ /* points right while folded, down while the work shows */
111
+ .pretui-collapsed-chevron {
112
+ flex: none;
113
+ width: 0.3125rem;
114
+ height: 0.3125rem;
115
+ margin-inline-start: 0.0625rem;
116
+ border-inline-end: 1.5px solid currentColor;
117
+ border-block-end: 1.5px solid currentColor;
118
+ transform: rotate(-45deg);
119
+ transition: transform 160ms
120
+ var(--pretui-ease-enter, cubic-bezier(0.22, 0.61, 0.25, 1));
121
+ }
122
+ .pretui-collapsed-chevron[data-open] {
123
+ transform: rotate(45deg);
124
+ }
125
+ @media (prefers-reduced-motion: reduce) {
126
+ .pretui-collapsed-chevron {
127
+ transition: none;
128
+ }
129
+ }
130
+ /* the row form: ToolRow's grid (inset, disc, gap), its height, and
131
+ the receipt's quiet caption voice (sans, tabular), with no capsule
132
+ around it */
133
+ /* the row form keeps a hover pad but hangs it outside the text
134
+ edge, so its check lines up with every other mark in the thread */
135
+ .pretui-collapsed[data-variant='row'] {
136
+ display: flex;
137
+ box-sizing: content-box;
138
+ width: 100%;
139
+ min-height: 1.625rem;
140
+ gap: var(--pretui-toolrow-gap, var(--boxel-sp-xs));
141
+ margin-inline: calc(
142
+ -1 * var(--pretui-toolrow-inset, var(--boxel-sp-xs))
143
+ );
144
+ padding: 0 var(--pretui-toolrow-inset, var(--boxel-sp-xs));
145
+ border-radius: var(--boxel-border-radius-sm);
146
+ background-color: transparent;
147
+ box-shadow: none;
148
+ font-size: var(--boxel-caption-font-size);
149
+ line-height: var(--boxel-caption-line-height);
150
+ color: var(--subtle-foreground);
151
+ }
152
+ .pretui-collapsed[data-variant='row']:hover {
153
+ background-color: var(--inset);
154
+ color: var(--muted-foreground);
155
+ }
156
+ .pretui-collapsed[data-variant='row'] .pretui-collapsed-check {
157
+ width: var(--pretui-toolrow-disc, 1rem);
158
+ text-align: center;
159
+ font-size: var(--boxel-ui-label-font-size);
160
+ line-height: var(--boxel-ui-label-line-height);
40
161
  }
41
162
  }
42
163
  </style>