@citizenplane/pimp 18.19.1 → 18.19.3
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/dist/components/CpAncillaryCategory.vue.d.ts +3 -3
- package/dist/components/CpAncillaryCategory.vue.d.ts.map +1 -1
- package/dist/components/CpButton.vue.d.ts +9 -5
- package/dist/components/CpButton.vue.d.ts.map +1 -1
- package/dist/pimp.es.js +65 -66
- package/dist/pimp.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/CpAncillaryCategory.vue +74 -72
- package/src/components/CpButton.vue +10 -0
- package/src/stories/CpAncillaryCategory.stories.ts +50 -0
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="cpAncillaryCategory">
|
|
3
|
-
<
|
|
4
|
-
|
|
3
|
+
<component
|
|
4
|
+
:is="headerTag"
|
|
5
|
+
v-bind="headerAttrs"
|
|
6
|
+
class="cpAncillaryCategory__header"
|
|
7
|
+
@click="handleHeaderClick"
|
|
8
|
+
>
|
|
9
|
+
<div class="cpAncillaryCategory__lead">
|
|
5
10
|
<div class="cpAncillaryCategory__visual">
|
|
6
11
|
<img
|
|
7
12
|
v-if="visual"
|
|
@@ -12,34 +17,32 @@
|
|
|
12
17
|
/>
|
|
13
18
|
<cp-icon v-else class="cpAncillaryCategory__fallbackIcon" size="40" type="shopping-bag" />
|
|
14
19
|
</div>
|
|
15
|
-
<div class="
|
|
16
|
-
<
|
|
17
|
-
|
|
20
|
+
<div class="cpAncillaryCategory__content">
|
|
21
|
+
<div class="cpAncillaryCategory__texts">
|
|
22
|
+
<span :id="titleId" class="cpAncillaryCategory__title">{{ title }}</span>
|
|
23
|
+
<span class="cpAncillaryCategory__description">{{ description }}</span>
|
|
24
|
+
</div>
|
|
25
|
+
<div v-if="isSwitch" class="cpAncillaryCategory__trailing">
|
|
26
|
+
<span v-if="hasFromPrice" class="cpAncillaryCategory__price">{{ formattedPrice }}</span>
|
|
27
|
+
<cp-switch v-model="checked" color="accent" />
|
|
28
|
+
</div>
|
|
29
|
+
<div v-else-if="isActuallyExpandable" class="cpAncillaryCategory__trailing">
|
|
30
|
+
<span v-if="hasFromPrice" class="cpAncillaryCategory__fromPriceClip">
|
|
31
|
+
<span :aria-hidden="isOpen" class="cpAncillaryCategory__fromPrice" :class="fromPriceDynamicClass">
|
|
32
|
+
<span class="cpAncillaryCategory__fromPriceLabel">{{ fromPriceLabel }}</span>
|
|
33
|
+
<span class="cpAncillaryCategory__fromPriceAmount">{{ formattedPrice }}</span>
|
|
34
|
+
</span>
|
|
35
|
+
</span>
|
|
36
|
+
<cp-icon
|
|
37
|
+
class="cpAncillaryCategory__chevron"
|
|
38
|
+
:class="chevronDynamicClass"
|
|
39
|
+
size="24"
|
|
40
|
+
type="chevron-down"
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
18
43
|
</div>
|
|
19
|
-
</button>
|
|
20
|
-
<div v-if="isSwitch" class="cpAncillaryCategory__trailing">
|
|
21
|
-
<span v-if="hasFromPrice" class="cpAncillaryCategory__price">{{ formattedPrice }}</span>
|
|
22
|
-
<cp-switch v-model="checked" color="accent" />
|
|
23
44
|
</div>
|
|
24
|
-
|
|
25
|
-
<span v-if="hasFromPrice" class="cpAncillaryCategory__fromPriceClip">
|
|
26
|
-
<span :aria-hidden="isOpen" class="cpAncillaryCategory__fromPrice" :class="fromPriceDynamicClass">
|
|
27
|
-
<span class="cpAncillaryCategory__fromPriceLabel">{{ fromPriceLabel }}</span>
|
|
28
|
-
<span class="cpAncillaryCategory__fromPriceAmount">{{ formattedPrice }}</span>
|
|
29
|
-
</span>
|
|
30
|
-
</span>
|
|
31
|
-
<button
|
|
32
|
-
:aria-controls="bodyId"
|
|
33
|
-
:aria-expanded="isOpen"
|
|
34
|
-
:aria-labelledby="titleId"
|
|
35
|
-
class="cpAncillaryCategory__toggle"
|
|
36
|
-
type="button"
|
|
37
|
-
@click="handleToggle"
|
|
38
|
-
>
|
|
39
|
-
<cp-icon class="cpAncillaryCategory__chevron" :class="chevronDynamicClass" size="24" type="chevron-down" />
|
|
40
|
-
</button>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
45
|
+
</component>
|
|
43
46
|
<cp-transition-expand v-if="isActuallyExpandable">
|
|
44
47
|
<div v-if="isOpen">
|
|
45
48
|
<div :id="bodyId" class="cpAncillaryCategory__body">
|
|
@@ -98,6 +101,12 @@ const toggleId = useId()
|
|
|
98
101
|
const titleId = computed(() => `${toggleId}-title`)
|
|
99
102
|
const bodyId = computed(() => `${toggleId}-body`)
|
|
100
103
|
|
|
104
|
+
const headerTag = computed(() => (isActuallyExpandable.value ? 'button' : 'div'))
|
|
105
|
+
|
|
106
|
+
const headerAttrs = computed(() =>
|
|
107
|
+
isActuallyExpandable.value ? { type: 'button', 'aria-expanded': isOpen.value, 'aria-controls': bodyId.value } : {},
|
|
108
|
+
)
|
|
109
|
+
|
|
101
110
|
const categoryVisuals: Partial<Record<CpAncillaryCategoryTypes, string>> = {
|
|
102
111
|
[CpAncillaryCategoryTypes.BAGGAGES]: BaggagesVisual,
|
|
103
112
|
[CpAncillaryCategoryTypes.CARBON_OFFSET]: CarbonOffsetVisual,
|
|
@@ -126,8 +135,8 @@ const fromPriceDynamicClass = computed(() => ({ 'cpAncillaryCategory__fromPrice-
|
|
|
126
135
|
|
|
127
136
|
const chevronDynamicClass = computed(() => ({ 'cpAncillaryCategory__chevron--isRotated': isOpen.value }))
|
|
128
137
|
|
|
129
|
-
const
|
|
130
|
-
isOpen.value = !isOpen.value
|
|
138
|
+
const handleHeaderClick = () => {
|
|
139
|
+
if (isActuallyExpandable.value) isOpen.value = !isOpen.value
|
|
131
140
|
}
|
|
132
141
|
</script>
|
|
133
142
|
|
|
@@ -141,15 +150,38 @@ const handleToggle = () => {
|
|
|
141
150
|
border-radius: var(--cp-radius-xl);
|
|
142
151
|
background: var(--cp-background-primary);
|
|
143
152
|
box-shadow: var(--cp-shadows-xs);
|
|
153
|
+
container-type: inline-size;
|
|
144
154
|
gap: var(--cp-spacing-sm);
|
|
145
155
|
|
|
146
156
|
&__header {
|
|
157
|
+
@extend %u-focus-outline;
|
|
158
|
+
|
|
147
159
|
display: flex;
|
|
148
160
|
width: 100%;
|
|
149
|
-
align-items: center;
|
|
150
161
|
padding: var(--cp-spacing-lg);
|
|
151
162
|
border-radius: var(--cp-radius-lg);
|
|
163
|
+
text-align: left;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
&__lead {
|
|
167
|
+
display: flex;
|
|
168
|
+
width: 100%;
|
|
169
|
+
min-width: 0;
|
|
170
|
+
align-items: center;
|
|
171
|
+
gap: var(--cp-spacing-xl);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
&__content {
|
|
175
|
+
display: flex;
|
|
176
|
+
min-width: 0;
|
|
177
|
+
flex: auto;
|
|
178
|
+
align-items: center;
|
|
152
179
|
gap: var(--cp-spacing-lg);
|
|
180
|
+
|
|
181
|
+
@container (width < 30rem) {
|
|
182
|
+
flex-direction: column;
|
|
183
|
+
align-items: stretch;
|
|
184
|
+
}
|
|
153
185
|
}
|
|
154
186
|
|
|
155
187
|
&__trailing {
|
|
@@ -160,6 +192,11 @@ const handleToggle = () => {
|
|
|
160
192
|
padding: 0 var(--cp-spacing-xl);
|
|
161
193
|
border-radius: var(--cp-radius-lg);
|
|
162
194
|
gap: var(--cp-spacing-lg);
|
|
195
|
+
|
|
196
|
+
@container (width < 30rem) {
|
|
197
|
+
justify-content: flex-start;
|
|
198
|
+
padding: 0;
|
|
199
|
+
}
|
|
163
200
|
}
|
|
164
201
|
|
|
165
202
|
&__price {
|
|
@@ -177,7 +214,7 @@ const handleToggle = () => {
|
|
|
177
214
|
&__fromPrice {
|
|
178
215
|
display: flex;
|
|
179
216
|
align-items: center;
|
|
180
|
-
gap: var(--cp-spacing-
|
|
217
|
+
gap: var(--cp-spacing-sm);
|
|
181
218
|
opacity: 1;
|
|
182
219
|
transform: translate3d(0, 0, 0);
|
|
183
220
|
transition:
|
|
@@ -206,46 +243,6 @@ const handleToggle = () => {
|
|
|
206
243
|
line-height: var(--cp-text-lg-line-height);
|
|
207
244
|
}
|
|
208
245
|
|
|
209
|
-
&__toggle {
|
|
210
|
-
display: flex;
|
|
211
|
-
flex: none;
|
|
212
|
-
align-items: center;
|
|
213
|
-
justify-content: center;
|
|
214
|
-
padding: var(--cp-spacing-xs);
|
|
215
|
-
border: 0;
|
|
216
|
-
border-radius: 50%;
|
|
217
|
-
appearance: none;
|
|
218
|
-
background: transparent;
|
|
219
|
-
color: inherit;
|
|
220
|
-
cursor: pointer;
|
|
221
|
-
transition: background-color 200ms ease;
|
|
222
|
-
|
|
223
|
-
@media (hover: hover) {
|
|
224
|
-
&:hover {
|
|
225
|
-
background: var(--cp-background-secondary-hover);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
&:focus-visible {
|
|
230
|
-
border-radius: 50%;
|
|
231
|
-
background: var(--cp-background-secondary-hover);
|
|
232
|
-
|
|
233
|
-
@extend %u-focus-outline;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
&__lead {
|
|
238
|
-
@extend %u-focus-outline;
|
|
239
|
-
|
|
240
|
-
display: flex;
|
|
241
|
-
width: 100%;
|
|
242
|
-
min-width: 0;
|
|
243
|
-
flex: auto;
|
|
244
|
-
align-items: center;
|
|
245
|
-
gap: var(--cp-spacing-xl);
|
|
246
|
-
text-align: left;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
246
|
&__visual {
|
|
250
247
|
display: flex;
|
|
251
248
|
width: fn.px-to-rem(96);
|
|
@@ -273,6 +270,7 @@ const handleToggle = () => {
|
|
|
273
270
|
&__texts {
|
|
274
271
|
display: flex;
|
|
275
272
|
min-width: 0;
|
|
273
|
+
flex: auto;
|
|
276
274
|
flex-direction: column;
|
|
277
275
|
}
|
|
278
276
|
|
|
@@ -297,6 +295,10 @@ const handleToggle = () => {
|
|
|
297
295
|
&--isRotated {
|
|
298
296
|
rotate: 180deg;
|
|
299
297
|
}
|
|
298
|
+
|
|
299
|
+
@container (width < 30rem) {
|
|
300
|
+
display: none;
|
|
301
|
+
}
|
|
300
302
|
}
|
|
301
303
|
|
|
302
304
|
&__body {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
role="button"
|
|
11
11
|
tabindex="0"
|
|
12
12
|
:type="type"
|
|
13
|
+
@click="handleClick"
|
|
13
14
|
>
|
|
14
15
|
<span class="cpButton__body">
|
|
15
16
|
<span v-if="isLoading" class="cpButton__loader">
|
|
@@ -57,6 +58,10 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
57
58
|
size: 'md',
|
|
58
59
|
})
|
|
59
60
|
|
|
61
|
+
const emit = defineEmits<{
|
|
62
|
+
click: [event: MouseEvent]
|
|
63
|
+
}>()
|
|
64
|
+
|
|
60
65
|
const slots: Slots = useSlots()
|
|
61
66
|
|
|
62
67
|
const capitalizedAppearance = computed(() => capitalizeFirstLetter(props.appearance))
|
|
@@ -73,6 +78,11 @@ const isButtonDisabled = computed(() => props.disabled || props.isLoading)
|
|
|
73
78
|
|
|
74
79
|
const hrefValue = computed(() => (props.tag === 'a' ? props.href : undefined))
|
|
75
80
|
|
|
81
|
+
const handleClick = (event: MouseEvent): void => {
|
|
82
|
+
if (isButtonDisabled.value) return
|
|
83
|
+
emit('click', event)
|
|
84
|
+
}
|
|
85
|
+
|
|
76
86
|
const dynamicClasses = computed(() => {
|
|
77
87
|
return [
|
|
78
88
|
`cpButton--is${capitalizedAppearance.value}`,
|
|
@@ -221,6 +221,56 @@ export const Switch: Story = {
|
|
|
221
221
|
}),
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Same expandable and switch cards at a 358px container width: the
|
|
226
|
+
* container query on the root stacks the from-price under the texts
|
|
227
|
+
* instead of beside them.
|
|
228
|
+
*/
|
|
229
|
+
export const Mobile: Story = {
|
|
230
|
+
args: {
|
|
231
|
+
...Default.args,
|
|
232
|
+
},
|
|
233
|
+
parameters: { controls: { disable: true } },
|
|
234
|
+
render: () => ({
|
|
235
|
+
components: { CpAncillaryCategory },
|
|
236
|
+
setup() {
|
|
237
|
+
const switchChecked = ref(false)
|
|
238
|
+
return { galleryListStyle, galleryRowStyle, docLabelStyle, switchChecked }
|
|
239
|
+
},
|
|
240
|
+
template: `
|
|
241
|
+
<div :style="galleryListStyle">
|
|
242
|
+
<div :style="galleryRowStyle">
|
|
243
|
+
<span :style="docLabelStyle">Expandable</span>
|
|
244
|
+
<div style="width: 358px;">
|
|
245
|
+
<CpAncillaryCategory
|
|
246
|
+
title="Sport Equipments"
|
|
247
|
+
description="Travel with special or oversized items you need to bring along."
|
|
248
|
+
type="sportEquipments"
|
|
249
|
+
is-expandable
|
|
250
|
+
is-default-closed
|
|
251
|
+
:from-price="5990"
|
|
252
|
+
currency="EUR"
|
|
253
|
+
/>
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
<div :style="galleryRowStyle">
|
|
257
|
+
<span :style="docLabelStyle">Switch</span>
|
|
258
|
+
<div style="width: 358px;">
|
|
259
|
+
<CpAncillaryCategory
|
|
260
|
+
v-model:checked="switchChecked"
|
|
261
|
+
title="Carbon offset"
|
|
262
|
+
description="Compensate the CO2 emissions of your flight"
|
|
263
|
+
type="carbonOffset"
|
|
264
|
+
:from-price="490"
|
|
265
|
+
currency="EUR"
|
|
266
|
+
/>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
`,
|
|
271
|
+
}),
|
|
272
|
+
}
|
|
273
|
+
|
|
224
274
|
/* -------------------------------------------------------------------------- */
|
|
225
275
|
/* Gallery */
|
|
226
276
|
/* -------------------------------------------------------------------------- */
|