@citizenplane/pimp 16.0.3 → 16.1.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.
Files changed (61) hide show
  1. package/dist/pimp.es.js +313 -285
  2. package/dist/pimp.umd.js +21 -21
  3. package/dist/style.css +1 -1
  4. package/package.json +2 -1
  5. package/src/components/CpHeading.vue +4 -5
  6. package/src/components/CpText.vue +141 -0
  7. package/src/components/index.ts +2 -0
  8. package/src/stories/BaseInputLabel.stories.ts +36 -9
  9. package/src/stories/Colors.mdx +9 -0
  10. package/src/stories/Colors.stories.ts +177 -0
  11. package/src/stories/CpAccordion.stories.ts +187 -158
  12. package/src/stories/CpAccordionGroup.stories.ts +50 -94
  13. package/src/stories/CpAirlineLogo.stories.ts +49 -28
  14. package/src/stories/CpAlert.stories.ts +195 -158
  15. package/src/stories/CpBadge.stories.ts +259 -193
  16. package/src/stories/CpButton.stories.ts +257 -426
  17. package/src/stories/CpCheckbox.stories.ts +101 -29
  18. package/src/stories/CpContextualMenu.stories.ts +9 -8
  19. package/src/stories/CpDate.stories.ts +52 -25
  20. package/src/stories/CpDatepicker.stories.ts +57 -88
  21. package/src/stories/CpDialog.stories.ts +22 -1
  22. package/src/stories/CpHeading.stories.ts +59 -20
  23. package/src/stories/CpIcon.stories.ts +98 -31
  24. package/src/stories/CpInput.stories.ts +142 -67
  25. package/src/stories/CpItemActions.stories.ts +22 -27
  26. package/src/stories/CpLoader.stories.ts +54 -6
  27. package/src/stories/CpMenuItem.stories.ts +52 -26
  28. package/src/stories/CpMultiselect.stories.ts +52 -71
  29. package/src/stories/CpPartnerBadge.stories.ts +53 -74
  30. package/src/stories/CpRadio.stories.ts +44 -48
  31. package/src/stories/CpRadioGroup.stories.ts +46 -39
  32. package/src/stories/CpSelect.stories.ts +98 -39
  33. package/src/stories/CpSelectMenu.stories.ts +49 -57
  34. package/src/stories/CpSelectableButton.stories.ts +170 -81
  35. package/src/stories/CpSwitch.stories.ts +135 -133
  36. package/src/stories/CpTable.stories.ts +54 -1
  37. package/src/stories/CpTableEmptyState.stories.ts +11 -7
  38. package/src/stories/CpTabs.stories.ts +22 -4
  39. package/src/stories/CpTelInput.stories.ts +25 -23
  40. package/src/stories/CpText.stories.ts +131 -0
  41. package/src/stories/CpTextarea.stories.ts +59 -23
  42. package/src/stories/CpToast.stories.ts +53 -103
  43. package/src/stories/CpTooltip.stories.ts +82 -77
  44. package/src/stories/CpTransitionCounter.stories.ts +4 -0
  45. package/src/stories/CpTransitionExpand.stories.ts +11 -6
  46. package/src/stories/CpTransitionListItems.stories.ts +5 -0
  47. package/src/stories/CpTransitionSize.stories.ts +8 -0
  48. package/src/stories/CpTransitionSlide.stories.ts +4 -0
  49. package/src/stories/CpTransitionTabContent.stories.ts +4 -0
  50. package/src/stories/Dimensions.mdx +9 -0
  51. package/src/stories/Dimensions.stories.ts +119 -0
  52. package/src/stories/Easings.mdx +9 -0
  53. package/src/stories/Easings.stories.ts +101 -0
  54. package/src/stories/FocusRings.mdx +9 -0
  55. package/src/stories/FocusRings.stories.ts +74 -0
  56. package/src/stories/Shadows.mdx +9 -0
  57. package/src/stories/Shadows.stories.ts +100 -0
  58. package/src/stories/Typography.mdx +9 -0
  59. package/src/stories/Typography.stories.ts +181 -0
  60. package/src/stories/documentationStyles.ts +2 -10
  61. package/src/stories/tokenUtils.ts +259 -0
@@ -6,7 +6,7 @@ import type { MenuItem } from 'primevue/menuitem'
6
6
  import CpItemActions from '@/components/CpItemActions.vue'
7
7
 
8
8
  const meta = {
9
- title: 'Menu/CpItemActions',
9
+ title: 'Molecules/CpItemActions',
10
10
  component: CpItemActions,
11
11
  argTypes: {
12
12
  actions: {
@@ -19,27 +19,19 @@ const meta = {
19
19
  export default meta
20
20
  type Story = StoryObj<typeof meta>
21
21
 
22
+ /**
23
+ * Contextual action menu attached to a list item. The `cp-item-actions-trigger`
24
+ * attribute on the parent element lets clicks through to the item while
25
+ * still opening the menu on the trigger button.
26
+ */
22
27
  export const Default: Story = {
23
28
  render: () => ({
24
29
  components: { CpItemActions },
25
30
  setup() {
26
- const actions: MenuItem[] = ref([
27
- {
28
- icon: 'edit',
29
- label: 'Action 1',
30
- command: () => alert('Action 1 clicked'),
31
- },
32
- {
33
- icon: 'download',
34
- label: 'Action 3',
35
- command: () => alert('Action 3 clicked'),
36
- },
37
- {
38
- icon: 'trash-2',
39
- label: 'Action 2',
40
- command: () => alert('Action 2 clicked'),
41
- isCritical: true,
42
- },
31
+ const actions = ref<MenuItem[]>([
32
+ { icon: 'edit', label: 'Action 1', command: () => alert('Action 1 clicked') },
33
+ { icon: 'download', label: 'Action 3', command: () => alert('Action 3 clicked') },
34
+ { icon: 'trash-2', label: 'Action 2', command: () => alert('Action 2 clicked'), isCritical: true },
43
35
  ])
44
36
 
45
37
  const listItems = [1, 2, 3, 4]
@@ -57,15 +49,18 @@ export const Default: Story = {
57
49
  },
58
50
  template: `
59
51
  <div style="padding: 20px; display: flex; flex-direction: column; gap: 16px; min-width: 400px;">
60
- <ul>
61
- <li v-for="(item, index) in listItems" :key="item" :style="listItemStyle" @click="parentClick" cp-item-actions-trigger>
62
- <p>Item {{ index + 1 }}</p>
63
- <CpItemActions
64
- size="xs"
65
- :actions="actions"
66
- />
67
- </li>
68
- </ul>
52
+ <ul>
53
+ <li
54
+ v-for="(item, index) in listItems"
55
+ :key="item"
56
+ :style="listItemStyle"
57
+ cp-item-actions-trigger
58
+ @click="parentClick"
59
+ >
60
+ <p>Item {{ index + 1 }}</p>
61
+ <CpItemActions size="xs" :actions="actions" />
62
+ </li>
63
+ </ul>
69
64
  </div>
70
65
  `,
71
66
  }),
@@ -2,18 +2,23 @@ import type { Meta, StoryObj } from '@storybook/vue3'
2
2
 
3
3
  import CpLoader from '@/components/CpLoader.vue'
4
4
 
5
+ import { docCellStyle, docLabelStyle, docRowWrapStyle } from '@/stories/documentationStyles'
6
+
7
+ const loaderSizes = ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'] as const
8
+ const loaderColors = ['neutral', 'accent', 'error', 'warning', 'success'] as const
9
+
5
10
  const meta = {
6
- title: 'Visual/CpLoader',
11
+ title: 'Atoms/CpLoader',
7
12
  component: CpLoader,
8
13
  argTypes: {
9
14
  size: {
10
15
  control: 'select',
11
- options: ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'],
16
+ options: loaderSizes,
12
17
  description: 'Size of the loader in pixels',
13
18
  },
14
19
  color: {
15
20
  control: 'select',
16
- options: ['neutral', 'accent', 'error', 'warning', 'success'],
21
+ options: loaderColors,
17
22
  description: 'The color variant of the loader',
18
23
  },
19
24
  duration: {
@@ -26,8 +31,51 @@ const meta = {
26
31
  export default meta
27
32
  type Story = StoryObj<typeof meta>
28
33
 
34
+ /**
35
+ * Default loader. Use the controls to experiment with each prop in isolation.
36
+ */
29
37
  export const Default: Story = {
30
- args: {
31
- color: 'neutral',
32
- },
38
+ args: { color: 'neutral' },
39
+ }
40
+
41
+ /**
42
+ * Every size rendered side by side.
43
+ */
44
+ export const Sizes: Story = {
45
+ parameters: { controls: { disable: true } },
46
+ render: () => ({
47
+ components: { CpLoader },
48
+ setup() {
49
+ return { loaderSizes, docCellStyle, docLabelStyle, docRowWrapStyle }
50
+ },
51
+ template: `
52
+ <div :style="docRowWrapStyle">
53
+ <div v-for="size in loaderSizes" :key="size" :style="docCellStyle">
54
+ <span :style="docLabelStyle">{{ size }}</span>
55
+ <CpLoader :size="size" color="accent" />
56
+ </div>
57
+ </div>
58
+ `,
59
+ }),
60
+ }
61
+
62
+ /**
63
+ * All semantic colors rendered side by side.
64
+ */
65
+ export const Colors: Story = {
66
+ parameters: { controls: { disable: true } },
67
+ render: () => ({
68
+ components: { CpLoader },
69
+ setup() {
70
+ return { loaderColors, docCellStyle, docLabelStyle, docRowWrapStyle }
71
+ },
72
+ template: `
73
+ <div :style="docRowWrapStyle">
74
+ <div v-for="color in loaderColors" :key="color" :style="docCellStyle">
75
+ <span :style="docLabelStyle">{{ color }}</span>
76
+ <CpLoader :color="color" size="lg" />
77
+ </div>
78
+ </div>
79
+ `,
80
+ }),
33
81
  }
@@ -2,8 +2,13 @@ import type { Meta, StoryObj } from '@storybook/vue3'
2
2
 
3
3
  import CpMenuItem from '@/components/CpMenuItem.vue'
4
4
 
5
+ import { docLabelStyle, docRowColumnStyle } from '@/stories/documentationStyles'
6
+
7
+ const menuItemCellStyle = 'display: flex; flex-direction: column; gap: 8px; width: 260px;'
8
+ const menuItemFrameStyle = 'width: 260px; border: 1px solid #e5e5e5; border-radius: 8px;'
9
+
5
10
  const meta = {
6
- title: 'Menu/CpMenuItem',
11
+ title: 'Atoms/CpMenuItem',
7
12
  component: CpMenuItem,
8
13
  argTypes: {
9
14
  label: {
@@ -49,6 +54,9 @@ const meta = {
49
54
  export default meta
50
55
  type Story = StoryObj<typeof meta>
51
56
 
57
+ /**
58
+ * Default menu item. Use the controls to experiment with each prop in isolation.
59
+ */
52
60
  export const Default: Story = {
53
61
  args: {
54
62
  label: 'Edit',
@@ -75,30 +83,48 @@ export const Default: Story = {
75
83
  }),
76
84
  }
77
85
 
78
- export const Critical: Story = {
79
- args: {
80
- ...Default.args,
81
- label: 'Delete',
82
- icon: 'trash-2',
83
- isCritical: true,
84
- command: () => alert('Delete clicked'),
85
- },
86
- }
87
-
88
- export const Disabled: Story = {
89
- args: {
90
- ...Default.args,
91
- label: 'Archive',
92
- icon: 'archive',
93
- isDisabled: true,
94
- },
95
- }
86
+ /* -------------------------------------------------------------------------- */
87
+ /* States */
88
+ /* -------------------------------------------------------------------------- */
96
89
 
97
- export const Loading: Story = {
98
- args: {
99
- ...Default.args,
100
- label: 'Download',
101
- icon: 'download',
102
- isLoading: true,
103
- },
90
+ /**
91
+ * Every state available for a menu item: default, critical (destructive),
92
+ * disabled and loading.
93
+ */
94
+ export const States: Story = {
95
+ parameters: { controls: { disable: true } },
96
+ render: () => ({
97
+ components: { CpMenuItem },
98
+ setup() {
99
+ return { docRowColumnStyle, menuItemCellStyle, menuItemFrameStyle, docLabelStyle }
100
+ },
101
+ template: `
102
+ <div :style="docRowColumnStyle">
103
+ <div :style="menuItemCellStyle">
104
+ <span :style="docLabelStyle">Default</span>
105
+ <div :style="menuItemFrameStyle">
106
+ <CpMenuItem label="Edit" icon="edit-3" />
107
+ </div>
108
+ </div>
109
+ <div :style="menuItemCellStyle">
110
+ <span :style="docLabelStyle">Critical</span>
111
+ <div :style="menuItemFrameStyle">
112
+ <CpMenuItem label="Delete" icon="trash-2" :is-critical="true" />
113
+ </div>
114
+ </div>
115
+ <div :style="menuItemCellStyle">
116
+ <span :style="docLabelStyle">Disabled</span>
117
+ <div :style="menuItemFrameStyle">
118
+ <CpMenuItem label="Archive" icon="archive" :is-disabled="true" />
119
+ </div>
120
+ </div>
121
+ <div :style="menuItemCellStyle">
122
+ <span :style="docLabelStyle">Loading</span>
123
+ <div :style="menuItemFrameStyle">
124
+ <CpMenuItem label="Download" icon="download" :is-loading="true" />
125
+ </div>
126
+ </div>
127
+ </div>
128
+ `,
129
+ }),
104
130
  }
@@ -51,69 +51,33 @@ const airlineOptions: IOption[] = [
51
51
  ]
52
52
 
53
53
  const meta = {
54
- title: 'Form/CpMultiSelect',
54
+ title: 'Organisms/CpMultiSelect',
55
55
  component: CpMultiselect,
56
56
  argTypes: {
57
- label: {
58
- control: 'text',
59
- description: 'Label of the select',
60
- },
61
- required: {
62
- control: 'boolean',
63
- description: 'Whether the select is required',
64
- },
65
- name: {
66
- control: 'text',
67
- description: 'Name of the select',
68
- },
69
- placeholder: {
70
- control: 'text',
71
- description: 'Placeholder of the select',
72
- },
73
- isInvalid: {
74
- control: 'boolean',
75
- description: 'Whether the select is invalid',
76
- },
77
- multiple: {
78
- control: 'boolean',
79
- description: 'Whether the select should be multiple',
80
- },
81
- options: {
82
- control: 'object',
83
- description: 'Options of the select',
84
- },
85
- errorMessage: {
86
- control: 'text',
87
- description: 'Error message of the select',
88
- },
89
- disabled: {
90
- control: 'boolean',
91
- description: 'Whether the select is disabled',
92
- },
93
- isLoading: {
94
- control: 'boolean',
95
- description: 'Whether the select is loading',
96
- },
97
- emptyMessage: {
98
- control: 'text',
99
- description: 'Message displayed when no options are found',
100
- },
101
- trackBy: {
102
- control: 'text',
103
- description: 'Property to track the selected option',
104
- },
105
- size: {
106
- control: 'select',
107
- options: ['sm', 'md'],
108
- description: 'Size of the multiselect',
109
- },
57
+ label: { control: 'text', description: 'Label of the select' },
58
+ required: { control: 'boolean', description: 'Whether the select is required' },
59
+ name: { control: 'text', description: 'Name of the select' },
60
+ placeholder: { control: 'text', description: 'Placeholder of the select' },
61
+ isInvalid: { control: 'boolean', description: 'Whether the select is invalid' },
62
+ multiple: { control: 'boolean', description: 'Whether the select should be multiple' },
63
+ options: { control: 'object', description: 'Options of the select' },
64
+ errorMessage: { control: 'text', description: 'Error message of the select' },
65
+ disabled: { control: 'boolean', description: 'Whether the select is disabled' },
66
+ isLoading: { control: 'boolean', description: 'Whether the select is loading' },
67
+ emptyMessage: { control: 'text', description: 'Message displayed when no options are found' },
68
+ trackBy: { control: 'text', description: 'Property to track the selected option' },
69
+ size: { control: 'select', options: ['sm', 'md'], description: 'Size of the multiselect' },
110
70
  },
111
71
  } satisfies Meta<typeof CpMultiselect>
112
72
 
113
73
  export default meta
114
74
  type Story = StoryObj<typeof meta>
115
75
 
116
- export const DefaultSearchHandler: Story = {
76
+ /**
77
+ * Single-value multiselect with the built-in search filter. The `#prefix`
78
+ * slot adds an icon before the input.
79
+ */
80
+ export const Single: Story = {
117
81
  args: {
118
82
  placeholder: 'Select a supplier',
119
83
  multiple: false,
@@ -128,7 +92,7 @@ export const DefaultSearchHandler: Story = {
128
92
  return { args, selectedSupplier }
129
93
  },
130
94
  template: `
131
- <div style="padding: 20px;width: 25rem;">
95
+ <div style="padding: 20px; width: 25rem;">
132
96
  <CpMultiselect v-model="selectedSupplier" v-bind="args">
133
97
  <template #prefix>
134
98
  <cp-partner-badge type="supplier" size="sm" />
@@ -139,7 +103,12 @@ export const DefaultSearchHandler: Story = {
139
103
  }),
140
104
  }
141
105
 
142
- export const Multiple: Story = {
106
+ /**
107
+ * Multi-value selection with an async search handler. Selected options are
108
+ * rendered as chips and can be customized through `#tag-leading-icon` and
109
+ * `#option`.
110
+ */
111
+ export const MultipleWithAsyncSearch: Story = {
143
112
  args: {
144
113
  required: false,
145
114
  name: 'select',
@@ -176,7 +145,7 @@ export const Multiple: Story = {
176
145
  return { args, selectedAirlines, dynamicOptions, handleSearch, isLoading }
177
146
  },
178
147
  template: `
179
- <div style="padding: 20px;max-width: 25rem;">
148
+ <div style="padding: 20px; max-width: 25rem;">
180
149
  <CpMultiselect v-model="selectedAirlines" v-bind="args" :options="dynamicOptions" :is-loading="isLoading" @search="handleSearch">
181
150
  <template #prefix>
182
151
  <cp-partner-badge type="airline" size="sm" />
@@ -196,6 +165,10 @@ export const Multiple: Story = {
196
165
  }),
197
166
  }
198
167
 
168
+ /**
169
+ * Invalid state with a label, required indicator and an error message
170
+ * underneath the input.
171
+ */
199
172
  export const Invalid: Story = {
200
173
  args: {
201
174
  placeholder: 'Select a supplier',
@@ -213,7 +186,7 @@ export const Invalid: Story = {
213
186
  return { args, selectedSupplier }
214
187
  },
215
188
  template: `
216
- <div style="padding: 20px;max-width: 25rem;">
189
+ <div style="padding: 20px; max-width: 25rem;">
217
190
  <CpMultiselect v-model="selectedSupplier" v-bind="args">
218
191
  <template #prefix>
219
192
  <cp-partner-badge type="supplier" size="sm" />
@@ -230,6 +203,10 @@ export const Invalid: Story = {
230
203
  }),
231
204
  }
232
205
 
206
+ /**
207
+ * Disabled state — the field is non-interactive and its menu cannot be
208
+ * opened.
209
+ */
233
210
  export const Disabled: Story = {
234
211
  args: {
235
212
  placeholder: 'Select a supplier',
@@ -244,7 +221,7 @@ export const Disabled: Story = {
244
221
  return { args, selectedSupplier }
245
222
  },
246
223
  template: `
247
- <div style="padding: 20px;max-width: 25rem;">
224
+ <div style="padding: 20px; max-width: 25rem;">
248
225
  <CpMultiselect v-model="selectedSupplier" v-bind="args">
249
226
  <template #prefix>
250
227
  <cp-icon type="airport-terminal" size="16" />
@@ -261,6 +238,10 @@ export const Disabled: Story = {
261
238
  }),
262
239
  }
263
240
 
241
+ /**
242
+ * Free-form tag input. `withoutTypeahead` removes the search affordance so
243
+ * users can enter arbitrary values that become chips.
244
+ */
264
245
  export const WithoutTypeahead: Story = {
265
246
  args: {
266
247
  placeholder: 'Select a supplier',
@@ -275,18 +256,18 @@ export const WithoutTypeahead: Story = {
275
256
  return { args, selectedSupplier }
276
257
  },
277
258
  template: `
278
- <div style="padding: 20px;max-width: 25rem;">
259
+ <div style="padding: 20px; max-width: 25rem;">
279
260
  <CpMultiselect v-model="selectedSupplier" v-bind="args">
280
- <template #chip="{ value, removeCallback }">
281
- <slot name="tag" :option="value" :remove="removeCallback">
282
- <cp-badge class="cpMultiselect__tag" is-clearable size="sm" @on-clear="removeCallback">
283
- <template #leading-icon>
284
- <slot name="tag-leading-icon" :option="value" />
285
- </template>
286
- {{ value }}
287
- </cp-badge>
288
- </slot>
289
- </template>
261
+ <template #chip="{ value, removeCallback }">
262
+ <slot name="tag" :option="value" :remove="removeCallback">
263
+ <cp-badge class="cpMultiselect__tag" is-clearable size="sm" @on-clear="removeCallback">
264
+ <template #leading-icon>
265
+ <slot name="tag-leading-icon" :option="value" />
266
+ </template>
267
+ {{ value }}
268
+ </cp-badge>
269
+ </slot>
270
+ </template>
290
271
  <template #tag="{ option, remove }">
291
272
  <cp-badge class="cpMultiselect__tag" is-clearable size="sm" @on-clear="remove">
292
273
  {{ option }}
@@ -3,9 +3,12 @@ import type { Meta, StoryObj } from '@storybook/vue3'
3
3
  import CpPartnerBadge from '@/components/CpPartnerBadge.vue'
4
4
 
5
5
  import { PartnerTypes } from '@/constants'
6
+ import { docCellStyle, docLabelStyle, docRowWrapStyle } from '@/stories/documentationStyles'
7
+
8
+ const partnerSizes = ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'] as const
6
9
 
7
10
  const meta = {
8
- title: 'Visual/CpPartnerBadge',
11
+ title: 'Atoms/CpPartnerBadge',
9
12
  component: CpPartnerBadge,
10
13
  parameters: {
11
14
  docs: {
@@ -27,7 +30,7 @@ const meta = {
27
30
  },
28
31
  size: {
29
32
  control: 'select',
30
- options: ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl', '4xl'],
33
+ options: partnerSizes,
31
34
  description: 'The size of the badge',
32
35
  table: {
33
36
  type: { summary: 'string' },
@@ -50,6 +53,10 @@ const defaultRender = (args) => ({
50
53
  template: defaultTemplate,
51
54
  })
52
55
 
56
+ /**
57
+ * Default partner badge. Use the controls to experiment with each prop in
58
+ * isolation.
59
+ */
53
60
  export const Default: Story = {
54
61
  args: {
55
62
  type: PartnerTypes.OTA,
@@ -57,86 +64,65 @@ export const Default: Story = {
57
64
  render: defaultRender,
58
65
  }
59
66
 
60
- export const OTA: Story = {
61
- args: {
62
- type: PartnerTypes.OTA,
63
- },
64
- render: defaultRender,
65
- parameters: {
66
- docs: {
67
- description: {
68
- story: 'Partner badge for Online Travel Agencies (OTA) with orange background and OTA icon.',
69
- },
70
- },
71
- },
72
- }
67
+ /* -------------------------------------------------------------------------- */
68
+ /* Types */
69
+ /* -------------------------------------------------------------------------- */
73
70
 
74
- export const Airline: Story = {
75
- args: {
76
- type: PartnerTypes.AIRLINE,
77
- },
78
- render: defaultRender,
79
- parameters: {
80
- docs: {
81
- description: {
82
- story: 'Partner badge for Airlines with blue background and airline icon.',
83
- },
84
- },
85
- },
86
- }
87
-
88
- export const Supplier: Story = {
89
- args: {
90
- type: PartnerTypes.SUPPLIER,
91
- },
92
- render: defaultRender,
93
- parameters: {
94
- docs: {
95
- description: {
96
- story: 'Partner badge for Suppliers with purple background and supplier icon.',
97
- },
71
+ /**
72
+ * Every partner type rendered side by side. Each type gets its own icon and
73
+ * background color.
74
+ */
75
+ export const Types: Story = {
76
+ parameters: { controls: { disable: true } },
77
+ render: () => ({
78
+ components: { CpPartnerBadge },
79
+ setup() {
80
+ const entries = Object.entries(PartnerTypes)
81
+ return { entries, docCellStyle, docLabelStyle, docRowWrapStyle }
98
82
  },
99
- },
83
+ template: `
84
+ <div :style="docRowWrapStyle">
85
+ <div v-for="[name, type] in entries" :key="type" :style="docCellStyle">
86
+ <span :style="docLabelStyle">{{ name.toLowerCase() }}</span>
87
+ <CpPartnerBadge :type="type" />
88
+ </div>
89
+ </div>
90
+ `,
91
+ }),
100
92
  }
101
93
 
102
- export const ThirdParty: Story = {
103
- args: {
104
- type: PartnerTypes.THIRDPARTY,
105
- },
106
- render: defaultRender,
107
- parameters: {
108
- docs: {
109
- description: {
110
- story: 'Partner badge for Third Party partners with pink background and share icon.',
111
- },
112
- },
113
- },
114
- }
94
+ /* -------------------------------------------------------------------------- */
95
+ /* Sizes */
96
+ /* -------------------------------------------------------------------------- */
115
97
 
116
- export const AllTypes: Story = {
98
+ /**
99
+ * All sizes rendered side by side, from `2xs` to `4xl`.
100
+ */
101
+ export const Sizes: Story = {
102
+ parameters: { controls: { disable: true } },
117
103
  render: () => ({
118
104
  components: { CpPartnerBadge },
119
105
  setup() {
120
- return { PartnerTypes }
106
+ return { partnerSizes, PartnerTypes, docCellStyle, docLabelStyle, docRowWrapStyle }
121
107
  },
122
108
  template: `
123
- <div style="display: flex; gap: 16px; align-items: center;">
124
- <CpPartnerBadge :type="PartnerTypes.OTA" />
125
- <CpPartnerBadge :type="PartnerTypes.AIRLINE" />
126
- <CpPartnerBadge :type="PartnerTypes.SUPPLIER" />
127
- <CpPartnerBadge :type="PartnerTypes.THIRDPARTY" />
109
+ <div :style="docRowWrapStyle">
110
+ <div v-for="size in partnerSizes" :key="size" :style="docCellStyle">
111
+ <span :style="docLabelStyle">{{ size }}</span>
112
+ <CpPartnerBadge :type="PartnerTypes.OTA" :size="size" />
113
+ </div>
128
114
  </div>
129
115
  `,
130
116
  }),
131
- parameters: {
132
- docs: {
133
- description: {
134
- story: 'All partner badge types displayed together for comparison.',
135
- },
136
- },
137
- },
138
117
  }
139
118
 
119
+ /* -------------------------------------------------------------------------- */
120
+ /* Slots */
121
+ /* -------------------------------------------------------------------------- */
122
+
123
+ /**
124
+ * Override the default icon through the `#icon` slot.
125
+ */
140
126
  export const WithCustomIcon: Story = {
141
127
  render: () => ({
142
128
  components: { CpPartnerBadge },
@@ -151,11 +137,4 @@ export const WithCustomIcon: Story = {
151
137
  </CpPartnerBadge>
152
138
  `,
153
139
  }),
154
- parameters: {
155
- docs: {
156
- description: {
157
- story: 'Partner badge with a custom icon using the icon slot.',
158
- },
159
- },
160
- },
161
140
  }