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

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.
@@ -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
+ }
@@ -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
+ }