@propelinc/citrus-ui 0.3.2 → 0.3.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@propelinc/citrus-ui",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/propelinc/citrus-ui"
@@ -1,120 +1,57 @@
1
1
  <template>
2
- <div class="card" :class="{ [color]: !!color }">
3
- <div v-if="shouldShowHeader" class="card__header" :class="{ 'card__header--divided': divided }">
4
- <div class="card__header__title-container">
5
- <span data-test="card-title" class="card__header__title">
6
- <slot name="header:title">
7
- {{ title }}
8
- </slot>
9
- </span>
10
- </div>
2
+ <v-card flat class="card" :class="{ 'card--divided': divided }" :color="color">
3
+ <c-card-header v-if="title">
4
+ {{ title }}
5
+ </c-card-header>
11
6
 
12
- <div class="card__header__append">
13
- <slot name="header:append" />
14
- </div>
15
- </div>
16
-
17
- <div data-test="card-body" class="card__body" :class="{ 'card__body--fluid': fluid }">
18
- <slot />
19
- </div>
20
-
21
- <div class="card__footer" :class="{ 'card__footer--divided': divided }">
22
- <slot name="footer" />
23
- </div>
24
- </div>
7
+ <slot />
8
+ </v-card>
25
9
  </template>
26
10
 
27
11
  <script lang="ts">
28
12
  import { Component, Vue, Prop } from 'vue-property-decorator';
29
13
 
30
- @Component({ name: 'CCard' })
14
+ import CCardHeader from '@/components/CCardHeader.vue';
15
+
16
+ @Component({ name: 'CCard', components: { CCardHeader } })
31
17
  export default class CCard extends Vue {
32
18
  @Prop(String) title?: string;
33
- /** Removes padding from card body */
34
- @Prop({ type: Boolean, default: false }) fluid!: boolean;
35
- /** Shows borders between header, body, and footer */
19
+ /** Shows borders between header, sections, and footer */
36
20
  @Prop({ type: Boolean, default: false }) divided!: boolean;
37
21
  /** Sets background color */
38
22
  @Prop(String) color?: string;
39
-
40
- get shouldShowHeader(): boolean {
41
- return (
42
- !!this.title ||
43
- !!this.$slots['header:append'] ||
44
- !!this.$scopedSlots['header:append'] ||
45
- !!this.$slots['header:title'] ||
46
- !!this.$scopedSlots['header:title']
47
- );
48
- }
49
23
  }
50
24
  </script>
51
25
 
52
26
  <style lang="less" scoped>
53
27
  @import '~@/styles/variables.less';
54
- @import '~@/styles/mixins/buttons.less';
55
28
 
56
29
  .card {
57
- background: @color-white;
58
30
  border: @border;
59
- border-radius: @border-radius;
31
+ border-radius: @border-radius !important;
60
32
  overflow: hidden;
61
33
 
62
34
  & + & {
63
35
  margin-top: 12px;
64
36
  }
65
- }
66
-
67
- .card__header {
68
- align-items: flex-start;
69
- display: flex;
70
- padding: @card-header-v-spacing @card-h-spacing 0;
71
- }
72
-
73
- .card__header__title-container {
74
- flex: 1 1 100%;
75
- }
76
-
77
- .card__header__title {
78
- .title();
79
-
80
- vertical-align: -4px;
81
- word-break: break-word;
82
- }
83
-
84
- .card__header__append:not(:empty) {
85
- flex: none;
86
- margin: -6px -12px -8px @card-h-spacing;
87
- }
88
-
89
- .card__header--divided {
90
- border-bottom: @border;
91
- padding-bottom: @card-header-v-spacing;
92
- }
93
-
94
- .card__body {
95
- padding: @card-body-v-spacing @card-h-spacing;
96
37
 
97
- .card__header:not(.card__header--divided) + & {
98
- padding-top: @card-body-v-spacing - 4px;
38
+ /deep/ .card__section + .card__footer {
39
+ margin-top: -16px;
99
40
  }
100
41
  }
101
42
 
102
- .card__body--fluid {
103
- padding: 0;
104
- }
105
-
106
- .card__footer {
107
- .button-container();
43
+ .card--divided {
44
+ /deep/
45
+ :is(.card__header, .card__section, .card__footer)
46
+ + :is(.card__header, .card__section, .card__footer) {
47
+ border-top: @border;
48
+ }
108
49
 
109
- &:not(:empty) {
110
- margin-top: -1 * @card-body-v-spacing;
111
- padding: 0 @card-h-spacing;
50
+ /deep/ .card__header + .card__section:not(.card__section--fluid) {
51
+ padding: 16px;
112
52
  }
113
- }
114
53
 
115
- .card__footer--divided {
116
- &:not(:empty) {
117
- border-top: @border;
54
+ /deep/ .card__section + .card__footer {
118
55
  margin-top: 0;
119
56
  }
120
57
  }
@@ -0,0 +1,44 @@
1
+ <template>
2
+ <v-card-actions class="card__footer">
3
+ <slot />
4
+ </v-card-actions>
5
+ </template>
6
+
7
+ <script lang="ts">
8
+ import { Component, Vue } from 'vue-property-decorator';
9
+
10
+ @Component({ name: 'CCardFooter' })
11
+ export default class CCardFooter extends Vue {}
12
+ </script>
13
+
14
+ <style lang="less" scoped>
15
+ @import '~@/styles/variables.less';
16
+
17
+ .card__footer {
18
+ align-items: stretch;
19
+ display: flex;
20
+ flex-direction: column;
21
+ padding-left: 16px;
22
+ padding-right: 16px;
23
+
24
+ & /deep/ .button {
25
+ margin-left: 0 !important;
26
+ margin-right: 0 !important;
27
+ }
28
+
29
+ & /deep/ .button--primary,
30
+ & /deep/ .button--secondary {
31
+ margin: 4px 0;
32
+
33
+ &:not(:first-child) {
34
+ margin-top: 8px;
35
+ }
36
+ }
37
+
38
+ & /deep/ .button--tertiary {
39
+ &:not(:first-child) {
40
+ margin-top: 4px;
41
+ }
42
+ }
43
+ }
44
+ </style>
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <v-card-title class="card__header">
3
+ <div class="card__header__title-container">
4
+ <span data-test="card-title" class="card__header__title">
5
+ <slot />
6
+ </span>
7
+ </div>
8
+
9
+ <div class="card__header__append">
10
+ <slot name="append" />
11
+ </div>
12
+ </v-card-title>
13
+ </template>
14
+
15
+ <script lang="ts">
16
+ import { Component, Vue } from 'vue-property-decorator';
17
+
18
+ @Component({ name: 'CCardHeader' })
19
+ export default class CCardHeader extends Vue {}
20
+ </script>
21
+
22
+ <style lang="less" scoped>
23
+ @import '~@/styles/variables.less';
24
+
25
+ .card__header {
26
+ align-items: flex-start;
27
+ display: flex;
28
+ flex-wrap: nowrap;
29
+ padding: 12px @card-h-spacing;
30
+ }
31
+
32
+ .card__header__title-container {
33
+ flex: 1 1 auto;
34
+ line-height: 1;
35
+ }
36
+
37
+ .card__header__title {
38
+ .title();
39
+
40
+ line-height: 1;
41
+ vertical-align: -1px;
42
+ word-break: break-word;
43
+ }
44
+
45
+ .card__header__append:not(:empty) {
46
+ flex: none;
47
+ margin: -6px -12px -8px @card-h-spacing;
48
+ }
49
+ </style>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <v-card-text
3
+ data-test="card-section"
4
+ class="card__section"
5
+ :class="{ 'card__section--fluid': fluid }"
6
+ >
7
+ <slot />
8
+ </v-card-text>
9
+ </template>
10
+
11
+ <script lang="ts">
12
+ import { Component, Vue, Prop } from 'vue-property-decorator';
13
+
14
+ @Component({ name: 'CCardSection' })
15
+ export default class CCardSection extends Vue {
16
+ @Prop({ type: Boolean, default: false }) fluid!: boolean;
17
+ }
18
+ </script>
19
+
20
+ <style lang="less" scoped>
21
+ @import '~@/styles/variables.less';
22
+
23
+ .card__section {
24
+ color: @color-navy !important;
25
+ }
26
+
27
+ .card__section--fluid {
28
+ padding: 0 !important;
29
+ }
30
+ </style>
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <v-btn
3
+ class="icon-button"
3
4
  data-test="icon-button"
4
5
  :class="{ [colorScheme.container]: colorScheme.container }"
5
6
  icon
@@ -1,45 +1,43 @@
1
1
  <template>
2
2
  <v-dialog
3
- :width="loading ? '160' : undefined"
4
3
  :persistent="!dismissible || !!loading"
5
4
  no-click-animation
6
5
  :value="value"
6
+ scrollable
7
7
  @input="(value) => $emit('input', value)"
8
8
  >
9
9
  <c-card v-if="loading" key="loading" data-test="modal-loading">
10
- <div class="modal__loading">
11
- <div class="modal__loading__icon-container">
12
- <font-awesome-icon :icon="faSync" class="fa-spin modal__loading__icon" />
10
+ <c-card-section>
11
+ <div class="modal__loading">
12
+ <div class="modal__loading__icon-container">
13
+ <font-awesome-icon :icon="faSync" class="fa-spin modal__loading__icon" />
14
+ </div>
15
+
16
+ <div
17
+ v-if="hasLoadingMessage"
18
+ data-test="modal-loading-message"
19
+ class="modal__loading__message"
20
+ >
21
+ {{ loading }}
22
+ </div>
13
23
  </div>
14
-
15
- <div
16
- v-if="hasLoadingMessage"
17
- data-test="modal-loading-message"
18
- class="modal__loading__message"
19
- >
20
- {{ loading }}
21
- </div>
22
- </div>
24
+ </c-card-section>
23
25
  </c-card>
24
- <c-card v-else key="default" :fluid="fluid" data-test="modal">
25
- <template #header:title>
26
+ <c-card v-else key="default" data-test="modal">
27
+ <c-card-header>
26
28
  <span class="modal__header__title" data-test="modal-title">{{ title }}</span>
27
- </template>
28
29
 
29
- <template #header:append>
30
- <c-icon-button
31
- v-if="dismissible"
32
- data-test="modal-dismiss"
33
- :icon="faTimes"
34
- @click="$emit('input', false)"
35
- />
36
- </template>
30
+ <template #append>
31
+ <c-icon-button
32
+ v-if="dismissible"
33
+ data-test="modal-dismiss"
34
+ :icon="faTimes"
35
+ @click="$emit('input', false)"
36
+ />
37
+ </template>
38
+ </c-card-header>
37
39
 
38
40
  <slot />
39
-
40
- <template #footer>
41
- <slot name="footer" />
42
- </template>
43
41
  </c-card>
44
42
  </v-dialog>
45
43
  </template>
@@ -49,17 +47,17 @@ import { faSync, faTimes } from '@fortawesome/pro-light-svg-icons';
49
47
  import { Component, Vue, Prop } from 'vue-property-decorator';
50
48
 
51
49
  import CCard from '@/components/CCard.vue';
50
+ import CCardHeader from '@/components/CCardHeader.vue';
51
+ import CCardSection from '@/components/CCardSection.vue';
52
52
  import CIconButton from '@/components/CIconButton.vue';
53
53
 
54
- @Component({ name: 'CModal', components: { CCard, CIconButton } })
54
+ @Component({ name: 'CModal', components: { CCard, CCardSection, CCardHeader, CIconButton } })
55
55
  export default class CModal extends Vue {
56
56
  faSync = faSync;
57
57
  faTimes = faTimes;
58
58
 
59
59
  @Prop({ type: Boolean, default: false }) value!: boolean;
60
60
  @Prop(String) title?: string;
61
- /** Removes padding from modal body */
62
- @Prop({ type: Boolean, default: false }) fluid!: boolean;
63
61
  /** Shows loading state + sets loading message if string */
64
62
  @Prop([String, Boolean]) loading?: string | boolean;
65
63
  /** Allows modal to be dismissed */
@@ -85,7 +83,7 @@ export default class CModal extends Vue {
85
83
  }
86
84
 
87
85
  .modal__loading__icon-container {
88
- padding: 12px 0;
86
+ padding: 32px 0 12px;
89
87
  }
90
88
 
91
89
  .modal__loading__icon {
@@ -96,9 +94,4 @@ export default class CModal extends Vue {
96
94
  .modal__loading__message {
97
95
  font-weight: @font-weight-bold;
98
96
  }
99
-
100
- /deep/ .card__footer:not(:empty) {
101
- margin-top: -12px;
102
- padding-bottom: 4px;
103
- }
104
97
  </style>
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <form-field :field-id="id" :disabled="disabled" :label="label">
3
+ <v-textarea
4
+ :id="id"
5
+ v-bind="$attrs"
6
+ data-test="text-area"
7
+ class="text-area__input"
8
+ :class="{ 'text-area__input--disabled': disabled }"
9
+ auto-grow
10
+ outlined
11
+ single-line
12
+ :placeholder="placeholder"
13
+ :disabled="disabled"
14
+ :value="value"
15
+ :rules="rules"
16
+ validate-on-blur
17
+ :hide-details="rules.length === 0"
18
+ @input="(value) => $emit('input', value)"
19
+ />
20
+ </form-field>
21
+ </template>
22
+
23
+ <script lang="ts">
24
+ import { Component, Vue, Prop } from 'vue-property-decorator';
25
+
26
+ import FormField from '@/components/helpers/FormField.vue';
27
+
28
+ @Component({ name: 'CTextArea', components: { FormField } })
29
+ export default class CTextArea extends Vue {
30
+ @Prop(String) label?: string;
31
+ @Prop(String) placeholder?: string;
32
+ @Prop({ type: String, required: true }) id!: string;
33
+ @Prop({ type: Boolean, default: false }) disabled!: boolean;
34
+ @Prop({ type: String, default: '' }) value!: string;
35
+ @Prop({ type: Array, default: () => [] }) rules!: ((value: string) => string | boolean)[];
36
+ }
37
+ </script>
38
+
39
+ <style lang="less" scoped>
40
+ @import '~@/styles/form-fields.less';
41
+
42
+ .text-area__input {
43
+ .form-field();
44
+ }
45
+
46
+ .text-area__input--disabled {
47
+ .form-field-disabled();
48
+ }
49
+ </style>
package/src/index.d.ts CHANGED
@@ -8,6 +8,9 @@ export const CAlert: Component;
8
8
  export const CBanner: Component;
9
9
  export const CButton: Component;
10
10
  export const CCard: Component;
11
+ export const CCardFooter: Component;
12
+ export const CCardHeader: Component;
13
+ export const CCardSection: Component;
11
14
  export const CCheckbox: Component;
12
15
  export const CIconButton: Component;
13
16
  export const CListItem: Component;
@@ -18,6 +21,7 @@ export const CSegmentedButtonOption: Component;
18
21
  export const CSelect: Component;
19
22
  export const CSkeletonLoaderCircle: Component;
20
23
  export const CSkeletonLoaderText: Component;
24
+ export const CTextArea: Component;
21
25
  export const CTextField: Component;
22
26
 
23
27
  export const Theme: typeof _Theme;
package/src/index.ts CHANGED
@@ -4,6 +4,9 @@ import _CAlert from '@/components/CAlert.vue';
4
4
  import _CBanner from '@/components/CBanner.vue';
5
5
  import _CButton from '@/components/CButton.vue';
6
6
  import _CCard from '@/components/CCard.vue';
7
+ import _CCardFooter from '@/components/CCardFooter.vue';
8
+ import _CCardHeader from '@/components/CCardHeader.vue';
9
+ import _CCardSection from '@/components/CCardSection.vue';
7
10
  import _CCheckbox from '@/components/CCheckbox.vue';
8
11
  import _CIconButton from '@/components/CIconButton.vue';
9
12
  import _CListItem from '@/components/CListItem.vue';
@@ -14,6 +17,7 @@ import _CSegmentedButtonOption from '@/components/CSegmentedButtonOption.vue';
14
17
  import _CSelect from '@/components/CSelect.vue';
15
18
  import _CSkeletonLoaderCircle from '@/components/CSkeletonLoaderCircle.vue';
16
19
  import _CSkeletonLoaderText from '@/components/CSkeletonLoaderText.vue';
20
+ import _CTextArea from '@/components/CTextArea.vue';
17
21
  import _CTextField from '@/components/CTextField.vue';
18
22
  import _Icons from '@/theme/icons';
19
23
 
@@ -27,6 +31,9 @@ export const CAlert = _CAlert;
27
31
  export const CBanner = _CBanner;
28
32
  export const CButton = _CButton;
29
33
  export const CCard = _CCard;
34
+ export const CCardFooter = _CCardFooter;
35
+ export const CCardHeader = _CCardHeader;
36
+ export const CCardSection = _CCardSection;
30
37
  export const CCheckbox = _CCheckbox;
31
38
  export const CIconButton = _CIconButton;
32
39
  export const CListItem = _CListItem;
@@ -37,4 +44,5 @@ export const CSegmentedButtonOption = _CSegmentedButtonOption;
37
44
  export const CSelect = _CSelect;
38
45
  export const CSkeletonLoaderCircle = _CSkeletonLoaderCircle;
39
46
  export const CSkeletonLoaderText = _CSkeletonLoaderText;
47
+ export const CTextArea = _CTextArea;
40
48
  export const CTextField = _CTextField;
@@ -16,6 +16,7 @@
16
16
  & /deep/ .v-input__slot {
17
17
  min-height: 48px;
18
18
  padding: 0 16px !important; // Override Vuetify.
19
+ z-index: 0;
19
20
  }
20
21
 
21
22
  & /deep/ input,
@@ -99,7 +99,6 @@
99
99
  }
100
100
 
101
101
  // CARDS
102
- @card-body-v-spacing: 16px;
103
102
  @card-h-spacing: 16px;
104
103
  @card-header-v-spacing: 12px;
105
104
 
@@ -1,22 +0,0 @@
1
- .button-container() {
2
- align-items: stretch;
3
- display: flex;
4
- flex-direction: column;
5
-
6
- & /deep/ .button--primary,
7
- & /deep/ .button--secondary {
8
- margin-top: 12px;
9
-
10
- &:last-child {
11
- margin-bottom: 12px;
12
- }
13
- }
14
-
15
- & /deep/ .button--tertiary {
16
- margin-top: 8px;
17
-
18
- &:last-child {
19
- margin-bottom: 8px;
20
- }
21
- }
22
- }