@lo-tek/interfaces 0.0.0-stage → 0.37.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 +3254 -0
- package/LICENSE +21 -0
- package/README.md +129 -2
- package/agent/astro.md +400 -0
- package/agent/bundles.md +429 -0
- package/agent/datastar.md +409 -0
- package/agent/html.md +388 -0
- package/agent/react.md +440 -0
- package/agent/templates.md +472 -0
- package/core/lotek-core.wasm +0 -0
- package/core/lotek.wasm +0 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +14 -0
- package/dist/cli.js.map +1 -0
- package/dist/components/css/accordion/accordion.d.ts +37 -0
- package/dist/components/css/accordion/accordion.d.ts.map +1 -0
- package/dist/components/css/accordion/accordion.js +31 -0
- package/dist/components/css/accordion/accordion.js.map +1 -0
- package/dist/components/css/alert/alert.d.ts +35 -0
- package/dist/components/css/alert/alert.d.ts.map +1 -0
- package/dist/components/css/alert/alert.js +29 -0
- package/dist/components/css/alert/alert.js.map +1 -0
- package/dist/components/css/avatar/avatar.d.ts +40 -0
- package/dist/components/css/avatar/avatar.d.ts.map +1 -0
- package/dist/components/css/avatar/avatar.js +30 -0
- package/dist/components/css/avatar/avatar.js.map +1 -0
- package/dist/components/css/badge/badge.d.ts +24 -0
- package/dist/components/css/badge/badge.d.ts.map +1 -0
- package/dist/components/css/badge/badge.js +24 -0
- package/dist/components/css/badge/badge.js.map +1 -0
- package/dist/components/css/breadcrumbs/breadcrumbs.d.ts +26 -0
- package/dist/components/css/breadcrumbs/breadcrumbs.d.ts.map +1 -0
- package/dist/components/css/breadcrumbs/breadcrumbs.js +24 -0
- package/dist/components/css/breadcrumbs/breadcrumbs.js.map +1 -0
- package/dist/components/css/button/button.d.ts +26 -0
- package/dist/components/css/button/button.d.ts.map +1 -0
- package/dist/components/css/button/button.js +25 -0
- package/dist/components/css/button/button.js.map +1 -0
- package/dist/components/css/card/card.d.ts +36 -0
- package/dist/components/css/card/card.d.ts.map +1 -0
- package/dist/components/css/card/card.js +28 -0
- package/dist/components/css/card/card.js.map +1 -0
- package/dist/components/css/checkbox/checkbox.d.ts +32 -0
- package/dist/components/css/checkbox/checkbox.d.ts.map +1 -0
- package/dist/components/css/checkbox/checkbox.js +27 -0
- package/dist/components/css/checkbox/checkbox.js.map +1 -0
- package/dist/components/css/divider/divider.d.ts +29 -0
- package/dist/components/css/divider/divider.d.ts.map +1 -0
- package/dist/components/css/divider/divider.js +23 -0
- package/dist/components/css/divider/divider.js.map +1 -0
- package/dist/components/css/error-text/error-text.d.ts +24 -0
- package/dist/components/css/error-text/error-text.d.ts.map +1 -0
- package/dist/components/css/error-text/error-text.js +18 -0
- package/dist/components/css/error-text/error-text.js.map +1 -0
- package/dist/components/css/fieldset/fieldset.d.ts +55 -0
- package/dist/components/css/fieldset/fieldset.d.ts.map +1 -0
- package/dist/components/css/fieldset/fieldset.js +39 -0
- package/dist/components/css/fieldset/fieldset.js.map +1 -0
- package/dist/components/css/file-upload/file-upload.d.ts +41 -0
- package/dist/components/css/file-upload/file-upload.d.ts.map +1 -0
- package/dist/components/css/file-upload/file-upload.js +32 -0
- package/dist/components/css/file-upload/file-upload.js.map +1 -0
- package/dist/components/css/heading/heading.d.ts +29 -0
- package/dist/components/css/heading/heading.d.ts.map +1 -0
- package/dist/components/css/heading/heading.js +23 -0
- package/dist/components/css/heading/heading.js.map +1 -0
- package/dist/components/css/help-text/help-text.d.ts +24 -0
- package/dist/components/css/help-text/help-text.d.ts.map +1 -0
- package/dist/components/css/help-text/help-text.js +23 -0
- package/dist/components/css/help-text/help-text.js.map +1 -0
- package/dist/components/css/icon/icon.d.ts +34 -0
- package/dist/components/css/icon/icon.d.ts.map +1 -0
- package/dist/components/css/icon/icon.js +25 -0
- package/dist/components/css/icon/icon.js.map +1 -0
- package/dist/components/css/input/input.d.ts +40 -0
- package/dist/components/css/input/input.d.ts.map +1 -0
- package/dist/components/css/input/input.js +45 -0
- package/dist/components/css/input/input.js.map +1 -0
- package/dist/components/css/label/label.d.ts +33 -0
- package/dist/components/css/label/label.d.ts.map +1 -0
- package/dist/components/css/label/label.js +23 -0
- package/dist/components/css/label/label.js.map +1 -0
- package/dist/components/css/link/link.d.ts +28 -0
- package/dist/components/css/link/link.d.ts.map +1 -0
- package/dist/components/css/link/link.js +20 -0
- package/dist/components/css/link/link.js.map +1 -0
- package/dist/components/css/list/list.d.ts +31 -0
- package/dist/components/css/list/list.d.ts.map +1 -0
- package/dist/components/css/list/list.js +25 -0
- package/dist/components/css/list/list.js.map +1 -0
- package/dist/components/css/pagination/pagination.d.ts +27 -0
- package/dist/components/css/pagination/pagination.d.ts.map +1 -0
- package/dist/components/css/pagination/pagination.js +25 -0
- package/dist/components/css/pagination/pagination.js.map +1 -0
- package/dist/components/css/paragraph/paragraph.d.ts +36 -0
- package/dist/components/css/paragraph/paragraph.d.ts.map +1 -0
- package/dist/components/css/paragraph/paragraph.js +26 -0
- package/dist/components/css/paragraph/paragraph.js.map +1 -0
- package/dist/components/css/progress/progress.d.ts +53 -0
- package/dist/components/css/progress/progress.d.ts.map +1 -0
- package/dist/components/css/progress/progress.js +38 -0
- package/dist/components/css/progress/progress.js.map +1 -0
- package/dist/components/css/radio/radio.d.ts +32 -0
- package/dist/components/css/radio/radio.d.ts.map +1 -0
- package/dist/components/css/radio/radio.js +27 -0
- package/dist/components/css/radio/radio.js.map +1 -0
- package/dist/components/css/search/search.d.ts +34 -0
- package/dist/components/css/search/search.d.ts.map +1 -0
- package/dist/components/css/search/search.js +32 -0
- package/dist/components/css/search/search.js.map +1 -0
- package/dist/components/css/select/select.d.ts +40 -0
- package/dist/components/css/select/select.d.ts.map +1 -0
- package/dist/components/css/select/select.js +31 -0
- package/dist/components/css/select/select.js.map +1 -0
- package/dist/components/css/shared.d.ts +90 -0
- package/dist/components/css/shared.d.ts.map +1 -0
- package/dist/components/css/shared.js +167 -0
- package/dist/components/css/shared.js.map +1 -0
- package/dist/components/css/skeleton/skeleton.d.ts +29 -0
- package/dist/components/css/skeleton/skeleton.d.ts.map +1 -0
- package/dist/components/css/skeleton/skeleton.js +23 -0
- package/dist/components/css/skeleton/skeleton.js.map +1 -0
- package/dist/components/css/skip-link/skip-link.d.ts +18 -0
- package/dist/components/css/skip-link/skip-link.d.ts.map +1 -0
- package/dist/components/css/skip-link/skip-link.js +16 -0
- package/dist/components/css/skip-link/skip-link.js.map +1 -0
- package/dist/components/css/spinner/spinner.d.ts +33 -0
- package/dist/components/css/spinner/spinner.d.ts.map +1 -0
- package/dist/components/css/spinner/spinner.js +25 -0
- package/dist/components/css/spinner/spinner.js.map +1 -0
- package/dist/components/css/sr-only/sr-only.d.ts +17 -0
- package/dist/components/css/sr-only/sr-only.d.ts.map +1 -0
- package/dist/components/css/sr-only/sr-only.js +15 -0
- package/dist/components/css/sr-only/sr-only.js.map +1 -0
- package/dist/components/css/switch/switch.d.ts +37 -0
- package/dist/components/css/switch/switch.d.ts.map +1 -0
- package/dist/components/css/switch/switch.js +29 -0
- package/dist/components/css/switch/switch.js.map +1 -0
- package/dist/components/css/table/table.d.ts +76 -0
- package/dist/components/css/table/table.d.ts.map +1 -0
- package/dist/components/css/table/table.js +59 -0
- package/dist/components/css/table/table.js.map +1 -0
- package/dist/components/css/tag/tag.d.ts +35 -0
- package/dist/components/css/tag/tag.d.ts.map +1 -0
- package/dist/components/css/tag/tag.js +27 -0
- package/dist/components/css/tag/tag.js.map +1 -0
- package/dist/components/css/textarea/textarea.d.ts +23 -0
- package/dist/components/css/textarea/textarea.d.ts.map +1 -0
- package/dist/components/css/textarea/textarea.js +18 -0
- package/dist/components/css/textarea/textarea.js.map +1 -0
- package/dist/components/css/toggle-group/toggle-group.d.ts +31 -0
- package/dist/components/css/toggle-group/toggle-group.d.ts.map +1 -0
- package/dist/components/css/toggle-group/toggle-group.js +29 -0
- package/dist/components/css/toggle-group/toggle-group.js.map +1 -0
- package/dist/components/css/tooltip/tooltip.d.ts +31 -0
- package/dist/components/css/tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/css/tooltip/tooltip.js +29 -0
- package/dist/components/css/tooltip/tooltip.js.map +1 -0
- package/dist/components/default-texts.d.ts +35 -0
- package/dist/components/default-texts.d.ts.map +1 -0
- package/dist/components/default-texts.js +35 -0
- package/dist/components/default-texts.js.map +1 -0
- package/dist/components/events.d.ts +77 -0
- package/dist/components/events.d.ts.map +1 -0
- package/dist/components/events.js +3 -0
- package/dist/components/events.js.map +1 -0
- package/dist/components/frame/dialog/dialog.d.ts +122 -0
- package/dist/components/frame/dialog/dialog.d.ts.map +1 -0
- package/dist/components/frame/dialog/dialog.js +112 -0
- package/dist/components/frame/dialog/dialog.js.map +1 -0
- package/dist/components/frame/dialog/lt-dialog.d.ts +104 -0
- package/dist/components/frame/dialog/lt-dialog.d.ts.map +1 -0
- package/dist/components/frame/dialog/lt-dialog.js +431 -0
- package/dist/components/frame/dialog/lt-dialog.js.map +1 -0
- package/dist/components/frame/error-summary/error-summary.d.ts +40 -0
- package/dist/components/frame/error-summary/error-summary.d.ts.map +1 -0
- package/dist/components/frame/error-summary/error-summary.js +32 -0
- package/dist/components/frame/error-summary/error-summary.js.map +1 -0
- package/dist/components/frame/error-summary/lt-error-summary.d.ts +82 -0
- package/dist/components/frame/error-summary/lt-error-summary.d.ts.map +1 -0
- package/dist/components/frame/error-summary/lt-error-summary.js +302 -0
- package/dist/components/frame/error-summary/lt-error-summary.js.map +1 -0
- package/dist/components/frame/field/field-core.d.ts +92 -0
- package/dist/components/frame/field/field-core.d.ts.map +1 -0
- package/dist/components/frame/field/field-core.js +63 -0
- package/dist/components/frame/field/field-core.js.map +1 -0
- package/dist/components/frame/field/lt-field.d.ts +173 -0
- package/dist/components/frame/field/lt-field.d.ts.map +1 -0
- package/dist/components/frame/field/lt-field.js +580 -0
- package/dist/components/frame/field/lt-field.js.map +1 -0
- package/dist/components/frame/popover/lt-popover.d.ts +132 -0
- package/dist/components/frame/popover/lt-popover.d.ts.map +1 -0
- package/dist/components/frame/popover/lt-popover.js +490 -0
- package/dist/components/frame/popover/lt-popover.js.map +1 -0
- package/dist/components/frame/popover/popover.d.ts +49 -0
- package/dist/components/frame/popover/popover.d.ts.map +1 -0
- package/dist/components/frame/popover/popover.js +64 -0
- package/dist/components/frame/popover/popover.js.map +1 -0
- package/dist/components/frame/session-timeout/lt-session-timeout.d.ts +198 -0
- package/dist/components/frame/session-timeout/lt-session-timeout.d.ts.map +1 -0
- package/dist/components/frame/session-timeout/lt-session-timeout.js +573 -0
- package/dist/components/frame/session-timeout/lt-session-timeout.js.map +1 -0
- package/dist/components/frame/session-timeout/session-timeout.d.ts +113 -0
- package/dist/components/frame/session-timeout/session-timeout.d.ts.map +1 -0
- package/dist/components/frame/session-timeout/session-timeout.js +101 -0
- package/dist/components/frame/session-timeout/session-timeout.js.map +1 -0
- package/dist/components/frame/suggestion/lt-suggestion.d.ts +361 -0
- package/dist/components/frame/suggestion/lt-suggestion.d.ts.map +1 -0
- package/dist/components/frame/suggestion/lt-suggestion.js +1152 -0
- package/dist/components/frame/suggestion/lt-suggestion.js.map +1 -0
- package/dist/components/frame/suggestion/suggestion.d.ts +143 -0
- package/dist/components/frame/suggestion/suggestion.d.ts.map +1 -0
- package/dist/components/frame/suggestion/suggestion.js +127 -0
- package/dist/components/frame/suggestion/suggestion.js.map +1 -0
- package/dist/components/frame/tabs/lt-tabs.d.ts +404 -0
- package/dist/components/frame/tabs/lt-tabs.d.ts.map +1 -0
- package/dist/components/frame/tabs/lt-tabs.js +1201 -0
- package/dist/components/frame/tabs/lt-tabs.js.map +1 -0
- package/dist/components/frame/tabs/tabs.d.ts +112 -0
- package/dist/components/frame/tabs/tabs.d.ts.map +1 -0
- package/dist/components/frame/tabs/tabs.js +107 -0
- package/dist/components/frame/tabs/tabs.js.map +1 -0
- package/dist/components/host-element.d.ts +135 -0
- package/dist/components/host-element.d.ts.map +1 -0
- package/dist/components/host-element.js +366 -0
- package/dist/components/host-element.js.map +1 -0
- package/dist/components/standalone/connection-status/connection-status.d.ts +28 -0
- package/dist/components/standalone/connection-status/connection-status.d.ts.map +1 -0
- package/dist/components/standalone/connection-status/connection-status.js +22 -0
- package/dist/components/standalone/connection-status/connection-status.js.map +1 -0
- package/dist/components/standalone/connection-status/lt-connection-status.d.ts +81 -0
- package/dist/components/standalone/connection-status/lt-connection-status.d.ts.map +1 -0
- package/dist/components/standalone/connection-status/lt-connection-status.js +216 -0
- package/dist/components/standalone/connection-status/lt-connection-status.js.map +1 -0
- package/dist/components/standalone/toast/lt-toast.d.ts +109 -0
- package/dist/components/standalone/toast/lt-toast.d.ts.map +1 -0
- package/dist/components/standalone/toast/lt-toast.js +256 -0
- package/dist/components/standalone/toast/lt-toast.js.map +1 -0
- package/dist/components/standalone/toast/toast.d.ts +52 -0
- package/dist/components/standalone/toast/toast.d.ts.map +1 -0
- package/dist/components/standalone/toast/toast.js +42 -0
- package/dist/components/standalone/toast/toast.js.map +1 -0
- package/dist/diagnostics/core.d.ts +137 -0
- package/dist/diagnostics/core.d.ts.map +1 -0
- package/dist/diagnostics/core.js +72 -0
- package/dist/diagnostics/core.js.map +1 -0
- package/dist/diagnostics/default-core.d.ts +10 -0
- package/dist/diagnostics/default-core.d.ts.map +1 -0
- package/dist/diagnostics/default-core.js +72 -0
- package/dist/diagnostics/default-core.js.map +1 -0
- package/dist/diagnostics/index.d.ts +84 -0
- package/dist/diagnostics/index.d.ts.map +1 -0
- package/dist/diagnostics/index.js +106 -0
- package/dist/diagnostics/index.js.map +1 -0
- package/dist/dom.d.ts +55 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +162 -0
- package/dist/dom.js.map +1 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx/react.d.ts +180 -0
- package/dist/jsx/react.d.ts.map +1 -0
- package/dist/jsx/react.js +2 -0
- package/dist/jsx/react.js.map +1 -0
- package/dist/lotek.css +3617 -0
- package/dist/lt.d.ts +325 -0
- package/dist/lt.d.ts.map +1 -0
- package/dist/lt.js +183 -0
- package/dist/lt.js.map +1 -0
- package/dist/react.d.ts +492 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +296 -0
- package/dist/react.js.map +1 -0
- package/dist/register.d.ts +17 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +35 -0
- package/dist/register.js.map +1 -0
- package/dist/tokens/color.d.ts +43 -0
- package/dist/tokens/color.d.ts.map +1 -0
- package/dist/tokens/color.js +123 -0
- package/dist/tokens/color.js.map +1 -0
- package/dist/tokens/contract.d.ts +18 -0
- package/dist/tokens/contract.d.ts.map +1 -0
- package/dist/tokens/contract.js +18 -0
- package/dist/tokens/contract.js.map +1 -0
- package/dist/tokens/matrix-cells.d.ts +30 -0
- package/dist/tokens/matrix-cells.d.ts.map +1 -0
- package/dist/tokens/matrix-cells.js +273 -0
- package/dist/tokens/matrix-cells.js.map +1 -0
- package/dist/tokens/matrix.d.ts +18 -0
- package/dist/tokens/matrix.d.ts.map +1 -0
- package/dist/tokens/matrix.js +21 -0
- package/dist/tokens/matrix.js.map +1 -0
- package/dist/tokens/theme-check.d.ts +42 -0
- package/dist/tokens/theme-check.d.ts.map +1 -0
- package/dist/tokens/theme-check.js +10 -0
- package/dist/tokens/theme-check.js.map +1 -0
- package/dist/tokens/theme.d.ts +94 -0
- package/dist/tokens/theme.d.ts.map +1 -0
- package/dist/tokens/theme.js +14 -0
- package/dist/tokens/theme.js.map +1 -0
- package/dist/tokens/tokens.d.ts +122 -0
- package/dist/tokens/tokens.d.ts.map +1 -0
- package/dist/tokens/tokens.js +158 -0
- package/dist/tokens/tokens.js.map +1 -0
- package/dist/vocabulary/classes.d.ts +3 -0
- package/dist/vocabulary/classes.d.ts.map +1 -0
- package/dist/vocabulary/classes.js +1320 -0
- package/dist/vocabulary/classes.js.map +1 -0
- package/dist/vocabulary/elements.d.ts +3 -0
- package/dist/vocabulary/elements.d.ts.map +1 -0
- package/dist/vocabulary/elements.js +410 -0
- package/dist/vocabulary/elements.js.map +1 -0
- package/dist/vocabulary/types.d.ts +175 -0
- package/dist/vocabulary/types.d.ts.map +1 -0
- package/dist/vocabulary/types.js +11 -0
- package/dist/vocabulary/types.js.map +1 -0
- package/dist/wasi-host.d.ts +24 -0
- package/dist/wasi-host.d.ts.map +1 -0
- package/dist/wasi-host.js +140 -0
- package/dist/wasi-host.js.map +1 -0
- package/live-templates.xml +62 -0
- package/manifest/files.json +373 -0
- package/manifest/manifest.json +4965 -0
- package/manifest/manifest.schema.json +513 -0
- package/package.json +404 -4
- package/src/cli.ts +21 -0
- package/src/components/css/accordion/accordion.css +102 -0
- package/src/components/css/accordion/accordion.ts +50 -0
- package/src/components/css/alert/alert.css +53 -0
- package/src/components/css/alert/alert.ts +48 -0
- package/src/components/css/avatar/avatar.css +96 -0
- package/src/components/css/avatar/avatar.ts +57 -0
- package/src/components/css/badge/badge.css +42 -0
- package/src/components/css/badge/badge.ts +43 -0
- package/src/components/css/breadcrumbs/breadcrumbs.css +62 -0
- package/src/components/css/breadcrumbs/breadcrumbs.ts +30 -0
- package/src/components/css/button/button.css +128 -0
- package/src/components/css/button/button.ts +44 -0
- package/src/components/css/card/card.css +65 -0
- package/src/components/css/card/card.ts +50 -0
- package/src/components/css/checkbox/checkbox.css +114 -0
- package/src/components/css/checkbox/checkbox.ts +50 -0
- package/src/components/css/divider/divider.css +38 -0
- package/src/components/css/divider/divider.ts +42 -0
- package/src/components/css/error-text/error-text.css +21 -0
- package/src/components/css/error-text/error-text.ts +37 -0
- package/src/components/css/fieldset/fieldset.css +72 -0
- package/src/components/css/fieldset/fieldset.ts +87 -0
- package/src/components/css/file-upload/file-upload.css +102 -0
- package/src/components/css/file-upload/file-upload.ts +65 -0
- package/src/components/css/heading/heading.css +33 -0
- package/src/components/css/heading/heading.ts +42 -0
- package/src/components/css/help-text/help-text.css +24 -0
- package/src/components/css/help-text/help-text.ts +42 -0
- package/src/components/css/icon/icon.css +20 -0
- package/src/components/css/icon/icon.ts +44 -0
- package/src/components/css/input/input.css +145 -0
- package/src/components/css/input/input.ts +77 -0
- package/src/components/css/label/label.css +42 -0
- package/src/components/css/label/label.ts +51 -0
- package/src/components/css/link/link.css +38 -0
- package/src/components/css/link/link.ts +38 -0
- package/src/components/css/list/list.css +53 -0
- package/src/components/css/list/list.ts +44 -0
- package/src/components/css/pagination/pagination.css +95 -0
- package/src/components/css/pagination/pagination.ts +33 -0
- package/src/components/css/paragraph/paragraph.css +31 -0
- package/src/components/css/paragraph/paragraph.ts +53 -0
- package/src/components/css/progress/progress.css +161 -0
- package/src/components/css/progress/progress.ts +78 -0
- package/src/components/css/radio/radio.css +94 -0
- package/src/components/css/radio/radio.ts +50 -0
- package/src/components/css/search/search.css +50 -0
- package/src/components/css/search/search.ts +56 -0
- package/src/components/css/select/select.css +321 -0
- package/src/components/css/select/select.ts +63 -0
- package/src/components/css/shared.ts +199 -0
- package/src/components/css/skeleton/skeleton.css +62 -0
- package/src/components/css/skeleton/skeleton.ts +43 -0
- package/src/components/css/skip-link/skip-link.css +41 -0
- package/src/components/css/skip-link/skip-link.ts +22 -0
- package/src/components/css/spinner/spinner.css +48 -0
- package/src/components/css/spinner/spinner.ts +48 -0
- package/src/components/css/sr-only/sr-only.css +16 -0
- package/src/components/css/sr-only/sr-only.ts +21 -0
- package/src/components/css/switch/switch.css +105 -0
- package/src/components/css/switch/switch.ts +50 -0
- package/src/components/css/table/table.css +159 -0
- package/src/components/css/table/table.ts +107 -0
- package/src/components/css/tag/tag.css +58 -0
- package/src/components/css/tag/tag.ts +49 -0
- package/src/components/css/textarea/textarea.css +83 -0
- package/src/components/css/textarea/textarea.ts +40 -0
- package/src/components/css/toggle-group/toggle-group.css +92 -0
- package/src/components/css/toggle-group/toggle-group.ts +37 -0
- package/src/components/css/tooltip/tooltip.css +89 -0
- package/src/components/css/tooltip/tooltip.ts +37 -0
- package/src/components/default-texts.ts +34 -0
- package/src/components/events.ts +68 -0
- package/src/components/frame/dialog/dialog.css +306 -0
- package/src/components/frame/dialog/dialog.ts +166 -0
- package/src/components/frame/dialog/lt-dialog.ts +510 -0
- package/src/components/frame/error-summary/error-summary.css +47 -0
- package/src/components/frame/error-summary/error-summary.ts +56 -0
- package/src/components/frame/error-summary/lt-error-summary.ts +344 -0
- package/src/components/frame/field/field-core.ts +152 -0
- package/src/components/frame/field/field.css +17 -0
- package/src/components/frame/field/lt-field.ts +753 -0
- package/src/components/frame/popover/lt-popover.ts +555 -0
- package/src/components/frame/popover/popover.css +50 -0
- package/src/components/frame/popover/popover.ts +102 -0
- package/src/components/frame/session-timeout/lt-session-timeout.ts +681 -0
- package/src/components/frame/session-timeout/session-timeout.css +50 -0
- package/src/components/frame/session-timeout/session-timeout.ts +156 -0
- package/src/components/frame/suggestion/lt-suggestion.ts +1358 -0
- package/src/components/frame/suggestion/suggestion.css +132 -0
- package/src/components/frame/suggestion/suggestion.ts +172 -0
- package/src/components/frame/tabs/lt-tabs.ts +1319 -0
- package/src/components/frame/tabs/tabs.css +128 -0
- package/src/components/frame/tabs/tabs.ts +188 -0
- package/src/components/host-element.ts +400 -0
- package/src/components/standalone/connection-status/connection-status.css +41 -0
- package/src/components/standalone/connection-status/connection-status.ts +41 -0
- package/src/components/standalone/connection-status/lt-connection-status.ts +242 -0
- package/src/components/standalone/toast/lt-toast.ts +300 -0
- package/src/components/standalone/toast/toast.css +78 -0
- package/src/components/standalone/toast/toast.ts +70 -0
- package/src/diagnostics/core.ts +210 -0
- package/src/diagnostics/default-core.ts +81 -0
- package/src/diagnostics/index.ts +150 -0
- package/src/dom.ts +185 -0
- package/src/index.ts +218 -0
- package/src/jsx/react.ts +212 -0
- package/src/lt.ts +192 -0
- package/src/react.ts +411 -0
- package/src/register.ts +43 -0
- package/src/tailwind/tailwind.css +169 -0
- package/src/tokens/boundary.css +104 -0
- package/src/tokens/color-contract.json +231 -0
- package/src/tokens/color.ts +150 -0
- package/src/tokens/contract.ts +24 -0
- package/src/tokens/matrix-cells.ts +375 -0
- package/src/tokens/matrix.ts +32 -0
- package/src/tokens/theme-check.ts +51 -0
- package/src/tokens/theme.ts +104 -0
- package/src/tokens/tokens.css +569 -0
- package/src/tokens/tokens.ts +223 -0
- package/src/vocabulary/classes.ts +1322 -0
- package/src/vocabulary/elements.ts +412 -0
- package/src/vocabulary/types.ts +178 -0
- package/src/wasi-host.ts +155 -0
- package/web-types.json +800 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { INPUT_CLASS, input } from "../input/input.js"
|
|
2
|
+
import {
|
|
3
|
+
attributes,
|
|
4
|
+
type FieldState,
|
|
5
|
+
fieldStates,
|
|
6
|
+
isFieldState,
|
|
7
|
+
} from "../shared.js"
|
|
8
|
+
|
|
9
|
+
export const SEARCH_CLASS = "lt-search" as const
|
|
10
|
+
/** The row with the search field and the button next to it. */
|
|
11
|
+
export const SEARCH_ROW_CLASS = "lt-search-row" as const
|
|
12
|
+
|
|
13
|
+
export type SearchOptions = {
|
|
14
|
+
/** Validation state. Default: `default`. */
|
|
15
|
+
state?: FieldState
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type SearchAttributes = {
|
|
19
|
+
class: `${typeof INPUT_CLASS} ${typeof SEARCH_CLASS}`
|
|
20
|
+
type: "search"
|
|
21
|
+
"data-state"?: "invalid" | "success"
|
|
22
|
+
"aria-invalid"?: "true"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The attributes for a search field.
|
|
27
|
+
*
|
|
28
|
+
* The field is an `lt-input` with room for the magnifying glass, so both
|
|
29
|
+
* classes are set. `type="search"` gives the browser's own cross for
|
|
30
|
+
* clearing the field, and on mobile a keyboard with "Search" instead of
|
|
31
|
+
* "Enter".
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* <input {...search()} name="q" />
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export const search = Object.assign(
|
|
38
|
+
({ state = "default" }: SearchOptions = {}): SearchAttributes => {
|
|
39
|
+
const base = input({ type: "search", state })
|
|
40
|
+
return attributes(
|
|
41
|
+
{
|
|
42
|
+
...base,
|
|
43
|
+
class: `${INPUT_CLASS} ${SEARCH_CLASS}` as const,
|
|
44
|
+
type: "search" as const,
|
|
45
|
+
"data-variant": undefined,
|
|
46
|
+
},
|
|
47
|
+
base,
|
|
48
|
+
) as SearchAttributes
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
/** The class on the row with the field and the button. */
|
|
52
|
+
row: SEARCH_ROW_CLASS,
|
|
53
|
+
states: fieldStates,
|
|
54
|
+
isState: isFieldState,
|
|
55
|
+
},
|
|
56
|
+
)
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
@layer lotek {
|
|
2
|
+
.lt-select {
|
|
3
|
+
/* The design system cannot assume the consumer has a CSS reset. Without
|
|
4
|
+
border-box, padding and border are added outside the width, and the
|
|
5
|
+
field becomes wider than the box it sits in. */
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
|
|
8
|
+
display: block;
|
|
9
|
+
width: var(--lt-select-width, 100%);
|
|
10
|
+
padding: var(--lt-select-padding, var(--lt-spacing-2) var(--lt-spacing-3));
|
|
11
|
+
/* The end side is the room for the arrow, and it is fixed: the arrow is
|
|
12
|
+
drawn a fixed distance from the edge, so less room would put the text
|
|
13
|
+
on top of it. So `--lt-select-padding` applies to everything except
|
|
14
|
+
this side here. With `data-picker="styled"` the arrow takes real
|
|
15
|
+
room, and there the variable applies to all four sides. */
|
|
16
|
+
padding-inline-end: calc(var(--lt-spacing-4) + var(--lt-spacing-2));
|
|
17
|
+
font-family: inherit;
|
|
18
|
+
font-size: var(--lt-font-size-m);
|
|
19
|
+
line-height: var(--lt-line-height-default);
|
|
20
|
+
color: var(--lt-color-neutral-text-strong);
|
|
21
|
+
background-color: var(--lt-color-neutral-canvas);
|
|
22
|
+
border: 1px solid var(--lt-color-neutral-border);
|
|
23
|
+
border-radius: var(--lt-select-radius, var(--lt-spacing-1));
|
|
24
|
+
appearance: none;
|
|
25
|
+
background-image:
|
|
26
|
+
linear-gradient(
|
|
27
|
+
45deg,
|
|
28
|
+
transparent 50%,
|
|
29
|
+
var(--lt-color-neutral-text-subtle) 50%
|
|
30
|
+
),
|
|
31
|
+
linear-gradient(
|
|
32
|
+
135deg,
|
|
33
|
+
var(--lt-color-neutral-text-subtle) 50%,
|
|
34
|
+
transparent 50%
|
|
35
|
+
);
|
|
36
|
+
background-position:
|
|
37
|
+
calc(100% - 1rem) calc(50% - 0.1rem),
|
|
38
|
+
calc(100% - 0.75rem) calc(50% - 0.1rem);
|
|
39
|
+
background-size:
|
|
40
|
+
0.35rem 0.35rem,
|
|
41
|
+
0.35rem 0.35rem;
|
|
42
|
+
background-repeat: no-repeat;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* The arrow is two gradients, and `background-position` has no logical
|
|
46
|
+
variant. The mirrored version is the same two pieces, moved to the left
|
|
47
|
+
edge and swapped: the one that was outermost is now innermost. From the
|
|
48
|
+
left the position is given to the piece's left edge, from the right with
|
|
49
|
+
`calc(100% - ...)` to the same point on the other side, so the distances
|
|
50
|
+
are the same numbers. With 0.35rem subtracted the arrow sat 6 pixels
|
|
51
|
+
from the edge instead of 12. */
|
|
52
|
+
.lt-select:dir(rtl) {
|
|
53
|
+
background-position:
|
|
54
|
+
0.75rem calc(50% - 0.1rem),
|
|
55
|
+
1rem calc(50% - 0.1rem);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.lt-select:hover {
|
|
59
|
+
border-color: var(--lt-color-neutral-border-strong);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.lt-select:focus-visible {
|
|
63
|
+
outline: var(--lt-focus-ring);
|
|
64
|
+
outline-offset: 2px;
|
|
65
|
+
border-color: var(--lt-color-accent-border);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.lt-select:disabled,
|
|
69
|
+
.lt-select[aria-disabled="true"] {
|
|
70
|
+
background-color: var(--lt-color-disabled-surface);
|
|
71
|
+
color: var(--lt-color-disabled-text);
|
|
72
|
+
border-color: var(--lt-color-disabled-surface);
|
|
73
|
+
/* No pointer-events: none here. The browser already blocks a disabled
|
|
74
|
+
field, and pointer-events would only stop the cursor from showing. The
|
|
75
|
+
element is then not hit by the mouse at all. */
|
|
76
|
+
cursor: not-allowed;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* aria-disabled is only information for screen readers; the element still
|
|
80
|
+
works. Here pointer-events stops the mouse, at the cost of the cursor.
|
|
81
|
+
If the field should really be off, use `disabled` or `readonly`. */
|
|
82
|
+
.lt-select[aria-disabled="true"] {
|
|
83
|
+
pointer-events: none;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.lt-select[data-state="invalid"] {
|
|
87
|
+
border-color: var(--lt-color-danger-text);
|
|
88
|
+
background-color: var(--lt-color-danger-surface);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.lt-select[data-state="invalid"]:focus-visible {
|
|
92
|
+
outline-color: var(--lt-color-danger-text);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.lt-select[data-state="success"] {
|
|
96
|
+
border-color: var(--lt-color-success-text);
|
|
97
|
+
background-color: var(--lt-color-success-surface);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.lt-select[data-state="success"]:focus-visible {
|
|
101
|
+
outline-color: var(--lt-color-success-text);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Disabled wins over a state. `[data-state]` used to come after
|
|
105
|
+
`:disabled` with the same specificity, and an invalid field in a form
|
|
106
|
+
that was disabled during submission looked red, not disabled. */
|
|
107
|
+
.lt-select:is(:disabled, [aria-disabled="true"])[data-state] {
|
|
108
|
+
background-color: var(--lt-color-disabled-surface);
|
|
109
|
+
color: var(--lt-color-disabled-text);
|
|
110
|
+
border-color: var(--lt-color-disabled-surface);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
* The dropdown list is a window from the operating system, and no CSS
|
|
115
|
+
* reaches into it. `appearance: base-select` asks the browser to draw it
|
|
116
|
+
* inside the page instead: `::picker(select)` becomes a normal element,
|
|
117
|
+
* and each `<option>` can get the design system's colours and spacing.
|
|
118
|
+
*
|
|
119
|
+
* It is optional, and turned on with `data-picker="styled"`. Firefox 150
|
|
120
|
+
* does not have it, and there the field keeps the browser's own list. It
|
|
121
|
+
* is the same component with two looks, not something that breaks.
|
|
122
|
+
*/
|
|
123
|
+
@supports (appearance: base-select) {
|
|
124
|
+
.lt-select[data-picker="styled"],
|
|
125
|
+
.lt-select[data-picker="styled"]::picker(select) {
|
|
126
|
+
appearance: base-select;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* The button now draws its own arrow with `::picker-icon`, so the
|
|
130
|
+
gradients must go. The arrow takes real room in the layout, and the
|
|
131
|
+
room we kept for the drawn arrow would then be there twice. */
|
|
132
|
+
.lt-select[data-picker="styled"] {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
justify-content: space-between;
|
|
136
|
+
gap: var(--lt-spacing-2);
|
|
137
|
+
background-image: none;
|
|
138
|
+
padding: var(
|
|
139
|
+
--lt-select-padding,
|
|
140
|
+
var(--lt-spacing-2) var(--lt-spacing-3)
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* The text in the button is the current choice. Long choices should be
|
|
145
|
+
clipped, not push the arrow out of the field. Without
|
|
146
|
+
`min-inline-size: 0` it does not shrink, because flex gives it the
|
|
147
|
+
minimum width of its content.
|
|
148
|
+
|
|
149
|
+
The browser does not create <selectedcontent> by itself. It only
|
|
150
|
+
exists when the author writes
|
|
151
|
+
`<button><selectedcontent></selectedcontent></button>` first in the
|
|
152
|
+
select. Without it the choice is drawn in the browser's own shadow
|
|
153
|
+
DOM, which no rule reaches, and a long choice wraps over several
|
|
154
|
+
lines. `white-space: nowrap` on the select does not help: the text
|
|
155
|
+
does not shrink there, and the arrow is pushed out of the field. */
|
|
156
|
+
/* biome-ignore lint/correctness/noUnknownTypeSelector: <selectedcontent> is
|
|
157
|
+
the element that shows the selected option in a customisable
|
|
158
|
+
dropdown list. Biome does not know it yet. */
|
|
159
|
+
.lt-select[data-picker="styled"] selectedcontent {
|
|
160
|
+
min-inline-size: 0;
|
|
161
|
+
overflow: hidden;
|
|
162
|
+
white-space: nowrap;
|
|
163
|
+
text-overflow: ellipsis;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.lt-select[data-picker="styled"]::picker-icon {
|
|
167
|
+
color: var(--lt-color-neutral-text-subtle);
|
|
168
|
+
transition: rotate 120ms ease;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.lt-select[data-picker="styled"]:open::picker-icon {
|
|
172
|
+
rotate: 180deg;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.lt-select[data-picker="styled"]::picker(select) {
|
|
176
|
+
box-sizing: border-box;
|
|
177
|
+
min-inline-size: anchor-size(self-inline);
|
|
178
|
+
/* The list should fill the room that is actually left down to the
|
|
179
|
+
edge of the window, not stretch beyond it. `stretch` is exactly
|
|
180
|
+
that room, and the margin is subtracted. */
|
|
181
|
+
max-block-size: stretch;
|
|
182
|
+
margin-block: var(--lt-select-viewport-margin, var(--lt-spacing-2));
|
|
183
|
+
padding: 0;
|
|
184
|
+
overflow-y: auto;
|
|
185
|
+
background: var(--lt-color-neutral-canvas);
|
|
186
|
+
border: 1px solid var(--lt-color-neutral-border);
|
|
187
|
+
border-radius: var(--lt-select-radius, var(--lt-spacing-1));
|
|
188
|
+
box-shadow: var(--lt-shadow-overlay);
|
|
189
|
+
/* If there is no room below the field, the list goes above it. */
|
|
190
|
+
position-try-fallbacks: flip-block;
|
|
191
|
+
opacity: 0;
|
|
192
|
+
transition:
|
|
193
|
+
opacity 120ms ease,
|
|
194
|
+
overlay 120ms allow-discrete,
|
|
195
|
+
display 120ms allow-discrete;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.lt-select[data-picker="styled"]:open::picker(select) {
|
|
199
|
+
opacity: 1;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@starting-style {
|
|
203
|
+
.lt-select[data-picker="styled"]:open::picker(select) {
|
|
204
|
+
opacity: 0;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* The height can only be animated where `calc-size` exists, since `auto`
|
|
209
|
+
is otherwise not a value that can be transitioned to. Without support
|
|
210
|
+
the height stays `auto`, and only the opacity fades. */
|
|
211
|
+
@supports (block-size: calc-size(auto, size)) {
|
|
212
|
+
.lt-select[data-picker="styled"]::picker(select) {
|
|
213
|
+
block-size: 0;
|
|
214
|
+
transition:
|
|
215
|
+
opacity 120ms ease,
|
|
216
|
+
block-size 120ms ease,
|
|
217
|
+
overlay 120ms allow-discrete,
|
|
218
|
+
display 120ms allow-discrete;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.lt-select[data-picker="styled"]:open::picker(select) {
|
|
222
|
+
block-size: calc-size(auto, size);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@starting-style {
|
|
226
|
+
.lt-select[data-picker="styled"]:open::picker(select) {
|
|
227
|
+
block-size: 0;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* The group heading is not an element we can target when it comes from
|
|
233
|
+
`label=`, only from `<legend>`. So it is set on the group, and
|
|
234
|
+
inherited down: the size and colour set it apart from the options,
|
|
235
|
+
and `text-indent` gives it the same left edge as the text in an
|
|
236
|
+
option. The options set those three back to their own values. */
|
|
237
|
+
.lt-select[data-picker="styled"] optgroup {
|
|
238
|
+
padding-block: var(--lt-spacing-2) var(--lt-spacing-1);
|
|
239
|
+
font-size: var(--lt-font-size-s);
|
|
240
|
+
color: var(--lt-color-neutral-text-subtle);
|
|
241
|
+
text-indent: var(--lt-spacing-3);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.lt-select[data-picker="styled"] option {
|
|
245
|
+
text-indent: 0;
|
|
246
|
+
display: flex;
|
|
247
|
+
align-items: center;
|
|
248
|
+
gap: var(--lt-spacing-2);
|
|
249
|
+
padding: var(
|
|
250
|
+
--lt-select-option-padding,
|
|
251
|
+
var(--lt-spacing-2) var(--lt-spacing-3)
|
|
252
|
+
);
|
|
253
|
+
font-family: inherit;
|
|
254
|
+
font-size: var(--lt-font-size-m);
|
|
255
|
+
line-height: var(--lt-line-height-default);
|
|
256
|
+
color: var(--lt-color-neutral-text-strong);
|
|
257
|
+
background: var(--lt-color-neutral-canvas);
|
|
258
|
+
cursor: pointer;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* The tick comes after the text, not before it, so all the options get
|
|
262
|
+
the text in the same place. */
|
|
263
|
+
.lt-select[data-picker="styled"] option::checkmark {
|
|
264
|
+
order: 1;
|
|
265
|
+
margin-inline-start: auto;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.lt-select[data-picker="styled"] option:hover {
|
|
269
|
+
background: var(--lt-color-accent-surface);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.lt-select[data-picker="styled"] option:checked {
|
|
273
|
+
background: var(--lt-color-accent-fill);
|
|
274
|
+
color: var(--lt-color-accent-content);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/* Focus is shown with a border, not with a surface. The arrow keys move
|
|
278
|
+
focus between the options, and the selected one already has its own
|
|
279
|
+
surface. A different background colour would therefore disappear
|
|
280
|
+
exactly where the user is. */
|
|
281
|
+
.lt-select[data-picker="styled"] option:focus {
|
|
282
|
+
outline: var(--lt-focus-ring);
|
|
283
|
+
outline-offset: -2px;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.lt-select[data-picker="styled"] option:checked:focus {
|
|
287
|
+
outline-color: var(--lt-color-accent-content);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.lt-select[data-picker="styled"] option:disabled {
|
|
291
|
+
color: var(--lt-color-disabled-text);
|
|
292
|
+
background: var(--lt-color-disabled-surface);
|
|
293
|
+
cursor: not-allowed;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
@media (prefers-reduced-motion: reduce) {
|
|
297
|
+
.lt-select[data-picker="styled"]::picker(select),
|
|
298
|
+
.lt-select[data-picker="styled"]::picker-icon {
|
|
299
|
+
transition: none;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/* High contrast: the arrow is two gradients, and they are removed in the
|
|
305
|
+
mode. The browser's own arrow is then better than none. The list drawn
|
|
306
|
+
in the page falls back for the same reason: the browser's own list uses
|
|
307
|
+
the system colours, and they are the only ones guaranteed to be
|
|
308
|
+
readable in the mode. */
|
|
309
|
+
@media (forced-colors: active) {
|
|
310
|
+
.lt-select,
|
|
311
|
+
.lt-select[data-picker="styled"] {
|
|
312
|
+
display: block;
|
|
313
|
+
appearance: auto;
|
|
314
|
+
background-image: none;
|
|
315
|
+
padding: var(
|
|
316
|
+
--lt-select-padding,
|
|
317
|
+
var(--lt-spacing-2) var(--lt-spacing-3)
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
attributes,
|
|
3
|
+
createGuard,
|
|
4
|
+
type FieldState,
|
|
5
|
+
fieldStates,
|
|
6
|
+
isFieldState,
|
|
7
|
+
type NonDefaultFieldState,
|
|
8
|
+
} from "../shared.js"
|
|
9
|
+
|
|
10
|
+
export const SELECT_CLASS = "lt-select" as const
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Who draws the dropdown list.
|
|
14
|
+
*
|
|
15
|
+
* `auto` is the browser's own list, a window from the operating system that
|
|
16
|
+
* cannot be styled. `styled` asks the browser to draw it inside the page
|
|
17
|
+
* instead, so it gets the design system's colours, spacing and shadow.
|
|
18
|
+
*/
|
|
19
|
+
export const selectPickers = ["auto", "styled"] as const
|
|
20
|
+
export type SelectPicker = (typeof selectPickers)[number]
|
|
21
|
+
export type NonDefaultSelectPicker = Exclude<SelectPicker, "auto">
|
|
22
|
+
export const isSelectPicker = createGuard(selectPickers)
|
|
23
|
+
|
|
24
|
+
export type SelectOptions = {
|
|
25
|
+
/** Validation state. Default: `default`. */
|
|
26
|
+
state?: FieldState
|
|
27
|
+
/** Who draws the dropdown list. Default: `auto`. */
|
|
28
|
+
picker?: SelectPicker
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type SelectAttributes = {
|
|
32
|
+
class: typeof SELECT_CLASS
|
|
33
|
+
"data-state"?: NonDefaultFieldState
|
|
34
|
+
"data-picker"?: NonDefaultSelectPicker
|
|
35
|
+
"aria-invalid"?: "true"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The attributes for a dropdown list.
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* <select {...select({ state: "invalid" })} />
|
|
43
|
+
* <select {...select({ picker: "styled" })} />
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export const select = Object.assign(
|
|
47
|
+
({
|
|
48
|
+
state = "default",
|
|
49
|
+
picker = "auto",
|
|
50
|
+
}: SelectOptions = {}): SelectAttributes =>
|
|
51
|
+
attributes({
|
|
52
|
+
class: SELECT_CLASS,
|
|
53
|
+
"data-state": state === "default" ? undefined : state,
|
|
54
|
+
"data-picker": picker === "auto" ? undefined : picker,
|
|
55
|
+
"aria-invalid": state === "invalid" ? ("true" as const) : undefined,
|
|
56
|
+
}),
|
|
57
|
+
{
|
|
58
|
+
states: fieldStates,
|
|
59
|
+
isState: isFieldState,
|
|
60
|
+
pickers: selectPickers,
|
|
61
|
+
isPicker: isSelectPicker,
|
|
62
|
+
},
|
|
63
|
+
)
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared building blocks for the component API.
|
|
3
|
+
*
|
|
4
|
+
* Each component exports one function that takes an object of options and
|
|
5
|
+
* returns the attributes you spread onto the element. The shape is the same
|
|
6
|
+
* for all of them, so you only need to learn it once.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The attributes each set manages, including those that are off right now.
|
|
11
|
+
*
|
|
12
|
+
* `attributes()` drops the keys without a value, and with them the record of
|
|
13
|
+
* which attributes the builder function has a say in. `setAttributes` needs
|
|
14
|
+
* exactly that: `lt.switch()` manages `disabled` and must be able to remove
|
|
15
|
+
* it, while `lt.button()` has never written it and must leave it alone. The
|
|
16
|
+
* list is kept in a map beside the object, not on it, so spreading, JSON and
|
|
17
|
+
* React see the same as before.
|
|
18
|
+
*/
|
|
19
|
+
const managed = new WeakMap<object, readonly string[]>()
|
|
20
|
+
|
|
21
|
+
/** The names the set manages, or `undefined` for a set we did not create. */
|
|
22
|
+
export function managedNames(set: object): readonly string[] | undefined {
|
|
23
|
+
return managed.get(set)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Gives a set rewritten from another the same managed names.
|
|
28
|
+
*
|
|
29
|
+
* `/react` renames `class` to `className` in a new object, and the new object
|
|
30
|
+
* was not in the map. `lt.setAttributes` from there then only cleaned up
|
|
31
|
+
* `data-*`, and `aria-invalid` stayed after the field was corrected. The
|
|
32
|
+
* names are given as they are spelled in the new set.
|
|
33
|
+
*
|
|
34
|
+
* For `/react` and other entry points that rewrite the sets, not for apps: a
|
|
35
|
+
* set from `lt.*` is already managed.
|
|
36
|
+
*/
|
|
37
|
+
export function rememberManaged(set: object, names: readonly string[]): void {
|
|
38
|
+
managed.set(set, names)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Removes attributes without a value, so `{...spread}` does not set empty
|
|
43
|
+
* fields.
|
|
44
|
+
*
|
|
45
|
+
* When the set builds on another, as `lt.search()` does on `lt.input()`, the
|
|
46
|
+
* other is passed in as `based`. The spread has already lost the keys that
|
|
47
|
+
* were off, and without this the search field only managed `data-state` when
|
|
48
|
+
* it happened to be set: it could be set, but not removed.
|
|
49
|
+
*/
|
|
50
|
+
export function attributes<T extends Record<string, unknown>>(
|
|
51
|
+
values: T,
|
|
52
|
+
...based: object[]
|
|
53
|
+
): T {
|
|
54
|
+
const result = {} as T
|
|
55
|
+
for (const [name, value] of Object.entries(values)) {
|
|
56
|
+
if (value !== undefined) {
|
|
57
|
+
;(result as Record<string, unknown>)[name] = value
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const names = new Set(Object.keys(values))
|
|
61
|
+
for (const set of based) {
|
|
62
|
+
for (const name of managed.get(set) ?? []) names.add(name)
|
|
63
|
+
}
|
|
64
|
+
managed.set(result, [...names])
|
|
65
|
+
return result
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Creates a type guard for a list of allowed strings. */
|
|
69
|
+
export function createGuard<T extends string>(allowed: readonly T[]) {
|
|
70
|
+
return (value: string): value is T =>
|
|
71
|
+
(allowed as readonly string[]).includes(value)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Validation state for form controls.
|
|
76
|
+
*
|
|
77
|
+
* Input, textarea and select each had an identical type of their own. Now
|
|
78
|
+
* there is one, so a value can pass between them without conversion.
|
|
79
|
+
*/
|
|
80
|
+
export const fieldStates = ["default", "invalid", "success"] as const
|
|
81
|
+
export type FieldState = (typeof fieldStates)[number]
|
|
82
|
+
export type NonDefaultFieldState = Exclude<FieldState, "default">
|
|
83
|
+
export const isFieldState = createGuard(fieldStates)
|
|
84
|
+
|
|
85
|
+
/** How a required field is marked in its label. */
|
|
86
|
+
export const requiredMarkers = ["symbol", "text"] as const
|
|
87
|
+
export type RequiredMarker = (typeof requiredMarkers)[number]
|
|
88
|
+
export const isRequiredMarker = createGuard(requiredMarkers)
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Warns once per message, in the console.
|
|
92
|
+
*
|
|
93
|
+
* The builder functions are pure functions without an element to attach the
|
|
94
|
+
* message to, so they cannot use `warnAboutMarkup`. The deduplication is
|
|
95
|
+
* needed all the same: an app that renders a list of fields would otherwise
|
|
96
|
+
* say the same thing per field and per render.
|
|
97
|
+
*/
|
|
98
|
+
const said = new Set<string>()
|
|
99
|
+
|
|
100
|
+
export function warnOnce(message: string): void {
|
|
101
|
+
if (typeof console === "undefined" || said.has(message)) return
|
|
102
|
+
said.add(message)
|
|
103
|
+
console.warn(message)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let idCounter = 0
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Creates an id that is unique within the document.
|
|
110
|
+
*
|
|
111
|
+
* Safe only when the markup is rendered once. When the same field is rendered
|
|
112
|
+
* both on a server and in the browser, the two runs give two different ids,
|
|
113
|
+
* and the wiring is broken until the framework has corrected it.
|
|
114
|
+
*/
|
|
115
|
+
export function createFieldId(): string {
|
|
116
|
+
idCounter += 1
|
|
117
|
+
return `lt-field-${idCounter}-${Math.random().toString(36).slice(2, 8)}`
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The keys a builder function creates ids from, checked.
|
|
122
|
+
*
|
|
123
|
+
* A key is the same as `key` in React: a fixed value from the data, such as
|
|
124
|
+
* a record id. The id is the same on every render, and a server update
|
|
125
|
+
* recognises the element. An index is not a key: if the server inserts a row
|
|
126
|
+
* first, the same index points to something else.
|
|
127
|
+
*
|
|
128
|
+
* Throws, instead of warning and creating a fallback as `idOrFallback` does:
|
|
129
|
+
* an empty key, one with whitespace or two identical ones give ids that are
|
|
130
|
+
* empty, invalid or identical, and there is no fallback that is right.
|
|
131
|
+
* Whitespace is what JavaScript counts as whitespace (`\s`), which the
|
|
132
|
+
* Kotlin version spells out.
|
|
133
|
+
*/
|
|
134
|
+
export function checkedKeys(builder: string, keys: unknown): string[] {
|
|
135
|
+
if (!Array.isArray(keys)) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
`${builder}: keys is missing. Pass a list with one key per element, taken from the data, such as a record id.`,
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
const seen = new Set<string>()
|
|
141
|
+
for (const key of keys) {
|
|
142
|
+
if (typeof key !== "string") {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`${builder}: a key in keys is not a string but ${typeof key}. The keys become ids; turn numbers into strings, as in String(recordId).`,
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
if (key === "") {
|
|
148
|
+
throw new Error(
|
|
149
|
+
`${builder}: a key in keys is empty. The keys become ids, and each must be a fixed value from the data.`,
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
if (/\s/.test(key)) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
`${builder}: the key "${key}" contains whitespace. The keys become ids, and an id cannot contain whitespace.`,
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
if (seen.has(key)) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`${builder}: the key "${key}" appears twice in keys. The keys become ids, and two equal ids point to the same element.`,
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
seen.add(key)
|
|
163
|
+
}
|
|
164
|
+
return keys
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* The id the builder function received, or a fallback with a warning.
|
|
169
|
+
*
|
|
170
|
+
* Every builder function that takes an id requires it in the type. That is
|
|
171
|
+
* not enough on its own: a consumer without TypeScript sees no type, and
|
|
172
|
+
* plain HTML with `<script type="module">` is a first-class way to use
|
|
173
|
+
* LO-TEK. Without the fallback the ids became strings like `undefined-list`,
|
|
174
|
+
* `aria-controls` pointed there, and the wiring was broken in a way that
|
|
175
|
+
* looked valid.
|
|
176
|
+
*
|
|
177
|
+
* The empty string counts as no id. `lt.field({ id: "" })` gave `for=""` and
|
|
178
|
+
* `help.id="-help"`, the same problem without anything saying so.
|
|
179
|
+
*
|
|
180
|
+
* The name of the builder function is in the message. Without it the
|
|
181
|
+
* suggestion field said "lt.field()" and sent the developer to the wrong
|
|
182
|
+
* place.
|
|
183
|
+
*/
|
|
184
|
+
export function idOrFallback(
|
|
185
|
+
builder: string,
|
|
186
|
+
id: string | undefined,
|
|
187
|
+
option = "id",
|
|
188
|
+
): string {
|
|
189
|
+
if (typeof id === "string" && id.trim() !== "") return id
|
|
190
|
+
|
|
191
|
+
warnOnce(
|
|
192
|
+
`${builder}: no ${option} given, so a random one is created, and two runs ` +
|
|
193
|
+
"create two different ones. Rendered on a server and in the browser, the " +
|
|
194
|
+
"wiring points to something that does not exist, and a server that sends " +
|
|
195
|
+
"the region again with a new id makes the morph replace the elements and " +
|
|
196
|
+
`lose what the user did in them. Pass ${option}, in React from useId().`,
|
|
197
|
+
)
|
|
198
|
+
return createFieldId()
|
|
199
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
@layer lotek {
|
|
2
|
+
.lt-skeleton {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
display: block;
|
|
5
|
+
inline-size: 100%;
|
|
6
|
+
block-size: var(--lt-skeleton-height, var(--lt-spacing-4));
|
|
7
|
+
border-radius: var(--lt-skeleton-radius, var(--lt-spacing-1));
|
|
8
|
+
background: var(--lt-color-neutral-surface);
|
|
9
|
+
/* The shimmer is a gradient moving across the surface, not an opacity
|
|
10
|
+
that pulses. The contrast against the page surface then stays the
|
|
11
|
+
same all the way. */
|
|
12
|
+
background-image: linear-gradient(
|
|
13
|
+
90deg,
|
|
14
|
+
transparent 0%,
|
|
15
|
+
var(--lt-color-neutral-canvas) 50%,
|
|
16
|
+
transparent 100%
|
|
17
|
+
);
|
|
18
|
+
background-size: 200% 100%;
|
|
19
|
+
background-repeat: no-repeat;
|
|
20
|
+
animation: lt-skeleton-shimmer 1600ms ease-in-out infinite;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* The text lines are low, so the default radius is smaller. The variable
|
|
24
|
+
applies here too. */
|
|
25
|
+
.lt-skeleton[data-variant="text"] {
|
|
26
|
+
block-size: var(--lt-font-size-m);
|
|
27
|
+
border-radius: var(--lt-skeleton-radius, var(--lt-spacing-0-5));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.lt-skeleton[data-variant="circle"] {
|
|
31
|
+
inline-size: var(--lt-skeleton-height, var(--lt-spacing-10));
|
|
32
|
+
block-size: var(--lt-skeleton-height, var(--lt-spacing-10));
|
|
33
|
+
border-radius: 50%;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@keyframes lt-skeleton-shimmer {
|
|
37
|
+
from {
|
|
38
|
+
background-position: 150% 0;
|
|
39
|
+
}
|
|
40
|
+
to {
|
|
41
|
+
background-position: -50% 0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@media (prefers-reduced-motion: reduce) {
|
|
46
|
+
.lt-skeleton {
|
|
47
|
+
animation: none;
|
|
48
|
+
background-image: none;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* High contrast: the surface and the shimmer are backgrounds, and both are
|
|
53
|
+
forced to the page surface colour. Without a border the placeholder was
|
|
54
|
+
invisible. */
|
|
55
|
+
@media (forced-colors: active) {
|
|
56
|
+
.lt-skeleton {
|
|
57
|
+
border: 1px solid GrayText;
|
|
58
|
+
animation: none;
|
|
59
|
+
background-image: none;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|