@volverjs/ui-vue 0.0.9-beta.4 → 0.0.9-beta.6

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 (39) hide show
  1. package/README.md +2 -2
  2. package/auto-imports.d.ts +2 -0
  3. package/dist/components/VvAlertGroup/VvAlertGroup.vue.d.ts +1 -1
  4. package/dist/components/VvCombobox/VvCombobox.es.js +15 -5
  5. package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
  6. package/dist/components/VvCombobox/VvCombobox.vue.d.ts +22 -10
  7. package/dist/components/VvCombobox/index.d.ts +15 -6
  8. package/dist/components/VvDropdown/VvDropdown.es.js +1 -1
  9. package/dist/components/VvDropdown/VvDropdown.umd.js +1 -1
  10. package/dist/components/VvDropdown/VvDropdown.vue.d.ts +4 -4
  11. package/dist/components/index.es.js +15 -5
  12. package/dist/components/index.umd.js +1 -1
  13. package/dist/composables/alert/useAlert.d.ts +27 -0
  14. package/dist/composables/index.d.ts +2 -0
  15. package/dist/composables/index.es.js +81 -0
  16. package/dist/composables/index.umd.js +1 -0
  17. package/dist/constants.d.ts +10 -0
  18. package/dist/icons.es.js +3 -3
  19. package/dist/icons.umd.js +1 -1
  20. package/dist/stories/AccordionGroup/AccordionGroup.stories.d.ts +1 -1
  21. package/dist/stories/AccordionGroup/AccordionGroupSlots.stories.d.ts +7 -7
  22. package/dist/stories/AlertGroup/AlertGroupSlots.stories.d.ts +2 -2
  23. package/dist/stories/AlertGroup/AlertGroupWithComposable.stories.d.ts +6 -0
  24. package/dist/stories/Combobox/Combobox.settings.d.ts +106 -12
  25. package/package.json +16 -8
  26. package/src/assets/icons/detailed.json +1 -1
  27. package/src/assets/icons/normal.json +1 -1
  28. package/src/assets/icons/simple.json +1 -1
  29. package/src/components/VvCombobox/VvCombobox.vue +2 -3
  30. package/src/components/VvCombobox/index.ts +11 -0
  31. package/src/components/VvDropdown/VvDropdown.vue +1 -1
  32. package/src/composables/alert/useAlert.ts +103 -0
  33. package/src/composables/index.ts +3 -0
  34. package/src/constants.ts +21 -0
  35. package/src/stories/AlertGroup/AlertGroup.test.ts +13 -0
  36. package/src/stories/AlertGroup/AlertGroupSlots.stories.ts +3 -3
  37. package/src/stories/AlertGroup/AlertGroupWithComposable.stories.ts +118 -0
  38. package/src/stories/Combobox/Combobox.settings.ts +107 -1
  39. package/src/types/alert.d.ts +20 -0
@@ -334,7 +334,7 @@
334
334
  autoPlacement: propsDefaults.value.autoPlacement,
335
335
  arrow: propsDefaults.value.arrow,
336
336
  autofocusFirst: searchable.value
337
- ? false
337
+ ? true
338
338
  : propsDefaults.value.autofocusFirst,
339
339
  triggerWidth: propsDefaults.value.triggerWidth,
340
340
  modifiers: propsDefaults.value.dropdownModifiers,
@@ -390,7 +390,6 @@
390
390
  <slot name="dropdown::before" />
391
391
  <input
392
392
  v-if="searchable"
393
- v-show="expanded"
394
393
  :id="hasSearchId"
395
394
  ref="inputSearchEl"
396
395
  v-model="searchText"
@@ -579,7 +578,7 @@
579
578
  <!-- Close button if dropdown custom position is enabled and floating-ui disabled -->
580
579
  <VvButton
581
580
  v-if="dropdownEl?.customPosition"
582
- label="Close"
581
+ :label="closeLabel"
583
582
  modifiers="secondary"
584
583
  @click="dropdownEl.hide()"
585
584
  />
@@ -40,6 +40,13 @@ export const VvComboboxProps = {
40
40
  ...UnselectableProps,
41
41
  ...DropdownProps,
42
42
  ...LabelProps,
43
+ /**
44
+ * Dropdown show / hide transition name
45
+ */
46
+ transitionName: {
47
+ type: String,
48
+ default: 'vv-dropdown--mobile-fade-block',
49
+ },
43
50
  /**
44
51
  * modelValue can be a string, number, boolean, object or array of string, number, boolean, object
45
52
  */
@@ -71,6 +78,10 @@ export const VvComboboxProps = {
71
78
  * Label for deselected option hint
72
79
  */
73
80
  deselectHintLabel: { type: String, default: 'Press enter to remove' },
81
+ /**
82
+ * Label close button
83
+ */
84
+ closeLabel: { type: String, default: 'Close' },
74
85
  /**
75
86
  * Select input placeholder
76
87
  */
@@ -318,7 +318,7 @@
318
318
  }
319
319
  return [
320
320
  ...element.querySelectorAll(
321
- 'a[href], button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])',
321
+ 'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])',
322
322
  ),
323
323
  ].filter(
324
324
  (el) =>
@@ -0,0 +1,103 @@
1
+ import {
2
+ DEFAULT_ALERT_AUTO_CLOSE,
3
+ DEFAULT_ALERT_DISMISSABLE,
4
+ DEFAULT_ALERT_GROUP,
5
+ DEFAULT_ALERT_MODIFIERS,
6
+ DEFAULT_ALERT_INFO_ICON,
7
+ DefaultAlertIconMap,
8
+ } from '@/constants'
9
+ import type { Alert, AlertModifiers } from '@/types/alert'
10
+
11
+ const groups = reactive(
12
+ new Map<string, Map<string, Alert>>([
13
+ [DEFAULT_ALERT_GROUP, new Map<string, Alert>()],
14
+ ]),
15
+ )
16
+
17
+ /**
18
+ * @description Composable to access alert groups, alerts and functions to add, remove and get alerts by group.
19
+ * @example
20
+ * const { groups, alerts, addAlert, removeAlert, getAlerts } = useAlert()
21
+ * addAlert({
22
+ * title: 'Success!',
23
+ * modifiers: 'success',
24
+ * })
25
+ *
26
+ * `<vv-alert-group :items="alerts" :onClose="removeAlert" />`
27
+ *
28
+ * @returns {
29
+ * alerts: ComputedRef<Alert[]> reactive list of alerts default group,
30
+ * groups: ReactiveRef<Map<string, Map<string, Alert>>>,
31
+ * addAlert: Function to add alert,
32
+ * removeAlert: Function to remove alert,
33
+ * getAlerts: Function to get alerts by group
34
+ * }
35
+ */
36
+ export const useAlert = () => {
37
+ const addAlert = (
38
+ {
39
+ id = crypto.randomUUID(),
40
+ group = DEFAULT_ALERT_GROUP,
41
+ title,
42
+ icon = DEFAULT_ALERT_INFO_ICON,
43
+ content,
44
+ footer,
45
+ modifiers = DEFAULT_ALERT_MODIFIERS,
46
+ dismissable = DEFAULT_ALERT_DISMISSABLE,
47
+ autoClose = DEFAULT_ALERT_AUTO_CLOSE,
48
+ } = {} as Partial<Alert>,
49
+ ) => {
50
+ if (!groups.has(group)) {
51
+ groups.set(group, new Map<string, Alert>())
52
+ }
53
+ const groupMap = groups.get(group)
54
+ const normalizedModifiers =
55
+ typeof modifiers === 'string' ? modifiers.split(' ') : modifiers
56
+
57
+ if (!icon) {
58
+ const alertModifier = normalizedModifiers.find((modifier) =>
59
+ DefaultAlertIconMap.has(modifier as AlertModifiers),
60
+ ) as AlertModifiers | undefined
61
+
62
+ if (alertModifier) {
63
+ icon = DefaultAlertIconMap.get(alertModifier) as string
64
+ }
65
+ }
66
+ groupMap?.set(id.toString(), {
67
+ id,
68
+ group,
69
+ title,
70
+ icon,
71
+ content,
72
+ footer,
73
+ modifiers,
74
+ dismissable,
75
+ autoClose,
76
+ timestamp: Date.now(),
77
+ })
78
+ }
79
+
80
+ const removeAlert = (id: string | number, group = DEFAULT_ALERT_GROUP) => {
81
+ const groupMap = groups.get(group)
82
+ groupMap?.delete(id.toString())
83
+ }
84
+
85
+ const getAlerts = (group = DEFAULT_ALERT_GROUP) => {
86
+ return computed(() => {
87
+ const groupMap = groups.get(group)
88
+ return groupMap && groupMap instanceof Map
89
+ ? Array.from(groupMap?.values()).sort(
90
+ (a, b) => a.timestamp - b.timestamp,
91
+ )
92
+ : []
93
+ })
94
+ }
95
+
96
+ return {
97
+ groups,
98
+ alerts: getAlerts(),
99
+ addAlert,
100
+ removeAlert,
101
+ getAlerts,
102
+ }
103
+ }
@@ -0,0 +1,3 @@
1
+ import { useAlert } from './alert/useAlert'
2
+
3
+ export { useAlert }
package/src/constants.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { InjectionKey, Ref } from 'vue'
2
2
  import type { Emitter } from 'mitt'
3
3
  import type { Volver } from './Volver'
4
+ import type { AlertModifiers } from './types/alert'
4
5
 
5
6
  export const DEFAULT_ICONIFY_PROVIDER = 'vv'
6
7
 
@@ -110,3 +111,23 @@ export const INJECTION_KEY_ALERT_GROUP = Symbol.for(
110
111
  name?: Ref<string | undefined>
111
112
  bus?: Emitter<{ close: string }>
112
113
  }>
114
+ export const DEFAULT_ALERT_AUTO_CLOSE = 10000
115
+ export const DEFAULT_ALERT_MODIFIERS = 'info'
116
+ export const DEFAULT_ALERT_DISMISSABLE = true
117
+ export const DEFAULT_ALERT_GROUP = 'default'
118
+ export const DEFAULT_ALERT_INFO_ICON = 'information'
119
+ export const DEFAULT_ALERT_SUCCESS_ICON = 'check-circle'
120
+ export const DEFAULT_ALERT_WARNING_ICON = 'warning'
121
+ export const DEFAULT_ALERT_DANGER_ICON = 'error'
122
+ export const DefaultAlertIconMap = new Map<AlertModifiers, string>([
123
+ ['success', DEFAULT_ALERT_SUCCESS_ICON],
124
+ ['info', DEFAULT_ALERT_INFO_ICON],
125
+ ['warning', DEFAULT_ALERT_WARNING_ICON],
126
+ ['danger', DEFAULT_ALERT_DANGER_ICON],
127
+ ])
128
+ // {
129
+ // success: DEFAULT_ALERT_SUCCESS_ICON,
130
+ // info: DEFAULT_ALERT_INFO_ICON,
131
+ // warning: DEFAULT_ALERT_WARNING_ICON,
132
+ // danger: DEFAULT_ALERT_DANGER_ICON,
133
+ // }
@@ -6,6 +6,8 @@ export async function defaultTest({ canvasElement, args }: PlayAttributes) {
6
6
  const element = (await within(canvasElement).findByTestId(
7
7
  'element',
8
8
  )) as HTMLElement
9
+ const buttons =
10
+ canvasElement.getElementsByClassName('buttons-container')?.[0]
9
11
 
10
12
  expect(element).toHaveClass('vv-alert-group')
11
13
 
@@ -71,6 +73,17 @@ export async function defaultTest({ canvasElement, args }: PlayAttributes) {
71
73
  expect(element.lastElementChild?.innerHTML).toEqual(div.innerHTML)
72
74
  }
73
75
 
76
+ if (buttons) {
77
+ // click every button child and expect to have alert with correct css class
78
+ for (let i = 0; i < buttons.children.length; i++) {
79
+ const button = buttons.children[i] as HTMLElement
80
+ await button.click()
81
+ expect(alertGroupList.lastElementChild).toHaveClass(
82
+ `vv-alert--${button.id}`,
83
+ )
84
+ }
85
+ }
86
+
74
87
  // check accessibility
75
88
  await expect(element).toHaveNoViolations()
76
89
  }
@@ -1,11 +1,11 @@
1
1
  import type { Meta } from '@storybook/vue3'
2
- import VvAlert from '@/components/VvAlert/VvAlert.vue'
2
+ import VvAlertGroup from '@/components/VvAlertGroup/VvAlertGroup.vue'
3
3
  import { defaultArgs, argTypes } from './AlertGroup.settings'
4
4
  import { Default as DefaultStory, type Story } from './AlertGroup.stories'
5
5
 
6
- const meta: Meta<typeof VvAlert> = {
6
+ const meta: Meta<typeof VvAlertGroup> = {
7
7
  title: 'Components/AlertGroup/Slots',
8
- component: VvAlert,
8
+ component: VvAlertGroup,
9
9
  args: defaultArgs,
10
10
  argTypes,
11
11
  }
@@ -0,0 +1,118 @@
1
+ import type { Meta } from '@storybook/vue3'
2
+ import VvAlertGroup from '@/components/VvAlertGroup/VvAlertGroup.vue'
3
+ import VvButton from '@/components/VvButton/VvButton.vue'
4
+ import { defaultArgs, argTypes } from './AlertGroup.settings'
5
+ import { Default as DefaultStory, type Story } from './AlertGroup.stories'
6
+ import { useAlert } from '@/composables/alert/useAlert'
7
+
8
+ const meta: Meta<typeof VvAlertGroup> = {
9
+ title: 'Components/AlertGroup/UseComposable',
10
+ component: VvAlertGroup,
11
+ args: defaultArgs,
12
+ argTypes,
13
+ tags: ['autodocs'],
14
+ }
15
+
16
+ export default meta
17
+
18
+ export const UseComposable: Story = {
19
+ ...DefaultStory,
20
+ parameters: {
21
+ docs: {
22
+ source: {
23
+ type: 'code',
24
+ language: 'html',
25
+ code: /* html */ `
26
+ <div class="flex gap-md">
27
+ <vv-button label="Show success" modifiers="secondary" @click="showSuccess" class="mb-lg" />
28
+ <vv-button label="Show danger" modifiers="secondary" @click="showDanger" class="mb-lg" />
29
+ <vv-button label="Show warning" modifiers="secondary" @click="showWarning" class="mb-lg" />
30
+ <vv-button label="Show info" modifiers="secondary" @click="showInfo" class="mb-lg" />
31
+ </div>
32
+ <vv-alert-group v-bind="args" :items="alerts" :onClose="removeAlert" data-testId="element" />
33
+
34
+ <script setup lang='ts'>
35
+ import { useAlert } from '@volverjs/ui-vue/composables'
36
+
37
+ const { addAlert, removeAlert, alerts } = useAlert()
38
+
39
+ function showSuccess() {
40
+ addAlert({
41
+ title: 'Success!',
42
+ modifiers: 'success',
43
+ })
44
+ }
45
+ function showDanger() {
46
+ addAlert({
47
+ title: 'Danger!',
48
+ modifiers: 'danger',
49
+ })
50
+ }
51
+ function showWarning() {
52
+ addAlert({
53
+ title: 'Warning!',
54
+ modifiers: 'warning',
55
+ })
56
+ }
57
+ function showInfo() {
58
+ addAlert({
59
+ title: 'Info!',
60
+ modifiers: 'info',
61
+ })
62
+ }
63
+ </script>
64
+ `,
65
+ },
66
+ },
67
+ },
68
+ render: (args) => ({
69
+ components: { VvAlertGroup, VvButton },
70
+ setup() {
71
+ const { addAlert, removeAlert, alerts } = useAlert()
72
+
73
+ function showSuccess() {
74
+ addAlert({
75
+ title: 'Success!',
76
+ modifiers: 'success',
77
+ })
78
+ }
79
+ function showDanger() {
80
+ addAlert({
81
+ title: 'Danger!',
82
+ modifiers: 'danger',
83
+ })
84
+ }
85
+ function showWarning() {
86
+ addAlert({
87
+ title: 'Warning!',
88
+ modifiers: 'warning',
89
+ })
90
+ }
91
+ function showInfo() {
92
+ addAlert({
93
+ title: 'Info!',
94
+ modifiers: 'info',
95
+ })
96
+ }
97
+
98
+ return {
99
+ args,
100
+ alerts,
101
+ removeAlert,
102
+ showSuccess,
103
+ showDanger,
104
+ showWarning,
105
+ showInfo,
106
+ }
107
+ },
108
+ template: /* html */ `
109
+ <div class="buttons-container flex gap-md" >
110
+ <vv-button id="success" label="Show success" modifiers="secondary" @click="showSuccess" class="mb-lg" />
111
+ <vv-button id="danger" label="Show danger" modifiers="secondary" @click="showDanger" class="mb-lg" />
112
+ <vv-button id="warning" label="Show warning" modifiers="secondary" @click="showWarning" class="mb-lg" />
113
+ <vv-button id="info" label="Show info" modifiers="secondary" @click="showInfo" class="mb-lg" />
114
+ </div>
115
+ <vv-alert-group v-bind="args" :items="alerts" :onClose="removeAlert" data-testId="element" />
116
+ `,
117
+ }),
118
+ }
@@ -86,7 +86,7 @@ export const argTypes = {
86
86
  },
87
87
  },
88
88
  noResultsLabel: {
89
- description: 'Label of "no results" options',
89
+ description: 'Label for no search results',
90
90
  control: {
91
91
  type: 'text',
92
92
  },
@@ -96,6 +96,83 @@ export const argTypes = {
96
96
  },
97
97
  },
98
98
  },
99
+ noOptionsLabel: {
100
+ description: 'Label for no options available',
101
+ control: {
102
+ type: 'text',
103
+ },
104
+ table: {
105
+ defaultValue: {
106
+ summary: 'No options available',
107
+ },
108
+ },
109
+ },
110
+ selectedHintLabel: {
111
+ description: 'Label for selected option hint',
112
+ control: {
113
+ type: 'text',
114
+ },
115
+ table: {
116
+ defaultValue: {
117
+ summary: 'Selected',
118
+ },
119
+ },
120
+ },
121
+ deselectActionLabel: {
122
+ description: 'Label for deselect action button',
123
+ control: {
124
+ type: 'text',
125
+ },
126
+ table: {
127
+ defaultValue: {
128
+ summary: 'Deselect',
129
+ },
130
+ },
131
+ },
132
+ selectHintLabel: {
133
+ description: 'Label for select option hint',
134
+ control: {
135
+ type: 'text',
136
+ },
137
+ table: {
138
+ defaultValue: {
139
+ summary: 'Press enter to select',
140
+ },
141
+ },
142
+ },
143
+ deselectHintLabel: {
144
+ description: 'Label for deselected option hint',
145
+ control: {
146
+ type: 'text',
147
+ },
148
+ table: {
149
+ defaultValue: {
150
+ summary: 'Press enter to remove',
151
+ },
152
+ },
153
+ },
154
+ closeLabel: {
155
+ description: 'Label for close button',
156
+ control: {
157
+ type: 'text',
158
+ },
159
+ table: {
160
+ defaultValue: {
161
+ summary: 'Close',
162
+ },
163
+ },
164
+ },
165
+ loadingLabel: {
166
+ description: 'Label for loading',
167
+ control: {
168
+ type: 'text',
169
+ },
170
+ table: {
171
+ defaultValue: {
172
+ summary: 'Loading...',
173
+ },
174
+ },
175
+ },
99
176
  placeholder: {
100
177
  description: 'Text that appears when it has no value set.',
101
178
  control: {
@@ -116,6 +193,11 @@ export const argTypes = {
116
193
  control: {
117
194
  type: 'text',
118
195
  },
196
+ table: {
197
+ defaultValue: {
198
+ summary: 'Search...',
199
+ },
200
+ },
119
201
  },
120
202
  debounceSearch: {
121
203
  description: 'Debounce milliseconds for search',
@@ -173,6 +255,22 @@ export const argTypes = {
173
255
  type: 'text',
174
256
  },
175
257
  description: 'Modifiers for dropdown',
258
+ table: {
259
+ defaultValue: {
260
+ summary: 'mobile',
261
+ },
262
+ },
263
+ },
264
+ transitionName: {
265
+ control: {
266
+ type: 'text',
267
+ },
268
+ description: 'Transition name for dropdown',
269
+ table: {
270
+ defaultValue: {
271
+ summary: 'vv-dropdown--mobile-fade-block',
272
+ },
273
+ },
176
274
  },
177
275
  autoOpen: {
178
276
  description: 'Open dropdown on focus',
@@ -190,6 +288,14 @@ export const argTypes = {
190
288
  },
191
289
  },
192
290
  },
291
+ autofocusFirst: {
292
+ description: 'Autofocus first option on open dropdown',
293
+ table: {
294
+ defaultValue: {
295
+ summary: true,
296
+ },
297
+ },
298
+ },
193
299
  before: {
194
300
  control: {
195
301
  type: 'text',
@@ -0,0 +1,20 @@
1
+ export type AlertModifiers =
2
+ | 'success'
3
+ | 'info'
4
+ | 'warning'
5
+ | 'danger'
6
+ | 'brand'
7
+ | 'accent'
8
+
9
+ export type Alert = {
10
+ id: string | number
11
+ group: string
12
+ title?: string
13
+ icon: string | Record<string, unknown>
14
+ content?: string
15
+ footer?: string
16
+ modifiers: AlertModifiers
17
+ dismissable: boolean
18
+ autoClose: number
19
+ timestamp: number
20
+ }