@poodle64/ui 2026.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +624 -0
- package/dist/components/ui/alert/alert-description.svelte +23 -0
- package/dist/components/ui/alert/alert-description.svelte.d.ts +9 -0
- package/dist/components/ui/alert/alert-title.svelte +23 -0
- package/dist/components/ui/alert/alert-title.svelte.d.ts +9 -0
- package/dist/components/ui/alert/alert.svelte +46 -0
- package/dist/components/ui/alert/alert.svelte.d.ts +28 -0
- package/dist/components/ui/alert/index.d.ts +4 -0
- package/dist/components/ui/alert/index.js +4 -0
- package/dist/components/ui/alert-dialog/alert-dialog-action.svelte +27 -0
- package/dist/components/ui/alert-dialog/alert-dialog-action.svelte.d.ts +9 -0
- package/dist/components/ui/alert-dialog/alert-dialog-cancel.svelte +27 -0
- package/dist/components/ui/alert-dialog/alert-dialog-cancel.svelte.d.ts +9 -0
- package/dist/components/ui/alert-dialog/alert-dialog-content.svelte +39 -0
- package/dist/components/ui/alert-dialog/alert-dialog-content.svelte.d.ts +11 -0
- package/dist/components/ui/alert-dialog/alert-dialog-description.svelte +20 -0
- package/dist/components/ui/alert-dialog/alert-dialog-description.svelte.d.ts +4 -0
- package/dist/components/ui/alert-dialog/alert-dialog-footer.svelte +23 -0
- package/dist/components/ui/alert-dialog/alert-dialog-footer.svelte.d.ts +5 -0
- package/dist/components/ui/alert-dialog/alert-dialog-header.svelte +23 -0
- package/dist/components/ui/alert-dialog/alert-dialog-header.svelte.d.ts +5 -0
- package/dist/components/ui/alert-dialog/alert-dialog-media.svelte +23 -0
- package/dist/components/ui/alert-dialog/alert-dialog-media.svelte.d.ts +5 -0
- package/dist/components/ui/alert-dialog/alert-dialog-overlay.svelte +20 -0
- package/dist/components/ui/alert-dialog/alert-dialog-overlay.svelte.d.ts +4 -0
- package/dist/components/ui/alert-dialog/alert-dialog-portal.svelte +7 -0
- package/dist/components/ui/alert-dialog/alert-dialog-portal.svelte.d.ts +3 -0
- package/dist/components/ui/alert-dialog/alert-dialog-title.svelte +20 -0
- package/dist/components/ui/alert-dialog/alert-dialog-title.svelte.d.ts +4 -0
- package/dist/components/ui/alert-dialog/alert-dialog-trigger.svelte +7 -0
- package/dist/components/ui/alert-dialog/alert-dialog-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/alert-dialog/alert-dialog.svelte +7 -0
- package/dist/components/ui/alert-dialog/alert-dialog.svelte.d.ts +3 -0
- package/dist/components/ui/alert-dialog/index.d.ts +13 -0
- package/dist/components/ui/alert-dialog/index.js +15 -0
- package/dist/components/ui/app-dialog/app-dialog.svelte +111 -0
- package/dist/components/ui/app-dialog/app-dialog.svelte.d.ts +41 -0
- package/dist/components/ui/app-dialog/index.d.ts +2 -0
- package/dist/components/ui/app-dialog/index.js +2 -0
- package/dist/components/ui/app-shell/app-nav.svelte +299 -0
- package/dist/components/ui/app-shell/app-nav.svelte.d.ts +22 -0
- package/dist/components/ui/app-shell/app-shell.svelte +675 -0
- package/dist/components/ui/app-shell/app-shell.svelte.d.ts +157 -0
- package/dist/components/ui/app-shell/index.d.ts +6 -0
- package/dist/components/ui/app-shell/index.js +6 -0
- package/dist/components/ui/app-shell/measure.d.ts +28 -0
- package/dist/components/ui/app-shell/measure.js +21 -0
- package/dist/components/ui/app-shell/texture.d.ts +32 -0
- package/dist/components/ui/app-shell/texture.js +27 -0
- package/dist/components/ui/app-shell/types.d.ts +134 -0
- package/dist/components/ui/app-shell/types.js +88 -0
- package/dist/components/ui/arc-gauge/arc-gauge.svelte +112 -0
- package/dist/components/ui/arc-gauge/arc-gauge.svelte.d.ts +15 -0
- package/dist/components/ui/arc-gauge/index.d.ts +3 -0
- package/dist/components/ui/arc-gauge/index.js +2 -0
- package/dist/components/ui/avatar/avatar-fallback.svelte +26 -0
- package/dist/components/ui/avatar/avatar-fallback.svelte.d.ts +4 -0
- package/dist/components/ui/avatar/avatar-image.svelte +17 -0
- package/dist/components/ui/avatar/avatar-image.svelte.d.ts +4 -0
- package/dist/components/ui/avatar/avatar.svelte +31 -0
- package/dist/components/ui/avatar/avatar.svelte.d.ts +4 -0
- package/dist/components/ui/avatar/index.d.ts +4 -0
- package/dist/components/ui/avatar/index.js +6 -0
- package/dist/components/ui/badge/badge.svelte +50 -0
- package/dist/components/ui/badge/badge.svelte.d.ts +38 -0
- package/dist/components/ui/badge/index.d.ts +2 -0
- package/dist/components/ui/badge/index.js +2 -0
- package/dist/components/ui/bar-row/bar-row.svelte +42 -0
- package/dist/components/ui/bar-row/bar-row.svelte.d.ts +12 -0
- package/dist/components/ui/bar-row/index.d.ts +2 -0
- package/dist/components/ui/bar-row/index.js +2 -0
- package/dist/components/ui/button/button.svelte +89 -0
- package/dist/components/ui/button/button.svelte.d.ts +70 -0
- package/dist/components/ui/button/index.d.ts +2 -0
- package/dist/components/ui/button/index.js +4 -0
- package/dist/components/ui/card/card-action.svelte +23 -0
- package/dist/components/ui/card/card-action.svelte.d.ts +5 -0
- package/dist/components/ui/card/card-content.svelte +20 -0
- package/dist/components/ui/card/card-content.svelte.d.ts +5 -0
- package/dist/components/ui/card/card-description.svelte +20 -0
- package/dist/components/ui/card/card-description.svelte.d.ts +5 -0
- package/dist/components/ui/card/card-footer.svelte +23 -0
- package/dist/components/ui/card/card-footer.svelte.d.ts +5 -0
- package/dist/components/ui/card/card-header.svelte +23 -0
- package/dist/components/ui/card/card-header.svelte.d.ts +5 -0
- package/dist/components/ui/card/card-title.svelte +52 -0
- package/dist/components/ui/card/card-title.svelte.d.ts +8 -0
- package/dist/components/ui/card/card.svelte +25 -0
- package/dist/components/ui/card/card.svelte.d.ts +8 -0
- package/dist/components/ui/card/index.d.ts +8 -0
- package/dist/components/ui/card/index.js +10 -0
- package/dist/components/ui/checkbox/checkbox.svelte +36 -0
- package/dist/components/ui/checkbox/checkbox.svelte.d.ts +8 -0
- package/dist/components/ui/checkbox/index.d.ts +2 -0
- package/dist/components/ui/checkbox/index.js +2 -0
- package/dist/components/ui/command/command-dialog.svelte +42 -0
- package/dist/components/ui/command/command-dialog.svelte.d.ts +14 -0
- package/dist/components/ui/command/command-empty.svelte +17 -0
- package/dist/components/ui/command/command-empty.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-group.svelte +33 -0
- package/dist/components/ui/command/command-group.svelte.d.ts +7 -0
- package/dist/components/ui/command/command-input.svelte +36 -0
- package/dist/components/ui/command/command-input.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-item.svelte +27 -0
- package/dist/components/ui/command/command-item.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-link-item.svelte +20 -0
- package/dist/components/ui/command/command-link-item.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-list.svelte +20 -0
- package/dist/components/ui/command/command-list.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-loading.svelte +7 -0
- package/dist/components/ui/command/command-loading.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-separator.svelte +17 -0
- package/dist/components/ui/command/command-separator.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-shortcut.svelte +23 -0
- package/dist/components/ui/command/command-shortcut.svelte.d.ts +5 -0
- package/dist/components/ui/command/command.svelte +28 -0
- package/dist/components/ui/command/command.svelte.d.ts +8 -0
- package/dist/components/ui/command/index.d.ts +12 -0
- package/dist/components/ui/command/index.js +14 -0
- package/dist/components/ui/command-palette/command-palette.svelte +94 -0
- package/dist/components/ui/command-palette/command-palette.svelte.d.ts +40 -0
- package/dist/components/ui/command-palette/index.d.ts +3 -0
- package/dist/components/ui/command-palette/index.js +2 -0
- package/dist/components/ui/context-column/context-column.svelte +56 -0
- package/dist/components/ui/context-column/context-column.svelte.d.ts +14 -0
- package/dist/components/ui/context-column/index.d.ts +2 -0
- package/dist/components/ui/context-column/index.js +2 -0
- package/dist/components/ui/data-table/data-table.svelte.d.ts +40 -0
- package/dist/components/ui/data-table/data-table.svelte.js +110 -0
- package/dist/components/ui/data-table/flex-render.svelte +40 -0
- package/dist/components/ui/data-table/flex-render.svelte.d.ts +33 -0
- package/dist/components/ui/data-table/index.d.ts +3 -0
- package/dist/components/ui/data-table/index.js +3 -0
- package/dist/components/ui/data-table/render-helpers.d.ts +90 -0
- package/dist/components/ui/data-table/render-helpers.js +99 -0
- package/dist/components/ui/data-table-tanstack/data-table-tanstack.svelte +247 -0
- package/dist/components/ui/data-table-tanstack/data-table-tanstack.svelte.d.ts +79 -0
- package/dist/components/ui/data-table-tanstack/index.d.ts +3 -0
- package/dist/components/ui/data-table-tanstack/index.js +2 -0
- package/dist/components/ui/data-table-toolbar/data-table-toolbar.svelte +102 -0
- package/dist/components/ui/data-table-toolbar/data-table-toolbar.svelte.d.ts +32 -0
- package/dist/components/ui/data-table-toolbar/index.d.ts +3 -0
- package/dist/components/ui/data-table-toolbar/index.js +2 -0
- package/dist/components/ui/detail-panel/detail-panel.svelte +95 -0
- package/dist/components/ui/detail-panel/detail-panel.svelte.d.ts +26 -0
- package/dist/components/ui/detail-panel/index.d.ts +2 -0
- package/dist/components/ui/detail-panel/index.js +2 -0
- package/dist/components/ui/dialog/dialog-close.svelte +11 -0
- package/dist/components/ui/dialog/dialog-close.svelte.d.ts +4 -0
- package/dist/components/ui/dialog/dialog-content.svelte +48 -0
- package/dist/components/ui/dialog/dialog-content.svelte.d.ts +13 -0
- package/dist/components/ui/dialog/dialog-description.svelte +20 -0
- package/dist/components/ui/dialog/dialog-description.svelte.d.ts +4 -0
- package/dist/components/ui/dialog/dialog-footer.svelte +35 -0
- package/dist/components/ui/dialog/dialog-footer.svelte.d.ts +8 -0
- package/dist/components/ui/dialog/dialog-header.svelte +20 -0
- package/dist/components/ui/dialog/dialog-header.svelte.d.ts +5 -0
- package/dist/components/ui/dialog/dialog-overlay.svelte +20 -0
- package/dist/components/ui/dialog/dialog-overlay.svelte.d.ts +4 -0
- package/dist/components/ui/dialog/dialog-portal.svelte +7 -0
- package/dist/components/ui/dialog/dialog-portal.svelte.d.ts +3 -0
- package/dist/components/ui/dialog/dialog-title.svelte +17 -0
- package/dist/components/ui/dialog/dialog-title.svelte.d.ts +4 -0
- package/dist/components/ui/dialog/dialog-trigger.svelte +11 -0
- package/dist/components/ui/dialog/dialog-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/dialog/dialog.svelte +7 -0
- package/dist/components/ui/dialog/dialog.svelte.d.ts +3 -0
- package/dist/components/ui/dialog/index.d.ts +11 -0
- package/dist/components/ui/dialog/index.js +13 -0
- package/dist/components/ui/dialog-section/dialog-section.svelte +20 -0
- package/dist/components/ui/dialog-section/dialog-section.svelte.d.ts +8 -0
- package/dist/components/ui/dialog-section/index.d.ts +2 -0
- package/dist/components/ui/dialog-section/index.js +2 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +16 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +44 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte.d.ts +9 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +31 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte.d.ts +10 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +22 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte.d.ts +8 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group.svelte +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +27 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte.d.ts +8 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte +27 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte.d.ts +8 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-portal.svelte +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-portal.svelte.d.ts +3 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +16 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +34 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-separator.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +23 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte.d.ts +5 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +20 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +29 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte.d.ts +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub.svelte +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub.svelte.d.ts +3 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu.svelte.d.ts +3 -0
- package/dist/components/ui/dropdown-menu/index.d.ts +18 -0
- package/dist/components/ui/dropdown-menu/index.js +18 -0
- package/dist/components/ui/empty-state/empty-state.svelte +44 -0
- package/dist/components/ui/empty-state/empty-state.svelte.d.ts +14 -0
- package/dist/components/ui/empty-state/index.d.ts +2 -0
- package/dist/components/ui/empty-state/index.js +2 -0
- package/dist/components/ui/error-state/error-state.svelte +52 -0
- package/dist/components/ui/error-state/error-state.svelte.d.ts +10 -0
- package/dist/components/ui/error-state/index.d.ts +2 -0
- package/dist/components/ui/error-state/index.js +2 -0
- package/dist/components/ui/info-tip/index.d.ts +2 -0
- package/dist/components/ui/info-tip/index.js +2 -0
- package/dist/components/ui/info-tip/info-tip.svelte +37 -0
- package/dist/components/ui/info-tip/info-tip.svelte.d.ts +10 -0
- package/dist/components/ui/input/index.d.ts +2 -0
- package/dist/components/ui/input/index.js +4 -0
- package/dist/components/ui/input/input.svelte +48 -0
- package/dist/components/ui/input/input.svelte.d.ts +13 -0
- package/dist/components/ui/input-group/index.d.ts +7 -0
- package/dist/components/ui/input-group/index.js +9 -0
- package/dist/components/ui/input-group/input-group-addon.svelte +53 -0
- package/dist/components/ui/input-group/input-group-addon.svelte.d.ts +32 -0
- package/dist/components/ui/input-group/input-group-button.svelte +49 -0
- package/dist/components/ui/input-group/input-group-button.svelte.d.ts +32 -0
- package/dist/components/ui/input-group/input-group-input.svelte +23 -0
- package/dist/components/ui/input-group/input-group-input.svelte.d.ts +11 -0
- package/dist/components/ui/input-group/input-group-text.svelte +22 -0
- package/dist/components/ui/input-group/input-group-text.svelte.d.ts +5 -0
- package/dist/components/ui/input-group/input-group-textarea.svelte +23 -0
- package/dist/components/ui/input-group/input-group-textarea.svelte.d.ts +3 -0
- package/dist/components/ui/input-group/input-group.svelte +24 -0
- package/dist/components/ui/input-group/input-group.svelte.d.ts +5 -0
- package/dist/components/ui/label/index.d.ts +2 -0
- package/dist/components/ui/label/index.js +4 -0
- package/dist/components/ui/label/label.svelte +20 -0
- package/dist/components/ui/label/label.svelte.d.ts +4 -0
- package/dist/components/ui/loading-state/index.d.ts +2 -0
- package/dist/components/ui/loading-state/index.js +2 -0
- package/dist/components/ui/loading-state/loading-state.svelte +28 -0
- package/dist/components/ui/loading-state/loading-state.svelte.d.ts +8 -0
- package/dist/components/ui/page-header/index.d.ts +2 -0
- package/dist/components/ui/page-header/index.js +2 -0
- package/dist/components/ui/page-header/page-header.svelte +100 -0
- package/dist/components/ui/page-header/page-header.svelte.d.ts +17 -0
- package/dist/components/ui/panel/index.d.ts +2 -0
- package/dist/components/ui/panel/index.js +2 -0
- package/dist/components/ui/panel/panel.svelte +54 -0
- package/dist/components/ui/panel/panel.svelte.d.ts +16 -0
- package/dist/components/ui/password-input/index.d.ts +2 -0
- package/dist/components/ui/password-input/index.js +4 -0
- package/dist/components/ui/password-input/password-input.svelte +48 -0
- package/dist/components/ui/password-input/password-input.svelte.d.ts +8 -0
- package/dist/components/ui/popover/index.d.ts +4 -0
- package/dist/components/ui/popover/index.js +6 -0
- package/dist/components/ui/popover/popover-content.svelte +45 -0
- package/dist/components/ui/popover/popover-content.svelte.d.ts +7 -0
- package/dist/components/ui/popover/popover-trigger.svelte +7 -0
- package/dist/components/ui/popover/popover-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/popover/popover.svelte +7 -0
- package/dist/components/ui/popover/popover.svelte.d.ts +3 -0
- package/dist/components/ui/progress/index.d.ts +2 -0
- package/dist/components/ui/progress/index.js +4 -0
- package/dist/components/ui/progress/progress.svelte +30 -0
- package/dist/components/ui/progress/progress.svelte.d.ts +4 -0
- package/dist/components/ui/scorecard/index.d.ts +2 -0
- package/dist/components/ui/scorecard/index.js +2 -0
- package/dist/components/ui/scorecard/scorecard.svelte +35 -0
- package/dist/components/ui/scorecard/scorecard.svelte.d.ts +8 -0
- package/dist/components/ui/select/index.d.ts +12 -0
- package/dist/components/ui/select/index.js +14 -0
- package/dist/components/ui/select/select-content.svelte +45 -0
- package/dist/components/ui/select/select-content.svelte.d.ts +11 -0
- package/dist/components/ui/select/select-group-heading.svelte +21 -0
- package/dist/components/ui/select/select-group-heading.svelte.d.ts +10 -0
- package/dist/components/ui/select/select-group.svelte +17 -0
- package/dist/components/ui/select/select-group.svelte.d.ts +4 -0
- package/dist/components/ui/select/select-item.svelte +38 -0
- package/dist/components/ui/select/select-item.svelte.d.ts +4 -0
- package/dist/components/ui/select/select-label.svelte +20 -0
- package/dist/components/ui/select/select-label.svelte.d.ts +6 -0
- package/dist/components/ui/select/select-portal.svelte +7 -0
- package/dist/components/ui/select/select-portal.svelte.d.ts +3 -0
- package/dist/components/ui/select/select-scroll-down-button.svelte +23 -0
- package/dist/components/ui/select/select-scroll-down-button.svelte.d.ts +4 -0
- package/dist/components/ui/select/select-scroll-up-button.svelte +23 -0
- package/dist/components/ui/select/select-scroll-up-button.svelte.d.ts +4 -0
- package/dist/components/ui/select/select-separator.svelte +18 -0
- package/dist/components/ui/select/select-separator.svelte.d.ts +4 -0
- package/dist/components/ui/select/select-trigger.svelte +29 -0
- package/dist/components/ui/select/select-trigger.svelte.d.ts +8 -0
- package/dist/components/ui/select/select.svelte +11 -0
- package/dist/components/ui/select/select.svelte.d.ts +3 -0
- package/dist/components/ui/separator/index.d.ts +2 -0
- package/dist/components/ui/separator/index.js +4 -0
- package/dist/components/ui/separator/separator.svelte +23 -0
- package/dist/components/ui/separator/separator.svelte.d.ts +4 -0
- package/dist/components/ui/skeleton/index.d.ts +2 -0
- package/dist/components/ui/skeleton/index.js +4 -0
- package/dist/components/ui/skeleton/skeleton.svelte +17 -0
- package/dist/components/ui/skeleton/skeleton.svelte.d.ts +5 -0
- package/dist/components/ui/sonner/index.d.ts +1 -0
- package/dist/components/ui/sonner/index.js +1 -0
- package/dist/components/ui/sonner/sonner.svelte +34 -0
- package/dist/components/ui/sonner/sonner.svelte.d.ts +4 -0
- package/dist/components/ui/sparkline/index.d.ts +3 -0
- package/dist/components/ui/sparkline/index.js +2 -0
- package/dist/components/ui/sparkline/sparkline.svelte +90 -0
- package/dist/components/ui/sparkline/sparkline.svelte.d.ts +16 -0
- package/dist/components/ui/stat-card/index.d.ts +2 -0
- package/dist/components/ui/stat-card/index.js +2 -0
- package/dist/components/ui/stat-card/stat-card.svelte +77 -0
- package/dist/components/ui/stat-card/stat-card.svelte.d.ts +34 -0
- package/dist/components/ui/stat-list/index.d.ts +3 -0
- package/dist/components/ui/stat-list/index.js +2 -0
- package/dist/components/ui/stat-list/stat-list.svelte +80 -0
- package/dist/components/ui/stat-list/stat-list.svelte.d.ts +23 -0
- package/dist/components/ui/status/index.d.ts +1 -0
- package/dist/components/ui/status/index.js +1 -0
- package/dist/components/ui/status-badge/index.d.ts +3 -0
- package/dist/components/ui/status-badge/index.js +2 -0
- package/dist/components/ui/status-badge/status-badge.svelte +53 -0
- package/dist/components/ui/status-badge/status-badge.svelte.d.ts +39 -0
- package/dist/components/ui/switch/index.d.ts +2 -0
- package/dist/components/ui/switch/index.js +4 -0
- package/dist/components/ui/switch/switch.svelte +39 -0
- package/dist/components/ui/switch/switch.svelte.d.ts +4 -0
- package/dist/components/ui/table/index.d.ts +10 -0
- package/dist/components/ui/table/index.js +12 -0
- package/dist/components/ui/table/table-body.svelte +20 -0
- package/dist/components/ui/table/table-body.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-caption.svelte +20 -0
- package/dist/components/ui/table/table-caption.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-cell.svelte +20 -0
- package/dist/components/ui/table/table-cell.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-classes.d.ts +15 -0
- package/dist/components/ui/table/table-classes.js +15 -0
- package/dist/components/ui/table/table-footer.svelte +20 -0
- package/dist/components/ui/table/table-footer.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-head.svelte +23 -0
- package/dist/components/ui/table/table-head.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-header.svelte +20 -0
- package/dist/components/ui/table/table-header.svelte.d.ts +5 -0
- package/dist/components/ui/table/table-row.svelte +23 -0
- package/dist/components/ui/table/table-row.svelte.d.ts +5 -0
- package/dist/components/ui/table/table.svelte +37 -0
- package/dist/components/ui/table/table.svelte.d.ts +20 -0
- package/dist/components/ui/tabs/index.d.ts +5 -0
- package/dist/components/ui/tabs/index.js +7 -0
- package/dist/components/ui/tabs/tabs-content.svelte +13 -0
- package/dist/components/ui/tabs/tabs-content.svelte.d.ts +4 -0
- package/dist/components/ui/tabs/tabs-list.svelte +16 -0
- package/dist/components/ui/tabs/tabs-list.svelte.d.ts +4 -0
- package/dist/components/ui/tabs/tabs-trigger.svelte +16 -0
- package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/tabs/tabs.svelte +19 -0
- package/dist/components/ui/tabs/tabs.svelte.d.ts +4 -0
- package/dist/components/ui/textarea/index.d.ts +2 -0
- package/dist/components/ui/textarea/index.js +4 -0
- package/dist/components/ui/textarea/textarea.svelte +22 -0
- package/dist/components/ui/textarea/textarea.svelte.d.ts +5 -0
- package/dist/components/ui/tile-grid/index.d.ts +2 -0
- package/dist/components/ui/tile-grid/index.js +2 -0
- package/dist/components/ui/tile-grid/tile-grid.svelte +66 -0
- package/dist/components/ui/tile-grid/tile-grid.svelte.d.ts +43 -0
- package/dist/components/ui/tooltip/index.d.ts +6 -0
- package/dist/components/ui/tooltip/index.js +8 -0
- package/dist/components/ui/tooltip/tooltip-content.svelte +52 -0
- package/dist/components/ui/tooltip/tooltip-content.svelte.d.ts +11 -0
- package/dist/components/ui/tooltip/tooltip-portal.svelte +7 -0
- package/dist/components/ui/tooltip/tooltip-portal.svelte.d.ts +4 -0
- package/dist/components/ui/tooltip/tooltip-provider.svelte +7 -0
- package/dist/components/ui/tooltip/tooltip-provider.svelte.d.ts +4 -0
- package/dist/components/ui/tooltip/tooltip-trigger.svelte +7 -0
- package/dist/components/ui/tooltip/tooltip-trigger.svelte.d.ts +4 -0
- package/dist/components/ui/tooltip/tooltip.svelte +7 -0
- package/dist/components/ui/tooltip/tooltip.svelte.d.ts +4 -0
- package/dist/styles.css +961 -0
- package/dist/utils.d.ts +12 -0
- package/dist/utils.js +5 -0
- package/package.json +81 -0
package/dist/styles.css
ADDED
|
@@ -0,0 +1,961 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @poodle64/ui — component stylesheet.
|
|
3
|
+
*
|
|
4
|
+
* The composed components (PageHeader, StatusBadge, Panel, …) need three things
|
|
5
|
+
* the shadcn variable layer does not supply: a small type/tracking scale, a card
|
|
6
|
+
* "milled edge" treatment, and the status chip/dot classes. Every app that
|
|
7
|
+
* hand-built its own page chrome also hand-built these, which is exactly the
|
|
8
|
+
* drift this package exists to end — so they ship here, with the components that
|
|
9
|
+
* depend on them, rather than being re-typed into each app's own app.css.
|
|
10
|
+
*
|
|
11
|
+
* Import ONCE in the consuming app's app.css, after the token imports:
|
|
12
|
+
*
|
|
13
|
+
* @import '@poodle64/design-tokens/tokens.tw.css';
|
|
14
|
+
* @import '@poodle64/design-tokens/tokens.css';
|
|
15
|
+
* @import '@poodle64/ui/styles.css';
|
|
16
|
+
*
|
|
17
|
+
* Everything here resolves through either a --ds-* token (owned by
|
|
18
|
+
* @poodle64/design-tokens) or a shadcn semantic variable (--border, --primary,
|
|
19
|
+
* --muted-foreground, …) supplied by the app's own alias layer. There is no
|
|
20
|
+
* palette in this file: change the app's palette and every class below follows.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
+
The enter/exit animation utilities.
|
|
25
|
+
|
|
26
|
+
Every overlay this package ships is written against `animate-in`,
|
|
27
|
+
`animate-out`, `fade-in-0`, `zoom-in-95` and `slide-in-from-*`. None of those
|
|
28
|
+
are Tailwind utilities — they come from tw-animate-css — so in an app that
|
|
29
|
+
does not import it they compile to NOTHING, and the transition is dead for a
|
|
30
|
+
second, independent reason on top of the variant question below. Same
|
|
31
|
+
silence: the class is in the DOM, no rule exists, nothing fails.
|
|
32
|
+
|
|
33
|
+
It is a dependency rather than a peer, and imported here rather than
|
|
34
|
+
documented as a setup step, for the same reason the variants are declared
|
|
35
|
+
here: the package writes the utilities, so the package owns what makes them
|
|
36
|
+
real. An app that imports tw-animate-css itself as well loses nothing — the
|
|
37
|
+
definitions are identical.
|
|
38
|
+
|
|
39
|
+
It must stay the FIRST statement in this file: CSS requires @import before
|
|
40
|
+
any other at-rule, and the @custom-variant declarations below are at-rules.
|
|
41
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
42
|
+
@import 'tw-animate-css';
|
|
43
|
+
|
|
44
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
The dark variant.
|
|
46
|
+
|
|
47
|
+
Tailwind v4 resolves a bare `dark:` against `prefers-color-scheme`, not
|
|
48
|
+
against a class. Every component in this package — the shell's theme-toggle
|
|
49
|
+
icons, the input surfaces, the destructive ring refinements, ~50 utilities in
|
|
50
|
+
all — is written against the CLASS strategy, so without this line every one
|
|
51
|
+
of them is dead in a consuming app and the app's theme switch moves the
|
|
52
|
+
palette while leaving the components' dark refinements behind. Nothing fails:
|
|
53
|
+
the class is in the DOM, the rule simply never matches.
|
|
54
|
+
|
|
55
|
+
It was unowned until now. All four adopting apps had independently typed the
|
|
56
|
+
identical declaration into their own app.css, which is precisely the drift
|
|
57
|
+
this package exists to end — and it meant the FIFTH app to adopt would get a
|
|
58
|
+
silently half-dark component set. It ships here, with the utilities that
|
|
59
|
+
depend on it. The selector is byte-identical to what those apps already
|
|
60
|
+
declare, so an app that keeps its own copy re-declares the same thing and
|
|
61
|
+
nothing changes; an app that deletes its copy loses nothing.
|
|
62
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
63
|
+
@custom-variant dark (&:is(.dark *));
|
|
64
|
+
|
|
65
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
66
|
+
The bits-ui open/closed variants.
|
|
67
|
+
|
|
68
|
+
Same defect as `dark` above, one attribute along. This package writes ~47
|
|
69
|
+
`data-open:` / `data-closed:` utilities across the dialogue, alert-dialogue,
|
|
70
|
+
dropdown-menu, popover, tooltip, select and command surfaces — the whole
|
|
71
|
+
enter/exit animation of every overlay it ships. Tailwind v4 compiles a bare
|
|
72
|
+
`data-open:` to `&[data-open]`, and bits-ui does not emit `data-open`: it
|
|
73
|
+
emits `data-state="open"` / `data-state="closed"`. So the utilities exist in
|
|
74
|
+
the stylesheet, match nothing, and every overlay opens and closes with no
|
|
75
|
+
transition. Nothing fails — the class is in the DOM, the rule simply never
|
|
76
|
+
matches — which is why four of the five adopting apps shipped with dead
|
|
77
|
+
overlay transitions and none of them noticed.
|
|
78
|
+
|
|
79
|
+
Only these two need declaring. The other five shorthand data-variants this
|
|
80
|
+
package writes — `data-selected`, `data-highlighted`, `data-disabled`,
|
|
81
|
+
`data-placeholder` (bits-ui, all emitted as empty-string-or-undefined) and
|
|
82
|
+
`data-inset` (set by this package's own menu items) — are BARE attributes, so
|
|
83
|
+
Tailwind's default `&[data-x]` already matches them and a declaration here
|
|
84
|
+
would only restate it. `src/test/data-state-variants.test.ts` is what keeps
|
|
85
|
+
that distinction honest: it enumerates every shorthand data-variant the built
|
|
86
|
+
package ships and fails on any one whose compiled selector is not the
|
|
87
|
+
attribute the DOM actually carries, so a new unowned variant cannot ship.
|
|
88
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
89
|
+
@custom-variant data-open (&[data-state='open']);
|
|
90
|
+
@custom-variant data-closed (&[data-state='closed']);
|
|
91
|
+
|
|
92
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
93
|
+
The shadcn semantic surface.
|
|
94
|
+
|
|
95
|
+
Every component in this package is written against the shadcn colour names
|
|
96
|
+
(bg-card, bg-popover, bg-muted, bg-accent, border-input, bg-secondary and
|
|
97
|
+
their -foreground pairs). Declaring those names as plain custom properties
|
|
98
|
+
makes the VARIABLE exist but never tells Tailwind they are theme colours, so
|
|
99
|
+
the utilities compile to nothing at all: no build error, no lint hit, no
|
|
100
|
+
failing test — just a class in the DOM with no CSS behind it. Registration
|
|
101
|
+
is therefore two steps, and both are needed.
|
|
102
|
+
|
|
103
|
+
Step one, below: the mapping itself, declared once. Each shadcn name aliases
|
|
104
|
+
a --ds-* token from @poodle64/design-tokens, so a consuming app that picks a
|
|
105
|
+
palette by overriding --ds-color-* moves this whole surface with it, and
|
|
106
|
+
.dark flows through untouched.
|
|
107
|
+
|
|
108
|
+
The values are not a fresh design: they are what every app in the estate had
|
|
109
|
+
already converged on independently, hoisted here verbatim. There was no
|
|
110
|
+
disagreement to arbitrate — the surface ladder mapping (card/accent on
|
|
111
|
+
surface-2, popover on surface-3, muted/secondary on surface-1, input on
|
|
112
|
+
border) is identical in every app that had one.
|
|
113
|
+
|
|
114
|
+
The override point is --ds-color-*, and it reaches everything below. The
|
|
115
|
+
bare names are the contract components and app CSS read directly (the chip
|
|
116
|
+
colour, the selected-row rule, the card edge); redeclaring one after this
|
|
117
|
+
import is a deliberate per-app deviation rather than the setup tax it is
|
|
118
|
+
today.
|
|
119
|
+
|
|
120
|
+
card/card-foreground/popover/popover-foreground/secondary/
|
|
121
|
+
secondary-foreground/muted/accent/accent-foreground/input carry NO default
|
|
122
|
+
here (design-system#8). A bare name declared unconditionally at :root
|
|
123
|
+
freezes there: its own var(--ds-color-*) reference resolves once, at
|
|
124
|
+
:root, and every descendant inherits that fixed result regardless of a
|
|
125
|
+
later --ds-color-* override or a scoped .dark wrapper below it. These ten
|
|
126
|
+
names are consumed ONLY through the @theme inline fallback chain below
|
|
127
|
+
(var(--card, var(--ds-color-surface-2)), …), so leaving them undeclared by
|
|
128
|
+
default means that fallback — not a frozen alias — is what every consumer
|
|
129
|
+
resolves against, and both a scoped --ds-color-* override and a scoped
|
|
130
|
+
.dark wrapper reach it. An app that still sets one of these by name (the
|
|
131
|
+
existing, undocumented but working escape hatch) is unaffected: var()'s
|
|
132
|
+
fallback triggers only when the name is undeclared anywhere in the chain.
|
|
133
|
+
|
|
134
|
+
background/foreground/primary/primary-foreground/destructive/
|
|
135
|
+
destructive-foreground/border/border-strong/ring/muted-foreground/radius
|
|
136
|
+
keep their default here because this package's OWN hand-written CSS below
|
|
137
|
+
(.ds-nav-indicator, .ds-card-edge, .ds-dialog-section, .ds-skip-link:focus,
|
|
138
|
+
.ds-ink-neutral, .ds-chip-neutral, …) reads them as
|
|
139
|
+
plain, unconditional var() — not through a fallback — and because the
|
|
140
|
+
Tailwind utilities for these are generated by @poodle64/design-tokens'
|
|
141
|
+
OWN @theme inline registration off --ds-color-* directly, never through
|
|
142
|
+
these bare names at all (they were never in that utility's chain to begin
|
|
143
|
+
with, so removing their default would only cost the internal CSS above,
|
|
144
|
+
for no scoping gain). */
|
|
145
|
+
:root {
|
|
146
|
+
--background: var(--ds-color-background);
|
|
147
|
+
--foreground: var(--ds-color-foreground);
|
|
148
|
+
--primary: var(--ds-color-primary);
|
|
149
|
+
--primary-foreground: var(--ds-color-primary-foreground);
|
|
150
|
+
--destructive: var(--ds-color-destructive);
|
|
151
|
+
--destructive-foreground: var(--ds-color-destructive-foreground);
|
|
152
|
+
--border: var(--ds-color-border);
|
|
153
|
+
--border-strong: var(--ds-color-border-strong);
|
|
154
|
+
--ring: var(--ds-color-ring);
|
|
155
|
+
--muted-foreground: var(--ds-color-muted-foreground);
|
|
156
|
+
|
|
157
|
+
/* Consumed by the input-group size ramp as calc(var(--radius) - n). The
|
|
158
|
+
button ramp uses --radius-md from @poodle64/design-tokens instead. */
|
|
159
|
+
--radius: var(--ds-radius-lg);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
163
|
+
Step two: register those names with Tailwind so the utilities generate.
|
|
164
|
+
|
|
165
|
+
`inline` is what makes the override story work — Tailwind substitutes the
|
|
166
|
+
value into the utility, so .bg-card lands on var(--card) and follows any
|
|
167
|
+
redefinition of --card, at any scope, including .dark. Without it the
|
|
168
|
+
utility would freeze against whatever --card meant in :root.
|
|
169
|
+
|
|
170
|
+
Only the names @poodle64/design-tokens does NOT already register appear
|
|
171
|
+
here, and that exclusivity is load-bearing rather than tidiness. Registering
|
|
172
|
+
a key both packages claim makes the winner depend on which stylesheet was
|
|
173
|
+
imported last, so an app overriding it would get different results from the
|
|
174
|
+
same CSS depending on its import order, silently. One owner per key removes
|
|
175
|
+
the question; `background`, `foreground`, `primary`, `border`, `ring`,
|
|
176
|
+
`destructive` and their pairs stay the token package's, which is why they
|
|
177
|
+
are absent below despite being part of the same surface.
|
|
178
|
+
|
|
179
|
+
Sidebar and chart colours are deliberately NOT registered here either. This
|
|
180
|
+
package ships no sidebar or chart component, so nothing it exports could
|
|
181
|
+
reference them, and they are the one part of the shadcn surface the estate
|
|
182
|
+
genuinely disagrees on (chrome hue is an app's own decision, not a shared
|
|
183
|
+
default). An app using them registers them itself, as it does today.
|
|
184
|
+
|
|
185
|
+
Each value is a fallback chain, `var(--bare-name, var(--ds-color-x))`, not
|
|
186
|
+
a single reference (design-system#8). --card etc. carry no default (see
|
|
187
|
+
the :root block above), so by default every one of these resolves through
|
|
188
|
+
the --ds-color-* fallback — evaluated live at the consuming element, so a
|
|
189
|
+
scoped subtree override or a scoped .dark wrapper both reach it. An app
|
|
190
|
+
that still sets --card (etc.) by name keeps working unchanged: var()'s
|
|
191
|
+
fallback is used only when the name is undeclared anywhere in the chain.
|
|
192
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
193
|
+
@theme inline {
|
|
194
|
+
--color-card: var(--card, var(--ds-color-surface-2));
|
|
195
|
+
--color-card-foreground: var(--card-foreground, var(--ds-color-foreground));
|
|
196
|
+
--color-popover: var(--popover, var(--ds-color-surface-3));
|
|
197
|
+
--color-popover-foreground: var(--popover-foreground, var(--ds-color-foreground));
|
|
198
|
+
--color-secondary: var(--secondary, var(--ds-color-surface-1));
|
|
199
|
+
--color-secondary-foreground: var(--secondary-foreground, var(--ds-color-foreground));
|
|
200
|
+
--color-muted: var(--muted, var(--ds-color-surface-1));
|
|
201
|
+
--color-accent: var(--accent, var(--ds-color-surface-2));
|
|
202
|
+
--color-accent-foreground: var(--accent-foreground, var(--ds-color-foreground));
|
|
203
|
+
--color-input: var(--input, var(--ds-color-border));
|
|
204
|
+
|
|
205
|
+
/* The shell's chrome surface — the nav rail and the top bar.
|
|
206
|
+
Deliberately NOT `sidebar`. `20-sveltekit-frontend.md` makes the
|
|
207
|
+
`sidebar-*` set the app's own to define, and this package registers
|
|
208
|
+
neither `sidebar-*` nor `chart-*`; painting the shell off a `sidebar`
|
|
209
|
+
colour utility would have meant claiming a key the estate has not agreed
|
|
210
|
+
on and that no app can then override without a stylesheet-order coin
|
|
211
|
+
toss. (Naming the class literally here would itself trip the dead-utility
|
|
212
|
+
gate, which reads every string this package ships.) `shell` is a
|
|
213
|
+
name neither package claimed, so the one-owner-per-key rule holds, and it
|
|
214
|
+
defaults to a token this package already resolves. An app that already
|
|
215
|
+
has a chrome hue points its own token at it in one line:
|
|
216
|
+
|
|
217
|
+
:root { --ds-shell-chrome: var(--sidebar); }
|
|
218
|
+
|
|
219
|
+
The two foreground keys are the chrome's INK, and they are consumed —
|
|
220
|
+
by the rail, the bar, every chrome control and every nav rule below.
|
|
221
|
+
`--color-shell-foreground` was registered and read by nothing until now,
|
|
222
|
+
which made it a trap rather than an affordance: an app pointing
|
|
223
|
+
`--ds-shell-chrome-foreground` at a contrasting value got no effect and
|
|
224
|
+
had to override a package style to get chrome ink that inverts against
|
|
225
|
+
the palette. Both default to the same tokens the chrome used to hard-code
|
|
226
|
+
(`--foreground` / `--muted-foreground`), so nothing moves until an app
|
|
227
|
+
asks it to; two declarations then invert the whole chrome:
|
|
228
|
+
|
|
229
|
+
:root {
|
|
230
|
+
--ds-shell-chrome: var(--ds-color-primary);
|
|
231
|
+
--ds-shell-chrome-foreground: var(--ds-color-primary-foreground);
|
|
232
|
+
--ds-shell-chrome-muted-foreground: color-mix(
|
|
233
|
+
in oklch, var(--ds-color-primary-foreground) 70%, transparent);
|
|
234
|
+
}
|
|
235
|
+
*/
|
|
236
|
+
--color-shell: var(--ds-shell-chrome);
|
|
237
|
+
--color-shell-foreground: var(--ds-shell-chrome-foreground);
|
|
238
|
+
--color-shell-muted-foreground: var(--ds-shell-chrome-muted-foreground);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
242
|
+
Theme registration — the scale keys the composed components reference as
|
|
243
|
+
Tailwind utilities (text-display, text-body, text-stat, tracking-eyebrow).
|
|
244
|
+
An app may override any of these by re-declaring the key after this import.
|
|
245
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
246
|
+
@theme {
|
|
247
|
+
/* Eyebrow / column-head tracking — pairs with text-2xs + uppercase. */
|
|
248
|
+
--tracking-eyebrow: 0.06em;
|
|
249
|
+
|
|
250
|
+
/* Page-title and large-readout size (PageHeader, StatCard). */
|
|
251
|
+
--text-display: 1.75rem;
|
|
252
|
+
--text-display--line-height: 2.125rem;
|
|
253
|
+
--text-display--letter-spacing: -0.02em;
|
|
254
|
+
|
|
255
|
+
/* Panel/card heading size — one step above the sm body default. */
|
|
256
|
+
--text-body: 0.9375rem;
|
|
257
|
+
|
|
258
|
+
/* StatList readout value size. */
|
|
259
|
+
--text-stat: 1.0625rem;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
263
|
+
Atmosphere variables consumed by .ds-edge. Derived from the app's own
|
|
264
|
+
semantic --foreground so the edge highlight inverts correctly between light
|
|
265
|
+
and dark with no per-mode override. The drop shadow is a neutral translucent
|
|
266
|
+
black in both modes (a shadow is an absence of light, not a palette colour);
|
|
267
|
+
an app wanting a tinted shadow overrides --ds-shadow-sm.
|
|
268
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
269
|
+
:root {
|
|
270
|
+
--ds-card-edge: color-mix(in oklch, var(--foreground) 6%, transparent);
|
|
271
|
+
--ds-shadow-sm:
|
|
272
|
+
0 1px 2px oklch(0 0 0 / 0.1),
|
|
273
|
+
0 1px 1px oklch(0 0 0 / 0.06);
|
|
274
|
+
|
|
275
|
+
/* ── Shell geometry ──────────────────────────────────────────────────────
|
|
276
|
+
Named custom properties rather than Tailwind theme keys, deliberately:
|
|
277
|
+
a `--spacing-*` or `--container-*` entry with a name like `rail` would
|
|
278
|
+
sit inside a namespace Tailwind resolves the sizing utilities against
|
|
279
|
+
(`22-file-extensions`-adjacent trap documented in
|
|
280
|
+
tailwind-namespace.test.ts). Outside those namespaces there is nothing
|
|
281
|
+
to shadow, and an app still retunes the rail in one declaration.
|
|
282
|
+
──────────────────────────────────────────────────────────────────────── */
|
|
283
|
+
--ds-shell-chrome: var(--ds-color-surface-1);
|
|
284
|
+
--ds-shell-chrome-foreground: var(--ds-color-foreground);
|
|
285
|
+
--ds-shell-chrome-muted-foreground: var(--ds-color-muted-foreground);
|
|
286
|
+
--ds-shell-rail-width: 15.5rem;
|
|
287
|
+
--ds-shell-rail-width-collapsed: 3.5rem;
|
|
288
|
+
|
|
289
|
+
/* ── Content measure ──────────────────────────────────────────────────────
|
|
290
|
+
The scale AppShell's `measure` prop selects between, as custom properties
|
|
291
|
+
for the same reason the rail width is one: an app retunes a tier in one
|
|
292
|
+
declaration instead of waiting on a release of this package.
|
|
293
|
+
|
|
294
|
+
`prose` is in `ch` deliberately, where the other two are in `rem`. A
|
|
295
|
+
reading measure is a count of CHARACTERS, not a length — the whole claim
|
|
296
|
+
is "a line the eye can track back from", and that is a function of the
|
|
297
|
+
face and size the app actually set, not of a number someone typed once.
|
|
298
|
+
`page` and `wide` are page frames rather than reading measures, so they
|
|
299
|
+
are lengths and stay in rem.
|
|
300
|
+
──────────────────────────────────────────────────────────────────────── */
|
|
301
|
+
--ds-shell-measure-prose: 72ch;
|
|
302
|
+
--ds-shell-measure-page: 80rem;
|
|
303
|
+
--ds-shell-measure-wide: 120rem;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
@layer base {
|
|
307
|
+
/**
|
|
308
|
+
* The milled edge. Cards read as having depth from a hairline border plus a
|
|
309
|
+
* 1px inner highlight, not from a heavy drop shadow (shared-design-language
|
|
310
|
+
* §2 and §6). Applied by DetailPanel, AppDialog, Panel, StatCard, StatList,
|
|
311
|
+
* EmptyState, ErrorState and DataTableTanstack.
|
|
312
|
+
*/
|
|
313
|
+
.ds-edge {
|
|
314
|
+
box-shadow:
|
|
315
|
+
inset 0 1px 0 0 var(--ds-card-edge),
|
|
316
|
+
var(--ds-shadow-sm);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** Tabular figures, so a column of numbers aligns. */
|
|
320
|
+
.ds-tabular {
|
|
321
|
+
font-variant-numeric: tabular-nums;
|
|
322
|
+
font-feature-settings: 'tnum';
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Dialogue sections: a divider with even spacing is drawn between adjacent
|
|
327
|
+
* DialogSections, so every dialogue separates its information the same way.
|
|
328
|
+
* The first section in a body carries no divider. This adjacent-sibling rule
|
|
329
|
+
* is the whole behaviour of DialogSection — the component is inert without it.
|
|
330
|
+
*/
|
|
331
|
+
.ds-dialog-section + .ds-dialog-section {
|
|
332
|
+
margin-top: 1.25rem;
|
|
333
|
+
border-top: 1px solid color-mix(in oklch, var(--border) 60%, transparent);
|
|
334
|
+
padding-top: 1.25rem;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Status chips and dots: one source for every state pill in every app.
|
|
339
|
+
* Vocabulary: success | warning | error | info | neutral (see the Status type
|
|
340
|
+
* exported from @poodle64/ui/status). Consumed by StatusBadge, StatCard,
|
|
341
|
+
* StatList and DataTableToolbar.
|
|
342
|
+
*
|
|
343
|
+
* `-primary` below is the one exception: a StatusBadge-only extension for
|
|
344
|
+
* brand-emphasis chips (not a health state), keyed off --ds-color-primary
|
|
345
|
+
* rather than a --ds-color-status-* token. It is NOT part of the shared
|
|
346
|
+
* five-state vocabulary above — StatCard, StatList and DataTableToolbar
|
|
347
|
+
* never see it, and the Status type itself stays closed at five states.
|
|
348
|
+
*/
|
|
349
|
+
.ds-chip {
|
|
350
|
+
display: inline-flex;
|
|
351
|
+
align-items: center;
|
|
352
|
+
gap: 0.375rem;
|
|
353
|
+
border-radius: var(--ds-radius-sm);
|
|
354
|
+
padding: 0.1rem 0.5rem 0.1rem 0.4rem;
|
|
355
|
+
font-size: 0.75rem;
|
|
356
|
+
line-height: 1rem;
|
|
357
|
+
font-weight: 500;
|
|
358
|
+
white-space: nowrap;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.ds-dot {
|
|
362
|
+
width: 0.5rem;
|
|
363
|
+
height: 0.5rem;
|
|
364
|
+
border-radius: 9999px;
|
|
365
|
+
flex: none;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.ds-chip-success {
|
|
369
|
+
color: var(--ds-color-status-success);
|
|
370
|
+
background: color-mix(in oklch, var(--ds-color-status-success) 14%, transparent);
|
|
371
|
+
}
|
|
372
|
+
.ds-dot-success {
|
|
373
|
+
background: var(--ds-color-status-success);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.ds-chip-warning {
|
|
377
|
+
color: var(--ds-color-status-warning);
|
|
378
|
+
background: color-mix(in oklch, var(--ds-color-status-warning) 16%, transparent);
|
|
379
|
+
}
|
|
380
|
+
.ds-dot-warning {
|
|
381
|
+
background: var(--ds-color-status-warning);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.ds-chip-error {
|
|
385
|
+
color: var(--ds-color-status-error);
|
|
386
|
+
background: color-mix(in oklch, var(--ds-color-status-error) 15%, transparent);
|
|
387
|
+
}
|
|
388
|
+
.ds-dot-error {
|
|
389
|
+
background: var(--ds-color-status-error);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.ds-chip-info {
|
|
393
|
+
color: var(--ds-color-status-info);
|
|
394
|
+
background: color-mix(in oklch, var(--ds-color-status-info) 16%, transparent);
|
|
395
|
+
}
|
|
396
|
+
.ds-dot-info {
|
|
397
|
+
background: var(--ds-color-status-info);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.ds-chip-neutral {
|
|
401
|
+
color: var(--muted-foreground);
|
|
402
|
+
background: color-mix(in oklch, var(--ds-color-status-neutral) 14%, transparent);
|
|
403
|
+
}
|
|
404
|
+
.ds-dot-neutral {
|
|
405
|
+
background: var(--ds-color-status-neutral);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.ds-chip-primary {
|
|
409
|
+
color: var(--ds-color-primary);
|
|
410
|
+
background: color-mix(in oklch, var(--ds-color-primary) 14%, transparent);
|
|
411
|
+
}
|
|
412
|
+
.ds-dot-primary {
|
|
413
|
+
background: var(--ds-color-primary);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Ink in the status vocabulary, for text that IS the state rather than text
|
|
418
|
+
* that sits beside a chip. StatCard's `valueTone` is the first consumer: a
|
|
419
|
+
* negative figure should read as negative on the figure itself, not on a dot
|
|
420
|
+
* two lines above it.
|
|
421
|
+
*
|
|
422
|
+
* Same five names and the same tokens as the chips, so a palette change moves
|
|
423
|
+
* both together and an app cannot end up with a red chip beside an orange
|
|
424
|
+
* number.
|
|
425
|
+
*/
|
|
426
|
+
.ds-ink-success {
|
|
427
|
+
color: var(--ds-color-status-success);
|
|
428
|
+
}
|
|
429
|
+
.ds-ink-warning {
|
|
430
|
+
color: var(--ds-color-status-warning);
|
|
431
|
+
}
|
|
432
|
+
.ds-ink-error {
|
|
433
|
+
color: var(--ds-color-status-error);
|
|
434
|
+
}
|
|
435
|
+
.ds-ink-info {
|
|
436
|
+
color: var(--ds-color-status-info);
|
|
437
|
+
}
|
|
438
|
+
.ds-ink-neutral {
|
|
439
|
+
color: var(--muted-foreground);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* A dot for a state that is still moving (StatusBadge's `pulse`). Opacity
|
|
444
|
+
* only — no scale — so the pulse cannot shift the row it sits in, and the dot
|
|
445
|
+
* never fades below the contrast at which it is still legible as a colour.
|
|
446
|
+
*/
|
|
447
|
+
.ds-dot-pulse {
|
|
448
|
+
animation: ds-dot-pulse 1.6s ease-in-out infinite;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
@keyframes ds-dot-pulse {
|
|
452
|
+
0%,
|
|
453
|
+
100% {
|
|
454
|
+
opacity: 1;
|
|
455
|
+
}
|
|
456
|
+
50% {
|
|
457
|
+
opacity: 0.35;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* ─────────────────────────────────────────────────────────────────────────
|
|
462
|
+
The application shell (AppShell, AppNav, CommandPalette).
|
|
463
|
+
|
|
464
|
+
These are real CSS rather than utilities on the elements because the shell
|
|
465
|
+
renders the SAME nav link in two places — desktop rail, mobile drawer —
|
|
466
|
+
and every surveyed app that had two nav call sites had let the two drift
|
|
467
|
+
apart. One rule set, two call sites, no drift. The tints are color-mix over the app's own --primary and
|
|
468
|
+
--foreground, so a palette change moves them and this file holds no colour.
|
|
469
|
+
───────────────────────────────────────────────────────────────────────── */
|
|
470
|
+
/* Nav ink is a pair of locals rather than the page's --foreground directly,
|
|
471
|
+
because AppNav is rendered in two different kinds of surface: inside the
|
|
472
|
+
shell's chrome (rail, drawer), and — exported in its own
|
|
473
|
+
right — as a route-scoped secondary column sitting on the ordinary page
|
|
474
|
+
background. The default is the page's own ink, and only the chrome
|
|
475
|
+
surfaces below re-point it, so an app that inverts its chrome moves the
|
|
476
|
+
rail's text without dragging a secondary nav on `bg-background` with it.
|
|
477
|
+
|
|
478
|
+
The indirection through --ds-nav-chrome-ink is what makes that actually
|
|
479
|
+
work, and it is not decoration. A custom property declared on an element
|
|
480
|
+
beats one inherited into it, and `.ds-nav` is a DESCENDANT of every chrome
|
|
481
|
+
surface below — so re-pointing --ds-nav-ink on the rail was overridden by
|
|
482
|
+
`.ds-nav`'s own declaration a moment later, on the very element that
|
|
483
|
+
consumes it. Both declarations were correct in isolation and the winner
|
|
484
|
+
was decided by which element carried it, which is why no compiled-CSS gate
|
|
485
|
+
could see it: it is a cascade fact, and it needs an engine. It was
|
|
486
|
+
invisible in use too, because both sides default to the same token, so the
|
|
487
|
+
only symptom was an app inverting its chrome and getting nothing —
|
|
488
|
+
precisely the dead affordance `theme-coverage.test.ts` calls "worse than a
|
|
489
|
+
missing key". `harness/drive.mjs` now drives an inverted chrome and reads
|
|
490
|
+
the resolved ink back.
|
|
491
|
+
|
|
492
|
+
The chrome sets a variable `.ds-nav` READS rather than one it re-declares,
|
|
493
|
+
so the fallback chain resolves in the right order at the point of use. */
|
|
494
|
+
.ds-nav {
|
|
495
|
+
--ds-nav-ink: var(--ds-nav-chrome-ink, var(--foreground));
|
|
496
|
+
--ds-nav-ink-muted: var(--ds-nav-chrome-ink-muted, var(--muted-foreground));
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.ds-shell-rail,
|
|
500
|
+
.ds-shell-bar {
|
|
501
|
+
--ds-nav-chrome-ink: var(--ds-shell-chrome-foreground);
|
|
502
|
+
--ds-nav-chrome-ink-muted: var(--ds-shell-chrome-muted-foreground);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.ds-nav-item {
|
|
506
|
+
position: relative;
|
|
507
|
+
display: flex;
|
|
508
|
+
align-items: center;
|
|
509
|
+
gap: 0.75rem;
|
|
510
|
+
border-radius: var(--ds-radius-md);
|
|
511
|
+
padding: 0.5rem 0.625rem;
|
|
512
|
+
font-size: 0.875rem;
|
|
513
|
+
line-height: 1.25rem;
|
|
514
|
+
color: var(--ds-nav-ink-muted);
|
|
515
|
+
white-space: nowrap;
|
|
516
|
+
transition:
|
|
517
|
+
color 150ms,
|
|
518
|
+
background-color 150ms;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.ds-nav-item:hover {
|
|
522
|
+
color: var(--ds-nav-ink);
|
|
523
|
+
background: color-mix(in oklch, var(--ds-nav-ink) 5%, transparent);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/* The active row's INK is the chrome's own foreground, never --primary.
|
|
527
|
+
(#11.)
|
|
528
|
+
|
|
529
|
+
--ds-color-primary is the one token the package invites every app to
|
|
530
|
+
override, and the constraint stated where an app picks it is that it clear
|
|
531
|
+
AA against its own -foreground pair — the FILL case, primary as a button
|
|
532
|
+
background. Consuming it as ink on the chrome is a second, stricter and
|
|
533
|
+
entirely undocumented requirement, and an app can satisfy the stated one by
|
|
534
|
+
a mile and fail this one badly: a warm amber that is 7.69:1 as a fill
|
|
535
|
+
measured 1.90:1 here, and a saturated blue that is 5:1 as a fill measured
|
|
536
|
+
2.87:1. Two real app palettes, both sanctioned, both illegible. The package
|
|
537
|
+
default only ever cleared it by 0.05.
|
|
538
|
+
|
|
539
|
+
So the shell stops asking a colour it does not control to be legible text.
|
|
540
|
+
The ink is the chrome's foreground, which the app's palette is ALREADY
|
|
541
|
+
obliged to keep AA against the chrome, and the guarantee is inherited from
|
|
542
|
+
that existing contract rather than invented as a new one — 15.09:1 on the
|
|
543
|
+
package default, and no app is told to repaint its brand.
|
|
544
|
+
|
|
545
|
+
Two alternatives were measured and lost. Deriving an accessible ink by
|
|
546
|
+
clamping lightness (`oklch(from var(--primary) min(l, X) c h)`) is not
|
|
547
|
+
sound across the gamut — a saturated green clamped to L 0.55 still lands at
|
|
548
|
+
3.44:1 — so it trades a visible failure for a subtler one. Mixing primary
|
|
549
|
+
into the chrome ink IS provable (35% clears 4.5:1 for every in-gamut
|
|
550
|
+
primary in both modes) but at that ratio the hue is so diluted it reads as
|
|
551
|
+
warm or cool grey, which degrades every palette that was already fine to
|
|
552
|
+
buy safety for palettes no app has.
|
|
553
|
+
|
|
554
|
+
The brand is not lost, it moves to where it is not text: the 12% tint
|
|
555
|
+
below, the edge bar, the underline. An app that wants its brand back ON the
|
|
556
|
+
label sets --ds-nav-ink-active and owns the contrast knowingly:
|
|
557
|
+
|
|
558
|
+
:root { --ds-nav-ink-active: var(--ds-color-primary); }
|
|
559
|
+
|
|
560
|
+
It is read through a var() fallback rather than declared with a default,
|
|
561
|
+
deliberately: declaring `--ds-nav-ink-active: var(--ds-nav-ink)` at :root
|
|
562
|
+
would resolve where --ds-nav-ink does not exist and poison the property. */
|
|
563
|
+
.ds-nav-item[data-active='true'] {
|
|
564
|
+
color: var(--ds-nav-ink-active, var(--ds-nav-ink));
|
|
565
|
+
background: color-mix(in oklch, var(--primary) 12%, transparent);
|
|
566
|
+
font-weight: 500;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/* Colour alone never carries the active state (WCAG 1.4.1): the rail marks it
|
|
570
|
+
with a flush edge bar.
|
|
571
|
+
|
|
572
|
+
The bar keeps --primary at full strength, and that is a decision rather
|
|
573
|
+
than an oversight. WCAG 1.4.11 holds a state indicator to 3:1 only when the
|
|
574
|
+
state is not conveyed some other way; here it is conveyed three other ways
|
|
575
|
+
— the ink lifts from muted to full, the weight goes to 500, and the row
|
|
576
|
+
carries aria-current="page" — so the bar is free to be the one place the
|
|
577
|
+
app's brand survives undiluted. `harness/drive.mjs` asserts that redundancy
|
|
578
|
+
on every palette rather than trusting this paragraph, and prints the bar's
|
|
579
|
+
own ratio beside it. */
|
|
580
|
+
.ds-nav-indicator {
|
|
581
|
+
position: absolute;
|
|
582
|
+
left: 0;
|
|
583
|
+
top: 0.375rem;
|
|
584
|
+
bottom: 0.375rem;
|
|
585
|
+
width: 0.125rem;
|
|
586
|
+
border-radius: 9999px;
|
|
587
|
+
background: var(--primary);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.ds-nav-heading {
|
|
591
|
+
padding: 0 0.625rem 0.25rem;
|
|
592
|
+
font-size: var(--ds-text-2xs);
|
|
593
|
+
font-weight: 500;
|
|
594
|
+
text-transform: uppercase;
|
|
595
|
+
/* Fallback is load-bearing, not belt-and-braces: Tailwind tree-shakes an
|
|
596
|
+
@theme key whose utility nothing generates, so reading --tracking-eyebrow
|
|
597
|
+
from plain CSS works only while some component still uses the utility
|
|
598
|
+
form. The literal keeps this rule correct on its own; the var keeps an
|
|
599
|
+
app's override flowing through. */
|
|
600
|
+
letter-spacing: var(--tracking-eyebrow, 0.06em);
|
|
601
|
+
color: color-mix(in oklch, var(--ds-nav-ink-muted) 70%, transparent);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/* A count badge is small text on a tint, so it carries the 4.5:1 text floor
|
|
605
|
+
with the least margin of anything in the nav — and it was the worst of the
|
|
606
|
+
three (#11): 1.73:1 under a warm amber, and 3.72:1 even on the package
|
|
607
|
+
default, because it sits on the active row's tint AND its own. Same fix,
|
|
608
|
+
same reason: the ink is the chrome's, the brand stays in the chip. */
|
|
609
|
+
.ds-nav-badge {
|
|
610
|
+
margin-left: auto;
|
|
611
|
+
border-radius: 9999px;
|
|
612
|
+
padding: 0 0.375rem;
|
|
613
|
+
font-size: var(--ds-text-2xs);
|
|
614
|
+
font-weight: 500;
|
|
615
|
+
font-variant-numeric: tabular-nums;
|
|
616
|
+
color: var(--ds-nav-ink);
|
|
617
|
+
background: color-mix(in oklch, var(--primary) 15%, transparent);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/* A parent whose SECTION you are in, but whose own href does not match. Flat
|
|
621
|
+
prefix matching already covers the ordinary case — children under the
|
|
622
|
+
parent's own path light it up — so this only fires where the children live
|
|
623
|
+
at their own top-level routes and the parent would otherwise go dark while
|
|
624
|
+
you are inside it.
|
|
625
|
+
|
|
626
|
+
It lifts the ink and nothing else, on purpose. The tint, the weight and the
|
|
627
|
+
edge bar are what "this row IS the page" means in this rail, and spending
|
|
628
|
+
any of them on "the page is somewhere below this row" would leave two rows
|
|
629
|
+
claiming to be the current one. */
|
|
630
|
+
.ds-nav-item[data-within='true'] {
|
|
631
|
+
color: var(--ds-nav-ink);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/* The disclosed rows. The indent is measured against the parent's own
|
|
635
|
+
geometry rather than picked: .ds-nav-item pads 0.625rem and the icon is
|
|
636
|
+
1.125rem, so the icon's centre line sits at 1.1875rem — where the guide
|
|
637
|
+
border goes — and 0.625rem of padding here plus the child's own 0.625rem
|
|
638
|
+
lands its label at 2.5rem, exactly under the parent's. The border is a real
|
|
639
|
+
affordance at fifteen rows, not decoration: it is what makes the run
|
|
640
|
+
scannable as one section. */
|
|
641
|
+
.ds-nav-children {
|
|
642
|
+
display: flex;
|
|
643
|
+
flex-direction: column;
|
|
644
|
+
gap: 0.125rem;
|
|
645
|
+
margin-top: 0.125rem;
|
|
646
|
+
margin-left: 1.1875rem;
|
|
647
|
+
padding-left: 0.625rem;
|
|
648
|
+
border-left: 1px solid var(--border);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/* `hidden` is an attribute the UA stylesheet honours at the weakest possible
|
|
652
|
+
specificity, so the `display: flex` above beats it and a closed group would
|
|
653
|
+
render wide open. This is not belt-and-braces; without it the attribute is
|
|
654
|
+
inert for layout while still hiding the rows from assistive technology,
|
|
655
|
+
which is the worst of both. */
|
|
656
|
+
.ds-nav-children[hidden] {
|
|
657
|
+
display: none;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/* A child sits on the chrome like any other row, one step quieter at rest.
|
|
661
|
+
The active child keeps the full active treatment from .ds-nav-item — it is
|
|
662
|
+
the current page, and depth does not make it less so. */
|
|
663
|
+
.ds-nav-item[data-child='true'] {
|
|
664
|
+
font-size: 0.8125rem;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.ds-nav-row {
|
|
668
|
+
display: flex;
|
|
669
|
+
align-items: center;
|
|
670
|
+
gap: 0.125rem;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/* The link takes the room and the chevron takes what is left, so a long label
|
|
674
|
+
truncates instead of pushing the control out of the rail. min-width: 0 is
|
|
675
|
+
what actually permits the shrink — a flex item's automatic minimum size is
|
|
676
|
+
its content, and .ds-nav-item is nowrap. */
|
|
677
|
+
.ds-nav-row > .ds-nav-item {
|
|
678
|
+
flex: 1 1 auto;
|
|
679
|
+
min-width: 0;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
.ds-nav-disclosure {
|
|
683
|
+
display: grid;
|
|
684
|
+
flex: none;
|
|
685
|
+
place-items: center;
|
|
686
|
+
width: 1.75rem;
|
|
687
|
+
height: 1.75rem;
|
|
688
|
+
border-radius: var(--ds-radius-md);
|
|
689
|
+
color: var(--ds-nav-ink-muted);
|
|
690
|
+
transition:
|
|
691
|
+
color 150ms,
|
|
692
|
+
background-color 150ms;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.ds-nav-disclosure:hover {
|
|
696
|
+
color: var(--ds-nav-ink);
|
|
697
|
+
background: color-mix(in oklch, var(--ds-nav-ink) 5%, transparent);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/* The rotation IS the open/closed state for a sighted user, paired with the
|
|
701
|
+
aria-expanded that carries it for everyone else. Transform on the icon
|
|
702
|
+
rather than a swapped glyph, so the two states are the same object moving
|
|
703
|
+
rather than two pictures. */
|
|
704
|
+
.ds-nav-disclosure > svg {
|
|
705
|
+
transition: transform 150ms ease;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
.ds-nav-disclosure[aria-expanded='true'] > svg {
|
|
709
|
+
transform: rotate(90deg);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.ds-nav[data-collapsed='true'] {
|
|
713
|
+
padding-inline: 0.375rem;
|
|
714
|
+
}
|
|
715
|
+
.ds-nav[data-collapsed='true'] .ds-nav-item {
|
|
716
|
+
justify-content: center;
|
|
717
|
+
padding-inline: 0;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/* The rail is ONE element in two states, not two elements (see the comment in
|
|
721
|
+
app-shell.svelte): below md it is hidden until `data-drawer` turns it into
|
|
722
|
+
an overlay; at md and up it is the permanent column and `data-drawer` means
|
|
723
|
+
nothing. Expressing the swap here rather than as competing utility classes
|
|
724
|
+
is what makes it deterministic — `fixed` and `sticky` set the same property,
|
|
725
|
+
so which won would otherwise depend on Tailwind's emission order, not on the
|
|
726
|
+
order they appear in the class attribute.
|
|
727
|
+
|
|
728
|
+
48rem is Tailwind's own --breakpoint-md. It is written literally because a
|
|
729
|
+
media query cannot read a custom property; an app that retunes the md
|
|
730
|
+
breakpoint must retune this rule with it. */
|
|
731
|
+
.ds-shell-rail {
|
|
732
|
+
display: none;
|
|
733
|
+
position: sticky;
|
|
734
|
+
top: 0;
|
|
735
|
+
height: 100dvh;
|
|
736
|
+
width: var(--ds-shell-rail-width);
|
|
737
|
+
transition: width 200ms ease;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.ds-shell-rail[data-drawer='true'] {
|
|
741
|
+
display: flex;
|
|
742
|
+
position: fixed;
|
|
743
|
+
inset-block: 0;
|
|
744
|
+
left: 0;
|
|
745
|
+
z-index: 50;
|
|
746
|
+
max-width: 82vw;
|
|
747
|
+
box-shadow:
|
|
748
|
+
0 10px 15px -3px oklch(0 0 0 / 0.1),
|
|
749
|
+
0 4px 6px -4px oklch(0 0 0 / 0.1);
|
|
750
|
+
animation: ds-drawer-in 200ms ease-out;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
@media (min-width: 48rem) {
|
|
754
|
+
.ds-shell-rail {
|
|
755
|
+
display: flex;
|
|
756
|
+
}
|
|
757
|
+
/* At md the drawer state is inert: the rail is already on screen, so an
|
|
758
|
+
overlay opened on a phone and then widened must not stay an overlay. */
|
|
759
|
+
.ds-shell-rail[data-drawer='true'] {
|
|
760
|
+
position: sticky;
|
|
761
|
+
z-index: auto;
|
|
762
|
+
max-width: none;
|
|
763
|
+
box-shadow: none;
|
|
764
|
+
animation: none;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.ds-shell-rail[data-collapsed='true'] {
|
|
769
|
+
width: var(--ds-shell-rail-width-collapsed);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/* The content measure: the shell's content box is ONE element in four
|
|
773
|
+
states, the same shape as the rail above it.
|
|
774
|
+
|
|
775
|
+
Real declarations here rather than a `max-w-[var(--ds-shell-measure-page)]`
|
|
776
|
+
utility on the component, for the reason the rail's width is here too: an
|
|
777
|
+
arbitrary utility only exists if the CONSUMER's Tailwind build happened to
|
|
778
|
+
scan the file that spells it, whereas this stylesheet is imported by every
|
|
779
|
+
consumer as a condition of using the package at all. Whoever writes the
|
|
780
|
+
utility owns whatever makes it real.
|
|
781
|
+
|
|
782
|
+
`full` writes no attribute and matches nothing here, so a shell that never
|
|
783
|
+
asked for a measure carries no class, no attribute and no declaration —
|
|
784
|
+
which is what makes the prop additive rather than a default anyone has to
|
|
785
|
+
opt out of.
|
|
786
|
+
|
|
787
|
+
The cap is the BORDER box, so `padded` spends its inline padding inside
|
|
788
|
+
the measure rather than outside it. That is the same arithmetic as the
|
|
789
|
+
`mx-auto max-w-4xl px-6` idiom this replaces, and keeping it means one
|
|
790
|
+
element rather than a second wrapper nobody asked for. */
|
|
791
|
+
.ds-shell-measure {
|
|
792
|
+
margin-inline: auto;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.ds-shell-measure[data-measure='prose'] {
|
|
796
|
+
max-width: var(--ds-shell-measure-prose);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.ds-shell-measure[data-measure='page'] {
|
|
800
|
+
max-width: var(--ds-shell-measure-page);
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
.ds-shell-measure[data-measure='wide'] {
|
|
804
|
+
max-width: var(--ds-shell-measure-wide);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/* The content texture: the house atmosphere, painted once by the shell on its
|
|
808
|
+
own scrolling content region.
|
|
809
|
+
|
|
810
|
+
Two apps had built this picture separately — a faint dot-grid floor plus a
|
|
811
|
+
soft accent vignette in the top-right — under two names, in two app.css
|
|
812
|
+
files, and one applied it as a helper class per route so it reached four
|
|
813
|
+
routes out of about fifteen. It is the same drift the nav rules above were
|
|
814
|
+
hoisted to end, one layer down.
|
|
815
|
+
|
|
816
|
+
A BACKGROUND, not a layer, and that is the design. Both apps first reached
|
|
817
|
+
for an absolutely positioned `::before` inside the scroller, which is wrong
|
|
818
|
+
three ways at once: at `z-index: auto` a positioned box paints above
|
|
819
|
+
non-positioned content, so the atmosphere tints the page rather than sitting
|
|
820
|
+
under it (invisible only because it is faint); `z-index: -1` trades that for
|
|
821
|
+
sinking behind an ancestor's background, since neither `<main>` nor
|
|
822
|
+
`.ds-shell` opens a stacking context; and it has to be excused from
|
|
823
|
+
hit-testing by hand. A background layer cannot be hit-tested, always paints
|
|
824
|
+
beneath every descendant, adds no box to the flex column, and opens no
|
|
825
|
+
stacking context — every one of those properties for free.
|
|
826
|
+
|
|
827
|
+
`background-attachment: local` is what makes it the page's FLOOR rather than
|
|
828
|
+
a backdrop behind a moving page. A scroll container's background defaults to
|
|
829
|
+
`scroll`, which pins it to the border box: the dots would hang motionless
|
|
830
|
+
while the content slid over them. `local` resolves the painting and
|
|
831
|
+
positioning areas against the scrollable area instead, so the texture
|
|
832
|
+
travels with the content that sits on it. The vignette's height is therefore
|
|
833
|
+
a length rather than a percentage — under `local` a percentage would resolve
|
|
834
|
+
against the whole scroll height and stretch one corner glow down a 5000px
|
|
835
|
+
page.
|
|
836
|
+
|
|
837
|
+
That length defaults to `calc(100dvh - 3.5rem)` rather than `100dvh`, and
|
|
838
|
+
the 3.5rem is the top bar's own `h-14`: `.ds-shell` is `h-dvh` with the bar
|
|
839
|
+
above `<main>` in the same column, so the region this paints is one bar
|
|
840
|
+
shorter than the viewport and a plain `100dvh` overshoots it by about 6%.
|
|
841
|
+
The literal is written out for the same reason `48rem` is in the rail's
|
|
842
|
+
media query below — nothing here can read the bar's Tailwind utility — so
|
|
843
|
+
an app that retunes the bar height retunes this alongside it, in the knob
|
|
844
|
+
already provided.
|
|
845
|
+
|
|
846
|
+
The five knobs are read through var() fallbacks at the point of use rather
|
|
847
|
+
than declared at :root, for the reason the @theme inline block above states
|
|
848
|
+
(design-system#8): a :root alias holding a var() reference resolves once, at
|
|
849
|
+
:root, and a scoped override or a scoped .dark wrapper below it can never
|
|
850
|
+
reach the result. Read here, they resolve live on the element that paints
|
|
851
|
+
them. It also means this feature adds nothing at all to a consumer's :root —
|
|
852
|
+
a shell that never asks for a texture receives one rule set whose selector
|
|
853
|
+
matches nothing.
|
|
854
|
+
|
|
855
|
+
An app retunes any of them in one declaration:
|
|
856
|
+
|
|
857
|
+
:root {
|
|
858
|
+
--ds-shell-texture-grid-ink: oklch(0.68 0.02 250 / 0.5);
|
|
859
|
+
--ds-shell-texture-vignette-ink: color-mix(in oklch, var(--primary) 8%, transparent);
|
|
860
|
+
--ds-shell-texture-grid-pitch: 24px;
|
|
861
|
+
--ds-shell-texture-vignette-at: 15% -10%;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
The corner is a knob rather than a fixed 85% because it is the one value an
|
|
865
|
+
app cannot otherwise reach without redeclaring this whole rule, and because
|
|
866
|
+
a radial-gradient position is PHYSICAL — there is no logical form of `at
|
|
867
|
+
85%`, so an RTL app wanting the glow at the reading-start corner has to be
|
|
868
|
+
able to say so. Driven at `dir=rtl` alongside a 24px root size and
|
|
869
|
+
`forced-colors: active`, none of which move the texture on their own.
|
|
870
|
+
|
|
871
|
+
A plain wash rather than a grid is that same declaration with the grid ink
|
|
872
|
+
set to `transparent`, which is why `grid` is the only named texture: the
|
|
873
|
+
apps differed on values, not on pictures. */
|
|
874
|
+
.ds-shell-texture[data-texture='grid'] {
|
|
875
|
+
background-image:
|
|
876
|
+
radial-gradient(
|
|
877
|
+
120% 70% at var(--ds-shell-texture-vignette-at, 85% -10%),
|
|
878
|
+
var(--ds-shell-texture-vignette-ink, color-mix(in oklch, var(--primary) 6%, transparent)),
|
|
879
|
+
transparent 60%
|
|
880
|
+
),
|
|
881
|
+
radial-gradient(
|
|
882
|
+
circle at 1px 1px,
|
|
883
|
+
var(--ds-shell-texture-grid-ink, color-mix(in oklch, var(--foreground) 14%, transparent))
|
|
884
|
+
1px,
|
|
885
|
+
transparent 0
|
|
886
|
+
);
|
|
887
|
+
background-repeat: no-repeat, repeat;
|
|
888
|
+
background-position: 0 0;
|
|
889
|
+
background-size:
|
|
890
|
+
100% var(--ds-shell-texture-vignette-height, calc(100dvh - 3.5rem)),
|
|
891
|
+
var(--ds-shell-texture-grid-pitch, 30px) var(--ds-shell-texture-grid-pitch, 30px);
|
|
892
|
+
background-attachment: local, local;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/* Not on paper. A 30px dot grid prints as banding on any real printer, and a
|
|
896
|
+
vignette prints as a smudge in one corner — both apps that built this had
|
|
897
|
+
independently learned that and written the same suppression into their own
|
|
898
|
+
print rules, which is the copy this package is here to take over.
|
|
899
|
+
|
|
900
|
+
Later in the file than the rule above and in the same layer, so it wins
|
|
901
|
+
without `!important`; an app's own print rules are unlayered and still beat
|
|
902
|
+
it, which is the right way round. The white is the content region's, not the
|
|
903
|
+
document's — `html`/`body` stay the app's to decide.
|
|
904
|
+
|
|
905
|
+
`#fff` is the one literal colour in an otherwise entirely token-driven
|
|
906
|
+
feature, on the same grounds `--ds-shadow-sm` gives for its neutral black:
|
|
907
|
+
paper is white, which is a fact about the medium rather than a palette
|
|
908
|
+
choice, and a brand-tinted "white" here would only spend the reader's
|
|
909
|
+
toner. An app that genuinely wants the region printed in a colour paints it
|
|
910
|
+
from its own unlayered print rules and wins. */
|
|
911
|
+
@media print {
|
|
912
|
+
.ds-shell-texture[data-texture='grid'] {
|
|
913
|
+
background-image: none;
|
|
914
|
+
background-color: #fff;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/* The bypass link (WCAG 2.4.1): off-screen until focused, then a real target
|
|
919
|
+
above the sticky bar. */
|
|
920
|
+
.ds-skip-link {
|
|
921
|
+
position: absolute;
|
|
922
|
+
left: 0.5rem;
|
|
923
|
+
top: -3rem;
|
|
924
|
+
z-index: 60;
|
|
925
|
+
border-radius: var(--ds-radius-md);
|
|
926
|
+
background: var(--popover, var(--ds-color-surface-3));
|
|
927
|
+
color: var(--popover-foreground, var(--ds-color-foreground));
|
|
928
|
+
padding: 0.5rem 1rem;
|
|
929
|
+
font-size: 0.875rem;
|
|
930
|
+
font-weight: 500;
|
|
931
|
+
box-shadow: var(--ds-shadow-sm);
|
|
932
|
+
transition: top 150ms ease;
|
|
933
|
+
}
|
|
934
|
+
.ds-skip-link:focus {
|
|
935
|
+
top: 0.5rem;
|
|
936
|
+
outline: 2px solid var(--ring);
|
|
937
|
+
outline-offset: 2px;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
@keyframes ds-drawer-in {
|
|
941
|
+
from {
|
|
942
|
+
transform: translateX(-100%);
|
|
943
|
+
}
|
|
944
|
+
to {
|
|
945
|
+
transform: translateX(0);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
@media (prefers-reduced-motion: reduce) {
|
|
950
|
+
.ds-shell-rail[data-drawer='true'],
|
|
951
|
+
.ds-dot-pulse {
|
|
952
|
+
animation: none;
|
|
953
|
+
}
|
|
954
|
+
.ds-shell-rail {
|
|
955
|
+
transition: none;
|
|
956
|
+
}
|
|
957
|
+
.ds-nav-disclosure > svg {
|
|
958
|
+
transition: none;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|