@propelinc/citrus-ui 0.5.1 → 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 +56 -86
- 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 +63 -77
- 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 +280 -119
- package/src/styles/_form-fields.scss +69 -16
- 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 +39 -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 +57 -45
- 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/.nvmrc +0 -1
- package/.stylelintrc.js +0 -3
- package/babel.config.js +0 -3
- package/dist/citrus-ui.common.js +0 -42228
- package/dist/citrus-ui.common.js.map +0 -1
- package/dist/citrus-ui.css +0 -1
- package/dist/citrus-ui.umd.js +0 -42238
- 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/postcss.config.js +0 -5
- 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 -73
- 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/tsconfig.dist.json +0 -9
- package/tsconfig.json +0 -42
- package/vue.config.js +0 -5
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
<!-- eslint-disable vue/no-deprecated-slot-attribute -->
|
|
2
|
+
<template>
|
|
3
|
+
<sl-button
|
|
4
|
+
v-bind="$attrs"
|
|
5
|
+
ref="button"
|
|
6
|
+
class="c-button"
|
|
7
|
+
:class="{
|
|
8
|
+
'c-button--block': injectedOrPropBlock,
|
|
9
|
+
'c-button--has-prefix-icon': hasIcon && iconPosition === 'prefix',
|
|
10
|
+
'c-button--has-suffix-icon': hasIcon && iconPosition === 'suffix',
|
|
11
|
+
[`c-button-level--${level}`]: level,
|
|
12
|
+
[`c-button-variant--${computedVariant}`]: computedVariant,
|
|
13
|
+
[`c-button-size--${computedSize}`]: computedSize,
|
|
14
|
+
}"
|
|
15
|
+
:data-block="dataBlock"
|
|
16
|
+
:data-href="routerDestinationOrHref"
|
|
17
|
+
:data-level="level"
|
|
18
|
+
:data-loading="dataLoading"
|
|
19
|
+
:data-size="computedSize"
|
|
20
|
+
data-test="button"
|
|
21
|
+
:data-variant="computedVariant"
|
|
22
|
+
:disabled="disabled"
|
|
23
|
+
:href="routerDestinationOrHref"
|
|
24
|
+
:loading="loading || undefined"
|
|
25
|
+
:size="computedSize"
|
|
26
|
+
:target="target"
|
|
27
|
+
:variant="shoelaceVariant"
|
|
28
|
+
v-on="animationListeners"
|
|
29
|
+
@click="onClick"
|
|
30
|
+
@sl-focus="$emit('focus', $event)"
|
|
31
|
+
@sl-blur="$emit('blur', $event)"
|
|
32
|
+
>
|
|
33
|
+
<span v-if="hasIcon" :slot="iconPosition" data-test="button-icon-slot">
|
|
34
|
+
<slot name="icon">
|
|
35
|
+
<font-awesome-icon v-if="icon" :icon="icon" />
|
|
36
|
+
</slot>
|
|
37
|
+
</span>
|
|
38
|
+
<slot data-test="button-default-slot" />
|
|
39
|
+
</sl-button>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<script lang="ts">
|
|
43
|
+
import type { IconDefinition } from '@fortawesome/fontawesome-svg-core';
|
|
44
|
+
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
|
45
|
+
import '@shoelace-style/shoelace/dist/components/button/button.js';
|
|
46
|
+
import type { PropType } from 'vue';
|
|
47
|
+
import { computed, defineComponent, inject, ref, toRefs } from 'vue';
|
|
48
|
+
import type { RouteLocationRaw } from 'vue-router';
|
|
49
|
+
|
|
50
|
+
import type {
|
|
51
|
+
ButtonIconPosition,
|
|
52
|
+
ButtonLevel,
|
|
53
|
+
ButtonShoelaceVariant,
|
|
54
|
+
ButtonSize,
|
|
55
|
+
ButtonVariant,
|
|
56
|
+
} from '@propelinc/citrus-ui/src/components/CButton/types';
|
|
57
|
+
import { useTapAnimation } from '@propelinc/citrus-ui/src/composables/animation';
|
|
58
|
+
import { useRouterLink } from '@propelinc/citrus-ui/src/composables/router';
|
|
59
|
+
import { useSlotHasContent } from '@propelinc/citrus-ui/src/composables/slots';
|
|
60
|
+
import { BLOCK, BOUNCE_AMOUNT, LARGE } from '@propelinc/citrus-ui/src/services/injections/buttons';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Shoelace has a set of variants that don't match the variant names we would like to use.
|
|
64
|
+
* This mapping is used to translate the variant names to the correct Shoelace variant names
|
|
65
|
+
* and apply it to the underlying Shoelace button component.
|
|
66
|
+
*/
|
|
67
|
+
export const VARIANT_TO_SHOELACE_VARIANT: Record<ButtonVariant, ButtonShoelaceVariant> = {
|
|
68
|
+
primary: 'primary',
|
|
69
|
+
// Shoelace `default` is an outline style
|
|
70
|
+
secondary: 'default',
|
|
71
|
+
tertiary: 'text',
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const BLOCK_BOUNCE_AMOUNT = 0.96;
|
|
75
|
+
const BASE_BOUNCE_AMOUNT = 0.94;
|
|
76
|
+
|
|
77
|
+
export default defineComponent({
|
|
78
|
+
components: {
|
|
79
|
+
FontAwesomeIcon,
|
|
80
|
+
},
|
|
81
|
+
props: {
|
|
82
|
+
/** Controls whether button appears as full-width */
|
|
83
|
+
block: { type: Boolean, default: false },
|
|
84
|
+
/** Controls whether button is disabled */
|
|
85
|
+
disabled: { type: Boolean, default: false },
|
|
86
|
+
/** Designates the button as an anchor and applies the href attribute */
|
|
87
|
+
href: { type: String, default: undefined },
|
|
88
|
+
/** Chooses an icon to render on the left side of the button */
|
|
89
|
+
icon: {
|
|
90
|
+
type: [String, Array, Object] as PropType<string | string[] | IconDefinition>,
|
|
91
|
+
default: undefined,
|
|
92
|
+
},
|
|
93
|
+
/** Chooses whether to place the icon before or after the button text */
|
|
94
|
+
iconPosition: {
|
|
95
|
+
type: String as PropType<ButtonIconPosition>,
|
|
96
|
+
default: 'prefix',
|
|
97
|
+
validator: (value: string) => ['prefix', 'suffix'].includes(value),
|
|
98
|
+
},
|
|
99
|
+
/**
|
|
100
|
+
* @deprecated use `size` prop instead
|
|
101
|
+
* Controls whether button uses the large variant
|
|
102
|
+
*/
|
|
103
|
+
large: { type: Boolean, default: false, deprecated: true },
|
|
104
|
+
/** Controls the level of the button */
|
|
105
|
+
level: {
|
|
106
|
+
type: String as PropType<ButtonLevel>,
|
|
107
|
+
default: 'normal',
|
|
108
|
+
validator: (value: string) => ['normal', 'danger'].includes(value),
|
|
109
|
+
},
|
|
110
|
+
/** Controls whether button is loading */
|
|
111
|
+
loading: { type: Boolean, default: false },
|
|
112
|
+
/**
|
|
113
|
+
* @deprecated use `variant` prop instead
|
|
114
|
+
* Controls whether button uses the secondary variant */
|
|
115
|
+
secondary: { type: Boolean, default: false, deprecated: true },
|
|
116
|
+
/**
|
|
117
|
+
* Controls the size of the button
|
|
118
|
+
* @default 'medium'
|
|
119
|
+
*/
|
|
120
|
+
size: {
|
|
121
|
+
type: String as PropType<ButtonSize>,
|
|
122
|
+
default: 'medium',
|
|
123
|
+
validator: (value: string) => ['medium', 'large'].includes(value),
|
|
124
|
+
},
|
|
125
|
+
/** Designates the target attribute. Only use with the href prop. */
|
|
126
|
+
target: { type: String, default: undefined },
|
|
127
|
+
/**
|
|
128
|
+
* @deprecated use `variant` prop instead
|
|
129
|
+
* Controls whether button uses the tertiary variant
|
|
130
|
+
*/
|
|
131
|
+
tertiary: { type: Boolean, default: false, deprecated: true },
|
|
132
|
+
/** Controls whether button functions as a router-link */
|
|
133
|
+
to: { type: [Object, String] as PropType<RouteLocationRaw>, default: undefined },
|
|
134
|
+
/**
|
|
135
|
+
* Controls the styling of the button
|
|
136
|
+
* @default 'primary'
|
|
137
|
+
*/
|
|
138
|
+
variant: {
|
|
139
|
+
type: String as PropType<ButtonVariant>,
|
|
140
|
+
default: 'primary',
|
|
141
|
+
validator: (value: string) => ['primary', 'secondary', 'tertiary'].includes(value),
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
emits: ['click', 'focus', 'blur'],
|
|
145
|
+
setup(props, { emit }) {
|
|
146
|
+
const { block, to } = toRefs(props);
|
|
147
|
+
const { href: routerDestination, navigate } = useRouterLink(to);
|
|
148
|
+
const routerDestinationOrHref = computed(() => routerDestination.value ?? props.href);
|
|
149
|
+
|
|
150
|
+
const dataLoading = computed<true | undefined>(() => props.loading || undefined);
|
|
151
|
+
|
|
152
|
+
const injectedBlock = inject(BLOCK, undefined);
|
|
153
|
+
const injectedOrPropBlock = computed(() => injectedBlock?.value ?? props.block);
|
|
154
|
+
const dataBlock = computed<true | undefined>(() => injectedOrPropBlock.value || undefined);
|
|
155
|
+
|
|
156
|
+
const iconSlotHasContent = useSlotHasContent('icon');
|
|
157
|
+
const hasIcon = computed(() => iconSlotHasContent.value || !!props.icon);
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Handle the deprecated `secondary` and `tertiary` props.
|
|
161
|
+
*/
|
|
162
|
+
const computedVariant = computed((): ButtonVariant => {
|
|
163
|
+
if (props.secondary) {
|
|
164
|
+
return 'secondary';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (props.tertiary) {
|
|
168
|
+
return 'tertiary';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return props.variant;
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Map the computed variant to the Shoelace variant
|
|
176
|
+
*/
|
|
177
|
+
const shoelaceVariant = computed(() => VARIANT_TO_SHOELACE_VARIANT[computedVariant.value]);
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The deprecated `large` prop can be injected through a provider.
|
|
181
|
+
*/
|
|
182
|
+
const injectedLarge = inject(LARGE, undefined);
|
|
183
|
+
const injectedOrPropsLarge = computed(() => injectedLarge?.value ?? props.large);
|
|
184
|
+
/**
|
|
185
|
+
* Because we want the `size` prop to have a default, it's always supplied.
|
|
186
|
+
* Thus, our only option to respect the deprecated `large` prop is to give it priority.
|
|
187
|
+
*/
|
|
188
|
+
const computedSize = computed(() => {
|
|
189
|
+
if (injectedOrPropsLarge.value) {
|
|
190
|
+
return 'large';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return props.size;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
function onClick(event: MouseEvent): void {
|
|
197
|
+
/**
|
|
198
|
+
* If the button is disabled or loading, do not take action.
|
|
199
|
+
* This prevents double/extra clicks when an async operation is in progress.
|
|
200
|
+
*/
|
|
201
|
+
if (props.disabled || props.loading) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
navigate(event);
|
|
206
|
+
emit('click', event);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const button = ref<HTMLElement | null>(null);
|
|
210
|
+
const injectedBounceAmount = inject(BOUNCE_AMOUNT, null);
|
|
211
|
+
const bounceAmount = computed(() => {
|
|
212
|
+
/**
|
|
213
|
+
* If the button is disabled or loading, do not animate the button.
|
|
214
|
+
*/
|
|
215
|
+
if (props.disabled || props.loading) {
|
|
216
|
+
return 1;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (injectedBounceAmount) {
|
|
220
|
+
return injectedBounceAmount;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (block.value) {
|
|
224
|
+
return BLOCK_BOUNCE_AMOUNT;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return BASE_BOUNCE_AMOUNT;
|
|
228
|
+
});
|
|
229
|
+
const animationListeners = useTapAnimation({
|
|
230
|
+
el: button,
|
|
231
|
+
keyframes: {
|
|
232
|
+
default: { transform: 'scale(1)' },
|
|
233
|
+
pressed: { transform: `scale(${bounceAmount.value})` },
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
animationListeners,
|
|
239
|
+
button,
|
|
240
|
+
computedSize,
|
|
241
|
+
computedVariant,
|
|
242
|
+
dataBlock,
|
|
243
|
+
dataLoading,
|
|
244
|
+
hasIcon,
|
|
245
|
+
injectedOrPropBlock,
|
|
246
|
+
injectedOrPropsLarge,
|
|
247
|
+
onClick,
|
|
248
|
+
routerDestinationOrHref,
|
|
249
|
+
shoelaceVariant,
|
|
250
|
+
};
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
</script>
|
|
254
|
+
|
|
255
|
+
<style lang="scss" scoped>
|
|
256
|
+
@import '@propelinc/citrus-ui/src/styles/core';
|
|
257
|
+
@import '@propelinc/citrus-ui/src/styles/button';
|
|
258
|
+
|
|
259
|
+
.c-button {
|
|
260
|
+
// Prevents the iOS tap highlight color from showing up on buttons
|
|
261
|
+
-webkit-tap-highlight-color: transparent;
|
|
262
|
+
|
|
263
|
+
&::part(base) {
|
|
264
|
+
// Included in all buttons so that they line up in rows, even buttons with transparent borders
|
|
265
|
+
border-width: $border-width;
|
|
266
|
+
transition: background-color 0.2s ease-in-out;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
&::part(label) {
|
|
270
|
+
padding: 0 16px;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.c-button-size--medium::part(base) {
|
|
275
|
+
--sl-input-height-medium: #{$button-size-medium};
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.c-button-size--large::part(base) {
|
|
279
|
+
--sl-input-height-large: #{$button-size-large};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.c-button--has-prefix-icon {
|
|
283
|
+
&::part(base) {
|
|
284
|
+
padding-inline-start: 16px;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
&::part(label) {
|
|
288
|
+
padding-inline-start: 8px;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.c-button--has-suffix-icon {
|
|
293
|
+
&::part(base) {
|
|
294
|
+
padding-inline-end: 16px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
&::part(label) {
|
|
298
|
+
padding-inline-end: 8px;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.c-button--block {
|
|
303
|
+
min-width: 100%;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.c-button-variant--primary::part(base) {
|
|
307
|
+
@include button-theme-primary;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.c-button-variant--primary.c-button-level--danger::part(base) {
|
|
311
|
+
@include button-theme-primary-danger;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.c-button-variant--secondary::part(base) {
|
|
315
|
+
@include button-theme-secondary;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.c-button-variant--secondary.c-button-level--danger::part(base) {
|
|
319
|
+
@include button-theme-secondary-danger;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.c-button-variant--tertiary::part(base) {
|
|
323
|
+
@include button-theme-tertiary;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.c-button-variant--tertiary.c-button-level--danger::part(base) {
|
|
327
|
+
@include button-theme-tertiary-danger;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Override Shoelace's default disabled styles
|
|
332
|
+
* (The danger styles seem fine)
|
|
333
|
+
*/
|
|
334
|
+
:not(.c-button-level--danger) {
|
|
335
|
+
&.c-button-variant--primary[disabled]::part(base) {
|
|
336
|
+
@include button-theme($color-gray-400, $color-gray-200, $color-gray-200);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
&.c-button-variant--secondary[disabled]::part(base) {
|
|
340
|
+
@include button-theme($color-gray-300, $color-gray-300, transparent);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
&.c-button-variant--tertiary[disabled]::part(base) {
|
|
344
|
+
@include button-theme($color-gray-300, transparent, transparent);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
</style>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type ButtonSize = 'medium' | 'large';
|
|
2
|
+
export type ButtonLevel = 'normal' | 'danger';
|
|
3
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'tertiary';
|
|
4
|
+
export type ButtonShoelaceVariant = 'default' | 'primary' | 'text';
|
|
5
|
+
export type ButtonIconPosition = 'prefix' | 'suffix';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component :is="tag" class="c-button-stack" data-test="c-button-stack">
|
|
3
|
+
<slot />
|
|
4
|
+
</component>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import { defineComponent, provide, ref, toRefs } from 'vue';
|
|
9
|
+
|
|
10
|
+
import { BLOCK, LARGE } from '@propelinc/citrus-ui/src/services/injections/buttons';
|
|
11
|
+
|
|
12
|
+
export default defineComponent({
|
|
13
|
+
props: {
|
|
14
|
+
tag: { type: String, default: 'div' },
|
|
15
|
+
large: { type: Boolean, default: null },
|
|
16
|
+
},
|
|
17
|
+
setup(props) {
|
|
18
|
+
const { large } = toRefs(props);
|
|
19
|
+
|
|
20
|
+
provide(BLOCK, ref(true));
|
|
21
|
+
provide(LARGE, large);
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<style scoped>
|
|
27
|
+
/**
|
|
28
|
+
* FIXME: https://linear.app/slanden/issue/FE-37/remove-exported-margins
|
|
29
|
+
* These are exported margins, would be preferable to use a Flex column with gap instead
|
|
30
|
+
*/
|
|
31
|
+
:deep() {
|
|
32
|
+
.c-button + .c-button {
|
|
33
|
+
margin-top: 8px;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
</style>
|
package/src/components/CCard.vue
CHANGED
|
@@ -1,64 +1,172 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class="card"
|
|
7
|
-
:class="{
|
|
8
|
-
|
|
2
|
+
<component
|
|
3
|
+
:is="config.element"
|
|
4
|
+
v-bind="config.attrs"
|
|
5
|
+
data-test="card"
|
|
6
|
+
class="c-card"
|
|
7
|
+
:class="{
|
|
8
|
+
'c-card--tile': tile,
|
|
9
|
+
'c-card--borderless': borderless,
|
|
10
|
+
'c-card--link': config.isLink,
|
|
11
|
+
'c-card--stretch': stretch,
|
|
12
|
+
}"
|
|
9
13
|
:href="href"
|
|
10
|
-
:
|
|
11
|
-
|
|
14
|
+
:style="{
|
|
15
|
+
'--background-color': backgroundCssColor,
|
|
16
|
+
'--border-color': borderCssColor,
|
|
17
|
+
}"
|
|
18
|
+
:to="to"
|
|
12
19
|
>
|
|
13
|
-
<
|
|
20
|
+
<CCardHeader v-if="title">
|
|
14
21
|
{{ title }}
|
|
15
|
-
</
|
|
16
|
-
|
|
22
|
+
</CCardHeader>
|
|
17
23
|
<slot />
|
|
18
|
-
</
|
|
24
|
+
</component>
|
|
19
25
|
</template>
|
|
20
26
|
|
|
21
27
|
<script lang="ts">
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@Prop(String) href?: string;
|
|
36
|
-
@Prop({ type: Boolean, default: true }) outlined!: boolean;
|
|
28
|
+
import type { PropType } from 'vue';
|
|
29
|
+
import { computed, defineComponent, toRefs } from 'vue';
|
|
30
|
+
import type { RouteLocationRaw } from 'vue-router';
|
|
31
|
+
|
|
32
|
+
import CCardHeader from '@propelinc/citrus-ui/src/components/CCardHeader.vue';
|
|
33
|
+
import { useCssColor } from '@propelinc/citrus-ui/src/composables/colors';
|
|
34
|
+
|
|
35
|
+
type RoutingVariant = 'none' | 'internal' | 'external';
|
|
36
|
+
|
|
37
|
+
export interface InternalCardConfig {
|
|
38
|
+
attrs: Record<string, unknown>;
|
|
39
|
+
element: string;
|
|
40
|
+
isLink: boolean;
|
|
37
41
|
}
|
|
42
|
+
|
|
43
|
+
export default defineComponent({
|
|
44
|
+
components: { CCardHeader },
|
|
45
|
+
props: {
|
|
46
|
+
/** Sets the border color of the card */
|
|
47
|
+
borderColor: { type: String, default: undefined },
|
|
48
|
+
|
|
49
|
+
/** Removes the border of the card */
|
|
50
|
+
borderless: { type: Boolean, default: false },
|
|
51
|
+
|
|
52
|
+
/** Sets the background color of the entire card */
|
|
53
|
+
color: { type: String, default: undefined },
|
|
54
|
+
|
|
55
|
+
/** Navigates externally on click */
|
|
56
|
+
href: { type: String, default: undefined },
|
|
57
|
+
|
|
58
|
+
/** Stretches the card vertically to fill the height of the parent container */
|
|
59
|
+
stretch: { type: Boolean, default: false },
|
|
60
|
+
|
|
61
|
+
/** Toggles a squared-off card style intended to fill the width of the page */
|
|
62
|
+
tile: { type: Boolean, default: false },
|
|
63
|
+
|
|
64
|
+
/** Sets the title of the card */
|
|
65
|
+
title: { type: String, default: undefined },
|
|
66
|
+
|
|
67
|
+
/** Navigates within the app on click */
|
|
68
|
+
to: { type: [Object, String] as PropType<RouteLocationRaw | undefined>, default: undefined },
|
|
69
|
+
},
|
|
70
|
+
setup(props, { attrs }) {
|
|
71
|
+
const { href, to } = toRefs(props);
|
|
72
|
+
|
|
73
|
+
const { cssColor: backgroundCssColor } = useCssColor(() => props.color);
|
|
74
|
+
const { cssColor: borderCssColor } = useCssColor(() => props.borderColor);
|
|
75
|
+
|
|
76
|
+
const routingVariant = computed<RoutingVariant>(() => {
|
|
77
|
+
if (to.value) {
|
|
78
|
+
return 'internal';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (href.value) {
|
|
82
|
+
return 'external';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return 'none';
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const config = computed<InternalCardConfig>(() => {
|
|
89
|
+
switch (routingVariant.value) {
|
|
90
|
+
case 'internal':
|
|
91
|
+
return {
|
|
92
|
+
attrs,
|
|
93
|
+
element: 'router-link',
|
|
94
|
+
isLink: true,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
case 'external':
|
|
98
|
+
return {
|
|
99
|
+
attrs: {
|
|
100
|
+
...attrs,
|
|
101
|
+
role: 'link',
|
|
102
|
+
tabindex: '0',
|
|
103
|
+
target: '_blank',
|
|
104
|
+
},
|
|
105
|
+
element: 'a',
|
|
106
|
+
isLink: true,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
case 'none':
|
|
110
|
+
default:
|
|
111
|
+
return { attrs, element: 'div', isLink: false };
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return { config, backgroundCssColor, borderCssColor };
|
|
116
|
+
},
|
|
117
|
+
});
|
|
38
118
|
</script>
|
|
39
119
|
|
|
40
120
|
<style lang="scss" scoped>
|
|
41
|
-
@import '
|
|
121
|
+
@import '@propelinc/citrus-ui/src/styles/core';
|
|
42
122
|
|
|
43
|
-
.card {
|
|
123
|
+
.c-card {
|
|
124
|
+
--background-color: #{$color-background};
|
|
125
|
+
--border-color: #{$color-border};
|
|
126
|
+
--border-radius: #{$border-radius-next};
|
|
127
|
+
--text-color: #{$color-text-primary};
|
|
128
|
+
|
|
129
|
+
background-color: var(--background-color);
|
|
130
|
+
border-color: var(--border-color);
|
|
131
|
+
border-radius: var(--border-radius);
|
|
132
|
+
border-style: solid;
|
|
133
|
+
border-width: $border-width;
|
|
134
|
+
color: var(--text-color);
|
|
135
|
+
display: block;
|
|
136
|
+
max-width: 100%;
|
|
44
137
|
overflow: hidden;
|
|
45
138
|
|
|
139
|
+
/**
|
|
140
|
+
* FIXME: (kyleshevlin - https://linear.app/slanden/issue/FE-37/remove-exported-margins):
|
|
141
|
+
* This is an "exported margin" and we should try to remove it. They make composition difficult.
|
|
142
|
+
* Read more here: https://kyleshevlin.com/no-outer-margin
|
|
143
|
+
*
|
|
144
|
+
* For example, imagine we want to have multiple cards in a row. This selector will add a
|
|
145
|
+
* margin-top to every card except the first. That would not be desired.
|
|
146
|
+
*
|
|
147
|
+
* Ideally, layout of sibling cards is always handled by a parent element.
|
|
148
|
+
*/
|
|
46
149
|
& + & {
|
|
47
|
-
margin-top:
|
|
150
|
+
margin-top: 8px;
|
|
48
151
|
}
|
|
49
152
|
}
|
|
50
153
|
|
|
51
|
-
.card--
|
|
52
|
-
:
|
|
53
|
-
border-top: $border;
|
|
54
|
-
}
|
|
154
|
+
.c-card--tile {
|
|
155
|
+
--border-radius: 0;
|
|
55
156
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
157
|
+
border-left: none;
|
|
158
|
+
border-right: none;
|
|
159
|
+
}
|
|
59
160
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
161
|
+
.c-card--borderless {
|
|
162
|
+
--border-color: transparent;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.c-card--link {
|
|
166
|
+
cursor: pointer;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.c-card--stretch {
|
|
170
|
+
height: 100%;
|
|
63
171
|
}
|
|
64
172
|
</style>
|
|
@@ -1,39 +1,23 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-card-
|
|
2
|
+
<CButtonStack v-bind="$attrs" data-test="card-footer" class="c-card-footer">
|
|
3
3
|
<slot />
|
|
4
|
-
</
|
|
4
|
+
</CButtonStack>
|
|
5
5
|
</template>
|
|
6
6
|
|
|
7
7
|
<script lang="ts">
|
|
8
|
-
import {
|
|
8
|
+
import { defineComponent } from 'vue';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
import CButtonStack from '@propelinc/citrus-ui/src/components/CButtonStack.vue';
|
|
11
|
+
|
|
12
|
+
export default defineComponent({
|
|
13
|
+
components: { CButtonStack },
|
|
14
|
+
});
|
|
12
15
|
</script>
|
|
13
16
|
|
|
14
17
|
<style lang="scss" scoped>
|
|
15
|
-
@import '
|
|
16
|
-
|
|
17
|
-
.card__footer {
|
|
18
|
-
align-items: stretch;
|
|
19
|
-
flex-direction: column;
|
|
20
|
-
|
|
21
|
-
::v-deep {
|
|
22
|
-
:is(.button--primary, .button--secondary) + :is(.button--primary, .button--secondary) {
|
|
23
|
-
margin-top: 8px;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
:is(.button--primary, .button--secondary) + .button--tertiary {
|
|
27
|
-
margin-top: 4px;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.button--tertiary + .button--tertiary {
|
|
31
|
-
margin-top: 4px;
|
|
32
|
-
}
|
|
18
|
+
@import '@propelinc/citrus-ui/src/styles/core';
|
|
33
19
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
}
|
|
20
|
+
.c-card-footer {
|
|
21
|
+
padding: 0 16px 16px;
|
|
38
22
|
}
|
|
39
23
|
</style>
|