@govtechsg/sgds-web-component 3.0.0-rc.0 → 3.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (491) hide show
  1. package/Masthead/index.js +1 -1
  2. package/README.md +5 -5
  3. package/base/button.js +1 -1
  4. package/base/form-control-element.d.ts +4 -11
  5. package/base/form-control-element.js +13 -23
  6. package/base/form-control-element.js.map +1 -1
  7. package/components/Accordion/accordion-item.js +1 -1
  8. package/components/Accordion/index.umd.js +7 -19
  9. package/components/Accordion/index.umd.js.map +1 -1
  10. package/components/Accordion/sgds-accordion-item.d.ts +3 -7
  11. package/components/Accordion/sgds-accordion-item.js +6 -18
  12. package/components/Accordion/sgds-accordion-item.js.map +1 -1
  13. package/components/ActionCard/index.umd.js +407 -329
  14. package/components/ActionCard/index.umd.js.map +1 -1
  15. package/components/Alert/alert.js +1 -1
  16. package/components/Alert/index.umd.js +553 -485
  17. package/components/Alert/index.umd.js.map +1 -1
  18. package/components/Alert/sgds-alert.d.ts +2 -2
  19. package/components/Alert/sgds-alert.js +6 -13
  20. package/components/Alert/sgds-alert.js.map +1 -1
  21. package/components/Badge/badge.js +1 -1
  22. package/components/Badge/index.umd.js +9 -10
  23. package/components/Badge/index.umd.js.map +1 -1
  24. package/components/Badge/sgds-badge.d.ts +4 -5
  25. package/components/Badge/sgds-badge.js +6 -7
  26. package/components/Badge/sgds-badge.js.map +1 -1
  27. package/components/Button/index.umd.js +8 -81
  28. package/components/Button/index.umd.js.map +1 -1
  29. package/components/Button/sgds-button.js +1 -1
  30. package/components/Button/sgds-button.js.map +1 -1
  31. package/components/Checkbox/checkbox.js +1 -1
  32. package/components/Checkbox/index.umd.js +541 -475
  33. package/components/Checkbox/index.umd.js.map +1 -1
  34. package/components/Checkbox/sgds-checkbox-group.d.ts +7 -1
  35. package/components/Checkbox/sgds-checkbox-group.js +15 -4
  36. package/components/Checkbox/sgds-checkbox-group.js.map +1 -1
  37. package/components/Checkbox/sgds-checkbox.d.ts +30 -21
  38. package/components/Checkbox/sgds-checkbox.js +77 -60
  39. package/components/Checkbox/sgds-checkbox.js.map +1 -1
  40. package/components/ComboBox/index.umd.js +385 -216
  41. package/components/ComboBox/index.umd.js.map +1 -1
  42. package/components/Datepicker/datepicker-input.d.ts +4 -2
  43. package/components/Datepicker/datepicker-input.js +24 -7
  44. package/components/Datepicker/datepicker-input.js.map +1 -1
  45. package/components/Datepicker/index.umd.js +433 -244
  46. package/components/Datepicker/index.umd.js.map +1 -1
  47. package/components/Datepicker/sgds-datepicker.d.ts +1 -1
  48. package/components/Datepicker/sgds-datepicker.js.map +1 -1
  49. package/components/Drawer/index.umd.js +2 -2
  50. package/components/Drawer/index.umd.js.map +1 -1
  51. package/components/Dropdown/index.umd.js +8 -81
  52. package/components/Dropdown/index.umd.js.map +1 -1
  53. package/components/FileUpload/file-upload.js +1 -1
  54. package/components/FileUpload/index.umd.js +579 -272
  55. package/components/FileUpload/index.umd.js.map +1 -1
  56. package/components/FileUpload/sgds-file-upload.d.ts +42 -30
  57. package/components/FileUpload/sgds-file-upload.js +147 -103
  58. package/components/FileUpload/sgds-file-upload.js.map +1 -1
  59. package/components/Footer/footer-item.js +6 -0
  60. package/components/Footer/footer-item.js.map +1 -0
  61. package/components/Footer/footer.js +1 -1
  62. package/components/Footer/index.d.ts +2 -0
  63. package/components/Footer/index.js +2 -0
  64. package/components/Footer/index.js.map +1 -1
  65. package/components/Footer/index.umd.js +93 -94
  66. package/components/Footer/index.umd.js.map +1 -1
  67. package/components/Footer/sgds-footer-item.d.ts +13 -0
  68. package/components/Footer/sgds-footer-item.js +27 -0
  69. package/components/Footer/sgds-footer-item.js.map +1 -0
  70. package/components/Footer/sgds-footer.d.ts +9 -30
  71. package/components/Footer/sgds-footer.js +65 -90
  72. package/components/Footer/sgds-footer.js.map +1 -1
  73. package/components/Icon/icon.js +6 -0
  74. package/components/Icon/icon.js.map +1 -0
  75. package/components/Icon/index.d.ts +6 -0
  76. package/components/Icon/index.js +4 -0
  77. package/components/Icon/index.js.map +1 -0
  78. package/components/Icon/index.umd.js +4389 -0
  79. package/components/Icon/index.umd.js.map +1 -0
  80. package/components/Icon/sgds-icon.d.ts +21 -0
  81. package/components/Icon/sgds-icon.js +64 -0
  82. package/components/Icon/sgds-icon.js.map +1 -0
  83. package/components/IconButton/icon-button.js +1 -1
  84. package/components/IconButton/index.umd.js +6 -9
  85. package/components/IconButton/index.umd.js.map +1 -1
  86. package/components/IconButton/sgds-icon-button.d.ts +2 -2
  87. package/components/IconButton/sgds-icon-button.js +4 -9
  88. package/components/IconButton/sgds-icon-button.js.map +1 -1
  89. package/components/Input/index.umd.js +1734 -1376
  90. package/components/Input/index.umd.js.map +1 -1
  91. package/components/Input/sgds-input.d.ts +41 -21
  92. package/components/Input/sgds-input.js +103 -66
  93. package/components/Input/sgds-input.js.map +1 -1
  94. package/components/Masthead/index.umd.js +1 -1
  95. package/components/Masthead/masthead.js +1 -1
  96. package/components/Modal/index.umd.js +2 -2
  97. package/components/Modal/index.umd.js.map +1 -1
  98. package/components/QuantityToggle/index.umd.js +894 -316
  99. package/components/QuantityToggle/index.umd.js.map +1 -1
  100. package/components/QuantityToggle/sgds-quantity-toggle.d.ts +42 -15
  101. package/components/QuantityToggle/sgds-quantity-toggle.js +129 -62
  102. package/components/QuantityToggle/sgds-quantity-toggle.js.map +1 -1
  103. package/components/Radio/index.umd.js +516 -203
  104. package/components/Radio/index.umd.js.map +1 -1
  105. package/components/Radio/sgds-radio-group.d.ts +38 -27
  106. package/components/Radio/sgds-radio-group.js +100 -84
  107. package/components/Radio/sgds-radio-group.js.map +1 -1
  108. package/components/Radio/sgds-radio.js +1 -1
  109. package/components/Radio/sgds-radio.js.map +1 -1
  110. package/components/Stepper/index.umd.js +2 -1
  111. package/components/Stepper/index.umd.js.map +1 -1
  112. package/components/Stepper/sgds-stepper.d.ts +1 -0
  113. package/components/Stepper/sgds-stepper.js +1 -0
  114. package/components/Stepper/sgds-stepper.js.map +1 -1
  115. package/components/Stepper/stepper.js +1 -1
  116. package/components/Switch/index.umd.js +21 -321
  117. package/components/Switch/index.umd.js.map +1 -1
  118. package/components/Switch/sgds-switch.js +1 -2
  119. package/components/Switch/sgds-switch.js.map +1 -1
  120. package/components/Textarea/index.umd.js +1554 -1336
  121. package/components/Textarea/index.umd.js.map +1 -1
  122. package/components/Textarea/sgds-textarea.d.ts +33 -22
  123. package/components/Textarea/sgds-textarea.js +78 -75
  124. package/components/Textarea/sgds-textarea.js.map +1 -1
  125. package/components/Textarea/textarea.js +1 -1
  126. package/components/Toast/index.umd.js +9 -21
  127. package/components/Toast/index.umd.js.map +1 -1
  128. package/components/Toast/sgds-toast.d.ts +2 -1
  129. package/components/Toast/sgds-toast.js +6 -18
  130. package/components/Toast/sgds-toast.js.map +1 -1
  131. package/components/Toast/toast.js +1 -1
  132. package/components/Tooltip/index.umd.js +14 -14
  133. package/components/Tooltip/index.umd.js.map +1 -1
  134. package/components/Tooltip/sgds-tooltip.d.ts +4 -7
  135. package/components/Tooltip/sgds-tooltip.js +14 -14
  136. package/components/Tooltip/sgds-tooltip.js.map +1 -1
  137. package/components/index.d.ts +1 -0
  138. package/components/index.js +1 -0
  139. package/components/index.js.map +1 -1
  140. package/components/index.umd.js +1320 -1126
  141. package/components/index.umd.js.map +1 -1
  142. package/css/reboot.css +39 -6
  143. package/css/sgds.css +0 -2
  144. package/icons/arrow-bar-down.svg +3 -0
  145. package/icons/arrow-bar-left.svg +3 -0
  146. package/icons/arrow-bar-right.svg +3 -0
  147. package/icons/arrow-bar-up.svg +3 -0
  148. package/icons/arrow-clockwise.svg +3 -0
  149. package/icons/arrow-down.svg +3 -0
  150. package/icons/arrow-left.svg +3 -0
  151. package/icons/arrow-repeat.svg +3 -0
  152. package/icons/arrow-right.svg +3 -0
  153. package/icons/arrow-up.svg +3 -0
  154. package/icons/bank-fill.svg +3 -0
  155. package/icons/bell-slash.svg +3 -0
  156. package/icons/bell.svg +3 -0
  157. package/icons/bi-funnel.svg +3 -0
  158. package/icons/bookmark-fill.svg +3 -0
  159. package/icons/bookmark.svg +3 -0
  160. package/icons/box-arrow-up-right.svg +3 -0
  161. package/icons/box-seam.svg +3 -0
  162. package/icons/building.svg +3 -0
  163. package/icons/calculator.svg +3 -0
  164. package/icons/calendar-check.svg +4 -0
  165. package/icons/calendar-x.svg +4 -0
  166. package/icons/calendar.svg +3 -0
  167. package/icons/camera.svg +3 -0
  168. package/icons/chat-left-text.svg +3 -0
  169. package/icons/check-circle-fill.svg +3 -0
  170. package/icons/check-circle.svg +3 -0
  171. package/icons/check.svg +3 -0
  172. package/icons/chevron-down.svg +3 -0
  173. package/icons/chevron-left.svg +3 -0
  174. package/icons/chevron-right.svg +3 -0
  175. package/icons/chevron-up .svg +3 -0
  176. package/icons/clock.svg +4 -0
  177. package/icons/cloud-check.svg +4 -0
  178. package/icons/cloud-download.svg +3 -0
  179. package/icons/cloud-upload.svg +3 -0
  180. package/icons/cloud.svg +3 -0
  181. package/icons/compass.svg +4 -0
  182. package/icons/cross.svg +3 -0
  183. package/icons/cursor-fill.svg +3 -0
  184. package/icons/cursor.svg +3 -0
  185. package/icons/dash-circle.svg +3 -0
  186. package/icons/dash-square.svg +3 -0
  187. package/icons/dash.svg +3 -0
  188. package/icons/download.svg +3 -0
  189. package/icons/exclamation-circle-fill.svg +3 -0
  190. package/icons/exclamation-circle.svg +4 -0
  191. package/icons/exclamation-triangle-fill.svg +3 -0
  192. package/icons/exclamation-triangle.svg +4 -0
  193. package/icons/exclamation.svg +4 -0
  194. package/icons/eye-fill.svg +3 -0
  195. package/icons/eye-slash-fill.svg +4 -0
  196. package/icons/eye-slash.svg +3 -0
  197. package/icons/eye.svg +3 -0
  198. package/icons/facebook.svg +3 -0
  199. package/icons/file-earmark-text.svg +3 -0
  200. package/icons/file-pdf.svg +4 -0
  201. package/icons/file-plus.svg +4 -0
  202. package/icons/file-text.svg +3 -0
  203. package/icons/file.svg +3 -0
  204. package/icons/files.svg +4 -0
  205. package/icons/folder-check.svg +4 -0
  206. package/icons/folder-minus.svg +4 -0
  207. package/icons/folder-plus.svg +4 -0
  208. package/icons/folder.svg +3 -0
  209. package/icons/gear.svg +3 -0
  210. package/icons/geo-alt.svg +4 -0
  211. package/icons/geo-fill.svg +4 -0
  212. package/icons/geo.svg +4 -0
  213. package/icons/google.svg +3 -0
  214. package/icons/grid-fill.svg +3 -0
  215. package/icons/hand-thumbs-down.svg +3 -0
  216. package/icons/hand-thumbs-up.svg +3 -0
  217. package/icons/hdd.svg +3 -0
  218. package/icons/house-door.svg +3 -0
  219. package/icons/house.svg +3 -0
  220. package/icons/image.svg +3 -0
  221. package/icons/inbox.svg +3 -0
  222. package/icons/info-circle-fill.svg +3 -0
  223. package/icons/info-circle.svg +4 -0
  224. package/icons/instagram.svg +3 -0
  225. package/icons/layers.svg +3 -0
  226. package/icons/layout-text-window-reverse.svg +3 -0
  227. package/icons/layout-text-window.svg +3 -0
  228. package/icons/layout.svg +3 -0
  229. package/icons/link.svg +3 -0
  230. package/icons/linkedin.svg +3 -0
  231. package/icons/list.svg +3 -0
  232. package/icons/lock-fill.svg +3 -0
  233. package/icons/lock.svg +3 -0
  234. package/icons/mail.svg +3 -0
  235. package/icons/map.svg +3 -0
  236. package/icons/paperclip.svg +3 -0
  237. package/icons/pencil.svg +3 -0
  238. package/icons/pending-circle.svg +3 -0
  239. package/icons/person-dash.svg +3 -0
  240. package/icons/person-plus.svg +3 -0
  241. package/icons/person-x.svg +3 -0
  242. package/icons/person.svg +3 -0
  243. package/icons/pin-map-fill.svg +3 -0
  244. package/icons/pin.svg +3 -0
  245. package/icons/placeholder.svg +3 -0
  246. package/icons/plus-circle.svg +3 -0
  247. package/icons/plus-square.svg +3 -0
  248. package/icons/plus.svg +3 -0
  249. package/icons/printer.svg +3 -0
  250. package/icons/question-circle.svg +4 -0
  251. package/icons/save.svg +3 -0
  252. package/icons/search.svg +3 -0
  253. package/icons/share.svg +3 -0
  254. package/icons/slash-circle.svg +3 -0
  255. package/icons/sliders.svg +3 -0
  256. package/icons/speedometer.svg +3 -0
  257. package/icons/star-fill.svg +3 -0
  258. package/icons/star.svg +3 -0
  259. package/icons/stoplights.svg +4 -0
  260. package/icons/telephone.svg +3 -0
  261. package/icons/three-dots-vertical.svg +3 -0
  262. package/icons/three-dots.svg +3 -0
  263. package/icons/toggle-off.svg +3 -0
  264. package/icons/toggle-on.svg +3 -0
  265. package/icons/trash.svg +3 -0
  266. package/icons/twitter-x.svg +3 -0
  267. package/icons/unlock.svg +3 -0
  268. package/icons/upload.svg +3 -0
  269. package/icons/window-dash.svg +4 -0
  270. package/icons/window-desktop.svg +4 -0
  271. package/icons/window-dock.svg +4 -0
  272. package/icons/window-fullscreen.svg +3 -0
  273. package/icons/window-plus.svg +4 -0
  274. package/icons/window-sidebar.svg +3 -0
  275. package/icons/window-split.svg +3 -0
  276. package/icons/window-stack.svg +3 -0
  277. package/icons/window-x.svg +4 -0
  278. package/icons/window.svg +3 -0
  279. package/icons/x-circle-fill.svg +3 -0
  280. package/icons/x-circle.svg +3 -0
  281. package/icons/youtube.svg +3 -0
  282. package/icons/zoom-in.svg +3 -0
  283. package/icons/zoom-out.svg +3 -0
  284. package/index.d.ts +1 -0
  285. package/index.js +1 -0
  286. package/index.js.map +1 -1
  287. package/index.umd.js +1340 -1121
  288. package/index.umd.js.map +1 -1
  289. package/internals/CloseButton/close-button.js +1 -1
  290. package/internals/CloseButton/sgds-close-button.js +1 -1
  291. package/internals/CloseButton/sgds-close-button.js.map +1 -1
  292. package/package.json +1 -1
  293. package/react/base/button.cjs.js +1 -1
  294. package/react/base/button.js +1 -1
  295. package/react/base/form-control-element.cjs.js +13 -23
  296. package/react/base/form-control-element.cjs.js.map +1 -1
  297. package/react/base/form-control-element.js +13 -23
  298. package/react/base/form-control-element.js.map +1 -1
  299. package/react/checkbox/index.cjs.js +2 -0
  300. package/react/checkbox/index.cjs.js.map +1 -1
  301. package/react/checkbox/index.d.ts +2 -0
  302. package/react/checkbox/index.js +2 -0
  303. package/react/checkbox/index.js.map +1 -1
  304. package/react/components/Accordion/accordion-item.cjs.js +1 -1
  305. package/react/components/Accordion/accordion-item.js +1 -1
  306. package/react/components/Accordion/sgds-accordion-item.cjs.js +6 -18
  307. package/react/components/Accordion/sgds-accordion-item.cjs.js.map +1 -1
  308. package/react/components/Accordion/sgds-accordion-item.js +6 -18
  309. package/react/components/Accordion/sgds-accordion-item.js.map +1 -1
  310. package/react/components/Alert/alert.cjs.js +1 -1
  311. package/react/components/Alert/alert.js +1 -1
  312. package/react/components/Alert/sgds-alert.cjs.js +5 -12
  313. package/react/components/Alert/sgds-alert.cjs.js.map +1 -1
  314. package/react/components/Alert/sgds-alert.js +6 -13
  315. package/react/components/Alert/sgds-alert.js.map +1 -1
  316. package/react/components/Badge/badge.cjs.js +1 -1
  317. package/react/components/Badge/badge.js +1 -1
  318. package/react/components/Badge/sgds-badge.cjs.js +6 -7
  319. package/react/components/Badge/sgds-badge.cjs.js.map +1 -1
  320. package/react/components/Badge/sgds-badge.js +6 -7
  321. package/react/components/Badge/sgds-badge.js.map +1 -1
  322. package/react/components/Button/sgds-button.cjs.js +2 -2
  323. package/react/components/Button/sgds-button.cjs.js.map +1 -1
  324. package/react/components/Button/sgds-button.js +1 -1
  325. package/react/components/Button/sgds-button.js.map +1 -1
  326. package/react/components/Checkbox/checkbox.cjs.js +1 -1
  327. package/react/components/Checkbox/checkbox.js +1 -1
  328. package/react/components/Checkbox/sgds-checkbox-group.cjs.js +15 -4
  329. package/react/components/Checkbox/sgds-checkbox-group.cjs.js.map +1 -1
  330. package/react/components/Checkbox/sgds-checkbox-group.js +15 -4
  331. package/react/components/Checkbox/sgds-checkbox-group.js.map +1 -1
  332. package/react/components/Checkbox/sgds-checkbox.cjs.js +77 -60
  333. package/react/components/Checkbox/sgds-checkbox.cjs.js.map +1 -1
  334. package/react/components/Checkbox/sgds-checkbox.js +77 -60
  335. package/react/components/Checkbox/sgds-checkbox.js.map +1 -1
  336. package/react/components/Datepicker/datepicker-input.cjs.js +24 -7
  337. package/react/components/Datepicker/datepicker-input.cjs.js.map +1 -1
  338. package/react/components/Datepicker/datepicker-input.js +24 -7
  339. package/react/components/Datepicker/datepicker-input.js.map +1 -1
  340. package/react/components/Datepicker/sgds-datepicker.cjs.js.map +1 -1
  341. package/react/components/Datepicker/sgds-datepicker.js.map +1 -1
  342. package/react/components/FileUpload/file-upload.cjs.js +1 -1
  343. package/react/components/FileUpload/file-upload.js +1 -1
  344. package/react/components/FileUpload/sgds-file-upload.cjs.js +145 -101
  345. package/react/components/FileUpload/sgds-file-upload.cjs.js.map +1 -1
  346. package/react/components/FileUpload/sgds-file-upload.js +147 -103
  347. package/react/components/FileUpload/sgds-file-upload.js.map +1 -1
  348. package/react/components/Footer/footer-item.cjs.js +11 -0
  349. package/react/components/Footer/footer-item.cjs.js.map +1 -0
  350. package/react/components/Footer/footer-item.js +7 -0
  351. package/react/components/Footer/footer-item.js.map +1 -0
  352. package/react/components/Footer/footer.cjs.js +1 -1
  353. package/react/components/Footer/footer.js +1 -1
  354. package/react/components/Footer/sgds-footer-item.cjs.js +33 -0
  355. package/react/components/Footer/sgds-footer-item.cjs.js.map +1 -0
  356. package/react/components/Footer/sgds-footer-item.js +28 -0
  357. package/react/components/Footer/sgds-footer-item.js.map +1 -0
  358. package/react/components/Footer/sgds-footer.cjs.js +65 -90
  359. package/react/components/Footer/sgds-footer.cjs.js.map +1 -1
  360. package/react/components/Footer/sgds-footer.js +65 -90
  361. package/react/components/Footer/sgds-footer.js.map +1 -1
  362. package/react/components/Icon/icon.cjs.js +11 -0
  363. package/react/components/Icon/icon.cjs.js.map +1 -0
  364. package/react/components/Icon/icon.js +7 -0
  365. package/react/components/Icon/icon.js.map +1 -0
  366. package/react/components/Icon/sgds-icon.cjs.js +70 -0
  367. package/react/components/Icon/sgds-icon.cjs.js.map +1 -0
  368. package/react/components/Icon/sgds-icon.js +65 -0
  369. package/react/components/Icon/sgds-icon.js.map +1 -0
  370. package/react/components/IconButton/icon-button.cjs.js +1 -1
  371. package/react/components/IconButton/icon-button.js +1 -1
  372. package/react/components/IconButton/sgds-icon-button.cjs.js +4 -9
  373. package/react/components/IconButton/sgds-icon-button.cjs.js.map +1 -1
  374. package/react/components/IconButton/sgds-icon-button.js +4 -9
  375. package/react/components/IconButton/sgds-icon-button.js.map +1 -1
  376. package/react/components/Input/sgds-input.cjs.js +101 -64
  377. package/react/components/Input/sgds-input.cjs.js.map +1 -1
  378. package/react/components/Input/sgds-input.js +103 -66
  379. package/react/components/Input/sgds-input.js.map +1 -1
  380. package/react/components/Masthead/masthead.cjs.js +1 -1
  381. package/react/components/Masthead/masthead.js +1 -1
  382. package/react/components/QuantityToggle/sgds-quantity-toggle.cjs.js +128 -61
  383. package/react/components/QuantityToggle/sgds-quantity-toggle.cjs.js.map +1 -1
  384. package/react/components/QuantityToggle/sgds-quantity-toggle.js +129 -62
  385. package/react/components/QuantityToggle/sgds-quantity-toggle.js.map +1 -1
  386. package/react/components/Radio/sgds-radio-group.cjs.js +99 -83
  387. package/react/components/Radio/sgds-radio-group.cjs.js.map +1 -1
  388. package/react/components/Radio/sgds-radio-group.js +100 -84
  389. package/react/components/Radio/sgds-radio-group.js.map +1 -1
  390. package/react/components/Radio/sgds-radio.cjs.js +1 -1
  391. package/react/components/Radio/sgds-radio.cjs.js.map +1 -1
  392. package/react/components/Radio/sgds-radio.js +1 -1
  393. package/react/components/Radio/sgds-radio.js.map +1 -1
  394. package/react/components/Stepper/sgds-stepper.cjs.js +1 -0
  395. package/react/components/Stepper/sgds-stepper.cjs.js.map +1 -1
  396. package/react/components/Stepper/sgds-stepper.js +1 -0
  397. package/react/components/Stepper/sgds-stepper.js.map +1 -1
  398. package/react/components/Stepper/stepper.cjs.js +1 -1
  399. package/react/components/Stepper/stepper.js +1 -1
  400. package/react/components/Switch/sgds-switch.cjs.js +1 -2
  401. package/react/components/Switch/sgds-switch.cjs.js.map +1 -1
  402. package/react/components/Switch/sgds-switch.js +1 -2
  403. package/react/components/Switch/sgds-switch.js.map +1 -1
  404. package/react/components/Textarea/sgds-textarea.cjs.js +76 -73
  405. package/react/components/Textarea/sgds-textarea.cjs.js.map +1 -1
  406. package/react/components/Textarea/sgds-textarea.js +78 -75
  407. package/react/components/Textarea/sgds-textarea.js.map +1 -1
  408. package/react/components/Textarea/textarea.cjs.js +1 -1
  409. package/react/components/Textarea/textarea.js +1 -1
  410. package/react/components/Toast/sgds-toast.cjs.js +6 -18
  411. package/react/components/Toast/sgds-toast.cjs.js.map +1 -1
  412. package/react/components/Toast/sgds-toast.js +6 -18
  413. package/react/components/Toast/sgds-toast.js.map +1 -1
  414. package/react/components/Toast/toast.cjs.js +1 -1
  415. package/react/components/Toast/toast.js +1 -1
  416. package/react/components/Tooltip/sgds-tooltip.cjs.js +14 -14
  417. package/react/components/Tooltip/sgds-tooltip.cjs.js.map +1 -1
  418. package/react/components/Tooltip/sgds-tooltip.js +14 -14
  419. package/react/components/Tooltip/sgds-tooltip.js.map +1 -1
  420. package/react/footer-item/index.cjs.js +39 -0
  421. package/react/footer-item/index.cjs.js.map +1 -0
  422. package/react/footer-item/index.d.ts +3 -0
  423. package/react/footer-item/index.js +15 -0
  424. package/react/footer-item/index.js.map +1 -0
  425. package/react/icon/index.cjs.js +42 -0
  426. package/react/icon/index.cjs.js.map +1 -0
  427. package/react/icon/index.d.ts +6 -0
  428. package/react/icon/index.js +18 -0
  429. package/react/icon/index.js.map +1 -0
  430. package/react/index.cjs.js +64 -60
  431. package/react/index.cjs.js.map +1 -1
  432. package/react/index.d.ts +2 -0
  433. package/react/index.js +2 -0
  434. package/react/index.js.map +1 -1
  435. package/react/input/index.cjs.js +3 -1
  436. package/react/input/index.cjs.js.map +1 -1
  437. package/react/input/index.d.ts +2 -0
  438. package/react/input/index.js +3 -1
  439. package/react/input/index.js.map +1 -1
  440. package/react/internals/CloseButton/close-button.cjs.js +1 -1
  441. package/react/internals/CloseButton/close-button.js +1 -1
  442. package/react/internals/CloseButton/sgds-close-button.cjs.js +1 -1
  443. package/react/internals/CloseButton/sgds-close-button.cjs.js.map +1 -1
  444. package/react/internals/CloseButton/sgds-close-button.js +1 -1
  445. package/react/internals/CloseButton/sgds-close-button.js.map +1 -1
  446. package/react/styles/form-hint.cjs.js +1 -1
  447. package/react/styles/form-hint.js +1 -1
  448. package/react/styles/form-label.cjs.js +1 -1
  449. package/react/styles/form-label.js +1 -1
  450. package/react/utils/formSubmitController.cjs.js +64 -0
  451. package/react/utils/formSubmitController.cjs.js.map +1 -0
  452. package/react/utils/formSubmitController.js +60 -0
  453. package/react/utils/formSubmitController.js.map +1 -0
  454. package/react/utils/inputValidationController.cjs.js +130 -0
  455. package/react/utils/inputValidationController.cjs.js.map +1 -0
  456. package/react/utils/inputValidationController.js +126 -0
  457. package/react/utils/inputValidationController.js.map +1 -0
  458. package/react/utils/validatorMixin.cjs.js +108 -0
  459. package/react/utils/validatorMixin.cjs.js.map +1 -0
  460. package/react/utils/validatorMixin.js +104 -0
  461. package/react/utils/validatorMixin.js.map +1 -0
  462. package/styles/form-hint.js +1 -1
  463. package/styles/form-label.js +1 -1
  464. package/themes/day.css +1 -1
  465. package/themes/night.css +3 -2
  466. package/themes/root.css +2 -0
  467. package/utils/{form.d.ts → formSubmitController.d.ts} +10 -20
  468. package/utils/formSubmitController.js +59 -0
  469. package/utils/formSubmitController.js.map +1 -0
  470. package/utils/inputValidationController.d.ts +70 -0
  471. package/utils/inputValidationController.js +125 -0
  472. package/utils/inputValidationController.js.map +1 -0
  473. package/utils/validatorMixin.d.ts +24 -0
  474. package/utils/validatorMixin.js +103 -0
  475. package/utils/validatorMixin.js.map +1 -0
  476. package/base/form-check-element.d.ts +0 -50
  477. package/base/form-check-element.js +0 -169
  478. package/base/form-check-element.js.map +0 -1
  479. package/css/body.css +0 -28
  480. package/css/caption.css +0 -7
  481. package/css/label.css +0 -28
  482. package/react/base/form-check-element.cjs.js +0 -175
  483. package/react/base/form-check-element.cjs.js.map +0 -1
  484. package/react/base/form-check-element.js +0 -170
  485. package/react/base/form-check-element.js.map +0 -1
  486. package/react/utils/form.cjs.js +0 -137
  487. package/react/utils/form.cjs.js.map +0 -1
  488. package/react/utils/form.js +0 -133
  489. package/react/utils/form.js.map +0 -1
  490. package/utils/form.js +0 -132
  491. package/utils/form.js.map +0 -1
@@ -30,6 +30,270 @@
30
30
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
31
31
  };
32
32
 
33
+ const appliedClassMixins = new WeakMap();
34
+
35
+ /** Vefify if the Mixin was previously applyed
36
+ * @private
37
+ * @param {function} mixin Mixin being applyed
38
+ * @param {object} superClass Class receiving the new mixin
39
+ * @returns {boolean}
40
+ */
41
+ function wasMixinPreviouslyApplied(mixin, superClass) {
42
+ let klass = superClass;
43
+ while (klass) {
44
+ if (appliedClassMixins.get(klass) === mixin) {
45
+ return true;
46
+ }
47
+ klass = Object.getPrototypeOf(klass);
48
+ }
49
+ return false;
50
+ }
51
+
52
+ /** Apply each mixin in the chain to make sure they are not applied more than once to the final class.
53
+ * @export
54
+ * @param {function} mixin Mixin to be applyed
55
+ * @returns {object} Mixed class with mixin applied
56
+ */
57
+ function dedupeMixin(mixin) {
58
+ return superClass => {
59
+ if (wasMixinPreviouslyApplied(mixin, superClass)) {
60
+ return superClass;
61
+ }
62
+ const mixedClass = mixin(superClass);
63
+ appliedClassMixins.set(mixedClass, mixin);
64
+ return mixedClass;
65
+ };
66
+ }
67
+
68
+ /**
69
+ * @license
70
+ * Copyright 2019 Google LLC
71
+ * SPDX-License-Identifier: BSD-3-Clause
72
+ */
73
+ const global$5 = window;
74
+ /**
75
+ * Whether the current browser supports `adoptedStyleSheets`.
76
+ */
77
+ const supportsAdoptingStyleSheets$2 = global$5.ShadowRoot &&
78
+ (global$5.ShadyCSS === undefined || global$5.ShadyCSS.nativeShadow) &&
79
+ 'adoptedStyleSheets' in Document.prototype &&
80
+ 'replace' in CSSStyleSheet.prototype;
81
+ /**
82
+ * Applies the given styles to a `shadowRoot`. When Shadow DOM is
83
+ * available but `adoptedStyleSheets` is not, styles are appended to the
84
+ * `shadowRoot` to [mimic spec behavior](https://wicg.github.io/construct-stylesheets/#using-constructed-stylesheets).
85
+ * Note, when shimming is used, any styles that are subsequently placed into
86
+ * the shadowRoot should be placed *before* any shimmed adopted styles. This
87
+ * will match spec behavior that gives adopted sheets precedence over styles in
88
+ * shadowRoot.
89
+ */
90
+ const adoptStyles$2 = (renderRoot, styles) => {
91
+ if (supportsAdoptingStyleSheets$2) {
92
+ renderRoot.adoptedStyleSheets = styles.map((s) => s instanceof CSSStyleSheet ? s : s.styleSheet);
93
+ }
94
+ else {
95
+ styles.forEach((s) => {
96
+ const style = document.createElement('style');
97
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
98
+ const nonce = global$5['litNonce'];
99
+ if (nonce !== undefined) {
100
+ style.setAttribute('nonce', nonce);
101
+ }
102
+ style.textContent = s.cssText;
103
+ renderRoot.appendChild(style);
104
+ });
105
+ }
106
+ };
107
+
108
+ /**
109
+ * @typedef {import('./types').RenderOptions} RenderOptions
110
+ * @typedef {import('./types').ScopedElementsMixin} ScopedElementsMixin
111
+ * @typedef {import('./types').ScopedElementsHost} ScopedElementsHost
112
+ * @typedef {import('./types').ScopedElementsMap} ScopedElementsMap
113
+ * @typedef {import('@lit/reactive-element').CSSResultOrNative} CSSResultOrNative
114
+ */
115
+
116
+ // @ts-ignore
117
+ const supportsScopedRegistry = !!ShadowRoot.prototype.createElement;
118
+
119
+ /**
120
+ * @template {import('./types').Constructor<HTMLElement>} T
121
+ * @param {T} superclass
122
+ * @return {T & import('./types').Constructor<ScopedElementsHost>}
123
+ */
124
+ const ScopedElementsMixinImplementation = superclass =>
125
+ /** @type {ScopedElementsHost} */
126
+ class ScopedElementsHost extends superclass {
127
+ /**
128
+ * Obtains the scoped elements definitions map if specified.
129
+ *
130
+ * @returns {ScopedElementsMap}
131
+ */
132
+ static get scopedElements() {
133
+ return {};
134
+ }
135
+
136
+ /**
137
+ * Obtains the ShadowRoot options.
138
+ *
139
+ * @type {ShadowRootInit}
140
+ */
141
+ static get shadowRootOptions() {
142
+ return this.__shadowRootOptions;
143
+ }
144
+
145
+ /**
146
+ * Set the shadowRoot options.
147
+ *
148
+ * @param {ShadowRootInit} value
149
+ */
150
+ static set shadowRootOptions(value) {
151
+ this.__shadowRootOptions = value;
152
+ }
153
+
154
+ /**
155
+ * Obtains the element styles.
156
+ *
157
+ * @returns {CSSResultOrNative[]}
158
+ */
159
+ static get elementStyles() {
160
+ return this.__elementStyles;
161
+ }
162
+
163
+ static set elementStyles(styles) {
164
+ this.__elementStyles = styles;
165
+ }
166
+
167
+ // either TS or ESLint will complain here
168
+ // eslint-disable-next-line no-unused-vars
169
+ constructor(..._args) {
170
+ super();
171
+ /** @type {RenderOptions} */
172
+ this.renderOptions = this.renderOptions || undefined;
173
+ }
174
+
175
+ /**
176
+ * Obtains the CustomElementRegistry associated to the ShadowRoot.
177
+ *
178
+ * @returns {CustomElementRegistry}
179
+ */
180
+ get registry() {
181
+ // @ts-ignore
182
+ return this.constructor.__registry;
183
+ }
184
+
185
+ /**
186
+ * Set the CustomElementRegistry associated to the ShadowRoot
187
+ *
188
+ * @param {CustomElementRegistry} registry
189
+ */
190
+ set registry(registry) {
191
+ // @ts-ignore
192
+ this.constructor.__registry = registry;
193
+ }
194
+
195
+ createRenderRoot() {
196
+ const { scopedElements, shadowRootOptions, elementStyles } =
197
+ /** @type {typeof ScopedElementsHost} */ (this.constructor);
198
+
199
+ const shouldCreateRegistry =
200
+ !this.registry ||
201
+ // @ts-ignore
202
+ (this.registry === this.constructor.__registry &&
203
+ !Object.prototype.hasOwnProperty.call(this.constructor, '__registry'));
204
+
205
+ /**
206
+ * Create a new registry if:
207
+ * - the registry is not defined
208
+ * - this class doesn't have its own registry *AND* has no shared registry
209
+ */
210
+ if (shouldCreateRegistry) {
211
+ this.registry = supportsScopedRegistry ? new CustomElementRegistry() : customElements;
212
+ for (const [tagName, klass] of Object.entries(scopedElements)) {
213
+ this.defineScopedElement(tagName, klass);
214
+ }
215
+ }
216
+
217
+ /** @type {ShadowRootInit} */
218
+ const options = {
219
+ mode: 'open',
220
+ ...shadowRootOptions,
221
+ customElements: this.registry,
222
+ };
223
+
224
+ const createdRoot = this.attachShadow(options);
225
+ if (supportsScopedRegistry) {
226
+ this.renderOptions.creationScope = createdRoot;
227
+ }
228
+
229
+ if (createdRoot instanceof ShadowRoot) {
230
+ adoptStyles$2(createdRoot, elementStyles);
231
+ this.renderOptions.renderBefore = this.renderOptions.renderBefore || createdRoot.firstChild;
232
+ }
233
+
234
+ return createdRoot;
235
+ }
236
+
237
+ createScopedElement(tagName) {
238
+ const root = supportsScopedRegistry ? this.shadowRoot : document;
239
+ // @ts-ignore polyfill to support createElement on shadowRoot is loaded
240
+ return root.createElement(tagName);
241
+ }
242
+
243
+ /**
244
+ * Defines a scoped element.
245
+ *
246
+ * @param {string} tagName
247
+ * @param {typeof HTMLElement} klass
248
+ */
249
+ defineScopedElement(tagName, klass) {
250
+ const registeredClass = this.registry.get(tagName);
251
+ if (registeredClass && supportsScopedRegistry === false && registeredClass !== klass) {
252
+ // eslint-disable-next-line no-console
253
+ console.error(
254
+ [
255
+ `You are trying to re-register the "${tagName}" custom element with a different class via ScopedElementsMixin.`,
256
+ 'This is only possible with a CustomElementRegistry.',
257
+ 'Your browser does not support this feature so you will need to load a polyfill for it.',
258
+ 'Load "@webcomponents/scoped-custom-element-registry" before you register ANY web component to the global customElements registry.',
259
+ 'e.g. add "<script src="/node_modules/@webcomponents/scoped-custom-element-registry/scoped-custom-element-registry.min.js"></script>" as your first script tag.',
260
+ 'For more details you can visit https://open-wc.org/docs/development/scoped-elements/',
261
+ ].join('\n'),
262
+ );
263
+ }
264
+ if (!registeredClass) {
265
+ return this.registry.define(tagName, klass);
266
+ }
267
+ return this.registry.get(tagName);
268
+ }
269
+
270
+ /**
271
+ * @deprecated use the native el.tagName instead
272
+ *
273
+ * @param {string} tagName
274
+ * @returns {string} the tag name
275
+ */
276
+ // eslint-disable-next-line class-methods-use-this
277
+ getScopedTagName(tagName) {
278
+ // @ts-ignore
279
+ return this.constructor.getScopedTagName(tagName);
280
+ }
281
+
282
+ /**
283
+ * @deprecated use the native el.tagName instead
284
+ *
285
+ * @param {string} tagName
286
+ * @returns {string} the tag name
287
+ */
288
+ // eslint-disable-next-line class-methods-use-this
289
+ static getScopedTagName(tagName) {
290
+ // @ts-ignore
291
+ return this.__registry.get(tagName) ? tagName : undefined;
292
+ }
293
+ };
294
+
295
+ const ScopedElementsMixin = dedupeMixin(ScopedElementsMixinImplementation);
296
+
33
297
  /**
34
298
  * @license
35
299
  * Copyright 2019 Google LLC
@@ -1322,6 +1586,32 @@
1322
1586
  };
1323
1587
  }
1324
1588
 
1589
+ /**
1590
+ * @license
1591
+ * Copyright 2017 Google LLC
1592
+ * SPDX-License-Identifier: BSD-3-Clause
1593
+ */
1594
+ /**
1595
+ * Declares a private or protected reactive property that still triggers
1596
+ * updates to the element when it changes. It does not reflect from the
1597
+ * corresponding attribute.
1598
+ *
1599
+ * Properties declared this way must not be used from HTML or HTML templating
1600
+ * systems, they're solely for properties internal to the element. These
1601
+ * properties may be renamed by optimization tools like closure compiler.
1602
+ * @category Decorator
1603
+ */
1604
+ function state(options) {
1605
+ return property({
1606
+ ...options,
1607
+ // Add both `state` and `attribute` because we found a third party
1608
+ // controller that is keying off of PropertyOptions.state to determine
1609
+ // whether a field is a private internal property or not.
1610
+ state: true,
1611
+ attribute: false,
1612
+ });
1613
+ }
1614
+
1325
1615
  /**
1326
1616
  * @license
1327
1617
  * Copyright 2017 Google LLC
@@ -1466,6 +1756,59 @@
1466
1756
  });
1467
1757
  }
1468
1758
 
1759
+ /**
1760
+ * @license
1761
+ * Copyright 2017 Google LLC
1762
+ * SPDX-License-Identifier: BSD-3-Clause
1763
+ */
1764
+ // Note, in the future, we may extend this decorator to support the use case
1765
+ // where the queried element may need to do work to become ready to interact
1766
+ // with (e.g. load some implementation code). If so, we might elect to
1767
+ // add a second argument defining a function that can be run to make the
1768
+ // queried element loaded/updated/ready.
1769
+ /**
1770
+ * A property decorator that converts a class property into a getter that
1771
+ * returns a promise that resolves to the result of a querySelector on the
1772
+ * element's renderRoot done after the element's `updateComplete` promise
1773
+ * resolves. When the queried property may change with element state, this
1774
+ * decorator can be used instead of requiring users to await the
1775
+ * `updateComplete` before accessing the property.
1776
+ *
1777
+ * @param selector A DOMString containing one or more selectors to match.
1778
+ *
1779
+ * See: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
1780
+ *
1781
+ * ```ts
1782
+ * class MyElement {
1783
+ * @queryAsync('#first')
1784
+ * first: Promise<HTMLDivElement>;
1785
+ *
1786
+ * render() {
1787
+ * return html`
1788
+ * <div id="first"></div>
1789
+ * <div id="second"></div>
1790
+ * `;
1791
+ * }
1792
+ * }
1793
+ *
1794
+ * // external usage
1795
+ * async doSomethingWithFirst() {
1796
+ * (await aMyElement.first).doSomething();
1797
+ * }
1798
+ * ```
1799
+ * @category Decorator
1800
+ */
1801
+ function queryAsync(selector) {
1802
+ return ((obj, name) => {
1803
+ return desc(obj, name, {
1804
+ async get() {
1805
+ await this.updateComplete;
1806
+ return this.renderRoot?.querySelector(selector) ?? null;
1807
+ },
1808
+ });
1809
+ });
1810
+ }
1811
+
1469
1812
  /**
1470
1813
  * @license
1471
1814
  * Copyright 2017 Google LLC
@@ -3227,10 +3570,6 @@
3227
3570
  */
3228
3571
  const html = withStatic(html$1);
3229
3572
 
3230
- function genId (componentName = "", elementName = "") {
3231
- return `id-${Math.random().toString().substring(2, 6)}-sgds-${componentName}-${elementName}`;
3232
- }
3233
-
3234
3573
  /**
3235
3574
  * @license
3236
3575
  * Copyright 2019 Google LLC
@@ -4579,15 +4918,15 @@
4579
4918
  `is not recommended.`);
4580
4919
  }
4581
4920
 
4582
- var css_248z$b = css`.invalid-feedback-container{display:flex;gap:var(--sgds-form-gap-sm)}.invalid-feedback{color:var(--sgds-form-danger-color);font-size:var(--sgds-font-size-1);font-weight:var(--sgds-font-weight-regular)}`;
4921
+ var css_248z$c = css`.invalid-feedback-container{display:flex;gap:var(--sgds-form-gap-sm)}.invalid-feedback{color:var(--sgds-form-danger-color);font-size:var(--sgds-font-size-1);font-weight:var(--sgds-font-weight-regular)}`;
4583
4922
 
4584
- var css_248z$a = css`.form-text{color:var(--sgds-form-color-subtle);font-size:var(--sgds-font-size-1)}`;
4923
+ var css_248z$b = css`.form-text{color:var(--sgds-form-color-subtle);font-size:var(--sgds-font-size-1)}.form-text.disabled{opacity:var(--sgds-opacity-50)}`;
4585
4924
 
4586
- var css_248z$9 = css`.form-label{margin-bottom:0}.form-check-label,.form-label{color:var(--sgds-form-color)}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:not-allowed}`;
4925
+ var css_248z$a = css`.form-label{color:var(--sgds-form-color);margin-bottom:0}.form-label.disabled{opacity:var(--sgds-opacity-50)}.form-check-label{color:var(--sgds-form-color)}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:not-allowed}`;
4587
4926
 
4588
- var css_248z$8 = css`.form-control::placeholder{color:var(--sgds-form-color-subtle);font-family:var(--sgds-font-family-brand);font-weight:var(--sgds-font-weight-light);line-height:var(--sgds-line-height-heading)}`;
4927
+ var css_248z$9 = css`.form-control::placeholder{color:var(--sgds-form-color-subtle);font-family:var(--sgds-font-family-brand);font-weight:var(--sgds-font-weight-light);line-height:var(--sgds-line-height-heading)}`;
4589
4928
 
4590
- var css_248z$7 = css`:host{-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);color:var(--sgds-body-color);font-family:var(--sgds-font-family-brand);font-size:var(--sgds-font-size-2);font-weight:var(--sgds-font-weight-regular);line-height:var(--sgds-line-height-heading);margin:0;*,:after,:before{box-sizing:border-box}:disabled{cursor:not-allowed}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}::slotted(a[target=_blank]):after{background-color:currentColor;content:"/";display:inline-block;margin:0 .125rem;-webkit-mask-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-up-right"><path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/><path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/></svg>');mask-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-up-right"><path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/><path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/></svg>');-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;mask-size:73%;-webkit-mask-size:73%;padding:0 .45em}::slotted(a){color:var(--sgds-link);text-decoration:var(--sgds-link-decoration)}::slotted(a:hover){color:var(--sgds-link-hover-color)}::slotted(svg){vertical-align:middle}}`;
4929
+ var css_248z$8 = css`:host{-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);color:var(--sgds-body-color);font-family:var(--sgds-font-family-brand);font-size:var(--sgds-font-size-2);font-weight:var(--sgds-font-weight-regular);line-height:var(--sgds-line-height-heading);margin:0;*,:after,:before{box-sizing:border-box}:disabled{cursor:not-allowed}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}::slotted(a[target=_blank]):after{background-color:currentColor;content:"/";display:inline-block;margin:0 .125rem;-webkit-mask-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-up-right"><path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/><path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/></svg>');mask-image:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-up-right"><path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/><path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/></svg>');-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;mask-size:73%;-webkit-mask-size:73%;padding:0 .45em}::slotted(a){color:var(--sgds-link);text-decoration:var(--sgds-link-decoration)}::slotted(a:hover){color:var(--sgds-link-hover-color)}::slotted(svg){vertical-align:middle}}`;
4591
4930
 
4592
4931
  /**
4593
4932
  * @cssprop --sgds-{stateColor} - State colors in hexadecimal value
@@ -4605,7 +4944,11 @@
4605
4944
  return event;
4606
4945
  }
4607
4946
  }
4608
- SgdsElement.styles = [css_248z$7];
4947
+ SgdsElement.styles = [css_248z$8];
4948
+
4949
+ function generateId (componentName = "", elementName = "") {
4950
+ return `id-${Math.random().toString().substring(2, 6)}-sgds-${componentName}-${elementName}`;
4951
+ }
4609
4952
 
4610
4953
  class FormControlElement extends SgdsElement {
4611
4954
  constructor() {
@@ -4616,18 +4959,23 @@
4616
4959
  this.hintText = "";
4617
4960
  /** Disables the input. */
4618
4961
  this.disabled = false;
4619
- /** Allows invalidFeedback, invalid and valid styles to be visible with the input */
4620
- this.hasFeedback = false;
4621
- /**Feedback text for error state when validated */
4622
- this.invalidFeedback = "";
4623
4962
  /** Marks the component as invalid. Replace the pseudo :invalid selector for absent in custom elements */
4624
4963
  this.invalid = false;
4625
- /** Makes the input a required field. */
4626
- this.required = false;
4627
- this.labelId = genId("label");
4964
+ this._controlId = generateId("input");
4965
+ this._labelId = generateId("label");
4966
+ }
4967
+ /** Programatically sets the invalid state of the input. Pass in boolean value in the argument */
4968
+ setInvalid(bool) {
4969
+ this.invalid = bool;
4970
+ if (bool) {
4971
+ this.emit("sgds-invalid");
4972
+ }
4973
+ else {
4974
+ this.emit("sgds-valid");
4975
+ }
4628
4976
  }
4629
4977
  }
4630
- FormControlElement.styles = [...SgdsElement.styles, css_248z$b, css_248z$a, css_248z$9, css_248z$8];
4978
+ FormControlElement.styles = [...SgdsElement.styles, css_248z$c, css_248z$b, css_248z$a, css_248z$9];
4631
4979
  __decorate([
4632
4980
  property({ reflect: true })
4633
4981
  ], FormControlElement.prototype, "label", void 0);
@@ -4640,24 +4988,11 @@
4640
4988
  __decorate([
4641
4989
  property({ type: Boolean, reflect: true })
4642
4990
  ], FormControlElement.prototype, "disabled", void 0);
4643
- __decorate([
4644
- property()
4645
- ], FormControlElement.prototype, "min", void 0);
4646
- __decorate([
4647
- property()
4648
- ], FormControlElement.prototype, "max", void 0);
4649
- __decorate([
4650
- property({ type: Boolean, reflect: true })
4651
- ], FormControlElement.prototype, "hasFeedback", void 0);
4652
- __decorate([
4653
- property({ type: String, reflect: true })
4654
- ], FormControlElement.prototype, "invalidFeedback", void 0);
4655
4991
  __decorate([
4656
4992
  property({ type: Boolean, reflect: true })
4657
4993
  ], FormControlElement.prototype, "invalid", void 0);
4658
- __decorate([
4659
- property({ type: Boolean, reflect: true })
4660
- ], FormControlElement.prototype, "required", void 0);
4994
+
4995
+ var css_248z$7 = css`svg{vertical-align:middle}`;
4661
4996
 
4662
4997
  // @defaultValue decorator
4663
4998
  const defaultValue = (propertyName = "value") => (proto, key) => {
@@ -4679,137 +5014,227 @@
4679
5014
  };
4680
5015
  };
4681
5016
 
4682
- const reportValidityOverloads = new WeakMap();
4683
- class FormSubmitController {
5017
+ /**
5018
+ * SGDS custom form validation methods and behaviours
5019
+ */
5020
+ class InputValidationController {
4684
5021
  constructor(host, options) {
4685
5022
  (this.host = host).addController(this);
4686
- this.options = Object.assign({ form: (input) => {
4687
- return input.closest("form");
4688
- }, name: (input) => input.name, value: (input) => input.value, defaultValue: (input) => input.defaultValue, disabled: (input) => input.disabled, reportValidity: (input) => {
4689
- return typeof input.reportValidity === "function" ? input.reportValidity() : true;
4690
- }, setValue: (input, value) => {
4691
- input.value = value;
4692
- } }, options);
4693
- this.handleFormData = this.handleFormData.bind(this);
4694
- this.handleFormSubmit = this.handleFormSubmit.bind(this);
4695
- this.handleFormReset = this.handleFormReset.bind(this);
4696
- this.reportFormValidity = this.reportFormValidity.bind(this);
5023
+ this._internals = this.host.attachInternals();
5024
+ this.options = Object.assign({ setInvalid: (host, value) => {
5025
+ host.invalid = value;
5026
+ }, value: (host) => {
5027
+ return host.value;
5028
+ }, input: (host) => host.input }, options);
4697
5029
  }
4698
5030
  hostConnected() {
4699
- this.form = this.options.form(this.host);
4700
- if (this.form) {
4701
- this.form.addEventListener("formdata", this.handleFormData);
4702
- this.form.addEventListener("submit", this.handleFormSubmit);
4703
- this.form.addEventListener("reset", this.handleFormReset);
4704
- // Overload the form's reportValidity() method so it looks at Shoelace form controls
4705
- if (!reportValidityOverloads.has(this.form)) {
4706
- reportValidityOverloads.set(this.form, this.form.reportValidity);
4707
- this.form.reportValidity = () => this.reportFormValidity();
4708
- }
4709
- }
5031
+ this.host.addEventListener("invalid", e => this.handleInvalid(e));
4710
5032
  }
4711
5033
  hostDisconnected() {
4712
- if (this.form) {
4713
- this.form.removeEventListener("formdata", this.handleFormData);
4714
- this.form.removeEventListener("submit", this.handleFormSubmit);
4715
- this.form.removeEventListener("reset", this.handleFormReset);
4716
- // Remove the overload and restore the original method
4717
- if (reportValidityOverloads.has(this.form)) {
4718
- this.form.reportValidity = reportValidityOverloads.get(this.form);
4719
- reportValidityOverloads.delete(this.form);
4720
- }
4721
- this.form = undefined;
4722
- }
5034
+ this.host.removeEventListener("invalid", e => this.handleInvalid(e));
5035
+ }
5036
+ /**
5037
+ * Prevents the native browser error message pop up when reportValidity() called by
5038
+ * associated form or the component's reportValidity during constraint validation
5039
+ * Sets invalid reactive prop to true
5040
+ */
5041
+ handleInvalid(e) {
5042
+ e.preventDefault();
5043
+ this.options.setInvalid(this.host, true);
5044
+ }
5045
+ /**
5046
+ * Sets invalid to false when invoked and
5047
+ * Updates the ValidityState based on new value, but
5048
+ * does not update invalid reactive prop
5049
+ * @param e
5050
+ */
5051
+ handleInput(e) {
5052
+ const input = e.target;
5053
+ this.options.setInvalid(this.host, false);
5054
+ this.validateInput(input);
5055
+ }
5056
+ /**
5057
+ * Validate the input's new value after onChange and
5058
+ * update invalid reactive prop
5059
+ * @param e
5060
+ */
5061
+ handleChange(e) {
5062
+ const input = e.target;
5063
+ this.validateInput(input);
5064
+ this.options.setInvalid(this.host, !this.checkValidity());
5065
+ }
5066
+ get form() {
5067
+ return this._internals.form;
5068
+ }
5069
+ get validity() {
5070
+ return this._internals.validity;
5071
+ }
5072
+ get validationMessage() {
5073
+ return this._internals.validationMessage;
5074
+ }
5075
+ get willValidate() {
5076
+ return this._internals.willValidate;
5077
+ }
5078
+ /**
5079
+ * Checks the validity and updates the invalid reactive prop of form components
5080
+ */
5081
+ updateInvalidState() {
5082
+ this.options.setInvalid(this.host, !this.checkValidity());
5083
+ }
5084
+ /**
5085
+ * Resets the ValidityState of the control
5086
+ */
5087
+ resetValidity() {
5088
+ return this._internals.setValidity({});
4723
5089
  }
4724
- handleFormData(event) {
4725
- const disabled = this.options.disabled(this.host);
4726
- const name = this.options.name(this.host);
5090
+ /**
5091
+ * Reports the validity
5092
+ */
5093
+ checkValidity() {
5094
+ return this._internals.checkValidity();
5095
+ }
5096
+ /**
5097
+ * Reports the validity with a error popup message
5098
+ */
5099
+ reportValidity() {
5100
+ return this._internals.reportValidity();
5101
+ }
5102
+ /**
5103
+ * Sets the form control value into FormData,
5104
+ * making the value of control accessible via FormData
5105
+ */
5106
+ setFormValue() {
4727
5107
  const value = this.options.value(this.host);
4728
- if (!disabled && typeof name === "string" && typeof value !== "undefined") {
4729
- if (Array.isArray(value)) {
4730
- value.forEach(val => {
4731
- event.formData.append(name, val.toString());
4732
- });
4733
- }
4734
- else {
4735
- event.formData.append(name, value.toString());
4736
- }
4737
- }
5108
+ this._internals.setFormValue(value);
4738
5109
  }
4739
- handleFormSubmit(event) {
4740
- const disabled = this.options.disabled(this.host);
4741
- const reportValidity = this.options.reportValidity;
4742
- if (this.form && !this.form.noValidate && !disabled && !reportValidity(this.host)) {
4743
- event.preventDefault();
4744
- event.stopImmediatePropagation();
4745
- }
4746
- }
4747
- handleFormReset() {
4748
- this.options.setValue(this.host, this.options.defaultValue(this.host));
4749
- }
4750
- reportFormValidity() {
4751
- //
4752
- // Shoelace form controls work hard to act like regular form controls. They support the Constraint Validation API
4753
- // and its associated methods such as setCustomValidity() and reportValidity(). However, the HTMLFormElement also
4754
- // has a reportValidity() method that will trigger validation on all child controls. Since we're not yet using
4755
- // ElementInternals, we need to overload this method so it looks for any element with the reportValidity() method.
4756
- //
4757
- // We preserve the original method in a WeakMap, but we don't call it from the overload because that would trigger
4758
- // validations in an unexpected order. When the element disconnects, we revert to the original behavior. This won't
4759
- // be necessary once we can use ElementInternals.
4760
- //
4761
- // Note that we're also honoring the form's novalidate attribute.
4762
- //
4763
- if (this.form && !this.form.noValidate) {
4764
- // This seems sloppy, but checking all elements will cover native inputs, Shoelace inputs, and other custom
4765
- // elements that support the constraint validation API.
4766
- const elements = this.form.querySelectorAll("*");
4767
- for (const element of elements) {
4768
- if (typeof element.reportValidity === "function") {
4769
- if (!element.reportValidity()) {
4770
- return false;
4771
- }
5110
+ /**
5111
+ * Updates the ValidityState of the input in form component at current state
5112
+ */
5113
+ validateInput(input) {
5114
+ /** When the form control is disabled, its always valid */
5115
+ if (this.options.input(this.host).disabled) {
5116
+ return this._internals.setValidity({});
5117
+ }
5118
+ // get the validity of the internal <input>
5119
+ const validState = input.validity;
5120
+ // if the input is invalid, show the correct error
5121
+ if (!validState.valid) {
5122
+ // loop through the error reasons
5123
+ for (const state in validState) {
5124
+ // if there is an error and corresponding attribute holding
5125
+ // the message
5126
+ if (validState[state]) {
5127
+ this.validationError = state.toString();
5128
+ // set the validity error reason and the corresponding
5129
+ // message
5130
+ this._internals.setValidity({ [this.validationError]: true }, input.validationMessage, input);
4772
5131
  }
4773
5132
  }
4774
5133
  }
4775
- return true;
5134
+ else {
5135
+ this._internals.setValidity({});
5136
+ }
4776
5137
  }
4777
- doAction(type, invoker) {
4778
- if (this.form) {
4779
- const button = document.createElement("button");
4780
- button.type = type;
4781
- button.style.position = "absolute";
4782
- button.style.width = "0";
4783
- button.style.height = "0";
4784
- button.style.clipPath = "inset(50%)";
4785
- button.style.overflow = "hidden";
4786
- button.style.whiteSpace = "nowrap";
4787
- // Pass form attributes through to the temporary button
4788
- if (invoker) {
4789
- ["formaction", "formmethod", "formnovalidate", "formtarget"].forEach(attr => {
4790
- if (invoker.hasAttribute(attr)) {
4791
- button.setAttribute(attr, invoker.getAttribute(attr));
4792
- }
4793
- });
5138
+ }
5139
+
5140
+ /**
5141
+ * @summary The FormValidationMixin used by the form components
5142
+ * @param superClass
5143
+ * @returns
5144
+ */
5145
+ const SgdsFormValidatorMixin = (superClass) => {
5146
+ class ToBeValidatedElement extends superClass {
5147
+ constructor() {
5148
+ super(...arguments);
5149
+ this._isTouched = false;
5150
+ }
5151
+ connectedCallback() {
5152
+ super.connectedCallback();
5153
+ this.inputValidationController = new InputValidationController(this);
5154
+ }
5155
+ async firstUpdated(changedProperties) {
5156
+ super.firstUpdated(changedProperties);
5157
+ /* Either input or sgds-input. For example, quantity-toggle uses sgds-input */
5158
+ this.input =
5159
+ this.shadowRoot.querySelector("input") || (await this.sgdsInput) || this.shadowRoot.querySelector("textarea");
5160
+ this._mixinValidate(this.input);
5161
+ }
5162
+ /**
5163
+ * Native lifecycle of Form-Associated Custom Element Callbacks
5164
+ */
5165
+ formResetCallback() {
5166
+ if (this._mixinResetFormControl) {
5167
+ this._mixinResetFormControl();
5168
+ }
5169
+ else {
5170
+ this.value = this.defaultValue;
5171
+ this._mixinResetValidity(this.input);
4794
5172
  }
4795
- this.form.append(button);
4796
- button.click();
4797
- button.remove();
5173
+ this._mixinSetFormValue();
5174
+ }
5175
+ /**
5176
+ *
5177
+ * Methods use by classes using this mixin
5178
+ */
5179
+ /**
5180
+ * OnChange of form component
5181
+ * 1. Make value of control accessible via FormData
5182
+ * 2. Run change handler
5183
+ */
5184
+ _mixinHandleChange(e) {
5185
+ this._mixinSetFormValue();
5186
+ this.inputValidationController.handleChange(e);
5187
+ }
5188
+ /**
5189
+ * OnChange of form component
5190
+ * 1. Make value of control accessible via FormData
5191
+ * 2. Run input handler
5192
+ */
5193
+ _mixinHandleInputChange(e) {
5194
+ this._mixinSetFormValue();
5195
+ this.inputValidationController.handleInput(e);
5196
+ }
5197
+ /**
5198
+ * During form resetting,
5199
+ * 1. ValidityState is reset
5200
+ * 2. invalid reactive prop is updated after the reset
5201
+ * 3. Revalidates the ValidityState (but do not update invalid prop)
5202
+ * to prepare for the next validity check
5203
+ * 4. Reset touched state to false for a pristine form
5204
+ */
5205
+ _mixinResetValidity(input) {
5206
+ this.inputValidationController.resetValidity();
5207
+ this.inputValidationController.updateInvalidState();
5208
+ this.inputValidationController.validateInput(input);
5209
+ this._isTouched ? (this._isTouched = false) : null;
5210
+ }
5211
+ _mixinValidate(input) {
5212
+ this.inputValidationController.validateInput(input);
5213
+ }
5214
+ _mixinSetFormValue() {
5215
+ this.inputValidationController.setFormValue();
5216
+ }
5217
+ _mixinCheckValidity() {
5218
+ return this.inputValidationController.checkValidity();
5219
+ }
5220
+ _mixinReportValidity() {
5221
+ return this.inputValidationController.reportValidity();
5222
+ }
5223
+ _mixinGetValidity() {
5224
+ return this.inputValidationController.validity;
5225
+ }
5226
+ _mixinGetValidationMessage() {
5227
+ return this.inputValidationController.validationMessage;
4798
5228
  }
4799
5229
  }
4800
- /** Resets the form, restoring all the control to their default value */
4801
- reset(invoker) {
4802
- this.doAction("reset", invoker);
4803
- }
4804
- /** Submits the form, triggering validation and form data injection. */
4805
- submit(invoker) {
4806
- // Calling form.submit() bypasses the submit event and constraint validation. To prevent this, we can inject a
4807
- // native submit button into the form, "click" it, then remove it to simulate a standard form submission.
4808
- this.doAction("submit", invoker);
4809
- }
4810
- }
5230
+ ToBeValidatedElement.formAssociated = true;
5231
+ __decorate([
5232
+ queryAsync("sgds-input")
5233
+ ], ToBeValidatedElement.prototype, "sgdsInput", void 0);
5234
+ return ToBeValidatedElement;
5235
+ };
4811
5236
 
4812
- var css_248z$6 = css`:host{--sgds-btn-font-weight:var(--sgds-font-weight-regular);--sgds-btn-bg:var(--sgds-primary-bg);--sgds-btn-hover-bg:var(--sgds-primary-bg-emphasis);--sgds-btn-border-radius:var(--sgds-border-radius-md)}:host([variant=primary]){--sgds-btn-bg:var(--sgds-primary-bg);--sgds-btn-color:var(--sgds-default-color-on-dark)}:host([variant=outline]){--sgds-btn-bg:var(--sgds-default-bg-transparent);--sgds-btn-hover-bg:var(--sgds-primary-bg-translucent);--sgds-btn-color:var(--sgds-primary-color);--sgds-btn-border-width:var(--sgds-border-width-1);--sgds-btn-border-color:var(--sgds-primary-border-color)}:host([variant=ghost]){--sgds-btn-bg:var(--sgds-default-bg-transparent);--sgds-btn-hover-bg:var(--sgds-primary-bg-translucent);--sgds-btn-color:var(--sgds-primary-color)}:host([variant=danger]){--sgds-btn-bg:var(--sgds-danger-bg);--sgds-btn-hover-bg:var(--sgds-danger-bg-emphasis);--sgds-btn-color:var(--sgds-default-color-on-dark)}.btn{align-items:center;background-color:var(--sgds-btn-bg);border:1px solid var(--sgds-default-border-color-transparent);border-radius:var(--sgds-btn-border-radius);color:var(--sgds-default-color-on-dark);cursor:pointer;display:inline-flex;font-size:var(--sgds-font-size-2);font-weight:var(--sgds-btn-font-weight);gap:var(--sgds-gap-2-xs);height:var(--sgds-dimension-48);justify-content:center;line-height:var(--sgds-line-height-md);min-width:var(--sgds-dimension-96);padding:0 var(--sgds-padding-lg);text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;user-select:none;vertical-align:middle}.btn-ghost,.btn-outline,.btn-primary{color:var(--sgds-btn-color)}.btn-outline{border:var(--sgds-btn-border-width) solid var(--sgds-btn-border-color)}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn.active,.btn:hover{background-color:var(--sgds-btn-hover-bg)}.btn:focus,.btn:focus-visible{background-color:var(--sgds-btn-hover-bg);border-color:transparent;box-shadow:var(--sgds-box-shadow-focus);outline:0}.btn.disabled,.btn:disabled{color:var(--sgds-btn-color);opacity:var(--sgds-opacity-50);pointer-events:none}.btn-lg{font-size:var(--sgds-font-size-3);height:var(--sgds-dimension-56);min-width:var(--sgds-dimension-112);padding:0 var(--sgds-padding-xl)}.btn-sm{font-size:var(--sgds-font-size-1);height:var(--sgds-dimension-40);min-width:var(--sgds-dimension-80);padding:0 var(--sgds-padding-md)}`;
5237
+ var css_248z$6 = css`:host{--sgds-btn-font-weight:var(--sgds-font-weight-regular);--sgds-btn-bg:var(--sgds-primary-bg);--sgds-btn-hover-bg:var(--sgds-primary-bg-emphasis);--sgds-btn-border-radius:var(--sgds-border-radius-md)}:host([variant=primary]){--sgds-btn-bg:var(--sgds-primary-bg);--sgds-btn-color:var(--sgds-default-color-on-dark)}:host([variant=outline]){--sgds-btn-bg:var(--sgds-default-bg-transparent);--sgds-btn-hover-bg:var(--sgds-primary-bg-translucent);--sgds-btn-color:var(--sgds-primary-color);--sgds-btn-border-width:var(--sgds-border-width-1);--sgds-btn-border-color:var(--sgds-primary-border-color)}:host([variant=ghost]){--sgds-btn-bg:var(--sgds-default-bg-transparent);--sgds-btn-hover-bg:var(--sgds-primary-bg-translucent);--sgds-btn-color:var(--sgds-primary-color)}:host([variant=danger]){--sgds-btn-bg:var(--sgds-danger-bg);--sgds-btn-hover-bg:var(--sgds-danger-bg-emphasis);--sgds-btn-color:var(--sgds-default-color-on-dark)}.btn{align-items:center;background-color:var(--sgds-btn-bg);border:1px solid var(--sgds-default-border-color-transparent);border-radius:var(--sgds-btn-border-radius);color:var(--sgds-default-color-on-dark);cursor:pointer;display:inline-flex;font-size:var(--sgds-font-size-2);font-weight:var(--sgds-btn-font-weight);gap:var(--sgds-gap-2-xs);height:var(--sgds-dimension-48);justify-content:center;line-height:var(--sgds-line-height-md);min-width:var(--sgds-dimension-96);padding:0 var(--sgds-padding-lg);text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;user-select:none;vertical-align:middle}.btn-ghost,.btn-outline,.btn-primary{color:var(--sgds-btn-color)}.btn-outline{border:var(--sgds-btn-border-width) solid var(--sgds-btn-border-color)}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn.active,.btn:hover{background-color:var(--sgds-btn-hover-bg)}.btn:focus,.btn:focus-visible{background-color:var(--sgds-btn-hover-bg);border-color:transparent;box-shadow:var(--sgds-box-shadow-focus);outline:0}.btn.disabled,.btn:disabled{color:var(--sgds-btn-color);opacity:var(--sgds-opacity-50);pointer-events:none}.btn-lg{font-size:var(--sgds-font-size-3);height:var(--sgds-dimension-56);min-width:var(--sgds-dimension-112);padding:0 var(--sgds-padding-xl)}.btn-sm{font-size:var(--sgds-font-size-1);height:var(--sgds-dimension-40);min-width:var(--sgds-dimension-80);padding:0 var(--sgds-padding-md)}.btn slot::slotted(*){color:var(--sgds-btn-color)}`;
4813
5238
 
4814
5239
  class ButtonElement extends SgdsElement {
4815
5240
  constructor() {
@@ -4880,11 +5305,13 @@
4880
5305
  property({ type: String })
4881
5306
  ], ButtonElement.prototype, "ariaLabel", void 0);
4882
5307
 
4883
- var css_248z$5 = css`.btn.btn-icon{display:flex;height:var(--sgds-dimension-48,56px);min-width:unset;padding:0;width:var(--sgds-dimension-48,56px)}.btn.btn-icon.btn-lg{font-size:var(--sgds-font-size-3);height:var(--sgds-dimension-56);min-width:unset;padding:0;width:var(--sgds-dimension-56)}.btn.btn-icon.btn-sm{font-size:var(--sgds-font-size-1);height:var(--sgds-dimension-40);min-width:unset;padding:0;width:var(--sgds-dimension-40)}.btn>svg{height:var(--sgds-dimension-24);width:var(--sgds-dimension-24)}.btn-lg>svg{height:var(--sgds-dimension-32);width:var(--sgds-dimension-32)}.btn-sm>svg{height:var(--sgds-dimension-20);width:var(--sgds-dimension-20)}`;
5308
+ var css_248z$5 = css`.btn.btn-icon{display:flex;height:var(--sgds-dimension-48,56px);min-width:unset;padding:0;width:var(--sgds-dimension-48,56px)}.btn.btn-icon.btn-lg{font-size:var(--sgds-font-size-3);height:var(--sgds-dimension-56);min-width:unset;padding:0;width:var(--sgds-dimension-56)}.btn.btn-icon.btn-sm{font-size:var(--sgds-font-size-1);height:var(--sgds-dimension-40);min-width:unset;padding:0;width:var(--sgds-dimension-40)}`;
4884
5309
 
4885
5310
  /**
4886
5311
  * @summary An icon button is a user interface element that combines an icon and a button, serving as a clickable or tabbable component.
4887
5312
  *
5313
+ * @slot default - The slot for sgds-icon
5314
+ *
4888
5315
  * @event sgds-blur - Emitted when the button is blurred.
4889
5316
  * @event sgds-focus - Emitted when the button is focused.
4890
5317
  */
@@ -4901,7 +5328,7 @@
4901
5328
  [`btn-${this.size}`]: this.size
4902
5329
  })}"
4903
5330
  ?disabled=${ifDefined(isLink ? undefined : this.disabled)}
4904
- type="button"
5331
+ type=${ifDefined(isLink ? undefined : "button")}
4905
5332
  href=${ifDefined(isLink ? this.href : undefined)}
4906
5333
  target=${ifDefined(isLink ? this.target : undefined)}
4907
5334
  download=${ifDefined(isLink ? this.download : undefined)}
@@ -4914,19 +5341,12 @@
4914
5341
  @blur=${this._handleBlur}
4915
5342
  aria-label=${ifDefined(this.ariaLabel)}
4916
5343
  >
4917
- <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
4918
- <path fill-rule="evenodd" clip-rule="evenodd" d="M3 12C3 11.8295 3.06773 11.666 3.18828 11.5455C3.30883 11.4249 3.47233 11.3572 3.64282 11.3572H18.8043L14.7584 7.31258C14.6377 7.19187 14.5699 7.02817 14.5699 6.85746C14.5699 6.68676 14.6377 6.52305 14.7584 6.40235C14.8791 6.28165 15.0428 6.21384 15.2135 6.21384C15.3842 6.21384 15.5479 6.28165 15.6686 6.40235L20.8111 11.5449C20.871 11.6046 20.9185 11.6755 20.9509 11.7536C20.9833 11.8317 21 11.9154 21 12C21 12.0845 20.9833 12.1683 20.9509 12.2464C20.9185 12.3245 20.871 12.3954 20.8111 12.4551L15.6686 17.5976C15.5479 17.7183 15.3842 17.7861 15.2135 17.7861C15.0428 17.7861 14.8791 17.7183 14.7584 17.5976C14.6377 17.4769 14.5699 17.3132 14.5699 17.1425C14.5699 16.9718 14.6377 16.8081 14.7584 16.6874L18.8043 12.6428H3.64282C3.47233 12.6428 3.30883 12.5751 3.18828 12.4545C3.06773 12.334 3 12.1705 3 12Z" fill="currentColor"/>
4919
- </svg>
5344
+ <slot></slot>
4920
5345
  </${tag}>
4921
5346
  `;
4922
5347
  }
4923
5348
  }
4924
5349
  SgdsIconButton.styles = [...ButtonElement.styles, css_248z$5];
4925
- __decorate([
4926
- property({ type: String, reflect: true })
4927
- ], SgdsIconButton.prototype, "name", void 0);
4928
-
4929
- var css_248z$4 = css`.form-control-container{display:flex;flex-direction:column;gap:var(--sgds-form-gap-md)}.input-group{align-items:stretch;display:flex;flex-wrap:wrap;gap:var(--sgds-form-gap-lg);position:relative}.input-group>sgds-input{flex:1 1 auto;min-width:0;position:relative}.input-group sgds-button:focus,.input-group>sgds-input:focus{z-index:3}.visually-hidden{clip:rect(0,0,0,0)!important;border:0!important;height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:1px!important}`;
4930
5350
 
4931
5351
  /**
4932
5352
  * @license
@@ -4998,11 +5418,48 @@
4998
5418
  */
4999
5419
  const unsafeSVG = directive(UnsafeSVGDirective);
5000
5420
 
5001
- var css_248z$3 = css`:host{--sgds-spinner-bg:var(--sgds-primary-bg);display:inline-flex}:host([variant=neutral]){--sgds-spinner-bg:var(--sgds-neutral-color-emphasis)}.spinner-wrapper{align-items:center;display:flex;flex-direction:column;gap:var(--sgds-gap-2-xs)}.spinner{animation:spinner .75s linear infinite;border-radius:50%;border-right:.25em solid var(--sgds-alternate-bg);border:.25em solid var(--sgds-alternate-bg);border-right-color:var(--sgds-spinner-bg);color:var(--sgds-spinner-color);display:inline-flex;height:var(--sgds-dimension-32);width:var(--sgds-dimension-32)}.spinner-sm{height:var(--sgds-dimension-24);width:var(--sgds-dimension-24)}.spinner-lg{height:var(--sgds-dimension-48);width:var(--sgds-dimension-48)}.spinner-label{font-size:var(--sgds-font-size-1)}@media (prefers-reduced-motion:reduce){.spinner{animation-duration:1.5s}}
5421
+ // @watch decorator
5422
+ //
5423
+ // Runs when an observed property changes, e.g. @property or @state, but before the component updates.
5424
+ //
5425
+ // To wait for an update to complete after a change occurs, use `await this.updateComplete` in the handler. To start
5426
+ // watching after the initial update/render, use `{ waitUntilFirstUpdate: true }` or `this.hasUpdated` in the handler.
5427
+ //
5428
+ // Usage:
5429
+ //
5430
+ // @watch('propName')
5431
+ // handlePropChange(oldValue, newValue) {
5432
+ // ...
5433
+ // }
5434
+ function watch(propName, options) {
5435
+ const resolvedOptions = Object.assign({ waitUntilFirstUpdate: false }, options);
5436
+ return (proto, decoratedFnName) => {
5437
+ // @ts-expect-error -- update is a protected property
5438
+ const { update } = proto;
5439
+ if (propName in proto) {
5440
+ const propNameKey = propName;
5441
+ // @ts-expect-error -- update is a protected property
5442
+ proto.update = function (changedProps) {
5443
+ if (changedProps.has(propNameKey)) {
5444
+ const oldValue = changedProps.get(propNameKey);
5445
+ const newValue = this[propNameKey];
5446
+ if (oldValue !== newValue) {
5447
+ if (!resolvedOptions.waitUntilFirstUpdate || this.hasUpdated) {
5448
+ this[decoratedFnName](oldValue, newValue);
5449
+ }
5450
+ }
5451
+ }
5452
+ update.call(this, changedProps);
5453
+ };
5454
+ }
5455
+ };
5456
+ }
5457
+
5458
+ var css_248z$4 = css`:host{--sgds-spinner-bg:var(--sgds-primary-bg);display:inline-flex}:host([variant=neutral]){--sgds-spinner-bg:var(--sgds-neutral-color-emphasis)}.spinner-wrapper{align-items:center;display:flex;flex-direction:column;gap:var(--sgds-gap-2-xs)}.spinner{animation:spinner .75s linear infinite;border-radius:50%;border-right:.25em solid var(--sgds-alternate-bg);border:.25em solid var(--sgds-alternate-bg);border-right-color:var(--sgds-spinner-bg);color:var(--sgds-spinner-color);display:inline-flex;height:var(--sgds-dimension-32);width:var(--sgds-dimension-32)}.spinner-sm{height:var(--sgds-dimension-24);width:var(--sgds-dimension-24)}.spinner-lg{height:var(--sgds-dimension-48);width:var(--sgds-dimension-48)}.spinner-label{font-size:var(--sgds-font-size-1)}@media (prefers-reduced-motion:reduce){.spinner{animation-duration:1.5s}}
5002
5459
 
5003
5460
  /*! CSS Used keyframes */@keyframes spinner{to{transform:rotate(1turn)}}.sr-only{clip:rect(0,0,0,0);border:0;height:1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}`;
5004
5461
 
5005
- var css_248z$2 = css`.text-primary{color:var(--sgds-primary-rgb)!important}.text-secondary{color:var(--sgds-secondary-rgb)!important}.text-success{color:var(--sgds-success-rgb)!important}.text-info{color:var(--sgds-info-rgb)!important}.text-warning{color:var(--sgds-warning-rgb)!important}.text-danger{color:var(--sgds-danger-rgb)!important}.text-light{color:var(--sgds-light-rgb)!important}.text-dark{color:var(--sgds-dark-rgb)!important}.text-muted{color:var(--sgds-secondary-color)!important}`;
5462
+ var css_248z$3 = css`.text-primary{color:var(--sgds-primary-rgb)!important}.text-secondary{color:var(--sgds-secondary-rgb)!important}.text-success{color:var(--sgds-success-rgb)!important}.text-info{color:var(--sgds-info-rgb)!important}.text-warning{color:var(--sgds-warning-rgb)!important}.text-danger{color:var(--sgds-danger-rgb)!important}.text-light{color:var(--sgds-light-rgb)!important}.text-dark{color:var(--sgds-dark-rgb)!important}.text-muted{color:var(--sgds-secondary-color)!important}`;
5006
5463
 
5007
5464
  /**
5008
5465
  * @summary Spinners notify the users that their request is being processed.
@@ -5032,7 +5489,7 @@
5032
5489
  `;
5033
5490
  }
5034
5491
  }
5035
- SgdsSpinner.styles = [...SgdsElement.styles, css_248z$2, css_248z$3];
5492
+ SgdsSpinner.styles = [...SgdsElement.styles, css_248z$3, css_248z$4];
5036
5493
  __decorate([
5037
5494
  property({ type: String, reflect: true })
5038
5495
  ], SgdsSpinner.prototype, "variant", void 0);
@@ -5043,44 +5500,7 @@
5043
5500
  property({ reflect: true, type: String })
5044
5501
  ], SgdsSpinner.prototype, "label", void 0);
5045
5502
 
5046
- // @watch decorator
5047
- //
5048
- // Runs when an observed property changes, e.g. @property or @state, but before the component updates.
5049
- //
5050
- // To wait for an update to complete after a change occurs, use `await this.updateComplete` in the handler. To start
5051
- // watching after the initial update/render, use `{ waitUntilFirstUpdate: true }` or `this.hasUpdated` in the handler.
5052
- //
5053
- // Usage:
5054
- //
5055
- // @watch('propName')
5056
- // handlePropChange(oldValue, newValue) {
5057
- // ...
5058
- // }
5059
- function watch(propName, options) {
5060
- const resolvedOptions = Object.assign({ waitUntilFirstUpdate: false }, options);
5061
- return (proto, decoratedFnName) => {
5062
- // @ts-expect-error -- update is a protected property
5063
- const { update } = proto;
5064
- if (propName in proto) {
5065
- const propNameKey = propName;
5066
- // @ts-expect-error -- update is a protected property
5067
- proto.update = function (changedProps) {
5068
- if (changedProps.has(propNameKey)) {
5069
- const oldValue = changedProps.get(propNameKey);
5070
- const newValue = this[propNameKey];
5071
- if (oldValue !== newValue) {
5072
- if (!resolvedOptions.waitUntilFirstUpdate || this.hasUpdated) {
5073
- this[decoratedFnName](oldValue, newValue);
5074
- }
5075
- }
5076
- }
5077
- update.call(this, changedProps);
5078
- };
5079
- }
5080
- };
5081
- }
5082
-
5083
- var css_248z$1 = css`.form-control-container{display:flex;flex-direction:column;gap:var(--sgds-form-gap-md)}.form-control-container.disabled{opacity:var(--sgds-opacity-50)}.form-control-group{align-items:center;background-color:var(--sgds-form-bg);border:var(--sgds-form-border-width-default) solid var(--sgds-form-border-color);border-radius:var(--sgds-form-border-radius-md);display:flex;gap:var(--sgds-form-gap-md);height:var(--sgds-dimension-48);justify-content:center;min-width:var(--sgds-dimension-256);padding:0 var(--sgds-form-padding-x);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;width:-webkit-fill-available;width:-moz-available}.form-control{appearance:none;background-clip:padding-box;background:none;border:none;color:var(--sgds-form-color);display:block;flex-grow:1;font-size:var(--sgds-font-size-2);line-height:var(--sgds-line-height-heading);outline:none;padding:0}.form-control-group>.form-control:focus{z-index:3}@media (prefers-reduced-motion:reduce){.form-control-group{transition:none}}.form-control-group.readonly{border-color:var(--sgds-form-border-color-muted)}.form-control-group:not(.disabled):not(.is-invalid):hover{border:var(--sgds-form-border-width-thick) solid var(--sgds-form-border-color-emphasis)}.form-control-group:not(.disabled):not(.is-invalid):focus,.form-control-group:not(.disabled):not(.is-invalid):focus-within{border:var(--sgds-form-border-width-thick) solid var(--sgds-form-border-color-emphasis);box-shadow:var(--sgds-form-box-shadow-focus);outline:0}.form-control-group.is-invalid{border:var(--sgds-form-border-width-thick) solid var(--sgds-form-danger-border-color)}.form-control-group.disabled{background-color:var(--sgds-form-bg-muted)}:host(.quantity-toggle) input::-webkit-inner-spin-button{appearance:none;margin:0}:host(.quantity-toggle) input{text-align:center}.form-control-icon{align-items:center;display:flex;height:var(--sgds-form-icon-size-lg);justify-content:center;width:var(--sgds-form-icon-size-lg)}.form-control-prefix,.form-control-suffix{color:var(--sgds-form-color-subtle)}.form-control-group.quantity-toggle{padding:0}`;
5503
+ var css_248z$2 = css`.form-control-container{display:flex;flex-direction:column;gap:var(--sgds-form-gap-md)}.form-control-container.disabled{opacity:var(--sgds-opacity-50)}.form-control-group{align-items:center;background-color:var(--sgds-form-bg);border:var(--sgds-form-border-width-default) solid var(--sgds-form-border-color);border-radius:var(--sgds-form-border-radius-md);display:flex;gap:var(--sgds-form-gap-md);height:var(--sgds-dimension-48);justify-content:center;min-width:var(--sgds-dimension-256);padding:0 var(--sgds-form-padding-x);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;width:-webkit-fill-available;width:-moz-available}.form-control{appearance:none;background-clip:padding-box;background:none;border:none;color:var(--sgds-form-color);display:block;flex-grow:1;font-size:var(--sgds-font-size-2);line-height:var(--sgds-line-height-heading);outline:none;padding:0}.form-control-group>.form-control:focus{z-index:3}@media (prefers-reduced-motion:reduce){.form-control-group{transition:none}}.form-control-group.readonly{border-color:var(--sgds-form-border-color-muted)}.form-control-group:not(.disabled):not(.is-invalid):hover{border:var(--sgds-form-border-width-thick) solid var(--sgds-form-border-color-emphasis)}.form-control-group:not(.disabled):not(.is-invalid):focus,.form-control-group:not(.disabled):not(.is-invalid):focus-within{border:var(--sgds-form-border-width-thick) solid var(--sgds-form-border-color-emphasis);box-shadow:var(--sgds-form-box-shadow-focus);outline:0}.form-control-group.is-invalid{border:var(--sgds-form-border-width-thick) solid var(--sgds-form-danger-border-color)}.form-control-group.disabled{background-color:var(--sgds-form-bg-muted)}:host(.quantity-toggle) input::-webkit-inner-spin-button{appearance:none;margin:0}:host(.quantity-toggle) input{text-align:center}.form-control-icon{align-items:center;display:flex;height:var(--sgds-form-icon-size-lg);justify-content:center;width:var(--sgds-form-icon-size-lg)}.form-control-prefix,.form-control-suffix{color:var(--sgds-form-color-subtle)}.form-control-group.quantity-toggle{padding:0}`;
5084
5504
 
5085
5505
  /**
5086
5506
  * @summary Text inputs allow your users to enter letters, numbers and symbols on a single line.
@@ -5089,14 +5509,13 @@
5089
5509
  * @event sgds-input - Emitted when the control receives input and its value changes.
5090
5510
  * @event sgds-focus - Emitted when input is in focus.
5091
5511
  * @event sgds-blur - Emitted when input is not in focus.
5512
+ * @event sgds-invalid - Emitted when input is invalid
5513
+ * @event sgds-valid - Emitted when input is valid
5092
5514
  *
5093
5515
  */
5094
- class SgdsInput extends FormControlElement {
5516
+ class SgdsInput extends SgdsFormValidatorMixin(ScopedElementsMixin(FormControlElement)) {
5095
5517
  constructor() {
5096
5518
  super(...arguments);
5097
- /**@internal */
5098
- this.formSubmitController = new FormSubmitController(this);
5099
- /** The type of input which works the same as HTMLInputElement */
5100
5519
  this.type = "text";
5101
5520
  /** The input's placeholder text. */
5102
5521
  this.placeholder = "placeholder";
@@ -5104,16 +5523,17 @@
5104
5523
  this.autofocus = false;
5105
5524
  /** Makes the input readonly. */
5106
5525
  this.readonly = false;
5107
- /**The input's value attribute. */
5108
- this.value = "";
5109
5526
  /**Gets or sets the default value used to reset this element. The initial value corresponds to the one originally specified in the HTML that created this element. */
5110
5527
  this.defaultValue = "";
5111
5528
  /** Marks the component as valid. */
5112
5529
  this.valid = false;
5113
5530
  /** Marks the component as loading. */
5114
5531
  this.loading = false;
5115
- /**@internal */
5116
- this.inputId = genId("input", this.type);
5532
+ /** Makes the input a required field. */
5533
+ this.required = false;
5534
+ /**The input's value attribute. */
5535
+ this.value = "";
5536
+ this._isTouched = false;
5117
5537
  }
5118
5538
  /**@internal */
5119
5539
  static get scopedElements() {
@@ -5129,60 +5549,79 @@
5129
5549
  blur() {
5130
5550
  this.input.blur();
5131
5551
  }
5132
- /** Checks for validity and shows the browser's validation message if the control is invalid. */
5133
- reportValidity() {
5134
- return this.input.reportValidity();
5135
- }
5136
- /** Sets a custom validation message. Pass an empty string to restore validity */
5137
- setCustomValidity(err) {
5138
- return this.input.setCustomValidity(err);
5139
- }
5140
5552
  /** Programatically sets the invalid state of the input. Pass in boolean value in the argument */
5141
5553
  setInvalid(bool) {
5142
5554
  this.invalid = bool;
5555
+ if (bool) {
5556
+ this.emit("sgds-invalid");
5557
+ }
5558
+ else {
5559
+ this.emit("sgds-valid");
5560
+ }
5143
5561
  }
5144
- _handleClick() {
5145
- this.focus();
5562
+ /**
5563
+ * Checks for validity. Under the hood, HTMLFormElement's reportValidity method calls this method to check for component's validity state
5564
+ * Note that the native error popup is prevented for SGDS form components by default. Instead the validation message shows up in the feedback container of SgdsInput
5565
+ */
5566
+ reportValidity() {
5567
+ return this._mixinReportValidity();
5146
5568
  }
5147
- _handleChange(event) {
5148
- this.value = this.input.value;
5149
- this.emit(event);
5569
+ /**
5570
+ * Checks for validity without any native error popup message
5571
+ */
5572
+ checkValidity() {
5573
+ return this._mixinCheckValidity();
5574
+ }
5575
+ /**
5576
+ * Returns the ValidityState object
5577
+ */
5578
+ get validity() {
5579
+ return this._mixinGetValidity();
5580
+ }
5581
+ /**
5582
+ * Returns the validation message based on the ValidityState
5583
+ */
5584
+ get validationMessage() {
5585
+ return this._mixinGetValidationMessage();
5150
5586
  }
5151
5587
  _handleFocus() {
5152
5588
  this.emit("sgds-focus");
5153
5589
  }
5154
5590
  _handleBlur() {
5591
+ this._isTouched = true;
5155
5592
  this.emit("sgds-blur");
5156
5593
  }
5157
- _handleKeyDown(event) {
5158
- const hasModifier = event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
5159
- // Pressing enter when focused on an input should submit the form like a native input, but we wait a tick before
5160
- // submitting to allow users to cancel the keydown event if they need to
5161
- if (event.key === "Enter" && !hasModifier) {
5162
- setTimeout(() => {
5163
- // Prevent submission when enter is click on a submission in an Input Method Editor with isComposing
5164
- if (!event.defaultPrevented && !event.isComposing) {
5165
- this.formSubmitController.submit();
5166
- }
5167
- });
5594
+ _handleClick() {
5595
+ this.focus();
5596
+ }
5597
+ _handleChange(e) {
5598
+ this.value = this.input.value;
5599
+ this.emit("sgds-change");
5600
+ super._mixinHandleChange(e);
5601
+ }
5602
+ _handleInputChange(e) {
5603
+ this.value = this.input.value;
5604
+ this.emit("sgds-input");
5605
+ super._mixinHandleInputChange(e);
5606
+ }
5607
+ /** @internal */
5608
+ _handleIsTouched() {
5609
+ if (this._isTouched) {
5610
+ this.setInvalid(!this._mixinCheckValidity());
5168
5611
  }
5169
5612
  }
5170
5613
  _handleDisabledChange() {
5171
5614
  // Disabled form controls are always valid, so we need to recheck validity when the state changes
5172
- this.input.disabled = this.disabled;
5173
- this.invalid = !this.input.checkValidity();
5174
- }
5175
- _handleValueChange() {
5176
- this.invalid = !this.input.checkValidity();
5615
+ this.setInvalid(false);
5177
5616
  }
5178
5617
  _renderInput() {
5618
+ const wantFeedbackStyle = this.hasFeedback === "both" || this.hasFeedback === "style";
5179
5619
  return html `
5180
5620
  <div
5181
5621
  class="form-control-group ${classMap({
5182
5622
  disabled: this.disabled,
5183
5623
  readonly: this.readonly,
5184
- "is-invalid": this.invalid && this.hasFeedback,
5185
- "quantity-toggle": this.classList.contains("quantity-toggle")
5624
+ "is-invalid": this.invalid && wantFeedbackStyle
5186
5625
  })}"
5187
5626
  @click=${this._handleClick}
5188
5627
  >
@@ -5191,7 +5630,7 @@
5191
5630
  <input
5192
5631
  class="form-control"
5193
5632
  type=${this.type}
5194
- id=${this.inputId}
5633
+ id=${this._controlId}
5195
5634
  name=${ifDefined(this.name)}
5196
5635
  placeholder=${ifDefined(this.placeholder)}
5197
5636
  aria-invalid=${this.invalid ? "true" : "false"}
@@ -5206,15 +5645,14 @@
5206
5645
  min=${ifDefined(this.min)}
5207
5646
  max=${ifDefined(this.max)}
5208
5647
  step=${ifDefined(this.step)}
5209
- @input=${() => this._handleChange("sgds-input")}
5210
- @change=${() => this._handleChange("sgds-change")}
5211
- @keydown=${this._handleKeyDown}
5648
+ @input=${(e) => this._handleInputChange(e)}
5649
+ @change=${(e) => this._handleChange(e)}
5212
5650
  @invalid=${() => this.setInvalid(true)}
5213
5651
  @focus=${this._handleFocus}
5214
5652
  @blur=${this._handleBlur}
5215
- aria-describedby=${ifDefined(this.invalid && this.hasFeedback ? `${this.inputId}-invalid` : undefined)}
5216
- aria-labelledby="${this.labelId} ${this.inputId}Help ${this.invalid && this.hasFeedback
5217
- ? `${this.inputId}-invalid`
5653
+ aria-describedby=${ifDefined(this.invalid && this.hasFeedback ? `${this._controlId}-invalid` : undefined)}
5654
+ aria-labelledby="${this._labelId} ${this._controlId}Help ${this.invalid && this.hasFeedback
5655
+ ? `${this._controlId}-invalid`
5218
5656
  : ""}"
5219
5657
  />
5220
5658
  ${this.loading ? html `<sgds-spinner size="sm"></sgds-spinner>` : nothing}
@@ -5231,7 +5669,8 @@
5231
5669
  `;
5232
5670
  }
5233
5671
  _renderFeedback() {
5234
- return this.invalid && this.hasFeedback
5672
+ const wantFeedbackText = this.hasFeedback === "both" || this.hasFeedback === "text";
5673
+ return this.invalid && wantFeedbackText
5235
5674
  ? html ` <div class="invalid-feedback-container">
5236
5675
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
5237
5676
  <path
@@ -5239,15 +5678,17 @@
5239
5678
  fill="#B90000"
5240
5679
  />
5241
5680
  </svg>
5242
- <div id="${this.inputId}-invalid" class="invalid-feedback">${this.invalidFeedback}</div>
5681
+ <div id="${this._controlId}-invalid" class="invalid-feedback">
5682
+ ${this.invalidFeedback ? this.invalidFeedback : this.input.validationMessage}
5683
+ </div>
5243
5684
  </div>`
5244
5685
  : html `${this._renderHintText()}`;
5245
5686
  }
5246
5687
  _renderLabel() {
5247
5688
  const labelTemplate = html `
5248
5689
  <label
5249
- for=${this.inputId}
5250
- id=${this.labelId}
5690
+ for=${this._controlId}
5691
+ id=${this._labelId}
5251
5692
  class=${classMap({
5252
5693
  "form-label": true,
5253
5694
  required: this.required
@@ -5258,7 +5699,7 @@
5258
5699
  return this.label && labelTemplate;
5259
5700
  }
5260
5701
  _renderHintText() {
5261
- const hintTextTemplate = html ` <div id="${this.inputId}Help" class="form-text">${this.hintText}</div> `;
5702
+ const hintTextTemplate = html ` <div id="${this._controlId}Help" class="form-text">${this.hintText}</div> `;
5262
5703
  return this.hintText && hintTextTemplate;
5263
5704
  }
5264
5705
  render() {
@@ -5273,10 +5714,7 @@
5273
5714
  `;
5274
5715
  }
5275
5716
  }
5276
- SgdsInput.styles = [...FormControlElement.styles, css_248z$1];
5277
- __decorate([
5278
- query("input.form-control")
5279
- ], SgdsInput.prototype, "input", void 0);
5717
+ SgdsInput.styles = [...FormControlElement.styles, css_248z$9, css_248z$2];
5280
5718
  __decorate([
5281
5719
  property({ reflect: true })
5282
5720
  ], SgdsInput.prototype, "type", void 0);
@@ -5295,6 +5733,12 @@
5295
5733
  __decorate([
5296
5734
  property({ type: Number, reflect: true })
5297
5735
  ], SgdsInput.prototype, "maxlength", void 0);
5736
+ __decorate([
5737
+ property()
5738
+ ], SgdsInput.prototype, "min", void 0);
5739
+ __decorate([
5740
+ property()
5741
+ ], SgdsInput.prototype, "max", void 0);
5298
5742
  __decorate([
5299
5743
  property({ type: String, reflect: true })
5300
5744
  ], SgdsInput.prototype, "placeholder", void 0);
@@ -5311,8 +5755,11 @@
5311
5755
  property()
5312
5756
  ], SgdsInput.prototype, "step", void 0);
5313
5757
  __decorate([
5314
- property({ reflect: true })
5315
- ], SgdsInput.prototype, "value", void 0);
5758
+ property({ type: String, reflect: true })
5759
+ ], SgdsInput.prototype, "hasFeedback", void 0);
5760
+ __decorate([
5761
+ property({ type: String, reflect: true })
5762
+ ], SgdsInput.prototype, "invalidFeedback", void 0);
5316
5763
  __decorate([
5317
5764
  defaultValue()
5318
5765
  ], SgdsInput.prototype, "defaultValue", void 0);
@@ -5322,57 +5769,160 @@
5322
5769
  __decorate([
5323
5770
  property({ type: Boolean, reflect: true })
5324
5771
  ], SgdsInput.prototype, "loading", void 0);
5772
+ __decorate([
5773
+ property({ type: Boolean, reflect: true })
5774
+ ], SgdsInput.prototype, "required", void 0);
5775
+ __decorate([
5776
+ property({ reflect: true })
5777
+ ], SgdsInput.prototype, "value", void 0);
5778
+ __decorate([
5779
+ state()
5780
+ ], SgdsInput.prototype, "_isTouched", void 0);
5781
+ __decorate([
5782
+ watch("_isTouched", { waitUntilFirstUpdate: true })
5783
+ ], SgdsInput.prototype, "_handleIsTouched", null);
5325
5784
  __decorate([
5326
5785
  watch("disabled", { waitUntilFirstUpdate: true })
5327
5786
  ], SgdsInput.prototype, "_handleDisabledChange", null);
5328
- __decorate([
5329
- watch("value", { waitUntilFirstUpdate: true })
5330
- ], SgdsInput.prototype, "_handleValueChange", null);
5331
5787
 
5332
- var css_248z = css`svg{vertical-align:middle}`;
5788
+ var css_248z$1 = css`.form-control-container{display:flex;flex-direction:column;gap:var(--sgds-form-gap-md)}.input-group{align-items:stretch;display:flex;flex-wrap:wrap;gap:var(--sgds-form-gap-lg);position:relative}.input-group>sgds-input{flex:1 1 auto;min-width:0;position:relative}.input-group sgds-button:focus,.input-group>sgds-input:focus{z-index:3}.visually-hidden{clip:rect(0,0,0,0)!important;border:0!important;height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:1px!important}`;
5789
+
5790
+ var css_248z = css`:host([size=sm]) svg{height:var(--sgds-icon-size-sm);width:var(--sgds-icon-size-sm)}:host([size=md]) svg{height:var(--sgds-icon-size-md);width:var(--sgds-icon-size-md)}:host([size=xl]) svg{height:var(--sgds-icon-size-xl);width:var(--sgds-icon-size-xl)}:host([size="2-xl"]) svg{height:var(--sgds-icon-size-2-xl);width:var(--sgds-icon-size-2-xl)}:host([size="3-xl"]) svg{height:var(--sgds-icon-size-3-xl);width:var(--sgds-icon-size-3-xl)}svg{display:block;height:var(--sgds-icon-size-lg);width:var(--sgds-icon-size-lg)}`;
5333
5791
 
5334
5792
  /**
5335
- * @summary The quantity toggle component is used to increase or decrease an incremental venue, best used when the user needs to enter or adjust the quantity of a selected item.
5793
+ * @summary Icons offer a form of visual shorthand that we are all familiar with. They can label, inform and aid navigation quickly and effectively in minimal space. Icons must first and foremost communicate meaning. By default, the icon component renders icons form SgdsIcon library set
5336
5794
  *
5337
- * @csspart base - The base wrapper of the quantity toggle component.
5338
- * @csspart button - The plus and minus button of quantity toggle
5795
+ * @event sgds-blur - Emitted when the button is blurred.
5796
+ * @event sgds-focus - Emitted when the button is focused.
5797
+ */
5798
+ class SgdsIcon extends SgdsElement {
5799
+ constructor() {
5800
+ super(...arguments);
5801
+ /** Specifies a small, medium or large icon, the size is medium by default. */
5802
+ this.size = "lg";
5803
+ /** @internal */
5804
+ this._svgContent = null;
5805
+ }
5806
+ async firstUpdated() {
5807
+ if (this.name) {
5808
+ this.loadSvg(this.name);
5809
+ }
5810
+ }
5811
+ updated() {
5812
+ this.style.display = this._svgContent ? "flex" : "none";
5813
+ }
5814
+ async loadSvg(name) {
5815
+ if (name) {
5816
+ // Dynamically import the SVG if not cached
5817
+ try {
5818
+ //TODO: This path is too specific to our repo, it won't work for users
5819
+ const response = await fetch(`/src/icons/${name}.svg`);
5820
+ if (response.ok) {
5821
+ const svgContent = await response.text();
5822
+ // Render the SVG
5823
+ // this.renderSvg(svgContent);
5824
+ this._svgContent = svgContent;
5825
+ }
5826
+ }
5827
+ catch (error) {
5828
+ console.error(`Error loading SVG: ${name}`, error);
5829
+ }
5830
+ }
5831
+ }
5832
+ render() {
5833
+ return html `${unsafeSVG(this._svgContent)}`;
5834
+ }
5835
+ }
5836
+ SgdsIcon.styles = [...SgdsElement.styles, css_248z];
5837
+ __decorate([
5838
+ property({ type: String, reflect: true })
5839
+ ], SgdsIcon.prototype, "name", void 0);
5840
+ __decorate([
5841
+ property({ type: String, reflect: true })
5842
+ ], SgdsIcon.prototype, "size", void 0);
5843
+ __decorate([
5844
+ state()
5845
+ ], SgdsIcon.prototype, "_svgContent", void 0);
5846
+
5847
+ /**
5848
+ * @summary The quantity toggle component is used to increase or decrease an incremental venue, best used when the user needs to enter or adjust the quantity of a selected item.
5339
5849
  *
5340
5850
  * @event sgds-change - Emitted when an alteration to the control's value is committed by the user.
5341
5851
  * @event sgds-input - Emitted when the control receives input and its value changes.
5342
5852
  *
5343
5853
  */
5344
- class SgdsQuantityToggle extends FormControlElement {
5854
+ class SgdsQuantityToggle extends SgdsFormValidatorMixin(ScopedElementsMixin(FormControlElement)) {
5345
5855
  constructor() {
5346
5856
  super(...arguments);
5347
- /** @internal */
5348
- this.formSubmitController = new FormSubmitController(this);
5349
5857
  /** Controls the size of the quantity toggle */
5350
5858
  this.size = "md";
5351
5859
  /** The input's value. Set to 0 by default */
5352
5860
  this.value = 0;
5353
- /** Disables the entire quantity toggle */
5354
- this.disabled = false;
5355
- /** The quantity toggle's button variants */
5356
- this.iconButtonVariant = "ghost";
5861
+ // /** The quantity toggle's button variants */
5862
+ // @property({ type: String }) iconButtonVariant = "ghost";
5357
5863
  /** Controls the incremental / decremental value of the input */
5358
5864
  this.step = 1;
5359
5865
  /** Gets or sets the default value used to reset this element. The initial value corresponds to the one originally specified in the HTML that created this element. */
5360
5866
  this.defaultValue = 0;
5361
- /** @internal The id forwarded to input element */
5362
- this.inputId = genId("quantity-toggle", "input");
5363
5867
  }
5364
5868
  /** @internal */
5365
5869
  static get scopedElements() {
5366
5870
  return {
5367
5871
  "sgds-input": SgdsInput,
5368
- "sgds-icon-button": SgdsIconButton
5872
+ "sgds-icon-button": SgdsIconButton,
5873
+ "sgds-icon": SgdsIcon
5369
5874
  };
5370
5875
  }
5371
- _handleChange() {
5372
- if (parseInt(this.input.value) < this.step || this.input.value === "") {
5373
- this.input.value = "0";
5876
+ /**
5877
+ * Checks for validity. Under the hood, HTMLFormElement's reportValidity method calls this method to check for component's validity state
5878
+ * Note that the native error popup is prevented for SGDS form components by default. Instead the validation message shows up in the feedback container of SgdsInput
5879
+ */
5880
+ reportValidity() {
5881
+ return this._mixinReportValidity();
5882
+ }
5883
+ /**
5884
+ * Checks for validity without any native error popup message
5885
+ */
5886
+ checkValidity() {
5887
+ return this._mixinCheckValidity();
5888
+ }
5889
+ /**
5890
+ * Returns the ValidityState object
5891
+ */
5892
+ get validity() {
5893
+ return this._mixinGetValidity();
5894
+ }
5895
+ /**
5896
+ * Returns the validation message based on the ValidityState
5897
+ */
5898
+ get validationMessage() {
5899
+ return this._mixinGetValidationMessage();
5900
+ }
5901
+ async _handleChange() {
5902
+ const sgdsInput = await this._sgdsInput;
5903
+ if (parseInt(sgdsInput.value) < this.step || sgdsInput.value === "") {
5904
+ sgdsInput.value = "0";
5905
+ }
5906
+ this.value = parseInt(sgdsInput.value);
5907
+ this._mixinSetFormValue();
5908
+ this._mixinValidate(sgdsInput.input);
5909
+ this.invalid = !this._mixinReportValidity();
5910
+ }
5911
+ async _handleInputChange() {
5912
+ const sgdsInput = await this._sgdsInput;
5913
+ this.invalid = false;
5914
+ if (parseInt(sgdsInput.value) < this.step || sgdsInput.value === "") {
5915
+ sgdsInput.value = "0";
5374
5916
  }
5375
- this.value = parseInt(this.input.value);
5917
+ this.value = parseInt(sgdsInput.value);
5918
+ this._mixinSetFormValue();
5919
+ this._mixinValidate(sgdsInput.input);
5920
+ }
5921
+ async _mixinResetFormControl() {
5922
+ const sgdsInput = await this._sgdsInput;
5923
+ this.value = this.defaultValue;
5924
+ sgdsInput.input.value = this.value.toString();
5925
+ this._mixinResetValidity(sgdsInput.input);
5376
5926
  }
5377
5927
  _handleKeyDown(event) {
5378
5928
  const allowedKeys = [
@@ -5389,6 +5939,12 @@
5389
5939
  event.preventDefault();
5390
5940
  }
5391
5941
  }
5942
+ _handleInvalid() {
5943
+ this.invalid = true;
5944
+ }
5945
+ _handleValid() {
5946
+ this.invalid = false;
5947
+ }
5392
5948
  /** Simulates a click on the plus button */
5393
5949
  plus() {
5394
5950
  this.plusBtn.click();
@@ -5397,23 +5953,41 @@
5397
5953
  minus() {
5398
5954
  this.minusBtn.click();
5399
5955
  }
5400
- _onPlus(event) {
5956
+ async _onPlus(event) {
5957
+ const sgdsInput = await this._sgdsInput;
5401
5958
  event.preventDefault();
5402
5959
  event.stopPropagation();
5403
- this.value = parseInt(this.input.value) + parseInt(this.input.step);
5960
+ this.value = parseInt(sgdsInput.value) + parseInt(sgdsInput.step.toString());
5961
+ this._validateOnClick(sgdsInput.input);
5404
5962
  }
5405
- _onMinus(event) {
5963
+ async _onMinus(event) {
5964
+ const sgdsInput = await this._sgdsInput;
5406
5965
  event.preventDefault();
5407
5966
  event.stopPropagation();
5408
5967
  if (this.value < this.step) {
5409
5968
  this.value = 0;
5410
5969
  }
5411
5970
  else {
5412
- this.value = parseInt(this.input.value) - parseInt(this.input.step);
5971
+ this.value = parseInt(sgdsInput.value) - parseInt(sgdsInput.step.toString());
5413
5972
  }
5973
+ this._validateOnClick(sgdsInput.input);
5974
+ }
5975
+ /**
5976
+ * Validates the input on button clicks of the toggle.
5977
+ * Input is validated every time the button is click to update the invalid state
5978
+ * to indiciate the validity of quantity toggle
5979
+ * @param input native HTMLInputElement
5980
+ */
5981
+ async _validateOnClick(input) {
5982
+ const sgdsInput = await this._sgdsInput;
5983
+ await sgdsInput.updateComplete;
5984
+ this._mixinSetFormValue();
5985
+ this._mixinValidate(input);
5986
+ this.invalid = !this._mixinReportValidity();
5414
5987
  }
5415
5988
  _renderFeedback() {
5416
- return this.invalid && this.hasFeedback
5989
+ const wantFeedbackText = this.hasFeedback === "both" || this.hasFeedback === "text";
5990
+ return this.invalid && wantFeedbackText
5417
5991
  ? html ` <div class="invalid-feedback-container">
5418
5992
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
5419
5993
  <path
@@ -5421,17 +5995,20 @@
5421
5995
  fill="#B90000"
5422
5996
  />
5423
5997
  </svg>
5424
- <div id="${this.inputId}-invalid" class="invalid-feedback">${this.invalidFeedback}</div>
5998
+ <div id="${this._controlId}-invalid" class="invalid-feedback">
5999
+ ${this.invalidFeedback ? this.invalidFeedback : this.validationMessage}
6000
+ </div>
5425
6001
  </div>`
5426
6002
  : html `${this._renderHintText()}`;
5427
6003
  }
5428
6004
  _renderLabel() {
5429
6005
  const labelTemplate = html `
5430
6006
  <label
5431
- for=${this.inputId}
5432
- id=${this.labelId}
6007
+ for=${this._controlId}
6008
+ id=${this._labelId}
5433
6009
  class=${classMap({
5434
- "form-label": true
6010
+ "form-label": true,
6011
+ disabled: this.disabled
5435
6012
  })}
5436
6013
  >${this.label}</label
5437
6014
  >
@@ -5439,30 +6016,22 @@
5439
6016
  return this.label && labelTemplate;
5440
6017
  }
5441
6018
  _renderHintText() {
5442
- const hintTextTemplate = html ` <div id="${this.inputId}Help" class="form-text">${this.hintText}</div> `;
6019
+ const hintTextTemplate = html ` <div id="${this._controlId}Help" class="form-text">${this.hintText}</div> `;
5443
6020
  return this.hintText && hintTextTemplate;
5444
6021
  }
5445
6022
  render() {
5446
6023
  return html `
5447
6024
  <div class="form-control-container">
5448
6025
  ${this._renderLabel()}
5449
- <div
5450
- part="base"
5451
- class="${classMap({
5452
- disabled: this.disabled,
5453
- "input-group": true,
5454
- [`input-group-${this.size}`]: this.size
5455
- })}"
5456
- variant="quantity-toggle"
5457
- size=${this.size}
5458
- >
6026
+ <div class="input-group">
5459
6027
  <sgds-icon-button
5460
- variant=${this.iconButtonVariant}
6028
+ variant="ghost"
5461
6029
  ariaLabel=${`decrease by ${this.step}`}
5462
- part="button"
5463
6030
  ?disabled=${this.disabled || (this.min !== undefined ? this.value <= this.min : this.value < 1)}
5464
6031
  @click=${this._onMinus}
5465
- ></sgds-icon-button>
6032
+ >
6033
+ <sgds-icon name="dash"></sgds-icon>
6034
+ </sgds-icon-button>
5466
6035
  <sgds-input
5467
6036
  type="number"
5468
6037
  class="quantity-toggle"
@@ -5470,21 +6039,24 @@
5470
6039
  step=${ifDefined(this.step)}
5471
6040
  min=${ifDefined(this.min)}
5472
6041
  max=${ifDefined(this.max)}
5473
- .value=${live(this.value.toString())}
5474
- @sgds-change=${() => this._handleChange()}
5475
- @sgds-input=${() => this._handleChange()}
6042
+ .value=${live(this.value)}
6043
+ @sgds-change=${this._handleChange}
6044
+ @sgds-input=${this._handleInputChange}
6045
+ @sgds-invalid=${this._handleInvalid}
6046
+ @sgds-valid=${this._handleValid}
5476
6047
  @keydown=${this._handleKeyDown}
5477
6048
  ?disabled=${this.disabled}
6049
+ id=${this._controlId}
5478
6050
  ?invalid=${this.invalid}
5479
- id=${this.inputId}
6051
+ hasFeedback=${ifDefined(this.hasFeedback !== "text" ? "style" : undefined)}
5480
6052
  ></sgds-input>
5481
6053
  <sgds-icon-button
5482
- variant=${this.iconButtonVariant}
6054
+ variant="ghost"
5483
6055
  ariaLabel=${`increase by ${this.step}`}
5484
- part="button"
5485
6056
  @click=${this._onPlus}
5486
6057
  ?disabled=${this.disabled || (this.max !== undefined && this.max && this.value >= this.max)}
5487
- ></sgds-icon-button>
6058
+ ><sgds-icon name="plus"></sgds-icon>
6059
+ </sgds-icon-button>
5488
6060
  </div>
5489
6061
  <div id="announcer" role="region" aria-live="assertive" class="visually-hidden">${this.value}</div>
5490
6062
  ${this._renderFeedback()}
@@ -5492,10 +6064,7 @@
5492
6064
  `;
5493
6065
  }
5494
6066
  }
5495
- SgdsQuantityToggle.styles = [...FormControlElement.styles, css_248z, css_248z$4];
5496
- __decorate([
5497
- query("sgds-input")
5498
- ], SgdsQuantityToggle.prototype, "input", void 0);
6067
+ SgdsQuantityToggle.styles = [...FormControlElement.styles, css_248z$9, css_248z$7, css_248z$1];
5499
6068
  __decorate([
5500
6069
  query("sgds-icon-button[ariaLabel^='increase by']")
5501
6070
  ], SgdsQuantityToggle.prototype, "plusBtn", void 0);
@@ -5508,18 +6077,27 @@
5508
6077
  __decorate([
5509
6078
  property({ type: Number, reflect: true })
5510
6079
  ], SgdsQuantityToggle.prototype, "value", void 0);
5511
- __decorate([
5512
- property({ type: Boolean, reflect: true })
5513
- ], SgdsQuantityToggle.prototype, "disabled", void 0);
5514
- __decorate([
5515
- property({ type: String })
5516
- ], SgdsQuantityToggle.prototype, "iconButtonVariant", void 0);
5517
6080
  __decorate([
5518
6081
  property({ type: Number })
5519
6082
  ], SgdsQuantityToggle.prototype, "step", void 0);
6083
+ __decorate([
6084
+ property()
6085
+ ], SgdsQuantityToggle.prototype, "min", void 0);
6086
+ __decorate([
6087
+ property()
6088
+ ], SgdsQuantityToggle.prototype, "max", void 0);
6089
+ __decorate([
6090
+ property({ type: String, reflect: true })
6091
+ ], SgdsQuantityToggle.prototype, "hasFeedback", void 0);
6092
+ __decorate([
6093
+ property({ type: String, reflect: true })
6094
+ ], SgdsQuantityToggle.prototype, "invalidFeedback", void 0);
5520
6095
  __decorate([
5521
6096
  defaultValue()
5522
6097
  ], SgdsQuantityToggle.prototype, "defaultValue", void 0);
6098
+ __decorate([
6099
+ queryAsync("sgds-input")
6100
+ ], SgdsQuantityToggle.prototype, "_sgdsInput", void 0);
5523
6101
 
5524
6102
  customElements.define("sgds-quantity-toggle", SgdsQuantityToggle);
5525
6103