@codeleap/web 3.18.3 → 3.18.4
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeleap/web",
|
|
3
|
-
"version": "3.18.
|
|
3
|
+
"version": "3.18.4",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
"react-window": "1.8.5",
|
|
42
42
|
"slick-carousel": "^1.8.1",
|
|
43
43
|
"url-parse": "^1.5.10",
|
|
44
|
-
"uuid": "^8.3.2"
|
|
44
|
+
"uuid": "^8.3.2",
|
|
45
|
+
"zustand": "^4.4.1"
|
|
45
46
|
},
|
|
46
47
|
"peerDependencies": {
|
|
47
48
|
"@codeleap/common": "*",
|
|
@@ -36,7 +36,6 @@ export type DrawerProps = {
|
|
|
36
36
|
style?: React.CSSProperties
|
|
37
37
|
animationDuration?: string
|
|
38
38
|
closeButtonProps?: Partial<ActionIconProps>
|
|
39
|
-
scrollLocked?: boolean
|
|
40
39
|
closeIcon?: IconPlaceholder
|
|
41
40
|
children?: React.ReactNode
|
|
42
41
|
} & ComponentVariants<typeof DrawerPresets> & ComponentCommonProps
|
|
@@ -68,7 +67,6 @@ const defaultProps: Partial<DrawerProps> = {
|
|
|
68
67
|
darkenBackground: true,
|
|
69
68
|
size: '75vw',
|
|
70
69
|
title: null,
|
|
71
|
-
scrollLocked: false,
|
|
72
70
|
closeIcon: 'x' as IconPlaceholder,
|
|
73
71
|
}
|
|
74
72
|
|
|
@@ -95,11 +93,10 @@ export const Drawer = (props: DrawerProps) => {
|
|
|
95
93
|
style,
|
|
96
94
|
animationDuration,
|
|
97
95
|
debugName,
|
|
98
|
-
scrollLocked,
|
|
99
96
|
closeIcon,
|
|
100
97
|
} = allProps as DrawerProps
|
|
101
98
|
|
|
102
|
-
usePopState(open, toggle
|
|
99
|
+
usePopState(open, toggle)
|
|
103
100
|
|
|
104
101
|
const [hiddenStyle, axis, positioning] = resolveHiddenDrawerPosition(position)
|
|
105
102
|
|
|
@@ -134,7 +131,6 @@ export const Drawer = (props: DrawerProps) => {
|
|
|
134
131
|
visible={open}
|
|
135
132
|
css={variantStyles.overlay}
|
|
136
133
|
onPress={toggle}
|
|
137
|
-
scrollLocked={scrollLocked}
|
|
138
134
|
/>
|
|
139
135
|
)}
|
|
140
136
|
|
|
@@ -25,17 +25,18 @@ import { ActionIcon, ActionIconProps } from '../ActionIcon'
|
|
|
25
25
|
import { Scroll } from '../Scroll'
|
|
26
26
|
import { ComponentCommonProps } from '../../types'
|
|
27
27
|
import { Touchable, TouchableProps } from '../Touchable'
|
|
28
|
+
import { modalScrollLock, ModalStore } from '../../lib/modal'
|
|
28
29
|
|
|
29
30
|
export * from './styles'
|
|
30
31
|
|
|
31
32
|
export type ModalProps =
|
|
32
33
|
{
|
|
33
|
-
visible
|
|
34
|
+
visible?: boolean
|
|
34
35
|
children?: React.ReactNode
|
|
35
36
|
title?: React.ReactNode | string
|
|
36
37
|
description?: React.ReactNode | string
|
|
37
38
|
renderModalBody?: (props: ModalBodyProps) => React.ReactElement
|
|
38
|
-
toggle
|
|
39
|
+
toggle?: AnyFunction
|
|
39
40
|
styles?: StylesOf<ModalComposition>
|
|
40
41
|
style?: React.CSSProperties
|
|
41
42
|
accessible?: boolean
|
|
@@ -56,9 +57,11 @@ export type ModalProps =
|
|
|
56
57
|
overlayProps?: Partial<OverlayProps>
|
|
57
58
|
zIndex?: number
|
|
58
59
|
withScrollContainer?: boolean
|
|
59
|
-
|
|
60
|
+
scrollLock?: boolean
|
|
60
61
|
backdropProps?: Partial<TouchableProps>
|
|
61
62
|
alterHistory?: boolean
|
|
63
|
+
modalId?: string
|
|
64
|
+
autoIndex?: boolean
|
|
62
65
|
} & ComponentVariants<typeof ModalPresets> & ComponentCommonProps
|
|
63
66
|
|
|
64
67
|
function focusModal(event: FocusEvent, id: string) {
|
|
@@ -148,7 +151,9 @@ const defaultProps: Partial<ModalProps> = {
|
|
|
148
151
|
zIndex: null,
|
|
149
152
|
description: null,
|
|
150
153
|
withScrollContainer: false,
|
|
151
|
-
|
|
154
|
+
scrollLock: false,
|
|
155
|
+
autoIndex: false,
|
|
156
|
+
alterHistory: false,
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
export const ModalContent = (
|
|
@@ -178,12 +183,15 @@ export const ModalContent = (
|
|
|
178
183
|
zIndex,
|
|
179
184
|
withScrollContainer,
|
|
180
185
|
debugName,
|
|
181
|
-
scrollLocked,
|
|
182
186
|
backdropProps = {},
|
|
183
|
-
alterHistory
|
|
187
|
+
alterHistory,
|
|
188
|
+
id: modalId,
|
|
189
|
+
autoIndex,
|
|
184
190
|
...props
|
|
185
191
|
} = modalProps
|
|
186
192
|
|
|
193
|
+
const index = ModalStore(store => (store.indexes?.[modalId] ?? 0))
|
|
194
|
+
|
|
187
195
|
const id = useId()
|
|
188
196
|
const modalRef = useRef(null)
|
|
189
197
|
const variantStyles = useDefaultComponentStyle<'u:Modal', typeof ModalPresets>('u:Modal', {
|
|
@@ -264,10 +272,11 @@ export const ModalContent = (
|
|
|
264
272
|
aria-hidden={!visible}
|
|
265
273
|
css={[
|
|
266
274
|
variantStyles.wrapper,
|
|
267
|
-
_zIndex,
|
|
268
275
|
visible
|
|
269
276
|
? variantStyles['wrapper:visible']
|
|
270
277
|
: variantStyles['wrapper:hidden'],
|
|
278
|
+
autoIndex ? { zIndex: index } : {},
|
|
279
|
+
_zIndex,
|
|
271
280
|
]}
|
|
272
281
|
>
|
|
273
282
|
<Overlay
|
|
@@ -279,7 +288,6 @@ export const ModalContent = (
|
|
|
279
288
|
? variantStyles['backdrop:visible']
|
|
280
289
|
: variantStyles['backdrop:hidden'],
|
|
281
290
|
]}
|
|
282
|
-
scrollLocked={scrollLocked}
|
|
283
291
|
{...overlayProps}
|
|
284
292
|
/>
|
|
285
293
|
|
|
@@ -343,18 +351,24 @@ export const Modal = (props) => {
|
|
|
343
351
|
|
|
344
352
|
const {
|
|
345
353
|
accessible,
|
|
346
|
-
|
|
347
|
-
|
|
354
|
+
visible: _visible,
|
|
355
|
+
scrollLock,
|
|
356
|
+
modalId: _modalId,
|
|
357
|
+
autoIndex,
|
|
358
|
+
toggle: _toggle,
|
|
348
359
|
} = allProps
|
|
349
360
|
|
|
350
|
-
const modalId = useRef(v4())
|
|
361
|
+
const modalId = useRef(_modalId ?? v4())
|
|
362
|
+
const setIndex = ModalStore(store => store.setIndex)
|
|
363
|
+
|
|
364
|
+
const visible = TypeGuards.isBoolean(_visible) ? _visible : ModalStore(store => (store.modals?.[_modalId] ?? false))
|
|
365
|
+
const toggle = TypeGuards.isFunction(_toggle) ? _toggle : ModalStore(store => () => store.toggle(_modalId))
|
|
351
366
|
|
|
352
367
|
onMount(() => {
|
|
353
368
|
if (accessible) {
|
|
354
|
-
const currentId = modalId
|
|
355
369
|
const appRoot = document.body
|
|
356
|
-
appRoot.addEventListener('focusin', (e) => focusModal(e,
|
|
357
|
-
return () => appRoot.removeEventListener('focusin', (e) => focusModal(e,
|
|
370
|
+
appRoot.addEventListener('focusin', (e) => focusModal(e, modalId.current))
|
|
371
|
+
return () => appRoot.removeEventListener('focusin', (e) => focusModal(e, modalId.current))
|
|
358
372
|
}
|
|
359
373
|
})
|
|
360
374
|
|
|
@@ -365,16 +379,16 @@ export const Modal = (props) => {
|
|
|
365
379
|
appRoot.setAttribute('tabindex', `${-1}`)
|
|
366
380
|
}
|
|
367
381
|
|
|
368
|
-
if (visible)
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
382
|
+
if (scrollLock) modalScrollLock(visible, modalId.current)
|
|
383
|
+
|
|
384
|
+
if (autoIndex) {
|
|
385
|
+
setTimeout(() => {
|
|
386
|
+
setIndex(visible, modalId.current)
|
|
387
|
+
}, visible ? 0 : 500)
|
|
374
388
|
}
|
|
375
389
|
}, [visible])
|
|
376
390
|
|
|
377
|
-
const content = <ModalContent {...props} id={modalId.current} />
|
|
391
|
+
const content = <ModalContent {...props} visible={visible} toggle={toggle} id={modalId.current} />
|
|
378
392
|
|
|
379
393
|
// if (renderStatus === 'unmounted') return null
|
|
380
394
|
|
|
@@ -388,4 +402,3 @@ export const Modal = (props) => {
|
|
|
388
402
|
}
|
|
389
403
|
|
|
390
404
|
Modal.defaultProps = defaultProps
|
|
391
|
-
|
|
@@ -14,7 +14,6 @@ export type OverlayProps<T extends NativeHTMLElement = 'div'> = {
|
|
|
14
14
|
visible?: boolean
|
|
15
15
|
styles?: StylesOf<OverlayComposition>
|
|
16
16
|
onPress?: TouchableProps<'div'>['onClick']
|
|
17
|
-
scrollLocked?: boolean
|
|
18
17
|
} & ComponentVariants<typeof OverlayPresets> & Omit<ViewProps<T>, 'variants' | 'responsiveVariants'>
|
|
19
18
|
|
|
20
19
|
export * from './styles'
|
|
@@ -25,7 +24,6 @@ export const Overlay = <T extends NativeHTMLElement>(overlayProps:OverlayProps<T
|
|
|
25
24
|
responsiveVariants,
|
|
26
25
|
variants,
|
|
27
26
|
styles,
|
|
28
|
-
scrollLocked = false,
|
|
29
27
|
...props
|
|
30
28
|
} = overlayProps
|
|
31
29
|
|
|
@@ -35,7 +33,7 @@ export const Overlay = <T extends NativeHTMLElement>(overlayProps:OverlayProps<T
|
|
|
35
33
|
styles,
|
|
36
34
|
})
|
|
37
35
|
|
|
38
|
-
usePopState(visible, props.onPress
|
|
36
|
+
usePopState(visible, props.onPress)
|
|
39
37
|
|
|
40
38
|
const Component = props.onClick || props.onPress ? Touchable : View
|
|
41
39
|
|
package/src/index.ts
CHANGED
package/src/lib/modal.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { TypeGuards } from '@codeleap/common'
|
|
2
|
+
import { create } from 'zustand'
|
|
3
|
+
|
|
4
|
+
type TModalStore = {
|
|
5
|
+
identifier: string | null
|
|
6
|
+
indexes: Record<string, number>
|
|
7
|
+
modals: Record<string, boolean>
|
|
8
|
+
setIndex: (visible: boolean, modalIdentifier: string) => void
|
|
9
|
+
toggle: (id: string, to?: boolean) => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const INDEX = 99
|
|
13
|
+
|
|
14
|
+
export const ModalStore = create<TModalStore>((set) => ({
|
|
15
|
+
identifier: null,
|
|
16
|
+
indexes: {},
|
|
17
|
+
modals: {},
|
|
18
|
+
setIndex: (visible: boolean, modalIdentifier: string) => set(store => {
|
|
19
|
+
const indexes = store.indexes
|
|
20
|
+
|
|
21
|
+
if (!visible) {
|
|
22
|
+
indexes[modalIdentifier] = INDEX
|
|
23
|
+
|
|
24
|
+
return { indexes }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let currentIndex = 0
|
|
28
|
+
|
|
29
|
+
for (const key in indexes) {
|
|
30
|
+
if (indexes[key] > currentIndex) {
|
|
31
|
+
currentIndex = indexes[key]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
indexes[modalIdentifier] = currentIndex + INDEX
|
|
36
|
+
|
|
37
|
+
return { indexes }
|
|
38
|
+
}),
|
|
39
|
+
toggle: (id: string, to = null) => set(store => {
|
|
40
|
+
const modals = store.modals
|
|
41
|
+
|
|
42
|
+
const hasModal = TypeGuards.isBoolean(modals?.[id])
|
|
43
|
+
const visible = TypeGuards.isBoolean(to) ? to : (hasModal ? !modals?.[id] : true)
|
|
44
|
+
|
|
45
|
+
modals[id] = visible
|
|
46
|
+
|
|
47
|
+
return { modals }
|
|
48
|
+
})
|
|
49
|
+
}))
|
|
50
|
+
|
|
51
|
+
export function toggleModal(id: string, to: boolean = null) {
|
|
52
|
+
ModalStore.getState().toggle(id, to)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function modalScrollLock(to: boolean, modalIdentifier: string) {
|
|
56
|
+
let modalId = ModalStore.getState().identifier
|
|
57
|
+
|
|
58
|
+
const alreadyDifferentOpenedModal = !TypeGuards.isNil(modalId) && modalIdentifier !== modalId
|
|
59
|
+
|
|
60
|
+
if (alreadyDifferentOpenedModal) return
|
|
61
|
+
|
|
62
|
+
if (TypeGuards.isNil(modalId) && to === true) {
|
|
63
|
+
ModalStore.setState({ identifier: modalIdentifier })
|
|
64
|
+
modalId = modalIdentifier
|
|
65
|
+
} else if (!TypeGuards.isNil(modalId) && to === false) {
|
|
66
|
+
ModalStore.setState({ identifier: null })
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const htmlStyle = document?.documentElement?.style
|
|
70
|
+
|
|
71
|
+
if (htmlStyle.overflowX !== 'hidden') {
|
|
72
|
+
htmlStyle.overflowX = 'hidden'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (to) {
|
|
76
|
+
htmlStyle.overflowY = 'hidden'
|
|
77
|
+
} else if (modalIdentifier === modalId && to === false) {
|
|
78
|
+
htmlStyle.overflowY = 'auto'
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/lib/usePopState.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnyFunction, useIsomorphicEffect, useUnmount } from '@codeleap/common'
|
|
2
2
|
|
|
3
|
-
export const usePopState = (dependence: boolean, handler: AnyFunction
|
|
3
|
+
export const usePopState = (dependence: boolean, handler: AnyFunction) => {
|
|
4
4
|
useIsomorphicEffect(() => {
|
|
5
5
|
if (dependence) {
|
|
6
6
|
window.history.pushState(null, null, window.location.pathname)
|