@bronzelabs/oakma-ui 0.0.1 → 0.0.3
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/index.d.ts +345 -0
- package/dist/index.js +2 -0
- package/dist/oakma-ui.css +2 -0
- package/package.json +7 -2
- package/.prettierrc.cjs +0 -25
- package/.storybook/components/ActionButton.tsx +0 -44
- package/.storybook/components/DummyIcons.tsx +0 -47
- package/.storybook/components/index.ts +0 -2
- package/.storybook/docs/blocks/ImportStatement.tsx +0 -52
- package/.storybook/docs/blocks/index.ts +0 -1
- package/.storybook/docs/page.tsx +0 -41
- package/.storybook/main.ts +0 -21
- package/.storybook/postcss.config.cjs +0 -8
- package/.storybook/preview-body.html +0 -20
- package/.storybook/preview-head.html +0 -6
- package/.storybook/preview.tsx +0 -30
- package/.storybook/tailwind.css +0 -6
- package/.storybook/utils/index.ts +0 -2
- package/.storybook/utils/renderAsReact.tsx +0 -30
- package/.storybook/utils/renderDocsWithProps.tsx +0 -22
- package/@types/markdown.d.ts +0 -4
- package/eslint.config.js +0 -91
- package/postcss.config.cjs +0 -8
- package/scripts/release.sh +0 -76
- package/src/components/Button/Button.stories.tsx +0 -314
- package/src/components/Button/Button.tsx +0 -132
- package/src/components/Button/index.ts +0 -2
- package/src/components/Button/types.ts +0 -19
- package/src/components/Checkbox/Checkbox.stories.tsx +0 -152
- package/src/components/Checkbox/Checkbox.tsx +0 -90
- package/src/components/Checkbox/index.ts +0 -2
- package/src/components/Checkbox/types.ts +0 -6
- package/src/components/Chip/Chip.stories.tsx +0 -146
- package/src/components/Chip/Chip.tsx +0 -59
- package/src/components/Chip/index.ts +0 -2
- package/src/components/Chip/types.ts +0 -6
- package/src/components/Drawer/Drawer.docs.md +0 -88
- package/src/components/Drawer/Drawer.stories.tsx +0 -239
- package/src/components/Drawer/Drawer.tsx +0 -194
- package/src/components/Drawer/index.ts +0 -3
- package/src/components/Drawer/types.ts +0 -3
- package/src/components/Dropdown/AsyncDropdown.tsx +0 -105
- package/src/components/Dropdown/Dropdown.docs.md +0 -33
- package/src/components/Dropdown/Dropdown.stories.tsx +0 -419
- package/src/components/Dropdown/Dropdown.tsx +0 -104
- package/src/components/Dropdown/MultiValue.tsx +0 -19
- package/src/components/Dropdown/ValueContainer.tsx +0 -114
- package/src/components/Dropdown/index.ts +0 -4
- package/src/components/Dropdown/types.ts +0 -29
- package/src/components/Dropdown/useDropdown.tsx +0 -257
- package/src/components/Logo/Logo.stories.tsx +0 -130
- package/src/components/Logo/Logo.tsx +0 -80
- package/src/components/Logo/index.ts +0 -2
- package/src/components/Modal/Modal.docs.md +0 -94
- package/src/components/Modal/Modal.stories.tsx +0 -318
- package/src/components/Modal/Modal.tsx +0 -217
- package/src/components/Modal/index.ts +0 -1
- package/src/components/MultiSelect/AsyncMultiSelect.tsx +0 -47
- package/src/components/MultiSelect/MultiSelect.docs.md +0 -37
- package/src/components/MultiSelect/MultiSelect.stories.tsx +0 -493
- package/src/components/MultiSelect/MultiSelect.tsx +0 -81
- package/src/components/MultiSelect/index.ts +0 -2
- package/src/components/Notification/Notification.stories.tsx +0 -158
- package/src/components/Notification/Notification.tsx +0 -110
- package/src/components/Notification/index.ts +0 -1
- package/src/components/Notification/types.ts +0 -11
- package/src/components/Notifications/Notifications.docs.md +0 -103
- package/src/components/Notifications/Notifications.stories.tsx +0 -159
- package/src/components/Notifications/Notifications.tsx +0 -90
- package/src/components/Notifications/NotificationsContext.tsx +0 -90
- package/src/components/Notifications/index.ts +0 -7
- package/src/components/Select/Select.stories.tsx +0 -234
- package/src/components/Select/Select.tsx +0 -129
- package/src/components/Select/index.ts +0 -2
- package/src/components/Select/types.ts +0 -1
- package/src/components/Spinner/Spinner.stories.tsx +0 -55
- package/src/components/Spinner/Spinner.tsx +0 -48
- package/src/components/Spinner/index.ts +0 -2
- package/src/components/Spinner/types.ts +0 -8
- package/src/components/TextArea/TextArea.stories.tsx +0 -243
- package/src/components/TextArea/TextArea.tsx +0 -133
- package/src/components/TextArea/index.ts +0 -2
- package/src/components/TextArea/types.ts +0 -4
- package/src/components/TextField/Container.tsx +0 -68
- package/src/components/TextField/ErrorMessage.tsx +0 -37
- package/src/components/TextField/Icon.tsx +0 -77
- package/src/components/TextField/Label.tsx +0 -56
- package/src/components/TextField/NotchBorder.tsx +0 -67
- package/src/components/TextField/index.ts +0 -14
- package/src/components/TextField/types.ts +0 -15
- package/src/components/TextField/useInputKeyboardFocus.tsx +0 -63
- package/src/components/TextInput/TextInput.stories.tsx +0 -384
- package/src/components/TextInput/TextInput.tsx +0 -255
- package/src/components/TextInput/index.ts +0 -2
- package/src/components/TextInput/types.ts +0 -4
- package/src/components/Toggle/Toggle.stories.tsx +0 -142
- package/src/components/Toggle/Toggle.tsx +0 -69
- package/src/components/Toggle/index.ts +0 -1
- package/src/hooks/index.ts +0 -6
- package/src/hooks/useCombinedRefs.ts +0 -37
- package/src/hooks/useEventListener.ts +0 -87
- package/src/hooks/useFocusTrap/createAriaHider.ts +0 -62
- package/src/hooks/useFocusTrap/index.ts +0 -1
- package/src/hooks/useFocusTrap/scopeTab.ts +0 -46
- package/src/hooks/useFocusTrap/tabbable.ts +0 -107
- package/src/hooks/useFocusTrap/useFocusTrap.ts +0 -97
- package/src/hooks/useIsomorphicLayoutEffect.ts +0 -14
- package/src/hooks/useLockBodyScroll.ts +0 -24
- package/src/hooks/useOnClickOutside.ts +0 -53
- package/src/index.ts +0 -22
- package/src/tailwind.css +0 -4
- package/src/types/helpers.ts +0 -11
- package/src/types/polymorphic.ts +0 -39
- package/src/utils/animation/variants.ts +0 -21
- package/src/utils/array/index.ts +0 -1
- package/src/utils/array/uniqBy.ts +0 -12
- package/src/utils/common/index.ts +0 -1
- package/src/utils/common/isFunction.ts +0 -17
- package/src/utils/react/extractDisplayName.ts +0 -15
- package/src/utils/react/index.ts +0 -1
- package/tsconfig.json +0 -16
- package/tsconfig.production.json +0 -19
- package/tsup.config.ts +0 -16
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
|
|
3
|
-
// Components
|
|
4
|
-
import Notification from "./Notification"
|
|
5
|
-
|
|
6
|
-
// Types
|
|
7
|
-
import type { Meta, StoryFn } from "@storybook/react-webpack5"
|
|
8
|
-
import type { NotificationProps } from "./Notification"
|
|
9
|
-
import { NOTIFICATION_VARIANTS } from "./types"
|
|
10
|
-
|
|
11
|
-
// Utils
|
|
12
|
-
import { DummyPhoneIcon } from "../../../.storybook/components"
|
|
13
|
-
|
|
14
|
-
/*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
const meta: Meta<NotificationProps> = {
|
|
22
|
-
title: "Components/Notification",
|
|
23
|
-
component: Notification,
|
|
24
|
-
parameters: {
|
|
25
|
-
docs: {
|
|
26
|
-
description: {
|
|
27
|
-
component:
|
|
28
|
-
"A notification banner used to surface messages, alerts, or status updates to the user.",
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
controls: {
|
|
32
|
-
exclude: ["className", "ref", "leadingIcon"],
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
argTypes: {
|
|
36
|
-
variant: {
|
|
37
|
-
type: "string",
|
|
38
|
-
description: "Visual variant of the Notification.",
|
|
39
|
-
table: {
|
|
40
|
-
type: { summary: NOTIFICATION_VARIANTS.map(v => `"${v}"`).join(" | ") },
|
|
41
|
-
defaultValue: { summary: '"default"' },
|
|
42
|
-
},
|
|
43
|
-
options: NOTIFICATION_VARIANTS,
|
|
44
|
-
control: { type: "select" },
|
|
45
|
-
},
|
|
46
|
-
text: {
|
|
47
|
-
type: "string",
|
|
48
|
-
description: "The primary message text.",
|
|
49
|
-
table: {
|
|
50
|
-
type: { summary: "React.ReactNode" },
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
subText: {
|
|
54
|
-
type: "string",
|
|
55
|
-
description: "Optional secondary message displayed below the primary text.",
|
|
56
|
-
table: {
|
|
57
|
-
type: { summary: "React.ReactNode" },
|
|
58
|
-
defaultValue: { summary: "undefined" },
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
onClose: {
|
|
62
|
-
description: "When provided, renders a dismiss button that calls this handler.",
|
|
63
|
-
table: {
|
|
64
|
-
type: { summary: "() => void" },
|
|
65
|
-
defaultValue: { summary: "undefined" },
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
args: {
|
|
70
|
-
text: "Notification message here",
|
|
71
|
-
variant: "default",
|
|
72
|
-
},
|
|
73
|
-
decorators: [
|
|
74
|
-
Story => (
|
|
75
|
-
<div style={{ width: 350 }}>
|
|
76
|
-
<Story />
|
|
77
|
-
</div>
|
|
78
|
-
),
|
|
79
|
-
],
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const Template: StoryFn<NotificationProps> = args => <Notification {...args} />
|
|
83
|
-
|
|
84
|
-
const Default = Template.bind({})
|
|
85
|
-
const Dark = Template.bind({})
|
|
86
|
-
const WithLeadingIcon = Template.bind({})
|
|
87
|
-
const WithSubText = Template.bind({})
|
|
88
|
-
const WithAllFeatures = Template.bind({})
|
|
89
|
-
|
|
90
|
-
// Args
|
|
91
|
-
Default.args = {
|
|
92
|
-
onClose: () => {},
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
Dark.args = {
|
|
96
|
-
variant: "dark",
|
|
97
|
-
onClose: () => {},
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
WithLeadingIcon.args = {
|
|
101
|
-
leadingIcon: <DummyPhoneIcon />,
|
|
102
|
-
onClose: () => {},
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
WithSubText.args = {
|
|
106
|
-
subText: "Sub-text message here.",
|
|
107
|
-
onClose: () => {},
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
WithAllFeatures.args = {
|
|
111
|
-
leadingIcon: <DummyPhoneIcon />,
|
|
112
|
-
subText: "Sub-text message here.",
|
|
113
|
-
onClose: () => {},
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Parameters
|
|
117
|
-
Default.parameters = {
|
|
118
|
-
docs: {
|
|
119
|
-
description: {
|
|
120
|
-
story: "Default light notification with a dismiss button.",
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
Dark.parameters = {
|
|
126
|
-
docs: {
|
|
127
|
-
description: {
|
|
128
|
-
story: 'Dark teal variant. Pass `variant="dark"` to enable.',
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
WithLeadingIcon.parameters = {
|
|
134
|
-
docs: {
|
|
135
|
-
description: {
|
|
136
|
-
story: "Pass any React node to `leadingIcon` to render an icon before the message.",
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
WithSubText.parameters = {
|
|
142
|
-
docs: {
|
|
143
|
-
description: {
|
|
144
|
-
story: "Provide `subText` to render a secondary line of smaller text beneath the message.",
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
WithAllFeatures.parameters = {
|
|
150
|
-
docs: {
|
|
151
|
-
description: {
|
|
152
|
-
story: "Leading icon, primary message, sub-text, and dismiss button all together.",
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export { Default, Dark, WithLeadingIcon, WithSubText, WithAllFeatures }
|
|
158
|
-
export default meta
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
|
|
3
|
-
// Components
|
|
4
|
-
import { XMarkIcon } from "@heroicons/react/20/solid"
|
|
5
|
-
|
|
6
|
-
// Types
|
|
7
|
-
import { NotificationVariant } from "./types"
|
|
8
|
-
|
|
9
|
-
// Utils
|
|
10
|
-
import clsx from "clsx"
|
|
11
|
-
|
|
12
|
-
// Params
|
|
13
|
-
interface NotificationProps extends Omit<React.ComponentPropsWithRef<"div">, "children"> {
|
|
14
|
-
variant?: NotificationVariant
|
|
15
|
-
leadingIcon?: React.ReactNode
|
|
16
|
-
text: string
|
|
17
|
-
subText?: string | React.ReactNode
|
|
18
|
-
onClose?: () => void
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface NotificationData extends Pick<NotificationProps, "variant" | "text" | "subText"> {
|
|
22
|
-
/** The id of the Notification. */
|
|
23
|
-
id: string
|
|
24
|
-
/** Time that the notification was added. */
|
|
25
|
-
timestamp: number
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/*
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
const Notification: React.FC<NotificationProps> = ({
|
|
36
|
-
variant = "default",
|
|
37
|
-
text,
|
|
38
|
-
subText,
|
|
39
|
-
leadingIcon,
|
|
40
|
-
onClose,
|
|
41
|
-
className,
|
|
42
|
-
...rest
|
|
43
|
-
}) => {
|
|
44
|
-
return (
|
|
45
|
-
<div
|
|
46
|
-
className={clsx(
|
|
47
|
-
"flex w-full items-start gap-2 rounded-2xl border px-4 py-3 shadow-md",
|
|
48
|
-
variant === "default" && "border-stroke-dark bg-white",
|
|
49
|
-
variant === "dark" && "border-transparent bg-teal-100",
|
|
50
|
-
className,
|
|
51
|
-
)}
|
|
52
|
-
{...rest}
|
|
53
|
-
>
|
|
54
|
-
{leadingIcon && (
|
|
55
|
-
<span
|
|
56
|
-
className={clsx(
|
|
57
|
-
"mt-0.5 size-5 shrink-0",
|
|
58
|
-
variant === "default" && "text-teal-100",
|
|
59
|
-
variant === "dark" && "text-white",
|
|
60
|
-
)}
|
|
61
|
-
>
|
|
62
|
-
{leadingIcon}
|
|
63
|
-
</span>
|
|
64
|
-
)}
|
|
65
|
-
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
|
66
|
-
<p
|
|
67
|
-
className={clsx(
|
|
68
|
-
"text-sm font-medium tracking-[-0.14px]",
|
|
69
|
-
variant === "default" && "text-neutral-100",
|
|
70
|
-
variant === "dark" && "text-white",
|
|
71
|
-
)}
|
|
72
|
-
>
|
|
73
|
-
{text}
|
|
74
|
-
</p>
|
|
75
|
-
{subText && (
|
|
76
|
-
<p
|
|
77
|
-
className={clsx(
|
|
78
|
-
"text-xs",
|
|
79
|
-
variant === "default" && "text-neutral-50",
|
|
80
|
-
variant === "dark" && "text-teal-10",
|
|
81
|
-
)}
|
|
82
|
-
>
|
|
83
|
-
{subText}
|
|
84
|
-
</p>
|
|
85
|
-
)}
|
|
86
|
-
</div>
|
|
87
|
-
|
|
88
|
-
{onClose && (
|
|
89
|
-
<button
|
|
90
|
-
type="button"
|
|
91
|
-
onClick={onClose}
|
|
92
|
-
aria-label="Dismiss notification"
|
|
93
|
-
className={clsx(
|
|
94
|
-
"flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-full transition-colors ease-out",
|
|
95
|
-
variant === "default" &&
|
|
96
|
-
"text-neutral-50 hover:bg-neutral-50/10 hover:text-neutral-100 focus-visible:bg-neutral-50/10 focus-visible:text-neutral-100 active:bg-neutral-50/20",
|
|
97
|
-
variant === "dark" &&
|
|
98
|
-
"text-white/70 hover:bg-white/10 hover:text-white focus-visible:bg-white/10 focus-visible:text-white active:bg-white/20",
|
|
99
|
-
)}
|
|
100
|
-
>
|
|
101
|
-
<XMarkIcon className="size-5" />
|
|
102
|
-
</button>
|
|
103
|
-
)}
|
|
104
|
-
</div>
|
|
105
|
-
)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
Notification.displayName = "Notification"
|
|
109
|
-
export default Notification
|
|
110
|
-
export type { NotificationProps, NotificationData }
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default, type NotificationProps, type NotificationData } from "./Notification"
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
## Usage
|
|
2
|
-
|
|
3
|
-
To being, wrap you entire application in `NotificationsProvider`. This will provide the context for the notifications to be displayed and allow the adding and removing of notifications from anywhere in the app:
|
|
4
|
-
|
|
5
|
-
```tsx
|
|
6
|
-
import { NotificationsProvider } from "@bronzelabs/oakma-ui"
|
|
7
|
-
|
|
8
|
-
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
9
|
-
return (
|
|
10
|
-
<html lang="en">
|
|
11
|
-
<body>
|
|
12
|
-
<NotificationsProvider>
|
|
13
|
-
<main>{children}</main>
|
|
14
|
-
</NotificationsProvider>
|
|
15
|
-
</body>
|
|
16
|
-
</html>
|
|
17
|
-
)
|
|
18
|
-
}
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
In most cases you'll want to display the notifications in their default, fixed position in the viewport. To do this, add the `Notifications` component to the layout of your app:
|
|
22
|
-
|
|
23
|
-
```tsx
|
|
24
|
-
import { NotificationsProvider, Notifications } from "@bronzelabs/oakma-ui"
|
|
25
|
-
|
|
26
|
-
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
27
|
-
return (
|
|
28
|
-
<html lang="en">
|
|
29
|
-
<body>
|
|
30
|
-
<NotificationsProvider>
|
|
31
|
-
<main>{children}</main>
|
|
32
|
-
<Notifications /> { /* <----- */ }
|
|
33
|
-
</NotificationsProvider>
|
|
34
|
-
</body>
|
|
35
|
-
</html>
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### Adding a notification
|
|
41
|
-
|
|
42
|
-
To add a notification, use the `useNotifications` hook to access the `addNotification` method. This accepts either a single or an array of `Notification` objects as its only argument. The `Notification` object has the following properties:
|
|
43
|
-
|
|
44
|
-
| Property | Type | Description |
|
|
45
|
-
| --------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
46
|
-
| `id` | `string` | A unique identifier for the notification. If not provided, one will be generated. |
|
|
47
|
-
| `text` | `string \| React.ReactNode` | Content to display inside the Notification. Can also be a ReactNode to allow passing of jsx with things like links. |
|
|
48
|
-
| `subText` | `string \| React.ReactNode` | Optional content to display below the main text. Can also be a ReactNode. |
|
|
49
|
-
| `variant` | `"default"` \| `"dark"` | The style variant of the Notification. Currently just controls light/dark. |
|
|
50
|
-
|
|
51
|
-
```tsx
|
|
52
|
-
"use client"
|
|
53
|
-
|
|
54
|
-
import { useNotifications } from "@bronzelabs/oakma-ui"
|
|
55
|
-
|
|
56
|
-
export default function MyComponent() {
|
|
57
|
-
const { addNotification } = useNotifications()
|
|
58
|
-
|
|
59
|
-
function handleClick() {
|
|
60
|
-
addNotification({
|
|
61
|
-
text: "This is a success notification",
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return <button onClick={handleClick}>Add notification</button>
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
You can also pass an optional second argument to `addNotification` to specify whether the notification should automatically dismiss after a certain amount of time. By default, notifications will automatically dismiss after 5 seconds. To disable this behavior, pass `false` as the second argument:
|
|
70
|
-
|
|
71
|
-
```tsx
|
|
72
|
-
export default function MyComponent() {
|
|
73
|
-
// {/* ... */}
|
|
74
|
-
|
|
75
|
-
function handleClick() {
|
|
76
|
-
addNotification({
|
|
77
|
-
text: "This notification will not automatically dismiss",
|
|
78
|
-
}, false)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// {/* ... */}
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Removing a notification
|
|
86
|
-
|
|
87
|
-
To remove a notification, use the `useNotifications` hook to access the `removeNotification` method. This function accepts the `id` of the notification you want to remove as its only argument.
|
|
88
|
-
|
|
89
|
-
```tsx
|
|
90
|
-
"use client"
|
|
91
|
-
|
|
92
|
-
import { useNotifications } from "@bronzelabs/oakma-ui"
|
|
93
|
-
|
|
94
|
-
export default function MyComponent() {
|
|
95
|
-
const { removeNotification } = useNotifications()
|
|
96
|
-
|
|
97
|
-
function handleClick() {
|
|
98
|
-
removeNotification("1")
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return <button onClick={handleClick}>Remove notification</button>
|
|
102
|
-
}
|
|
103
|
-
```
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import React, { useEffect } from "react"
|
|
2
|
-
|
|
3
|
-
// Components
|
|
4
|
-
import Notifications, { type NotificationsProps } from "./Notifications"
|
|
5
|
-
import Notification, { type NotificationData } from "../Notification"
|
|
6
|
-
import { NotificationsProvider, useNotifications } from "./NotificationsContext"
|
|
7
|
-
|
|
8
|
-
// Types
|
|
9
|
-
import type { StoryFn, Meta } from "@storybook/react-webpack5"
|
|
10
|
-
import type { PickPartial } from "../../types/helpers"
|
|
11
|
-
|
|
12
|
-
// Utils
|
|
13
|
-
import { StorybookActionButton } from "../../../.storybook/components"
|
|
14
|
-
import extraDocs from "./Notifications.docs.md"
|
|
15
|
-
import { renderDocsWithProps } from "../../../.storybook/utils"
|
|
16
|
-
|
|
17
|
-
// Data
|
|
18
|
-
const data: PickPartial<NotificationData, "id" | "timestamp">[] = [
|
|
19
|
-
{
|
|
20
|
-
text: "This is the first notification",
|
|
21
|
-
subText: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
text: "This is the second notification",
|
|
25
|
-
subText: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
text: "This is the third notification",
|
|
29
|
-
subText: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
|
30
|
-
},
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
/*
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
const meta = {
|
|
41
|
-
title: "Components/Notifications",
|
|
42
|
-
component: Notifications,
|
|
43
|
-
subcomponents: { Notification },
|
|
44
|
-
parameters: {
|
|
45
|
-
docs: {
|
|
46
|
-
page: renderDocsWithProps({ extraDocs }),
|
|
47
|
-
},
|
|
48
|
-
controls: {
|
|
49
|
-
exclude: ["className", "ref", "children"],
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
argTypes: {
|
|
53
|
-
isDisismissable: {
|
|
54
|
-
type: "boolean",
|
|
55
|
-
description: "Whether the notifications can be dismissed by an internal `X` button or not",
|
|
56
|
-
table: {
|
|
57
|
-
type: { summary: "boolean" },
|
|
58
|
-
defaultValue: { summary: "false" },
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
args: {
|
|
63
|
-
isDisismissable: false,
|
|
64
|
-
},
|
|
65
|
-
decorators: [
|
|
66
|
-
Story => (
|
|
67
|
-
<div style={{ width: 400 }}>
|
|
68
|
-
<Story />
|
|
69
|
-
</div>
|
|
70
|
-
),
|
|
71
|
-
],
|
|
72
|
-
} satisfies Meta<typeof Notifications>
|
|
73
|
-
|
|
74
|
-
// Templates
|
|
75
|
-
const Template: StoryFn<NotificationsProps> = args => {
|
|
76
|
-
const { addNotification } = useNotifications()
|
|
77
|
-
|
|
78
|
-
useEffect(() => addNotification(data, false), [addNotification])
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<Notifications
|
|
82
|
-
{...args}
|
|
83
|
-
/**
|
|
84
|
-
* Position in the main app is fixed to the top right corner, however, in storybook
|
|
85
|
-
* this is positioning it outside the relevant container, therefore, its position
|
|
86
|
-
* needs to be reset.
|
|
87
|
-
*/
|
|
88
|
-
style={{
|
|
89
|
-
position: "relative",
|
|
90
|
-
top: "auto",
|
|
91
|
-
right: "auto",
|
|
92
|
-
bottom: "auto",
|
|
93
|
-
left: "auto",
|
|
94
|
-
}}
|
|
95
|
-
/>
|
|
96
|
-
)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Stories
|
|
100
|
-
const Default = Template.bind({})
|
|
101
|
-
const Dismissable = Template.bind({})
|
|
102
|
-
const Playground = Template.bind({})
|
|
103
|
-
|
|
104
|
-
// Args
|
|
105
|
-
Dismissable.args = {
|
|
106
|
-
isDisismissable: true,
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
Playground.args = {
|
|
110
|
-
isDisismissable: true,
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Decorators
|
|
114
|
-
Default.decorators = [Story => <NotificationsProvider>{<Story />}</NotificationsProvider>]
|
|
115
|
-
|
|
116
|
-
Dismissable.decorators = [Story => <NotificationsProvider>{<Story />}</NotificationsProvider>]
|
|
117
|
-
|
|
118
|
-
Playground.decorators = [
|
|
119
|
-
Story => {
|
|
120
|
-
const { notifications, addNotification, removeNotification } = useNotifications()
|
|
121
|
-
|
|
122
|
-
return (
|
|
123
|
-
<div>
|
|
124
|
-
{<Story />}
|
|
125
|
-
<div
|
|
126
|
-
style={{
|
|
127
|
-
marginTop: 48,
|
|
128
|
-
display: "flex",
|
|
129
|
-
alignItems: "center",
|
|
130
|
-
justifyContent: "center",
|
|
131
|
-
gap: 16,
|
|
132
|
-
}}
|
|
133
|
-
>
|
|
134
|
-
<StorybookActionButton
|
|
135
|
-
onClick={() =>
|
|
136
|
-
addNotification(
|
|
137
|
-
{
|
|
138
|
-
text: "This is a dummy notification",
|
|
139
|
-
subText: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
|
140
|
-
variant: Math.round(Math.random()) > 0 ? "default" : "dark",
|
|
141
|
-
},
|
|
142
|
-
false,
|
|
143
|
-
)
|
|
144
|
-
}
|
|
145
|
-
>
|
|
146
|
-
Add
|
|
147
|
-
</StorybookActionButton>
|
|
148
|
-
<StorybookActionButton onClick={() => removeNotification(notifications.at(0)?.id)}>
|
|
149
|
-
Remove
|
|
150
|
-
</StorybookActionButton>
|
|
151
|
-
</div>
|
|
152
|
-
</div>
|
|
153
|
-
)
|
|
154
|
-
},
|
|
155
|
-
Story => <NotificationsProvider>{<Story />}</NotificationsProvider>,
|
|
156
|
-
]
|
|
157
|
-
|
|
158
|
-
export default meta
|
|
159
|
-
export { Default, Dismissable, Playground }
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import React, { useCallback } from "react"
|
|
4
|
-
|
|
5
|
-
// Components
|
|
6
|
-
import Notification from "../Notification"
|
|
7
|
-
|
|
8
|
-
// Types
|
|
9
|
-
|
|
10
|
-
// Utils
|
|
11
|
-
import clsx from "clsx"
|
|
12
|
-
import { useNotifications } from "./NotificationsContext"
|
|
13
|
-
import { motion, AnimatePresence, type Variants } from "motion/react"
|
|
14
|
-
|
|
15
|
-
// Props
|
|
16
|
-
interface NotificationsProps extends React.ComponentProps<"div"> {
|
|
17
|
-
isDisismissable?: boolean
|
|
18
|
-
children?: never
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const notificationVariants: Variants = {
|
|
22
|
-
initial: {
|
|
23
|
-
opacity: 0,
|
|
24
|
-
y: 15,
|
|
25
|
-
},
|
|
26
|
-
animate: {
|
|
27
|
-
opacity: 1,
|
|
28
|
-
y: 0,
|
|
29
|
-
transition: {
|
|
30
|
-
ease: "easeOut",
|
|
31
|
-
duration: 0.15,
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
exit: {
|
|
35
|
-
opacity: 0,
|
|
36
|
-
x: "4rem",
|
|
37
|
-
transition: {
|
|
38
|
-
ease: "easeOut",
|
|
39
|
-
duration: 0.15,
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/*
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
*/
|
|
50
|
-
|
|
51
|
-
const Notifications: React.FC<NotificationsProps> = ({ className, isDisismissable, ...rest }) => {
|
|
52
|
-
// State
|
|
53
|
-
const { notifications: data, removeNotification } = useNotifications()
|
|
54
|
-
|
|
55
|
-
// Functions
|
|
56
|
-
const handleRemove = useCallback(
|
|
57
|
-
(id: string) => () => removeNotification(id),
|
|
58
|
-
[removeNotification],
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<div
|
|
63
|
-
className={clsx(
|
|
64
|
-
"w-[min(25rem, 96vw)] fixed inset-x-[2vw] top-0 z-9999 md:top-6 md:right-6 md:left-auto",
|
|
65
|
-
className,
|
|
66
|
-
)}
|
|
67
|
-
{...rest}
|
|
68
|
-
>
|
|
69
|
-
<AnimatePresence>
|
|
70
|
-
{data?.map(item => (
|
|
71
|
-
<motion.div
|
|
72
|
-
key={item.id}
|
|
73
|
-
className="my-3 w-full min-w-82 select-none"
|
|
74
|
-
initial="initial"
|
|
75
|
-
animate="animate"
|
|
76
|
-
exit="exit"
|
|
77
|
-
variants={notificationVariants}
|
|
78
|
-
layout
|
|
79
|
-
>
|
|
80
|
-
<Notification {...item} onClose={isDisismissable ? handleRemove(item.id) : undefined} />
|
|
81
|
-
</motion.div>
|
|
82
|
-
))}
|
|
83
|
-
</AnimatePresence>
|
|
84
|
-
</div>
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
Notifications.displayName = "Notifications"
|
|
89
|
-
export default Notifications
|
|
90
|
-
export type { NotificationsProps }
|