@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.
@@ -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(46);
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(8);
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(24);
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
 
@@ -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
- // Date pickers
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="xs" />
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="xs" />
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="xs" />
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;">
package/tsconfig.json CHANGED
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "isolatedModules": true,
4
+ "moduleResolution": "bundler",
5
+ "module": "esnext",
4
6
  "strict": true,
5
7
  "jsx": "preserve",
6
8
  "jsxImportSource": "vue",