@citizenplane/pimp 9.1.11 → 9.2.0

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.
@@ -151,32 +151,33 @@ const isSelectedValue = (value: string): boolean => {
151
151
  <style lang="scss">
152
152
  .cpSelectMenu {
153
153
  position: relative;
154
- font-size: fn.px-to-em(16);
154
+ font-size: fn.px-to-em(14);
155
155
 
156
156
  &__button {
157
157
  box-shadow: inset 0 fn.px-to-em(1) fn.px-to-em(2) rgba(0, 0, 0, 0.12);
158
- border: fn.px-to-rem(1) solid colors.$neutral-dark-4;
158
+ border: none;
159
+ outline: fn.px-to-rem(1) solid colors.$neutral-dark-4;
159
160
  border-radius: fn.px-to-em(10);
160
161
  background: colors.$neutral-light;
161
- padding: fn.px-to-em(12);
162
+ padding: fn.px-to-rem(8);
162
163
  width: 100%;
163
- height: sizing.$component-size-default;
164
164
  display: flex;
165
165
  align-items: center;
166
166
  justify-content: space-between;
167
167
  font-size: inherit;
168
+ line-height: fn.px-to-rem(24);
168
169
  font-weight: normal;
169
170
  text-transform: capitalize;
170
171
 
171
172
  &:hover,
172
173
  &:active,
173
174
  &:focus {
174
- border-color: colors.$secondary-color;
175
+ outline: fn.px-to-rem(1) solid colors.$secondary-color;
175
176
  }
176
177
 
177
178
  &:focus {
178
- outline: none !important;
179
- box-shadow: 0 0 0 fn.px-to-em(3) color.scale(colors.$secondary-color, $lightness: 80%);
179
+ outline: fn.px-to-rem(2) solid colors.$secondary-color;
180
+ box-shadow: 0 0 0 fn.px-to-em(2) color.scale(colors.$secondary-color, $lightness: 80%);
180
181
  }
181
182
  }
182
183
 
@@ -57,23 +57,22 @@
57
57
  <td v-show="areRowOptionsEnabled(rowData)" class="cpTable__cell cpTable__cell--isOptions">
58
58
  <div class="cpTable__actions">
59
59
  <slot name="row-quick-actions" :row="rowData">
60
- <template v-if="hasQuickOptions">
61
- <button
62
- v-for="option in quickOptions"
63
- :key="option.id"
64
- v-tooltip="getQuickOptionTooltip(option)"
65
- type="button"
66
- class="cpTable__action"
67
- :class="getQuickOptionClasses(option)"
68
- :disabled="option.isDisabled"
69
- @click.stop="($event) => option.action(rowData, $event)"
70
- >
71
- <cp-icon :type="option.icon" size="16" />
72
- </button>
73
- </template>
74
60
  <button
61
+ v-for="option in quickOptions"
62
+ :key="option.id"
63
+ v-tooltip="getQuickOptionTooltip(option)"
75
64
  type="button"
76
- class="cpTable__defaultAction"
65
+ class="cpTable__action"
66
+ :class="getQuickOptionClasses(option)"
67
+ :disabled="option.isDisabled"
68
+ @click.stop="($event) => option.action(getRowPayload(rowIndex), $event)"
69
+ >
70
+ <cp-icon :type="option.icon" size="16" />
71
+ </button>
72
+
73
+ <button
74
+ type="button"
75
+ class="cpTable__action cpTable__action--isDefault"
77
76
  @click.stop="handleContextMenu({ rowData, rowIndex }, $event)"
78
77
  >
79
78
  <cp-icon type="more-vertical" size="16" />
@@ -205,30 +204,17 @@ const pageNumber = ref(0)
205
204
  const cpTableContainer = ref<HTMLElement | null>(null)
206
205
  const contextualMenu = ref<InstanceType<typeof CpContextualMenu>>()
207
206
 
208
- const hasQuickOptions = computed(() => !!quickOptions.value.length)
209
207
  const hasRowOptions = computed(() => props.enableRowOptions && props.rowOptions.length)
210
208
  const hasMoreQuickActionsThanLimit = computed(() => props.rowOptions.length >= props.quickOptionsLimit)
211
209
 
212
- const defaultRowOption = computed<RowOptions>(() => {
213
- return {
214
- id: 'more',
215
- label: 'More',
216
- icon: 'more-vertical',
217
- action: (rowData: Record<string, unknown>, $event: MouseEvent) => {
218
- handleContextMenu({ rowData, rowIndex: null }, $event)
219
- },
220
- }
221
- })
222
-
223
210
  const quickOptions = computed(() => {
224
211
  if (!props.enableRowOptions || !props.rowOptions.length || props.quickOptionsLimit === 0) return []
225
212
 
226
213
  if (hasMoreQuickActionsThanLimit.value) {
227
- const slicedOptions = props.rowOptions.slice(0, props.quickOptionsLimit)
228
- return [...slicedOptions, defaultRowOption.value]
214
+ return props.rowOptions.slice(0, props.quickOptionsLimit)
229
215
  }
230
216
 
231
- return [...props.rowOptions, defaultRowOption.value]
217
+ return props.rowOptions
232
218
  })
233
219
 
234
220
  const currentRowData = ref<Record<string, unknown>>({})
@@ -375,12 +361,12 @@ const paginationResultsDetails = computed(() => {
375
361
  })
376
362
 
377
363
  const handleContextMenu = (
378
- { rowData, rowIndex }: { rowData: Record<string, unknown>; rowIndex: number | null },
364
+ { rowData, rowIndex }: { rowData: Record<string, unknown>; rowIndex: number },
379
365
  event: MouseEvent,
380
366
  ) => {
381
367
  if (!hasRowOptions.value || isFullWidthRow(rowData)) return
382
368
 
383
- currentRowData.value = rowIndex !== null ? getRowPayload(rowIndex) : rowData
369
+ currentRowData.value = getRowPayload(rowIndex)
384
370
 
385
371
  showContextualMenu(event)
386
372
  }
@@ -697,7 +683,7 @@ defineExpose({ hideContextualMenu, resetPagination, currentRowData })
697
683
  color: initial;
698
684
 
699
685
  // Add border-right only if the action is not the last one and the next one is not the default action
700
- &:not(:last-child):not(:has(+ .cpTable__defaultAction)) {
686
+ &:not(:last-child) {
701
687
  border-right: 1px solid colors.$border-color;
702
688
  }
703
689
 
@@ -717,12 +703,9 @@ defineExpose({ hideContextualMenu, resetPagination, currentRowData })
717
703
  }
718
704
  }
719
705
 
720
- &--isOptions .cpTable__defaultAction {
706
+ &--isOptions .cpTable__action--isDefault {
721
707
  display: inline-flex;
722
- padding: sp.$space-sm;
723
- border: fn.px-to-rem(1) solid colors.$border-color;
724
- border-radius: fn.px-to-rem(8);
725
- background-color: colors.$neutral-light;
708
+ align-items: center;
726
709
  color: colors.$neutral-dark-1;
727
710
 
728
711
  &:hover {
@@ -735,6 +718,25 @@ defineExpose({ hideContextualMenu, resetPagination, currentRowData })
735
718
  box-shadow: 0 0 0 fn.px-to-em(3) color.scale(colors.$secondary-color, $lightness: 80%);
736
719
  }
737
720
  }
721
+
722
+ @mixin cp-table-only-default-action-visible-style {
723
+ padding: sp.$space-sm;
724
+ border: fn.px-to-rem(1) solid colors.$border-color;
725
+ border-radius: fn.px-to-rem(8);
726
+ background-color: colors.$neutral-light;
727
+ }
728
+
729
+ // Solo default action mode
730
+ &--isOptions .cpTable__action:only-child.cpTable__action--isDefault {
731
+ @include cp-table-only-default-action-visible-style;
732
+ }
733
+
734
+ // Touch device mode : only default action visible
735
+ @media (hover: none) and (pointer: coarse) {
736
+ &--isOptions .cpTable__action--isDefault {
737
+ @include cp-table-only-default-action-visible-style;
738
+ }
739
+ }
738
740
  }
739
741
 
740
742
  // On desktop devices, display options only on row focus or hover
@@ -746,7 +748,7 @@ defineExpose({ hideContextualMenu, resetPagination, currentRowData })
746
748
  }
747
749
 
748
750
  // Actions wrapper on desktop : displayed only if there are quick actions inside
749
- &__cell--isOptions:has(.cpTable__action) .cpTable__actions {
751
+ &__cell--isOptions .cpTable__actions:has(> :nth-child(2)) {
750
752
  position: absolute;
751
753
  top: 50%;
752
754
  transform: translateY(-50%);
@@ -765,11 +767,6 @@ defineExpose({ hideContextualMenu, resetPagination, currentRowData })
765
767
  display: flex;
766
768
  }
767
769
 
768
- // Desktop : hide default action if there are quick actions inside
769
- &__cell--isOptions:has(.cpTable__action) .cpTable__defaultAction {
770
- display: none;
771
- }
772
-
773
770
  &__row:focus &__cell--isOptions,
774
771
  &__row:focus-within &__cell--isOptions,
775
772
  &__row:hover &__cell--isOptions {
@@ -217,7 +217,7 @@ export const WithCustomRowOptions: Story = {
217
217
  label: 'Disable',
218
218
  icon: 'history',
219
219
  isDisabled: true,
220
- action: () => console.log('History'),
220
+ action: (payload) => console.log('History', payload),
221
221
  },
222
222
  {
223
223
  id: 'delete',
@@ -247,3 +247,56 @@ export const WithCustomRowOptions: Story = {
247
247
  `,
248
248
  }),
249
249
  }
250
+
251
+ export const WithOnlyDefaultAction: Story = {
252
+ args: {
253
+ ...Default.args,
254
+ enableRowOptions: true,
255
+ quickOptionsLimit: 0,
256
+ },
257
+ render: (args) => ({
258
+ components: { CpTable },
259
+ setup() {
260
+ const isEditLoading = ref(false)
261
+
262
+ const rowOptions = computed(() => [
263
+ {
264
+ id: 'see',
265
+ label: 'See',
266
+ icon: 'eye',
267
+ action: () => console.log('See'),
268
+ },
269
+ {
270
+ id: 'edit',
271
+ label: 'Edit',
272
+ icon: 'edit-2',
273
+ isAsync: true,
274
+ isLoading: isEditLoading.value,
275
+ action: async (payload) => {
276
+ isEditLoading.value = true
277
+ console.log('Edit', payload)
278
+ await new Promise((resolve) => setTimeout(resolve, 2000))
279
+ isEditLoading.value = false
280
+ },
281
+ },
282
+ ])
283
+
284
+ return { args, isEditLoading, rowOptions }
285
+ },
286
+ template: `
287
+ <CpTable v-bind="args" :row-options="rowOptions">
288
+ <template #status="{ cell }">
289
+ <span :style="{
290
+ padding: '4px 8px',
291
+ borderRadius: '4px',
292
+ fontSize: '12px',
293
+ backgroundColor: cell === 'Active' ? '#10B981' : '#EF4444',
294
+ color: 'white'
295
+ }">
296
+ {{ cell }}
297
+ </span>
298
+ </template>
299
+ </CpTable>
300
+ `,
301
+ }),
302
+ }