@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,146 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
|
|
3
|
-
// Components
|
|
4
|
-
import Chip from "./Chip"
|
|
5
|
-
|
|
6
|
-
// Types
|
|
7
|
-
import type { Meta, StoryFn } from "@storybook/react-webpack5"
|
|
8
|
-
import type { ChipProps } from "./Chip"
|
|
9
|
-
import { CHIP_SIZES } from "./types"
|
|
10
|
-
|
|
11
|
-
// Utils
|
|
12
|
-
import { DummyPhoneIcon } from "../../../.storybook/components"
|
|
13
|
-
|
|
14
|
-
/*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
const meta: Meta<ChipProps> = {
|
|
22
|
-
title: "Components/Chip",
|
|
23
|
-
component: Chip,
|
|
24
|
-
parameters: {
|
|
25
|
-
docs: {
|
|
26
|
-
description: {
|
|
27
|
-
component: "A compact label used to categorise, filter, or provide status context.",
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
controls: {
|
|
31
|
-
exclude: ["className", "ref"],
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
argTypes: {
|
|
35
|
-
size: {
|
|
36
|
-
type: "string",
|
|
37
|
-
description: "Size of the Chip.",
|
|
38
|
-
table: {
|
|
39
|
-
type: {
|
|
40
|
-
summary: Object.keys(CHIP_SIZES)
|
|
41
|
-
.map(s => `"${s}"`)
|
|
42
|
-
.join(" | "),
|
|
43
|
-
},
|
|
44
|
-
defaultValue: {
|
|
45
|
-
summary: `"sm"`,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
options: Object.keys(CHIP_SIZES),
|
|
49
|
-
control: { type: "select" },
|
|
50
|
-
},
|
|
51
|
-
children: {
|
|
52
|
-
type: "string",
|
|
53
|
-
description: "The label text to display inside the Chip.",
|
|
54
|
-
table: {
|
|
55
|
-
type: { summary: "React.ReactNode" },
|
|
56
|
-
defaultValue: { summary: "undefined" },
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
count: {
|
|
60
|
-
description: "Displays a count badge before the label.",
|
|
61
|
-
table: {
|
|
62
|
-
type: { summary: "number | string" },
|
|
63
|
-
defaultValue: { summary: "undefined" },
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
args: {
|
|
68
|
-
size: "sm",
|
|
69
|
-
children: "Label",
|
|
70
|
-
},
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const Template: StoryFn<ChipProps> = args => <Chip {...args} />
|
|
74
|
-
|
|
75
|
-
const SizesTemplate: StoryFn<ChipProps> = args => (
|
|
76
|
-
<>
|
|
77
|
-
<Chip {...args} size="sm">
|
|
78
|
-
Small
|
|
79
|
-
</Chip>
|
|
80
|
-
<Chip {...args} size="lg">
|
|
81
|
-
Large
|
|
82
|
-
</Chip>
|
|
83
|
-
</>
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
const Default = Template.bind({})
|
|
87
|
-
const Sizes = SizesTemplate.bind({})
|
|
88
|
-
const WithLeadingIcon = Template.bind({})
|
|
89
|
-
const WithTrailingIcon = Template.bind({})
|
|
90
|
-
const WithCount = Template.bind({})
|
|
91
|
-
|
|
92
|
-
// Args
|
|
93
|
-
WithLeadingIcon.args = { leadingIcon: <DummyPhoneIcon /> }
|
|
94
|
-
WithTrailingIcon.args = { trailingIcon: <DummyPhoneIcon /> }
|
|
95
|
-
WithCount.args = { count: 2 }
|
|
96
|
-
|
|
97
|
-
// Parameters
|
|
98
|
-
Sizes.parameters = {
|
|
99
|
-
docs: {
|
|
100
|
-
description: {
|
|
101
|
-
story: 'Chip renders in two sizes (`"sm"`, `"lg"`). Default is `"sm"`.',
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
WithLeadingIcon.parameters = {
|
|
107
|
-
docs: {
|
|
108
|
-
description: {
|
|
109
|
-
story: "Pass any React node to `leadingIcon` to render an icon before the label.",
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
WithTrailingIcon.parameters = {
|
|
115
|
-
docs: {
|
|
116
|
-
description: {
|
|
117
|
-
story: "Pass any React node to `trailingIcon` to render an icon after the label.",
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
WithCount.parameters = {
|
|
123
|
-
docs: {
|
|
124
|
-
description: {
|
|
125
|
-
story:
|
|
126
|
-
"Passing a `count` prop renders a small badge before the label, useful for indicating quantities.",
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Decorators
|
|
132
|
-
Default.decorators = [
|
|
133
|
-
Story => (
|
|
134
|
-
<div className="flex flex-wrap items-center gap-4">
|
|
135
|
-
<Story />
|
|
136
|
-
</div>
|
|
137
|
-
),
|
|
138
|
-
]
|
|
139
|
-
|
|
140
|
-
Sizes.decorators = [...Default.decorators]
|
|
141
|
-
WithLeadingIcon.decorators = [...Default.decorators]
|
|
142
|
-
WithTrailingIcon.decorators = [...Default.decorators]
|
|
143
|
-
WithCount.decorators = [...Default.decorators]
|
|
144
|
-
|
|
145
|
-
export { Default, Sizes, WithLeadingIcon, WithTrailingIcon, WithCount }
|
|
146
|
-
export default meta
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
|
|
3
|
-
// Types
|
|
4
|
-
import type { ChipSize } from "./types"
|
|
5
|
-
|
|
6
|
-
// Utils
|
|
7
|
-
import { clsx } from "clsx"
|
|
8
|
-
|
|
9
|
-
// Params
|
|
10
|
-
export interface ChipProps extends React.ComponentPropsWithRef<"div"> {
|
|
11
|
-
size?: ChipSize
|
|
12
|
-
leadingIcon?: React.ReactNode
|
|
13
|
-
trailingIcon?: React.ReactNode
|
|
14
|
-
count?: number | string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/*
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
const Chip: React.FC<ChipProps> = ({
|
|
26
|
-
size = "sm",
|
|
27
|
-
leadingIcon,
|
|
28
|
-
trailingIcon,
|
|
29
|
-
count,
|
|
30
|
-
children,
|
|
31
|
-
className,
|
|
32
|
-
ref,
|
|
33
|
-
...rest
|
|
34
|
-
}) => {
|
|
35
|
-
return (
|
|
36
|
-
<div
|
|
37
|
-
ref={ref}
|
|
38
|
-
className={clsx(
|
|
39
|
-
"inline-flex items-center gap-1 rounded-full bg-teal-100/20 font-medium whitespace-nowrap text-teal-100",
|
|
40
|
-
size === "sm" && "h-6 px-2 text-xs/3",
|
|
41
|
-
size === "lg" && "tracking-heading h-8 px-3 text-sm/6",
|
|
42
|
-
className,
|
|
43
|
-
)}
|
|
44
|
-
{...rest}
|
|
45
|
-
>
|
|
46
|
-
{leadingIcon && <span className="size-4 shrink-0">{leadingIcon}</span>}
|
|
47
|
-
{count !== undefined && (
|
|
48
|
-
<span className="flex size-4 shrink-0 items-center justify-center rounded-full bg-teal-100 text-xs/3 text-white">
|
|
49
|
-
{count}
|
|
50
|
-
</span>
|
|
51
|
-
)}
|
|
52
|
-
{children}
|
|
53
|
-
{trailingIcon && <span className="size-4 shrink-0">{trailingIcon}</span>}
|
|
54
|
-
</div>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
Chip.displayName = "Chip"
|
|
59
|
-
export default Chip
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
## Usage
|
|
2
|
-
|
|
3
|
-
The `Drawer` component's state is controlled by the `isOpen` and `onClose` props.
|
|
4
|
-
|
|
5
|
-
<br>
|
|
6
|
-
|
|
7
|
-
### Opening/Closing the Drawer
|
|
8
|
-
|
|
9
|
-
To open and close the `Drawer`, create an external state that determines when the drawer is open:
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
"use client"
|
|
13
|
-
|
|
14
|
-
import { useState } from "react"
|
|
15
|
-
import { Drawer } from "@bronnzelabs/oakma-ui"
|
|
16
|
-
|
|
17
|
-
export default function Page() {
|
|
18
|
-
const [isOpen, setIsOpen] = useState<boolean>(false)
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<>
|
|
22
|
-
<button onClick={() => setIsOpen(true)}>Open drawer</button>
|
|
23
|
-
<Drawer isOpen={isOpen} onClose={() => setIsOpen(false)}>
|
|
24
|
-
<div className="p-6">
|
|
25
|
-
<p>Some content</p>
|
|
26
|
-
</div>
|
|
27
|
-
</Drawer>
|
|
28
|
-
</>
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
By default, `onClose` is called when the close button is clicked, when the user clicks outside the drawer, or when the Escape key is pressed.
|
|
34
|
-
|
|
35
|
-
### Position
|
|
36
|
-
|
|
37
|
-
Use the `position` prop to control which edge of the screen the Drawer slides in from. Accepted values are `"top"`, `"right"`, `"bottom"`, and `"left"` (default `"left"`).
|
|
38
|
-
|
|
39
|
-
```tsx
|
|
40
|
-
"use client"
|
|
41
|
-
|
|
42
|
-
import { useState } from "react"
|
|
43
|
-
import { Drawer } from "@bronnzelabs/oakma-ui"
|
|
44
|
-
|
|
45
|
-
export default function Page() {
|
|
46
|
-
const [isOpen, setIsOpen] = useState<boolean>(false)
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<>
|
|
50
|
-
<button onClick={() => setIsOpen(true)}>Open drawer</button>
|
|
51
|
-
<Drawer position="right" isOpen={isOpen} onClose={() => setIsOpen(false)}>
|
|
52
|
-
<div className="p-6">
|
|
53
|
-
<p>Some content</p>
|
|
54
|
-
</div>
|
|
55
|
-
</Drawer>
|
|
56
|
-
</>
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Handling Focus
|
|
62
|
-
|
|
63
|
-
By default, the `trapFocus` prop is set to `true`. This traps keyboard focus within the drawer, preventing the user from focusing outside it until it is closed.
|
|
64
|
-
|
|
65
|
-
If you want to set the initial focus to a specific element inside the drawer, add the `data-autofocus` prop to it.
|
|
66
|
-
|
|
67
|
-
```tsx
|
|
68
|
-
"use client"
|
|
69
|
-
|
|
70
|
-
import { useState } from "react"
|
|
71
|
-
import { Drawer } from "@bronnzelabs/oakma-ui"
|
|
72
|
-
|
|
73
|
-
export default function Page() {
|
|
74
|
-
const [isOpen, setIsOpen] = useState<boolean>(false)
|
|
75
|
-
|
|
76
|
-
return (
|
|
77
|
-
<>
|
|
78
|
-
<button onClick={() => setIsOpen(true)}>Open drawer</button>
|
|
79
|
-
<Drawer isOpen={isOpen} onClose={() => setIsOpen(false)}>
|
|
80
|
-
<form className="p-6">
|
|
81
|
-
<input type="text" data-autofocus /> {/* <--- this will be focused first */}
|
|
82
|
-
<button onClick={() => setIsOpen(false)}>Submit</button>
|
|
83
|
-
</form>
|
|
84
|
-
</Drawer>
|
|
85
|
-
</>
|
|
86
|
-
)
|
|
87
|
-
}
|
|
88
|
-
```
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react"
|
|
2
|
-
|
|
3
|
-
// Components
|
|
4
|
-
import Drawer from "./Drawer"
|
|
5
|
-
import Modal from "../Modal"
|
|
6
|
-
|
|
7
|
-
// Types
|
|
8
|
-
import type { StoryFn, Meta } from "@storybook/react-webpack5"
|
|
9
|
-
import type { DrawerProps } from "./Drawer"
|
|
10
|
-
import { DRAWER_POSITIONS } from "./types"
|
|
11
|
-
|
|
12
|
-
// Utils
|
|
13
|
-
import { StorybookActionButton } from "../../../.storybook/components"
|
|
14
|
-
import { renderDocsWithProps } from "../../../.storybook/utils"
|
|
15
|
-
import extraDocs from "./Drawer.docs.md"
|
|
16
|
-
|
|
17
|
-
/*
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
const config: Meta<typeof Drawer> = {
|
|
25
|
-
title: "Components/Drawer",
|
|
26
|
-
component: Drawer,
|
|
27
|
-
parameters: {
|
|
28
|
-
controls: {
|
|
29
|
-
exclude: ["ref", "children"],
|
|
30
|
-
},
|
|
31
|
-
docs: {
|
|
32
|
-
description: {
|
|
33
|
-
component: "A panel that slides in from any edge of the screen, rendered in a portal.",
|
|
34
|
-
},
|
|
35
|
-
page: renderDocsWithProps({ extraDocs }),
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
argTypes: {
|
|
39
|
-
position: {
|
|
40
|
-
type: "string",
|
|
41
|
-
description: "Side of the screen on which the Drawer will be opened.",
|
|
42
|
-
table: {
|
|
43
|
-
type: { summary: DRAWER_POSITIONS.map(v => `"${v}"`).join(" | ") },
|
|
44
|
-
defaultValue: { summary: "right" },
|
|
45
|
-
},
|
|
46
|
-
control: "select",
|
|
47
|
-
options: DRAWER_POSITIONS,
|
|
48
|
-
},
|
|
49
|
-
isOpen: {
|
|
50
|
-
type: "boolean",
|
|
51
|
-
description: "Whether the Drawer is open.",
|
|
52
|
-
table: {
|
|
53
|
-
type: { summary: "boolean" },
|
|
54
|
-
defaultValue: { summary: "false" },
|
|
55
|
-
},
|
|
56
|
-
control: false,
|
|
57
|
-
},
|
|
58
|
-
onClose: {
|
|
59
|
-
description: "Function called when the Drawer is closed.",
|
|
60
|
-
table: {
|
|
61
|
-
type: { summary: "() => void" },
|
|
62
|
-
},
|
|
63
|
-
control: false,
|
|
64
|
-
},
|
|
65
|
-
withBackdrop: {
|
|
66
|
-
type: "boolean",
|
|
67
|
-
description: "Whether the backdrop should be rendered.",
|
|
68
|
-
table: {
|
|
69
|
-
type: { summary: "boolean" },
|
|
70
|
-
defaultValue: { summary: "true" },
|
|
71
|
-
},
|
|
72
|
-
control: "boolean",
|
|
73
|
-
},
|
|
74
|
-
withCloseButton: {
|
|
75
|
-
type: "boolean",
|
|
76
|
-
description: "Whether the close button should be rendered.",
|
|
77
|
-
table: {
|
|
78
|
-
type: { summary: "boolean" },
|
|
79
|
-
defaultValue: { summary: "true" },
|
|
80
|
-
},
|
|
81
|
-
control: "boolean",
|
|
82
|
-
},
|
|
83
|
-
closeOnClickOutside: {
|
|
84
|
-
type: "boolean",
|
|
85
|
-
description: "Whether the Drawer should be closed when user clicks on the overlay.",
|
|
86
|
-
table: {
|
|
87
|
-
type: { summary: "boolean" },
|
|
88
|
-
defaultValue: { summary: "true" },
|
|
89
|
-
},
|
|
90
|
-
control: "boolean",
|
|
91
|
-
},
|
|
92
|
-
closeOnEscape: {
|
|
93
|
-
type: "boolean",
|
|
94
|
-
description: "Whether `onClose` should be called when user presses the escape key.",
|
|
95
|
-
table: {
|
|
96
|
-
type: { summary: "boolean" },
|
|
97
|
-
defaultValue: { summary: "true" },
|
|
98
|
-
},
|
|
99
|
-
control: "boolean",
|
|
100
|
-
},
|
|
101
|
-
lockScroll: {
|
|
102
|
-
type: "boolean",
|
|
103
|
-
description: "Whether scroll should be locked when `isOpen={true}`.",
|
|
104
|
-
table: {
|
|
105
|
-
type: { summary: "boolean" },
|
|
106
|
-
defaultValue: { summary: "true" },
|
|
107
|
-
},
|
|
108
|
-
control: "boolean",
|
|
109
|
-
},
|
|
110
|
-
trapFocus: {
|
|
111
|
-
type: "boolean",
|
|
112
|
-
description: "Whether focus should be trapped within the drawer when `isOpen={true}`.",
|
|
113
|
-
table: {
|
|
114
|
-
type: { summary: "boolean" },
|
|
115
|
-
defaultValue: { summary: "true" },
|
|
116
|
-
},
|
|
117
|
-
control: "boolean",
|
|
118
|
-
},
|
|
119
|
-
portal: {
|
|
120
|
-
description: "The portal the Drawer should be rendered inside.",
|
|
121
|
-
table: {
|
|
122
|
-
type: { summary: "Element | DocumentFragment" },
|
|
123
|
-
},
|
|
124
|
-
control: false,
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
args: {
|
|
128
|
-
position: "right",
|
|
129
|
-
withBackdrop: true,
|
|
130
|
-
withCloseButton: true,
|
|
131
|
-
closeOnClickOutside: true,
|
|
132
|
-
closeOnEscape: true,
|
|
133
|
-
lockScroll: true,
|
|
134
|
-
trapFocus: true,
|
|
135
|
-
},
|
|
136
|
-
decorators: [
|
|
137
|
-
(Story, context) => {
|
|
138
|
-
if (context.name === "Drawer With Modal") {
|
|
139
|
-
return <Story />
|
|
140
|
-
}
|
|
141
|
-
const [isOpen, setIsOpen] = useState(false)
|
|
142
|
-
return (
|
|
143
|
-
<>
|
|
144
|
-
<StorybookActionButton onClick={() => setIsOpen(true)}>Open Drawer</StorybookActionButton>
|
|
145
|
-
<Story args={{ ...context.args, isOpen: isOpen, onClose: () => setIsOpen(false) }} />
|
|
146
|
-
</>
|
|
147
|
-
)
|
|
148
|
-
},
|
|
149
|
-
],
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Templates
|
|
153
|
-
const Template: StoryFn<DrawerProps> = args => <Drawer {...args} />
|
|
154
|
-
|
|
155
|
-
const DrawerWithModalTemplate: StoryFn<DrawerProps> = args => {
|
|
156
|
-
const [drawerOpen, setDrawerOpen] = useState(false)
|
|
157
|
-
const [modalOpen, setModalOpen] = useState(false)
|
|
158
|
-
|
|
159
|
-
return (
|
|
160
|
-
<>
|
|
161
|
-
<StorybookActionButton onClick={() => setDrawerOpen(true)}>Open Drawer</StorybookActionButton>
|
|
162
|
-
<Drawer {...args} isOpen={drawerOpen} onClose={() => setDrawerOpen(false)}>
|
|
163
|
-
<div className="flex flex-col gap-4 p-6">
|
|
164
|
-
<StorybookActionButton onClick={() => setModalOpen(true)}>
|
|
165
|
-
Open Modal
|
|
166
|
-
</StorybookActionButton>
|
|
167
|
-
</div>
|
|
168
|
-
<Modal
|
|
169
|
-
isOpen={modalOpen}
|
|
170
|
-
onClose={() => setModalOpen(false)}
|
|
171
|
-
title="Test Modal"
|
|
172
|
-
subTitle="Close me and the drawer should stay open"
|
|
173
|
-
>
|
|
174
|
-
<div className="p-4">Modal Content</div>
|
|
175
|
-
</Modal>
|
|
176
|
-
</Drawer>
|
|
177
|
-
</>
|
|
178
|
-
)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Stories
|
|
182
|
-
const Default = Template.bind({})
|
|
183
|
-
const Scroll = Template.bind({})
|
|
184
|
-
const TrapFocus = Template.bind({})
|
|
185
|
-
const DrawerWithModal = DrawerWithModalTemplate.bind({})
|
|
186
|
-
|
|
187
|
-
// Args
|
|
188
|
-
Scroll.args = {
|
|
189
|
-
children: (
|
|
190
|
-
<div className="h-full overflow-scroll p-6">
|
|
191
|
-
{Array(100)
|
|
192
|
-
.fill(0)
|
|
193
|
-
.map((_, i) => (
|
|
194
|
-
// eslint-disable-next-line react/no-array-index-key
|
|
195
|
-
<p key={i}>Drawer with scroll</p>
|
|
196
|
-
))}
|
|
197
|
-
</div>
|
|
198
|
-
),
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
TrapFocus.args = {
|
|
202
|
-
children: (
|
|
203
|
-
<div className="flex flex-col gap-8 p-6">
|
|
204
|
-
<button>Button 1</button>
|
|
205
|
-
<button>Button 2</button>
|
|
206
|
-
<button>Button 3</button>
|
|
207
|
-
</div>
|
|
208
|
-
),
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Parameters
|
|
212
|
-
Scroll.parameters = {
|
|
213
|
-
docs: {
|
|
214
|
-
description: {
|
|
215
|
-
story: "The drawer panel itself is fixed-size; overflowing content automatically scrolls.",
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
TrapFocus.parameters = {
|
|
221
|
-
docs: {
|
|
222
|
-
description: {
|
|
223
|
-
story:
|
|
224
|
-
"When `trapFocus={true}`, keyboard focus cycles only between the focusable elements inside the open Drawer.",
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
DrawerWithModal.parameters = {
|
|
230
|
-
docs: {
|
|
231
|
-
description: {
|
|
232
|
-
story:
|
|
233
|
-
"Demonstrates that opening a Modal from inside the Drawer does not trigger the Drawer's `closeOnClickOutside` or `closeOnEscape` handlers — closing the Modal leaves the Drawer open.",
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export { Default, Scroll, TrapFocus, DrawerWithModal }
|
|
239
|
-
export default config
|