@citizenplane/pimp 9.1.0 → 9.1.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@citizenplane/pimp",
3
- "version": "9.1.0",
3
+ "version": "9.1.2",
4
4
  "scripts": {
5
5
  "dev": "storybook dev -p 8080",
6
6
  "build-storybook": "storybook build --output-dir ./docs",
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <context-menu ref="menu" :model="items" :pt="passThroughConfig">
3
3
  <template #item="{ item, props }">
4
- <cp-menu-item v-bind="{ ...item, ...props.action }" />
4
+ <cp-menu-item v-bind="{ ...item, ...props.action }" @on-async-command-complete="hide" />
5
5
  </template>
6
6
  </context-menu>
7
7
  </template>
@@ -5,7 +5,7 @@
5
5
  class="cpMenuItem__button"
6
6
  :class="dynamicClass"
7
7
  :disabled="disabled"
8
- @click.stop="handleItemClick"
8
+ @click="handleItemClick"
9
9
  >
10
10
  <transition name="fade" :duration="100" mode="out-in">
11
11
  <span v-if="isLoading" class="cpMenuItem__loaderWrapper">
@@ -28,6 +28,7 @@ import { computed } from 'vue'
28
28
  import type { MenuItem } from 'primevue/menuitem'
29
29
 
30
30
  interface Props {
31
+ isAsync?: boolean
31
32
  isCritical?: boolean
32
33
  isDisabled?: boolean
33
34
  isLoading?: boolean
@@ -44,9 +45,10 @@ const props = withDefaults(defineProps<Props & Omit<MenuItem, 'class' | 'disable
44
45
  isLoading: false,
45
46
  isDisabled: false,
46
47
  isCritical: false,
48
+ isAsync: false,
47
49
  })
48
50
 
49
- const emit = defineEmits(['onItemClick'])
51
+ const emit = defineEmits(['onItemClick', 'onAsyncCommandComplete'])
50
52
 
51
53
  const dynamicClass = computed(() => ({
52
54
  'cpMenuItem__button--reverseLabel': props.reverseLabel,
@@ -55,12 +57,18 @@ const dynamicClass = computed(() => ({
55
57
 
56
58
  const disabled = computed(() => props.isLoading || props.isDisabled)
57
59
 
58
- const handleItemClick = (event: Event) => {
59
- if (props.command) {
60
- props.command({
61
- originalEvent: event,
62
- item: props,
63
- })
60
+ const handleItemClick = async (event: Event) => {
61
+ if (!props.command) return
62
+
63
+ if (props.isAsync) {
64
+ // Stop the event from bubbling up to prevent menu auto close
65
+ event.stopPropagation()
66
+
67
+ await props.command({ originalEvent: event, item: props })
68
+
69
+ emit('onAsyncCommandComplete')
70
+ } else {
71
+ props.command({ originalEvent: event, item: props })
64
72
  }
65
73
 
66
74
  emit('onItemClick')
@@ -108,7 +108,12 @@
108
108
  </div>
109
109
  </div>
110
110
  <div class="cpTable__overlay" />
111
- <cp-contextual-menu v-if="hasRowOptions" ref="contextualMenu" :items="contextualMenuItems" />
111
+ <cp-contextual-menu
112
+ v-if="hasRowOptions"
113
+ ref="contextualMenu"
114
+ :items="contextualMenuItems"
115
+ @hide="resetCurrentRowData"
116
+ />
112
117
  </div>
113
118
  </template>
114
119
 
@@ -152,6 +157,7 @@ interface RowOptions {
152
157
  action: (rowData: Record<string, unknown>, $event: MouseEvent) => void
153
158
  icon: string
154
159
  id: string
160
+ isAsync?: boolean
155
161
  isCritical?: boolean
156
162
  isDisabled?: boolean
157
163
  isLoading?: boolean
@@ -208,7 +214,9 @@ const defaultRowOption = computed<RowOptions>(() => {
208
214
  id: 'more',
209
215
  label: 'More',
210
216
  icon: 'more-vertical',
211
- action: (rowData: Record<string, unknown>, $event: MouseEvent) => showContextualMenu($event),
217
+ action: (rowData: Record<string, unknown>, $event: MouseEvent) => {
218
+ handleContextMenu({ rowData, rowIndex: null }, $event)
219
+ },
212
220
  }
213
221
  })
214
222
 
@@ -367,17 +375,19 @@ const paginationResultsDetails = computed(() => {
367
375
  })
368
376
 
369
377
  const handleContextMenu = (
370
- { rowData, rowIndex }: { rowData: Record<string, unknown>; rowIndex: number },
378
+ { rowData, rowIndex }: { rowData: Record<string, unknown>; rowIndex: number | null },
371
379
  event: MouseEvent,
372
380
  ) => {
373
381
  if (!hasRowOptions.value || isFullWidthRow(rowData)) return
374
- currentRowData.value = getRowPayload(rowIndex)
382
+
383
+ currentRowData.value = rowIndex !== null ? getRowPayload(rowIndex) : rowData
375
384
 
376
385
  showContextualMenu(event)
377
386
  }
378
387
 
379
388
  const showContextualMenu = (event: MouseEvent) => contextualMenu.value?.show(event)
380
389
  const hideContextualMenu = () => contextualMenu.value?.hide()
390
+ const resetCurrentRowData = () => (currentRowData.value = {})
381
391
 
382
392
  const getQuickOptionTooltip = (option: RowOptions) => (!option.isDisabled ? option.label : '')
383
393
 
@@ -45,11 +45,16 @@ export const Default: Story = {
45
45
  label: 'Download',
46
46
  icon: 'download',
47
47
  isLoading: isLoading.value,
48
- command: () => {
48
+ isAsync: true,
49
+ command: async () => {
49
50
  isLoading.value = true
50
- setTimeout(() => (isLoading.value = false), 2000)
51
+ await new Promise((resolve) => setTimeout(resolve, 2000))
52
+ isLoading.value = false
51
53
  },
52
54
  },
55
+ {
56
+ separator: true,
57
+ },
53
58
  {
54
59
  label: 'Delete',
55
60
  icon: 'trash-2',
@@ -1,3 +1,5 @@
1
+ import { ref, computed } from 'vue'
2
+
1
3
  import type { Meta, StoryObj } from '@storybook/vue3'
2
4
 
3
5
  import CpTable from '@/components/CpTable.vue'
@@ -184,42 +186,52 @@ export const WithCustomRowOptions: Story = {
184
186
  args: {
185
187
  ...Default.args,
186
188
  enableRowOptions: true,
187
- rowOptions: [
188
- {
189
- id: 'see',
190
- label: 'See',
191
- icon: 'eye',
192
- action: () => console.log('See'),
193
- },
194
- {
195
- id: 'edit',
196
- label: 'Edit',
197
- icon: 'edit-2',
198
- action: (payload) => console.log('Edit', payload),
199
- },
200
- {
201
- id: 'disable',
202
- label: 'Disable',
203
- icon: 'history',
204
- isDisabled: true,
205
- action: () => console.log('History'),
206
- },
207
- {
208
- id: 'delete',
209
- label: 'Delete',
210
- icon: 'trash',
211
- isCritical: true,
212
- action: () => console.log('Delete'),
213
- },
214
- ],
215
189
  },
216
190
  render: (args) => ({
217
191
  components: { CpTable },
218
192
  setup() {
219
- return { args }
193
+ const isEditLoading = ref(false)
194
+
195
+ const rowOptions = computed(() => [
196
+ {
197
+ id: 'see',
198
+ label: 'See',
199
+ icon: 'eye',
200
+ action: () => console.log('See'),
201
+ },
202
+ {
203
+ id: 'edit',
204
+ label: 'Edit',
205
+ icon: 'edit-2',
206
+ isAsync: true,
207
+ isLoading: isEditLoading.value,
208
+ action: async (payload) => {
209
+ isEditLoading.value = true
210
+ console.log('Edit', payload)
211
+ await new Promise((resolve) => setTimeout(resolve, 2000))
212
+ isEditLoading.value = false
213
+ },
214
+ },
215
+ {
216
+ id: 'disable',
217
+ label: 'Disable',
218
+ icon: 'history',
219
+ isDisabled: true,
220
+ action: () => console.log('History'),
221
+ },
222
+ {
223
+ id: 'delete',
224
+ label: 'Delete',
225
+ icon: 'trash',
226
+ isCritical: true,
227
+ action: () => console.log('Delete'),
228
+ },
229
+ ])
230
+
231
+ return { args, isEditLoading, rowOptions }
220
232
  },
221
233
  template: `
222
- <CpTable v-bind="args">
234
+ <CpTable v-bind="args" :row-options="rowOptions">
223
235
  <template #status="{ cell }">
224
236
  <span :style="{
225
237
  padding: '4px 8px',