@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 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
- 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, value: value || undefined, defaultValue: defaultValue || ``, onKeyUp: (e) => {
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 && form && onSubmit) {
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
- dispatch(dispatch(UPDATE_FORM_FIELD(form || 'orphan', name, val == "" ? null : val, forms)));
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
- }, onFocus: e => touched == false && dispatch(UPDATE_FORM_FIELD(form || 'orphan', `touched`, true, forms)) }) }));
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, 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, createSlice, el, filterHTMLProps, filterStyleProps, generateModalRoutes, generatePreservedRoutes, generateRegularRoutes, getCookie, getHostname, getUriParams, grab, imgPromiseFactory, isEmail, isIPv4, isUrl, randstr, removeCookie, rgb2hex, setCSSVar, setCookie, shuffleArray, ucfirst, useDevice, useDispatch, useImage, useLang, useResizeObserver, useStore, useTheme, useToast, uuid };
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
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'],
3
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
4
+ transform: {
5
+ '^.+\\.tsx?$': 'ts-jest'
6
+ }
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zuzjs/ui",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -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>}
@@ -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`
@@ -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
- SyntheticEvent,
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
- as,
15
- size,
16
- color,
17
- hover,
18
- pos,
19
- items
20
- } = props;
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
- hover={hover || {}}
25
- flex
40
+ bref={nodeRef}
41
+ flex dir={`cols`}
26
42
  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
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={m.on ? m.on : () => {}}>{m.label}</Button>)}
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
  })