polpo 0.1.0 → 0.1.2
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/.storybook/theme.ts +2 -2
- package/.turbo/turbo-build.log +0 -77
- package/.turbo/turbo-lint.log +1 -1
- package/README.md +2 -5
- package/dist/chunk-CFYQBHH5.js +3 -0
- package/dist/chunk-CFYQBHH5.js.map +1 -0
- package/dist/chunk-MAWW6AA7.js +3 -0
- package/dist/chunk-MAWW6AA7.js.map +1 -0
- package/dist/get-modal-position-drle0OjP.d.cts +49 -0
- package/dist/get-modal-position-drle0OjP.d.ts +49 -0
- package/dist/helpers.cjs +1 -1
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +9 -2
- package/dist/helpers.d.ts +9 -2
- package/dist/helpers.js +1 -1
- package/dist/hooks.cjs +1 -1
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +59 -21
- package/dist/hooks.d.ts +59 -21
- package/dist/hooks.js +1 -1
- package/dist/ui.cjs +601 -389
- package/dist/ui.cjs.map +1 -1
- package/dist/ui.d.cts +97 -77
- package/dist/ui.d.ts +97 -77
- package/dist/ui.js +585 -373
- package/dist/ui.js.map +1 -1
- package/dist/use-modal-in-container-DiNW1PE_.d.cts +34 -0
- package/dist/use-modal-in-container-neGo-kMk.d.ts +34 -0
- package/package.json +5 -5
- package/src/components/buttons/button/button.stories.tsx +4 -4
- package/src/components/buttons/button/button.style.ts +10 -5
- package/src/components/buttons/button/button.tsx +7 -19
- package/src/components/cards/flip-card/flip-card.tsx +1 -1
- package/src/components/cursor/cursor.stories.tsx +35 -0
- package/src/components/cursor/cursor.style.ts +73 -0
- package/src/components/cursor/cursor.tsx +49 -0
- package/src/components/cursor/index.ts +1 -0
- package/src/components/form/checkbox/checkbox.stories.tsx +51 -0
- package/src/components/form/checkbox/checkbox.style.ts +73 -37
- package/src/components/form/checkbox/checkbox.tsx +38 -4
- package/src/components/form/field/field.stories.tsx +5 -1
- package/src/components/form/field/field.style.ts +12 -0
- package/src/components/form/field/field.tsx +3 -1
- package/src/components/form/field/field.types.ts +6 -0
- package/src/components/form/input-color/input-color.style.ts +5 -4
- package/src/components/form/input-color/input-color.tsx +41 -44
- package/src/components/form/radio/radio.stories.tsx +29 -5
- package/src/components/form/radio/radio.style.ts +45 -24
- package/src/components/form/radio/radio.tsx +22 -3
- package/src/components/form/select/options.tsx +119 -67
- package/src/components/form/select/select.stories.tsx +103 -42
- package/src/components/form/select/select.style.ts +10 -92
- package/src/components/form/select/select.tsx +19 -42
- package/src/components/form/select/select.types.ts +4 -21
- package/src/components/form/slider/slider.style.ts +2 -0
- package/src/components/icon/icons/social.tsx +17 -1
- package/src/components/index.ts +1 -0
- package/src/components/infinity-scroll/infinity-scroll.tsx +1 -1
- package/src/components/line/line.stories.tsx +3 -4
- package/src/components/modals/action-modal/action-modal.stories.tsx +58 -39
- package/src/components/modals/action-modal/action-modal.style.ts +13 -25
- package/src/components/modals/action-modal/action-modal.tsx +68 -70
- package/src/components/modals/aside-modal/aside-modal.stories.tsx +11 -15
- package/src/components/modals/aside-modal/aside-modal.style.ts +17 -37
- package/src/components/modals/aside-modal/aside-modal.tsx +41 -43
- package/src/components/modals/confirmation-modal/confirmation-modal.stories.tsx +21 -9
- package/src/components/modals/index.ts +2 -0
- package/src/components/modals/menu/index.ts +1 -0
- package/src/components/modals/menu/menu.stories.tsx +69 -0
- package/src/components/modals/menu/menu.style.ts +62 -0
- package/src/components/modals/menu/menu.tsx +142 -0
- package/src/components/modals/modal/backdrop.tsx +70 -0
- package/src/components/modals/modal/index.ts +1 -0
- package/src/components/modals/modal/modal.stories.tsx +325 -0
- package/src/components/modals/modal/modal.style.ts +62 -2
- package/src/components/modals/modal/modal.tsx +82 -123
- package/src/components/modals/portal/index.ts +1 -0
- package/src/components/modals/portal/portal.tsx +18 -0
- package/src/components/tabs/tabs-list.tsx +13 -10
- package/src/components/tabs/tabs.style.ts +48 -43
- package/src/components/tag/tag.stories.tsx +11 -12
- package/src/components/tag/tag.style.ts +9 -4
- package/src/components/tag/tag.tsx +2 -12
- package/src/components/tooltips/tooltip/tooltip.stories.tsx +5 -2
- package/src/components/tooltips/tooltip/tooltip.style.ts +37 -6
- package/src/components/tooltips/tooltip/tooltip.tsx +33 -19
- package/src/components/typography/typography.stories.tsx +3 -1
- package/src/components/typography/typography.tsx +21 -0
- package/src/contexts/theme-context/theme.animations.ts +91 -2
- package/src/contexts/theme-context/theme.defaults.ts +1 -1
- package/src/core/http-client.ts +49 -47
- package/src/core/variants/color.ts +3 -30
- package/src/core/variants/radius.ts +12 -41
- package/src/core/variants/size.ts +8 -33
- package/src/helpers/get-modal-position-relative-to-screen.ts +86 -0
- package/src/helpers/get-modal-position.ts +173 -28
- package/src/helpers/index.ts +1 -0
- package/src/hooks/index.ts +9 -3
- package/src/hooks/use-click-outside.ts +32 -0
- package/src/hooks/use-cookie.ts +124 -0
- package/src/hooks/use-dimensions.ts +11 -14
- package/src/hooks/use-dom-container.ts +32 -0
- package/src/hooks/use-event-listener.ts +4 -4
- package/src/hooks/use-geolocation.ts +63 -0
- package/src/hooks/use-in-view.ts +9 -11
- package/src/hooks/use-intersection-observer.ts +19 -0
- package/src/hooks/use-modal-in-container.ts +60 -52
- package/src/hooks/use-modal-transition.ts +54 -0
- package/src/hooks/use-modal.ts +21 -0
- package/src/hooks/use-mouse-position.ts +55 -7
- package/src/hooks/use-resize-observer.ts +18 -0
- package/src/stories/GettingStarted.mdx +2 -6
- package/svg/Name=npm, Category=social.svg +3 -0
- package/tsconfig.json +1 -0
- package/vite.config.ts +1 -0
- package/.turbo/daemon/f5c5c8fb195b01d0-turbo.log.2024-05-26 +0 -0
- package/.turbo/turbo-build$colon$watch.log +0 -96
- package/.turbo/turbo-build-storybook.log +0 -0
- package/.turbo/turbo-lint$colon$fix.log +0 -2
- package/dist/chunk-M4KRSYE7.js +0 -3
- package/dist/chunk-M4KRSYE7.js.map +0 -1
- package/dist/chunk-U5XSMSKZ.js +0 -3
- package/dist/chunk-U5XSMSKZ.js.map +0 -1
- package/dist/get-modal-position-DPftPoU2.d.cts +0 -28
- package/dist/get-modal-position-DPftPoU2.d.ts +0 -28
- package/src/components/form/select/select-option.tsx +0 -84
- package/src/hooks/use-observer.ts +0 -18
- package/src/hooks/use-on-click-outside-ref.ts +0 -17
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { Button } from '../../buttons';
|
|
2
|
+
|
|
3
|
+
import { Modal as ModalComponent, ModalProps } from './modal';
|
|
4
|
+
|
|
5
|
+
import { PositionContainer } from '@polpo/helpers';
|
|
6
|
+
import { useModal } from '@polpo/hooks';
|
|
7
|
+
import { Grid, Line, ModalBackdrop, Typography } from '@polpo/ui';
|
|
8
|
+
|
|
9
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
10
|
+
|
|
11
|
+
const Modal = ({ children, ...props }: ModalProps) => (
|
|
12
|
+
<ModalComponent backdrop='none' {...props} style={{ borderRadius: '1em' }}>
|
|
13
|
+
<Grid style={{ width: '400px', maxWidth: '100%', padding: '1em' }}>
|
|
14
|
+
<Typography variant='header4' color='primary'>
|
|
15
|
+
{children}
|
|
16
|
+
</Typography>
|
|
17
|
+
<Line />
|
|
18
|
+
<Typography>
|
|
19
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit. At, commodi dolore, doloremque doloribus esse
|
|
20
|
+
excepturi impedit in, ipsam ipsum iste magni nihil officiis quasi quia quod similique tenetur? Aliquid cum dolor
|
|
21
|
+
incidunt nihil?
|
|
22
|
+
</Typography>
|
|
23
|
+
</Grid>
|
|
24
|
+
</ModalComponent>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const meta: Meta<typeof ModalComponent> = {
|
|
28
|
+
title: 'Modals/Modal',
|
|
29
|
+
component: ModalComponent,
|
|
30
|
+
argTypes: {
|
|
31
|
+
animation: { control: { type: 'inline-radio', options: ['none', 'fade-down', 'bounce'] } },
|
|
32
|
+
windowOffset: { control: { type: 'range', min: 0, max: 100 } },
|
|
33
|
+
offset: { control: { type: 'range', min: 0, max: 100 } },
|
|
34
|
+
position: { control: 'inline-radio', options: Object.values(PositionContainer) },
|
|
35
|
+
closeOnClickOutside: { control: 'boolean' },
|
|
36
|
+
opacity: { control: { type: 'range', min: 0, max: 1, step: 0.1 } },
|
|
37
|
+
backdrop: { control: { type: 'inline-radio', options: Object.values(ModalBackdrop) } },
|
|
38
|
+
transitionDuration: { control: false },
|
|
39
|
+
backdropOnClick: { control: false },
|
|
40
|
+
zIndex: { control: false },
|
|
41
|
+
id: { control: false },
|
|
42
|
+
children: { control: false },
|
|
43
|
+
isOpen: { control: false },
|
|
44
|
+
onClose: { control: false },
|
|
45
|
+
className: { control: false },
|
|
46
|
+
style: { control: false },
|
|
47
|
+
rootStyle: { control: false },
|
|
48
|
+
closeAnimationClassName: { control: false },
|
|
49
|
+
containerRef: { control: false },
|
|
50
|
+
modalRef: { control: false },
|
|
51
|
+
},
|
|
52
|
+
args: {
|
|
53
|
+
offset: 20,
|
|
54
|
+
windowOffset: 10,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default meta;
|
|
59
|
+
type Story = StoryObj<typeof ModalComponent>;
|
|
60
|
+
|
|
61
|
+
export const AllContainerPositions: Story = {
|
|
62
|
+
argTypes: {
|
|
63
|
+
position: { control: false },
|
|
64
|
+
},
|
|
65
|
+
render: args => {
|
|
66
|
+
const modal1 = useModal<HTMLButtonElement>();
|
|
67
|
+
const modal2 = useModal<HTMLButtonElement>();
|
|
68
|
+
const modal3 = useModal<HTMLButtonElement>();
|
|
69
|
+
const modal4 = useModal<HTMLButtonElement>();
|
|
70
|
+
const modal5 = useModal<HTMLButtonElement>();
|
|
71
|
+
const modal6 = useModal<HTMLButtonElement>();
|
|
72
|
+
const modal7 = useModal<HTMLButtonElement>();
|
|
73
|
+
const modal8 = useModal<HTMLButtonElement>();
|
|
74
|
+
const modal9 = useModal<HTMLButtonElement>();
|
|
75
|
+
const modal10 = useModal<HTMLButtonElement>();
|
|
76
|
+
const modal11 = useModal<HTMLButtonElement>();
|
|
77
|
+
const modal12 = useModal<HTMLButtonElement>();
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<Grid gtc='repeat(3, 1fr)' gap='20px'>
|
|
81
|
+
<Button width='full' ref={modal1.containerRef} onClick={modal1.openModal}>
|
|
82
|
+
top left
|
|
83
|
+
</Button>
|
|
84
|
+
<Modal
|
|
85
|
+
{...args}
|
|
86
|
+
containerRef={modal1.containerRef}
|
|
87
|
+
id='container-modal'
|
|
88
|
+
isOpen={modal1.isOpen}
|
|
89
|
+
onClose={modal1.closeModal}
|
|
90
|
+
position='top left'
|
|
91
|
+
>
|
|
92
|
+
top left
|
|
93
|
+
</Modal>
|
|
94
|
+
<Button width='full' ref={modal2.containerRef} onClick={modal2.openModal}>
|
|
95
|
+
top center
|
|
96
|
+
</Button>
|
|
97
|
+
<Modal
|
|
98
|
+
{...args}
|
|
99
|
+
containerRef={modal2.containerRef}
|
|
100
|
+
id='container-modal'
|
|
101
|
+
isOpen={modal2.isOpen}
|
|
102
|
+
onClose={modal2.closeModal}
|
|
103
|
+
position='top center'
|
|
104
|
+
>
|
|
105
|
+
top center
|
|
106
|
+
</Modal>
|
|
107
|
+
<Button width='full' ref={modal3.containerRef} onClick={modal3.openModal}>
|
|
108
|
+
top right
|
|
109
|
+
</Button>
|
|
110
|
+
<Modal
|
|
111
|
+
{...args}
|
|
112
|
+
containerRef={modal3.containerRef}
|
|
113
|
+
id='container-modal'
|
|
114
|
+
isOpen={modal3.isOpen}
|
|
115
|
+
onClose={modal3.closeModal}
|
|
116
|
+
position='top right'
|
|
117
|
+
>
|
|
118
|
+
top right
|
|
119
|
+
</Modal>
|
|
120
|
+
|
|
121
|
+
<Button width='full' ref={modal4.containerRef} onClick={modal4.openModal}>
|
|
122
|
+
left top
|
|
123
|
+
</Button>
|
|
124
|
+
<Modal
|
|
125
|
+
{...args}
|
|
126
|
+
containerRef={modal4.containerRef}
|
|
127
|
+
id='container-modal'
|
|
128
|
+
isOpen={modal4.isOpen}
|
|
129
|
+
onClose={modal4.closeModal}
|
|
130
|
+
position='left top'
|
|
131
|
+
>
|
|
132
|
+
left top
|
|
133
|
+
</Modal>
|
|
134
|
+
<span />
|
|
135
|
+
<Button width='full' ref={modal5.containerRef} onClick={modal5.openModal}>
|
|
136
|
+
right top
|
|
137
|
+
</Button>
|
|
138
|
+
<Modal
|
|
139
|
+
{...args}
|
|
140
|
+
containerRef={modal5.containerRef}
|
|
141
|
+
id='container-modal'
|
|
142
|
+
isOpen={modal5.isOpen}
|
|
143
|
+
onClose={modal5.closeModal}
|
|
144
|
+
position='right top'
|
|
145
|
+
>
|
|
146
|
+
right top
|
|
147
|
+
</Modal>
|
|
148
|
+
|
|
149
|
+
<Button width='full' ref={modal6.containerRef} onClick={modal6.openModal}>
|
|
150
|
+
left center
|
|
151
|
+
</Button>
|
|
152
|
+
<Modal
|
|
153
|
+
{...args}
|
|
154
|
+
containerRef={modal6.containerRef}
|
|
155
|
+
id='container-modal'
|
|
156
|
+
isOpen={modal6.isOpen}
|
|
157
|
+
onClose={modal6.closeModal}
|
|
158
|
+
position='left center'
|
|
159
|
+
>
|
|
160
|
+
left center
|
|
161
|
+
</Modal>
|
|
162
|
+
<span />
|
|
163
|
+
<Button width='full' ref={modal7.containerRef} onClick={modal7.openModal}>
|
|
164
|
+
right center
|
|
165
|
+
</Button>
|
|
166
|
+
<Modal
|
|
167
|
+
{...args}
|
|
168
|
+
containerRef={modal7.containerRef}
|
|
169
|
+
id='container-modal'
|
|
170
|
+
isOpen={modal7.isOpen}
|
|
171
|
+
onClose={modal7.closeModal}
|
|
172
|
+
position='right center'
|
|
173
|
+
>
|
|
174
|
+
right center
|
|
175
|
+
</Modal>
|
|
176
|
+
|
|
177
|
+
<Button width='full' ref={modal8.containerRef} onClick={modal8.openModal}>
|
|
178
|
+
left bottom
|
|
179
|
+
</Button>
|
|
180
|
+
<Modal
|
|
181
|
+
{...args}
|
|
182
|
+
containerRef={modal8.containerRef}
|
|
183
|
+
id='container-modal'
|
|
184
|
+
isOpen={modal8.isOpen}
|
|
185
|
+
onClose={modal8.closeModal}
|
|
186
|
+
position='left bottom'
|
|
187
|
+
>
|
|
188
|
+
left bottom
|
|
189
|
+
</Modal>
|
|
190
|
+
<span />
|
|
191
|
+
<Button width='full' ref={modal9.containerRef} onClick={modal9.openModal}>
|
|
192
|
+
right bottom
|
|
193
|
+
</Button>
|
|
194
|
+
<Modal
|
|
195
|
+
{...args}
|
|
196
|
+
containerRef={modal9.containerRef}
|
|
197
|
+
id='container-modal'
|
|
198
|
+
isOpen={modal9.isOpen}
|
|
199
|
+
onClose={modal9.closeModal}
|
|
200
|
+
position='right bottom'
|
|
201
|
+
>
|
|
202
|
+
right bottom
|
|
203
|
+
</Modal>
|
|
204
|
+
|
|
205
|
+
<Button width='full' ref={modal10.containerRef} onClick={modal10.openModal}>
|
|
206
|
+
bottom left
|
|
207
|
+
</Button>
|
|
208
|
+
<Modal
|
|
209
|
+
{...args}
|
|
210
|
+
containerRef={modal10.containerRef}
|
|
211
|
+
id='container-modal'
|
|
212
|
+
isOpen={modal10.isOpen}
|
|
213
|
+
onClose={modal10.closeModal}
|
|
214
|
+
position='bottom left'
|
|
215
|
+
>
|
|
216
|
+
bottom left
|
|
217
|
+
</Modal>
|
|
218
|
+
<Button width='full' ref={modal11.containerRef} onClick={modal11.openModal}>
|
|
219
|
+
bottom center
|
|
220
|
+
</Button>
|
|
221
|
+
<Modal
|
|
222
|
+
{...args}
|
|
223
|
+
containerRef={modal11.containerRef}
|
|
224
|
+
id='container-modal'
|
|
225
|
+
isOpen={modal11.isOpen}
|
|
226
|
+
onClose={modal11.closeModal}
|
|
227
|
+
position='bottom center'
|
|
228
|
+
>
|
|
229
|
+
bottom center
|
|
230
|
+
</Modal>
|
|
231
|
+
<Button width='full' ref={modal12.containerRef} onClick={modal12.openModal}>
|
|
232
|
+
bottom right
|
|
233
|
+
</Button>
|
|
234
|
+
<Modal
|
|
235
|
+
{...args}
|
|
236
|
+
containerRef={modal12.containerRef}
|
|
237
|
+
id='container-modal'
|
|
238
|
+
isOpen={modal12.isOpen}
|
|
239
|
+
onClose={modal12.closeModal}
|
|
240
|
+
position='bottom right'
|
|
241
|
+
>
|
|
242
|
+
bottom right
|
|
243
|
+
</Modal>
|
|
244
|
+
</Grid>
|
|
245
|
+
);
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
export const AllScreenPositions: Story = {
|
|
250
|
+
argTypes: {
|
|
251
|
+
position: { control: false },
|
|
252
|
+
},
|
|
253
|
+
render: args => {
|
|
254
|
+
const modal1 = useModal();
|
|
255
|
+
const modal2 = useModal();
|
|
256
|
+
const modal3 = useModal();
|
|
257
|
+
const modal4 = useModal();
|
|
258
|
+
const modal5 = useModal();
|
|
259
|
+
const modal6 = useModal();
|
|
260
|
+
const modal7 = useModal();
|
|
261
|
+
const modal8 = useModal();
|
|
262
|
+
const modal9 = useModal();
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<Grid gtc='repeat(3, 1fr)' gap='20px'>
|
|
266
|
+
<Button width='full' onClick={modal1.openModal}>
|
|
267
|
+
top left
|
|
268
|
+
</Button>
|
|
269
|
+
<Modal {...args} id='screen-modal' isOpen={modal1.isOpen} onClose={modal1.closeModal} position='top left'>
|
|
270
|
+
top left
|
|
271
|
+
</Modal>
|
|
272
|
+
<Button width='full' onClick={modal2.openModal}>
|
|
273
|
+
top center
|
|
274
|
+
</Button>
|
|
275
|
+
<Modal {...args} id='screen-modal' isOpen={modal2.isOpen} onClose={modal2.closeModal} position='top center'>
|
|
276
|
+
top center
|
|
277
|
+
</Modal>
|
|
278
|
+
<Button width='full' onClick={modal3.openModal}>
|
|
279
|
+
top right
|
|
280
|
+
</Button>
|
|
281
|
+
<Modal {...args} id='screen-modal' isOpen={modal3.isOpen} onClose={modal3.closeModal} position='top right'>
|
|
282
|
+
top right
|
|
283
|
+
</Modal>
|
|
284
|
+
|
|
285
|
+
<Button width='full' onClick={modal4.openModal}>
|
|
286
|
+
left center
|
|
287
|
+
</Button>
|
|
288
|
+
<Modal {...args} id='screen-modal' isOpen={modal4.isOpen} onClose={modal4.closeModal} position='left center'>
|
|
289
|
+
left center
|
|
290
|
+
</Modal>
|
|
291
|
+
<Button width='full' onClick={modal5.openModal}>
|
|
292
|
+
center
|
|
293
|
+
</Button>
|
|
294
|
+
<Modal {...args} id='screen-modal' isOpen={modal5.isOpen} onClose={modal5.closeModal} position='center'>
|
|
295
|
+
center
|
|
296
|
+
</Modal>
|
|
297
|
+
<Button width='full' onClick={modal6.openModal}>
|
|
298
|
+
right center
|
|
299
|
+
</Button>
|
|
300
|
+
<Modal {...args} id='screen-modal' isOpen={modal6.isOpen} onClose={modal6.closeModal} position='right center'>
|
|
301
|
+
right center
|
|
302
|
+
</Modal>
|
|
303
|
+
|
|
304
|
+
<Button width='full' onClick={modal7.openModal}>
|
|
305
|
+
bottom left
|
|
306
|
+
</Button>
|
|
307
|
+
<Modal {...args} id='screen-modal' isOpen={modal7.isOpen} onClose={modal7.closeModal} position='bottom left'>
|
|
308
|
+
bottom left
|
|
309
|
+
</Modal>
|
|
310
|
+
<Button width='full' onClick={modal8.openModal}>
|
|
311
|
+
bottom center
|
|
312
|
+
</Button>
|
|
313
|
+
<Modal {...args} id='screen-modal' isOpen={modal8.isOpen} onClose={modal8.closeModal} position='bottom center'>
|
|
314
|
+
bottom center
|
|
315
|
+
</Modal>
|
|
316
|
+
<Button width='full' onClick={modal9.openModal}>
|
|
317
|
+
bottom right
|
|
318
|
+
</Button>
|
|
319
|
+
<Modal {...args} id='screen-modal' isOpen={modal9.isOpen} onClose={modal9.closeModal} position='bottom right'>
|
|
320
|
+
bottom right
|
|
321
|
+
</Modal>
|
|
322
|
+
</Grid>
|
|
323
|
+
);
|
|
324
|
+
},
|
|
325
|
+
};
|
|
@@ -1,10 +1,70 @@
|
|
|
1
1
|
import styled from 'styled-components';
|
|
2
2
|
|
|
3
|
-
export const
|
|
4
|
-
|
|
3
|
+
export const ModalStyle = styled.section`
|
|
4
|
+
position: fixed;
|
|
5
|
+
z-index: 1001;
|
|
6
|
+
pointer-events: none;
|
|
7
|
+
`;
|
|
8
|
+
|
|
9
|
+
export const ModalContentStyle = styled.section`
|
|
10
|
+
background: ${props => props.theme.colors.background.paper};
|
|
11
|
+
pointer-events: initial;
|
|
12
|
+
|
|
13
|
+
&.animation-fade-down {
|
|
14
|
+
animation: fadeInDown 200ms ease;
|
|
15
|
+
|
|
16
|
+
&.modal-close {
|
|
17
|
+
animation: fadeOutUp 200ms ease;
|
|
18
|
+
transform: translateY(-10px);
|
|
19
|
+
opacity: 0;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&.animation-bounce {
|
|
24
|
+
animation: bounceIn 500ms ease;
|
|
25
|
+
|
|
26
|
+
&.modal-close {
|
|
27
|
+
animation: bounceOut 500ms ease;
|
|
28
|
+
transform: scale3d(0.3, 0.3, 0.3);
|
|
29
|
+
opacity: 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
export const BackdropStyle = styled.section`
|
|
5
35
|
position: fixed;
|
|
6
36
|
width: 100%;
|
|
7
37
|
height: 100%;
|
|
8
38
|
top: 0;
|
|
9
39
|
left: 0;
|
|
40
|
+
z-index: 1000;
|
|
41
|
+
animation: backdropOpen 500ms cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
42
|
+
|
|
43
|
+
&.backdrop-close {
|
|
44
|
+
animation: backdropClose 500ms cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
45
|
+
opacity: 0;
|
|
46
|
+
transform: translateY(-10px);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@keyframes backdropOpen {
|
|
50
|
+
from {
|
|
51
|
+
opacity: 0;
|
|
52
|
+
transform: translateY(-10px);
|
|
53
|
+
}
|
|
54
|
+
to {
|
|
55
|
+
opacity: 1;
|
|
56
|
+
transform: translateY(0);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@keyframes backdropClose {
|
|
61
|
+
from {
|
|
62
|
+
opacity: 1;
|
|
63
|
+
transform: translateY(0);
|
|
64
|
+
}
|
|
65
|
+
to {
|
|
66
|
+
opacity: 0;
|
|
67
|
+
transform: translateY(-10px);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
10
70
|
`;
|
|
@@ -1,132 +1,91 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (typeof ref === 'function') {
|
|
67
|
-
ref(modalContainer);
|
|
68
|
-
} else if (ref) {
|
|
69
|
-
ref.current = modalContainer;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
document.body.appendChild(modalContainer);
|
|
1
|
+
import React, { CSSProperties, useLayoutEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Backdrop, BackdropProps } from './backdrop';
|
|
4
|
+
import { ModalContentStyle, ModalStyle } from './modal.style';
|
|
5
|
+
|
|
6
|
+
import { ModalState, useClassNames, useModalInContainer, UseModalInContainerParams } from '@polpo/hooks';
|
|
7
|
+
import { Portal } from '@polpo/ui';
|
|
8
|
+
|
|
9
|
+
export type ModalProps = Omit<BackdropProps, 'modalState'> &
|
|
10
|
+
Omit<UseModalInContainerParams, 'modalRef' | 'onClose'> & {
|
|
11
|
+
id: string;
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
isOpen: boolean;
|
|
14
|
+
onClose: () => void;
|
|
15
|
+
className?: string;
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
rootStyle?: CSSProperties;
|
|
18
|
+
animation?: 'none' | 'fade-down' | 'bounce';
|
|
19
|
+
closeAnimationClassName?: string;
|
|
20
|
+
modalRef?: React.RefObject<HTMLElement>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const Modal = ({
|
|
24
|
+
id,
|
|
25
|
+
children,
|
|
26
|
+
isOpen,
|
|
27
|
+
onClose,
|
|
28
|
+
className = '',
|
|
29
|
+
style = {},
|
|
30
|
+
rootStyle = {},
|
|
31
|
+
animation = 'fade-down',
|
|
32
|
+
closeAnimationClassName = 'modal-close',
|
|
33
|
+
modalRef: modalRefProp,
|
|
34
|
+
closeOnClickOutside,
|
|
35
|
+
transitionDuration = 300,
|
|
36
|
+
windowOffset = 10,
|
|
37
|
+
offset = 20,
|
|
38
|
+
position,
|
|
39
|
+
containerRef,
|
|
40
|
+
zIndex = 1000,
|
|
41
|
+
...backdropProps
|
|
42
|
+
}: ModalProps) => {
|
|
43
|
+
const modalRef = useRef<HTMLElement>(null);
|
|
44
|
+
const { openModal, closeModal, modalState, isVisible } = useModalInContainer({
|
|
45
|
+
modalRef: modalRefProp ?? modalRef,
|
|
46
|
+
containerRef,
|
|
47
|
+
closeOnClickOutside,
|
|
48
|
+
offset,
|
|
49
|
+
windowOffset,
|
|
50
|
+
position,
|
|
51
|
+
transitionDuration,
|
|
52
|
+
onClose,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const modalContentClassName = useClassNames({
|
|
56
|
+
[className]: true,
|
|
57
|
+
[`animation-${animation}`]: Boolean(animation) && animation !== 'none',
|
|
58
|
+
[closeAnimationClassName]: modalState === ModalState.CLOSING || modalState === ModalState.CLOSED,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
useLayoutEffect(() => {
|
|
62
|
+
if (modalState === ModalState.CLOSED && isOpen) {
|
|
63
|
+
openModal();
|
|
64
|
+
} else if (modalState === ModalState.OPEN && !isOpen) {
|
|
65
|
+
closeModal();
|
|
73
66
|
}
|
|
67
|
+
}, [isOpen, openModal, closeModal, modalState]);
|
|
74
68
|
|
|
75
|
-
|
|
76
|
-
* return () => {
|
|
77
|
-
* if (modalContainer.parentNode === document.body) {
|
|
78
|
-
* document.body.removeChild(modalContainer);
|
|
79
|
-
* }
|
|
80
|
-
* };
|
|
81
|
-
*/
|
|
82
|
-
}, [containerID, ref]);
|
|
83
|
-
|
|
84
|
-
const backgroundStyles = useMemo(() => {
|
|
85
|
-
switch (backdrop) {
|
|
86
|
-
case ModalBackdrop.OPAQUE:
|
|
87
|
-
return {
|
|
88
|
-
background: `${theme.colors.background.paper}${(opacity * 255)?.toString(16)}`,
|
|
89
|
-
};
|
|
90
|
-
case ModalBackdrop.TRANSPARENT:
|
|
91
|
-
return {
|
|
92
|
-
background: 'transparent',
|
|
93
|
-
};
|
|
94
|
-
case ModalBackdrop.BLUR:
|
|
95
|
-
return {
|
|
96
|
-
background: `${theme.colors.background.paper}${(opacity * 255)?.toString(16)}`,
|
|
97
|
-
backdropFilter: 'blur(5px)',
|
|
98
|
-
};
|
|
99
|
-
case ModalBackdrop.NONE:
|
|
100
|
-
return {
|
|
101
|
-
display: 'none',
|
|
102
|
-
};
|
|
103
|
-
default:
|
|
104
|
-
return {};
|
|
105
|
-
}
|
|
106
|
-
}, [backdrop, theme.colors.background.paper, opacity]);
|
|
107
|
-
|
|
108
|
-
const root = document.getElementById(containerID);
|
|
109
|
-
|
|
110
|
-
if (!isOpen || !root) {
|
|
69
|
+
if (!isVisible) {
|
|
111
70
|
return null;
|
|
112
71
|
}
|
|
113
72
|
|
|
114
|
-
return
|
|
115
|
-
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
className={className}
|
|
73
|
+
return (
|
|
74
|
+
<Portal id={`modal-${id}`}>
|
|
75
|
+
<Backdrop {...backdropProps} modalState={modalState} zIndex={zIndex} />
|
|
76
|
+
<ModalStyle
|
|
77
|
+
ref={modalRefProp ?? modalRef}
|
|
120
78
|
style={{
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
...
|
|
79
|
+
maxWidth: `calc(100dvw - ${windowOffset * 2}px)`,
|
|
80
|
+
maxHeight: `calc(100dvh - ${windowOffset * 2}px)`,
|
|
81
|
+
...rootStyle,
|
|
82
|
+
zIndex: +zIndex + 1,
|
|
124
83
|
}}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
84
|
+
>
|
|
85
|
+
<ModalContentStyle style={style} className={modalContentClassName}>
|
|
86
|
+
{children}
|
|
87
|
+
</ModalContentStyle>
|
|
88
|
+
</ModalStyle>
|
|
89
|
+
</Portal>
|
|
129
90
|
);
|
|
130
91
|
};
|
|
131
|
-
|
|
132
|
-
export const Modal = forwardRef(ModalComponent);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './portal';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ForwardedRef, forwardRef, ReactNode, useMemo } from 'react';
|
|
2
|
+
import { createPortal } from 'react-dom';
|
|
3
|
+
|
|
4
|
+
import { useDomContainer } from '@polpo/hooks';
|
|
5
|
+
|
|
6
|
+
type PortalProps = {
|
|
7
|
+
id: string;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const PortalComponent = ({ children, id }: PortalProps, ref: ForwardedRef<HTMLElement>) => {
|
|
12
|
+
const uuid = useMemo(() => crypto.randomUUID(), []);
|
|
13
|
+
const root = useDomContainer(`${id}-${uuid}`, ref);
|
|
14
|
+
|
|
15
|
+
return createPortal(children, root);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const Portal = forwardRef(PortalComponent);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { useTheme } from 'styled-components';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import { RadiusVariants, SizeVariants, useRadiusClassName, useSizeClassName } from '../../core/variants';
|
|
4
|
+
import { RadiusVariants, SizeVariants } from '../../core/variants';
|
|
6
5
|
|
|
7
6
|
import { Tabs } from './tabs';
|
|
8
|
-
import { TabListStyle,
|
|
7
|
+
import { TabListStyle, TabListColorStyle } from './tabs.style';
|
|
9
8
|
|
|
10
9
|
import { useClassNames } from '@polpo/hooks';
|
|
10
|
+
import { ThemeColor } from '@polpo/ui';
|
|
11
11
|
|
|
12
12
|
const DefaultRect = {
|
|
13
13
|
top: 0,
|
|
@@ -34,7 +34,7 @@ export enum TabListDirection {
|
|
|
34
34
|
VERTICAL = 'vertical',
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
const getColor = (color?: ThemeColor):
|
|
37
|
+
const getColor = (color?: ThemeColor): TabListColorStyle | null => {
|
|
38
38
|
if (color) {
|
|
39
39
|
return {
|
|
40
40
|
$color: color.main,
|
|
@@ -78,11 +78,7 @@ export const TabsList = ({
|
|
|
78
78
|
const selectedTabRef = useRef<HTMLSpanElement>(null);
|
|
79
79
|
const [isSelectorActive, setIsSelectorActive] = useState(false);
|
|
80
80
|
const [selector, setSelector] = useState(DefaultRect);
|
|
81
|
-
const tabRadius = useRadiusClassName(radius);
|
|
82
|
-
const tabSize = useSizeClassName(size);
|
|
83
81
|
const containerClassNames = useClassNames({
|
|
84
|
-
[tabRadius]: true,
|
|
85
|
-
[tabSize]: true,
|
|
86
82
|
'solid-variant': variant === TabListVariant.SOLID,
|
|
87
83
|
'ghost-variant': variant === TabListVariant.GHOST,
|
|
88
84
|
'flat-variant': variant === TabListVariant.FLAT,
|
|
@@ -112,13 +108,20 @@ export const TabsList = ({
|
|
|
112
108
|
}
|
|
113
109
|
}, [isSelectorActive, variant, openTab]);
|
|
114
110
|
|
|
115
|
-
const containerColors:
|
|
111
|
+
const containerColors: TabListColorStyle = (color && getColor(theme.colors[color])) || {
|
|
116
112
|
$color: theme.colors.text.main,
|
|
117
113
|
$colorContrast: theme.colors.background.main,
|
|
118
114
|
};
|
|
119
115
|
|
|
120
116
|
return (
|
|
121
|
-
<TabListStyle
|
|
117
|
+
<TabListStyle
|
|
118
|
+
{...containerColors}
|
|
119
|
+
className={containerClassNames}
|
|
120
|
+
ref={containerRef}
|
|
121
|
+
style={style}
|
|
122
|
+
$size={size}
|
|
123
|
+
$radius={radius}
|
|
124
|
+
>
|
|
122
125
|
{Boolean(variant) && <span className={`tabs-selector ${isSelectorActive ? 'active' : ''}`} style={selector} />}
|
|
123
126
|
{tabs.map(({ id, label }) => (
|
|
124
127
|
<Tabs.Tab key={id} id={id} ref={id === openTab ? selectedTabRef : null}>
|