@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
|
@@ -327,8 +327,8 @@ page you are on — that is what keeps two overlapping surfaces reading in the c
|
|
|
327
327
|
- **`lr-base`** — contains the explicitly scoped native-element rules only when the optional
|
|
328
328
|
`native.css` asset is imported.
|
|
329
329
|
- **`lr-theme`** — where every `--lr-theme-*` token `theme.css` ships is declared.
|
|
330
|
-
- **`lr-theme-preset`** —
|
|
331
|
-
[`
|
|
330
|
+
- **`lr-theme-preset`** — the compatibility layer name that holds optional look stylesheets, such as
|
|
331
|
+
[`looks/shadcn.css`](#the-shadcn-look--looksshadcncss). Empty unless one is imported.
|
|
332
332
|
- **`lr-utilities`** — contains exact `lr-*` classes only when the optional `utilities.css` asset is
|
|
333
333
|
imported.
|
|
334
334
|
- **`lr-overrides`** — named so an application can opt its own rules into a defined position
|
|
@@ -383,111 +383,39 @@ first statement the browser sees is appended at the end, so an older four-name s
|
|
|
383
383
|
`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
|
|
384
384
|
reason.
|
|
385
385
|
|
|
386
|
-
|
|
386
|
+
<a id="the-shadcn-look--themesshadcncss"></a>
|
|
387
387
|
|
|
388
|
-
|
|
389
|
-
"new-york" style on its Neutral base colour:
|
|
388
|
+
### The shadcn look — looks/shadcn.css
|
|
390
389
|
|
|
391
|
-
|
|
390
|
+
Import the base resolver and the optional look stylesheet, then select the look on the scope that should receive it:
|
|
391
|
+
|
|
392
|
+
~~~ts
|
|
392
393
|
import "@aceshooting/lyra-ui/theme.css";
|
|
393
|
-
import "@aceshooting/lyra-ui/
|
|
394
|
-
|
|
394
|
+
import "@aceshooting/lyra-ui/looks/shadcn.css";
|
|
395
|
+
import { setLyraStyle } from "@aceshooting/lyra-ui/theme.js";
|
|
395
396
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
- **load order does not matter** — the preset beats `theme.css` whichever is emitted first;
|
|
400
|
-
- **any unlayered rule of yours beats both**, exactly as it beats `theme.css` alone;
|
|
401
|
-
- **`setLyraTheme({ accent })` still wins** — the runtime writes inline style on `<html>`, which beats
|
|
402
|
-
every layer.
|
|
403
|
-
|
|
404
|
-
**Modes.** The light block applies to `:root, .lr-light, [data-lr-theme='light'], .light` and the
|
|
405
|
-
dark block to `.lr-dark, [data-lr-theme='dark'], .dark` (declared after light, same specificity). An
|
|
406
|
-
application that toggles `.dark` on `<html>` the shadcn way gets Lyra's dark mode with no extra
|
|
407
|
-
wiring, and a nested `.dark` (or `.light`) region is themed on its own, native `color-scheme`
|
|
408
|
-
included. Only the preset knows `.dark`/`.light`: `theme.css` never reads those class names, since an
|
|
409
|
-
application may already use them for something else. That is why each preset block also repeats
|
|
410
|
-
`theme.css`'s own value, for that mode, of every input the preset does not restyle — the success,
|
|
411
|
-
warning and remaining danger slots, the scrims, and the chart, graph and terminal ramps — so a bare
|
|
412
|
-
`.dark` switches those too instead of leaving light status tints and light chart colours on a dark
|
|
413
|
-
page.
|
|
414
|
-
|
|
415
|
-
| Input | Light | Dark | Notes |
|
|
416
|
-
| --- | --- | --- | --- |
|
|
417
|
-
| `color-surface-default` / `-raised` / `-overlay` | `#ffffff` / `#fafafa` / `#ffffff` | `#0a0a0a` / `#171717` / `#171717` | page, card/sidebar, popover |
|
|
418
|
-
| `color-text-normal` / `-quiet` | `#0a0a0a` / `#737373` | `#fafafa` / `#a1a1a1` | |
|
|
419
|
-
| `color-surface-border`, `color-border-strong` | `#919191` | `#646464` | control boundaries, 3:1 on page and raised surface |
|
|
420
|
-
| `color-surface-border-subtle` | `#e5e5e5` | `rgb(255 255 255 / 0.1)` | decorative edges only |
|
|
421
|
-
| `color-brand-*`, `color-neutral-*` | quiet `#f5f5f5`, normal `#e5e5e5`, loud `#171717` | quiet `#262626`, normal `#404040`, loud `#e5e5e5` | monochrome: primary and secondary are one family |
|
|
422
|
-
| `color-danger-fill-loud` / `-on-loud` | `#d6000a` / `#ffffff` | `#ff6467` / `#0a0a0a` | other danger, success and warning slots keep Lyra's values |
|
|
423
|
-
| `color-focus`, `focus-ring-width`, `focus-ring-offset` | `#8b8b8b`, `3px`, `0px` | `#787878`, `3px`, `0px` | |
|
|
424
|
-
| `color-mix-partner` | `#737373` | `#737373` | hover/press mix toward a mid grey |
|
|
425
|
-
| `border-radius-m` / `-xs` | `0.5rem` / `0.25rem` | same | |
|
|
426
|
-
| `font-family-body` / `-mono` | `'Geist', 'Inter', ui-sans-serif, system-ui, sans-serif` / `'Geist Mono', ui-monospace, …` | same | fonts are named, not shipped |
|
|
427
|
-
| `font-size-m` | `0.875rem` | same | shadcn UI text is `text-sm` |
|
|
428
|
-
| `form-control-height-s` / `-m` / `-l`, `icon-button-size` | `2rem` / `2.25rem` / `2.5rem`, `2.25rem` | same | the 44px coarse-pointer floor still applies |
|
|
429
|
-
| `shadow-xs` … `shadow-xl` | Tailwind geometry, alpha 0.05 / 0.1 | same geometry, alphas ×3 | `--lr-theme-shadow-color` still tints them |
|
|
430
|
-
|
|
431
|
-
Every name in the first column is `--lr-theme-` plus the cell. The default `<lr-button>`
|
|
432
|
-
(`variant="neutral" appearance="accent"`) is shadcn's primary; `appearance="filled"` is secondary,
|
|
433
|
-
`"outlined"` outline, `"plain"` ghost, `variant="danger"` destructive, `appearance="link"` link.
|
|
434
|
-
|
|
435
|
-
**Deliberate deviations from shadcn**, each keeping a contrast guarantee shadcn does not make — the
|
|
436
|
-
repository's contrast gate re-measures every value in both modes:
|
|
437
|
-
|
|
438
|
-
- **Control borders** use the control grey above, not shadcn's `#e5e5e5` hairline (1.26:1 on white).
|
|
439
|
-
The hairline survives as `--lr-color-border-subtle`, for decoration only.
|
|
440
|
-
- **Focus** is an opaque grey, 3.41:1 / 4.48:1 against the page. shadcn's half-transparent ring
|
|
441
|
-
measures about 1.5:1 / 1.9:1.
|
|
442
|
-
- **Danger.** Components set text in the loud danger colour — error messages on the page, the body of
|
|
443
|
-
a danger callout on the quiet danger tint. shadcn's `#e7000b` measures 4.10:1 on that tint, so the
|
|
444
|
-
preset uses `#d6000a`, the same red a notch darker. Dark danger is a light red under near-black
|
|
445
|
-
text, not white on a dark red, for the same reason.
|
|
446
|
-
- **Charts** keep Lyra's validated series ramp: two of shadcn's chart colours fall below 3:1 on
|
|
447
|
-
white, and the ramp is also checked for colour-blind separation.
|
|
448
|
-
- **Hover and press** mix toward a mid grey. The default mixes toward the text colour, and shadcn's
|
|
449
|
-
primary _is_ the text colour, so the default button would show no hover or press state at all.
|
|
450
|
-
- **Code-fence syntax colouring** (`lr-code-block` / `lr-markdown`'s keyword/string/comment tokens)
|
|
451
|
-
is the one surface the preset does not repaint: it stays GitHub's light/dark Shiki theme pair in
|
|
452
|
-
both modes, with no property yet to substitute a different pair. Only which of the two fixed
|
|
453
|
-
themes paints (light or dark) tracks the preset, through the same light/dark switch every other
|
|
454
|
-
surface here reads. Unlike charts, above, this one carries no `--lr-theme-*` input at all — a
|
|
455
|
-
deliberate scope line, not an oversight.
|
|
456
|
-
|
|
457
|
-
**Accents.** `lr-button`'s default renders the `neutral` role, and a bare accent only re-derives
|
|
458
|
-
`brand`, so the preset aliases neutral's loud slots to brand's in both modes
|
|
459
|
-
(`--lr-theme-color-neutral-fill-loud: var(--lr-theme-color-brand-fill-loud)`, and likewise
|
|
460
|
-
`on-loud` and `border-loud`). With no accent that is the brand literal, so nothing changes; with
|
|
461
|
-
`setLyraTheme({ accent: GEMSTONES.emerald.fill })` the default button, checked checkboxes and
|
|
462
|
-
radios, and the focus ring follow the accent, while neutral's quiet and normal tiers — shadcn's
|
|
463
|
-
secondary and muted — stay grey. **Switch modes through `setLyraTheme({ mode })`** (or the
|
|
464
|
-
no-flash bootstrap) in an application that uses accents: the runtime derives the accent ramp for the
|
|
465
|
-
mode it resolved and writes `data-lr-theme`, which the preset honours. Toggling `.dark` alone would
|
|
466
|
-
leave a light-mode accent ramp on a dark page. Tailwind users can point `dark:` at
|
|
467
|
-
`[data-lr-theme=dark]` to share that one switch.
|
|
468
|
-
|
|
469
|
-
**Overriding the preset.** An unlayered `:root { --lr-theme-… }` wins, as always. A mode-specific
|
|
470
|
-
override must name the mode selectors, because the preset re-declares every input it sets on each of
|
|
471
|
-
them — so a nested `.dark` region re-applies the preset's dark value over one you set on `:root`:
|
|
397
|
+
setLyraStyle({ look: "shadcn" });
|
|
398
|
+
~~~
|
|
472
399
|
|
|
473
|
-
|
|
474
|
-
:root, .lr-light, [data-lr-theme="light"], .light { --lr-theme-color-brand-fill-loud: #4f46e5; }
|
|
475
|
-
.lr-dark, [data-lr-theme="dark"], .dark { --lr-theme-color-brand-fill-loud: #818cf8; }
|
|
476
|
-
```
|
|
400
|
+
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.
|
|
477
401
|
|
|
478
|
-
|
|
479
|
-
(`.lr-light`/`.lr-dark`/`data-lr-theme`), not on `.dark`/`.light`: the resolved layer published by
|
|
480
|
-
[`tokens-root.css`](#reading-the-resolved-tokens-from-your-own-components--tokens-rootcss) and the
|
|
481
|
-
`--lr-focus-ring` composite `theme.css` declares for your own `outline: var(--lr-focus-ring)` rules.
|
|
482
|
-
A nested region whose _own_ light-DOM elements read either should carry `data-lr-theme="dark"`
|
|
483
|
-
alongside `.dark`. Components are unaffected; they re-derive both on their own `:host`.
|
|
402
|
+
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.
|
|
484
403
|
|
|
485
|
-
|
|
486
|
-
sidebar tone, opt `lr-app-rail` in with one line:
|
|
404
|
+
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.
|
|
487
405
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
406
|
+
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.
|
|
407
|
+
|
|
408
|
+
Override the look through an unlayered application rule or the lr-overrides layer:
|
|
409
|
+
|
|
410
|
+
~~~css
|
|
411
|
+
@layer lr-overrides {
|
|
412
|
+
[data-lr-look="shadcn"] {
|
|
413
|
+
--lr-theme-color-brand-fill-loud: #4f46e5;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
~~~
|
|
417
|
+
|
|
418
|
+
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.
|
|
491
419
|
|
|
492
420
|
### Where an override actually reaches
|
|
493
421
|
|
|
@@ -669,7 +597,7 @@ dark palette. Two things switch that fallback off:
|
|
|
669
597
|
|
|
670
598
|
Note the asymmetry: the _light_ pin is read on the component itself (`:host([data-lr-theme='light'])`),
|
|
671
599
|
while a _dark_ ancestor is followed through `:host-context()`. Putting `data-lr-theme="light"` on
|
|
672
|
-
`<html>` — what `
|
|
600
|
+
`<html>` — what `setLyraStyle({ mode: 'light' })` does — pins the page through
|
|
673
601
|
`theme.css`'s real `--lr-theme-*` values, which inherit into every shadow root. Without `theme.css`
|
|
674
602
|
there are no such values to inherit, so put the attribute on the components you actually need
|
|
675
603
|
pinned.
|
|
@@ -677,340 +605,59 @@ pinned.
|
|
|
677
605
|
The token layer also sets `:host([hidden]) { display: none !important; }` and an inherited
|
|
678
606
|
`box-sizing: border-box` reset.
|
|
679
607
|
|
|
680
|
-
###
|
|
608
|
+
### Style runtime — @aceshooting/lyra-ui/theme.js
|
|
681
609
|
|
|
682
|
-
|
|
683
|
-
choice, apply it on load, avoid the flash of wrong theme before the app boots. `theme.js` is that
|
|
684
|
-
runtime, published as its own subpath: **zero dependencies, no Lit, no component imports, and no
|
|
685
|
-
side effects on import**, so an app can persist and apply a theme without pulling the component
|
|
686
|
-
graph into its first-paint bundle.
|
|
610
|
+
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.
|
|
687
611
|
|
|
688
|
-
|
|
689
|
-
import {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
setLyraTheme({ accent: { brand: { light: "#2563eb", dark: "#f59e0b" } } }); // per-mode base color
|
|
696
|
-
setLyraTheme({ surface: "#0b0f1a" }); // mixes every ramp against this instead of the mode default
|
|
697
|
-
setLyraTheme({ mode: "auto" }); // follows the OS, including later changes
|
|
698
|
-
setLyraTheme({
|
|
699
|
-
tokens: {
|
|
700
|
-
"--lr-theme-border-radius-m": "0.5rem", // both modes
|
|
701
|
-
"--lr-theme-color-surface-default": { light: "#ffffff", dark: "#0a0a0a" }, // per mode
|
|
702
|
-
},
|
|
703
|
-
}); // replaces any previous token map wholesale
|
|
704
|
-
setLyraTheme({ tokens: null }); // back to whatever the stylesheets say
|
|
705
|
-
setLyraTheme({ mode: "unset", accent: null, surface: null, tokens: null }); // removes Lyra's overrides
|
|
706
|
-
```
|
|
612
|
+
~~~ts
|
|
613
|
+
import {
|
|
614
|
+
defineLyraLook,
|
|
615
|
+
getLyraStyle,
|
|
616
|
+
resetLyraStyle,
|
|
617
|
+
setLyraStyle,
|
|
618
|
+
} from "@aceshooting/lyra-ui/theme.js";
|
|
707
619
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
tab or a previous session is picked up cold. Where storage is unreadable or unwritable it
|
|
719
|
-
reports the theme last applied, so the return value always describes what the document is
|
|
720
|
-
actually showing and a toggle UI bound to it stays in sync.
|
|
721
|
-
- **`mode`** is `'light' | 'dark' | 'auto' | 'unset'`. `'light'`/`'dark'` set **both
|
|
722
|
-
`data-lr-theme`** (the
|
|
723
|
-
attribute `theme.css` actually keys its palette blocks on) **and `data-theme`** (the generic
|
|
724
|
-
attribute canvas-rendered components watch, so `lr-chart`/`lr-heatmap`/`lr-qr-code` repaint on
|
|
725
|
-
the switch rather than keeping stale colors — see `llms/components/lr-chart.md`). `'auto'`
|
|
726
|
-
resolves `prefers-color-scheme` immediately and keeps following changes. `'unset'` removes both
|
|
727
|
-
attributes; use it when the application owns mode selection through another cascade.
|
|
728
|
-
- **`accent`** is either an absolute CSS color — shorthand for `{ brand: <that color> }`, and the
|
|
729
|
-
only shape prior to 16.0.0 — or a per-role record
|
|
730
|
-
`{ brand?, success?, warning?, danger?, neutral? }`. Only the roles you supply are (re)derived;
|
|
731
|
-
an omitted role keeps whatever the static palette (`llms/tokens.md`) already provides. For each
|
|
732
|
-
supplied role, Lyra derives the complete quiet/normal/loud fill, border, and paired on-color
|
|
733
|
-
ramp as inline `--lr-theme-color-<role>-*` inputs; `brand` additionally keeps `--lr-theme-accent`
|
|
734
|
-
(a compatibility value holding the raw brand color, resolved for the active mode when the role
|
|
735
|
-
is per-mode) and `--lr-theme-color-focus`, which no other role drives. Each paired foreground is
|
|
736
|
-
selected for at least 4.5:1 contrast against its fill; normal/loud borders and the brand focus
|
|
737
|
-
color are adjusted to at least 3:1 against the resolved surface (see `surface` below). Malformed
|
|
738
|
-
values, CSS-wide keywords, `currentColor`, system colors, relative-color syntax, and unresolved
|
|
739
|
-
`var()` expressions fail closed to `null` — at the whole `accent` field for a bare-string call,
|
|
740
|
-
or at just that one role (or role/mode branch) for a per-role record, so one bad role does not
|
|
741
|
-
take the others down with it. Pass `accent: null` to restore the palette supplied by
|
|
742
|
-
`theme.css` entirely.
|
|
743
|
-
- **Per-mode accent.** Each role's value can itself be a bare color/`null` (applied to both
|
|
744
|
-
resolved modes, as above) or a `{ light?, dark? }` map deriving that role's ramp from a
|
|
745
|
-
genuinely *different base color* per resolved mode — not merely a different tint weight of the
|
|
746
|
-
same hue — for example `{ brand: { light: "#2563eb", dark: "#f59e0b" } }`. An omitted branch
|
|
747
|
-
(or a role/branch that fails validation) keeps that mode's inherited/palette default; the branch
|
|
748
|
-
actually painted follows the *resolved* mode, so it updates automatically when `mode: 'auto'`
|
|
749
|
-
follows a `prefers-color-scheme` change. The stored/returned/event-detail shape always mirrors
|
|
750
|
-
what you supplied (bare color or `{ light, dark }`), never collapsed to a single resolved color.
|
|
751
|
-
- **`surface`** is an absolute CSS color used as every role's ramp mix base, instead of the
|
|
752
|
-
shipped light/dark defaults (`#1a1a1a` dark / `#ffffff` light). It follows the same absolute
|
|
753
|
-
CSS color and fail-closed-to-`null` rules as `accent`; an alpha channel is composited against
|
|
754
|
-
the mode's own default surface before use. `null` (the default) keeps those shipped defaults.
|
|
755
|
-
Supplying `surface` changes the quiet/normal/loud mix ratios and every border/focus contrast
|
|
756
|
-
check for **every** currently-supplied role at once — it is one mix base per apply, not
|
|
757
|
-
per-role.
|
|
758
|
-
|
|
759
|
-
These are `--lr-theme-*` inputs, so they reach every nested shadow root — see "Where an override
|
|
760
|
-
actually reaches" above for why setting a `--lr-*` token instead would not.
|
|
761
|
-
- **`tokens`** is a map of `--lr-theme-*` inputs written inline on `<html>`, persisted and restored
|
|
762
|
-
before first paint like the other fields. Each value is a CSS string for both modes or a
|
|
763
|
-
`{ light?, dark? }` pair; a `null` or omitted branch leaves that mode to the stylesheets. A map
|
|
764
|
-
always **replaces** the previous one wholesale — compose with object spread
|
|
765
|
-
(`{ ...LYRA_SHADCN_THEME_PRESET.theme.tokens, "--lr-theme-border-radius-m": "0" }`) — and
|
|
766
|
-
`tokens: null`, `{}` or a map with no valid entry removes it; omitting `tokens` keeps the current
|
|
767
|
-
map. Per-mode branches apply only while Lyra resolves a mode, so `mode: "unset"` writes the bare
|
|
768
|
-
values only (use the `themes/*.css` stylesheet instead when an application-owned `.dark` class
|
|
769
|
-
decides the mode). Inline `--lr-theme-*` values your application sets itself on `<html>` and that
|
|
770
|
-
are not in a map are never touched; a name that *is* in the map is owned by the runtime while the
|
|
771
|
-
map is applied, and an earlier inline value for it is not restored on removal.
|
|
772
|
-
|
|
773
|
-
**Grammar and limits.** Invalid entries are dropped one by one (`setLyraTheme()` never throws;
|
|
774
|
-
`defineLyraThemePreset()` throws `TypeError` for the same cases). A name must match
|
|
775
|
-
`--lr-theme-[a-z0-9]+(-[a-z0-9]+)*`, be at most 80 characters, and not be `--lr-theme-accent`
|
|
776
|
-
(owned by `accent`). A value is trimmed and must be 1–256 characters; it may not contain a
|
|
777
|
-
control character or line break, a backslash, a backtick, any of
|
|
778
|
-
`; { } ! < > @ [ ] $ ^ | ~ = ? & :`, U+2028/U+2029, or a
|
|
779
|
-
comment delimiter; it may not be a CSS-wide keyword (`inherit`, `initial`, `unset`, `revert`,
|
|
780
|
-
`revert-layer`); every function must be one of `rgb rgba hsl hsla hwb lab lch oklab oklch color
|
|
781
|
-
color-mix light-dark calc min max clamp var cubic-bezier steps linear` (so `url()`, `image-set()`,
|
|
782
|
-
`attr()`, `env()` and unknown functions are rejected); and parentheses and quotes must balance. A
|
|
783
|
-
map holds at most 512 entries (more normalizes to no map at all). The check is DOM-free, so
|
|
784
|
-
`defineLyraThemePreset()`, the runtime, the bootstrap and the preset generator apply it
|
|
785
|
-
identically.
|
|
786
|
-
|
|
787
|
-
**Contrast floor.** With a resolved mode, colour families the static contrast gate checks are
|
|
788
|
-
measured before they are written; a failing value is replaced by the nearest passing mix toward
|
|
789
|
-
black or white, serialized as `rgb(r g b)`, and a passing value is written verbatim. The snapshot
|
|
790
|
-
and the stored record always keep the value you supplied. The references are the explicit
|
|
791
|
-
`surface`, else the map's `--lr-theme-color-surface-default`, else the mode default (**S**:
|
|
792
|
-
`#ffffff` / `#1a1a1a`); the map's `color-surface-raised` else `#f6f8fa` / `#22272e` (**R**); the
|
|
793
|
-
painted `color-text-normal` else `#1a1a1a` / `#f2f2f2` (**T**); and the map's
|
|
794
|
-
`color-overlay-strong` else black at 0.92 / 0.95 over S (**O**). Names below omit `--lr-theme-`:
|
|
795
|
-
|
|
796
|
-
| Tokens | Against | Floor |
|
|
797
|
-
| --- | --- | --- |
|
|
798
|
-
| `color-text-normal`, `color-text-quiet` | S and R | 4.5 |
|
|
799
|
-
| `color-<role>-on-<tier>`, when its `color-<role>-fill-<tier>` is in the map (a missing on-* is synthesized) | its fill | 4.5 |
|
|
800
|
-
| `color-on-strong-overlay` (synthesized when only `color-overlay-strong` is in the map) | O | 4.5 |
|
|
801
|
-
| `color-<role>-border-normal`/`-loud`, `color-surface-border`, `color-border-strong`, `color-focus` | S | 3 |
|
|
802
|
-
| `color-chart-<n>` | S | 3 |
|
|
803
|
-
| `terminal-color-<name>` | R | 4.5 |
|
|
804
|
-
| `terminal-bg-<name>` | T | 4.5 |
|
|
805
|
-
|
|
806
|
-
**Unchecked, written verbatim:** `*-border-quiet` and `color-surface-border-subtle` (decorative by
|
|
807
|
-
contract); `color-<role>-fill-*` (measured through their on-* partner); an on-* whose fill-* is not
|
|
808
|
-
in the same map; `color-surface-default`, `-raised` and `-overlay` (references, not foregrounds —
|
|
809
|
-
text on `color-surface-overlay` is not measured); `color-overlay`, `color-no-data` and
|
|
810
|
-
`color-mix-partner`; chart-series colour-vision separation (the static gate only); every
|
|
811
|
-
non-colour token (fonts, radii, sizes, shadows, durations — including
|
|
812
|
-
`--lr-theme-icon-button-size`, whose target-size floor is yours to keep); and any value or
|
|
813
|
-
reference that does not resolve to a colour — `var()`, `light-dark()`, relative colours,
|
|
814
|
-
`currentColor`, system colours, and **every** value when a canvas is unavailable (no 2D context,
|
|
815
|
-
or pixel reads blocked). An unresolved row is written verbatim and synthesizes nothing; the accent
|
|
816
|
-
still fails closed as it always has. The runtime never reads computed styles, so a reference an
|
|
817
|
-
application stylesheet changes without the map carrying it is not seen.
|
|
818
|
-
|
|
819
|
-
**Precedence.** accent ramp (for the roles it paints) > runtime tokens (inline on `<html>`) >
|
|
820
|
-
your unlayered CSS > `lr-theme-preset` (`themes/shadcn.css`) > `lr-theme` (`theme.css`) >
|
|
821
|
-
component fallbacks. Runtime tokens therefore beat an unlayered `:root { --lr-theme-*: … }`
|
|
822
|
-
override, like the accent does; put your override in the map instead. An element that re-declares
|
|
823
|
-
a `--lr-theme-*` input itself — a `.lr-dark`/`data-lr-theme` island, a `data-lr-theme`-pinned
|
|
824
|
-
component, app-scoped CSS — keeps its own value inside that subtree (the accent ramp has the same
|
|
825
|
-
limitation).
|
|
826
|
-
|
|
827
|
-
**Snapshots.** `getLyraTheme()`, the stored record and the `lr-theme-change` /
|
|
828
|
-
`lr-theme-preset-change` details carry `tokens` **only while a map is applied** — the key is
|
|
829
|
-
absent, not `null`, otherwise, on every path including unwritable storage and the automatic mode
|
|
830
|
-
flip. The map is normalized and deep-frozen: trimmed strings, and every per-mode entry carries
|
|
831
|
-
both `light` and `dark` (`null` for a missing branch).
|
|
832
|
-
- **Unbalanced colours fail closed.** An `accent` (any role or branch) or `surface` with an
|
|
833
|
-
unclosed parenthesis or quote, such as `rgb(0 0 0`, is rejected to `null` like every other
|
|
834
|
-
malformed value. The browser's own parser closes such a construct implicitly, but written raw
|
|
835
|
-
into an inline `style` it swallows the declarations after it when that attribute is re-parsed.
|
|
836
|
-
|
|
837
|
-
**Theme presets.** `@aceshooting/lyra-ui/theme/presets.js` exports
|
|
838
|
-
`LYRA_THEME_PRESETS`, `defineLyraThemePreset()` and `applyLyraThemePreset()`. Built-in keys are
|
|
839
|
-
`system`, `light`, `dark`, `unset`, `emerald`, `ruby`, `amethyst`, and `sapphire`; the gemstone
|
|
840
|
-
presets use system-following mode plus the named brand accent. Application presets use a stable
|
|
841
|
-
lowercase kebab-case `id` and a `theme: { mode?, accent?, surface? }` record — the same shapes
|
|
842
|
-
`setLyraTheme()` accepts, including a per-role `accent` record. `defineLyraThemePreset()`
|
|
843
|
-
validates the id and field shapes, freezes both records, and leaves CSS color-syntax validation to
|
|
844
|
-
the production runtime when the preset is applied:
|
|
620
|
+
setLyraStyle({ mode: "dark" }); // unspecified axes keep their current value
|
|
621
|
+
setLyraStyle({ accent: "sapphire" }); // named palette accent
|
|
622
|
+
setLyraStyle({ accent: "#7c3aed" }); // absolute CSS color
|
|
623
|
+
setLyraStyle({ accentBackground: "#0b0f1a" }); // reference surface for accent ramps
|
|
624
|
+
setLyraStyle({ mode: "system" }); // follows prefers-color-scheme
|
|
625
|
+
setLyraStyle({ look: "shadcn", surface: "glass", density: "compact" });
|
|
626
|
+
const style = getLyraStyle();
|
|
627
|
+
resetLyraStyle(["look"]); // reset only the look axis
|
|
628
|
+
setLyraStyle({ mode: "unset", accent: null, accentBackground: null, overrides: null });
|
|
629
|
+
~~~
|
|
845
630
|
|
|
846
|
-
|
|
847
|
-
import {
|
|
848
|
-
applyLyraThemePreset,
|
|
849
|
-
defineLyraThemePreset,
|
|
850
|
-
} from "@aceshooting/lyra-ui/theme/presets.js";
|
|
851
|
-
|
|
852
|
-
applyLyraThemePreset("sapphire");
|
|
853
|
-
applyLyraThemePreset(
|
|
854
|
-
defineLyraThemePreset({
|
|
855
|
-
id: "application-ocean",
|
|
856
|
-
theme: {
|
|
857
|
-
mode: "dark",
|
|
858
|
-
accent: { brand: "#22d3ee", danger: "#dc2626" },
|
|
859
|
-
surface: "#0b0f1a",
|
|
860
|
-
},
|
|
861
|
-
})
|
|
862
|
-
);
|
|
863
|
-
```
|
|
631
|
+
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.
|
|
864
632
|
|
|
865
|
-
|
|
866
|
-
runtime validation, Lyra reflects the id to `data-lr-theme-preset` and emits
|
|
867
|
-
`lr-theme-preset-change` on `window` with `{ id, theme }`, where `theme` is the complete applied
|
|
868
|
-
snapshot. If runtime validation changes a field (for example, an invalid accent fails closed to
|
|
869
|
-
`null`), only the ordinary `lr-theme-change` event is emitted and no preset marker is written,
|
|
870
|
-
because the resulting state is not exactly that named preset. A direct `setLyraTheme()` call also
|
|
871
|
-
removes the preset marker.
|
|
872
|
-
|
|
873
|
-
**Token presets: a look as its own axis.** A preset's `theme` may carry `tokens` (see `tokens`
|
|
874
|
-
above). `defineLyraThemePreset()` validates the whole map against the same grammar the runtime
|
|
875
|
-
applies and throws `TypeError` on any violation, so a map it accepts is never changed at run time and
|
|
876
|
-
the preset still claims its marker — even where a canvas is unavailable. A look is independent of
|
|
877
|
-
mode, accent and surface: a preset that omits those fields leaves them as they are, and the built-in
|
|
878
|
-
presets never mention `tokens`, so `applyLyraThemePreset("sapphire")` or `"dark"` keeps the current
|
|
879
|
-
look. Either order reaches the same state; only the marker (the last applied id) differs. The
|
|
880
|
-
shadcn look ships as a generated runtime preset, built from `themes/shadcn.css` so the two can never
|
|
881
|
-
drift:
|
|
633
|
+
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.
|
|
882
634
|
|
|
883
|
-
|
|
884
|
-
import { applyLyraThemePreset, defineLyraThemePreset } from "@aceshooting/lyra-ui/theme/presets.js";
|
|
885
|
-
import { LYRA_SHADCN_THEME_PRESET } from "@aceshooting/lyra-ui/theme/presets/shadcn.js";
|
|
886
|
-
|
|
887
|
-
applyLyraThemePreset(LYRA_SHADCN_THEME_PRESET); // look on; mode, accent and surface kept
|
|
888
|
-
applyLyraThemePreset("sapphire"); // an accent on top of the look
|
|
889
|
-
|
|
890
|
-
// The exact stylesheet rendering (no accent ramp, default surface), keeping a marker:
|
|
891
|
-
applyLyraThemePreset(
|
|
892
|
-
defineLyraThemePreset({
|
|
893
|
-
id: "shadcn-exact",
|
|
894
|
-
theme: { ...LYRA_SHADCN_THEME_PRESET.theme, accent: null, surface: null },
|
|
895
|
-
})
|
|
896
|
-
);
|
|
897
|
-
```
|
|
635
|
+
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.
|
|
898
636
|
|
|
899
|
-
|
|
900
|
-
before first paint, needs no stylesheet swap, and is written inline, so it beats unlayered `:root`
|
|
901
|
-
overrides. The `themes/shadcn.css` stylesheet is the one to use for light/dark **islands**, for an
|
|
902
|
-
application-owned `.dark`/`.light` class, or for a page with no theme runtime. The runtime preset
|
|
903
|
-
module is a separate subpath, so an application that only uses `presets.js` pays nothing for it.
|
|
904
|
-
|
|
905
|
-
**No-flash bootstrap.** `lyraThemeBootstrap` is a self-contained IIFE **string** (not a function),
|
|
906
|
-
meant to be inlined into a `<script>` in `<head>` **before any stylesheet**, so the persisted theme
|
|
907
|
-
is on the root element before first paint. It reads `localStorage['lyra-theme']`.
|
|
908
|
-
`createLyraThemeBootstrap({ storageKey })` returns the same kind of string for an application-owned
|
|
909
|
-
key, so an existing persistence layer can reuse the pre-paint half independently of
|
|
910
|
-
`setLyraTheme()`/`getLyraTheme()`. Calling the factory with no options returns the same string as
|
|
911
|
-
`lyraThemeBootstrap`. The result is a string precisely so this can happen in an unbundled
|
|
912
|
-
`<script>` context without shipping or parsing the module. Custom keys are escaped against HTML
|
|
913
|
-
script termination and JavaScript line separators. Under a Content Security Policy, give the
|
|
914
|
-
inline script the nonce or hash required by the application:
|
|
637
|
+
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.
|
|
915
638
|
|
|
916
|
-
|
|
639
|
+
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.
|
|
640
|
+
|
|
641
|
+
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.
|
|
642
|
+
|
|
643
|
+
**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.
|
|
644
|
+
|
|
645
|
+
The bootstrap string can be inlined with the application's CSP nonce or hash:
|
|
646
|
+
|
|
647
|
+
~~~html
|
|
917
648
|
<head>
|
|
918
649
|
<script>
|
|
919
650
|
/* server-inlines lyraThemeBootstrap here */
|
|
920
651
|
</script>
|
|
921
652
|
<link rel="stylesheet" href="/theme.css" />
|
|
922
653
|
</head>
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
Both variants read a stored `{ mode, accent, surface }` record, resolve `auto`, and derive the same
|
|
926
|
-
per-role ramp(s) from the same math — the bootstrap re-implements it inline (self-contained, so it
|
|
927
|
-
can run before any module loads) rather than importing the runtime, but the two are tested to never
|
|
928
|
-
drift. A missing or malformed record receives the runtime's
|
|
929
|
-
`{ mode: 'auto', accent: null, surface: null }` default; blocked `localStorage` leaves the document
|
|
930
|
-
untouched rather than throwing before your app loads.
|
|
931
|
-
|
|
932
|
-
The stored record also carries `tokens` while a map is applied, and the bootstrap restores it
|
|
933
|
-
before first paint: the same grammar, the same per-mode branch for the resolved mode, and the same
|
|
934
|
-
contrast floor as the runtime. It records the names it wrote on `<html>`, so the runtime's first
|
|
935
|
-
apply removes or rewrites exactly those. Token values are read from storage at run time and never
|
|
936
|
-
serialized into the script string. **The bootstrap's bytes change with library releases** — this
|
|
937
|
-
one included — so a deployment that pins a CSP hash for the inline script (or for
|
|
938
|
-
`theme-bootstrap.js`) must regenerate that hash when upgrading, or the browser blocks the bootstrap
|
|
939
|
-
and the first-paint flash returns.
|
|
940
|
-
|
|
941
|
-
**External-file delivery for a strict CSP.** `@aceshooting/lyra-ui/theme-bootstrap.js` is a
|
|
942
|
-
third, non-module way to ship the same bootstrap: a static script asset published alongside the
|
|
943
|
-
package, containing exactly `lyraThemeBootstrap`'s bytes (both are produced from the same build
|
|
944
|
-
step, so they can never drift apart). Reference it with a plain `<script src>` in `<head>`,
|
|
945
|
-
still before any stylesheet:
|
|
946
|
-
|
|
947
|
-
```html
|
|
948
|
-
<head>
|
|
949
|
-
<script src="/vendor/theme-bootstrap.js"></script>
|
|
950
|
-
<link rel="stylesheet" href="/theme.css" />
|
|
951
|
-
</head>
|
|
952
|
-
```
|
|
654
|
+
~~~
|
|
953
655
|
|
|
954
|
-
|
|
955
|
-
per-response nonce — a static HTML entry, for example — where the documented inline-script
|
|
956
|
-
nonce/hash guidance above does not apply. Serving it same-origin (copy it into your build output,
|
|
957
|
-
or configure your bundler/static host to do so) needs no hash at all; hashing it for an even
|
|
958
|
-
stricter policy uses the same CSP `script-src` hash mechanism browsers already apply to any
|
|
959
|
-
external script resource.
|
|
656
|
+
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.
|
|
960
657
|
|
|
961
|
-
**
|
|
962
|
-
as a plain classic script — never `type="module"` and never `async` — because it reads its own
|
|
963
|
-
configuration synchronously through `document.currentScript` while it runs, and that property is
|
|
964
|
-
`null` for both of those loading modes (as well as for anything scheduled after the script has
|
|
965
|
-
already finished executing). Two optional attributes on that same `<script>` tag override the
|
|
966
|
-
defaults without regenerating the file:
|
|
658
|
+
**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).
|
|
967
659
|
|
|
968
|
-
|
|
969
|
-
<head>
|
|
970
|
-
<script
|
|
971
|
-
src="/vendor/theme-bootstrap.js"
|
|
972
|
-
data-lr-theme-storage-key="my-app-theme"
|
|
973
|
-
data-lr-theme-attributes="data-lr-theme data-theme"
|
|
974
|
-
></script>
|
|
975
|
-
<link rel="stylesheet" href="/theme.css" />
|
|
976
|
-
</head>
|
|
977
|
-
```
|
|
978
|
-
|
|
979
|
-
- `data-lr-theme-storage-key` — the `localStorage` key to read, in place of the default
|
|
980
|
-
`'lyra-theme'`. Equivalent to `createLyraThemeBootstrap({ storageKey })`'s argument, but
|
|
981
|
-
resolved by the static file itself at parse time rather than baked in ahead of time. This is
|
|
982
|
-
what lets an application with its own pre-existing storage key use the static asset instead of
|
|
983
|
-
inlining a per-app copy.
|
|
984
|
-
- `data-lr-theme-attributes` — a space-separated list of attribute names to set on
|
|
985
|
-
`<html>` in place of the default `data-lr-theme data-theme` pair, replacing that list entirely
|
|
986
|
-
rather than adding to it.
|
|
987
|
-
|
|
988
|
-
Both attributes are optional and independently validated; an absent, empty, oversized, or
|
|
989
|
-
malformed value falls back to the built-in default rather than throwing, so a `<script>` tag with
|
|
990
|
-
neither attribute — every existing deployment — behaves exactly as before. `data-lr-theme-storage-key`
|
|
991
|
-
must be a non-empty string of at most 200 characters (its content is otherwise unrestricted — it is
|
|
992
|
-
only ever used as an opaque `localStorage` key, never written to the DOM). `data-lr-theme-attributes`
|
|
993
|
-
must parse to one to eight tokens, each unique and each matching `data-[a-z0-9]+(-[a-z0-9]+)*` —
|
|
994
|
-
which rejects an event-handler name (`onload`), a native attribute (`style`, `class`, `id`), any
|
|
995
|
-
token containing whitespace, a quote, `=`, or a control character, an empty list, and a duplicated
|
|
996
|
-
token — because these attribute names reach `setAttribute()`/`removeAttribute()` on the document
|
|
997
|
-
root. A `document.currentScript` of `null` (module/async misuse, or a script tag re-read after it
|
|
998
|
-
finished running) is treated the same as no configuration at all.
|
|
999
|
-
|
|
1000
|
-
An application-owned key from `createLyraThemeBootstrap({ storageKey })` can still be inlined as
|
|
1001
|
-
documented above; the static file's own script-tag attributes are the alternative for a strict-CSP
|
|
1002
|
-
deployment that cannot inline that call.
|
|
1003
|
-
|
|
1004
|
-
**Migrating from 15.x.** `accent` used to be exactly an absolute CSS color or `null`; that shape
|
|
1005
|
-
still works unchanged (`setLyraTheme({ accent: '#7c3aed' })` keeps deriving only the brand ramp).
|
|
1006
|
-
What changed is `LyraTheme` gaining a `surface` field alongside it — a strict superset for every
|
|
1007
|
-
caller that only ever read/wrote `mode`/`accent`, since `getLyraTheme()` now also returns
|
|
1008
|
-
`surface: null` by default. Only code that structurally compares the whole returned record (for
|
|
1009
|
-
example `assert.deepEqual(getLyraTheme(), { mode, accent })`) needs the extra field added.
|
|
1010
|
-
|
|
1011
|
-
**`tokens` is optional and absent unless used.** `LyraTheme` also gains an optional `tokens` field;
|
|
1012
|
-
`getLyraTheme()`, the stored record and both event details omit the key entirely until a token map
|
|
1013
|
-
is applied, so `assert.deepEqual(getLyraTheme(), { mode, accent, surface })` keeps passing.
|
|
660
|
+
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.
|
|
1014
661
|
|
|
1015
662
|
### Invalidating canvas theme values
|
|
1016
663
|
|
|
@@ -1031,267 +678,27 @@ canvas consumer's redraw to its normal microtask/render schedule. The optional r
|
|
|
1031
678
|
browser realm; it does not limit invalidation to a subtree. The function is a no-op during server
|
|
1032
679
|
rendering and retains no document or stylesheet after the last canvas consumer disconnects.
|
|
1033
680
|
|
|
1034
|
-
|
|
681
|
+
<!-- focused-native-styles:start -->
|
|
682
|
+
### Optional native styles and CSS utilities
|
|
1035
683
|
|
|
1036
|
-
|
|
1037
|
-
barrel, a component entry, or `theme.css`, so applications that do not opt in keep their existing
|
|
1038
|
-
native-element and utility conventions unchanged.
|
|
684
|
+
The complete native CSS and utility contract is in the [native styles guide](./native-styles-and-utilities.md#optional-native-styles-and-css-utilities).
|
|
1039
685
|
|
|
1040
|
-
|
|
1041
|
-
@import "@aceshooting/lyra-ui/native.css";
|
|
1042
|
-
@import "@aceshooting/lyra-ui/utilities.css";
|
|
1043
|
-
```
|
|
686
|
+
#### Utility class inventory
|
|
1044
687
|
|
|
1045
|
-
|
|
1046
|
-
**descendants** of an explicit `.lr-native` scope. It has no `:root`, `html`, `body`, or unscoped
|
|
1047
|
-
reset, and the element carrying `.lr-native` is not styled by the native bundle itself. The rules
|
|
1048
|
-
stay in light DOM: they do not pierce a component's shadow root.
|
|
688
|
+
[Read the utility classes](./native-styles-and-utilities.md#utility-class-inventory).
|
|
1049
689
|
|
|
1050
|
-
|
|
1051
|
-
<section class="lr-native">
|
|
1052
|
-
<h2>Profile</h2>
|
|
1053
|
-
<label for="profile-name">Display name</label>
|
|
1054
|
-
<input id="profile-name" />
|
|
1055
|
-
<button type="button">Save</button>
|
|
1056
|
-
</section>
|
|
1057
|
-
```
|
|
690
|
+
#### Typography
|
|
1058
691
|
|
|
1059
|
-
|
|
1060
|
-
uses a substring class selector, so a class such as `app-lr-flex-preview` does not opt in. Both
|
|
1061
|
-
assets repeat `@layer lr-base, lr-theme, lr-theme-preset, lr-utilities, lr-overrides`; an ordinary unlayered
|
|
1062
|
-
application rule therefore beats them regardless of load order. A third opt-in asset,
|
|
1063
|
-
[`tokens-root.css`](#reading-the-resolved-tokens-from-your-own-components--tokens-rootcss), is not a
|
|
1064
|
-
style sheet in the same sense — it declares custom properties only, and exists so your own
|
|
1065
|
-
components can read the resolved `--lr-*` tokens these two are written against.
|
|
1066
|
-
|
|
1067
|
-
### Utility class inventory
|
|
1068
|
-
|
|
1069
|
-
| Group | Exact classes |
|
|
1070
|
-
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1071
|
-
| Display and composition | `lr-block`, `lr-inline-block`, `lr-flex`, `lr-inline-flex`, `lr-grid`, `lr-flow-root`, `lr-stack`, `lr-cluster`, `lr-grid-auto` |
|
|
1072
|
-
| Flex direction and wrapping | `lr-row`, `lr-column`, `lr-wrap`, `lr-nowrap`, `lr-grow`, `lr-grow-0`, `lr-shrink`, `lr-shrink-0` |
|
|
1073
|
-
| Item alignment | `lr-items-start`, `lr-items-center`, `lr-items-end`, `lr-items-stretch`, `lr-items-baseline`, `lr-self-start`, `lr-self-center`, `lr-self-end`, `lr-self-stretch` |
|
|
1074
|
-
| Distribution | `lr-justify-start`, `lr-justify-center`, `lr-justify-end`, `lr-justify-between`, `lr-justify-around` |
|
|
1075
|
-
| Gaps | `lr-gap-0`, `lr-gap-xs`, `lr-gap-s`, `lr-gap-m`, `lr-gap-l`, `lr-gap-2xl` |
|
|
1076
|
-
| Logical sizing | `lr-inline-full`, `lr-block-full`, `lr-size-full`, `lr-min-inline-0`, `lr-min-block-0`, `lr-max-inline-full`, `lr-max-inline-prose`, `lr-center` |
|
|
1077
|
-
| Overflow | `lr-overflow-auto`, `lr-overflow-hidden` |
|
|
1078
|
-
| Text alignment and size | `lr-text-start`, `lr-text-center`, `lr-text-end`, `lr-text-xs`, `lr-text-sm`, `lr-text-base`, `lr-text-lg`, `lr-text-xl`, `lr-text-quiet` |
|
|
1079
|
-
| Font | `lr-font-normal`, `lr-font-medium`, `lr-font-semibold`, `lr-font-bold`, `lr-font-mono` |
|
|
1080
|
-
| Text flow | `lr-text-break`, `lr-text-nowrap`, `lr-truncate`, `lr-text-balance`, `lr-text-pretty`, `lr-prose` |
|
|
1081
|
-
| Typography | `lr-typography`, `lr-not-typography`, `lr-heading-1`, `lr-heading-2`, `lr-heading-3`, `lr-heading-4`, `lr-inline-code` |
|
|
1082
|
-
| Visibility and focus | `lr-visually-hidden`, `lr-visually-hidden-focusable`, `lr-fouce-hidden`, `lr-hidden` |
|
|
1083
|
-
| Page allocation | `lr-page-mobile-only`, `lr-page-desktop-only` |
|
|
1084
|
-
|
|
1085
|
-
`lr-fouce-hidden` hides only an opted-in custom element while it matches `:not(:defined)`, then
|
|
1086
|
-
reveals it automatically after registration. `lr-visually-hidden-focusable` becomes visible on
|
|
1087
|
-
focus or when a descendant receives focus, making it suitable for skip links.
|
|
1088
|
-
|
|
1089
|
-
The Page helpers key off the reflected `view` state of their containing `<lr-page>`:
|
|
1090
|
-
`lr-page-mobile-only` is hidden for `view="desktop"`, and `lr-page-desktop-only` is hidden for
|
|
1091
|
-
`view="mobile"`. Page derives that state from its own allocated inline size, not the viewport.
|
|
1092
|
-
|
|
1093
|
-
### Typography
|
|
1094
|
-
|
|
1095
|
-
`utilities.css` also carries an opt-in typography look for light-DOM content. Nothing changes for
|
|
1096
|
-
markup that does not use these classes.
|
|
1097
|
-
|
|
1098
|
-
- **Scope** — `lr-typography` styles bare `h1`–`h6`, `p`, `a[href]`, `blockquote`, `ul`/`ol`/`li`,
|
|
1099
|
-
inline `code` (not `pre code`) and `table`/`th`/`td`/`tr` **descendants**, and spaces its direct
|
|
1100
|
-
children. Use it for CMS or Markdown-rendered HTML you cannot annotate element by element.
|
|
1101
|
-
- **Roles** — `lr-heading-1` … `lr-heading-4` give any element a heading level's look without
|
|
1102
|
-
changing its semantic level; `lr-inline-code` gives one element the inline-code chip. Role classes
|
|
1103
|
-
apply anywhere, including inside a boundary, and an explicit role beats the element's own level
|
|
1104
|
-
inside the scope (`<h3 class="lr-heading-1">` renders heading-1).
|
|
1105
|
-
- **Boundary** — `lr-not-typography` removes an element and its whole subtree from every element
|
|
1106
|
-
look. Use it around layout lists (`<ul class="lr-cluster">` tag rows, nav), embedded widgets and
|
|
1107
|
-
component clusters. A nested `lr-typography` inside a boundary is not re-enabled.
|
|
1108
|
-
- **Named-slot children are skipped.** A child with a `slot` attribute (`<lr-card><h2
|
|
1109
|
-
slot="header">`) is component chrome and keeps the component's own styling; default-slot content
|
|
1110
|
-
is styled.
|
|
1111
|
-
- **The scope element itself is never styled.** It sets no font, size, colour or margin, so it can
|
|
1112
|
-
sit on an app region. `<blockquote class="lr-typography">` does nothing: wrap single elements.
|
|
1113
|
-
Root font and colour come from the page, from `lr-prose` or from `lr-native`
|
|
1114
|
-
(`class="lr-prose lr-typography"` is the usual pairing).
|
|
1115
|
-
|
|
1116
|
-
Choose the element for the document outline and the class for the look: `<h2 class="lr-heading-1">`
|
|
1117
|
-
for a visually dominant section heading, never `<div class="lr-heading-1">`.
|
|
1118
|
-
|
|
1119
|
-
| Element in `lr-typography` | Role class | Look |
|
|
1120
|
-
| -------------------------- | ---------------- | -------------------------------------------------------------------------------------- |
|
|
1121
|
-
| `h1` | `lr-heading-1` | `--lr-font-size-3xl`, bold, compact leading |
|
|
1122
|
-
| `h2` | `lr-heading-2` | `--lr-font-size-2xl`, semibold, subtle bottom rule with `--lr-space-s` padding |
|
|
1123
|
-
| `h3` | `lr-heading-3` | `--lr-font-size-xl`, semibold |
|
|
1124
|
-
| `h4` | `lr-heading-4` | `--lr-font-size-lg`, semibold |
|
|
1125
|
-
| `h5` / `h6` | — | `--lr-font-size-m` / `--lr-font-size-sm`, semibold |
|
|
1126
|
-
| `p` | — | `--lr-line-height-loose` |
|
|
1127
|
-
| `a[href]` | — | `--lr-color-brand`, always underlined; the underline thickens on hover |
|
|
1128
|
-
| `blockquote` | — | italic, subtle `--lr-border-width-medium` inline-start edge, inherited colour |
|
|
1129
|
-
| `ul` / `ol` | — | `--lr-space-2xl` indent, markers restated (disc/circle/square, decimal), item rhythm |
|
|
1130
|
-
| inline `code` | `lr-inline-code` | mono chip on `--lr-color-neutral-fill-quiet`, `0.875em`, semibold; inherits link colour |
|
|
1131
|
-
| `table` | — | full width, collapsed subtle cell borders, bold `th`, `--lr-color-surface-raised` zebra |
|
|
1132
|
-
|
|
1133
|
-
Headings, role classes and quotes inherit their colour, so a role class inside a banner or alert
|
|
1134
|
-
keeps that surface's text colour. Heading tracking reads `--lr-heading-letter-spacing`, then the
|
|
1135
|
-
`--lr-theme-heading-letter-spacing` theme input, then `normal`.
|
|
1136
|
-
|
|
1137
|
-
**Lead, large, small and muted** are compositions of existing utilities:
|
|
1138
|
-
|
|
1139
|
-
| Look | Classes |
|
|
1140
|
-
| ----- | ------------------------------- |
|
|
1141
|
-
| Lead | `lr-text-xl lr-text-quiet` |
|
|
1142
|
-
| Large | `lr-text-lg lr-font-semibold` |
|
|
1143
|
-
| Small | `lr-text-sm lr-font-medium` |
|
|
1144
|
-
| Muted | `lr-text-sm lr-text-quiet` |
|
|
1145
|
-
|
|
1146
|
-
For an exact 0.875rem muted/small size, use a class of your own with the token chain (resolved
|
|
1147
|
-
`--lr-*` tokens are undefined at document scope unless `tokens-root.css` is loaded):
|
|
692
|
+
[Read the light-DOM typography rules](./native-styles-and-utilities.md#typography).
|
|
1148
693
|
|
|
1149
|
-
|
|
1150
|
-
.app-muted {
|
|
1151
|
-
font-size: var(--lr-font-size-md-sm, var(--lr-theme-font-size-md-sm, 0.875rem));
|
|
1152
|
-
}
|
|
1153
|
-
.app-small {
|
|
1154
|
-
font-size: var(--lr-font-size-md-sm, var(--lr-theme-font-size-md-sm, 0.875rem));
|
|
1155
|
-
line-height: var(--lr-line-height-none, var(--lr-theme-line-height-none, 1));
|
|
1156
|
-
}
|
|
1157
|
-
```
|
|
1158
|
-
|
|
1159
|
-
Combine `.app-muted` with `lr-text-quiet`, and `.app-small` with `lr-font-medium`.
|
|
1160
|
-
|
|
1161
|
-
**Precedence.** Every selector has zero specificity, so source order and layers decide:
|
|
1162
|
-
|
|
1163
|
-
1. The typography element looks and role classes open the `lr-utilities` layer, so any other `lr-*`
|
|
1164
|
-
utility on the same element wins: `class="lr-heading-2 lr-text-quiet"` is a quiet heading, and a
|
|
1165
|
-
scope `<blockquote class="lr-center">` is centred.
|
|
1166
|
-
2. An explicit heading role class beats the element's own scope look (`<h2 class="lr-heading-4">`
|
|
1167
|
-
has no bottom rule).
|
|
1168
|
-
3. In `class="lr-prose lr-typography"`, `lr-prose` keeps the measure, root type and colour, and the
|
|
1169
|
-
typography element looks and heading-aware spacing win. Inside a boundary, or on a named-slot
|
|
1170
|
-
child, `lr-prose` applies exactly as before. Plain `lr-prose` output is unchanged.
|
|
1171
|
-
4. `lr-utilities` beats `lr-base`, so the scope beats `lr-native` normalization, including its link,
|
|
1172
|
-
quote and heading colours.
|
|
1173
|
-
5. A layered reset (such as Tailwind's `base` preflight) loses only when you declare the documented
|
|
1174
|
-
layer order first — see [Using the light-DOM stylesheets with a CSS
|
|
1175
|
-
reset](#using-the-light-dom-stylesheets-with-a-css-reset-tailwind-v4-preflight-and-similar).
|
|
1176
|
-
Authored `type` (lists) and `align` (cells) attributes are presentational hints that any author
|
|
1177
|
-
rule, including a reset, overrides.
|
|
1178
|
-
|
|
1179
|
-
Any unlayered application rule beats all of the above.
|
|
1180
|
-
|
|
1181
|
-
**Flow.** Every direct, non-slotted child of the scope has its block margins replaced by
|
|
1182
|
-
`--lr-prose-flow-space` (default `--lr-space-l`), and a heading gets twice that space before it.
|
|
1183
|
-
That includes wrappers, `hr`, `img`, `details`, `section` and `lr-*` elements, so a component's own
|
|
1184
|
-
host margin is overridden at that position (wrap it in a `<div>` to keep it). Flow counts the
|
|
1185
|
-
immediately preceding element sibling, including non-rendered ones (`<style>`, `<template>`,
|
|
1186
|
-
`[hidden]`), so keep those out of the scope's direct children. Blocks nested inside `li` or
|
|
1187
|
-
`blockquote` keep the page's own margins. Do not put `lr-stack`/`lr-cluster` on the scope element
|
|
1188
|
-
itself — gap and flow margins would add up (set `--lr-prose-flow-space: 0` if you must).
|
|
1189
|
-
|
|
1190
|
-
**Wide tables** go in a focusable, labelled scroll region, labelled by the table's own caption:
|
|
1191
|
-
|
|
1192
|
-
```html
|
|
1193
|
-
<div class="lr-overflow-auto" role="region" aria-labelledby="pricing-caption" tabindex="0">
|
|
1194
|
-
<table>
|
|
1195
|
-
<caption id="pricing-caption">Plans and prices</caption>
|
|
1196
|
-
…
|
|
1197
|
-
</table>
|
|
1198
|
-
</div>
|
|
1199
|
-
```
|
|
1200
|
-
|
|
1201
|
-
**Differences from the shadcn/ui look.** Values come from Lyra's scale:
|
|
1202
|
-
|
|
1203
|
-
| Element | Lyra | shadcn/ui |
|
|
1204
|
-
| --------------------- | ------------------------------------------------------------- | --------------------------------------- |
|
|
1205
|
-
| Heading sizes | 2 / 1.75 / 1.25 / 1.125rem | 2.25 / 1.875 / 1.5 / 1.25rem |
|
|
1206
|
-
| h1 weight | 700 | 800 |
|
|
1207
|
-
| Tracking | `normal` unless the hook or theme input sets it; `themes/shadcn.css` sets -0.025em | tight |
|
|
1208
|
-
| Flow spacing | 1rem (`--lr-prose-flow-space`) | 1.5rem |
|
|
1209
|
-
| Space before headings | 2 × flow = 2rem for every level | 2.5rem before h2, 2rem before h3 |
|
|
1210
|
-
| Paragraph leading | 1.6 | 1.75rem |
|
|
1211
|
-
| Quote and list indent | 1rem and 2rem | 1.5rem each |
|
|
1212
|
-
| Inline code size | 0.875em (scales inside headings) | 0.875rem |
|
|
1213
|
-
| Inline code padding | 0.25rem inline / 0.125rem block | 0.3rem / 0.2rem |
|
|
1214
|
-
| Table stripe | `--lr-color-surface-raised` (matches `lr-data-grid`) | muted fill |
|
|
1215
|
-
| Links | brand colour, inherited weight, underline | primary colour, medium weight, underline |
|
|
1216
|
-
| Muted and small size | 0.8125rem via `lr-text-sm` (exact recipe above) | 0.875rem |
|
|
1217
|
-
| Small line-height | inherited (exact recipe above) | 1 |
|
|
1218
|
-
|
|
1219
|
-
**Languages.** Only logical properties are used, so edges and indents mirror under `dir="rtl"`.
|
|
1220
|
-
Blockquotes under `:lang()` `ar`, `fa`, `ur`, `ps`, `ckb`, `sd`, `ug`, `syr`, `he`, `yi`, `ja`, `ko`
|
|
1221
|
-
and `zh` are not italic (those scripts have no true italic), and headings under `ar`, `fa`, `ur`,
|
|
1222
|
-
`ps`, `ckb`, `sd`, `ug` and `syr` reset `letter-spacing` to `normal` (negative tracking breaks
|
|
1223
|
-
cursive joins). To add a language to either list, or to opt back in, write an unlayered rule; it
|
|
1224
|
-
wins.
|
|
1225
|
-
|
|
1226
|
-
**`lr-markdown`** renders into its own shadow root, which `utilities.css` cannot reach. For a
|
|
1227
|
-
similar look, use its existing parts and hooks:
|
|
1228
|
-
|
|
1229
|
-
```css
|
|
1230
|
-
lr-markdown::part(inline-code) {
|
|
1231
|
-
background: var(--lr-color-neutral-fill-quiet, var(--lr-theme-color-neutral-fill-quiet));
|
|
1232
|
-
font-weight: var(--lr-font-weight-semibold, var(--lr-theme-font-weight-semibold, 600));
|
|
1233
|
-
}
|
|
1234
|
-
lr-markdown {
|
|
1235
|
-
--lr-markdown-table-header-bg: transparent;
|
|
1236
|
-
}
|
|
1237
|
-
lr-markdown::part(blockquote) {
|
|
1238
|
-
font-style: italic;
|
|
1239
|
-
}
|
|
1240
|
-
```
|
|
694
|
+
#### Using the light-DOM stylesheets with a CSS reset (Tailwind v4 preflight and similar)
|
|
1241
695
|
|
|
1242
|
-
|
|
696
|
+
[Read the CSS reset guidance](./native-styles-and-utilities.md#using-the-light-dom-stylesheets-with-a-css-reset-tailwind-v4-preflight-and-similar).
|
|
1243
697
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
A layered reset such as Tailwind v4's preflight lives in its own `base` layer. Layer order is fixed
|
|
1247
|
-
by first appearance, so if the reset's layers are declared first they sort **after** Lyra's and
|
|
1248
|
-
outrank `native.css` and `utilities.css`: headings shrink to body size, list markers and link
|
|
1249
|
-
underlines disappear. Declare the full order as the **first** CSS the page loads — for example a
|
|
1250
|
-
tiny `layers.css` imported before `tailwindcss` and before any Lyra CSS:
|
|
1251
|
-
|
|
1252
|
-
```css
|
|
1253
|
-
/* layers.css — load first */
|
|
1254
|
-
@layer theme, base, lr-base, lr-theme, lr-theme-preset, components, lr-utilities, utilities, lr-overrides;
|
|
1255
|
-
```
|
|
698
|
+
#### Bundle-specific override hooks
|
|
1256
699
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
them. An authored `type` on a list or `align` on a cell does not: presentational hints lose to every
|
|
1260
|
-
author rule, so under a reset set `list-style-type` (or `text-align`) with a class instead.
|
|
1261
|
-
|
|
1262
|
-
### Bundle-specific override hooks
|
|
1263
|
-
|
|
1264
|
-
The bundles consume the ordinary shared color, typography, spacing, border, radius, focus, size,
|
|
1265
|
-
and opacity tokens first. These additional hooks customize only the light-DOM bundle behavior:
|
|
1266
|
-
|
|
1267
|
-
| Hook | Default/fallback and use |
|
|
1268
|
-
| ----------------------------------------- | ---------------------------------------------------------------------------- |
|
|
1269
|
-
| `--lr-layout-gap` | `--lr-space-m`; default gap for `lr-stack`, `lr-cluster`, and `lr-grid-auto` |
|
|
1270
|
-
| `--lr-grid-min-inline-size` | `--lr-size-14rem`; minimum auto-grid item inline size |
|
|
1271
|
-
| `--lr-content-max-inline-size` | `--lr-size-48rem`; `lr-center` content measure |
|
|
1272
|
-
| `--lr-prose-max-inline-size` | `65ch`; `lr-prose` and `lr-max-inline-prose` measure |
|
|
1273
|
-
| `--lr-prose-flow-space` | `--lr-space-l`; flow spacing between direct blocks of `lr-prose` and `lr-typography`; the space before an `lr-typography` heading is twice this value |
|
|
1274
|
-
| `--lr-prose-quote-padding` | `--lr-space-l`; logical quote inset in `lr-prose` and `lr-typography` |
|
|
1275
|
-
| `--lr-prose-quote-border-width` | `--lr-border-width-thick` in `lr-prose`, `--lr-border-width-medium` in `lr-typography`; logical quote edge |
|
|
1276
|
-
| `--lr-heading-letter-spacing` | `--lr-theme-heading-letter-spacing`, then `normal`; heading tracking for `lr-heading-1`–`4` and `lr-typography` headings |
|
|
1277
|
-
| `--lr-theme-heading-letter-spacing` | unset; theme input for heading tracking (no resolved `--lr-*` token); `themes/shadcn.css` sets it |
|
|
1278
|
-
| `--lr-visually-hidden-size` | `--lr-size-1px` (1px); retained hidden box size |
|
|
1279
|
-
| `--lr-native-link-decoration-width` | `--lr-border-width-thin`; resting underline thickness |
|
|
1280
|
-
| `--lr-native-link-underline-offset` | `--lr-space-2xs`; underline offset |
|
|
1281
|
-
| `--lr-native-link-hover-decoration-width` | `--lr-border-width-medium`; hovered underline thickness |
|
|
1282
|
-
| `--lr-native-pre-padding` | `--lr-space-m`; preformatted block padding |
|
|
1283
|
-
| `--lr-native-tab-size` | `2`; preformatted tab width |
|
|
1284
|
-
| `--lr-native-quote-padding` | `--lr-space-l`; native blockquote logical inset |
|
|
1285
|
-
| `--lr-native-quote-border-width` | `--lr-border-width-thick`; native blockquote logical edge |
|
|
1286
|
-
| `--lr-native-control-min-block-size` | `--lr-icon-button-size`; native control hit-area floor |
|
|
1287
|
-
| `--lr-native-control-padding-block` | `--lr-space-s`; native control block padding |
|
|
1288
|
-
| `--lr-native-control-padding-inline` | `--lr-space-m`; native control inline padding |
|
|
1289
|
-
| `--lr-native-placeholder-opacity` | `1`; native input/textarea placeholder opacity |
|
|
1290
|
-
| `--lr-native-summary-min-block-size` | `--lr-icon-button-size`; native summary hit-area floor |
|
|
1291
|
-
| `--lr-native-fieldset-padding` | `--lr-space-l`; fieldset padding |
|
|
1292
|
-
| `--lr-native-legend-padding` | `--lr-space-xs`; legend inline padding |
|
|
1293
|
-
| `--lr-native-table-cell-padding` | `--lr-space-s`; caption and table-cell padding |
|
|
1294
|
-
| `--lr-native-rule-space` | `--lr-space-l`; horizontal-rule block margin |
|
|
700
|
+
[Read the override hooks](./native-styles-and-utilities.md#bundle-specific-override-hooks).
|
|
701
|
+
<!-- focused-native-styles:end -->
|
|
1295
702
|
|
|
1296
703
|
### Composing looks, surfaces and density
|
|
1297
704
|
|
|
@@ -1513,19 +920,21 @@ unchanged. Step numbers and interactive context-meter legend rows use matching s
|
|
|
1513
920
|
pairs; control-border colors no longer act as their text backgrounds. Material uses 8% hover and
|
|
1514
921
|
12% press state layers with its `currentColor` mix partner, keeping filled-action labels at 4.5:1.
|
|
1515
922
|
|
|
1516
|
-
Runtime custom accents, including `
|
|
923
|
+
Runtime custom accents, including `setLyraStyle({ accent })` and legacy gemstone presets, now
|
|
1517
924
|
floor the loud fill to 4.5:1 against its quiet fill and the built-in reference surfaces because the
|
|
1518
925
|
same token paints accent text. Its on-loud foreground follows the corrected fill. For example,
|
|
1519
926
|
light shadcn emerald changes from `#34d399` with black on-loud text to `#1a6a4d` with white text
|
|
1520
927
|
(6.537:1). Checked controls, brand text and streaming accents follow that loud token; secondary
|
|
1521
928
|
neutral controls stay unchanged. The requested and persisted accent color is retained.
|
|
1522
929
|
|
|
1523
|
-
The
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
930
|
+
The runtime and no-flash bootstrap still read v1 records written by the retired theme API. On
|
|
931
|
+
read, auto becomes system and the old accent reference surface becomes accentBackground. A saved
|
|
932
|
+
`tokens` map remains runtime-look tokens (`lookForm: 'runtime'`), separate from public `overrides`;
|
|
933
|
+
without a valid saved look id, the runtime look is named `custom`. A CSS color such as aquamarine
|
|
934
|
+
remains a CSS color and is not converted into the named gemstone. New writes use the current style
|
|
935
|
+
record while retaining those runtime-look tokens. parseLyraStyleRecord() and
|
|
936
|
+
lyraStyleAttributes() provide DOM-free server-rendering helpers; render the returned attributes
|
|
937
|
+
through the framework's normal HTML escaping.
|
|
1529
938
|
|
|
1530
939
|
Glass is a treatment for eligible navigation and floating chrome. It does not make content panels,
|
|
1531
940
|
forms, charts or dialogs translucent. Unsupported blur, reduced transparency, increased contrast and
|