@citizenplane/pimp 8.1.2 → 8.2.1

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.
@@ -3,55 +3,72 @@
3
3
  <span v-if="hasIconSlot" class="cpBadge__icon"> <slot name="icon" /></span>
4
4
  <cp-icon v-else-if="icon" :type="icon" class="cpBadge__icon" />
5
5
  <span class="cpBadge__label"><slot /></span>
6
+ <button v-if="isClearable" class="cpBadge__clear" type="button" @click="onClear">
7
+ <cp-icon class="cpBadge__icon cpBadge__icon--isClear" type="x" />
8
+ </button>
6
9
  </div>
7
10
  </template>
8
11
 
9
12
  <script>
10
- import { capitalizeFirstLetter } from '@/helpers'
11
-
13
+ // Need to be declared in module scope, see https://stackoverflow.com/a/70947352
12
14
  const badgeColors = ['neutral', 'blue', 'green', 'red', 'orange', 'purple', 'teal', 'pink', 'yellow']
15
+ </script>
13
16
 
14
- export default {
15
- props: {
16
- color: {
17
- type: String,
18
- default: '',
19
- validator: (value) => Object.values(badgeColors).includes(value) || value === '',
20
- },
21
- isSolid: {
22
- type: Boolean,
23
- default: false,
24
- required: false,
25
- },
26
- isPlain: {
27
- type: Boolean,
28
- default: false,
29
- required: false,
30
- },
31
- icon: {
32
- type: String,
33
- default: '',
34
- required: false,
35
- },
17
+ <script setup>
18
+ import { computed, useSlots } from 'vue'
19
+
20
+ import { capitalizeFirstLetter } from '@/helpers'
21
+
22
+ const props = defineProps({
23
+ color: {
24
+ type: String,
25
+ default: '',
26
+ validator: (value) => badgeColors.includes(value) || value === '',
27
+ },
28
+ isSolid: {
29
+ type: Boolean,
30
+ default: false,
31
+ },
32
+ isPlain: {
33
+ type: Boolean,
34
+ default: false,
35
+ },
36
+ isClearable: {
37
+ type: Boolean,
38
+ default: false,
36
39
  },
37
- computed: {
38
- capitalizedColor() {
39
- return capitalizeFirstLetter(this.color)
40
- },
41
- computedClasses() {
42
- const hasIcon = this.icon !== '' || this.hasIconSlot
43
-
44
- return [
45
- this.isSolid ? 'cpBadge--isSolid' : '',
46
- this.isPlain ? 'cpBadge--isPlain' : '',
47
- hasIcon ? 'cpBadge--hasIcon' : '',
48
- this.capitalizedColor ? `cpBadge--is${this.capitalizedColor}` : '',
49
- ]
50
- },
51
- hasIconSlot() {
52
- return !!this.$slots.icon
53
- },
40
+ icon: {
41
+ type: String,
42
+ default: '',
54
43
  },
44
+ })
45
+
46
+ const emits = defineEmits(['on-clear'])
47
+
48
+ const slots = useSlots()
49
+
50
+ const capitalizedColor = computed(() => {
51
+ return capitalizeFirstLetter(props.color)
52
+ })
53
+
54
+ const hasIconSlot = computed(() => {
55
+ return !!slots.icon
56
+ })
57
+
58
+ const computedClasses = computed(() => {
59
+ const hasIcon = props.icon !== '' || hasIconSlot.value
60
+
61
+ return {
62
+ 'cpBadge--isSolid': props.isSolid,
63
+ 'cpBadge--isPlain': props.isPlain,
64
+ 'cpBadge--hasIcon': hasIcon,
65
+ 'cpBadge--isClearable': props.isClearable,
66
+ [`cpBadge--is${capitalizedColor.value}`]: capitalizedColor.value,
67
+ }
68
+ })
69
+
70
+ const onClear = () => {
71
+ emits('on-clear')
55
72
  }
56
73
  </script>
57
74
 
@@ -60,11 +77,23 @@ export default {
60
77
  background-color: rgba($color, 0.14);
61
78
  border-color: transparent;
62
79
  color: $color;
80
+
81
+ .cpBadge__clear:hover,
82
+ .cpBadge__clear:focus-visible {
83
+ background-color: $color;
84
+ }
63
85
  }
64
86
 
65
87
  @mixin cp-badge-color-solid($color) {
88
+ color: $neutral-light;
66
89
  background-color: $color;
67
90
  border-color: transparent;
91
+
92
+ .cpBadge__clear:hover,
93
+ .cpBadge__clear:focus-visible {
94
+ color: $color;
95
+ background-color: $neutral-light;
96
+ }
68
97
  }
69
98
 
70
99
  @mixin cp-badge-style($color, $className) {
@@ -80,11 +109,29 @@ export default {
80
109
  .cpBadge {
81
110
  display: inline-flex;
82
111
  align-items: center;
83
- padding: pxToRem(4) pxToRem(8);
112
+ padding-block: $space-sm;
84
113
  font-size: pxToEm(14);
85
114
  font-weight: 500;
86
115
  border-radius: pxToRem(1000);
87
- border: pxToRem(1) solid $border-color;
116
+ border: 1px solid $border-color;
117
+
118
+ @include cp-badge-style($neutral-dark, 'Neutral');
119
+ @include cp-badge-style($secondary-color, 'Blue');
120
+ @include cp-badge-style($green-2, 'Green');
121
+ @include cp-badge-style($red, 'Red');
122
+ @include cp-badge-style($orange, 'Orange');
123
+ @include cp-badge-style($purple, 'Purple');
124
+ @include cp-badge-style($blue-1, 'Teal');
125
+ @include cp-badge-style($pink, 'Pink');
126
+ @include cp-badge-style($yellow, 'Yellow');
127
+
128
+ &--isYellow#{&}--isSolid {
129
+ color: darken($yellow, 20);
130
+
131
+ &:before {
132
+ background-color: darken($yellow, 20);
133
+ }
134
+ }
88
135
 
89
136
  &:not(#{&}--isPlain):not(#{&}--hasIcon)::before {
90
137
  content: '';
@@ -96,51 +143,52 @@ export default {
96
143
  background-color: currentColor;
97
144
  }
98
145
 
99
- &--isSolid {
100
- color: $neutral-light;
146
+ &:not(&--isClearable) {
147
+ padding-inline: $space;
148
+ }
149
+
150
+ &--isClearable {
151
+ padding-left: $space;
152
+ padding-right: $space-sm;
101
153
  }
102
154
 
103
155
  &__label {
104
156
  @extend %u-text-ellipsis;
105
157
  flex: 1;
158
+ min-width: 0;
106
159
  }
107
160
 
108
161
  &__icon {
162
+ color: currentColor;
109
163
  width: pxToRem(16);
110
164
  height: pxToRem(16);
111
- margin-right: $space-sm;
112
- color: currentColor;
113
- stroke: currentColor;
114
165
 
115
- svg {
116
- width: 100%;
117
- height: 100%;
166
+ &:not(&--isClear) {
167
+ margin-right: $space-sm;
118
168
  }
119
- }
120
-
121
- @include cp-badge-style($neutral-dark, 'Neutral');
122
-
123
- @include cp-badge-style($secondary-color, 'Blue');
124
-
125
- @include cp-badge-style($green-2, 'Green');
126
-
127
- @include cp-badge-style($red, 'Red');
128
-
129
- @include cp-badge-style($orange, 'Orange');
130
-
131
- @include cp-badge-style($purple, 'Purple');
132
169
 
133
- @include cp-badge-style($blue-1, 'Teal');
134
-
135
- @include cp-badge-style($pink, 'Pink');
170
+ &--isClear svg {
171
+ stroke-width: pxToRem(2);
172
+ }
173
+ }
136
174
 
137
- @include cp-badge-style($yellow, 'Yellow');
175
+ &__clear {
176
+ display: flex;
177
+ align-items: center;
178
+ justify-content: center;
179
+ margin-left: pxToRem(6);
180
+ padding: pxToRem(1);
181
+ border-radius: 100%;
182
+ color: inherit;
138
183
 
139
- &--isYellow#{&}--isSolid {
140
- color: darken($yellow, 20);
184
+ &:hover,
185
+ &:focus-visible {
186
+ color: $neutral-light;
187
+ background-color: $neutral-dark;
188
+ }
141
189
 
142
- &:before {
143
- background-color: darken($yellow, 20);
190
+ &:focus {
191
+ outline: none !important;
144
192
  }
145
193
  }
146
194
  }
@@ -1,15 +1,16 @@
1
1
  <template>
2
- <section-container section-title="Toggles" class="sectionAtomicElements">
2
+ <section-container section-title="Atomic elements" class="sectionAtomicElements">
3
3
  <div class="item">
4
4
  <h3>Badge</h3>
5
5
  <div class="sectionAtomicElements__badges">
6
6
  <cp-badge
7
- v-for="{ color, label, icon, plain, solid } in badgeList"
7
+ v-for="{ color, label, icon, plain, solid, clear } in badgeList"
8
8
  :key="color"
9
9
  :color="color"
10
10
  :icon="icon"
11
11
  :is-plain="plain"
12
12
  :is-solid="solid"
13
+ :is-clearable="clear"
13
14
  class="sectionAtomicElements__badge"
14
15
  >
15
16
  {{ label }}
@@ -31,11 +32,12 @@ export default {
31
32
  badgeList: [
32
33
  {
33
34
  color: '',
34
- label: 'Default plain',
35
+ label: 'Default plain clearable',
36
+ clear: true,
35
37
  },
36
38
  {
37
39
  color: '',
38
- label: 'Default plain',
40
+ label: 'Default plain w/ icon',
39
41
  icon: 'copy',
40
42
  },
41
43
  {
@@ -44,27 +46,29 @@ export default {
44
46
  },
45
47
  {
46
48
  color: 'green',
47
- label: 'Processed',
49
+ label: 'Solid green clearable',
48
50
  solid: true,
51
+ clear: true,
49
52
  },
50
53
  {
51
54
  color: 'red',
52
- label: 'Aborted',
55
+ label: 'Default red',
56
+ icon: 'copy',
53
57
  },
54
58
  {
55
59
  color: 'blue',
56
- label: 'In Progress',
60
+ label: 'Default blue clearable',
61
+ clear: true,
57
62
  },
58
63
  {
59
64
  color: 'purple',
60
- label: 'trial',
65
+ label: 'Solid purple w/ icon',
61
66
  icon: 'copy',
62
67
  solid: true,
63
68
  },
64
69
  ],
65
70
  }
66
71
  },
67
- methods: {},
68
72
  }
69
73
  </script>
70
74
 
@@ -72,11 +76,8 @@ export default {
72
76
  .sectionAtomicElements {
73
77
  &__badges {
74
78
  display: flex;
75
- margin: pxToRem(-4);
76
- }
77
-
78
- &__badge {
79
- margin: pxToRem(4);
79
+ flex-wrap: wrap;
80
+ gap: $space;
80
81
  }
81
82
  }
82
83
  </style>
@@ -33,7 +33,6 @@ export default {
33
33
 
34
34
  .item {
35
35
  width: 100%;
36
- max-width: 600px;
37
36
  margin-bottom: 20px;
38
37
  display: flex;
39
38
  flex-direction: column;