@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,523 @@
|
|
|
1
|
+
// Pretui — CardEmbed: the frame around a host-rendered card inside the transcript.
|
|
2
|
+
import Component from '@glimmer/component';
|
|
3
|
+
import { StateGlyph } from './state-glyph';
|
|
4
|
+
import { on } from '@ember/modifier';
|
|
5
|
+
import type { ComponentLike } from '@glint/template';
|
|
6
|
+
import { cssDeclaration, cssStyleFrom } from '../pretui-css';
|
|
7
|
+
|
|
8
|
+
export type CardEmbedState =
|
|
9
|
+
| 'pending'
|
|
10
|
+
| 'loading'
|
|
11
|
+
| 'ready'
|
|
12
|
+
| 'error'
|
|
13
|
+
| 'missing'
|
|
14
|
+
| 'auth-required'
|
|
15
|
+
| 'cancelled';
|
|
16
|
+
export type CardEmbedFormat =
|
|
17
|
+
| 'fitted'
|
|
18
|
+
| 'embedded'
|
|
19
|
+
| 'isolated'
|
|
20
|
+
| 'edit'
|
|
21
|
+
| 'atom';
|
|
22
|
+
|
|
23
|
+
export interface CardEmbedSignature {
|
|
24
|
+
Args: {
|
|
25
|
+
/** the format the host renders the card in; drives the sizing */
|
|
26
|
+
format?: CardEmbedFormat;
|
|
27
|
+
/** an explicit box, from the ref's args or the host's size parser:
|
|
28
|
+
* '320px', '100%' */
|
|
29
|
+
width?: string;
|
|
30
|
+
height?: string;
|
|
31
|
+
/** the least height the card gets. Default: fitted 4rem, embedded
|
|
32
|
+
* 7.5rem, isolated 12.5rem */
|
|
33
|
+
minHeight?: string;
|
|
34
|
+
/** past this, the card scrolls in its own box */
|
|
35
|
+
maxHeight?: string;
|
|
36
|
+
/** 'ready' (default), 'pending' (the call is still writing it: the
|
|
37
|
+
* box is held with a shimmering line), 'loading' (the card is
|
|
38
|
+
* fetching), 'error', 'missing' (deleted since) */
|
|
39
|
+
state?: CardEmbedState;
|
|
40
|
+
/** the card's title: the frame's name, and the pending line */
|
|
41
|
+
label?: string;
|
|
42
|
+
/** its type, said quietly: 'Tea lot' */
|
|
43
|
+
kind?: string;
|
|
44
|
+
/** open the card where the reader works; a corner Open with an arrow icon */
|
|
45
|
+
onOpen?: () => void;
|
|
46
|
+
/** the corner button's words. Default 'Open'; 'Open in Boxel' inside
|
|
47
|
+
* an MCP App, where `@onOpen` calls the host's openLink */
|
|
48
|
+
openLabel?: string;
|
|
49
|
+
/** the hat: one 1.625rem line over the card with its type, its title and
|
|
50
|
+
* its actions (Open, and `<:actions>`). Default: on for embedded,
|
|
51
|
+
* isolated and edit, which are big enough to carry one; off for fitted
|
|
52
|
+
* and atom, which keep a quiet corner Open */
|
|
53
|
+
hat?: boolean;
|
|
54
|
+
/** the type's icon, in the hat: a boxel-icons component */
|
|
55
|
+
icon?: ComponentLike<{ Element: SVGSVGElement }>;
|
|
56
|
+
/** why it could not show, or why it was cancelled */
|
|
57
|
+
error?: string;
|
|
58
|
+
onRetry?: () => void;
|
|
59
|
+
/** fill the width it is given, with no cap and no outer edge: the
|
|
60
|
+
* top-level frame of an MCP App iframe */
|
|
61
|
+
fill?: boolean;
|
|
62
|
+
/** the definite box a fitted card needs when nothing around it has a
|
|
63
|
+
* height: an aspect ratio ('16 / 9') or a height ('180px') */
|
|
64
|
+
envelope?: string;
|
|
65
|
+
/** 'auth-required': what access is missing ("Saving needs edit access
|
|
66
|
+
* to Home renovation"), with one action */
|
|
67
|
+
authPrompt?: string;
|
|
68
|
+
authorizeLabel?: string;
|
|
69
|
+
onAuthorize?: () => void;
|
|
70
|
+
};
|
|
71
|
+
Blocks: {
|
|
72
|
+
/** the host's CardRenderer */
|
|
73
|
+
default: [];
|
|
74
|
+
/** replaces the pending line */
|
|
75
|
+
pending: [];
|
|
76
|
+
/** more corner actions, beside Open */
|
|
77
|
+
actions: [];
|
|
78
|
+
};
|
|
79
|
+
Element: HTMLDivElement;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const MIN: Record<CardEmbedFormat, string> = {
|
|
83
|
+
fitted: '4rem',
|
|
84
|
+
embedded: '7.5rem',
|
|
85
|
+
isolated: '12.5rem',
|
|
86
|
+
edit: '12.5rem',
|
|
87
|
+
atom: '1.25rem',
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Pret UI cannot render a card (that is the host's CardRenderer), so this
|
|
92
|
+
* is the frame, the states and the sizing around one. It holds the card's
|
|
93
|
+
* box while the call is still writing it (Law 8: late values never shift
|
|
94
|
+
* layout), stops the transcript's prose styles at its edge so the card
|
|
95
|
+
* keeps its own type and theme, scrolls a tall card in its own box, and
|
|
96
|
+
* offers "Open ↗" in a corner, outside the card's own tab order.
|
|
97
|
+
*/
|
|
98
|
+
export class CardEmbed extends Component<CardEmbedSignature> {
|
|
99
|
+
get format(): CardEmbedFormat {
|
|
100
|
+
return this.args.format ?? 'fitted';
|
|
101
|
+
}
|
|
102
|
+
get state(): CardEmbedState {
|
|
103
|
+
return this.args.state ?? 'ready';
|
|
104
|
+
}
|
|
105
|
+
get isPending() {
|
|
106
|
+
return this.state === 'pending';
|
|
107
|
+
}
|
|
108
|
+
get isLoading() {
|
|
109
|
+
return this.state === 'loading';
|
|
110
|
+
}
|
|
111
|
+
get isError() {
|
|
112
|
+
return (
|
|
113
|
+
this.state === 'error' ||
|
|
114
|
+
this.state === 'missing' ||
|
|
115
|
+
this.state === 'cancelled'
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
get needsAuth() {
|
|
119
|
+
return this.state === 'auth-required';
|
|
120
|
+
}
|
|
121
|
+
get authText(): string {
|
|
122
|
+
return this.args.authPrompt ?? 'This needs more access';
|
|
123
|
+
}
|
|
124
|
+
/** a card that failed can be tried again; a deleted one cannot */
|
|
125
|
+
get canRetry() {
|
|
126
|
+
return this.state === 'error' && Boolean(this.args.onRetry);
|
|
127
|
+
}
|
|
128
|
+
get hasHat(): boolean {
|
|
129
|
+
if (this.args.hat !== undefined) {
|
|
130
|
+
return this.args.hat;
|
|
131
|
+
}
|
|
132
|
+
let f = this.format;
|
|
133
|
+
return (
|
|
134
|
+
(f === 'embedded' || f === 'isolated' || f === 'edit') &&
|
|
135
|
+
Boolean(this.args.label ?? this.args.kind)
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
get showsCard() {
|
|
139
|
+
return this.state === 'ready' || this.state === 'loading';
|
|
140
|
+
}
|
|
141
|
+
/** each size is validated as one CSS value; a rejected one is dropped
|
|
142
|
+
* and the frame keeps its default */
|
|
143
|
+
get boxStyle() {
|
|
144
|
+
let { envelope, minHeight, width, height, maxHeight } = this.args;
|
|
145
|
+
let ratio = envelope?.includes('/');
|
|
146
|
+
return cssStyleFrom([
|
|
147
|
+
cssDeclaration('--pretui-embed-min', minHeight) ??
|
|
148
|
+
`--pretui-embed-min: ${MIN[this.format]}`,
|
|
149
|
+
ratio ? cssDeclaration('aspect-ratio', envelope) : undefined,
|
|
150
|
+
envelope && !ratio
|
|
151
|
+
? cssDeclaration('--pretui-embed-h', envelope)
|
|
152
|
+
: undefined,
|
|
153
|
+
cssDeclaration('--pretui-embed-w', width),
|
|
154
|
+
cssDeclaration('--pretui-embed-h', height),
|
|
155
|
+
cssDeclaration('--pretui-embed-max-h', maxHeight),
|
|
156
|
+
]);
|
|
157
|
+
}
|
|
158
|
+
get pendingText(): string {
|
|
159
|
+
let what = this.args.label ?? this.args.kind ?? 'the card';
|
|
160
|
+
return `Making ${what}…`;
|
|
161
|
+
}
|
|
162
|
+
get errorText(): string {
|
|
163
|
+
let what = this.args.label ?? this.args.kind ?? 'the card';
|
|
164
|
+
if (this.state === 'cancelled') {
|
|
165
|
+
return this.args.error ? `Cancelled · ${this.args.error}` : 'Cancelled';
|
|
166
|
+
}
|
|
167
|
+
return this.state === 'missing'
|
|
168
|
+
? `${what} was deleted since`
|
|
169
|
+
: (this.args.error ?? `Couldn’t show ${what}`);
|
|
170
|
+
}
|
|
171
|
+
get openLabel(): string {
|
|
172
|
+
return this.args.openLabel
|
|
173
|
+
? `${this.args.openLabel}: ${this.args.label ?? 'the card'}`
|
|
174
|
+
: `Open ${this.args.label ?? 'the card'} on the stack`;
|
|
175
|
+
}
|
|
176
|
+
get openText(): string {
|
|
177
|
+
return this.args.openLabel ?? 'Open';
|
|
178
|
+
}
|
|
179
|
+
authorize = () => this.args.onAuthorize?.();
|
|
180
|
+
open = () => this.args.onOpen?.();
|
|
181
|
+
retry = () => this.args.onRetry?.();
|
|
182
|
+
<template>
|
|
183
|
+
<div
|
|
184
|
+
class='pretui-embed'
|
|
185
|
+
role='group'
|
|
186
|
+
aria-label={{if @label @label 'Card'}}
|
|
187
|
+
aria-busy={{if (if this.isPending true this.isLoading) 'true'}}
|
|
188
|
+
data-format={{this.format}}
|
|
189
|
+
data-state={{this.state}}
|
|
190
|
+
data-fill={{if @fill 'true'}}
|
|
191
|
+
data-hat={{if this.hasHat 'true'}}
|
|
192
|
+
data-scroll-region={{if @maxHeight 'true'}}
|
|
193
|
+
style={{this.boxStyle}}
|
|
194
|
+
data-test-pretui-card-embed={{this.state}}
|
|
195
|
+
...attributes
|
|
196
|
+
>
|
|
197
|
+
{{#if this.hasHat}}
|
|
198
|
+
<div class='pretui-embed-hat' data-test-pretui-card-embed-hat>
|
|
199
|
+
{{#if @icon}}<@icon
|
|
200
|
+
class='pretui-embed-hat-icon'
|
|
201
|
+
width='14'
|
|
202
|
+
height='14'
|
|
203
|
+
aria-hidden='true'
|
|
204
|
+
/>{{/if}}
|
|
205
|
+
{{#if @kind}}<span
|
|
206
|
+
class='pretui-embed-hat-kind'
|
|
207
|
+
>{{@kind}}</span>{{/if}}
|
|
208
|
+
{{#if @label}}<span
|
|
209
|
+
class='pretui-embed-hat-title'
|
|
210
|
+
title={{@label}}
|
|
211
|
+
>{{@label}}</span>{{/if}}
|
|
212
|
+
<span class='pretui-embed-hat-actions'>
|
|
213
|
+
{{yield to='actions'}}
|
|
214
|
+
{{#if (if @onOpen this.showsCard)}}
|
|
215
|
+
<button
|
|
216
|
+
type='button'
|
|
217
|
+
class='pretui-embed-hat-open'
|
|
218
|
+
aria-label={{this.openLabel}}
|
|
219
|
+
{{on 'click' this.open}}
|
|
220
|
+
data-test-pretui-card-embed-open
|
|
221
|
+
>{{this.openText}}
|
|
222
|
+
<StateGlyph @glyph='open' @size={{11}} /></button>
|
|
223
|
+
{{/if}}
|
|
224
|
+
</span>
|
|
225
|
+
</div>
|
|
226
|
+
{{/if}}
|
|
227
|
+
{{#if this.isPending}}
|
|
228
|
+
<div class='pretui-embed-pending' data-test-pretui-card-embed-pending>
|
|
229
|
+
{{#if (has-block 'pending')}}{{yield to='pending'}}{{else}}
|
|
230
|
+
<span class='pretui-embed-shimmer'>{{this.pendingText}}</span>
|
|
231
|
+
{{/if}}
|
|
232
|
+
</div>
|
|
233
|
+
{{else if this.needsAuth}}
|
|
234
|
+
<div
|
|
235
|
+
class='pretui-embed-error'
|
|
236
|
+
data-kind='auth'
|
|
237
|
+
role='status'
|
|
238
|
+
data-test-pretui-card-embed-auth
|
|
239
|
+
>
|
|
240
|
+
<span>{{this.authText}}</span>
|
|
241
|
+
{{#if @onAuthorize}}<button
|
|
242
|
+
type='button'
|
|
243
|
+
class='pretui-embed-act'
|
|
244
|
+
data-kind='primary'
|
|
245
|
+
data-test-pretui-card-embed-authorize
|
|
246
|
+
{{on 'click' this.authorize}}
|
|
247
|
+
>{{if
|
|
248
|
+
@authorizeLabel
|
|
249
|
+
@authorizeLabel
|
|
250
|
+
'Ask for access'
|
|
251
|
+
}}</button>{{/if}}
|
|
252
|
+
</div>
|
|
253
|
+
{{else if this.isError}}
|
|
254
|
+
<div
|
|
255
|
+
class='pretui-embed-error'
|
|
256
|
+
role='status'
|
|
257
|
+
data-test-pretui-card-embed-error
|
|
258
|
+
>
|
|
259
|
+
<span>{{this.errorText}}</span>
|
|
260
|
+
{{#if this.canRetry}}<button
|
|
261
|
+
type='button'
|
|
262
|
+
class='pretui-embed-act'
|
|
263
|
+
data-test-pretui-card-embed-retry
|
|
264
|
+
{{on 'click' this.retry}}
|
|
265
|
+
>Retry</button>{{/if}}
|
|
266
|
+
</div>
|
|
267
|
+
{{else}}
|
|
268
|
+
<div class='pretui-embed-card'>{{yield}}</div>
|
|
269
|
+
{{/if}}
|
|
270
|
+
{{#if
|
|
271
|
+
(if
|
|
272
|
+
this.hasHat
|
|
273
|
+
false
|
|
274
|
+
(if this.showsCard (if @onOpen true (has-block 'actions')))
|
|
275
|
+
)
|
|
276
|
+
}}
|
|
277
|
+
<div class='pretui-embed-corner'>
|
|
278
|
+
{{yield to='actions'}}
|
|
279
|
+
{{#if @onOpen}}
|
|
280
|
+
<button
|
|
281
|
+
type='button'
|
|
282
|
+
class='pretui-embed-open'
|
|
283
|
+
aria-label={{this.openLabel}}
|
|
284
|
+
{{on 'click' this.open}}
|
|
285
|
+
data-test-pretui-card-embed-open
|
|
286
|
+
>{{this.openText}}
|
|
287
|
+
<StateGlyph @glyph='open' @size={{11}} /></button>
|
|
288
|
+
{{/if}}
|
|
289
|
+
</div>
|
|
290
|
+
{{/if}}
|
|
291
|
+
</div>
|
|
292
|
+
<style scoped>
|
|
293
|
+
@layer PretComponent {
|
|
294
|
+
/* a size container at the text column's width: the card's own
|
|
295
|
+
container queries see the embed, not the window */
|
|
296
|
+
.pretui-embed {
|
|
297
|
+
container-type: inline-size;
|
|
298
|
+
position: relative;
|
|
299
|
+
box-sizing: border-box;
|
|
300
|
+
width: var(--pretui-embed-w, 100%);
|
|
301
|
+
max-width: var(--pretui-embed-max, 37.5rem);
|
|
302
|
+
min-height: var(--pretui-embed-min);
|
|
303
|
+
height: var(--pretui-embed-h, auto);
|
|
304
|
+
max-height: var(--pretui-embed-max-h, none);
|
|
305
|
+
overflow: auto;
|
|
306
|
+
border-radius: var(--boxel-border-radius);
|
|
307
|
+
box-shadow: 0 0 0 1px var(--border);
|
|
308
|
+
isolation: isolate;
|
|
309
|
+
contain: layout paint;
|
|
310
|
+
/* the transcript's prose stops at the frame: the card brings
|
|
311
|
+
its own measure, leading and link colour */
|
|
312
|
+
font-family: var(--font-sans);
|
|
313
|
+
font-size: var(--boxel-font-size);
|
|
314
|
+
font-weight: 400;
|
|
315
|
+
font-style: normal;
|
|
316
|
+
line-height: normal;
|
|
317
|
+
letter-spacing: normal;
|
|
318
|
+
text-align: start;
|
|
319
|
+
white-space: normal;
|
|
320
|
+
color: var(--foreground);
|
|
321
|
+
}
|
|
322
|
+
/* the hat: one quiet line in the frame's own chrome over the card's
|
|
323
|
+
surface, lower than the host's card header: the type as a mono
|
|
324
|
+
eyebrow, the title at the small size, and the actions as text */
|
|
325
|
+
.pretui-embed[data-hat] {
|
|
326
|
+
display: grid;
|
|
327
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
328
|
+
}
|
|
329
|
+
.pretui-embed-hat {
|
|
330
|
+
position: sticky;
|
|
331
|
+
inset-block-start: 0;
|
|
332
|
+
z-index: 1;
|
|
333
|
+
display: flex;
|
|
334
|
+
align-items: center;
|
|
335
|
+
gap: var(--boxel-sp-2xs);
|
|
336
|
+
min-width: 0;
|
|
337
|
+
height: 1.625rem;
|
|
338
|
+
padding: 0 var(--boxel-sp-2xs) 0 var(--boxel-sp-xs);
|
|
339
|
+
background-color: var(--card);
|
|
340
|
+
box-shadow: 0 1px 0 var(--border);
|
|
341
|
+
color: var(--card-foreground);
|
|
342
|
+
}
|
|
343
|
+
.pretui-embed-hat-icon {
|
|
344
|
+
flex: none;
|
|
345
|
+
color: var(--muted-foreground);
|
|
346
|
+
}
|
|
347
|
+
.pretui-embed-hat-kind {
|
|
348
|
+
flex: none;
|
|
349
|
+
font-family: var(--font-mono);
|
|
350
|
+
font-size: var(--boxel-font-size-2xs);
|
|
351
|
+
font-weight: 500;
|
|
352
|
+
letter-spacing: 0.06em;
|
|
353
|
+
text-transform: uppercase;
|
|
354
|
+
color: var(--subtle-foreground);
|
|
355
|
+
}
|
|
356
|
+
.pretui-embed-hat-title {
|
|
357
|
+
min-width: 0;
|
|
358
|
+
overflow: hidden;
|
|
359
|
+
text-overflow: ellipsis;
|
|
360
|
+
white-space: nowrap;
|
|
361
|
+
font-size: var(--boxel-font-size-xs);
|
|
362
|
+
font-weight: 500;
|
|
363
|
+
}
|
|
364
|
+
.pretui-embed-hat-actions {
|
|
365
|
+
display: flex;
|
|
366
|
+
align-items: center;
|
|
367
|
+
gap: var(--boxel-sp-6xs);
|
|
368
|
+
margin-inline-start: auto;
|
|
369
|
+
}
|
|
370
|
+
.pretui-embed-hat-open {
|
|
371
|
+
display: inline-flex;
|
|
372
|
+
align-items: center;
|
|
373
|
+
gap: var(--boxel-sp-5xs);
|
|
374
|
+
height: 1.5rem;
|
|
375
|
+
padding: 0 var(--boxel-sp-2xs);
|
|
376
|
+
border: 0;
|
|
377
|
+
border-radius: var(--boxel-border-radius-xs);
|
|
378
|
+
background-color: transparent;
|
|
379
|
+
font-family: inherit;
|
|
380
|
+
font-size: var(--boxel-font-size-2xs);
|
|
381
|
+
font-weight: 500;
|
|
382
|
+
color: var(--muted-foreground);
|
|
383
|
+
cursor: pointer;
|
|
384
|
+
}
|
|
385
|
+
.pretui-embed-hat-open:hover {
|
|
386
|
+
color: var(--primary-ink);
|
|
387
|
+
background-color: var(--hover);
|
|
388
|
+
}
|
|
389
|
+
.pretui-embed-hat-open:focus-visible {
|
|
390
|
+
outline: 2px solid var(--ring);
|
|
391
|
+
outline-offset: 1px;
|
|
392
|
+
}
|
|
393
|
+
/* the iframe's top level: the whole width, no cap, no edge */
|
|
394
|
+
.pretui-embed[data-fill] {
|
|
395
|
+
max-width: none;
|
|
396
|
+
border-radius: 0;
|
|
397
|
+
box-shadow: none;
|
|
398
|
+
}
|
|
399
|
+
.pretui-embed-card {
|
|
400
|
+
display: grid;
|
|
401
|
+
min-height: inherit;
|
|
402
|
+
}
|
|
403
|
+
.pretui-embed-card > :deep(*) {
|
|
404
|
+
min-width: 0;
|
|
405
|
+
}
|
|
406
|
+
.pretui-embed-pending,
|
|
407
|
+
.pretui-embed-error {
|
|
408
|
+
display: flex;
|
|
409
|
+
align-items: center;
|
|
410
|
+
gap: var(--boxel-sp-xs);
|
|
411
|
+
box-sizing: border-box;
|
|
412
|
+
height: 100%;
|
|
413
|
+
min-height: var(--pretui-embed-min);
|
|
414
|
+
padding: var(--boxel-sp-sm);
|
|
415
|
+
background-color: var(--inset);
|
|
416
|
+
font-size: var(--boxel-font-size-xs);
|
|
417
|
+
color: var(--muted-foreground);
|
|
418
|
+
}
|
|
419
|
+
/* the shimmer is a moving gradient in CSS: no clock */
|
|
420
|
+
.pretui-embed-shimmer {
|
|
421
|
+
background-image: linear-gradient(
|
|
422
|
+
90deg,
|
|
423
|
+
var(--muted-foreground) 0%,
|
|
424
|
+
var(--foreground) 50%,
|
|
425
|
+
var(--muted-foreground) 100%
|
|
426
|
+
);
|
|
427
|
+
background-size: 200% 100%;
|
|
428
|
+
-webkit-background-clip: text;
|
|
429
|
+
background-clip: text;
|
|
430
|
+
color: transparent;
|
|
431
|
+
animation: pretui-embed-shimmer 1.6s linear infinite;
|
|
432
|
+
}
|
|
433
|
+
@keyframes pretui-embed-shimmer {
|
|
434
|
+
from {
|
|
435
|
+
background-position: 100% 0;
|
|
436
|
+
}
|
|
437
|
+
to {
|
|
438
|
+
background-position: -100% 0;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
.pretui-embed-error[data-kind='auth'] {
|
|
442
|
+
color: var(--foreground);
|
|
443
|
+
}
|
|
444
|
+
.pretui-embed-act[data-kind='primary'] {
|
|
445
|
+
padding: 0 var(--boxel-sp-xs);
|
|
446
|
+
border-radius: var(--boxel-border-radius-pill);
|
|
447
|
+
background-color: var(--primary);
|
|
448
|
+
color: var(--primary-foreground);
|
|
449
|
+
}
|
|
450
|
+
.pretui-embed[data-state='error'] .pretui-embed-error {
|
|
451
|
+
color: var(--destructive-ink);
|
|
452
|
+
}
|
|
453
|
+
/* 1.5rem tall, the least a pointer target takes */
|
|
454
|
+
.pretui-embed-act {
|
|
455
|
+
min-height: 1.5rem;
|
|
456
|
+
padding: 0 var(--boxel-sp-4xs);
|
|
457
|
+
border: 0;
|
|
458
|
+
border-radius: var(--boxel-border-radius-xs);
|
|
459
|
+
background-color: transparent;
|
|
460
|
+
font-family: inherit;
|
|
461
|
+
font-size: inherit;
|
|
462
|
+
font-weight: 600;
|
|
463
|
+
color: var(--foreground);
|
|
464
|
+
cursor: pointer;
|
|
465
|
+
}
|
|
466
|
+
.pretui-embed-act:hover {
|
|
467
|
+
color: var(--primary-ink);
|
|
468
|
+
}
|
|
469
|
+
/* Open sits in the corner, quiet until the frame is hovered or
|
|
470
|
+
focused (always on touch), never over the card's own controls'
|
|
471
|
+
focus order: it comes after the card */
|
|
472
|
+
.pretui-embed-corner {
|
|
473
|
+
position: absolute;
|
|
474
|
+
inset-block-start: var(--boxel-sp-2xs);
|
|
475
|
+
inset-inline-end: var(--boxel-sp-2xs);
|
|
476
|
+
display: flex;
|
|
477
|
+
gap: var(--boxel-sp-4xs);
|
|
478
|
+
opacity: 0;
|
|
479
|
+
transition: opacity 120ms ease-out;
|
|
480
|
+
}
|
|
481
|
+
.pretui-embed:hover .pretui-embed-corner,
|
|
482
|
+
.pretui-embed:focus-within .pretui-embed-corner {
|
|
483
|
+
opacity: 1;
|
|
484
|
+
}
|
|
485
|
+
@media (hover: none) {
|
|
486
|
+
.pretui-embed-corner {
|
|
487
|
+
opacity: 1;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
.pretui-embed-open {
|
|
491
|
+
height: 1.5rem;
|
|
492
|
+
padding: 0 var(--boxel-sp-xs);
|
|
493
|
+
border: 0;
|
|
494
|
+
border-radius: var(--boxel-border-radius-pill);
|
|
495
|
+
background-color: var(--popover);
|
|
496
|
+
box-shadow: 0 0 0 1px var(--border-strong);
|
|
497
|
+
font-family: inherit;
|
|
498
|
+
font-size: var(--boxel-font-size-2xs);
|
|
499
|
+
font-weight: 500;
|
|
500
|
+
color: var(--popover-foreground);
|
|
501
|
+
cursor: pointer;
|
|
502
|
+
}
|
|
503
|
+
.pretui-embed-open:hover {
|
|
504
|
+
color: var(--primary-ink);
|
|
505
|
+
}
|
|
506
|
+
.pretui-embed-open:focus-visible,
|
|
507
|
+
.pretui-embed-act:focus-visible {
|
|
508
|
+
outline: 2px solid var(--ring);
|
|
509
|
+
outline-offset: 1px;
|
|
510
|
+
}
|
|
511
|
+
@media (prefers-reduced-motion: reduce) {
|
|
512
|
+
.pretui-embed-shimmer {
|
|
513
|
+
animation: none;
|
|
514
|
+
color: var(--muted-foreground);
|
|
515
|
+
}
|
|
516
|
+
.pretui-embed-corner {
|
|
517
|
+
transition: none;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
</style>
|
|
522
|
+
</template>
|
|
523
|
+
}
|