@codeleap/web 2.4.7 → 3.0.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/package.json +20 -19
- package/src/components/ActionIcon/index.tsx +59 -0
- package/src/components/ActionIcon/styles.ts +9 -0
- package/src/components/ActivityIndicator/index.tsx +78 -0
- package/src/components/ActivityIndicator/styles.ts +11 -0
- package/src/components/Button/index.tsx +125 -0
- package/src/components/Button/styles.ts +22 -0
- package/src/components/Checkbox/index.tsx +138 -0
- package/src/components/Checkbox/styles.ts +20 -0
- package/src/components/Collapse/index.tsx +87 -0
- package/src/components/Collapse/styles.ts +8 -0
- package/src/components/Drawer/index.tsx +148 -0
- package/src/components/Drawer/styles.ts +8 -0
- package/src/components/FileInput.tsx +51 -0
- package/src/components/Icon/index.tsx +53 -0
- package/src/components/Icon/styles.ts +9 -0
- package/src/components/InputBase/index.tsx +104 -0
- package/src/components/InputBase/styles.ts +167 -0
- package/src/components/InputBase/types.ts +28 -0
- package/src/components/InputBase/utils.ts +41 -0
- package/src/components/Link/index.tsx +69 -0
- package/src/components/Link/styles.ts +11 -0
- package/src/components/List/index.tsx +103 -0
- package/src/components/List/styles.ts +8 -0
- package/src/components/LoadingOverlay/index.tsx +34 -0
- package/src/components/LoadingOverlay/styles.ts +12 -0
- package/src/components/Modal/index.tsx +189 -0
- package/src/components/Modal/styles.ts +26 -0
- package/src/components/NumberIncrement/index.tsx +292 -0
- package/src/components/NumberIncrement/styles.ts +15 -0
- package/src/components/Overlay/index.tsx +42 -0
- package/src/components/Overlay/styles.ts +8 -0
- package/src/components/RadioInput/index.tsx +155 -0
- package/src/components/RadioInput/styles.ts +14 -0
- package/src/components/Scroll/index.tsx +29 -0
- package/src/components/Scroll/styles.ts +8 -0
- package/src/components/Select/index.tsx +438 -0
- package/src/components/Select/styles.ts +179 -0
- package/src/components/Select/types.ts +100 -0
- package/src/components/Slider/index.tsx +303 -0
- package/src/components/Slider/styles.ts +11 -0
- package/src/components/Switch/index.tsx +128 -0
- package/src/components/Switch/styles.ts +20 -0
- package/src/components/Text/index.tsx +62 -0
- package/src/components/Text/styles.ts +9 -0
- package/src/components/TextInput/index.tsx +253 -0
- package/src/components/TextInput/mask.tsx +165 -0
- package/src/components/TextInput/styles.ts +15 -0
- package/src/components/Tooltip/index.tsx +155 -0
- package/src/components/Tooltip/styles.ts +9 -0
- package/src/components/Touchable/index.tsx +72 -0
- package/src/components/Touchable/styles.ts +11 -0
- package/src/components/View/index.tsx +94 -0
- package/src/components/View/styles.ts +8 -0
- package/src/components/components.ts +29 -0
- package/src/components/defaultStyles.ts +51 -0
- package/src/index.ts +6 -0
- package/src/lib/OSAlert.tsx +190 -0
- package/src/lib/Toast.ts +23 -0
- package/src/lib/hooks.ts +340 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/logger.ts +13 -0
- package/src/lib/utils/cookies.ts +13 -0
- package/src/lib/utils/index.ts +4 -0
- package/src/lib/utils/pollyfils/scroll.ts +65 -0
- package/src/lib/utils/stopPropagation.ts +15 -0
- package/src/types/index.ts +1 -0
- package/src/types/utility.ts +3 -0
- package/dist/components/ActivityIndicator/index.d.ts +0 -12
- package/dist/components/ActivityIndicator/index.js +0 -57
- package/dist/components/ActivityIndicator/index.js.map +0 -1
- package/dist/components/ActivityIndicator/styles.d.ts +0 -53
- package/dist/components/ActivityIndicator/styles.js +0 -22
- package/dist/components/ActivityIndicator/styles.js.map +0 -1
- package/dist/components/Button.d.ts +0 -18
- package/dist/components/Button.js +0 -67
- package/dist/components/Button.js.map +0 -1
- package/dist/components/CenterWrapper.d.ts +0 -7
- package/dist/components/CenterWrapper.js +0 -28
- package/dist/components/CenterWrapper.js.map +0 -1
- package/dist/components/Checkbox/index.d.ts +0 -12
- package/dist/components/Checkbox/index.js +0 -58
- package/dist/components/Checkbox/index.js.map +0 -1
- package/dist/components/Checkbox/styles.d.ts +0 -53
- package/dist/components/Checkbox/styles.js +0 -64
- package/dist/components/Checkbox/styles.js.map +0 -1
- package/dist/components/Collapse.d.ts +0 -20
- package/dist/components/Collapse.js +0 -68
- package/dist/components/Collapse.js.map +0 -1
- package/dist/components/ContentView.d.ts +0 -10
- package/dist/components/ContentView.js +0 -52
- package/dist/components/ContentView.js.map +0 -1
- package/dist/components/Drawer.d.ts +0 -23
- package/dist/components/Drawer.js +0 -73
- package/dist/components/Drawer.js.map +0 -1
- package/dist/components/FileInput.d.ts +0 -8
- package/dist/components/FileInput.js +0 -69
- package/dist/components/FileInput.js.map +0 -1
- package/dist/components/HorizontalScroll.d.ts +0 -3
- package/dist/components/HorizontalScroll.js +0 -42
- package/dist/components/HorizontalScroll.js.map +0 -1
- package/dist/components/Icon.d.ts +0 -8
- package/dist/components/Icon.js +0 -55
- package/dist/components/Icon.js.map +0 -1
- package/dist/components/Link.d.ts +0 -7
- package/dist/components/Link.js +0 -63
- package/dist/components/Link.js.map +0 -1
- package/dist/components/List.d.ts +0 -18
- package/dist/components/List.js +0 -52
- package/dist/components/List.js.map +0 -1
- package/dist/components/Modal/index.d.ts +0 -21
- package/dist/components/Modal/index.js +0 -116
- package/dist/components/Modal/index.js.map +0 -1
- package/dist/components/Modal/styles.d.ts +0 -56
- package/dist/components/Modal/styles.js +0 -36
- package/dist/components/Modal/styles.js.map +0 -1
- package/dist/components/Overlay.d.ts +0 -10
- package/dist/components/Overlay.js +0 -41
- package/dist/components/Overlay.js.map +0 -1
- package/dist/components/RadioInput/index.d.ts +0 -21
- package/dist/components/RadioInput/index.js +0 -55
- package/dist/components/RadioInput/index.js.map +0 -1
- package/dist/components/RadioInput/styles.d.ts +0 -54
- package/dist/components/RadioInput/styles.js +0 -44
- package/dist/components/RadioInput/styles.js.map +0 -1
- package/dist/components/RouterPage/Menu.d.ts +0 -10
- package/dist/components/RouterPage/Menu.js +0 -36
- package/dist/components/RouterPage/Menu.js.map +0 -1
- package/dist/components/RouterPage/MenuItem.d.ts +0 -12
- package/dist/components/RouterPage/MenuItem.js +0 -42
- package/dist/components/RouterPage/MenuItem.js.map +0 -1
- package/dist/components/RouterPage/Router.d.ts +0 -8
- package/dist/components/RouterPage/Router.js +0 -27
- package/dist/components/RouterPage/Router.js.map +0 -1
- package/dist/components/RouterPage/index.d.ts +0 -29
- package/dist/components/RouterPage/index.js +0 -85
- package/dist/components/RouterPage/index.js.map +0 -1
- package/dist/components/RouterPage/styles.d.ts +0 -54
- package/dist/components/RouterPage/styles.js +0 -87
- package/dist/components/RouterPage/styles.js.map +0 -1
- package/dist/components/Scroll.d.ts +0 -5
- package/dist/components/Scroll.js +0 -24
- package/dist/components/Scroll.js.map +0 -1
- package/dist/components/Select/Custom.d.ts +0 -8
- package/dist/components/Select/Custom.js +0 -104
- package/dist/components/Select/Custom.js.map +0 -1
- package/dist/components/Select/Multi.d.ts +0 -3
- package/dist/components/Select/Multi.js +0 -105
- package/dist/components/Select/Multi.js.map +0 -1
- package/dist/components/Select/Native.d.ts +0 -17
- package/dist/components/Select/Native.js +0 -44
- package/dist/components/Select/Native.js.map +0 -1
- package/dist/components/Select/index.d.ts +0 -12
- package/dist/components/Select/index.js +0 -40
- package/dist/components/Select/index.js.map +0 -1
- package/dist/components/Select/styles.d.ts +0 -5
- package/dist/components/Select/styles.js +0 -57
- package/dist/components/Select/styles.js.map +0 -1
- package/dist/components/Select/types.d.ts +0 -49
- package/dist/components/Select/types.js +0 -3
- package/dist/components/Select/types.js.map +0 -1
- package/dist/components/Slider.d.ts +0 -5
- package/dist/components/Slider.js +0 -39
- package/dist/components/Slider.js.map +0 -1
- package/dist/components/Text.d.ts +0 -9
- package/dist/components/Text.js +0 -43
- package/dist/components/Text.js.map +0 -1
- package/dist/components/TextInput.d.ts +0 -150
- package/dist/components/TextInput.js +0 -125
- package/dist/components/TextInput.js.map +0 -1
- package/dist/components/Tooltip.d.ts +0 -12
- package/dist/components/Tooltip.js +0 -122
- package/dist/components/Tooltip.js.map +0 -1
- package/dist/components/Touchable.d.ts +0 -15
- package/dist/components/Touchable.js +0 -52
- package/dist/components/Touchable.js.map +0 -1
- package/dist/components/View.d.ts +0 -10
- package/dist/components/View.js +0 -62
- package/dist/components/View.js.map +0 -1
- package/dist/components/index.d.ts +0 -24
- package/dist/components/index.js +0 -37
- package/dist/components/index.js.map +0 -1
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -25
- package/dist/index.js.map +0 -1
- package/dist/lib/OSAlert.d.ts +0 -21
- package/dist/lib/OSAlert.js +0 -140
- package/dist/lib/OSAlert.js.map +0 -1
- package/dist/lib/Toast.d.ts +0 -13
- package/dist/lib/Toast.js +0 -32
- package/dist/lib/Toast.js.map +0 -1
- package/dist/lib/hooks.d.ts +0 -28
- package/dist/lib/hooks.js +0 -183
- package/dist/lib/hooks.js.map +0 -1
- package/dist/lib/logger.d.ts +0 -2
- package/dist/lib/logger.js +0 -16
- package/dist/lib/logger.js.map +0 -1
- package/dist/lib/utils/cookies.d.ts +0 -6
- package/dist/lib/utils/cookies.js +0 -15
- package/dist/lib/utils/cookies.js.map +0 -1
- package/dist/lib/utils/index.d.ts +0 -4
- package/dist/lib/utils/index.js +0 -23
- package/dist/lib/utils/index.js.map +0 -1
- package/dist/lib/utils/pollyfils/scroll.d.ts +0 -1
- package/dist/lib/utils/pollyfils/scroll.js +0 -66
- package/dist/lib/utils/pollyfils/scroll.js.map +0 -1
- package/dist/lib/utils/stopPropagation.d.ts +0 -1
- package/dist/lib/utils/stopPropagation.js +0 -20
- package/dist/lib/utils/stopPropagation.js.map +0 -1
- package/dist/types/utility.d.ts +0 -2
- package/dist/types/utility.js +0 -3
- package/dist/types/utility.js.map +0 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { VariableSizeList as VirtualList , VariableSizeListProps} from 'react-window'
|
|
2
|
+
import { ComponentProps, CSSProperties, ReactElement } from 'react'
|
|
3
|
+
import AutoSizer from 'react-virtualized-auto-sizer'
|
|
4
|
+
import {
|
|
5
|
+
ComponentVariants,
|
|
6
|
+
useDefaultComponentStyle
|
|
7
|
+
} from '@codeleap/common'
|
|
8
|
+
import { StylesOf } from '../../types/utility'
|
|
9
|
+
import { CSSObject } from '@emotion/react'
|
|
10
|
+
import { ListComposition, ListPresets } from './styles'
|
|
11
|
+
|
|
12
|
+
export type ListRender<T> = (itemProps: {
|
|
13
|
+
item: T
|
|
14
|
+
index: number
|
|
15
|
+
style: CSSProperties
|
|
16
|
+
}) => ReactElement
|
|
17
|
+
|
|
18
|
+
export * from './styles'
|
|
19
|
+
|
|
20
|
+
export type ListProps<T> = {
|
|
21
|
+
styles?: StylesOf<ListComposition>
|
|
22
|
+
css?: CSSObject
|
|
23
|
+
data: T[]
|
|
24
|
+
getSize: (i: T, idx: number) => number
|
|
25
|
+
renderItem: ListRender<T>
|
|
26
|
+
} & Omit<
|
|
27
|
+
VariableSizeListProps,
|
|
28
|
+
| 'itemCount'
|
|
29
|
+
| 'itemSize'
|
|
30
|
+
| 'itemData'
|
|
31
|
+
| 'itemHeight'
|
|
32
|
+
| 'width'
|
|
33
|
+
| 'height'
|
|
34
|
+
| 'children'
|
|
35
|
+
> &
|
|
36
|
+
ComponentVariants<typeof ListPresets>
|
|
37
|
+
|
|
38
|
+
export const List = <T extends unknown>(
|
|
39
|
+
listProps: ListProps<T>,
|
|
40
|
+
) => {
|
|
41
|
+
const {
|
|
42
|
+
variants,
|
|
43
|
+
responsiveVariants,
|
|
44
|
+
styles,
|
|
45
|
+
data,
|
|
46
|
+
getSize,
|
|
47
|
+
renderItem: Item,
|
|
48
|
+
...viewProps
|
|
49
|
+
} = listProps
|
|
50
|
+
|
|
51
|
+
const variantStyles = useDefaultComponentStyle('View', {
|
|
52
|
+
variants,
|
|
53
|
+
responsiveVariants,
|
|
54
|
+
styles,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
<AutoSizer>
|
|
60
|
+
{({ height, width }) => (
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
<VirtualList
|
|
63
|
+
height={height}
|
|
64
|
+
width={width}
|
|
65
|
+
itemCount={data.length}
|
|
66
|
+
itemData={data}
|
|
67
|
+
itemSize={(idx) => getSize(data[idx], idx)}
|
|
68
|
+
css={variantStyles.wrapper}
|
|
69
|
+
{...viewProps}
|
|
70
|
+
>
|
|
71
|
+
{({ style, index }) => (
|
|
72
|
+
<Item item={data[index]} style={style} index={index} />
|
|
73
|
+
)}
|
|
74
|
+
</VirtualList>
|
|
75
|
+
)}
|
|
76
|
+
</AutoSizer>
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
// return <View {...viewProps}>
|
|
80
|
+
// {data.map((item, idx) => <Component item={item} idx={idx} key={idx}/>)}
|
|
81
|
+
// </View>
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// const rowHeights = new Array(1000)
|
|
85
|
+
// .fill(true)
|
|
86
|
+
// .map(() => 25 + Math.round(Math.random() * 50));
|
|
87
|
+
|
|
88
|
+
// const getItemSize = index => rowHeights[index];
|
|
89
|
+
|
|
90
|
+
// const Row = ({ index, style }) => (
|
|
91
|
+
// <div style={style}>Row {index}</div>
|
|
92
|
+
// );
|
|
93
|
+
|
|
94
|
+
// const Example = () => (
|
|
95
|
+
// <List
|
|
96
|
+
// height={150}
|
|
97
|
+
// itemCount={1000}
|
|
98
|
+
// itemSize={getItemSize}
|
|
99
|
+
// width={300}
|
|
100
|
+
// >
|
|
101
|
+
// {Row}
|
|
102
|
+
// </List>
|
|
103
|
+
// );
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createDefaultVariantFactory, includePresets } from "@codeleap/common";
|
|
2
|
+
import { ViewComposition } from "../View";
|
|
3
|
+
|
|
4
|
+
export type ListComposition = ViewComposition
|
|
5
|
+
|
|
6
|
+
const createListStyles = createDefaultVariantFactory<ListComposition>()
|
|
7
|
+
|
|
8
|
+
export const ListPresets = includePresets((styles) => createListStyles(() => ({ wrapper: styles })))
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ComponentVariants, useDefaultComponentStyle } from "@codeleap/common"
|
|
2
|
+
import React from "react"
|
|
3
|
+
import { StylesOf } from "../.."
|
|
4
|
+
import { LoadingOverlayComposition, LoadingOverlayPresets } from "./styles"
|
|
5
|
+
import {View} from '../View'
|
|
6
|
+
import { ActivityIndicator } from "../ActivityIndicator"
|
|
7
|
+
|
|
8
|
+
export type LoadingOverlayProps = React.PropsWithChildren<{
|
|
9
|
+
visible?: boolean
|
|
10
|
+
styles?: StylesOf<LoadingOverlayComposition>
|
|
11
|
+
}> & ComponentVariants<typeof LoadingOverlayPresets>
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export const LoadingOverlay = (props: LoadingOverlayProps) => {
|
|
15
|
+
const { visible, children, styles, variants,responsiveVariants } = props
|
|
16
|
+
|
|
17
|
+
const variantStyles = useDefaultComponentStyle<'u:LoadingOverlay', typeof LoadingOverlayPresets>('u:LoadingOverlay', {
|
|
18
|
+
variants, styles, responsiveVariants, rootElement: 'wrapper'
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
return <View css={[variantStyles.wrapper, visible && variantStyles["wrapper:visible"]]}>
|
|
22
|
+
<ActivityIndicator
|
|
23
|
+
styles={{
|
|
24
|
+
wrapper: [variantStyles.indicatorWrapper, visible && variantStyles["indicatorWrapper:visible"]],
|
|
25
|
+
backCircle: [variantStyles.indicatorBackCircle, visible && variantStyles["indicatorBackCircle:visible"]],
|
|
26
|
+
frontCircle: [variantStyles.indicatorFrontCircle, visible && variantStyles["indicatorFrontCircle:visible"]],
|
|
27
|
+
circle: [variantStyles.indicatorCircle, visible && variantStyles["indicatorCircle:visible"]],
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
{children}
|
|
31
|
+
</View>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export * from './styles'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createDefaultVariantFactory, includePresets } from "@codeleap/common";
|
|
2
|
+
import { ActivityIndicatorComposition } from "../ActivityIndicator";
|
|
3
|
+
|
|
4
|
+
type LoadingOverlayStates = 'visible'
|
|
5
|
+
|
|
6
|
+
export type LoadingOverlayParts = 'wrapper' | `indicator${Capitalize<ActivityIndicatorComposition>}`
|
|
7
|
+
|
|
8
|
+
export type LoadingOverlayComposition = `${LoadingOverlayParts}:${LoadingOverlayStates}` | LoadingOverlayParts
|
|
9
|
+
|
|
10
|
+
export const createLoadingOverlayStyle = createDefaultVariantFactory<LoadingOverlayComposition>()
|
|
11
|
+
|
|
12
|
+
export const LoadingOverlayPresets = includePresets(s => createLoadingOverlayStyle(() => ({wrapper: s})))
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/** @jsx jsx */
|
|
2
|
+
import { jsx } from '@emotion/react'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
AnyFunction,
|
|
6
|
+
ComponentVariants,
|
|
7
|
+
IconPlaceholder,
|
|
8
|
+
onUpdate,
|
|
9
|
+
useDefaultComponentStyle,
|
|
10
|
+
useNestedStylesByKey,
|
|
11
|
+
} from '@codeleap/common'
|
|
12
|
+
|
|
13
|
+
import { ReactNode, useEffect, useId, useLayoutEffect, useRef } from 'react'
|
|
14
|
+
import ReactDOM from 'react-dom'
|
|
15
|
+
|
|
16
|
+
import { v4 } from 'uuid'
|
|
17
|
+
|
|
18
|
+
import { StylesOf } from '../../types/utility'
|
|
19
|
+
import { Button } from '../Button'
|
|
20
|
+
import { View } from '../View'
|
|
21
|
+
import { Text } from '../Text'
|
|
22
|
+
import { Overlay } from '../Overlay'
|
|
23
|
+
|
|
24
|
+
import {ModalComposition,ModalPresets} from './styles'
|
|
25
|
+
import { ActionIcon } from '../ActionIcon'
|
|
26
|
+
|
|
27
|
+
export * from './styles'
|
|
28
|
+
|
|
29
|
+
export type ModalProps = React.PropsWithChildren<{
|
|
30
|
+
visible: boolean
|
|
31
|
+
title?: React.ReactNode
|
|
32
|
+
toggle: AnyFunction
|
|
33
|
+
styles?: StylesOf<ModalComposition>
|
|
34
|
+
accessible?: boolean
|
|
35
|
+
showClose?: boolean
|
|
36
|
+
closable?: boolean
|
|
37
|
+
scroll?: boolean
|
|
38
|
+
footer?: ReactNode
|
|
39
|
+
debugName?: string
|
|
40
|
+
} & ComponentVariants<typeof ModalPresets>
|
|
41
|
+
>
|
|
42
|
+
function focusModal(event: FocusEvent, id: string) {
|
|
43
|
+
event.preventDefault()
|
|
44
|
+
const modal = document.getElementById(id)
|
|
45
|
+
if (modal) {
|
|
46
|
+
modal.focus()
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export const ModalContent: React.FC<ModalProps & { id: string }> = (
|
|
50
|
+
modalProps,
|
|
51
|
+
) => {
|
|
52
|
+
const {
|
|
53
|
+
children,
|
|
54
|
+
closable = true,
|
|
55
|
+
visible,
|
|
56
|
+
title = '',
|
|
57
|
+
toggle,
|
|
58
|
+
responsiveVariants,
|
|
59
|
+
variants,
|
|
60
|
+
styles,
|
|
61
|
+
showClose = true,
|
|
62
|
+
footer,
|
|
63
|
+
...props
|
|
64
|
+
} = modalProps
|
|
65
|
+
|
|
66
|
+
const id = useId()
|
|
67
|
+
|
|
68
|
+
const variantStyles = useDefaultComponentStyle<'u:Modal', typeof ModalPresets>('u:Modal', {
|
|
69
|
+
responsiveVariants,
|
|
70
|
+
variants,
|
|
71
|
+
styles,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
onUpdate(() => {
|
|
75
|
+
if (visible) {
|
|
76
|
+
document.body.style.overflow = 'hidden'
|
|
77
|
+
} else {
|
|
78
|
+
document.body.style.overflow = 'auto'
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
}, [visible])
|
|
82
|
+
|
|
83
|
+
function closeOnEscPress(e: React.KeyboardEvent<HTMLDivElement>) {
|
|
84
|
+
if (e.key === 'Escape') {
|
|
85
|
+
toggle()
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
useLayoutEffect(() => {
|
|
90
|
+
const modal = document.getElementById(id)
|
|
91
|
+
if (modal) {
|
|
92
|
+
modal.focus()
|
|
93
|
+
}
|
|
94
|
+
}, [id])
|
|
95
|
+
|
|
96
|
+
const closeButtonStyles = useNestedStylesByKey('closeButton', variantStyles)
|
|
97
|
+
const close = closable ? toggle : () => {}
|
|
98
|
+
return (
|
|
99
|
+
<View
|
|
100
|
+
aria-hidden={!visible}
|
|
101
|
+
css={[variantStyles.wrapper, visible ? variantStyles['wrapper:visible'] : variantStyles['wrapper:hidden']]}
|
|
102
|
+
>
|
|
103
|
+
<Overlay
|
|
104
|
+
visible={visible}
|
|
105
|
+
|
|
106
|
+
css={[variantStyles.backdrop, visible ? variantStyles['backdrop:visible'] : variantStyles['backdrop:hidden'] ]}
|
|
107
|
+
/>
|
|
108
|
+
<View css={variantStyles.innerWrapper} >
|
|
109
|
+
<View css={variantStyles.backdropPressable} onClick={close}/>
|
|
110
|
+
<View
|
|
111
|
+
component='section'
|
|
112
|
+
css={[variantStyles.box, visible ? variantStyles['box:visible'] : variantStyles['box:hidden']]}
|
|
113
|
+
className='content'
|
|
114
|
+
onKeyDown={closeOnEscPress}
|
|
115
|
+
tabIndex={0}
|
|
116
|
+
id={id}
|
|
117
|
+
aria-modal={true}
|
|
118
|
+
role='dialog'
|
|
119
|
+
aria-describedby={`${id}-title`}
|
|
120
|
+
aria-label='Close the modal by presing Escape key'
|
|
121
|
+
{...props}
|
|
122
|
+
>
|
|
123
|
+
{(title || showClose) && (
|
|
124
|
+
<View
|
|
125
|
+
component='header'
|
|
126
|
+
className='modal-header header'
|
|
127
|
+
id={`${id}-title`}
|
|
128
|
+
css={variantStyles.header}
|
|
129
|
+
>
|
|
130
|
+
{typeof title === 'string' ? <Text text={title} css={variantStyles.title} /> : title}
|
|
131
|
+
|
|
132
|
+
{showClose && closable && (
|
|
133
|
+
<ActionIcon
|
|
134
|
+
icon={'close' as IconPlaceholder}
|
|
135
|
+
|
|
136
|
+
onPress={toggle}
|
|
137
|
+
styles={closeButtonStyles}
|
|
138
|
+
/>
|
|
139
|
+
)}
|
|
140
|
+
</View>
|
|
141
|
+
)}
|
|
142
|
+
|
|
143
|
+
<View css={variantStyles.body}>{children}</View>
|
|
144
|
+
{footer && (
|
|
145
|
+
<View component='footer' css={variantStyles.footer}>
|
|
146
|
+
{footer}
|
|
147
|
+
</View>
|
|
148
|
+
)}
|
|
149
|
+
</View>
|
|
150
|
+
</View>
|
|
151
|
+
</View>
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export const Modal: React.FC<ModalProps> = ({ accessible, ...props }) => {
|
|
156
|
+
const modalId = useRef(v4())
|
|
157
|
+
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
if (accessible) {
|
|
160
|
+
const currentId = modalId.current
|
|
161
|
+
const appRoot = document.body
|
|
162
|
+
appRoot.addEventListener('focusin', (e) => focusModal(e, currentId))
|
|
163
|
+
return () => appRoot.removeEventListener('focusin', (e) => focusModal(e, currentId))
|
|
164
|
+
}
|
|
165
|
+
}, [])
|
|
166
|
+
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
if (accessible) {
|
|
169
|
+
const appRoot = document.body
|
|
170
|
+
appRoot.setAttribute('aria-hidden', `${props.visible}`)
|
|
171
|
+
appRoot.setAttribute('tabindex', `${-1}`)
|
|
172
|
+
}
|
|
173
|
+
}, [props.visible])
|
|
174
|
+
|
|
175
|
+
if (accessible) {
|
|
176
|
+
if (props.visible) {
|
|
177
|
+
document.body.style.overflow = 'hidden'
|
|
178
|
+
return ReactDOM.createPortal(
|
|
179
|
+
<ModalContent {...props} id={modalId.current} />,
|
|
180
|
+
document.body,
|
|
181
|
+
)
|
|
182
|
+
} else {
|
|
183
|
+
document.body.style.overflow = 'visible'
|
|
184
|
+
return null
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return <ModalContent {...props} id={modalId.current} />
|
|
189
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createDefaultVariantFactory,
|
|
3
|
+
includePresets,
|
|
4
|
+
} from '@codeleap/common'
|
|
5
|
+
import { ActionIconComposition } from '../ActionIcon'
|
|
6
|
+
|
|
7
|
+
export type AnimatableParts = 'box' | 'backdrop' | 'wrapper'
|
|
8
|
+
|
|
9
|
+
export type ModalParts =
|
|
10
|
+
| AnimatableParts
|
|
11
|
+
| 'body'
|
|
12
|
+
| 'footer'
|
|
13
|
+
| 'header'
|
|
14
|
+
| 'title'
|
|
15
|
+
| 'innerWrapper'
|
|
16
|
+
| 'backdropPressable'
|
|
17
|
+
| `closeButton${Capitalize<ActionIconComposition>}`
|
|
18
|
+
|
|
19
|
+
export type ModalComposition =
|
|
20
|
+
| ModalParts
|
|
21
|
+
| `${AnimatableParts}:visible`
|
|
22
|
+
| `${AnimatableParts}:hidden`
|
|
23
|
+
|
|
24
|
+
const createModalStyle = createDefaultVariantFactory<ModalComposition>()
|
|
25
|
+
|
|
26
|
+
export const ModalPresets = includePresets((style) => createModalStyle(() => ({ body: style })))
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import {
|
|
3
|
+
ComponentVariants,
|
|
4
|
+
yup,
|
|
5
|
+
useDefaultComponentStyle,
|
|
6
|
+
StylesOf,
|
|
7
|
+
PropsOf,
|
|
8
|
+
TypeGuards,
|
|
9
|
+
onUpdate,
|
|
10
|
+
useState,
|
|
11
|
+
useRef,
|
|
12
|
+
useValidate,
|
|
13
|
+
FormTypes,
|
|
14
|
+
IconPlaceholder,
|
|
15
|
+
} from '@codeleap/common'
|
|
16
|
+
import { View } from '../View'
|
|
17
|
+
import { NumberIncrementPresets, NumberIncrementComposition } from './styles'
|
|
18
|
+
import { InputBase, InputBaseProps, selectInputBaseProps } from '../InputBase'
|
|
19
|
+
import { Text } from '../Text'
|
|
20
|
+
import {
|
|
21
|
+
PatternFormat,
|
|
22
|
+
PatternFormatProps as PFProps,
|
|
23
|
+
NumericFormat,
|
|
24
|
+
NumericFormatProps as NFProps,
|
|
25
|
+
NumberFormatBase,
|
|
26
|
+
} from 'react-number-format'
|
|
27
|
+
import { FormatInputValueFunction } from 'react-number-format/types/types'
|
|
28
|
+
|
|
29
|
+
export * from './styles'
|
|
30
|
+
|
|
31
|
+
export type NumberIncrementProps = Pick<
|
|
32
|
+
InputBaseProps,
|
|
33
|
+
'debugName' | 'disabled' | 'label'
|
|
34
|
+
> & {
|
|
35
|
+
variants?: ComponentVariants<typeof NumberIncrementPresets>['variants']
|
|
36
|
+
styles?: StylesOf<NumberIncrementComposition>
|
|
37
|
+
value: number
|
|
38
|
+
onValueChange: (value: number) => void
|
|
39
|
+
onChangeText?: (value: number) => void
|
|
40
|
+
validate?: FormTypes.ValidatorWithoutForm<string> | yup.SchemaOf<string>
|
|
41
|
+
style?: PropsOf<typeof View>['style']
|
|
42
|
+
max?: number
|
|
43
|
+
min?: number
|
|
44
|
+
step?: number
|
|
45
|
+
editable?: boolean
|
|
46
|
+
prefix?: NFProps['prefix']
|
|
47
|
+
suffix?: NFProps['suffix']
|
|
48
|
+
separator?: NFProps['thousandSeparator']
|
|
49
|
+
format?: PFProps['format']
|
|
50
|
+
mask?: PFProps['mask']
|
|
51
|
+
hasSeparator?: boolean
|
|
52
|
+
_error?: string
|
|
53
|
+
formatter?: FormatInputValueFunction
|
|
54
|
+
placeholder?: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const NumberIncrement = (props: NumberIncrementProps) => {
|
|
58
|
+
const {
|
|
59
|
+
inputBaseProps,
|
|
60
|
+
others,
|
|
61
|
+
} = selectInputBaseProps(props)
|
|
62
|
+
|
|
63
|
+
const {
|
|
64
|
+
variants = [],
|
|
65
|
+
style = {},
|
|
66
|
+
styles = {},
|
|
67
|
+
value,
|
|
68
|
+
disabled,
|
|
69
|
+
onValueChange,
|
|
70
|
+
onChangeText,
|
|
71
|
+
max = 1000000000,
|
|
72
|
+
min = 0,
|
|
73
|
+
step = 1,
|
|
74
|
+
editable = true,
|
|
75
|
+
hasSeparator = false,
|
|
76
|
+
format = null,
|
|
77
|
+
mask = undefined,
|
|
78
|
+
suffix,
|
|
79
|
+
separator = null,
|
|
80
|
+
prefix,
|
|
81
|
+
validate,
|
|
82
|
+
_error,
|
|
83
|
+
formatter = null,
|
|
84
|
+
placeholder,
|
|
85
|
+
} = others
|
|
86
|
+
|
|
87
|
+
const [isFocused, setIsFocused] = useState(false)
|
|
88
|
+
|
|
89
|
+
const innerWrapperRef = useRef(null)
|
|
90
|
+
const innerInputRef = useRef<HTMLInputElement>(null)
|
|
91
|
+
|
|
92
|
+
const validation = useValidate(value, validate)
|
|
93
|
+
|
|
94
|
+
const hasError = !validation.isValid || _error
|
|
95
|
+
const errorMessage = validation.message || _error
|
|
96
|
+
|
|
97
|
+
const incrementDisabled = React.useMemo(() => {
|
|
98
|
+
if (TypeGuards.isNumber(max) && (Number(value) >= max)) {
|
|
99
|
+
return true
|
|
100
|
+
}
|
|
101
|
+
return false
|
|
102
|
+
}, [value])
|
|
103
|
+
|
|
104
|
+
const decrementDisabled = React.useMemo(() => {
|
|
105
|
+
if (TypeGuards.isNumber(min) && (Number(value) <= min)) {
|
|
106
|
+
return true
|
|
107
|
+
}
|
|
108
|
+
return false
|
|
109
|
+
}, [value])
|
|
110
|
+
|
|
111
|
+
const variantStyles = useDefaultComponentStyle<'u:NumberIncrement', typeof NumberIncrementPresets>(
|
|
112
|
+
'u:NumberIncrement',
|
|
113
|
+
{
|
|
114
|
+
variants,
|
|
115
|
+
styles,
|
|
116
|
+
rootElement: 'wrapper',
|
|
117
|
+
},
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
const onChange = (newValue: number) => {
|
|
121
|
+
if (onValueChange) onValueChange?.(newValue)
|
|
122
|
+
if (onChangeText) onChangeText?.(newValue)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const handleChange = React.useCallback((action: 'increment' | 'decrement') => {
|
|
126
|
+
validation?.onInputFocused()
|
|
127
|
+
|
|
128
|
+
if (action === 'increment' && !incrementDisabled) {
|
|
129
|
+
const newValue = Number(value) + step
|
|
130
|
+
onChange(newValue)
|
|
131
|
+
return
|
|
132
|
+
} else if (action === 'decrement' && !decrementDisabled) {
|
|
133
|
+
const newValue = Number(value) - step
|
|
134
|
+
onChange(newValue)
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
validation?.onInputBlurred()
|
|
139
|
+
}, [validation?.onInputBlurred, validation?.onInputFocused, value])
|
|
140
|
+
|
|
141
|
+
const inputTextStyle = React.useMemo(() => {
|
|
142
|
+
return [
|
|
143
|
+
variantStyles.input,
|
|
144
|
+
isFocused && variantStyles['input:focus'],
|
|
145
|
+
hasError && variantStyles['input:error'],
|
|
146
|
+
disabled && variantStyles['input:disabled'],
|
|
147
|
+
]
|
|
148
|
+
}, [disabled, isFocused, hasError])
|
|
149
|
+
|
|
150
|
+
const placeholderStyles = [
|
|
151
|
+
variantStyles.placeholder,
|
|
152
|
+
isFocused && variantStyles['placeholder:focus'],
|
|
153
|
+
hasError && variantStyles['placeholder:error'],
|
|
154
|
+
disabled && variantStyles['placeholder:disabled'],
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
const handleBlur = React.useCallback(() => {
|
|
158
|
+
if (TypeGuards.isNumber(max) && (value >= max)) {
|
|
159
|
+
onChange(max)
|
|
160
|
+
return
|
|
161
|
+
} else if (TypeGuards.isNumber(min) && (value <= min) || !value) {
|
|
162
|
+
onChange(min)
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
validation?.onInputBlurred()
|
|
167
|
+
}, [validation?.onInputBlurred, value])
|
|
168
|
+
|
|
169
|
+
const handleFocus = React.useCallback(() => {
|
|
170
|
+
validation?.onInputFocused()
|
|
171
|
+
setIsFocused(true)
|
|
172
|
+
}, [validation?.onInputFocused])
|
|
173
|
+
|
|
174
|
+
onUpdate(() => {
|
|
175
|
+
function handleKeyboardEvent(event: KeyboardEvent) {
|
|
176
|
+
if (!isFocused) return
|
|
177
|
+
|
|
178
|
+
if (event.keyCode === 39 || event.key === 'ArrowRight') {
|
|
179
|
+
handleChange('increment')
|
|
180
|
+
} else if (event.keyCode === 37 || event.key === 'ArrowLeft') {
|
|
181
|
+
handleChange('decrement')
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
document.addEventListener('keydown', handleKeyboardEvent)
|
|
186
|
+
|
|
187
|
+
return () => {
|
|
188
|
+
document.removeEventListener('keydown', handleKeyboardEvent)
|
|
189
|
+
}
|
|
190
|
+
}, [handleChange, isFocused])
|
|
191
|
+
|
|
192
|
+
onUpdate(() => {
|
|
193
|
+
function handleClickOutside(event: MouseEvent) {
|
|
194
|
+
if (innerWrapperRef.current && !innerWrapperRef.current.contains(event.target)) {
|
|
195
|
+
setIsFocused(false)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
document.addEventListener('mousedown', handleClickOutside)
|
|
200
|
+
|
|
201
|
+
return () => {
|
|
202
|
+
document.removeEventListener('mousedown', handleClickOutside)
|
|
203
|
+
}
|
|
204
|
+
}, [innerWrapperRef])
|
|
205
|
+
|
|
206
|
+
const handleChangeInput: NFProps['onValueChange'] = (values) => {
|
|
207
|
+
const { floatValue } = values
|
|
208
|
+
|
|
209
|
+
onChange(Number(floatValue))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const InputFormat = TypeGuards.isString(format) || TypeGuards.isString(mask)
|
|
213
|
+
? PatternFormat
|
|
214
|
+
: NumericFormat
|
|
215
|
+
|
|
216
|
+
const Input = TypeGuards.isFunction(formatter)
|
|
217
|
+
? NumberFormatBase
|
|
218
|
+
: InputFormat
|
|
219
|
+
|
|
220
|
+
return (
|
|
221
|
+
<InputBase
|
|
222
|
+
{...inputBaseProps}
|
|
223
|
+
error={hasError ? errorMessage : null}
|
|
224
|
+
styles={{
|
|
225
|
+
...variantStyles,
|
|
226
|
+
innerWrapper: [
|
|
227
|
+
variantStyles.innerWrapper,
|
|
228
|
+
editable && variantStyles['innerWrapper:cursor'],
|
|
229
|
+
],
|
|
230
|
+
}}
|
|
231
|
+
rightIcon={{
|
|
232
|
+
name: 'plus' as IconPlaceholder,
|
|
233
|
+
disabled: disabled || incrementDisabled,
|
|
234
|
+
onPress: () => handleChange('increment'),
|
|
235
|
+
component: 'button',
|
|
236
|
+
...inputBaseProps.rightIcon,
|
|
237
|
+
}}
|
|
238
|
+
leftIcon={{
|
|
239
|
+
name: 'minus' as IconPlaceholder,
|
|
240
|
+
disabled: disabled || decrementDisabled,
|
|
241
|
+
onPress: () => handleChange('decrement'),
|
|
242
|
+
component: 'button',
|
|
243
|
+
...inputBaseProps.leftIcon,
|
|
244
|
+
}}
|
|
245
|
+
style={style}
|
|
246
|
+
disabled={disabled}
|
|
247
|
+
focused={isFocused}
|
|
248
|
+
innerWrapperProps={{
|
|
249
|
+
...(inputBaseProps.innerWrapperProps || {}),
|
|
250
|
+
onClick: () => {
|
|
251
|
+
setIsFocused(true)
|
|
252
|
+
innerInputRef.current?.focus?.()
|
|
253
|
+
},
|
|
254
|
+
}}
|
|
255
|
+
innerWrapperRef={innerWrapperRef}
|
|
256
|
+
>
|
|
257
|
+
{editable && !disabled ? (
|
|
258
|
+
<Input
|
|
259
|
+
displayType='input'
|
|
260
|
+
css={[
|
|
261
|
+
...inputTextStyle,
|
|
262
|
+
{
|
|
263
|
+
'&::placeholder': placeholderStyles,
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
'&:focus': [
|
|
267
|
+
{
|
|
268
|
+
outline: 'none',
|
|
269
|
+
borderWidth: 0,
|
|
270
|
+
borderColor: 'transparent',
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
]}
|
|
275
|
+
inputMode='numeric'
|
|
276
|
+
onValueChange={handleChangeInput}
|
|
277
|
+
onBlur={handleBlur}
|
|
278
|
+
onFocus={handleFocus}
|
|
279
|
+
value={value}
|
|
280
|
+
thousandSeparator={separator}
|
|
281
|
+
thousandsGroupStyle={hasSeparator || TypeGuards.isString(separator) ? 'thousand' : 'none'}
|
|
282
|
+
suffix={suffix}
|
|
283
|
+
prefix={prefix}
|
|
284
|
+
format={TypeGuards.isFunction(formatter) ? formatter as any : format}
|
|
285
|
+
mask={mask}
|
|
286
|
+
placeholder={placeholder}
|
|
287
|
+
getInputRef={innerInputRef}
|
|
288
|
+
/>
|
|
289
|
+
) : <Text text={String(value)} css={inputTextStyle} />}
|
|
290
|
+
</InputBase>
|
|
291
|
+
)
|
|
292
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createDefaultVariantFactory, includePresets } from '@codeleap/common'
|
|
2
|
+
import { InputBaseParts } from '../InputBase'
|
|
3
|
+
|
|
4
|
+
export type NumberIncrementParts = InputBaseParts | 'input' | 'placeholder'
|
|
5
|
+
|
|
6
|
+
export type NumberIncrementStates = 'disabled' | 'focus' | 'error'
|
|
7
|
+
|
|
8
|
+
export type NumberIncrementComposition =
|
|
9
|
+
| NumberIncrementParts
|
|
10
|
+
| `${NumberIncrementParts}:${NumberIncrementStates}`
|
|
11
|
+
| `innerWrapper:cursor`
|
|
12
|
+
|
|
13
|
+
const createNumberIncrementStyle = createDefaultVariantFactory<NumberIncrementComposition>()
|
|
14
|
+
|
|
15
|
+
export const NumberIncrementPresets = includePresets((styles) => createNumberIncrementStyle(() => ({ wrapper: styles })))
|