@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.
- package/bundled-realms/pretui/components/agent-mark.gts +98 -0
- package/bundled-realms/pretui/components/agent-question.gts +340 -37
- package/bundled-realms/pretui/components/answer-footer.gts +249 -0
- package/bundled-realms/pretui/components/card-embed.gts +523 -0
- package/bundled-realms/pretui/components/card-pills.gts +725 -0
- package/bundled-realms/pretui/components/code-block.gts +87 -45
- package/bundled-realms/pretui/components/collapsed-turn.gts +133 -12
- package/bundled-realms/pretui/components/compaction-chip.gts +81 -67
- package/bundled-realms/pretui/components/composer-cap.gts +516 -0
- package/bundled-realms/pretui/components/context-ring.gts +108 -0
- package/bundled-realms/pretui/components/diff-block.gts +1002 -31
- package/bundled-realms/pretui/components/diff-stat.gts +102 -0
- package/bundled-realms/pretui/components/jump-chip.gts +86 -53
- package/bundled-realms/pretui/components/markdown-stream.gts +799 -0
- package/bundled-realms/pretui/components/markdown-surface.gts +71 -0
- package/bundled-realms/pretui/components/plan-mark.gts +147 -0
- package/bundled-realms/pretui/components/prose.gts +185 -8
- package/bundled-realms/pretui/components/prose.md +6 -8
- package/bundled-realms/pretui/components/quick-look.gts +377 -0
- package/bundled-realms/pretui/components/reactions.gts +136 -0
- package/bundled-realms/pretui/components/recommendation.gts +67 -36
- package/bundled-realms/pretui/components/result-card.gts +58 -22
- package/bundled-realms/pretui/components/segmented-control.gts +13 -8
- package/bundled-realms/pretui/components/session-prep.gts +12 -11
- package/bundled-realms/pretui/components/sliding-highlight.gts +8 -3
- package/bundled-realms/pretui/components/speaker-label.gts +132 -0
- package/bundled-realms/pretui/components/state-glyph.gts +121 -0
- package/bundled-realms/pretui/components/step-list.gts +62 -60
- package/bundled-realms/pretui/components/stick-to-bottom.gts +1150 -0
- package/bundled-realms/pretui/components/system-line.gts +143 -0
- package/bundled-realms/pretui/components/task-checklist.gts +184 -0
- package/bundled-realms/pretui/components/thinking.gts +63 -94
- package/bundled-realms/pretui/components/tool-change-table.gts +285 -0
- package/bundled-realms/pretui/components/tool-gate.gts +462 -0
- package/bundled-realms/pretui/components/tool-group.gts +920 -0
- package/bundled-realms/pretui/components/tool-icon.ts +64 -0
- package/bundled-realms/pretui/components/tool-meta.gts +82 -0
- package/bundled-realms/pretui/components/tool-plan.gts +197 -0
- package/bundled-realms/pretui/components/tool-row.gts +2087 -0
- package/bundled-realms/pretui/components/turn-changes.gts +227 -0
- package/bundled-realms/pretui/components/user-bubble.gts +575 -0
- package/bundled-realms/pretui/components/work-item.gts +185 -48
- package/bundled-realms/pretui/docs/scroll-anchoring-protocol.md +136 -0
- package/bundled-realms/pretui/internal/markdown-projection.ts +438 -0
- package/bundled-realms/pretui/internal/mount-queue.ts +79 -0
- package/bundled-realms/pretui/internal/tool-phrases.ts +168 -0
- package/bundled-realms/pretui/package.json +2 -1
- package/bundled-test-harness/assets/{ai-module-creation-test-beRNwH-e.js → ai-module-creation-test-B6FQKqIl.js} +1 -1
- package/bundled-test-harness/assets/{app-CtezUCip.js → app-KpPqdyX3.js} +4 -4
- package/bundled-test-harness/assets/{binary-upload-dedupe-test-bI8T0QLl.js → binary-upload-dedupe-test-DN00y1tM.js} +1 -1
- package/bundled-test-harness/assets/{can-invoke-test-DVaU_yRT.js → can-invoke-test-Bl-EUFM3.js} +1 -1
- package/bundled-test-harness/assets/{card-chooser-paging-test-DnxMnXKR.js → card-chooser-paging-test-BNuZRHX3.js} +1 -1
- package/bundled-test-harness/assets/{card-chooser-test-DUSnLr-u.js → card-chooser-test-wKfPOOT4.js} +1 -1
- package/bundled-test-harness/assets/{card-def-field-def-relationships-test-GBUr3tFK.js → card-def-field-def-relationships-test-CduQ6zan.js} +1 -1
- package/bundled-test-harness/assets/{card-delete-test-CQveO1VC.js → card-delete-test-DKxolj5o.js} +1 -1
- package/bundled-test-harness/assets/{check-correctness-test-D2M2p66N.js → check-correctness-test-B-kgHztp.js} +1 -1
- package/bundled-test-harness/assets/{codeblocks-test-AdolhdCA.js → codeblocks-test-BDD7qK_V.js} +1 -1
- package/bundled-test-harness/assets/{compaction-test-DvyAQq56.js → compaction-test-BweolkhG.js} +1 -1
- package/bundled-test-harness/assets/{container-DIF_9lZ9.css → container-B5B6u-xm.css} +29 -22
- package/bundled-test-harness/assets/{container-DvvqmNpg.js → container-BnJjIM6J.js} +9 -6
- package/bundled-test-harness/assets/{create-listing-modal-test-D95JfQab.js → create-listing-modal-test-FvcAKpIa.js} +1 -1
- package/bundled-test-harness/assets/{debug-message-test-BcNtj7Wr.js → debug-message-test-CJ18Evt7.js} +1 -1
- package/bundled-test-harness/assets/{externals-DCnB4XSS.js → externals-BWjhmCD4.js} +1 -1
- package/bundled-test-harness/assets/{fallback-banner-live-delete-test-5lnN1pv2.js → fallback-banner-live-delete-test-C2H3BrT-.js} +1 -1
- package/bundled-test-harness/assets/{fallback-banner-test-DFb_m_Kq.js → fallback-banner-test-C10aYjkj.js} +1 -1
- package/bundled-test-harness/assets/{fallback-models-test-p3YIwj1L.js → fallback-models-test-BxoPiaGF.js} +1 -1
- package/bundled-test-harness/assets/{file-attachment-test-CmyjNWRR.js → file-attachment-test-DeKyzYaz.js} +1 -1
- package/bundled-test-harness/assets/{general-test-CX-TFDuX.js → general-test-BewzrpoB.js} +1 -1
- package/bundled-test-harness/assets/{index-query-engine-test-CY2tAkot.js → index-query-engine-test-BtI8Y2LR.js} +1 -1
- package/bundled-test-harness/assets/{instance-filter-matcher-test-CMBTh8xn.js → instance-filter-matcher-test-BHXHGHjE.js} +1 -1
- package/bundled-test-harness/assets/{main-BOZbZVem.js → main-CqAHZ2kK.js} +1 -1
- package/bundled-test-harness/assets/{message-tool-test-CfjRSJvt.js → message-tool-test-NMaPJFsd.js} +1 -1
- package/bundled-test-harness/assets/{model-cost-tier-test-mZG84Uso.js → model-cost-tier-test-BgbfN2LH.js} +1 -1
- package/bundled-test-harness/assets/{operation-lowering-test-CHnjKSJb.js → operation-lowering-test-C4IaOjsA.js} +1 -1
- package/bundled-test-harness/assets/{operator-mode-card-chooser-test-KWS8lq16.js → operator-mode-card-chooser-test-Bwe47Rn7.js} +1 -1
- package/bundled-test-harness/assets/{operator-mode-links-test-CViFt0Ws.js → operator-mode-links-test-BU4jkC-B.js} +1 -1
- package/bundled-test-harness/assets/{operator-mode-test-D0gZM2yw.js → operator-mode-test-Bh0rGM9z.js} +1 -1
- package/bundled-test-harness/assets/{operator-mode-ui-test-CEvHJ9DS.js → operator-mode-ui-test-whgUw0ju.js} +1 -1
- package/bundled-test-harness/assets/{overlay-menu-items-test-Pw80RXsr.js → overlay-menu-items-test-Cwn1vr8q.js} +1 -1
- package/bundled-test-harness/assets/{past-sessions-test-CW0-Bjav.js → past-sessions-test-Bh24N-Kz.js} +1 -1
- package/bundled-test-harness/assets/{permission-checking-realm-test-D5uXQypS.js → permission-checking-realm-test-DKnnAy0f.js} +1 -1
- package/bundled-test-harness/assets/{realm-config-policy-standing-test-Btatheni.js → realm-config-policy-standing-test-DngdYypq.js} +1 -1
- package/bundled-test-harness/assets/{realm-config-routing-rule-edit-test-Dh5zW13o.js → realm-config-routing-rule-edit-test-_rkFU8SN.js} +1 -1
- package/bundled-test-harness/assets/{realm-config-settings-test-BJa8gv_C.js → realm-config-settings-test-CR9NH0Zn.js} +1 -1
- package/bundled-test-harness/assets/{reasoning-test-2Zp37cQB.js → reasoning-test-0lH10kRl.js} +1 -1
- package/bundled-test-harness/assets/{room-message-test-BsrON13e.js → room-message-test-C-PddE4Y.js} +1 -1
- package/bundled-test-harness/assets/{run-realm-code-BxktQf6R.js → run-realm-code-C8N7DtN-.js} +1 -1
- package/bundled-test-harness/assets/{run-realm-code-test-7grpTos-.js → run-realm-code-test-DBdp147q.js} +1 -1
- package/bundled-test-harness/assets/{schema-generation-test-CM9ggQji.js → schema-generation-test-CB1Hb7GQ.js} +1 -1
- package/bundled-test-harness/assets/{scrolling-test-BER00htB.js → scrolling-test-3PhVin8h.js} +1 -1
- package/bundled-test-harness/assets/{searchable-option-test-Ctf8r3HZ.js → searchable-option-test-BAdOiL4U.js} +1 -1
- package/bundled-test-harness/assets/{sending-test-BJGobs2E.js → sending-test-KSmu1tSJ.js} +1 -1
- package/bundled-test-harness/assets/{skills-test-GPOsHRN6.js → skills-test-D-dlcFpd.js} +1 -1
- package/bundled-test-harness/assets/{store-test-QvvHimzH.js → store-test-CEW7xQjZ.js} +1 -1
- package/bundled-test-harness/assets/{tests-DoTEpvcF.js → tests-QYqqa6nv.js} +47 -47
- package/bundled-test-harness/assets/{text-input-validator-test-CYYH2N0L.js → text-input-validator-test-D8iNOWep.js} +1 -1
- package/bundled-test-harness/assets/{to-device-streaming-test-Ctqa0bVp.js → to-device-streaming-test-trCX-505.js} +1 -1
- package/bundled-test-harness/assets/{token-usage-test-BQVbK3X0.js → token-usage-test-C6sULooH.js} +1 -1
- package/bundled-test-harness/assets/{tools-DU8Rc15s.js → tools-UJfD-_al.js} +1 -1
- package/bundled-test-harness/assets/{tools-test-B13yvEKE.js → tools-test-Brav31AV.js} +1 -1
- package/bundled-test-harness/assets/{worker-DHBEBihX.js → worker-9ph9_Lpv.js} +31 -26
- package/bundled-test-harness/index.html +8 -8
- package/bundled-test-harness/tests/index.html +8 -8
- package/bundled-types/host-app/lib/realm-runner/worker.ts +8 -51
- package/bundled-types/runtime-common/realm-runner-script.d.ts +3 -0
- 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
|
-
|
|
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.
|
|
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
|
|
34
|
-
|
|
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.
|
|
132
|
+
<b>{{this.pickedLabel}}</b>
|
|
37
133
|
</div>
|
|
38
134
|
{{else}}
|
|
39
|
-
<div
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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:
|
|
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-
|
|
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:
|
|
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:
|
|
67
|
-
padding: 0
|
|
68
|
-
border-radius:
|
|
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:
|
|
71
|
-
box-shadow:
|
|
72
|
-
font: inherit;
|
|
73
|
-
font-size: var(--
|
|
74
|
-
|
|
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
|
|
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:
|
|
85
|
-
padding: 0
|
|
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(--
|
|
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
|
|
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:
|
|
97
|
-
|
|
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:
|
|
103
|
-
font-size: var(--
|
|
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(--
|
|
410
|
+
color: var(--foreground);
|
|
108
411
|
}
|
|
109
412
|
.pretui-answered b {
|
|
110
413
|
color: var(--foreground);
|
|
111
|
-
font-weight:
|
|
414
|
+
font-weight: 600;
|
|
112
415
|
}
|
|
113
416
|
}
|
|
114
417
|
</style>
|