shoelace-rails-ui 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +42 -0
- data/LICENSE.txt +21 -0
- data/README-real.md +24 -0
- data/README.md +43 -0
- data/Rakefile +16 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/shoelace/rails/ui/version.rb +9 -0
- data/lib/shoelace/rails/ui.rb +12 -0
- data/regenerate.rb +48 -0
- data/remote-src/.DS_Store +0 -0
- data/remote-src/2.0.0.beta64/.DS_Store +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.editorconfig +15 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.github/CODE_OF_CONDUCT.md +44 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.github/FUNDING.yml +1 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.github/ISSUE_TEMPLATE/config.yml +4 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.github/SECURITY.md +7 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.github/workflows/node.js.yml +30 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.github/workflows/release.yml +17 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.gitignore +8 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.husky/pre-commit +4 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.prettierignore +12 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.vscode/extensions.json +9 -0
- data/remote-src/2.0.0.beta64/shoelace-next/.vscode/settings.json +4 -0
- data/remote-src/2.0.0.beta64/shoelace-next/CONTRIBUTING.md +5 -0
- data/remote-src/2.0.0.beta64/shoelace-next/LICENSE.md +7 -0
- data/remote-src/2.0.0.beta64/shoelace-next/README.md +94 -0
- data/remote-src/2.0.0.beta64/shoelace-next/cspell.json +110 -0
- data/remote-src/2.0.0.beta64/shoelace-next/custom-elements-manifest.config.js +104 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/404.md +5 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/_sidebar.md +89 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/icons/sprite.svg +1 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/chrome.png +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/edge.png +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/firefox.png +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/logo.svg +7 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/og-image.png +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/opera.png +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/safari.png +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/shoe.svg +134 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/tie.webp +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/touch-icon.png +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/twitter-card.png +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/undraw-content-team.svg +80 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/undraw-not-found.svg +1 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/walk.gif +0 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/wordmark.svg +7 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/code-block/code-block.css +228 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/code-block/code-block.js +376 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/metadata/metadata.js +537 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/scroll-position/scroll-position.js +24 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/search/lunr.min.js +1311 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/search/search.css +180 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/search/search.js +293 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/theme-picker/theme-picker.css +29 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/theme-picker/theme-picker.js +83 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/styles/docs.css +642 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/alert.md +441 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/animated-image.md +128 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/animation.md +351 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/avatar.md +201 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/badge.md +191 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/breadcrumb-item.md +35 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/breadcrumb.md +266 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/button-group.md +470 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/button.md +453 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/card.md +311 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/checkbox.md +71 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/color-picker.md +101 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/details.md +89 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/dialog.md +265 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/divider.md +152 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/drawer.md +452 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/dropdown.md +389 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/format-bytes.md +126 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/format-date.md +120 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/format-number.md +124 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/icon-button.md +160 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/icon.md +711 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/image-comparer.md +51 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/include.md +47 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/input.md +283 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/menu-item.md +255 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/menu-label.md +52 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/menu.md +49 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/mutation-observer.md +196 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/progress-bar.md +144 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/progress-ring.md +178 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/qr-code.md +167 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/radio-group.md +52 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/radio.md +59 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/range.md +180 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/rating.md +153 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/relative-time.md +105 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/resize-observer.md +68 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/responsive-media.md +73 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/select.md +457 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/skeleton.md +439 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/spinner.md +86 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/split-panel.md +671 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/switch.md +77 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/tab-group.md +359 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/tab-panel.md +41 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/tab.md +29 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/tag.md +142 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/textarea.md +184 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/tooltip.md +410 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/components/visually-hidden.md +47 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/frameworks/angular.md +46 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/frameworks/react.md +156 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/frameworks/vue.md +92 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/customizing.md +153 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/form-controls.md +336 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/installation.md +137 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/localization.md +140 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/overview.md +131 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/themes.md +139 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/usage.md +173 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/index.html +98 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/resources/accessibility.md +18 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/resources/changelog.md +925 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/resources/community.md +53 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/resources/contributing.md +261 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/border-radius.md +12 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/color.md +439 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/elevation.md +11 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/spacing.md +16 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/transition.md +11 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/typography.md +58 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/z-index.md +11 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/tutorials/integrating-with-laravel.md +117 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/tutorials/integrating-with-nextjs.md +137 -0
- data/remote-src/2.0.0.beta64/shoelace-next/docs/tutorials/integrating-with-rails.md +103 -0
- data/remote-src/2.0.0.beta64/shoelace-next/lint-staged.config.js +4 -0
- data/remote-src/2.0.0.beta64/shoelace-next/package-lock.json +9534 -0
- data/remote-src/2.0.0.beta64/shoelace-next/package.json +93 -0
- data/remote-src/2.0.0.beta64/shoelace-next/prettier.config.cjs +17 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/build.js +158 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-css.js +42 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-icons.js +71 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-metadata.js +11 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-react.js +63 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-search.js +100 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-vscode-data.js +58 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/plop/plopfile.js +67 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/plop/templates/component/component.hbs +44 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/plop/templates/component/docs.hbs +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/plop/templates/component/styles.hbs +10 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/plop/templates/component/tests.hbs +13 -0
- data/remote-src/2.0.0.beta64/shoelace-next/scripts/shared.js +18 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/alert/alert.styles.ts +95 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/alert/alert.test.ts +93 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/alert/alert.ts +238 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/animated-image/animated-image.styles.ts +52 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/animated-image/animated-image.test.ts +13 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/animated-image/animated-image.ts +120 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/animation/animation.styles.ts +10 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/animation/animation.ts +222 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/animation/animations.ts +15 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/avatar/avatar.styles.ts +66 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/avatar/avatar.test.ts +111 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/avatar/avatar.ts +83 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/badge/badge.styles.ts +94 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/badge/badge.test.ts +77 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/badge/badge.ts +53 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb/breadcrumb.styles.ts +12 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb/breadcrumb.test.ts +104 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb/breadcrumb.ts +82 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb-item/breadcrumb-item.styles.ts +85 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb-item/breadcrumb-item.test.ts +160 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb-item/breadcrumb-item.ts +92 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/button/button.styles.ts +637 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/button/button.ts +209 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/button-group/button-group.styles.ts +15 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/button-group/button-group.ts +84 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/card/card.styles.ts +62 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/card/card.test.ts +139 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/card/card.ts +68 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/checkbox/checkbox.styles.ts +108 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/checkbox/checkbox.test.ts +47 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/checkbox/checkbox.ts +203 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/color-picker/color-picker.styles.ts +326 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/color-picker/color-picker.test.ts +43 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/color-picker/color-picker.ts +853 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/details/details.styles.ts +73 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/details/details.test.ts +153 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/details/details.ts +192 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/dialog/dialog.styles.ts +106 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/dialog/dialog.test.ts +135 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/dialog/dialog.ts +296 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/divider/divider.styles.ts +25 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/divider/divider.ts +34 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/drawer/drawer.styles.ts +142 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/drawer/drawer.test.ts +135 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/drawer/drawer.ts +377 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/dropdown/dropdown.styles.ts +58 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/dropdown/dropdown.test.ts +147 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/dropdown/dropdown.ts +459 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/format-bytes/format-bytes.ts +35 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/format-date/format-date.ts +81 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/format-number/format-number.ts +69 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/icon.styles.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/icon.ts +131 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/library.default.ts +9 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/library.system.ts +97 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/library.ts +49 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/request.ts +36 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon-button/icon-button.styles.ts +48 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon-button/icon-button.ts +100 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/image-comparer/image-comparer.styles.ts +77 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/image-comparer/image-comparer.ts +147 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/include/include.styles.ts +10 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/include/include.test.ts +62 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/include/include.ts +80 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/include/request.ts +23 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/input/input.styles.ts +282 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/input/input.test.ts +35 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/input/input.ts +410 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu/menu.styles.ts +18 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu/menu.ts +205 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu-item/menu-item.styles.ts +84 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu-item/menu-item.ts +92 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu-label/menu-label.styles.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu-label/menu-label.ts +30 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/mutation-observer/mutation-observer.styles.ts +10 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/mutation-observer/mutation-observer.test.ts +13 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/mutation-observer/mutation-observer.ts +118 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-bar/progress-bar.styles.ts +57 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-bar/progress-bar.test.ts +89 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-bar/progress-bar.ts +74 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-ring/progress-ring.styles.ts +66 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-ring/progress-ring.test.ts +68 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-ring/progress-ring.ts +84 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/qr-code/qr-code.styles.ts +22 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/qr-code/qr-code.ts +90 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/radio/radio.styles.ts +107 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/radio/radio.test.ts +65 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/radio/radio.ts +226 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/radio-group/radio-group.styles.ts +47 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/radio-group/radio-group.ts +66 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/range/range.styles.ts +192 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/range/range.ts +273 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/rating/rating.styles.ts +79 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/rating/rating.ts +249 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/relative-time/relative-time.ts +116 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/resize-observer/resize-observer.styles.ts +10 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/resize-observer/resize-observer.ts +87 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/responsive-media/responsive-media.styles.ts +36 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/responsive-media/responsive-media.ts +50 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/select/select.styles.ts +331 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/select/select.test.ts +56 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/select/select.ts +560 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/skeleton/skeleton.styles.ts +60 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/skeleton/skeleton.ts +46 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/spinner/spinner.styles.ts +56 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/spinner/spinner.test.ts +24 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/spinner/spinner.ts +34 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/split-panel/split-panel.styles.ts +76 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/split-panel/split-panel.test.ts +13 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/split-panel/split-panel.ts +272 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/switch/switch.styles.ts +135 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/switch/switch.test.ts +64 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/switch/switch.ts +187 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab/tab.styles.ts +61 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab/tab.ts +104 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab-group/tab-group.styles.ts +209 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab-group/tab-group.ts +409 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab-panel/tab-panel.styles.ts +17 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab-panel/tab-panel.ts +49 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tag/tag.styles.ts +110 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tag/tag.ts +92 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/textarea/textarea.styles.ts +167 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/textarea/textarea.test.ts +35 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/textarea/textarea.ts +339 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tooltip/tooltip.styles.ts +131 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tooltip/tooltip.test.ts +117 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/tooltip/tooltip.ts +355 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/visually-hidden/visually-hidden.styles.ts +18 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/visually-hidden/visually-hidden.test.ts +39 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/components/visually-hidden/visually-hidden.ts +24 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/declaration.d.ts +8 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/animate.ts +70 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/event.ts +35 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/focus-visible.ts +26 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/form-control.ts +203 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/formdata-event-polyfill.ts +93 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/math.ts +8 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/modal.ts +53 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/number.ts +32 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/offset.ts +13 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/scroll.ts +57 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/slot.ts +91 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/string.ts +3 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/support.ts +15 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/tabbable.ts +81 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/internal/watch.ts +40 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/shoelace.ts +58 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/styles/component.styles.ts +23 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/styles/form-control.styles.ts +52 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/styles/utility.styles.ts +23 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/themes/dark.styles.ts +524 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/themes/light.styles.ts +524 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/de-ch.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/de.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/en.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/es.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/fr.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/he.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/ja.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/nl.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/pl.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/pt.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/translations/ru.ts +21 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/animation-registry.ts +59 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/animation.ts +1 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/base-path.ts +43 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/form.ts +22 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/icon-library.ts +1 -0
- data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/localize.ts +5 -0
- data/remote-src/2.0.0.beta64/shoelace-next/tsconfig.json +35 -0
- data/remote-src/2.0.0.beta64/shoelace-next/vercel.json +4 -0
- data/remote-src/2.0.0.beta64/shoelace-next/web-test-runner.config.js +14 -0
- data/shoelace-rails-ui.gemspec +39 -0
- data/shoelace-rails-ui.rb +0 -0
- metadata +377 -0
@@ -0,0 +1,336 @@
|
|
1
|
+
# Form Controls
|
2
|
+
|
3
|
+
Every Shoelace component makes use of a [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) to encapsulate markup, styles, and behavior. One caveat of this approach is that native `<form>` elements do not recognize form controls located inside a shadow root.
|
4
|
+
|
5
|
+
Shoelace solves this problem by using the [`formdata`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/formdata_event) event, which is [available in all modern browsers](https://caniuse.com/mdn-api_htmlformelement_formdata_event). This means, when a form is submitted, Shoelace form controls will automatically append their values to the `FormData` object that's used to submit the form. In most cases, things will "just work." However, if you're using a form serialization library, it might need to be adapted to recognize Shoelace form controls.
|
6
|
+
|
7
|
+
?> If you're using an older browser that doesn't support the `formdata` event, a lightweight polyfill will be automatically applied to ensure forms submit as expected.
|
8
|
+
|
9
|
+
## Form Serialization
|
10
|
+
|
11
|
+
Serialization is just a fancy word for collecting form data. If you're relying on standard form submissions, e.g. `<form action="...">`, you can probably skip this section. However, most modern apps use the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) or a library such as [axios](https://github.com/axios/axios) to submit forms using JavaScript.
|
12
|
+
|
13
|
+
The [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) interface offers a standard way to serialize forms in the browser. You can create a `FormData` object from any `<form>` element like this.
|
14
|
+
|
15
|
+
```js
|
16
|
+
const form = document.querySelector('form');
|
17
|
+
const data = new FormData(form);
|
18
|
+
|
19
|
+
// All form control data is available in a FormData object
|
20
|
+
```
|
21
|
+
|
22
|
+
However, some folks find `FormData` tricky to work with or they need to pass a JSON payload to their server. To accommodate this, Shoelace offers a serialization utility that gathers form data and returns a simple JavaScript object instead.
|
23
|
+
|
24
|
+
```js
|
25
|
+
import { serialize } from '@shoelace-style/shoelace/dist/utilities/form.js';
|
26
|
+
|
27
|
+
const form = document.querySelector('form');
|
28
|
+
const data = serialize(form);
|
29
|
+
|
30
|
+
// All form control data is available in a plain object
|
31
|
+
```
|
32
|
+
|
33
|
+
This results in an object with name/value pairs that map to each form control. If more than one form control shares the same name, the values will be passed as an array, e.g. `{ name: ['value1', 'value2'] }`.
|
34
|
+
|
35
|
+
## Form Control Validation
|
36
|
+
|
37
|
+
Client-side validation can be enabled through the browser's [Constraint Validation API](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation) for Shoelace form controls. You can activate it using attributes such as `required`, `pattern`, `minlength`, and `maxlength`. Shoelace implements many of the same attributes as native form controls, but check each form control's documentation for a list of all supported properties.
|
38
|
+
|
39
|
+
As the user interacts with a form control, its `invalid` attribute will reflect its validity based on its current value and the constraints that have been defined. When a form control is invalid, the containing form will not be submitted. Instead, the browser will show the user a relevant error message. If you don't want to use client-side validation, you can suppress this behavior by adding `novalidate` to the surrounding `<form>` element.
|
40
|
+
|
41
|
+
All form controls support validation, but not all validation props are available for every component. Refer to a component's documentation to see which validation props it supports.
|
42
|
+
|
43
|
+
!> Client-side validation can be used to improve the UX of forms, but it is not a replacement for server-side validation. **You should always validate and sanitize user input on the server!**
|
44
|
+
|
45
|
+
### Required Fields
|
46
|
+
|
47
|
+
To make a field required, use the `required` prop. The form will not be submitted if a required form control is empty.
|
48
|
+
|
49
|
+
```html preview
|
50
|
+
<form class="input-validation-required">
|
51
|
+
<sl-input name="name" label="Name" required></sl-input>
|
52
|
+
<br>
|
53
|
+
<sl-select label="Favorite Animal" clearable required>
|
54
|
+
<sl-menu-item value="birds">Birds</sl-menu-item>
|
55
|
+
<sl-menu-item value="cats">Cats</sl-menu-item>
|
56
|
+
<sl-menu-item value="dogs">Dogs</sl-menu-item>
|
57
|
+
<sl-menu-item value="other">Other</sl-menu-item>
|
58
|
+
</sl-select>
|
59
|
+
<br>
|
60
|
+
<sl-textarea name="comment" label="Comment" required></sl-textarea>
|
61
|
+
<br>
|
62
|
+
<sl-checkbox required>Check me before submitting</sl-checkbox>
|
63
|
+
<br><br>
|
64
|
+
<sl-button type="submit" variant="primary">Submit</sl-button>
|
65
|
+
</form>
|
66
|
+
|
67
|
+
<script>
|
68
|
+
const form = document.querySelector('.input-validation-required');
|
69
|
+
form.addEventListener('submit', event => {
|
70
|
+
event.preventDefault();
|
71
|
+
alert('All fields are valid!')
|
72
|
+
});
|
73
|
+
</script>
|
74
|
+
```
|
75
|
+
|
76
|
+
```jsx react
|
77
|
+
import {
|
78
|
+
SlButton,
|
79
|
+
SlCheckbox,
|
80
|
+
SlInput,
|
81
|
+
SlMenuItem,
|
82
|
+
SlSelect,
|
83
|
+
SlTextarea
|
84
|
+
} from '@shoelace-style/shoelace/dist/react';
|
85
|
+
|
86
|
+
const App = () => {
|
87
|
+
function handleSubmit(event) {
|
88
|
+
event.preventDefault();
|
89
|
+
alert('All fields are valid!');
|
90
|
+
}
|
91
|
+
|
92
|
+
return (
|
93
|
+
<form onSubmit={handleSubmit}>
|
94
|
+
<SlInput name="name" label="Name" required />
|
95
|
+
<br />
|
96
|
+
<SlSelect label="Favorite Animal" clearable required>
|
97
|
+
<SlMenuItem value="birds">Birds</SlMenuItem>
|
98
|
+
<SlMenuItem value="cats">Cats</SlMenuItem>
|
99
|
+
<SlMenuItem value="dogs">Dogs</SlMenuItem>
|
100
|
+
<SlMenuItem value="other">Other</SlMenuItem>
|
101
|
+
</SlSelect>
|
102
|
+
<br />
|
103
|
+
<SlTextarea name="comment" label="Comment" required></SlTextarea>
|
104
|
+
<br />
|
105
|
+
<SlCheckbox required>Check me before submitting</SlCheckbox>
|
106
|
+
<br /><br />
|
107
|
+
<SlButton type="submit" variant="primary">Submit</SlButton>
|
108
|
+
</form>
|
109
|
+
);
|
110
|
+
};
|
111
|
+
```
|
112
|
+
|
113
|
+
### Input Patterns
|
114
|
+
|
115
|
+
To restrict a value to a specific [pattern](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern), use the `pattern` attribute. This example only allows the letters A-Z, so the form will not submit if a number or symbol is entered. This only works with `<sl-input>` elements.
|
116
|
+
|
117
|
+
```html preview
|
118
|
+
<form class="input-validation-pattern">
|
119
|
+
<sl-input name="letters" required label="Letters" pattern="[A-Za-z]+"></sl-input>
|
120
|
+
<br>
|
121
|
+
<sl-button type="submit" variant="primary">Submit</sl-button>
|
122
|
+
</form>
|
123
|
+
|
124
|
+
<script>
|
125
|
+
const form = document.querySelector('.input-validation-pattern');
|
126
|
+
form.addEventListener('submit', event => {
|
127
|
+
event.preventDefault();
|
128
|
+
alert('All fields are valid!')
|
129
|
+
});
|
130
|
+
</script>
|
131
|
+
```
|
132
|
+
|
133
|
+
```jsx react
|
134
|
+
import { SlButton, SlInput } from '@shoelace-style/shoelace/dist/react';
|
135
|
+
|
136
|
+
const App = () => {
|
137
|
+
function handleSubmit(event) {
|
138
|
+
event.preventDefault();
|
139
|
+
alert('All fields are valid!');
|
140
|
+
}
|
141
|
+
|
142
|
+
return (
|
143
|
+
<form onSubmit={handleSubmit}>
|
144
|
+
<SlInput name="letters" required label="Letters" pattern="[A-Za-z]+" />
|
145
|
+
<br />
|
146
|
+
<SlButton type="submit" variant="primary">Submit</SlButton>
|
147
|
+
</form>
|
148
|
+
);
|
149
|
+
};
|
150
|
+
```
|
151
|
+
|
152
|
+
### Input Types
|
153
|
+
|
154
|
+
Some input types will automatically trigger constraints, such as `email` and `url`.
|
155
|
+
|
156
|
+
```html preview
|
157
|
+
<form class="input-validation-type">
|
158
|
+
<sl-input variant="email" label="Email" placeholder="you@example.com" required></sl-input>
|
159
|
+
<br>
|
160
|
+
<sl-input variant="url" label="URL" placeholder="https://example.com/" required></sl-input>
|
161
|
+
<br>
|
162
|
+
<sl-button type="submit" variant="primary">Submit</sl-button>
|
163
|
+
</form>
|
164
|
+
|
165
|
+
<script>
|
166
|
+
const form = document.querySelector('.input-validation-type');
|
167
|
+
form.addEventListener('submit', event => {
|
168
|
+
event.preventDefault();
|
169
|
+
alert('All fields are valid!')
|
170
|
+
});
|
171
|
+
</script>
|
172
|
+
```
|
173
|
+
|
174
|
+
```jsx react
|
175
|
+
import { SlButton, SlInput } from '@shoelace-style/shoelace/dist/react';
|
176
|
+
|
177
|
+
const App = () => {
|
178
|
+
function handleSubmit(event) {
|
179
|
+
event.preventDefault();
|
180
|
+
alert('All fields are valid!');
|
181
|
+
}
|
182
|
+
|
183
|
+
return (
|
184
|
+
<form onSubmit={handleSubmit}>
|
185
|
+
<SlInput variant="email" label="Email" placeholder="you@example.com" required />
|
186
|
+
<br />
|
187
|
+
<SlInput variant="url" label="URL" placeholder="https://example.com/" required />
|
188
|
+
<br />
|
189
|
+
<SlButton type="submit" variant="primary">Submit</SlButton>
|
190
|
+
</form>
|
191
|
+
);
|
192
|
+
};
|
193
|
+
```
|
194
|
+
|
195
|
+
### Custom Validation
|
196
|
+
|
197
|
+
To create a custom validation error, use the `setCustomValidity` method. The form will not be submitted when this method is called with anything other than an empty string, and its message will be shown by the browser as the validation error. To make the input valid again, call the method a second time with an empty string as the argument.
|
198
|
+
|
199
|
+
```html preview
|
200
|
+
<form class="input-validation-custom">
|
201
|
+
<sl-input label="Type 'shoelace'" required></sl-input>
|
202
|
+
<br>
|
203
|
+
<sl-button type="submit" variant="primary">Submit</sl-button>
|
204
|
+
</form>
|
205
|
+
|
206
|
+
<script>
|
207
|
+
const form = document.querySelector('.input-validation-custom');
|
208
|
+
const input = form.querySelector('sl-input');
|
209
|
+
|
210
|
+
form.addEventListener('submit', event => {
|
211
|
+
event.preventDefault();
|
212
|
+
alert('All fields are valid!')
|
213
|
+
});
|
214
|
+
|
215
|
+
input.addEventListener('sl-input', () => {
|
216
|
+
if (input.value === 'shoelace') {
|
217
|
+
input.setCustomValidity('');
|
218
|
+
} else {
|
219
|
+
input.setCustomValidity('Hey, you\'re supposed to type \'shoelace\' before submitting this!');
|
220
|
+
}
|
221
|
+
});
|
222
|
+
</script>
|
223
|
+
```
|
224
|
+
|
225
|
+
```jsx react
|
226
|
+
import { useRef, useState } from 'react';
|
227
|
+
import { SlButton, SlInput } from '@shoelace-style/shoelace/dist/react';
|
228
|
+
|
229
|
+
const App = () => {
|
230
|
+
const input = useRef(null);
|
231
|
+
const [value, setValue] = useState('');
|
232
|
+
|
233
|
+
function handleInput(event) {
|
234
|
+
setValue(event.target.value);
|
235
|
+
|
236
|
+
if (event.target.value === 'shoelace') {
|
237
|
+
input.current.setCustomValidity('');
|
238
|
+
} else {
|
239
|
+
input.current.setCustomValidity('Hey, you\'re supposed to type \'shoelace\' before submitting this!');
|
240
|
+
}
|
241
|
+
}
|
242
|
+
|
243
|
+
function handleSubmit(event) {
|
244
|
+
event.preventDefault();
|
245
|
+
alert('All fields are valid!');
|
246
|
+
}
|
247
|
+
|
248
|
+
return (
|
249
|
+
<form onSubmit={handleSubmit}>
|
250
|
+
<SlInput
|
251
|
+
ref={input}
|
252
|
+
label="Type 'shoelace'"
|
253
|
+
required
|
254
|
+
value={value}
|
255
|
+
onSlInput={handleInput}
|
256
|
+
/>
|
257
|
+
<br />
|
258
|
+
<SlButton type="submit" variant="primary">Submit</SlButton>
|
259
|
+
</form>
|
260
|
+
);
|
261
|
+
};
|
262
|
+
```
|
263
|
+
|
264
|
+
### Custom Validation Styles
|
265
|
+
|
266
|
+
The `invalid` attribute reflects the form control's validity, so you can style invalid fields using the `[invalid]` selector. The example below demonstrates how you can give erroneous fields a different appearance. Type something other than "shoelace" to demonstrate this.
|
267
|
+
|
268
|
+
```html preview
|
269
|
+
<sl-input class="custom-input" required pattern="shoelace">
|
270
|
+
<small slot="help-text">Please enter "shoelace" to continue</small>
|
271
|
+
</sl-input>
|
272
|
+
|
273
|
+
<style>
|
274
|
+
.custom-input[invalid]:not([disabled])::part(label),
|
275
|
+
.custom-input[invalid]:not([disabled])::part(help-text) {
|
276
|
+
color: var(--sl-color-danger-600);
|
277
|
+
}
|
278
|
+
|
279
|
+
.custom-input[invalid]:not([disabled])::part(base) {
|
280
|
+
border-color: var(--sl-color-danger-500);
|
281
|
+
}
|
282
|
+
|
283
|
+
.custom-input[invalid]:focus-within::part(base) {
|
284
|
+
box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-color-danger-500);
|
285
|
+
}
|
286
|
+
</style>
|
287
|
+
```
|
288
|
+
|
289
|
+
```jsx react
|
290
|
+
import { SlInput } from '@shoelace-style/shoelace/dist/react';
|
291
|
+
|
292
|
+
const css = `
|
293
|
+
.custom-input[invalid]:not([disabled])::part(label),
|
294
|
+
.custom-input[invalid]:not([disabled])::part(help-text) {
|
295
|
+
color: var(--sl-color-danger-600);
|
296
|
+
}
|
297
|
+
|
298
|
+
.custom-input[invalid]:not([disabled])::part(base) {
|
299
|
+
border-color: var(--sl-color-danger-500);
|
300
|
+
}
|
301
|
+
|
302
|
+
.custom-input[invalid]:focus-within::part(base) {
|
303
|
+
box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-color-danger-500);
|
304
|
+
}
|
305
|
+
`;
|
306
|
+
|
307
|
+
const App = () => (
|
308
|
+
<>
|
309
|
+
<SlInput className="custom-input" required pattern="shoelace">
|
310
|
+
<small slot="help-text">Please enter "shoelace" to continue</small>
|
311
|
+
</SlInput>
|
312
|
+
|
313
|
+
<style>{css}</style>
|
314
|
+
</>
|
315
|
+
);
|
316
|
+
```
|
317
|
+
|
318
|
+
### Third-party Validation
|
319
|
+
|
320
|
+
To opt out of the browser's built-in validation and use your own, add the `novalidate` attribute to the form. This will ignore all constraints and prevent the browser from showing its own warnings when form controls are invalid.
|
321
|
+
|
322
|
+
Remember that the `invalid` attribute on form controls reflects validity as defined by the [Constraint Validation API](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation). You can set it initially, but the `invalid` attribute will update as the user interacts with the form control. As such, you should not rely on it to set invalid styles using a custom validation library.
|
323
|
+
|
324
|
+
Instead, toggle a class and target it in your stylesheet as shown below.
|
325
|
+
|
326
|
+
```html
|
327
|
+
<form novalidate>
|
328
|
+
<sl-input class="invalid"></sl-input>
|
329
|
+
</form>
|
330
|
+
|
331
|
+
<style>
|
332
|
+
sl-input.invalid {
|
333
|
+
...
|
334
|
+
}
|
335
|
+
</style>
|
336
|
+
```
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# Installation
|
2
|
+
|
3
|
+
You can use Shoelace via CDN or by installing it locally. You can also [cherry pick](#cherry-picking) individual components for faster load times.
|
4
|
+
|
5
|
+
If you're using a framework, make sure to check out the pages for [React](/frameworks/react), [Vue](/frameworks/vue), and [Angular](/frameworks/angular).
|
6
|
+
|
7
|
+
## CDN Installation (Easiest)
|
8
|
+
|
9
|
+
The easiest way to install Shoelace is with the CDN. Just add the following tags to your page to get all components and the default light theme.
|
10
|
+
|
11
|
+
```html
|
12
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/themes/light.css">
|
13
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/shoelace.js"></script>
|
14
|
+
```
|
15
|
+
|
16
|
+
?> If you're only using a handful of components, it will be more efficient to [cherry pick](#cherry-picking) the ones you need.
|
17
|
+
|
18
|
+
### Dark Theme
|
19
|
+
|
20
|
+
If you prefer to use the [dark theme](/getting-started/themes#dark-theme) instead, use this code and add `<html class="sl-theme-dark">` to the page.
|
21
|
+
|
22
|
+
```html
|
23
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/themes/dark.css">
|
24
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/shoelace.js"></script>
|
25
|
+
```
|
26
|
+
|
27
|
+
### Light & Dark Theme
|
28
|
+
|
29
|
+
If you want to load the light or dark theme based on the user's `prefers-color-scheme` setting, use this. The `media` attributes ensure that only the user's preferred theme stylesheet loads and the `onload` attribute sets the appropriate [theme class](/getting-started/themes) on the `<html>` element.
|
30
|
+
|
31
|
+
```html
|
32
|
+
<link rel="stylesheet" media="(prefers-color-scheme:light)" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/themes/light.css">
|
33
|
+
<link rel="stylesheet" media="(prefers-color-scheme:dark)"
|
34
|
+
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/themes/dark.css"
|
35
|
+
onload="document.documentElement.classList.add('sl-theme-dark');">
|
36
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/shoelace.js"></script>
|
37
|
+
```
|
38
|
+
|
39
|
+
Now you can [start using Shoelace!](/getting-started/usage)
|
40
|
+
|
41
|
+
## Local Installation
|
42
|
+
|
43
|
+
If you don't want to use the CDN, you can install Shoelace locally with the following command.
|
44
|
+
|
45
|
+
```bash
|
46
|
+
npm install @shoelace-style/shoelace
|
47
|
+
```
|
48
|
+
|
49
|
+
It's up to you to make the source files available to your app. One way to do this is to create a route in your app called `/shoelace` that serves static files from `node_modules/@shoelace-style/shoelace`.
|
50
|
+
|
51
|
+
Once you've done that, add the following tags to your page. Make sure to update `href` and `src` so they point to the route you created.
|
52
|
+
|
53
|
+
```html
|
54
|
+
<link rel="stylesheet" href="/shoelace/dist/themes/light.css">
|
55
|
+
<script type="module" src="/shoelace/dist/shoelace.js"></script>
|
56
|
+
```
|
57
|
+
|
58
|
+
Alternatively, [you can use a bundler](#bundling).
|
59
|
+
|
60
|
+
?> For clarity, the docs will usually show imports from `@shoelace-style/shoelace`. If you're not using a module resolver or bundler, you'll need to adjust these paths to point to the folder Shoelace is in.
|
61
|
+
|
62
|
+
## Setting the Base Path
|
63
|
+
|
64
|
+
Some components rely on assets (icons, images, etc.) and Shoelace needs to know where they're located. For convenience, Shoelace will try to auto-detect the correct location based on the script you've loaded it from. This assumes assets are colocated with `shoelace.js` and will "just work" for most users.
|
65
|
+
|
66
|
+
However, if you're [cherry picking](#cherry-picking) or [bundling](#bundling) Shoelace, you'll need to set the base path. You can do this one of two ways.
|
67
|
+
|
68
|
+
```html
|
69
|
+
<!-- Option 1: the data-shoelace attribute -->
|
70
|
+
<script src="bundle.js" data-shoelace="/path/to/shoelace/dist"></script>
|
71
|
+
|
72
|
+
<!-- Option 2: the setBasePath() method -->
|
73
|
+
<script src="bundle.js"></script>
|
74
|
+
<script type="module">
|
75
|
+
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js';
|
76
|
+
setBasePath('/path/to/shoelace/dist');
|
77
|
+
</script>
|
78
|
+
```
|
79
|
+
|
80
|
+
?> The library also exports a `getBasePath()` method you can use to reference assets.
|
81
|
+
|
82
|
+
## Cherry Picking
|
83
|
+
|
84
|
+
The previous approach is the _easiest_ way to load Shoelace, but easy isn't always efficient. You'll incur the full size of the library even if you only use a handful of components. This is convenient for prototyping or if you're using most of the components, but it may result in longer load times in production. To improve this, you can cherry pick the components you need.
|
85
|
+
|
86
|
+
Cherry picking can be done from your local install or [directly from the CDN](https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/). This will limit the number of files the browser has to download and reduce the amount of bytes being transferred. The disadvantage is that you need to load component manually.
|
87
|
+
|
88
|
+
Here's an example that loads only the button component. Again, if you're not using a module resolver, you'll need to adjust the path to point to the folder Shoelace is in.
|
89
|
+
|
90
|
+
```html
|
91
|
+
<link rel="stylesheet" href="/path/to/shoelace/dist/themes/light.css">
|
92
|
+
|
93
|
+
<script type="module" data-shoelace="/path/to/shoelace/dist">
|
94
|
+
import '@shoelace-style/shoelace/dist/components/button/button.js';
|
95
|
+
|
96
|
+
// <sl-button> is ready to use!
|
97
|
+
</script>
|
98
|
+
```
|
99
|
+
|
100
|
+
You can copy and paste the code to import a component from the "Importing" section of the component's documentation. Note that some components have dependencies that are automatically imported when you cherry pick. If a component has dependencies, they will be listed in the "Dependencies" section of its docs.
|
101
|
+
|
102
|
+
!> Never cherry pick components or utilities from `shoelace.js` as this will cause the browser to load the entire library. Instead, cherry pick from specific modules as shown above.
|
103
|
+
|
104
|
+
!> You will see files named `chunk.[hash].js` in the `chunks` directory. Never import these files directly, as they are generated and change from version to version.
|
105
|
+
|
106
|
+
## Bundling
|
107
|
+
|
108
|
+
Shoelace is distributed as a collection of standard ES modules that [all modern browsers can understand](https://caniuse.com/es6-module). However, importing a lot of modules can result in a lot of HTTP requests and potentially longer load times. Using a CDN can alleviate this, but some users may wish to further optimize their imports with a bundler.
|
109
|
+
|
110
|
+
To use Shoelace with a bundler, first install Shoelace along with your bundler of choice.
|
111
|
+
|
112
|
+
```bash
|
113
|
+
npm install @shoelace-style/shoelace
|
114
|
+
```
|
115
|
+
|
116
|
+
Now it's time to configure your bundler. Configurations vary for each tool, but here are some examples to help you get started.
|
117
|
+
|
118
|
+
- [Example webpack config](https://github.com/shoelace-style/webpack-example/blob/master/webpack.config.js)
|
119
|
+
- [Example Rollup config](https://github.com/shoelace-style/rollup-example/blob/master/rollup.config.js)
|
120
|
+
|
121
|
+
Once your bundler is configured, you'll be able to import Shoelace components and utilities.
|
122
|
+
|
123
|
+
```js
|
124
|
+
import '@shoelace-style/shoelace/dist/themes/light.css';
|
125
|
+
import '@shoelace-style/shoelace/dist/components/button/button.js';
|
126
|
+
import '@shoelace-style/shoelace/dist/components/icon/icon.js';
|
127
|
+
import '@shoelace-style/shoelace/dist/components/input/input.js';
|
128
|
+
import '@shoelace-style/shoelace/dist/components/rating/rating.js';
|
129
|
+
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js';
|
130
|
+
|
131
|
+
// Set the base path to the folder you copied Shoelace's assets to
|
132
|
+
setBasePath('/path/to/shoelace/dist');
|
133
|
+
|
134
|
+
// <sl-button>, <sl-icon>, <sl-input>, and <sl-rating> are ready to use!
|
135
|
+
```
|
136
|
+
|
137
|
+
!> Component modules include side effects for registration purposes. Because of this, importing directly from `@shoelace-style/shoelace` may result in a larger bundle size than necessary. For optimal tree shaking, always cherry pick, i.e. import components and utilities from their respective files, as shown above.
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# Localization
|
2
|
+
|
3
|
+
Components can be localized by importing the appropriate translation file and setting the desired [`lang` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang) on the `<html>` element. Here's an example that renders Shoelace components in Spanish.
|
4
|
+
|
5
|
+
```html
|
6
|
+
<html lang="es">
|
7
|
+
<head>
|
8
|
+
<script type="module" src="/path/to/shoelace/dist/translations/es.js"></script>
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<body>
|
12
|
+
...
|
13
|
+
</body>
|
14
|
+
</html>
|
15
|
+
```
|
16
|
+
|
17
|
+
Through the magic of a mutation observer, changing the `lang` attribute will automatically update all localized components to use the new locale.
|
18
|
+
|
19
|
+
?> Shoelace provides a localization mechanism for component internals. This is not designed to be used as localization tool for your entire application. You should use a more appropriate tool such as [i18next](https://www.i18next.com/) if you need to localize content in your app.
|
20
|
+
|
21
|
+
## Available Translations
|
22
|
+
|
23
|
+
Shoelace ships with the following translations. The default is English (US), which also serves as the fallback locale. As such, you do not need to import the English translation.
|
24
|
+
|
25
|
+
- `en` - English (US)
|
26
|
+
- `de-CH` - German (Switzerland)
|
27
|
+
- `de` - German
|
28
|
+
- `es` - Spanish (Latin America)
|
29
|
+
- `fr` - French
|
30
|
+
- `he` - Hebrew
|
31
|
+
- `ja` - Japanese
|
32
|
+
- `nl` - Dutch
|
33
|
+
- `pl` - Polish
|
34
|
+
- `pt` - Portuguese
|
35
|
+
- `ru` - Russian
|
36
|
+
|
37
|
+
The location of translations depends on how you're consuming Shoelace.
|
38
|
+
|
39
|
+
- If you're using the CDN, [import them from the CDN](https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace?path=dist%2Ftranslations)
|
40
|
+
- If you're using a bundler, import them from `@shoelace-style/shoelace/dist/translations/[lang].js`
|
41
|
+
|
42
|
+
You do not need to load translations up front. You can import them dynamically even after updating the `lang` attribute. Once a translation is registered, localized components will update automatically.
|
43
|
+
|
44
|
+
```js
|
45
|
+
// Same as setting <html lang="de">
|
46
|
+
document.documentElement.lang = 'de';
|
47
|
+
|
48
|
+
// Import the translation
|
49
|
+
import('/path/to/shoelace/dist/translations/de.js');
|
50
|
+
```
|
51
|
+
|
52
|
+
### Translation Resolution
|
53
|
+
|
54
|
+
The locale set by `<html lang="...">` is the default locale for the document. If a country code is provided, e.g. `es-PE` for Peruvian Spanish, the localization library will resolve it like this:
|
55
|
+
|
56
|
+
1. Look for `es-PE`
|
57
|
+
2. Look for `es`
|
58
|
+
3. Fall back to `en`
|
59
|
+
|
60
|
+
Shoelace uses English as a fallback to provide a better experience than rendering nothing or throwing an error.
|
61
|
+
|
62
|
+
### Submitting New Translations or Improvements
|
63
|
+
|
64
|
+
To contribute new translations or improvements to existing translations, please submit a pull request on GitHub. Translations are located in [`src/translations`](https://github.com/shoelace-style/shoelace/blob/next/src/translations) and can be edited directly on GitHub if you don't want to clone the repo locally.
|
65
|
+
|
66
|
+
Regional translations are welcome! For example, if a German translation (`de`) exists it's perfectly acceptable to submit a German (Switzerland) (`de-CH`) translation.
|
67
|
+
|
68
|
+
If you have any questions, please start a [discussion](https://github.com/shoelace-style/shoelace/discussions) or ask in the [community chat](https://discord.gg/mg8f26C).
|
69
|
+
|
70
|
+
## Multiple Locales Per Page
|
71
|
+
|
72
|
+
You can use a different locale for an individual component by setting its `lang` attribute. Here's a contrived example to demonstrate.
|
73
|
+
|
74
|
+
```html
|
75
|
+
<html lang="es">
|
76
|
+
...
|
77
|
+
|
78
|
+
<body>
|
79
|
+
<sl-button><!-- Spanish --></sl-button>
|
80
|
+
<sl-button lang="ru"><!-- Russian --></sl-button>
|
81
|
+
</body>
|
82
|
+
</html>
|
83
|
+
```
|
84
|
+
|
85
|
+
For performance reasons, the `lang` attribute must be on the component itself, not on an ancestor element.
|
86
|
+
|
87
|
+
```html
|
88
|
+
<html lang="es">
|
89
|
+
...
|
90
|
+
|
91
|
+
<body>
|
92
|
+
<div lang="ru">
|
93
|
+
<sl-button><!-- still in Spanish --></sl-button>
|
94
|
+
</div>
|
95
|
+
</body>
|
96
|
+
</html>
|
97
|
+
```
|
98
|
+
|
99
|
+
This limitation exists because there's no efficient way to determine the current locale of a given element in a DOM tree. I consider this a gap in the platform and [I've proposed a couple properties](https://github.com/whatwg/html/issues/7039) to make this possible.
|
100
|
+
|
101
|
+
## Creating Your Own Translations
|
102
|
+
|
103
|
+
You can provide your own translations if you have specific needs or if you don't want to wait for a translation to land upstream. The easiest way to do this is to copy `src/translations/en.ts` into your own project and translate the terms inside. When your translation is done, you can import it and use it just like a built-in translation.
|
104
|
+
|
105
|
+
Let's create a Spanish translation as an example. The following assumes you're using TypeScript, but you can also create translations with regular JavaScript.
|
106
|
+
|
107
|
+
```js
|
108
|
+
import { registerTranslation } from '@shoelace-style/shoelace/dist/utilities/localize';
|
109
|
+
import type { Translation } from '@shoelace-style/shoelace/dist/utilities/localize';
|
110
|
+
|
111
|
+
const translation: Translation = {
|
112
|
+
$code: 'es',
|
113
|
+
$name: 'Español',
|
114
|
+
$dir: 'ltr',
|
115
|
+
|
116
|
+
term1: '...',
|
117
|
+
term2: '...',
|
118
|
+
...
|
119
|
+
};
|
120
|
+
|
121
|
+
registerTranslation(translation);
|
122
|
+
|
123
|
+
export default translation;
|
124
|
+
```
|
125
|
+
|
126
|
+
Once your translation has been compiled to JavaScript, import it and activate it like this.
|
127
|
+
|
128
|
+
```html
|
129
|
+
<html lang="es">
|
130
|
+
<head>
|
131
|
+
<script type="module" src="/path/to/es.js"></script>
|
132
|
+
</head>
|
133
|
+
|
134
|
+
<body>
|
135
|
+
...
|
136
|
+
</body>
|
137
|
+
</html>
|
138
|
+
```
|
139
|
+
|
140
|
+
?> If your translation isn't working, make sure you're using the same localize module when importing `registerTranslation`. If you're using a different module, your translation won't be recognized.
|