paris 0.3.0 → 0.4.1
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/CHANGELOG.md +26 -0
- package/package.json +14 -12
- package/src/pages/_app.tsx +1 -1
- package/src/pages/index.tsx +1 -1
- package/src/stories/Pagination.mdx +73 -0
- package/src/stories/button/Button.module.scss +11 -1
- package/src/stories/button/Button.tsx +40 -17
- package/src/stories/card/Card.module.scss +14 -0
- package/src/stories/card/Card.stories.ts +33 -0
- package/src/stories/card/Card.tsx +55 -0
- package/src/stories/card/index.ts +1 -0
- package/src/stories/checkbox/Checkbox.module.scss +57 -0
- package/src/stories/checkbox/Checkbox.stories.ts +27 -0
- package/src/stories/checkbox/Checkbox.tsx +58 -0
- package/src/stories/checkbox/index.ts +1 -0
- package/src/stories/combobox/Combobox.module.scss +5 -0
- package/src/stories/combobox/Combobox.stories.ts +84 -0
- package/src/stories/combobox/Combobox.tsx +264 -0
- package/src/stories/combobox/index.ts +1 -0
- package/src/stories/dialog/Dialog.module.scss +187 -0
- package/src/stories/dialog/Dialog.stories.tsx +70 -0
- package/src/stories/dialog/Dialog.tsx +279 -0
- package/src/stories/dialog/index.ts +1 -0
- package/src/stories/drawer/Drawer.module.scss +284 -0
- package/src/stories/drawer/Drawer.stories.tsx +94 -0
- package/src/stories/drawer/Drawer.tsx +339 -0
- package/src/stories/drawer/index.ts +1 -0
- package/src/stories/field/Field.module.scss +5 -0
- package/src/stories/field/Field.stories.ts +32 -0
- package/src/stories/field/Field.tsx +106 -0
- package/src/stories/field/index.ts +1 -0
- package/src/stories/icon/ChevronLeft.tsx +11 -0
- package/src/stories/icon/ChevronRight.tsx +11 -0
- package/src/stories/icon/Close.tsx +11 -0
- package/src/stories/icon/Icon.module.scss +5 -0
- package/src/stories/icon/Icon.stories.ts +28 -0
- package/src/stories/icon/Icon.tsx +46 -0
- package/src/stories/icon/index.ts +4 -0
- package/src/stories/input/Input.module.scss +3 -2
- package/src/stories/input/Input.stories.ts +2 -0
- package/src/stories/input/Input.tsx +38 -73
- package/src/stories/pagination/index.ts +1 -0
- package/src/stories/pagination/usePagination.ts +106 -0
- package/src/stories/select/Select.module.scss +8 -4
- package/src/stories/select/Select.stories.ts +5 -3
- package/src/stories/select/Select.tsx +80 -7
- package/src/stories/theme/themes.ts +75 -2
- package/src/stories/theme/tw-preflight.css +3 -1
- package/src/stories/tilt/Tilt.module.scss +1 -0
- package/src/stories/tilt/Tilt.stories.tsx +43 -0
- package/src/stories/tilt/Tilt.tsx +65 -0
- package/src/stories/tilt/index.ts +1 -0
- package/src/stories/utility/RemoveFromDOM.tsx +19 -0
- package/src/stories/utility/TextWhenString.tsx +28 -0
- package/src/stories/utility/VisuallyHidden.tsx +25 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
ComponentPropsWithoutRef, FC, MouseEventHandler, PropsWithChildren, ReactNode,
|
|
5
|
+
} from 'react';
|
|
6
|
+
import { Dialog as HDialog, Transition } from '@headlessui/react';
|
|
7
|
+
import { Fragment, useEffect, useState } from 'react';
|
|
8
|
+
import clsx from 'clsx';
|
|
9
|
+
import styles from './Dialog.module.scss';
|
|
10
|
+
import { Text } from '../text';
|
|
11
|
+
import { Button } from '../button';
|
|
12
|
+
import { pvar } from '../theme';
|
|
13
|
+
import { TextWhenString } from '../utility/TextWhenString';
|
|
14
|
+
import { VisuallyHidden } from '../utility/VisuallyHidden';
|
|
15
|
+
import { RemoveFromDOM } from '../utility/RemoveFromDOM';
|
|
16
|
+
import { Close, Icon } from '../icon';
|
|
17
|
+
|
|
18
|
+
export type DialogProps = {
|
|
19
|
+
/**
|
|
20
|
+
* The dialog's open state.
|
|
21
|
+
*/
|
|
22
|
+
isOpen?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* A callback that will be called when the user closes the dialog by clicking the close button or the backdrop overlay.
|
|
25
|
+
* @param value {boolean} - The new open state of the dialog.
|
|
26
|
+
*/
|
|
27
|
+
onClose?: (value: boolean) => void | Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* The title of the dialog. Required for accessibility, but can be hidden with the `hideTitle` prop.
|
|
30
|
+
*
|
|
31
|
+
* If a string is passed, it will be wrapped in a {@link Text} component with `headingXSmall` styling.
|
|
32
|
+
*/
|
|
33
|
+
title: ReactNode;
|
|
34
|
+
/**
|
|
35
|
+
* Whether the title should be hidden. If `true`, the title will be visually hidden but still accessible to screen readers.
|
|
36
|
+
*
|
|
37
|
+
* If you're hiding the title to add a custom header, you can also hide the close button and render your own by using the `hideCloseButton` prop.
|
|
38
|
+
*
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
hideTitle?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Whether the close button should be hidden. This will entirely remove the close button from the DOM, so you should provide your own way to close the dialog.
|
|
44
|
+
*
|
|
45
|
+
* @default false
|
|
46
|
+
*/
|
|
47
|
+
hideCloseButton?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* The width of the dialog.
|
|
50
|
+
*
|
|
51
|
+
* @default 'default'
|
|
52
|
+
*/
|
|
53
|
+
width?: 'compact' | 'default' | 'large' | 'full';
|
|
54
|
+
/**
|
|
55
|
+
* The height of the dialog.
|
|
56
|
+
*
|
|
57
|
+
* @default 'content'
|
|
58
|
+
*/
|
|
59
|
+
height?: 'content' | 'full';
|
|
60
|
+
/**
|
|
61
|
+
* Whether the dialog can be moved with mouse dragging.
|
|
62
|
+
*
|
|
63
|
+
* @default true
|
|
64
|
+
*/
|
|
65
|
+
draggable?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* The dialog's appearance styling. `simple` is a simple white dialog with a border. `glass` is a glassmorphic dialog with a blurred background.
|
|
68
|
+
*
|
|
69
|
+
* @default 'simple'
|
|
70
|
+
*/
|
|
71
|
+
appearance?: 'simple' | 'glass';
|
|
72
|
+
/**
|
|
73
|
+
* Optional overrides for props of each dialog component.
|
|
74
|
+
*
|
|
75
|
+
* Valid keys are: `root`, `overlayContainer`, `overlay`, `panelContainer`, `panel`, `panelHeader`, `panelTitle`, `panelCloseButton`.
|
|
76
|
+
*/
|
|
77
|
+
overrides?: {
|
|
78
|
+
/** The root element containing all elements */
|
|
79
|
+
root?: ComponentPropsWithoutRef<'div'>,
|
|
80
|
+
/** The container for the backdrop overlay */
|
|
81
|
+
overlayContainer?: ComponentPropsWithoutRef<'div'>,
|
|
82
|
+
/** The backdrop overlay */
|
|
83
|
+
overlay?: ComponentPropsWithoutRef<'div'>,
|
|
84
|
+
/** The container for the dialog panel */
|
|
85
|
+
panelContainer?: ComponentPropsWithoutRef<'div'>,
|
|
86
|
+
/** The dialog panel */
|
|
87
|
+
panel?: ComponentPropsWithoutRef<'div'>,
|
|
88
|
+
/** The header of the dialog panel, which contains the title and close button */
|
|
89
|
+
panelHeader?: ComponentPropsWithoutRef<'div'>,
|
|
90
|
+
/** The title within the dialog panel */
|
|
91
|
+
panelTitle?: ComponentPropsWithoutRef<'h1'>,
|
|
92
|
+
/** The close button within the dialog panel */
|
|
93
|
+
panelCloseButton?: ComponentPropsWithoutRef<'button'>,
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Dialogs are modal components that appear on top of the main content and require user interaction to dismiss.
|
|
99
|
+
*
|
|
100
|
+
* They render to a Portal, so they can be used anywhere in the DOM.
|
|
101
|
+
*
|
|
102
|
+
* <hr />
|
|
103
|
+
*
|
|
104
|
+
* To use this component, import it as follows:
|
|
105
|
+
*
|
|
106
|
+
* ```js
|
|
107
|
+
* import { Dialog } from 'paris/dialog';
|
|
108
|
+
* ```
|
|
109
|
+
* @constructor
|
|
110
|
+
*/
|
|
111
|
+
export const Dialog: FC<PropsWithChildren<DialogProps>> = ({
|
|
112
|
+
isOpen = false,
|
|
113
|
+
onClose = () => {},
|
|
114
|
+
title,
|
|
115
|
+
hideTitle = false,
|
|
116
|
+
hideCloseButton = false,
|
|
117
|
+
overrides = {},
|
|
118
|
+
width = 'default',
|
|
119
|
+
height = 'content',
|
|
120
|
+
draggable = false,
|
|
121
|
+
appearance = 'simple',
|
|
122
|
+
children,
|
|
123
|
+
}) => {
|
|
124
|
+
const [dragging, setDragging] = useState(false);
|
|
125
|
+
const [position, setPosition] = useState({ top: 0, left: 0 });
|
|
126
|
+
const [startPosition, setStartPosition] = useState({ x: 0, y: 0 });
|
|
127
|
+
|
|
128
|
+
const handleMouseDown: MouseEventHandler<HTMLDivElement> = (e) => {
|
|
129
|
+
if (draggable) {
|
|
130
|
+
setDragging(true);
|
|
131
|
+
setStartPosition({ x: e.clientX, y: e.clientY });
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const handleMouseUp = () => {
|
|
136
|
+
if (draggable) {
|
|
137
|
+
setDragging(false);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const handleMouseMove: MouseEventHandler<HTMLDivElement> = (e) => {
|
|
142
|
+
if (dragging && draggable) {
|
|
143
|
+
setPosition({
|
|
144
|
+
top: position.top + (e.clientY - startPosition.y),
|
|
145
|
+
left: position.left + (e.clientX - startPosition.x),
|
|
146
|
+
});
|
|
147
|
+
setStartPosition({ x: e.clientX, y: e.clientY });
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
if (isOpen) {
|
|
153
|
+
setDragging(false);
|
|
154
|
+
setPosition({ top: 0, left: 0 });
|
|
155
|
+
setStartPosition({ x: 0, y: 0 });
|
|
156
|
+
}
|
|
157
|
+
}, [isOpen]);
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<Transition
|
|
161
|
+
appear
|
|
162
|
+
show={isOpen}
|
|
163
|
+
as={Fragment}
|
|
164
|
+
>
|
|
165
|
+
<HDialog
|
|
166
|
+
as="div"
|
|
167
|
+
onClose={onClose}
|
|
168
|
+
{...overrides.root}
|
|
169
|
+
className={clsx(
|
|
170
|
+
styles.root,
|
|
171
|
+
overrides.root?.className,
|
|
172
|
+
)}
|
|
173
|
+
>
|
|
174
|
+
<HDialog.Overlay
|
|
175
|
+
{...overrides.overlayContainer}
|
|
176
|
+
className={clsx(
|
|
177
|
+
styles.overlayContainer,
|
|
178
|
+
overrides.overlayContainer?.className,
|
|
179
|
+
)}
|
|
180
|
+
>
|
|
181
|
+
<Transition.Child
|
|
182
|
+
as={Fragment}
|
|
183
|
+
enter={styles.enter}
|
|
184
|
+
enterFrom={styles.enterFrom}
|
|
185
|
+
enterTo={styles.enterTo}
|
|
186
|
+
leave={styles.leave}
|
|
187
|
+
leaveFrom={styles.leaveFrom}
|
|
188
|
+
leaveTo={styles.leaveTo}
|
|
189
|
+
>
|
|
190
|
+
<div
|
|
191
|
+
{...overrides.overlay}
|
|
192
|
+
className={clsx(
|
|
193
|
+
styles.overlay,
|
|
194
|
+
overrides.overlay?.className,
|
|
195
|
+
)}
|
|
196
|
+
/>
|
|
197
|
+
</Transition.Child>
|
|
198
|
+
</HDialog.Overlay>
|
|
199
|
+
|
|
200
|
+
<div
|
|
201
|
+
{...overrides.panelContainer}
|
|
202
|
+
className={clsx(
|
|
203
|
+
styles.panelContainer,
|
|
204
|
+
overrides.panelContainer?.className,
|
|
205
|
+
)}
|
|
206
|
+
>
|
|
207
|
+
<Transition.Child
|
|
208
|
+
as={Fragment}
|
|
209
|
+
enter={styles.enter}
|
|
210
|
+
enterFrom={styles.enterFrom}
|
|
211
|
+
enterTo={styles.enterTo}
|
|
212
|
+
leave={styles.leave}
|
|
213
|
+
leaveFrom={styles.leaveFrom}
|
|
214
|
+
leaveTo={styles.leaveTo}
|
|
215
|
+
>
|
|
216
|
+
<HDialog.Panel
|
|
217
|
+
{...overrides.panel}
|
|
218
|
+
className={clsx(
|
|
219
|
+
styles.panel,
|
|
220
|
+
styles[appearance],
|
|
221
|
+
styles[`w-${width}`],
|
|
222
|
+
styles[`h-${height}`],
|
|
223
|
+
overrides.panel?.className,
|
|
224
|
+
)}
|
|
225
|
+
style={{ top: `${position.top}px`, left: `${position.left}px` }}
|
|
226
|
+
onMouseDown={handleMouseDown}
|
|
227
|
+
onMouseUp={handleMouseUp}
|
|
228
|
+
onMouseMove={handleMouseMove}
|
|
229
|
+
>
|
|
230
|
+
<div
|
|
231
|
+
{...overrides.panelHeader}
|
|
232
|
+
className={clsx(
|
|
233
|
+
styles.header,
|
|
234
|
+
overrides.panelHeader?.className,
|
|
235
|
+
)}
|
|
236
|
+
>
|
|
237
|
+
<VisuallyHidden when={hideTitle}>
|
|
238
|
+
<HDialog.Title
|
|
239
|
+
{...overrides.panelTitle}
|
|
240
|
+
as="h1"
|
|
241
|
+
className={clsx(
|
|
242
|
+
styles.title,
|
|
243
|
+
overrides.panelTitle?.className,
|
|
244
|
+
)}
|
|
245
|
+
>
|
|
246
|
+
<TextWhenString
|
|
247
|
+
kind="headingXSmall"
|
|
248
|
+
>
|
|
249
|
+
{title}
|
|
250
|
+
</TextWhenString>
|
|
251
|
+
</HDialog.Title>
|
|
252
|
+
</VisuallyHidden>
|
|
253
|
+
<RemoveFromDOM when={hideCloseButton}>
|
|
254
|
+
<Button
|
|
255
|
+
kind="tertiary"
|
|
256
|
+
shape="circle"
|
|
257
|
+
onClick={() => onClose(false)}
|
|
258
|
+
startEnhancer={(
|
|
259
|
+
<Icon size={20} icon={Close} />
|
|
260
|
+
)}
|
|
261
|
+
{...overrides.panelCloseButton}
|
|
262
|
+
data-title-hidden={hideTitle}
|
|
263
|
+
className={clsx(
|
|
264
|
+
styles.closeButton,
|
|
265
|
+
overrides.panelCloseButton?.className,
|
|
266
|
+
)}
|
|
267
|
+
>
|
|
268
|
+
Close dialog
|
|
269
|
+
</Button>
|
|
270
|
+
</RemoveFromDOM>
|
|
271
|
+
</div>
|
|
272
|
+
{children}
|
|
273
|
+
</HDialog.Panel>
|
|
274
|
+
</Transition.Child>
|
|
275
|
+
</div>
|
|
276
|
+
</HDialog>
|
|
277
|
+
</Transition>
|
|
278
|
+
);
|
|
279
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Dialog';
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
$translateInX: 30%;
|
|
2
|
+
$translateInY: 100%;
|
|
3
|
+
$translateOutX: 20%;
|
|
4
|
+
$translateOutY: 60%;
|
|
5
|
+
|
|
6
|
+
$panelMinMargin: 16px;
|
|
7
|
+
$defaultSize: 360px;
|
|
8
|
+
|
|
9
|
+
$panelPaddingX: 20px;
|
|
10
|
+
$panelPaddingY: 24px;
|
|
11
|
+
|
|
12
|
+
$duration: var(--pte-animations-duration-relaxed);
|
|
13
|
+
$paginationDuration: var(--pte-animations-duration-normal);
|
|
14
|
+
$panelAnimationDelay: var(--pte-animations-duration-fast);
|
|
15
|
+
//$panelAnimationDelay: var(--pte-animations-duration-rapid);
|
|
16
|
+
//$duration: var(--pte-animations-duration-normal);
|
|
17
|
+
|
|
18
|
+
.root {
|
|
19
|
+
position: fixed;
|
|
20
|
+
inset: 0;
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
z-index: 10;
|
|
23
|
+
user-select: var(--pte-utils-defaultUserSelect);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.overlay {
|
|
27
|
+
position: absolute;
|
|
28
|
+
inset: 0;
|
|
29
|
+
background-color: var(--pte-colors-backgroundOverlayDark);
|
|
30
|
+
will-change: backdrop-filter, opacity;
|
|
31
|
+
backdrop-filter: blur(0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.overlayContainer {
|
|
35
|
+
.enterFrom {
|
|
36
|
+
backdrop-filter: blur(0);
|
|
37
|
+
}
|
|
38
|
+
.enterTo {
|
|
39
|
+
backdrop-filter: blur(2px);
|
|
40
|
+
}
|
|
41
|
+
.leave {
|
|
42
|
+
transition-delay: $panelAnimationDelay;
|
|
43
|
+
}
|
|
44
|
+
.leaveFrom {
|
|
45
|
+
backdrop-filter: blur(2px);
|
|
46
|
+
}
|
|
47
|
+
.leaveTo {
|
|
48
|
+
backdrop-filter: blur(0);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.panelContainer {
|
|
53
|
+
position: fixed;
|
|
54
|
+
|
|
55
|
+
justify-self: flex-end;
|
|
56
|
+
|
|
57
|
+
z-index: 10;
|
|
58
|
+
|
|
59
|
+
.enter {
|
|
60
|
+
transition: $duration var(--pte-animations-timing-easeOut);
|
|
61
|
+
transition-delay: $panelAnimationDelay;
|
|
62
|
+
//transition-delay: 50ms;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.leave {
|
|
66
|
+
transition: $duration var(--pte-animations-timing-easeIn);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
&.from-right {
|
|
70
|
+
right: 0;
|
|
71
|
+
padding-left: $panelMinMargin;
|
|
72
|
+
|
|
73
|
+
.enterFrom {
|
|
74
|
+
transform: translateX($translateInX);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.enterTo, .leaveFrom {
|
|
78
|
+
transform: translateX(0);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.leaveTo {
|
|
82
|
+
transform: translateX($translateOutX);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&.from-left {
|
|
87
|
+
left: 0;
|
|
88
|
+
padding-right: $panelMinMargin;
|
|
89
|
+
|
|
90
|
+
.enterFrom {
|
|
91
|
+
transform: translateX(-$translateInX);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.enterTo, .leaveFrom {
|
|
95
|
+
transform: translateX(0);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.leaveTo {
|
|
99
|
+
transform: translateX(-$translateOutX);
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
&.from-left, &.from-right {
|
|
106
|
+
height: 100vh;
|
|
107
|
+
top: 0;
|
|
108
|
+
bottom: 0;
|
|
109
|
+
|
|
110
|
+
&.size-default {
|
|
111
|
+
width: min(100vw, $defaultSize);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
&.size-content {
|
|
115
|
+
width: auto;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&.size-full {
|
|
119
|
+
width: 100vw;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
&.from-top {
|
|
124
|
+
top: 0;
|
|
125
|
+
padding-bottom: $panelMinMargin;
|
|
126
|
+
|
|
127
|
+
.enterFrom {
|
|
128
|
+
transform: translateY(-$translateInY);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.enterTo, .leaveFrom {
|
|
132
|
+
transform: translateY(0);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.leaveTo {
|
|
136
|
+
transform: translateY(-$translateOutY);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
&.from-bottom {
|
|
141
|
+
bottom: 0;
|
|
142
|
+
padding: $panelMinMargin 0 0;
|
|
143
|
+
|
|
144
|
+
.enterFrom {
|
|
145
|
+
transform: translateY($translateInY);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.enterTo, .leaveFrom {
|
|
149
|
+
transform: translateY(0);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.leaveTo {
|
|
153
|
+
transform: translateY($translateOutY);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
&.from-top, &.from-bottom {
|
|
158
|
+
width: 100vw;
|
|
159
|
+
left: 0;
|
|
160
|
+
right: 0;
|
|
161
|
+
|
|
162
|
+
&.size-default {
|
|
163
|
+
height: min(100vh, $defaultSize);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
&.size-content {
|
|
167
|
+
height: auto;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
&.size-full {
|
|
171
|
+
height: 100vh;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.panel {
|
|
177
|
+
position: relative;
|
|
178
|
+
height: 100%;
|
|
179
|
+
padding: $panelPaddingY $panelPaddingX;
|
|
180
|
+
background-color: var(--pte-colors-backgroundPrimary);
|
|
181
|
+
overflow: auto;
|
|
182
|
+
border: 1px solid transparent;
|
|
183
|
+
|
|
184
|
+
display: flex;
|
|
185
|
+
flex-direction: column;
|
|
186
|
+
justify-content: flex-start;
|
|
187
|
+
align-items: stretch;
|
|
188
|
+
gap: $panelPaddingY;
|
|
189
|
+
|
|
190
|
+
&.enterFrom {
|
|
191
|
+
box-shadow: none;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
&.enterTo, &.leaveFrom {
|
|
195
|
+
&.from-right {
|
|
196
|
+
border-left-color: var(--pte-borders-dropdown-color);
|
|
197
|
+
box-shadow: var(--pte-lighting-shallowLeft);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
&.from-left {
|
|
201
|
+
border-right-color: var(--pte-borders-dropdown-color);
|
|
202
|
+
box-shadow: var(--pte-lighting-shallowRight);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
&.from-top {
|
|
206
|
+
border-bottom-color: var(--pte-borders-dropdown-color);
|
|
207
|
+
box-shadow: var(--pte-lighting-shallowBottom);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
&.from-bottom {
|
|
211
|
+
border-top-color: var(--pte-borders-dropdown-color);
|
|
212
|
+
box-shadow: var(--pte-lighting-shallowTop);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
&.leaveTo {
|
|
217
|
+
box-shadow: none;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.closeButton {
|
|
222
|
+
position: absolute;
|
|
223
|
+
right: $panelPaddingX;
|
|
224
|
+
top: $panelPaddingY - 5px;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.paginationNav {
|
|
228
|
+
width: 100%;
|
|
229
|
+
display: flex;
|
|
230
|
+
flex-direction: row;
|
|
231
|
+
justify-content: space-between;
|
|
232
|
+
align-items: center;
|
|
233
|
+
|
|
234
|
+
font-size: 16px;
|
|
235
|
+
|
|
236
|
+
.closeButton {
|
|
237
|
+
position: relative;
|
|
238
|
+
right: 0;
|
|
239
|
+
top: 0;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.navButton {
|
|
243
|
+
padding: 2px;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.paginationButtons {
|
|
248
|
+
display: flex;
|
|
249
|
+
flex-direction: row;
|
|
250
|
+
align-items: center;
|
|
251
|
+
gap: 8px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.enter {
|
|
255
|
+
transition: $duration var(--pte-animations-timing-easeOut);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.enterFrom, .enterFromOpacity {
|
|
259
|
+
opacity: 0;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.enterTo, .enterToOpacity {
|
|
263
|
+
opacity: 1;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.leave {
|
|
267
|
+
transition: $duration var(--pte-animations-timing-easeIn);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.leaveFrom, .leaveFromOpacity {
|
|
271
|
+
opacity: 1;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.leaveTo, .leaveToOpacity {
|
|
275
|
+
opacity: 0;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.paginationEnter {
|
|
279
|
+
transition: $paginationDuration var(--pte-animations-timing-easeInQuad);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.paginationLeave {
|
|
283
|
+
transition: $paginationDuration var(--pte-animations-timing-easeOutQuad);
|
|
284
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { memo, useState } from 'react';
|
|
4
|
+
import { Drawer } from './Drawer';
|
|
5
|
+
import { Button } from '../button';
|
|
6
|
+
import { usePagination } from '../pagination';
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof Drawer> = {
|
|
9
|
+
title: 'Surfaces/Drawer',
|
|
10
|
+
component: Drawer,
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
type Story = StoryObj<typeof Drawer>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
args: {
|
|
19
|
+
title: 'Transaction details',
|
|
20
|
+
children: 'This was a transaction for $22.89 at Il Tramezzino in Beverly Hills, CA.',
|
|
21
|
+
},
|
|
22
|
+
render: (args) => {
|
|
23
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
24
|
+
return (
|
|
25
|
+
<>
|
|
26
|
+
<Button
|
|
27
|
+
onClick={() => setIsOpen(true)}
|
|
28
|
+
>
|
|
29
|
+
View details
|
|
30
|
+
</Button>
|
|
31
|
+
<Drawer
|
|
32
|
+
{...args}
|
|
33
|
+
isOpen={isOpen}
|
|
34
|
+
onClose={setIsOpen}
|
|
35
|
+
>
|
|
36
|
+
{args.children}
|
|
37
|
+
</Drawer>
|
|
38
|
+
</>
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Paginated: Story = {
|
|
44
|
+
args: {
|
|
45
|
+
title: 'Creation process',
|
|
46
|
+
children: [],
|
|
47
|
+
},
|
|
48
|
+
render: (args) => {
|
|
49
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
50
|
+
const pages = ['step1', 'step2', 'step3'] as const;
|
|
51
|
+
const pagination = usePagination<typeof pages>('step1');
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<>
|
|
55
|
+
<Button
|
|
56
|
+
onClick={() => setIsOpen(true)}
|
|
57
|
+
>
|
|
58
|
+
Start process
|
|
59
|
+
</Button>
|
|
60
|
+
<Drawer
|
|
61
|
+
{...args}
|
|
62
|
+
isOpen={isOpen}
|
|
63
|
+
onClose={setIsOpen}
|
|
64
|
+
pagination={pagination}
|
|
65
|
+
>
|
|
66
|
+
<div key="step1" style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
67
|
+
Step 1: Enter your name
|
|
68
|
+
<Button
|
|
69
|
+
onClick={() => pagination.open('step2')}
|
|
70
|
+
>
|
|
71
|
+
Go to step 2
|
|
72
|
+
</Button>
|
|
73
|
+
<Button
|
|
74
|
+
onClick={() => pagination.open('step3')}
|
|
75
|
+
>
|
|
76
|
+
Go to step 3
|
|
77
|
+
</Button>
|
|
78
|
+
</div>
|
|
79
|
+
<div key="step2" style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
80
|
+
Step 2: Enter your address
|
|
81
|
+
<Button
|
|
82
|
+
onClick={() => pagination.open('step3')}
|
|
83
|
+
>
|
|
84
|
+
Go to step 3
|
|
85
|
+
</Button>
|
|
86
|
+
</div>
|
|
87
|
+
<div key="step3" style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
88
|
+
Step 3: Enter your credit card information
|
|
89
|
+
</div>
|
|
90
|
+
</Drawer>
|
|
91
|
+
</>
|
|
92
|
+
);
|
|
93
|
+
},
|
|
94
|
+
};
|