@design.estate/dees-catalog 4.1.0 → 4.1.1
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/dist_bundle/bundle.js +1356 -1297
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.d.ts +5 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.js +43 -129
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-fullscreen.d.ts +26 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-fullscreen.js +211 -0
- package/package.json +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.ts +33 -121
- package/ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-fullscreen.ts +168 -0
|
@@ -22,6 +22,7 @@ import { harnessCardStyles, harnessPillStyles, harnessMonoStyles } from '../harn
|
|
|
22
22
|
import { harnessFormatDuration, harnessTruncate } from '../harness.helpers.js';
|
|
23
23
|
import '../dees-harness-content-blocks/dees-harness-content-blocks.js';
|
|
24
24
|
import '../../00group-dataview/dees-dataview-codebox/dees-dataview-codebox.js';
|
|
25
|
+
import './dees-harness-tool-fullscreen.js';
|
|
25
26
|
import '../../00group-feedback/dees-badge/dees-badge.js';
|
|
26
27
|
import '../../00group-utility/dees-icon/dees-icon.js';
|
|
27
28
|
|
|
@@ -54,21 +55,23 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
54
55
|
@state()
|
|
55
56
|
accessor outputExpanded: boolean = false;
|
|
56
57
|
|
|
57
|
-
/** Body height cap; content
|
|
58
|
+
/** Body height cap; taller content scrolls in place and offers fullscreen. */
|
|
58
59
|
@property({ type: Number })
|
|
59
60
|
accessor bodyCapPx: number = 360;
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
/** Set on the card inside the fullscreen modal: no cap, no maximize bar. */
|
|
63
|
+
@property({ type: Boolean })
|
|
64
|
+
accessor uncapped: boolean = false;
|
|
63
65
|
|
|
64
66
|
@state()
|
|
65
|
-
accessor
|
|
67
|
+
accessor bodyOverflowing: boolean = false;
|
|
66
68
|
|
|
67
69
|
@state()
|
|
68
70
|
accessor returnFlash: boolean = false;
|
|
69
71
|
|
|
70
72
|
private bodyResizeObserver: ResizeObserver | null = null;
|
|
71
73
|
private observedBodyInner: Element | null = null;
|
|
74
|
+
private fullscreenPortal: HTMLElementTagNameMap['dees-harness-tool-fullscreen'] | null = null;
|
|
72
75
|
|
|
73
76
|
public static styles = [
|
|
74
77
|
themeDefaultStyles,
|
|
@@ -198,22 +201,14 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
/* Three body modes: collapsed (no body), normal (content fits the
|
|
201
|
-
cap), capped (content taller than the cap
|
|
202
|
-
offers fullscreen). */
|
|
204
|
+
cap), capped (content taller than the cap scrolls inside the frame
|
|
205
|
+
and offers the fullscreen modal). */
|
|
203
206
|
.bodyClipFrame {
|
|
204
207
|
position: relative;
|
|
205
|
-
overflow:
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
content: '';
|
|
210
|
-
position: absolute;
|
|
211
|
-
left: 0;
|
|
212
|
-
right: 0;
|
|
213
|
-
bottom: 0;
|
|
214
|
-
height: 44px;
|
|
215
|
-
background: linear-gradient(to bottom, transparent, var(--dees-color-bg-primary));
|
|
216
|
-
pointer-events: none;
|
|
208
|
+
overflow-y: auto;
|
|
209
|
+
overflow-x: hidden;
|
|
210
|
+
scrollbar-width: thin;
|
|
211
|
+
scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
|
|
217
212
|
}
|
|
218
213
|
|
|
219
214
|
.maximizeBar {
|
|
@@ -237,74 +232,6 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
237
232
|
color: var(--dees-color-link-hover);
|
|
238
233
|
}
|
|
239
234
|
|
|
240
|
-
.fullscreenLayer {
|
|
241
|
-
position: fixed;
|
|
242
|
-
inset: 0;
|
|
243
|
-
z-index: 4000;
|
|
244
|
-
display: grid;
|
|
245
|
-
place-items: center;
|
|
246
|
-
padding: 4vh 3vw;
|
|
247
|
-
background: color-mix(in srgb, var(--dees-color-bg-primary) 55%, transparent);
|
|
248
|
-
backdrop-filter: blur(6px);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
.fullscreenPanel {
|
|
252
|
-
display: flex;
|
|
253
|
-
flex-direction: column;
|
|
254
|
-
width: min(1200px, 100%);
|
|
255
|
-
height: 100%;
|
|
256
|
-
min-height: 0;
|
|
257
|
-
border: 1px solid var(--dees-color-border-default);
|
|
258
|
-
border-radius: var(--dees-radius-lg);
|
|
259
|
-
background: var(--dees-color-bg-primary);
|
|
260
|
-
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.4);
|
|
261
|
-
overflow: hidden;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
.fullscreenHeader {
|
|
265
|
-
display: flex;
|
|
266
|
-
flex: 0 0 auto;
|
|
267
|
-
align-items: center;
|
|
268
|
-
gap: var(--dees-spacing-sm);
|
|
269
|
-
padding: var(--dees-spacing-sm) var(--dees-spacing-md);
|
|
270
|
-
border-bottom: 1px solid var(--dees-color-border-subtle);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
.fullscreenTitle {
|
|
274
|
-
min-width: 0;
|
|
275
|
-
overflow: hidden;
|
|
276
|
-
text-overflow: ellipsis;
|
|
277
|
-
white-space: nowrap;
|
|
278
|
-
font-size: var(--dees-font-control-size-sm, 12px);
|
|
279
|
-
font-weight: 650;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
.fullscreenClose {
|
|
283
|
-
display: grid;
|
|
284
|
-
place-items: center;
|
|
285
|
-
margin-left: auto;
|
|
286
|
-
padding: 6px;
|
|
287
|
-
border: 0;
|
|
288
|
-
border-radius: var(--dees-radius-md);
|
|
289
|
-
background: transparent;
|
|
290
|
-
color: var(--dees-color-text-secondary);
|
|
291
|
-
cursor: pointer;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
.fullscreenClose:hover {
|
|
295
|
-
background: var(--dees-color-hover);
|
|
296
|
-
color: var(--dees-color-text-primary);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
.fullscreenBody {
|
|
300
|
-
flex: 1;
|
|
301
|
-
min-height: 0;
|
|
302
|
-
overflow: auto;
|
|
303
|
-
padding: var(--dees-spacing-md);
|
|
304
|
-
scrollbar-width: thin;
|
|
305
|
-
scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
235
|
/* Locates the card after minimizing: a brief highlight pulse. */
|
|
309
236
|
.harness-card.returnFlash {
|
|
310
237
|
animation: harness-card-return-flash 1.4s var(--dees-ease-standard);
|
|
@@ -385,15 +312,15 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
385
312
|
</span>
|
|
386
313
|
</span>
|
|
387
314
|
</button>
|
|
388
|
-
${this.isOpen
|
|
315
|
+
${this.isOpen
|
|
389
316
|
? html`
|
|
390
317
|
<div
|
|
391
|
-
class="bodyClipFrame
|
|
392
|
-
style=${`max-height: ${this.bodyCapPx}px;`}
|
|
318
|
+
class="bodyClipFrame"
|
|
319
|
+
style=${this.uncapped ? '' : `max-height: ${this.bodyCapPx}px;`}
|
|
393
320
|
>
|
|
394
321
|
<div class="body bodyInner">${this.renderBody(call)}</div>
|
|
395
322
|
</div>
|
|
396
|
-
${this.bodyOverflowing
|
|
323
|
+
${this.bodyOverflowing && !this.uncapped
|
|
397
324
|
? html`
|
|
398
325
|
<button class="maximizeBar" type="button" @click=${this.openFullscreen}>
|
|
399
326
|
<dees-icon icon="lucide:Maximize2" iconSize="12"></dees-icon>
|
|
@@ -404,36 +331,26 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
404
331
|
`
|
|
405
332
|
: ''}
|
|
406
333
|
</div>
|
|
407
|
-
${this.maximized
|
|
408
|
-
? html`
|
|
409
|
-
<div class="fullscreenLayer" @click=${(event: Event) => {
|
|
410
|
-
if (event.target === event.currentTarget) this.closeFullscreen();
|
|
411
|
-
}}>
|
|
412
|
-
<div class="fullscreenPanel">
|
|
413
|
-
<header class="fullscreenHeader">
|
|
414
|
-
<dees-icon .icon=${descriptor.icon} iconSize="15"></dees-icon>
|
|
415
|
-
<span class="fullscreenTitle">${label}${subtitle ? ` · ${subtitle}` : ''}</span>
|
|
416
|
-
<button class="fullscreenClose" type="button" @click=${this.closeFullscreen}>
|
|
417
|
-
<dees-icon icon="lucide:Minimize2" iconSize="15"></dees-icon>
|
|
418
|
-
</button>
|
|
419
|
-
</header>
|
|
420
|
-
<div class="fullscreenBody">${this.renderBody(call)}</div>
|
|
421
|
-
</div>
|
|
422
|
-
</div>
|
|
423
|
-
`
|
|
424
|
-
: ''}
|
|
425
334
|
`;
|
|
426
335
|
}
|
|
427
336
|
|
|
428
337
|
private readonly openFullscreen = (): void => {
|
|
429
|
-
this.
|
|
430
|
-
|
|
338
|
+
if (this.fullscreenPortal) return;
|
|
339
|
+
// Appended to document.body: content-visibility containment in the
|
|
340
|
+
// transcript would trap a position: fixed layer inside this card.
|
|
341
|
+
const portal = document.createElement('dees-harness-tool-fullscreen');
|
|
342
|
+
portal.call = this.enrichedCall;
|
|
343
|
+
portal.toolRegistry = this.toolRegistry;
|
|
344
|
+
portal.addEventListener('tool-fullscreen-close', this.closeFullscreen, { once: true });
|
|
345
|
+
document.body.append(portal);
|
|
346
|
+
this.fullscreenPortal = portal;
|
|
431
347
|
};
|
|
432
348
|
|
|
433
349
|
private readonly closeFullscreen = (): void => {
|
|
434
|
-
|
|
435
|
-
if (!
|
|
436
|
-
this.
|
|
350
|
+
const portal = this.fullscreenPortal;
|
|
351
|
+
if (!portal) return;
|
|
352
|
+
this.fullscreenPortal = null;
|
|
353
|
+
portal.remove();
|
|
437
354
|
// The flash locates the card the user was just reading in fullscreen.
|
|
438
355
|
this.returnFlash = true;
|
|
439
356
|
requestAnimationFrame(() => {
|
|
@@ -441,15 +358,9 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
441
358
|
});
|
|
442
359
|
};
|
|
443
360
|
|
|
444
|
-
private readonly handleFullscreenKeydown = (event: KeyboardEvent): void => {
|
|
445
|
-
if (event.key === 'Escape') {
|
|
446
|
-
event.preventDefault();
|
|
447
|
-
this.closeFullscreen();
|
|
448
|
-
}
|
|
449
|
-
};
|
|
450
|
-
|
|
451
361
|
public updated(changedProperties: Map<PropertyKey, unknown>): void {
|
|
452
362
|
super.updated(changedProperties);
|
|
363
|
+
if (this.uncapped) return;
|
|
453
364
|
const bodyInner = this.shadowRoot?.querySelector('.bodyInner') ?? null;
|
|
454
365
|
if (bodyInner === this.observedBodyInner) return;
|
|
455
366
|
this.bodyResizeObserver?.disconnect();
|
|
@@ -468,7 +379,8 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
468
379
|
}
|
|
469
380
|
|
|
470
381
|
public async disconnectedCallback(): Promise<void> {
|
|
471
|
-
|
|
382
|
+
this.fullscreenPortal?.remove();
|
|
383
|
+
this.fullscreenPortal = null;
|
|
472
384
|
this.bodyResizeObserver?.disconnect();
|
|
473
385
|
this.bodyResizeObserver = null;
|
|
474
386
|
this.observedBodyInner = null;
|
package/ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-fullscreen.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DeesElement,
|
|
3
|
+
html,
|
|
4
|
+
css,
|
|
5
|
+
customElement,
|
|
6
|
+
type TemplateResult,
|
|
7
|
+
property,
|
|
8
|
+
cssManager,
|
|
9
|
+
} from '@design.estate/dees-element';
|
|
10
|
+
import { themeDefaultStyles } from '../../00theme.js';
|
|
11
|
+
import type { IHarnessToolCall } from '../interfaces.js';
|
|
12
|
+
import { DeesHarnessToolRegistry, parseMcpName } from '../toolregistry.js';
|
|
13
|
+
import '../../00group-utility/dees-icon/dees-icon.js';
|
|
14
|
+
|
|
15
|
+
declare global {
|
|
16
|
+
interface HTMLElementTagNameMap {
|
|
17
|
+
'dees-harness-tool-fullscreen': DeesHarnessToolFullscreen;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Fullscreen view of one tool card, appended to document.body by
|
|
23
|
+
* DeesHarnessToolCard so it escapes every containment context
|
|
24
|
+
* (content-visibility, transforms) that would trap a position: fixed layer
|
|
25
|
+
* inside the transcript. Emits `tool-fullscreen-close` on Escape, backdrop
|
|
26
|
+
* press, or the minimize button; the owning card removes it and flashes.
|
|
27
|
+
*/
|
|
28
|
+
@customElement('dees-harness-tool-fullscreen')
|
|
29
|
+
export class DeesHarnessToolFullscreen extends DeesElement {
|
|
30
|
+
@property({ attribute: false })
|
|
31
|
+
accessor call: IHarnessToolCall = { id: '', name: '', status: 'pending' };
|
|
32
|
+
|
|
33
|
+
@property({ attribute: false })
|
|
34
|
+
accessor toolRegistry: DeesHarnessToolRegistry = DeesHarnessToolRegistry.default;
|
|
35
|
+
|
|
36
|
+
public static styles = [
|
|
37
|
+
themeDefaultStyles,
|
|
38
|
+
cssManager.defaultStyles,
|
|
39
|
+
css`
|
|
40
|
+
:host {
|
|
41
|
+
position: fixed;
|
|
42
|
+
inset: 0;
|
|
43
|
+
z-index: 4000;
|
|
44
|
+
display: grid;
|
|
45
|
+
place-items: center;
|
|
46
|
+
padding: 4vh 3vw;
|
|
47
|
+
background: color-mix(in srgb, var(--dees-color-bg-primary) 55%, transparent);
|
|
48
|
+
backdrop-filter: blur(6px);
|
|
49
|
+
font-family: var(--dees-font-family);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.panel {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
width: min(1200px, 100%);
|
|
56
|
+
height: 100%;
|
|
57
|
+
min-height: 0;
|
|
58
|
+
border: 1px solid var(--dees-color-border-default);
|
|
59
|
+
border-radius: var(--dees-radius-lg);
|
|
60
|
+
background: var(--dees-color-bg-primary);
|
|
61
|
+
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.4);
|
|
62
|
+
overflow: hidden;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.panelHeader {
|
|
66
|
+
display: flex;
|
|
67
|
+
flex: 0 0 auto;
|
|
68
|
+
align-items: center;
|
|
69
|
+
gap: var(--dees-spacing-sm);
|
|
70
|
+
padding: var(--dees-spacing-sm) var(--dees-spacing-md);
|
|
71
|
+
border-bottom: 1px solid var(--dees-color-border-subtle);
|
|
72
|
+
color: var(--dees-color-text-primary);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.panelTitle {
|
|
76
|
+
min-width: 0;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
text-overflow: ellipsis;
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
font-size: var(--dees-font-control-size-sm, 12px);
|
|
81
|
+
font-weight: 650;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.panelClose {
|
|
85
|
+
display: grid;
|
|
86
|
+
place-items: center;
|
|
87
|
+
margin-left: auto;
|
|
88
|
+
padding: 6px;
|
|
89
|
+
border: 0;
|
|
90
|
+
border-radius: var(--dees-radius-md);
|
|
91
|
+
background: transparent;
|
|
92
|
+
color: var(--dees-color-text-secondary);
|
|
93
|
+
cursor: pointer;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.panelClose:hover {
|
|
97
|
+
background: var(--dees-color-hover);
|
|
98
|
+
color: var(--dees-color-text-primary);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.panelBody {
|
|
102
|
+
flex: 1;
|
|
103
|
+
min-height: 0;
|
|
104
|
+
overflow: auto;
|
|
105
|
+
padding: var(--dees-spacing-md);
|
|
106
|
+
scrollbar-width: thin;
|
|
107
|
+
scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.panelBody dees-harness-tool-card {
|
|
111
|
+
display: block;
|
|
112
|
+
}
|
|
113
|
+
`,
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
public render(): TemplateResult {
|
|
117
|
+
const parsed = this.call.mcp ? undefined : parseMcpName(this.call.name);
|
|
118
|
+
const enriched = parsed
|
|
119
|
+
? { ...this.call, mcp: { serverName: parsed.serverName, toolName: parsed.toolName } }
|
|
120
|
+
: this.call;
|
|
121
|
+
const descriptor = this.toolRegistry.resolve(enriched);
|
|
122
|
+
const label = typeof descriptor.label === 'function' ? descriptor.label(enriched) : descriptor.label;
|
|
123
|
+
const subtitle = descriptor.subtitle?.(enriched) ?? '';
|
|
124
|
+
return html`
|
|
125
|
+
<div class="panel" @click=${(event: Event) => event.stopPropagation()}>
|
|
126
|
+
<header class="panelHeader">
|
|
127
|
+
<dees-icon .icon=${descriptor.icon} iconSize="15"></dees-icon>
|
|
128
|
+
<span class="panelTitle">${label}${subtitle ? ` · ${subtitle}` : ''}</span>
|
|
129
|
+
<button class="panelClose" type="button" @click=${this.emitClose}>
|
|
130
|
+
<dees-icon icon="lucide:Minimize2" iconSize="15"></dees-icon>
|
|
131
|
+
</button>
|
|
132
|
+
</header>
|
|
133
|
+
<div class="panelBody">
|
|
134
|
+
<dees-harness-tool-card
|
|
135
|
+
.call=${this.call}
|
|
136
|
+
.toolRegistry=${this.toolRegistry}
|
|
137
|
+
.expanded=${true}
|
|
138
|
+
.outputExpanded=${true}
|
|
139
|
+
uncapped
|
|
140
|
+
></dees-harness-tool-card>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public firstUpdated(): void {
|
|
147
|
+
window.addEventListener('keydown', this.handleKeydown);
|
|
148
|
+
this.addEventListener('click', (event) => {
|
|
149
|
+
if (event.target === this) this.emitClose();
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private readonly handleKeydown = (event: KeyboardEvent): void => {
|
|
154
|
+
if (event.key === 'Escape') {
|
|
155
|
+
event.preventDefault();
|
|
156
|
+
this.emitClose();
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
private readonly emitClose = (): void => {
|
|
161
|
+
this.dispatchEvent(new CustomEvent('tool-fullscreen-close', { bubbles: false }));
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
public async disconnectedCallback(): Promise<void> {
|
|
165
|
+
window.removeEventListener('keydown', this.handleKeydown);
|
|
166
|
+
await super.disconnectedCallback();
|
|
167
|
+
}
|
|
168
|
+
}
|