@citizenplane/pimp 10.6.2 → 10.7.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@citizenplane/pimp",
3
- "version": "10.6.2",
3
+ "version": "10.7.0",
4
4
  "scripts": {
5
5
  "dev": "storybook dev -p 8080",
6
6
  "build-storybook": "storybook build --output-dir ./docs",
@@ -41,7 +41,8 @@
41
41
  "primevue": "^4.5.4",
42
42
  "vue": "^3.5.27",
43
43
  "vue-bind-once": "^0.2.1",
44
- "vue-tel-input": "^9.5.0"
44
+ "vue-tel-input": "^9.5.0",
45
+ "web-haptics": "^0.0.6"
45
46
  },
46
47
  "devDependencies": {
47
48
  "@babel/core": "^7.28.6",
@@ -8,6 +8,7 @@
8
8
  role="button"
9
9
  tabindex="0"
10
10
  :type="type"
11
+ @click="handleClick"
11
12
  >
12
13
  <span class="cpButton__body">
13
14
  <span v-if="isLoading" class="cpButton__loader"><cp-loader :color="Colors.NEUTRAL" /></span>
@@ -24,8 +25,10 @@
24
25
 
25
26
  <script setup lang="ts">
26
27
  import { computed, useSlots } from 'vue'
28
+ import { useWebHaptics } from 'web-haptics/vue'
27
29
 
28
30
  import { ButtonAppearances, ButtonTags, ButtonTypes } from '@/constants/Button'
31
+ import { Haptics } from '@/constants/Hapitcs'
29
32
 
30
33
  import CpLoader from '@/components/CpLoader.vue'
31
34
 
@@ -36,6 +39,7 @@ interface Props {
36
39
  appearance?: ButtonAppearances
37
40
  color?: Colors
38
41
  disabled?: boolean
42
+ enableHaptics?: boolean
39
43
  isLoading?: boolean
40
44
  isSquare?: boolean
41
45
  size?: Sizes
@@ -46,15 +50,13 @@ interface Props {
46
50
  const props = withDefaults(defineProps<Props>(), {
47
51
  appearance: ButtonAppearances.DEFAULT,
48
52
  color: undefined,
49
- disabled: false,
50
53
  tag: ButtonTags.BUTTON,
51
54
  type: ButtonTypes.BUTTON,
52
- isLoading: false,
53
- isSquare: false,
54
55
  size: Sizes.MD,
55
56
  })
56
57
 
57
58
  const slots = useSlots()
59
+ const { trigger } = useWebHaptics()
58
60
 
59
61
  const capitalizedAppearance = computed(() => capitalizeFirstLetter(props.appearance))
60
62
 
@@ -81,6 +83,12 @@ const dynamicClasses = computed(() => {
81
83
  },
82
84
  ]
83
85
  })
86
+
87
+ const handleClick = () => {
88
+ if (props.enableHaptics) {
89
+ trigger(Haptics.RIGID)
90
+ }
91
+ }
84
92
  </script>
85
93
 
86
94
  <style lang="scss">
@@ -30,6 +30,9 @@
30
30
 
31
31
  <script setup lang="ts">
32
32
  import { computed, useId } from 'vue'
33
+ import { useWebHaptics } from 'web-haptics/vue'
34
+
35
+ import { Haptics } from '@/constants/Hapitcs'
33
36
 
34
37
  import CpTooltip from '@/components/CpTooltip.vue'
35
38
 
@@ -40,6 +43,7 @@ interface Props {
40
43
  autofocus?: boolean
41
44
  color?: string
42
45
  disabled?: boolean
46
+ enableHaptics?: boolean
43
47
  groupName?: string
44
48
  helper?: string
45
49
  isRequired?: boolean
@@ -68,6 +72,8 @@ const props = withDefaults(defineProps<Props>(), {
68
72
 
69
73
  const emit = defineEmits<Emits>()
70
74
 
75
+ const { trigger } = useWebHaptics()
76
+
71
77
  const switchUniqueId = useId()
72
78
 
73
79
  const capitalizedColor = computed(() => {
@@ -87,6 +93,10 @@ const computedClasses = computed(() => {
87
93
  })
88
94
 
89
95
  const handleClick = (value: boolean): void => {
96
+ if (props.enableHaptics) {
97
+ trigger(Haptics.SOFT)
98
+ }
99
+
90
100
  emit('update:modelValue', !value)
91
101
  }
92
102
  </script>
@@ -62,13 +62,18 @@
62
62
 
63
63
  <script setup lang="ts">
64
64
  import Toast from 'primevue/toast'
65
+ import ToastEventBus from 'primevue/toasteventbus'
66
+ import { onMounted } from 'vue'
67
+ import { useWebHaptics } from 'web-haptics/vue'
65
68
 
66
69
  import { CpToastTypes } from '@/constants/CpToastTypes'
70
+ import { Haptics } from '@/constants/Hapitcs'
67
71
 
68
72
  import { capitalizeFirstLetter } from '@/helpers'
69
73
 
70
74
  interface Message {
71
75
  detail?: string
76
+ enableHaptics?: boolean
72
77
  life?: number
73
78
  primaryAction?: {
74
79
  label: string
@@ -87,6 +92,8 @@ interface Message {
87
92
  summary: string
88
93
  }
89
94
 
95
+ onMounted(() => ToastEventBus.on('add', handleToastAdded))
96
+
90
97
  const displayTimer = (message: Message) => message.showTimer && message.life !== undefined
91
98
 
92
99
  const getDynamicClass = (severity: string) => `cpToast--is${capitalizeFirstLetter(severity)}`
@@ -129,6 +136,28 @@ const handleActionClick = (onClick: VoidFunction, closeCallback: VoidFunction) =
129
136
  }
130
137
 
131
138
  const handleMouse = () => true
139
+
140
+ const { trigger } = useWebHaptics()
141
+
142
+ const resolveHapticLevel = (severity: CpToastTypes) => {
143
+ switch (severity) {
144
+ case CpToastTypes.SUCCESS:
145
+ return Haptics.SUCCESS
146
+ case CpToastTypes.WARNING:
147
+ return Haptics.WARNING
148
+ case CpToastTypes.ERROR:
149
+ return Haptics.ERROR
150
+ case CpToastTypes.INFO:
151
+ default:
152
+ return Haptics.SOFT
153
+ }
154
+ }
155
+
156
+ const handleToastAdded = (message: Message) => {
157
+ if (message.enableHaptics) {
158
+ trigger(resolveHapticLevel(message.severity))
159
+ }
160
+ }
132
161
  </script>
133
162
 
134
163
  <style lang="scss">
@@ -0,0 +1,13 @@
1
+ export const Haptics = {
2
+ SUCCESS: 'success',
3
+ WARNING: 'warning',
4
+ ERROR: 'error',
5
+ LIGHT: 'light',
6
+ MEDIUM: 'medium',
7
+ HEAVY: 'heavy',
8
+ SOFT: 'soft',
9
+ RIGID: 'rigid',
10
+ SELECTION: 'selection',
11
+ NUDGE: 'nudge',
12
+ BUZZ: 'buzz',
13
+ }
@@ -112,6 +112,24 @@ export const WithIcons: Story = {
112
112
  }),
113
113
  }
114
114
 
115
+ export const WithHaptics: Story = {
116
+ args: { ...Default.args, enableHaptics: true },
117
+ render: (args) => ({
118
+ components: { CpButton },
119
+ setup() {
120
+ const onClick = () => {
121
+ console.log('Button clicked')
122
+ }
123
+ return { args, onClick }
124
+ },
125
+ template: `
126
+ <CpButton v-bind="args" @click="onClick">
127
+ Button with haptics
128
+ </CpButton>
129
+ `,
130
+ }),
131
+ }
132
+
115
133
  export const Loading: Story = {
116
134
  args: { ...Default.args, isLoading: true },
117
135
  render: defaultRender,
@@ -83,6 +83,28 @@ export const Default: Story = {
83
83
  }),
84
84
  }
85
85
 
86
+ export const WithHaptics: Story = {
87
+ args: {
88
+ ...Default.args,
89
+ enableHaptics: true,
90
+ },
91
+ render: (args) => ({
92
+ components: { CpSwitch },
93
+ setup() {
94
+ const value = ref(false)
95
+ return { args, value }
96
+ },
97
+ template: `
98
+ <div style="padding: 20px;">
99
+ <CpSwitch
100
+ v-model="value"
101
+ v-bind="args"
102
+ />
103
+ </div>
104
+ `,
105
+ }),
106
+ }
107
+
86
108
  export const Disabled: Story = {
87
109
  args: {
88
110
  ...Default.args,
@@ -19,6 +19,7 @@ const meta: Meta<typeof CpToast> = {
19
19
  args: {
20
20
  position: 'top-right',
21
21
  group: undefined,
22
+ enableHaptics: false,
22
23
  },
23
24
  }
24
25
 
@@ -36,6 +37,7 @@ export const Default: Story = {
36
37
  severity: CpToastTypes.SECONDARY,
37
38
  summary: `Hello i'm a cpToast !`,
38
39
  detail: 'This is a cpToast description.',
40
+ enableHaptics: true,
39
41
  }
40
42
 
41
43
  const notifySecondary = () => toast.add({ ...baseOptions })