@zuzjs/ui 0.3.1 → 0.3.3
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 +232 -92
- package/dist/styles.css +2 -2
- package/jest.config.js +7 -0
- package/package.json +1 -1
- package/rollup.config.js +68 -0
- package/src/comps/box.tsx +1 -0
- package/src/comps/button.tsx +1 -0
- package/src/comps/contextmenu.tsx +38 -19
- package/src/comps/input.tsx +141 -6
- package/src/comps/mediaplayer.tsx +12 -0
- package/src/comps/toaster.tsx +11 -5
- package/src/context/store/theme.tsx +2 -2
- package/src/core/index.ts +79 -5
- package/src/core/styles.ts +12 -1
- package/src/hooks/index.tsx +2 -1
- package/src/hooks/useContextMenu.tsx +86 -51
- package/src/hooks/useDevice.tsx +27 -23
- 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 -3
- package/src/scss/style.scss +2 -2
- package/tsconfig.json +21 -0
- package/tsconfig.lib.json +9 -0
- package/tsconfig.spec.json +21 -0
- package/src/core/defaultTheme.ts +0 -90
- package/src/redux/slices/app.js +0 -26
- package/src/redux/slices/form.js +0 -46
- package/src/redux/store.js +0 -33
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
|
@@ -17,6 +17,7 @@ const Box = forwardRef((props : { [ key: string ] : any }, ref) => {
|
|
|
17
17
|
{...cleanProps(props)}
|
|
18
18
|
title={props.title || undefined}
|
|
19
19
|
id={props.id || undefined}
|
|
20
|
+
onDoubleClick={props.onDoubleClick || undefined}
|
|
20
21
|
onClick={props.onClick || _noClick}
|
|
21
22
|
className={`${props.as ? `${props.as} ` : ``}${cx(css`${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`}
|
|
22
23
|
ref={props.bref || ref}>{props.html ? <span dangerouslySetInnerHTML={{ __html: props.html }} /> : props.children}</div>}
|
package/src/comps/button.tsx
CHANGED
|
@@ -30,6 +30,7 @@ const Button = forwardRef((props: { [ key: string ] : any }, ref : LegacyRef<HTM
|
|
|
30
30
|
border-radius: 2px;
|
|
31
31
|
${buildCSS(props)} &:hover {${buildCSS(props.hover || {})}} &:active {${buildCSS(props.active || {})}}`)}`}
|
|
32
32
|
ref={ref}
|
|
33
|
+
onDoubleClick={props.onDoubleClick || undefined}
|
|
33
34
|
onClick={e => {
|
|
34
35
|
if(props.form && props.type && props.type == 'submit'){
|
|
35
36
|
props.onSubmit(forms[props.form]);
|
|
@@ -3,37 +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
|
-
|
|
40
|
+
bref={nodeRef}
|
|
25
41
|
flex dir={`cols`}
|
|
26
42
|
fixed
|
|
27
|
-
top={
|
|
28
|
-
left={
|
|
29
|
-
|
|
30
|
-
as={`
|
|
31
|
-
size={size || 24}
|
|
32
|
-
color={color || `#111111`}
|
|
33
|
-
>
|
|
34
|
-
{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
|
|
35
47
|
key={`cm-${i}-${m.id}`}
|
|
36
|
-
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>)}
|
|
37
56
|
</Box>
|
|
38
57
|
)
|
|
39
58
|
})
|
package/src/comps/input.tsx
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FC,
|
|
3
|
+
Ref,
|
|
3
4
|
LegacyRef,
|
|
4
5
|
forwardRef,
|
|
5
6
|
useRef,
|
|
6
7
|
SyntheticEvent,
|
|
8
|
+
useEffect,
|
|
9
|
+
memo,
|
|
7
10
|
} from 'react';
|
|
8
11
|
import { ClassNames } from '@emotion/react'
|
|
9
12
|
import { nanoid } from 'nanoid';
|
|
@@ -15,7 +18,102 @@ import {
|
|
|
15
18
|
UPDATE_FORM_FIELD
|
|
16
19
|
} from '../actions'
|
|
17
20
|
|
|
18
|
-
const
|
|
21
|
+
const SIZING_STYLE = [
|
|
22
|
+
'borderBottomWidth',
|
|
23
|
+
'borderLeftWidth',
|
|
24
|
+
'borderRightWidth',
|
|
25
|
+
'borderTopWidth',
|
|
26
|
+
'boxSizing',
|
|
27
|
+
'fontFamily',
|
|
28
|
+
'fontSize',
|
|
29
|
+
'fontStyle',
|
|
30
|
+
'fontWeight',
|
|
31
|
+
'letterSpacing',
|
|
32
|
+
'lineHeight',
|
|
33
|
+
'paddingBottom',
|
|
34
|
+
'paddingLeft',
|
|
35
|
+
'paddingRight',
|
|
36
|
+
'paddingTop',
|
|
37
|
+
// non-standard
|
|
38
|
+
'tabSize',
|
|
39
|
+
'textIndent',
|
|
40
|
+
// non-standard
|
|
41
|
+
'textRendering',
|
|
42
|
+
'textTransform',
|
|
43
|
+
'width',
|
|
44
|
+
'wordBreak',
|
|
45
|
+
] as const;
|
|
46
|
+
type SizingProps = Extract<
|
|
47
|
+
(typeof SIZING_STYLE)[number],
|
|
48
|
+
keyof CSSStyleDeclaration
|
|
49
|
+
>;
|
|
50
|
+
|
|
51
|
+
export const noop = () => {};
|
|
52
|
+
|
|
53
|
+
const pick = <Obj extends { [key: string]: any }, Key extends keyof Obj>(
|
|
54
|
+
props: Key[],
|
|
55
|
+
obj: Obj,
|
|
56
|
+
): Pick<Obj, Key> =>
|
|
57
|
+
props.reduce((acc, prop) => {
|
|
58
|
+
acc[prop] = obj[prop];
|
|
59
|
+
return acc;
|
|
60
|
+
}, {} as Pick<Obj, Key>);
|
|
61
|
+
|
|
62
|
+
type SizingStyle = Pick<CSSStyleDeclaration, SizingProps>;
|
|
63
|
+
|
|
64
|
+
export type SizingData = {
|
|
65
|
+
sizingStyle: SizingStyle;
|
|
66
|
+
paddingSize: number;
|
|
67
|
+
borderSize: number;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const isIE = typeof window !== "undefined" && !!(document.documentElement as any).currentStyle
|
|
71
|
+
|
|
72
|
+
const getSizingData = (node: HTMLElement): SizingData | null => {
|
|
73
|
+
|
|
74
|
+
const style = window.getComputedStyle(node);
|
|
75
|
+
|
|
76
|
+
if (style === null) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const sizingStyle = pick(SIZING_STYLE as unknown as SizingProps[], style);
|
|
81
|
+
const { boxSizing } = sizingStyle;
|
|
82
|
+
|
|
83
|
+
// probably node is detached from DOM, can't read computed dimensions
|
|
84
|
+
if (boxSizing === '') {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// IE (Edge has already correct behaviour) returns content width as computed width
|
|
89
|
+
// so we need to add manually padding and border widths
|
|
90
|
+
if (isIE && boxSizing === 'border-box') {
|
|
91
|
+
sizingStyle.width =
|
|
92
|
+
parseFloat(sizingStyle.width!) +
|
|
93
|
+
parseFloat(sizingStyle.borderRightWidth!) +
|
|
94
|
+
parseFloat(sizingStyle.borderLeftWidth!) +
|
|
95
|
+
parseFloat(sizingStyle.paddingRight!) +
|
|
96
|
+
parseFloat(sizingStyle.paddingLeft!) +
|
|
97
|
+
'px';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const paddingSize =
|
|
101
|
+
parseFloat(sizingStyle.paddingBottom!) +
|
|
102
|
+
parseFloat(sizingStyle.paddingTop!);
|
|
103
|
+
|
|
104
|
+
const borderSize =
|
|
105
|
+
parseFloat(sizingStyle.borderBottomWidth!) +
|
|
106
|
+
parseFloat(sizingStyle.borderTopWidth!);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
sizingStyle,
|
|
110
|
+
paddingSize,
|
|
111
|
+
borderSize,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const Input = forwardRef((props : { [ key: string ] : any }, ref : Ref<HTMLTextAreaElement|HTMLInputElement>) => {
|
|
19
117
|
|
|
20
118
|
const {
|
|
21
119
|
as,
|
|
@@ -24,6 +122,8 @@ const Input = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTM
|
|
|
24
122
|
onChange,
|
|
25
123
|
onKeyUp,
|
|
26
124
|
onClick,
|
|
125
|
+
onBlur,
|
|
126
|
+
onFocus,
|
|
27
127
|
readOnly,
|
|
28
128
|
type,
|
|
29
129
|
tag,
|
|
@@ -35,7 +135,10 @@ const Input = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTM
|
|
|
35
135
|
value,
|
|
36
136
|
defaultValue,
|
|
37
137
|
fref,
|
|
38
|
-
autoComplete
|
|
138
|
+
autoComplete,
|
|
139
|
+
elastic,
|
|
140
|
+
minRows,
|
|
141
|
+
maxRows
|
|
39
142
|
} = props;
|
|
40
143
|
|
|
41
144
|
const dispatch = useDispatch(STORE_FORM_KEY)
|
|
@@ -47,6 +150,29 @@ const Input = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTM
|
|
|
47
150
|
|
|
48
151
|
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);`;
|
|
49
152
|
|
|
153
|
+
const isControlled = props.value !== undefined;
|
|
154
|
+
const measurementsCacheRef = useRef<SizingData>();
|
|
155
|
+
|
|
156
|
+
const handleElastic = () => {
|
|
157
|
+
const node = _ref.current!
|
|
158
|
+
const nodeSizingData = measurementsCacheRef.current
|
|
159
|
+
? measurementsCacheRef.current : getSizingData(node)
|
|
160
|
+
if (!nodeSizingData) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
measurementsCacheRef.current = nodeSizingData;
|
|
164
|
+
|
|
165
|
+
// const [height, rowHeight] = calculateNodeHeight(
|
|
166
|
+
// nodeSizingData,
|
|
167
|
+
// node.value || node.placeholder || 'x',
|
|
168
|
+
// minRows || 6,
|
|
169
|
+
// maxRows || 6,
|
|
170
|
+
// );
|
|
171
|
+
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
useEffect(() => {}, [])
|
|
175
|
+
|
|
50
176
|
return (
|
|
51
177
|
<ClassNames>
|
|
52
178
|
{({ css, cx }) => <El
|
|
@@ -63,27 +189,36 @@ const Input = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTM
|
|
|
63
189
|
defaultValue={defaultValue || ``}
|
|
64
190
|
onKeyUp={(e : SyntheticEvent) => {
|
|
65
191
|
let k = e['keyCode'] || ['which'];
|
|
66
|
-
if(El != 'textarea' && k == 13
|
|
192
|
+
if(form && onSubmit && El != 'textarea' && k == 13){
|
|
67
193
|
onSubmit(forms[form]);
|
|
194
|
+
}else{
|
|
195
|
+
if(onKeyUp) onKeyUp(e)
|
|
68
196
|
}
|
|
197
|
+
|
|
69
198
|
}}
|
|
70
199
|
onChange={e => {
|
|
71
200
|
let val = type == 'file' ?
|
|
72
201
|
e.currentTarget.files
|
|
73
202
|
: e.currentTarget.value;
|
|
74
|
-
dispatch( dispatch( UPDATE_FORM_FIELD( form || 'orphan', name, val == "" ? null : val, forms ) ) );
|
|
203
|
+
if(form) dispatch( dispatch( UPDATE_FORM_FIELD( form || 'orphan', name, val == "" ? null : val, forms ) ) );
|
|
204
|
+
// if(El == `textarea` && elastic) handleElastic()
|
|
75
205
|
onChange && onChange(val == "" ? null : val)
|
|
76
206
|
}}
|
|
77
207
|
onClick={onClick ? onClick : () => {}}
|
|
78
208
|
readOnly={readOnly || false}
|
|
79
209
|
onBlur={e => {
|
|
210
|
+
if(onBlur) onBlur(e)
|
|
80
211
|
if(touched){}
|
|
81
212
|
}}
|
|
82
|
-
onFocus={ e =>
|
|
213
|
+
onFocus={ e => {
|
|
214
|
+
if(touched == false)dispatch( UPDATE_FORM_FIELD( form || 'orphan', `touched`, true, forms ) )
|
|
215
|
+
if(onFocus) onFocus(e)
|
|
216
|
+
}}
|
|
83
217
|
/>}
|
|
84
218
|
</ClassNames>
|
|
85
219
|
)
|
|
86
|
-
|
|
220
|
+
|
|
221
|
+
|
|
87
222
|
})
|
|
88
223
|
|
|
89
224
|
export default Input
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
LegacyRef
|
|
4
|
+
} from 'react'
|
|
5
|
+
import { ClassNames } from '@emotion/react'
|
|
6
|
+
import { buildCSS } from '../core'
|
|
7
|
+
|
|
8
|
+
const MediaPlayer = forwardRef((props : { [ key: string ] : any }, ref : LegacyRef<HTMLImageElement>) => {
|
|
9
|
+
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
export default MediaPlayer;
|
package/src/comps/toaster.tsx
CHANGED
|
@@ -16,12 +16,17 @@ class Toaster {
|
|
|
16
16
|
this.#defaultTimeLeft = 4
|
|
17
17
|
const rootID = config?.root || `toast-container`;
|
|
18
18
|
this.#root = rootID;
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
|
|
20
|
+
this.addRoot();
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
addRoot(){
|
|
25
|
+
if(window.document.querySelector(`#${this.#root}`)) return;
|
|
21
26
|
var root = window.document.createElement('div');
|
|
22
|
-
root.id =
|
|
23
|
-
|
|
24
|
-
this.#container = window.document.querySelector(`#${
|
|
27
|
+
root.id = this.#root;
|
|
28
|
+
window.document.body.appendChild(root);
|
|
29
|
+
this.#container = window.document.querySelector(`#${this.#root}`)
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
show = (
|
|
@@ -57,6 +62,7 @@ class Toaster {
|
|
|
57
62
|
}){
|
|
58
63
|
|
|
59
64
|
var self = this;
|
|
65
|
+
self.addRoot();
|
|
60
66
|
var tout = null,
|
|
61
67
|
ID = 'toast-' + nanoid(),
|
|
62
68
|
toast = window.document.createElement('div'),
|
|
@@ -32,11 +32,11 @@ class AppTheme {
|
|
|
32
32
|
get = () => {
|
|
33
33
|
let self = this;
|
|
34
34
|
if(self.#mode === "auto"){
|
|
35
|
-
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
|
|
35
|
+
typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
|
|
36
36
|
self.#mode = event.matches ? "dark" : "light";
|
|
37
37
|
self.#listen(self.#mode);
|
|
38
38
|
});
|
|
39
|
-
return window.matchMedia &&
|
|
39
|
+
return typeof window !== 'undefined' && window.matchMedia &&
|
|
40
40
|
window.matchMedia('(prefers-color-scheme: dark)').matches ?
|
|
41
41
|
self.#darkTheme : self.#lightTheme;
|
|
42
42
|
}else{
|
package/src/core/index.ts
CHANGED
|
@@ -45,7 +45,7 @@ const cleanProps = (props : any) => {
|
|
|
45
45
|
delete _props[k]
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
|
-
let _extras = [`as
|
|
48
|
+
let _extras = [`as`,`hover`,`bref`,`tag`]
|
|
49
49
|
_extras.map(x => x in _props && delete _props[x])
|
|
50
50
|
return _props
|
|
51
51
|
}
|
|
@@ -105,7 +105,7 @@ const buildFormData = (data : object) : FormData => {
|
|
|
105
105
|
return formData;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
const
|
|
108
|
+
const withRest = async (uri : string, data : object, timeout : number = 60, fd : object = null, progress? : Function, bearer : string = `__ha`) => {
|
|
109
109
|
var Bearer = getCookie(bearer) || `${randstr(8)}^${randstr(8)}`;
|
|
110
110
|
window['__grabToken'] = axios.CancelToken.source();
|
|
111
111
|
if(fd){
|
|
@@ -228,7 +228,7 @@ const filterHTMLProps = (props : any) => {
|
|
|
228
228
|
return filter;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
const uuid = () => nanoid()
|
|
231
|
+
const uuid = (len=21) => nanoid(len)
|
|
232
232
|
|
|
233
233
|
const addScript = (src: string, callback: () => any) => {
|
|
234
234
|
var s = document.createElement('script')
|
|
@@ -320,6 +320,77 @@ const getMousePosition = e => {
|
|
|
320
320
|
return pos;
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
+
const copyToClipboard = (str : string, callback: Function) => {
|
|
324
|
+
const el = document.createElement('textarea');
|
|
325
|
+
let storeContentEditable = el.contentEditable;
|
|
326
|
+
let storeReadOnly = el.readOnly;
|
|
327
|
+
el.value = str;
|
|
328
|
+
el.contentEditable = `true`;
|
|
329
|
+
el.readOnly = false;
|
|
330
|
+
el.setAttribute('readonly', `false`);
|
|
331
|
+
el.setAttribute('contenteditable', `true`);
|
|
332
|
+
el.style.position = 'absolute';
|
|
333
|
+
el.style.left = '-999999999px';
|
|
334
|
+
document.body.appendChild(el);
|
|
335
|
+
const selected =
|
|
336
|
+
document.getSelection().rangeCount > 0
|
|
337
|
+
? document.getSelection().getRangeAt(0)
|
|
338
|
+
: false;
|
|
339
|
+
el.select();
|
|
340
|
+
el.setSelectionRange(0, 999999);
|
|
341
|
+
document.execCommand('copy');
|
|
342
|
+
document.body.removeChild(el);
|
|
343
|
+
if (selected) {
|
|
344
|
+
document.getSelection().removeAllRanges();
|
|
345
|
+
document.getSelection().addRange(selected);
|
|
346
|
+
}
|
|
347
|
+
el.contentEditable = storeContentEditable;
|
|
348
|
+
el.readOnly = storeReadOnly;
|
|
349
|
+
if(callback) callback()
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Format bytes as human-readable text.
|
|
354
|
+
*
|
|
355
|
+
* @param bytes Number of bytes.
|
|
356
|
+
* @param si True to use metric (SI) units, aka powers of 1000. False to use
|
|
357
|
+
* binary (IEC), aka powers of 1024.
|
|
358
|
+
* @param dp Number of decimal places to display.
|
|
359
|
+
*
|
|
360
|
+
* @return Formatted string.
|
|
361
|
+
*/
|
|
362
|
+
const formatSize = (bytes, si=false, dp=1) => {
|
|
363
|
+
const thresh = si ? 1000 : 1024;
|
|
364
|
+
|
|
365
|
+
if (Math.abs(bytes) < thresh) {
|
|
366
|
+
return bytes + ' B';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const units = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
|
370
|
+
let u = -1;
|
|
371
|
+
const r = 10**dp;
|
|
372
|
+
|
|
373
|
+
do {
|
|
374
|
+
bytes /= thresh;
|
|
375
|
+
++u;
|
|
376
|
+
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
return bytes.toFixed(dp) + ' ' + units[u];
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const slugify = (...args: (string | number)[]): string => {
|
|
383
|
+
const value = args.join(' ')
|
|
384
|
+
|
|
385
|
+
return value
|
|
386
|
+
.normalize('NFD') // split an accented letter in the base letter and the acent
|
|
387
|
+
.replace(/[\u0300-\u036f]/g, '') // remove all previously split accents
|
|
388
|
+
.toLowerCase()
|
|
389
|
+
.trim()
|
|
390
|
+
.replace(/[^a-z0-9 ]/g, '') // remove all chars not letters, numbers and spaces (to be replaced)
|
|
391
|
+
.replace(/\s+/g, '-') // separator
|
|
392
|
+
}
|
|
393
|
+
|
|
323
394
|
export {
|
|
324
395
|
addProps,
|
|
325
396
|
addScript,
|
|
@@ -329,7 +400,7 @@ export {
|
|
|
329
400
|
byName,
|
|
330
401
|
byId,
|
|
331
402
|
el,
|
|
332
|
-
|
|
403
|
+
withRest,
|
|
333
404
|
isEmail,
|
|
334
405
|
isIPv4,
|
|
335
406
|
isUrl,
|
|
@@ -352,6 +423,9 @@ export {
|
|
|
352
423
|
getHostname,
|
|
353
424
|
parseFilename,
|
|
354
425
|
camelCase,
|
|
355
|
-
getMousePosition
|
|
426
|
+
getMousePosition,
|
|
427
|
+
formatSize,
|
|
428
|
+
copyToClipboard,
|
|
429
|
+
slugify
|
|
356
430
|
}
|
|
357
431
|
|
package/src/core/styles.ts
CHANGED
|
@@ -3,6 +3,10 @@ const cssProps : { [key: string] : any } = {
|
|
|
3
3
|
"alignContent": "align-content",
|
|
4
4
|
|
|
5
5
|
"aic": "aic",
|
|
6
|
+
"ais": "ais",
|
|
7
|
+
"aie": "aie",
|
|
8
|
+
"nous": "nous",
|
|
9
|
+
"nope": "nope",
|
|
6
10
|
"ai": "align-items",
|
|
7
11
|
"alignItems": "align-items",
|
|
8
12
|
|
|
@@ -278,6 +282,7 @@ const cssProps : { [key: string] : any } = {
|
|
|
278
282
|
"wordBreak": "word-break",
|
|
279
283
|
"wordSpacing": "word-spacing",
|
|
280
284
|
"wrap": "wrap",
|
|
285
|
+
"textWrap": "textWrap",
|
|
281
286
|
"wordWrap": "word-wrap",
|
|
282
287
|
"writingMode": "writing-mode",
|
|
283
288
|
"zIndex": "z-index",
|
|
@@ -317,6 +322,8 @@ const cssPropsDirect : { [key : string] : any } = {
|
|
|
317
322
|
'flex' : 'display: flex;',
|
|
318
323
|
'fwrap' : 'flex-wrap: wrap;',
|
|
319
324
|
'aic' : 'align-items: center;',
|
|
325
|
+
'ais' : 'align-items: flex-start;',
|
|
326
|
+
'aie' : 'align-items: flex-end;',
|
|
320
327
|
'ass' : 'align-self: flex-start;',
|
|
321
328
|
'asc' : 'align-self: center;',
|
|
322
329
|
'ase' : 'align-self: flex-end;',
|
|
@@ -329,13 +336,17 @@ const cssPropsDirect : { [key : string] : any } = {
|
|
|
329
336
|
'block' : 'display: block;',
|
|
330
337
|
'bold' : "font-weight: bold;",
|
|
331
338
|
'wrap' : "word-wrap: break-word;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 99%;",
|
|
339
|
+
'textWrap' : "word-wrap: break-word;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;max-width: 99%;",
|
|
332
340
|
'pointer' : "cursor: pointer;",
|
|
333
341
|
'fb' : 'font-family: var(--primary-font-bold);',
|
|
334
342
|
'ph' : 'padding-left: __VALUE__;padding-right: __VALUE__;',
|
|
335
343
|
'pv' : 'padding-bottom: __VALUE__;padding-top: __VALUE__;',
|
|
336
344
|
'mv' : 'margin-bottom: __VALUE__;margin-top: __VALUE__;',
|
|
337
345
|
'mh' : 'margin-left: __VALUE__;margin-right: __VALUE__;',
|
|
338
|
-
'anim' : 'transition:all __VALUE__s linear 0s;'
|
|
346
|
+
'anim' : 'transition:all __VALUE__s linear 0s;',
|
|
347
|
+
'nous' : 'user-select: none;',
|
|
348
|
+
'nope' : 'pointer-events: none;',
|
|
349
|
+
'tdn' : 'text-decoration: none;',
|
|
339
350
|
}
|
|
340
351
|
|
|
341
352
|
const cssPropsIgnore : string[] = [
|
package/src/hooks/index.tsx
CHANGED
|
@@ -6,4 +6,5 @@ export { default as useResizeObserver } from './useResizeObserver'
|
|
|
6
6
|
export { default as useDevice } from './useDevice'
|
|
7
7
|
export { default as useToast } from './useToast'
|
|
8
8
|
export { default as useLang } from './useLang'
|
|
9
|
-
export { default as useContextMenu } from './useContextMenu'
|
|
9
|
+
export { default as useContextMenu } from './useContextMenu'
|
|
10
|
+
export { default as useRender } from './useRender'
|