@zuzjs/ui 0.2.4 → 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.
Files changed (66) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +78 -4
  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/placeholder.tsx +58 -0
  22. package/src/comps/root.tsx +32 -0
  23. package/src/comps/select.tsx +63 -0
  24. package/src/comps/spacer.tsx +20 -0
  25. package/src/comps/spinner.tsx +36 -0
  26. package/src/comps/text.tsx +27 -0
  27. package/src/comps/toaster.tsx +115 -0
  28. package/src/comps/tweet.tsx +48 -0
  29. package/src/context/AppContext.tsx +3 -0
  30. package/src/context/AppProvider.tsx +101 -0
  31. package/src/context/_AppProvider.tsx +116 -0
  32. package/src/context/combineReducers.tsx +47 -0
  33. package/src/context/combineState.tsx +14 -0
  34. package/src/context/createSlice.tsx +40 -0
  35. package/src/context/index.tsx +6 -0
  36. package/src/context/reduceReducers.tsx +6 -0
  37. package/src/context/store/appbase.tsx +19 -0
  38. package/src/context/store/theme.tsx +52 -0
  39. package/src/core/defaultTheme.ts +89 -0
  40. package/src/core/extractCurrentDesignState.tsx +0 -0
  41. package/src/core/index.ts +285 -0
  42. package/src/core/router.ts +86 -0
  43. package/src/core/styles.ts +361 -0
  44. package/src/hooks/index.tsx +8 -0
  45. package/src/hooks/useAppReducer.tsx +40 -0
  46. package/src/hooks/useChooseEffect.tsx +6 -0
  47. package/src/hooks/useDevice.tsx +164 -0
  48. package/src/hooks/useDispatch.tsx +37 -0
  49. package/src/hooks/useImage.tsx +58 -0
  50. package/src/hooks/useResizeObserver.tsx +84 -0
  51. package/src/hooks/useRouter.tsx +45 -0
  52. package/src/hooks/useSelector.tsx +9 -0
  53. package/src/hooks/useStore.tsx +27 -0
  54. package/src/hooks/useTheme.tsx +9 -0
  55. package/src/hooks/useToast.tsx +11 -0
  56. package/src/index.tsx +32 -0
  57. package/src/kit/Builder.tsx +18 -0
  58. package/src/kit/Component.tsx +32 -0
  59. package/src/kit/Header.tsx +21 -0
  60. package/src/redux/slices/app.js +26 -0
  61. package/src/redux/slices/form.js +46 -0
  62. package/src/redux/store.js +33 -0
  63. package/src/scss/constants.scss +4 -0
  64. package/src/scss/mixins.scss +3 -0
  65. package/src/scss/props.scss +60 -0
  66. package/src/scss/style.scss +106 -0
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # zuzjs
package/dist/index.js CHANGED
@@ -251,6 +251,7 @@ const cssProps = {
251
251
  "@charset": "@charset",
252
252
  "clear": "clear",
253
253
  "clip": "clip",
254
+ "clipPath": "clip-path",
254
255
  "color": "color",
255
256
  "columnCount": "column-count",
256
257
  "columnFill": "column-fill",
@@ -555,12 +556,12 @@ const UPDATE_FORM_FIELD = (formName, field, value, forms) => {
555
556
  };
556
557
 
557
558
  const Input = forwardRef((props, ref) => {
558
- const { as, accept, multiple, onChange, type, tag, placeholder, name, form, touched, onSubmit, defaultValue } = props;
559
+ const { as, accept, multiple, onChange, type, tag, placeholder, name, form, touched, onSubmit, defaultValue, fref } = props;
559
560
  const dispatch = useDispatch(STORE_FORM_KEY);
560
561
  const { forms } = useStore(state => state[STORE_FORM_KEY], false);
561
562
  let Tag = tag || 'input';
562
563
  const El = Tag;
563
- const _ref = useRef();
564
+ const _ref = fref || useRef();
564
565
  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);`;
565
566
  return (jsx(ClassNames, { children: ({ css, cx }) => jsx(El, { type: type || `text`, placeholder: placeholder || undefined, name: name || nanoid(), multiple: type == 'file' ? multiple : undefined, accept: accept || `*`, className: `${as ? `${as} ` : ``}f ${cx(css `${_defaultCSS}${buildCSS(props)}&:hover {${buildCSS(props.hover || {})}} &:focus {${buildCSS(props.focus || {})}}`)}`, ref: _ref, defaultValue: defaultValue || ``, onKeyUp: (e) => {
566
567
  let k = e['keyCode'] || ['which'];
@@ -572,7 +573,7 @@ const Input = forwardRef((props, ref) => {
572
573
  e.currentTarget.files
573
574
  : e.currentTarget.value;
574
575
  dispatch(dispatch(UPDATE_FORM_FIELD(form || 'orphan', name, val == "" ? null : val, forms)));
575
- onChange && onChange(e.target.value == "" ? null : e.target.value);
576
+ onChange && onChange(val == "" ? null : val);
576
577
  }, onBlur: e => {
577
578
  }, onFocus: e => touched == false && dispatch(UPDATE_FORM_FIELD(form || 'orphan', `touched`, true, forms)) }) }));
578
579
  });
@@ -909,6 +910,79 @@ const Button = forwardRef((props, ref) => {
909
910
  } }));
910
911
  });
911
912
 
913
+ const patterns = {
914
+ route: [/^.*\/src\/pages\/|\.(jsx|tsx)$/g, ''],
915
+ splat: [/\[\.{3}\w+\]/g, '*'],
916
+ param: [/\[([^\]]+)\]/g, ':$1'],
917
+ slash: [/^index$|\./g, '/'],
918
+ optional: [/^-(:?[\w-]+)/, '$1?'],
919
+ };
920
+ const generatePreservedRoutes = (files) => {
921
+ return Object.keys(files).reduce((routes, key) => {
922
+ const path = key.replace(...patterns.route);
923
+ return Object.assign(Object.assign({}, routes), { [path]: files[key] });
924
+ }, {});
925
+ };
926
+ const generateRegularRoutes = (files, buildRoute) => {
927
+ const filteredRoutes = Object.keys(files).filter((key) => !key.includes('/_') || /_layout\.(jsx|tsx)$/.test(key));
928
+ return filteredRoutes.reduce((routes, key) => {
929
+ const module = files[key];
930
+ const route = Object.assign({ id: key.replace(...patterns.route) }, buildRoute(module, key));
931
+ const segments = key
932
+ .replace(...patterns.route)
933
+ .replace(...patterns.splat)
934
+ .replace(...patterns.param)
935
+ .split('/')
936
+ .filter(Boolean);
937
+ segments.reduce((parent, segment, index) => {
938
+ var _a, _b;
939
+ const path = segment.replace(...patterns.slash).replace(...patterns.optional);
940
+ const root = index === 0;
941
+ const leaf = index === segments.length - 1 && segments.length > 1;
942
+ const node = !root && !leaf;
943
+ const layout = segment === '_layout';
944
+ const group = /\(\w+\)/.test(path);
945
+ const insert = /^\w|\//.test(path) ? 'unshift' : 'push';
946
+ if (root) {
947
+ const last = segments.length === 1;
948
+ if (last) {
949
+ routes.push(Object.assign({ path }, route));
950
+ return parent;
951
+ }
952
+ }
953
+ if (root || node) {
954
+ const current = root ? routes : parent.children;
955
+ const found = current === null || current === void 0 ? void 0 : current.find((route) => { var _a, _b; return route.path === path || ((_b = (_a = route.id) === null || _a === void 0 ? void 0 : _a.split('@')) === null || _b === void 0 ? void 0 : _b[0]) === path; });
956
+ const props = group ? ((route === null || route === void 0 ? void 0 : route.component) ? { id: path, path: '/' } : { id: path }) : { path };
957
+ if (found)
958
+ (_a = found.children) !== null && _a !== void 0 ? _a : (found.children = []);
959
+ else
960
+ current === null || current === void 0 ? void 0 : current[insert](Object.assign(Object.assign({}, props), { children: [] }));
961
+ return found || (current === null || current === void 0 ? void 0 : current[insert === 'unshift' ? 0 : current.length - 1]);
962
+ }
963
+ if (layout) {
964
+ return Object.assign(parent, Object.assign(Object.assign({}, route), { id: `${parent.id || parent.path}@${route.id}` }));
965
+ }
966
+ if (leaf) {
967
+ (_b = parent === null || parent === void 0 ? void 0 : parent.children) === null || _b === void 0 ? void 0 : _b[insert]((route === null || route === void 0 ? void 0 : route.index) ? route : Object.assign({ path }, route));
968
+ }
969
+ return parent;
970
+ }, {});
971
+ return routes;
972
+ }, []);
973
+ };
974
+ const generateModalRoutes = (files) => {
975
+ return Object.keys(files).reduce((modals, key) => {
976
+ var _a;
977
+ const path = key
978
+ .replace(...patterns.route)
979
+ .replace(/\+|\(\w+\)\//g, '')
980
+ .replace(/(\/)?index/g, '')
981
+ .replace(/\./g, '/');
982
+ return Object.assign(Object.assign({}, modals), { [`/${path}`]: (_a = files[key]) === null || _a === void 0 ? void 0 : _a.default });
983
+ }, {});
984
+ };
985
+
912
986
  const makeCSSValue = (k, v, o) => {
913
987
  let ignore = cssPropsIgnore.indexOf(o) == -1;
914
988
  if (k in cssPropsDirect && ignore == true) {
@@ -1349,4 +1423,4 @@ const Header = forwardRef((props, ref) => {
1349
1423
  return (jsx(Fragment, { children: buildComponent(data) }));
1350
1424
  });
1351
1425
 
1352
- export { App, Component as Block, Box, Button, Checkbox, ContextMenu, Cover, Form, Header, Heading, Icon, Image, Input, Placeholder, AppProvider as Provider, Select, Spacer, Spinner, Text, Toaster, Tweet, addProps, addScript, buildCSS, buildFormData, byId, byName, createSlice, el, filterHTMLProps, filterStyleProps, getCookie, getUriParams, grab, isEmail, isIPv4, isUrl, randstr, removeCookie, rgb2hex, setCSSVar, setCookie, shuffleArray, ucfirst, useDevice, useDispatch, useImage, useResizeObserver, useStore, useTheme, useToast, uuid };
1426
+ export { App, Component as Block, Box, Button, Checkbox, ContextMenu, Cover, Form, Header, Heading, Icon, Image, Input, Placeholder, AppProvider as Provider, Select, Spacer, Spinner, Text, Toaster, Tweet, addProps, addScript, buildCSS, buildFormData, byId, byName, createSlice, el, filterHTMLProps, filterStyleProps, generateModalRoutes, generatePreservedRoutes, generateRegularRoutes, getCookie, getUriParams, grab, isEmail, isIPv4, isUrl, randstr, removeCookie, rgb2hex, setCSSVar, setCookie, shuffleArray, ucfirst, useDevice, useDispatch, useImage, useResizeObserver, useStore, useTheme, useToast, uuid };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zuzjs/ui",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -34,12 +34,14 @@
34
34
  "devDependencies": {
35
35
  "@rollup/plugin-commonjs": "^24.0.1",
36
36
  "postcss": "^8.4.21",
37
+ "react-router-dom": "^6.14.2",
37
38
  "rimraf": "^4.4.1",
38
39
  "rollup": "^3.20.2",
39
40
  "rollup-plugin-livereload": "^2.0.5",
40
41
  "rollup-plugin-scss": "^4.0.0",
41
42
  "rollup-plugin-typescript2": "^0.34.1",
42
43
  "rollup-plugin-uglify": "^6.0.4",
43
- "sass": "^1.60.0"
44
+ "sass": "^1.60.0",
45
+ "vite-plugin-environment": "^1.1.3"
44
46
  }
45
47
  }
File without changes
@@ -0,0 +1,29 @@
1
+ import { UNDO } from './undo'
2
+ import { REDO } from './redo'
3
+ import { RESET } from './reset'
4
+
5
+ export const ADD_FORM = (name, fields, forms) => ({
6
+ forms: {
7
+ ...forms,
8
+ [name] : { touched: false, loading: false, ...fields }
9
+ }
10
+ })
11
+
12
+ export const UPDATE_FORM_FIELD = (formName, field, value, forms) => {
13
+ if(forms[formName]){
14
+ let _forms = {
15
+ ...forms
16
+ }
17
+ _forms[formName][field] = value;
18
+ return {
19
+ forms: _forms
20
+ }
21
+ }
22
+ return {}
23
+ }
24
+
25
+ export {
26
+ UNDO,
27
+ REDO,
28
+ RESET
29
+ }
@@ -0,0 +1 @@
1
+ export const REDO = 'REDO';
@@ -0,0 +1 @@
1
+ export const RESET = 'RESET';
@@ -0,0 +1 @@
1
+ export const UNDO = 'UNDO';
@@ -0,0 +1,34 @@
1
+ import {
2
+ forwardRef,
3
+ useEffect
4
+ } from 'react';
5
+ import { setCSSVar, buildCSS } from '../core'
6
+ import { Provider } from '../context'
7
+ import { ClassNames } from '@emotion/react'
8
+ import { useStore } from '../hooks'
9
+
10
+ const AppMain = forwardRef((props : { [ key: string ] : any }, ref) => {
11
+
12
+ // const { dispatch } = useStore()
13
+
14
+ // if("theme" in props && !theme){
15
+ // dispatch(setTheme(props.theme));
16
+ // }
17
+
18
+ return (
19
+ <ClassNames>
20
+ {({ 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>}
21
+ </ClassNames>
22
+ )
23
+ })
24
+
25
+ const App = forwardRef((props : { [ key: string ] : any }, ref) => {
26
+
27
+ return (
28
+ <Provider>
29
+ <AppMain />
30
+ </Provider>
31
+ )
32
+ })
33
+
34
+ export default App
@@ -0,0 +1,23 @@
1
+ import {
2
+ forwardRef,
3
+ useEffect
4
+ } from 'react';
5
+ import { ClassNames } from '@emotion/react'
6
+ import { buildCSS } from '../core'
7
+
8
+ const Box = forwardRef((props : { [ key: string ] : any }, ref) => {
9
+
10
+ const _noClick = () => {}
11
+
12
+ return (
13
+ <ClassNames>
14
+ {({ css, cx }) => <div
15
+ id={props.id || undefined}
16
+ onClick={props.onClick || _noClick}
17
+ className={`${props.as ? `${props.as} ` : ``}${cx(css`${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`}
18
+ ref={props.bref || ref}>{props.html ? <span dangerouslySetInnerHTML={{ __html: props.html }} /> : props.children}</div>}
19
+ </ClassNames>
20
+ )
21
+ })
22
+
23
+ export default Box;
@@ -0,0 +1,45 @@
1
+ import React, {
2
+ forwardRef,
3
+ LegacyRef
4
+ } from 'react';
5
+ import { ClassNames } from '@emotion/react'
6
+ import {
7
+ buildCSS,
8
+ filterStyleProps
9
+ } from '../core'
10
+ import { useStore } from '../hooks'
11
+ import { STORE_FORM_KEY } from '../context/AppProvider'
12
+ const Button = forwardRef((props: { [ key: string ] : any }, ref : LegacyRef<HTMLButtonElement>) => {
13
+
14
+ const { forms } = useStore(state => state[STORE_FORM_KEY], false);
15
+ const _otherProps = {}
16
+ if(props.html){
17
+ _otherProps['dangerouslySetInnerHTML'] = { __html: props.html }
18
+ }
19
+
20
+ return (
21
+ <ClassNames>
22
+ {({ css, cx }) => {
23
+ return (
24
+ <button
25
+ title={"title" in props ? props.title : undefined}
26
+ type={props.type}
27
+ className={`button${props.as ? ` ${props.as}` : ``} ${cx(css`
28
+ padding: 5px 10px;
29
+ border-radius: 2px;
30
+ ${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`}
31
+ ref={ref}
32
+ onClick={e => {
33
+ if(props.form && props.type && props.type == 'submit'){
34
+ props.onSubmit(forms[props.form]);
35
+ }else{
36
+ props.onClick ? props.onClick(e) : () => console.warn('onClick Missing')
37
+ }
38
+ }} disabled={props.disabled || false} >{props.html ? <span dangerouslySetInnerHTML={{ __html: props.html }} /> : props.children}</button>
39
+ )
40
+ }}
41
+ </ClassNames>
42
+ )
43
+ })
44
+
45
+ export default Button;
@@ -0,0 +1,74 @@
1
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import PropTypes from 'prop-types'
3
+ import { nanoid } from 'nanoid'
4
+ import Box from './box'
5
+ import Button from './button'
6
+ import useTheme from '../hooks/useTheme'
7
+ import useDispatch from '../hooks/useDispatch'
8
+ import useStore from '../hooks/useStore'
9
+ import { STORE_FORM_KEY } from '../context/AppProvider'
10
+ import {
11
+ UPDATE_FORM_FIELD
12
+ } from '../actions'
13
+ import { ClassNames } from '@emotion/react'
14
+
15
+ function Checkbox(props) {
16
+
17
+ const {
18
+ checked,
19
+ as,
20
+ name,
21
+ form,
22
+ touched,
23
+ onChange
24
+ } = props;
25
+
26
+ const [_checked, setChecked] = useState(checked || false)
27
+ const theme = useTheme();
28
+
29
+ const dispatch = useDispatch(STORE_FORM_KEY)
30
+ const { forms } = useStore(state => state[STORE_FORM_KEY], false)
31
+
32
+ const switchCheck = useCallback(() => {
33
+ let nextVal = !_checked;
34
+ onChange && onChange(nextVal)
35
+ setChecked(nextVal)
36
+ dispatch( dispatch( UPDATE_FORM_FIELD( form || 'orphan', name, nextVal, forms ) ) );
37
+ }, [_checked])
38
+
39
+ const defaultCSS = `cursor: pointer;&:before {
40
+ background: ${!_checked ? `transparent` : theme.color} !important;
41
+ }`
42
+
43
+ const _name = useMemo(() => name || nanoid(), [name])
44
+
45
+ return (
46
+ <ClassNames>
47
+ {({ css, cx }) => <>
48
+ <input
49
+ onChange={switchCheck}
50
+ id={`zuz${_name}`}
51
+ // className={`${_checked ? 'y' : 'n'} ${as ? ` ${as} ` : ``}f ${cx(css`opacity: 0;position: absolute;&:checked {${defaultCSSChecked}}`)}`}
52
+ className={`zuz-checkbox`}
53
+ name={_name}
54
+ type={`checkbox`}
55
+ value={`checked`}
56
+ />
57
+ <label
58
+ className={`${as ? `${as} ` : ``}f ${cx(css`${defaultCSS}`)}`}
59
+ htmlFor={`zuz${_name}`} />
60
+ </>}
61
+ </ClassNames>
62
+ // <Button
63
+ // overflow={`hidden`}
64
+ // name={name || nanoid()}
65
+ // onClick={switchCheck}
66
+ // w={38} h={22} r={20} bg={`#ddd`} rel>
67
+ // <Box w={38} h={22} anim={`0.2`} abs top={0} r={20} left={0} transform={`translateX(${_checked ? 0 : -16}px)`} bg={theme.color}>
68
+ // <Box w={18} h={18} abs right={2} top={2} bg={`#fff`} r={20} boxShadow={`0px 0px 0px 5px ${_checked ? theme.color : `#ddd`}`} />
69
+ // </Box>
70
+ // </Button>
71
+ );
72
+ }
73
+
74
+ export default Checkbox;
@@ -0,0 +1,32 @@
1
+ import React, {
2
+ forwardRef
3
+ } from 'react';
4
+ import styled from '@emotion/styled'
5
+ import { css } from '@emotion/react'
6
+ import {
7
+ buildCSS,
8
+ filterHTMLProps
9
+ } from '../core'
10
+
11
+ // const CoreBlock = styled.section`display: block;`
12
+ // const buildComponent = (props: any) => Block.withComponent(props.for || `div`)`${buildCSS(props)}`
13
+
14
+ const Component = forwardRef((props: any, ref: any) => {
15
+
16
+ const Tag = props.for;
17
+ const Block = (
18
+ typeof props.for == 'string' ?
19
+ styled[props.for || `div`] : Tag
20
+ )`${buildCSS(props)}`;
21
+ // const Block = styled.`${buildCSS(props)}`;
22
+ // const Block = CoreBlock.withComponent(props.for)`background: red`
23
+ // console.log(props)
24
+ // console.log(Styles)
25
+
26
+
27
+ // return <button>{props.children}</button>
28
+ return <Block className={props.as || ``} {...filterHTMLProps(props)} />
29
+
30
+ })
31
+
32
+ export default Component;
@@ -0,0 +1,43 @@
1
+ import {
2
+ FC,
3
+ LegacyRef,
4
+ forwardRef,
5
+ useRef,
6
+ SyntheticEvent,
7
+ } from 'react';
8
+ import Box from './box'
9
+ import Button from './button'
10
+
11
+ const ContextMenu = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTMLHeadingElement>) => {
12
+
13
+ const {
14
+ as,
15
+ size,
16
+ color,
17
+ hover,
18
+ pos,
19
+ items
20
+ } = props;
21
+
22
+ return (
23
+ <Box
24
+ hover={hover || {}}
25
+ flex
26
+ fixed
27
+ top={pos?.y || 0}
28
+ left={pos?.x || 0}
29
+ bref={ref}
30
+ as={`contextmenu-${as}`}
31
+ ai={`c`}
32
+ jc={`c`}
33
+ size={size || 24}
34
+ color={color || `#111111`}
35
+ >
36
+ {items && items.map((m, i) => <Button
37
+ key={`cm-${i}-${m.id}`}
38
+ onClick={m.on ? m.on : () => {}}>{m.label}</Button>)}
39
+ </Box>
40
+ )
41
+ })
42
+
43
+ export default ContextMenu;
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import Box from './box'
3
+ import Spinner from './spinner'
4
+ import Heading from './heading'
5
+ import PropTypes from 'prop-types'
6
+
7
+ const Cover = (props) => {
8
+
9
+ return (
10
+ <Box key={`cover-cloud`} abs fill
11
+ bgFilter={props.backdrop ? `saturate(${props.backdrop.saturate}%) blur(${props.backdrop.blur}px)` : undefined}
12
+ zIndex={`2`}
13
+ bg={props.bg}>
14
+ <Box key={`cover-shadow`} abs abc aic jcc flex dir={`cols`} gap={20}>
15
+ <Spinner key={`cover-spinner`} />
16
+ {props.label && <Heading key={`cover-label`} size={16} as={`f`} opacity={0.7}>{props.label}</Heading>}
17
+ </Box>
18
+ </Box>
19
+ );
20
+ }
21
+
22
+ Cover.defaultProps = {
23
+ bg: `rgba(0,0,0,0.5)`,
24
+ backdrop: { saturate: 80, blur: 10 },
25
+ label: null
26
+ }
27
+
28
+ Cover.propTypes = {
29
+ bg: PropTypes.string,
30
+ backdrop: PropTypes.object,
31
+ label: PropTypes.string,
32
+ }
33
+
34
+ export default Cover;
@@ -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;