@aceshooting/lyra-ui 1.2.0 → 2.0.0
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/README.md +11 -0
- package/custom-elements.json +23341 -11202
- package/dist/components/app-rail/app-rail.d.ts +171 -0
- package/dist/components/app-rail/app-rail.js +483 -0
- package/dist/components/app-rail/app-rail.styles.d.ts +1 -0
- package/dist/components/app-rail/app-rail.styles.js +125 -0
- package/dist/components/attachment-chip/attachment-chip.d.ts +114 -0
- package/dist/components/attachment-chip/attachment-chip.js +312 -0
- package/dist/components/attachment-chip/attachment-chip.styles.d.ts +1 -0
- package/dist/components/attachment-chip/attachment-chip.styles.js +184 -0
- package/dist/components/attachment-trigger/attachment-trigger.d.ts +83 -0
- package/dist/components/attachment-trigger/attachment-trigger.js +258 -0
- package/dist/components/attachment-trigger/attachment-trigger.styles.d.ts +1 -0
- package/dist/components/attachment-trigger/attachment-trigger.styles.js +68 -0
- package/dist/components/chart/box-plot.js +11 -1
- package/dist/components/chart/chart-loader.d.ts +44 -13
- package/dist/components/chart/chart-loader.js +65 -18
- package/dist/components/chart/chart.d.ts +1 -2
- package/dist/components/chart/chart.js +67 -12
- package/dist/components/chart/histogram-bin.d.ts +4 -1
- package/dist/components/chart/histogram-bin.js +24 -14
- package/dist/components/chart/lite-chart.d.ts +54 -0
- package/dist/components/chart/lite-chart.js +140 -22
- package/dist/components/chart/lite-chart.styles.js +9 -0
- package/dist/components/chat-composer/chat-composer.d.ts +92 -0
- package/dist/components/chat-composer/chat-composer.js +285 -0
- package/dist/components/chat-composer/chat-composer.styles.d.ts +1 -0
- package/dist/components/chat-composer/chat-composer.styles.js +135 -0
- package/dist/components/chat-message/chat-message.d.ts +113 -0
- package/dist/components/chat-message/chat-message.js +291 -0
- package/dist/components/chat-message/chat-message.styles.d.ts +1 -0
- package/dist/components/chat-message/chat-message.styles.js +203 -0
- package/dist/components/checkbox/checkbox.d.ts +59 -0
- package/dist/components/checkbox/checkbox.js +230 -0
- package/dist/components/checkbox/checkbox.styles.d.ts +1 -0
- package/dist/components/checkbox/checkbox.styles.js +70 -0
- package/dist/components/chip/chip-group.d.ts +56 -0
- package/dist/components/chip/chip-group.js +124 -0
- package/dist/components/chip/chip-group.styles.d.ts +1 -0
- package/dist/components/chip/chip-group.styles.js +57 -0
- package/dist/components/chip/chip.d.ts +64 -0
- package/dist/components/chip/chip.js +115 -0
- package/dist/components/chip/chip.styles.d.ts +1 -0
- package/dist/components/chip/chip.styles.js +115 -0
- package/dist/components/citation-badge/citation-badge.d.ts +113 -0
- package/dist/components/citation-badge/citation-badge.js +300 -0
- package/dist/components/citation-badge/citation-badge.styles.d.ts +1 -0
- package/dist/components/citation-badge/citation-badge.styles.js +96 -0
- package/dist/components/code-block/code-block.d.ts +89 -0
- package/dist/components/code-block/code-block.js +317 -0
- package/dist/components/code-block/code-block.styles.d.ts +1 -0
- package/dist/components/code-block/code-block.styles.js +187 -0
- package/dist/components/code-block/code-loader.d.ts +44 -0
- package/dist/components/code-block/code-loader.js +79 -0
- package/dist/components/combobox/combobox.d.ts +19 -1
- package/dist/components/combobox/combobox.js +84 -14
- package/dist/components/combobox/option.d.ts +5 -1
- package/dist/components/combobox/option.js +35 -0
- package/dist/components/context-meter/context-meter.d.ts +53 -0
- package/dist/components/context-meter/context-meter.js +150 -0
- package/dist/components/context-meter/context-meter.styles.d.ts +1 -0
- package/dist/components/context-meter/context-meter.styles.js +120 -0
- package/dist/components/conversation-item/conversation-item.d.ts +128 -0
- package/dist/components/conversation-item/conversation-item.js +322 -0
- package/dist/components/conversation-item/conversation-item.styles.d.ts +1 -0
- package/dist/components/conversation-item/conversation-item.styles.js +155 -0
- package/dist/components/date-picker/date-input.d.ts +24 -0
- package/dist/components/date-picker/date-input.js +134 -22
- package/dist/components/date-picker/date-picker.d.ts +7 -0
- package/dist/components/date-picker/date-picker.js +85 -16
- package/dist/components/dialog/confirm.d.ts +40 -0
- package/dist/components/dialog/confirm.js +79 -0
- package/dist/components/dialog/dialog.d.ts +85 -0
- package/dist/components/dialog/dialog.js +272 -0
- package/dist/components/dialog/dialog.styles.d.ts +1 -0
- package/dist/components/dialog/dialog.styles.js +52 -0
- package/dist/components/dock-panel/dock-panel.d.ts +134 -0
- package/dist/components/dock-panel/dock-panel.js +345 -0
- package/dist/components/dock-panel/dock-panel.styles.d.ts +1 -0
- package/dist/components/dock-panel/dock-panel.styles.js +145 -0
- package/dist/components/document-preview/document-preview.d.ts +135 -0
- package/dist/components/document-preview/document-preview.js +372 -0
- package/dist/components/document-preview/document-preview.styles.d.ts +1 -0
- package/dist/components/document-preview/document-preview.styles.js +191 -0
- package/dist/components/export-button/csv.js +1 -1
- package/dist/components/export-button/export-button.js +2 -0
- package/dist/components/flag/flag.d.ts +29 -13
- package/dist/components/flag/flag.js +39 -13
- package/dist/components/gauge/gauge.js +19 -10
- package/dist/components/generation-status/generation-status.d.ts +109 -0
- package/dist/components/generation-status/generation-status.js +273 -0
- package/dist/components/generation-status/generation-status.styles.d.ts +1 -0
- package/dist/components/generation-status/generation-status.styles.js +84 -0
- package/dist/components/heatmap/calendar-grid.d.ts +4 -1
- package/dist/components/heatmap/calendar-grid.js +25 -12
- package/dist/components/heatmap/heatmap-scale.d.ts +6 -0
- package/dist/components/heatmap/heatmap-scale.js +7 -1
- package/dist/components/heatmap/heatmap.d.ts +74 -0
- package/dist/components/heatmap/heatmap.js +135 -23
- package/dist/components/json-viewer/json-viewer.d.ts +53 -0
- package/dist/components/json-viewer/json-viewer.js +283 -0
- package/dist/components/json-viewer/json-viewer.styles.d.ts +1 -0
- package/dist/components/json-viewer/json-viewer.styles.js +176 -0
- package/dist/components/kbd/kbd.d.ts +77 -0
- package/dist/components/kbd/kbd.js +214 -0
- package/dist/components/kbd/kbd.styles.d.ts +1 -0
- package/dist/components/kbd/kbd.styles.js +52 -0
- package/dist/components/live-region/live-region.d.ts +81 -0
- package/dist/components/live-region/live-region.js +153 -0
- package/dist/components/live-region/live-region.styles.d.ts +1 -0
- package/dist/components/live-region/live-region.styles.js +10 -0
- package/dist/components/map/map.d.ts +8 -6
- package/dist/components/map/map.js +44 -8
- package/dist/components/markdown/markdown-loader.d.ts +34 -0
- package/dist/components/markdown/markdown-loader.js +43 -0
- package/dist/components/markdown/markdown.d.ts +81 -0
- package/dist/components/markdown/markdown.js +284 -0
- package/dist/components/markdown/markdown.styles.d.ts +1 -0
- package/dist/components/markdown/markdown.styles.js +82 -0
- package/dist/components/media-card/media-card.d.ts +122 -0
- package/dist/components/media-card/media-card.js +295 -0
- package/dist/components/media-card/media-card.styles.d.ts +1 -0
- package/dist/components/media-card/media-card.styles.js +132 -0
- package/dist/components/mention-popover/mention-popover.d.ts +200 -0
- package/dist/components/mention-popover/mention-popover.js +475 -0
- package/dist/components/mention-popover/mention-popover.styles.d.ts +1 -0
- package/dist/components/mention-popover/mention-popover.styles.js +101 -0
- package/dist/components/menu/menu-item.d.ts +62 -0
- package/dist/components/menu/menu-item.js +119 -0
- package/dist/components/menu/menu-item.styles.d.ts +1 -0
- package/dist/components/menu/menu-item.styles.js +67 -0
- package/dist/components/menu/menu.d.ts +143 -0
- package/dist/components/menu/menu.js +365 -0
- package/dist/components/menu/menu.styles.d.ts +1 -0
- package/dist/components/menu/menu.styles.js +66 -0
- package/dist/components/model-select/model-select.d.ts +125 -0
- package/dist/components/model-select/model-select.js +490 -0
- package/dist/components/model-select/model-select.styles.d.ts +1 -0
- package/dist/components/model-select/model-select.styles.js +189 -0
- package/dist/components/model-settings-panel/model-settings-panel.d.ts +69 -0
- package/dist/components/model-settings-panel/model-settings-panel.js +145 -0
- package/dist/components/model-settings-panel/model-settings-panel.styles.d.ts +1 -0
- package/dist/components/model-settings-panel/model-settings-panel.styles.js +82 -0
- package/dist/components/playback/playback.d.ts +13 -1
- package/dist/components/playback/playback.js +47 -14
- package/dist/components/responsive-panel/responsive-panel.d.ts +150 -0
- package/dist/components/responsive-panel/responsive-panel.js +365 -0
- package/dist/components/responsive-panel/responsive-panel.styles.d.ts +1 -0
- package/dist/components/responsive-panel/responsive-panel.styles.js +103 -0
- package/dist/components/result-card/result-card.d.ts +44 -0
- package/dist/components/result-card/result-card.js +83 -0
- package/dist/components/result-card/result-card.styles.d.ts +1 -0
- package/dist/components/result-card/result-card.styles.js +50 -0
- package/dist/components/result-card/result-field.d.ts +36 -0
- package/dist/components/result-card/result-field.js +87 -0
- package/dist/components/result-card/result-field.styles.d.ts +1 -0
- package/dist/components/result-card/result-field.styles.js +32 -0
- package/dist/components/select/select.d.ts +43 -2
- package/dist/components/select/select.js +150 -17
- package/dist/components/slider/slider.d.ts +89 -0
- package/dist/components/slider/slider.js +352 -0
- package/dist/components/slider/slider.styles.d.ts +1 -0
- package/dist/components/slider/slider.styles.js +87 -0
- package/dist/components/source-card/source-card.d.ts +92 -0
- package/dist/components/source-card/source-card.js +148 -0
- package/dist/components/source-card/source-card.styles.d.ts +1 -0
- package/dist/components/source-card/source-card.styles.js +69 -0
- package/dist/components/source-list/source-list.d.ts +63 -0
- package/dist/components/source-list/source-list.js +122 -0
- package/dist/components/source-list/source-list.styles.d.ts +1 -0
- package/dist/components/source-list/source-list.styles.js +59 -0
- package/dist/components/sparkline/sparkline.js +27 -13
- package/dist/components/split/split.d.ts +93 -1
- package/dist/components/split/split.js +284 -15
- package/dist/components/split/split.styles.js +30 -0
- package/dist/components/stat/stat.d.ts +6 -1
- package/dist/components/stat/stat.js +8 -2
- package/dist/components/stream-status/stream-status.d.ts +110 -0
- package/dist/components/stream-status/stream-status.js +210 -0
- package/dist/components/stream-status/stream-status.styles.d.ts +1 -0
- package/dist/components/stream-status/stream-status.styles.js +103 -0
- package/dist/components/streaming-text/streaming-text.d.ts +98 -0
- package/dist/components/streaming-text/streaming-text.js +209 -0
- package/dist/components/streaming-text/streaming-text.styles.d.ts +1 -0
- package/dist/components/streaming-text/streaming-text.styles.js +62 -0
- package/dist/components/switch/switch.d.ts +58 -0
- package/dist/components/switch/switch.js +179 -0
- package/dist/components/switch/switch.styles.d.ts +1 -0
- package/dist/components/switch/switch.styles.js +75 -0
- package/dist/components/table/table.d.ts +73 -4
- package/dist/components/table/table.js +169 -20
- package/dist/components/table/table.styles.js +6 -1
- package/dist/components/tabs/tabs.d.ts +51 -0
- package/dist/components/tabs/tabs.js +190 -0
- package/dist/components/tabs/tabs.styles.d.ts +1 -0
- package/dist/components/tabs/tabs.styles.js +63 -0
- package/dist/components/thinking-panel/thinking-panel.d.ts +121 -0
- package/dist/components/thinking-panel/thinking-panel.js +235 -0
- package/dist/components/thinking-panel/thinking-panel.styles.d.ts +1 -0
- package/dist/components/thinking-panel/thinking-panel.styles.js +117 -0
- package/dist/components/toast/toast-item.d.ts +1 -0
- package/dist/components/toast/toast-item.js +31 -6
- package/dist/components/tool-approval-dialog/tool-approval-dialog.d.ts +130 -0
- package/dist/components/tool-approval-dialog/tool-approval-dialog.js +403 -0
- package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.d.ts +1 -0
- package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.js +160 -0
- package/dist/components/tool-call-chip/tool-call-chip.d.ts +89 -0
- package/dist/components/tool-call-chip/tool-call-chip.js +288 -0
- package/dist/components/tool-call-chip/tool-call-chip.styles.d.ts +1 -0
- package/dist/components/tool-call-chip/tool-call-chip.styles.js +203 -0
- package/dist/components/tool-param-form/tool-param-form.d.ts +145 -0
- package/dist/components/tool-param-form/tool-param-form.js +366 -0
- package/dist/components/tool-param-form/tool-param-form.styles.d.ts +1 -0
- package/dist/components/tool-param-form/tool-param-form.styles.js +75 -0
- package/dist/components/tool-result-dialog/tool-result-dialog.d.ts +102 -0
- package/dist/components/tool-result-dialog/tool-result-dialog.js +393 -0
- package/dist/components/tool-result-dialog/tool-result-dialog.styles.d.ts +1 -0
- package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +176 -0
- package/dist/components/tool-result-view/registry.d.ts +81 -0
- package/dist/components/tool-result-view/registry.js +84 -0
- package/dist/components/tool-result-view/tool-result-view.d.ts +55 -0
- package/dist/components/tool-result-view/tool-result-view.js +138 -0
- package/dist/components/tool-result-view/tool-result-view.styles.d.ts +1 -0
- package/dist/components/tool-result-view/tool-result-view.styles.js +13 -0
- package/dist/components/tool-select-dialog/tool-select-dialog.d.ts +151 -0
- package/dist/components/tool-select-dialog/tool-select-dialog.js +439 -0
- package/dist/components/tool-select-dialog/tool-select-dialog.styles.d.ts +1 -0
- package/dist/components/tool-select-dialog/tool-select-dialog.styles.js +182 -0
- package/dist/components/tree/tree-node.d.ts +11 -2
- package/dist/components/tree/tree-node.js +16 -6
- package/dist/components/tree/tree.d.ts +8 -2
- package/dist/components/tree/tree.js +18 -11
- package/dist/components/typing-indicator/typing-indicator.d.ts +60 -0
- package/dist/components/typing-indicator/typing-indicator.js +96 -0
- package/dist/components/typing-indicator/typing-indicator.styles.d.ts +1 -0
- package/dist/components/typing-indicator/typing-indicator.styles.js +132 -0
- package/dist/components/virtual-list/virtual-list.d.ts +173 -0
- package/dist/components/virtual-list/virtual-list.js +461 -0
- package/dist/components/virtual-list/virtual-list.styles.d.ts +1 -0
- package/dist/components/virtual-list/virtual-list.styles.js +44 -0
- package/dist/components/word-cloud/word-cloud-layout.js +14 -1
- package/dist/components/word-cloud/word-cloud.d.ts +6 -0
- package/dist/components/word-cloud/word-cloud.js +25 -14
- package/dist/components/word-cloud/word-cloud.styles.js +3 -2
- package/dist/internal/announcer.d.ts +57 -0
- package/dist/internal/announcer.js +71 -0
- package/dist/internal/form-associated.d.ts +1 -0
- package/dist/internal/form-associated.js +55 -11
- package/dist/internal/group-by-recency.d.ts +50 -0
- package/dist/internal/group-by-recency.js +80 -0
- package/dist/internal/rtl.d.ts +23 -0
- package/dist/internal/rtl.js +28 -0
- package/dist/internal/scroll-lock.d.ts +10 -5
- package/dist/internal/scroll-lock.js +30 -14
- package/dist/internal/tokens.styles.js +6 -0
- package/dist/lyra.d.ts +130 -31
- package/dist/lyra.js +94 -26
- package/llms-full.txt +3836 -17
- package/llms.txt +16 -1
- package/package.json +23 -5
- package/dist/components/chart/bar-chart.stories.d.ts +0 -5
- package/dist/components/chart/bar-chart.stories.js +0 -20
- package/dist/components/chart/box-plot.stories.d.ts +0 -5
- package/dist/components/chart/box-plot.stories.js +0 -29
- package/dist/components/chart/bubble-chart.stories.d.ts +0 -5
- package/dist/components/chart/bubble-chart.stories.js +0 -26
- package/dist/components/chart/chart.stories.d.ts +0 -32
- package/dist/components/chart/chart.stories.js +0 -141
- package/dist/components/chart/doughnut-chart.stories.d.ts +0 -5
- package/dist/components/chart/doughnut-chart.stories.js +0 -26
- package/dist/components/chart/histogram.stories.d.ts +0 -5
- package/dist/components/chart/histogram.stories.js +0 -17
- package/dist/components/chart/line-chart.stories.d.ts +0 -22
- package/dist/components/chart/line-chart.stories.js +0 -99
- package/dist/components/chart/lite-chart.stories.d.ts +0 -14
- package/dist/components/chart/lite-chart.stories.js +0 -114
- package/dist/components/chart/pie-chart.stories.d.ts +0 -5
- package/dist/components/chart/pie-chart.stories.js +0 -26
- package/dist/components/chart/polar-area-chart.stories.d.ts +0 -5
- package/dist/components/chart/polar-area-chart.stories.js +0 -20
- package/dist/components/chart/radar-chart.stories.d.ts +0 -5
- package/dist/components/chart/radar-chart.stories.js +0 -20
- package/dist/components/chart/scatter-chart.stories.d.ts +0 -5
- package/dist/components/chart/scatter-chart.stories.js +0 -31
- package/dist/components/combobox/combobox.stories.d.ts +0 -24
- package/dist/components/combobox/combobox.stories.js +0 -102
- package/dist/components/date-picker/date-input.stories.d.ts +0 -10
- package/dist/components/date-picker/date-input.stories.js +0 -48
- package/dist/components/date-picker/date-picker.stories.d.ts +0 -10
- package/dist/components/date-picker/date-picker.stories.js +0 -25
- package/dist/components/empty/empty.stories.d.ts +0 -7
- package/dist/components/empty/empty.stories.js +0 -34
- package/dist/components/export-button/export-button.stories.d.ts +0 -7
- package/dist/components/export-button/export-button.stories.js +0 -37
- package/dist/components/file-input/file-input.stories.d.ts +0 -7
- package/dist/components/file-input/file-input.stories.js +0 -19
- package/dist/components/flag/flag.stories.d.ts +0 -6
- package/dist/components/flag/flag.stories.js +0 -31
- package/dist/components/gauge/gauge.stories.d.ts +0 -8
- package/dist/components/gauge/gauge.stories.js +0 -19
- package/dist/components/graph/graph.stories.d.ts +0 -8
- package/dist/components/graph/graph.stories.js +0 -68
- package/dist/components/heatmap/heatmap.stories.d.ts +0 -27
- package/dist/components/heatmap/heatmap.stories.js +0 -179
- package/dist/components/map/map.stories.d.ts +0 -15
- package/dist/components/map/map.stories.js +0 -135
- package/dist/components/playback/playback.stories.d.ts +0 -7
- package/dist/components/playback/playback.stories.js +0 -16
- package/dist/components/select/select.stories.d.ts +0 -21
- package/dist/components/select/select.stories.js +0 -91
- package/dist/components/skeleton/skeleton.stories.d.ts +0 -5
- package/dist/components/skeleton/skeleton.stories.js +0 -16
- package/dist/components/sparkline/sparkline.stories.d.ts +0 -11
- package/dist/components/sparkline/sparkline.stories.js +0 -39
- package/dist/components/split/split.stories.d.ts +0 -7
- package/dist/components/split/split.stories.js +0 -36
- package/dist/components/stat/stat.stories.d.ts +0 -9
- package/dist/components/stat/stat.stories.js +0 -81
- package/dist/components/table/table.stories.d.ts +0 -12
- package/dist/components/table/table.stories.js +0 -67
- package/dist/components/time-range/time-range.stories.d.ts +0 -8
- package/dist/components/time-range/time-range.stories.js +0 -26
- package/dist/components/toast/toast.stories.d.ts +0 -8
- package/dist/components/toast/toast.stories.js +0 -72
- package/dist/components/tree/tree.stories.d.ts +0 -9
- package/dist/components/tree/tree.stories.js +0 -52
- package/dist/components/widget/widget.stories.d.ts +0 -9
- package/dist/components/widget/widget.stories.js +0 -74
- package/dist/components/word-cloud/word-cloud.stories.d.ts +0 -10
- package/dist/components/word-cloud/word-cloud.stories.js +0 -55
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { html, svg, nothing } from 'lit';
|
|
8
|
+
import { property, state } from 'lit/decorators.js';
|
|
9
|
+
import { LyraElement } from '../../internal/lyra-element.js';
|
|
10
|
+
import { defineElement } from '../../internal/prefix.js';
|
|
11
|
+
import { lockScroll } from '../../internal/scroll-lock.js';
|
|
12
|
+
import { nextId } from '../../internal/a11y.js';
|
|
13
|
+
import { closeIcon, expandIcon } from '../../internal/icons.js';
|
|
14
|
+
import { styles } from './tool-result-dialog.styles.js';
|
|
15
|
+
const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
16
|
+
// Shadow-piercing so a slotted custom element's real focusable target (e.g.
|
|
17
|
+
// an <input> inside its own shadow root) is found even though the host tag
|
|
18
|
+
// itself doesn't match FOCUSABLE_SELECTOR. Deliberately duplicated from
|
|
19
|
+
// lyra-dialog's identical helper rather than imported/shared -- this
|
|
20
|
+
// component is its own standalone overlay with its own header chrome and
|
|
21
|
+
// must not depend on lyra-dialog (see this file's authoring notes).
|
|
22
|
+
function collectFocusable(el) {
|
|
23
|
+
const result = [];
|
|
24
|
+
if (el.matches(FOCUSABLE_SELECTOR)) {
|
|
25
|
+
result.push(el);
|
|
26
|
+
}
|
|
27
|
+
if (el instanceof HTMLSlotElement) {
|
|
28
|
+
for (const assigned of el.assignedElements({ flatten: true })) {
|
|
29
|
+
result.push(...collectFocusable(assigned));
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
const container = el.shadowRoot ?? el;
|
|
34
|
+
for (const child of Array.from(container.children)) {
|
|
35
|
+
result.push(...collectFocusable(child));
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
/** Whether `el` is actually laid out/paintable -- `checkVisibility()` (falling
|
|
40
|
+
* back to `getClientRects().length` where unsupported) correctly follows
|
|
41
|
+
* flattened-tree/slot assignment, unlike `offsetParent`. Mirrors
|
|
42
|
+
* lyra-dialog's/lyra-widget's identical helper. */
|
|
43
|
+
function isRendered(el) {
|
|
44
|
+
return el.checkVisibility ? el.checkVisibility() : el.getClientRects().length > 0;
|
|
45
|
+
}
|
|
46
|
+
// Mirrors the shared icon set's viewBox/stroke conventions
|
|
47
|
+
// (internal/icons.ts's chevronIcon()/closeIcon()/etc.) without adding
|
|
48
|
+
// tool-result-specific glyphs to that module -- it's off limits here -- so
|
|
49
|
+
// these still read as part of the same visual language as the rest of the
|
|
50
|
+
// library's inline icons. Same approach lyra-checkbox's/lyra-chat-message's
|
|
51
|
+
// own local glyphs take for the identical reason.
|
|
52
|
+
const ICON_VIEW_BOX = '0 0 24 24';
|
|
53
|
+
const ICON_STROKE_WIDTH = '1.75';
|
|
54
|
+
function icon(paths) {
|
|
55
|
+
return svg `
|
|
56
|
+
<svg
|
|
57
|
+
width="1em"
|
|
58
|
+
height="1em"
|
|
59
|
+
viewBox=${ICON_VIEW_BOX}
|
|
60
|
+
fill="none"
|
|
61
|
+
stroke="currentColor"
|
|
62
|
+
stroke-width=${ICON_STROKE_WIDTH}
|
|
63
|
+
stroke-linecap="round"
|
|
64
|
+
stroke-linejoin="round"
|
|
65
|
+
aria-hidden="true"
|
|
66
|
+
focusable="false"
|
|
67
|
+
>${paths}</svg>
|
|
68
|
+
`;
|
|
69
|
+
}
|
|
70
|
+
/** A "restore from maximized" glyph -- the mirror image of `expandIcon()`,
|
|
71
|
+
* arrows pointing inward toward the center instead of outward toward the
|
|
72
|
+
* corners, same as lyra-widget's fullscreen-exit affordance reuses
|
|
73
|
+
* `closeIcon()` for the analogous "undo the expanded state" action. A
|
|
74
|
+
* distinct glyph (not `closeIcon()`) is used here because this dialog
|
|
75
|
+
* already has its own, separate close button right next to it -- two
|
|
76
|
+
* identical "x" icons side by side would be ambiguous about which one
|
|
77
|
+
* dismisses the dialog and which one only un-maximizes it. */
|
|
78
|
+
function shrinkIcon() {
|
|
79
|
+
return icon(svg `
|
|
80
|
+
<polyline points="4 14 10 14 10 20"></polyline>
|
|
81
|
+
<polyline points="20 10 14 10 14 4"></polyline>
|
|
82
|
+
<line x1="14" y1="10" x2="21" y2="3"></line>
|
|
83
|
+
<line x1="3" y1="21" x2="10" y2="14"></line>
|
|
84
|
+
`);
|
|
85
|
+
}
|
|
86
|
+
function pendingIcon() {
|
|
87
|
+
return icon(svg `<circle cx="12" cy="12" r="9"></circle><polyline points="12 7 12 12 15 14"></polyline>`);
|
|
88
|
+
}
|
|
89
|
+
/** A three-quarter arc, spun by the `[status="running"] [part="status"] svg`
|
|
90
|
+
* CSS animation -- a full circle wouldn't visibly convey rotation. */
|
|
91
|
+
function runningIcon() {
|
|
92
|
+
return icon(svg `<path d="M21 12a9 9 0 1 1-9-9"></path>`);
|
|
93
|
+
}
|
|
94
|
+
function successIcon() {
|
|
95
|
+
return icon(svg `<circle cx="12" cy="12" r="9"></circle><polyline points="8 12.5 11 15.5 16 9.5"></polyline>`);
|
|
96
|
+
}
|
|
97
|
+
function errorIcon() {
|
|
98
|
+
return icon(svg `
|
|
99
|
+
<circle cx="12" cy="12" r="9"></circle>
|
|
100
|
+
<line x1="9" y1="9" x2="15" y2="15"></line>
|
|
101
|
+
<line x1="15" y1="9" x2="9" y2="15"></line>
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
/** A "blocked" glyph (circle + diagonal slash) -- distinct from `errorIcon()`
|
|
105
|
+
* since a denial is a policy rejection, not a runtime failure. */
|
|
106
|
+
function deniedIcon() {
|
|
107
|
+
return icon(svg `<circle cx="12" cy="12" r="9"></circle><line x1="6" y1="18" x2="18" y2="6"></line>`);
|
|
108
|
+
}
|
|
109
|
+
const STATUS_ICON = {
|
|
110
|
+
pending: pendingIcon,
|
|
111
|
+
running: runningIcon,
|
|
112
|
+
success: successIcon,
|
|
113
|
+
error: errorIcon,
|
|
114
|
+
denied: deniedIcon,
|
|
115
|
+
};
|
|
116
|
+
/** Visible (not just color-coded) text for every status. */
|
|
117
|
+
const STATUS_LABEL = {
|
|
118
|
+
pending: 'Pending',
|
|
119
|
+
running: 'Running',
|
|
120
|
+
success: 'Success',
|
|
121
|
+
error: 'Error',
|
|
122
|
+
denied: 'Denied',
|
|
123
|
+
};
|
|
124
|
+
/** `820` -> `"820ms"`; `1500` -> `"1.5s"`; `2000` -> `"2s"`. Sub-second
|
|
125
|
+
* durations are the common case for a single tool call, so they get the
|
|
126
|
+
* more precise unit; once a call runs a full second or longer, trimming to
|
|
127
|
+
* (at most) one decimal place of seconds reads better than a 4-5 digit
|
|
128
|
+
* millisecond count. */
|
|
129
|
+
function formatDuration(ms) {
|
|
130
|
+
if (!Number.isFinite(ms) || ms < 1000) {
|
|
131
|
+
return `${Math.round(Math.max(0, ms))}ms`;
|
|
132
|
+
}
|
|
133
|
+
const seconds = ms / 1000;
|
|
134
|
+
const rounded = Math.round(seconds * 10) / 10;
|
|
135
|
+
return `${Number.isInteger(rounded) ? rounded.toFixed(0) : rounded.toFixed(1)}s`;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* `<lyra-tool-result-dialog>` — a full tool-call detail overlay: a status/
|
|
139
|
+
* duration header plus a `body` slot where a consumer typically places a
|
|
140
|
+
* `<lyra-tabs>` with Input/Preview/JSON/Raw panels. This component knows
|
|
141
|
+
* nothing about what's inside that slot — it only supplies the modal chrome
|
|
142
|
+
* around it.
|
|
143
|
+
*
|
|
144
|
+
* This is its own standalone overlay implementation (`role="dialog"`,
|
|
145
|
+
* focus-trapped, Escape/backdrop-dismissible, scroll-locking) rather than
|
|
146
|
+
* nesting a `<lyra-dialog>` in its shadow template — see `<lyra-dialog>`'s
|
|
147
|
+
* own header comment for why a new overlay component in this library
|
|
148
|
+
* duplicates that pattern locally instead of composing the previous one:
|
|
149
|
+
* slot-forwarding into a nested `<lyra-dialog>` would put a forwarding
|
|
150
|
+
* `<slot>` where a light-DOM-scanning descendant (e.g. a slotted
|
|
151
|
+
* `<lyra-tabs>`'s own `Array.from(this.children)` scan) expects real
|
|
152
|
+
* projected content.
|
|
153
|
+
*
|
|
154
|
+
* `maximized` toggles between a constrained modal size and a near-fullscreen
|
|
155
|
+
* size within the same open dialog and open/close lifecycle — unlike
|
|
156
|
+
* `<lyra-widget>`'s fullscreen mode, there's no non-modal resting state to
|
|
157
|
+
* return to, so no separate scroll-lock/focus-trap bookkeeping is needed for
|
|
158
|
+
* the transition itself.
|
|
159
|
+
*
|
|
160
|
+
* @customElement lyra-tool-result-dialog
|
|
161
|
+
* @slot body - The dialog's main content — typically a `<lyra-tabs>` with
|
|
162
|
+
* Input/Preview/JSON/Raw panels, entirely consumer-assembled.
|
|
163
|
+
* @slot footer - Optional action buttons, rendered in a bottom row.
|
|
164
|
+
* @event lyra-dialog-close - `detail: ToolResultDialogCloseReason`. Fired
|
|
165
|
+
* exactly once per dismissal, via Escape, a backdrop click, the built-in
|
|
166
|
+
* close button, or a `close()` call.
|
|
167
|
+
* @event lyra-maximize-change - `detail: boolean` (the new `maximized`
|
|
168
|
+
* state), fired when the header's maximize/restore toggle is clicked.
|
|
169
|
+
* @csspart backdrop - The full-viewport scrim behind the panel.
|
|
170
|
+
* @csspart panel - The dialog panel itself (`role="dialog"` while open).
|
|
171
|
+
* @csspart header - The row containing the tool name, status, duration, and toggle/close buttons.
|
|
172
|
+
* @csspart title - The wrapper around the tool name, status, and duration.
|
|
173
|
+
* @csspart tool-name - The `tool-name` text.
|
|
174
|
+
* @csspart status - The status badge (icon + text).
|
|
175
|
+
* @csspart duration - The formatted `duration-ms` text.
|
|
176
|
+
* @csspart header-actions - The wrapper around the maximize and close buttons.
|
|
177
|
+
* @csspart maximize-button - The built-in maximize/restore toggle button.
|
|
178
|
+
* @csspart close-button - The built-in close button.
|
|
179
|
+
* @csspart body - The wrapper around the `body` slot.
|
|
180
|
+
* @csspart footer - The wrapper around the `footer` slot.
|
|
181
|
+
*/
|
|
182
|
+
export class LyraToolResultDialog extends LyraElement {
|
|
183
|
+
constructor() {
|
|
184
|
+
super(...arguments);
|
|
185
|
+
/** Whether the dialog is open. Set this (or call `close()`) — there is no separate `show()`/`hide()` pair. */
|
|
186
|
+
this.open = false;
|
|
187
|
+
/** The tool's name, rendered prominently in the header. */
|
|
188
|
+
this.toolName = '';
|
|
189
|
+
/** The tool call's current lifecycle state — drives the header's status badge. */
|
|
190
|
+
this.status = 'pending';
|
|
191
|
+
/** Near-fullscreen presentation of the same open dialog. */
|
|
192
|
+
this.maximized = false;
|
|
193
|
+
this.hasFooterSlot = false;
|
|
194
|
+
this.titleId = nextId('tool-result-dialog-title');
|
|
195
|
+
this.onFooterSlotChange = (e) => {
|
|
196
|
+
this.hasFooterSlot = e.target.assignedElements({ flatten: true }).length > 0;
|
|
197
|
+
};
|
|
198
|
+
this.onBackdropClick = () => {
|
|
199
|
+
this.close('backdrop');
|
|
200
|
+
};
|
|
201
|
+
this.onCloseButtonClick = () => {
|
|
202
|
+
this.close('close-button');
|
|
203
|
+
};
|
|
204
|
+
this.toggleMaximized = () => {
|
|
205
|
+
this.maximized = !this.maximized;
|
|
206
|
+
this.emit('lyra-maximize-change', this.maximized);
|
|
207
|
+
};
|
|
208
|
+
this.onDocKeyDown = (e) => {
|
|
209
|
+
if (!this.open)
|
|
210
|
+
return;
|
|
211
|
+
if (e.key === 'Escape') {
|
|
212
|
+
e.preventDefault();
|
|
213
|
+
this.close('escape');
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (e.key !== 'Tab')
|
|
217
|
+
return;
|
|
218
|
+
const focusable = this.getFocusableElements();
|
|
219
|
+
if (focusable.length === 0) {
|
|
220
|
+
e.preventDefault();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const first = focusable[0];
|
|
224
|
+
const last = focusable[focusable.length - 1];
|
|
225
|
+
const active = this.getActiveElement();
|
|
226
|
+
if (e.shiftKey && active === first) {
|
|
227
|
+
e.preventDefault();
|
|
228
|
+
last.focus();
|
|
229
|
+
}
|
|
230
|
+
else if (!e.shiftKey && active === last) {
|
|
231
|
+
e.preventDefault();
|
|
232
|
+
first.focus();
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
static { this.styles = [LyraElement.styles, styles]; }
|
|
237
|
+
willUpdate(changed) {
|
|
238
|
+
if (!this.hasUpdated) {
|
|
239
|
+
this.hasFooterSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'footer');
|
|
240
|
+
}
|
|
241
|
+
if (changed.has('open')) {
|
|
242
|
+
if (this.open) {
|
|
243
|
+
// Captured here (before render) rather than from a click event on
|
|
244
|
+
// some specific internal control -- like lyra-dialog, a trigger
|
|
245
|
+
// typically lives *outside* this component entirely, so "whatever
|
|
246
|
+
// had focus right before open" is the only generally correct
|
|
247
|
+
// definition of "the trigger".
|
|
248
|
+
const active = this.getActiveElement();
|
|
249
|
+
this.lastTrigger = active instanceof HTMLElement ? active : undefined;
|
|
250
|
+
this.releaseScrollLock = lockScroll();
|
|
251
|
+
document.addEventListener('keydown', this.onDocKeyDown);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
this.releaseScrollLock?.();
|
|
255
|
+
this.releaseScrollLock = undefined;
|
|
256
|
+
document.removeEventListener('keydown', this.onDocKeyDown);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Runs after render (not willUpdate) so [part="panel"] has already landed
|
|
261
|
+
// in the DOM before the fallback .focus() call below can rely on it --
|
|
262
|
+
// mirrors lyra-dialog's identical ordering rationale.
|
|
263
|
+
updated(changed) {
|
|
264
|
+
if (changed.has('open') && this.open) {
|
|
265
|
+
const first = this.getFocusableElements()[0];
|
|
266
|
+
if (first) {
|
|
267
|
+
first.focus();
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
this.shadowRoot?.querySelector('[part="panel"]')?.focus();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
connectedCallback() {
|
|
275
|
+
super.connectedCallback();
|
|
276
|
+
// A reconnect (e.g. a drag-and-drop reparent keeping this same element
|
|
277
|
+
// instance) fires disconnectedCallback then connectedCallback
|
|
278
|
+
// synchronously with no update in between, so willUpdate never reruns to
|
|
279
|
+
// notice `open` is still true -- restore the scroll lock/trap it dropped.
|
|
280
|
+
if (this.hasUpdated && this.open && !this.releaseScrollLock) {
|
|
281
|
+
this.releaseScrollLock = lockScroll();
|
|
282
|
+
document.addEventListener('keydown', this.onDocKeyDown);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
disconnectedCallback() {
|
|
286
|
+
super.disconnectedCallback();
|
|
287
|
+
this.releaseScrollLock?.();
|
|
288
|
+
this.releaseScrollLock = undefined;
|
|
289
|
+
document.removeEventListener('keydown', this.onDocKeyDown);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Close the dialog and return focus to whatever had it before the dialog
|
|
293
|
+
* opened. `reason` is forwarded as the `lyra-dialog-close` detail --
|
|
294
|
+
* built-in triggers pass `'escape'`/`'backdrop'`/`'close-button'`; a
|
|
295
|
+
* consumer's own close affordance (e.g. a footer action button) should
|
|
296
|
+
* call this directly with its own reason string, so every dismissal path
|
|
297
|
+
* funnels through the same event instead of the consumer having to also
|
|
298
|
+
* toggle `open` itself.
|
|
299
|
+
*/
|
|
300
|
+
close(reason = 'api') {
|
|
301
|
+
if (!this.open)
|
|
302
|
+
return;
|
|
303
|
+
this.open = false;
|
|
304
|
+
this.emit('lyra-dialog-close', reason);
|
|
305
|
+
this.lastTrigger?.focus();
|
|
306
|
+
}
|
|
307
|
+
// Bounds Tab/Shift+Tab to the panel while open. Order follows the header's
|
|
308
|
+
// own maximize/close buttons, then the body slot, then the footer slot --
|
|
309
|
+
// the same order the flattened tree already tabs through (mirrors
|
|
310
|
+
// lyra-widget's identical actions-before-body ordering for its fullscreen
|
|
311
|
+
// mode).
|
|
312
|
+
getFocusableElements() {
|
|
313
|
+
const root = this.shadowRoot;
|
|
314
|
+
if (!root)
|
|
315
|
+
return [];
|
|
316
|
+
const fromSlot = (selector) => {
|
|
317
|
+
const slot = root.querySelector(selector);
|
|
318
|
+
return slot ? slot.assignedElements({ flatten: true }).flatMap(collectFocusable) : [];
|
|
319
|
+
};
|
|
320
|
+
const headerButtons = Array.from(root.querySelectorAll('[part="maximize-button"], [part="close-button"]'));
|
|
321
|
+
return [...headerButtons, ...fromSlot('slot[name="body"]'), ...fromSlot('slot[name="footer"]')].filter(isRendered);
|
|
322
|
+
}
|
|
323
|
+
getActiveElement() {
|
|
324
|
+
let active = document.activeElement;
|
|
325
|
+
while (active) {
|
|
326
|
+
const inner = active.shadowRoot?.activeElement ?? null;
|
|
327
|
+
if (!inner)
|
|
328
|
+
break;
|
|
329
|
+
active = inner;
|
|
330
|
+
}
|
|
331
|
+
return active;
|
|
332
|
+
}
|
|
333
|
+
render() {
|
|
334
|
+
const hasDuration = this.durationMs != null;
|
|
335
|
+
return html `
|
|
336
|
+
<div part="backdrop" @click=${this.onBackdropClick}></div>
|
|
337
|
+
<div
|
|
338
|
+
part="panel"
|
|
339
|
+
role=${this.open ? 'dialog' : nothing}
|
|
340
|
+
aria-modal=${this.open ? 'true' : nothing}
|
|
341
|
+
aria-labelledby=${this.titleId}
|
|
342
|
+
tabindex="-1"
|
|
343
|
+
>
|
|
344
|
+
<div part="header">
|
|
345
|
+
<div part="title">
|
|
346
|
+
<span part="tool-name" id=${this.titleId}>${this.toolName || 'Tool call'}</span>
|
|
347
|
+
<span part="status">${STATUS_ICON[this.status]()}<span>${STATUS_LABEL[this.status]}</span></span>
|
|
348
|
+
${hasDuration ? html `<span part="duration">${formatDuration(this.durationMs)}</span>` : nothing}
|
|
349
|
+
</div>
|
|
350
|
+
<div part="header-actions">
|
|
351
|
+
<button
|
|
352
|
+
part="maximize-button"
|
|
353
|
+
type="button"
|
|
354
|
+
aria-pressed=${this.maximized ? 'true' : 'false'}
|
|
355
|
+
aria-label=${this.maximized ? 'Restore' : 'Maximize'}
|
|
356
|
+
@click=${this.toggleMaximized}
|
|
357
|
+
>
|
|
358
|
+
${this.maximized ? shrinkIcon() : expandIcon()}
|
|
359
|
+
</button>
|
|
360
|
+
<button part="close-button" type="button" aria-label="Close" @click=${this.onCloseButtonClick}>
|
|
361
|
+
${closeIcon()}
|
|
362
|
+
</button>
|
|
363
|
+
</div>
|
|
364
|
+
</div>
|
|
365
|
+
<div part="body">
|
|
366
|
+
<slot name="body"></slot>
|
|
367
|
+
</div>
|
|
368
|
+
<div part="footer" ?hidden=${!this.hasFooterSlot}>
|
|
369
|
+
<slot name="footer" @slotchange=${this.onFooterSlotChange}></slot>
|
|
370
|
+
</div>
|
|
371
|
+
</div>
|
|
372
|
+
`;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
__decorate([
|
|
376
|
+
property({ type: Boolean, reflect: true })
|
|
377
|
+
], LyraToolResultDialog.prototype, "open", void 0);
|
|
378
|
+
__decorate([
|
|
379
|
+
property({ attribute: 'tool-name' })
|
|
380
|
+
], LyraToolResultDialog.prototype, "toolName", void 0);
|
|
381
|
+
__decorate([
|
|
382
|
+
property({ reflect: true })
|
|
383
|
+
], LyraToolResultDialog.prototype, "status", void 0);
|
|
384
|
+
__decorate([
|
|
385
|
+
property({ type: Number, attribute: 'duration-ms' })
|
|
386
|
+
], LyraToolResultDialog.prototype, "durationMs", void 0);
|
|
387
|
+
__decorate([
|
|
388
|
+
property({ type: Boolean, reflect: true })
|
|
389
|
+
], LyraToolResultDialog.prototype, "maximized", void 0);
|
|
390
|
+
__decorate([
|
|
391
|
+
state()
|
|
392
|
+
], LyraToolResultDialog.prototype, "hasFooterSlot", void 0);
|
|
393
|
+
defineElement('tool-result-dialog', LyraToolResultDialog);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const styles: import("lit").CSSResult;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
export const styles = css `
|
|
3
|
+
:host {
|
|
4
|
+
/* Backdrop scrim color -- component-specific so a host can retheme it
|
|
5
|
+
without a raw literal leaking into the public API (no shared
|
|
6
|
+
--wa-*-overlay token exists in the design system to resolve through,
|
|
7
|
+
same rationale as lyra-dialog's --lyra-dialog-overlay-color and
|
|
8
|
+
lyra-widget's --lyra-widget-overlay-color). */
|
|
9
|
+
--lyra-tool-result-dialog-overlay-color: rgb(0 0 0 / 0.5);
|
|
10
|
+
/* Inset applied to the panel while [maximized] -- overridable the same
|
|
11
|
+
way lyra-widget's --lyra-widget-fullscreen-inset is, e.g. to leave a
|
|
12
|
+
persistent app rail visible. */
|
|
13
|
+
--lyra-tool-result-dialog-maximized-inset: var(--lyra-space-l);
|
|
14
|
+
display: none;
|
|
15
|
+
position: fixed;
|
|
16
|
+
inset: 0;
|
|
17
|
+
z-index: 1000;
|
|
18
|
+
align-items: center;
|
|
19
|
+
justify-content: center;
|
|
20
|
+
padding: var(--lyra-space-l);
|
|
21
|
+
}
|
|
22
|
+
:host([open]) {
|
|
23
|
+
display: flex;
|
|
24
|
+
}
|
|
25
|
+
[part='backdrop'] {
|
|
26
|
+
position: absolute;
|
|
27
|
+
inset: 0;
|
|
28
|
+
background: var(--lyra-tool-result-dialog-overlay-color);
|
|
29
|
+
}
|
|
30
|
+
[part='panel'] {
|
|
31
|
+
position: relative;
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
inline-size: min(48rem, 100%);
|
|
35
|
+
max-block-size: 100%;
|
|
36
|
+
background: var(--lyra-color-surface);
|
|
37
|
+
border: 1px solid var(--lyra-color-border);
|
|
38
|
+
border-radius: var(--lyra-radius);
|
|
39
|
+
box-shadow: var(--lyra-shadow);
|
|
40
|
+
overflow: hidden;
|
|
41
|
+
transition:
|
|
42
|
+
inline-size var(--lyra-transition-base),
|
|
43
|
+
block-size var(--lyra-transition-base);
|
|
44
|
+
}
|
|
45
|
+
:host([maximized]) [part='panel'] {
|
|
46
|
+
position: fixed;
|
|
47
|
+
inset: var(--lyra-tool-result-dialog-maximized-inset);
|
|
48
|
+
inline-size: auto;
|
|
49
|
+
max-block-size: none;
|
|
50
|
+
}
|
|
51
|
+
[part='header'] {
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-wrap: wrap;
|
|
54
|
+
align-items: center;
|
|
55
|
+
gap: var(--lyra-space-s);
|
|
56
|
+
padding: var(--lyra-space-m) var(--lyra-space-l);
|
|
57
|
+
border-block-end: 1px solid var(--lyra-color-border);
|
|
58
|
+
}
|
|
59
|
+
[part='title'] {
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-wrap: wrap;
|
|
62
|
+
align-items: center;
|
|
63
|
+
gap: var(--lyra-space-s);
|
|
64
|
+
flex: 1 1 auto;
|
|
65
|
+
min-inline-size: 0;
|
|
66
|
+
}
|
|
67
|
+
[part='tool-name'] {
|
|
68
|
+
font-weight: 600;
|
|
69
|
+
overflow: hidden;
|
|
70
|
+
text-overflow: ellipsis;
|
|
71
|
+
white-space: nowrap;
|
|
72
|
+
}
|
|
73
|
+
[part='status'] {
|
|
74
|
+
display: inline-flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
gap: 0.25rem;
|
|
77
|
+
padding: 0.125rem var(--lyra-space-xs);
|
|
78
|
+
border-radius: var(--lyra-radius);
|
|
79
|
+
font-size: 0.75rem;
|
|
80
|
+
font-weight: 600;
|
|
81
|
+
color: var(--lyra-color-text-quiet);
|
|
82
|
+
background: transparent;
|
|
83
|
+
}
|
|
84
|
+
[part='status'] svg {
|
|
85
|
+
inline-size: 1em;
|
|
86
|
+
block-size: 1em;
|
|
87
|
+
}
|
|
88
|
+
/* pending stays the neutral/quiet treatment above -- it's the resting
|
|
89
|
+
state before a tool call has done anything worth calling out. */
|
|
90
|
+
:host([status='running']) [part='status'] {
|
|
91
|
+
color: var(--lyra-color-brand);
|
|
92
|
+
background: var(--lyra-color-brand-quiet);
|
|
93
|
+
}
|
|
94
|
+
:host([status='success']) [part='status'] {
|
|
95
|
+
color: var(--lyra-color-success);
|
|
96
|
+
background: var(--lyra-color-success-quiet);
|
|
97
|
+
}
|
|
98
|
+
:host([status='error']) [part='status'] {
|
|
99
|
+
color: var(--lyra-color-danger);
|
|
100
|
+
background: var(--lyra-color-danger-quiet);
|
|
101
|
+
}
|
|
102
|
+
/* 'denied' is a policy rejection, not a runtime failure -- the warning
|
|
103
|
+
(not danger) tinted-background reads that distinction without relying on
|
|
104
|
+
the status text alone. */
|
|
105
|
+
:host([status='denied']) [part='status'] {
|
|
106
|
+
color: var(--lyra-color-warning);
|
|
107
|
+
background: var(--lyra-color-warning-quiet);
|
|
108
|
+
}
|
|
109
|
+
:host([status='running']) [part='status'] svg {
|
|
110
|
+
animation: lyra-tool-result-dialog-spin 1s linear infinite;
|
|
111
|
+
}
|
|
112
|
+
[part='duration'] {
|
|
113
|
+
font-size: 0.75rem;
|
|
114
|
+
color: var(--lyra-color-text-quiet);
|
|
115
|
+
white-space: nowrap;
|
|
116
|
+
}
|
|
117
|
+
[part='header-actions'] {
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
gap: var(--lyra-space-xs);
|
|
121
|
+
flex: 0 0 auto;
|
|
122
|
+
}
|
|
123
|
+
[part='maximize-button'],
|
|
124
|
+
[part='close-button'] {
|
|
125
|
+
display: inline-flex;
|
|
126
|
+
align-items: center;
|
|
127
|
+
justify-content: center;
|
|
128
|
+
min-inline-size: var(--lyra-icon-button-size);
|
|
129
|
+
min-block-size: var(--lyra-icon-button-size);
|
|
130
|
+
border: none;
|
|
131
|
+
background: transparent;
|
|
132
|
+
color: var(--lyra-color-text-quiet);
|
|
133
|
+
border-radius: var(--lyra-radius);
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
}
|
|
136
|
+
[part='maximize-button']:hover,
|
|
137
|
+
[part='close-button']:hover {
|
|
138
|
+
background: var(--lyra-color-brand-quiet);
|
|
139
|
+
color: var(--lyra-color-brand);
|
|
140
|
+
}
|
|
141
|
+
[part='maximize-button']:focus-visible,
|
|
142
|
+
[part='close-button']:focus-visible {
|
|
143
|
+
outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
|
|
144
|
+
outline-offset: var(--lyra-focus-ring-offset);
|
|
145
|
+
}
|
|
146
|
+
[part='body'] {
|
|
147
|
+
flex: 1 1 auto;
|
|
148
|
+
min-block-size: 0;
|
|
149
|
+
padding: var(--lyra-space-l);
|
|
150
|
+
overflow: auto;
|
|
151
|
+
}
|
|
152
|
+
[part='footer'] {
|
|
153
|
+
display: flex;
|
|
154
|
+
align-items: center;
|
|
155
|
+
justify-content: flex-end;
|
|
156
|
+
gap: var(--lyra-space-s);
|
|
157
|
+
padding: var(--lyra-space-m) var(--lyra-space-l);
|
|
158
|
+
border-block-start: 1px solid var(--lyra-color-border);
|
|
159
|
+
}
|
|
160
|
+
[part='footer'][hidden] {
|
|
161
|
+
display: none;
|
|
162
|
+
}
|
|
163
|
+
@keyframes lyra-tool-result-dialog-spin {
|
|
164
|
+
to {
|
|
165
|
+
transform: rotate(360deg);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
@media (prefers-reduced-motion: reduce) {
|
|
169
|
+
[part='panel'] {
|
|
170
|
+
transition: none !important;
|
|
171
|
+
}
|
|
172
|
+
:host([status='running']) [part='status'] svg {
|
|
173
|
+
animation: none !important;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
`;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A type-keyed dispatch registry for tool-result renderers -- a tiny plugin
|
|
3
|
+
* system so a host app can teach `<lyra-tool-result-view>` how to draw the
|
|
4
|
+
* result of e.g. a `get_weather` or `run_query` tool call without this
|
|
5
|
+
* library knowing anything about either. Dispatch is a two-step lookup
|
|
6
|
+
* (elipa-inspired): an exact match on the tool's name first, falling back to
|
|
7
|
+
* a facade/shape-based `matches(payload)` scan when no name matches --
|
|
8
|
+
* useful when several tool names share one result shape (e.g. every
|
|
9
|
+
* "*_search" tool returning `{ results: [...] }`) or when the caller doesn't
|
|
10
|
+
* reliably know the tool name at all.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* One registered renderer. Either `render` is present directly, or `load` is
|
|
14
|
+
* -- a definition registered purely as `{ load }` is expected to resolve (via
|
|
15
|
+
* dynamic `import()`, typically) to the real `render`/`matches` pair on
|
|
16
|
+
* first use, so a host app can code-split a rarely-used or heavy renderer
|
|
17
|
+
* (e.g. one pulling in a charting library) instead of paying for it on every
|
|
18
|
+
* page that merely registers it.
|
|
19
|
+
*
|
|
20
|
+
* `matches` is only ever consulted *before* `load` resolves when it's
|
|
21
|
+
* supplied inline at registration time -- a definition that needs
|
|
22
|
+
* shape-based dispatch and also wants to lazy-load its `render` should
|
|
23
|
+
* register a lightweight synchronous `matches` up front alongside `load`;
|
|
24
|
+
* one that dispatches purely by exact tool-name key doesn't need `matches`
|
|
25
|
+
* at all, loaded or not.
|
|
26
|
+
*/
|
|
27
|
+
export interface ToolRendererDefinition {
|
|
28
|
+
/**
|
|
29
|
+
* Renders `result` (and the tool-call `args` that produced it, when
|
|
30
|
+
* available) as UI. Typed loosely as `unknown` rather than Lit's
|
|
31
|
+
* `TemplateResult` so any lit-html-renderable value works too (a plain
|
|
32
|
+
* string, a DOM node, an array of templates) -- consumers already own
|
|
33
|
+
* their own Lit import and don't need this module to add one.
|
|
34
|
+
*/
|
|
35
|
+
render?: (result: unknown, args: unknown) => unknown;
|
|
36
|
+
/** Facade/shape-based dispatch predicate -- see the module doc's dispatch order. */
|
|
37
|
+
matches?: (payload: unknown) => boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Lazy loader for a code-split renderer. Resolves to either a definition
|
|
40
|
+
* directly, or a `{ default }`-shaped module namespace object (so
|
|
41
|
+
* `load: () => import('./my-renderer.js')` works unmodified when that
|
|
42
|
+
* module's default export is itself a `ToolRendererDefinition`).
|
|
43
|
+
*/
|
|
44
|
+
load?: () => Promise<ToolRendererDefinition | {
|
|
45
|
+
default: ToolRendererDefinition;
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
48
|
+
/** A tool-name -> renderer-definition registry, as consulted by `findToolRenderer()`. */
|
|
49
|
+
export type ToolRendererRegistry = Map<string, ToolRendererDefinition>;
|
|
50
|
+
/** Registers (or overwrites) the renderer for `name` in the default registry. */
|
|
51
|
+
export declare function registerToolRenderer(name: string, def: ToolRendererDefinition): void;
|
|
52
|
+
/** The module-level default registry `registerToolRenderer()` writes to and `<lyra-tool-result-view>` reads from when no `registry` prop is set. */
|
|
53
|
+
export declare function getDefaultToolRendererRegistry(): ToolRendererRegistry;
|
|
54
|
+
/**
|
|
55
|
+
* Finds the renderer definition for `toolName`/`payload` in `registry`
|
|
56
|
+
* (the default registry when omitted), in dispatch order:
|
|
57
|
+
* 1. An exact `toolName` key match.
|
|
58
|
+
* 2. Failing that, the first entry (in registration order -- a `Map`
|
|
59
|
+
* already iterates that way) whose `matches(payload)` returns `true`.
|
|
60
|
+
* 3. `undefined` -- the caller falls back to `<lyra-json-viewer>`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function findToolRenderer(toolName: string, payload: unknown, registry?: ToolRendererRegistry): ToolRendererDefinition | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Resolves `def` to a definition guaranteed to carry a real `render` --
|
|
65
|
+
* awaiting and unwrapping `def.load()` (caching the result so a lazy
|
|
66
|
+
* definition's `load()` runs at most once no matter how many times it's
|
|
67
|
+
* dispatched to) when `def.load` is present, or returning `def` as-is
|
|
68
|
+
* otherwise. A rejected `load()` is *not* cached -- the definition stays
|
|
69
|
+
* registered, so a later resolution attempt (e.g. after a transient network
|
|
70
|
+
* failure) gets a fresh `load()` call rather than being stuck replaying one
|
|
71
|
+
* failed promise forever.
|
|
72
|
+
*/
|
|
73
|
+
export declare function loadToolRenderer(def: ToolRendererDefinition): Promise<ToolRendererDefinition>;
|
|
74
|
+
/**
|
|
75
|
+
* Test-only utility: empties the default registry and its `load()` cache so
|
|
76
|
+
* one test's `registerToolRenderer()` calls can't leak into the next. Mirrors
|
|
77
|
+
* the fact that this module (like `toaster.ts`'s per-placement region map) is
|
|
78
|
+
* deliberately singleton, module-level state -- there is no per-instance
|
|
79
|
+
* registry to construct fresh in a test's own `fixture()` call instead.
|
|
80
|
+
*/
|
|
81
|
+
export declare function clearToolRenderers(): void;
|