@aceshooting/lyra-ui 1.1.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 +12 -1
- package/custom-elements.json +21460 -8489
- 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 +12 -2
- package/dist/components/chart/chart.js +121 -14
- 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 +63 -0
- package/dist/components/chart/lite-chart.js +181 -23
- 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 +42 -5
- package/dist/components/flag/flag.js +70 -3
- 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 +89 -3
- package/dist/components/heatmap/heatmap.js +158 -29
- 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 +45 -1
- package/dist/components/select/select.js +114 -17
- package/dist/components/select/select.styles.js +26 -2
- 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 +22 -1
- package/dist/components/stat/stat.js +49 -3
- package/dist/components/stat/stat.styles.js +20 -0
- 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/widget/widget.d.ts +10 -0
- package/dist/components/widget/widget.js +24 -1
- package/dist/components/widget/widget.styles.js +9 -2
- 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 +4 -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 +3921 -32
- 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 -12
- package/dist/components/chart/lite-chart.stories.js +0 -98
- 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 -5
- package/dist/components/flag/flag.stories.js +0 -17
- 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 -22
- package/dist/components/heatmap/heatmap.stories.js +0 -154
- 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 -19
- package/dist/components/select/select.stories.js +0 -75
- 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 -8
- package/dist/components/stat/stat.stories.js +0 -64
- 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 -7
- package/dist/components/widget/widget.stories.js +0 -41
- 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,372 @@
|
|
|
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, nothing, svg } 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 { srOnly } from '../../internal/a11y.js';
|
|
12
|
+
import { styles } from './document-preview.styles.js';
|
|
13
|
+
const IDLE_TEXT_FETCH = { kind: 'idle' };
|
|
14
|
+
function classifyFormat(mimeType) {
|
|
15
|
+
const mt = mimeType.trim().toLowerCase();
|
|
16
|
+
if (mt.startsWith('text/') || mt === 'application/json')
|
|
17
|
+
return 'text';
|
|
18
|
+
if (mt.startsWith('image/'))
|
|
19
|
+
return 'image';
|
|
20
|
+
return 'generic';
|
|
21
|
+
}
|
|
22
|
+
// Mirrors the shared icon set's viewBox/stroke conventions
|
|
23
|
+
// (internal/icons.ts's chevronIcon()/closeIcon()/etc.) without adding
|
|
24
|
+
// document/download glyphs to that module -- it's off limits here -- so
|
|
25
|
+
// these one-off icons still read as part of the same visual language as the
|
|
26
|
+
// rest of the library's inline icons.
|
|
27
|
+
const ICON_VIEW_BOX = '0 0 24 24';
|
|
28
|
+
const ICON_STROKE_WIDTH = '1.75';
|
|
29
|
+
/** A generic "document" glyph for the can't-preview-this fallback. Same
|
|
30
|
+
* shape as `<lyra-attachment-chip>`'s local `fileGlyph()` -- duplicated
|
|
31
|
+
* rather than imported (these are two independently consumable components)
|
|
32
|
+
* but kept visually identical so an unpreviewable-file affordance reads the
|
|
33
|
+
* same wherever it shows up in the library. */
|
|
34
|
+
function fileGlyph() {
|
|
35
|
+
return svg `
|
|
36
|
+
<svg
|
|
37
|
+
width="1em"
|
|
38
|
+
height="1em"
|
|
39
|
+
viewBox=${ICON_VIEW_BOX}
|
|
40
|
+
fill="none"
|
|
41
|
+
stroke="currentColor"
|
|
42
|
+
stroke-width=${ICON_STROKE_WIDTH}
|
|
43
|
+
stroke-linecap="round"
|
|
44
|
+
stroke-linejoin="round"
|
|
45
|
+
aria-hidden="true"
|
|
46
|
+
focusable="false"
|
|
47
|
+
><path d="M6 2h8l6 6v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2Z"></path><polyline points="14 2 14 8 20 8"></polyline></svg>
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
/** A downward arrow into a tray -- the conventional "download" glyph. */
|
|
51
|
+
function downloadIcon() {
|
|
52
|
+
return icon(svg `
|
|
53
|
+
<path d="M12 3v12"></path>
|
|
54
|
+
<polyline points="7 11 12 16 17 11"></polyline>
|
|
55
|
+
<path d="M4 18v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"></path>
|
|
56
|
+
`);
|
|
57
|
+
}
|
|
58
|
+
function icon(paths) {
|
|
59
|
+
return svg `
|
|
60
|
+
<svg
|
|
61
|
+
width="1em"
|
|
62
|
+
height="1em"
|
|
63
|
+
viewBox=${ICON_VIEW_BOX}
|
|
64
|
+
fill="none"
|
|
65
|
+
stroke="currentColor"
|
|
66
|
+
stroke-width=${ICON_STROKE_WIDTH}
|
|
67
|
+
stroke-linecap="round"
|
|
68
|
+
stroke-linejoin="round"
|
|
69
|
+
aria-hidden="true"
|
|
70
|
+
focusable="false"
|
|
71
|
+
>${paths}</svg>
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* `<lyra-document-preview>` — a format-dispatching viewer for one document/
|
|
76
|
+
* attachment, plus the visual state machine for an async server-side
|
|
77
|
+
* conversion a host app runs in front of it.
|
|
78
|
+
*
|
|
79
|
+
* Format dispatch is intentionally minimal (see this family's scope
|
|
80
|
+
* guidance): only `text/*`/`application/json` (plain, scrollable `<pre>` —
|
|
81
|
+
* no syntax highlighting; compose `<lyra-code-block>` yourself via the
|
|
82
|
+
* `unsupported` slot for that) and `image/*` (a contained `<img>`) render
|
|
83
|
+
* inline. Everything else — PDF, office documents, video, audio, or any
|
|
84
|
+
* unrecognized MIME type — falls back to a generic "can't preview this"
|
|
85
|
+
* state: a file glyph, a short message, and (when `src` is set) a native
|
|
86
|
+
* `<a download>` link. This is a deliberate ceiling, not a gap: this
|
|
87
|
+
* component ships a dispatch *shell*, not a format registry. The
|
|
88
|
+
* `unsupported` slot is the escape hatch for every format left out of the
|
|
89
|
+
* built-in three — plug in a PDF.js viewer, an office-doc renderer, a
|
|
90
|
+
* `<lyra-code-block>`, or anything else keyed off `mime-type` yourself.
|
|
91
|
+
*
|
|
92
|
+
* `status="converting"` is a second, independent axis from format dispatch.
|
|
93
|
+
* This component does not know your backend's conversion API shape and
|
|
94
|
+
* therefore owns none of the actual polling/fetch — a host that's converting
|
|
95
|
+
* a non-natively-previewable format server-side (e.g. .docx → .pdf) polls
|
|
96
|
+
* its own backend and updates `status`/`progress`/`src` here as that
|
|
97
|
+
* proceeds. This component only *visualizes* that state: an indeterminate
|
|
98
|
+
* spinner, or a determinate one once `progress` is supplied. Once the host
|
|
99
|
+
* flips `status` to `"ready"` (typically alongside a new `src`/`mime-type`
|
|
100
|
+
* pointing at the converted artifact), normal format dispatch resumes.
|
|
101
|
+
*
|
|
102
|
+
* The one piece of async work this component *does* own is fetching a
|
|
103
|
+
* `text/*`/`application/json` `src` itself (there's no other way to get a
|
|
104
|
+
* `<pre>`'s text content from a URL) — gated behind the same generation-
|
|
105
|
+
* counter guard `<lyra-tool-result-view>`'s `resolve()` uses, so a `src`
|
|
106
|
+
* reassigned mid-fetch can't have a stale response clobber a newer one. A
|
|
107
|
+
* failure here (network error, non-2xx response) renders inline via
|
|
108
|
+
* `[part="error"]` and fires `lyra-render-error`, independently of the
|
|
109
|
+
* host-owned `status` prop — mirrors `<lyra-markdown>`'s identical stance
|
|
110
|
+
* that a *rendering* failure and a host's own state machine are different
|
|
111
|
+
* concerns.
|
|
112
|
+
*
|
|
113
|
+
* Accessibility: the `"converting"` state (no numeric `progress`) is a
|
|
114
|
+
* `role="status"` region wrapping a visually-hidden "Converting document…"
|
|
115
|
+
* string. This is a *plain* static region, not routed through
|
|
116
|
+
* `<lyra-live-region>`/`Announcer` — like `<lyra-typing-indicator>`'s
|
|
117
|
+
* identical judgement call (see that component's class doc), this only ever
|
|
118
|
+
* has one thing to announce (entering the state), not a rapidly-repeating
|
|
119
|
+
* stream of updates, so the coalescing machinery a high-frequency component
|
|
120
|
+
* needs would be pure overhead here. Once real `progress` is available, the
|
|
121
|
+
* region becomes a standard `role="progressbar"` instead, which is
|
|
122
|
+
* self-describing via `aria-valuenow` with no extra live-region wiring
|
|
123
|
+
* needed. `status="error"` renders `[part="error"]` as `role="alert"` — an
|
|
124
|
+
* assertive, one-shot failure notice, the same native-role shortcut
|
|
125
|
+
* `<lyra-live-region>`'s own `mode="assertive"` maps to, without requiring
|
|
126
|
+
* the announcer machinery here either.
|
|
127
|
+
*
|
|
128
|
+
* @customElement lyra-document-preview
|
|
129
|
+
* @slot unsupported - Escape hatch: when populated, its content renders
|
|
130
|
+
* *instead of* the generic download fallback for any `mime-type` this
|
|
131
|
+
* component doesn't natively support (i.e. whenever format dispatch would
|
|
132
|
+
* otherwise fall through to "generic"). Ignored while `mime-type` resolves
|
|
133
|
+
* to `text`/`image` dispatch, or while `status` is `"converting"`/`"error"`.
|
|
134
|
+
* @event lyra-download - `detail: { src, filename }` — fired when the
|
|
135
|
+
* generic-download fallback's link is activated. The browser download
|
|
136
|
+
* itself needs no JS (a plain `<a download>` handles it); this is purely
|
|
137
|
+
* for a host that wants to observe/log the download.
|
|
138
|
+
* @event lyra-render-error - `detail: { error }` — fired when this
|
|
139
|
+
* component's own `text/*`/`application/json` `fetch(src)` fails. Distinct
|
|
140
|
+
* from `status="error"`, which is entirely host-driven (see the class
|
|
141
|
+
* doc).
|
|
142
|
+
* @csspart base - The root container.
|
|
143
|
+
* @csspart header - The row above the body, holding `filename`. Hidden entirely when `filename` is unset.
|
|
144
|
+
* @csspart filename - The filename text.
|
|
145
|
+
* @csspart body - The wrapper around whichever content is currently showing (text/image preview, the generic fallback, the spinner, or the error message).
|
|
146
|
+
* @csspart spinner - The converting/loading indicator — indeterminate (`role="status"`) or, once numeric progress is known, a determinate `role="progressbar"`. Used both for `status="converting"` and for this component's own in-flight text fetch.
|
|
147
|
+
* @csspart error - The error message region (`role="alert"`) — used both for `status="error"` and for a failed text fetch.
|
|
148
|
+
* @csspart download-link - The `<a download>` affordance in the generic fallback. Only rendered when `src` is set.
|
|
149
|
+
*/
|
|
150
|
+
export class LyraDocumentPreview extends LyraElement {
|
|
151
|
+
constructor() {
|
|
152
|
+
super(...arguments);
|
|
153
|
+
/** URL to fetch (for `text`/`application/json`) or display (`image`, or as
|
|
154
|
+
* the generic fallback's download `href`). Optional — gracefully absent
|
|
155
|
+
* while, e.g., a conversion is still in progress. */
|
|
156
|
+
this.src = '';
|
|
157
|
+
/** Drives format dispatch — see the class doc. */
|
|
158
|
+
this.mimeType = '';
|
|
159
|
+
/** Shown in the header and used as the download link's suggested filename. */
|
|
160
|
+
this.filename = '';
|
|
161
|
+
/** Host-owned lifecycle state. `"converting"` shows the spinner regardless
|
|
162
|
+
* of `mime-type`/`src`; `"error"` shows `errorMessage` regardless of
|
|
163
|
+
* either. `"idle"`/`"ready"` both resume normal format dispatch — this
|
|
164
|
+
* component doesn't require a host that has no conversion step to ever
|
|
165
|
+
* set `"ready"` explicitly. */
|
|
166
|
+
this.status = 'idle';
|
|
167
|
+
/** Shown (via `[part="error"]`) while `status="error"`. */
|
|
168
|
+
this.errorMessage = '';
|
|
169
|
+
/** A CSS length (e.g. `"24rem"`); once set, `[part="body"]` scrolls
|
|
170
|
+
* internally past this height instead of growing the page — same
|
|
171
|
+
* contract as `<lyra-json-viewer>`'s identically-named prop. */
|
|
172
|
+
this.maxHeight = '';
|
|
173
|
+
this.hasUnsupportedSlot = false;
|
|
174
|
+
this.textFetch = IDLE_TEXT_FETCH;
|
|
175
|
+
// Bumped on every fetchText() call so a stale in-flight fetch (superseded
|
|
176
|
+
// by a newer src/mime-type/status before it settles) can detect it's no
|
|
177
|
+
// longer current and skip writing its result over a more recent one --
|
|
178
|
+
// same guard <lyra-tool-result-view>'s resolve() uses.
|
|
179
|
+
this.fetchGeneration = 0;
|
|
180
|
+
this.onUnsupportedSlotChange = (e) => {
|
|
181
|
+
this.hasUnsupportedSlot = e.target.assignedElements({ flatten: true }).length > 0;
|
|
182
|
+
};
|
|
183
|
+
this.onDownloadClick = () => {
|
|
184
|
+
this.emit('lyra-download', { src: this.src, filename: this.filename });
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
static { this.styles = [LyraElement.styles, styles, srOnly]; }
|
|
188
|
+
willUpdate(changed) {
|
|
189
|
+
if (!this.hasUpdated) {
|
|
190
|
+
this.hasUnsupportedSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'unsupported');
|
|
191
|
+
}
|
|
192
|
+
const shouldFetchText = classifyFormat(this.mimeType) === 'text' &&
|
|
193
|
+
this.src !== '' &&
|
|
194
|
+
this.status !== 'converting' &&
|
|
195
|
+
this.status !== 'error';
|
|
196
|
+
if (shouldFetchText) {
|
|
197
|
+
// Refetch when the target itself changed, or when this just became
|
|
198
|
+
// fetchable (e.g. a "converting" -> "ready" transition) and nothing
|
|
199
|
+
// has been fetched yet -- but not on every unrelated property change.
|
|
200
|
+
if (!this.hasUpdated ||
|
|
201
|
+
changed.has('src') ||
|
|
202
|
+
changed.has('mimeType') ||
|
|
203
|
+
(changed.has('status') && this.textFetch.kind === 'idle')) {
|
|
204
|
+
void this.fetchText(this.src);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (this.textFetch.kind !== 'idle') {
|
|
208
|
+
// No longer applicable (format changed away from text, src cleared,
|
|
209
|
+
// or status moved to converting/error) -- invalidate any in-flight
|
|
210
|
+
// fetch and drop the stale result so a later re-entry starts clean.
|
|
211
|
+
this.fetchGeneration++;
|
|
212
|
+
this.textFetch = IDLE_TEXT_FETCH;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
async fetchText(url) {
|
|
216
|
+
const generation = ++this.fetchGeneration;
|
|
217
|
+
this.textFetch = { kind: 'loading' };
|
|
218
|
+
try {
|
|
219
|
+
const response = await fetch(url);
|
|
220
|
+
if (!response.ok)
|
|
221
|
+
throw new Error(`${response.status} ${response.statusText}`);
|
|
222
|
+
const text = await response.text();
|
|
223
|
+
if (generation !== this.fetchGeneration)
|
|
224
|
+
return;
|
|
225
|
+
this.textFetch = { kind: 'loaded', text };
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
if (generation !== this.fetchGeneration)
|
|
229
|
+
return;
|
|
230
|
+
const message = error instanceof Error ? error.message : 'Failed to load document.';
|
|
231
|
+
this.textFetch = { kind: 'error', message };
|
|
232
|
+
this.emit('lyra-render-error', { error });
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/** Renders `[part="spinner"]` -- indeterminate (`role="status"` + a
|
|
236
|
+
* visually-hidden label, per the class doc's accessibility note) when
|
|
237
|
+
* `progressValue` is absent, or a `role="progressbar"` once it's a finite
|
|
238
|
+
* 0-100 number. Shared by the host-driven `"converting"` state and this
|
|
239
|
+
* component's own in-flight text fetch (which never has a numeric
|
|
240
|
+
* progress of its own to report). */
|
|
241
|
+
renderSpinner(label, progressValue) {
|
|
242
|
+
const hasProgress = progressValue != null && Number.isFinite(progressValue);
|
|
243
|
+
if (hasProgress) {
|
|
244
|
+
const clamped = Math.min(100, Math.max(0, progressValue));
|
|
245
|
+
const rounded = Math.round(clamped);
|
|
246
|
+
return html `
|
|
247
|
+
<div
|
|
248
|
+
part="spinner"
|
|
249
|
+
role="progressbar"
|
|
250
|
+
aria-valuenow=${rounded}
|
|
251
|
+
aria-valuemin="0"
|
|
252
|
+
aria-valuemax="100"
|
|
253
|
+
aria-label=${label}
|
|
254
|
+
>
|
|
255
|
+
<span class="ring determinate" style=${`--lyra-document-preview-progress:${clamped}`}></span>
|
|
256
|
+
<span class="spinner-text">${rounded}%</span>
|
|
257
|
+
</div>
|
|
258
|
+
`;
|
|
259
|
+
}
|
|
260
|
+
return html `
|
|
261
|
+
<div part="spinner" role="status">
|
|
262
|
+
<span class="ring" aria-hidden="true"></span>
|
|
263
|
+
<span class="sr-only">${label}</span>
|
|
264
|
+
</div>
|
|
265
|
+
`;
|
|
266
|
+
}
|
|
267
|
+
renderError(message) {
|
|
268
|
+
return html `<div part="error" role="alert">${message || 'Something went wrong.'}</div>`;
|
|
269
|
+
}
|
|
270
|
+
renderTextPreview() {
|
|
271
|
+
if (this.src === '')
|
|
272
|
+
return html `<pre class="text"></pre>`;
|
|
273
|
+
switch (this.textFetch.kind) {
|
|
274
|
+
case 'loaded':
|
|
275
|
+
return html `<pre class="text">${this.textFetch.text}</pre>`;
|
|
276
|
+
case 'error':
|
|
277
|
+
return this.renderError(this.textFetch.message);
|
|
278
|
+
case 'loading':
|
|
279
|
+
case 'idle':
|
|
280
|
+
default:
|
|
281
|
+
return this.renderSpinner('Loading document…');
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
renderImagePreview() {
|
|
285
|
+
if (this.src === '')
|
|
286
|
+
return html `<p class="empty-note">No image to display.</p>`;
|
|
287
|
+
return html `<img src=${this.src} alt=${this.filename || 'Document preview'} />`;
|
|
288
|
+
}
|
|
289
|
+
renderDownloadFallback() {
|
|
290
|
+
const label = this.filename || 'this file';
|
|
291
|
+
return html `
|
|
292
|
+
<div class="fallback">
|
|
293
|
+
<span class="fallback-icon" aria-hidden="true">${fileGlyph()}</span>
|
|
294
|
+
<p class="fallback-text">Preview not available for ${label}.</p>
|
|
295
|
+
${this.src !== ''
|
|
296
|
+
? html `
|
|
297
|
+
<a
|
|
298
|
+
part="download-link"
|
|
299
|
+
href=${this.src}
|
|
300
|
+
download=${this.filename || ''}
|
|
301
|
+
@click=${this.onDownloadClick}
|
|
302
|
+
>
|
|
303
|
+
${downloadIcon()}<span>Download</span>
|
|
304
|
+
</a>
|
|
305
|
+
`
|
|
306
|
+
: nothing}
|
|
307
|
+
</div>
|
|
308
|
+
`;
|
|
309
|
+
}
|
|
310
|
+
/** The `<slot>` element renders unconditionally (not just while
|
|
311
|
+
* `hasUnsupportedSlot`) so a slot-assignment change is always observable
|
|
312
|
+
* via `slotchange` -- same reasoning as `<lyra-chat-message>`'s
|
|
313
|
+
* always-rendered optional slots. */
|
|
314
|
+
renderGenericFallback() {
|
|
315
|
+
return html `
|
|
316
|
+
<slot name="unsupported" @slotchange=${this.onUnsupportedSlotChange}></slot>
|
|
317
|
+
${this.hasUnsupportedSlot ? nothing : this.renderDownloadFallback()}
|
|
318
|
+
`;
|
|
319
|
+
}
|
|
320
|
+
renderBody() {
|
|
321
|
+
if (this.status === 'converting')
|
|
322
|
+
return this.renderSpinner('Converting document…', this.progress);
|
|
323
|
+
if (this.status === 'error')
|
|
324
|
+
return this.renderError(this.errorMessage);
|
|
325
|
+
switch (classifyFormat(this.mimeType)) {
|
|
326
|
+
case 'text':
|
|
327
|
+
return this.renderTextPreview();
|
|
328
|
+
case 'image':
|
|
329
|
+
return this.renderImagePreview();
|
|
330
|
+
default:
|
|
331
|
+
return this.renderGenericFallback();
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
render() {
|
|
335
|
+
return html `
|
|
336
|
+
<div part="base" style=${this.maxHeight ? `--lyra-document-preview-max-height:${this.maxHeight}` : nothing}>
|
|
337
|
+
<div part="header" ?hidden=${!this.filename}>
|
|
338
|
+
<span part="filename" title=${this.filename}>${this.filename}</span>
|
|
339
|
+
</div>
|
|
340
|
+
<div part="body">${this.renderBody()}</div>
|
|
341
|
+
</div>
|
|
342
|
+
`;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
__decorate([
|
|
346
|
+
property()
|
|
347
|
+
], LyraDocumentPreview.prototype, "src", void 0);
|
|
348
|
+
__decorate([
|
|
349
|
+
property({ attribute: 'mime-type' })
|
|
350
|
+
], LyraDocumentPreview.prototype, "mimeType", void 0);
|
|
351
|
+
__decorate([
|
|
352
|
+
property()
|
|
353
|
+
], LyraDocumentPreview.prototype, "filename", void 0);
|
|
354
|
+
__decorate([
|
|
355
|
+
property({ reflect: true })
|
|
356
|
+
], LyraDocumentPreview.prototype, "status", void 0);
|
|
357
|
+
__decorate([
|
|
358
|
+
property({ type: Number })
|
|
359
|
+
], LyraDocumentPreview.prototype, "progress", void 0);
|
|
360
|
+
__decorate([
|
|
361
|
+
property({ attribute: 'error-message' })
|
|
362
|
+
], LyraDocumentPreview.prototype, "errorMessage", void 0);
|
|
363
|
+
__decorate([
|
|
364
|
+
property({ attribute: 'max-height' })
|
|
365
|
+
], LyraDocumentPreview.prototype, "maxHeight", void 0);
|
|
366
|
+
__decorate([
|
|
367
|
+
state()
|
|
368
|
+
], LyraDocumentPreview.prototype, "hasUnsupportedSlot", void 0);
|
|
369
|
+
__decorate([
|
|
370
|
+
state()
|
|
371
|
+
], LyraDocumentPreview.prototype, "textFetch", void 0);
|
|
372
|
+
defineElement('document-preview', LyraDocumentPreview);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const styles: import("lit").CSSResult;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
export const styles = css `
|
|
3
|
+
:host {
|
|
4
|
+
display: block;
|
|
5
|
+
/* Consumer-tunable scroll cap on [part='body'] -- 'none' means the
|
|
6
|
+
preview grows with its content until a caller opts into an internal
|
|
7
|
+
scrollbar, same contract as lyra-json-viewer's identical
|
|
8
|
+
--lyra-json-viewer-max-height. */
|
|
9
|
+
--lyra-document-preview-max-height: none;
|
|
10
|
+
/* No shared --wa-*/--lyra-* monospace token exists to resolve through
|
|
11
|
+
(same gap lyra-json-viewer's own --lyra-json-viewer-font documents) --
|
|
12
|
+
contained here so a host page can retheme it. */
|
|
13
|
+
--lyra-document-preview-font: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
[part='base'] {
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
border: 1px solid var(--lyra-color-border);
|
|
21
|
+
border-radius: var(--lyra-radius);
|
|
22
|
+
background: var(--lyra-color-surface);
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
[part='header'] {
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
gap: var(--lyra-space-s);
|
|
30
|
+
padding: var(--lyra-space-s) var(--lyra-space-m);
|
|
31
|
+
border-block-end: 1px solid var(--lyra-color-border);
|
|
32
|
+
background: var(--lyra-color-surface);
|
|
33
|
+
}
|
|
34
|
+
[part='header'][hidden] {
|
|
35
|
+
display: none;
|
|
36
|
+
}
|
|
37
|
+
[part='filename'] {
|
|
38
|
+
overflow: hidden;
|
|
39
|
+
text-overflow: ellipsis;
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
font-weight: 600;
|
|
42
|
+
font-size: 0.875rem;
|
|
43
|
+
color: var(--lyra-color-text);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
[part='body'] {
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: center;
|
|
51
|
+
min-block-size: 10rem;
|
|
52
|
+
max-block-size: var(--lyra-document-preview-max-height);
|
|
53
|
+
box-sizing: border-box;
|
|
54
|
+
overflow: auto;
|
|
55
|
+
flex: 1 1 auto;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* -- text/*, application/json: plain, scrollable <pre> -----------------
|
|
59
|
+
No syntax highlighting -- see the class doc for why that's intentionally
|
|
60
|
+
out of scope here. */
|
|
61
|
+
pre.text {
|
|
62
|
+
align-self: stretch;
|
|
63
|
+
box-sizing: border-box;
|
|
64
|
+
margin: 0;
|
|
65
|
+
padding: var(--lyra-space-m);
|
|
66
|
+
font-family: var(--lyra-document-preview-font);
|
|
67
|
+
font-size: 0.8125rem;
|
|
68
|
+
line-height: 1.6;
|
|
69
|
+
white-space: pre;
|
|
70
|
+
overflow: auto;
|
|
71
|
+
color: var(--lyra-color-text);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* -- image/* -------------------------------------------------------- */
|
|
75
|
+
[part='body'] img {
|
|
76
|
+
display: block;
|
|
77
|
+
max-inline-size: 100%;
|
|
78
|
+
max-block-size: 100%;
|
|
79
|
+
object-fit: contain;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.empty-note {
|
|
83
|
+
margin: 0;
|
|
84
|
+
padding: var(--lyra-space-m);
|
|
85
|
+
color: var(--lyra-color-text-quiet);
|
|
86
|
+
font-size: 0.875rem;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* -- generic download fallback ------------------------------------- */
|
|
90
|
+
.fallback {
|
|
91
|
+
display: flex;
|
|
92
|
+
flex-direction: column;
|
|
93
|
+
align-items: center;
|
|
94
|
+
gap: var(--lyra-space-s);
|
|
95
|
+
padding: var(--lyra-space-l);
|
|
96
|
+
text-align: center;
|
|
97
|
+
}
|
|
98
|
+
.fallback-icon {
|
|
99
|
+
display: inline-flex;
|
|
100
|
+
font-size: 2rem;
|
|
101
|
+
color: var(--lyra-color-text-quiet);
|
|
102
|
+
}
|
|
103
|
+
.fallback-icon svg {
|
|
104
|
+
display: block;
|
|
105
|
+
}
|
|
106
|
+
.fallback-text {
|
|
107
|
+
margin: 0;
|
|
108
|
+
color: var(--lyra-color-text-quiet);
|
|
109
|
+
font-size: 0.875rem;
|
|
110
|
+
}
|
|
111
|
+
[part='download-link'] {
|
|
112
|
+
display: inline-flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
gap: var(--lyra-space-xs);
|
|
115
|
+
padding: var(--lyra-space-xs) var(--lyra-space-m);
|
|
116
|
+
border-radius: var(--lyra-radius);
|
|
117
|
+
background: var(--lyra-color-brand);
|
|
118
|
+
color: var(--lyra-color-on-brand);
|
|
119
|
+
font: inherit;
|
|
120
|
+
font-weight: 600;
|
|
121
|
+
font-size: 0.8125rem;
|
|
122
|
+
text-decoration: none;
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
transition: background-color var(--lyra-transition-fast);
|
|
125
|
+
}
|
|
126
|
+
[part='download-link']:hover {
|
|
127
|
+
background: color-mix(in srgb, var(--lyra-color-brand) 85%, black);
|
|
128
|
+
}
|
|
129
|
+
[part='download-link']:focus-visible {
|
|
130
|
+
outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
|
|
131
|
+
outline-offset: var(--lyra-focus-ring-offset);
|
|
132
|
+
}
|
|
133
|
+
[part='download-link'] svg {
|
|
134
|
+
display: block;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* -- spinner (converting / loading text) ----------------------------- */
|
|
138
|
+
[part='spinner'] {
|
|
139
|
+
display: flex;
|
|
140
|
+
flex-direction: column;
|
|
141
|
+
align-items: center;
|
|
142
|
+
gap: var(--lyra-space-s);
|
|
143
|
+
padding: var(--lyra-space-l);
|
|
144
|
+
}
|
|
145
|
+
.ring {
|
|
146
|
+
display: inline-block;
|
|
147
|
+
inline-size: 2rem;
|
|
148
|
+
block-size: 2rem;
|
|
149
|
+
border-radius: 50%;
|
|
150
|
+
border: 3px solid var(--lyra-color-border);
|
|
151
|
+
border-block-start-color: var(--lyra-color-brand);
|
|
152
|
+
animation: lyra-document-preview-spin 0.8s linear infinite;
|
|
153
|
+
}
|
|
154
|
+
/* Determinate progress reuses the same ring shape but holds a fixed
|
|
155
|
+
rotation instead of spinning -- conic-gradient renders the actual fill,
|
|
156
|
+
so the ring visually communicates a real fraction rather than motion. */
|
|
157
|
+
.ring.determinate {
|
|
158
|
+
animation: none;
|
|
159
|
+
border-color: transparent;
|
|
160
|
+
background: conic-gradient(
|
|
161
|
+
var(--lyra-color-brand) calc(var(--lyra-document-preview-progress, 0) * 1%),
|
|
162
|
+
var(--lyra-color-border) 0
|
|
163
|
+
);
|
|
164
|
+
-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
|
|
165
|
+
mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
|
|
166
|
+
}
|
|
167
|
+
.spinner-text {
|
|
168
|
+
color: var(--lyra-color-text-quiet);
|
|
169
|
+
font-size: 0.8125rem;
|
|
170
|
+
font-variant-numeric: tabular-nums;
|
|
171
|
+
}
|
|
172
|
+
@keyframes lyra-document-preview-spin {
|
|
173
|
+
to {
|
|
174
|
+
transform: rotate(360deg);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
@media (prefers-reduced-motion: reduce) {
|
|
178
|
+
.ring {
|
|
179
|
+
animation: none !important;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* -- error ------------------------------------------------------------ */
|
|
184
|
+
[part='error'] {
|
|
185
|
+
margin: 0;
|
|
186
|
+
padding: var(--lyra-space-l);
|
|
187
|
+
color: var(--lyra-color-danger);
|
|
188
|
+
font-size: 0.875rem;
|
|
189
|
+
text-align: center;
|
|
190
|
+
}
|
|
191
|
+
`;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// reliably trigger spreadsheet formula evaluation) — guarding it forces text rendering on
|
|
3
3
|
// ordinary negative numbers/currency. Per OWASP CSV-injection guidance, '-' is intentionally
|
|
4
4
|
// excluded here.
|
|
5
|
-
const UNSAFE_LEADING = /^[=+@\t\r]/;
|
|
5
|
+
const UNSAFE_LEADING = /^[=+@\t\r\n]/;
|
|
6
6
|
const NEEDS_QUOTING = /[",\r\n]/;
|
|
7
7
|
/** Escapes a CSV field: quotes as needed, guards against formula injection. */
|
|
8
8
|
export function escapeCsvField(value) {
|
|
@@ -83,7 +83,9 @@ export class LyraExportButton extends LyraElement {
|
|
|
83
83
|
disconnectedCallback() {
|
|
84
84
|
super.disconnectedCallback();
|
|
85
85
|
this.cleanup?.();
|
|
86
|
+
this.cleanup = undefined;
|
|
86
87
|
document.removeEventListener('pointerdown', this.onDocPointer);
|
|
88
|
+
this.open = false;
|
|
87
89
|
}
|
|
88
90
|
openMenu() {
|
|
89
91
|
if (this.open)
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { type TemplateResult, type PropertyValues } from 'lit';
|
|
2
2
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
3
3
|
import '../skeleton/skeleton.js';
|
|
4
|
-
type
|
|
4
|
+
type FlagVariant = 'compact' | 'standard' | 'detailed';
|
|
5
|
+
type FlagUrlResolver = (code: string, options?: {
|
|
6
|
+
variant?: FlagVariant;
|
|
7
|
+
}) => Promise<string | undefined>;
|
|
5
8
|
/**
|
|
6
9
|
* Resolves the optional peer dependency `@aceshooting/lyra-flags`'s `flagUrl`
|
|
7
10
|
* via the given importer (a real dynamic import by default). Uncached and
|
|
@@ -31,10 +34,19 @@ export declare function loadFlagUrl(importFlags?: () => Promise<{
|
|
|
31
34
|
* `src` instead to skip the peer-package round trip (and its loading-skeleton
|
|
32
35
|
* flash) entirely.
|
|
33
36
|
*
|
|
37
|
+
* The ~65 flags whose design includes a detailed coat of arms/seal/emblem (e.g. `es`, `pt`) ship
|
|
38
|
+
* three fidelity tiers; choose one with `variant`: `"compact"` (a tiny WebP raster for icon-scale
|
|
39
|
+
* use — menu items, language selectors, dense lists), the default `"standard"` (icon-optimized
|
|
40
|
+
* vector for card/row sizes), or `"detailed"` (the pristine full-detail vector for hero-scale
|
|
41
|
+
* display). A no-op for every other code — all tiers resolve to the same file. See `variant`'s own
|
|
42
|
+
* doc.
|
|
43
|
+
*
|
|
34
44
|
* @customElement lyra-flag
|
|
35
45
|
* @example <lyra-flag country="fr"></lyra-flag>
|
|
36
46
|
* @example <lyra-flag language="en" label="English"></lyra-flag>
|
|
37
47
|
* @example <lyra-flag src=${frUrl} label="French"></lyra-flag>
|
|
48
|
+
* @example <lyra-flag country="es" variant="compact"></lyra-flag>
|
|
49
|
+
* @example <lyra-flag country="es" variant="detailed"></lyra-flag>
|
|
38
50
|
* @csspart image - The underlying <img>.
|
|
39
51
|
*/
|
|
40
52
|
export declare class LyraFlag extends LyraElement {
|
|
@@ -53,14 +65,39 @@ export declare class LyraFlag extends LyraElement {
|
|
|
53
65
|
*/
|
|
54
66
|
src?: string;
|
|
55
67
|
/**
|
|
56
|
-
* Accessible label / `alt` text. Defaults to
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
68
|
+
* Accessible label / `alt` text. Defaults to a localized, human-readable
|
|
69
|
+
* region name derived from the *resolved country code* via
|
|
70
|
+
* `Intl.DisplayNames` (e.g. `"United Kingdom"`) — for a `language`-only
|
|
71
|
+
* element (e.g. `language="en"`) that's the mapped country's display name,
|
|
72
|
+
* not the language tag itself. Falls back to the bare uppercase code if
|
|
73
|
+
* `Intl.DisplayNames` can't resolve it. Has no default when only `src` is
|
|
74
|
+
* given (no country/language to derive one from).
|
|
60
75
|
*/
|
|
61
76
|
label?: string;
|
|
62
77
|
/** Render as a circular flag. */
|
|
63
78
|
round: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Which fidelity tier to load, for the ~65 `country`/`language` codes whose source art embeds a
|
|
81
|
+
* coat of arms/seal/emblem (for every other code all tiers are the same file, so this is a safe
|
|
82
|
+
* no-op):
|
|
83
|
+
* - `"compact"` — a tiny WebP raster for icon-scale use (menu items, language selectors, dense
|
|
84
|
+
* lists; ~12–28px), where the emblem detail is invisible anyway.
|
|
85
|
+
* - `"standard"` (default) — the icon-optimized vector, for card/row sizes (~28–96px).
|
|
86
|
+
* - `"detailed"` — the pristine, full-detail vector, for rendering larger than icon scale (e.g.
|
|
87
|
+
* a hero display) where the extra illustrative detail is actually visible.
|
|
88
|
+
*
|
|
89
|
+
* Has no effect when `src` is set — a pre-resolved URL is used as-is regardless. Takes precedence
|
|
90
|
+
* over the deprecated `detailed` boolean.
|
|
91
|
+
*/
|
|
92
|
+
variant?: FlagVariant;
|
|
93
|
+
/**
|
|
94
|
+
* @deprecated Use `variant="detailed"` instead. Kept as an alias for one minor cycle; when
|
|
95
|
+
* `variant` is unset, `detailed` still maps to the detailed tier. Removed in the next major.
|
|
96
|
+
*/
|
|
97
|
+
detailed: boolean;
|
|
98
|
+
/** The effective tier to request: an explicit `variant` wins; otherwise the deprecated
|
|
99
|
+
* `detailed` boolean is honored; otherwise `"standard"`. */
|
|
100
|
+
private get effectiveVariant();
|
|
64
101
|
private resolvedSrc?;
|
|
65
102
|
/** True while the lazy-loaded `@aceshooting/lyra-flags` peer resolver is in flight. */
|
|
66
103
|
private loading;
|