@zuzjs/ui 0.2.8 → 0.3.1

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/dist/index.js CHANGED
@@ -6,6 +6,8 @@ import Cookies from 'js-cookie';
6
6
  import axios from 'axios';
7
7
  import { nanoid } from 'nanoid';
8
8
  import { ClassNames } from '@emotion/react';
9
+ import ReactDOM from 'react-dom/client';
10
+ export { Link } from 'react-router-dom';
9
11
  import styled from '@emotion/styled';
10
12
 
11
13
  const AppContext = createContext({});
@@ -59,25 +61,27 @@ class AppTheme {
59
61
  _AppTheme_darkTheme.set(this, void 0);
60
62
  this.get = () => {
61
63
  let self = this;
62
- // if(self.#mode === "auto"){
63
- // window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
64
- // self.#mode = event.matches ? "dark" : "light";
65
- // self.#listen(self.#mode);
66
- // });
67
- // return window.matchMedia &&
68
- // window.matchMedia('(prefers-color-scheme: dark)').matches ?
69
- // self.#darkTheme : self.#lightTheme;
70
- // }else
71
- if (__classPrivateFieldGet(self, _AppTheme_mode, "f") === "light") {
72
- return __classPrivateFieldGet(self, _AppTheme_lightTheme, "f");
64
+ if (__classPrivateFieldGet(self, _AppTheme_mode, "f") === "auto") {
65
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
66
+ __classPrivateFieldSet(self, _AppTheme_mode, event.matches ? "dark" : "light", "f");
67
+ __classPrivateFieldGet(self, _AppTheme_listen, "f").call(self, __classPrivateFieldGet(self, _AppTheme_mode, "f"));
68
+ });
69
+ return window.matchMedia &&
70
+ window.matchMedia('(prefers-color-scheme: dark)').matches ?
71
+ __classPrivateFieldGet(self, _AppTheme_darkTheme, "f") : __classPrivateFieldGet(self, _AppTheme_lightTheme, "f");
73
72
  }
74
- else if (__classPrivateFieldGet(self, _AppTheme_mode, "f") === "dark") {
75
- return __classPrivateFieldGet(self, _AppTheme_darkTheme, "f");
73
+ else {
74
+ if (__classPrivateFieldGet(self, _AppTheme_mode, "f") === "light") {
75
+ return __classPrivateFieldGet(self, _AppTheme_lightTheme, "f");
76
+ }
77
+ else if (__classPrivateFieldGet(self, _AppTheme_mode, "f") === "dark") {
78
+ return __classPrivateFieldGet(self, _AppTheme_darkTheme, "f");
79
+ }
76
80
  }
77
81
  };
78
82
  const conf = _conf || {};
79
83
  __classPrivateFieldSet(this, _AppTheme_listen, "listen" in conf ? conf.listen : (mod) => { console.log(`Theme switched to ${mod}`); }, "f");
80
- __classPrivateFieldSet(this, _AppTheme_mode, conf.mode || "auto", "f");
84
+ __classPrivateFieldSet(this, _AppTheme_mode, conf.mode || conf.theme.mode || "auto", "f");
81
85
  __classPrivateFieldSet(this, _AppTheme_lightTheme, Object.assign({
82
86
  //CORE
83
87
  tag: "light", dark: false, primary: '#edeef5', secondary: '#f9f9f9', textColor: '#111111' }, ("theme" in conf && "light" in conf.theme ? Object.assign({}, conf.theme.light) : {})), "f");
@@ -88,6 +92,26 @@ class AppTheme {
88
92
  }
89
93
  _AppTheme_mode = new WeakMap(), _AppTheme_listen = new WeakMap(), _AppTheme_lightTheme = new WeakMap(), _AppTheme_darkTheme = new WeakMap();
90
94
 
95
+ var _AppLang_mode, _AppLang_listen, _AppLang_lang;
96
+ class AppLang {
97
+ constructor(_conf) {
98
+ _AppLang_mode.set(this, void 0);
99
+ _AppLang_listen.set(this, void 0);
100
+ _AppLang_lang.set(this, void 0);
101
+ this.get = () => {
102
+ let self = this;
103
+ return __classPrivateFieldGet(self, _AppLang_lang, "f");
104
+ };
105
+ const conf = _conf || {};
106
+ __classPrivateFieldSet(this, _AppLang_listen, "listen" in conf ? conf.listen : (mod) => { console.log(`Lang switched to ${mod}`); }, "f");
107
+ __classPrivateFieldSet(this, _AppLang_mode, conf.mode || "en", "f");
108
+ __classPrivateFieldSet(this, _AppLang_lang, Object.assign({
109
+ //CORE
110
+ tag: "en" }, ("lang" in conf ? Object.assign({}, conf.lang) : {})), "f");
111
+ }
112
+ }
113
+ _AppLang_mode = new WeakMap(), _AppLang_listen = new WeakMap(), _AppLang_lang = new WeakMap();
114
+
91
115
  let isMounted = true;
92
116
  const STORE_KEY = `__zuzjs`;
93
117
  const STORE_FORM_KEY = `${STORE_KEY}forms`;
@@ -102,14 +126,14 @@ const defaultState = {
102
126
  }
103
127
  };
104
128
  const rootReducer = (state, action) => (Object.assign(Object.assign({}, state), action.payload));
105
- const AppProvider = ({ children, initialState = {}, theme = {} }) => {
129
+ const AppProvider = ({ children, initialState = {}, theme = {}, lang = {} }) => {
106
130
  useEffect(() => {
107
131
  isMounted = true;
108
132
  return () => {
109
133
  isMounted = false;
110
134
  };
111
135
  }, []);
112
- const rootState = useMemo(() => (Object.assign(Object.assign(Object.assign({}, defaultState), initialState), { theme: new AppTheme({ theme }).get() })), [initialState]);
136
+ const rootState = useMemo(() => (Object.assign(Object.assign(Object.assign({}, defaultState), initialState), { theme: new AppTheme({ theme }).get(), lang: new AppLang({ lang }).get() })), [initialState]);
113
137
  const [state, _dispatch] = useReducer(rootReducer, rootState);
114
138
  const dispatch = useCallback((args) => {
115
139
  if (isMounted) {
@@ -135,12 +159,14 @@ const AppProvider = ({ children, initialState = {}, theme = {} }) => {
135
159
  };
136
160
  AppProvider.defaultProps = {
137
161
  theme: {},
162
+ lang: {},
138
163
  initialState: {},
139
164
  };
140
165
  AppProvider.propTypes = {
141
166
  children: PropTypes.node.isRequired,
142
167
  initialState: PropTypes.instanceOf(Object),
143
- theme: PropTypes.instanceOf(Object)
168
+ theme: PropTypes.instanceOf(Object),
169
+ lang: PropTypes.instanceOf(Object)
144
170
  };
145
171
 
146
172
  const createSlice = ({ name, initialState, reducers }) => {
@@ -556,14 +582,14 @@ const UPDATE_FORM_FIELD = (formName, field, value, forms) => {
556
582
  };
557
583
 
558
584
  const Input = forwardRef((props, ref) => {
559
- const { as, accept, multiple, onChange, onKeyUp, onClick, readOnly, type, tag, placeholder, name, form, touched, onSubmit, defaultValue, fref } = props;
585
+ const { as, accept, multiple, onChange, onKeyUp, onClick, readOnly, type, tag, placeholder, name, form, touched, onSubmit, value, defaultValue, fref, autoComplete } = props;
560
586
  const dispatch = useDispatch(STORE_FORM_KEY);
561
587
  const { forms } = useStore(state => state[STORE_FORM_KEY], false);
562
588
  let Tag = tag || 'input';
563
589
  const El = Tag;
564
590
  const _ref = fref || useRef();
565
591
  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);`;
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) => {
592
+ return (jsx(ClassNames, { children: ({ css, cx }) => jsx(El, Object.assign({}, cleanProps(props), { type: type || `text`, placeholder: placeholder || undefined, autoComplete: autoComplete || 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, value: value || undefined, defaultValue: defaultValue || ``, onKeyUp: (e) => {
567
593
  let k = e['keyCode'] || ['which'];
568
594
  if (El != 'textarea' && k == 13 && form && onSubmit) {
569
595
  onSubmit(forms[form]);
@@ -575,7 +601,7 @@ const Input = forwardRef((props, ref) => {
575
601
  dispatch(dispatch(UPDATE_FORM_FIELD(form || 'orphan', name, val == "" ? null : val, forms)));
576
602
  onChange && onChange(val == "" ? null : val);
577
603
  }, onClick: onClick ? onClick : () => { }, readOnly: readOnly || false, onBlur: e => {
578
- }, onFocus: e => touched == false && dispatch(UPDATE_FORM_FIELD(form || 'orphan', `touched`, true, forms)) }) }));
604
+ }, onFocus: e => touched == false && dispatch(UPDATE_FORM_FIELD(form || 'orphan', `touched`, true, forms)) })) }));
579
605
  });
580
606
 
581
607
  const Select = forwardRef((props, ref) => {
@@ -601,45 +627,70 @@ const useTheme = (mod = 'auto') => {
601
627
  return state['theme'] || {};
602
628
  };
603
629
 
604
- const useImage = (url, crossOrigin, referrerpolicy) => {
605
- const statusRef = useRef('loading');
606
- const imageRef = useRef();
607
- const [_, setStateToken] = useState(0);
608
- const oldUrl = useRef();
609
- const oldCrossOrigin = useRef();
610
- const oldReferrerPolicy = useRef();
611
- if (oldUrl.current !== url || oldCrossOrigin.current !== crossOrigin || oldReferrerPolicy.current !== referrerpolicy) {
612
- statusRef.current = 'loading';
613
- imageRef.current = undefined;
614
- oldUrl.current = url;
615
- oldCrossOrigin.current = crossOrigin;
616
- oldReferrerPolicy.current = referrerpolicy;
617
- }
618
- useLayoutEffect(function () {
619
- if (!url)
620
- return;
621
- var img = document.createElement('img');
622
- function onload() {
623
- statusRef.current = 'loaded';
624
- imageRef.current = img;
625
- setStateToken(Math.random());
626
- }
627
- function onerror() {
628
- statusRef.current = 'failed';
629
- imageRef.current = undefined;
630
- setStateToken(Math.random());
631
- }
632
- img.addEventListener('load', onload);
633
- img.addEventListener('error', onerror);
634
- crossOrigin && (img.crossOrigin = crossOrigin);
635
- referrerpolicy && (img.referrerPolicy = referrerpolicy);
636
- img.src = url;
637
- return function cleanup() {
638
- img.removeEventListener('load', onload);
639
- img.removeEventListener('error', onerror);
630
+ const removeBlankArrayElements = (a) => a.filter((x) => x);
631
+ const stringToArray = (x) => (Array.isArray(x) ? x : [x]);
632
+ const cache = {};
633
+ // sequential map.find for promises
634
+ const promiseFind = (arr, promiseFactory) => {
635
+ let done = false;
636
+ return new Promise((resolve, reject) => {
637
+ const queueNext = (src) => {
638
+ return promiseFactory(src).then(() => {
639
+ done = true;
640
+ resolve(src);
641
+ });
640
642
  };
641
- }, [url, crossOrigin, referrerpolicy]);
642
- return [imageRef.current, statusRef.current];
643
+ arr
644
+ .reduce((p, src) => {
645
+ // ensure we aren't done before enqueuing the next source
646
+ return p.catch(() => {
647
+ if (!done)
648
+ return queueNext(src);
649
+ });
650
+ }, queueNext(arr.shift()))
651
+ .catch(reject);
652
+ });
653
+ };
654
+ const useImage = ({ srcList, imgPromise = imgPromiseFactory({ decode: true }), useSuspense = true, }) => {
655
+ const [, setIsSettled] = useState(false);
656
+ const sourceList = removeBlankArrayElements(stringToArray(srcList));
657
+ const sourceKey = sourceList.join('');
658
+ if (!cache[sourceKey]) {
659
+ // create promise to loop through sources and try to load one
660
+ cache[sourceKey] = {
661
+ promise: promiseFind(sourceList, imgPromise),
662
+ cache: 'pending',
663
+ error: null,
664
+ };
665
+ }
666
+ // when promise resolves/reject, update cache & state
667
+ if (cache[sourceKey].cache === 'resolved') {
668
+ return { src: cache[sourceKey].src, isLoading: false, error: null };
669
+ }
670
+ if (cache[sourceKey].cache === 'rejected') {
671
+ if (useSuspense)
672
+ throw cache[sourceKey].error;
673
+ return { isLoading: false, error: cache[sourceKey].error, src: undefined };
674
+ }
675
+ cache[sourceKey].promise
676
+ // if a source was found, update cache
677
+ // when not using suspense, update state to force a rerender
678
+ .then((src) => {
679
+ cache[sourceKey] = Object.assign(Object.assign({}, cache[sourceKey]), { cache: 'resolved', src });
680
+ if (!useSuspense)
681
+ setIsSettled(sourceKey);
682
+ })
683
+ // if no source was found, or if another error occurred, update cache
684
+ // when not using suspense, update state to force a rerender
685
+ .catch((error) => {
686
+ cache[sourceKey] = Object.assign(Object.assign({}, cache[sourceKey]), { cache: 'rejected', error });
687
+ if (!useSuspense)
688
+ setIsSettled(sourceKey);
689
+ });
690
+ // cache[sourceKey].cache === 'pending')
691
+ if (useSuspense)
692
+ throw cache[sourceKey].promise;
693
+ return { isLoading: true, src: undefined, error: null };
643
694
  };
644
695
 
645
696
  /** External Dependencies */
@@ -799,13 +850,14 @@ const useDevice = (config, defaultBreakpoint, hydrateInitial = true) => {
799
850
  return currentBreakpoint;
800
851
  };
801
852
 
802
- var _Toaster_container, _Toaster_startTop, _Toaster_tout, _Toaster_defaultTimeLeft;
853
+ var _Toaster_container, _Toaster_startTop, _Toaster_tout, _Toaster_defaultTimeLeft, _Toaster_root;
803
854
  class Toaster {
804
855
  constructor(config) {
805
856
  _Toaster_container.set(this, void 0);
806
857
  _Toaster_startTop.set(this, void 0);
807
858
  _Toaster_tout.set(this, void 0);
808
859
  _Toaster_defaultTimeLeft.set(this, void 0);
860
+ _Toaster_root.set(this, void 0);
809
861
  this.show = (message, duration) => {
810
862
  let self = this;
811
863
  self.toast({
@@ -816,12 +868,13 @@ class Toaster {
816
868
  __classPrivateFieldSet(this, _Toaster_startTop, 20, "f");
817
869
  __classPrivateFieldSet(this, _Toaster_defaultTimeLeft, 4, "f");
818
870
  const rootID = (config === null || config === void 0 ? void 0 : config.root) || `toast-container`;
819
- if (document.querySelector(`#${rootID}`))
871
+ __classPrivateFieldSet(this, _Toaster_root, rootID, "f");
872
+ if (window.document.querySelector(`#${rootID}`))
820
873
  return;
821
- var root = document.createElement('div');
874
+ var root = window.document.createElement('div');
822
875
  root.id = rootID;
823
- document.body.appendChild(root);
824
- __classPrivateFieldSet(this, _Toaster_container, document.querySelector(`#${rootID}`), "f");
876
+ window.document.body.appendChild(root);
877
+ __classPrivateFieldSet(this, _Toaster_container, window.document.querySelector(`#${rootID}`), "f");
825
878
  }
826
879
  dismiss(ID) {
827
880
  let self = this;
@@ -841,7 +894,7 @@ class Toaster {
841
894
  }
842
895
  toast(config) {
843
896
  var self = this;
844
- var ID = 'toast-' + nanoid(), toast = document.createElement('div'); document.createElement('div');
897
+ var ID = 'toast-' + nanoid(), toast = window.document.createElement('div'); window.document.createElement('div');
845
898
  toast.id = ID;
846
899
  toast.style.backgroundColor = `#111`;
847
900
  toast.style.color = `#fff`;
@@ -856,7 +909,7 @@ class Toaster {
856
909
  toast.classList.add('fixed');
857
910
  toast.classList.add('f');
858
911
  toast.innerHTML = config.message || `You haven't passed "message" in this toast`;
859
- __classPrivateFieldGet(self, _Toaster_container, "f").appendChild(toast);
912
+ (__classPrivateFieldGet(self, _Toaster_container, "f") || window.document.querySelector(`#${__classPrivateFieldGet(self, _Toaster_root, "f")}`)).appendChild(toast);
860
913
  self.arrangeToasts()
861
914
  .then(() => {
862
915
  setTimeout(() => {
@@ -883,20 +936,93 @@ class Toaster {
883
936
  });
884
937
  }
885
938
  }
886
- _Toaster_container = new WeakMap(), _Toaster_startTop = new WeakMap(), _Toaster_tout = new WeakMap(), _Toaster_defaultTimeLeft = new WeakMap();
939
+ _Toaster_container = new WeakMap(), _Toaster_startTop = new WeakMap(), _Toaster_tout = new WeakMap(), _Toaster_defaultTimeLeft = new WeakMap(), _Toaster_root = new WeakMap();
887
940
 
888
941
  const useToast = () => {
889
942
  const toaster = useMemo(() => new Toaster(), []);
890
943
  return toaster;
891
944
  };
892
945
 
946
+ const useLang = (mod = 'en') => {
947
+ const state = useContext(AppContext);
948
+ return state['lang'] || {};
949
+ };
950
+
951
+ const Box = forwardRef((props, ref) => {
952
+ const _noClick = () => { };
953
+ // console.log(props)
954
+ return (jsx(ClassNames, { children: ({ css, cx }) => jsx("div", Object.assign({}, cleanProps(props), { title: props.title || undefined, id: props.id || undefined, onClick: props.onClick || _noClick, className: `${props.as ? `${props.as} ` : ``}${cx(css `${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`, ref: props.bref || ref }, { children: props.html ? jsx("span", { dangerouslySetInnerHTML: { __html: props.html } }) : props.children })) }));
955
+ });
956
+
957
+ const useContextMenu = (contextID) => {
958
+ const ID = `context-${contextID}`;
959
+ useState(false);
960
+ const [root, setRoot] = useState(null);
961
+ const nodeRef = useRef(null);
962
+ const el = (e) => window.document.createElement(e);
963
+ function checkBoundaries(x, y) {
964
+ if (nodeRef.current) {
965
+ const { innerWidth, innerHeight } = window;
966
+ const { offsetWidth, offsetHeight } = nodeRef.current;
967
+ if (x + offsetWidth > innerWidth)
968
+ x -= x + offsetWidth - innerWidth;
969
+ if (y + offsetHeight > innerHeight)
970
+ y -= y + offsetHeight - innerHeight;
971
+ }
972
+ return { x, y };
973
+ }
974
+ const hide = () => {
975
+ try {
976
+ root === null || root === void 0 ? void 0 : root.unmount();
977
+ setRoot(null);
978
+ }
979
+ catch (e) { }
980
+ };
981
+ const Menu = (e, items) => {
982
+ const p = getMousePosition(e);
983
+ const { x, y } = checkBoundaries(p.x, p.y);
984
+ return (jsx(Box, Object.assign({ bref: nodeRef, flex: true, dir: `cols`, fixed: true, top: y, left: x, as: `zuz-contextmenu ${ID}` }, { children: items && items.map((m, i) => m.id == `line` ? jsx(Box, { as: `line` }, `line-${i}-${m.id}`) : jsx("button", Object.assign({ onClick: ev => {
985
+ if (m.onClick) {
986
+ m.onClick(ev, m);
987
+ }
988
+ else {
989
+ console.log(`No onClick eventFound`);
990
+ }
991
+ hide();
992
+ } }, { children: m.label }), `cm-${i}-${m.id}`)) })));
993
+ };
994
+ const show = (e, items) => {
995
+ e.preventDefault();
996
+ e.stopPropagation();
997
+ if (!window.document.querySelector(`#context-${contextID}`)) {
998
+ let div = el(`div`);
999
+ div.id = ID;
1000
+ window.document.body.appendChild(div);
1001
+ }
1002
+ root.render(Menu(e, items));
1003
+ };
1004
+ useEffect(() => {
1005
+ if (!window.document.querySelector(`#context-${contextID}`)) {
1006
+ let div = el(`div`);
1007
+ div.id = ID;
1008
+ window.document.body.appendChild(div);
1009
+ }
1010
+ if (!root)
1011
+ setRoot(ReactDOM.createRoot(document.getElementById(ID)));
1012
+ }, [root]);
1013
+ return {
1014
+ show,
1015
+ hide
1016
+ };
1017
+ };
1018
+
893
1019
  const Button = forwardRef((props, ref) => {
894
1020
  const { forms } = useStore(state => state[STORE_FORM_KEY], false);
895
1021
  if (props.html) {
896
1022
  ({ __html: props.html });
897
1023
  }
898
1024
  return (jsx(ClassNames, { children: ({ css, cx }) => {
899
- return (jsx("button", Object.assign({ title: "title" in props ? props.title : undefined, type: props.type, className: `button${props.as ? ` ${props.as}` : ``} ${cx(css `
1025
+ return (jsx("button", Object.assign({}, cleanProps(props), { title: "title" in props ? props.title : undefined, type: props.type, className: `button${props.as ? ` ${props.as}` : ``} ${cx(css `
900
1026
  padding: 5px 10px;
901
1027
  border-radius: 2px;
902
1028
  ${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`, ref: ref, onClick: e => {
@@ -1001,6 +1127,17 @@ const makeCSSValue = (k, v, o) => {
1001
1127
  }
1002
1128
  return `${k}:${v}${unit};`;
1003
1129
  };
1130
+ const cleanProps = (props) => {
1131
+ let _props = Object.assign({}, props);
1132
+ Object.keys(_props).map(k => {
1133
+ if (k in cssProps) {
1134
+ delete _props[k];
1135
+ }
1136
+ });
1137
+ let _extras = [`as`, `hover`, `bref`];
1138
+ _extras.map(x => x in _props && delete _props[x]);
1139
+ return _props;
1140
+ };
1004
1141
  const buildCSS = (props) => {
1005
1142
  let css = ``;
1006
1143
  Object.keys(props).map(k => {
@@ -1037,7 +1174,7 @@ const randstr = function (len) {
1037
1174
  }
1038
1175
  return text;
1039
1176
  };
1040
- const setCookie = (key, value, expiry) => Cookies.set(key, value, { expires: expiry || 7 });
1177
+ const setCookie = (key, value, expiry, host) => Cookies.set(key, value, { expires: expiry || 7, domain: host || window.location.host });
1041
1178
  const getCookie = (key) => Cookies.get(key) || null;
1042
1179
  const removeCookie = (key) => Cookies.remove(key);
1043
1180
  const buildFormData = (data) => {
@@ -1190,6 +1327,53 @@ const getUriParams = () => {
1190
1327
  return xny;
1191
1328
  };
1192
1329
  const rgb2hex = rgb => `#${rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/).slice(1).map(n => parseInt(n, 10).toString(16).padStart(2, '0')).join('')}`;
1330
+ const getHostname = url => {
1331
+ if (window.URL) {
1332
+ let u = new window.URL(url);
1333
+ return u.hostname;
1334
+ }
1335
+ else {
1336
+ var a = document.createElement(`a`);
1337
+ a.href = url;
1338
+ return a.hostname.replace("www.", "");
1339
+ }
1340
+ };
1341
+ const imgPromiseFactory = ({ decode = true, crossOrigin = '' }) => (src) => {
1342
+ return new Promise((resolve, reject) => {
1343
+ const i = new Image();
1344
+ if (crossOrigin)
1345
+ i.crossOrigin = crossOrigin;
1346
+ i.onload = () => {
1347
+ decode && i.decode ? i.decode().then(resolve).catch(reject) : resolve();
1348
+ };
1349
+ i.onerror = reject;
1350
+ i.src = src;
1351
+ });
1352
+ };
1353
+ const parseFilename = nm => {
1354
+ var re = /(?:\.([^.]+))?$/;
1355
+ return {
1356
+ name: nm.split('.').slice(0, -1).join('.'),
1357
+ ext: re.exec(nm)[1]
1358
+ };
1359
+ };
1360
+ const camelCase = str => str.replace(":", "-").replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
1361
+ const getMousePosition = e => {
1362
+ const pos = {
1363
+ x: e.clientX,
1364
+ y: e.clientY,
1365
+ };
1366
+ const touch = e.changedTouches;
1367
+ if (touch) {
1368
+ pos.x = touch[0].clientX;
1369
+ pos.y = touch[0].clientY;
1370
+ }
1371
+ if (!pos.x || pos.x < 0)
1372
+ pos.x = 0;
1373
+ if (!pos.y || pos.y < 0)
1374
+ pos.y = 0;
1375
+ return pos;
1376
+ };
1193
1377
 
1194
1378
  const AppMain = forwardRef((props, ref) => {
1195
1379
  // const { dispatch } = useStore()
@@ -1202,11 +1386,6 @@ const App = forwardRef((props, ref) => {
1202
1386
  return (jsx(AppProvider, { children: jsx(AppMain, {}) }));
1203
1387
  });
1204
1388
 
1205
- const Box = forwardRef((props, ref) => {
1206
- const _noClick = () => { };
1207
- return (jsx(ClassNames, { children: ({ css, cx }) => jsx("div", Object.assign({ id: props.id || undefined, onClick: props.onClick || _noClick, className: `${props.as ? `${props.as} ` : ``}${cx(css `${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`, ref: props.bref || ref }, { children: props.html ? jsx("span", { dangerouslySetInnerHTML: { __html: props.html } }) : props.children })) }));
1208
- });
1209
-
1210
1389
  // const CoreBlock = styled.section`display: block;`
1211
1390
  // const buildComponent = (props: any) => Block.withComponent(props.for || `div`)`${buildCSS(props)}`
1212
1391
  const Component = forwardRef((props, ref) => {
@@ -1338,9 +1517,18 @@ const Icon = forwardRef((props, ref) => {
1338
1517
  return (jsx(Box, Object.assign({ hover: hover || {}, flex: true, bref: ref, as: `icon-${as}`, ai: `c`, jc: `c`, size: size || 24, color: color || `#111111` }, { children: path && Array(path).fill(undefined).map((p, i) => jsx("span", { className: `path${i + 1}` }, `ico-${as}-${i}`)) })));
1339
1518
  });
1340
1519
 
1341
- const Image = forwardRef((props, ref) => {
1342
- const [photo, status] = useImage(props.src, 'anonymous', 'origin');
1343
- return (jsx(ClassNames, { children: ({ css, cx }) => jsxs("picture", Object.assign({ className: cx(css `${buildCSS({ flex: true })}`) }, { children: [status == 'loading' && jsx(Box, { className: `${props.as ? `${props.as} ` : ``}${cx(css `background: #eee;${buildCSS(props)}`)}` }), status == 'loaded' && jsx("img", { src: props.src, className: `${props.as ? `${props.as} ` : ``}${cx(css `${buildCSS(props)}`)}`, ref: ref })] })) }));
1520
+ const Image$1 = forwardRef((props, ref) => {
1521
+ const { src, isLoading, error } = useImage({ srcList: props.src, useSuspense: false });
1522
+ return (jsx(ClassNames, { children: ({ css, cx }) => jsxs(Fragment, { children: [isLoading && jsx(Box, { className: `${props.as ? `${props.as} ` : ``}${cx(css `background: #eee;${buildCSS(props)}`)}` }), !isLoading && jsx("img", { src: src, className: `${props.as ? `${props.as} ` : ``}${cx(css `${buildCSS(props)}`)}`, ref: ref })] }) })
1523
+ // <ClassNames>
1524
+ // {({ css, cx }) => <picture className={cx(css`${buildCSS({ flex: true })}`)}>
1525
+ // {status == 'loading' && <Box className={`${props.as ? `${props.as} ` : ``}${cx(css`background: #eee;${buildCSS(props)}`)}`} />}
1526
+ // {status == 'loaded' && <img src={props.src}
1527
+ // className={`${props.as ? `${props.as} ` : ``}${cx(css`${buildCSS(props)}`)}`}
1528
+ // ref={ref} />}
1529
+ // </picture>}
1530
+ // </ClassNames>
1531
+ );
1344
1532
  });
1345
1533
 
1346
1534
  const DEFAULT_COLUMNS = 2;
@@ -1528,7 +1716,7 @@ const Tweet = (props) => {
1528
1716
 
1529
1717
  const ContextMenu = forwardRef((props, ref) => {
1530
1718
  const { as, size, color, hover, pos, items } = props;
1531
- return (jsx(Box, Object.assign({ hover: hover || {}, flex: true, fixed: true, top: (pos === null || pos === void 0 ? void 0 : pos.y) || 0, left: (pos === null || pos === void 0 ? void 0 : pos.x) || 0, bref: ref, as: `contextmenu-${as}`, ai: `c`, jc: `c`, size: size || 24, color: color || `#111111` }, { children: items && items.map((m, i) => jsx(Button, Object.assign({ onClick: m.on ? m.on : () => { } }, { children: m.label }), `cm-${i}-${m.id}`)) })));
1719
+ return (jsx(Box, Object.assign({ hover: hover || {}, flex: true, dir: `cols`, fixed: true, top: (pos === null || pos === void 0 ? void 0 : pos.y) || 0, left: (pos === null || pos === void 0 ? void 0 : pos.x) || 0, bref: ref, as: `contextmenu-${as}`, size: size || 24, color: color || `#111111` }, { children: items && items.map((m, i) => jsx(Button, Object.assign({ onClick: m.on ? m.on : () => { } }, { children: m.label }), `cm-${i}-${m.id}`)) })));
1532
1720
  });
1533
1721
 
1534
1722
  const buildElement = (el) => {
@@ -1548,4 +1736,4 @@ const Header = forwardRef((props, ref) => {
1548
1736
  return (jsx(Fragment, { children: buildComponent(data) }));
1549
1737
  });
1550
1738
 
1551
- export { App, Component as Block, Box, Button, Checkbox, ContextMenu, Cover, Form, Header, Heading, Icon, Image, Input, Masonry, 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 };
1739
+ export { App, Component as Block, Box, Button, Checkbox, ContextMenu, Cover, Form, Header, Heading, Icon, Image$1 as Image, Input, Masonry, Placeholder, AppProvider as Provider, Select, Spacer, Spinner, Text, Toaster, Tweet, addProps, addScript, buildCSS, buildFormData, byId, byName, camelCase, cleanProps, createSlice, el, filterHTMLProps, filterStyleProps, generateModalRoutes, generatePreservedRoutes, generateRegularRoutes, getCookie, getHostname, getMousePosition, getUriParams, grab, imgPromiseFactory, isEmail, isIPv4, isUrl, parseFilename, randstr, removeCookie, rgb2hex, setCSSVar, setCookie, shuffleArray, ucfirst, useContextMenu, useDevice, useDispatch, useImage, useLang, useResizeObserver, useStore, useTheme, useToast, uuid };
package/dist/styles.css CHANGED
@@ -312,6 +312,50 @@ button {
312
312
  font-size: 72px;
313
313
  }
314
314
 
315
+ /*
316
+ BoldSize
317
+ It will generate .b400 { font-weight: 400; } from '400'
318
+ */
319
+ .bold {
320
+ font-weight: bold;
321
+ }
322
+
323
+ .b100 {
324
+ font-weight: 100;
325
+ }
326
+
327
+ .b200 {
328
+ font-weight: 200;
329
+ }
330
+
331
+ .b300 {
332
+ font-weight: 300;
333
+ }
334
+
335
+ .b400 {
336
+ font-weight: 400;
337
+ }
338
+
339
+ .b500 {
340
+ font-weight: 500;
341
+ }
342
+
343
+ .b600 {
344
+ font-weight: 600;
345
+ }
346
+
347
+ .b700 {
348
+ font-weight: 700;
349
+ }
350
+
351
+ .b800 {
352
+ font-weight: 800;
353
+ }
354
+
355
+ .b900 {
356
+ font-weight: 900;
357
+ }
358
+
315
359
  @-webkit-keyframes rotating /* Safari and Chrome */ {
316
360
  from {
317
361
  -webkit-transform: rotate(0deg);
@@ -411,4 +455,31 @@ button {
411
455
  }
412
456
  .zuz-checkbox:checked + label:after {
413
457
  left: 20px;
458
+ }
459
+
460
+ .zuz-contextmenu {
461
+ min-width: 220px;
462
+ border-radius: 5px;
463
+ padding: 4px;
464
+ background: rgba(34, 34, 34, 0.5);
465
+ border: 1px rgba(255, 255, 255, 0.25) solid;
466
+ box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.45);
467
+ backdrop-filter: blur(20px);
468
+ }
469
+ .zuz-contextmenu button {
470
+ border: 0px;
471
+ text-align: left;
472
+ padding: 4px 6px;
473
+ background: rgba(0, 0, 0, 0);
474
+ cursor: pointer;
475
+ color: #fff;
476
+ border-radius: 4px;
477
+ }
478
+ .zuz-contextmenu button:hover {
479
+ background: #385fd2;
480
+ }
481
+ .zuz-contextmenu .line {
482
+ height: 1px;
483
+ background: rgba(255, 255, 255, 0.25);
484
+ margin: 4px 6px;
414
485
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zuzjs/ui",
3
- "version": "0.2.8",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
package/src/comps/box.tsx CHANGED
@@ -3,15 +3,19 @@ import {
3
3
  useEffect
4
4
  } from 'react';
5
5
  import { ClassNames } from '@emotion/react'
6
- import { buildCSS } from '../core'
6
+ import { cleanProps, buildCSS } from '../core'
7
7
 
8
8
  const Box = forwardRef((props : { [ key: string ] : any }, ref) => {
9
9
 
10
10
  const _noClick = () => {}
11
11
 
12
+ // console.log(props)
13
+
12
14
  return (
13
15
  <ClassNames>
14
16
  {({ css, cx }) => <div
17
+ {...cleanProps(props)}
18
+ title={props.title || undefined}
15
19
  id={props.id || undefined}
16
20
  onClick={props.onClick || _noClick}
17
21
  className={`${props.as ? `${props.as} ` : ``}${cx(css`${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`}
@@ -5,7 +5,7 @@ import React, {
5
5
  import { ClassNames } from '@emotion/react'
6
6
  import {
7
7
  buildCSS,
8
- filterStyleProps
8
+ cleanProps
9
9
  } from '../core'
10
10
  import { useStore } from '../hooks'
11
11
  import { STORE_FORM_KEY } from '../context/AppProvider'
@@ -22,6 +22,7 @@ const Button = forwardRef((props: { [ key: string ] : any }, ref : LegacyRef<HTM
22
22
  {({ css, cx }) => {
23
23
  return (
24
24
  <button
25
+ {...cleanProps(props)}
25
26
  title={"title" in props ? props.title : undefined}
26
27
  type={props.type}
27
28
  className={`button${props.as ? ` ${props.as}` : ``} ${cx(css`
@@ -22,14 +22,12 @@ const ContextMenu = forwardRef((props : { [ key: string ] : any }, ref : LegacyR
22
22
  return (
23
23
  <Box
24
24
  hover={hover || {}}
25
- flex
25
+ flex dir={`cols`}
26
26
  fixed
27
27
  top={pos?.y || 0}
28
28
  left={pos?.x || 0}
29
29
  bref={ref}
30
30
  as={`contextmenu-${as}`}
31
- ai={`c`}
32
- jc={`c`}
33
31
  size={size || 24}
34
32
  color={color || `#111111`}
35
33
  >