@citizenplane/pimp 10.6.1 → 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/dist/pimp.es.js +6069 -5871
- package/dist/pimp.umd.js +44 -44
- package/dist/style.css +1 -1
- package/package.json +3 -2
- package/src/components/CpButton.vue +11 -3
- package/src/components/CpMenuItem.vue +1 -0
- package/src/components/CpSwitch.vue +10 -0
- package/src/components/CpTable.vue +6 -133
- package/src/components/CpToast.vue +29 -0
- package/src/constants/Hapitcs.ts +13 -0
- package/src/stories/CpButton.stories.ts +18 -0
- package/src/stories/CpSwitch.stories.ts +22 -0
- package/src/stories/CpToast.stories.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@citizenplane/pimp",
|
|
3
|
-
"version": "10.
|
|
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>
|
|
@@ -695,75 +695,15 @@ defineExpose({ hideContextualMenu, resetPagination, currentRowData })
|
|
|
695
695
|
}
|
|
696
696
|
|
|
697
697
|
&__row {
|
|
698
|
-
&--body:not(:last-of-type)
|
|
699
|
-
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
&--body:has(+ #{&}--isFullWidth),
|
|
703
|
-
&--isFullWidth:has(+ .cpTable__row:hover) {
|
|
704
|
-
box-shadow: none !important;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
&--isFullWidth:has(+ .cpTable__row:is(:hover, :focus, :focus-within), + .cpTable__row--isSelected)
|
|
708
|
-
+ .cpTable__row::after {
|
|
709
|
-
box-shadow: none !important;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
&--isFullWidth {
|
|
713
|
-
border-top: none;
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
&--body:not(#{&}--isFullWidth):is(:hover, :focus, :focus-within) {
|
|
717
|
-
position: relative;
|
|
718
|
-
transition: background-color 100ms ease-in-out;
|
|
698
|
+
&--body:not(:last-of-type) {
|
|
699
|
+
border-bottom: var(--cp-dimensions-0_25) solid var(--cp-border-soft);
|
|
719
700
|
}
|
|
720
701
|
|
|
721
|
-
&--body:not(#{&}--isFullWidth):
|
|
702
|
+
&--body:not(#{&}--isFullWidth):not(#{&}--isSelected):hover,
|
|
703
|
+
&--body:not(#{&}--isFullWidth):not(#{&}--isSelected):focus,
|
|
704
|
+
&--body:not(#{&}--isFullWidth):not(#{&}--isSelected):focus-within {
|
|
722
705
|
background-color: var(--cp-background-primary-hover);
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
&--body:not(#{&}--isFullWidth):not(
|
|
726
|
-
:has(+ #{&}--isSelected),
|
|
727
|
-
:has(+ .cpTable__row:is(:hover, :focus, :focus-within))
|
|
728
|
-
):is(:hover, :focus, :focus-within)::after {
|
|
729
|
-
content: '';
|
|
730
|
-
position: absolute;
|
|
731
|
-
inset: 0;
|
|
732
|
-
border-radius: var(--cp-radius-md);
|
|
733
|
-
box-shadow: inset 0 0 0 var(--cp-dimensions-0_25) var(--cp-border-soft);
|
|
734
|
-
pointer-events: none;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
&--body:not(#{&}--isFullWidth):hover td:first-child,
|
|
738
|
-
&--body:not(#{&}--isFullWidth):focus td:first-child,
|
|
739
|
-
&--body:not(#{&}--isFullWidth):focus-within td:first-child {
|
|
740
|
-
border-top-left-radius: var(--cp-radius-md);
|
|
741
|
-
border-bottom-left-radius: var(--cp-radius-md);
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
&--body:not(#{&}--isFullWidth):hover td:last-child,
|
|
745
|
-
&--body:not(#{&}--isFullWidth):focus td:last-child,
|
|
746
|
-
&--body:not(#{&}--isFullWidth):focus-within td:last-child {
|
|
747
|
-
border-top-right-radius: var(--cp-radius-md);
|
|
748
|
-
border-bottom-right-radius: var(--cp-radius-md);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
&--body:not(#{&}--isFullWidth):has(.cpTable__cell--isOptions:not([style*='display: none'])):hover
|
|
752
|
-
td:nth-last-child(2),
|
|
753
|
-
&--body:not(#{&}--isFullWidth):has(.cpTable__cell--isOptions:not([style*='display: none'])):focus
|
|
754
|
-
td:nth-last-child(2),
|
|
755
|
-
&--body:not(#{&}--isFullWidth):has(.cpTable__cell--isOptions:not([style*='display: none'])):focus-within
|
|
756
|
-
td:nth-last-child(2) {
|
|
757
|
-
border-top-right-radius: 0;
|
|
758
|
-
border-bottom-right-radius: 0;
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
&--body:not(#{&}--isFullWidth):has(.cpTable__cell--isOptions[style*='display: none']):hover td:nth-last-child(2),
|
|
762
|
-
&--body:not(#{&}--isFullWidth):has(.cpTable__cell--isOptions[style*='display: none']):focus td:nth-last-child(2),
|
|
763
|
-
&--body:not(#{&}--isFullWidth):has(.cpTable__cell--isOptions[style*='display: none']):focus-within
|
|
764
|
-
td:nth-last-child(2) {
|
|
765
|
-
border-top-right-radius: var(--cp-radius-md);
|
|
766
|
-
border-bottom-right-radius: var(--cp-radius-md);
|
|
706
|
+
transition: background-color 100ms ease-in-out;
|
|
767
707
|
}
|
|
768
708
|
|
|
769
709
|
&--body:not(#{&}--isFullWidth):not(#{&}--isSelected):focus,
|
|
@@ -774,8 +714,6 @@ defineExpose({ hideContextualMenu, resetPagination, currentRowData })
|
|
|
774
714
|
&--isFullWidth td {
|
|
775
715
|
padding: var(--cp-spacing-md);
|
|
776
716
|
background-color: var(--cp-background-secondary);
|
|
777
|
-
border-radius: var(--cp-radius-md);
|
|
778
|
-
box-shadow: inset 0 0 0 var(--cp-dimensions-0_25) var(--cp-border-soft);
|
|
779
717
|
}
|
|
780
718
|
|
|
781
719
|
&--isClickable {
|
|
@@ -787,49 +725,6 @@ defineExpose({ hideContextualMenu, resetPagination, currentRowData })
|
|
|
787
725
|
color: var(--cp-text-accent-primary);
|
|
788
726
|
}
|
|
789
727
|
|
|
790
|
-
&--isSelected {
|
|
791
|
-
position: relative;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
&--isSelected:not(:has(+ #{&}--isFullWidth))::after {
|
|
795
|
-
content: '';
|
|
796
|
-
position: absolute;
|
|
797
|
-
inset: 0;
|
|
798
|
-
border-radius: var(--cp-radius-md);
|
|
799
|
-
box-shadow: inset 0 0 0 var(--cp-dimensions-0_25) var(--cp-utility-accent-100);
|
|
800
|
-
pointer-events: none;
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
&--isSelected td:first-child {
|
|
804
|
-
border-top-left-radius: var(--cp-radius-md);
|
|
805
|
-
border-bottom-left-radius: var(--cp-radius-md);
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
&--isSelected td:last-child {
|
|
809
|
-
border-top-right-radius: var(--cp-radius-md);
|
|
810
|
-
border-bottom-right-radius: var(--cp-radius-md);
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
&--isSelected:has(.cpTable__cell--isOptions:not([style*='display: none'])) td:nth-last-child(2) {
|
|
814
|
-
border-top-right-radius: 0;
|
|
815
|
-
border-bottom-right-radius: 0;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
&--isSelected:has(.cpTable__cell--isOptions[style*='display: none']) td:nth-last-child(2) {
|
|
819
|
-
border-top-right-radius: var(--cp-radius-md);
|
|
820
|
-
border-bottom-right-radius: var(--cp-radius-md);
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
&--body:not(#{&}--isFullWidth):is(:hover, :focus, :focus-within),
|
|
824
|
-
&--body:not(#{&}--isFullWidth).cpTable__row--isSelected {
|
|
825
|
-
box-shadow: none !important;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
&--body:not(#{&}--isFullWidth):has(+ #{&}--isSelected),
|
|
829
|
-
&--body:not(#{&}--isFullWidth):has(+ #{&}:is(:hover, :focus, :focus-within)) {
|
|
830
|
-
box-shadow: none !important;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
728
|
&--body td {
|
|
834
729
|
font-size: var(--cp-text-size-sm);
|
|
835
730
|
}
|
|
@@ -873,28 +768,6 @@ defineExpose({ hideContextualMenu, resetPagination, currentRowData })
|
|
|
873
768
|
}
|
|
874
769
|
}
|
|
875
770
|
|
|
876
|
-
&:has(
|
|
877
|
-
.cpTable__row--body:first-of-type:is(:hover, :focus, :focus-within),
|
|
878
|
-
.cpTable__row--body:first-of-type.cpTable__row--isSelected
|
|
879
|
-
) {
|
|
880
|
-
.cpTable__column:after {
|
|
881
|
-
background-color: transparent;
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
&:has(
|
|
886
|
-
.cpTable__row--body:last-of-type:is(:hover, :focus, :focus-within),
|
|
887
|
-
.cpTable__row--body:last-of-type.cpTable__row--isSelected
|
|
888
|
-
) {
|
|
889
|
-
.cpTable__container--hasPagination {
|
|
890
|
-
border-bottom-color: transparent;
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
&__table:has(.cpTable__row--body:first-of-type.cpTable__row--isFullWidth) &__column:after {
|
|
895
|
-
background-color: transparent;
|
|
896
|
-
}
|
|
897
|
-
|
|
898
771
|
&__columnEditor {
|
|
899
772
|
padding-right: calc(var(--cp-spacing-lg) + var(--cp-dimensions-0_5));
|
|
900
773
|
|
|
@@ -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">
|
|
@@ -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 })
|