@kaizen/components 1.35.2 → 1.37.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/cjs/KaizenProvider/KaizenProvider.cjs +6 -1
- package/dist/cjs/KaizenProvider/KaizenProvider.cjs.map +1 -1
- package/dist/cjs/Modal/ContextModal/ContextModal.cjs +9 -6
- package/dist/cjs/Modal/ContextModal/ContextModal.cjs.map +1 -1
- package/dist/cjs/Notification/ToastNotification/ToastNotification/ToastNotification.cjs +33 -0
- package/dist/cjs/Notification/ToastNotification/ToastNotification/ToastNotification.cjs.map +1 -0
- package/dist/cjs/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.cjs +36 -0
- package/dist/cjs/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.cjs.map +1 -0
- package/dist/cjs/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.module.scss.cjs +7 -0
- package/dist/cjs/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.module.scss.cjs.map +1 -0
- package/dist/cjs/Notification/ToastNotification/ToastNotificationsList/subcomponents/ToastNotificationsMap/ToastNotificationsMap.cjs +42 -0
- package/dist/cjs/Notification/ToastNotification/ToastNotificationsList/subcomponents/ToastNotificationsMap/ToastNotificationsMap.cjs.map +1 -0
- package/dist/cjs/Notification/ToastNotification/context/ToastNotificationContext.cjs +72 -0
- package/dist/cjs/Notification/ToastNotification/context/ToastNotificationContext.cjs.map +1 -0
- package/dist/cjs/Notification/ToastNotification/hooks/useToastNotification.cjs +9 -0
- package/dist/cjs/Notification/ToastNotification/hooks/useToastNotification.cjs.map +1 -0
- package/dist/cjs/RichTextEditor/RichTextEditor/RichTextEditor.cjs +6 -2
- package/dist/cjs/RichTextEditor/RichTextEditor/RichTextEditor.cjs.map +1 -1
- package/dist/cjs/__future__/Select/Select.cjs +14 -1
- package/dist/cjs/__future__/Select/Select.cjs.map +1 -1
- package/dist/cjs/dts/Modal/ContextModal/ContextModal.d.ts +2 -1
- package/dist/cjs/dts/Notification/ToastNotification/ToastNotification/ToastNotification.d.ts +16 -0
- package/dist/cjs/dts/Notification/ToastNotification/ToastNotification/index.d.ts +1 -0
- package/dist/cjs/dts/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.d.ts +4 -0
- package/dist/cjs/dts/Notification/ToastNotification/ToastNotificationsList/subcomponents/ToastNotificationsMap/ToastNotificationsMap.d.ts +12 -0
- package/dist/cjs/dts/Notification/ToastNotification/ToastNotificationsList/subcomponents/ToastNotificationsMap/index.d.ts +1 -0
- package/dist/cjs/dts/Notification/ToastNotification/context/ToastNotificationContext.d.ts +21 -0
- package/dist/cjs/dts/Notification/ToastNotification/hooks/useToastNotification.d.ts +2 -0
- package/dist/cjs/dts/Notification/ToastNotification/index.d.ts +3 -2
- package/dist/cjs/dts/Notification/ToastNotification/types.d.ts +1 -9
- package/dist/cjs/dts/Notification/index.d.ts +1 -0
- package/dist/cjs/dts/RichTextEditor/RichTextEditor/RichTextEditor.d.ts +1 -1
- package/dist/cjs/dts/__future__/Select/Select.d.ts +5 -1
- package/dist/cjs/dts/index.d.ts +4 -3
- package/dist/cjs/index.cjs +16 -8
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.css +9 -8
- package/dist/esm/KaizenProvider/KaizenProvider.mjs +6 -1
- package/dist/esm/KaizenProvider/KaizenProvider.mjs.map +1 -1
- package/dist/esm/Modal/ContextModal/ContextModal.mjs +9 -6
- package/dist/esm/Modal/ContextModal/ContextModal.mjs.map +1 -1
- package/dist/esm/Notification/ToastNotification/ToastNotification/ToastNotification.mjs +31 -0
- package/dist/esm/Notification/ToastNotification/ToastNotification/ToastNotification.mjs.map +1 -0
- package/dist/esm/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.mjs +34 -0
- package/dist/esm/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.mjs.map +1 -0
- package/dist/esm/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.module.scss.mjs +5 -0
- package/dist/esm/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.module.scss.mjs.map +1 -0
- package/dist/esm/Notification/ToastNotification/ToastNotificationsList/subcomponents/ToastNotificationsMap/ToastNotificationsMap.mjs +40 -0
- package/dist/esm/Notification/ToastNotification/ToastNotificationsList/subcomponents/ToastNotificationsMap/ToastNotificationsMap.mjs.map +1 -0
- package/dist/esm/Notification/ToastNotification/context/ToastNotificationContext.mjs +69 -0
- package/dist/esm/Notification/ToastNotification/context/ToastNotificationContext.mjs.map +1 -0
- package/dist/esm/Notification/ToastNotification/hooks/useToastNotification.mjs +7 -0
- package/dist/esm/Notification/ToastNotification/hooks/useToastNotification.mjs.map +1 -0
- package/dist/esm/RichTextEditor/RichTextEditor/RichTextEditor.mjs +6 -2
- package/dist/esm/RichTextEditor/RichTextEditor/RichTextEditor.mjs.map +1 -1
- package/dist/esm/__future__/Select/Select.mjs +15 -2
- package/dist/esm/__future__/Select/Select.mjs.map +1 -1
- package/dist/esm/dts/Modal/ContextModal/ContextModal.d.ts +2 -1
- package/dist/esm/dts/Notification/ToastNotification/ToastNotification/ToastNotification.d.ts +16 -0
- package/dist/esm/dts/Notification/ToastNotification/ToastNotification/index.d.ts +1 -0
- package/dist/esm/dts/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.d.ts +4 -0
- package/dist/esm/dts/Notification/ToastNotification/ToastNotificationsList/subcomponents/ToastNotificationsMap/ToastNotificationsMap.d.ts +12 -0
- package/dist/esm/dts/Notification/ToastNotification/ToastNotificationsList/subcomponents/ToastNotificationsMap/index.d.ts +1 -0
- package/dist/esm/dts/Notification/ToastNotification/context/ToastNotificationContext.d.ts +21 -0
- package/dist/esm/dts/Notification/ToastNotification/hooks/useToastNotification.d.ts +2 -0
- package/dist/esm/dts/Notification/ToastNotification/index.d.ts +3 -2
- package/dist/esm/dts/Notification/ToastNotification/types.d.ts +1 -9
- package/dist/esm/dts/Notification/index.d.ts +1 -0
- package/dist/esm/dts/RichTextEditor/RichTextEditor/RichTextEditor.d.ts +1 -1
- package/dist/esm/dts/__future__/Select/Select.d.ts +5 -1
- package/dist/esm/dts/index.d.ts +4 -3
- package/dist/esm/index.css +8 -7
- package/dist/esm/index.mjs +8 -4
- package/dist/esm/index.mjs.map +1 -1
- package/dist/index.d.ts +136 -81
- package/dist/styles.css +1 -1
- package/package.json +2 -2
- package/src/DatePicker/DatePicker.spec.tsx +1 -1
- package/src/KaizenProvider/KaizenProvider.tsx +6 -1
- package/src/Modal/ContextModal/ContextModal.spec.tsx +3 -3
- package/src/Modal/ContextModal/ContextModal.tsx +9 -5
- package/src/Notification/ToastNotification/ToastNotification/ToastNotification.spec.tsx +33 -0
- package/src/Notification/ToastNotification/ToastNotification/ToastNotification.tsx +48 -0
- package/src/Notification/ToastNotification/ToastNotification/index.ts +1 -0
- package/src/Notification/ToastNotification/{subcomponents/ToastNotificationsList → ToastNotificationsList}/ToastNotificationsList.module.scss +1 -1
- package/src/Notification/ToastNotification/ToastNotificationsList/ToastNotificationsList.tsx +40 -0
- package/src/Notification/ToastNotification/ToastNotificationsList/subcomponents/ToastNotificationsMap/ToastNotificationsMap.tsx +49 -0
- package/src/Notification/ToastNotification/ToastNotificationsList/subcomponents/ToastNotificationsMap/index.ts +1 -0
- package/src/Notification/ToastNotification/_docs/ToastNotification.mdx +19 -14
- package/src/Notification/ToastNotification/_docs/ToastNotification.stickersheet.stories.tsx +33 -70
- package/src/Notification/ToastNotification/_docs/ToastNotification.stories.tsx +123 -93
- package/src/Notification/ToastNotification/context/ToastNotificationContext.tsx +96 -0
- package/src/Notification/ToastNotification/hooks/useToastNotification.ts +9 -0
- package/src/Notification/ToastNotification/index.ts +3 -2
- package/src/Notification/ToastNotification/types.ts +1 -18
- package/src/Notification/index.ts +1 -0
- package/src/RichTextEditor/RichTextEditor/RichTextEditor.tsx +6 -1
- package/src/RichTextEditor/utils/commands/addMark.spec.ts +0 -1
- package/src/Tooltip/Tooltip.spec.tsx +6 -1
- package/src/__future__/Select/Select.spec.tsx +78 -2
- package/src/__future__/Select/Select.tsx +18 -2
- package/src/__future__/Select/_docs/Select.mdx +8 -0
- package/src/__future__/Select/_docs/Select.stories.tsx +29 -0
- package/src/index.ts +4 -3
- package/dist/cjs/dts/Notification/ToastNotification/ToastNotification.d.ts +0 -14
- package/dist/cjs/dts/Notification/ToastNotification/subcomponents/ToastNotificationManager/ToastNotificationManager.d.ts +0 -7
- package/dist/cjs/dts/Notification/ToastNotification/subcomponents/ToastNotificationManager/index.d.ts +0 -1
- package/dist/cjs/dts/Notification/ToastNotification/subcomponents/ToastNotificationsList/ToastNotificationsList.d.ts +0 -11
- package/dist/cjs/dts/Notification/ToastNotification/subcomponents/ToastNotificationsListContainer/ToastNotificationsListContainer.d.ts +0 -7
- package/dist/cjs/dts/Notification/ToastNotification/subcomponents/ToastNotificationsListContainer/index.d.ts +0 -1
- package/dist/esm/dts/Notification/ToastNotification/ToastNotification.d.ts +0 -14
- package/dist/esm/dts/Notification/ToastNotification/subcomponents/ToastNotificationManager/ToastNotificationManager.d.ts +0 -7
- package/dist/esm/dts/Notification/ToastNotification/subcomponents/ToastNotificationManager/index.d.ts +0 -1
- package/dist/esm/dts/Notification/ToastNotification/subcomponents/ToastNotificationsList/ToastNotificationsList.d.ts +0 -11
- package/dist/esm/dts/Notification/ToastNotification/subcomponents/ToastNotificationsListContainer/ToastNotificationsListContainer.d.ts +0 -7
- package/dist/esm/dts/Notification/ToastNotification/subcomponents/ToastNotificationsListContainer/index.d.ts +0 -1
- package/src/Notification/ToastNotification/ToastNotification.spec.tsx +0 -31
- package/src/Notification/ToastNotification/ToastNotification.tsx +0 -43
- package/src/Notification/ToastNotification/subcomponents/ToastNotificationManager/ToastNotificationManager.spec.tsx +0 -144
- package/src/Notification/ToastNotification/subcomponents/ToastNotificationManager/ToastNotificationManager.tsx +0 -135
- package/src/Notification/ToastNotification/subcomponents/ToastNotificationManager/index.ts +0 -1
- package/src/Notification/ToastNotification/subcomponents/ToastNotificationsList/ToastNotificationsList.tsx +0 -40
- package/src/Notification/ToastNotification/subcomponents/ToastNotificationsListContainer/ToastNotificationsListContainer.spec.tsx +0 -73
- package/src/Notification/ToastNotification/subcomponents/ToastNotificationsListContainer/ToastNotificationsListContainer.tsx +0 -31
- package/src/Notification/ToastNotification/subcomponents/ToastNotificationsListContainer/index.ts +0 -1
- /package/dist/cjs/dts/Notification/ToastNotification/{subcomponents/ToastNotificationsList → ToastNotificationsList}/index.d.ts +0 -0
- /package/dist/esm/dts/Notification/ToastNotification/{subcomponents/ToastNotificationsList → ToastNotificationsList}/index.d.ts +0 -0
- /package/src/Notification/ToastNotification/{subcomponents/ToastNotificationsList → ToastNotificationsList}/index.ts +0 -0
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import React from "react"
|
|
1
|
+
import React, { useEffect, useId } from "react"
|
|
2
2
|
import { Meta, StoryObj } from "@storybook/react"
|
|
3
3
|
import { Button } from "~components/Button"
|
|
4
|
-
import {
|
|
5
|
-
addToastNotification,
|
|
6
|
-
removeToastNotification,
|
|
7
|
-
clearToastNotifications,
|
|
8
|
-
ToastNotification,
|
|
9
|
-
} from "../index"
|
|
4
|
+
import { ToastNotification, useToastNotification } from "../index"
|
|
10
5
|
|
|
11
6
|
const meta = {
|
|
12
7
|
title: "Components/Notifications/ToastNotification",
|
|
@@ -28,7 +23,26 @@ export default meta
|
|
|
28
23
|
|
|
29
24
|
type Story = StoryObj<typeof meta>
|
|
30
25
|
|
|
26
|
+
const ToastNotificationTemplate: Story = {
|
|
27
|
+
render: args => {
|
|
28
|
+
const reactId = useId()
|
|
29
|
+
const { updateToastNotification } = useToastNotification()
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
updateToastNotification({
|
|
33
|
+
...args,
|
|
34
|
+
id: args.id ?? reactId,
|
|
35
|
+
message: args.children,
|
|
36
|
+
persistent: args.hideCloseIcon,
|
|
37
|
+
})
|
|
38
|
+
}, [args])
|
|
39
|
+
|
|
40
|
+
return <ToastNotification {...args} />
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
31
44
|
export const Playground: Story = {
|
|
45
|
+
...ToastNotificationTemplate,
|
|
32
46
|
parameters: {
|
|
33
47
|
docs: {
|
|
34
48
|
canvas: {
|
|
@@ -39,104 +53,120 @@ export const Playground: Story = {
|
|
|
39
53
|
}
|
|
40
54
|
|
|
41
55
|
export const CreateNotification: Story = {
|
|
42
|
-
render: () =>
|
|
43
|
-
|
|
44
|
-
label="Create notification"
|
|
45
|
-
onClick={() =>
|
|
46
|
-
addToastNotification({
|
|
47
|
-
title: "Informative",
|
|
48
|
-
type: "informative",
|
|
49
|
-
message: "New notification!",
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
/>
|
|
53
|
-
),
|
|
54
|
-
}
|
|
56
|
+
render: () => {
|
|
57
|
+
const { addToastNotification } = useToastNotification()
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
render: () => (
|
|
58
|
-
<>
|
|
59
|
+
return (
|
|
59
60
|
<Button
|
|
60
61
|
label="Create notification"
|
|
61
|
-
classNameOverride="!mr-12"
|
|
62
|
-
onClick={() =>
|
|
63
|
-
addToastNotification({
|
|
64
|
-
id: "id--update-example",
|
|
65
|
-
title: "Cautionary",
|
|
66
|
-
type: "cautionary",
|
|
67
|
-
message: "This content will be updated",
|
|
68
|
-
})
|
|
69
|
-
}
|
|
70
|
-
/>
|
|
71
|
-
<Button
|
|
72
|
-
label="Update notification"
|
|
73
62
|
onClick={() =>
|
|
74
63
|
addToastNotification({
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
message: "The content was successfully updated",
|
|
64
|
+
title: "Informative",
|
|
65
|
+
type: "informative",
|
|
66
|
+
message: "New notification!",
|
|
79
67
|
})
|
|
80
68
|
}
|
|
81
69
|
/>
|
|
82
|
-
|
|
83
|
-
|
|
70
|
+
)
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const UpdateNotification: Story = {
|
|
75
|
+
render: () => {
|
|
76
|
+
const { addToastNotification, updateToastNotification } =
|
|
77
|
+
useToastNotification()
|
|
78
|
+
return (
|
|
79
|
+
<>
|
|
80
|
+
<Button
|
|
81
|
+
label="Create notification"
|
|
82
|
+
classNameOverride="!mr-12"
|
|
83
|
+
onClick={() =>
|
|
84
|
+
addToastNotification({
|
|
85
|
+
id: "id--update-example",
|
|
86
|
+
title: "Cautionary",
|
|
87
|
+
type: "cautionary",
|
|
88
|
+
message: "This content will be updated",
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
/>
|
|
92
|
+
<Button
|
|
93
|
+
label="Update notification"
|
|
94
|
+
onClick={() =>
|
|
95
|
+
updateToastNotification({
|
|
96
|
+
id: "id--update-example",
|
|
97
|
+
title: "Success",
|
|
98
|
+
type: "positive",
|
|
99
|
+
message: "The content was successfully updated",
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
/>
|
|
103
|
+
</>
|
|
104
|
+
)
|
|
105
|
+
},
|
|
84
106
|
}
|
|
85
107
|
|
|
86
108
|
export const RemoveNotification: Story = {
|
|
87
|
-
render: () =>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
109
|
+
render: () => {
|
|
110
|
+
const { addToastNotification, removeToastNotification } =
|
|
111
|
+
useToastNotification()
|
|
112
|
+
return (
|
|
113
|
+
<>
|
|
114
|
+
<Button
|
|
115
|
+
label="Create notification"
|
|
116
|
+
classNameOverride="!mr-12"
|
|
117
|
+
onClick={() =>
|
|
118
|
+
addToastNotification({
|
|
119
|
+
id: "id--remove-example",
|
|
120
|
+
title: "Remove",
|
|
121
|
+
type: "negative",
|
|
122
|
+
message: "This notification will be removed",
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
/>
|
|
126
|
+
<Button
|
|
127
|
+
label="Remove notification"
|
|
128
|
+
onClick={() => removeToastNotification("id--remove-example")}
|
|
129
|
+
/>
|
|
130
|
+
</>
|
|
131
|
+
)
|
|
132
|
+
},
|
|
107
133
|
}
|
|
108
134
|
|
|
109
135
|
export const ClearNotifications: Story = {
|
|
110
|
-
render: () =>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
136
|
+
render: () => {
|
|
137
|
+
const { addToastNotification, clearToastNotifications } =
|
|
138
|
+
useToastNotification()
|
|
139
|
+
return (
|
|
140
|
+
<>
|
|
141
|
+
<Button
|
|
142
|
+
label="Create notifications"
|
|
143
|
+
classNameOverride="!mr-12"
|
|
144
|
+
onClick={() => {
|
|
145
|
+
addToastNotification({
|
|
146
|
+
id: "id--clear-example-1",
|
|
147
|
+
title: "First",
|
|
148
|
+
type: "positive",
|
|
149
|
+
message: "This notification will be removed",
|
|
150
|
+
})
|
|
151
|
+
addToastNotification({
|
|
152
|
+
id: "id--clear-example-2",
|
|
153
|
+
title: "Second",
|
|
154
|
+
type: "cautionary",
|
|
155
|
+
message: "This notification will also be removed",
|
|
156
|
+
})
|
|
157
|
+
addToastNotification({
|
|
158
|
+
id: "id--clear-example-3",
|
|
159
|
+
title: "Third",
|
|
160
|
+
type: "negative",
|
|
161
|
+
message: "This notification will also also be removed",
|
|
162
|
+
})
|
|
163
|
+
}}
|
|
164
|
+
/>
|
|
165
|
+
<Button
|
|
166
|
+
label="Clear notifications"
|
|
167
|
+
onClick={() => clearToastNotifications()}
|
|
168
|
+
/>
|
|
169
|
+
</>
|
|
170
|
+
)
|
|
171
|
+
},
|
|
142
172
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React, { useContext, useState } from "react"
|
|
2
|
+
import { v4 as uuidv4 } from "uuid"
|
|
3
|
+
import { ToastNotificationObj } from "../types"
|
|
4
|
+
|
|
5
|
+
type ToastNotificationObjOptionalId = Omit<ToastNotificationObj, "id"> & {
|
|
6
|
+
id?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type ToastNotificationContextValue = {
|
|
10
|
+
notifications: ToastNotificationObj[]
|
|
11
|
+
addToastNotification: (notification: ToastNotificationObjOptionalId) => void
|
|
12
|
+
updateToastNotification: (notification: ToastNotificationObj) => void
|
|
13
|
+
removeToastNotification: (notificationId: string) => void
|
|
14
|
+
clearToastNotifications: () => void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const ToastNotificationContext =
|
|
18
|
+
React.createContext<ToastNotificationContextValue | null>(null)
|
|
19
|
+
|
|
20
|
+
export const useToastNotificationContext =
|
|
21
|
+
(): ToastNotificationContextValue => {
|
|
22
|
+
const context = useContext(ToastNotificationContext)
|
|
23
|
+
|
|
24
|
+
if (!context) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"useToastNotificationContext must be used within the ToastNotificationContext.Provider"
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return context
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type ToastNotificationProviderProps = {
|
|
34
|
+
children: React.ReactNode
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const ToastNotificationProvider = ({
|
|
38
|
+
children,
|
|
39
|
+
}: ToastNotificationProviderProps): JSX.Element | null => {
|
|
40
|
+
const [notifications, setNotifications] = useState<ToastNotificationObj[]>([])
|
|
41
|
+
|
|
42
|
+
const addToastNotification: ToastNotificationContextValue["addToastNotification"] =
|
|
43
|
+
notification => {
|
|
44
|
+
const uuid = uuidv4()
|
|
45
|
+
const notificationWithId = { id: uuid, ...notification }
|
|
46
|
+
|
|
47
|
+
const notificationExists = notifications.find(
|
|
48
|
+
({ id }) => id === notification.id
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if (!notificationExists) {
|
|
52
|
+
setNotifications(existing => [...existing, notificationWithId])
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const updateToastNotification = (
|
|
57
|
+
notification: ToastNotificationObj
|
|
58
|
+
): void => {
|
|
59
|
+
const notificationIndex = notifications.findIndex(
|
|
60
|
+
({ id }) => id === notification.id
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
const copy = notifications.slice()
|
|
64
|
+
copy.splice(notificationIndex, 1, notification) // Mutation to insert notification over itself
|
|
65
|
+
setNotifications(copy)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const removeToastNotification = (notificationID: string): void => {
|
|
69
|
+
const notificationIndex = notifications.findIndex(
|
|
70
|
+
({ id }) => id === notificationID
|
|
71
|
+
)
|
|
72
|
+
const copy = notifications.slice()
|
|
73
|
+
copy.splice(notificationIndex, 1) // Mutation
|
|
74
|
+
setNotifications(copy)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const clearToastNotifications = (): void => {
|
|
78
|
+
setNotifications([])
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const value = {
|
|
82
|
+
notifications,
|
|
83
|
+
addToastNotification,
|
|
84
|
+
updateToastNotification,
|
|
85
|
+
removeToastNotification,
|
|
86
|
+
clearToastNotifications,
|
|
87
|
+
} satisfies ToastNotificationContextValue
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<ToastNotificationContext.Provider value={value}>
|
|
91
|
+
{children}
|
|
92
|
+
</ToastNotificationContext.Provider>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
ToastNotificationProvider.displayName = "ToastNotificationProvider"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ToastNotificationContextValue,
|
|
3
|
+
useToastNotificationContext,
|
|
4
|
+
} from "../context/ToastNotificationContext"
|
|
5
|
+
|
|
6
|
+
export const useToastNotification = (): ToastNotificationContextValue => {
|
|
7
|
+
const context = useToastNotificationContext()
|
|
8
|
+
return context
|
|
9
|
+
}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { DataAttributes } from "~types/DataAttributes"
|
|
2
2
|
import { NotificationType } from "../types"
|
|
3
3
|
|
|
4
|
-
type
|
|
5
|
-
|
|
6
|
-
export type ToastNotification = {
|
|
4
|
+
export type ToastNotificationObj = {
|
|
7
5
|
id: string
|
|
8
6
|
type: NotificationType
|
|
9
7
|
title: string
|
|
@@ -15,18 +13,3 @@ export type ToastNotification = {
|
|
|
15
13
|
*/
|
|
16
14
|
persistent?: boolean
|
|
17
15
|
} & DataAttributes
|
|
18
|
-
|
|
19
|
-
export type ToastNotificationWithOptionals = Modify<
|
|
20
|
-
ToastNotification,
|
|
21
|
-
{
|
|
22
|
-
id?: string
|
|
23
|
-
}
|
|
24
|
-
>
|
|
25
|
-
|
|
26
|
-
export type AddToastNotification = (
|
|
27
|
-
notification: ToastNotificationWithOptionals
|
|
28
|
-
) => void
|
|
29
|
-
|
|
30
|
-
export type RemoveToastNotification = (notificationId: string) => void
|
|
31
|
-
|
|
32
|
-
export type ClearToastNotifications = () => void
|
|
@@ -74,6 +74,7 @@ export const RichTextEditor = ({
|
|
|
74
74
|
defaultValue,
|
|
75
75
|
labelText,
|
|
76
76
|
"aria-labelledby": labelledBy,
|
|
77
|
+
"aria-describedby": describedBy,
|
|
77
78
|
classNameOverride,
|
|
78
79
|
controls,
|
|
79
80
|
rows = 3,
|
|
@@ -144,7 +145,11 @@ export const RichTextEditor = ({
|
|
|
144
145
|
: ""
|
|
145
146
|
const descriptionAria = description ? `${editorId}-rte-description` : ""
|
|
146
147
|
|
|
147
|
-
const ariaDescribedBy =
|
|
148
|
+
const ariaDescribedBy = classnames(
|
|
149
|
+
validationMessageAria,
|
|
150
|
+
descriptionAria,
|
|
151
|
+
describedBy
|
|
152
|
+
)
|
|
148
153
|
|
|
149
154
|
return (
|
|
150
155
|
<>
|
|
@@ -48,6 +48,8 @@ describe("<Tooltip />", () => {
|
|
|
48
48
|
// Non-semantic elements without roles should not have aria-description on them.
|
|
49
49
|
// They won't read to all screen readers as expected and may be reported in Storybook's accessibility tab (which uses Axe under the hood)
|
|
50
50
|
it("doesn't add an accessible description when wrapping a non-semantic element", async () => {
|
|
51
|
+
const warn = jest.spyOn(console, "warn").mockImplementation()
|
|
52
|
+
|
|
51
53
|
render(
|
|
52
54
|
<Tooltip
|
|
53
55
|
text="Tooltip popup description for div"
|
|
@@ -62,6 +64,9 @@ describe("<Tooltip />", () => {
|
|
|
62
64
|
expect(screen.getByText("Non semantic element")).not.toHaveAttribute(
|
|
63
65
|
"aria-describedby"
|
|
64
66
|
)
|
|
67
|
+
expect(warn).toHaveBeenCalledWith(
|
|
68
|
+
"<Tooltip /> is not directly wrapping a semantic element, screen reader users will not be able to access the tooltip info. To ensure accessibility, Tooltip should be wrapping a semantic and focusable element directly."
|
|
69
|
+
)
|
|
65
70
|
})
|
|
66
71
|
})
|
|
67
72
|
})
|
|
@@ -74,7 +79,7 @@ describe("<Tooltip />", () => {
|
|
|
74
79
|
isInitiallyVisible
|
|
75
80
|
position="below"
|
|
76
81
|
>
|
|
77
|
-
<div role="textbox" contentEditable="true" aria-multiline="true"
|
|
82
|
+
<div role="textbox" contentEditable="true" aria-multiline="true" />
|
|
78
83
|
</Tooltip>
|
|
79
84
|
)
|
|
80
85
|
await waitFor(() => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react"
|
|
2
|
-
import { render, waitFor } from "@testing-library/react"
|
|
2
|
+
import { render, waitFor, screen, within } from "@testing-library/react"
|
|
3
3
|
import userEvent from "@testing-library/user-event"
|
|
4
4
|
import { Select, SelectProps } from "./Select"
|
|
5
5
|
import { singleMockItems } from "./_docs/mockData"
|
|
@@ -17,7 +17,6 @@ const SelectWrapper = ({
|
|
|
17
17
|
)
|
|
18
18
|
return (
|
|
19
19
|
<Select
|
|
20
|
-
id="id--select"
|
|
21
20
|
label="Mock Label"
|
|
22
21
|
items={items}
|
|
23
22
|
description="This is a description"
|
|
@@ -356,4 +355,81 @@ describe("<Select />", () => {
|
|
|
356
355
|
})
|
|
357
356
|
})
|
|
358
357
|
})
|
|
358
|
+
|
|
359
|
+
describe("Popover portal", () => {
|
|
360
|
+
it("has accessible trigger controls", async () => {
|
|
361
|
+
render(<SelectWrapper isOpen />)
|
|
362
|
+
|
|
363
|
+
const trigger = screen.getByRole("combobox", {
|
|
364
|
+
name: "Mock Label",
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
await waitFor(() => {
|
|
368
|
+
expect(trigger).toHaveAttribute("aria-controls")
|
|
369
|
+
})
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
it("will portal to the document body by default", async () => {
|
|
373
|
+
render(<SelectWrapper selectedKey="batch-brew" isOpen />)
|
|
374
|
+
|
|
375
|
+
const popover = screen.getByRole("dialog")
|
|
376
|
+
// expected div that FocusOn adds to the popover
|
|
377
|
+
const popoverFocusWrapper = popover.parentNode
|
|
378
|
+
|
|
379
|
+
await waitFor(() => {
|
|
380
|
+
const expectedBodyTag = popoverFocusWrapper?.parentNode
|
|
381
|
+
expect(expectedBodyTag?.nodeName).toEqual("BODY")
|
|
382
|
+
})
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
it("will render as a descendant of the element matching the id", async () => {
|
|
386
|
+
const SelectWithPortal = (): JSX.Element => {
|
|
387
|
+
const portalContainerId = "id--portal-container"
|
|
388
|
+
return (
|
|
389
|
+
<>
|
|
390
|
+
<div
|
|
391
|
+
id={portalContainerId}
|
|
392
|
+
data-testid="id--portal-container-test"
|
|
393
|
+
></div>
|
|
394
|
+
<SelectWrapper
|
|
395
|
+
selectedKey="batch-brew"
|
|
396
|
+
isOpen
|
|
397
|
+
portalContainerId={portalContainerId}
|
|
398
|
+
/>
|
|
399
|
+
</>
|
|
400
|
+
)
|
|
401
|
+
}
|
|
402
|
+
render(<SelectWithPortal />)
|
|
403
|
+
|
|
404
|
+
await waitFor(() => {
|
|
405
|
+
const newPortalRegion = screen.getByTestId("id--portal-container-test")
|
|
406
|
+
const popover = within(newPortalRegion).getByRole("dialog")
|
|
407
|
+
|
|
408
|
+
expect(popover).toBeInTheDocument()
|
|
409
|
+
})
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
it("will portal to the document body if the id does not match", async () => {
|
|
413
|
+
const SelectWithPortal = (): JSX.Element => {
|
|
414
|
+
const expectedContainerId = "id--portal-container"
|
|
415
|
+
return (
|
|
416
|
+
<>
|
|
417
|
+
<div id="id--wrong-id"></div>
|
|
418
|
+
<SelectWrapper
|
|
419
|
+
selectedKey="batch-brew"
|
|
420
|
+
isOpen
|
|
421
|
+
portalContainerId={expectedContainerId}
|
|
422
|
+
/>
|
|
423
|
+
</>
|
|
424
|
+
)
|
|
425
|
+
}
|
|
426
|
+
render(<SelectWithPortal />)
|
|
427
|
+
|
|
428
|
+
await waitFor(() => {
|
|
429
|
+
const popover = within(document.body).getByRole("dialog")
|
|
430
|
+
|
|
431
|
+
expect(popover).toBeInTheDocument()
|
|
432
|
+
})
|
|
433
|
+
})
|
|
434
|
+
})
|
|
359
435
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useId } from "react"
|
|
1
|
+
import React, { useEffect, useId, useState } from "react"
|
|
2
2
|
import { UseFloatingReturn } from "@floating-ui/react-dom"
|
|
3
3
|
import { useButton } from "@react-aria/button"
|
|
4
4
|
import { HiddenSelect, useSelect } from "@react-aria/select"
|
|
@@ -67,6 +67,10 @@ export type SelectProps<Option extends SelectOption = SelectOption> = {
|
|
|
67
67
|
* @deprecated: Either define `disabled` in your `Option` (in `items`), or use `disabledKeys`
|
|
68
68
|
*/
|
|
69
69
|
disabledValues?: Key[]
|
|
70
|
+
/**
|
|
71
|
+
* Creates a portal for the Popover to the matching element id
|
|
72
|
+
*/
|
|
73
|
+
portalContainerId?: string
|
|
70
74
|
} & OverrideClassName<Omit<AriaSelectProps<Option>, OmittedAriaSelectProps>>
|
|
71
75
|
|
|
72
76
|
/**
|
|
@@ -89,13 +93,14 @@ export const Select = <Option extends SelectOption = SelectOption>({
|
|
|
89
93
|
description,
|
|
90
94
|
placeholder,
|
|
91
95
|
isDisabled,
|
|
96
|
+
portalContainerId,
|
|
92
97
|
...restProps
|
|
93
98
|
}: SelectProps<Option>): JSX.Element => {
|
|
94
99
|
const { refs } = useFloating<HTMLButtonElement>()
|
|
95
100
|
const triggerRef = refs.reference
|
|
96
|
-
|
|
97
101
|
const id = propsId ?? useId()
|
|
98
102
|
const descriptionId = `${id}--description`
|
|
103
|
+
const popoverId = `${id}--popover`
|
|
99
104
|
|
|
100
105
|
const disabledKeys = getDisabledKeysFromItems(items)
|
|
101
106
|
|
|
@@ -151,6 +156,15 @@ export const Select = <Option extends SelectOption = SelectOption>({
|
|
|
151
156
|
ref: refs.setReference,
|
|
152
157
|
}
|
|
153
158
|
|
|
159
|
+
const [portalContainer, setPortalContainer] = useState<HTMLElement>()
|
|
160
|
+
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (portalContainerId) {
|
|
163
|
+
const portalElement = document.getElementById(portalContainerId)
|
|
164
|
+
portalElement && setPortalContainer(portalElement)
|
|
165
|
+
}
|
|
166
|
+
}, [])
|
|
167
|
+
|
|
154
168
|
return (
|
|
155
169
|
<div
|
|
156
170
|
className={classnames(
|
|
@@ -173,6 +187,8 @@ export const Select = <Option extends SelectOption = SelectOption>({
|
|
|
173
187
|
)}
|
|
174
188
|
{state.isOpen && (
|
|
175
189
|
<Popover
|
|
190
|
+
id={popoverId}
|
|
191
|
+
portalContainer={portalContainer}
|
|
176
192
|
refs={refs}
|
|
177
193
|
focusOnProps={{
|
|
178
194
|
onEscapeKey: state.close,
|
|
@@ -98,3 +98,11 @@ Add validation messages using `status` and `validationMessage`.
|
|
|
98
98
|
|
|
99
99
|
Set `isFullWidth` to `true` to have the Select span the full width of its container.
|
|
100
100
|
<Canvas of={SelectStories.FullWidth} />
|
|
101
|
+
|
|
102
|
+
### Portals
|
|
103
|
+
|
|
104
|
+
By default, the Select's popover will attach itself to the `body` of the document using React's `createPortal`.
|
|
105
|
+
|
|
106
|
+
You can change the default behaviour by providing a `portalContainerId` to attach this to different element in the DOM. This can help to resolve issues that may arise with `z-index` or having a Select in a modal.
|
|
107
|
+
|
|
108
|
+
<Canvas of={SelectStories.PortalContainer} />
|
|
@@ -161,3 +161,32 @@ export const Validation: Story = {
|
|
|
161
161
|
export const FullWidth: Story = {
|
|
162
162
|
args: { isFullWidth: true },
|
|
163
163
|
}
|
|
164
|
+
|
|
165
|
+
export const PortalContainer: Story = {
|
|
166
|
+
render: args => {
|
|
167
|
+
const portalContainerId = "id--portal-container"
|
|
168
|
+
return (
|
|
169
|
+
<>
|
|
170
|
+
<div
|
|
171
|
+
id={portalContainerId}
|
|
172
|
+
className="flex gap-24 bg-gray-200 p-12 overflow-hidden h-[200px] relative"
|
|
173
|
+
>
|
|
174
|
+
<Select
|
|
175
|
+
{...args}
|
|
176
|
+
label="Default"
|
|
177
|
+
selectedKey="batch-brew"
|
|
178
|
+
id="id--select-default"
|
|
179
|
+
/>
|
|
180
|
+
<Select
|
|
181
|
+
{...args}
|
|
182
|
+
label="Inner portal"
|
|
183
|
+
selectedKey="batch-brew"
|
|
184
|
+
id="id--select-inner"
|
|
185
|
+
portalContainerId={portalContainerId}
|
|
186
|
+
/>
|
|
187
|
+
</div>
|
|
188
|
+
</>
|
|
189
|
+
)
|
|
190
|
+
},
|
|
191
|
+
parameters: { docs: { source: { type: "code" } } },
|
|
192
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -48,13 +48,14 @@ export * from "./Table"
|
|
|
48
48
|
export * from "./Tabs"
|
|
49
49
|
export * from "./Tag"
|
|
50
50
|
export * from "./Text"
|
|
51
|
-
export * from "./TextField"
|
|
52
51
|
export * from "./TextArea"
|
|
53
52
|
export * from "./TextAreaField"
|
|
53
|
+
export * from "./TextField"
|
|
54
54
|
export * from "./Tile"
|
|
55
55
|
export * from "./TimeField"
|
|
56
|
+
export * from "./TitleBlockZen"
|
|
56
57
|
export * from "./ToggleSwitch"
|
|
57
58
|
export * from "./Tooltip"
|
|
58
|
-
export * from "./
|
|
59
|
-
export * from "./Workflow"
|
|
59
|
+
export * from "./VisuallyHidden"
|
|
60
60
|
export * from "./Well"
|
|
61
|
+
export * from "./Workflow"
|