@citizenplane/pimp 10.2.0 → 10.2.2

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.2.0",
3
+ "version": "10.2.2",
4
4
  "scripts": {
5
5
  "dev": "storybook dev -p 8080",
6
6
  "build-storybook": "storybook build --output-dir ./docs",
@@ -17,6 +17,7 @@
17
17
  --cp-background-solid: var(--cp-colors-grey-900);
18
18
  --cp-background-disabled: var(--cp-colors-grey-50);
19
19
  --cp-background-overlay: rgba(62, 62, 91, 0.86);
20
+ --cp-background-black: var(--cp-colors-black);
20
21
 
21
22
  --cp-background-accent-primary: var(--cp-colors-accent-50);
22
23
  --cp-background-accent-primary-hover: var(--cp-colors-accent-100);
@@ -63,8 +63,6 @@ interface Emits {
63
63
  }
64
64
 
65
65
  interface Props {
66
- autocomplete?: string
67
- disabled?: boolean
68
66
  errorMessage?: string
69
67
  help?: string
70
68
  inputId?: string | null
@@ -73,26 +71,20 @@ interface Props {
73
71
  label?: string
74
72
  mask?: string | Record<string, unknown> | null
75
73
  modelValue?: string | number | boolean
76
- placeholder?: string
77
74
  removeBorder?: boolean
78
- required?: boolean
79
75
  size?: Sizes
80
76
  tooltip?: string
81
- type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url'
82
77
  }
83
78
 
84
79
  const props = withDefaults(defineProps<Props>(), {
85
- autocomplete: '',
86
80
  errorMessage: '',
87
81
  label: '',
88
82
  help: '',
89
83
  inputId: null,
90
84
  mask: null,
91
85
  modelValue: '',
92
- placeholder: '',
93
86
  size: Sizes.MD,
94
87
  tooltip: '',
95
- type: 'text',
96
88
  })
97
89
 
98
90
  const emit = defineEmits<Emits>()
@@ -131,7 +123,7 @@ const cpInputContainer = ref<HTMLDivElement | null>(null)
131
123
  const isDisabled = computed(() => checkAttribute('disabled'))
132
124
  const isRequired = computed(() => checkAttribute('required'))
133
125
 
134
- const isEmail = computed(() => props.type === 'email')
126
+ const isEmail = computed(() => attrs['type'] === 'email')
135
127
 
136
128
  const dynamicClasses = computed(() => {
137
129
  return [
@@ -1,31 +1,67 @@
1
1
  <template>
2
- <v-tooltip :aria-id="ariaId" class="cpTooltip" :container="false" :disabled :distance>
2
+ <v-tooltip
3
+ :aria-id="ariaId"
4
+ class="cpTooltip"
5
+ :class="dynamicTooltipClasses"
6
+ :container="false"
7
+ :disabled
8
+ :distance
9
+ :placement
10
+ >
3
11
  <slot />
4
12
  <template #popper>
5
- <span v-if="content">
6
- {{ content }}
7
- </span>
8
- <slot v-else name="content" />
13
+ <div class="cpTooltip__wrapper">
14
+ <div class="cpTooltip__content">
15
+ <span v-if="content">
16
+ {{ content }}
17
+ </span>
18
+ <slot v-else name="content" />
19
+ </div>
20
+ <template v-if="hasSubcontent">
21
+ <hr class="cpTooltip__separator" />
22
+ <div class="cpTooltip__subcontent">
23
+ <span v-if="subcontent">{{ subcontent }}</span>
24
+ <slot v-else name="subcontent" />
25
+ </div>
26
+ </template>
27
+ </div>
9
28
  </template>
10
29
  </v-tooltip>
11
30
  </template>
12
31
 
13
32
  <script setup lang="ts">
14
33
  import { Tooltip as VTooltip } from 'floating-vue'
15
- import { useId } from 'vue'
34
+ import { useId, useSlots, computed } from 'vue'
35
+
36
+ import { Colors } from '@/constants'
37
+ import { capitalizeFirstLetter } from '@/helpers'
38
+
39
+ type TooltipColors = Colors.ACCENT | Colors.NEUTRAL
40
+ type Placement = 'top' | 'right' | 'bottom' | 'left'
16
41
 
17
42
  interface Props {
43
+ color?: TooltipColors
18
44
  content?: string
19
45
  disabled?: boolean
20
46
  distance?: number
47
+ placement?: Placement
48
+ subcontent?: string
21
49
  }
22
50
 
23
- withDefaults(defineProps<Props>(), {
51
+ const props = withDefaults(defineProps<Props>(), {
24
52
  content: '',
25
53
  distance: 8,
54
+ color: Colors.ACCENT,
55
+ placement: undefined,
56
+ subcontent: '',
26
57
  })
27
58
 
28
59
  const ariaId = useId()
60
+ const slots = useSlots()
61
+
62
+ const hasSubcontent = computed(() => !!(props.subcontent || slots.subcontent))
63
+
64
+ const dynamicTooltipClasses = computed(() => [`cpTooltip--is${capitalizeFirstLetter(props.color)}`])
29
65
  </script>
30
66
 
31
67
  <style lang="scss">
@@ -36,13 +72,51 @@ const ariaId = useId()
36
72
  .v-popper__inner {
37
73
  padding: var(--cp-spacing-md) var(--cp-spacing-lg);
38
74
  border-radius: var(--cp-radius-md);
39
- background-color: var(--cp-background-accent-solid);
75
+ background-color: var(--cp-tooltip-bg);
40
76
  font-size: var(--cp-text-size-xs);
41
77
  line-height: var(--cp-line-height-xs);
78
+ max-width: fn.px-to-rem(300);
79
+ text-align: left;
80
+ font-weight: 400;
81
+ }
82
+
83
+ .cpTooltip__content {
84
+ color: var(--cp-tooltip-content-text);
85
+ }
86
+
87
+ .cpTooltip__wrapper {
88
+ display: flex;
89
+ flex-direction: column;
90
+ align-items: flex-start;
91
+ }
92
+
93
+ .cpTooltip__separator {
94
+ border: none;
95
+ border-top: 1px solid var(--cp-colors-white);
96
+ opacity: 0.5;
97
+ width: 100%;
98
+ margin: var(--cp-spacing-md) 0;
99
+ }
100
+
101
+ .cpTooltip__subcontent {
102
+ font-style: italic;
103
+ color: var(--cp-tooltip-subcontent-text);
42
104
  }
43
105
 
44
106
  .v-popper__arrow-outer {
45
- border-color: var(--cp-background-accent-solid);
107
+ border-color: var(--cp-tooltip-bg);
108
+ }
109
+
110
+ &.cpTooltip--isAccent {
111
+ --cp-tooltip-bg: var(--cp-background-accent-solid);
112
+ --cp-tooltip-content-text: var(--cp-foreground-white);
113
+ --cp-tooltip-subcontent-text: var(--cp-foreground-white);
114
+ }
115
+
116
+ &.cpTooltip--isNeutral {
117
+ --cp-tooltip-bg: color-mix(in srgb, var(--cp-background-black) 80%, transparent);
118
+ --cp-tooltip-content-text: var(--cp-foreground-white);
119
+ --cp-tooltip-subcontent-text: color-mix(in srgb, var(--cp-foreground-white) 70%, transparent);
46
120
  }
47
121
  }
48
122
  </style>
@@ -10,6 +10,15 @@ const meta = {
10
10
  control: 'text',
11
11
  description: 'The content to display in the tooltip',
12
12
  },
13
+ subcontent: {
14
+ control: 'text',
15
+ description: 'Optional secondary content',
16
+ },
17
+ color: {
18
+ control: 'select',
19
+ options: ['accent', 'neutral'],
20
+ description: 'The color variant',
21
+ },
13
22
  placement: {
14
23
  control: 'select',
15
24
  options: ['top', 'right', 'bottom', 'left'],
@@ -101,6 +110,50 @@ export const WithHTMLContent: Story = {
101
110
  }),
102
111
  }
103
112
 
113
+ export const WithSubcontentSlot: Story = {
114
+ args: {
115
+ content: 'Main content',
116
+ placement: 'top',
117
+ },
118
+ render: (args) => ({
119
+ components: { CpTooltip },
120
+ setup() {
121
+ return { args }
122
+ },
123
+ template: `
124
+ <div style="padding: 100px; text-align: center;">
125
+ <CpTooltip v-bind="args">
126
+ <button type="button">Hover me</button>
127
+ <template #subcontent>
128
+ <p>Optional subcontent via slot, it can be a long text to see how it works and includes <b>HTML</b> <u>tags</u></p>
129
+ </template>
130
+ </CpTooltip>
131
+ </div>
132
+ `,
133
+ }),
134
+ }
135
+
136
+ export const WithSubcontentProp: Story = {
137
+ args: {
138
+ content: 'Main content',
139
+ subcontent: 'Optional subcontent via prop',
140
+ placement: 'top',
141
+ },
142
+ render: (args) => ({
143
+ components: { CpTooltip },
144
+ setup() {
145
+ return { args }
146
+ },
147
+ template: `
148
+ <div style="padding: 100px; text-align: center;">
149
+ <CpTooltip v-bind="args">
150
+ <button type="button">Hover me</button>
151
+ </CpTooltip>
152
+ </div>
153
+ `,
154
+ }),
155
+ }
156
+
104
157
  export const Disabled: Story = {
105
158
  args: {
106
159
  disabled: true,