@aceshooting/lyra-ui 23.0.0 → 24.1.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/CHANGELOG.md +16 -39
- package/README.md +72 -35
- package/custom-elements.json +1 -1
- package/design-tokens.json +1 -1
- package/dist/cli/lyra-rename-ledger.mjs +1 -1
- package/dist/cli/migration-contract.json +1 -1
- package/dist/cli/migration-contract.mjs +1 -1
- package/dist/cli/migration-renames.mjs +2 -2
- package/dist/cli/migration-transforms.mjs +2 -2
- package/dist/components/agent-tools/approval-queue/approval-queue.class.d.ts +1 -4
- package/dist/components/agent-tools/approval-queue/approval-queue.class.js +1 -3
- package/dist/components/agent-tools/compare-panel/compare-panel.class.d.ts +1 -4
- package/dist/components/agent-tools/compare-panel/compare-panel.class.js +1 -1
- package/dist/components/agent-tools/confirm-bar/confirm-bar.class.d.ts +1 -7
- package/dist/components/agent-tools/confirm-bar/confirm-bar.class.js +2 -2
- package/dist/components/agent-tools/context-inspector/context-inspector.class.d.ts +1 -1
- package/dist/components/agent-tools/evaluation-run/evaluation-run.class.d.ts +2 -5
- package/dist/components/agent-tools/evaluation-run/evaluation-run.class.js +1 -3
- package/dist/components/agent-tools/terminal/terminal.class.d.ts +1 -4
- package/dist/components/agent-tools/terminal/terminal.class.js +2 -2
- package/dist/components/agent-tools/tool-approval-dialog/tool-approval-dialog.class.d.ts +1 -7
- package/dist/components/agent-tools/tool-approval-dialog/tool-approval-dialog.class.js +1 -1
- package/dist/components/agent-tools/tool-timeline/tool-timeline.class.d.ts +1 -4
- package/dist/components/agent-tools/tool-timeline/tool-timeline.class.js +1 -3
- package/dist/components/charts/chart/lite-chart-axis-layout.d.ts +13 -0
- package/dist/components/charts/chart/lite-chart-axis-layout.js +1 -0
- package/dist/components/charts/chart/lite-chart.class.d.ts +1 -11
- package/dist/components/charts/chart/lite-chart.class.js +4 -4
- package/dist/components/conversation/agent-workspace/agent-workspace.class.d.ts +13 -3
- package/dist/components/conversation/agent-workspace/agent-workspace.class.js +1 -2
- package/dist/components/conversation/chat-message/chat-message.class.d.ts +3 -9
- package/dist/components/conversation/chat-message/chat-message.class.js +1 -1
- package/dist/components/conversation/code-block/code-block-base.class.js +1 -1
- package/dist/components/conversation/code-block/code-block-core.class.d.ts +6 -8
- package/dist/components/conversation/code-block/code-block-shared.d.ts +1 -4
- package/dist/components/conversation/code-block/code-block.class.d.ts +4 -6
- package/dist/components/conversation/markdown/markdown-base.class.d.ts +1 -3
- package/dist/components/conversation/markdown/markdown-base.class.js +1 -1
- package/dist/components/conversation/markdown/markdown-core.class.d.ts +1 -4
- package/dist/components/conversation/markdown/markdown.class.d.ts +1 -4
- package/dist/components/conversation/message-actions/message-actions.class.d.ts +1 -4
- package/dist/components/conversation/message-actions/message-actions.class.js +1 -1
- package/dist/components/conversation/message-feedback/message-feedback.class.d.ts +1 -4
- package/dist/components/conversation/message-feedback/message-feedback.class.js +2 -2
- package/dist/components/conversation/message-parts/message-parts.class.d.ts +2 -5
- package/dist/components/conversation/message-parts/message-parts.class.js +3 -3
- package/dist/components/conversation/streaming-text/streaming-text-base.class.d.ts +1 -1
- package/dist/components/conversation/streaming-text/streaming-text-core.class.d.ts +2 -0
- package/dist/components/conversation/streaming-text/streaming-text-core.class.js +0 -1
- package/dist/components/conversation/streaming-text/streaming-text.class.d.ts +2 -0
- package/dist/components/conversation/streaming-text/streaming-text.class.js +0 -1
- package/dist/components/conversation/thread-list/thread-list.class.d.ts +6 -17
- package/dist/components/conversation/thread-list/thread-list.class.js +6 -6
- package/dist/components/data/context-meter/context-meter.class.d.ts +1 -6
- package/dist/components/data/context-meter/context-meter.class.js +1 -1
- package/dist/components/data/data-grid/data-grid.class.d.ts +0 -1
- package/dist/components/data/data-grid/data-grid.class.js +2 -2
- package/dist/components/data/document-library/document-library.class.d.ts +6 -13
- package/dist/components/data/document-library/document-library.class.js +1 -2
- package/dist/components/data/heatmap/heatmap-grid-navigation.d.ts +7 -0
- package/dist/components/data/heatmap/heatmap-grid-navigation.js +1 -0
- package/dist/components/data/heatmap/heatmap.class.d.ts +3 -23
- package/dist/components/data/heatmap/heatmap.class.js +2 -2
- package/dist/components/data/sequence-strip/sequence-strip.class.d.ts +3 -9
- package/dist/components/data/sequence-strip/sequence-strip.class.js +3 -3
- package/dist/components/data/table/table.class.d.ts +5 -14
- package/dist/components/data/table/table.class.js +6 -6
- package/dist/components/forms/button/button.class.d.ts +2 -2
- package/dist/components/forms/button/button.class.js +9 -9
- package/dist/components/forms/combobox/combobox.class.d.ts +1 -4
- package/dist/components/forms/combobox/combobox.class.js +2 -2
- package/dist/components/forms/input/time-input.class.d.ts +1 -1
- package/dist/components/forms/input/time-input.class.js +1 -1
- package/dist/components/forms/select/select.class.d.ts +1 -2
- package/dist/components/forms/swatch-picker/swatch-picker.class.d.ts +3 -1
- package/dist/components/forms/swatch-picker/swatch-picker.class.js +1 -1
- package/dist/components/layout/app-rail/app-rail-item.class.d.ts +3 -6
- package/dist/components/layout/app-rail/app-rail-item.class.js +1 -1
- package/dist/components/layout/app-rail/app-rail.class.d.ts +2 -4
- package/dist/components/layout/app-rail/app-rail.class.js +1 -1
- package/dist/components/layout/app-rail-group/app-rail-group.class.d.ts +2 -6
- package/dist/components/layout/app-rail-group/app-rail-group.class.js +1 -1
- package/dist/components/layout/carousel/carousel.class.d.ts +1 -4
- package/dist/components/layout/carousel/carousel.class.js +2 -2
- package/dist/components/layout/command-palette/command-palette.class.js +1 -1
- package/dist/components/layout/details/details.class.d.ts +2 -4
- package/dist/components/layout/details/details.class.js +1 -1
- package/dist/components/layout/dock-panel/dock-panel.class.d.ts +3 -7
- package/dist/components/layout/dock-panel/dock-panel.class.js +1 -1
- package/dist/components/layout/menu/menu.class.js +1 -1
- package/dist/components/layout/multi-split/multi-split.class.d.ts +2 -4
- package/dist/components/layout/multi-split/multi-split.class.js +1 -1
- package/dist/components/layout/navigation-menu-item/navigation-menu-item.class.d.ts +2 -4
- package/dist/components/layout/navigation-menu-item/navigation-menu-item.class.js +1 -1
- package/dist/components/layout/reorder-list/reorder-item.class.d.ts +1 -4
- package/dist/components/layout/reorder-list/reorder-item.class.js +2 -2
- package/dist/components/media/attachment-trigger/attachment-trigger.class.d.ts +5 -9
- package/dist/components/media/attachment-trigger/attachment-trigger.class.js +5 -5
- package/dist/components/media/av-player/av-player.class.js +3 -3
- package/dist/components/media/file-input/file-input.class.d.ts +3 -6
- package/dist/components/media/file-input/file-input.class.js +3 -3
- package/dist/components/media/lightbox/lightbox.class.d.ts +11 -20
- package/dist/components/media/lightbox/lightbox.class.js +1 -1
- package/dist/components/media/map/map-data-layers.d.ts +20 -0
- package/dist/components/media/map/map-data-layers.js +1 -0
- package/dist/components/media/map/map.class.js +3 -3
- package/dist/components/media/media-time.d.ts +2 -0
- package/dist/components/media/media-time.js +1 -0
- package/dist/components/media/video/video.class.js +5 -5
- package/dist/components/media/video-playlist/video-playlist.class.js +2 -2
- package/dist/components/overlays/callout/callout.class.d.ts +2 -5
- package/dist/components/overlays/callout/callout.class.js +2 -2
- package/dist/components/overlays/dialog/dialog.class.d.ts +4 -7
- package/dist/components/overlays/dialog/dialog.class.js +2 -2
- package/dist/components/overlays/overlay/dropdown.class.d.ts +5 -10
- package/dist/components/overlays/overlay/dropdown.class.js +2 -2
- package/dist/components/overlays/overlay/popover.class.d.ts +2 -3
- package/dist/components/overlays/popup/popup.class.js +1 -1
- package/dist/components/overlays/progress/progress-bar.class.d.ts +1 -4
- package/dist/components/overlays/progress/progress-bar.class.js +2 -2
- package/dist/components/overlays/progress/progress-ring.class.d.ts +1 -4
- package/dist/components/overlays/progress/progress-ring.class.js +2 -2
- package/dist/components/overlays/progress/progress-shared.d.ts +3 -3
- package/dist/components/overlays/progress/progress-shared.js +1 -1
- package/dist/components/overlays/toast/toast-item.class.js +1 -1
- package/dist/components/retrieval/graph/graph.class.d.ts +5 -10
- package/dist/components/retrieval/graph/graph.class.js +1 -1
- package/dist/components/retrieval/knowledge-base/knowledge-base.class.d.ts +7 -14
- package/dist/components/retrieval/knowledge-base/knowledge-base.class.js +2 -3
- package/dist/components/retrieval/knowledge-graph-explorer/knowledge-graph-explorer.class.d.ts +2 -8
- package/dist/components/retrieval/memory-panel/memory-panel.class.js +0 -4
- package/dist/components/retrieval/rag-answer/rag-answer.class.js +1 -1
- package/dist/components/utility/export-button/export-button.class.d.ts +6 -10
- package/dist/components/utility/export-button/export-button.class.js +1 -1
- package/dist/components/utility/mention-popover/mention-popover.class.js +1 -1
- package/dist/components/viewers/geojson-view/geojson-view.class.d.ts +1 -1
- package/dist/components/viewers/highlight-layer/highlight-layer-timing.js +1 -1
- package/dist/components/viewers/pdf-viewer/pdf-viewer.class.js +4 -4
- package/dist/events.d.ts +17 -78
- package/dist/framework-types.d.ts +1 -1
- package/dist/internal/catalog-picker.js +1 -1
- package/dist/internal/css-motion-time.d.ts +7 -0
- package/dist/internal/css-motion-time.js +1 -0
- package/dist/internal/data-state-renderer.d.ts +1 -3
- package/dist/internal/data-state-renderer.js +1 -1
- package/dist/internal/localization-runtime.d.ts +2 -0
- package/dist/internal/localization-runtime.js +1 -1
- package/dist/internal/lyra-element.js +2 -2
- package/dist/internal/package-metadata.d.ts +1 -1
- package/dist/internal/package-metadata.js +1 -1
- package/dist/looks/data.css +1 -1
- package/dist/looks/terminal.css +1 -1
- package/dist/lyra.d.ts +1 -592
- package/dist/lyra.js +1 -1
- package/dist/testing/event-factory.d.ts +2 -2
- package/dist/testing/interaction-drivers.d.ts +5 -3
- package/dist/testing/lyra-tag-event-map.js +1 -1
- package/dist/theme/looks/data.d.ts +1 -1
- package/dist/theme/looks/data.js +1 -1
- package/dist/theme/looks/terminal.d.ts +1 -1
- package/dist/theme/looks/terminal.js +1 -1
- package/dist/theme/theme.d.ts +2 -80
- package/dist/theme/theme.js +1 -1
- package/llms/components/lr-agent-workspace.md +24 -2
- package/llms/components/lr-alert.md +1 -1
- package/llms/components/lr-animation.md +1 -1
- package/llms/components/lr-app-rail.md +8 -10
- package/llms/components/lr-approval-queue.md +2 -4
- package/llms/components/lr-attachment-trigger.md +3 -4
- package/llms/components/lr-badge.md +2 -2
- package/llms/components/lr-button.md +45 -99
- package/llms/components/lr-callout.md +3 -4
- package/llms/components/lr-carousel.md +3 -5
- package/llms/components/lr-chat-message.md +1 -2
- package/llms/components/lr-claim-evidence.md +1 -1
- package/llms/components/lr-code-block-core.md +2 -2
- package/llms/components/lr-code-block.md +5 -6
- package/llms/components/lr-color-picker.md +1 -1
- package/llms/components/lr-combobox.md +5 -6
- package/llms/components/lr-compare-panel.md +2 -4
- package/llms/components/lr-confirm-bar.md +3 -7
- package/llms/components/lr-context-inspector.md +3 -2
- package/llms/components/lr-context-menu.md +2 -2
- package/llms/components/lr-context-meter.md +2 -4
- package/llms/components/lr-copy-button.md +1 -1
- package/llms/components/lr-data-grid.md +4 -7
- package/llms/components/lr-details.md +3 -3
- package/llms/components/lr-dialog.md +4 -6
- package/llms/components/lr-dock-panel.md +5 -6
- package/llms/components/lr-document-library.md +5 -7
- package/llms/components/lr-drawer.md +3 -3
- package/llms/components/lr-dropdown.md +4 -5
- package/llms/components/lr-eval-run.md +3 -5
- package/llms/components/lr-export-button.md +4 -7
- package/llms/components/lr-file-input.md +0 -5
- package/llms/components/lr-funnel.md +1 -1
- package/llms/components/lr-graph.md +3 -7
- package/llms/components/lr-icon.md +1 -1
- package/llms/components/lr-include.md +1 -1
- package/llms/components/lr-input.md +31 -79
- package/llms/components/lr-json-viewer.md +1 -1
- package/llms/components/lr-knowledge-base.md +4 -6
- package/llms/components/lr-knowledge-graph-explorer.md +2 -5
- package/llms/components/lr-known-date.md +1 -1
- package/llms/components/lr-lightbox.md +9 -7
- package/llms/components/lr-lite-chart.md +1 -5
- package/llms/components/lr-markdown-core.md +3 -4
- package/llms/components/lr-markdown.md +3 -5
- package/llms/components/lr-mcp-app.md +1 -1
- package/llms/components/lr-message-actions.md +2 -3
- package/llms/components/lr-message-feedback.md +1 -3
- package/llms/components/lr-message-parts.md +4 -5
- package/llms/components/lr-multi-split.md +8 -7
- package/llms/components/lr-native-time-input.md +1 -1
- package/llms/components/lr-navigation-menu.md +5 -5
- package/llms/components/lr-number-input.md +3 -1
- package/llms/components/lr-otp-input.md +2 -0
- package/llms/components/lr-page.md +1 -1
- package/llms/components/lr-pan-zoom.md +1 -1
- package/llms/components/lr-phone-input.md +3 -1
- package/llms/components/lr-popover.md +2 -2
- package/llms/components/lr-progress-bar.md +3 -5
- package/llms/components/lr-progress-ring.md +5 -7
- package/llms/components/lr-prompt-input.md +1 -1
- package/llms/components/lr-prompt-queue.md +1 -1
- package/llms/components/lr-prompt-studio.md +1 -1
- package/llms/components/lr-rag-eval-dashboard.md +1 -1
- package/llms/components/lr-rating.md +2 -2
- package/llms/components/lr-realtime-session.md +1 -1
- package/llms/components/lr-reorder-item.md +1 -1
- package/llms/components/lr-reorder-list.md +2 -3
- package/llms/components/lr-retrieval-compare.md +1 -1
- package/llms/components/lr-select.md +3 -1
- package/llms/components/lr-selection-toolbar.md +1 -1
- package/llms/components/lr-sequence-strip.md +3 -8
- package/llms/components/lr-span-waterfall.md +1 -1
- package/llms/components/lr-split-panel.md +1 -1
- package/llms/components/lr-streaming-text-core.md +2 -1
- package/llms/components/lr-streaming-text.md +3 -2
- package/llms/components/lr-subagent-panel.md +1 -1
- package/llms/components/lr-swatch-picker.md +7 -6
- package/llms/components/lr-switch.md +3 -1
- package/llms/components/lr-table.md +33 -85
- package/llms/components/lr-terminal.md +2 -5
- package/llms/components/lr-textarea.md +1 -1
- package/llms/components/lr-thread-list.md +8 -14
- package/llms/components/lr-time-input.md +1 -1
- package/llms/components/lr-toggle-group.md +2 -2
- package/llms/components/lr-toggle.md +1 -1
- package/llms/components/lr-tool-approval-dialog.md +4 -7
- package/llms/components/lr-tool-call-block.md +1 -1
- package/llms/components/lr-tool-timeline.md +2 -5
- package/llms/components/lr-video-playlist.md +1 -1
- package/llms/components/lr-video.md +1 -1
- package/llms/components/lr-widget-renderer.md +7 -6
- package/llms/components/lr-zoomable-frame.md +1 -1
- package/llms/index.md +3 -618
- package/llms/migration.md +614 -614
- package/llms/shared/events-and-types.md +32 -31
- package/llms/shared/frameworks-and-ssr.md +7 -3
- package/llms/shared/imports-and-registration.md +22 -22
- package/llms/shared/localization-and-rtl.md +2 -2
- package/llms/shared/native-styles-and-utilities.md +263 -0
- package/llms/shared/styles-and-tokens.md +85 -676
- package/llms/shared/testing-and-utilities.md +12 -11
- package/llms/shared/v23-to-v24-migration.md +167 -0
- package/llms/shared.md +149 -494
- package/llms/tokens.md +3 -3
- package/llms.txt +9 -4
- package/package.json +7 -311
- package/registrations.json +1 -1
- package/vscode-html-data.json +1 -1
- package/web-types.json +1 -1
- package/dist/ssr-loader.d.ts +0 -2
- package/dist/ssr-loader.js +0 -1
- package/dist/theme/presets/shadcn.d.ts +0 -22
- package/dist/theme/presets/shadcn.js +0 -1
- package/dist/theme/presets.d.ts +0 -49
- package/dist/theme/presets.js +0 -1
- package/dist/themes/shadcn.css +0 -1
package/llms/shared.md
CHANGED
|
@@ -59,8 +59,8 @@ way, and moving to the replacement removes the warning. A test suite that fails
|
|
|
59
59
|
while deliberately exercising a deprecated form can pre-seed Lit's development-mode
|
|
60
60
|
`globalThis.litIssuedWarnings` set, before the element renders, with the key
|
|
61
61
|
`lyra-deprecated:<owner>:<kind>:<name>` — `<kind>` and `<name>` as in the deprecation record.
|
|
62
|
-
`<owner>` is the element name or package-relative module specifier
|
|
63
|
-
|
|
62
|
+
`<owner>` is the element name or package-relative module specifier. Theme migration guidance is in
|
|
63
|
+
[styles and tokens](styles-and-tokens.md).
|
|
64
64
|
|
|
65
65
|
### Release history and upgrade notes
|
|
66
66
|
|
|
@@ -81,6 +81,13 @@ The major-version landmarks after 9.0.0 are:
|
|
|
81
81
|
that themselves overrode the hook are affected. Collection snapshot enforcement moved to a
|
|
82
82
|
decorator-agnostic accessor seam instead.
|
|
83
83
|
|
|
84
|
+
- **24.0.0:** removed eligible v22 compatibility routes, including package-root component
|
|
85
|
+
constructors, duplicate nested registration entries, the combined `ssr-loader.js` entry, and the
|
|
86
|
+
retired theme/preset facade. Use stable tag-shaped registration entries, a component's
|
|
87
|
+
registration-free `.class.js` subpath, the split SSR/hydration entries, and the current style API.
|
|
88
|
+
The [v23-to-v24 migration guide](v23-to-v24-migration.md) gives the removed routes, ordered
|
|
89
|
+
consumer cleanup and retained-profile instructions.
|
|
90
|
+
|
|
84
91
|
### The support window
|
|
85
92
|
|
|
86
93
|
Compatibility promises are bounded by a published support window, not by "evergreen browsers":
|
|
@@ -105,9 +112,9 @@ import "@aceshooting/lyra-ui/components/lr-combobox.js"; // registers <lr-combob
|
|
|
105
112
|
import "@aceshooting/lyra-ui/components/lr-table.js"; // registers <lr-table>
|
|
106
113
|
```
|
|
107
114
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
115
|
+
Family barrel entries remain supported and register their family. Class-only `.class.js` entries
|
|
116
|
+
use their owning family/component path because they intentionally expose source organization and
|
|
117
|
+
do not register a tag.
|
|
111
118
|
|
|
112
119
|
New application code can import any component through its stable tag-shaped path:
|
|
113
120
|
|
|
@@ -118,8 +125,7 @@ import "@aceshooting/lyra-ui/components/lr-tool-call-block.js";
|
|
|
118
125
|
```
|
|
119
126
|
|
|
120
127
|
`llms/index.md` lists every tag and its owning implementation module. The stable tag-shaped alias
|
|
121
|
-
and the family
|
|
122
|
-
export.
|
|
128
|
+
and the supported family barrel each resolve through the package's component exports.
|
|
123
129
|
|
|
124
130
|
The package root is a pure, side-effect-free export surface. Import a component entry to register
|
|
125
131
|
only that tag, or use the explicit `all.js` entry when whole-library registration is needed:
|
|
@@ -128,17 +134,11 @@ only that tag, or use the explicit `all.js` entry when whole-library registratio
|
|
|
128
134
|
import "@aceshooting/lyra-ui/all.js"; // explicitly registers the root-included tags
|
|
129
135
|
```
|
|
130
136
|
|
|
131
|
-
|
|
132
|
-
component
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
Family-shaped registration imports are also deprecated. Both deprecated root component-class exports
|
|
137
|
-
and family-shaped registration imports keep working throughout the compatibility window, with
|
|
138
|
-
removal no earlier than 24.0.0. Stable tag-shaped registration imports and class-only subpaths are
|
|
139
|
-
the canonical routes. The package root's helpers and types remain available. `all.js` is
|
|
140
|
-
side-effectful and registers the root-included inventory; prefer tag-shaped imports in application
|
|
141
|
-
code for smaller bundles.
|
|
137
|
+
The package root does not re-export component constructors. Import a class from its owning
|
|
138
|
+
component's `.class.js` subpath; import the stable tag-shaped entry to register it. The root remains
|
|
139
|
+
a side-effect-free home for shared utilities and types. Family registration barrels and `all.js`
|
|
140
|
+
remain side-effectful convenience entries; prefer tag-shaped imports for smaller application
|
|
141
|
+
bundles.
|
|
142
142
|
|
|
143
143
|
The entry points, then:
|
|
144
144
|
|
|
@@ -177,7 +177,7 @@ The entry points, then:
|
|
|
177
177
|
LyraAnchor,
|
|
178
178
|
LyraHighlight,
|
|
179
179
|
AnchorTargetCapabilities,
|
|
180
|
-
} from "@aceshooting/lyra-ui/components/
|
|
180
|
+
} from "@aceshooting/lyra-ui/components/lr-document-viewer.js";
|
|
181
181
|
```
|
|
182
182
|
Prefer the granular entry for component-local imports; use the root export when an application
|
|
183
183
|
deliberately shares the contracts across several viewer integrations.
|
|
@@ -185,13 +185,13 @@ The entry points, then:
|
|
|
185
185
|
a pre-resolved `src`) additionally needs
|
|
186
186
|
`import '@aceshooting/lyra-ui/components/media/flag/flag-peer.js';` once.
|
|
187
187
|
- **Other subpaths.** `@aceshooting/lyra-ui/theme.css` (ready-made light/dark theme),
|
|
188
|
-
`@aceshooting/lyra-ui/
|
|
189
|
-
[The shadcn look](#the-shadcn-look--
|
|
188
|
+
`@aceshooting/lyra-ui/looks/shadcn.css` (opt-in shadcn/ui look, imported after `theme.css` — see
|
|
189
|
+
[The shadcn look](#the-shadcn-look--looksshadcncss)),
|
|
190
190
|
`@aceshooting/lyra-ui/tokens-root.css` (opt-in: the curated resolved `--lr-*` tokens at `:root`,
|
|
191
191
|
so your own components can read them),
|
|
192
192
|
`@aceshooting/lyra-ui/native.css` (opt-in native-element styles inside `.lr-native`),
|
|
193
193
|
`@aceshooting/lyra-ui/utilities.css` (opt-in light-DOM layout/text/typography utilities),
|
|
194
|
-
`@aceshooting/lyra-ui/theme.js` (the zero-dependency
|
|
194
|
+
`@aceshooting/lyra-ui/theme.js` (the zero-dependency style runtime),
|
|
195
195
|
`@aceshooting/lyra-ui/localization.js` (side-effect-free locale runtime),
|
|
196
196
|
`@aceshooting/lyra-ui/autoloader.js` (side-effect-free on-demand tag loading),
|
|
197
197
|
`@aceshooting/lyra-ui/autoloader-cdn.js` (browser-guarded auto-start side effect),
|
|
@@ -376,7 +376,8 @@ Lyra-specific events are `lr-`-prefixed `CustomEvent`s (`lr-change`, `lr-input`,
|
|
|
376
376
|
dispatched through `LyraElement`'s `protected emit<T>(name, detail?, options?)`: **bubbling,
|
|
377
377
|
composed, and non-cancelable by default**, with the payload on `event.detail`. A component that
|
|
378
378
|
offers a genuine veto point opts into `{ cancelable: true }` and checks `defaultPrevented` before
|
|
379
|
-
acting (as `lr-export` does) — that is called out per component.
|
|
379
|
+
acting (as `lr-export-request` on `<lr-export-button>` does) — that is called out per component.
|
|
380
|
+
Native wrappers may additionally
|
|
380
381
|
relay unprefixed `Event`, `InputEvent`, or `FocusEvent` instances; each component section documents
|
|
381
382
|
the exact native names, constructors, bubbling, and cancelability it supports.
|
|
382
383
|
|
|
@@ -393,6 +394,10 @@ Every one of those names is also typed — per component through its own event m
|
|
|
393
394
|
through `@aceshooting/lyra-ui/events` for listeners on an ancestor, `document` or `window`. See
|
|
394
395
|
"TypeScript" below.
|
|
395
396
|
|
|
397
|
+
For event-detail compatibility fields removed in the v23-to-v24 upgrade,
|
|
398
|
+
use step 7 of the [migration checklist](v23-to-v24-migration.md#migrate-a-project-in-reviewable-steps).
|
|
399
|
+
Those nested detail fields are separate from deprecated event names and are not automatic renames.
|
|
400
|
+
|
|
396
401
|
## TypeScript
|
|
397
402
|
|
|
398
403
|
- **Per-component event maps.** Every component with events exports a `Lyra<Name>EventMap` type, and
|
|
@@ -401,7 +406,7 @@ through `@aceshooting/lyra-ui/events` for listeners on an ancestor, `document` o
|
|
|
401
406
|
```ts
|
|
402
407
|
import { LyraTable } from "@aceshooting/lyra-ui/components/data/table/table.class.js";
|
|
403
408
|
const table = document.querySelector("lr-table") as LyraTable;
|
|
404
|
-
table.addEventListener("lr-sort", (event) => event.detail.
|
|
409
|
+
table.addEventListener("lr-sort", (event) => event.detail.sortKey); // typed
|
|
405
410
|
```
|
|
406
411
|
- **`HTMLElementTagNameMap`** is augmented in the `.class.d.ts` files. `document.querySelector('lr-table')`
|
|
407
412
|
is only typed as `LyraTable` when that class module is in the type graph — importing just the
|
|
@@ -440,13 +445,13 @@ through `@aceshooting/lyra-ui/events` for listeners on an ancestor, `document` o
|
|
|
440
445
|
`LyraGlobalEventMap` is exported as well, for writing your own typed helper over it.
|
|
441
446
|
|
|
442
447
|
- **The surface is per-event type aliases, not runtime event classes.** `LyraSortEvent` and its
|
|
443
|
-
generated siblings are `type` aliases over
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
listener would cost every consumer runtime bytes for
|
|
447
|
-
costs zero.
|
|
448
|
+
generated siblings are `type` aliases over component event-map entries. `LyraSortEvent` unions
|
|
449
|
+
the `lr-sort` entries for document-library, eval-dataset and table. These aliases have no runtime
|
|
450
|
+
constructor and cannot be used with `new` or `instanceof`. The module compiles to `export {};`:
|
|
451
|
+
shipping runtime event subclasses to type a listener would cost every consumer runtime bytes for
|
|
452
|
+
a compile-time concern, so it deliberately costs zero.
|
|
448
453
|
- **A shared event name narrows to the union of its dispatchers.** One name can come from several
|
|
449
|
-
components with different details
|
|
454
|
+
components with different details, such as `lr-select` and `lr-selection-change`, so
|
|
450
455
|
its global entry is the _union_ of their entries, and `event.detail` there exposes only what all
|
|
451
456
|
of them share. Index the owning component's own map when you need one component's exact detail:
|
|
452
457
|
|
|
@@ -1130,8 +1135,8 @@ page you are on — that is what keeps two overlapping surfaces reading in the c
|
|
|
1130
1135
|
- **`lr-base`** — contains the explicitly scoped native-element rules only when the optional
|
|
1131
1136
|
`native.css` asset is imported.
|
|
1132
1137
|
- **`lr-theme`** — where every `--lr-theme-*` token `theme.css` ships is declared.
|
|
1133
|
-
- **`lr-theme-preset`** —
|
|
1134
|
-
[`
|
|
1138
|
+
- **`lr-theme-preset`** — the compatibility layer name that holds optional look stylesheets, such as
|
|
1139
|
+
[`looks/shadcn.css`](#the-shadcn-look--looksshadcncss). Empty unless one is imported.
|
|
1135
1140
|
- **`lr-utilities`** — contains exact `lr-*` classes only when the optional `utilities.css` asset is
|
|
1136
1141
|
imported.
|
|
1137
1142
|
- **`lr-overrides`** — named so an application can opt its own rules into a defined position
|
|
@@ -1186,111 +1191,39 @@ first statement the browser sees is appended at the end, so an older four-name s
|
|
|
1186
1191
|
`lr-theme-preset`) would rank an imported look preset above `lr-overrides` and your own layer. Every Lyra stylesheet that declares an order repeats the same five names for exactly this
|
|
1187
1192
|
reason.
|
|
1188
1193
|
|
|
1189
|
-
|
|
1194
|
+
<a id="the-shadcn-look--themesshadcncss"></a>
|
|
1190
1195
|
|
|
1191
|
-
|
|
1192
|
-
"new-york" style on its Neutral base colour:
|
|
1196
|
+
### The shadcn look — looks/shadcn.css
|
|
1193
1197
|
|
|
1194
|
-
|
|
1198
|
+
Import the base resolver and the optional look stylesheet, then select the look on the scope that should receive it:
|
|
1199
|
+
|
|
1200
|
+
~~~ts
|
|
1195
1201
|
import "@aceshooting/lyra-ui/theme.css";
|
|
1196
|
-
import "@aceshooting/lyra-ui/
|
|
1197
|
-
|
|
1202
|
+
import "@aceshooting/lyra-ui/looks/shadcn.css";
|
|
1203
|
+
import { setLyraStyle } from "@aceshooting/lyra-ui/theme.js";
|
|
1198
1204
|
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
- **load order does not matter** — the preset beats `theme.css` whichever is emitted first;
|
|
1203
|
-
- **any unlayered rule of yours beats both**, exactly as it beats `theme.css` alone;
|
|
1204
|
-
- **`setLyraTheme({ accent })` still wins** — the runtime writes inline style on `<html>`, which beats
|
|
1205
|
-
every layer.
|
|
1206
|
-
|
|
1207
|
-
**Modes.** The light block applies to `:root, .lr-light, [data-lr-theme='light'], .light` and the
|
|
1208
|
-
dark block to `.lr-dark, [data-lr-theme='dark'], .dark` (declared after light, same specificity). An
|
|
1209
|
-
application that toggles `.dark` on `<html>` the shadcn way gets Lyra's dark mode with no extra
|
|
1210
|
-
wiring, and a nested `.dark` (or `.light`) region is themed on its own, native `color-scheme`
|
|
1211
|
-
included. Only the preset knows `.dark`/`.light`: `theme.css` never reads those class names, since an
|
|
1212
|
-
application may already use them for something else. That is why each preset block also repeats
|
|
1213
|
-
`theme.css`'s own value, for that mode, of every input the preset does not restyle — the success,
|
|
1214
|
-
warning and remaining danger slots, the scrims, and the chart, graph and terminal ramps — so a bare
|
|
1215
|
-
`.dark` switches those too instead of leaving light status tints and light chart colours on a dark
|
|
1216
|
-
page.
|
|
1217
|
-
|
|
1218
|
-
| Input | Light | Dark | Notes |
|
|
1219
|
-
| --- | --- | --- | --- |
|
|
1220
|
-
| `color-surface-default` / `-raised` / `-overlay` | `#ffffff` / `#fafafa` / `#ffffff` | `#0a0a0a` / `#171717` / `#171717` | page, card/sidebar, popover |
|
|
1221
|
-
| `color-text-normal` / `-quiet` | `#0a0a0a` / `#737373` | `#fafafa` / `#a1a1a1` | |
|
|
1222
|
-
| `color-surface-border`, `color-border-strong` | `#919191` | `#646464` | control boundaries, 3:1 on page and raised surface |
|
|
1223
|
-
| `color-surface-border-subtle` | `#e5e5e5` | `rgb(255 255 255 / 0.1)` | decorative edges only |
|
|
1224
|
-
| `color-brand-*`, `color-neutral-*` | quiet `#f5f5f5`, normal `#e5e5e5`, loud `#171717` | quiet `#262626`, normal `#404040`, loud `#e5e5e5` | monochrome: primary and secondary are one family |
|
|
1225
|
-
| `color-danger-fill-loud` / `-on-loud` | `#d6000a` / `#ffffff` | `#ff6467` / `#0a0a0a` | other danger, success and warning slots keep Lyra's values |
|
|
1226
|
-
| `color-focus`, `focus-ring-width`, `focus-ring-offset` | `#8b8b8b`, `3px`, `0px` | `#787878`, `3px`, `0px` | |
|
|
1227
|
-
| `color-mix-partner` | `#737373` | `#737373` | hover/press mix toward a mid grey |
|
|
1228
|
-
| `border-radius-m` / `-xs` | `0.5rem` / `0.25rem` | same | |
|
|
1229
|
-
| `font-family-body` / `-mono` | `'Geist', 'Inter', ui-sans-serif, system-ui, sans-serif` / `'Geist Mono', ui-monospace, …` | same | fonts are named, not shipped |
|
|
1230
|
-
| `font-size-m` | `0.875rem` | same | shadcn UI text is `text-sm` |
|
|
1231
|
-
| `form-control-height-s` / `-m` / `-l`, `icon-button-size` | `2rem` / `2.25rem` / `2.5rem`, `2.25rem` | same | the 44px coarse-pointer floor still applies |
|
|
1232
|
-
| `shadow-xs` … `shadow-xl` | Tailwind geometry, alpha 0.05 / 0.1 | same geometry, alphas ×3 | `--lr-theme-shadow-color` still tints them |
|
|
1233
|
-
|
|
1234
|
-
Every name in the first column is `--lr-theme-` plus the cell. The default `<lr-button>`
|
|
1235
|
-
(`variant="neutral" appearance="accent"`) is shadcn's primary; `appearance="filled"` is secondary,
|
|
1236
|
-
`"outlined"` outline, `"plain"` ghost, `variant="danger"` destructive, `appearance="link"` link.
|
|
1237
|
-
|
|
1238
|
-
**Deliberate deviations from shadcn**, each keeping a contrast guarantee shadcn does not make — the
|
|
1239
|
-
repository's contrast gate re-measures every value in both modes:
|
|
1240
|
-
|
|
1241
|
-
- **Control borders** use the control grey above, not shadcn's `#e5e5e5` hairline (1.26:1 on white).
|
|
1242
|
-
The hairline survives as `--lr-color-border-subtle`, for decoration only.
|
|
1243
|
-
- **Focus** is an opaque grey, 3.41:1 / 4.48:1 against the page. shadcn's half-transparent ring
|
|
1244
|
-
measures about 1.5:1 / 1.9:1.
|
|
1245
|
-
- **Danger.** Components set text in the loud danger colour — error messages on the page, the body of
|
|
1246
|
-
a danger callout on the quiet danger tint. shadcn's `#e7000b` measures 4.10:1 on that tint, so the
|
|
1247
|
-
preset uses `#d6000a`, the same red a notch darker. Dark danger is a light red under near-black
|
|
1248
|
-
text, not white on a dark red, for the same reason.
|
|
1249
|
-
- **Charts** keep Lyra's validated series ramp: two of shadcn's chart colours fall below 3:1 on
|
|
1250
|
-
white, and the ramp is also checked for colour-blind separation.
|
|
1251
|
-
- **Hover and press** mix toward a mid grey. The default mixes toward the text colour, and shadcn's
|
|
1252
|
-
primary _is_ the text colour, so the default button would show no hover or press state at all.
|
|
1253
|
-
- **Code-fence syntax colouring** (`lr-code-block` / `lr-markdown`'s keyword/string/comment tokens)
|
|
1254
|
-
is the one surface the preset does not repaint: it stays GitHub's light/dark Shiki theme pair in
|
|
1255
|
-
both modes, with no property yet to substitute a different pair. Only which of the two fixed
|
|
1256
|
-
themes paints (light or dark) tracks the preset, through the same light/dark switch every other
|
|
1257
|
-
surface here reads. Unlike charts, above, this one carries no `--lr-theme-*` input at all — a
|
|
1258
|
-
deliberate scope line, not an oversight.
|
|
1259
|
-
|
|
1260
|
-
**Accents.** `lr-button`'s default renders the `neutral` role, and a bare accent only re-derives
|
|
1261
|
-
`brand`, so the preset aliases neutral's loud slots to brand's in both modes
|
|
1262
|
-
(`--lr-theme-color-neutral-fill-loud: var(--lr-theme-color-brand-fill-loud)`, and likewise
|
|
1263
|
-
`on-loud` and `border-loud`). With no accent that is the brand literal, so nothing changes; with
|
|
1264
|
-
`setLyraTheme({ accent: GEMSTONES.emerald.fill })` the default button, checked checkboxes and
|
|
1265
|
-
radios, and the focus ring follow the accent, while neutral's quiet and normal tiers — shadcn's
|
|
1266
|
-
secondary and muted — stay grey. **Switch modes through `setLyraTheme({ mode })`** (or the
|
|
1267
|
-
no-flash bootstrap) in an application that uses accents: the runtime derives the accent ramp for the
|
|
1268
|
-
mode it resolved and writes `data-lr-theme`, which the preset honours. Toggling `.dark` alone would
|
|
1269
|
-
leave a light-mode accent ramp on a dark page. Tailwind users can point `dark:` at
|
|
1270
|
-
`[data-lr-theme=dark]` to share that one switch.
|
|
1271
|
-
|
|
1272
|
-
**Overriding the preset.** An unlayered `:root { --lr-theme-… }` wins, as always. A mode-specific
|
|
1273
|
-
override must name the mode selectors, because the preset re-declares every input it sets on each of
|
|
1274
|
-
them — so a nested `.dark` region re-applies the preset's dark value over one you set on `:root`:
|
|
1205
|
+
setLyraStyle({ look: "shadcn" });
|
|
1206
|
+
~~~
|
|
1275
1207
|
|
|
1276
|
-
|
|
1277
|
-
:root, .lr-light, [data-lr-theme="light"], .light { --lr-theme-color-brand-fill-loud: #4f46e5; }
|
|
1278
|
-
.lr-dark, [data-lr-theme="dark"], .dark { --lr-theme-color-brand-fill-loud: #818cf8; }
|
|
1279
|
-
```
|
|
1208
|
+
The stylesheet declares values only under data-lr-look="shadcn". It composes with the independent mode, surface, density, and accent axes. For a local region, set data-lr-look="shadcn" on that region or use applyLyraStyleScope(). A nested data-lr-mode="dark" still changes mode without changing the look.
|
|
1280
1209
|
|
|
1281
|
-
|
|
1282
|
-
(`.lr-light`/`.lr-dark`/`data-lr-theme`), not on `.dark`/`.light`: the resolved layer published by
|
|
1283
|
-
[`tokens-root.css`](#reading-the-resolved-tokens-from-your-own-components--tokens-rootcss) and the
|
|
1284
|
-
`--lr-focus-ring` composite `theme.css` declares for your own `outline: var(--lr-focus-ring)` rules.
|
|
1285
|
-
A nested region whose _own_ light-DOM elements read either should carry `data-lr-theme="dark"`
|
|
1286
|
-
alongside `.dark`. Components are unaffected; they re-derive both on their own `:host`.
|
|
1210
|
+
The look sets --lr-theme-* inputs, so no component API changes. Its rules use Lyra's named cascade layers: unlayered application rules still win, and runtime accent ramps still take precedence over look values for the roles they paint. Import order between theme.css and looks/shadcn.css does not change the layer order.
|
|
1287
1211
|
|
|
1288
|
-
|
|
1289
|
-
sidebar tone, opt `lr-app-rail` in with one line:
|
|
1212
|
+
The shadcn look uses Neutral for primary and secondary controls. Its default button appearance is primary; filled is secondary, outlined is outline, plain is ghost, and danger remains destructive. The measured palette keeps control borders at least 3:1, uses an opaque focus color, keeps chart series contrast-qualified, and mixes hover and press toward mid grey so the monochrome primary still has a visible interaction state. Code-fence syntax colors continue to use the built-in light/dark Shiki themes.
|
|
1290
1213
|
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1214
|
+
Accents are independent from the look. A named accent such as emerald recolors the default button, checked controls, and focus ring while secondary and muted neutral tiers stay grey. Select mode with setLyraStyle({ mode: "system" }) or an explicit light/dark choice so the runtime resolves the accent ramp and updates data-lr-theme. Toggling an application class alone does not update an accent ramp managed by the runtime.
|
|
1215
|
+
|
|
1216
|
+
Override the look through an unlayered application rule or the lr-overrides layer:
|
|
1217
|
+
|
|
1218
|
+
~~~css
|
|
1219
|
+
@layer lr-overrides {
|
|
1220
|
+
[data-lr-look="shadcn"] {
|
|
1221
|
+
--lr-theme-color-brand-fill-loud: #4f46e5;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
~~~
|
|
1225
|
+
|
|
1226
|
+
The former global themes/shadcn.css facade and its data-lr-theme-preset behavior have been removed. Use looks/shadcn.css and the data-lr-look axis for new styling.
|
|
1294
1227
|
|
|
1295
1228
|
### Where an override actually reaches
|
|
1296
1229
|
|
|
@@ -1472,7 +1405,7 @@ dark palette. Two things switch that fallback off:
|
|
|
1472
1405
|
|
|
1473
1406
|
Note the asymmetry: the _light_ pin is read on the component itself (`:host([data-lr-theme='light'])`),
|
|
1474
1407
|
while a _dark_ ancestor is followed through `:host-context()`. Putting `data-lr-theme="light"` on
|
|
1475
|
-
`<html>` — what `
|
|
1408
|
+
`<html>` — what `setLyraStyle({ mode: 'light' })` does — pins the page through
|
|
1476
1409
|
`theme.css`'s real `--lr-theme-*` values, which inherit into every shadow root. Without `theme.css`
|
|
1477
1410
|
there are no such values to inherit, so put the attribute on the components you actually need
|
|
1478
1411
|
pinned.
|
|
@@ -1480,340 +1413,59 @@ pinned.
|
|
|
1480
1413
|
The token layer also sets `:host([hidden]) { display: none !important; }` and an inherited
|
|
1481
1414
|
`box-sizing: border-box` reset.
|
|
1482
1415
|
|
|
1483
|
-
###
|
|
1416
|
+
### Style runtime — @aceshooting/lyra-ui/theme.js
|
|
1484
1417
|
|
|
1485
|
-
|
|
1486
|
-
choice, apply it on load, avoid the flash of wrong theme before the app boots. `theme.js` is that
|
|
1487
|
-
runtime, published as its own subpath: **zero dependencies, no Lit, no component imports, and no
|
|
1488
|
-
side effects on import**, so an app can persist and apply a theme without pulling the component
|
|
1489
|
-
graph into its first-paint bundle.
|
|
1418
|
+
The standalone style runtime has no Lit or component dependency and does not touch the document or storage when imported. It stores the selected style under localStorage['lyra-theme'], applies it to the document root, and announces changes through lr-style-change.
|
|
1490
1419
|
|
|
1491
|
-
|
|
1492
|
-
import {
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
setLyraTheme({ accent: { brand: { light: "#2563eb", dark: "#f59e0b" } } }); // per-mode base color
|
|
1499
|
-
setLyraTheme({ surface: "#0b0f1a" }); // mixes every ramp against this instead of the mode default
|
|
1500
|
-
setLyraTheme({ mode: "auto" }); // follows the OS, including later changes
|
|
1501
|
-
setLyraTheme({
|
|
1502
|
-
tokens: {
|
|
1503
|
-
"--lr-theme-border-radius-m": "0.5rem", // both modes
|
|
1504
|
-
"--lr-theme-color-surface-default": { light: "#ffffff", dark: "#0a0a0a" }, // per mode
|
|
1505
|
-
},
|
|
1506
|
-
}); // replaces any previous token map wholesale
|
|
1507
|
-
setLyraTheme({ tokens: null }); // back to whatever the stylesheets say
|
|
1508
|
-
setLyraTheme({ mode: "unset", accent: null, surface: null, tokens: null }); // removes Lyra's overrides
|
|
1509
|
-
```
|
|
1420
|
+
~~~ts
|
|
1421
|
+
import {
|
|
1422
|
+
defineLyraLook,
|
|
1423
|
+
getLyraStyle,
|
|
1424
|
+
resetLyraStyle,
|
|
1425
|
+
setLyraStyle,
|
|
1426
|
+
} from "@aceshooting/lyra-ui/theme.js";
|
|
1510
1427
|
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
tab or a previous session is picked up cold. Where storage is unreadable or unwritable it
|
|
1522
|
-
reports the theme last applied, so the return value always describes what the document is
|
|
1523
|
-
actually showing and a toggle UI bound to it stays in sync.
|
|
1524
|
-
- **`mode`** is `'light' | 'dark' | 'auto' | 'unset'`. `'light'`/`'dark'` set **both
|
|
1525
|
-
`data-lr-theme`** (the
|
|
1526
|
-
attribute `theme.css` actually keys its palette blocks on) **and `data-theme`** (the generic
|
|
1527
|
-
attribute canvas-rendered components watch, so `lr-chart`/`lr-heatmap`/`lr-qr-code` repaint on
|
|
1528
|
-
the switch rather than keeping stale colors — see `llms/components/lr-chart.md`). `'auto'`
|
|
1529
|
-
resolves `prefers-color-scheme` immediately and keeps following changes. `'unset'` removes both
|
|
1530
|
-
attributes; use it when the application owns mode selection through another cascade.
|
|
1531
|
-
- **`accent`** is either an absolute CSS color — shorthand for `{ brand: <that color> }`, and the
|
|
1532
|
-
only shape prior to 16.0.0 — or a per-role record
|
|
1533
|
-
`{ brand?, success?, warning?, danger?, neutral? }`. Only the roles you supply are (re)derived;
|
|
1534
|
-
an omitted role keeps whatever the static palette (`llms/tokens.md`) already provides. For each
|
|
1535
|
-
supplied role, Lyra derives the complete quiet/normal/loud fill, border, and paired on-color
|
|
1536
|
-
ramp as inline `--lr-theme-color-<role>-*` inputs; `brand` additionally keeps `--lr-theme-accent`
|
|
1537
|
-
(a compatibility value holding the raw brand color, resolved for the active mode when the role
|
|
1538
|
-
is per-mode) and `--lr-theme-color-focus`, which no other role drives. Each paired foreground is
|
|
1539
|
-
selected for at least 4.5:1 contrast against its fill; normal/loud borders and the brand focus
|
|
1540
|
-
color are adjusted to at least 3:1 against the resolved surface (see `surface` below). Malformed
|
|
1541
|
-
values, CSS-wide keywords, `currentColor`, system colors, relative-color syntax, and unresolved
|
|
1542
|
-
`var()` expressions fail closed to `null` — at the whole `accent` field for a bare-string call,
|
|
1543
|
-
or at just that one role (or role/mode branch) for a per-role record, so one bad role does not
|
|
1544
|
-
take the others down with it. Pass `accent: null` to restore the palette supplied by
|
|
1545
|
-
`theme.css` entirely.
|
|
1546
|
-
- **Per-mode accent.** Each role's value can itself be a bare color/`null` (applied to both
|
|
1547
|
-
resolved modes, as above) or a `{ light?, dark? }` map deriving that role's ramp from a
|
|
1548
|
-
genuinely *different base color* per resolved mode — not merely a different tint weight of the
|
|
1549
|
-
same hue — for example `{ brand: { light: "#2563eb", dark: "#f59e0b" } }`. An omitted branch
|
|
1550
|
-
(or a role/branch that fails validation) keeps that mode's inherited/palette default; the branch
|
|
1551
|
-
actually painted follows the *resolved* mode, so it updates automatically when `mode: 'auto'`
|
|
1552
|
-
follows a `prefers-color-scheme` change. The stored/returned/event-detail shape always mirrors
|
|
1553
|
-
what you supplied (bare color or `{ light, dark }`), never collapsed to a single resolved color.
|
|
1554
|
-
- **`surface`** is an absolute CSS color used as every role's ramp mix base, instead of the
|
|
1555
|
-
shipped light/dark defaults (`#1a1a1a` dark / `#ffffff` light). It follows the same absolute
|
|
1556
|
-
CSS color and fail-closed-to-`null` rules as `accent`; an alpha channel is composited against
|
|
1557
|
-
the mode's own default surface before use. `null` (the default) keeps those shipped defaults.
|
|
1558
|
-
Supplying `surface` changes the quiet/normal/loud mix ratios and every border/focus contrast
|
|
1559
|
-
check for **every** currently-supplied role at once — it is one mix base per apply, not
|
|
1560
|
-
per-role.
|
|
1561
|
-
|
|
1562
|
-
These are `--lr-theme-*` inputs, so they reach every nested shadow root — see "Where an override
|
|
1563
|
-
actually reaches" above for why setting a `--lr-*` token instead would not.
|
|
1564
|
-
- **`tokens`** is a map of `--lr-theme-*` inputs written inline on `<html>`, persisted and restored
|
|
1565
|
-
before first paint like the other fields. Each value is a CSS string for both modes or a
|
|
1566
|
-
`{ light?, dark? }` pair; a `null` or omitted branch leaves that mode to the stylesheets. A map
|
|
1567
|
-
always **replaces** the previous one wholesale — compose with object spread
|
|
1568
|
-
(`{ ...LYRA_SHADCN_THEME_PRESET.theme.tokens, "--lr-theme-border-radius-m": "0" }`) — and
|
|
1569
|
-
`tokens: null`, `{}` or a map with no valid entry removes it; omitting `tokens` keeps the current
|
|
1570
|
-
map. Per-mode branches apply only while Lyra resolves a mode, so `mode: "unset"` writes the bare
|
|
1571
|
-
values only (use the `themes/*.css` stylesheet instead when an application-owned `.dark` class
|
|
1572
|
-
decides the mode). Inline `--lr-theme-*` values your application sets itself on `<html>` and that
|
|
1573
|
-
are not in a map are never touched; a name that *is* in the map is owned by the runtime while the
|
|
1574
|
-
map is applied, and an earlier inline value for it is not restored on removal.
|
|
1575
|
-
|
|
1576
|
-
**Grammar and limits.** Invalid entries are dropped one by one (`setLyraTheme()` never throws;
|
|
1577
|
-
`defineLyraThemePreset()` throws `TypeError` for the same cases). A name must match
|
|
1578
|
-
`--lr-theme-[a-z0-9]+(-[a-z0-9]+)*`, be at most 80 characters, and not be `--lr-theme-accent`
|
|
1579
|
-
(owned by `accent`). A value is trimmed and must be 1–256 characters; it may not contain a
|
|
1580
|
-
control character or line break, a backslash, a backtick, any of
|
|
1581
|
-
`; { } ! < > @ [ ] $ ^ | ~ = ? & :`, U+2028/U+2029, or a
|
|
1582
|
-
comment delimiter; it may not be a CSS-wide keyword (`inherit`, `initial`, `unset`, `revert`,
|
|
1583
|
-
`revert-layer`); every function must be one of `rgb rgba hsl hsla hwb lab lch oklab oklch color
|
|
1584
|
-
color-mix light-dark calc min max clamp var cubic-bezier steps linear` (so `url()`, `image-set()`,
|
|
1585
|
-
`attr()`, `env()` and unknown functions are rejected); and parentheses and quotes must balance. A
|
|
1586
|
-
map holds at most 512 entries (more normalizes to no map at all). The check is DOM-free, so
|
|
1587
|
-
`defineLyraThemePreset()`, the runtime, the bootstrap and the preset generator apply it
|
|
1588
|
-
identically.
|
|
1589
|
-
|
|
1590
|
-
**Contrast floor.** With a resolved mode, colour families the static contrast gate checks are
|
|
1591
|
-
measured before they are written; a failing value is replaced by the nearest passing mix toward
|
|
1592
|
-
black or white, serialized as `rgb(r g b)`, and a passing value is written verbatim. The snapshot
|
|
1593
|
-
and the stored record always keep the value you supplied. The references are the explicit
|
|
1594
|
-
`surface`, else the map's `--lr-theme-color-surface-default`, else the mode default (**S**:
|
|
1595
|
-
`#ffffff` / `#1a1a1a`); the map's `color-surface-raised` else `#f6f8fa` / `#22272e` (**R**); the
|
|
1596
|
-
painted `color-text-normal` else `#1a1a1a` / `#f2f2f2` (**T**); and the map's
|
|
1597
|
-
`color-overlay-strong` else black at 0.92 / 0.95 over S (**O**). Names below omit `--lr-theme-`:
|
|
1598
|
-
|
|
1599
|
-
| Tokens | Against | Floor |
|
|
1600
|
-
| --- | --- | --- |
|
|
1601
|
-
| `color-text-normal`, `color-text-quiet` | S and R | 4.5 |
|
|
1602
|
-
| `color-<role>-on-<tier>`, when its `color-<role>-fill-<tier>` is in the map (a missing on-* is synthesized) | its fill | 4.5 |
|
|
1603
|
-
| `color-on-strong-overlay` (synthesized when only `color-overlay-strong` is in the map) | O | 4.5 |
|
|
1604
|
-
| `color-<role>-border-normal`/`-loud`, `color-surface-border`, `color-border-strong`, `color-focus` | S | 3 |
|
|
1605
|
-
| `color-chart-<n>` | S | 3 |
|
|
1606
|
-
| `terminal-color-<name>` | R | 4.5 |
|
|
1607
|
-
| `terminal-bg-<name>` | T | 4.5 |
|
|
1608
|
-
|
|
1609
|
-
**Unchecked, written verbatim:** `*-border-quiet` and `color-surface-border-subtle` (decorative by
|
|
1610
|
-
contract); `color-<role>-fill-*` (measured through their on-* partner); an on-* whose fill-* is not
|
|
1611
|
-
in the same map; `color-surface-default`, `-raised` and `-overlay` (references, not foregrounds —
|
|
1612
|
-
text on `color-surface-overlay` is not measured); `color-overlay`, `color-no-data` and
|
|
1613
|
-
`color-mix-partner`; chart-series colour-vision separation (the static gate only); every
|
|
1614
|
-
non-colour token (fonts, radii, sizes, shadows, durations — including
|
|
1615
|
-
`--lr-theme-icon-button-size`, whose target-size floor is yours to keep); and any value or
|
|
1616
|
-
reference that does not resolve to a colour — `var()`, `light-dark()`, relative colours,
|
|
1617
|
-
`currentColor`, system colours, and **every** value when a canvas is unavailable (no 2D context,
|
|
1618
|
-
or pixel reads blocked). An unresolved row is written verbatim and synthesizes nothing; the accent
|
|
1619
|
-
still fails closed as it always has. The runtime never reads computed styles, so a reference an
|
|
1620
|
-
application stylesheet changes without the map carrying it is not seen.
|
|
1621
|
-
|
|
1622
|
-
**Precedence.** accent ramp (for the roles it paints) > runtime tokens (inline on `<html>`) >
|
|
1623
|
-
your unlayered CSS > `lr-theme-preset` (`themes/shadcn.css`) > `lr-theme` (`theme.css`) >
|
|
1624
|
-
component fallbacks. Runtime tokens therefore beat an unlayered `:root { --lr-theme-*: … }`
|
|
1625
|
-
override, like the accent does; put your override in the map instead. An element that re-declares
|
|
1626
|
-
a `--lr-theme-*` input itself — a `.lr-dark`/`data-lr-theme` island, a `data-lr-theme`-pinned
|
|
1627
|
-
component, app-scoped CSS — keeps its own value inside that subtree (the accent ramp has the same
|
|
1628
|
-
limitation).
|
|
1629
|
-
|
|
1630
|
-
**Snapshots.** `getLyraTheme()`, the stored record and the `lr-theme-change` /
|
|
1631
|
-
`lr-theme-preset-change` details carry `tokens` **only while a map is applied** — the key is
|
|
1632
|
-
absent, not `null`, otherwise, on every path including unwritable storage and the automatic mode
|
|
1633
|
-
flip. The map is normalized and deep-frozen: trimmed strings, and every per-mode entry carries
|
|
1634
|
-
both `light` and `dark` (`null` for a missing branch).
|
|
1635
|
-
- **Unbalanced colours fail closed.** An `accent` (any role or branch) or `surface` with an
|
|
1636
|
-
unclosed parenthesis or quote, such as `rgb(0 0 0`, is rejected to `null` like every other
|
|
1637
|
-
malformed value. The browser's own parser closes such a construct implicitly, but written raw
|
|
1638
|
-
into an inline `style` it swallows the declarations after it when that attribute is re-parsed.
|
|
1639
|
-
|
|
1640
|
-
**Theme presets.** `@aceshooting/lyra-ui/theme/presets.js` exports
|
|
1641
|
-
`LYRA_THEME_PRESETS`, `defineLyraThemePreset()` and `applyLyraThemePreset()`. Built-in keys are
|
|
1642
|
-
`system`, `light`, `dark`, `unset`, `emerald`, `ruby`, `amethyst`, and `sapphire`; the gemstone
|
|
1643
|
-
presets use system-following mode plus the named brand accent. Application presets use a stable
|
|
1644
|
-
lowercase kebab-case `id` and a `theme: { mode?, accent?, surface? }` record — the same shapes
|
|
1645
|
-
`setLyraTheme()` accepts, including a per-role `accent` record. `defineLyraThemePreset()`
|
|
1646
|
-
validates the id and field shapes, freezes both records, and leaves CSS color-syntax validation to
|
|
1647
|
-
the production runtime when the preset is applied:
|
|
1428
|
+
setLyraStyle({ mode: "dark" }); // unspecified axes keep their current value
|
|
1429
|
+
setLyraStyle({ accent: "sapphire" }); // named palette accent
|
|
1430
|
+
setLyraStyle({ accent: "#7c3aed" }); // absolute CSS color
|
|
1431
|
+
setLyraStyle({ accentBackground: "#0b0f1a" }); // reference surface for accent ramps
|
|
1432
|
+
setLyraStyle({ mode: "system" }); // follows prefers-color-scheme
|
|
1433
|
+
setLyraStyle({ look: "shadcn", surface: "glass", density: "compact" });
|
|
1434
|
+
const style = getLyraStyle();
|
|
1435
|
+
resetLyraStyle(["look"]); // reset only the look axis
|
|
1436
|
+
setLyraStyle({ mode: "unset", accent: null, accentBackground: null, overrides: null });
|
|
1437
|
+
~~~
|
|
1648
1438
|
|
|
1649
|
-
|
|
1650
|
-
import {
|
|
1651
|
-
applyLyraThemePreset,
|
|
1652
|
-
defineLyraThemePreset,
|
|
1653
|
-
} from "@aceshooting/lyra-ui/theme/presets.js";
|
|
1654
|
-
|
|
1655
|
-
applyLyraThemePreset("sapphire");
|
|
1656
|
-
applyLyraThemePreset(
|
|
1657
|
-
defineLyraThemePreset({
|
|
1658
|
-
id: "application-ocean",
|
|
1659
|
-
theme: {
|
|
1660
|
-
mode: "dark",
|
|
1661
|
-
accent: { brand: "#22d3ee", danger: "#dc2626" },
|
|
1662
|
-
surface: "#0b0f1a",
|
|
1663
|
-
},
|
|
1664
|
-
})
|
|
1665
|
-
);
|
|
1666
|
-
```
|
|
1439
|
+
setLyraStyle() accepts independent choices for look, surface, density, mode, accent, accentBackground, and overrides. Omitted axes keep their current selection; null resets an axis. The returned LyraStyle snapshot includes the selected values, a resolved mode when the choice is system, and lookForm to distinguish a stylesheet look from a runtime look.
|
|
1667
1440
|
|
|
1668
|
-
|
|
1669
|
-
runtime validation, Lyra reflects the id to `data-lr-theme-preset` and emits
|
|
1670
|
-
`lr-theme-preset-change` on `window` with `{ id, theme }`, where `theme` is the complete applied
|
|
1671
|
-
snapshot. If runtime validation changes a field (for example, an invalid accent fails closed to
|
|
1672
|
-
`null`), only the ordinary `lr-theme-change` event is emitted and no preset marker is written,
|
|
1673
|
-
because the resulting state is not exactly that named preset. A direct `setLyraTheme()` call also
|
|
1674
|
-
removes the preset marker.
|
|
1675
|
-
|
|
1676
|
-
**Token presets: a look as its own axis.** A preset's `theme` may carry `tokens` (see `tokens`
|
|
1677
|
-
above). `defineLyraThemePreset()` validates the whole map against the same grammar the runtime
|
|
1678
|
-
applies and throws `TypeError` on any violation, so a map it accepts is never changed at run time and
|
|
1679
|
-
the preset still claims its marker — even where a canvas is unavailable. A look is independent of
|
|
1680
|
-
mode, accent and surface: a preset that omits those fields leaves them as they are, and the built-in
|
|
1681
|
-
presets never mention `tokens`, so `applyLyraThemePreset("sapphire")` or `"dark"` keeps the current
|
|
1682
|
-
look. Either order reaches the same state; only the marker (the last applied id) differs. The
|
|
1683
|
-
shadcn look ships as a generated runtime preset, built from `themes/shadcn.css` so the two can never
|
|
1684
|
-
drift:
|
|
1441
|
+
mode is light, dark, system, or unset. Explicit modes set both data-lr-theme and data-theme; system follows the operating system and updates both attributes when it changes; unset removes Lyra's mode attributes. The lr-style-change event carries { style, changed }, where changed lists the affected fields. Applications can listen to this one event for document style changes.
|
|
1685
1442
|
|
|
1686
|
-
|
|
1687
|
-
import { applyLyraThemePreset, defineLyraThemePreset } from "@aceshooting/lyra-ui/theme/presets.js";
|
|
1688
|
-
import { LYRA_SHADCN_THEME_PRESET } from "@aceshooting/lyra-ui/theme/presets/shadcn.js";
|
|
1689
|
-
|
|
1690
|
-
applyLyraThemePreset(LYRA_SHADCN_THEME_PRESET); // look on; mode, accent and surface kept
|
|
1691
|
-
applyLyraThemePreset("sapphire"); // an accent on top of the look
|
|
1692
|
-
|
|
1693
|
-
// The exact stylesheet rendering (no accent ramp, default surface), keeping a marker:
|
|
1694
|
-
applyLyraThemePreset(
|
|
1695
|
-
defineLyraThemePreset({
|
|
1696
|
-
id: "shadcn-exact",
|
|
1697
|
-
theme: { ...LYRA_SHADCN_THEME_PRESET.theme, accent: null, surface: null },
|
|
1698
|
-
})
|
|
1699
|
-
);
|
|
1700
|
-
```
|
|
1443
|
+
accent accepts one of Lyra's named palettes or an absolute CSS color. A custom color is shorthand for a brand color; an object can set colors for brand, success, warning, danger, and neutral independently. Each role can use a { light, dark } pair. Lyra derives quiet, normal, and loud fill, border, and on-color ramps. Foregrounds meet 4.5:1 contrast against their fills; normal and loud borders and the brand focus color meet 3:1 against the selected reference surface. Invalid colors fail closed.
|
|
1701
1444
|
|
|
1702
|
-
|
|
1703
|
-
before first paint, needs no stylesheet swap, and is written inline, so it beats unlayered `:root`
|
|
1704
|
-
overrides. The `themes/shadcn.css` stylesheet is the one to use for light/dark **islands**, for an
|
|
1705
|
-
application-owned `.dark`/`.light` class, or for a page with no theme runtime. The runtime preset
|
|
1706
|
-
module is a separate subpath, so an application that only uses `presets.js` pays nothing for it.
|
|
1707
|
-
|
|
1708
|
-
**No-flash bootstrap.** `lyraThemeBootstrap` is a self-contained IIFE **string** (not a function),
|
|
1709
|
-
meant to be inlined into a `<script>` in `<head>` **before any stylesheet**, so the persisted theme
|
|
1710
|
-
is on the root element before first paint. It reads `localStorage['lyra-theme']`.
|
|
1711
|
-
`createLyraThemeBootstrap({ storageKey })` returns the same kind of string for an application-owned
|
|
1712
|
-
key, so an existing persistence layer can reuse the pre-paint half independently of
|
|
1713
|
-
`setLyraTheme()`/`getLyraTheme()`. Calling the factory with no options returns the same string as
|
|
1714
|
-
`lyraThemeBootstrap`. The result is a string precisely so this can happen in an unbundled
|
|
1715
|
-
`<script>` context without shipping or parsing the module. Custom keys are escaped against HTML
|
|
1716
|
-
script termination and JavaScript line separators. Under a Content Security Policy, give the
|
|
1717
|
-
inline script the nonce or hash required by the application:
|
|
1445
|
+
accentBackground is an absolute CSS color used as the accent ramps' reference surface. surface is a separate visual treatment: solid or glass. density selects compact, comfortable, or touch. These axes remain independent, so changing the look does not reset mode, accent, surface, or density.
|
|
1718
1446
|
|
|
1719
|
-
|
|
1447
|
+
A LyraLook is a named token definition. Define an application look with defineLyraLook({ id, tokens }), then pass it as the look choice. A look supplies --lr-theme-* inputs; overrides applies an independent map of those inputs to the document root. Both accept CSS strings or per-mode { light, dark } values. Overrides replace the previous map wholesale; compose them with object spread. Values are validated, trimmed, and deep-frozen. Invalid entries are ignored, and maps are limited to 512 entries.
|
|
1448
|
+
|
|
1449
|
+
The token grammar rejects CSS-wide keywords, control characters, unsafe punctuation, unbalanced functions or quotes, and functions outside the documented color and layout set. Color families checked by the static contrast gate are corrected to meet their contrast floor before painting. The snapshot and stored record retain the normalized requested values. Inline style ownership records only properties Lyra wrote and restores an earlier author value when a choice is cleared.
|
|
1450
|
+
|
|
1451
|
+
**Saved styles and the no-flash bootstrap.** getLyraStyle() re-reads storage on each call, so a value written by another tab is visible. If storage is unavailable, the runtime reports its last applied style and continues applying changes without persistence. lyraThemeBootstrap is a self-contained IIFE string for a script in head before stylesheets; it restores the saved style before first paint. createLyraThemeBootstrap({ storageKey }) produces the same string for an application-owned key. Both runtime and bootstrap safely read v1 records using mode: "auto", surface, and tokens, translating them to the current style axes. Keep this reader when migrating old saved preferences; new writes use the current style record.
|
|
1452
|
+
|
|
1453
|
+
The bootstrap string can be inlined with the application's CSP nonce or hash:
|
|
1454
|
+
|
|
1455
|
+
~~~html
|
|
1720
1456
|
<head>
|
|
1721
1457
|
<script>
|
|
1722
1458
|
/* server-inlines lyraThemeBootstrap here */
|
|
1723
1459
|
</script>
|
|
1724
1460
|
<link rel="stylesheet" href="/theme.css" />
|
|
1725
1461
|
</head>
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
Both variants read a stored `{ mode, accent, surface }` record, resolve `auto`, and derive the same
|
|
1729
|
-
per-role ramp(s) from the same math — the bootstrap re-implements it inline (self-contained, so it
|
|
1730
|
-
can run before any module loads) rather than importing the runtime, but the two are tested to never
|
|
1731
|
-
drift. A missing or malformed record receives the runtime's
|
|
1732
|
-
`{ mode: 'auto', accent: null, surface: null }` default; blocked `localStorage` leaves the document
|
|
1733
|
-
untouched rather than throwing before your app loads.
|
|
1734
|
-
|
|
1735
|
-
The stored record also carries `tokens` while a map is applied, and the bootstrap restores it
|
|
1736
|
-
before first paint: the same grammar, the same per-mode branch for the resolved mode, and the same
|
|
1737
|
-
contrast floor as the runtime. It records the names it wrote on `<html>`, so the runtime's first
|
|
1738
|
-
apply removes or rewrites exactly those. Token values are read from storage at run time and never
|
|
1739
|
-
serialized into the script string. **The bootstrap's bytes change with library releases** — this
|
|
1740
|
-
one included — so a deployment that pins a CSP hash for the inline script (or for
|
|
1741
|
-
`theme-bootstrap.js`) must regenerate that hash when upgrading, or the browser blocks the bootstrap
|
|
1742
|
-
and the first-paint flash returns.
|
|
1743
|
-
|
|
1744
|
-
**External-file delivery for a strict CSP.** `@aceshooting/lyra-ui/theme-bootstrap.js` is a
|
|
1745
|
-
third, non-module way to ship the same bootstrap: a static script asset published alongside the
|
|
1746
|
-
package, containing exactly `lyraThemeBootstrap`'s bytes (both are produced from the same build
|
|
1747
|
-
step, so they can never drift apart). Reference it with a plain `<script src>` in `<head>`,
|
|
1748
|
-
still before any stylesheet:
|
|
1462
|
+
~~~
|
|
1749
1463
|
|
|
1750
|
-
|
|
1751
|
-
<head>
|
|
1752
|
-
<script src="/vendor/theme-bootstrap.js"></script>
|
|
1753
|
-
<link rel="stylesheet" href="/theme.css" />
|
|
1754
|
-
</head>
|
|
1755
|
-
```
|
|
1464
|
+
For a strict CSP that disallows inline scripts, the package also publishes theme-bootstrap.js, a classic script asset with identical bytes. Load it synchronously before stylesheets. Its optional data-lr-theme-storage-key and data-lr-theme-attributes attributes select an application-owned storage key or mode-attribute list; values are validated and fall back to defaults when invalid.
|
|
1756
1465
|
|
|
1757
|
-
|
|
1758
|
-
per-response nonce — a static HTML entry, for example — where the documented inline-script
|
|
1759
|
-
nonce/hash guidance above does not apply. Serving it same-origin (copy it into your build output,
|
|
1760
|
-
or configure your bundler/static host to do so) needs no hash at all; hashing it for an even
|
|
1761
|
-
stricter policy uses the same CSP `script-src` hash mechanism browsers already apply to any
|
|
1762
|
-
external script resource.
|
|
1466
|
+
**Migrating the retired theme facade.** New code uses setLyraStyle() and getLyraStyle(). Map old auto mode to system, an old surface reference color to accentBackground, and an old token map to overrides; review custom CSS colors that share a gemstone name before choosing a named accent. Replace preset definitions with a LyraLook plus explicit style choices. Replace selectors for data-lr-theme-preset with the actual axis they need, such as data-lr-look="shadcn". Import looks/shadcn.css in place of the removed fixed themes/shadcn.css facade and select the look with setLyraStyle({ look: "shadcn" }) or a scoped data-lr-look attribute. Listen for lr-style-change and read event.detail.style and event.detail.changed; the old theme and preset events are no longer emitted. For the complete project-by-project sequence, see [Upgrading from v23 to v24](v23-to-v24-migration.md).
|
|
1763
1467
|
|
|
1764
|
-
|
|
1765
|
-
as a plain classic script — never `type="module"` and never `async` — because it reads its own
|
|
1766
|
-
configuration synchronously through `document.currentScript` while it runs, and that property is
|
|
1767
|
-
`null` for both of those loading modes (as well as for anything scheduled after the script has
|
|
1768
|
-
already finished executing). Two optional attributes on that same `<script>` tag override the
|
|
1769
|
-
defaults without regenerating the file:
|
|
1770
|
-
|
|
1771
|
-
```html
|
|
1772
|
-
<head>
|
|
1773
|
-
<script
|
|
1774
|
-
src="/vendor/theme-bootstrap.js"
|
|
1775
|
-
data-lr-theme-storage-key="my-app-theme"
|
|
1776
|
-
data-lr-theme-attributes="data-lr-theme data-theme"
|
|
1777
|
-
></script>
|
|
1778
|
-
<link rel="stylesheet" href="/theme.css" />
|
|
1779
|
-
</head>
|
|
1780
|
-
```
|
|
1781
|
-
|
|
1782
|
-
- `data-lr-theme-storage-key` — the `localStorage` key to read, in place of the default
|
|
1783
|
-
`'lyra-theme'`. Equivalent to `createLyraThemeBootstrap({ storageKey })`'s argument, but
|
|
1784
|
-
resolved by the static file itself at parse time rather than baked in ahead of time. This is
|
|
1785
|
-
what lets an application with its own pre-existing storage key use the static asset instead of
|
|
1786
|
-
inlining a per-app copy.
|
|
1787
|
-
- `data-lr-theme-attributes` — a space-separated list of attribute names to set on
|
|
1788
|
-
`<html>` in place of the default `data-lr-theme data-theme` pair, replacing that list entirely
|
|
1789
|
-
rather than adding to it.
|
|
1790
|
-
|
|
1791
|
-
Both attributes are optional and independently validated; an absent, empty, oversized, or
|
|
1792
|
-
malformed value falls back to the built-in default rather than throwing, so a `<script>` tag with
|
|
1793
|
-
neither attribute — every existing deployment — behaves exactly as before. `data-lr-theme-storage-key`
|
|
1794
|
-
must be a non-empty string of at most 200 characters (its content is otherwise unrestricted — it is
|
|
1795
|
-
only ever used as an opaque `localStorage` key, never written to the DOM). `data-lr-theme-attributes`
|
|
1796
|
-
must parse to one to eight tokens, each unique and each matching `data-[a-z0-9]+(-[a-z0-9]+)*` —
|
|
1797
|
-
which rejects an event-handler name (`onload`), a native attribute (`style`, `class`, `id`), any
|
|
1798
|
-
token containing whitespace, a quote, `=`, or a control character, an empty list, and a duplicated
|
|
1799
|
-
token — because these attribute names reach `setAttribute()`/`removeAttribute()` on the document
|
|
1800
|
-
root. A `document.currentScript` of `null` (module/async misuse, or a script tag re-read after it
|
|
1801
|
-
finished running) is treated the same as no configuration at all.
|
|
1802
|
-
|
|
1803
|
-
An application-owned key from `createLyraThemeBootstrap({ storageKey })` can still be inlined as
|
|
1804
|
-
documented above; the static file's own script-tag attributes are the alternative for a strict-CSP
|
|
1805
|
-
deployment that cannot inline that call.
|
|
1806
|
-
|
|
1807
|
-
**Migrating from 15.x.** `accent` used to be exactly an absolute CSS color or `null`; that shape
|
|
1808
|
-
still works unchanged (`setLyraTheme({ accent: '#7c3aed' })` keeps deriving only the brand ramp).
|
|
1809
|
-
What changed is `LyraTheme` gaining a `surface` field alongside it — a strict superset for every
|
|
1810
|
-
caller that only ever read/wrote `mode`/`accent`, since `getLyraTheme()` now also returns
|
|
1811
|
-
`surface: null` by default. Only code that structurally compares the whole returned record (for
|
|
1812
|
-
example `assert.deepEqual(getLyraTheme(), { mode, accent })`) needs the extra field added.
|
|
1813
|
-
|
|
1814
|
-
**`tokens` is optional and absent unless used.** `LyraTheme` also gains an optional `tokens` field;
|
|
1815
|
-
`getLyraTheme()`, the stored record and both event details omit the key entirely until a token map
|
|
1816
|
-
is applied, so `assert.deepEqual(getLyraTheme(), { mode, accent, surface })` keeps passing.
|
|
1468
|
+
Historical v1 stored records remain readable by the runtime and bootstrap. The removed JavaScript functions, preset subpaths, preset event, root marker, and fixed stylesheet are not available in the current API.
|
|
1817
1469
|
|
|
1818
1470
|
### Invalidating canvas theme values
|
|
1819
1471
|
|
|
@@ -2084,7 +1736,7 @@ itself — gap and flow margins would add up (set `--lr-prose-flow-space: 0` if
|
|
|
2084
1736
|
| --------------------- | ------------------------------------------------------------- | --------------------------------------- |
|
|
2085
1737
|
| Heading sizes | 2 / 1.75 / 1.25 / 1.125rem | 2.25 / 1.875 / 1.5 / 1.25rem |
|
|
2086
1738
|
| h1 weight | 700 | 800 |
|
|
2087
|
-
| Tracking | `normal` unless the hook or theme input sets it; `
|
|
1739
|
+
| Tracking | `normal` unless the hook or theme input sets it; `looks/shadcn.css` sets -0.025em | tight |
|
|
2088
1740
|
| Flow spacing | 1rem (`--lr-prose-flow-space`) | 1.5rem |
|
|
2089
1741
|
| Space before headings | 2 × flow = 2rem for every level | 2.5rem before h2, 2rem before h3 |
|
|
2090
1742
|
| Paragraph leading | 1.6 | 1.75rem |
|
|
@@ -2154,7 +1806,7 @@ and opacity tokens first. These additional hooks customize only the light-DOM bu
|
|
|
2154
1806
|
| `--lr-prose-quote-padding` | `--lr-space-l`; logical quote inset in `lr-prose` and `lr-typography` |
|
|
2155
1807
|
| `--lr-prose-quote-border-width` | `--lr-border-width-thick` in `lr-prose`, `--lr-border-width-medium` in `lr-typography`; logical quote edge |
|
|
2156
1808
|
| `--lr-heading-letter-spacing` | `--lr-theme-heading-letter-spacing`, then `normal`; heading tracking for `lr-heading-1`–`4` and `lr-typography` headings |
|
|
2157
|
-
| `--lr-theme-heading-letter-spacing` | unset; theme input for heading tracking (no resolved `--lr-*` token); `
|
|
1809
|
+
| `--lr-theme-heading-letter-spacing` | unset; theme input for heading tracking (no resolved `--lr-*` token); `looks/shadcn.css` sets it |
|
|
2158
1810
|
| `--lr-visually-hidden-size` | `--lr-size-1px` (1px); retained hidden box size |
|
|
2159
1811
|
| `--lr-native-link-decoration-width` | `--lr-border-width-thin`; resting underline thickness |
|
|
2160
1812
|
| `--lr-native-link-underline-offset` | `--lr-space-2xs`; underline offset |
|
|
@@ -2234,8 +1886,8 @@ The side-effect-free `@aceshooting/lyra-ui/localization.js` entry exports
|
|
|
2234
1886
|
`LyraPluralMessage`, `LyraPluralCategory`, `LyraLocaleBridgeOptions` and `LyraLocaleBridgeCleanup`.
|
|
2235
1887
|
The package root continues to re-export the runtime for compatibility and remains registration-free;
|
|
2236
1888
|
use the dedicated entry when the application only needs locale setup and the narrower import graph.
|
|
2237
|
-
The former
|
|
2238
|
-
|
|
1889
|
+
The former utility-scoped entry point was removed in 23.0.0. Change that import specifier to
|
|
1890
|
+
`@aceshooting/lyra-ui/localization.js`; the helper contracts are unchanged.
|
|
2239
1891
|
**`LYRA_DEFAULT_STRINGS` is the authoritative key list** (matching the `LyraMessageKey` union) —
|
|
2240
1892
|
read it to find the key to override rather than guessing one. Date, number, byte, relative-time and
|
|
2241
1893
|
calendar output goes through `Intl`.
|
|
@@ -2673,12 +2325,16 @@ and adapters emit empty JavaScript and do not register elements.
|
|
|
2673
2325
|
|
|
2674
2326
|
## SSR and declarative shadow DOM
|
|
2675
2327
|
|
|
2328
|
+
When replacing the removed combined `ssr-loader.js` route, split browser hydration from component
|
|
2329
|
+
registration and server rendering as shown below. The [v23-to-v24 migration guide](v23-to-v24-migration.md)
|
|
2330
|
+
has the ordered upgrade steps and environment-specific import mapping.
|
|
2331
|
+
|
|
2676
2332
|
Root, `all.js`, and granular component imports are server-safe under the supported Node 22+ runtime.
|
|
2677
2333
|
`@aceshooting/lyra-ui/ssr/all.js` is the **server-only** convenience entry: unlike the browser
|
|
2678
2334
|
`all.js`, it registers the complete inventory including the optional-peer families — defining those
|
|
2679
2335
|
tags never imports their peers (each component loads its own lazily, client-side), and the
|
|
2680
2336
|
browser-bundle argument for excluding them does not apply to a server render. Use the public
|
|
2681
|
-
`@aceshooting/lyra-ui/ssr
|
|
2337
|
+
`@aceshooting/lyra-ui/ssr.js` entry for the tested Lit SSR contract. Its exported
|
|
2682
2338
|
`LYRA_SSR_SUPPORT_MATRIX`, `LYRA_SSR_RENDER_AND_HYDRATE_TAGS`, and
|
|
2683
2339
|
`LYRA_SSR_CLIENT_RENDER_TAGS` classify every inventory tag exactly once:
|
|
2684
2340
|
|
|
@@ -2691,7 +2347,7 @@ browser-bundle argument for excluding them does not apply to a server render. Us
|
|
|
2691
2347
|
Server setup (the fallback must precede Lit's renderer):
|
|
2692
2348
|
|
|
2693
2349
|
```ts
|
|
2694
|
-
import { lyraSsrElementRenderers } from "@aceshooting/lyra-ui/ssr
|
|
2350
|
+
import { lyraSsrElementRenderers } from "@aceshooting/lyra-ui/ssr.js";
|
|
2695
2351
|
import { render, LitElementRenderer } from "@lit-labs/ssr";
|
|
2696
2352
|
import { html } from "lit";
|
|
2697
2353
|
|
|
@@ -2700,7 +2356,7 @@ const result = render(html`<lr-page><main>Dashboard</main></lr-page>`, {
|
|
|
2700
2356
|
});
|
|
2701
2357
|
```
|
|
2702
2358
|
|
|
2703
|
-
In the browser, import `@aceshooting/lyra-ui/
|
|
2359
|
+
In the browser, import `@aceshooting/lyra-ui/hydration.js` before any other module that can import
|
|
2704
2360
|
Lit. This installs `@lit-labs/ssr-client/lit-element-hydrate-support.js` before component
|
|
2705
2361
|
registration. `getLyraSsrMode(tagName)` reads one tag's tier, and
|
|
2706
2362
|
`diagnoseLyraHydration(document)` inspects current Lyra hosts in the supplied tree and every
|
|
@@ -2764,8 +2420,8 @@ real component — instead of hand-rolling a `CustomEvent` and guessing its shap
|
|
|
2764
2420
|
```ts
|
|
2765
2421
|
import { createLyraEvent } from '@aceshooting/lyra-ui/testing';
|
|
2766
2422
|
|
|
2767
|
-
const event = createLyraEvent('lr-confirm-bar', 'lr-approve', { args: null, waitUntil: () => {} });
|
|
2768
|
-
event.cancelable; // true — lr-confirm-bar's own lr-approve call site is cancelable
|
|
2423
|
+
const event = createLyraEvent('lr-confirm-bar', 'lr-approve-request', { args: null, waitUntil: () => {} });
|
|
2424
|
+
event.cancelable; // true — lr-confirm-bar's own lr-approve-request call site is cancelable
|
|
2769
2425
|
target.dispatchEvent(event);
|
|
2770
2426
|
```
|
|
2771
2427
|
|
|
@@ -2811,11 +2467,14 @@ await activateStep(stepper, 'review'); // clicks the [part="step"] button for th
|
|
|
2811
2467
|
same `[part="option"]` row plus `data-value` delegated-click pattern for its own listbox/popup.
|
|
2812
2468
|
`submitConfirmDecision()`
|
|
2813
2469
|
accepts either `<lr-confirm-bar>` or `<lr-tool-approval-dialog>`, which render the identical
|
|
2814
|
-
`[part="approve-button"]`/`[part="deny-button"]` pair
|
|
2815
|
-
|
|
2470
|
+
`[part="approve-button"]`/`[part="deny-button"]` pair and emit cancelable
|
|
2471
|
+
`lr-approve-request`/`lr-deny-request` events. The driver awaits the component's render;
|
|
2472
|
+
if a listener calls `preventDefault()` on either component, or `waitUntil()` on the confirm bar,
|
|
2473
|
+
the action may still be pending when the driver returns.
|
|
2816
2474
|
|
|
2817
2475
|
Each driver is `async` and awaits `updateComplete` before returning, so assertions written
|
|
2818
|
-
immediately after it see
|
|
2476
|
+
immediately after it see the render reached by that interaction. Host-driven async decisions
|
|
2477
|
+
still need their own completion check. Each driver also throws a plain `Error` — never a
|
|
2819
2478
|
silent no-op — when the requested interaction cannot actually happen: the target is disabled, the
|
|
2820
2479
|
option owner/stepper is read-only or has no matching row/step currently rendered, or the confirm
|
|
2821
2480
|
bar is already decided. That is the exact failure mode a hand-rolled event misses (for example
|
|
@@ -2987,10 +2646,8 @@ they carry no `tag`: `components/media/flag/flag-peer.js`,
|
|
|
2987
2646
|
stand in for. They are a separate array rather than tag-less rows mixed into `entries`, so a reader
|
|
2988
2647
|
that keys `entries` by `tag` keeps working; `integrations`, `distModule` and `localeKeys` are all
|
|
2989
2648
|
additive, which is why the schema version is unchanged. `registrationModule` is the `src/` path used
|
|
2990
|
-
internally; `distModule` is
|
|
2991
|
-
|
|
2992
|
-
resolve the other without reading `src/` or walking `dist/` — for an integration bridge,
|
|
2993
|
-
`distModule` equals `entry`, since there is no separate alias. `registers` is every `lr-*` tag
|
|
2649
|
+
internally; `distModule` is a retained published specifier and equals the stable `entry` for v24
|
|
2650
|
+
per-tag registrations and integration bridges. `registers` is every `lr-*` tag
|
|
2994
2651
|
importing `entry` defines, direct or transitive, derived from the same transitive-import analysis
|
|
2995
2652
|
`scripts/check-component-dependencies.mjs` already performs against the real registration graph
|
|
2996
2653
|
(not a second hand-maintained list). `localeKeys` is every `LyraMessageKey` the registered tags can
|
|
@@ -3033,8 +2690,8 @@ same way `all.js` registers its root-included tags (the package root itself regi
|
|
|
3033
2690
|
and want a single import; reach for the granular
|
|
3034
2691
|
`@aceshooting/lyra-ui/components/<tag>.js` path when you do not, because a barrel cannot be
|
|
3035
2692
|
tree-shaken down to the two elements you actually render. The tag-shaped path remains stable if a
|
|
3036
|
-
component moves between Lyra's internal family folders
|
|
3037
|
-
remain supported.
|
|
2693
|
+
component moves between Lyra's internal family folders. Duplicate nested registration paths were
|
|
2694
|
+
removed in v24; family barrels remain supported.
|
|
3038
2695
|
|
|
3039
2696
|
```js
|
|
3040
2697
|
import "@aceshooting/lyra-ui/components/forms"; // every form control
|
|
@@ -5037,34 +4694,30 @@ These named interfaces and helper signatures are available to typed integrations
|
|
|
5037
4694
|
copy, so a glyph rendered anywhere else on the page can match it exactly by consuming the same
|
|
5038
4695
|
export and attribute.
|
|
5039
4696
|
|
|
5040
|
-
- **`theme-presets-contracts`** — Shared utility contracts.
|
|
5041
|
-
`applyLyraThemePreset(/* public names: presetOrName */): unknown`
|
|
5042
|
-
`defineLyraThemePreset(/* public names: preset */): unknown`
|
|
5043
|
-
`LyraThemePresetChangeDetail {
|
|
5044
|
-
id: unknown;
|
|
5045
|
-
theme: unknown;
|
|
5046
|
-
}`
|
|
5047
|
-
`LyraThemePreset {
|
|
5048
|
-
id: unknown;
|
|
5049
|
-
theme: unknown;
|
|
5050
|
-
}`
|
|
5051
|
-
|
|
5052
4697
|
- **`theme-theme-contracts`** — Shared utility contracts.
|
|
5053
|
-
`createLyraThemeBootstrap(
|
|
5054
|
-
`getLyraTheme(): unknown`
|
|
4698
|
+
`createLyraThemeBootstrap(options?: LyraThemeBootstrapOptions): string`
|
|
5055
4699
|
`LyraThemeBootstrapOptions {
|
|
5056
|
-
storageKey
|
|
5057
|
-
}`
|
|
5058
|
-
`LyraTheme {
|
|
5059
|
-
mode: unknown;
|
|
5060
|
-
accent: unknown;
|
|
5061
|
-
surface: unknown;
|
|
5062
|
-
tokens: unknown;
|
|
4700
|
+
storageKey?: string;
|
|
5063
4701
|
}`
|
|
5064
|
-
`
|
|
4702
|
+
`LyraThemeSemanticRole = 'brand' | 'success' | 'warning' | 'danger' | 'neutral'`
|
|
4703
|
+
`LyraThemeAccentValue = string | null | { light?: string | null; dark?: string | null }`
|
|
4704
|
+
`LyraThemeAccent = string | null | Partial<Record<LyraThemeSemanticRole, LyraThemeAccentValue>>`
|
|
4705
|
+
``LyraThemeTokenName = `--lr-theme-${string}```
|
|
4706
|
+
`LyraThemeTokenValue = string | { light?: string | null; dark?: string | null }`
|
|
4707
|
+
`LyraThemeTokens = Readonly<Record<LyraThemeTokenName, LyraThemeTokenValue>>`
|
|
4708
|
+
`LyraStyleAxis = 'look' | 'surface' | 'density' | 'mode' | 'accent'`
|
|
4709
|
+
`LyraStyleField = LyraStyleAxis | 'accentBackground' | 'overrides'`
|
|
4710
|
+
`LyraLookId = 'lyra' | 'shadcn' | 'material' | (string & {})`
|
|
4711
|
+
`LyraSurface = 'solid' | 'glass'`
|
|
4712
|
+
`LyraDensity = 'compact' | 'comfortable' | 'touch'`
|
|
4713
|
+
`LyraMode = 'light' | 'dark' | 'system' | 'unset'`
|
|
4714
|
+
`LyraAccentName = 'emerald' | 'peridot' | 'topaz' | 'ruby' | 'tourmaline' | 'amethyst' | 'aquamarine' | 'sapphire' | 'hematite'`
|
|
4715
|
+
`LyraAccent = LyraAccentName | LyraThemeAccent`
|
|
4716
|
+
`LyraAccentBackground = string | { light?: string | null; dark?: string | null } | null`
|
|
5065
4717
|
`applyLyraStyleScope(element: Element, choices: LyraStyleScopeChoices | null): void`
|
|
5066
4718
|
`defineLyraLook<const Look extends LyraLook>(look: Look): Readonly<Look>`
|
|
5067
4719
|
`getLyraStyle(): Readonly<LyraStyle>`
|
|
4720
|
+
`lyraThemeBootstrap: string`
|
|
5068
4721
|
`LyraLook {
|
|
5069
4722
|
readonly id: LyraLookId;
|
|
5070
4723
|
readonly tokens: LyraThemeTokens;
|
|
@@ -5868,19 +5521,21 @@ unchanged. Step numbers and interactive context-meter legend rows use matching s
|
|
|
5868
5521
|
pairs; control-border colors no longer act as their text backgrounds. Material uses 8% hover and
|
|
5869
5522
|
12% press state layers with its `currentColor` mix partner, keeping filled-action labels at 4.5:1.
|
|
5870
5523
|
|
|
5871
|
-
Runtime custom accents, including `
|
|
5524
|
+
Runtime custom accents, including `setLyraStyle({ accent })` and legacy gemstone presets, now
|
|
5872
5525
|
floor the loud fill to 4.5:1 against its quiet fill and the built-in reference surfaces because the
|
|
5873
5526
|
same token paints accent text. Its on-loud foreground follows the corrected fill. For example,
|
|
5874
5527
|
light shadcn emerald changes from `#34d399` with black on-loud text to `#1a6a4d` with white text
|
|
5875
5528
|
(6.537:1). Checked controls, brand text and streaming accents follow that loud token; secondary
|
|
5876
5529
|
neutral controls stay unchanged. The requested and persisted accent color is retained.
|
|
5877
5530
|
|
|
5878
|
-
The
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5531
|
+
The runtime and no-flash bootstrap still read v1 records written by the retired theme API. On
|
|
5532
|
+
read, auto becomes system and the old accent reference surface becomes accentBackground. A saved
|
|
5533
|
+
`tokens` map remains runtime-look tokens (`lookForm: 'runtime'`), separate from public `overrides`;
|
|
5534
|
+
without a valid saved look id, the runtime look is named `custom`. A CSS color such as aquamarine
|
|
5535
|
+
remains a CSS color and is not converted into the named gemstone. New writes use the current style
|
|
5536
|
+
record while retaining those runtime-look tokens. parseLyraStyleRecord() and
|
|
5537
|
+
lyraStyleAttributes() provide DOM-free server-rendering helpers; render the returned attributes
|
|
5538
|
+
through the framework's normal HTML escaping.
|
|
5884
5539
|
|
|
5885
5540
|
Glass is a treatment for eligible navigation and floating chrome. It does not make content panels,
|
|
5886
5541
|
forms, charts or dialogs translucent. Unsupported blur, reduced transparency, increased contrast and
|