@propelinc/citrus-ui 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/citrus-ui.cdn.css +1 -1
  2. package/dist/citrus-ui.css +1 -1
  3. package/dist/colors/colors.d.ts +12 -0
  4. package/dist/components/CBadge.vue.d.ts +0 -1
  5. package/dist/components/CCard.vue.d.ts +0 -5
  6. package/dist/components/CIconButton.vue.d.ts +0 -6
  7. package/dist/components/CMaskedTextField.vue.d.ts +23 -60
  8. package/dist/components/CPhoneField.vue.d.ts +40 -92
  9. package/dist/components/CProgressRing.vue.d.ts +0 -1
  10. package/dist/components/CSelect.vue.d.ts +0 -4
  11. package/dist/components/CSkeleton.vue.d.ts +5 -1
  12. package/dist/components/CSkeletonLoaderCard.vue.d.ts +3 -0
  13. package/dist/components/CSplitInput.vue.d.ts +1 -5
  14. package/dist/components/CSsnField.vue.d.ts +41 -95
  15. package/dist/components/CSwitchListItem.vue.d.ts +1 -4
  16. package/dist/components/CTextArea.vue.d.ts +3 -8
  17. package/dist/components/CTextField.vue.d.ts +6 -14
  18. package/dist/components/CTextLink.vue.d.ts +0 -3
  19. package/dist/components/CZipcodeField.vue.d.ts +42 -96
  20. package/dist/components/index.d.ts +0 -2
  21. package/dist/composables/colors.d.ts +3 -2
  22. package/dist/composables/input-mask.d.ts +2 -2
  23. package/dist/composables/toast.d.ts +1 -0
  24. package/dist/index.cdn.mjs +3162 -3178
  25. package/dist/index.cdn.mjs.map +1 -1
  26. package/dist/index.mjs +1166 -1182
  27. package/dist/index.mjs.map +1 -1
  28. package/dist/styles.css +11 -2
  29. package/package.json +3 -1
  30. package/src/colors/colors.ts +44 -0
  31. package/src/colors/util-classes.ts +4 -0
  32. package/src/components/CAppBar.vue +3 -3
  33. package/src/components/CBadge.vue +3 -4
  34. package/src/components/CBottomSheet.vue +2 -2
  35. package/src/components/CCard.vue +3 -8
  36. package/src/components/CIconButton.vue +0 -6
  37. package/src/components/CLoader.vue +3 -3
  38. package/src/components/CMaskedTextField.vue +4 -9
  39. package/src/components/CProgressRing.vue +3 -4
  40. package/src/components/CSelect.vue +0 -4
  41. package/src/components/CSkeleton.vue +12 -1
  42. package/src/components/CSkeletonLoaderCard.vue +4 -1
  43. package/src/components/CSplitInput.vue +1 -5
  44. package/src/components/CSquaredIcon.vue +2 -2
  45. package/src/components/CSsnField.vue +1 -3
  46. package/src/components/CSwitchListItem.vue +1 -4
  47. package/src/components/CTextArea.vue +3 -8
  48. package/src/components/CTextField.vue +3 -11
  49. package/src/components/CTextLink.vue +0 -3
  50. package/src/components/CToastsList.vue +1 -0
  51. package/src/components/CZipcodeField.vue +2 -4
  52. package/src/components/index.ts +0 -2
  53. package/src/composables/colors.ts +12 -4
  54. package/src/composables/input-mask.ts +4 -4
  55. package/src/composables/toast.ts +1 -0
  56. package/src/styles/_core.scss +1 -1
  57. package/src/styles/_typography.scss +4 -0
  58. package/src/styles/layer-order.css +1 -0
  59. package/src/styles/tailwind.css +3 -0
  60. package/dist/components/CCol.vue.d.ts +0 -30
  61. package/dist/components/CRow.vue.d.ts +0 -41
  62. package/src/components/CCol.vue +0 -54
  63. package/src/components/CRow.vue +0 -64
@@ -4,7 +4,7 @@
4
4
  data-test="skeleton-loader-card"
5
5
  :style="{ height: `${height}px` }"
6
6
  >
7
- <CSkeleton />
7
+ <CSkeleton :squared="tile" />
8
8
  </div>
9
9
  </template>
10
10
 
@@ -15,9 +15,12 @@ withDefaults(
15
15
  defineProps<{
16
16
  /** Controls the height of the skeleton loader card */
17
17
  height?: number | string;
18
+ /** Toggles a squared-off card style intended to fill the width of the page */
19
+ tile?: boolean;
18
20
  }>(),
19
21
  {
20
22
  height: 100,
23
+ tile: false,
21
24
  }
22
25
  );
23
26
  </script>
@@ -46,7 +46,7 @@ const props = withDefaults(
46
46
  /** A hint to show the appropriate virtual keyboard, e.g. "numeric". */
47
47
  inputmode?: HTMLAttributes['inputmode'];
48
48
  /** The input's label */
49
- label?: string | null;
49
+ label?: string;
50
50
  /** The input's name */
51
51
  name?: string;
52
52
  /** Validation rules */
@@ -57,12 +57,8 @@ const props = withDefaults(
57
57
  value?: string;
58
58
  }>(),
59
59
  {
60
- autocomplete: undefined,
61
60
  dataTest: 'split-input',
62
61
  disabled: false,
63
- inputmode: undefined,
64
- label: null,
65
- name: undefined,
66
62
  rules: () => [],
67
63
  type: 'text',
68
64
  value: '',
@@ -19,7 +19,7 @@ import { FontAwesomeIcon as FontAwesomeIconComponent } from '@fortawesome/vue-fo
19
19
  import type { Component, VNode } from 'vue';
20
20
  import { computed, onMounted } from 'vue';
21
21
 
22
- import { useCssColor } from '@propelinc/citrus-ui/src/composables/colors';
22
+ import { usePaletteColor } from '@propelinc/citrus-ui/src/composables/colors';
23
23
  import type { FaIconArray } from '@propelinc/citrus-ui/src/types/font-awesome';
24
24
 
25
25
  // FontAwesomeIcon's prop types produce a union too complex for TypeScript to resolve
@@ -57,7 +57,7 @@ onMounted(() => {
57
57
  }
58
58
  });
59
59
 
60
- const { cssColor } = useCssColor(() => props.color);
60
+ const { cssColor } = usePaletteColor(() => props.color);
61
61
 
62
62
  const useWhiteIcon = computed(() => props.color === 'black');
63
63
  </script>
@@ -50,15 +50,13 @@ const props = withDefaults(
50
50
  defineProps<{
51
51
  dataTest?: string;
52
52
  id?: string;
53
- label?: string | null;
53
+ label?: string;
54
54
  rules?: Rules<string>;
55
55
  value?: string;
56
56
  fourDigitSsn?: boolean;
57
57
  }>(),
58
58
  {
59
59
  dataTest: 'ssn-field',
60
- id: undefined,
61
- label: null,
62
60
  rules: (): Rules<string> => [],
63
61
  value: '',
64
62
  fourDigitSsn: false,
@@ -49,7 +49,7 @@ withDefaults(
49
49
  /** Prevents the user from interacting with the switch */
50
50
  disabled?: boolean;
51
51
  /** Font Awesome icon to render on the left side of the component */
52
- icon?: string | string[] | IconDefinition | null;
52
+ icon?: string | string[] | IconDefinition;
53
53
  /** Color of the icon background */
54
54
  iconColor?: string;
55
55
  /** Plain body copy. Overridden by the default slot. */
@@ -62,10 +62,7 @@ withDefaults(
62
62
  {
63
63
  align: 'center',
64
64
  disabled: false,
65
- icon: null,
66
65
  iconColor: 'gray-100',
67
- label: undefined,
68
- title: undefined,
69
66
  value: false,
70
67
  }
71
68
  );
@@ -91,7 +91,7 @@ const props = withDefaults(
91
91
  * Overrides the default validation message. If provided, this error message will always
92
92
  * be shown, regardless of any other failing validation rules.
93
93
  */
94
- errorMessage?: string | null;
94
+ errorMessage?: string;
95
95
  /** Hides the label and instead labels the field with `aria-label` */
96
96
  hideLabel?: boolean;
97
97
  /**
@@ -100,9 +100,9 @@ const props = withDefaults(
100
100
  */
101
101
  hideDetails?: boolean | 'auto';
102
102
  /** The textarea element's id */
103
- id?: string | null;
103
+ id?: string;
104
104
  /** The textarea's label, both visual and screenreader-only */
105
- label?: string | null;
105
+ label?: string;
106
106
  /** Sets the maxlength attribute of the textarea */
107
107
  maxlength?: number;
108
108
  /** The textarea's placeholder */
@@ -124,13 +124,8 @@ const props = withDefaults(
124
124
  counterValue: null,
125
125
  dataTest: 'text-area',
126
126
  disabled: false,
127
- errorMessage: null,
128
127
  hideDetails: false,
129
128
  hideLabel: false,
130
- id: null,
131
- label: null,
132
- maxlength: undefined,
133
- placeholder: '',
134
129
  required: false,
135
130
  rules: () => [],
136
131
  value: '',
@@ -158,9 +158,9 @@ defineOptions({ inheritAttrs: false });
158
158
 
159
159
  const props = withDefaults(
160
160
  defineProps<{
161
- id?: string | null;
162
- label?: string | null;
163
- ariaLabel?: string | null;
161
+ id?: string;
162
+ label?: string;
163
+ ariaLabel?: string;
164
164
  placeholder?: string;
165
165
  type?:
166
166
  | 'text'
@@ -195,16 +195,9 @@ const props = withDefaults(
195
195
  errorMessage?: string;
196
196
  }>(),
197
197
  {
198
- id: null,
199
- label: null,
200
- ariaLabel: null,
201
- placeholder: '',
202
198
  type: 'text',
203
199
  clearable: false,
204
200
  size: 'medium',
205
- inputmode: undefined,
206
- minlength: undefined,
207
- maxlength: undefined,
208
201
  disabled: false,
209
202
  hideable: false,
210
203
  hideLabel: false,
@@ -216,7 +209,6 @@ const props = withDefaults(
216
209
  rules: () => [],
217
210
  validateOnBlur: true,
218
211
  required: false,
219
- errorMessage: undefined,
220
212
  }
221
213
  );
222
214
 
@@ -32,9 +32,6 @@ const props = withDefaults(
32
32
  underline?: boolean;
33
33
  }>(),
34
34
  {
35
- to: undefined,
36
- href: undefined,
37
- target: undefined,
38
35
  underline: true,
39
36
  }
40
37
  );
@@ -6,6 +6,7 @@
6
6
  :data-test="toast.dataTest || 'c-toast'"
7
7
  :message="toast.message"
8
8
  :variant="toast.variant"
9
+ :dismissible="toast.dismissible"
9
10
  @hide="dismissToast(toast.id)"
10
11
  />
11
12
  </template>
@@ -43,16 +43,14 @@ const props = withDefaults(
43
43
  defineProps<{
44
44
  dataTest?: string;
45
45
  id?: string;
46
- label?: string | null;
47
- placeholder?: string | null;
46
+ label?: string;
47
+ placeholder?: string;
48
48
  rules?: Rules<string>;
49
49
  value?: string;
50
50
  }>(),
51
51
  {
52
52
  dataTest: 'zipcode-field',
53
53
  id: undefined,
54
- label: null,
55
- placeholder: null,
56
54
  rules: (): Rules<string> => [],
57
55
  value: '',
58
56
  }
@@ -9,7 +9,6 @@ export { default as CCardFooter } from '@propelinc/citrus-ui/src/components/CCar
9
9
  export { default as CCardHeader } from '@propelinc/citrus-ui/src/components/CCardHeader.vue';
10
10
  export { default as CCardSection } from '@propelinc/citrus-ui/src/components/CCardSection.vue';
11
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
12
  export { default as CDivider } from '@propelinc/citrus-ui/src/components/CDivider.vue';
14
13
  export { default as CDobField } from '@propelinc/citrus-ui/src/components/CDobField.vue';
15
14
  export { default as CDobSelect } from '@propelinc/citrus-ui/src/components/CDobSelect.vue';
@@ -41,7 +40,6 @@ export { default as CProgressRing } from '@propelinc/citrus-ui/src/components/CP
41
40
  export { default as CRadio } from '@propelinc/citrus-ui/src/components/CRadio.vue';
42
41
  export { default as CRadioGroup } from '@propelinc/citrus-ui/src/components/CRadioGroup.vue';
43
42
  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
43
  export { default as CSafeArea } from '@propelinc/citrus-ui/src/components/CSafeArea.vue';
46
44
  export { default as CSectionHeader } from '@propelinc/citrus-ui/src/components/CSectionHeader.vue';
47
45
  export { default as CSelect } from '@propelinc/citrus-ui/src/components/CSelect.vue';
@@ -3,20 +3,23 @@ import { computed, toValue } from 'vue';
3
3
 
4
4
  import Colors, {
5
5
  type CssColor,
6
+ type RgbaColor,
6
7
  isColorKey,
7
8
  isCssColor,
9
+ isPaletteRgba,
8
10
  } from '@propelinc/citrus-ui/src/colors/colors';
9
11
 
10
12
  /**
11
13
  * Maps from a color name or hex code to its corresponding CSS color value.
12
14
  * Gray neutrals resolve to rgba(); other palette colors are hex.
15
+ * Can also accept a palette color converted to rgba for transparency via `withAlpha`.
13
16
  *
14
17
  * @param name - The color to resolve. Can be in kebab case, SCREAMING_SNAKE_CASE, or a hex code from the palette.
15
18
  * @returns The CSS color value (hex or rgba) and whether the color is valid.
16
19
  */
17
- export function useCssColor(name: MaybeRefOrGetter<string | undefined>): {
20
+ export function usePaletteColor(name: MaybeRefOrGetter<string | undefined>): {
18
21
  cssColor: Ref<CssColor | undefined>;
19
- isValidColor: Ref<boolean>;
22
+ isPaletteColor: Ref<boolean>;
20
23
  } {
21
24
  const normalizedColor = computed(() =>
22
25
  isCssColor(toValue(name)) ? (toValue(name)?.toLowerCase() as CssColor) : undefined
@@ -48,12 +51,17 @@ export function useCssColor(name: MaybeRefOrGetter<string | undefined>): {
48
51
  return normalizedColor.value;
49
52
  }
50
53
 
54
+ // If we're given a palette rgba (transparent variant via withAlpha), return it as-is
55
+ if (isPaletteRgba(toValue(name))) {
56
+ return toValue(name) as RgbaColor;
57
+ }
58
+
51
59
  return undefined;
52
60
  });
53
61
 
54
- const isValidColor = computed(() => {
62
+ const isPaletteColor = computed(() => {
55
63
  return cssColor.value !== undefined;
56
64
  });
57
65
 
58
- return { cssColor, isValidColor };
66
+ return { cssColor, isPaletteColor };
59
67
  }
@@ -3,8 +3,8 @@ import { type Ref, computed, watch } from 'vue';
3
3
 
4
4
  import { useInternalValue } from '@propelinc/citrus-ui/src/composables/binding';
5
5
 
6
- const toNumber = (value: number | string | null): number | null => {
7
- if (value === null || value === '') {
6
+ const toNumber = (value: number | string | null | undefined): number | null => {
7
+ if (value === null || value === undefined || value === '') {
8
8
  return null;
9
9
  } else if (typeof value === 'number') {
10
10
  return value;
@@ -68,7 +68,7 @@ export function useInputMask(
68
68
  }
69
69
 
70
70
  export function useMaskedMinLength(
71
- minlength: Ref<number | string | null>,
71
+ minlength: Ref<number | string | undefined>,
72
72
  value: Ref<string>,
73
73
  options: Ref<MaskOptions>
74
74
  ): Ref<number | null> {
@@ -122,7 +122,7 @@ export function useMaskedMinLength(
122
122
  }
123
123
 
124
124
  export function useMaskedMaxLength(
125
- maxlength: Ref<number | string | null>,
125
+ maxlength: Ref<number | string | undefined>,
126
126
  options: Ref<MaskOptions>
127
127
  ): Ref<number | null> {
128
128
  return computed(() => {
@@ -10,6 +10,7 @@ export interface Toast {
10
10
  dataTest?: string;
11
11
  message: string;
12
12
  variant: ToastVariant;
13
+ dismissible?: boolean;
13
14
  }
14
15
 
15
16
  interface ToastInjection {
@@ -187,7 +187,7 @@ $large-headline: (
187
187
  'font-family': var(--font-family-headline, #{$font-family-base}),
188
188
  'size': $font-size-2x-large,
189
189
  'weight': $font-weight-semibold,
190
- 'line-height': $line-height-small,
190
+ 'line-height': $line-height-medium,
191
191
  'letter-spacing': $letter-spacing-tighten-medium,
192
192
  );
193
193
 
@@ -62,6 +62,10 @@ body {
62
62
  @include caption;
63
63
  }
64
64
 
65
+ .wallet-caption {
66
+ @include wallet-caption;
67
+ }
68
+
65
69
  .caption-small {
66
70
  @include caption-small;
67
71
  }
@@ -0,0 +1 @@
1
+ @layer reset, base, components, utilities;
@@ -0,0 +1,3 @@
1
+ @import '@propelinc/propel-tailwind/src/tailwind.css';
2
+ @source "../components";
3
+ @source "../../stories/";
@@ -1,30 +0,0 @@
1
- import { VNode, DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
2
- type Cols = 'auto' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12';
3
- type __VLS_Props = {
4
- /**
5
- * Sets the default number of columns the component extends.
6
- * Available options are: 1 -> 12 and auto.
7
- */
8
- cols?: Cols | null;
9
- };
10
- declare function __VLS_template(): {
11
- attrs: Partial<{}>;
12
- slots: Readonly<{
13
- default?: () => VNode[];
14
- }> & {
15
- default?: () => VNode[];
16
- };
17
- refs: {};
18
- rootEl: HTMLDivElement;
19
- };
20
- type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
21
- declare const __VLS_component: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
22
- cols: Cols | null;
23
- }, {}, {}, {}, string, ComponentProvideOptions, false, {}, HTMLDivElement>;
24
- declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
25
- export default _default;
26
- type __VLS_WithTemplateSlots<T, S> = T & {
27
- new (): {
28
- $slots: S;
29
- };
30
- };
@@ -1,41 +0,0 @@
1
- import { VNode, DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
2
- type __VLS_Props = {
3
- /** Applies the align-items css property.
4
- * Available options are: start, center, end and stretch. */
5
- align?: 'center' | 'start' | 'end' | 'stretch' | null;
6
- /** Applies the align-content css property.
7
- * Available options are: start, center, end, and stretch. */
8
- alignContent?: 'center' | 'start' | 'end' | 'stretch' | null;
9
- /** Reduces the gutter between c-cols. */
10
- dense?: boolean;
11
- /** Removes the gutter between c-cols. */
12
- noGutters?: boolean;
13
- /** Applies the justify-content css property.
14
- * Available options are: start, center, end, space-between and space-around. */
15
- justify?: 'center' | 'start' | 'end' | 'space-between' | 'space-around' | null;
16
- };
17
- declare function __VLS_template(): {
18
- attrs: Partial<{}>;
19
- slots: Readonly<{
20
- default?: () => VNode[];
21
- }> & {
22
- default?: () => VNode[];
23
- };
24
- refs: {};
25
- rootEl: HTMLDivElement;
26
- };
27
- type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
28
- declare const __VLS_component: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
29
- align: "center" | "start" | "end" | "stretch" | null;
30
- alignContent: "center" | "start" | "end" | "stretch" | null;
31
- dense: boolean;
32
- noGutters: boolean;
33
- justify: "center" | "start" | "end" | "space-between" | "space-around" | null;
34
- }, {}, {}, {}, string, ComponentProvideOptions, false, {}, HTMLDivElement>;
35
- declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
36
- export default _default;
37
- type __VLS_WithTemplateSlots<T, S> = T & {
38
- new (): {
39
- $slots: S;
40
- };
41
- };
@@ -1,54 +0,0 @@
1
- <template>
2
- <div class="c-col" :class="{ [`c-col-${cols}`]: cols }">
3
- <slot />
4
- </div>
5
- </template>
6
-
7
- <script setup lang="ts">
8
- import type { VNode } from 'vue';
9
-
10
- type Cols = 'auto' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12';
11
-
12
- withDefaults(
13
- defineProps<{
14
- /**
15
- * Sets the default number of columns the component extends.
16
- * Available options are: 1 -> 12 and auto.
17
- */
18
- cols?: Cols | null;
19
- }>(),
20
- {
21
- cols: null,
22
- }
23
- );
24
-
25
- defineSlots<{
26
- default?: () => VNode[];
27
- }>();
28
- </script>
29
-
30
- <style lang="scss" scoped>
31
- .c-col {
32
- flex-basis: 0;
33
- flex-grow: 1;
34
- max-width: 100%;
35
-
36
- &:not(.c-col-auto) {
37
- padding: 12px;
38
- width: 100%;
39
- }
40
- }
41
-
42
- .c-col-auto {
43
- flex: 0 0 auto;
44
- max-width: 100%;
45
- width: auto;
46
- }
47
-
48
- @for $i from 1 through 12 {
49
- .c-col-#{$i} {
50
- flex: 0 0 calc(#{$i} / 12 * 100%);
51
- max-width: calc(#{$i} / 12 * 100%);
52
- }
53
- }
54
- </style>
@@ -1,64 +0,0 @@
1
- <template>
2
- <div
3
- class="c-row"
4
- :class="{
5
- 'c-row--dense': dense,
6
- 'c-row--no-gutters': noGutters,
7
- [`align-${align}`]: align,
8
- [`align-content-${alignContent}`]: alignContent,
9
- [`justify-${justify}`]: justify,
10
- }"
11
- >
12
- <slot />
13
- </div>
14
- </template>
15
-
16
- <script setup lang="ts">
17
- import type { VNode } from 'vue';
18
-
19
- withDefaults(
20
- defineProps<{
21
- /** Applies the align-items css property.
22
- * Available options are: start, center, end and stretch. */
23
- align?: 'center' | 'start' | 'end' | 'stretch' | null;
24
- /** Applies the align-content css property.
25
- * Available options are: start, center, end, and stretch. */
26
- alignContent?: 'center' | 'start' | 'end' | 'stretch' | null;
27
- /** Reduces the gutter between c-cols. */
28
- dense?: boolean;
29
- /** Removes the gutter between c-cols. */
30
- noGutters?: boolean;
31
- /** Applies the justify-content css property.
32
- * Available options are: start, center, end, space-between and space-around. */
33
- justify?: 'center' | 'start' | 'end' | 'space-between' | 'space-around' | null;
34
- }>(),
35
- {
36
- align: null,
37
- alignContent: null,
38
- dense: false,
39
- noGutters: false,
40
- justify: null,
41
- }
42
- );
43
-
44
- defineSlots<{
45
- default?: () => VNode[];
46
- }>();
47
- </script>
48
-
49
- <style lang="scss" scoped>
50
- .c-row {
51
- display: flex;
52
- flex: 1 1 auto;
53
- flex-wrap: wrap;
54
- margin: 0 -12px;
55
- }
56
-
57
- .c-row--dense {
58
- margin: 0 -4px;
59
- }
60
-
61
- .c-row--no-gutters {
62
- margin: 0;
63
- }
64
- </style>