shoelace-rails-ui 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (332) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/CHANGELOG.md +5 -0
  4. data/CODE_OF_CONDUCT.md +84 -0
  5. data/Gemfile +12 -0
  6. data/Gemfile.lock +42 -0
  7. data/LICENSE.txt +21 -0
  8. data/README-real.md +24 -0
  9. data/README.md +43 -0
  10. data/Rakefile +16 -0
  11. data/bin/console +15 -0
  12. data/bin/setup +8 -0
  13. data/lib/shoelace/rails/ui/version.rb +9 -0
  14. data/lib/shoelace/rails/ui.rb +12 -0
  15. data/regenerate.rb +48 -0
  16. data/remote-src/.DS_Store +0 -0
  17. data/remote-src/2.0.0.beta64/.DS_Store +0 -0
  18. data/remote-src/2.0.0.beta64/shoelace-next/.editorconfig +15 -0
  19. data/remote-src/2.0.0.beta64/shoelace-next/.github/CODE_OF_CONDUCT.md +44 -0
  20. data/remote-src/2.0.0.beta64/shoelace-next/.github/FUNDING.yml +1 -0
  21. data/remote-src/2.0.0.beta64/shoelace-next/.github/ISSUE_TEMPLATE/bug_report.md +36 -0
  22. data/remote-src/2.0.0.beta64/shoelace-next/.github/ISSUE_TEMPLATE/config.yml +4 -0
  23. data/remote-src/2.0.0.beta64/shoelace-next/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  24. data/remote-src/2.0.0.beta64/shoelace-next/.github/SECURITY.md +7 -0
  25. data/remote-src/2.0.0.beta64/shoelace-next/.github/workflows/node.js.yml +30 -0
  26. data/remote-src/2.0.0.beta64/shoelace-next/.github/workflows/release.yml +17 -0
  27. data/remote-src/2.0.0.beta64/shoelace-next/.gitignore +8 -0
  28. data/remote-src/2.0.0.beta64/shoelace-next/.husky/pre-commit +4 -0
  29. data/remote-src/2.0.0.beta64/shoelace-next/.prettierignore +12 -0
  30. data/remote-src/2.0.0.beta64/shoelace-next/.vscode/extensions.json +9 -0
  31. data/remote-src/2.0.0.beta64/shoelace-next/.vscode/settings.json +4 -0
  32. data/remote-src/2.0.0.beta64/shoelace-next/CONTRIBUTING.md +5 -0
  33. data/remote-src/2.0.0.beta64/shoelace-next/LICENSE.md +7 -0
  34. data/remote-src/2.0.0.beta64/shoelace-next/README.md +94 -0
  35. data/remote-src/2.0.0.beta64/shoelace-next/cspell.json +110 -0
  36. data/remote-src/2.0.0.beta64/shoelace-next/custom-elements-manifest.config.js +104 -0
  37. data/remote-src/2.0.0.beta64/shoelace-next/docs/404.md +5 -0
  38. data/remote-src/2.0.0.beta64/shoelace-next/docs/_sidebar.md +89 -0
  39. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/icons/sprite.svg +1 -0
  40. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/chrome.png +0 -0
  41. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/edge.png +0 -0
  42. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/firefox.png +0 -0
  43. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/logo.svg +7 -0
  44. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/og-image.png +0 -0
  45. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/opera.png +0 -0
  46. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/safari.png +0 -0
  47. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/shoe.svg +134 -0
  48. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/tie.webp +0 -0
  49. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/touch-icon.png +0 -0
  50. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/twitter-card.png +0 -0
  51. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/undraw-content-team.svg +80 -0
  52. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/undraw-not-found.svg +1 -0
  53. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/walk.gif +0 -0
  54. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/images/wordmark.svg +7 -0
  55. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/code-block/code-block.css +228 -0
  56. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/code-block/code-block.js +376 -0
  57. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/metadata/metadata.js +537 -0
  58. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/scroll-position/scroll-position.js +24 -0
  59. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/search/lunr.min.js +1311 -0
  60. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/search/search.css +180 -0
  61. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/search/search.js +293 -0
  62. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/theme-picker/theme-picker.css +29 -0
  63. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/plugins/theme-picker/theme-picker.js +83 -0
  64. data/remote-src/2.0.0.beta64/shoelace-next/docs/assets/styles/docs.css +642 -0
  65. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/alert.md +441 -0
  66. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/animated-image.md +128 -0
  67. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/animation.md +351 -0
  68. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/avatar.md +201 -0
  69. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/badge.md +191 -0
  70. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/breadcrumb-item.md +35 -0
  71. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/breadcrumb.md +266 -0
  72. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/button-group.md +470 -0
  73. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/button.md +453 -0
  74. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/card.md +311 -0
  75. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/checkbox.md +71 -0
  76. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/color-picker.md +101 -0
  77. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/details.md +89 -0
  78. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/dialog.md +265 -0
  79. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/divider.md +152 -0
  80. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/drawer.md +452 -0
  81. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/dropdown.md +389 -0
  82. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/format-bytes.md +126 -0
  83. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/format-date.md +120 -0
  84. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/format-number.md +124 -0
  85. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/icon-button.md +160 -0
  86. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/icon.md +711 -0
  87. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/image-comparer.md +51 -0
  88. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/include.md +47 -0
  89. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/input.md +283 -0
  90. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/menu-item.md +255 -0
  91. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/menu-label.md +52 -0
  92. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/menu.md +49 -0
  93. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/mutation-observer.md +196 -0
  94. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/progress-bar.md +144 -0
  95. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/progress-ring.md +178 -0
  96. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/qr-code.md +167 -0
  97. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/radio-group.md +52 -0
  98. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/radio.md +59 -0
  99. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/range.md +180 -0
  100. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/rating.md +153 -0
  101. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/relative-time.md +105 -0
  102. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/resize-observer.md +68 -0
  103. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/responsive-media.md +73 -0
  104. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/select.md +457 -0
  105. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/skeleton.md +439 -0
  106. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/spinner.md +86 -0
  107. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/split-panel.md +671 -0
  108. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/switch.md +77 -0
  109. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/tab-group.md +359 -0
  110. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/tab-panel.md +41 -0
  111. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/tab.md +29 -0
  112. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/tag.md +142 -0
  113. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/textarea.md +184 -0
  114. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/tooltip.md +410 -0
  115. data/remote-src/2.0.0.beta64/shoelace-next/docs/components/visually-hidden.md +47 -0
  116. data/remote-src/2.0.0.beta64/shoelace-next/docs/frameworks/angular.md +46 -0
  117. data/remote-src/2.0.0.beta64/shoelace-next/docs/frameworks/react.md +156 -0
  118. data/remote-src/2.0.0.beta64/shoelace-next/docs/frameworks/vue.md +92 -0
  119. data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/customizing.md +153 -0
  120. data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/form-controls.md +336 -0
  121. data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/installation.md +137 -0
  122. data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/localization.md +140 -0
  123. data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/overview.md +131 -0
  124. data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/themes.md +139 -0
  125. data/remote-src/2.0.0.beta64/shoelace-next/docs/getting-started/usage.md +173 -0
  126. data/remote-src/2.0.0.beta64/shoelace-next/docs/index.html +98 -0
  127. data/remote-src/2.0.0.beta64/shoelace-next/docs/resources/accessibility.md +18 -0
  128. data/remote-src/2.0.0.beta64/shoelace-next/docs/resources/changelog.md +925 -0
  129. data/remote-src/2.0.0.beta64/shoelace-next/docs/resources/community.md +53 -0
  130. data/remote-src/2.0.0.beta64/shoelace-next/docs/resources/contributing.md +261 -0
  131. data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/border-radius.md +12 -0
  132. data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/color.md +439 -0
  133. data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/elevation.md +11 -0
  134. data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/spacing.md +16 -0
  135. data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/transition.md +11 -0
  136. data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/typography.md +58 -0
  137. data/remote-src/2.0.0.beta64/shoelace-next/docs/tokens/z-index.md +11 -0
  138. data/remote-src/2.0.0.beta64/shoelace-next/docs/tutorials/integrating-with-laravel.md +117 -0
  139. data/remote-src/2.0.0.beta64/shoelace-next/docs/tutorials/integrating-with-nextjs.md +137 -0
  140. data/remote-src/2.0.0.beta64/shoelace-next/docs/tutorials/integrating-with-rails.md +103 -0
  141. data/remote-src/2.0.0.beta64/shoelace-next/lint-staged.config.js +4 -0
  142. data/remote-src/2.0.0.beta64/shoelace-next/package-lock.json +9534 -0
  143. data/remote-src/2.0.0.beta64/shoelace-next/package.json +93 -0
  144. data/remote-src/2.0.0.beta64/shoelace-next/prettier.config.cjs +17 -0
  145. data/remote-src/2.0.0.beta64/shoelace-next/scripts/build.js +158 -0
  146. data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-css.js +42 -0
  147. data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-icons.js +71 -0
  148. data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-metadata.js +11 -0
  149. data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-react.js +63 -0
  150. data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-search.js +100 -0
  151. data/remote-src/2.0.0.beta64/shoelace-next/scripts/make-vscode-data.js +58 -0
  152. data/remote-src/2.0.0.beta64/shoelace-next/scripts/plop/plopfile.js +67 -0
  153. data/remote-src/2.0.0.beta64/shoelace-next/scripts/plop/templates/component/component.hbs +44 -0
  154. data/remote-src/2.0.0.beta64/shoelace-next/scripts/plop/templates/component/docs.hbs +21 -0
  155. data/remote-src/2.0.0.beta64/shoelace-next/scripts/plop/templates/component/styles.hbs +10 -0
  156. data/remote-src/2.0.0.beta64/shoelace-next/scripts/plop/templates/component/tests.hbs +13 -0
  157. data/remote-src/2.0.0.beta64/shoelace-next/scripts/shared.js +18 -0
  158. data/remote-src/2.0.0.beta64/shoelace-next/src/components/alert/alert.styles.ts +95 -0
  159. data/remote-src/2.0.0.beta64/shoelace-next/src/components/alert/alert.test.ts +93 -0
  160. data/remote-src/2.0.0.beta64/shoelace-next/src/components/alert/alert.ts +238 -0
  161. data/remote-src/2.0.0.beta64/shoelace-next/src/components/animated-image/animated-image.styles.ts +52 -0
  162. data/remote-src/2.0.0.beta64/shoelace-next/src/components/animated-image/animated-image.test.ts +13 -0
  163. data/remote-src/2.0.0.beta64/shoelace-next/src/components/animated-image/animated-image.ts +120 -0
  164. data/remote-src/2.0.0.beta64/shoelace-next/src/components/animation/animation.styles.ts +10 -0
  165. data/remote-src/2.0.0.beta64/shoelace-next/src/components/animation/animation.ts +222 -0
  166. data/remote-src/2.0.0.beta64/shoelace-next/src/components/animation/animations.ts +15 -0
  167. data/remote-src/2.0.0.beta64/shoelace-next/src/components/avatar/avatar.styles.ts +66 -0
  168. data/remote-src/2.0.0.beta64/shoelace-next/src/components/avatar/avatar.test.ts +111 -0
  169. data/remote-src/2.0.0.beta64/shoelace-next/src/components/avatar/avatar.ts +83 -0
  170. data/remote-src/2.0.0.beta64/shoelace-next/src/components/badge/badge.styles.ts +94 -0
  171. data/remote-src/2.0.0.beta64/shoelace-next/src/components/badge/badge.test.ts +77 -0
  172. data/remote-src/2.0.0.beta64/shoelace-next/src/components/badge/badge.ts +53 -0
  173. data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb/breadcrumb.styles.ts +12 -0
  174. data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb/breadcrumb.test.ts +104 -0
  175. data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb/breadcrumb.ts +82 -0
  176. data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb-item/breadcrumb-item.styles.ts +85 -0
  177. data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb-item/breadcrumb-item.test.ts +160 -0
  178. data/remote-src/2.0.0.beta64/shoelace-next/src/components/breadcrumb-item/breadcrumb-item.ts +92 -0
  179. data/remote-src/2.0.0.beta64/shoelace-next/src/components/button/button.styles.ts +637 -0
  180. data/remote-src/2.0.0.beta64/shoelace-next/src/components/button/button.ts +209 -0
  181. data/remote-src/2.0.0.beta64/shoelace-next/src/components/button-group/button-group.styles.ts +15 -0
  182. data/remote-src/2.0.0.beta64/shoelace-next/src/components/button-group/button-group.ts +84 -0
  183. data/remote-src/2.0.0.beta64/shoelace-next/src/components/card/card.styles.ts +62 -0
  184. data/remote-src/2.0.0.beta64/shoelace-next/src/components/card/card.test.ts +139 -0
  185. data/remote-src/2.0.0.beta64/shoelace-next/src/components/card/card.ts +68 -0
  186. data/remote-src/2.0.0.beta64/shoelace-next/src/components/checkbox/checkbox.styles.ts +108 -0
  187. data/remote-src/2.0.0.beta64/shoelace-next/src/components/checkbox/checkbox.test.ts +47 -0
  188. data/remote-src/2.0.0.beta64/shoelace-next/src/components/checkbox/checkbox.ts +203 -0
  189. data/remote-src/2.0.0.beta64/shoelace-next/src/components/color-picker/color-picker.styles.ts +326 -0
  190. data/remote-src/2.0.0.beta64/shoelace-next/src/components/color-picker/color-picker.test.ts +43 -0
  191. data/remote-src/2.0.0.beta64/shoelace-next/src/components/color-picker/color-picker.ts +853 -0
  192. data/remote-src/2.0.0.beta64/shoelace-next/src/components/details/details.styles.ts +73 -0
  193. data/remote-src/2.0.0.beta64/shoelace-next/src/components/details/details.test.ts +153 -0
  194. data/remote-src/2.0.0.beta64/shoelace-next/src/components/details/details.ts +192 -0
  195. data/remote-src/2.0.0.beta64/shoelace-next/src/components/dialog/dialog.styles.ts +106 -0
  196. data/remote-src/2.0.0.beta64/shoelace-next/src/components/dialog/dialog.test.ts +135 -0
  197. data/remote-src/2.0.0.beta64/shoelace-next/src/components/dialog/dialog.ts +296 -0
  198. data/remote-src/2.0.0.beta64/shoelace-next/src/components/divider/divider.styles.ts +25 -0
  199. data/remote-src/2.0.0.beta64/shoelace-next/src/components/divider/divider.ts +34 -0
  200. data/remote-src/2.0.0.beta64/shoelace-next/src/components/drawer/drawer.styles.ts +142 -0
  201. data/remote-src/2.0.0.beta64/shoelace-next/src/components/drawer/drawer.test.ts +135 -0
  202. data/remote-src/2.0.0.beta64/shoelace-next/src/components/drawer/drawer.ts +377 -0
  203. data/remote-src/2.0.0.beta64/shoelace-next/src/components/dropdown/dropdown.styles.ts +58 -0
  204. data/remote-src/2.0.0.beta64/shoelace-next/src/components/dropdown/dropdown.test.ts +147 -0
  205. data/remote-src/2.0.0.beta64/shoelace-next/src/components/dropdown/dropdown.ts +459 -0
  206. data/remote-src/2.0.0.beta64/shoelace-next/src/components/format-bytes/format-bytes.ts +35 -0
  207. data/remote-src/2.0.0.beta64/shoelace-next/src/components/format-date/format-date.ts +81 -0
  208. data/remote-src/2.0.0.beta64/shoelace-next/src/components/format-number/format-number.ts +69 -0
  209. data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/icon.styles.ts +21 -0
  210. data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/icon.ts +131 -0
  211. data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/library.default.ts +9 -0
  212. data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/library.system.ts +97 -0
  213. data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/library.ts +49 -0
  214. data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon/request.ts +36 -0
  215. data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon-button/icon-button.styles.ts +48 -0
  216. data/remote-src/2.0.0.beta64/shoelace-next/src/components/icon-button/icon-button.ts +100 -0
  217. data/remote-src/2.0.0.beta64/shoelace-next/src/components/image-comparer/image-comparer.styles.ts +77 -0
  218. data/remote-src/2.0.0.beta64/shoelace-next/src/components/image-comparer/image-comparer.ts +147 -0
  219. data/remote-src/2.0.0.beta64/shoelace-next/src/components/include/include.styles.ts +10 -0
  220. data/remote-src/2.0.0.beta64/shoelace-next/src/components/include/include.test.ts +62 -0
  221. data/remote-src/2.0.0.beta64/shoelace-next/src/components/include/include.ts +80 -0
  222. data/remote-src/2.0.0.beta64/shoelace-next/src/components/include/request.ts +23 -0
  223. data/remote-src/2.0.0.beta64/shoelace-next/src/components/input/input.styles.ts +282 -0
  224. data/remote-src/2.0.0.beta64/shoelace-next/src/components/input/input.test.ts +35 -0
  225. data/remote-src/2.0.0.beta64/shoelace-next/src/components/input/input.ts +410 -0
  226. data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu/menu.styles.ts +18 -0
  227. data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu/menu.ts +205 -0
  228. data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu-item/menu-item.styles.ts +84 -0
  229. data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu-item/menu-item.ts +92 -0
  230. data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu-label/menu-label.styles.ts +21 -0
  231. data/remote-src/2.0.0.beta64/shoelace-next/src/components/menu-label/menu-label.ts +30 -0
  232. data/remote-src/2.0.0.beta64/shoelace-next/src/components/mutation-observer/mutation-observer.styles.ts +10 -0
  233. data/remote-src/2.0.0.beta64/shoelace-next/src/components/mutation-observer/mutation-observer.test.ts +13 -0
  234. data/remote-src/2.0.0.beta64/shoelace-next/src/components/mutation-observer/mutation-observer.ts +118 -0
  235. data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-bar/progress-bar.styles.ts +57 -0
  236. data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-bar/progress-bar.test.ts +89 -0
  237. data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-bar/progress-bar.ts +74 -0
  238. data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-ring/progress-ring.styles.ts +66 -0
  239. data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-ring/progress-ring.test.ts +68 -0
  240. data/remote-src/2.0.0.beta64/shoelace-next/src/components/progress-ring/progress-ring.ts +84 -0
  241. data/remote-src/2.0.0.beta64/shoelace-next/src/components/qr-code/qr-code.styles.ts +22 -0
  242. data/remote-src/2.0.0.beta64/shoelace-next/src/components/qr-code/qr-code.ts +90 -0
  243. data/remote-src/2.0.0.beta64/shoelace-next/src/components/radio/radio.styles.ts +107 -0
  244. data/remote-src/2.0.0.beta64/shoelace-next/src/components/radio/radio.test.ts +65 -0
  245. data/remote-src/2.0.0.beta64/shoelace-next/src/components/radio/radio.ts +226 -0
  246. data/remote-src/2.0.0.beta64/shoelace-next/src/components/radio-group/radio-group.styles.ts +47 -0
  247. data/remote-src/2.0.0.beta64/shoelace-next/src/components/radio-group/radio-group.ts +66 -0
  248. data/remote-src/2.0.0.beta64/shoelace-next/src/components/range/range.styles.ts +192 -0
  249. data/remote-src/2.0.0.beta64/shoelace-next/src/components/range/range.ts +273 -0
  250. data/remote-src/2.0.0.beta64/shoelace-next/src/components/rating/rating.styles.ts +79 -0
  251. data/remote-src/2.0.0.beta64/shoelace-next/src/components/rating/rating.ts +249 -0
  252. data/remote-src/2.0.0.beta64/shoelace-next/src/components/relative-time/relative-time.ts +116 -0
  253. data/remote-src/2.0.0.beta64/shoelace-next/src/components/resize-observer/resize-observer.styles.ts +10 -0
  254. data/remote-src/2.0.0.beta64/shoelace-next/src/components/resize-observer/resize-observer.ts +87 -0
  255. data/remote-src/2.0.0.beta64/shoelace-next/src/components/responsive-media/responsive-media.styles.ts +36 -0
  256. data/remote-src/2.0.0.beta64/shoelace-next/src/components/responsive-media/responsive-media.ts +50 -0
  257. data/remote-src/2.0.0.beta64/shoelace-next/src/components/select/select.styles.ts +331 -0
  258. data/remote-src/2.0.0.beta64/shoelace-next/src/components/select/select.test.ts +56 -0
  259. data/remote-src/2.0.0.beta64/shoelace-next/src/components/select/select.ts +560 -0
  260. data/remote-src/2.0.0.beta64/shoelace-next/src/components/skeleton/skeleton.styles.ts +60 -0
  261. data/remote-src/2.0.0.beta64/shoelace-next/src/components/skeleton/skeleton.ts +46 -0
  262. data/remote-src/2.0.0.beta64/shoelace-next/src/components/spinner/spinner.styles.ts +56 -0
  263. data/remote-src/2.0.0.beta64/shoelace-next/src/components/spinner/spinner.test.ts +24 -0
  264. data/remote-src/2.0.0.beta64/shoelace-next/src/components/spinner/spinner.ts +34 -0
  265. data/remote-src/2.0.0.beta64/shoelace-next/src/components/split-panel/split-panel.styles.ts +76 -0
  266. data/remote-src/2.0.0.beta64/shoelace-next/src/components/split-panel/split-panel.test.ts +13 -0
  267. data/remote-src/2.0.0.beta64/shoelace-next/src/components/split-panel/split-panel.ts +272 -0
  268. data/remote-src/2.0.0.beta64/shoelace-next/src/components/switch/switch.styles.ts +135 -0
  269. data/remote-src/2.0.0.beta64/shoelace-next/src/components/switch/switch.test.ts +64 -0
  270. data/remote-src/2.0.0.beta64/shoelace-next/src/components/switch/switch.ts +187 -0
  271. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab/tab.styles.ts +61 -0
  272. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab/tab.ts +104 -0
  273. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab-group/tab-group.styles.ts +209 -0
  274. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab-group/tab-group.ts +409 -0
  275. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab-panel/tab-panel.styles.ts +17 -0
  276. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tab-panel/tab-panel.ts +49 -0
  277. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tag/tag.styles.ts +110 -0
  278. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tag/tag.ts +92 -0
  279. data/remote-src/2.0.0.beta64/shoelace-next/src/components/textarea/textarea.styles.ts +167 -0
  280. data/remote-src/2.0.0.beta64/shoelace-next/src/components/textarea/textarea.test.ts +35 -0
  281. data/remote-src/2.0.0.beta64/shoelace-next/src/components/textarea/textarea.ts +339 -0
  282. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tooltip/tooltip.styles.ts +131 -0
  283. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tooltip/tooltip.test.ts +117 -0
  284. data/remote-src/2.0.0.beta64/shoelace-next/src/components/tooltip/tooltip.ts +355 -0
  285. data/remote-src/2.0.0.beta64/shoelace-next/src/components/visually-hidden/visually-hidden.styles.ts +18 -0
  286. data/remote-src/2.0.0.beta64/shoelace-next/src/components/visually-hidden/visually-hidden.test.ts +39 -0
  287. data/remote-src/2.0.0.beta64/shoelace-next/src/components/visually-hidden/visually-hidden.ts +24 -0
  288. data/remote-src/2.0.0.beta64/shoelace-next/src/declaration.d.ts +8 -0
  289. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/animate.ts +70 -0
  290. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/event.ts +35 -0
  291. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/focus-visible.ts +26 -0
  292. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/form-control.ts +203 -0
  293. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/formdata-event-polyfill.ts +93 -0
  294. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/math.ts +8 -0
  295. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/modal.ts +53 -0
  296. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/number.ts +32 -0
  297. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/offset.ts +13 -0
  298. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/scroll.ts +57 -0
  299. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/slot.ts +91 -0
  300. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/string.ts +3 -0
  301. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/support.ts +15 -0
  302. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/tabbable.ts +81 -0
  303. data/remote-src/2.0.0.beta64/shoelace-next/src/internal/watch.ts +40 -0
  304. data/remote-src/2.0.0.beta64/shoelace-next/src/shoelace.ts +58 -0
  305. data/remote-src/2.0.0.beta64/shoelace-next/src/styles/component.styles.ts +23 -0
  306. data/remote-src/2.0.0.beta64/shoelace-next/src/styles/form-control.styles.ts +52 -0
  307. data/remote-src/2.0.0.beta64/shoelace-next/src/styles/utility.styles.ts +23 -0
  308. data/remote-src/2.0.0.beta64/shoelace-next/src/themes/dark.styles.ts +524 -0
  309. data/remote-src/2.0.0.beta64/shoelace-next/src/themes/light.styles.ts +524 -0
  310. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/de-ch.ts +21 -0
  311. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/de.ts +21 -0
  312. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/en.ts +21 -0
  313. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/es.ts +21 -0
  314. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/fr.ts +21 -0
  315. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/he.ts +21 -0
  316. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/ja.ts +21 -0
  317. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/nl.ts +21 -0
  318. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/pl.ts +21 -0
  319. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/pt.ts +21 -0
  320. data/remote-src/2.0.0.beta64/shoelace-next/src/translations/ru.ts +21 -0
  321. data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/animation-registry.ts +59 -0
  322. data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/animation.ts +1 -0
  323. data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/base-path.ts +43 -0
  324. data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/form.ts +22 -0
  325. data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/icon-library.ts +1 -0
  326. data/remote-src/2.0.0.beta64/shoelace-next/src/utilities/localize.ts +5 -0
  327. data/remote-src/2.0.0.beta64/shoelace-next/tsconfig.json +35 -0
  328. data/remote-src/2.0.0.beta64/shoelace-next/vercel.json +4 -0
  329. data/remote-src/2.0.0.beta64/shoelace-next/web-test-runner.config.js +14 -0
  330. data/shoelace-rails-ui.gemspec +39 -0
  331. data/shoelace-rails-ui.rb +0 -0
  332. metadata +377 -0
@@ -0,0 +1,853 @@
1
+ import { LitElement, html } from 'lit';
2
+ import { customElement, property, query, state } from 'lit/decorators.js';
3
+ import { classMap } from 'lit/directives/class-map.js';
4
+ import { ifDefined } from 'lit/directives/if-defined.js';
5
+ import { live } from 'lit/directives/live.js';
6
+ import { styleMap } from 'lit/directives/style-map.js';
7
+ import { emit } from '../../internal/event';
8
+ import { watch } from '../../internal/watch';
9
+ import { clamp } from '../../internal/math';
10
+ import { FormSubmitController } from '../../internal/form-control';
11
+ import { LocalizeController } from '../../utilities/localize';
12
+ import type SlDropdown from '../dropdown/dropdown';
13
+ import type SlInput from '../input/input';
14
+ import color from 'color';
15
+ import styles from './color-picker.styles';
16
+
17
+ import '../button/button';
18
+ import '../button-group/button-group';
19
+ import '../dropdown/dropdown';
20
+ import '../icon/icon';
21
+ import '../input/input';
22
+
23
+ const hasEyeDropper = 'EyeDropper' in window;
24
+
25
+ /**
26
+ * @since 2.0
27
+ * @status stable
28
+ *
29
+ * @dependency sl-button
30
+ * @dependency sl-button-group
31
+ * @dependency sl-dropdown
32
+ * @dependency sl-input
33
+ *
34
+ * @event sl-change Emitted when the color picker's value changes.
35
+ *
36
+ * @csspart base - The component's base wrapper
37
+ * @csspart trigger - The color picker's dropdown trigger.
38
+ * @csspart swatches - The container that holds swatches.
39
+ * @csspart swatch - Each individual swatch.
40
+ * @csspart grid - The color grid.
41
+ * @csspart grid-handle - The color grid's handle.
42
+ * @csspart hue-slider - The hue slider.
43
+ * @csspart opacity-slider - The opacity slider.
44
+ * @csspart slider - Hue and opacity sliders.
45
+ * @csspart slider-handle - Hue and opacity slider handles.
46
+ * @csspart preview - The preview color.
47
+ * @csspart input - The text input.
48
+ * @csspart eye-dropper-button - The toggle format button's base.
49
+ * @csspart format-button - The toggle format button's base.
50
+ *
51
+ * @cssproperty --grid-width - The width of the color grid.
52
+ * @cssproperty --grid-height - The height of the color grid.
53
+ * @cssproperty --grid-handle-size - The size of the color grid's handle.
54
+ * @cssproperty --slider-height - The height of the hue and alpha sliders.
55
+ * @cssproperty --slider-handle-size - The diameter of the slider's handle.
56
+ * @cssproperty --swatch-size - The size of each predefined color swatch.
57
+ */
58
+ @customElement('sl-color-picker')
59
+ export default class SlColorPicker extends LitElement {
60
+ static styles = styles;
61
+
62
+ @query('[part="input"]') input: SlInput;
63
+ @query('[part="preview"]') previewButton: HTMLButtonElement;
64
+ @query('.color-dropdown') dropdown: SlDropdown;
65
+
66
+ // @ts-ignore
67
+ private formSubmitController = new FormSubmitController(this);
68
+ private isSafeValue = false;
69
+ private lastValueEmitted: string;
70
+ private localize = new LocalizeController(this);
71
+
72
+ @state() private inputValue = '';
73
+ @state() private hue = 0;
74
+ @state() private saturation = 100;
75
+ @state() private lightness = 100;
76
+ @state() private alpha = 100;
77
+
78
+ /** The current color. */
79
+ @property() value = '#ffffff';
80
+
81
+ /**
82
+ * The format to use for the display value. If opacity is enabled, these will translate to HEXA, RGBA, and HSLA
83
+ * respectively. The color picker will always accept user input in any format (including CSS color names) and convert
84
+ * it to the desired format.
85
+ */
86
+ @property() format: 'hex' | 'rgb' | 'hsl' = 'hex';
87
+
88
+ /** Renders the color picker inline rather than inside a dropdown. */
89
+ @property({ type: Boolean, reflect: true }) inline = false;
90
+
91
+ /** Determines the size of the color picker's trigger. This has no effect on inline color pickers. */
92
+ @property() size: 'small' | 'medium' | 'large' = 'medium';
93
+
94
+ /** Removes the format toggle. */
95
+ @property({ attribute: 'no-format-toggle', type: Boolean }) noFormatToggle = false;
96
+
97
+ /** The input's name attribute. */
98
+ @property() name = '';
99
+
100
+ /** Disables the color picker. */
101
+ @property({ type: Boolean, reflect: true }) disabled = false;
102
+
103
+ /**
104
+ * This will be true when the control is in an invalid state. Validity is determined by the `setCustomValidity()`
105
+ * method using the browser's constraint validation API.
106
+ */
107
+ @property({ type: Boolean, reflect: true }) invalid = false;
108
+
109
+ /**
110
+ * Enable this option to prevent the panel from being clipped when the component is placed inside a container with
111
+ * `overflow: auto|scroll`.
112
+ */
113
+ @property({ type: Boolean }) hoist = false;
114
+
115
+ /** Whether to show the opacity slider. */
116
+ @property({ type: Boolean }) opacity = false;
117
+
118
+ /** By default, the value will be set in lowercase. Set this to true to set it in uppercase instead. */
119
+ @property({ type: Boolean }) uppercase = false;
120
+
121
+ /**
122
+ * An array of predefined color swatches to display. Can include any format the color picker can parse, including
123
+ * HEX(A), RGB(A), HSL(A), and CSS color names.
124
+ */
125
+ @property({ attribute: false }) swatches: string[] = [
126
+ '#d0021b',
127
+ '#f5a623',
128
+ '#f8e71c',
129
+ '#8b572a',
130
+ '#7ed321',
131
+ '#417505',
132
+ '#bd10e0',
133
+ '#9013fe',
134
+ '#4a90e2',
135
+ '#50e3c2',
136
+ '#b8e986',
137
+ '#000',
138
+ '#444',
139
+ '#888',
140
+ '#ccc',
141
+ '#fff'
142
+ ];
143
+
144
+ /** The locale to render the component in. */
145
+ @property() lang: string;
146
+
147
+ firstUpdated() {
148
+ if (!this.setColor(this.value)) {
149
+ this.setColor(`#ffff`);
150
+ }
151
+
152
+ this.inputValue = this.value;
153
+ this.lastValueEmitted = this.value;
154
+ this.syncValues();
155
+ }
156
+
157
+ /** Returns the current value as a string in the specified format. */
158
+ getFormattedValue(format: 'hex' | 'hexa' | 'rgb' | 'rgba' | 'hsl' | 'hsla' = 'hex') {
159
+ const currentColor = this.parseColor(
160
+ `hsla(${this.hue}, ${this.saturation}%, ${this.lightness}%, ${this.alpha / 100})`
161
+ );
162
+
163
+ if (!currentColor) {
164
+ return '';
165
+ }
166
+
167
+ switch (format) {
168
+ case 'hex':
169
+ return currentColor.hex;
170
+ case 'hexa':
171
+ return currentColor.hexa;
172
+ case 'rgb':
173
+ return currentColor.rgb.string;
174
+ case 'rgba':
175
+ return currentColor.rgba.string;
176
+ case 'hsl':
177
+ return currentColor.hsl.string;
178
+ case 'hsla':
179
+ return currentColor.hsla.string;
180
+ default:
181
+ return '';
182
+ }
183
+ }
184
+
185
+ /** Checks for validity and shows the browser's validation message if the control is invalid. */
186
+ reportValidity() {
187
+ // If the input is invalid, show the dropdown so the browser can focus on it
188
+ if (!this.inline && this.input.invalid) {
189
+ return new Promise<void>(resolve => {
190
+ this.dropdown.addEventListener(
191
+ 'sl-after-show',
192
+ () => {
193
+ this.input.reportValidity();
194
+ resolve();
195
+ },
196
+ { once: true }
197
+ );
198
+ this.dropdown.show();
199
+ });
200
+ } else {
201
+ return this.input.reportValidity();
202
+ }
203
+ }
204
+
205
+ /** Sets a custom validation message. If `message` is not empty, the field will be considered invalid. */
206
+ setCustomValidity(message: string) {
207
+ this.input.setCustomValidity(message);
208
+ this.invalid = this.input.invalid;
209
+ }
210
+
211
+ handleCopy() {
212
+ this.input.select();
213
+ document.execCommand('copy');
214
+ this.previewButton.focus();
215
+
216
+ // Show copied animation
217
+ this.previewButton.classList.add('color-picker__preview-color--copied');
218
+ this.previewButton.addEventListener('animationend', () =>
219
+ this.previewButton.classList.remove('color-picker__preview-color--copied')
220
+ );
221
+ }
222
+
223
+ handleFormatToggle() {
224
+ const formats = ['hex', 'rgb', 'hsl'];
225
+ const nextIndex = (formats.indexOf(this.format) + 1) % formats.length;
226
+ this.format = formats[nextIndex] as 'hex' | 'rgb' | 'hsl';
227
+ }
228
+
229
+ handleAlphaDrag(event: any) {
230
+ const container = this.shadowRoot!.querySelector('.color-picker__slider.color-picker__alpha') as HTMLElement;
231
+ const handle = container.querySelector('.color-picker__slider-handle') as HTMLElement;
232
+ const { width } = container.getBoundingClientRect();
233
+
234
+ handle.focus();
235
+ event.preventDefault();
236
+
237
+ this.handleDrag(event, container, x => {
238
+ this.alpha = clamp((x / width) * 100, 0, 100);
239
+ this.syncValues();
240
+ });
241
+ }
242
+
243
+ handleHueDrag(event: any) {
244
+ const container = this.shadowRoot!.querySelector('.color-picker__slider.color-picker__hue') as HTMLElement;
245
+ const handle = container.querySelector('.color-picker__slider-handle') as HTMLElement;
246
+ const { width } = container.getBoundingClientRect();
247
+
248
+ handle.focus();
249
+ event.preventDefault();
250
+
251
+ this.handleDrag(event, container, x => {
252
+ this.hue = clamp((x / width) * 360, 0, 360);
253
+ this.syncValues();
254
+ });
255
+ }
256
+
257
+ handleGridDrag(event: any) {
258
+ const grid = this.shadowRoot!.querySelector('.color-picker__grid') as HTMLElement;
259
+ const handle = grid.querySelector('.color-picker__grid-handle') as HTMLElement;
260
+ const { width, height } = grid.getBoundingClientRect();
261
+
262
+ handle.focus();
263
+ event.preventDefault();
264
+
265
+ this.handleDrag(event, grid, (x, y) => {
266
+ this.saturation = clamp((x / width) * 100, 0, 100);
267
+ this.lightness = clamp(100 - (y / height) * 100, 0, 100);
268
+ this.syncValues();
269
+ });
270
+ }
271
+
272
+ handleDrag(event: any, container: HTMLElement, onMove: (x: number, y: number) => void) {
273
+ if (this.disabled) {
274
+ return;
275
+ }
276
+
277
+ const move = (event: any) => {
278
+ const dims = container.getBoundingClientRect();
279
+ const defaultView = container.ownerDocument.defaultView!;
280
+ const offsetX = dims.left + defaultView.pageXOffset;
281
+ const offsetY = dims.top + defaultView.pageYOffset;
282
+ const x = (event.changedTouches ? event.changedTouches[0].pageX : event.pageX) - offsetX;
283
+ const y = (event.changedTouches ? event.changedTouches[0].pageY : event.pageY) - offsetY;
284
+
285
+ onMove(x, y);
286
+ };
287
+
288
+ // Move on init
289
+ move(event);
290
+
291
+ const stop = () => {
292
+ document.removeEventListener('mousemove', move);
293
+ document.removeEventListener('touchmove', move);
294
+ document.removeEventListener('mouseup', stop);
295
+ document.removeEventListener('touchend', stop);
296
+ };
297
+
298
+ document.addEventListener('mousemove', move);
299
+ document.addEventListener('touchmove', move);
300
+ document.addEventListener('mouseup', stop);
301
+ document.addEventListener('touchend', stop);
302
+ }
303
+
304
+ handleAlphaKeyDown(event: KeyboardEvent) {
305
+ const increment = event.shiftKey ? 10 : 1;
306
+
307
+ if (event.key === 'ArrowLeft') {
308
+ event.preventDefault();
309
+ this.alpha = clamp(this.alpha - increment, 0, 100);
310
+ this.syncValues();
311
+ }
312
+
313
+ if (event.key === 'ArrowRight') {
314
+ event.preventDefault();
315
+ this.alpha = clamp(this.alpha + increment, 0, 100);
316
+ this.syncValues();
317
+ }
318
+
319
+ if (event.key === 'Home') {
320
+ event.preventDefault();
321
+ this.alpha = 0;
322
+ this.syncValues();
323
+ }
324
+
325
+ if (event.key === 'End') {
326
+ event.preventDefault();
327
+ this.alpha = 100;
328
+ this.syncValues();
329
+ }
330
+ }
331
+
332
+ handleHueKeyDown(event: KeyboardEvent) {
333
+ const increment = event.shiftKey ? 10 : 1;
334
+
335
+ if (event.key === 'ArrowLeft') {
336
+ event.preventDefault();
337
+ this.hue = clamp(this.hue - increment, 0, 360);
338
+ this.syncValues();
339
+ }
340
+
341
+ if (event.key === 'ArrowRight') {
342
+ event.preventDefault();
343
+ this.hue = clamp(this.hue + increment, 0, 360);
344
+ this.syncValues();
345
+ }
346
+
347
+ if (event.key === 'Home') {
348
+ event.preventDefault();
349
+ this.hue = 0;
350
+ this.syncValues();
351
+ }
352
+
353
+ if (event.key === 'End') {
354
+ event.preventDefault();
355
+ this.hue = 360;
356
+ this.syncValues();
357
+ }
358
+ }
359
+
360
+ handleGridKeyDown(event: KeyboardEvent) {
361
+ const increment = event.shiftKey ? 10 : 1;
362
+
363
+ if (event.key === 'ArrowLeft') {
364
+ event.preventDefault();
365
+ this.saturation = clamp(this.saturation - increment, 0, 100);
366
+ this.syncValues();
367
+ }
368
+
369
+ if (event.key === 'ArrowRight') {
370
+ event.preventDefault();
371
+ this.saturation = clamp(this.saturation + increment, 0, 100);
372
+ this.syncValues();
373
+ }
374
+
375
+ if (event.key === 'ArrowUp') {
376
+ event.preventDefault();
377
+ this.lightness = clamp(this.lightness + increment, 0, 100);
378
+ this.syncValues();
379
+ }
380
+
381
+ if (event.key === 'ArrowDown') {
382
+ event.preventDefault();
383
+ this.lightness = clamp(this.lightness - increment, 0, 100);
384
+ this.syncValues();
385
+ }
386
+ }
387
+
388
+ handleInputChange(event: CustomEvent) {
389
+ const target = event.target as HTMLInputElement;
390
+
391
+ this.setColor(target.value);
392
+ target.value = this.value;
393
+ event.stopPropagation();
394
+ }
395
+
396
+ handleInputKeyDown(event: KeyboardEvent) {
397
+ if (event.key === 'Enter') {
398
+ this.setColor(this.input.value);
399
+ this.input.value = this.value;
400
+ setTimeout(() => this.input.select());
401
+ }
402
+ }
403
+
404
+ normalizeColorString(colorString: string) {
405
+ //
406
+ // The color module we're using doesn't parse % values for the alpha channel in RGBA and HSLA. It also doesn't parse
407
+ // hex colors when the # is missing. This pre-parser tries to normalize these edge cases to provide a better
408
+ // experience for users who type in color values.
409
+ //
410
+ if (/rgba?/i.test(colorString)) {
411
+ const rgba = colorString
412
+ .replace(/[^\d.%]/g, ' ')
413
+ .split(' ')
414
+ .map(val => val.trim())
415
+ .filter(val => val.length);
416
+
417
+ if (rgba.length < 4) {
418
+ rgba[3] = '1';
419
+ }
420
+
421
+ if (rgba[3].indexOf('%') > -1) {
422
+ rgba[3] = (Number(rgba[3].replace(/%/g, '')) / 100).toString();
423
+ }
424
+
425
+ return `rgba(${rgba[0]}, ${rgba[1]}, ${rgba[2]}, ${rgba[3]})`;
426
+ }
427
+
428
+ if (/hsla?/i.test(colorString)) {
429
+ const hsla = colorString
430
+ .replace(/[^\d.%]/g, ' ')
431
+ .split(' ')
432
+ .map(val => val.trim())
433
+ .filter(val => val.length);
434
+
435
+ if (hsla.length < 4) {
436
+ hsla[3] = '1';
437
+ }
438
+
439
+ if (hsla[3].indexOf('%') > -1) {
440
+ hsla[3] = (Number(hsla[3].replace(/%/g, '')) / 100).toString();
441
+ }
442
+
443
+ return `hsla(${hsla[0]}, ${hsla[1]}, ${hsla[2]}, ${hsla[3]})`;
444
+ }
445
+
446
+ if (/^[0-9a-f]+$/i.test(colorString)) {
447
+ return `#${colorString}`;
448
+ }
449
+
450
+ return colorString;
451
+ }
452
+
453
+ parseColor(colorString: string) {
454
+ function toHex(value: number) {
455
+ const hex = Math.round(value).toString(16);
456
+ return hex.length === 1 ? `0${hex}` : hex;
457
+ }
458
+
459
+ let parsed: any;
460
+
461
+ // The color module has a weak parser, so we normalize certain things to make the user experience better
462
+ colorString = this.normalizeColorString(colorString);
463
+
464
+ try {
465
+ parsed = color(colorString);
466
+ } catch {
467
+ return false;
468
+ }
469
+
470
+ const hsl = {
471
+ h: parsed.hsl().color[0],
472
+ s: parsed.hsl().color[1],
473
+ l: parsed.hsl().color[2],
474
+ a: parsed.hsl().valpha
475
+ };
476
+
477
+ const rgb = {
478
+ r: parsed.rgb().color[0],
479
+ g: parsed.rgb().color[1],
480
+ b: parsed.rgb().color[2],
481
+ a: parsed.rgb().valpha
482
+ };
483
+
484
+ const hex = {
485
+ r: toHex(parsed.rgb().color[0]),
486
+ g: toHex(parsed.rgb().color[1]),
487
+ b: toHex(parsed.rgb().color[2]),
488
+ a: toHex(parsed.rgb().valpha * 255)
489
+ };
490
+
491
+ return {
492
+ hsl: {
493
+ h: hsl.h,
494
+ s: hsl.s,
495
+ l: hsl.l,
496
+ string: this.setLetterCase(`hsl(${Math.round(hsl.h)}, ${Math.round(hsl.s)}%, ${Math.round(hsl.l)}%)`)
497
+ },
498
+ hsla: {
499
+ h: hsl.h,
500
+ s: hsl.s,
501
+ l: hsl.l,
502
+ a: hsl.a,
503
+ string: this.setLetterCase(
504
+ `hsla(${Math.round(hsl.h)}, ${Math.round(hsl.s)}%, ${Math.round(hsl.l)}%, ${Number(
505
+ hsl.a.toFixed(2).toString()
506
+ )})`
507
+ )
508
+ },
509
+ rgb: {
510
+ r: rgb.r,
511
+ g: rgb.g,
512
+ b: rgb.b,
513
+ string: this.setLetterCase(`rgb(${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)})`)
514
+ },
515
+ rgba: {
516
+ r: rgb.r,
517
+ g: rgb.g,
518
+ b: rgb.b,
519
+ a: rgb.a,
520
+ string: this.setLetterCase(
521
+ `rgba(${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)}, ${Number(
522
+ rgb.a.toFixed(2).toString()
523
+ )})`
524
+ )
525
+ },
526
+ hex: this.setLetterCase(`#${hex.r}${hex.g}${hex.b}`),
527
+ hexa: this.setLetterCase(`#${hex.r}${hex.g}${hex.b}${hex.a}`)
528
+ };
529
+ }
530
+
531
+ setColor(colorString: string) {
532
+ const newColor = this.parseColor(colorString);
533
+
534
+ if (!newColor) {
535
+ return false;
536
+ }
537
+
538
+ this.hue = newColor.hsla.h;
539
+ this.saturation = newColor.hsla.s;
540
+ this.lightness = newColor.hsla.l;
541
+ this.alpha = this.opacity ? newColor.hsla.a * 100 : 100;
542
+
543
+ this.syncValues();
544
+
545
+ return true;
546
+ }
547
+
548
+ setLetterCase(string: string) {
549
+ if (typeof string !== 'string') return '';
550
+ return this.uppercase ? string.toUpperCase() : string.toLowerCase();
551
+ }
552
+
553
+ async syncValues() {
554
+ const currentColor = this.parseColor(
555
+ `hsla(${this.hue}, ${this.saturation}%, ${this.lightness}%, ${this.alpha / 100})`
556
+ );
557
+
558
+ if (!currentColor) {
559
+ return;
560
+ }
561
+
562
+ // Update the value
563
+ if (this.format === 'hsl') {
564
+ this.inputValue = this.opacity ? currentColor.hsla.string : currentColor.hsl.string;
565
+ } else if (this.format === 'rgb') {
566
+ this.inputValue = this.opacity ? currentColor.rgba.string : currentColor.rgb.string;
567
+ } else {
568
+ this.inputValue = this.opacity ? currentColor.hexa : currentColor.hex;
569
+ }
570
+
571
+ // Setting this.value will trigger the watcher which parses the new value. We want to bypass that behavior because
572
+ // we've already parsed the color here and conversion/rounding can lead to values changing slightly. WHen this
573
+ // happens, dragging the grid handle becomes jumpy. After the next update, the usual behavior is restored.
574
+ this.isSafeValue = true;
575
+ this.value = this.inputValue;
576
+ await this.updateComplete;
577
+ this.isSafeValue = false;
578
+ }
579
+
580
+ handleAfterHide() {
581
+ this.previewButton.classList.remove('color-picker__preview-color--copied');
582
+ }
583
+
584
+ handleEyeDropper() {
585
+ if (!hasEyeDropper) {
586
+ return;
587
+ }
588
+
589
+ // @ts-ignore
590
+ const eyeDropper = new EyeDropper();
591
+
592
+ eyeDropper
593
+ .open()
594
+ .then((colorSelectionResult: any) => this.setColor(colorSelectionResult.sRGBHex))
595
+ .catch(() => {
596
+ // The user canceled, do nothing
597
+ });
598
+ }
599
+
600
+ @watch('format')
601
+ handleFormatChange() {
602
+ this.syncValues();
603
+ }
604
+
605
+ @watch('opacity')
606
+ handleOpacityChange() {
607
+ this.alpha = 100;
608
+ }
609
+
610
+ @watch('value')
611
+ handleValueChange(oldValue: string, newValue: string) {
612
+ if (!this.isSafeValue) {
613
+ const newColor = this.parseColor(newValue);
614
+
615
+ if (newColor) {
616
+ this.inputValue = this.value;
617
+ this.hue = newColor.hsla.h;
618
+ this.saturation = newColor.hsla.s;
619
+ this.lightness = newColor.hsla.l;
620
+ this.alpha = newColor.hsla.a * 100;
621
+ } else {
622
+ this.inputValue = oldValue;
623
+ }
624
+ }
625
+
626
+ if (this.value !== this.lastValueEmitted) {
627
+ emit(this, 'sl-change');
628
+ this.lastValueEmitted = this.value;
629
+ }
630
+ }
631
+
632
+ render() {
633
+ const x = this.saturation;
634
+ const y = 100 - this.lightness;
635
+
636
+ const colorPicker = html`
637
+ <div
638
+ part="base"
639
+ class=${classMap({
640
+ 'color-picker': true,
641
+ 'color-picker--inline': this.inline,
642
+ 'color-picker--disabled': this.disabled
643
+ })}
644
+ aria-disabled=${this.disabled ? 'true' : 'false'}
645
+ >
646
+ <div
647
+ part="grid"
648
+ class="color-picker__grid"
649
+ style=${styleMap({ backgroundColor: `hsl(${this.hue}deg, 100%, 50%)` })}
650
+ @mousedown=${this.handleGridDrag}
651
+ @touchstart=${this.handleGridDrag}
652
+ >
653
+ <span
654
+ part="grid-handle"
655
+ class="color-picker__grid-handle"
656
+ style=${styleMap({
657
+ top: `${y}%`,
658
+ left: `${x}%`,
659
+ backgroundColor: `hsla(${this.hue}deg, ${this.saturation}%, ${this.lightness}%)`
660
+ })}
661
+ role="slider"
662
+ aria-label="HSL"
663
+ aria-valuetext=${`hsl(${Math.round(this.hue)}, ${Math.round(this.saturation)}%, ${Math.round(
664
+ this.lightness
665
+ )}%)`}
666
+ tabindex=${ifDefined(this.disabled ? undefined : '0')}
667
+ @keydown=${this.handleGridKeyDown}
668
+ ></span>
669
+ </div>
670
+
671
+ <div class="color-picker__controls">
672
+ <div class="color-picker__sliders">
673
+ <div
674
+ part="slider hue-slider"
675
+ class="color-picker__hue color-picker__slider"
676
+ @mousedown=${this.handleHueDrag}
677
+ @touchstart=${this.handleHueDrag}
678
+ >
679
+ <span
680
+ part="slider-handle"
681
+ class="color-picker__slider-handle"
682
+ style=${styleMap({
683
+ left: `${this.hue === 0 ? 0 : 100 / (360 / this.hue)}%`
684
+ })}
685
+ role="slider"
686
+ aria-label="hue"
687
+ aria-orientation="horizontal"
688
+ aria-valuemin="0"
689
+ aria-valuemax="360"
690
+ aria-valuenow=${Math.round(this.hue)}
691
+ tabindex=${ifDefined(this.disabled ? undefined : '0')}
692
+ @keydown=${this.handleHueKeyDown}
693
+ ></span>
694
+ </div>
695
+
696
+ ${this.opacity
697
+ ? html`
698
+ <div
699
+ part="slider opacity-slider"
700
+ class="color-picker__alpha color-picker__slider color-picker__transparent-bg"
701
+ @mousedown="${this.handleAlphaDrag}"
702
+ @touchstart="${this.handleAlphaDrag}"
703
+ >
704
+ <div
705
+ class="color-picker__alpha-gradient"
706
+ style=${styleMap({
707
+ backgroundImage: `linear-gradient(
708
+ to right,
709
+ hsl(${this.hue}deg, ${this.saturation}%, ${this.lightness}%, 0%) 0%,
710
+ hsl(${this.hue}deg, ${this.saturation}%, ${this.lightness}%) 100%
711
+ )`
712
+ })}
713
+ ></div>
714
+ <span
715
+ part="slider-handle"
716
+ class="color-picker__slider-handle"
717
+ style=${styleMap({
718
+ left: `${this.alpha}%`
719
+ })}
720
+ role="slider"
721
+ aria-label="alpha"
722
+ aria-orientation="horizontal"
723
+ aria-valuemin="0"
724
+ aria-valuemax="100"
725
+ aria-valuenow=${Math.round(this.alpha)}
726
+ tabindex=${ifDefined(this.disabled ? undefined : '0')}
727
+ @keydown=${this.handleAlphaKeyDown}
728
+ ></span>
729
+ </div>
730
+ `
731
+ : ''}
732
+ </div>
733
+
734
+ <button
735
+ type="button"
736
+ part="preview"
737
+ class="color-picker__preview color-picker__transparent-bg"
738
+ aria-label=${this.localize.term('copy')}
739
+ style=${styleMap({
740
+ '--preview-color': `hsla(${this.hue}deg, ${this.saturation}%, ${this.lightness}%, ${this.alpha / 100})`
741
+ })}
742
+ @click=${this.handleCopy}
743
+ ></button>
744
+ </div>
745
+
746
+ <div class="color-picker__user-input">
747
+ <sl-input
748
+ part="input"
749
+ type="text"
750
+ name=${this.name}
751
+ autocomplete="off"
752
+ autocorrect="off"
753
+ autocapitalize="off"
754
+ spellcheck="false"
755
+ .value=${live(this.inputValue)}
756
+ ?disabled=${this.disabled}
757
+ @keydown=${this.handleInputKeyDown}
758
+ @sl-change=${this.handleInputChange}
759
+ ></sl-input>
760
+
761
+ <sl-button-group>
762
+ ${!this.noFormatToggle
763
+ ? html`
764
+ <sl-button
765
+ aria-label=${this.localize.term('toggle_color_format')}
766
+ exportparts="base:format-button"
767
+ @click=${this.handleFormatToggle}
768
+ >
769
+ ${this.setLetterCase(this.format)}
770
+ </sl-button>
771
+ `
772
+ : ''}
773
+ ${hasEyeDropper
774
+ ? html`
775
+ <sl-button exportparts="base:eye-dropper-button" @click=${this.handleEyeDropper}>
776
+ <sl-icon
777
+ library="system"
778
+ name="eyedropper"
779
+ label=${this.localize.term('select_a_color_from_the_screen')}
780
+ ></sl-icon>
781
+ </sl-button>
782
+ `
783
+ : ''}
784
+ </sl-button-group>
785
+ </div>
786
+
787
+ ${this.swatches
788
+ ? html`
789
+ <div part="swatches" class="color-picker__swatches">
790
+ ${this.swatches.map(swatch => {
791
+ return html`
792
+ <div
793
+ part="swatch"
794
+ class="color-picker__swatch color-picker__transparent-bg"
795
+ tabindex=${ifDefined(this.disabled ? undefined : '0')}
796
+ role="button"
797
+ aria-label=${swatch}
798
+ @click=${() => !this.disabled && this.setColor(swatch)}
799
+ @keydown=${(event: KeyboardEvent) =>
800
+ !this.disabled && event.key === 'Enter' && this.setColor(swatch)}
801
+ >
802
+ <div class="color-picker__swatch-color" style=${styleMap({ backgroundColor: swatch })}></div>
803
+ </div>
804
+ `;
805
+ })}
806
+ </div>
807
+ `
808
+ : ''}
809
+ </div>
810
+ `;
811
+
812
+ // Render inline
813
+ if (this.inline) {
814
+ return colorPicker;
815
+ }
816
+
817
+ // Render as a dropdown
818
+ return html`
819
+ <sl-dropdown
820
+ class="color-dropdown"
821
+ aria-disabled=${this.disabled ? 'true' : 'false'}
822
+ .containing-element=${this}
823
+ ?disabled=${this.disabled}
824
+ ?hoist=${this.hoist}
825
+ @sl-after-hide=${this.handleAfterHide}
826
+ >
827
+ <button
828
+ part="trigger"
829
+ slot="trigger"
830
+ class=${classMap({
831
+ 'color-dropdown__trigger': true,
832
+ 'color-dropdown__trigger--disabled': this.disabled,
833
+ 'color-dropdown__trigger--small': this.size === 'small',
834
+ 'color-dropdown__trigger--medium': this.size === 'medium',
835
+ 'color-dropdown__trigger--large': this.size === 'large',
836
+ 'color-picker__transparent-bg': true
837
+ })}
838
+ style=${styleMap({
839
+ color: `hsla(${this.hue}deg, ${this.saturation}%, ${this.lightness}%, ${this.alpha / 100})`
840
+ })}
841
+ type="button"
842
+ ></button>
843
+ ${colorPicker}
844
+ </sl-dropdown>
845
+ `;
846
+ }
847
+ }
848
+
849
+ declare global {
850
+ interface HTMLElementTagNameMap {
851
+ 'sl-color-picker': SlColorPicker;
852
+ }
853
+ }