@hubspot/cms-component-library 0.1.0 → 0.2.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/components/componentLibrary/Accordion/AccordionContent/ContentFields.tsx +5 -3
- package/components/componentLibrary/Accordion/AccordionItem/StyleFields.tsx +5 -3
- package/components/componentLibrary/Accordion/AccordionItem/index.module.scss +2 -2
- package/components/componentLibrary/Accordion/AccordionItem/index.tsx +3 -3
- package/components/componentLibrary/Accordion/AccordionTitle/ContentFields.tsx +5 -3
- package/components/componentLibrary/Accordion/AccordionTitle/index.module.scss +2 -2
- package/components/componentLibrary/Accordion/stories/Accordion.stories.tsx +80 -1
- package/components/componentLibrary/Accordion/stories/AccordionDecorator.tsx +14 -14
- package/components/componentLibrary/Button/ContentFields.tsx +5 -3
- package/components/componentLibrary/Button/StyleFields.tsx +5 -3
- package/components/componentLibrary/Button/index.module.scss +22 -14
- package/components/componentLibrary/Button/index.tsx +6 -6
- package/components/componentLibrary/Button/stories/Button.AsButton.stories.tsx +30 -1
- package/components/componentLibrary/Button/stories/Button.AsLink.stories.tsx +38 -1
- package/components/componentLibrary/Button/stories/ButtonDecorator.tsx +1 -1
- package/components/componentLibrary/Card/StyleFields.tsx +5 -3
- package/components/componentLibrary/Card/stories/Card.stories.tsx +46 -1
- package/components/componentLibrary/Card/stories/CardDecorator.tsx +1 -1
- package/components/componentLibrary/Divider/ContentFields.tsx +5 -3
- package/components/componentLibrary/Divider/StyleFields.tsx +5 -3
- package/components/componentLibrary/Divider/index.module.scss +6 -6
- package/components/componentLibrary/Divider/index.tsx +7 -3
- package/components/componentLibrary/Divider/stories/Divider.stories.tsx +44 -50
- package/components/componentLibrary/Divider/stories/{DividerDecorator.module.css → DividerDecorator.module.scss} +5 -4
- package/components/componentLibrary/Divider/stories/DividerDecorator.tsx +1 -1
- package/components/componentLibrary/Divider/types.ts +3 -1
- package/components/componentLibrary/Drawer/hooks/index.tsx +13 -0
- package/components/componentLibrary/Drawer/index.module.scss +94 -0
- package/components/componentLibrary/Drawer/index.tsx +131 -0
- package/components/componentLibrary/Drawer/llm.txt +416 -0
- package/components/componentLibrary/Drawer/stories/Drawer.stories.tsx +512 -0
- package/components/componentLibrary/Drawer/stories/DrawerDecorator.module.scss +8 -0
- package/components/componentLibrary/Drawer/stories/DrawerDecorator.tsx +18 -0
- package/components/componentLibrary/Drawer/types.ts +25 -0
- package/components/componentLibrary/Flex/stories/FlexDecorator.tsx +1 -1
- package/components/componentLibrary/Flex/types.ts +3 -1
- package/components/componentLibrary/Grid/stories/Grid.stories.tsx +454 -152
- package/components/componentLibrary/Grid/stories/GridDecorator.tsx +2 -2
- package/components/componentLibrary/Heading/ContentFields.tsx +5 -3
- package/components/componentLibrary/Heading/StyleFields.tsx +11 -9
- package/components/componentLibrary/Heading/index.tsx +3 -3
- package/components/componentLibrary/Heading/llm.txt +8 -8
- package/components/componentLibrary/Heading/stories/Heading.stories.tsx +3 -3
- package/components/componentLibrary/Heading/stories/HeadingDecorator.tsx +1 -1
- package/components/componentLibrary/Heading/types.ts +4 -4
- package/components/componentLibrary/Icon/ContentFields.tsx +5 -3
- package/components/componentLibrary/Icon/stories/Icon.stories.tsx +1 -1
- package/components/componentLibrary/Icon/stories/IconDecorator.tsx +1 -1
- package/components/componentLibrary/Image/ContentFields.tsx +5 -3
- package/components/componentLibrary/Image/index.tsx +4 -4
- package/components/componentLibrary/Image/llm.txt +17 -17
- package/components/componentLibrary/Image/stories/Image.stories.tsx +61 -18
- package/components/componentLibrary/Image/stories/ImageDecorator.tsx +1 -1
- package/components/componentLibrary/Image/types.ts +2 -2
- package/components/componentLibrary/LanguageSwitcher/ContentFields.tsx +18 -0
- package/components/componentLibrary/LanguageSwitcher/LanguageOptions.module.scss +37 -0
- package/components/componentLibrary/LanguageSwitcher/LanguageOptions.tsx +65 -0
- package/components/componentLibrary/LanguageSwitcher/StyleFields.tsx +48 -0
- package/components/componentLibrary/LanguageSwitcher/_dummyData.tsx +247 -0
- package/components/componentLibrary/LanguageSwitcher/assets/Globe.tsx +16 -0
- package/components/componentLibrary/LanguageSwitcher/index.module.scss +58 -0
- package/components/componentLibrary/LanguageSwitcher/index.tsx +125 -0
- package/components/componentLibrary/LanguageSwitcher/llm.txt +380 -0
- package/components/componentLibrary/LanguageSwitcher/stories/LanguageSwitcher.stories.tsx +349 -0
- package/components/componentLibrary/LanguageSwitcher/stories/LanguageSwitcherDecorator.module.scss +5 -0
- package/components/componentLibrary/LanguageSwitcher/stories/LanguageSwitcherDecorator.tsx +8 -0
- package/components/componentLibrary/LanguageSwitcher/types.ts +48 -0
- package/components/componentLibrary/LanguageSwitcher/utils.tsx +38 -0
- package/components/componentLibrary/Link/ContentFields.tsx +5 -3
- package/components/componentLibrary/Link/StyleFields.tsx +5 -3
- package/components/componentLibrary/Link/index.module.scss +10 -0
- package/components/componentLibrary/Link/index.tsx +24 -14
- package/components/componentLibrary/Link/stories/Link.stories.tsx +35 -5
- package/components/componentLibrary/Link/stories/LinkDecorator.tsx +11 -1
- package/components/componentLibrary/Link/types.ts +22 -13
- package/components/componentLibrary/List/ContentFields.tsx +5 -3
- package/components/componentLibrary/List/ListItem/ContentFields.tsx +6 -17
- package/components/componentLibrary/List/ListItem/index.module.scss +1 -13
- package/components/componentLibrary/List/ListItem/index.tsx +3 -30
- package/components/componentLibrary/List/ListItem/types.ts +1 -16
- package/components/componentLibrary/List/StyleFields.tsx +15 -18
- package/components/componentLibrary/List/index.module.scss +3 -0
- package/components/componentLibrary/List/index.tsx +5 -2
- package/components/componentLibrary/List/llm.txt +73 -103
- package/components/componentLibrary/List/stories/List.stories.tsx +56 -80
- package/components/componentLibrary/List/stories/ListDecorator.tsx +3 -6
- package/components/componentLibrary/List/types.ts +1 -3
- package/components/componentLibrary/Logo/_dummyLogoData.ts +12 -0
- package/components/componentLibrary/Logo/assets/hubspot-logo.png +0 -0
- package/components/componentLibrary/Logo/index.module.scss +22 -0
- package/components/componentLibrary/Logo/index.tsx +73 -0
- package/components/componentLibrary/Logo/llm.txt +262 -0
- package/components/componentLibrary/Logo/stories/Logo.stories.tsx +88 -0
- package/components/componentLibrary/Logo/stories/LogoDecorator.module.scss +10 -0
- package/components/componentLibrary/Logo/stories/LogoDecorator.tsx +8 -0
- package/components/componentLibrary/Logo/types.tsx +16 -0
- package/components/componentLibrary/Menu/ContentFields.tsx +16 -0
- package/components/componentLibrary/Menu/MenuItem/Chevron/index.module.scss +6 -0
- package/components/componentLibrary/Menu/MenuItem/Chevron/index.tsx +17 -0
- package/components/componentLibrary/Menu/MenuItem/index.module.scss +7 -0
- package/components/componentLibrary/Menu/MenuItem/index.tsx +266 -0
- package/components/componentLibrary/Menu/MenuItem/types.ts +17 -0
- package/components/componentLibrary/Menu/NavigationMenu/ContentFields.tsx +20 -0
- package/components/componentLibrary/Menu/NavigationMenu/index.tsx +18 -0
- package/components/componentLibrary/Menu/NavigationMenu/islands/NavigationMenuIsland.tsx +95 -0
- package/components/componentLibrary/Menu/NavigationMenu/islands/index.module.scss +100 -0
- package/components/componentLibrary/Menu/NavigationMenu/islands/types.ts +19 -0
- package/components/componentLibrary/Menu/NavigationMenu/llm.txt +197 -0
- package/components/componentLibrary/Menu/NavigationMenu/stories/NavigationMenu.stories.tsx +286 -0
- package/components/componentLibrary/Menu/NavigationMenu/stories/NavigationMenuDecorator.module.scss +15 -0
- package/components/componentLibrary/Menu/NavigationMenu/stories/NavigationMenuDecorator.tsx +12 -0
- package/components/componentLibrary/Menu/NavigationMenu/types.ts +3 -0
- package/components/componentLibrary/Menu/VerticalMenu/ContentFields.tsx +20 -0
- package/components/componentLibrary/Menu/VerticalMenu/index.tsx +18 -0
- package/components/componentLibrary/Menu/VerticalMenu/islands/index.module.scss +53 -0
- package/components/componentLibrary/Menu/VerticalMenu/islands/verticalMenuIsland.tsx +78 -0
- package/components/componentLibrary/Menu/VerticalMenu/llm.txt +177 -0
- package/components/componentLibrary/Menu/VerticalMenu/stories/VerticalMenu.stories.tsx +242 -0
- package/components/componentLibrary/Menu/VerticalMenu/stories/VerticalMenuDecorator.module.scss +19 -0
- package/components/componentLibrary/Menu/VerticalMenu/stories/VerticalMenuDecorator.tsx +12 -0
- package/components/componentLibrary/Menu/VerticalMenu/types.ts +21 -0
- package/components/componentLibrary/Menu/_dummyMenuData.js +1346 -0
- package/components/componentLibrary/Menu/types.ts +56 -0
- package/components/componentLibrary/Menu/utils/transformMenuData.ts +11 -0
- package/components/componentLibrary/_patterns/README.md +15 -17
- package/components/componentLibrary/_patterns/checklist-and-examples.md +17 -17
- package/components/componentLibrary/_patterns/component-structure.md +21 -23
- package/components/componentLibrary/_patterns/css-patterns.md +170 -18
- package/components/componentLibrary/_patterns/field-patterns.md +97 -27
- package/components/componentLibrary/_patterns/function-declaration-patterns.md +281 -0
- package/components/componentLibrary/_patterns/llm-txt.template.md +4 -2
- package/components/componentLibrary/_patterns/prop-naming-patterns.md +208 -0
- package/components/componentLibrary/_patterns/storybook-patterns.md +25 -8
- package/components/componentLibrary/_patterns/typescript-patterns.md +6 -3
- package/package.json +4 -2
- /package/components/componentLibrary/Button/stories/{ButtonDecorator.module.css → ButtonDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Card/stories/{CardDecorator.module.css → CardDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Flex/stories/{FlexDecorator.module.css → FlexDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Grid/stories/{GridDecorator.module.css → GridDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Heading/stories/{HeadingDecorator.module.css → HeadingDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Icon/stories/{IconDecorator.module.css → IconDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Image/stories/{ImageDecorator.module.css → ImageDecorator.module.scss} +0 -0
- /package/components/componentLibrary/Image/stories/assets/{catSmile.jpg → cat-smile.jpg} +0 -0
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import Drawer, { useDrawer } from '../index.js';
|
|
3
|
+
import { DrawerProps } from '../types.js';
|
|
4
|
+
import { withDrawerStyles, buttonStyle } from './DrawerDecorator.js';
|
|
5
|
+
import { SBContainer } from '@sb-utils/SBContainer.js';
|
|
6
|
+
import type { CSSVariables } from '../../utils/types.js';
|
|
7
|
+
|
|
8
|
+
const meta: Meta<DrawerProps> = {
|
|
9
|
+
title: 'Component Library/Drawer',
|
|
10
|
+
component: Drawer,
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: 'fullscreen',
|
|
13
|
+
docs: {
|
|
14
|
+
description: {
|
|
15
|
+
component: `The Drawer component provides a slide-out panel that overlays content from the side, top, or bottom of the viewport. It supports customizable directions, sizes, overlay control, and full-screen mode. Use the \`useDrawer\` hook for state management.`,
|
|
16
|
+
},
|
|
17
|
+
story: {
|
|
18
|
+
inline: false,
|
|
19
|
+
iframeHeight: 500,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
decorators: [withDrawerStyles],
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default meta;
|
|
27
|
+
type Story = StoryObj<typeof meta>;
|
|
28
|
+
|
|
29
|
+
export const Default: Story = {
|
|
30
|
+
render: () => {
|
|
31
|
+
const { isOpen, open, close } = useDrawer();
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<SBContainer flex direction="column" gap="medium">
|
|
35
|
+
<button type="button" style={buttonStyle} onClick={open}>
|
|
36
|
+
Open Drawer
|
|
37
|
+
</button>
|
|
38
|
+
<Drawer
|
|
39
|
+
open={isOpen}
|
|
40
|
+
direction="right"
|
|
41
|
+
onOverlayClick={close}
|
|
42
|
+
aria-label="Default drawer"
|
|
43
|
+
>
|
|
44
|
+
<SBContainer padding="large">
|
|
45
|
+
<h2>Drawer Content</h2>
|
|
46
|
+
<p>This is the default drawer sliding in from the right.</p>
|
|
47
|
+
<button type="button" style={buttonStyle} onClick={close}>
|
|
48
|
+
Close
|
|
49
|
+
</button>
|
|
50
|
+
</SBContainer>
|
|
51
|
+
</Drawer>
|
|
52
|
+
</SBContainer>
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const Directions: Story = {
|
|
58
|
+
name: 'Direction Options',
|
|
59
|
+
render: () => {
|
|
60
|
+
const rightDrawer = useDrawer();
|
|
61
|
+
const leftDrawer = useDrawer();
|
|
62
|
+
const topDrawer = useDrawer();
|
|
63
|
+
const bottomDrawer = useDrawer();
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<SBContainer flex direction="column" gap="large">
|
|
67
|
+
<SBContainer addBackground flex direction="row" gap="medium">
|
|
68
|
+
<button type="button" style={buttonStyle} onClick={rightDrawer.open}>
|
|
69
|
+
Right Drawer
|
|
70
|
+
</button>
|
|
71
|
+
<button type="button" style={buttonStyle} onClick={leftDrawer.open}>
|
|
72
|
+
Left Drawer
|
|
73
|
+
</button>
|
|
74
|
+
<button type="button" style={buttonStyle} onClick={topDrawer.open}>
|
|
75
|
+
Top Drawer
|
|
76
|
+
</button>
|
|
77
|
+
<button type="button" style={buttonStyle} onClick={bottomDrawer.open}>
|
|
78
|
+
Bottom Drawer
|
|
79
|
+
</button>
|
|
80
|
+
</SBContainer>
|
|
81
|
+
|
|
82
|
+
<Drawer
|
|
83
|
+
open={rightDrawer.isOpen}
|
|
84
|
+
direction="right"
|
|
85
|
+
onOverlayClick={rightDrawer.close}
|
|
86
|
+
aria-label="Right drawer"
|
|
87
|
+
>
|
|
88
|
+
<SBContainer padding="large">
|
|
89
|
+
<h2>Right Drawer</h2>
|
|
90
|
+
<p>Slides in from the right side of the screen.</p>
|
|
91
|
+
<button
|
|
92
|
+
type="button"
|
|
93
|
+
style={buttonStyle}
|
|
94
|
+
onClick={rightDrawer.close}
|
|
95
|
+
>
|
|
96
|
+
Close
|
|
97
|
+
</button>
|
|
98
|
+
</SBContainer>
|
|
99
|
+
</Drawer>
|
|
100
|
+
|
|
101
|
+
<Drawer
|
|
102
|
+
open={leftDrawer.isOpen}
|
|
103
|
+
direction="left"
|
|
104
|
+
onOverlayClick={leftDrawer.close}
|
|
105
|
+
aria-label="Left drawer"
|
|
106
|
+
>
|
|
107
|
+
<SBContainer padding="large">
|
|
108
|
+
<h2>Left Drawer</h2>
|
|
109
|
+
<p>Slides in from the left side of the screen.</p>
|
|
110
|
+
<button
|
|
111
|
+
type="button"
|
|
112
|
+
style={buttonStyle}
|
|
113
|
+
onClick={leftDrawer.close}
|
|
114
|
+
>
|
|
115
|
+
Close
|
|
116
|
+
</button>
|
|
117
|
+
</SBContainer>
|
|
118
|
+
</Drawer>
|
|
119
|
+
|
|
120
|
+
<Drawer
|
|
121
|
+
open={topDrawer.isOpen}
|
|
122
|
+
direction="top"
|
|
123
|
+
onOverlayClick={topDrawer.close}
|
|
124
|
+
aria-label="Top drawer"
|
|
125
|
+
>
|
|
126
|
+
<SBContainer padding="large">
|
|
127
|
+
<h2>Top Drawer</h2>
|
|
128
|
+
<p>Slides in from the top of the screen.</p>
|
|
129
|
+
<button type="button" style={buttonStyle} onClick={topDrawer.close}>
|
|
130
|
+
Close
|
|
131
|
+
</button>
|
|
132
|
+
</SBContainer>
|
|
133
|
+
</Drawer>
|
|
134
|
+
|
|
135
|
+
<Drawer
|
|
136
|
+
open={bottomDrawer.isOpen}
|
|
137
|
+
direction="bottom"
|
|
138
|
+
onOverlayClick={bottomDrawer.close}
|
|
139
|
+
aria-label="Bottom drawer"
|
|
140
|
+
>
|
|
141
|
+
<SBContainer padding="large">
|
|
142
|
+
<h2>Bottom Drawer</h2>
|
|
143
|
+
<p>Slides in from the bottom of the screen.</p>
|
|
144
|
+
<button
|
|
145
|
+
type="button"
|
|
146
|
+
style={buttonStyle}
|
|
147
|
+
onClick={bottomDrawer.close}
|
|
148
|
+
>
|
|
149
|
+
Close
|
|
150
|
+
</button>
|
|
151
|
+
</SBContainer>
|
|
152
|
+
</Drawer>
|
|
153
|
+
</SBContainer>
|
|
154
|
+
);
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export const Sizes: Story = {
|
|
159
|
+
name: 'Size Variations',
|
|
160
|
+
render: () => {
|
|
161
|
+
const smallDrawer = useDrawer();
|
|
162
|
+
const mediumDrawer = useDrawer();
|
|
163
|
+
const largeDrawer = useDrawer();
|
|
164
|
+
const fullScreenDrawer = useDrawer();
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<SBContainer flex direction="column" gap="large">
|
|
168
|
+
<SBContainer addBackground flex direction="row" gap="medium">
|
|
169
|
+
<button type="button" style={buttonStyle} onClick={smallDrawer.open}>
|
|
170
|
+
Small (250px)
|
|
171
|
+
</button>
|
|
172
|
+
<button type="button" style={buttonStyle} onClick={mediumDrawer.open}>
|
|
173
|
+
Medium (400px)
|
|
174
|
+
</button>
|
|
175
|
+
<button type="button" style={buttonStyle} onClick={largeDrawer.open}>
|
|
176
|
+
Large (600px)
|
|
177
|
+
</button>
|
|
178
|
+
<button
|
|
179
|
+
type="button"
|
|
180
|
+
style={buttonStyle}
|
|
181
|
+
onClick={fullScreenDrawer.open}
|
|
182
|
+
>
|
|
183
|
+
Full Screen
|
|
184
|
+
</button>
|
|
185
|
+
</SBContainer>
|
|
186
|
+
|
|
187
|
+
<Drawer
|
|
188
|
+
open={smallDrawer.isOpen}
|
|
189
|
+
direction="right"
|
|
190
|
+
size="250px"
|
|
191
|
+
onOverlayClick={smallDrawer.close}
|
|
192
|
+
aria-label="Small drawer"
|
|
193
|
+
>
|
|
194
|
+
<SBContainer padding="large">
|
|
195
|
+
<h3>Small Drawer</h3>
|
|
196
|
+
<p>Width: 250px</p>
|
|
197
|
+
<button
|
|
198
|
+
type="button"
|
|
199
|
+
style={buttonStyle}
|
|
200
|
+
onClick={smallDrawer.close}
|
|
201
|
+
>
|
|
202
|
+
Close
|
|
203
|
+
</button>
|
|
204
|
+
</SBContainer>
|
|
205
|
+
</Drawer>
|
|
206
|
+
|
|
207
|
+
<Drawer
|
|
208
|
+
open={mediumDrawer.isOpen}
|
|
209
|
+
direction="right"
|
|
210
|
+
size="400px"
|
|
211
|
+
onOverlayClick={mediumDrawer.close}
|
|
212
|
+
aria-label="Medium drawer"
|
|
213
|
+
>
|
|
214
|
+
<SBContainer padding="large">
|
|
215
|
+
<h3>Medium Drawer</h3>
|
|
216
|
+
<p>Width: 400px</p>
|
|
217
|
+
<button
|
|
218
|
+
type="button"
|
|
219
|
+
style={buttonStyle}
|
|
220
|
+
onClick={mediumDrawer.close}
|
|
221
|
+
>
|
|
222
|
+
Close
|
|
223
|
+
</button>
|
|
224
|
+
</SBContainer>
|
|
225
|
+
</Drawer>
|
|
226
|
+
|
|
227
|
+
<Drawer
|
|
228
|
+
open={largeDrawer.isOpen}
|
|
229
|
+
direction="right"
|
|
230
|
+
size="600px"
|
|
231
|
+
onOverlayClick={largeDrawer.close}
|
|
232
|
+
aria-label="Large drawer"
|
|
233
|
+
>
|
|
234
|
+
<SBContainer padding="large">
|
|
235
|
+
<h3>Large Drawer</h3>
|
|
236
|
+
<p>Width: 600px</p>
|
|
237
|
+
<button
|
|
238
|
+
type="button"
|
|
239
|
+
style={buttonStyle}
|
|
240
|
+
onClick={largeDrawer.close}
|
|
241
|
+
>
|
|
242
|
+
Close
|
|
243
|
+
</button>
|
|
244
|
+
</SBContainer>
|
|
245
|
+
</Drawer>
|
|
246
|
+
|
|
247
|
+
<Drawer
|
|
248
|
+
open={fullScreenDrawer.isOpen}
|
|
249
|
+
direction="right"
|
|
250
|
+
fullScreen
|
|
251
|
+
onOverlayClick={fullScreenDrawer.close}
|
|
252
|
+
aria-label="Full screen drawer"
|
|
253
|
+
>
|
|
254
|
+
<SBContainer padding="extralarge" flex direction="column" gap="large">
|
|
255
|
+
<h1>Full Screen Drawer</h1>
|
|
256
|
+
<p>
|
|
257
|
+
This drawer takes up the entire screen, useful for forms, detailed
|
|
258
|
+
content, or focused tasks.
|
|
259
|
+
</p>
|
|
260
|
+
<p>
|
|
261
|
+
The fullScreen prop overrides the size prop and makes the drawer
|
|
262
|
+
fill the viewport.
|
|
263
|
+
</p>
|
|
264
|
+
<button
|
|
265
|
+
type="button"
|
|
266
|
+
style={buttonStyle}
|
|
267
|
+
onClick={fullScreenDrawer.close}
|
|
268
|
+
>
|
|
269
|
+
Close
|
|
270
|
+
</button>
|
|
271
|
+
</SBContainer>
|
|
272
|
+
</Drawer>
|
|
273
|
+
</SBContainer>
|
|
274
|
+
);
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
export const WithoutOverlay: Story = {
|
|
279
|
+
name: 'Without Overlay',
|
|
280
|
+
render: () => {
|
|
281
|
+
const { isOpen, close, toggle } = useDrawer();
|
|
282
|
+
|
|
283
|
+
return (
|
|
284
|
+
<SBContainer flex direction="column" gap="medium">
|
|
285
|
+
<SBContainer addBackground>
|
|
286
|
+
<h4>Drawer Without Overlay</h4>
|
|
287
|
+
<p>
|
|
288
|
+
Set showOverlay to false to remove the dark backdrop. The drawer
|
|
289
|
+
will not close when clicking outside.
|
|
290
|
+
</p>
|
|
291
|
+
<button type="button" style={buttonStyle} onClick={toggle}>
|
|
292
|
+
{isOpen ? 'Close' : 'Open'} Drawer
|
|
293
|
+
</button>
|
|
294
|
+
</SBContainer>
|
|
295
|
+
|
|
296
|
+
<Drawer
|
|
297
|
+
open={isOpen}
|
|
298
|
+
direction="right"
|
|
299
|
+
showOverlay={false}
|
|
300
|
+
aria-label="Drawer without overlay"
|
|
301
|
+
>
|
|
302
|
+
<SBContainer padding="large">
|
|
303
|
+
<h3>No Overlay</h3>
|
|
304
|
+
<p>Background content remains visible and interactive.</p>
|
|
305
|
+
<button type="button" style={buttonStyle} onClick={close}>
|
|
306
|
+
Close
|
|
307
|
+
</button>
|
|
308
|
+
</SBContainer>
|
|
309
|
+
</Drawer>
|
|
310
|
+
</SBContainer>
|
|
311
|
+
);
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
export const KeyboardInteraction: Story = {
|
|
316
|
+
name: 'Keyboard Interaction',
|
|
317
|
+
render: () => {
|
|
318
|
+
const { isOpen, open, close } = useDrawer();
|
|
319
|
+
|
|
320
|
+
return (
|
|
321
|
+
<SBContainer flex direction="column" gap="medium">
|
|
322
|
+
<SBContainer addBackground>
|
|
323
|
+
<h4>Keyboard Support</h4>
|
|
324
|
+
<p>Press ESC to close the drawer when it is open</p>
|
|
325
|
+
<button type="button" style={buttonStyle} onClick={open}>
|
|
326
|
+
Open Drawer
|
|
327
|
+
</button>
|
|
328
|
+
</SBContainer>
|
|
329
|
+
|
|
330
|
+
<Drawer
|
|
331
|
+
open={isOpen}
|
|
332
|
+
direction="right"
|
|
333
|
+
onOverlayClick={close}
|
|
334
|
+
aria-label="Keyboard interactive drawer"
|
|
335
|
+
>
|
|
336
|
+
<SBContainer padding="large">
|
|
337
|
+
<h3>Keyboard Accessible</h3>
|
|
338
|
+
<p>
|
|
339
|
+
This drawer can be closed by pressing the <strong>ESC</strong> key
|
|
340
|
+
or clicking the overlay.
|
|
341
|
+
</p>
|
|
342
|
+
<p style={{ marginTop: '16px' }}>
|
|
343
|
+
Try pressing ESC on your keyboard to close this drawer.
|
|
344
|
+
</p>
|
|
345
|
+
<button type="button" style={buttonStyle} onClick={close}>
|
|
346
|
+
Or Click to Close
|
|
347
|
+
</button>
|
|
348
|
+
</SBContainer>
|
|
349
|
+
</Drawer>
|
|
350
|
+
</SBContainer>
|
|
351
|
+
);
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
export const BodyScrollLock: Story = {
|
|
356
|
+
name: 'Body Scroll Lock',
|
|
357
|
+
render: () => {
|
|
358
|
+
const { isOpen, open, close } = useDrawer();
|
|
359
|
+
|
|
360
|
+
return (
|
|
361
|
+
<SBContainer padding="large" style={{ minHeight: '200vh' }}>
|
|
362
|
+
<SBContainer addBackground>
|
|
363
|
+
<h4>Background Scroll Prevention</h4>
|
|
364
|
+
<p>
|
|
365
|
+
When the drawer is open, the background page scroll is locked to
|
|
366
|
+
prevent scrolling behind the overlay.
|
|
367
|
+
</p>
|
|
368
|
+
<p style={{ marginTop: '16px' }}>
|
|
369
|
+
This page has a long scrollable body. Scroll down and open the
|
|
370
|
+
drawer from any section - the background scroll will be locked.
|
|
371
|
+
</p>
|
|
372
|
+
</SBContainer>
|
|
373
|
+
|
|
374
|
+
{Array.from({ length: 20 }, (_, i) => (
|
|
375
|
+
<SBContainer
|
|
376
|
+
key={i}
|
|
377
|
+
padding="large"
|
|
378
|
+
addBackground
|
|
379
|
+
style={{
|
|
380
|
+
margin: '16px 0',
|
|
381
|
+
}}
|
|
382
|
+
>
|
|
383
|
+
<h3>Background Content Section {i + 1}</h3>
|
|
384
|
+
<p>
|
|
385
|
+
This is scrollable content on the main page. When the drawer is
|
|
386
|
+
open, you should not be able to scroll this content.
|
|
387
|
+
</p>
|
|
388
|
+
<button
|
|
389
|
+
type="button"
|
|
390
|
+
style={{ ...buttonStyle, marginTop: '12px' }}
|
|
391
|
+
onClick={open}
|
|
392
|
+
>
|
|
393
|
+
Open Drawer
|
|
394
|
+
</button>
|
|
395
|
+
</SBContainer>
|
|
396
|
+
))}
|
|
397
|
+
|
|
398
|
+
<Drawer
|
|
399
|
+
open={isOpen}
|
|
400
|
+
direction="right"
|
|
401
|
+
onOverlayClick={close}
|
|
402
|
+
aria-label="Drawer with scroll lock"
|
|
403
|
+
>
|
|
404
|
+
<SBContainer padding="large">
|
|
405
|
+
<h3>Drawer Content</h3>
|
|
406
|
+
<p>The background scroll is now locked.</p>
|
|
407
|
+
<p style={{ marginTop: '16px' }}>
|
|
408
|
+
Try scrolling the page - it should be prevented. The body element
|
|
409
|
+
has <code>overflow: hidden</code> applied when the drawer is open.
|
|
410
|
+
</p>
|
|
411
|
+
<button type="button" style={buttonStyle} onClick={close}>
|
|
412
|
+
Close Drawer
|
|
413
|
+
</button>
|
|
414
|
+
</SBContainer>
|
|
415
|
+
</Drawer>
|
|
416
|
+
</SBContainer>
|
|
417
|
+
);
|
|
418
|
+
},
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
export const NestedDrawers: Story = {
|
|
422
|
+
name: 'Nested Drawers',
|
|
423
|
+
render: () => {
|
|
424
|
+
const parentDrawer = useDrawer();
|
|
425
|
+
const childDrawer = useDrawer();
|
|
426
|
+
|
|
427
|
+
const childDrawerStyle: CSSVariables = {
|
|
428
|
+
'--hscl-drawer-zIndex': '1001',
|
|
429
|
+
'--hscl-drawer-overlay-zIndex': '1000',
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
return (
|
|
433
|
+
<SBContainer flex direction="column" gap="medium">
|
|
434
|
+
<SBContainer addBackground>
|
|
435
|
+
<h4>Nested Drawer Example</h4>
|
|
436
|
+
<p>
|
|
437
|
+
This example demonstrates opening a second drawer from within the
|
|
438
|
+
first drawer. Use this pattern carefully - only when necessary for
|
|
439
|
+
complex workflows.
|
|
440
|
+
</p>
|
|
441
|
+
<button
|
|
442
|
+
type="button"
|
|
443
|
+
style={{ ...buttonStyle, marginTop: '16px' }}
|
|
444
|
+
onClick={parentDrawer.open}
|
|
445
|
+
>
|
|
446
|
+
Open Parent Drawer
|
|
447
|
+
</button>
|
|
448
|
+
</SBContainer>
|
|
449
|
+
|
|
450
|
+
<Drawer
|
|
451
|
+
open={parentDrawer.isOpen}
|
|
452
|
+
direction="right"
|
|
453
|
+
size="400px"
|
|
454
|
+
onOverlayClick={parentDrawer.close}
|
|
455
|
+
aria-label="Parent drawer"
|
|
456
|
+
>
|
|
457
|
+
<SBContainer padding="large">
|
|
458
|
+
<h2>Parent Drawer</h2>
|
|
459
|
+
<p>This is the first level drawer.</p>
|
|
460
|
+
<p style={{ marginTop: '16px' }}>
|
|
461
|
+
Click the button below to open a second drawer on top of this one:
|
|
462
|
+
</p>
|
|
463
|
+
<button
|
|
464
|
+
type="button"
|
|
465
|
+
style={{ ...buttonStyle, marginTop: '16px' }}
|
|
466
|
+
onClick={childDrawer.open}
|
|
467
|
+
>
|
|
468
|
+
Open Child Drawer
|
|
469
|
+
</button>
|
|
470
|
+
<button
|
|
471
|
+
type="button"
|
|
472
|
+
style={{
|
|
473
|
+
...buttonStyle,
|
|
474
|
+
marginTop: '16px',
|
|
475
|
+
marginLeft: '12px',
|
|
476
|
+
backgroundColor: '#666',
|
|
477
|
+
}}
|
|
478
|
+
onClick={parentDrawer.close}
|
|
479
|
+
>
|
|
480
|
+
Close Parent
|
|
481
|
+
</button>
|
|
482
|
+
</SBContainer>
|
|
483
|
+
</Drawer>
|
|
484
|
+
|
|
485
|
+
<Drawer
|
|
486
|
+
open={childDrawer.isOpen}
|
|
487
|
+
direction="bottom"
|
|
488
|
+
fullScreen
|
|
489
|
+
onOverlayClick={childDrawer.close}
|
|
490
|
+
aria-label="Child drawer"
|
|
491
|
+
style={childDrawerStyle}
|
|
492
|
+
>
|
|
493
|
+
<SBContainer padding="large">
|
|
494
|
+
<h2>Child Drawer</h2>
|
|
495
|
+
<p>This drawer opened from within the parent drawer.</p>
|
|
496
|
+
<p style={{ marginTop: '16px' }}>
|
|
497
|
+
Notice how it appears on top with a higher z-index. Close this
|
|
498
|
+
drawer to return to the parent.
|
|
499
|
+
</p>
|
|
500
|
+
<button
|
|
501
|
+
type="button"
|
|
502
|
+
style={{ ...buttonStyle, marginTop: '16px' }}
|
|
503
|
+
onClick={childDrawer.close}
|
|
504
|
+
>
|
|
505
|
+
Close Child
|
|
506
|
+
</button>
|
|
507
|
+
</SBContainer>
|
|
508
|
+
</Drawer>
|
|
509
|
+
</SBContainer>
|
|
510
|
+
);
|
|
511
|
+
},
|
|
512
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Decorator } from '@storybook/react';
|
|
2
|
+
import styles from './DrawerDecorator.module.scss';
|
|
3
|
+
|
|
4
|
+
export const buttonStyle = {
|
|
5
|
+
padding: '8px 16px',
|
|
6
|
+
backgroundColor: '#0066cc',
|
|
7
|
+
color: 'white',
|
|
8
|
+
border: 'none',
|
|
9
|
+
borderRadius: '4px',
|
|
10
|
+
cursor: 'pointer',
|
|
11
|
+
fontSize: '14px',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const withDrawerStyles: Decorator = Story => (
|
|
15
|
+
<div className={styles.decoratorContainer}>
|
|
16
|
+
<Story />
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CSSVariables } from '../utils/types.js';
|
|
2
|
+
|
|
3
|
+
export type DrawerDirection = 'left' | 'right' | 'top' | 'bottom';
|
|
4
|
+
|
|
5
|
+
export type DrawerProps = {
|
|
6
|
+
open: boolean;
|
|
7
|
+
direction: DrawerDirection;
|
|
8
|
+
variant?: 'primary' | 'secondary' | 'tertiary';
|
|
9
|
+
className?: string;
|
|
10
|
+
style?: CSSVariables;
|
|
11
|
+
children?: React.ReactNode;
|
|
12
|
+
showOverlay?: boolean;
|
|
13
|
+
onOverlayClick?: () => void;
|
|
14
|
+
fullScreen?: boolean;
|
|
15
|
+
size?: string;
|
|
16
|
+
'aria-label'?: string;
|
|
17
|
+
'aria-labelledby'?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type UseDrawerReturn = {
|
|
21
|
+
isOpen: boolean;
|
|
22
|
+
open: () => void;
|
|
23
|
+
close: () => void;
|
|
24
|
+
toggle: () => void;
|
|
25
|
+
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { CSSVariables } from '../utils/types.js';
|
|
2
|
+
|
|
1
3
|
export type FlexDirection = 'row' | 'row-reverse' | 'column' | 'column-reverse';
|
|
2
4
|
|
|
3
5
|
export type FlexWrap = 'nowrap' | 'wrap' | 'wrap-reverse';
|
|
@@ -58,6 +60,6 @@ export type FlexProps = {
|
|
|
58
60
|
maxWidth?: string;
|
|
59
61
|
maxHeight?: string;
|
|
60
62
|
className?: string;
|
|
61
|
-
style?:
|
|
63
|
+
style?: CSSVariables;
|
|
62
64
|
children?: React.ReactNode;
|
|
63
65
|
};
|