@zuzjs/ui 0.2.4 → 0.2.6

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.
Files changed (67) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +214 -15
  3. package/package.json +4 -2
  4. package/src/actions/addForm.tsx +0 -0
  5. package/src/actions/index.tsx +29 -0
  6. package/src/actions/redo.tsx +1 -0
  7. package/src/actions/reset.tsx +1 -0
  8. package/src/actions/undo.tsx +1 -0
  9. package/src/comps/app.tsx +34 -0
  10. package/src/comps/box.tsx +23 -0
  11. package/src/comps/button.tsx +45 -0
  12. package/src/comps/checkbox.tsx +74 -0
  13. package/src/comps/component.tsx +32 -0
  14. package/src/comps/contextmenu.tsx +43 -0
  15. package/src/comps/cover.tsx +34 -0
  16. package/src/comps/form.tsx +89 -0
  17. package/src/comps/heading.tsx +31 -0
  18. package/src/comps/icon.tsx +36 -0
  19. package/src/comps/image.tsx +26 -0
  20. package/src/comps/input.tsx +80 -0
  21. package/src/comps/masonry.tsx +192 -0
  22. package/src/comps/placeholder.tsx +58 -0
  23. package/src/comps/root.tsx +32 -0
  24. package/src/comps/select.tsx +63 -0
  25. package/src/comps/spacer.tsx +20 -0
  26. package/src/comps/spinner.tsx +36 -0
  27. package/src/comps/text.tsx +27 -0
  28. package/src/comps/toaster.tsx +115 -0
  29. package/src/comps/tweet.tsx +48 -0
  30. package/src/context/AppContext.tsx +3 -0
  31. package/src/context/AppProvider.tsx +101 -0
  32. package/src/context/_AppProvider.tsx +116 -0
  33. package/src/context/combineReducers.tsx +47 -0
  34. package/src/context/combineState.tsx +14 -0
  35. package/src/context/createSlice.tsx +40 -0
  36. package/src/context/index.tsx +6 -0
  37. package/src/context/reduceReducers.tsx +6 -0
  38. package/src/context/store/appbase.tsx +19 -0
  39. package/src/context/store/theme.tsx +53 -0
  40. package/src/core/defaultTheme.ts +89 -0
  41. package/src/core/extractCurrentDesignState.tsx +0 -0
  42. package/src/core/index.ts +285 -0
  43. package/src/core/router.ts +86 -0
  44. package/src/core/styles.ts +361 -0
  45. package/src/hooks/index.tsx +8 -0
  46. package/src/hooks/useAppReducer.tsx +40 -0
  47. package/src/hooks/useChooseEffect.tsx +6 -0
  48. package/src/hooks/useDevice.tsx +164 -0
  49. package/src/hooks/useDispatch.tsx +37 -0
  50. package/src/hooks/useImage.tsx +58 -0
  51. package/src/hooks/useResizeObserver.tsx +84 -0
  52. package/src/hooks/useRouter.tsx +45 -0
  53. package/src/hooks/useSelector.tsx +9 -0
  54. package/src/hooks/useStore.tsx +27 -0
  55. package/src/hooks/useTheme.tsx +9 -0
  56. package/src/hooks/useToast.tsx +11 -0
  57. package/src/index.tsx +33 -0
  58. package/src/kit/Builder.tsx +18 -0
  59. package/src/kit/Component.tsx +32 -0
  60. package/src/kit/Header.tsx +21 -0
  61. package/src/redux/slices/app.js +26 -0
  62. package/src/redux/slices/form.js +46 -0
  63. package/src/redux/store.js +33 -0
  64. package/src/scss/constants.scss +4 -0
  65. package/src/scss/mixins.scss +3 -0
  66. package/src/scss/props.scss +60 -0
  67. package/src/scss/style.scss +106 -0
@@ -0,0 +1,89 @@
1
+ import {
2
+ Ref,
3
+ LegacyRef,
4
+ forwardRef,
5
+ useState,
6
+ createElement,
7
+ useEffect,
8
+ useImperativeHandle
9
+ } from 'react';
10
+ import PropTypes from 'prop-types'
11
+ import Box from './box'
12
+ import Cover from './cover'
13
+ import { addProps } from '../core'
14
+ import useDispatch from '../hooks/useDispatch'
15
+ import useStore from '../hooks/useStore'
16
+ import { STORE_FORM_KEY, STORE_DEFAUTLS } from '../context/AppProvider'
17
+ import { nanoid } from 'nanoid'
18
+ import {
19
+ ADD_FORM,
20
+ UPDATE_FORM_FIELD
21
+ } from '../actions'
22
+
23
+ const Form = forwardRef((props : { [ key: string ] : any }, ref : Ref<any>) => {
24
+
25
+ const {
26
+ name,
27
+ children,
28
+ onSubmit,
29
+ cover,
30
+ debug
31
+ } = props;
32
+
33
+ const [_html, setHTML] = useState(null);
34
+ const [_loading, setLoading] = useState(debug?.loading || false);
35
+ const dispatch = useDispatch(STORE_FORM_KEY)
36
+ const { forms } = useStore(state => state[STORE_FORM_KEY], false)
37
+
38
+ const buildFields = () => {
39
+ return addProps(children, { form : name, touched: undefined, loading: undefined, onSubmit: onSubmit ? onSubmit : () => console.log(`onSubmit Missing`) })
40
+ }
41
+
42
+ const update = (e : object) => Object.keys(e).map(k => {
43
+ dispatch( UPDATE_FORM_FIELD( name || 'orphan', k, e[k], forms ) )
44
+ if(k == 'loading') setLoading(e[k])
45
+ })
46
+
47
+ const get = (k : string) => forms[name][k] || null
48
+
49
+ useImperativeHandle(ref, () => ({
50
+ update,
51
+ get
52
+ }))
53
+
54
+ useEffect(() => {
55
+ let f = buildFields();
56
+ setHTML(f.children);
57
+ if(!forms[name]){
58
+ dispatch(ADD_FORM(name, f.fields, forms))
59
+ }
60
+ }, [children, forms[name]?.loading])
61
+
62
+ return createElement(
63
+ Box,
64
+ {
65
+ rel: true,
66
+ ...props,
67
+ as: name
68
+ },
69
+ [
70
+ _loading? <Cover key={`form-${name}-cover`} backdrop={cover?.filter || { saturate: 80, blur: 10 }} bg={cover?.bg || `rgba(0,0,0,0.5)`} /> : null,
71
+ _html
72
+ ]
73
+ )
74
+
75
+ })
76
+
77
+ Form.defaultProps = {
78
+ name: 'form1',
79
+ onSubmit: () => { console.log(`onSubmit not provided`) }
80
+ }
81
+
82
+ Form.propTypes = {
83
+ name: PropTypes.string.isRequired,
84
+ children: PropTypes.node.isRequired,
85
+ onSubmit: PropTypes.func.isRequired
86
+ }
87
+
88
+
89
+ export default Form
@@ -0,0 +1,31 @@
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 Heading = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTMLHeadingElement>) => {
11
+
12
+ const {
13
+ children,
14
+ as,
15
+ h
16
+ } = props;
17
+
18
+ let Tag : string = `h${h || 1}`;
19
+ const HeadingTag = Tag as `h1` | `h2` | `h3` | `h4` | `h5` | `h6`
20
+
21
+ return (
22
+ <ClassNames>
23
+ {({ css, cx }) => <HeadingTag
24
+ className={`${as ? `${as} ` : ``}${cx(css`${buildCSS(props)}`)}`}
25
+ ref={ref}
26
+ >{props.html ? <span dangerouslySetInnerHTML={{ __html: props.html }} /> : children}</HeadingTag>}
27
+ </ClassNames>
28
+ )
29
+ })
30
+
31
+ export default Heading;
@@ -0,0 +1,36 @@
1
+ import {
2
+ FC,
3
+ LegacyRef,
4
+ forwardRef,
5
+ useRef,
6
+ SyntheticEvent,
7
+ } from 'react';
8
+ import Box from './box'
9
+
10
+ const Icon = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTMLHeadingElement>) => {
11
+
12
+ const {
13
+ as,
14
+ path,
15
+ size,
16
+ color,
17
+ hover
18
+ } = props;
19
+
20
+ return (
21
+ <Box
22
+ hover={hover || {}}
23
+ flex
24
+ bref={ref}
25
+ as={`icon-${as}`}
26
+ ai={`c`}
27
+ jc={`c`}
28
+ size={size || 24}
29
+ color={color || `#111111`}
30
+ >
31
+ {path && Array(path).fill(undefined).map((p : any, i : any) => <span key={`ico-${as}-${i}`} className={`path${i+1}`} />)}
32
+ </Box>
33
+ )
34
+ })
35
+
36
+ export default Icon;
@@ -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,192 @@
1
+ import { Component, Children } from "react"
2
+ import PropTypes from 'prop-types'
3
+
4
+ const DEFAULT_COLUMNS = 2;
5
+
6
+ class Masonry extends Component<any, any> {
7
+
8
+ constructor(props : { [ key: string ] : any }) {
9
+ super(props);
10
+ // Correct scope for when methods are accessed externally
11
+ this.reCalculateColumnCount = this.reCalculateColumnCount.bind(this);
12
+ this.reCalculateColumnCountDebounce = this.reCalculateColumnCountDebounce.bind(this);
13
+ // default state
14
+ let columnCount
15
+ if (this.props && this.props.breakpointCols.default) {
16
+ columnCount = this.props.breakpointCols.default
17
+ } else {
18
+ columnCount = parseInt(this.props.breakpointCols) || DEFAULT_COLUMNS
19
+ }
20
+ this.state = {
21
+ columnCount
22
+ };
23
+ }
24
+
25
+ componentDidMount() {
26
+ this.reCalculateColumnCount();
27
+ // window may not be available in some environments
28
+ if(window) {
29
+ window.addEventListener('resize', this.reCalculateColumnCountDebounce);
30
+ }
31
+ }
32
+
33
+ componentDidUpdate() {
34
+ this.reCalculateColumnCount();
35
+ }
36
+
37
+ componentWillUnmount() {
38
+ if(window) {
39
+ window.removeEventListener('resize', this.reCalculateColumnCountDebounce);
40
+ }
41
+ }
42
+
43
+ reCalculateColumnCountDebounce() {
44
+ if(!window || !window.requestAnimationFrame) { // IE10+
45
+ this.reCalculateColumnCount();
46
+ return;
47
+ }
48
+
49
+ if(window.cancelAnimationFrame) { // IE10+
50
+ window.cancelAnimationFrame(this._lastRecalculateAnimationFrame);
51
+ }
52
+
53
+ }
54
+
55
+ _lastRecalculateAnimationFrame = window.requestAnimationFrame(() => {
56
+ this.reCalculateColumnCount();
57
+ });
58
+
59
+ reCalculateColumnCount() {
60
+ const windowWidth = window && window.innerWidth || Infinity;
61
+ let breakpointColsObject = this.props.breakpointCols;
62
+
63
+ // Allow passing a single number to `breakpointCols` instead of an object
64
+ if(typeof breakpointColsObject !== 'object') {
65
+ breakpointColsObject = {
66
+ default: parseInt(breakpointColsObject) || DEFAULT_COLUMNS
67
+ }
68
+ }
69
+
70
+ let matchedBreakpoint = Infinity;
71
+ let columns = breakpointColsObject.default || DEFAULT_COLUMNS;
72
+
73
+ for(let breakpoint in breakpointColsObject) {
74
+ const optBreakpoint = parseInt(breakpoint);
75
+ const isCurrentBreakpoint = optBreakpoint > 0 && windowWidth <= optBreakpoint;
76
+
77
+ if(isCurrentBreakpoint && optBreakpoint < matchedBreakpoint) {
78
+ matchedBreakpoint = optBreakpoint;
79
+ columns = breakpointColsObject[breakpoint];
80
+ }
81
+ }
82
+
83
+ columns = Math.max(1, parseInt(columns) || 1);
84
+
85
+ if(this.state.columnCount !== columns) {
86
+ this.setState({
87
+ columnCount: columns
88
+ });
89
+ this.props.onChange && this.props.onChange({ columns: columns });
90
+ }
91
+ }
92
+
93
+ itemsInColumns() {
94
+ const currentColumnCount = this.state.columnCount;
95
+ const itemsInColumns = new Array(currentColumnCount);
96
+
97
+ // Force children to be handled as an array
98
+ const items = Children.toArray(this.props.children)
99
+
100
+ for (let i = 0; i < items.length; i++) {
101
+ const columnIndex = i % currentColumnCount;
102
+
103
+ if(!itemsInColumns[columnIndex]) {
104
+ itemsInColumns[columnIndex] = [];
105
+ }
106
+
107
+ itemsInColumns[columnIndex].push(items[i]);
108
+ }
109
+
110
+ return itemsInColumns;
111
+ }
112
+
113
+ renderColumns() {
114
+ const { column, columnAttrs = {}, columnClassName } = this.props;
115
+ const childrenInColumns = this.itemsInColumns();
116
+ const columnWidth = `${100 / childrenInColumns.length}%`;
117
+ let className = columnClassName;
118
+
119
+ if(className && typeof className !== 'string') {
120
+ this.logDeprecated('The property "columnClassName" requires a string');
121
+
122
+ // This is a deprecated default and will be removed soon.
123
+ if(typeof className === 'undefined') {
124
+ className = 'my-masonry-grid_column';
125
+ }
126
+ }
127
+
128
+ const columnAttributes = {
129
+ // NOTE: the column property is undocumented and considered deprecated.
130
+ // It is an alias of the `columnAttrs` property
131
+ ...column,
132
+ ...columnAttrs,
133
+ style: {
134
+ ...columnAttrs.style,
135
+ width: columnWidth
136
+ },
137
+ className
138
+ };
139
+
140
+ return childrenInColumns.map((items, i) => {
141
+ return <div
142
+ {...columnAttributes}
143
+
144
+ key={i}
145
+ >
146
+ {items}
147
+ </div>;
148
+ });
149
+ }
150
+
151
+ logDeprecated(message) {
152
+ console.error('[Masonry]', message);
153
+ }
154
+
155
+ render() {
156
+ const {
157
+ // ignored
158
+ children,
159
+ breakpointCols,
160
+ columnClassName,
161
+ columnAttrs,
162
+ column,
163
+
164
+ // used
165
+ className,
166
+
167
+ ...rest
168
+ } = this.props;
169
+
170
+ let classNameOutput = className;
171
+
172
+ if(typeof className !== 'string') {
173
+ this.logDeprecated('The property "className" requires a string');
174
+
175
+ // This is a deprecated default and will be removed soon.
176
+ if(typeof className === 'undefined') {
177
+ classNameOutput = 'my-masonry-grid';
178
+ }
179
+ }
180
+
181
+ return (
182
+ <div
183
+ {...rest}
184
+ className={classNameOutput}
185
+ >
186
+ {this.renderColumns()}
187
+ </div>
188
+ );
189
+ }
190
+ }
191
+
192
+ export default Masonry;
@@ -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;