@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.
- package/README.md +54 -60
- package/dist/colors/colors.d.ts +31 -0
- package/dist/colors/theme.d.ts +2 -11
- package/dist/colors/util-classes.d.ts +11 -0
- package/dist/components/CAccordion.vue.d.ts +21 -0
- package/dist/components/CAccordionItem.vue.d.ts +41 -0
- package/dist/components/CAppBar.vue.d.ts +156 -0
- package/dist/components/CBadge.vue.d.ts +52 -0
- package/dist/components/CBottomSheet.vue.d.ts +226 -0
- package/dist/components/CButton/CButton.vue.d.ts +231 -0
- package/dist/components/CButton/types.d.ts +5 -0
- package/dist/components/CButtonStack.vue.d.ts +24 -0
- package/dist/components/CCard.vue.d.ts +107 -0
- package/dist/components/CCardFooter.vue.d.ts +26 -0
- package/dist/components/CCardHeader.vue.d.ts +3 -0
- package/dist/components/CCardSection.vue.d.ts +17 -0
- package/dist/components/CCheckbox.vue.d.ts +145 -0
- package/dist/components/CCol.vue.d.ts +21 -0
- package/dist/components/CDivider.vue.d.ts +17 -0
- package/dist/components/CDobField.vue.d.ts +2109 -0
- package/dist/components/CDobSelect.vue.d.ts +398 -0
- package/dist/components/CEmailField.vue.d.ts +699 -0
- package/dist/components/CExpandTransition.vue.d.ts +19 -0
- package/dist/components/CFadeTransition.vue.d.ts +3 -0
- package/dist/components/CFileInput.vue.d.ts +98 -0
- package/dist/components/CFixedPageFooter.vue.d.ts +106 -0
- package/dist/components/CForm.vue.d.ts +29 -0
- package/dist/components/CFormFieldCounter.vue.d.ts +42 -0
- package/dist/components/CIconButton.vue.d.ts +390 -0
- package/dist/components/CLabel.vue.d.ts +32 -0
- package/dist/components/CListItem.vue.d.ts +208 -0
- package/dist/components/CListItemContent.vue.d.ts +27 -0
- package/dist/components/CListItemIcon.vue.d.ts +54 -0
- package/dist/components/CLoader.vue.d.ts +73 -0
- package/dist/components/CLogo.vue.d.ts +19 -0
- package/dist/components/CMaskedTextField.vue.d.ts +2012 -0
- package/dist/components/CMenu.vue.d.ts +6 -0
- package/dist/components/CMenuItem.vue.d.ts +170 -0
- package/dist/components/CMenuLabel.vue.d.ts +3 -0
- package/dist/components/CModal.vue.d.ts +206 -0
- package/dist/components/CModalLoading.vue.d.ts +230 -0
- package/dist/components/CNotification.vue.d.ts +589 -0
- package/dist/components/CPhoneField.vue.d.ts +2088 -0
- package/dist/components/CPill.vue.d.ts +42 -0
- package/dist/components/CPillGroup.vue.d.ts +70 -0
- package/dist/components/CPopup.vue.d.ts +21 -0
- package/dist/components/CProgressLinear.vue.d.ts +61 -0
- package/dist/components/CProgressRing.vue.d.ts +103 -0
- package/dist/components/CRadio.vue.d.ts +73 -0
- package/dist/components/CRadioGroup.vue.d.ts +123 -0
- package/dist/components/CRebrand.vue.d.ts +28 -0
- package/dist/components/CRow.vue.d.ts +67 -0
- package/dist/components/CSafeArea.vue.d.ts +18 -0
- package/dist/components/CSectionHeader.vue.d.ts +28 -0
- package/dist/components/CSelect.vue.d.ts +293 -0
- package/dist/components/CSkeleton.vue.d.ts +3 -0
- package/dist/components/CSkeletonLoaderCard.vue.d.ts +21 -0
- package/dist/components/CSkeletonLoaderCircle.vue.d.ts +5 -0
- package/dist/components/CSkeletonLoaderText.vue.d.ts +44 -0
- package/dist/components/CSlideFadeTransition.vue.d.ts +58 -0
- package/dist/components/CSplitInput.vue.d.ts +2131 -0
- package/dist/components/CSquaredIcon.vue.d.ts +47 -0
- package/dist/components/CSsnField.vue.d.ts +2083 -0
- package/dist/components/CStatusDot.vue.d.ts +27 -0
- package/dist/components/CSwitch.vue.d.ts +54 -0
- package/dist/components/CSwitchListItem.vue.d.ts +392 -0
- package/dist/components/CTextArea.vue.d.ts +240 -0
- package/dist/components/CTextField.vue.d.ts +647 -0
- package/dist/components/CTextLink.vue.d.ts +55 -0
- package/dist/components/CThirdPartyLogo.vue.d.ts +128 -0
- package/dist/components/CTimeago.vue.d.ts +12 -0
- package/dist/components/CToast.vue.d.ts +458 -0
- package/dist/components/CToastsList.vue.d.ts +430 -0
- package/dist/components/CValidationMessage.vue.d.ts +45 -0
- package/dist/components/CZipcodeField.vue.d.ts +2080 -0
- package/dist/components/index.d.ts +66 -25
- package/dist/components/internal/CCloseButton.vue.d.ts +14 -0
- package/dist/composables/accessibility.d.ts +1 -0
- package/dist/composables/animation.d.ts +12 -0
- package/dist/composables/binding.d.ts +19 -0
- package/dist/composables/colors.d.ts +13 -0
- package/dist/composables/elements.d.ts +3 -0
- package/dist/composables/fields.d.ts +9 -0
- package/dist/composables/gestures.d.ts +53 -0
- package/dist/composables/i18n.d.ts +3 -0
- package/dist/composables/id.d.ts +11 -0
- package/dist/composables/input-mask.d.ts +18 -0
- package/dist/composables/router.d.ts +30 -0
- package/dist/composables/slots.d.ts +2 -0
- package/dist/composables/toast.d.ts +21 -0
- package/dist/composables/validations.d.ts +77 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.mjs +11738 -0
- package/dist/index.mjs.map +1 -0
- package/dist/plugin.d.ts +2 -2
- package/dist/services/animation.d.ts +17 -0
- package/dist/services/directives/index.d.ts +2 -0
- package/dist/services/directives/scroll-into-view.d.ts +7 -0
- package/dist/services/directives/tap-animation.d.ts +6 -0
- package/dist/services/id.d.ts +22 -0
- package/dist/services/injections/accordions.d.ts +3 -0
- package/dist/services/injections/animations.d.ts +2 -0
- package/dist/services/injections/buttons.d.ts +4 -0
- package/dist/services/injections/forms.d.ts +6 -0
- package/dist/services/injections/icon-buttons.d.ts +3 -0
- package/dist/services/injections/pills.d.ts +4 -0
- package/dist/services/injections/radio.d.ts +10 -0
- package/dist/styles/main.css +3002 -0
- package/dist/styles/utils.css +2319 -0
- package/dist/theme/icons.d.ts +35 -2
- package/dist/types/CForm.d.ts +12 -0
- package/dist/types/font-awesome.d.ts +5 -0
- package/dist/types.d.ts +12 -0
- package/index.ts +2 -0
- package/package.json +60 -45
- package/src/assets/fonts/grenette-regular.woff2 +0 -0
- package/src/assets/fonts/grenette-semibold.woff2 +0 -0
- package/src/assets/fonts/polymath.woff2 +0 -0
- package/src/assets/logos/propel/icon.svg +15 -0
- package/src/assets/logos/propel/lockup.svg +11 -0
- package/src/colors/colors.ts +173 -0
- package/src/colors/theme.ts +8 -14
- package/src/colors/util-classes.ts +49 -0
- package/src/componentResolver.js +33 -0
- package/src/components/CAccordion.vue +32 -7
- package/src/components/CAccordionItem.vue +109 -36
- package/src/components/CAppBar.vue +237 -0
- package/src/components/CBadge.vue +74 -0
- package/src/components/CBottomSheet.vue +430 -0
- package/src/components/CButton/CButton.vue +347 -0
- package/src/components/CButton/types.ts +5 -0
- package/src/components/CButtonStack.vue +36 -0
- package/src/components/CCard.vue +149 -41
- package/src/components/CCardFooter.vue +11 -27
- package/src/components/CCardHeader.vue +30 -21
- package/src/components/CCardSection.vue +23 -12
- package/src/components/CCheckbox.vue +191 -21
- package/src/components/CCol.vue +55 -0
- package/src/components/CDivider.vue +46 -0
- package/src/components/CDobField.vue +153 -0
- package/src/components/CDobSelect.vue +274 -0
- package/src/components/CEmailField.vue +61 -0
- package/src/components/CExpandTransition.vue +55 -0
- package/src/components/CFadeTransition.vue +23 -0
- package/src/components/CFileInput.vue +186 -0
- package/src/components/CFixedPageFooter.vue +76 -0
- package/src/components/CForm.vue +86 -0
- package/src/components/CFormFieldCounter.vue +40 -0
- package/src/components/CIconButton.vue +175 -59
- package/src/components/CLabel.vue +52 -0
- package/src/components/CListItem.vue +149 -45
- package/src/components/CListItemContent.vue +60 -0
- package/src/components/CListItemIcon.vue +27 -31
- package/src/components/CLoader.vue +156 -0
- package/src/components/CLogo.vue +23 -0
- package/src/components/CMaskedTextField.vue +118 -0
- package/src/components/CMenu.vue +24 -0
- package/src/components/CMenuItem.vue +106 -0
- package/src/components/CMenuLabel.vue +26 -0
- package/src/components/CModal.vue +198 -79
- package/src/components/CModalLoading.vue +27 -9
- package/src/components/CNotification.vue +86 -53
- package/src/components/CPhoneField.vue +69 -0
- package/src/components/CPill.vue +162 -0
- package/src/components/CPillGroup.vue +73 -0
- package/src/components/CPopup.vue +66 -0
- package/src/components/CProgressLinear.vue +52 -0
- package/src/components/CProgressRing.vue +126 -0
- package/src/components/CRadio.vue +138 -0
- package/src/components/CRadioGroup.vue +142 -0
- package/src/components/CRebrand.vue +28 -0
- package/src/components/CRow.vue +62 -0
- package/src/components/CSafeArea.vue +23 -0
- package/src/components/CSectionHeader.vue +50 -0
- package/src/components/CSelect.vue +223 -74
- package/src/components/CSkeleton.vue +65 -0
- package/src/components/CSkeletonLoaderCard.vue +29 -0
- package/src/components/CSkeletonLoaderCircle.vue +18 -14
- package/src/components/CSkeletonLoaderText.vue +127 -17
- package/src/components/CSlideFadeTransition.vue +100 -0
- package/src/components/CSplitInput.vue +111 -0
- package/src/components/CSquaredIcon.vue +83 -0
- package/src/components/CSsnField.vue +86 -0
- package/src/components/CStatusDot.vue +70 -0
- package/src/components/CSwitch.vue +125 -0
- package/src/components/CSwitchListItem.vue +110 -0
- package/src/components/CTextArea.vue +193 -47
- package/src/components/CTextField.vue +450 -93
- package/src/components/CTextLink.vue +48 -38
- package/src/components/CThirdPartyLogo.vue +127 -0
- package/src/components/CTimeago.vue +63 -0
- package/src/components/CToast.vue +259 -0
- package/src/components/CToastsList.vue +32 -0
- package/src/components/CValidationMessage.vue +70 -0
- package/src/components/CZipcodeField.vue +69 -0
- package/src/components/index.ts +66 -25
- package/src/components/internal/CCloseButton.vue +57 -0
- package/src/composables/accessibility.ts +29 -0
- package/src/composables/animation.ts +95 -0
- package/src/composables/binding.ts +34 -0
- package/src/composables/colors.ts +59 -0
- package/src/composables/elements.ts +72 -0
- package/src/composables/fields.ts +19 -0
- package/src/composables/gestures.ts +197 -0
- package/src/composables/i18n.ts +13 -0
- package/src/composables/id.ts +23 -0
- package/src/composables/input-mask.ts +139 -0
- package/src/composables/router.ts +64 -0
- package/src/composables/slots.ts +57 -0
- package/src/composables/toast.ts +64 -0
- package/src/composables/validations.ts +214 -0
- package/src/index.ts +7 -7
- package/src/plugin.ts +13 -6
- package/src/services/animation.ts +101 -0
- package/src/services/directives/index.ts +2 -0
- package/src/services/directives/scroll-into-view.ts +86 -0
- package/src/services/directives/tap-animation.ts +71 -0
- package/src/services/id.ts +31 -0
- package/src/services/injections/accordions.ts +4 -0
- package/src/services/injections/animations.ts +3 -0
- package/src/services/injections/buttons.ts +5 -0
- package/src/services/injections/forms.ts +8 -0
- package/src/services/injections/icon-buttons.ts +4 -0
- package/src/services/injections/pills.ts +7 -0
- package/src/services/injections/radio.ts +12 -0
- package/src/shims-vue.d.ts +6 -3
- package/src/styles/_animation.scss +19 -0
- package/src/styles/_button.scss +61 -0
- package/src/styles/_colors.scss +58 -11
- package/src/styles/_core.scss +248 -87
- package/src/styles/_form-fields.scss +68 -15
- package/src/styles/_grenette.scss +13 -0
- package/src/styles/_polymath.scss +14 -0
- package/src/styles/_reset.scss +105 -0
- package/src/styles/_shoelace.scss +46 -0
- package/src/styles/_typography.scss +40 -10
- package/src/styles/main.scss +6 -3
- package/src/styles/utils/a11y.scss +18 -0
- package/src/styles/utils/typography.scss +13 -0
- package/src/styles/utils.scss +560 -0
- package/src/styles/variables.scss +27 -15
- package/src/theme/icons.ts +16 -5
- package/src/types/CForm.ts +15 -0
- package/src/types/font-awesome.ts +6 -0
- package/src/types.ts +15 -0
- package/.browserslistrc +0 -3
- package/.eslintrc.js +0 -4
- package/.stylelintrc.js +0 -3
- package/babel.config.js +0 -3
- package/dist/citrus-ui.common.js +0 -43434
- package/dist/citrus-ui.common.js.map +0 -1
- package/dist/citrus-ui.css +0 -1
- package/dist/citrus-ui.umd.js +0 -43444
- package/dist/citrus-ui.umd.js.map +0 -1
- package/dist/citrus-ui.umd.min.js +0 -27
- package/dist/citrus-ui.umd.min.js.map +0 -1
- package/dist/demo.html +0 -10
- package/dist/fonts/Blitz-Script.85ed9abe.woff2 +0 -0
- package/dist/fonts/ObjectSans-Bold.5492f3d5.woff2 +0 -0
- package/dist/fonts/ObjectSans-BoldSlanted.29e2a87e.woff2 +0 -0
- package/dist/fonts/ObjectSans-Heavy.d0b2f035.woff2 +0 -0
- package/dist/fonts/ObjectSans-HeavySlanted.45e9c063.woff2 +0 -0
- package/dist/fonts/ObjectSans-Light.f885dec3.woff2 +0 -0
- package/dist/fonts/ObjectSans-LightSlanted.b8eb7c12.woff2 +0 -0
- package/dist/fonts/ObjectSans-Regular.e4ea0b90.woff2 +0 -0
- package/dist/fonts/ObjectSans-Slanted.57a90be9.woff2 +0 -0
- package/dist/fonts/ObjectSans-Thin.86d44227.woff2 +0 -0
- package/dist/fonts/ObjectSans-ThinSlanted.20342160.woff2 +0 -0
- package/jest.config.js +0 -9
- package/plopfile.js +0 -67
- package/project.json +0 -69
- package/src/assets/fonts/Blitz-Script.woff2 +0 -0
- package/src/assets/fonts/ObjectSans-Bold.woff2 +0 -0
- package/src/assets/fonts/ObjectSans-BoldSlanted.woff2 +0 -0
- package/src/assets/fonts/ObjectSans-Heavy.woff2 +0 -0
- package/src/assets/fonts/ObjectSans-HeavySlanted.woff2 +0 -0
- package/src/assets/fonts/ObjectSans-Light.woff2 +0 -0
- package/src/assets/fonts/ObjectSans-LightSlanted.woff2 +0 -0
- package/src/assets/fonts/ObjectSans-Regular.woff2 +0 -0
- package/src/assets/fonts/ObjectSans-Slanted.woff2 +0 -0
- package/src/assets/fonts/ObjectSans-Thin.woff2 +0 -0
- package/src/assets/fonts/ObjectSans-ThinSlanted.woff2 +0 -0
- package/src/components/CAlert.vue +0 -78
- package/src/components/CBanner.vue +0 -47
- package/src/components/CButton.vue +0 -146
- package/src/components/CListItemAction.vue +0 -29
- package/src/components/CSegmentedButton.vue +0 -47
- package/src/components/CSegmentedButtonOption.vue +0 -42
- package/src/components/helpers/FormField.vue +0 -48
- package/src/components/helpers/SelectInput.vue +0 -115
- package/src/shims-scss.d.ts +0 -4
- package/src/shims-vuetify.d.ts +0 -4
- package/src/styles/_blitz.scss +0 -8
- package/src/styles/_object-sans.scss +0 -23
- package/storybook-static/0.799c368cbe88266827ba.manager.bundle.js +0 -1
- package/storybook-static/0.a9f0a9ad.iframe.bundle.js +0 -3
- package/storybook-static/0.a9f0a9ad.iframe.bundle.js.LICENSE.txt +0 -8
- package/storybook-static/0.a9f0a9ad.iframe.bundle.js.map +0 -1
- package/storybook-static/1.0438fd8d.iframe.bundle.js +0 -3
- package/storybook-static/1.0438fd8d.iframe.bundle.js.LICENSE.txt +0 -17
- package/storybook-static/1.0438fd8d.iframe.bundle.js.map +0 -1
- package/storybook-static/1.9ebd2fb519f6726108de.manager.bundle.js +0 -1
- package/storybook-static/10.348d8814.iframe.bundle.js +0 -3
- package/storybook-static/10.348d8814.iframe.bundle.js.LICENSE.txt +0 -30
- package/storybook-static/10.348d8814.iframe.bundle.js.map +0 -1
- package/storybook-static/10.a85ea1a67689be8e19ff.manager.bundle.js +0 -1
- package/storybook-static/11.f4e922583ae35da460f3.manager.bundle.js +0 -2
- package/storybook-static/11.f4e922583ae35da460f3.manager.bundle.js.LICENSE.txt +0 -12
- package/storybook-static/12.1415460941f0bdcb8fa8.manager.bundle.js +0 -1
- package/storybook-static/2.75a17459.iframe.bundle.js +0 -3
- package/storybook-static/2.75a17459.iframe.bundle.js.LICENSE.txt +0 -26
- package/storybook-static/2.75a17459.iframe.bundle.js.map +0 -1
- package/storybook-static/5.f459d151315e6780c20f.manager.bundle.js +0 -2
- package/storybook-static/5.f459d151315e6780c20f.manager.bundle.js.LICENSE.txt +0 -8
- package/storybook-static/6.3bd64d820f3745f262ff.manager.bundle.js +0 -1
- package/storybook-static/6.ce8d99b4.iframe.bundle.js +0 -1
- package/storybook-static/7.3d04765dbf3f1dcd706c.manager.bundle.js +0 -1
- package/storybook-static/7.6633a922.iframe.bundle.js +0 -3
- package/storybook-static/7.6633a922.iframe.bundle.js.LICENSE.txt +0 -12
- package/storybook-static/7.6633a922.iframe.bundle.js.map +0 -1
- package/storybook-static/8.b541eadfcb9164835dfc.manager.bundle.js +0 -1
- package/storybook-static/8.fc5e1ebf.iframe.bundle.js +0 -1
- package/storybook-static/9.411ac8e451bbb10926c7.manager.bundle.js +0 -1
- package/storybook-static/9.724ac3ed.iframe.bundle.js +0 -3
- package/storybook-static/9.724ac3ed.iframe.bundle.js.LICENSE.txt +0 -15
- package/storybook-static/9.724ac3ed.iframe.bundle.js.map +0 -1
- package/storybook-static/css/main.95216119.css +0 -1
- package/storybook-static/css/vendors~main.02dc89bf.css +0 -1
- package/storybook-static/favicon.ico +0 -0
- package/storybook-static/fonts/Blitz-Script.85ed9abe.woff2 +0 -0
- package/storybook-static/fonts/ObjectSans-Bold.5492f3d5.woff2 +0 -0
- package/storybook-static/fonts/ObjectSans-BoldSlanted.29e2a87e.woff2 +0 -0
- package/storybook-static/fonts/ObjectSans-Heavy.d0b2f035.woff2 +0 -0
- package/storybook-static/fonts/ObjectSans-HeavySlanted.45e9c063.woff2 +0 -0
- package/storybook-static/fonts/ObjectSans-Light.f885dec3.woff2 +0 -0
- package/storybook-static/fonts/ObjectSans-LightSlanted.b8eb7c12.woff2 +0 -0
- package/storybook-static/fonts/ObjectSans-Regular.e4ea0b90.woff2 +0 -0
- package/storybook-static/fonts/ObjectSans-Slanted.57a90be9.woff2 +0 -0
- package/storybook-static/fonts/ObjectSans-Thin.86d44227.woff2 +0 -0
- package/storybook-static/fonts/ObjectSans-ThinSlanted.20342160.woff2 +0 -0
- package/storybook-static/iframe.html +0 -348
- package/storybook-static/index.html +0 -51
- package/storybook-static/main.7b4aec9c4352d4bb535b.manager.bundle.js +0 -1
- package/storybook-static/main.9e8c64c7.iframe.bundle.js +0 -1
- package/storybook-static/runtime~main.91a0c7330ab317d35c4a.manager.bundle.js +0 -1
- package/storybook-static/runtime~main.e4da100f.iframe.bundle.js +0 -1
- package/storybook-static/vendors~main.6660eda6.iframe.bundle.js +0 -7
- package/storybook-static/vendors~main.6660eda6.iframe.bundle.js.LICENSE.txt +0 -80
- package/storybook-static/vendors~main.6660eda6.iframe.bundle.js.map +0 -1
- package/storybook-static/vendors~main.f7f16cebbf3aa96a4f89.manager.bundle.js +0 -2
- package/storybook-static/vendors~main.f7f16cebbf3aa96a4f89.manager.bundle.js.LICENSE.txt +0 -110
- package/tsconfig.dist.json +0 -7
- package/tsconfig.json +0 -24
- package/vue.config.js +0 -5
package/src/components/index.ts
CHANGED
|
@@ -1,25 +1,66 @@
|
|
|
1
|
-
export { default as CAccordion } from '
|
|
2
|
-
export { default as CAccordionItem } from '
|
|
3
|
-
export { default as
|
|
4
|
-
export { default as
|
|
5
|
-
export { default as
|
|
6
|
-
export { default as
|
|
7
|
-
export { default as
|
|
8
|
-
export { default as
|
|
9
|
-
export { default as
|
|
10
|
-
export { default as
|
|
11
|
-
export { default as
|
|
12
|
-
export { default as
|
|
13
|
-
export { default as
|
|
14
|
-
export { default as
|
|
15
|
-
export { default as
|
|
16
|
-
export { default as
|
|
17
|
-
export { default as
|
|
18
|
-
export { default as
|
|
19
|
-
export { default as
|
|
20
|
-
export { default as
|
|
21
|
-
export { default as
|
|
22
|
-
export { default as
|
|
23
|
-
export { default as
|
|
24
|
-
export { default as
|
|
25
|
-
export { default as
|
|
1
|
+
export { default as CAccordion } from '@propelinc/citrus-ui/src/components/CAccordion.vue';
|
|
2
|
+
export { default as CAccordionItem } from '@propelinc/citrus-ui/src/components/CAccordionItem.vue';
|
|
3
|
+
export { default as CAppBar } from '@propelinc/citrus-ui/src/components/CAppBar.vue';
|
|
4
|
+
export { default as CBadge } from '@propelinc/citrus-ui/src/components/CBadge.vue';
|
|
5
|
+
export { default as CBottomSheet } from '@propelinc/citrus-ui/src/components/CBottomSheet.vue';
|
|
6
|
+
export { default as CButton } from '@propelinc/citrus-ui/src/components/CButton/CButton.vue';
|
|
7
|
+
export { default as CCard } from '@propelinc/citrus-ui/src/components/CCard.vue';
|
|
8
|
+
export { default as CCardFooter } from '@propelinc/citrus-ui/src/components/CCardFooter.vue';
|
|
9
|
+
export { default as CCardHeader } from '@propelinc/citrus-ui/src/components/CCardHeader.vue';
|
|
10
|
+
export { default as CCardSection } from '@propelinc/citrus-ui/src/components/CCardSection.vue';
|
|
11
|
+
export { default as CCheckbox } from '@propelinc/citrus-ui/src/components/CCheckbox.vue';
|
|
12
|
+
export { default as CCol } from '@propelinc/citrus-ui/src/components/CCol.vue';
|
|
13
|
+
export { default as CDivider } from '@propelinc/citrus-ui/src/components/CDivider.vue';
|
|
14
|
+
export { default as CDobField } from '@propelinc/citrus-ui/src/components/CDobField.vue';
|
|
15
|
+
export { default as CDobSelect } from '@propelinc/citrus-ui/src/components/CDobSelect.vue';
|
|
16
|
+
export { default as CEmailField } from '@propelinc/citrus-ui/src/components/CEmailField.vue';
|
|
17
|
+
export { default as CExpandTransition } from '@propelinc/citrus-ui/src/components/CExpandTransition.vue';
|
|
18
|
+
export { default as CFadeTransition } from '@propelinc/citrus-ui/src/components/CFadeTransition.vue';
|
|
19
|
+
export { default as CFileInput } from '@propelinc/citrus-ui/src/components/CFileInput.vue';
|
|
20
|
+
export { default as CFixedPageFooter } from '@propelinc/citrus-ui/src/components/CFixedPageFooter.vue';
|
|
21
|
+
export { default as CForm } from '@propelinc/citrus-ui/src/components/CForm.vue';
|
|
22
|
+
export { default as CIconButton } from '@propelinc/citrus-ui/src/components/CIconButton.vue';
|
|
23
|
+
export { default as CLabel } from '@propelinc/citrus-ui/src/components/CLabel.vue';
|
|
24
|
+
export { default as CListItem } from '@propelinc/citrus-ui/src/components/CListItem.vue';
|
|
25
|
+
export { default as CListItemIcon } from '@propelinc/citrus-ui/src/components/CListItemIcon.vue';
|
|
26
|
+
export { default as CLoader } from '@propelinc/citrus-ui/src/components/CLoader.vue';
|
|
27
|
+
export { default as CLogo } from '@propelinc/citrus-ui/src/components/CLogo.vue';
|
|
28
|
+
export { default as CMaskedTextField } from '@propelinc/citrus-ui/src/components/CMaskedTextField.vue';
|
|
29
|
+
export { default as CMenu } from '@propelinc/citrus-ui/src/components/CMenu.vue';
|
|
30
|
+
export { default as CMenuItem } from '@propelinc/citrus-ui/src/components/CMenuItem.vue';
|
|
31
|
+
export { default as CMenuLabel } from '@propelinc/citrus-ui/src/components/CMenuLabel.vue';
|
|
32
|
+
export { default as CModal } from '@propelinc/citrus-ui/src/components/CModal.vue';
|
|
33
|
+
export { default as CModalLoading } from '@propelinc/citrus-ui/src/components/CModalLoading.vue';
|
|
34
|
+
export { default as CNotification } from '@propelinc/citrus-ui/src/components/CNotification.vue';
|
|
35
|
+
export { default as CPhoneField } from '@propelinc/citrus-ui/src/components/CPhoneField.vue';
|
|
36
|
+
export { default as CPill } from '@propelinc/citrus-ui/src/components/CPill.vue';
|
|
37
|
+
export { default as CPillGroup } from '@propelinc/citrus-ui/src/components/CPillGroup.vue';
|
|
38
|
+
export { default as CPopup } from '@propelinc/citrus-ui/src/components/CPopup.vue';
|
|
39
|
+
export { default as CProgressLinear } from '@propelinc/citrus-ui/src/components/CProgressLinear.vue';
|
|
40
|
+
export { default as CProgressRing } from '@propelinc/citrus-ui/src/components/CProgressRing.vue';
|
|
41
|
+
export { default as CRadio } from '@propelinc/citrus-ui/src/components/CRadio.vue';
|
|
42
|
+
export { default as CRadioGroup } from '@propelinc/citrus-ui/src/components/CRadioGroup.vue';
|
|
43
|
+
export { default as CRebrand } from '@propelinc/citrus-ui/src/components/CRebrand.vue';
|
|
44
|
+
export { default as CRow } from '@propelinc/citrus-ui/src/components/CRow.vue';
|
|
45
|
+
export { default as CSafeArea } from '@propelinc/citrus-ui/src/components/CSafeArea.vue';
|
|
46
|
+
export { default as CSectionHeader } from '@propelinc/citrus-ui/src/components/CSectionHeader.vue';
|
|
47
|
+
export { default as CSelect } from '@propelinc/citrus-ui/src/components/CSelect.vue';
|
|
48
|
+
export { default as CSkeleton } from '@propelinc/citrus-ui/src/components/CSkeleton.vue';
|
|
49
|
+
export { default as CSkeletonLoaderCard } from '@propelinc/citrus-ui/src/components/CSkeletonLoaderCard.vue';
|
|
50
|
+
export { default as CSkeletonLoaderCircle } from '@propelinc/citrus-ui/src/components/CSkeletonLoaderCircle.vue';
|
|
51
|
+
export { default as CSkeletonLoaderText } from '@propelinc/citrus-ui/src/components/CSkeletonLoaderText.vue';
|
|
52
|
+
export { default as CSlideFadeTransition } from '@propelinc/citrus-ui/src/components/CSlideFadeTransition.vue';
|
|
53
|
+
export { default as CSplitInput } from '@propelinc/citrus-ui/src/components/CSplitInput.vue';
|
|
54
|
+
export { default as CSquaredIcon } from '@propelinc/citrus-ui/src/components/CSquaredIcon.vue';
|
|
55
|
+
export { default as CSsnField } from '@propelinc/citrus-ui/src/components/CSsnField.vue';
|
|
56
|
+
export { default as CStatusDot } from '@propelinc/citrus-ui/src/components/CStatusDot.vue';
|
|
57
|
+
export { default as CSwitch } from '@propelinc/citrus-ui/src/components/CSwitch.vue';
|
|
58
|
+
export { default as CSwitchListItem } from '@propelinc/citrus-ui/src/components/CSwitchListItem.vue';
|
|
59
|
+
export { default as CTextArea } from '@propelinc/citrus-ui/src/components/CTextArea.vue';
|
|
60
|
+
export { default as CTextField } from '@propelinc/citrus-ui/src/components/CTextField.vue';
|
|
61
|
+
export { default as CTextLink } from '@propelinc/citrus-ui/src/components/CTextLink.vue';
|
|
62
|
+
export { default as CThirdPartyLogo } from '@propelinc/citrus-ui/src/components/CThirdPartyLogo.vue';
|
|
63
|
+
export { default as CTimeago } from '@propelinc/citrus-ui/src/components/CTimeago.vue';
|
|
64
|
+
export { default as CToast } from '@propelinc/citrus-ui/src/components/CToast.vue';
|
|
65
|
+
export { default as CToastsList } from '@propelinc/citrus-ui/src/components/CToastsList.vue';
|
|
66
|
+
export { default as CZipcodeField } from '@propelinc/citrus-ui/src/components/CZipcodeField.vue';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button
|
|
3
|
+
v-tap-animation
|
|
4
|
+
class="c-close-button"
|
|
5
|
+
data-test="c-close-button"
|
|
6
|
+
:aria-label="$t('Close')"
|
|
7
|
+
:disabled="disabled"
|
|
8
|
+
@click="onClick"
|
|
9
|
+
>
|
|
10
|
+
<font-awesome-icon :icon="faXmark" />
|
|
11
|
+
</button>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { faXmark } from '@fortawesome/pro-regular-svg-icons';
|
|
16
|
+
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
|
17
|
+
|
|
18
|
+
import { tapAnimation as vTapAnimation } from '@propelinc/citrus-ui/src/services/directives';
|
|
19
|
+
|
|
20
|
+
defineProps<{
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
}>();
|
|
23
|
+
|
|
24
|
+
const emit = defineEmits(['click', 'focus', 'blur']);
|
|
25
|
+
|
|
26
|
+
const onClick = (): void => {
|
|
27
|
+
emit('click');
|
|
28
|
+
};
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<style lang="scss" scoped>
|
|
32
|
+
@import '@propelinc/citrus-ui/src/styles/core';
|
|
33
|
+
@import '@propelinc/citrus-ui/src/styles/button';
|
|
34
|
+
|
|
35
|
+
.c-close-button {
|
|
36
|
+
align-items: center;
|
|
37
|
+
border-radius: 50%;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
display: flex;
|
|
40
|
+
font-size: $font-size-icon-medium;
|
|
41
|
+
height: 36px;
|
|
42
|
+
justify-content: center;
|
|
43
|
+
padding: 8px;
|
|
44
|
+
width: 36px;
|
|
45
|
+
|
|
46
|
+
@include button-theme-close;
|
|
47
|
+
|
|
48
|
+
&:focus {
|
|
49
|
+
/**
|
|
50
|
+
* This is a workaround to get the focus ring to work with the button. Since we're not using Shoelace,
|
|
51
|
+
* we need to use the focus ring styles from Shoelace. Long term, we should create a custom focus ring styles.
|
|
52
|
+
*/
|
|
53
|
+
outline: var(--sl-focus-ring-width) solid var(--sl-focus-ring-color);
|
|
54
|
+
outline-offset: var(--sl-focus-ring-offset);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { onMounted, useAttrs } from 'vue';
|
|
2
|
+
|
|
3
|
+
export function useA11yLabelCheck(componentName: string, props?: Record<string, unknown>): void {
|
|
4
|
+
const attrs = useAttrs();
|
|
5
|
+
|
|
6
|
+
onMounted(() => {
|
|
7
|
+
const enableCheck = process.env.VUE_APP_DEBUG === 'yes' || process.env.NODE_ENV === 'test';
|
|
8
|
+
if (!enableCheck) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (
|
|
13
|
+
attrs.title ||
|
|
14
|
+
props?.title ||
|
|
15
|
+
attrs['aria-label'] ||
|
|
16
|
+
props?.ariaLabel ||
|
|
17
|
+
attrs['aria-labelledby'] ||
|
|
18
|
+
props?.ariaLabelledby ||
|
|
19
|
+
attrs['aria-hidden'] ||
|
|
20
|
+
props?.ariaHidden
|
|
21
|
+
) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.error(
|
|
26
|
+
`Missing ${componentName} label. This component won't be intelligible to screen readers. Typically, this is resolved by providing an aria-label.`
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { ElementAnimation } from '@shoelace-style/shoelace/dist/utilities/animation-registry.js';
|
|
2
|
+
import {
|
|
3
|
+
getAnimation,
|
|
4
|
+
setAnimation,
|
|
5
|
+
} from '@shoelace-style/shoelace/dist/utilities/animation-registry.js';
|
|
6
|
+
import type { Ref } from 'vue';
|
|
7
|
+
import { isRef, onMounted, ref, unref, watch } from 'vue';
|
|
8
|
+
|
|
9
|
+
type MaybeRef<T> = T | Ref<T>;
|
|
10
|
+
|
|
11
|
+
export function useShoelaceAnimation(
|
|
12
|
+
el: Ref<Element | null>,
|
|
13
|
+
animationName: string,
|
|
14
|
+
animation: MaybeRef<ElementAnimation | 'default' | null>
|
|
15
|
+
): void {
|
|
16
|
+
let defaultAnimation: ElementAnimation | null = null;
|
|
17
|
+
|
|
18
|
+
onMounted(() => {
|
|
19
|
+
if (el.value) {
|
|
20
|
+
defaultAnimation = getAnimation(el.value, animationName, { dir: 'ltr' });
|
|
21
|
+
|
|
22
|
+
const animationValue = unref(animation);
|
|
23
|
+
if (animationValue !== 'default') {
|
|
24
|
+
setAnimation(el.value, animationName, animationValue);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (isRef(animation)) {
|
|
30
|
+
watch(animation, () => {
|
|
31
|
+
if (el.value) {
|
|
32
|
+
const nextAnimation = animation.value === 'default' ? defaultAnimation : animation.value;
|
|
33
|
+
setAnimation(el.value, animationName, nextAnimation);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const TAP_ANIMATION_DURATION_MS = 100;
|
|
40
|
+
|
|
41
|
+
export function useTapAnimation({
|
|
42
|
+
el,
|
|
43
|
+
keyframes,
|
|
44
|
+
}: {
|
|
45
|
+
el: Ref<Element | null>;
|
|
46
|
+
keyframes: { default: Keyframe; pressed: Keyframe };
|
|
47
|
+
}): Record<string, () => void> {
|
|
48
|
+
const downAnimation = ref<Animation | null>(null);
|
|
49
|
+
const upAnimation = ref<Animation | null>(null);
|
|
50
|
+
|
|
51
|
+
function onPointerDown(): void {
|
|
52
|
+
if (!el.value) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
upAnimation.value?.cancel();
|
|
57
|
+
upAnimation.value = null;
|
|
58
|
+
|
|
59
|
+
downAnimation.value?.cancel();
|
|
60
|
+
downAnimation.value = el.value.animate([keyframes.default, keyframes.pressed], {
|
|
61
|
+
duration: TAP_ANIMATION_DURATION_MS,
|
|
62
|
+
fill: 'forwards',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function onPointerUp(): Promise<void> {
|
|
67
|
+
if (!downAnimation.value || upAnimation.value || !el.value) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// NOTE(mohan): Cancelling the animation will cause the finished promise to
|
|
72
|
+
// throw an error.
|
|
73
|
+
await downAnimation.value.finished.catch(() => {});
|
|
74
|
+
if (!el.value) {
|
|
75
|
+
// NOTE(slanden): This can happen if the element is removed from the DOM
|
|
76
|
+
// while the down animation is running.
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
upAnimation.value = el.value.animate([keyframes.pressed, keyframes.default], {
|
|
80
|
+
duration: TAP_ANIMATION_DURATION_MS,
|
|
81
|
+
fill: 'forwards',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await upAnimation.value.finished.catch(() => {});
|
|
85
|
+
upAnimation.value = null;
|
|
86
|
+
downAnimation.value = null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
pointerdown: onPointerDown,
|
|
91
|
+
pointerup: onPointerUp,
|
|
92
|
+
pointerleave: onPointerUp,
|
|
93
|
+
pointercancel: onPointerUp,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
import { ref, watch } from 'vue';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A composable that creates a ref that tracks the value of the provided ref.
|
|
6
|
+
*
|
|
7
|
+
* Whenever the provided ref changes, the returned ref updates, but not the
|
|
8
|
+
* other way around. When the returned ref changes, the `onChange` callback is
|
|
9
|
+
* called (if provided).
|
|
10
|
+
*
|
|
11
|
+
* Useful for components that need to respond both to user input and to
|
|
12
|
+
* programmatic changes.
|
|
13
|
+
*
|
|
14
|
+
* @param value - The value to bind to the internal value.
|
|
15
|
+
* @param options.onChange - A callback function that is called when the
|
|
16
|
+
* internal value changes.
|
|
17
|
+
* @returns A ref to the internal value.
|
|
18
|
+
*/
|
|
19
|
+
export function useInternalValue<T>(
|
|
20
|
+
value: Ref<T>,
|
|
21
|
+
options: { onChange?: (value: T) => void } = {}
|
|
22
|
+
): Ref<T> {
|
|
23
|
+
const internalValue = ref(value.value) as Ref<T>;
|
|
24
|
+
watch(value, (value) => {
|
|
25
|
+
internalValue.value = value;
|
|
26
|
+
});
|
|
27
|
+
watch(internalValue, (newInternalValue) => {
|
|
28
|
+
if (newInternalValue !== value.value) {
|
|
29
|
+
options.onChange?.(newInternalValue);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return internalValue;
|
|
34
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { MaybeRefOrGetter, Ref } from 'vue';
|
|
2
|
+
import { computed, toValue } from 'vue';
|
|
3
|
+
|
|
4
|
+
import Colors, {
|
|
5
|
+
type CssColor,
|
|
6
|
+
isColorKey,
|
|
7
|
+
isCssColor,
|
|
8
|
+
} from '@propelinc/citrus-ui/src/colors/colors';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Maps from a color name or hex code to its corresponding CSS color value.
|
|
12
|
+
* Gray neutrals resolve to rgba(); other palette colors are hex.
|
|
13
|
+
*
|
|
14
|
+
* @param name - The color to resolve. Can be in kebab case, SCREAMING_SNAKE_CASE, or a hex code from the palette.
|
|
15
|
+
* @returns The CSS color value (hex or rgba) and whether the color is valid.
|
|
16
|
+
*/
|
|
17
|
+
export function useCssColor(name: MaybeRefOrGetter<string | undefined>): {
|
|
18
|
+
cssColor: Ref<CssColor | undefined>;
|
|
19
|
+
isValidColor: Ref<boolean>;
|
|
20
|
+
} {
|
|
21
|
+
const normalizedColor = computed(() =>
|
|
22
|
+
isCssColor(toValue(name)) ? (toValue(name)?.toLowerCase() as CssColor) : undefined
|
|
23
|
+
);
|
|
24
|
+
const normalizedName = computed(() => {
|
|
25
|
+
if (!toValue(name)) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// If it is a CSS color already, we don't need to know its name
|
|
30
|
+
if (isCssColor(toValue(name))) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return toValue(name)?.replace(/-/g, '_').toUpperCase();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const cssColor = computed(() => {
|
|
38
|
+
// If we're given a color key, return the palette value (hex or rgba)
|
|
39
|
+
if (normalizedName.value && isColorKey(normalizedName.value)) {
|
|
40
|
+
return Colors[normalizedName.value];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// If we're given a CSS color AND it's in the palette, return it
|
|
44
|
+
if (
|
|
45
|
+
isCssColor(normalizedColor.value) &&
|
|
46
|
+
Object.values(Colors).includes(normalizedColor.value)
|
|
47
|
+
) {
|
|
48
|
+
return normalizedColor.value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return undefined;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const isValidColor = computed(() => {
|
|
55
|
+
return cssColor.value !== undefined;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return { cssColor, isValidColor };
|
|
59
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
|
3
|
+
|
|
4
|
+
// NOTE(mohan): A simplified port of vueuse/core's useResizeObserver.
|
|
5
|
+
// vueuse has type errors because our version of vue is so old.
|
|
6
|
+
export function useResizeObserver(
|
|
7
|
+
element: Ref<HTMLElement | null>,
|
|
8
|
+
callback: (entries: ResizeObserverEntry[]) => void
|
|
9
|
+
): void {
|
|
10
|
+
if (!('ResizeObserver' in window)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let observer: ResizeObserver | null = null;
|
|
15
|
+
|
|
16
|
+
watch(
|
|
17
|
+
element,
|
|
18
|
+
(value) => {
|
|
19
|
+
if (value) {
|
|
20
|
+
observer = new ResizeObserver(callback);
|
|
21
|
+
observer.observe(value);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{ immediate: true }
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
onBeforeUnmount(() => {
|
|
28
|
+
if (observer) {
|
|
29
|
+
observer.disconnect();
|
|
30
|
+
observer = null;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function useShoelaceShadowParts<T extends string>(
|
|
36
|
+
shoelaceComponent: Ref<HTMLElement | null>,
|
|
37
|
+
parts: T[]
|
|
38
|
+
): Record<T, Ref<HTMLElement | null>> {
|
|
39
|
+
const shadowParts = parts.reduce<Record<T, Ref<HTMLElement | null>>>(
|
|
40
|
+
(acc, part) => {
|
|
41
|
+
return { ...acc, [part]: ref<HTMLElement | null>(null) };
|
|
42
|
+
},
|
|
43
|
+
{} as Record<T, Ref<HTMLElement | null>>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
onMounted(async () => {
|
|
47
|
+
if (!shoelaceComponent.value) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
await customElements.whenDefined(shoelaceComponent.value.tagName.toLowerCase());
|
|
53
|
+
} catch {
|
|
54
|
+
// TODO: (kyleshevlin) we had to stub out Shoelace component in tests, which causes this to fail
|
|
55
|
+
// because there is no tagName for the stubbed component
|
|
56
|
+
// Silently handle error
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Make sure the component hasn't been destroyed at this point.
|
|
61
|
+
const shadowRoot = shoelaceComponent.value?.shadowRoot;
|
|
62
|
+
if (!shadowRoot) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
for (const part of parts) {
|
|
67
|
+
shadowParts[part].value = shadowRoot.querySelector(`[part="${part}"]`);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return shadowParts;
|
|
72
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Ref, type SetupContext, computed, ref } from 'vue';
|
|
2
|
+
|
|
3
|
+
export interface Field {
|
|
4
|
+
input: HTMLInputElement | null;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
interface FocusableField {
|
|
8
|
+
field: Ref<Field | null>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function useFocusableField(expose: SetupContext['expose']): FocusableField {
|
|
12
|
+
const field = ref<Field | null>(null);
|
|
13
|
+
const input = computed(() => field.value?.input as HTMLInputElement);
|
|
14
|
+
function focus(): void {
|
|
15
|
+
input?.value.focus();
|
|
16
|
+
}
|
|
17
|
+
expose({ focus });
|
|
18
|
+
return { field };
|
|
19
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
|
+
import { computed, onMounted, ref, watch } from 'vue';
|
|
3
|
+
|
|
4
|
+
export interface Coordinate {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface SimplifiedPointerEvent {
|
|
10
|
+
position: Coordinate;
|
|
11
|
+
timestamp: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type DragCallback = (dragDetails: {
|
|
15
|
+
/** How far the user has dragged in pixels */
|
|
16
|
+
distance: Coordinate;
|
|
17
|
+
/** Velocity of drag in pixels/ms */
|
|
18
|
+
velocity: Coordinate;
|
|
19
|
+
}) => void;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Listens for drag events on the provided element and tracks the distance and
|
|
23
|
+
* velocity of the drag.
|
|
24
|
+
*
|
|
25
|
+
* @param element - The element to listen for drag events on.
|
|
26
|
+
* @param options.onDragEnd - A callback that is called when the drag ends.
|
|
27
|
+
* @returns An object containing the drag distance and velocity.
|
|
28
|
+
*/
|
|
29
|
+
export const useDragListener = (
|
|
30
|
+
element: Ref<HTMLElement | null>,
|
|
31
|
+
options?: {
|
|
32
|
+
onDragEnd?: DragCallback;
|
|
33
|
+
}
|
|
34
|
+
): {
|
|
35
|
+
dragDistance: Ref<Coordinate | null>;
|
|
36
|
+
dragVelocity: Ref<Coordinate | null>;
|
|
37
|
+
} => {
|
|
38
|
+
const startDragTouch = ref<SimplifiedPointerEvent | null>(null);
|
|
39
|
+
const lastDragTouch = ref<SimplifiedPointerEvent | null>(null);
|
|
40
|
+
|
|
41
|
+
const dragVelocity = ref<Coordinate | null>(null);
|
|
42
|
+
const dragDistance = computed(() => {
|
|
43
|
+
if (!startDragTouch.value || !lastDragTouch.value) {
|
|
44
|
+
return { x: 0, y: 0 };
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
x: lastDragTouch.value.position.x - startDragTouch.value.position.x,
|
|
48
|
+
y: lastDragTouch.value.position.y - startDragTouch.value.position.y,
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const simplifyEvent = (event: TouchEvent): SimplifiedPointerEvent => {
|
|
53
|
+
const { clientX: x, clientY: y } = event.touches[0];
|
|
54
|
+
return { position: { x, y }, timestamp: event.timeStamp };
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const touchStartListener = (event: TouchEvent): void => {
|
|
58
|
+
startDragTouch.value = simplifyEvent(event);
|
|
59
|
+
lastDragTouch.value = startDragTouch.value;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const touchMoveListener = (event: TouchEvent): void => {
|
|
63
|
+
const newEvent = simplifyEvent(event);
|
|
64
|
+
if (lastDragTouch.value) {
|
|
65
|
+
const timeDelta = newEvent.timestamp - lastDragTouch.value.timestamp;
|
|
66
|
+
dragVelocity.value = {
|
|
67
|
+
x: (newEvent.position.x - lastDragTouch.value.position.x) / timeDelta,
|
|
68
|
+
y: (newEvent.position.y - lastDragTouch.value.position.y) / timeDelta,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
lastDragTouch.value = newEvent;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const touchEndListener = (): void => {
|
|
75
|
+
options?.onDragEnd?.({
|
|
76
|
+
distance: dragDistance.value,
|
|
77
|
+
velocity: dragVelocity.value ?? { x: 0, y: 0 },
|
|
78
|
+
});
|
|
79
|
+
startDragTouch.value = null;
|
|
80
|
+
lastDragTouch.value = null;
|
|
81
|
+
dragVelocity.value = null;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const addListeners = (element: HTMLElement | null): void => {
|
|
85
|
+
if (element) {
|
|
86
|
+
element.addEventListener('touchstart', touchStartListener);
|
|
87
|
+
element.addEventListener('touchmove', touchMoveListener);
|
|
88
|
+
element.addEventListener('touchend', touchEndListener);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const removeListeners = (element: HTMLElement | null): void => {
|
|
93
|
+
if (element) {
|
|
94
|
+
element.removeEventListener('touchstart', touchStartListener);
|
|
95
|
+
element.removeEventListener('touchmove', touchMoveListener);
|
|
96
|
+
element.removeEventListener('touchend', touchEndListener);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
onMounted(async () => {
|
|
101
|
+
addListeners(element.value);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
watch(element, (newElement, oldElement) => {
|
|
105
|
+
removeListeners(oldElement);
|
|
106
|
+
addListeners(newElement);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return { dragDistance, dragVelocity };
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Adds listeners to the provided element to prevent it from emitting touch
|
|
114
|
+
* events when it is scrolling.
|
|
115
|
+
*
|
|
116
|
+
* @param element - A scrollable element inside a draggable component.
|
|
117
|
+
*/
|
|
118
|
+
export const useScrollBoundary = (element: Ref<HTMLElement | null>): void => {
|
|
119
|
+
const isScrolling = ref(false);
|
|
120
|
+
const onScroll = (): void => {
|
|
121
|
+
isScrolling.value = true;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const onTouchEvent = (event: TouchEvent): void => {
|
|
125
|
+
if (isScrolling.value) {
|
|
126
|
+
event.stopPropagation();
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const onTouchEnd = (event: TouchEvent): void => {
|
|
130
|
+
onTouchEvent(event);
|
|
131
|
+
isScrolling.value = false;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const addListeners = (element: HTMLElement | null): void => {
|
|
135
|
+
if (element) {
|
|
136
|
+
element.addEventListener('scroll', onScroll);
|
|
137
|
+
element.addEventListener('touchstart', onTouchEvent);
|
|
138
|
+
element.addEventListener('touchmove', onTouchEvent);
|
|
139
|
+
element.addEventListener('touchend', onTouchEnd);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const removeListeners = (element: HTMLElement | null): void => {
|
|
144
|
+
if (element) {
|
|
145
|
+
element.removeEventListener('scroll', onScroll);
|
|
146
|
+
element.removeEventListener('touchstart', onTouchEvent);
|
|
147
|
+
element.removeEventListener('touchmove', onTouchEvent);
|
|
148
|
+
element.removeEventListener('touchend', onTouchEnd);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
onMounted(() => {
|
|
153
|
+
addListeners(element.value);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
watch(element, (newElement, oldElement) => {
|
|
157
|
+
removeListeners(oldElement);
|
|
158
|
+
addListeners(newElement);
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Clamps a value in between the provided min and max values. As the value
|
|
164
|
+
* increases above 0, it will approach the max, but will never reach it (and
|
|
165
|
+
* vice versa for the min).
|
|
166
|
+
*
|
|
167
|
+
* This can be used to create a "springy" effect where as a user pulls further
|
|
168
|
+
* on an element, it will move less and less.
|
|
169
|
+
*
|
|
170
|
+
* @param value - The value to clamp.
|
|
171
|
+
* @param options.min - The minimum value to keep the value above.
|
|
172
|
+
* @param options.max - The maximum value to keep the value below.
|
|
173
|
+
* @param options.resistance - The resistance value which determines how quickly
|
|
174
|
+
* the value approaches the min or max.
|
|
175
|
+
* @returns The clamped value.
|
|
176
|
+
*/
|
|
177
|
+
export const useElasticClamp = (
|
|
178
|
+
value: Ref<number | null>,
|
|
179
|
+
options?: Ref<{ min?: number; max?: number; resistance?: number }>
|
|
180
|
+
): Ref<number> => {
|
|
181
|
+
return computed(() => {
|
|
182
|
+
if (value.value === null) {
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const resistance = options?.value?.resistance ?? 7;
|
|
187
|
+
const { min, max } = options?.value ?? {};
|
|
188
|
+
const absValue = Math.abs(value.value);
|
|
189
|
+
if (min && value.value < 0) {
|
|
190
|
+
return (min * absValue) / (absValue - min * resistance);
|
|
191
|
+
} else if (max && value.value > 0) {
|
|
192
|
+
return (max * absValue) / (absValue + max * resistance);
|
|
193
|
+
} else {
|
|
194
|
+
return value.value;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { getCurrentInstance } from 'vue';
|
|
2
|
+
|
|
3
|
+
export function useTranslation(): {
|
|
4
|
+
t: (key: string, interpolations?: Record<string, string | number>) => string;
|
|
5
|
+
} {
|
|
6
|
+
const currentInstance = getCurrentInstance();
|
|
7
|
+
|
|
8
|
+
if (!currentInstance || !currentInstance.proxy) {
|
|
9
|
+
throw new Error('useTranslation must be called within a Vue component');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return { t: currentInstance.proxy.$t };
|
|
13
|
+
}
|