@citizenplane/pimp 8.32.2 → 8.32.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/dist/pimp.es.js +6790 -5668
- package/dist/pimp.umd.js +184 -36
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/README.md +1 -1
- package/src/assets/styles/helpers/_keyframes.scss +13 -0
- package/src/components/CpBadge.vue +0 -5
- package/src/components/CpContextualMenu.vue +49 -0
- package/src/components/CpMenuItem.vue +155 -0
- package/src/components/CpMultiselect.vue +19 -15
- package/src/components/index.ts +4 -17
- package/src/stories/CpContextualMenu.stories.ts +68 -0
- package/src/stories/CpMultiselect.stories.ts +3 -3
- package/tsconfig.json +2 -0
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
</template>
|
|
31
31
|
<template #chip="{ value, removeCallback }">
|
|
32
32
|
<slot name="selected-option" :option="value" :remove="removeCallback">
|
|
33
|
-
<cp-badge is-clearable size="sm" @on-clear="removeCallback
|
|
33
|
+
<cp-badge is-clearable size="sm" @on-clear="removeCallback">
|
|
34
34
|
<template #leading-icon>
|
|
35
35
|
<slot name="selected-option-leading-icon" :option="value" />
|
|
36
36
|
</template>
|
|
@@ -73,7 +73,6 @@ import { isEmpty } from '@/helpers/object'
|
|
|
73
73
|
|
|
74
74
|
interface Emits {
|
|
75
75
|
(e: 'search', query: string): void
|
|
76
|
-
(e: 'select', option: Record<string, unknown>): void
|
|
77
76
|
(e: 'clear'): void
|
|
78
77
|
(e: 'update:modelValue', value: Record<string, unknown> | Record<string, unknown>[] | null): void
|
|
79
78
|
}
|
|
@@ -143,12 +142,11 @@ const passThroughConfig = {
|
|
|
143
142
|
|
|
144
143
|
const multiselect = ref<InstanceType<typeof AutoComplete> | null>(null)
|
|
145
144
|
|
|
145
|
+
// @ts-expect-error 'overlayVisible' does not exist on type instance of AutoComplete
|
|
146
146
|
const isDropdownOpen = computed(() => multiselect.value?.overlayVisible)
|
|
147
147
|
|
|
148
148
|
const chevronDynamicClass = computed(() => {
|
|
149
|
-
return {
|
|
150
|
-
'cpMultiselect__dropdownIcon--isRotated': isDropdownOpen.value,
|
|
151
|
-
}
|
|
149
|
+
return { 'cpMultiselect__dropdownIcon--isRotated': isDropdownOpen.value }
|
|
152
150
|
})
|
|
153
151
|
|
|
154
152
|
const displayPrefix = computed(() => {
|
|
@@ -166,8 +164,10 @@ const handleClear = () => (selectModel.value = null)
|
|
|
166
164
|
|
|
167
165
|
const toggleDropdown = () => {
|
|
168
166
|
if (isDropdownOpen.value) {
|
|
167
|
+
// @ts-expect-error 'hide' does not exist on type instance of AutoComplete
|
|
169
168
|
multiselect.value?.hide()
|
|
170
169
|
} else {
|
|
170
|
+
// @ts-expect-error 'show' does not exist on type instance of AutoComplete
|
|
171
171
|
multiselect.value?.show()
|
|
172
172
|
}
|
|
173
173
|
}
|
|
@@ -181,16 +181,22 @@ const handleUpdateModelValue = (value: Record<string, unknown> | null) => {
|
|
|
181
181
|
|
|
182
182
|
const overrideAlignOverlay = () => {
|
|
183
183
|
if (multiselect.value) {
|
|
184
|
+
// @ts-expect-error 'alignOverlay' does not exist on type instance of AutoComplete
|
|
184
185
|
multiselect.value.alignOverlay = alignOverlay
|
|
185
186
|
}
|
|
186
187
|
}
|
|
187
188
|
|
|
188
189
|
const alignOverlay = () => {
|
|
190
|
+
// @ts-expect-error 'el' does not exist on type instance of AutoComplete
|
|
189
191
|
const target = multiselect.value?.$el
|
|
192
|
+
|
|
193
|
+
// @ts-expect-error 'overlay' does not exist on type instance of AutoComplete
|
|
190
194
|
if (!multiselect.value?.overlay || !target) return
|
|
191
195
|
|
|
196
|
+
// @ts-expect-error 'overlay' does not exist on type instance of AutoComplete
|
|
192
197
|
multiselect.value.overlay.style.width = `${getOuterWidth(target)}px`
|
|
193
198
|
|
|
199
|
+
// @ts-expect-error 'overlay' does not exist on type instance of AutoComplete
|
|
194
200
|
absolutePosition(multiselect.value.overlay, target)
|
|
195
201
|
}
|
|
196
202
|
|
|
@@ -208,6 +214,9 @@ onMounted(() => overrideAlignOverlay())
|
|
|
208
214
|
}
|
|
209
215
|
|
|
210
216
|
&__prefix {
|
|
217
|
+
display: flex;
|
|
218
|
+
align-items: center;
|
|
219
|
+
flex-shrink: 0;
|
|
211
220
|
order: -1;
|
|
212
221
|
|
|
213
222
|
&:empty {
|
|
@@ -217,10 +226,10 @@ onMounted(() => overrideAlignOverlay())
|
|
|
217
226
|
|
|
218
227
|
&__select {
|
|
219
228
|
display: flex;
|
|
220
|
-
min-height: fn.px-to-rem(
|
|
229
|
+
min-height: fn.px-to-rem(40);
|
|
221
230
|
align-items: center;
|
|
222
231
|
justify-content: space-between;
|
|
223
|
-
padding: fn.px-to-rem(
|
|
232
|
+
padding: fn.px-to-rem(10.5);
|
|
224
233
|
border: 1px solid colors.$border-color;
|
|
225
234
|
border-radius: fn.px-to-rem(10);
|
|
226
235
|
gap: sp.$space;
|
|
@@ -248,6 +257,7 @@ onMounted(() => overrideAlignOverlay())
|
|
|
248
257
|
flex: 1;
|
|
249
258
|
flex-wrap: wrap;
|
|
250
259
|
gap: sp.$space;
|
|
260
|
+
max-height: fn.px-to-rem(22);
|
|
251
261
|
}
|
|
252
262
|
|
|
253
263
|
&__toggle {
|
|
@@ -272,21 +282,15 @@ onMounted(() => overrideAlignOverlay())
|
|
|
272
282
|
padding: 0;
|
|
273
283
|
flex: 1;
|
|
274
284
|
font-size: fn.px-to-rem(14);
|
|
275
|
-
line-height: fn.px-to-rem(
|
|
285
|
+
line-height: fn.px-to-rem(22);
|
|
276
286
|
background-color: transparent;
|
|
287
|
+
width: 100%;
|
|
277
288
|
|
|
278
289
|
&:disabled {
|
|
279
290
|
cursor: not-allowed;
|
|
280
291
|
}
|
|
281
292
|
}
|
|
282
293
|
|
|
283
|
-
&__input {
|
|
284
|
-
padding: 0;
|
|
285
|
-
flex: 1;
|
|
286
|
-
font-size: fn.px-to-rem(14);
|
|
287
|
-
line-height: fn.px-to-rem(24);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
294
|
&__dropdownIcon {
|
|
291
295
|
@include mx.square-sizing(16);
|
|
292
296
|
|
package/src/components/index.ts
CHANGED
|
@@ -1,45 +1,33 @@
|
|
|
1
1
|
import { vTooltip } from 'floating-vue'
|
|
2
|
-
// PLUGINS
|
|
3
2
|
import { vMaska } from 'maska/vue'
|
|
4
3
|
import PrimeVue from 'primevue/config'
|
|
5
4
|
import { App } from 'vue'
|
|
6
5
|
import { BindOnceDirective } from 'vue-bind-once'
|
|
7
6
|
|
|
8
|
-
// DIRECTIVES
|
|
9
7
|
import ClickOutside from '../directives/ClickOutside'
|
|
10
8
|
import CpCoreDatepicker from '../libs/CoreDatepicker.vue'
|
|
11
9
|
import CpAirlineLogo from './CpAirlineLogo.vue'
|
|
12
|
-
// Feedback indicators
|
|
13
10
|
import CpAlert from './CpAlert.vue'
|
|
14
|
-
// COMPONENTS
|
|
15
|
-
// Atomic elements
|
|
16
11
|
import CpBadge from './CpBadge.vue'
|
|
17
|
-
// Buttons
|
|
18
12
|
import CpButton from './CpButton.vue'
|
|
19
13
|
import CpCalendar from './CpCalendar.vue'
|
|
20
|
-
// Toggles
|
|
21
14
|
import CpCheckbox from './CpCheckbox.vue'
|
|
22
|
-
|
|
15
|
+
import CpContextualMenu from './CpContextualMenu.vue'
|
|
23
16
|
import CpDate from './CpDate.vue'
|
|
24
17
|
import CpDatepicker from './CpDatepicker.vue'
|
|
25
18
|
import CpDialog from './CpDialog.vue'
|
|
26
19
|
import CpDialogWrapper from './CpDialogWrapper.vue'
|
|
27
|
-
// Typography
|
|
28
20
|
import CpHeading from './CpHeading.vue'
|
|
29
|
-
// Visual
|
|
30
21
|
import CpIcon from './CpIcon.vue'
|
|
31
|
-
// Inputs
|
|
32
22
|
import CpInput from './CpInput.vue'
|
|
33
|
-
// Dropdown menus
|
|
34
23
|
import CpLoader from './CpLoader.vue'
|
|
24
|
+
import CpMenuItem from './CpMenuItem.vue'
|
|
35
25
|
import CpMultiselect from './CpMultiselect.vue'
|
|
36
26
|
import CpPartnerBadge from './CpPartnerBadge.vue'
|
|
37
27
|
import CpRadio from './CpRadio.vue'
|
|
38
|
-
// Selects
|
|
39
28
|
import CpSelect from './CpSelect.vue'
|
|
40
29
|
import CpSelectMenu from './CpSelectMenu.vue'
|
|
41
30
|
import CpSwitch from './CpSwitch.vue'
|
|
42
|
-
// List and Tables
|
|
43
31
|
import CpTable from './CpTable.vue'
|
|
44
32
|
import CpTextarea from './CpTextarea.vue'
|
|
45
33
|
import CpToaster from './CpToaster.vue'
|
|
@@ -52,11 +40,8 @@ import IconGroupBy from './icons/IconGroupBy.vue'
|
|
|
52
40
|
import IconOta from './icons/IconOta.vue'
|
|
53
41
|
import IconSupplier from './icons/IconSupplier.vue'
|
|
54
42
|
import IconThirdParty from './icons/IconThirdParty.vue'
|
|
55
|
-
// Icons
|
|
56
43
|
import IconTooltip from './icons/IconTooltip.vue'
|
|
57
|
-
// Helpers and Utilities
|
|
58
44
|
import TransitionExpand from './TransitionExpand.vue'
|
|
59
|
-
// Methods
|
|
60
45
|
import createToaster from '@/plugins/toaster'
|
|
61
46
|
|
|
62
47
|
const Components = {
|
|
@@ -67,6 +52,8 @@ const Components = {
|
|
|
67
52
|
CpDialogWrapper,
|
|
68
53
|
CpDialog,
|
|
69
54
|
CpDate,
|
|
55
|
+
CpContextualMenu,
|
|
56
|
+
CpMenuItem,
|
|
70
57
|
CpCoreDatepicker,
|
|
71
58
|
CpDatepicker,
|
|
72
59
|
CpCalendar,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { computed, ref } from 'vue'
|
|
2
|
+
|
|
3
|
+
import type { Meta, StoryObj } from '@storybook/vue3'
|
|
4
|
+
|
|
5
|
+
import CpContextualMenu from '@/components/CpContextualMenu.vue'
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: 'CpContextualMenu',
|
|
9
|
+
component: CpContextualMenu,
|
|
10
|
+
parameters: {
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
'A component that displays airline logos using IATA codes. Fetches logos from Kiwi.com CDN and displays them with customizable sizes.',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
argTypes: {
|
|
19
|
+
items: {
|
|
20
|
+
control: 'object',
|
|
21
|
+
description: 'The items to display in the menu',
|
|
22
|
+
table: {
|
|
23
|
+
type: { summary: 'object' },
|
|
24
|
+
defaultValue: { summary: '[]' },
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
tags: ['autodocs'],
|
|
29
|
+
} satisfies Meta<typeof CpContextualMenu>
|
|
30
|
+
|
|
31
|
+
export default meta
|
|
32
|
+
type Story = StoryObj<typeof meta>
|
|
33
|
+
|
|
34
|
+
export const Default: Story = {
|
|
35
|
+
render: (args) => ({
|
|
36
|
+
components: { CpContextualMenu },
|
|
37
|
+
setup() {
|
|
38
|
+
const menu = ref<InstanceType<typeof CpContextualMenu>>()
|
|
39
|
+
const showMenu = (event: MouseEvent) => menu.value?.show(event)
|
|
40
|
+
|
|
41
|
+
const isLoading = ref(false)
|
|
42
|
+
|
|
43
|
+
const items = computed(() => [
|
|
44
|
+
{
|
|
45
|
+
label: 'Download',
|
|
46
|
+
icon: 'download',
|
|
47
|
+
isLoading: isLoading.value,
|
|
48
|
+
command: () => {
|
|
49
|
+
isLoading.value = true
|
|
50
|
+
setTimeout(() => (isLoading.value = false), 2000)
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
label: 'Delete',
|
|
55
|
+
icon: 'trash-2',
|
|
56
|
+
isCritical: true,
|
|
57
|
+
command: () => alert('Delete clicked'),
|
|
58
|
+
},
|
|
59
|
+
])
|
|
60
|
+
|
|
61
|
+
return { args, menu, showMenu, isLoading, items }
|
|
62
|
+
},
|
|
63
|
+
template: `
|
|
64
|
+
<p @contextmenu="showMenu">Right click on me to open the menu</p>
|
|
65
|
+
<CpContextualMenu :items="items" ref="menu" />
|
|
66
|
+
`,
|
|
67
|
+
}),
|
|
68
|
+
}
|
|
@@ -112,7 +112,7 @@ export const Single: Story = {
|
|
|
112
112
|
<div style="padding: 20px;">
|
|
113
113
|
<CpMultiselect v-model="selectedSupplier" v-bind="args" :options="dynamicOptions" :is-loading="isLoading" @search="handleSearch">
|
|
114
114
|
<template #prefix>
|
|
115
|
-
<cp-partner-badge type="supplier" size="
|
|
115
|
+
<cp-partner-badge type="supplier" size="sm" />
|
|
116
116
|
</template>
|
|
117
117
|
<template #option="{ option }">
|
|
118
118
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
@@ -191,7 +191,7 @@ export const Multiple: Story = {
|
|
|
191
191
|
<div style="padding: 20px;">
|
|
192
192
|
<CpMultiselect v-model="selectedAirlines" v-bind="args" :options="dynamicOptions" :is-loading="isLoading" @search="handleSearch">
|
|
193
193
|
<template #prefix>
|
|
194
|
-
<cp-partner-badge type="airline" size="
|
|
194
|
+
<cp-partner-badge type="airline" size="sm" />
|
|
195
195
|
</template>
|
|
196
196
|
<template #selected-option-leading-icon="{ option }">
|
|
197
197
|
<cp-airline-logo :iata-code="option.iata_code" size="14" />
|
|
@@ -225,7 +225,7 @@ export const Invalid: Story = {
|
|
|
225
225
|
<div style="padding: 20px;">
|
|
226
226
|
<CpMultiselect v-model="selectedSupplier" v-bind="args">
|
|
227
227
|
<template #prefix>
|
|
228
|
-
<cp-partner-badge type="supplier" size="
|
|
228
|
+
<cp-partner-badge type="supplier" size="sm" />
|
|
229
229
|
</template>
|
|
230
230
|
<template #option="{ option }">
|
|
231
231
|
<div style="display: flex; align-items: center; gap: 8px;">
|