@zuzjs/ui 0.2.3 → 0.2.5
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/README.md +1 -0
- package/dist/index.js +102 -6
- package/package.json +4 -2
- package/src/actions/addForm.tsx +0 -0
- package/src/actions/index.tsx +29 -0
- package/src/actions/redo.tsx +1 -0
- package/src/actions/reset.tsx +1 -0
- package/src/actions/undo.tsx +1 -0
- package/src/comps/app.tsx +34 -0
- package/src/comps/box.tsx +23 -0
- package/src/comps/button.tsx +45 -0
- package/src/comps/checkbox.tsx +74 -0
- package/src/comps/component.tsx +32 -0
- package/src/comps/contextmenu.tsx +43 -0
- package/src/comps/cover.tsx +34 -0
- package/src/comps/form.tsx +89 -0
- package/src/comps/heading.tsx +31 -0
- package/src/comps/icon.tsx +36 -0
- package/src/comps/image.tsx +26 -0
- package/src/comps/input.tsx +80 -0
- package/src/comps/placeholder.tsx +58 -0
- package/src/comps/root.tsx +32 -0
- package/src/comps/select.tsx +63 -0
- package/src/comps/spacer.tsx +20 -0
- package/src/comps/spinner.tsx +36 -0
- package/src/comps/text.tsx +27 -0
- package/src/comps/toaster.tsx +115 -0
- package/src/comps/tweet.tsx +48 -0
- package/src/context/AppContext.tsx +3 -0
- package/src/context/AppProvider.tsx +101 -0
- package/src/context/_AppProvider.tsx +116 -0
- package/src/context/combineReducers.tsx +47 -0
- package/src/context/combineState.tsx +14 -0
- package/src/context/createSlice.tsx +40 -0
- package/src/context/index.tsx +6 -0
- package/src/context/reduceReducers.tsx +6 -0
- package/src/context/store/appbase.tsx +19 -0
- package/src/context/store/theme.tsx +52 -0
- package/src/core/defaultTheme.ts +89 -0
- package/src/core/extractCurrentDesignState.tsx +0 -0
- package/src/core/index.ts +285 -0
- package/src/core/router.ts +86 -0
- package/src/core/styles.ts +361 -0
- package/src/hooks/index.tsx +8 -0
- package/src/hooks/useAppReducer.tsx +40 -0
- package/src/hooks/useChooseEffect.tsx +6 -0
- package/src/hooks/useDevice.tsx +164 -0
- package/src/hooks/useDispatch.tsx +37 -0
- package/src/hooks/useImage.tsx +58 -0
- package/src/hooks/useResizeObserver.tsx +84 -0
- package/src/hooks/useRouter.tsx +45 -0
- package/src/hooks/useSelector.tsx +9 -0
- package/src/hooks/useStore.tsx +27 -0
- package/src/hooks/useTheme.tsx +9 -0
- package/src/hooks/useToast.tsx +11 -0
- package/src/index.tsx +32 -0
- package/src/kit/Builder.tsx +18 -0
- package/src/kit/Component.tsx +32 -0
- package/src/kit/Header.tsx +21 -0
- package/src/redux/slices/app.js +26 -0
- package/src/redux/slices/form.js +46 -0
- package/src/redux/store.js +33 -0
- package/src/scss/constants.scss +4 -0
- package/src/scss/mixins.scss +3 -0
- package/src/scss/props.scss +60 -0
- package/src/scss/style.scss +106 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
LegacyRef
|
|
4
|
+
} from 'react'
|
|
5
|
+
import { ClassNames } from '@emotion/react'
|
|
6
|
+
import { buildCSS } from '../core'
|
|
7
|
+
import useImage from '../hooks/useImage'
|
|
8
|
+
import Box from './box'
|
|
9
|
+
|
|
10
|
+
const Image = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTMLImageElement>) => {
|
|
11
|
+
|
|
12
|
+
const [photo, status] = useImage(props.src, 'anonymous', 'origin');
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<ClassNames>
|
|
16
|
+
{({ css, cx }) => <picture className={cx(css`${buildCSS({ flex: true })}`)}>
|
|
17
|
+
{status == 'loading' && <Box className={`${props.as ? `${props.as} ` : ``}${cx(css`background: #eee;${buildCSS(props)}`)}`} />}
|
|
18
|
+
{status == 'loaded' && <img src={props.src}
|
|
19
|
+
className={`${props.as ? `${props.as} ` : ``}${cx(css`${buildCSS(props)}`)}`}
|
|
20
|
+
ref={ref} />}
|
|
21
|
+
</picture>}
|
|
22
|
+
</ClassNames>
|
|
23
|
+
)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export default Image;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FC,
|
|
3
|
+
LegacyRef,
|
|
4
|
+
forwardRef,
|
|
5
|
+
useRef,
|
|
6
|
+
SyntheticEvent,
|
|
7
|
+
} from 'react';
|
|
8
|
+
import { ClassNames } from '@emotion/react'
|
|
9
|
+
import { nanoid } from 'nanoid';
|
|
10
|
+
import { buildCSS } from '../core'
|
|
11
|
+
import { STORE_FORM_KEY } from '../context/AppProvider'
|
|
12
|
+
import useDispatch from '../hooks/useDispatch'
|
|
13
|
+
import useStore from '../hooks/useStore'
|
|
14
|
+
import {
|
|
15
|
+
UPDATE_FORM_FIELD
|
|
16
|
+
} from '../actions'
|
|
17
|
+
|
|
18
|
+
const Input = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTMLHeadingElement>) => {
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
as,
|
|
22
|
+
accept,
|
|
23
|
+
multiple,
|
|
24
|
+
onChange,
|
|
25
|
+
onKeyUp,
|
|
26
|
+
type,
|
|
27
|
+
tag,
|
|
28
|
+
placeholder,
|
|
29
|
+
name,
|
|
30
|
+
form,
|
|
31
|
+
touched,
|
|
32
|
+
onSubmit,
|
|
33
|
+
defaultValue,
|
|
34
|
+
fref
|
|
35
|
+
} = props;
|
|
36
|
+
|
|
37
|
+
const dispatch = useDispatch(STORE_FORM_KEY)
|
|
38
|
+
const { forms } = useStore(state => state[STORE_FORM_KEY], false)
|
|
39
|
+
|
|
40
|
+
let Tag : string = tag || 'input';
|
|
41
|
+
const El = Tag as `textarea` | `input`
|
|
42
|
+
const _ref = fref || useRef();
|
|
43
|
+
|
|
44
|
+
const _defaultCSS = `width: 100%;border-radius: var(--radius-base);padding-left: 4px;padding-right: 4px;border-style: solid;border-width: 1px;border-color: var(--colors-gray-200);`;
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<ClassNames>
|
|
48
|
+
{({ css, cx }) => <El
|
|
49
|
+
type={type || `text`}
|
|
50
|
+
placeholder={placeholder || undefined}
|
|
51
|
+
name={name || nanoid()}
|
|
52
|
+
multiple={type == 'file' ? multiple : undefined}
|
|
53
|
+
accept={accept || `*`}
|
|
54
|
+
className={`${as ? `${as} ` : ``}f ${cx(css`${_defaultCSS}${buildCSS(props)}&:hover {${buildCSS(props.hover || {})}} &:focus {${buildCSS(props.focus || {})}}`)}`}
|
|
55
|
+
ref={_ref}
|
|
56
|
+
defaultValue={defaultValue || ``}
|
|
57
|
+
onKeyUp={(e : SyntheticEvent) => {
|
|
58
|
+
let k = e['keyCode'] || ['which'];
|
|
59
|
+
if(El != 'textarea' && k == 13 && form && onSubmit){
|
|
60
|
+
onSubmit(forms[form]);
|
|
61
|
+
}
|
|
62
|
+
}}
|
|
63
|
+
onChange={e => {
|
|
64
|
+
let val = type == 'file' ?
|
|
65
|
+
e.currentTarget.files
|
|
66
|
+
: e.currentTarget.value;
|
|
67
|
+
dispatch( dispatch( UPDATE_FORM_FIELD( form || 'orphan', name, val == "" ? null : val, forms ) ) );
|
|
68
|
+
onChange && onChange(val == "" ? null : val)
|
|
69
|
+
}}
|
|
70
|
+
onBlur={e => {
|
|
71
|
+
if(touched){}
|
|
72
|
+
}}
|
|
73
|
+
onFocus={ e => touched == false && dispatch( UPDATE_FORM_FIELD( form || 'orphan', `touched`, true, forms ) ) }
|
|
74
|
+
/>}
|
|
75
|
+
</ClassNames>
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
export default Input
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef
|
|
3
|
+
} from 'react';
|
|
4
|
+
import PropTypes from 'prop-types'
|
|
5
|
+
import Box from './box'
|
|
6
|
+
|
|
7
|
+
export interface PlaceholderProps {
|
|
8
|
+
width: number|string,
|
|
9
|
+
height: number|string,
|
|
10
|
+
duration?: number,
|
|
11
|
+
bg?: string,
|
|
12
|
+
bgFrom?: string,
|
|
13
|
+
bgTo?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const calcPlaceholderStyle = (
|
|
17
|
+
width: number|string,
|
|
18
|
+
height: number|string,
|
|
19
|
+
duration = 1600
|
|
20
|
+
) => ({
|
|
21
|
+
backgroundSize: `${parseInt(width.toString()) * 10}px ${height}px`,
|
|
22
|
+
animationDuration: `${(duration / 1000).toFixed(1)}s`,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const Placeholder = forwardRef(({
|
|
26
|
+
width,
|
|
27
|
+
height,
|
|
28
|
+
duration,
|
|
29
|
+
bg,
|
|
30
|
+
bgFrom,
|
|
31
|
+
bgTo
|
|
32
|
+
} : PlaceholderProps, ref) => {
|
|
33
|
+
|
|
34
|
+
const placeholderStyle = calcPlaceholderStyle(width, height, duration);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Box
|
|
38
|
+
as={`shimmer`}
|
|
39
|
+
w={width}
|
|
40
|
+
h={height}
|
|
41
|
+
bg={bg || `#f6f7f8`}
|
|
42
|
+
backgroundImage={`linear-gradient(to right, ${bgFrom || `rgb(238, 238, 238)`} 8%, ${bgTo || `rgb(203, 203, 203)`} 18%, ${bgFrom || `rgb(238, 238, 238)`} 33%);`}
|
|
43
|
+
backgroundSize={placeholderStyle.backgroundSize}
|
|
44
|
+
animationDuration={placeholderStyle.animationDuration}
|
|
45
|
+
/>
|
|
46
|
+
)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
Placeholder.propTypes = {
|
|
50
|
+
width: PropTypes.oneOfType([ PropTypes.number, PropTypes.string ]).isRequired,
|
|
51
|
+
height: PropTypes.oneOfType([ PropTypes.number, PropTypes.string ]).isRequired,
|
|
52
|
+
duration: PropTypes.number,
|
|
53
|
+
bg: PropTypes.string,
|
|
54
|
+
bgFrom: PropTypes.string,
|
|
55
|
+
bgTo: PropTypes.string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default Placeholder;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useEffect
|
|
4
|
+
} from 'react';
|
|
5
|
+
import {
|
|
6
|
+
Provider
|
|
7
|
+
} from 'react-redux'
|
|
8
|
+
import appstore from '../redux/store'
|
|
9
|
+
import { setCSSVar, buildCSS } from '../core'
|
|
10
|
+
import { ClassNames } from '@emotion/react'
|
|
11
|
+
|
|
12
|
+
const AppRoot = forwardRef((props : { [ key: string ] : any }, ref) => {
|
|
13
|
+
|
|
14
|
+
if("reducers" in props){
|
|
15
|
+
props.reducers.map(r => appstore['injectReducer'](r.id, r.reducer));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if('primaryColor' in props) setCSSVar('primary-color', props.primaryColor);
|
|
20
|
+
if('primaryFont' in props) setCSSVar('primary-font', props.primaryFont);
|
|
21
|
+
}, [])
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Provider store={appstore}>
|
|
25
|
+
<ClassNames>
|
|
26
|
+
{({ css, cx }) => <main className={`${props.as ? props.as : `zuz-app`} ${cx(css`${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`}>{props.children}</main>}
|
|
27
|
+
</ClassNames>
|
|
28
|
+
</Provider>
|
|
29
|
+
)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
export default AppRoot;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FC,
|
|
3
|
+
LegacyRef,
|
|
4
|
+
forwardRef,
|
|
5
|
+
useRef,
|
|
6
|
+
useEffect
|
|
7
|
+
} from 'react';
|
|
8
|
+
import { ClassNames } from '@emotion/react'
|
|
9
|
+
import { buildCSS } from '../core'
|
|
10
|
+
import { nanoid } from 'nanoid';
|
|
11
|
+
import useStore from "../hooks/useStore";
|
|
12
|
+
import useDispatch from "../hooks/useDispatch";
|
|
13
|
+
import {
|
|
14
|
+
UPDATE_FORM_FIELD
|
|
15
|
+
} from '../actions'
|
|
16
|
+
import { STORE_FORM_KEY } from '../context/AppProvider'
|
|
17
|
+
|
|
18
|
+
const Select = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTMLHeadingElement>) => {
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
as,
|
|
22
|
+
onChange,
|
|
23
|
+
name,
|
|
24
|
+
form,
|
|
25
|
+
touched,
|
|
26
|
+
options,
|
|
27
|
+
defaultValue
|
|
28
|
+
} = props;
|
|
29
|
+
|
|
30
|
+
const _ref = useRef();
|
|
31
|
+
const dispatch = useDispatch(STORE_FORM_KEY)
|
|
32
|
+
const { forms } = useStore(state => state[STORE_FORM_KEY], false)
|
|
33
|
+
|
|
34
|
+
const _defaultCSS = `width: 100%;border-radius: var(--radius-base);padding-left: 4px;padding-right: 4px;border-style: solid;border-width: 1px;border-color: var(--colors-gray-200);`;
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
dispatch( dispatch( UPDATE_FORM_FIELD( form || 'orphan', name,
|
|
38
|
+
defaultValue && defaultValue != null && defaultValue != "" && defaultValue != undefined ? defaultValue : options[0]?.value || '-1',
|
|
39
|
+
forms ) ) );
|
|
40
|
+
}, [])
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<ClassNames>
|
|
44
|
+
{({ css, cx }) => <select
|
|
45
|
+
onChange={e => {
|
|
46
|
+
let val = e.currentTarget.value;
|
|
47
|
+
dispatch( dispatch( UPDATE_FORM_FIELD( form || 'orphan', name, val, forms ) ) );
|
|
48
|
+
onChange && onChange(val)
|
|
49
|
+
}}
|
|
50
|
+
onFocus={ e => touched == false && dispatch( UPDATE_FORM_FIELD( form || 'orphan', `touched`, true, forms ) ) }
|
|
51
|
+
onBlur={e => {
|
|
52
|
+
if(touched){}
|
|
53
|
+
}}
|
|
54
|
+
name={name || nanoid()}
|
|
55
|
+
className={`${as ? as : ``} ${cx(css`${_defaultCSS}${buildCSS(props)}&:hover {${buildCSS(props.hover || {})}}`)}`}
|
|
56
|
+
ref={_ref}>{options?.map(o => <option key={`select-${name}-option-${o.value}`} value={o.value}>{o.label}</option>)}</select>}
|
|
57
|
+
</ClassNames>
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
export default Select
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FC,
|
|
3
|
+
forwardRef
|
|
4
|
+
} from 'react';
|
|
5
|
+
import Box from './box'
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
w?: string|number,
|
|
9
|
+
h?: string|number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const Spacer : FC<Props> = ({
|
|
13
|
+
w, h
|
|
14
|
+
}) => {
|
|
15
|
+
return (
|
|
16
|
+
<Box as={`spacer`} w={w || 0} h={h || 0} />
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default Spacer;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import Box from './box'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
|
|
5
|
+
const Spinner = (props : any) => {
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<Box
|
|
9
|
+
rel
|
|
10
|
+
w={props.size}
|
|
11
|
+
h={props.size}
|
|
12
|
+
zIndex={`1`}
|
|
13
|
+
useSelect={`none`}>
|
|
14
|
+
<Box abs as={`spinner rotating`} animationDirection={`reverse`} animationDuration={typeof props.s1 == `string` ? props.s1 : `${props.s1}s`} w={props.size} r={props.radius} h={props.size} bg={props.color} opacity={0.2} />
|
|
15
|
+
<Box abs as={`spinner rotating`} animationDuration={typeof props.s2 == `string` ? props.s2 : `${props.s2}s`} w={props.size} r={props.radius} h={props.size} bg={props.color} opacity={0.5} />
|
|
16
|
+
</Box>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
Spinner.defaultProps = {
|
|
21
|
+
size: 30,
|
|
22
|
+
radius: 4,
|
|
23
|
+
color: `black`,
|
|
24
|
+
s1: `5s`,
|
|
25
|
+
s2: `1s`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
Spinner.propTypes = {
|
|
29
|
+
size: PropTypes.number.isRequired,
|
|
30
|
+
color: PropTypes.string,
|
|
31
|
+
radius: PropTypes.number,
|
|
32
|
+
s1: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
33
|
+
s2: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default Spinner;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FC,
|
|
3
|
+
LegacyRef,
|
|
4
|
+
forwardRef,
|
|
5
|
+
HTMLAttributes
|
|
6
|
+
} from 'react';
|
|
7
|
+
import { ClassNames } from '@emotion/react'
|
|
8
|
+
import { buildCSS } from '../core'
|
|
9
|
+
|
|
10
|
+
const Text = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTMLParagraphElement>) => {
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
children,
|
|
14
|
+
as
|
|
15
|
+
} = props;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<ClassNames>
|
|
19
|
+
{({ css, cx }) => <p
|
|
20
|
+
className={`${as ? `${as} ` : ``}${cx(css`${buildCSS(props)}`)}`}
|
|
21
|
+
ref={ref}
|
|
22
|
+
>{props.html ? <span dangerouslySetInnerHTML={{ __html: props.html }} /> : children}</p>}
|
|
23
|
+
</ClassNames>
|
|
24
|
+
)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export default Text;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { nanoid } from 'nanoid'
|
|
2
|
+
|
|
3
|
+
class Toaster {
|
|
4
|
+
|
|
5
|
+
#container : any;
|
|
6
|
+
#startTop : number
|
|
7
|
+
#tout : null
|
|
8
|
+
#defaultTimeLeft : number
|
|
9
|
+
|
|
10
|
+
constructor(config?: {
|
|
11
|
+
root : string,
|
|
12
|
+
duration: number
|
|
13
|
+
}){
|
|
14
|
+
this.#startTop = 20
|
|
15
|
+
this.#defaultTimeLeft = 4
|
|
16
|
+
const rootID = config?.root || `toast-container`;
|
|
17
|
+
if(document.querySelector(`#${rootID}`)) return;
|
|
18
|
+
var self = this;
|
|
19
|
+
var root = document.createElement('div');
|
|
20
|
+
root.id = rootID;
|
|
21
|
+
document.body.appendChild(root);
|
|
22
|
+
this.#container = document.querySelector(`#${rootID}`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
show = (
|
|
26
|
+
message: string | null,
|
|
27
|
+
duration?: number
|
|
28
|
+
) => {
|
|
29
|
+
let self = this;
|
|
30
|
+
self.toast({
|
|
31
|
+
message: message,
|
|
32
|
+
duration: duration
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
dismiss(ID: string){
|
|
37
|
+
let self = this
|
|
38
|
+
self.#tout && clearTimeout(self.#tout);
|
|
39
|
+
setTimeout(()=>{
|
|
40
|
+
let tost = document.querySelector(`#${ID}`);
|
|
41
|
+
tost && tost.classList.remove("visible");
|
|
42
|
+
// tost && tost.classList.add("hidden");
|
|
43
|
+
setTimeout(()=>{
|
|
44
|
+
try{
|
|
45
|
+
document.getElementById(ID).parentNode.removeChild(document.getElementById(ID));
|
|
46
|
+
}catch(e){}
|
|
47
|
+
self.arrangeToasts();
|
|
48
|
+
}, 200);
|
|
49
|
+
}, 200);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
toast(config?: {
|
|
53
|
+
message: string | null,
|
|
54
|
+
duration: number
|
|
55
|
+
}){
|
|
56
|
+
|
|
57
|
+
var self = this;
|
|
58
|
+
var tout = null,
|
|
59
|
+
ID = 'toast-' + nanoid(),
|
|
60
|
+
toast = document.createElement('div'),
|
|
61
|
+
toastBG = document.createElement('div');
|
|
62
|
+
|
|
63
|
+
toast.id = ID;
|
|
64
|
+
toast.style.backgroundColor = `#111`
|
|
65
|
+
toast.style.color = `#fff`
|
|
66
|
+
toast.style.transform = `translate(-50%, -300px) scale(0.5)`;
|
|
67
|
+
toast.style.position = `fixed`
|
|
68
|
+
toast.style.padding = `6px 12px`
|
|
69
|
+
toast.style.fontSize = `14px`
|
|
70
|
+
toast.style.left = `50%`
|
|
71
|
+
toast.style.maxWidth = `95%`
|
|
72
|
+
toast.style.zIndex = `2147483647`
|
|
73
|
+
toast.classList.add( 'zuz-toast' );
|
|
74
|
+
toast.classList.add( 'fixed' );
|
|
75
|
+
toast.classList.add( 'f' );
|
|
76
|
+
|
|
77
|
+
toast.innerHTML = config.message || `You haven't passed "message" in this toast`;
|
|
78
|
+
|
|
79
|
+
self.#container.appendChild(toast);
|
|
80
|
+
|
|
81
|
+
self.arrangeToasts()
|
|
82
|
+
.then(() => {
|
|
83
|
+
setTimeout(()=>{
|
|
84
|
+
let tost = document.querySelector("#"+ID);
|
|
85
|
+
tost.classList.add("showing");
|
|
86
|
+
tout = setTimeout(() => self.dismiss(ID), (config?.duration == undefined ? self.#defaultTimeLeft : config?.duration == -1 ? 86400 : config?.duration) * 1000);
|
|
87
|
+
setTimeout(()=>{
|
|
88
|
+
let tost = document.querySelector("#"+ID);
|
|
89
|
+
tost.classList.remove("showing");
|
|
90
|
+
tost.classList.add("visible");
|
|
91
|
+
}, 200)
|
|
92
|
+
|
|
93
|
+
}, 10)
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
arrangeToasts(){
|
|
98
|
+
var self = this, top = self.#startTop;
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
var toasts = document.querySelectorAll(".zuz-toast"),
|
|
101
|
+
i = toasts.length;
|
|
102
|
+
while(i--){
|
|
103
|
+
toasts[i]['style'].top = `${top}px`
|
|
104
|
+
top += parseInt(getComputedStyle(toasts[i]).height.replace('px', '')) + 6;
|
|
105
|
+
}
|
|
106
|
+
resolve(null);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export default Toaster;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
// import PropTypes from `prop-types`
|
|
3
|
+
import Box from './box'
|
|
4
|
+
import { addScript } from '../core';
|
|
5
|
+
|
|
6
|
+
const Tweet = (props) => {
|
|
7
|
+
|
|
8
|
+
const [rand, setRand] = useState(Math.random())
|
|
9
|
+
const _tweet = useRef()
|
|
10
|
+
|
|
11
|
+
const renderTweet = () => {
|
|
12
|
+
const twttr = window['twttr']
|
|
13
|
+
twttr.ready().then(({ widgets }) => {
|
|
14
|
+
const { options, onTweetLoadSuccess, onTweetLoadError } = props
|
|
15
|
+
widgets
|
|
16
|
+
.createTweetEmbed(props.id, _tweet.current, options || {})
|
|
17
|
+
.then((twitterWidgetElement) => {
|
|
18
|
+
// this.setState({
|
|
19
|
+
// isLoading: false
|
|
20
|
+
// })
|
|
21
|
+
// onTweetLoadSuccess && onTweetLoadSuccess(twitterWidgetElement)
|
|
22
|
+
})
|
|
23
|
+
.catch(() => {})
|
|
24
|
+
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const twttr = window['twttr']
|
|
30
|
+
if (!(twttr && twttr.ready)){
|
|
31
|
+
addScript(`https://platform.twitter.com/widgets.js`, renderTweet)
|
|
32
|
+
}else{
|
|
33
|
+
renderTweet()
|
|
34
|
+
}
|
|
35
|
+
}, [])
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
|
|
39
|
+
}, [rand])
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Box as={`tweet`} weight={1} bref={_tweet}></Box>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
export default Tweet;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useEffect,
|
|
4
|
+
useMemo,
|
|
5
|
+
useReducer
|
|
6
|
+
} from 'react'
|
|
7
|
+
import PropTypes from 'prop-types'
|
|
8
|
+
import AppContext from './AppContext'
|
|
9
|
+
import AppTheme from './store/theme'
|
|
10
|
+
|
|
11
|
+
let isMounted = true;
|
|
12
|
+
export const STORE_KEY = `__zuzjs`
|
|
13
|
+
export const STORE_FORM_KEY = `${STORE_KEY}forms`
|
|
14
|
+
export const STORE_DEFAUTLS = [`${STORE_KEY}base`, `${STORE_KEY}forms`]
|
|
15
|
+
|
|
16
|
+
const defaultState = {
|
|
17
|
+
[`${STORE_KEY}base`] : {
|
|
18
|
+
debug: true,
|
|
19
|
+
loading: false,
|
|
20
|
+
_tmp: Math.random()
|
|
21
|
+
},
|
|
22
|
+
[STORE_FORM_KEY] : {
|
|
23
|
+
forms: {}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const rootReducer = (state, action ) => ({
|
|
28
|
+
...state,
|
|
29
|
+
...action.payload
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const AppProvider = ({
|
|
33
|
+
children,
|
|
34
|
+
initialState = {},
|
|
35
|
+
theme = {}
|
|
36
|
+
}) => {
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
isMounted = true;
|
|
41
|
+
return () => {
|
|
42
|
+
isMounted = false;
|
|
43
|
+
}
|
|
44
|
+
}, [])
|
|
45
|
+
|
|
46
|
+
const rootState = useMemo(() => ({
|
|
47
|
+
...defaultState,
|
|
48
|
+
...initialState,
|
|
49
|
+
theme: new AppTheme({ theme }).get()
|
|
50
|
+
}), [initialState])
|
|
51
|
+
|
|
52
|
+
const [state, _dispatch] = useReducer(rootReducer, rootState);
|
|
53
|
+
|
|
54
|
+
const dispatch = useCallback((args) => {
|
|
55
|
+
if (isMounted) {
|
|
56
|
+
_dispatch({ ...args });
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
[_dispatch],
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// const dispatch = useCallback((payload = {}, _key = 'base') => {
|
|
63
|
+
// if(isMounted){
|
|
64
|
+
// const key = STORE_DEFAUTLS.indexOf(`${STORE_KEY}${_key}`) > -1 ? `${STORE_KEY}${_key}` : _key;
|
|
65
|
+
// const _state = { ...state[key] }
|
|
66
|
+
// console.log('key', key)
|
|
67
|
+
// console.log('state', _state)
|
|
68
|
+
// _dispatch({
|
|
69
|
+
// type: 'any',
|
|
70
|
+
// payload: {
|
|
71
|
+
// payload
|
|
72
|
+
// }
|
|
73
|
+
// })
|
|
74
|
+
// }
|
|
75
|
+
// }, [_dispatch]);
|
|
76
|
+
|
|
77
|
+
const providedValue = useMemo(
|
|
78
|
+
() => ({
|
|
79
|
+
...state,
|
|
80
|
+
dispatch
|
|
81
|
+
}),
|
|
82
|
+
[state]
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
return <AppContext.Provider value={providedValue}>{children}</AppContext.Provider>
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
AppProvider.defaultProps = {
|
|
91
|
+
theme: {},
|
|
92
|
+
initialState : {},
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
AppProvider.propTypes = {
|
|
96
|
+
children: PropTypes.node.isRequired,
|
|
97
|
+
initialState: PropTypes.instanceOf(Object),
|
|
98
|
+
theme: PropTypes.instanceOf(Object)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export default AppProvider
|