@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@citizenplane/pimp",
3
- "version": "16.0.3",
3
+ "version": "16.2.0",
4
4
  "scripts": {
5
5
  "dev": "storybook dev -p 8081",
6
6
  "build-storybook": "storybook build --output-dir ./docs",
@@ -11,6 +11,7 @@
11
11
  "lint:style:write": "stylelint \"**/*.{css,scss,vue}\" --fix",
12
12
  "format": "prettier . --write",
13
13
  "test": "jest tests",
14
+ "types": "vue-tsc --noEmit",
14
15
  "commitlint": "commitlint --edit",
15
16
  "prepare": "husky"
16
17
  },
@@ -48,11 +49,11 @@
48
49
  "@commitlint/cli": "20.4.2",
49
50
  "@eslint/eslintrc": "^3.3.3",
50
51
  "@eslint/js": "^9.39.2",
51
- "@storybook/addon-onboarding": "^9.1.17",
52
- "@storybook/addon-vitest": "^9.0.18",
52
+ "@storybook/addon-docs": "^10.3.5",
53
+ "@storybook/addon-onboarding": "^10.3.5",
54
+ "@storybook/addon-vitest": "^10.3.5",
53
55
  "@storybook/preset-scss": "^1.0.3",
54
- "@storybook/vue3": "^9.1.17",
55
- "@storybook/vue3-vite": "^9.1.17",
56
+ "@storybook/vue3-vite": "^10.3.5",
56
57
  "@stylistic/eslint-plugin": "^5.7.1",
57
58
  "@types/feather-icons": "^4.29.4",
58
59
  "@types/vue-tel-input": "^2.1.7",
@@ -70,7 +71,7 @@
70
71
  "eslint-config-prettier": "^10.1.8",
71
72
  "eslint-plugin-perfectionist": "^5.4.0",
72
73
  "eslint-plugin-prettier": "^5.5.5",
73
- "eslint-plugin-storybook": "^9.1.17",
74
+ "eslint-plugin-storybook": "^10.3.5",
74
75
  "eslint-plugin-vue": "^10.7.0",
75
76
  "globals": "^17.2.0",
76
77
  "husky": "^9.1.7",
@@ -81,11 +82,12 @@
81
82
  "prettier": "^3.6.2",
82
83
  "sass": "~1.97.3",
83
84
  "sass-loader": "^16.0.6",
84
- "storybook": "^9.1.17",
85
+ "storybook": "^10.3.5",
85
86
  "ts-jest": "^29.4.6",
86
87
  "typescript-eslint": "^8.54.0",
87
88
  "vite": "^7.3.1",
88
- "vitest": "^4.0.18"
89
+ "vitest": "^4.0.18",
90
+ "vue-tsc": "3.2.5"
89
91
  },
90
92
  "eslintConfig": {
91
93
  "extends": [
@@ -246,7 +246,9 @@ const selectDynamicClass = computed(() => {
246
246
  })
247
247
 
248
248
  const autocompleteFields = computed(() => {
249
- if (!props.autocompleteBirthday) return 'off'
249
+ if (!props.autocompleteBirthday) {
250
+ return { day: 'off', month: 'off', year: 'off' }
251
+ }
250
252
 
251
253
  return {
252
254
  day: 'bday-day',
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <component :is="$props.headingLevel" v-bind="$attrs" :class="`cpHeading--${size}`" class="cpHeading">
2
+ <component :is="$props.headingLevel" class="cpHeading" :class="`cpHeading--${size}`" v-bind="$attrs">
3
3
  <slot />
4
4
  </component>
5
5
  </template>
@@ -7,12 +7,11 @@
7
7
  <script setup lang="ts">
8
8
  import { HeadingLevels } from '@/constants'
9
9
 
10
- /**
11
- * @deprecated This component is deprecated. Please use directly CSS variables instead.
12
- */
13
-
14
10
  type HeadingSize = 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
15
11
 
12
+ /**
13
+ * @deprecated `CpHeading` is deprecated. Use CpText instead.
14
+ */
16
15
  interface Props {
17
16
  headingLevel?: HeadingLevels
18
17
  size?: HeadingSize
@@ -166,11 +166,8 @@ const selectModel = computed({
166
166
  get() {
167
167
  return props.modelValue
168
168
  },
169
- set(value: string | object | string[] | null) {
170
- if (typeof value === 'string') {
171
- return
172
- }
173
-
169
+ set(value) {
170
+ if (typeof value === 'string') return
174
171
  emit('update:modelValue', value)
175
172
  },
176
173
  })
@@ -126,6 +126,8 @@
126
126
  <script setup lang="ts">
127
127
  import { ref, computed, useId, watch } from 'vue'
128
128
 
129
+ import type { MenuItemCommandEvent } from 'primevue/menuitem'
130
+
129
131
  import { CpTableColumnObject } from '@/constants/CpTableColumn'
130
132
 
131
133
  import CpContextualMenu from '@/components/CpContextualMenu.vue'
@@ -154,7 +156,7 @@ interface Pagination {
154
156
  }
155
157
 
156
158
  interface RowOptions {
157
- action: (rowData: Record<string, unknown>, $event: MouseEvent) => void
159
+ action: (rowData: Record<string, unknown>, $event: Event) => void
158
160
  icon: string
159
161
  id: string
160
162
  isAsync?: boolean
@@ -228,7 +230,7 @@ const currentRowData = ref<Record<string, unknown>>({})
228
230
  const contextualMenuItems = computed(() => {
229
231
  return props.rowOptions.map((option) => ({
230
232
  ...option,
231
- command: ({ originalEvent }: { originalEvent: MouseEvent }) => option.action(currentRowData.value, originalEvent),
233
+ command: (event: MenuItemCommandEvent) => option.action(currentRowData.value, event.originalEvent),
232
234
  }))
233
235
  })
234
236
 
@@ -41,7 +41,9 @@
41
41
  </template>
42
42
 
43
43
  <script setup lang="ts">
44
- import { useAttrs, ref, useId, computed, nextTick } from 'vue'
44
+ import { computed, nextTick, ref, useAttrs, useId, useTemplateRef } from 'vue'
45
+
46
+ import type { ComponentPublicInstance } from 'vue'
45
47
 
46
48
  import BaseInputLabel from '@/components/BaseInputLabel.vue'
47
49
 
@@ -97,7 +99,13 @@ interface Emits {
97
99
  }
98
100
 
99
101
  const inputModel = defineModel<string>()
100
- const telInputRef = ref<HTMLInputElement | null>(null)
102
+
103
+ type VueTelInputInstance = ComponentPublicInstance & {
104
+ $el: HTMLElement
105
+ focus: VoidFunction
106
+ }
107
+
108
+ const telInputRefElement = useTemplateRef<VueTelInputInstance>('telInputRef')
101
109
 
102
110
  const helpMessageId = useId()
103
111
  const errorMessageId = useId()
@@ -139,27 +147,25 @@ const displayErrorMessage = computed(() => props.isInvalid && props.errorMessage
139
147
  const displayHelp = computed(() => props.help?.length && !displayErrorMessage.value)
140
148
 
141
149
  const focusOnInput = async () => {
142
- if (!telInputRef.value) return
143
- setTimeout(() => telInputRef.value?.focus(), 1)
150
+ if (!telInputRefElement.value) return
151
+ setTimeout(() => telInputRefElement.value?.focus(), 1)
144
152
  }
145
153
 
146
154
  const handleDropdownOpen = async () => {
147
- if (!telInputRef.value) return
155
+ if (!telInputRefElement.value) return
156
+
148
157
  await nextTick()
149
158
 
150
- const searchBox = telInputRef.value?.$el?.querySelector('input.vti__search_box')
159
+ const searchBox = telInputRefElement.value?.$el?.querySelector('input.vti__search_box')
160
+
151
161
  if (!searchBox) return
152
162
 
153
163
  setTimeout(() => searchBox.focus(), 1)
154
164
  }
155
165
 
156
- const handleCountryChanged = (country: { iso2: string }) => {
157
- emit('countryChanged', country?.iso2 || '')
158
- }
166
+ const handleCountryChanged = (country: { iso2: string }) => emit('countryChanged', country?.iso2 || '')
159
167
 
160
- const handleOnValidate = (phoneObject: PhoneObject) => {
161
- emit('validate', phoneObject)
162
- }
168
+ const handleOnValidate = (phoneObject: PhoneObject) => emit('validate', phoneObject)
163
169
  </script>
164
170
 
165
171
  <style lang="scss">
@@ -0,0 +1,141 @@
1
+ <template>
2
+ <component :is="tag" class="cpText" :class="dynamicClasses" v-bind="$attrs">
3
+ <slot />
4
+ </component>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { computed } from 'vue'
9
+
10
+ import { capitalizeFirstLetter } from '@/helpers'
11
+
12
+ export type CpTextSize =
13
+ | 'xs'
14
+ | 'sm'
15
+ | 'md'
16
+ | 'lg'
17
+ | 'xl'
18
+ | '2xl'
19
+ | '3xl'
20
+ | '4xl'
21
+ | '5xl'
22
+ | '6xl'
23
+ | '7xl'
24
+ | '8xl'
25
+ | '9xl'
26
+
27
+ export type CpTextWeight = 400 | 500 | 600 | 700
28
+
29
+ interface Props {
30
+ size?: CpTextSize
31
+ tag?: string
32
+ weight?: CpTextWeight
33
+ }
34
+
35
+ const props = withDefaults(defineProps<Props>(), {
36
+ size: 'md',
37
+ tag: 'p',
38
+ weight: 400,
39
+ })
40
+
41
+ const weightList = {
42
+ 400: 'normal',
43
+ 500: 'medium',
44
+ 600: 'semibold',
45
+ 700: 'bold',
46
+ }
47
+
48
+ const dynamicClasses = computed(() => [
49
+ `cpText--${props.size}`,
50
+ `cpText--is${capitalizeFirstLetter(weightList[props.weight])}`,
51
+ ])
52
+
53
+ defineOptions({
54
+ inheritAttrs: false,
55
+ })
56
+ </script>
57
+
58
+ <style lang="scss">
59
+ .cpText {
60
+ &--xs {
61
+ font-size: var(--cp-text-size-xs);
62
+ line-height: var(--cp-line-height-xs);
63
+ }
64
+
65
+ &--sm {
66
+ font-size: var(--cp-text-size-sm);
67
+ line-height: var(--cp-line-height-sm);
68
+ }
69
+
70
+ &--md {
71
+ font-size: var(--cp-text-size-md);
72
+ line-height: var(--cp-line-height-md);
73
+ }
74
+
75
+ &--lg {
76
+ font-size: var(--cp-text-size-lg);
77
+ line-height: var(--cp-line-height-lg);
78
+ }
79
+
80
+ &--xl {
81
+ font-size: var(--cp-text-size-xl);
82
+ line-height: var(--cp-line-height-xl);
83
+ }
84
+
85
+ &--2xl {
86
+ font-size: var(--cp-text-size-2xl);
87
+ line-height: var(--cp-line-height-2xl);
88
+ }
89
+
90
+ &--3xl {
91
+ font-size: var(--cp-text-size-3xl);
92
+ line-height: var(--cp-line-height-3xl);
93
+ }
94
+
95
+ &--4xl {
96
+ font-size: var(--cp-text-size-4xl);
97
+ line-height: var(--cp-line-height-4xl);
98
+ }
99
+
100
+ &--5xl {
101
+ font-size: var(--cp-text-size-5xl);
102
+ line-height: var(--cp-line-height-5xl);
103
+ }
104
+
105
+ &--6xl {
106
+ font-size: var(--cp-text-size-6xl);
107
+ line-height: var(--cp-line-height-6xl);
108
+ }
109
+
110
+ &--7xl {
111
+ font-size: var(--cp-text-size-7xl);
112
+ line-height: var(--cp-line-height-7xl);
113
+ }
114
+
115
+ &--8xl {
116
+ font-size: var(--cp-text-size-8xl);
117
+ line-height: var(--cp-line-height-8xl);
118
+ }
119
+
120
+ &--9xl {
121
+ font-size: var(--cp-text-size-9xl);
122
+ line-height: var(--cp-line-height-9xl);
123
+ }
124
+
125
+ &--isNormal {
126
+ font-weight: 400;
127
+ }
128
+
129
+ &--isMedium {
130
+ font-weight: 500;
131
+ }
132
+
133
+ &--isSemibold {
134
+ font-weight: 600;
135
+ }
136
+
137
+ &--isBold {
138
+ font-weight: 700;
139
+ }
140
+ }
141
+ </style>
@@ -92,7 +92,7 @@ interface Message {
92
92
  summary: string
93
93
  }
94
94
 
95
- onMounted(() => ToastEventBus.on('add', handleToastAdded))
95
+ onMounted(() => ToastEventBus.on('add', (payload: unknown) => handleToastAdded(payload as Message)))
96
96
 
97
97
  const displayTimer = (message: Message) => message.showTimer && message.life !== undefined
98
98
 
@@ -1,47 +1,50 @@
1
1
  <template>
2
- <transition name="expand" @enter="enter" @after-enter="afterEnter" @leave="leave">
2
+ <transition name="expand" @after-enter="afterEnter" @enter="enter" @leave="leave">
3
3
  <slot />
4
4
  </transition>
5
5
  </template>
6
6
 
7
7
  <script setup lang="ts">
8
- const afterEnter = (element: HTMLElement): void => {
9
- element.style.height = `auto`
8
+ const afterEnter = (element: Element) => {
9
+ const el = element as HTMLElement
10
+ el.style.height = `auto`
10
11
  }
11
12
 
12
- const enter = (element: HTMLElement): void => {
13
- const { width } = getComputedStyle(element)
13
+ const enter = (element: Element) => {
14
+ const el = element as HTMLElement
15
+ const { width } = getComputedStyle(el)
14
16
 
15
- element.style.width = width
16
- element.style.position = `absolute`
17
- element.style.visibility = `hidden`
18
- element.style.height = `auto`
17
+ el.style.width = width
18
+ el.style.position = `absolute`
19
+ el.style.visibility = `hidden`
20
+ el.style.height = `auto`
19
21
 
20
- const { height } = getComputedStyle(element)
22
+ const { height } = getComputedStyle(el)
21
23
 
22
- element.style.width = ''
23
- element.style.position = ''
24
- element.style.visibility = ''
25
- element.style.height = '0'
24
+ el.style.width = ''
25
+ el.style.position = ''
26
+ el.style.visibility = ''
27
+ el.style.height = '0'
26
28
 
27
29
  // Force repaint to make sure the
28
30
  // animation is triggered correctly.
29
31
 
30
32
  // @typescript-eslint/no-unused-expressions
31
- void getComputedStyle(element).height
33
+ void getComputedStyle(el).height
32
34
 
33
- requestAnimationFrame(() => (element.style.height = height))
35
+ requestAnimationFrame(() => (el.style.height = height))
34
36
  }
35
37
 
36
- const leave = (element: HTMLElement): void => {
37
- const { height } = getComputedStyle(element)
38
+ const leave = (element: Element): void => {
39
+ const el = element as HTMLElement
40
+ const { height } = getComputedStyle(el)
38
41
 
39
- element.style.height = height
42
+ el.style.height = height
40
43
 
41
44
  // Force repaint to make sure the
42
45
  // animation is triggered correctly.
43
46
  requestAnimationFrame(() => {
44
- element.style.height = '0'
47
+ el.style.height = '0'
45
48
  })
46
49
  }
47
50
  </script>
@@ -46,6 +46,7 @@ import CpTable from './CpTable.vue'
46
46
  import CpTableColumnEditor from './CpTableColumnEditor.vue'
47
47
  import CpTabs from './CpTabs.vue'
48
48
  import CpTelInput from './CpTelInput.vue'
49
+ import CpText from './CpText.vue'
49
50
  import CpTextarea from './CpTextarea.vue'
50
51
  import CpToast from './CpToast.vue'
51
52
  import CpTooltip from './CpTooltip.vue'
@@ -87,6 +88,7 @@ const Components = {
87
88
  CpAlert,
88
89
  CpLoader,
89
90
  CpInput,
91
+ CpText,
90
92
  CpTextarea,
91
93
  CpSelect,
92
94
  CpSelectMenu,
@@ -127,6 +127,7 @@
127
127
  </template>
128
128
 
129
129
  <script lang="ts">
130
+ // @ts-nocheck — legacy Options API bundle; excluded from strict type-checking until a typed rewrite.
130
131
  import { DateTime, Info } from 'luxon'
131
132
  import { useId } from 'vue'
132
133
 
@@ -1,9 +1,11 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3'
1
+ import type { Args, Meta, StoryObj } from '@storybook/vue3-vite'
2
2
 
3
3
  import BaseInputLabel from '@/components/BaseInputLabel.vue'
4
4
 
5
+ import { docCellStyle, docLabelStyle, docRowWrapStyle } from '@/stories/documentationStyles'
6
+
5
7
  const meta = {
6
- title: 'Form/BaseInputLabel',
8
+ title: 'Atoms/BaseInputLabel',
7
9
  component: BaseInputLabel,
8
10
  argTypes: {
9
11
  isInvalid: {
@@ -16,20 +18,45 @@ const meta = {
16
18
  export default meta
17
19
  type Story = StoryObj<typeof meta>
18
20
 
21
+ /**
22
+ * Default label used above form controls. Use the controls to experiment
23
+ * with each prop in isolation.
24
+ */
19
25
  export const Default: Story = {
20
- args: {
21
- isInvalid: false,
22
- },
23
- render: (args) => ({
26
+ args: { isInvalid: false },
27
+ render: (args: Args) => ({
24
28
  components: { BaseInputLabel },
25
29
  setup() {
26
30
  return { args }
27
31
  },
28
32
  template: `
29
33
  <div class="baseInputLabel-story">
30
- <BaseInputLabel v-bind="args">
31
- Default Label
32
- </BaseInputLabel>
34
+ <BaseInputLabel v-bind="args">Default Label</BaseInputLabel>
35
+ </div>
36
+ `,
37
+ }),
38
+ }
39
+
40
+ /**
41
+ * Default and invalid states side by side.
42
+ */
43
+ export const States: Story = {
44
+ parameters: { controls: { disable: true } },
45
+ render: () => ({
46
+ components: { BaseInputLabel },
47
+ setup() {
48
+ return { docCellStyle, docLabelStyle, docRowWrapStyle }
49
+ },
50
+ template: `
51
+ <div :style="docRowWrapStyle">
52
+ <div :style="docCellStyle">
53
+ <span :style="docLabelStyle">Default</span>
54
+ <BaseInputLabel>Default Label</BaseInputLabel>
55
+ </div>
56
+ <div :style="docCellStyle">
57
+ <span :style="docLabelStyle">Invalid</span>
58
+ <BaseInputLabel :is-invalid="true">Invalid Label</BaseInputLabel>
59
+ </div>
33
60
  </div>
34
61
  `,
35
62
  }),
@@ -0,0 +1,9 @@
1
+ import { Meta, Title, Description, Stories } from '@storybook/addon-docs/blocks'
2
+
3
+ import * as ColorsStories from './Colors.stories'
4
+
5
+ <Meta of={ColorsStories} />
6
+
7
+ <Title />
8
+ <Description />
9
+ <Stories />