@zuzjs/ui 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +249 -21
- package/dist/styles.css +27 -0
- package/jest.config.js +7 -0
- package/package.json +1 -1
- package/rollup.config.js +68 -0
- package/src/comps/box.tsx +6 -1
- package/src/comps/button.tsx +3 -1
- package/src/comps/contextmenu.tsx +39 -22
- package/src/comps/input.tsx +145 -7
- package/src/comps/mediaplayer.tsx +12 -0
- package/src/context/store/theme.tsx +1 -1
- package/src/core/index.ts +122 -2
- package/src/core/styles.ts +12 -1
- package/src/hooks/index.tsx +3 -1
- package/src/hooks/useContextMenu.tsx +123 -0
- package/src/hooks/useMediaPlayer.tsx +27 -0
- package/src/hooks/useNavigator.tsx +6 -0
- package/src/hooks/useRender.tsx +29 -0
- package/src/index.tsx +1 -1
- package/src/scss/style.scss +27 -0
- package/tsconfig.json +21 -0
- package/tsconfig.lib.json +9 -0
- package/tsconfig.spec.json +21 -0
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ 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';
|
|
9
10
|
export { Link } from 'react-router-dom';
|
|
10
11
|
import styled from '@emotion/styled';
|
|
11
12
|
|
|
@@ -80,7 +81,7 @@ class AppTheme {
|
|
|
80
81
|
};
|
|
81
82
|
const conf = _conf || {};
|
|
82
83
|
__classPrivateFieldSet(this, _AppTheme_listen, "listen" in conf ? conf.listen : (mod) => { console.log(`Theme switched to ${mod}`); }, "f");
|
|
83
|
-
__classPrivateFieldSet(this, _AppTheme_mode, conf.mode || "auto", "f");
|
|
84
|
+
__classPrivateFieldSet(this, _AppTheme_mode, conf.mode || conf.theme.mode || "auto", "f");
|
|
84
85
|
__classPrivateFieldSet(this, _AppTheme_lightTheme, Object.assign({
|
|
85
86
|
//CORE
|
|
86
87
|
tag: "light", dark: false, primary: '#edeef5', secondary: '#f9f9f9', textColor: '#111111' }, ("theme" in conf && "light" in conf.theme ? Object.assign({}, conf.theme.light) : {})), "f");
|
|
@@ -197,6 +198,10 @@ const cssProps = {
|
|
|
197
198
|
"ac": "align-content",
|
|
198
199
|
"alignContent": "align-content",
|
|
199
200
|
"aic": "aic",
|
|
201
|
+
"ais": "ais",
|
|
202
|
+
"aie": "aie",
|
|
203
|
+
"nous": "nous",
|
|
204
|
+
"nope": "nope",
|
|
200
205
|
"ai": "align-items",
|
|
201
206
|
"alignItems": "align-items",
|
|
202
207
|
"ass": "ass",
|
|
@@ -453,6 +458,7 @@ const cssProps = {
|
|
|
453
458
|
"wordBreak": "word-break",
|
|
454
459
|
"wordSpacing": "word-spacing",
|
|
455
460
|
"wrap": "wrap",
|
|
461
|
+
"textWrap": "textWrap",
|
|
456
462
|
"wordWrap": "word-wrap",
|
|
457
463
|
"writingMode": "writing-mode",
|
|
458
464
|
"zIndex": "z-index",
|
|
@@ -489,6 +495,8 @@ const cssPropsDirect = {
|
|
|
489
495
|
'flex': 'display: flex;',
|
|
490
496
|
'fwrap': 'flex-wrap: wrap;',
|
|
491
497
|
'aic': 'align-items: center;',
|
|
498
|
+
'ais': 'align-items: flex-start;',
|
|
499
|
+
'aie': 'align-items: flex-end;',
|
|
492
500
|
'ass': 'align-self: flex-start;',
|
|
493
501
|
'asc': 'align-self: center;',
|
|
494
502
|
'ase': 'align-self: flex-end;',
|
|
@@ -501,13 +509,17 @@ const cssPropsDirect = {
|
|
|
501
509
|
'block': 'display: block;',
|
|
502
510
|
'bold': "font-weight: bold;",
|
|
503
511
|
'wrap': "word-wrap: break-word;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 99%;",
|
|
512
|
+
'textWrap': "word-wrap: break-word;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 99%;",
|
|
504
513
|
'pointer': "cursor: pointer;",
|
|
505
514
|
'fb': 'font-family: var(--primary-font-bold);',
|
|
506
515
|
'ph': 'padding-left: __VALUE__;padding-right: __VALUE__;',
|
|
507
516
|
'pv': 'padding-bottom: __VALUE__;padding-top: __VALUE__;',
|
|
508
517
|
'mv': 'margin-bottom: __VALUE__;margin-top: __VALUE__;',
|
|
509
518
|
'mh': 'margin-left: __VALUE__;margin-right: __VALUE__;',
|
|
510
|
-
'anim': 'transition:all __VALUE__s linear 0s;'
|
|
519
|
+
'anim': 'transition:all __VALUE__s linear 0s;',
|
|
520
|
+
'nous': 'user-select: none;',
|
|
521
|
+
'nope': 'pointer-events: none;',
|
|
522
|
+
'tdn': 'text-decoration: none;',
|
|
511
523
|
};
|
|
512
524
|
const cssPropsIgnore = [
|
|
513
525
|
'weight', `opacity`
|
|
@@ -580,27 +592,44 @@ const UPDATE_FORM_FIELD = (formName, field, value, forms) => {
|
|
|
580
592
|
return {};
|
|
581
593
|
};
|
|
582
594
|
|
|
595
|
+
!!document.documentElement.currentStyle;
|
|
583
596
|
const Input = forwardRef((props, ref) => {
|
|
584
|
-
const { as, accept, multiple, onChange, onKeyUp, onClick, readOnly, type, tag, placeholder, name, form, touched, onSubmit, value, defaultValue, fref } = props;
|
|
597
|
+
const { as, accept, multiple, onChange, onKeyUp, onClick, onBlur, onFocus, readOnly, type, tag, placeholder, name, form, touched, onSubmit, value, defaultValue, fref, autoComplete, elastic, minRows, maxRows } = props;
|
|
585
598
|
const dispatch = useDispatch(STORE_FORM_KEY);
|
|
586
599
|
const { forms } = useStore(state => state[STORE_FORM_KEY], false);
|
|
587
600
|
let Tag = tag || 'input';
|
|
588
601
|
const El = Tag;
|
|
589
602
|
const _ref = fref || useRef();
|
|
590
603
|
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);`;
|
|
591
|
-
|
|
604
|
+
props.value !== undefined;
|
|
605
|
+
useRef();
|
|
606
|
+
useEffect(() => { }, []);
|
|
607
|
+
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) => {
|
|
592
608
|
let k = e['keyCode'] || ['which'];
|
|
593
|
-
if (El != 'textarea' && k == 13
|
|
609
|
+
if (form && onSubmit && El != 'textarea' && k == 13) {
|
|
594
610
|
onSubmit(forms[form]);
|
|
595
611
|
}
|
|
612
|
+
else {
|
|
613
|
+
if (onKeyUp)
|
|
614
|
+
onKeyUp(e);
|
|
615
|
+
}
|
|
596
616
|
}, onChange: e => {
|
|
597
617
|
let val = type == 'file' ?
|
|
598
618
|
e.currentTarget.files
|
|
599
619
|
: e.currentTarget.value;
|
|
600
|
-
|
|
620
|
+
if (form)
|
|
621
|
+
dispatch(dispatch(UPDATE_FORM_FIELD(form || 'orphan', name, val == "" ? null : val, forms)));
|
|
622
|
+
// if(El == `textarea` && elastic) handleElastic()
|
|
601
623
|
onChange && onChange(val == "" ? null : val);
|
|
602
624
|
}, onClick: onClick ? onClick : () => { }, readOnly: readOnly || false, onBlur: e => {
|
|
603
|
-
|
|
625
|
+
if (onBlur)
|
|
626
|
+
onBlur(e);
|
|
627
|
+
}, onFocus: e => {
|
|
628
|
+
if (touched == false)
|
|
629
|
+
dispatch(UPDATE_FORM_FIELD(form || 'orphan', `touched`, true, forms));
|
|
630
|
+
if (onFocus)
|
|
631
|
+
onFocus(e);
|
|
632
|
+
} })) }));
|
|
604
633
|
});
|
|
605
634
|
|
|
606
635
|
const Select = forwardRef((props, ref) => {
|
|
@@ -947,16 +976,128 @@ const useLang = (mod = 'en') => {
|
|
|
947
976
|
return state['lang'] || {};
|
|
948
977
|
};
|
|
949
978
|
|
|
979
|
+
const Box = forwardRef((props, ref) => {
|
|
980
|
+
const _noClick = () => { };
|
|
981
|
+
// console.log(props)
|
|
982
|
+
return (jsx(ClassNames, { children: ({ css, cx }) => jsx("div", Object.assign({}, cleanProps(props), { title: props.title || undefined, id: props.id || undefined, onDoubleClick: props.onDoubleClick || 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 })) }));
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
const Menu = ({ ID, hide, e, items, width }) => {
|
|
986
|
+
const nodeRef = useRef(null);
|
|
987
|
+
const [p, setP] = useState(getMousePosition(e));
|
|
988
|
+
const [visible, setVisible] = useState(false);
|
|
989
|
+
const checkBoundaries = (x, y) => {
|
|
990
|
+
if (nodeRef.current) {
|
|
991
|
+
const { innerWidth, innerHeight } = window;
|
|
992
|
+
const { offsetWidth, offsetHeight } = nodeRef.current;
|
|
993
|
+
if (x + offsetWidth > innerWidth)
|
|
994
|
+
x -= offsetWidth; //x + offsetWidth - innerWidth;
|
|
995
|
+
if (y + offsetHeight > innerHeight)
|
|
996
|
+
y -= offsetHeight;
|
|
997
|
+
}
|
|
998
|
+
setP({ x, y });
|
|
999
|
+
setVisible(true);
|
|
1000
|
+
};
|
|
1001
|
+
useEffect(() => {
|
|
1002
|
+
checkBoundaries(p.x, p.y);
|
|
1003
|
+
}, [e]);
|
|
1004
|
+
return (jsx(Box, Object.assign({ bref: nodeRef, flex: true, dir: `cols`, fixed: true, top: p.y, left: p.x, w: width || 220, opacity: visible ? 1 : 0, as: `zuz-contextmenu ${ID}` }, { children: items.map((m, i) => m.id == `line` ? jsx(Box, { as: `line` }, `line-${i}-${m.id}`) : jsx("button", Object.assign({ onClick: ev => {
|
|
1005
|
+
if (m.onClick) {
|
|
1006
|
+
m.onClick(ev, m);
|
|
1007
|
+
}
|
|
1008
|
+
else {
|
|
1009
|
+
console.log(`No onClick eventFound`);
|
|
1010
|
+
}
|
|
1011
|
+
hide();
|
|
1012
|
+
} }, { children: m.label }), `cm-${i}-${m.id}`)) })));
|
|
1013
|
+
};
|
|
1014
|
+
const useContextMenu = (contextID, contextWidth, contextToken = `____uchides`) => {
|
|
1015
|
+
const ID = `contextmenu-${contextID}`;
|
|
1016
|
+
useState(false);
|
|
1017
|
+
const [root, setRoot] = useState(null);
|
|
1018
|
+
const el = (e) => window.document.createElement(e);
|
|
1019
|
+
const createRoot = () => {
|
|
1020
|
+
if (!window.document.querySelector(`#${ID}`)) {
|
|
1021
|
+
let div = el(`div`);
|
|
1022
|
+
div.id = ID;
|
|
1023
|
+
window.document.body.appendChild(div);
|
|
1024
|
+
}
|
|
1025
|
+
};
|
|
1026
|
+
const hideAll = () => {
|
|
1027
|
+
if (window[contextToken]) {
|
|
1028
|
+
window[contextToken].map((h) => h['ID'] != ID && h['fnc']());
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
const _hide = () => {
|
|
1032
|
+
try {
|
|
1033
|
+
root === null || root === void 0 ? void 0 : root.unmount();
|
|
1034
|
+
document.querySelector(`#${ID}`).parentNode.removeChild(document.querySelector(`#${ID}`));
|
|
1035
|
+
setRoot(null);
|
|
1036
|
+
}
|
|
1037
|
+
catch (e) { }
|
|
1038
|
+
};
|
|
1039
|
+
const hide = () => {
|
|
1040
|
+
_hide();
|
|
1041
|
+
hideAll();
|
|
1042
|
+
};
|
|
1043
|
+
const show = (e, items) => {
|
|
1044
|
+
e.preventDefault();
|
|
1045
|
+
e.stopPropagation();
|
|
1046
|
+
hideAll();
|
|
1047
|
+
root.render(jsx(Menu, { e: e, width: contextWidth || 220, items: items, ID: ID, hide: hide }));
|
|
1048
|
+
};
|
|
1049
|
+
useEffect(() => {
|
|
1050
|
+
createRoot();
|
|
1051
|
+
if (!root)
|
|
1052
|
+
setRoot(ReactDOM.createRoot(document.getElementById(ID)));
|
|
1053
|
+
}, [root]);
|
|
1054
|
+
useEffect(() => {
|
|
1055
|
+
if (contextToken in window == false) {
|
|
1056
|
+
window[contextToken] = [];
|
|
1057
|
+
}
|
|
1058
|
+
if (window[contextToken].findIndex(x => x.ID == ID) == -1) {
|
|
1059
|
+
window[contextToken].push({ ID: ID, fnc: _hide });
|
|
1060
|
+
if (window[contextToken].length > document.querySelectorAll('div[id^="contextmenu-"]').length) {
|
|
1061
|
+
window[contextToken].shift();
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}, []);
|
|
1065
|
+
return {
|
|
1066
|
+
show,
|
|
1067
|
+
hide,
|
|
1068
|
+
hideAll
|
|
1069
|
+
};
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
const useRender = (isMounted, delay) => {
|
|
1073
|
+
const [canRender, setCanRender] = useState(false);
|
|
1074
|
+
// console.log(
|
|
1075
|
+
// `isMounted:`, isMounted,
|
|
1076
|
+
// `canRender:`, canRender,
|
|
1077
|
+
// )
|
|
1078
|
+
useEffect(() => {
|
|
1079
|
+
let outID;
|
|
1080
|
+
if (isMounted && !canRender) {
|
|
1081
|
+
setCanRender(true);
|
|
1082
|
+
}
|
|
1083
|
+
else if (isMounted && canRender) {
|
|
1084
|
+
outID = setTimeout(() => setCanRender(false), delay * 1000);
|
|
1085
|
+
}
|
|
1086
|
+
return () => clearTimeout(outID);
|
|
1087
|
+
}, [isMounted, delay]);
|
|
1088
|
+
return canRender;
|
|
1089
|
+
};
|
|
1090
|
+
|
|
950
1091
|
const Button = forwardRef((props, ref) => {
|
|
951
1092
|
const { forms } = useStore(state => state[STORE_FORM_KEY], false);
|
|
952
1093
|
if (props.html) {
|
|
953
1094
|
({ __html: props.html });
|
|
954
1095
|
}
|
|
955
1096
|
return (jsx(ClassNames, { children: ({ css, cx }) => {
|
|
956
|
-
return (jsx("button", Object.assign({ title: "title" in props ? props.title : undefined, type: props.type, className: `button${props.as ? ` ${props.as}` : ``} ${cx(css `
|
|
1097
|
+
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 `
|
|
957
1098
|
padding: 5px 10px;
|
|
958
1099
|
border-radius: 2px;
|
|
959
|
-
${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`, ref: ref, onClick: e => {
|
|
1100
|
+
${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`, ref: ref, onDoubleClick: props.onDoubleClick || undefined, onClick: e => {
|
|
960
1101
|
if (props.form && props.type && props.type == 'submit') {
|
|
961
1102
|
props.onSubmit(forms[props.form]);
|
|
962
1103
|
}
|
|
@@ -1058,6 +1199,17 @@ const makeCSSValue = (k, v, o) => {
|
|
|
1058
1199
|
}
|
|
1059
1200
|
return `${k}:${v}${unit};`;
|
|
1060
1201
|
};
|
|
1202
|
+
const cleanProps = (props) => {
|
|
1203
|
+
let _props = Object.assign({}, props);
|
|
1204
|
+
Object.keys(_props).map(k => {
|
|
1205
|
+
if (k in cssProps) {
|
|
1206
|
+
delete _props[k];
|
|
1207
|
+
}
|
|
1208
|
+
});
|
|
1209
|
+
let _extras = [`as`, `hover`, `bref`, `tag`];
|
|
1210
|
+
_extras.map(x => x in _props && delete _props[x]);
|
|
1211
|
+
return _props;
|
|
1212
|
+
};
|
|
1061
1213
|
const buildCSS = (props) => {
|
|
1062
1214
|
let css = ``;
|
|
1063
1215
|
Object.keys(props).map(k => {
|
|
@@ -1211,7 +1363,7 @@ const filterHTMLProps = (props) => {
|
|
|
1211
1363
|
});
|
|
1212
1364
|
return filter;
|
|
1213
1365
|
};
|
|
1214
|
-
const uuid = () => nanoid();
|
|
1366
|
+
const uuid = (len = 21) => nanoid(len);
|
|
1215
1367
|
const addScript = (src, callback) => {
|
|
1216
1368
|
var s = document.createElement('script');
|
|
1217
1369
|
s.setAttribute('src', src);
|
|
@@ -1270,6 +1422,92 @@ const imgPromiseFactory = ({ decode = true, crossOrigin = '' }) => (src) => {
|
|
|
1270
1422
|
i.src = src;
|
|
1271
1423
|
});
|
|
1272
1424
|
};
|
|
1425
|
+
const parseFilename = nm => {
|
|
1426
|
+
var re = /(?:\.([^.]+))?$/;
|
|
1427
|
+
return {
|
|
1428
|
+
name: nm.split('.').slice(0, -1).join('.'),
|
|
1429
|
+
ext: re.exec(nm)[1]
|
|
1430
|
+
};
|
|
1431
|
+
};
|
|
1432
|
+
const camelCase = str => str.replace(":", "-").replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
|
|
1433
|
+
const getMousePosition = e => {
|
|
1434
|
+
const pos = {
|
|
1435
|
+
x: e.clientX,
|
|
1436
|
+
y: e.clientY,
|
|
1437
|
+
};
|
|
1438
|
+
const touch = e.changedTouches;
|
|
1439
|
+
if (touch) {
|
|
1440
|
+
pos.x = touch[0].clientX;
|
|
1441
|
+
pos.y = touch[0].clientY;
|
|
1442
|
+
}
|
|
1443
|
+
if (!pos.x || pos.x < 0)
|
|
1444
|
+
pos.x = 0;
|
|
1445
|
+
if (!pos.y || pos.y < 0)
|
|
1446
|
+
pos.y = 0;
|
|
1447
|
+
return pos;
|
|
1448
|
+
};
|
|
1449
|
+
const copyToClipboard = (str, callback) => {
|
|
1450
|
+
const el = document.createElement('textarea');
|
|
1451
|
+
let storeContentEditable = el.contentEditable;
|
|
1452
|
+
let storeReadOnly = el.readOnly;
|
|
1453
|
+
el.value = str;
|
|
1454
|
+
el.contentEditable = `true`;
|
|
1455
|
+
el.readOnly = false;
|
|
1456
|
+
el.setAttribute('readonly', `false`);
|
|
1457
|
+
el.setAttribute('contenteditable', `true`);
|
|
1458
|
+
el.style.position = 'absolute';
|
|
1459
|
+
el.style.left = '-999999999px';
|
|
1460
|
+
document.body.appendChild(el);
|
|
1461
|
+
const selected = document.getSelection().rangeCount > 0
|
|
1462
|
+
? document.getSelection().getRangeAt(0)
|
|
1463
|
+
: false;
|
|
1464
|
+
el.select();
|
|
1465
|
+
el.setSelectionRange(0, 999999);
|
|
1466
|
+
document.execCommand('copy');
|
|
1467
|
+
document.body.removeChild(el);
|
|
1468
|
+
if (selected) {
|
|
1469
|
+
document.getSelection().removeAllRanges();
|
|
1470
|
+
document.getSelection().addRange(selected);
|
|
1471
|
+
}
|
|
1472
|
+
el.contentEditable = storeContentEditable;
|
|
1473
|
+
el.readOnly = storeReadOnly;
|
|
1474
|
+
if (callback)
|
|
1475
|
+
callback();
|
|
1476
|
+
};
|
|
1477
|
+
/**
|
|
1478
|
+
* Format bytes as human-readable text.
|
|
1479
|
+
*
|
|
1480
|
+
* @param bytes Number of bytes.
|
|
1481
|
+
* @param si True to use metric (SI) units, aka powers of 1000. False to use
|
|
1482
|
+
* binary (IEC), aka powers of 1024.
|
|
1483
|
+
* @param dp Number of decimal places to display.
|
|
1484
|
+
*
|
|
1485
|
+
* @return Formatted string.
|
|
1486
|
+
*/
|
|
1487
|
+
const formatSize = (bytes, si = false, dp = 1) => {
|
|
1488
|
+
const thresh = si ? 1000 : 1024;
|
|
1489
|
+
if (Math.abs(bytes) < thresh) {
|
|
1490
|
+
return bytes + ' B';
|
|
1491
|
+
}
|
|
1492
|
+
const units = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
1493
|
+
let u = -1;
|
|
1494
|
+
const r = 10 ** dp;
|
|
1495
|
+
do {
|
|
1496
|
+
bytes /= thresh;
|
|
1497
|
+
++u;
|
|
1498
|
+
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
|
|
1499
|
+
return bytes.toFixed(dp) + ' ' + units[u];
|
|
1500
|
+
};
|
|
1501
|
+
const slugify = (...args) => {
|
|
1502
|
+
const value = args.join(' ');
|
|
1503
|
+
return value
|
|
1504
|
+
.normalize('NFD') // split an accented letter in the base letter and the acent
|
|
1505
|
+
.replace(/[\u0300-\u036f]/g, '') // remove all previously split accents
|
|
1506
|
+
.toLowerCase()
|
|
1507
|
+
.trim()
|
|
1508
|
+
.replace(/[^a-z0-9 ]/g, '') // remove all chars not letters, numbers and spaces (to be replaced)
|
|
1509
|
+
.replace(/\s+/g, '-'); // separator
|
|
1510
|
+
};
|
|
1273
1511
|
|
|
1274
1512
|
const AppMain = forwardRef((props, ref) => {
|
|
1275
1513
|
// const { dispatch } = useStore()
|
|
@@ -1282,11 +1520,6 @@ const App = forwardRef((props, ref) => {
|
|
|
1282
1520
|
return (jsx(AppProvider, { children: jsx(AppMain, {}) }));
|
|
1283
1521
|
});
|
|
1284
1522
|
|
|
1285
|
-
const Box = forwardRef((props, ref) => {
|
|
1286
|
-
const _noClick = () => { };
|
|
1287
|
-
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 })) }));
|
|
1288
|
-
});
|
|
1289
|
-
|
|
1290
1523
|
// const CoreBlock = styled.section`display: block;`
|
|
1291
1524
|
// const buildComponent = (props: any) => Block.withComponent(props.for || `div`)`${buildCSS(props)}`
|
|
1292
1525
|
const Component = forwardRef((props, ref) => {
|
|
@@ -1615,11 +1848,6 @@ const Tweet = (props) => {
|
|
|
1615
1848
|
return (jsx(Box, { as: `tweet`, weight: 1, bref: _tweet }));
|
|
1616
1849
|
};
|
|
1617
1850
|
|
|
1618
|
-
const ContextMenu = forwardRef((props, ref) => {
|
|
1619
|
-
const { as, size, color, hover, pos, items } = props;
|
|
1620
|
-
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}`)) })));
|
|
1621
|
-
});
|
|
1622
|
-
|
|
1623
1851
|
const buildElement = (el) => {
|
|
1624
1852
|
switch (el.is) {
|
|
1625
1853
|
case "Box":
|
|
@@ -1637,4 +1865,4 @@ const Header = forwardRef((props, ref) => {
|
|
|
1637
1865
|
return (jsx(Fragment, { children: buildComponent(data) }));
|
|
1638
1866
|
});
|
|
1639
1867
|
|
|
1640
|
-
export { App, Component as Block, Box, Button, Checkbox,
|
|
1868
|
+
export { App, Component as Block, Box, Button, Checkbox, 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, copyToClipboard, createSlice, el, filterHTMLProps, filterStyleProps, formatSize, generateModalRoutes, generatePreservedRoutes, generateRegularRoutes, getCookie, getHostname, getMousePosition, getUriParams, grab, imgPromiseFactory, isEmail, isIPv4, isUrl, parseFilename, randstr, removeCookie, rgb2hex, setCSSVar, setCookie, shuffleArray, slugify, ucfirst, useContextMenu, useDevice, useDispatch, useImage, useLang, useRender, useResizeObserver, useStore, useTheme, useToast, uuid };
|
package/dist/styles.css
CHANGED
|
@@ -455,4 +455,31 @@ button {
|
|
|
455
455
|
}
|
|
456
456
|
.zuz-checkbox:checked + label:after {
|
|
457
457
|
left: 20px;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.zuz-contextmenu {
|
|
461
|
+
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: #5183ff;
|
|
480
|
+
}
|
|
481
|
+
.zuz-contextmenu .line {
|
|
482
|
+
height: 1px;
|
|
483
|
+
background: rgba(255, 255, 255, 0.25);
|
|
484
|
+
margin: 4px 6px;
|
|
458
485
|
}
|
package/jest.config.js
ADDED
package/package.json
CHANGED
package/rollup.config.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import typescript from 'rollup-plugin-typescript2';
|
|
2
|
+
import commonjs from '@rollup/plugin-commonjs';
|
|
3
|
+
import scss from "rollup-plugin-scss";
|
|
4
|
+
import postcss from 'postcss'
|
|
5
|
+
import livereload from 'rollup-plugin-livereload'
|
|
6
|
+
import { uglify } from 'rollup-plugin-uglify';
|
|
7
|
+
|
|
8
|
+
const isWatching = process && process.argv.includes('-w') || process.argv.includes('--watch')
|
|
9
|
+
|
|
10
|
+
export default [
|
|
11
|
+
{
|
|
12
|
+
input: ["src/index.tsx"],
|
|
13
|
+
output: [
|
|
14
|
+
{
|
|
15
|
+
dir: "dist",
|
|
16
|
+
entryFileNames: "[name].js",
|
|
17
|
+
format: "es",
|
|
18
|
+
exports: "named",
|
|
19
|
+
// preserveModules: true,
|
|
20
|
+
// preserveModulesRoot: 'src',
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
plugins: [
|
|
24
|
+
typescript(),
|
|
25
|
+
commonjs(),
|
|
26
|
+
scss({
|
|
27
|
+
processor: () => postcss(),
|
|
28
|
+
fileName: 'styles.css',
|
|
29
|
+
failOnError: true
|
|
30
|
+
}),
|
|
31
|
+
!isWatching && uglify()
|
|
32
|
+
// livereload()
|
|
33
|
+
],
|
|
34
|
+
external: [
|
|
35
|
+
"react","react-children-utilities","js-cookie","axios","nanoid","@reduxjs/toolkit","react-redux","react/jsx-runtime",
|
|
36
|
+
"@emotion/react","@emotion/styled","prop-types","react-hot-toast"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
// ,
|
|
40
|
+
// {
|
|
41
|
+
// input: ["src/kit/index.tsx"],
|
|
42
|
+
// output: [
|
|
43
|
+
// {
|
|
44
|
+
// dir: "dist",
|
|
45
|
+
// entryFileNames: "kit.js",
|
|
46
|
+
// format: "es",
|
|
47
|
+
// exports: "named",
|
|
48
|
+
// // preserveModules: true,
|
|
49
|
+
// // preserveModulesRoot: 'src',
|
|
50
|
+
// }
|
|
51
|
+
// ],
|
|
52
|
+
// plugins: [
|
|
53
|
+
// typescript(),
|
|
54
|
+
// // commonjs(),
|
|
55
|
+
// // scss({
|
|
56
|
+
// // processor: () => postcss(),
|
|
57
|
+
// // fileName: 'styles.css',
|
|
58
|
+
// // failOnError: true
|
|
59
|
+
// // }),
|
|
60
|
+
// // !isWatching && uglify()
|
|
61
|
+
// // livereload()
|
|
62
|
+
// ],
|
|
63
|
+
// // external: [
|
|
64
|
+
// // "react","react-children-utilities","js-cookie","axios","nanoid","@reduxjs/toolkit","react-redux","react/jsx-runtime",
|
|
65
|
+
// // "@emotion/react","@emotion/styled","prop-types","react-hot-toast"
|
|
66
|
+
// // ]
|
|
67
|
+
// }
|
|
68
|
+
];
|
package/src/comps/box.tsx
CHANGED
|
@@ -3,16 +3,21 @@ 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}
|
|
20
|
+
onDoubleClick={props.onDoubleClick || undefined}
|
|
16
21
|
onClick={props.onClick || _noClick}
|
|
17
22
|
className={`${props.as ? `${props.as} ` : ``}${cx(css`${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`}
|
|
18
23
|
ref={props.bref || ref}>{props.html ? <span dangerouslySetInnerHTML={{ __html: props.html }} /> : props.children}</div>}
|
package/src/comps/button.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import React, {
|
|
|
5
5
|
import { ClassNames } from '@emotion/react'
|
|
6
6
|
import {
|
|
7
7
|
buildCSS,
|
|
8
|
-
|
|
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`
|
|
@@ -29,6 +30,7 @@ const Button = forwardRef((props: { [ key: string ] : any }, ref : LegacyRef<HTM
|
|
|
29
30
|
border-radius: 2px;
|
|
30
31
|
${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`}
|
|
31
32
|
ref={ref}
|
|
33
|
+
onDoubleClick={props.onDoubleClick || undefined}
|
|
32
34
|
onClick={e => {
|
|
33
35
|
if(props.form && props.type && props.type == 'submit'){
|
|
34
36
|
props.onSubmit(forms[props.form]);
|
|
@@ -3,39 +3,56 @@ import {
|
|
|
3
3
|
LegacyRef,
|
|
4
4
|
forwardRef,
|
|
5
5
|
useRef,
|
|
6
|
-
|
|
6
|
+
useState,
|
|
7
|
+
useEffect,
|
|
7
8
|
} from 'react';
|
|
8
9
|
import Box from './box'
|
|
9
10
|
import Button from './button'
|
|
10
11
|
|
|
11
12
|
const ContextMenu = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTMLHeadingElement>) => {
|
|
12
13
|
|
|
13
|
-
const {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
const { ID, p, items, hide } = props;
|
|
15
|
+
// const [p, setP] = useState(p)
|
|
16
|
+
const nodeRef = useRef(null);
|
|
17
|
+
|
|
18
|
+
const checkBoundaries = () => {
|
|
19
|
+
|
|
20
|
+
let x = p.x
|
|
21
|
+
let y = p.y
|
|
22
|
+
|
|
23
|
+
if (nodeRef.current) {
|
|
24
|
+
const { innerWidth, innerHeight } = window;
|
|
25
|
+
const { offsetWidth, offsetHeight } = nodeRef.current;
|
|
26
|
+
|
|
27
|
+
if (x + offsetWidth > innerWidth) x -= x + offsetWidth - innerWidth;
|
|
28
|
+
|
|
29
|
+
if (y + offsetHeight > innerHeight) y -= y + offsetHeight - innerHeight;
|
|
30
|
+
}
|
|
31
|
+
// setP({x: x, y: y})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
// checkBoundaries();
|
|
36
|
+
}, [])
|
|
21
37
|
|
|
22
38
|
return (
|
|
23
39
|
<Box
|
|
24
|
-
|
|
25
|
-
flex
|
|
40
|
+
bref={nodeRef}
|
|
41
|
+
flex dir={`cols`}
|
|
26
42
|
fixed
|
|
27
|
-
top={
|
|
28
|
-
left={
|
|
29
|
-
|
|
30
|
-
as={`
|
|
31
|
-
ai={`c`}
|
|
32
|
-
jc={`c`}
|
|
33
|
-
size={size || 24}
|
|
34
|
-
color={color || `#111111`}
|
|
35
|
-
>
|
|
36
|
-
{items && items.map((m, i) => <Button
|
|
43
|
+
top={p.x}
|
|
44
|
+
left={p.y}
|
|
45
|
+
as={`zuz-contextmenu ${ID}`}>
|
|
46
|
+
{items && items.map((m, i) => m.id == `line` ? <Box as={`line`} key={`line-${i}-${m.id}`} /> : <button
|
|
37
47
|
key={`cm-${i}-${m.id}`}
|
|
38
|
-
onClick={
|
|
48
|
+
onClick={ev => {
|
|
49
|
+
if(m.onClick){
|
|
50
|
+
m.onClick(ev, m)
|
|
51
|
+
}else{
|
|
52
|
+
console.log(`No onClick eventFound`)
|
|
53
|
+
}
|
|
54
|
+
hide()
|
|
55
|
+
}}>{m.label}</button>)}
|
|
39
56
|
</Box>
|
|
40
57
|
)
|
|
41
58
|
})
|