@citizenplane/pimp 16.0.3 → 16.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.
Files changed (71) hide show
  1. package/dist/pimp.es.js +781 -757
  2. package/dist/pimp.umd.js +21 -21
  3. package/dist/style.css +1 -1
  4. package/package.json +10 -8
  5. package/src/components/CpDate.vue +3 -1
  6. package/src/components/CpHeading.vue +4 -5
  7. package/src/components/CpMultiselect.vue +2 -5
  8. package/src/components/CpTable.vue +4 -2
  9. package/src/components/CpTelInput.vue +18 -12
  10. package/src/components/CpText.vue +141 -0
  11. package/src/components/CpToast.vue +1 -1
  12. package/src/components/CpTransitionExpand.vue +23 -20
  13. package/src/components/index.ts +2 -0
  14. package/src/libs/CoreDatepicker.vue +1 -0
  15. package/src/stories/BaseInputLabel.stories.ts +36 -9
  16. package/src/stories/Colors.mdx +9 -0
  17. package/src/stories/Colors.stories.ts +177 -0
  18. package/src/stories/CpAccordion.stories.ts +188 -159
  19. package/src/stories/CpAccordionGroup.stories.ts +51 -95
  20. package/src/stories/CpAirlineLogo.stories.ts +52 -28
  21. package/src/stories/CpAlert.stories.ts +196 -159
  22. package/src/stories/CpBadge.stories.ts +260 -194
  23. package/src/stories/CpButton.stories.ts +257 -426
  24. package/src/stories/CpCheckbox.stories.ts +102 -30
  25. package/src/stories/CpContextualMenu.stories.ts +14 -9
  26. package/src/stories/CpDate.stories.ts +53 -26
  27. package/src/stories/CpDatepicker.stories.ts +53 -80
  28. package/src/stories/CpDialog.stories.ts +23 -2
  29. package/src/stories/CpHeading.stories.ts +60 -20
  30. package/src/stories/CpIcon.stories.ts +98 -31
  31. package/src/stories/CpInput.stories.ts +164 -73
  32. package/src/stories/CpItemActions.stories.ts +23 -12
  33. package/src/stories/CpLoader.stories.ts +55 -7
  34. package/src/stories/CpMenuItem.stories.ts +53 -27
  35. package/src/stories/CpMultiselect.stories.ts +53 -72
  36. package/src/stories/CpPartnerBadge.stories.ts +58 -76
  37. package/src/stories/CpRadio.stories.ts +45 -49
  38. package/src/stories/CpRadioGroup.stories.ts +47 -40
  39. package/src/stories/CpSelect.stories.ts +108 -34
  40. package/src/stories/CpSelectMenu.stories.ts +66 -55
  41. package/src/stories/CpSelectableButton.stories.ts +170 -81
  42. package/src/stories/CpSwitch.stories.ts +136 -134
  43. package/src/stories/CpTable.stories.ts +69 -13
  44. package/src/stories/CpTableEmptyState.stories.ts +11 -7
  45. package/src/stories/CpTabs.stories.ts +23 -5
  46. package/src/stories/CpTelInput.stories.ts +28 -19
  47. package/src/stories/CpText.stories.ts +131 -0
  48. package/src/stories/CpTextarea.stories.ts +74 -27
  49. package/src/stories/CpToast.stories.ts +75 -109
  50. package/src/stories/CpTooltip.stories.ts +82 -77
  51. package/src/stories/CpTransitionCounter.stories.ts +5 -1
  52. package/src/stories/CpTransitionExpand.stories.ts +12 -7
  53. package/src/stories/CpTransitionListItems.stories.ts +6 -1
  54. package/src/stories/CpTransitionSize.stories.ts +9 -1
  55. package/src/stories/CpTransitionSlide.stories.ts +5 -1
  56. package/src/stories/CpTransitionTabContent.stories.ts +5 -1
  57. package/src/stories/Dimensions.mdx +9 -0
  58. package/src/stories/Dimensions.stories.ts +119 -0
  59. package/src/stories/Easings.mdx +9 -0
  60. package/src/stories/Easings.stories.ts +101 -0
  61. package/src/stories/FocusRings.mdx +9 -0
  62. package/src/stories/FocusRings.stories.ts +74 -0
  63. package/src/stories/Shadows.mdx +9 -0
  64. package/src/stories/Shadows.stories.ts +100 -0
  65. package/src/stories/Typography.mdx +9 -0
  66. package/src/stories/Typography.stories.ts +181 -0
  67. package/src/stories/documentationStyles.ts +2 -10
  68. package/src/stories/tokenUtils.ts +259 -0
  69. package/src/types/primevue-toasteventbus.d.ts +14 -0
  70. package/tsconfig.json +1 -0
  71. package/.lintstagedrc.json +0 -4
@@ -1,12 +1,12 @@
1
1
  import { action } from 'storybook/actions'
2
2
  import { ref } from 'vue'
3
3
 
4
- import type { Args, Meta, StoryObj } from '@storybook/vue3'
4
+ import type { Args, Meta, StoryObj } from '@storybook/vue3-vite'
5
5
 
6
6
  import CpTabs from '@/components/CpTabs.vue'
7
7
 
8
8
  const meta = {
9
- title: 'Navigation/CpTabs',
9
+ title: 'Molecules/CpTabs',
10
10
  component: CpTabs,
11
11
  argTypes: {
12
12
  defaultActiveIndex: {
@@ -28,15 +28,18 @@ export default meta
28
28
 
29
29
  type Story = StoryObj<typeof meta>
30
30
 
31
- const defaultTemplate = '<CpTabs v-bind="args" @on-tab-click="args.onOnTabClick" />'
32
31
  const defaultRender = (args: Args) => ({
33
32
  components: { CpTabs },
34
33
  setup() {
35
34
  return { args }
36
35
  },
37
- template: defaultTemplate,
36
+ template: '<CpTabs v-bind="args" @on-tab-click="args.onOnTabClick" />',
38
37
  })
39
38
 
39
+ /**
40
+ * Default tabs rendered from an array of `{ title }` objects. Use the
41
+ * controls to experiment with each prop in isolation.
42
+ */
40
43
  export const Default: Story = {
41
44
  args: {
42
45
  defaultActiveIndex: 0,
@@ -47,6 +50,10 @@ export const Default: Story = {
47
50
  render: defaultRender,
48
51
  }
49
52
 
53
+ /**
54
+ * Tabs augmented with leading icons through the `icon` property on each
55
+ * tab object.
56
+ */
50
57
  export const WithIcons: Story = {
51
58
  args: {
52
59
  ...Default.args,
@@ -59,6 +66,10 @@ export const WithIcons: Story = {
59
66
  render: defaultRender,
60
67
  }
61
68
 
69
+ /**
70
+ * Tabs that display a count badge on the right — typically used for
71
+ * notifications or list sizes.
72
+ */
62
73
  export const WithCounts: Story = {
63
74
  args: {
64
75
  ...Default.args,
@@ -71,6 +82,9 @@ export const WithCounts: Story = {
71
82
  render: defaultRender,
72
83
  }
73
84
 
85
+ /**
86
+ * Icons and counts combined on the same tab.
87
+ */
74
88
  export const WithIconsAndCounts: Story = {
75
89
  args: {
76
90
  ...Default.args,
@@ -83,6 +97,10 @@ export const WithIconsAndCounts: Story = {
83
97
  render: defaultRender,
84
98
  }
85
99
 
100
+ /**
101
+ * Tabs nested inside a dialog — verifies the integration with overlay
102
+ * surfaces and the focus ring behaviour.
103
+ */
86
104
  export const InDialog: Story = {
87
105
  args: {
88
106
  ...Default.args,
@@ -105,7 +123,7 @@ export const InDialog: Story = {
105
123
  <CpTabs v-bind="args" @on-tab-click="args.onOnTabClick" v-if="isVisible" />
106
124
  </cp-dialog>
107
125
  </cp-transition-dialog>
108
- <div style="display: flex; justify-content: center; align-items: center; min-height: 240px; min-width:240px;">
126
+ <div style="display: flex; justify-content: center; align-items: center; min-height: 240px; min-width: 240px;">
109
127
  <cp-button @click="isVisible = !isVisible">Open dialog</cp-button>
110
128
  </div>
111
129
  `,
@@ -1,48 +1,57 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3'
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite'
2
2
 
3
3
  import CpTelInput from '@/components/CpTelInput.vue'
4
4
 
5
+ const telInputSizes = ['md', 'lg'] as const
6
+
5
7
  const meta = {
6
- title: 'Form/CpTelInput',
8
+ title: 'Molecules/CpTelInput',
7
9
  component: CpTelInput,
8
10
  argTypes: {
9
- telModel: {
11
+ modelValue: {
10
12
  control: 'text',
11
13
  description: 'The phone number value',
12
14
  },
13
15
  size: {
14
16
  control: 'select',
15
- options: ['md', 'lg'],
17
+ options: telInputSizes,
16
18
  description: 'The size of the input',
17
19
  },
18
20
  },
19
21
  } satisfies Meta<typeof CpTelInput>
20
22
 
21
23
  export default meta
24
+
22
25
  type Story = StoryObj<typeof meta>
23
26
 
27
+ type TelInputStoryArgs = NonNullable<Story['args']>
28
+
29
+ const defaultRender = (args: TelInputStoryArgs) => ({
30
+ components: { CpTelInput },
31
+ setup() {
32
+ return { args }
33
+ },
34
+ template: `<CpTelInput v-bind="args" />`,
35
+ })
36
+
37
+ /**
38
+ * Default telephone input with a country selector. Use the controls to
39
+ * experiment with each prop in isolation.
40
+ */
24
41
  export const Default: Story = {
25
42
  args: {
26
- telModel: '',
43
+ modelValue: '',
27
44
  },
28
- render: (args) => ({
29
- components: { CpTelInput },
30
- setup() {
31
- return { args }
32
- },
33
- template: `<CpTelInput v-bind="args" />`,
34
- }),
45
+ render: defaultRender,
35
46
  }
36
47
 
48
+ /**
49
+ * Pre-select a country via the `defaultCountry` ISO-2 code (e.g. `us`,
50
+ * `fr`, `gb`).
51
+ */
37
52
  export const WithDefaultCountry: Story = {
38
53
  args: {
39
54
  defaultCountry: 'us',
40
55
  },
41
- render: (args) => ({
42
- components: { CpTelInput },
43
- setup() {
44
- return { args }
45
- },
46
- template: `<CpTelInput v-bind="args" />`,
47
- }),
56
+ render: defaultRender,
48
57
  }
@@ -0,0 +1,131 @@
1
+ import type { Args, Meta, StoryObj } from '@storybook/vue3-vite'
2
+
3
+ import CpText from '@/components/CpText.vue'
4
+ import type { CpTextSize, CpTextWeight } from '@/components/CpText.vue'
5
+
6
+ import { docLabelStyle } from '@/stories/documentationStyles'
7
+
8
+ const textSizes = [
9
+ 'xs',
10
+ 'sm',
11
+ 'md',
12
+ 'lg',
13
+ 'xl',
14
+ '2xl',
15
+ '3xl',
16
+ '4xl',
17
+ '5xl',
18
+ '6xl',
19
+ '7xl',
20
+ '8xl',
21
+ '9xl',
22
+ ] as const satisfies readonly CpTextSize[]
23
+
24
+ const weights = [400, 500, 600, 700] as const satisfies readonly CpTextWeight[]
25
+
26
+ const rowStyle = 'display: grid; grid-template-columns: 56px 1fr; gap: 16px; align-items: center;'
27
+
28
+ const sizesRowStyle = 'display: flex; align-items: center; gap: 16px; width: max-content;'
29
+
30
+ const meta = {
31
+ title: 'Atoms/CpText',
32
+ component: CpText,
33
+ parameters: {
34
+ docs: {
35
+ description: {
36
+ component:
37
+ 'Typography primitive for body and UI copy. Pairs each `size` with the matching `--cp-text-size-*` and `--cp-line-height-*` design tokens. Override the root element with `tag` (defaults to `p`).',
38
+ },
39
+ },
40
+ },
41
+ argTypes: {
42
+ tag: {
43
+ control: 'text',
44
+ description: 'Root HTML tag (default: `p`).',
45
+ },
46
+ size: {
47
+ control: 'select',
48
+ options: textSizes,
49
+ description: 'Scale step from `xs` through `9xl`; maps to typography CSS variables.',
50
+ },
51
+ weight: {
52
+ control: 'select',
53
+ options: [undefined, ...weights],
54
+ description: 'Font weight from 400 to 700.',
55
+ },
56
+ },
57
+ } satisfies Meta<typeof CpText>
58
+
59
+ export default meta
60
+ type Story = StoryObj<typeof meta>
61
+
62
+ export const Default: Story = {
63
+ args: {
64
+ size: 'md',
65
+ },
66
+ render: (args: Args) => ({
67
+ components: { CpText },
68
+ setup() {
69
+ return { args }
70
+ },
71
+ template: `
72
+ <div style="padding: 20px;">
73
+ <CpText v-bind="args">Body text using the size and line-height tokens.</CpText>
74
+ </div>
75
+ `,
76
+ }),
77
+ }
78
+
79
+ export const Sizes: Story = {
80
+ parameters: { controls: { disable: true }, layout: 'padded' },
81
+ render: () => ({
82
+ components: { CpText },
83
+ setup() {
84
+ return { textSizes, sizesRowStyle, docLabelStyle }
85
+ },
86
+ template: `
87
+ <div style="display: flex; flex-direction: column; gap: 12px; overflow-x: auto; max-width: 100%;">
88
+ <div v-for="size in textSizes" :key="size" :style="sizesRowStyle">
89
+ <span :style="docLabelStyle + ' flex: 0 0 56px;'">{{ size }}</span>
90
+ <CpText :size="size" style="white-space: nowrap;">A design system offers guidelines and components for consistent visuals and better user experience.</CpText>
91
+ </div>
92
+ </div>
93
+ `,
94
+ }),
95
+ }
96
+
97
+ export const Weights: Story = {
98
+ parameters: { controls: { disable: true } },
99
+ render: () => ({
100
+ components: { CpText },
101
+ setup() {
102
+ return { weights, rowStyle, docLabelStyle }
103
+ },
104
+ template: `
105
+ <div style="padding: 20px; display: flex; flex-direction: column; gap: 12px;">
106
+ <div v-for="w in weights" :key="w" :style="rowStyle">
107
+ <span :style="docLabelStyle">{{ w }}</span>
108
+ <CpText :weight="w">Create a harmonious user experience</CpText>
109
+ </div>
110
+ </div>
111
+ `,
112
+ }),
113
+ }
114
+
115
+ export const CustomTag: Story = {
116
+ args: {
117
+ tag: 'span',
118
+ size: 'sm',
119
+ },
120
+ render: (args: Args) => ({
121
+ components: { CpText },
122
+ setup() {
123
+ return { args }
124
+ },
125
+ template: `
126
+ <div style="padding: 20px;">
127
+ <p>Inline text: <CpText v-bind="args">styled snippet</CpText> inside a paragraph.</p>
128
+ </div>
129
+ `,
130
+ }),
131
+ }
@@ -1,11 +1,23 @@
1
1
  import { ref } from 'vue'
2
2
 
3
- import type { Meta, StoryObj } from '@storybook/vue3'
3
+ import type { ComponentPropsAndSlots, Meta, StoryObj } from '@storybook/vue3-vite'
4
4
 
5
5
  import CpTextarea from '@/components/CpTextarea.vue'
6
6
 
7
+ import { docCellStyle, docLabelStyle, docRowColumnStyle } from '@/stories/documentationStyles'
8
+
9
+ /** Native `<textarea>` attributes not declared as Vue props (see `CpTextarea` template). */
10
+ type CpTextareaPassthroughAttrs = {
11
+ maxLength?: number
12
+ rows?: number
13
+ }
14
+
15
+ type CpTextareaStoryArgs = ComponentPropsAndSlots<typeof CpTextarea> & CpTextareaPassthroughAttrs
16
+
17
+ const textareaStackStyle = `${docCellStyle} width: 100%; max-width: 360px;`
18
+
7
19
  const meta = {
8
- title: 'Form/CpTextarea',
20
+ title: 'Atoms/CpTextarea',
9
21
  component: CpTextarea,
10
22
  argTypes: {
11
23
  modelValue: {
@@ -45,18 +57,24 @@ const meta = {
45
57
  description: 'Maximum number of characters allowed',
46
58
  },
47
59
  },
48
- } satisfies Meta<typeof CpTextarea>
60
+ } satisfies Meta<CpTextareaStoryArgs>
49
61
 
50
62
  export default meta
51
- type Story = StoryObj<typeof meta>
52
63
 
64
+ type Story = StoryObj<CpTextareaStoryArgs>
65
+
66
+ type TextareaStoryArgs = Partial<CpTextareaStoryArgs>
67
+
68
+ /**
69
+ * Default textarea. Use the controls to experiment with each prop in isolation.
70
+ */
53
71
  export const Default: Story = {
54
72
  args: {
55
73
  label: 'Textarea Label',
56
74
  placeholder: 'Enter your message here',
57
75
  rows: 4,
58
76
  },
59
- render: (args) => ({
77
+ render: (args: TextareaStoryArgs) => ({
60
78
  components: { CpTextarea },
61
79
  setup() {
62
80
  const value = ref('')
@@ -64,37 +82,63 @@ export const Default: Story = {
64
82
  },
65
83
  template: `
66
84
  <div style="max-width: 400px; padding: 20px;">
67
- <CpTextarea
68
- v-model="value"
69
- v-bind="args"
70
- />
85
+ <CpTextarea v-model="value" v-bind="args" />
71
86
  </div>
72
87
  `,
73
88
  }),
74
89
  }
75
90
 
76
- export const WithError: Story = {
77
- args: {
78
- ...Default.args,
79
- isInvalid: true,
80
- errorMessage: 'This field is required',
81
- },
82
- }
91
+ /* -------------------------------------------------------------------------- */
92
+ /* States */
93
+ /* -------------------------------------------------------------------------- */
83
94
 
84
- export const Required: Story = {
85
- args: {
86
- ...Default.args,
87
- required: true,
88
- },
95
+ /**
96
+ * Default, required, disabled and invalid states compared side by side.
97
+ */
98
+ export const States: Story = {
99
+ parameters: { controls: { disable: true } },
100
+ render: () => ({
101
+ components: { CpTextarea },
102
+ setup() {
103
+ const value = ref('')
104
+ return { value, docRowColumnStyle, textareaStackStyle, docLabelStyle }
105
+ },
106
+ template: `
107
+ <div :style="docRowColumnStyle">
108
+ <div :style="textareaStackStyle">
109
+ <span :style="docLabelStyle">Default</span>
110
+ <CpTextarea v-model="value" label="Textarea label" placeholder="Enter your message here" />
111
+ </div>
112
+ <div :style="textareaStackStyle">
113
+ <span :style="docLabelStyle">Required</span>
114
+ <CpTextarea v-model="value" label="Textarea label" placeholder="Enter your message here" :required="true" />
115
+ </div>
116
+ <div :style="textareaStackStyle">
117
+ <span :style="docLabelStyle">Disabled</span>
118
+ <CpTextarea v-model="value" label="Textarea label" placeholder="Enter your message here" :disabled="true" />
119
+ </div>
120
+ <div :style="textareaStackStyle">
121
+ <span :style="docLabelStyle">Invalid</span>
122
+ <CpTextarea
123
+ v-model="value"
124
+ label="Textarea label"
125
+ placeholder="Enter your message here"
126
+ :is-invalid="true"
127
+ error-message="This field is required"
128
+ />
129
+ </div>
130
+ </div>
131
+ `,
132
+ }),
89
133
  }
90
134
 
91
- export const Disabled: Story = {
92
- args: {
93
- ...Default.args,
94
- disabled: true,
95
- },
96
- }
135
+ /* -------------------------------------------------------------------------- */
136
+ /* Variants */
137
+ /* -------------------------------------------------------------------------- */
97
138
 
139
+ /**
140
+ * Enforce a character limit; a counter is shown below the field.
141
+ */
98
142
  export const WithMaxLength: Story = {
99
143
  args: {
100
144
  ...Default.args,
@@ -104,6 +148,9 @@ export const WithMaxLength: Story = {
104
148
  },
105
149
  }
106
150
 
151
+ /**
152
+ * Adjust the number of visible rows through the `rows` prop.
153
+ */
107
154
  export const CustomRows: Story = {
108
155
  args: {
109
156
  ...Default.args,