@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
@@ -0,0 +1,98 @@
1
+ // Pretui — AgentMark: the assistant's own icon, still when settled and animated while it works.
2
+ import Component from '@glimmer/component';
3
+ import { htmlSafe } from '@ember/template';
4
+ import { cssNumber } from '../pretui-css';
5
+
6
+ export interface AgentMarkSignature {
7
+ Args: {
8
+ /** the assistant is working: the mark animates (the host's animated
9
+ * icon), and holds still under reduced motion */
10
+ working?: boolean;
11
+ /** px. Default 16 */
12
+ size?: number;
13
+ };
14
+ Element: HTMLSpanElement;
15
+ }
16
+
17
+ /**
18
+ * The assistant's mark, wherever the transcript names it: beside its
19
+ * speaker label, at the head of a turn. The host gives its icon as tokens,
20
+ * since a realm-served kit carries no bitmaps:
21
+ *
22
+ * ```css
23
+ * --pretui-agent-icon: image-set(url(ai-assist-icon.webp) 1x, url(ai-assist-icon@2x.webp) 2x);
24
+ * --pretui-agent-icon-working: url(ai-assist-icon-animated.webp);
25
+ * --pretui-agent-glyph: '';
26
+ * ```
27
+ *
28
+ * Without them it draws the ✦ the kit uses elsewhere, which pulses while
29
+ * the assistant works. Decorative: the label beside it says who.
30
+ */
31
+ export class AgentMark extends Component<AgentMarkSignature> {
32
+ /** the size in rem (the argument is px, as icon sizes are), through the
33
+ * kit's number guard so a stray value cannot write other declarations */
34
+ get style() {
35
+ let px = cssNumber(this.args.size, 0, 1000) ?? 16;
36
+ return htmlSafe(`--pretui-agent-mark-size: ${px / 16}rem`);
37
+ }
38
+ <template>
39
+ <span
40
+ class='pretui-agentmark'
41
+ data-working={{if @working 'true'}}
42
+ style={{this.style}}
43
+ aria-hidden='true'
44
+ data-test-pretui-agent-mark={{if @working 'working' 'settled'}}
45
+ ...attributes
46
+ ></span>
47
+ <style scoped>
48
+ @layer PretComponent {
49
+ .pretui-agentmark {
50
+ display: inline-grid;
51
+ place-items: center;
52
+ flex: none;
53
+ width: var(--pretui-agent-mark-size);
54
+ height: var(--pretui-agent-mark-size);
55
+ background-image: var(--pretui-agent-icon, none);
56
+ background-size: contain;
57
+ background-repeat: no-repeat;
58
+ background-position: center;
59
+ /* a mark, not text: the glyph scales with the mark's box */
60
+ font-size: calc(var(--pretui-agent-mark-size) * 0.75);
61
+ line-height: 1;
62
+ /* settled, the fallback glyph is ink; teal is for live work */
63
+ color: var(--muted-foreground);
64
+ vertical-align: -0.2em;
65
+ }
66
+ .pretui-agentmark[data-working] {
67
+ color: var(--primary-ink);
68
+ }
69
+ .pretui-agentmark::before {
70
+ content: var(--pretui-agent-glyph, '✦');
71
+ }
72
+ .pretui-agentmark[data-working] {
73
+ background-image: var(
74
+ --pretui-agent-icon-working,
75
+ var(--pretui-agent-icon, none)
76
+ );
77
+ }
78
+ .pretui-agentmark[data-working]::before {
79
+ animation: pretui-agentmark-pulse 1.2s ease-in-out infinite;
80
+ }
81
+ @keyframes pretui-agentmark-pulse {
82
+ 50% {
83
+ opacity: 0.35;
84
+ transform: scale(0.8);
85
+ }
86
+ }
87
+ @media (prefers-reduced-motion: reduce) {
88
+ .pretui-agentmark[data-working] {
89
+ background-image: var(--pretui-agent-icon, none);
90
+ }
91
+ .pretui-agentmark[data-working]::before {
92
+ animation: none;
93
+ }
94
+ }
95
+ }
96
+ </style>
97
+ </template>
98
+ }
@@ -1,24 +1,116 @@
1
1
  // Pretui — AgentQuestion: a question the agent is waiting on, answered in place.
2
2
  import Component from '@glimmer/component';
3
+ import { StateGlyph } from './state-glyph';
3
4
  import { tracked } from '@glimmer/tracking';
4
5
  import { on } from '@ember/modifier';
5
6
  import { fn } from '@ember/helper';
7
+ import { cssStyle } from '../pretui-css';
6
8
 
7
9
  export interface AgentQuestionSignature {
8
10
  Args: {
9
11
  question: string;
10
12
  options?: string[];
13
+ /** richer answers than words: the real things to pick between. Each
14
+ * settles the question with its label */
15
+ choices?: AgentChoice[];
16
+ /** how @choices are drawn: 'cards' (a tile with an optional image and a
17
+ * line under the label) or 'swatches' (a colour chip and its name).
18
+ * Default 'cards' */
19
+ layout?: 'cards' | 'swatches';
20
+ /** the free answer's placeholder. Default 'Or type an answer…' */
21
+ otherLabel?: string;
11
22
  answered?: string;
12
23
  onAnswer?: (answer: string) => void;
24
+ /** the question, without its answers: a read-only transcript or a
25
+ * teammate's request */
26
+ readonly?: boolean;
27
+ /** false: a closed set, the given options only, with no free answer
28
+ * (a server that validates option ids). Default true */
29
+ freeAnswer?: boolean;
30
+ /** the answer is on its way: every option waits */
31
+ pending?: boolean;
32
+ /** a choice is picked first, then confirmed, so a stray tap on a card or
33
+ * a swatch never answers. Pills and the free answer still settle at once */
34
+ confirm?: boolean;
35
+ };
36
+ Blocks: {
37
+ /** a choice's own content, drawn above its label in place of its image:
38
+ * a live card, a rendered preview */
39
+ choice: [AgentChoice];
13
40
  };
14
41
  Element: HTMLDivElement;
15
42
  }
16
43
 
44
+ export interface AgentChoice {
45
+ label: string;
46
+ /** what the answer reports when it differs from the label: an id, a URL,
47
+ * a colour. Default the label */
48
+ value?: string;
49
+ /** a quieter line under the label: "Headlamps, city lights" */
50
+ sub?: string;
51
+ /** an image for a card choice */
52
+ image?: string;
53
+ /** a CSS colour for a swatch choice */
54
+ swatch?: string;
55
+ }
56
+
57
+ // a swatch is agent-supplied, so it is validated as one CSS value before it
58
+ // reaches the style attribute; a rejected value draws no colour
59
+ const swatchStyle = (choice: AgentChoice) => cssStyle('--swatch', choice.swatch);
60
+
61
+ const choiceValue = (choice: AgentChoice) => choice.value ?? choice.label;
62
+
17
63
  // ASK verb: option pills + free answer; settles to a quiet answered line.
18
64
  export class AgentQuestion extends Component<AgentQuestionSignature> {
19
- @tracked picked?: string = this.args.answered;
65
+ /** the reader's own answer, before the caller reports it back */
66
+ @tracked private localPicked?: string;
67
+ /** the settled answer: the caller's `@answered` wins, so a question that
68
+ * is answered elsewhere (a teammate's, a read-only transcript) settles
69
+ * when the answer arrives */
70
+ get picked(): string | undefined {
71
+ return this.args.answered ?? this.localPicked;
72
+ }
73
+ /** the choice picked but not yet confirmed (with @confirm) */
74
+ @tracked selected?: AgentChoice;
75
+ /** the settled answer as words: a choice's label, not its value */
76
+ get pickedLabel(): string | undefined {
77
+ let picked = this.picked;
78
+ let choice = this.args.choices?.find((c) => choiceValue(c) === picked);
79
+ return choice?.label ?? picked;
80
+ }
81
+ get confirmLabel(): string {
82
+ let choice = this.selected;
83
+ if (!choice) {
84
+ return this.args.layout === 'swatches' ? 'Pick a colour' : 'Pick one';
85
+ }
86
+ return this.args.layout === 'swatches'
87
+ ? `Use ${choice.label}`
88
+ : `Choose ${choice.label}`;
89
+ }
90
+ isSelected = (choice: AgentChoice) => this.selected === choice;
91
+ pick = (choice: AgentChoice) => {
92
+ if (this.args.readonly || this.args.pending) {
93
+ return;
94
+ }
95
+ if (this.args.confirm) {
96
+ this.selected = choice;
97
+ return;
98
+ }
99
+ this.settle(choiceValue(choice));
100
+ };
101
+ confirmPick = () => {
102
+ if (this.selected) {
103
+ this.settle(choiceValue(this.selected));
104
+ }
105
+ };
106
+ get offersFreeAnswer() {
107
+ return this.args.freeAnswer !== false;
108
+ }
20
109
  settle = (value: string) => {
21
- this.picked = value;
110
+ if (this.args.readonly || this.args.pending) {
111
+ return;
112
+ }
113
+ this.localPicked = value;
22
114
  this.args.onAnswer?.(value);
23
115
  };
24
116
  onKey = (e: Event) => {
@@ -30,85 +122,296 @@ export class AgentQuestion extends Component<AgentQuestionSignature> {
30
122
  };
31
123
  <template>
32
124
  {{#if this.picked}}
33
- <div class='pretui-answered' data-test-pretui-agent-question ...attributes>
34
- <span class='pretui-answered-check'>✓</span>
125
+ <div
126
+ class='pretui-answered'
127
+ data-test-pretui-agent-question
128
+ ...attributes
129
+ >
130
+ <StateGlyph class='pretui-answered-check' @glyph='done' />
35
131
  {{@question}}
36
- <b>{{this.picked}}</b>
132
+ <b>{{this.pickedLabel}}</b>
37
133
  </div>
38
134
  {{else}}
39
- <div class='pretui-question' data-test-pretui-agent-question ...attributes>
135
+ <div
136
+ class='pretui-question'
137
+ aria-busy={{if @pending 'true'}}
138
+ data-pending={{if @pending 'true'}}
139
+ data-test-pretui-agent-question
140
+ ...attributes
141
+ >
40
142
  <div class='pretui-question-text'>{{@question}}</div>
41
- <div class='pretui-question-opts'>
42
- {{#each @options as |option|}}
43
- <button type='button' class='pretui-qpill' {{on 'click' (fn this.settle option)}}>{{option}}</button>
44
- {{/each}}
45
- </div>
46
- <input class='pretui-qinput' aria-label='Answer' placeholder='Or type an answer…' {{on 'keydown' this.onKey}} />
143
+ {{#if @readonly}}
144
+ <p
145
+ class='pretui-question-readonly'
146
+ data-test-pretui-agent-question-readonly
147
+ >Waiting for an answer</p>
148
+ {{else}}
149
+ {{#if @options.length}}
150
+ <div class='pretui-question-opts'>
151
+ {{#each @options as |option|}}
152
+ <button
153
+ type='button'
154
+ class='pretui-qpill'
155
+ {{on 'click' (fn this.settle option)}}
156
+ >{{option}}</button>
157
+ {{/each}}
158
+ </div>
159
+ {{/if}}
160
+ {{#if @choices.length}}
161
+ <div
162
+ class='pretui-question-choices'
163
+ data-layout={{if @layout @layout 'cards'}}
164
+ data-test-pretui-agent-choices
165
+ >
166
+ {{#each @choices as |choice|}}
167
+ <button
168
+ type='button'
169
+ class='pretui-qchoice'
170
+ style={{swatchStyle choice}}
171
+ aria-pressed={{if
172
+ @confirm
173
+ (if (this.isSelected choice) 'true' 'false')
174
+ }}
175
+ {{on 'click' (fn this.pick choice)}}
176
+ data-test-pretui-agent-choice={{choice.label}}
177
+ >
178
+ {{#if (has-block 'choice')}}
179
+ <span class='pretui-qchoice-content'>{{yield
180
+ choice
181
+ to='choice'
182
+ }}</span>
183
+ {{else if choice.image}}<img
184
+ class='pretui-qchoice-image'
185
+ src={{choice.image}}
186
+ alt=''
187
+ data-test-pretui-agent-choice-image
188
+ />{{/if}}
189
+ {{#if choice.swatch}}<span
190
+ class='pretui-qchoice-swatch'
191
+ aria-hidden='true'
192
+ data-test-pretui-agent-choice-swatch
193
+ ></span>{{/if}}
194
+ <span class='pretui-qchoice-label'>{{choice.label}}</span>
195
+ {{#if choice.sub}}<span
196
+ class='pretui-qchoice-sub'
197
+ >{{choice.sub}}</span>{{/if}}
198
+ </button>
199
+ {{/each}}
200
+ </div>
201
+ {{#if @confirm}}
202
+ <button
203
+ type='button'
204
+ class='pretui-qconfirm'
205
+ disabled={{if this.selected false true}}
206
+ {{on 'click' this.confirmPick}}
207
+ data-test-pretui-agent-confirm
208
+ >{{this.confirmLabel}}</button>
209
+ {{/if}}
210
+ {{/if}}
211
+ {{#if this.offersFreeAnswer}}
212
+ <input
213
+ class='pretui-qinput'
214
+ aria-label='Answer'
215
+ placeholder={{if @otherLabel @otherLabel 'Or type an answer…'}}
216
+ disabled={{@pending}}
217
+ {{on 'keydown' this.onKey}}
218
+ />
219
+ {{/if}}
220
+ {{/if}}
47
221
  </div>
48
222
  {{/if}}
49
223
  <style scoped>
50
224
  @layer PretComponent {
51
225
  .pretui-question {
52
226
  display: grid;
53
- gap: 8px;
227
+ gap: var(--boxel-sp-xs);
54
228
  }
229
+ /* the question is the agent speaking: reading size, its weight the
230
+ one step up */
55
231
  .pretui-question-text {
56
- font-weight: 500;
232
+ font-size: var(--boxel-body-font-size);
233
+ line-height: var(--boxel-body-line-height);
234
+ font-weight: 600;
235
+ color: var(--foreground);
57
236
  }
58
237
  .pretui-question-opts {
59
238
  display: flex;
60
239
  flex-wrap: wrap;
61
- gap: 6px;
240
+ gap: var(--boxel-sp-xs);
62
241
  }
242
+ /* a quick answer: outlined and quiet, so no one option shouts */
63
243
  .pretui-qpill {
64
244
  display: inline-flex;
65
245
  align-items: center;
66
- height: 26px;
67
- padding: 0 calc(6px * var(--pretui-capsule-base, 1.35) + 13px * var(--pretui-radius-encroach, 0.35));
68
- border-radius: 13px;
246
+ height: 1.75rem;
247
+ padding: 0 var(--boxel-sp-sm);
248
+ border-radius: var(--boxel-border-radius-sm);
69
249
  border: 0;
70
- background: var(--card);
71
- box-shadow: var(--pretui-shadow-control, 0 0 0 1px var(--border));
72
- font: inherit;
73
- font-size: var(--text-ui, 12px);
74
- font-weight: 500;
250
+ background-color: transparent;
251
+ box-shadow: inset 0 0 0 1px var(--border);
252
+ font-family: inherit;
253
+ font-size: var(--boxel-ui-label-font-size);
254
+ line-height: var(--boxel-ui-label-line-height);
255
+ font-weight: 400;
75
256
  cursor: pointer;
76
257
  color: var(--foreground);
77
258
  }
78
259
  .pretui-qpill:hover {
79
- background: var(--hover, var(--boxel-100));
260
+ background-color: var(--hover);
261
+ box-shadow: inset 0 0 0 1px var(--border-strong);
262
+ }
263
+ .pretui-qpill:focus-visible {
264
+ outline: 2px solid var(--ring);
265
+ outline-offset: 1px;
266
+ }
267
+ /* the real things to pick between: tiles for cards, chips for
268
+ colours; a choice is one button, its label the answer */
269
+ .pretui-question-choices {
270
+ display: grid;
271
+ grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
272
+ gap: var(--boxel-sp-xs);
273
+ }
274
+ .pretui-question-choices[data-layout='swatches'] {
275
+ grid-template-columns: repeat(auto-fill, minmax(5.25rem, 1fr));
276
+ }
277
+ .pretui-qchoice {
278
+ display: grid;
279
+ align-content: start;
280
+ gap: var(--boxel-sp-6xs);
281
+ min-width: 0;
282
+ padding: var(--boxel-sp-xs);
283
+ border: 0;
284
+ border-radius: var(--boxel-border-radius-sm);
285
+ background-color: transparent;
286
+ box-shadow: inset 0 0 0 1px var(--border);
287
+ font-family: inherit;
288
+ text-align: start;
289
+ color: var(--foreground);
290
+ cursor: pointer;
291
+ }
292
+ .pretui-qchoice:hover {
293
+ background-color: var(--hover);
294
+ box-shadow: inset 0 0 0 1px var(--border-strong);
295
+ }
296
+ .pretui-qchoice:focus-visible {
297
+ outline: 2px solid var(--ring);
298
+ outline-offset: 2px;
299
+ }
300
+ /* picked, waiting for Confirm: outlined in ink-1 */
301
+ .pretui-qchoice[aria-pressed='true'] {
302
+ box-shadow: inset 0 0 0 2px var(--foreground);
303
+ }
304
+ .pretui-qchoice-content {
305
+ display: block;
306
+ height: var(--pretui-qchoice-content-h, 6rem);
307
+ margin-bottom: var(--boxel-sp-4xs);
308
+ overflow: hidden;
309
+ border-radius: var(--boxel-border-radius-xs);
310
+ pointer-events: none;
311
+ }
312
+ /* Confirm is the one answer: the moment's primary */
313
+ .pretui-qconfirm {
314
+ justify-self: start;
315
+ height: 1.75rem;
316
+ padding: 0 var(--boxel-sp-sm);
317
+ border: 0;
318
+ border-radius: var(--boxel-border-radius-sm);
319
+ background-color: var(--primary);
320
+ color: var(--primary-foreground);
321
+ font-family: inherit;
322
+ font-size: var(--boxel-ui-label-font-size);
323
+ line-height: var(--boxel-ui-label-line-height);
324
+ font-weight: 600;
325
+ cursor: pointer;
326
+ }
327
+ .pretui-qconfirm:disabled {
328
+ opacity: 0.5;
329
+ cursor: default;
330
+ }
331
+ .pretui-qconfirm:focus-visible {
332
+ outline: 2px solid var(--ring);
333
+ outline-offset: 2px;
334
+ }
335
+ .pretui-qchoice-image {
336
+ display: block;
337
+ width: 100%;
338
+ aspect-ratio: 16 / 10;
339
+ margin-bottom: var(--boxel-sp-4xs);
340
+ border-radius: var(--boxel-border-radius-xs);
341
+ background-color: var(--inset);
342
+ object-fit: cover;
343
+ }
344
+ .pretui-qchoice-swatch {
345
+ display: block;
346
+ height: 1.375rem;
347
+ margin-bottom: var(--boxel-sp-4xs);
348
+ border-radius: var(--boxel-border-radius-xs);
349
+ background-color: var(--swatch, var(--muted));
350
+ box-shadow: inset 0 0 0 1px var(--border);
351
+ }
352
+ .pretui-qchoice-label {
353
+ font-size: var(--boxel-ui-label-font-size);
354
+ line-height: var(--boxel-ui-label-line-height);
355
+ font-weight: 600;
356
+ overflow: hidden;
357
+ text-overflow: ellipsis;
358
+ white-space: nowrap;
359
+ }
360
+ .pretui-qchoice-sub {
361
+ font-size: var(--boxel-caption-font-size);
362
+ line-height: var(--boxel-caption-line-height);
363
+ color: var(--muted-foreground);
364
+ }
365
+ /* sent, waiting on the agent: the options step down to ink-3 and
366
+ take no more presses */
367
+ .pretui-question[data-pending] .pretui-qpill,
368
+ .pretui-question[data-pending] .pretui-qchoice {
369
+ color: var(--subtle-foreground);
370
+ pointer-events: none;
371
+ }
372
+ .pretui-question-readonly {
373
+ margin: 0;
374
+ font-size: var(--boxel-caption-font-size);
375
+ line-height: var(--boxel-caption-line-height);
376
+ color: var(--muted-foreground);
80
377
  }
81
378
  .pretui-qinput {
82
379
  display: flex;
83
380
  align-items: center;
84
- height: var(--control-h, 28px);
85
- padding: 0 9px;
381
+ height: 1.75rem;
382
+ padding: 0 var(--boxel-sp-xs);
86
383
  border: 0;
87
- border-radius: var(--radius);
88
- font: inherit;
89
- font-size: var(--text-ui-md, 12.5px);
384
+ border-radius: var(--boxel-border-radius-sm);
385
+ font-family: inherit;
386
+ font-size: var(--boxel-ui-label-font-size);
387
+ line-height: var(--boxel-ui-label-line-height);
90
388
  color: var(--foreground);
91
- background: var(--field, var(--boxel-light));
92
- box-shadow: 0 0 0 1px var(--input);
389
+ background-color: var(--field);
390
+ box-shadow: inset 0 0 0 1px var(--input);
93
391
  width: 100%;
94
392
  }
393
+ .pretui-qinput::placeholder {
394
+ color: var(--subtle-foreground);
395
+ }
95
396
  .pretui-qinput:focus {
96
- outline: none;
97
- box-shadow: 0 0 0 2px var(--primary), var(--pretui-shadow-inset, inset 0 1px 2px rgb(0 0 0 / 0.16));
397
+ outline: 2px solid var(--ring);
398
+ outline-offset: 1px;
98
399
  }
400
+ /* answered: done is ink with a check, the answer in ink-1 */
99
401
  .pretui-answered {
100
402
  display: flex;
101
403
  align-items: center;
102
- gap: 8px;
103
- font-size: var(--text-ui-md, 12.5px);
404
+ gap: var(--boxel-sp-xs);
405
+ font-size: var(--boxel-ui-label-font-size);
406
+ line-height: var(--boxel-ui-label-line-height);
104
407
  color: var(--muted-foreground);
105
408
  }
106
409
  .pretui-answered-check {
107
- color: var(--success, var(--boxel-success));
410
+ color: var(--foreground);
108
411
  }
109
412
  .pretui-answered b {
110
413
  color: var(--foreground);
111
- font-weight: 500;
414
+ font-weight: 600;
112
415
  }
113
416
  }
114
417
  </style>