@propelinc/citrus-ui 0.6.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. package/README.md +54 -60
  2. package/dist/colors/colors.d.ts +31 -0
  3. package/dist/colors/theme.d.ts +2 -11
  4. package/dist/colors/util-classes.d.ts +11 -0
  5. package/dist/components/CAccordion.vue.d.ts +21 -0
  6. package/dist/components/CAccordionItem.vue.d.ts +41 -0
  7. package/dist/components/CAppBar.vue.d.ts +156 -0
  8. package/dist/components/CBadge.vue.d.ts +52 -0
  9. package/dist/components/CBottomSheet.vue.d.ts +226 -0
  10. package/dist/components/CButton/CButton.vue.d.ts +231 -0
  11. package/dist/components/CButton/types.d.ts +5 -0
  12. package/dist/components/CButtonStack.vue.d.ts +24 -0
  13. package/dist/components/CCard.vue.d.ts +107 -0
  14. package/dist/components/CCardFooter.vue.d.ts +26 -0
  15. package/dist/components/CCardHeader.vue.d.ts +3 -0
  16. package/dist/components/CCardSection.vue.d.ts +17 -0
  17. package/dist/components/CCheckbox.vue.d.ts +145 -0
  18. package/dist/components/CCol.vue.d.ts +21 -0
  19. package/dist/components/CDivider.vue.d.ts +17 -0
  20. package/dist/components/CDobField.vue.d.ts +2109 -0
  21. package/dist/components/CDobSelect.vue.d.ts +398 -0
  22. package/dist/components/CEmailField.vue.d.ts +699 -0
  23. package/dist/components/CExpandTransition.vue.d.ts +19 -0
  24. package/dist/components/CFadeTransition.vue.d.ts +3 -0
  25. package/dist/components/CFileInput.vue.d.ts +98 -0
  26. package/dist/components/CFixedPageFooter.vue.d.ts +106 -0
  27. package/dist/components/CForm.vue.d.ts +29 -0
  28. package/dist/components/CFormFieldCounter.vue.d.ts +42 -0
  29. package/dist/components/CIconButton.vue.d.ts +390 -0
  30. package/dist/components/CLabel.vue.d.ts +32 -0
  31. package/dist/components/CListItem.vue.d.ts +208 -0
  32. package/dist/components/CListItemContent.vue.d.ts +27 -0
  33. package/dist/components/CListItemIcon.vue.d.ts +54 -0
  34. package/dist/components/CLoader.vue.d.ts +73 -0
  35. package/dist/components/CLogo.vue.d.ts +19 -0
  36. package/dist/components/CMaskedTextField.vue.d.ts +2012 -0
  37. package/dist/components/CMenu.vue.d.ts +6 -0
  38. package/dist/components/CMenuItem.vue.d.ts +170 -0
  39. package/dist/components/CMenuLabel.vue.d.ts +3 -0
  40. package/dist/components/CModal.vue.d.ts +206 -0
  41. package/dist/components/CModalLoading.vue.d.ts +230 -0
  42. package/dist/components/CNotification.vue.d.ts +589 -0
  43. package/dist/components/CPhoneField.vue.d.ts +2088 -0
  44. package/dist/components/CPill.vue.d.ts +42 -0
  45. package/dist/components/CPillGroup.vue.d.ts +70 -0
  46. package/dist/components/CPopup.vue.d.ts +21 -0
  47. package/dist/components/CProgressLinear.vue.d.ts +61 -0
  48. package/dist/components/CProgressRing.vue.d.ts +103 -0
  49. package/dist/components/CRadio.vue.d.ts +73 -0
  50. package/dist/components/CRadioGroup.vue.d.ts +123 -0
  51. package/dist/components/CRebrand.vue.d.ts +28 -0
  52. package/dist/components/CRow.vue.d.ts +67 -0
  53. package/dist/components/CSafeArea.vue.d.ts +18 -0
  54. package/dist/components/CSectionHeader.vue.d.ts +28 -0
  55. package/dist/components/CSelect.vue.d.ts +293 -0
  56. package/dist/components/CSkeleton.vue.d.ts +3 -0
  57. package/dist/components/CSkeletonLoaderCard.vue.d.ts +21 -0
  58. package/dist/components/CSkeletonLoaderCircle.vue.d.ts +5 -0
  59. package/dist/components/CSkeletonLoaderText.vue.d.ts +44 -0
  60. package/dist/components/CSlideFadeTransition.vue.d.ts +58 -0
  61. package/dist/components/CSplitInput.vue.d.ts +2131 -0
  62. package/dist/components/CSquaredIcon.vue.d.ts +47 -0
  63. package/dist/components/CSsnField.vue.d.ts +2083 -0
  64. package/dist/components/CStatusDot.vue.d.ts +27 -0
  65. package/dist/components/CSwitch.vue.d.ts +54 -0
  66. package/dist/components/CSwitchListItem.vue.d.ts +392 -0
  67. package/dist/components/CTextArea.vue.d.ts +240 -0
  68. package/dist/components/CTextField.vue.d.ts +647 -0
  69. package/dist/components/CTextLink.vue.d.ts +55 -0
  70. package/dist/components/CThirdPartyLogo.vue.d.ts +128 -0
  71. package/dist/components/CTimeago.vue.d.ts +12 -0
  72. package/dist/components/CToast.vue.d.ts +458 -0
  73. package/dist/components/CToastsList.vue.d.ts +430 -0
  74. package/dist/components/CValidationMessage.vue.d.ts +45 -0
  75. package/dist/components/CZipcodeField.vue.d.ts +2080 -0
  76. package/dist/components/index.d.ts +66 -25
  77. package/dist/components/internal/CCloseButton.vue.d.ts +14 -0
  78. package/dist/composables/accessibility.d.ts +1 -0
  79. package/dist/composables/animation.d.ts +12 -0
  80. package/dist/composables/binding.d.ts +19 -0
  81. package/dist/composables/colors.d.ts +13 -0
  82. package/dist/composables/elements.d.ts +3 -0
  83. package/dist/composables/fields.d.ts +9 -0
  84. package/dist/composables/gestures.d.ts +53 -0
  85. package/dist/composables/i18n.d.ts +3 -0
  86. package/dist/composables/id.d.ts +11 -0
  87. package/dist/composables/input-mask.d.ts +18 -0
  88. package/dist/composables/router.d.ts +30 -0
  89. package/dist/composables/slots.d.ts +2 -0
  90. package/dist/composables/toast.d.ts +21 -0
  91. package/dist/composables/validations.d.ts +77 -0
  92. package/dist/index.css +1 -0
  93. package/dist/index.d.ts +5 -4
  94. package/dist/index.mjs +11738 -0
  95. package/dist/index.mjs.map +1 -0
  96. package/dist/plugin.d.ts +2 -2
  97. package/dist/services/animation.d.ts +17 -0
  98. package/dist/services/directives/index.d.ts +2 -0
  99. package/dist/services/directives/scroll-into-view.d.ts +7 -0
  100. package/dist/services/directives/tap-animation.d.ts +6 -0
  101. package/dist/services/id.d.ts +22 -0
  102. package/dist/services/injections/accordions.d.ts +3 -0
  103. package/dist/services/injections/animations.d.ts +2 -0
  104. package/dist/services/injections/buttons.d.ts +4 -0
  105. package/dist/services/injections/forms.d.ts +6 -0
  106. package/dist/services/injections/icon-buttons.d.ts +3 -0
  107. package/dist/services/injections/pills.d.ts +4 -0
  108. package/dist/services/injections/radio.d.ts +10 -0
  109. package/dist/styles/main.css +3002 -0
  110. package/dist/styles/utils.css +2319 -0
  111. package/dist/theme/icons.d.ts +35 -2
  112. package/dist/types/CForm.d.ts +12 -0
  113. package/dist/types/font-awesome.d.ts +5 -0
  114. package/dist/types.d.ts +12 -0
  115. package/index.ts +2 -0
  116. package/package.json +60 -45
  117. package/src/assets/fonts/grenette-regular.woff2 +0 -0
  118. package/src/assets/fonts/grenette-semibold.woff2 +0 -0
  119. package/src/assets/fonts/polymath.woff2 +0 -0
  120. package/src/assets/logos/propel/icon.svg +15 -0
  121. package/src/assets/logos/propel/lockup.svg +11 -0
  122. package/src/colors/colors.ts +173 -0
  123. package/src/colors/theme.ts +8 -14
  124. package/src/colors/util-classes.ts +49 -0
  125. package/src/componentResolver.js +33 -0
  126. package/src/components/CAccordion.vue +32 -7
  127. package/src/components/CAccordionItem.vue +109 -36
  128. package/src/components/CAppBar.vue +237 -0
  129. package/src/components/CBadge.vue +74 -0
  130. package/src/components/CBottomSheet.vue +430 -0
  131. package/src/components/CButton/CButton.vue +347 -0
  132. package/src/components/CButton/types.ts +5 -0
  133. package/src/components/CButtonStack.vue +36 -0
  134. package/src/components/CCard.vue +149 -41
  135. package/src/components/CCardFooter.vue +11 -27
  136. package/src/components/CCardHeader.vue +30 -21
  137. package/src/components/CCardSection.vue +23 -12
  138. package/src/components/CCheckbox.vue +191 -21
  139. package/src/components/CCol.vue +55 -0
  140. package/src/components/CDivider.vue +46 -0
  141. package/src/components/CDobField.vue +153 -0
  142. package/src/components/CDobSelect.vue +274 -0
  143. package/src/components/CEmailField.vue +61 -0
  144. package/src/components/CExpandTransition.vue +55 -0
  145. package/src/components/CFadeTransition.vue +23 -0
  146. package/src/components/CFileInput.vue +186 -0
  147. package/src/components/CFixedPageFooter.vue +76 -0
  148. package/src/components/CForm.vue +86 -0
  149. package/src/components/CFormFieldCounter.vue +40 -0
  150. package/src/components/CIconButton.vue +175 -59
  151. package/src/components/CLabel.vue +52 -0
  152. package/src/components/CListItem.vue +149 -45
  153. package/src/components/CListItemContent.vue +60 -0
  154. package/src/components/CListItemIcon.vue +27 -31
  155. package/src/components/CLoader.vue +156 -0
  156. package/src/components/CLogo.vue +23 -0
  157. package/src/components/CMaskedTextField.vue +118 -0
  158. package/src/components/CMenu.vue +24 -0
  159. package/src/components/CMenuItem.vue +106 -0
  160. package/src/components/CMenuLabel.vue +26 -0
  161. package/src/components/CModal.vue +198 -79
  162. package/src/components/CModalLoading.vue +27 -9
  163. package/src/components/CNotification.vue +86 -53
  164. package/src/components/CPhoneField.vue +69 -0
  165. package/src/components/CPill.vue +162 -0
  166. package/src/components/CPillGroup.vue +73 -0
  167. package/src/components/CPopup.vue +66 -0
  168. package/src/components/CProgressLinear.vue +52 -0
  169. package/src/components/CProgressRing.vue +126 -0
  170. package/src/components/CRadio.vue +138 -0
  171. package/src/components/CRadioGroup.vue +142 -0
  172. package/src/components/CRebrand.vue +28 -0
  173. package/src/components/CRow.vue +62 -0
  174. package/src/components/CSafeArea.vue +23 -0
  175. package/src/components/CSectionHeader.vue +50 -0
  176. package/src/components/CSelect.vue +223 -74
  177. package/src/components/CSkeleton.vue +65 -0
  178. package/src/components/CSkeletonLoaderCard.vue +29 -0
  179. package/src/components/CSkeletonLoaderCircle.vue +18 -14
  180. package/src/components/CSkeletonLoaderText.vue +127 -17
  181. package/src/components/CSlideFadeTransition.vue +100 -0
  182. package/src/components/CSplitInput.vue +111 -0
  183. package/src/components/CSquaredIcon.vue +83 -0
  184. package/src/components/CSsnField.vue +86 -0
  185. package/src/components/CStatusDot.vue +70 -0
  186. package/src/components/CSwitch.vue +125 -0
  187. package/src/components/CSwitchListItem.vue +110 -0
  188. package/src/components/CTextArea.vue +193 -47
  189. package/src/components/CTextField.vue +450 -93
  190. package/src/components/CTextLink.vue +48 -38
  191. package/src/components/CThirdPartyLogo.vue +127 -0
  192. package/src/components/CTimeago.vue +63 -0
  193. package/src/components/CToast.vue +259 -0
  194. package/src/components/CToastsList.vue +32 -0
  195. package/src/components/CValidationMessage.vue +70 -0
  196. package/src/components/CZipcodeField.vue +69 -0
  197. package/src/components/index.ts +66 -25
  198. package/src/components/internal/CCloseButton.vue +57 -0
  199. package/src/composables/accessibility.ts +29 -0
  200. package/src/composables/animation.ts +95 -0
  201. package/src/composables/binding.ts +34 -0
  202. package/src/composables/colors.ts +59 -0
  203. package/src/composables/elements.ts +72 -0
  204. package/src/composables/fields.ts +19 -0
  205. package/src/composables/gestures.ts +197 -0
  206. package/src/composables/i18n.ts +13 -0
  207. package/src/composables/id.ts +23 -0
  208. package/src/composables/input-mask.ts +139 -0
  209. package/src/composables/router.ts +64 -0
  210. package/src/composables/slots.ts +57 -0
  211. package/src/composables/toast.ts +64 -0
  212. package/src/composables/validations.ts +214 -0
  213. package/src/index.ts +7 -7
  214. package/src/plugin.ts +13 -6
  215. package/src/services/animation.ts +101 -0
  216. package/src/services/directives/index.ts +2 -0
  217. package/src/services/directives/scroll-into-view.ts +86 -0
  218. package/src/services/directives/tap-animation.ts +71 -0
  219. package/src/services/id.ts +31 -0
  220. package/src/services/injections/accordions.ts +4 -0
  221. package/src/services/injections/animations.ts +3 -0
  222. package/src/services/injections/buttons.ts +5 -0
  223. package/src/services/injections/forms.ts +8 -0
  224. package/src/services/injections/icon-buttons.ts +4 -0
  225. package/src/services/injections/pills.ts +7 -0
  226. package/src/services/injections/radio.ts +12 -0
  227. package/src/shims-vue.d.ts +6 -3
  228. package/src/styles/_animation.scss +19 -0
  229. package/src/styles/_button.scss +61 -0
  230. package/src/styles/_colors.scss +58 -11
  231. package/src/styles/_core.scss +248 -87
  232. package/src/styles/_form-fields.scss +68 -15
  233. package/src/styles/_grenette.scss +13 -0
  234. package/src/styles/_polymath.scss +14 -0
  235. package/src/styles/_reset.scss +105 -0
  236. package/src/styles/_shoelace.scss +46 -0
  237. package/src/styles/_typography.scss +40 -10
  238. package/src/styles/main.scss +6 -3
  239. package/src/styles/utils/a11y.scss +18 -0
  240. package/src/styles/utils/typography.scss +13 -0
  241. package/src/styles/utils.scss +560 -0
  242. package/src/styles/variables.scss +27 -15
  243. package/src/theme/icons.ts +16 -5
  244. package/src/types/CForm.ts +15 -0
  245. package/src/types/font-awesome.ts +6 -0
  246. package/src/types.ts +15 -0
  247. package/.browserslistrc +0 -3
  248. package/.eslintrc.js +0 -4
  249. package/.stylelintrc.js +0 -3
  250. package/babel.config.js +0 -3
  251. package/dist/citrus-ui.common.js +0 -43434
  252. package/dist/citrus-ui.common.js.map +0 -1
  253. package/dist/citrus-ui.css +0 -1
  254. package/dist/citrus-ui.umd.js +0 -43444
  255. package/dist/citrus-ui.umd.js.map +0 -1
  256. package/dist/citrus-ui.umd.min.js +0 -27
  257. package/dist/citrus-ui.umd.min.js.map +0 -1
  258. package/dist/demo.html +0 -10
  259. package/dist/fonts/Blitz-Script.85ed9abe.woff2 +0 -0
  260. package/dist/fonts/ObjectSans-Bold.5492f3d5.woff2 +0 -0
  261. package/dist/fonts/ObjectSans-BoldSlanted.29e2a87e.woff2 +0 -0
  262. package/dist/fonts/ObjectSans-Heavy.d0b2f035.woff2 +0 -0
  263. package/dist/fonts/ObjectSans-HeavySlanted.45e9c063.woff2 +0 -0
  264. package/dist/fonts/ObjectSans-Light.f885dec3.woff2 +0 -0
  265. package/dist/fonts/ObjectSans-LightSlanted.b8eb7c12.woff2 +0 -0
  266. package/dist/fonts/ObjectSans-Regular.e4ea0b90.woff2 +0 -0
  267. package/dist/fonts/ObjectSans-Slanted.57a90be9.woff2 +0 -0
  268. package/dist/fonts/ObjectSans-Thin.86d44227.woff2 +0 -0
  269. package/dist/fonts/ObjectSans-ThinSlanted.20342160.woff2 +0 -0
  270. package/jest.config.js +0 -9
  271. package/plopfile.js +0 -67
  272. package/project.json +0 -69
  273. package/src/assets/fonts/Blitz-Script.woff2 +0 -0
  274. package/src/assets/fonts/ObjectSans-Bold.woff2 +0 -0
  275. package/src/assets/fonts/ObjectSans-BoldSlanted.woff2 +0 -0
  276. package/src/assets/fonts/ObjectSans-Heavy.woff2 +0 -0
  277. package/src/assets/fonts/ObjectSans-HeavySlanted.woff2 +0 -0
  278. package/src/assets/fonts/ObjectSans-Light.woff2 +0 -0
  279. package/src/assets/fonts/ObjectSans-LightSlanted.woff2 +0 -0
  280. package/src/assets/fonts/ObjectSans-Regular.woff2 +0 -0
  281. package/src/assets/fonts/ObjectSans-Slanted.woff2 +0 -0
  282. package/src/assets/fonts/ObjectSans-Thin.woff2 +0 -0
  283. package/src/assets/fonts/ObjectSans-ThinSlanted.woff2 +0 -0
  284. package/src/components/CAlert.vue +0 -78
  285. package/src/components/CBanner.vue +0 -47
  286. package/src/components/CButton.vue +0 -146
  287. package/src/components/CListItemAction.vue +0 -29
  288. package/src/components/CSegmentedButton.vue +0 -47
  289. package/src/components/CSegmentedButtonOption.vue +0 -42
  290. package/src/components/helpers/FormField.vue +0 -48
  291. package/src/components/helpers/SelectInput.vue +0 -115
  292. package/src/shims-scss.d.ts +0 -4
  293. package/src/shims-vuetify.d.ts +0 -4
  294. package/src/styles/_blitz.scss +0 -8
  295. package/src/styles/_object-sans.scss +0 -23
  296. package/storybook-static/0.799c368cbe88266827ba.manager.bundle.js +0 -1
  297. package/storybook-static/0.a9f0a9ad.iframe.bundle.js +0 -3
  298. package/storybook-static/0.a9f0a9ad.iframe.bundle.js.LICENSE.txt +0 -8
  299. package/storybook-static/0.a9f0a9ad.iframe.bundle.js.map +0 -1
  300. package/storybook-static/1.0438fd8d.iframe.bundle.js +0 -3
  301. package/storybook-static/1.0438fd8d.iframe.bundle.js.LICENSE.txt +0 -17
  302. package/storybook-static/1.0438fd8d.iframe.bundle.js.map +0 -1
  303. package/storybook-static/1.9ebd2fb519f6726108de.manager.bundle.js +0 -1
  304. package/storybook-static/10.348d8814.iframe.bundle.js +0 -3
  305. package/storybook-static/10.348d8814.iframe.bundle.js.LICENSE.txt +0 -30
  306. package/storybook-static/10.348d8814.iframe.bundle.js.map +0 -1
  307. package/storybook-static/10.a85ea1a67689be8e19ff.manager.bundle.js +0 -1
  308. package/storybook-static/11.f4e922583ae35da460f3.manager.bundle.js +0 -2
  309. package/storybook-static/11.f4e922583ae35da460f3.manager.bundle.js.LICENSE.txt +0 -12
  310. package/storybook-static/12.1415460941f0bdcb8fa8.manager.bundle.js +0 -1
  311. package/storybook-static/2.75a17459.iframe.bundle.js +0 -3
  312. package/storybook-static/2.75a17459.iframe.bundle.js.LICENSE.txt +0 -26
  313. package/storybook-static/2.75a17459.iframe.bundle.js.map +0 -1
  314. package/storybook-static/5.f459d151315e6780c20f.manager.bundle.js +0 -2
  315. package/storybook-static/5.f459d151315e6780c20f.manager.bundle.js.LICENSE.txt +0 -8
  316. package/storybook-static/6.3bd64d820f3745f262ff.manager.bundle.js +0 -1
  317. package/storybook-static/6.ce8d99b4.iframe.bundle.js +0 -1
  318. package/storybook-static/7.3d04765dbf3f1dcd706c.manager.bundle.js +0 -1
  319. package/storybook-static/7.6633a922.iframe.bundle.js +0 -3
  320. package/storybook-static/7.6633a922.iframe.bundle.js.LICENSE.txt +0 -12
  321. package/storybook-static/7.6633a922.iframe.bundle.js.map +0 -1
  322. package/storybook-static/8.b541eadfcb9164835dfc.manager.bundle.js +0 -1
  323. package/storybook-static/8.fc5e1ebf.iframe.bundle.js +0 -1
  324. package/storybook-static/9.411ac8e451bbb10926c7.manager.bundle.js +0 -1
  325. package/storybook-static/9.724ac3ed.iframe.bundle.js +0 -3
  326. package/storybook-static/9.724ac3ed.iframe.bundle.js.LICENSE.txt +0 -15
  327. package/storybook-static/9.724ac3ed.iframe.bundle.js.map +0 -1
  328. package/storybook-static/css/main.95216119.css +0 -1
  329. package/storybook-static/css/vendors~main.02dc89bf.css +0 -1
  330. package/storybook-static/favicon.ico +0 -0
  331. package/storybook-static/fonts/Blitz-Script.85ed9abe.woff2 +0 -0
  332. package/storybook-static/fonts/ObjectSans-Bold.5492f3d5.woff2 +0 -0
  333. package/storybook-static/fonts/ObjectSans-BoldSlanted.29e2a87e.woff2 +0 -0
  334. package/storybook-static/fonts/ObjectSans-Heavy.d0b2f035.woff2 +0 -0
  335. package/storybook-static/fonts/ObjectSans-HeavySlanted.45e9c063.woff2 +0 -0
  336. package/storybook-static/fonts/ObjectSans-Light.f885dec3.woff2 +0 -0
  337. package/storybook-static/fonts/ObjectSans-LightSlanted.b8eb7c12.woff2 +0 -0
  338. package/storybook-static/fonts/ObjectSans-Regular.e4ea0b90.woff2 +0 -0
  339. package/storybook-static/fonts/ObjectSans-Slanted.57a90be9.woff2 +0 -0
  340. package/storybook-static/fonts/ObjectSans-Thin.86d44227.woff2 +0 -0
  341. package/storybook-static/fonts/ObjectSans-ThinSlanted.20342160.woff2 +0 -0
  342. package/storybook-static/iframe.html +0 -348
  343. package/storybook-static/index.html +0 -51
  344. package/storybook-static/main.7b4aec9c4352d4bb535b.manager.bundle.js +0 -1
  345. package/storybook-static/main.9e8c64c7.iframe.bundle.js +0 -1
  346. package/storybook-static/runtime~main.91a0c7330ab317d35c4a.manager.bundle.js +0 -1
  347. package/storybook-static/runtime~main.e4da100f.iframe.bundle.js +0 -1
  348. package/storybook-static/vendors~main.6660eda6.iframe.bundle.js +0 -7
  349. package/storybook-static/vendors~main.6660eda6.iframe.bundle.js.LICENSE.txt +0 -80
  350. package/storybook-static/vendors~main.6660eda6.iframe.bundle.js.map +0 -1
  351. package/storybook-static/vendors~main.f7f16cebbf3aa96a4f89.manager.bundle.js +0 -2
  352. package/storybook-static/vendors~main.f7f16cebbf3aa96a4f89.manager.bundle.js.LICENSE.txt +0 -110
  353. package/tsconfig.dist.json +0 -7
  354. package/tsconfig.json +0 -24
  355. package/vue.config.js +0 -5
@@ -0,0 +1,430 @@
1
+ <!-- eslint-disable vue/no-deprecated-slot-attribute -->
2
+ <template>
3
+ <!--
4
+ For no-header prop below:
5
+ See https://vuejs.org/guide/extras/web-components#passing-dom-properties
6
+ Shoelace does not seem to properly specify the no-header prop; otherwise
7
+ a false value resolves to no-header="false" which is actually truthy
8
+ -->
9
+ <sl-drawer
10
+ ref="sheet"
11
+ class="c-bottom-sheet"
12
+ :class="{
13
+ 'c-bottom-sheet--hide-overlay': !overlay,
14
+ 'c-bottom-sheet--hide-title': hideTitle,
15
+ 'c-bottom-sheet--with-footer': footerHasContent,
16
+ 'c-bottom-sheet--with-dismiss': isDismissVisible,
17
+ }"
18
+ :style="{
19
+ '--panel-transform': panelTransform,
20
+ '--background-color-hex-code': backgroundCssColor,
21
+ '--overlay-opacity': overlayOpacity,
22
+ '--size': fixedSize || undefined,
23
+ }"
24
+ :data-test="getDataTestAttr()"
25
+ :open="animatedValue || undefined"
26
+ :no-header="hideTitle || undefined"
27
+ :label="ariaLabel"
28
+ placement="bottom"
29
+ :contained="contained || undefined"
30
+ :divided="divided || undefined"
31
+ @sl-request-close="onRequestClose"
32
+ @sl-hide="handleDismiss"
33
+ @sl-after-hide="onAfterClose"
34
+ @sl-after-show="$emit('opened')"
35
+ >
36
+ <div slot="label" :data-test="value ? `${dataTest}-title` : null">
37
+ <slot name="header">{{ title }}</slot>
38
+ </div>
39
+
40
+ <slot name="image" />
41
+
42
+ <div class="c-bottom-sheet__body" :data-test="getDataTestAttr('body')">
43
+ <slot name="body" />
44
+ </div>
45
+
46
+ <!-- NOTE(andrew): This renders in the body when the title is hidden because the header-actions
47
+ slot is not rendered when the title is hidden. Previously this only rendered in the body but
48
+ this caused issues on iOS where a scrollable body renders in a separate layer and the button
49
+ got rendered invisibly underneath the header. This is intentionally placed after the body so
50
+ it renders on top. -->
51
+ <div
52
+ v-if="isDismissVisible"
53
+ :slot="hideTitle ? undefined : 'header-actions'"
54
+ class="c-bottom-sheet__actions"
55
+ >
56
+ <c-close-button
57
+ :data-test="getDataTestAttr('dismiss')"
58
+ :disabled="disableDismiss"
59
+ @click="internalValue = false"
60
+ />
61
+ </div>
62
+
63
+ <CButtonStack v-if="footerHasContent" slot="footer" :data-test="getDataTestAttr('footer')">
64
+ <slot name="footer" />
65
+ </CButtonStack>
66
+ </sl-drawer>
67
+ </template>
68
+
69
+ <script lang="ts">
70
+ import { faXmark } from '@fortawesome/pro-regular-svg-icons';
71
+ import '@shoelace-style/shoelace/dist/components/drawer/drawer.js';
72
+ import type SlDrawer from '@shoelace-style/shoelace/dist/components/drawer/drawer.js';
73
+ import type { ElementAnimation } from '@shoelace-style/shoelace/dist/utilities/animation-registry.js';
74
+ import { setAnimation } from '@shoelace-style/shoelace/dist/utilities/animation-registry.js';
75
+ import type { Ref } from 'vue';
76
+ import { computed, defineComponent, nextTick, onMounted, ref, toRefs } from 'vue';
77
+
78
+ import CButtonStack from '@propelinc/citrus-ui/src/components/CButtonStack.vue';
79
+ import CCloseButton from '@propelinc/citrus-ui/src/components/internal/CCloseButton.vue';
80
+ import { useInternalValue } from '@propelinc/citrus-ui/src/composables/binding';
81
+ import { useCssColor } from '@propelinc/citrus-ui/src/composables/colors';
82
+ import { useShoelaceShadowParts } from '@propelinc/citrus-ui/src/composables/elements';
83
+ import {
84
+ useDragListener,
85
+ useElasticClamp,
86
+ useScrollBoundary,
87
+ } from '@propelinc/citrus-ui/src/composables/gestures';
88
+ import { useSlotHasContent } from '@propelinc/citrus-ui/src/composables/slots';
89
+ import { fadeIn, fadeOut, slideDown, slideUp } from '@propelinc/citrus-ui/src/services/animation';
90
+
91
+ /** Minimum distance, in pixels, the user has to drag for it to be considered a
92
+ * successful swipe. */
93
+ const MIN_SWIPE_DISTANCE = 100;
94
+ /** The minimum speed, in pixels per millisecond, the user has to drag down for
95
+ * it to be considered a successful swipe. */
96
+ const MIN_SWIPE_VELOCITY = 0.75;
97
+ /** The minimum speed, in pixels per millisecond, to animate the sheet sliding
98
+ * down after a successful swipe. */
99
+ const MIN_DISMISS_VELOCITY = 1.5;
100
+ /** Minimum duration, in milliseconds, for the slide down animation after a
101
+ * successful drag. */
102
+ const MIN_DISMISS_DURATION = 100;
103
+ /** Maximum distance the sheet can move in a direction it can't be dragged. */
104
+ const DRAG_CLAMP_DISTANCE = 240;
105
+ /** Fallback height for the sheet if the actual height is unknown. */
106
+ const SHEET_HEIGHT_FALLBACK = 300;
107
+
108
+ /**
109
+ * Was having issues with the useShoelaceAnimation composable not updating the animation quickly
110
+ * enough using the `watch` or `watchEffect` hooks, so we're just going to set the animations
111
+ * directly whenever we need to change the animation.
112
+ */
113
+ function setCustomAnimation(
114
+ el: Ref<Element | null>,
115
+ name: string,
116
+ animation: ElementAnimation
117
+ ): void {
118
+ if (!el.value) {
119
+ return;
120
+ }
121
+
122
+ setAnimation(el.value, name, animation);
123
+ }
124
+
125
+ export default defineComponent({
126
+ components: { CButtonStack, CCloseButton },
127
+ props: {
128
+ /** Aria label for the bottom sheet. This is required if title is hidden */
129
+ ariaLabel: { type: String, default: '' },
130
+ /** Background color of the bottom sheet */
131
+ backgroundColor: { type: String, default: '' },
132
+ /** Prefix for test selectors */
133
+ dataTest: { type: String, default: 'bottom-sheet' },
134
+ /** Disables the dismiss button */
135
+ disableDismiss: { type: Boolean, default: false },
136
+ /** Divided into header, body, and footer slots */
137
+ divided: { type: Boolean, default: false },
138
+ /** Fixed size, in CSS units. By default the drawer sizes itself to its contents. */
139
+ fixedSize: { type: String, default: '' },
140
+ /** Hides the dismiss 'x' button */
141
+ hideDismiss: { type: Boolean, default: false },
142
+ /** Allows for hiding the entire title bar, both the title and the dismiss 'x' button */
143
+ hideTitle: { type: Boolean, default: false },
144
+ /** Toggles the background behind the sheet. If there's no overlay, the sheet
145
+ * stays open as the user interacts with background content.' */
146
+ overlay: { type: Boolean, default: true },
147
+ /** Prevents the sheet from being dismissed when tapping on the overlay. If
148
+ * there is no overlay then this property is ignored, as the sheet always
149
+ * stays open. */
150
+ persistent: { type: Boolean, default: false },
151
+ /** If true, the bottom sheet will be contained within the viewport. */
152
+ contained: { type: Boolean, default: false },
153
+ /** Do not animate in the bottom sheet if it starts open. */
154
+ skipInitialAnimation: { type: Boolean, default: false },
155
+ /** The title of the bottom sheet */
156
+ title: { type: String, default: '' },
157
+ /** Controls whether or not the bottom sheet is showing */
158
+ value: { type: Boolean, default: false },
159
+ },
160
+ emits: ['input', 'opened', 'closed'],
161
+ setup(props, { emit }) {
162
+ // NOTE(slanden): Temporarily disabling because it's causing a lot of errors
163
+ // in the console - uses from CMS aren't specifying aria-label.
164
+ // watchEffect(() => {
165
+ // if (props.hideTitle && !props.ariaLabel) {
166
+ // console.error('CBottomSheet: aria-label is required when title is hidden');
167
+ // }
168
+ // });
169
+
170
+ // value: Value provided using props which can open/close the bottom sheet.
171
+ // internalValue: Tracks the open/closed state and lets the bottom sheet open and close even if
172
+ // the external value doesn't change.
173
+ // animatedValue: Same as internalValue but starts at false so the bottom sheet animates if it
174
+ // starts in an open state.
175
+ const { value } = toRefs(props);
176
+ const internalValue = useInternalValue(value, { onChange: (value) => emit('input', value) });
177
+ const mounted = ref(false);
178
+ const animatedValue = computed(() => {
179
+ // To animate in the bottom sheet we mount the component with the sheet closed.
180
+ if (!props.skipInitialAnimation && !mounted.value) {
181
+ return false;
182
+ }
183
+ return internalValue.value;
184
+ });
185
+ const { cssColor: backgroundCssColor } = useCssColor(() => props.backgroundColor);
186
+ onMounted(async () => {
187
+ // The bottom sheet does not animate unless we wait a tick. We don't know exactly why this
188
+ // is necessary.
189
+ await nextTick();
190
+ mounted.value = true;
191
+ });
192
+
193
+ const sheet = ref<SlDrawer | null>(null);
194
+ const { panel, overlay, body } = useShoelaceShadowParts(sheet, ['panel', 'overlay', 'body']);
195
+ useScrollBoundary(body);
196
+
197
+ // NOTE(mohan): There are three parts to the bottom sheet animation:
198
+ // 1. CSS variables. These are used when we want to set the exact height and
199
+ // opacity, i.e. when the user is actively moving the sheet.
200
+ // 2. The built-in Shoelace show and hide animations. If a user has swiped
201
+ // the sheet away, we calculate the exact animation that will smoothly
202
+ // continue the swipe and then dismiss the shoelace drawer.
203
+ // 3. Manually-called web animations. These are used when the sheet is being
204
+ // restored to its original position after a drag that was not fast or
205
+ // long enough to count as a swipe.
206
+ setCustomAnimation(sheet, 'drawer.showBottom', slideUp());
207
+ setCustomAnimation(sheet, 'drawer.overlay.show', fadeIn());
208
+ setCustomAnimation(sheet, 'drawer.hideBottom', slideDown());
209
+ setCustomAnimation(sheet, 'drawer.overlay.hide', fadeOut());
210
+
211
+ const handleDismiss = (): void => {
212
+ internalValue.value = false;
213
+ };
214
+
215
+ const onRequestClose = (event: Event): void => {
216
+ if (props.persistent) {
217
+ event.preventDefault();
218
+ }
219
+ };
220
+
221
+ const onAfterClose = (): void => {
222
+ // Reset the exit animations in case they were changed in a drag event
223
+ setCustomAnimation(sheet, 'drawer.hideBottom', slideDown());
224
+ setCustomAnimation(sheet, 'drawer.overlay.hide', fadeOut());
225
+ emit('closed');
226
+ };
227
+
228
+ /**
229
+ * Helper function to calculate the distance ratio of the sheet's transform.
230
+ */
231
+ const getTransformDistanceRatio = (distance: number): number => {
232
+ return distance / (panel.value?.clientHeight ?? SHEET_HEIGHT_FALLBACK);
233
+ };
234
+
235
+ const { dragDistance } = useDragListener(panel, {
236
+ onDragEnd: async ({ distance, velocity }) => {
237
+ const shouldDismiss =
238
+ !props.persistent && (distance.y > MIN_SWIPE_DISTANCE || velocity.y > MIN_SWIPE_VELOCITY);
239
+
240
+ if (shouldDismiss) {
241
+ const remainingDismissDistance = panel.value!.clientHeight - dragDistance.value!.y;
242
+ const dismissDuration = Math.max(
243
+ remainingDismissDistance / Math.max(velocity.y, MIN_DISMISS_VELOCITY),
244
+ MIN_DISMISS_DURATION
245
+ );
246
+ const dismissStart = getTransformDistanceRatio(distance.y);
247
+
248
+ // Here we set the custom animations to complete the dismissal animation smoothly
249
+ // from the point where the user ended their drag event.
250
+ setCustomAnimation(
251
+ sheet,
252
+ 'drawer.hideBottom',
253
+ slideDown({ start: dismissStart, duration: dismissDuration })
254
+ );
255
+ setCustomAnimation(
256
+ sheet,
257
+ 'drawer.overlay.hide',
258
+ fadeOut({ start: dismissStart, duration: dismissDuration })
259
+ );
260
+ handleDismiss();
261
+ } else {
262
+ /**
263
+ * This is when the user's drag event fails to trigger a dismissal
264
+ * We need to restore the sheet to its original position
265
+ */
266
+ const start = 1 - getTransformDistanceRatio(dragDistance.value!.y);
267
+ const slideUpAnimation = slideUp({ start });
268
+ const fadeInAnimation = fadeIn({ start });
269
+
270
+ // Here we imperatively animate the sheet and overlay back to their original positions
271
+ panel.value?.animate(slideUpAnimation.keyframes, slideUpAnimation.options);
272
+ overlay.value?.animate(fadeInAnimation.keyframes, fadeInAnimation.options);
273
+ }
274
+ },
275
+ });
276
+
277
+ /**
278
+ * The distance that the sheet has been currently dragged
279
+ */
280
+ const transformDistance = useElasticClamp(
281
+ computed(() => dragDistance.value?.y ?? 0),
282
+ computed(() => ({
283
+ min: -DRAG_CLAMP_DISTANCE,
284
+ max: props.persistent ? DRAG_CLAMP_DISTANCE : undefined,
285
+ }))
286
+ );
287
+
288
+ const transformDistanceRatio = computed(() =>
289
+ getTransformDistanceRatio(transformDistance.value)
290
+ );
291
+
292
+ const panelTransform = computed(() => `translateY(${transformDistance.value}px)`);
293
+
294
+ const overlayOpacity = computed(() => {
295
+ const result = 1 - transformDistanceRatio.value;
296
+
297
+ if (isNaN(result)) {
298
+ return 1;
299
+ }
300
+
301
+ return result;
302
+ });
303
+
304
+ // NOTE(mohan): We show data-test attributes only when the sheet is open.
305
+ // This helps simplify testing assertions.
306
+ const getDataTestAttr = (suffix?: string): string | null => {
307
+ const dataTest = suffix ? `${props.dataTest}-${suffix}` : props.dataTest;
308
+ return internalValue.value ? dataTest : null;
309
+ };
310
+
311
+ const footerHasContent = useSlotHasContent('footer');
312
+
313
+ const isDismissVisible = computed(
314
+ () => (!props.persistent && !props.hideDismiss) || props.disableDismiss
315
+ );
316
+
317
+ return {
318
+ backgroundCssColor,
319
+ animatedValue,
320
+ dragDistance,
321
+ faXmark,
322
+ footerHasContent,
323
+ getDataTestAttr,
324
+ handleDismiss,
325
+ internalValue,
326
+ isDismissVisible,
327
+ onRequestClose,
328
+ overlayOpacity,
329
+ panelTransform,
330
+ onAfterClose,
331
+ sheet,
332
+ transformDistance,
333
+ };
334
+ },
335
+ });
336
+ </script>
337
+
338
+ <style lang="scss" scoped>
339
+ @import '@propelinc/citrus-ui/src/styles/core';
340
+ @import '@propelinc/citrus-ui/src/styles/utils/a11y';
341
+
342
+ .c-bottom-sheet {
343
+ --size: auto;
344
+ --header-spacing: 24px;
345
+ --body-spacing: 0;
346
+ --bottom-padding: max(env(safe-area-inset-bottom, 0px), 16px);
347
+ --footer-spacing: 12px 24px var(--bottom-padding);
348
+
349
+ &::part(header-actions) {
350
+ padding: 0;
351
+ }
352
+
353
+ &::part(close-button) {
354
+ @include sr-only;
355
+ }
356
+
357
+ &::part(panel) {
358
+ background: var(--background-color-hex-code, $color-white);
359
+ border-radius: 12px 12px 0 0;
360
+ max-height: 90%;
361
+ overflow: visible;
362
+ transform: var(--panel-transform, none);
363
+
364
+ &::after {
365
+ background: var(--background-color-hex-code, $color-white);
366
+ bottom: -100px;
367
+ content: '';
368
+ height: 101px;
369
+ left: 0;
370
+ position: absolute;
371
+ right: 0;
372
+ }
373
+ }
374
+
375
+ &::part(body) {
376
+ border-radius: 12px 12px 0 0;
377
+
378
+ /**
379
+ * NOTE (kyleshevlin) adding position: relative here fixed an issue where certain actions (like
380
+ * clicking a checkbox) would hijack the bottom sheet body up and off the screen.
381
+ */
382
+ position: relative;
383
+ }
384
+
385
+ &::part(title) {
386
+ @include large-headline;
387
+
388
+ padding-bottom: 16px;
389
+ }
390
+
391
+ // Note(kayliegh): Add space to prevent long titles from colliding with dismiss button
392
+ &--with-dismiss::part(title) {
393
+ margin-right: 28px;
394
+ }
395
+
396
+ &::part(overlay) {
397
+ opacity: var(--overlay-opacity, 1);
398
+ }
399
+ }
400
+
401
+ .c-bottom-sheet__actions {
402
+ position: absolute;
403
+ right: 16px;
404
+ top: 16px;
405
+ }
406
+
407
+ .c-bottom-sheet__body {
408
+ padding: 0 24px var(--bottom-padding);
409
+
410
+ // NOTE(andrew): When there is a footer the bottom inset is handled by the footer and we just add
411
+ // spacing above the footer.
412
+ .c-bottom-sheet--with-footer & {
413
+ padding-bottom: 12px;
414
+ }
415
+ }
416
+
417
+ .c-bottom-sheet--hide-title {
418
+ // NOTE(mohan): When there is no title, we need to add some spacing to the top
419
+ // of the body so it doesn't touch the top of the panel.
420
+ .c-bottom-sheet__body {
421
+ padding-top: 16px;
422
+ }
423
+ }
424
+
425
+ .c-bottom-sheet--hide-overlay {
426
+ &::part(overlay) {
427
+ display: none;
428
+ }
429
+ }
430
+ </style>