mui-fast-start 0.1.4 → 0.2.0
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/README.md +356 -356
- package/README_KR.md +355 -0
- package/dist/components/Obj/Checkbox/ObjCheckIcon.d.ts +3 -0
- package/dist/components/Obj/Checkbox/ObjCheckIcon.d.ts.map +1 -0
- package/dist/components/Obj/Checkbox/ObjCheckbox.d.ts +3 -0
- package/dist/components/Obj/Checkbox/ObjCheckbox.d.ts.map +1 -0
- package/dist/components/Obj/Textfield/ObjFloat.d.ts +3 -0
- package/dist/components/Obj/Textfield/ObjFloat.d.ts.map +1 -0
- package/dist/components/Obj/Textfield/ObjInteger.d.ts +3 -0
- package/dist/components/Obj/Textfield/ObjInteger.d.ts.map +1 -0
- package/dist/components/Obj/Textfield/ObjText.d.ts +3 -0
- package/dist/components/Obj/Textfield/ObjText.d.ts.map +1 -0
- package/dist/components/Single/Checkbox/SingleCheckIcon.d.ts +3 -0
- package/dist/components/Single/Checkbox/SingleCheckIcon.d.ts.map +1 -0
- package/dist/components/Single/Checkbox/SingleCheckbox.d.ts +3 -0
- package/dist/components/Single/Checkbox/SingleCheckbox.d.ts.map +1 -0
- package/dist/components/Single/TextField/SingleFloat.d.ts +3 -0
- package/dist/components/Single/TextField/SingleFloat.d.ts.map +1 -0
- package/dist/components/Single/TextField/SingleInteger.d.ts +3 -0
- package/dist/components/Single/TextField/SingleInteger.d.ts.map +1 -0
- package/dist/components/Single/TextField/SingleText.d.ts +3 -0
- package/dist/components/Single/TextField/SingleText.d.ts.map +1 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/{types/hooks → hooks}/splits/useSplitSingleNumberProps.d.ts +2 -1
- package/dist/hooks/splits/useSplitSingleNumberProps.d.ts.map +1 -0
- package/dist/{types/hooks → hooks}/splits/useSplitSingleTextProps.d.ts +2 -1
- package/dist/hooks/splits/useSplitSingleTextProps.d.ts.map +1 -0
- package/dist/{types/hooks → hooks}/state/useObjToSingle.d.ts +2 -1
- package/dist/hooks/state/useObjToSingle.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +278 -0
- package/dist/styles/FastStartProvider.d.ts +21 -0
- package/dist/styles/FastStartProvider.d.ts.map +1 -0
- package/dist/styles/createDefaultProps.d.ts +3 -0
- package/dist/styles/createDefaultProps.d.ts.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/{types/props.d.ts → props.d.ts} +8 -1
- package/dist/types/props.d.ts.map +1 -0
- package/dist/types/{types/provider.d.ts → provider.d.ts} +2 -1
- package/dist/types/provider.d.ts.map +1 -0
- package/dist/types/{types/types.d.ts → types.d.ts} +1 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/number/calculate.d.ts +7 -0
- package/dist/utils/number/calculate.d.ts.map +1 -0
- package/dist/utils/object/error.d.ts +4 -0
- package/dist/utils/object/error.d.ts.map +1 -0
- package/dist/utils/object/merge.d.ts +4 -0
- package/dist/utils/object/merge.d.ts.map +1 -0
- package/eslint.config.js +23 -0
- package/examples/basic/README.md +73 -0
- package/examples/basic/eslint.config.js +23 -0
- package/examples/basic/index.html +13 -0
- package/examples/basic/package.json +37 -0
- package/examples/basic/src/App.css +5 -0
- package/examples/basic/src/App.tsx +28 -0
- package/examples/basic/src/index.css +30 -0
- package/examples/basic/src/main.tsx +57 -0
- package/examples/basic/src/pages/ObjPage.tsx +93 -0
- package/examples/basic/src/pages/SinglePage.tsx +70 -0
- package/examples/basic/tsconfig.app.json +38 -0
- package/examples/basic/tsconfig.json +7 -0
- package/examples/basic/tsconfig.node.json +35 -0
- package/examples/basic/vite.config.ts +28 -0
- package/mui-fast-start-0.1.5.tgz +0 -0
- package/package.json +67 -85
- package/src/components/Obj/Checkbox/ObjCheckIcon.tsx +19 -0
- package/src/components/Obj/Checkbox/ObjCheckbox.tsx +19 -0
- package/src/components/Obj/Textfield/ObjFloat.tsx +22 -0
- package/src/components/Obj/Textfield/ObjInteger.tsx +22 -0
- package/src/components/Obj/Textfield/ObjText.tsx +22 -0
- package/src/components/Single/Checkbox/SingleCheckIcon.tsx +25 -0
- package/src/components/Single/Checkbox/SingleCheckbox.tsx +31 -0
- package/src/components/Single/TextField/SingleFloat.tsx +12 -0
- package/src/components/Single/TextField/SingleInteger.tsx +12 -0
- package/src/components/Single/TextField/SingleText.tsx +12 -0
- package/src/components/index.ts +13 -0
- package/src/hooks/splits/useSplitSingleNumberProps.ts +159 -0
- package/src/hooks/splits/useSplitSingleTextProps.ts +36 -0
- package/src/hooks/state/useObjToSingle.ts +23 -0
- package/src/index.ts +8 -0
- package/src/styles/FastStartProvider.tsx +26 -0
- package/src/styles/createDefaultProps.ts +45 -0
- package/src/types/props.ts +67 -0
- package/src/types/provider.ts +47 -0
- package/src/types/types.ts +9 -0
- package/src/utils/number/calculate.ts +102 -0
- package/src/utils/object/error.ts +14 -0
- package/src/utils/object/merge.ts +47 -0
- package/src.zip +0 -0
- package/tsconfig.json +34 -0
- package/tsconfig.lib.json +9 -0
- package/vite.config.ts +35 -0
- package/dist/index.cjs.js +0 -1
- package/dist/index.esm.js +0 -266
- package/dist/types/components/Obj/Checkbox/ObjCheckIcon.d.ts +0 -3
- package/dist/types/components/Obj/Checkbox/ObjCheckbox.d.ts +0 -3
- package/dist/types/components/Obj/Textfield/ObjFloat.d.ts +0 -3
- package/dist/types/components/Obj/Textfield/ObjInteger.d.ts +0 -3
- package/dist/types/components/Obj/Textfield/ObjText.d.ts +0 -3
- package/dist/types/components/Single/Checkbox/SingleCheckIcon.d.ts +0 -3
- package/dist/types/components/Single/Checkbox/SingleCheckbox.d.ts +0 -3
- package/dist/types/components/Single/TextField/SingleFloat.d.ts +0 -3
- package/dist/types/components/Single/TextField/SingleInteger.d.ts +0 -3
- package/dist/types/components/Single/TextField/SingleText.d.ts +0 -3
- package/dist/types/components/index.d.ts +0 -12
- package/dist/types/styles/FastStartProvider.d.ts +0 -20
- package/dist/types/styles/createDefaultProps.d.ts +0 -3
- package/dist/types/styles/index.d.ts +0 -2
- package/dist/types/utils/number/calculate.d.ts +0 -5
- package/dist/types/utils/object/merge.d.ts +0 -3
- /package/{dist/types/hooks/index.d.ts → src/hooks/index.ts} +0 -0
- /package/{dist/types/types/index.d.ts → src/types/index.ts} +0 -0
- /package/{dist/types/utils/index.d.ts → src/utils/index.ts} +0 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {useContext} from "react";
|
|
2
|
+
import {TextField} from "@mui/material";
|
|
3
|
+
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
4
|
+
import {SingleNumberProps} from "../../../types";
|
|
5
|
+
import {useSplitSingleFloatProps} from "../../../hooks";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export const SingleFloat = (customProps: SingleNumberProps) => {
|
|
9
|
+
const defaultProps = useContext(FastStartContext)?.Single?.Float as SingleNumberProps;
|
|
10
|
+
const props = useSplitSingleFloatProps(defaultProps, customProps);
|
|
11
|
+
return <TextField {...props}/>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {useContext} from "react";
|
|
2
|
+
import {TextField} from "@mui/material";
|
|
3
|
+
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
4
|
+
import {SingleNumberProps} from "../../../types";
|
|
5
|
+
import {useSplitSingleIntegerProps} from "../../../hooks";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export const SingleInteger = (customProps: SingleNumberProps) => {
|
|
9
|
+
const defaultProps = useContext(FastStartContext)?.Single?.Integer as SingleNumberProps;
|
|
10
|
+
const props = useSplitSingleIntegerProps(defaultProps, customProps);
|
|
11
|
+
return <TextField {...props}/>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {useContext} from "react";
|
|
2
|
+
import useSplitSingleTextProps from '../../../hooks/splits/useSplitSingleTextProps';
|
|
3
|
+
import {TextField} from "@mui/material";
|
|
4
|
+
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
5
|
+
import {SingleTextProps} from "../../../types";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export const SingleText = (customProps: SingleTextProps) => {
|
|
9
|
+
const defaultProps = useContext(FastStartContext)?.Single?.Text as SingleTextProps;
|
|
10
|
+
const props = useSplitSingleTextProps(defaultProps, customProps);
|
|
11
|
+
return <TextField {...props}/>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Object components
|
|
2
|
+
export { ObjCheckbox } from './Obj/Checkbox/ObjCheckbox';
|
|
3
|
+
export { ObjCheckIcon } from './Obj/Checkbox/ObjCheckIcon';
|
|
4
|
+
export { ObjFloat } from './Obj/Textfield/ObjFloat';
|
|
5
|
+
export { ObjInteger } from './Obj/Textfield/ObjInteger';
|
|
6
|
+
export { ObjText } from './Obj/Textfield/ObjText';
|
|
7
|
+
|
|
8
|
+
// Single components
|
|
9
|
+
export { SingleCheckbox } from './Single/Checkbox/SingleCheckbox';
|
|
10
|
+
export { SingleCheckIcon } from './Single/Checkbox/SingleCheckIcon';
|
|
11
|
+
export { SingleFloat } from './Single/TextField/SingleFloat';
|
|
12
|
+
export { SingleInteger } from './Single/TextField/SingleInteger';
|
|
13
|
+
export { SingleText } from './Single/TextField/SingleText';
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type {TextFieldProps} from "@mui/material";
|
|
2
|
+
import {fastDeepMerge, floatCalculate, integerCalculate, processFloat, processInteger} from "../../utils";
|
|
3
|
+
import React, {useCallback, useMemo, useState} from "react";
|
|
4
|
+
import {InputLabelType, SingleNumberProps} from "../../types";
|
|
5
|
+
|
|
6
|
+
type CalculateNumber = number | null | undefined;
|
|
7
|
+
type CalculateFunction = (
|
|
8
|
+
value: string | null,
|
|
9
|
+
min: CalculateNumber,
|
|
10
|
+
max: CalculateNumber,
|
|
11
|
+
def: CalculateNumber
|
|
12
|
+
) => CalculateNumber;
|
|
13
|
+
|
|
14
|
+
const useSplitSingleNumberProps = (
|
|
15
|
+
defaultProps: SingleNumberProps,
|
|
16
|
+
customProps: SingleNumberProps,
|
|
17
|
+
process: (value: string) => string,
|
|
18
|
+
calculate: CalculateFunction,
|
|
19
|
+
lockKeys: string[] = []
|
|
20
|
+
): TextFieldProps => {
|
|
21
|
+
const [draft, setDraft] = useState<string | null>(null);
|
|
22
|
+
const {
|
|
23
|
+
get, set, errorData,
|
|
24
|
+
minLength, maxLength,
|
|
25
|
+
startAdornment, endAdornment,
|
|
26
|
+
disappear, def, min, max, step,
|
|
27
|
+
...props
|
|
28
|
+
} = useMemo(() =>
|
|
29
|
+
fastDeepMerge<SingleNumberProps>({...defaultProps}, customProps),
|
|
30
|
+
[defaultProps, customProps]
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const getCalculate = useCallback((value: string | null) => (
|
|
34
|
+
calculate(value, min, max, def)
|
|
35
|
+
), [calculate, min, max, def]);
|
|
36
|
+
|
|
37
|
+
const getKeyboardValue = useCallback((event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
38
|
+
const {value, valueAsNumber} = event.currentTarget;
|
|
39
|
+
return isNaN(valueAsNumber) ? getCalculate(value) : valueAsNumber;
|
|
40
|
+
}, [getCalculate]);
|
|
41
|
+
|
|
42
|
+
const getProcess = useCallback((event: React.ChangeEvent<HTMLInputElement>): string => {
|
|
43
|
+
const target = event.currentTarget;
|
|
44
|
+
const value: string = process(target.value);
|
|
45
|
+
if (value != target.value) {
|
|
46
|
+
target.value = value;
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}, [process]);
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
const onSelect = useCallback(() => {
|
|
53
|
+
if (draft == null) setDraft(get.toString());
|
|
54
|
+
}, [draft, get]);
|
|
55
|
+
|
|
56
|
+
const onChange = useCallback(
|
|
57
|
+
(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
58
|
+
const result: string = getProcess(event);
|
|
59
|
+
const num: CalculateNumber = getCalculate(result);
|
|
60
|
+
if (num != null && !isNaN(num) && get != num) {
|
|
61
|
+
set(num);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
setDraft(event.currentTarget.value);
|
|
65
|
+
},
|
|
66
|
+
[getProcess, getCalculate, get, set]
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const onBlur = useCallback((event: React.FocusEvent<HTMLInputElement>) => {
|
|
70
|
+
const {value} = event.currentTarget;
|
|
71
|
+
|
|
72
|
+
setDraft(null);
|
|
73
|
+
const num: CalculateNumber = getCalculate(value);
|
|
74
|
+
if (get != num) set(num as number);
|
|
75
|
+
}, [getCalculate, get, set]);
|
|
76
|
+
|
|
77
|
+
const onKeyDown = useCallback((event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
78
|
+
if (lockKeys.includes(event.key) || step == null) {
|
|
79
|
+
event.preventDefault();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const input = event.currentTarget;
|
|
84
|
+
if (event.key === "ArrowUp") {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
const calNum: CalculateNumber = getKeyboardValue(event);
|
|
87
|
+
if (calNum == null) return;
|
|
88
|
+
|
|
89
|
+
const num: number = calNum + step;
|
|
90
|
+
if (max != null && num > max) {
|
|
91
|
+
input.value = max.toString();
|
|
92
|
+
} else {
|
|
93
|
+
input.value = digitRound(num, step).toString();
|
|
94
|
+
}
|
|
95
|
+
} else if (event.key === "ArrowDown") {
|
|
96
|
+
event.preventDefault();
|
|
97
|
+
const calNum: CalculateNumber = getKeyboardValue(event);
|
|
98
|
+
if (calNum == null) return;
|
|
99
|
+
|
|
100
|
+
const num: number = calNum - step;
|
|
101
|
+
if (min != null && num < min) {
|
|
102
|
+
input.value = min.toString();
|
|
103
|
+
} else {
|
|
104
|
+
input.value = digitRound(num, step).toString();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}, [getKeyboardValue, lockKeys, max, min, step]);
|
|
108
|
+
|
|
109
|
+
const value = useMemo(() => (draft == null ? get : draft), [get, draft]);
|
|
110
|
+
const inputLabel: InputLabelType = useMemo(() => (
|
|
111
|
+
(draft == null && (!get || isNaN(get))) ? {} : { shrink: true }
|
|
112
|
+
), [draft, get]);
|
|
113
|
+
|
|
114
|
+
return fastDeepMerge<TextFieldProps>({
|
|
115
|
+
error: !!errorData,
|
|
116
|
+
helperText: errorData,
|
|
117
|
+
value,
|
|
118
|
+
onChange,
|
|
119
|
+
onSelect,
|
|
120
|
+
onBlur,
|
|
121
|
+
slotProps: {
|
|
122
|
+
htmlInput: {step, min, max, minLength, maxLength, onKeyDown},
|
|
123
|
+
inputLabel: inputLabel,
|
|
124
|
+
input: {startAdornment, endAdornment}
|
|
125
|
+
}
|
|
126
|
+
}, (props as TextFieldProps));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const digitRound = (num: number, step: number) => {
|
|
130
|
+
step = Math.abs(step);
|
|
131
|
+
if (step === 0) return num;
|
|
132
|
+
const decimals: number = -Math.floor(Math.log10(step));
|
|
133
|
+
if (decimals > 0) {
|
|
134
|
+
return Number(Math.round(num * Math.pow(10, decimals)) / Math.pow(10, decimals));
|
|
135
|
+
}
|
|
136
|
+
return num;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const useSplitSingleFloatProps = (
|
|
140
|
+
defaultProps: SingleNumberProps,
|
|
141
|
+
customProps: SingleNumberProps,
|
|
142
|
+
): TextFieldProps => useSplitSingleNumberProps(
|
|
143
|
+
defaultProps, customProps,
|
|
144
|
+
processFloat, floatCalculate
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const useSplitSingleIntegerProps = (
|
|
148
|
+
defaultProps: SingleNumberProps,
|
|
149
|
+
customProps: SingleNumberProps,
|
|
150
|
+
): TextFieldProps => useSplitSingleNumberProps(
|
|
151
|
+
defaultProps, customProps,
|
|
152
|
+
processInteger, integerCalculate,
|
|
153
|
+
[".", "e", "E"]
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
export {
|
|
157
|
+
useSplitSingleFloatProps,
|
|
158
|
+
useSplitSingleIntegerProps
|
|
159
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type {TextFieldProps} from "@mui/material";
|
|
2
|
+
import React, {useCallback} from "react";
|
|
3
|
+
import {SingleTextProps} from "../../types";
|
|
4
|
+
import {fastDeepMerge} from "../../utils";
|
|
5
|
+
|
|
6
|
+
const useSplitSingleTextProps = (
|
|
7
|
+
defaultProps: SingleTextProps,
|
|
8
|
+
customProps: SingleTextProps
|
|
9
|
+
): TextFieldProps => {
|
|
10
|
+
const {
|
|
11
|
+
get, set, errorData,
|
|
12
|
+
minLength, maxLength,
|
|
13
|
+
startAdornment, endAdornment,
|
|
14
|
+
...props
|
|
15
|
+
} = fastDeepMerge({...defaultProps}, customProps);
|
|
16
|
+
|
|
17
|
+
const onChange = useCallback(
|
|
18
|
+
(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
19
|
+
set(event.currentTarget.value);
|
|
20
|
+
},
|
|
21
|
+
[set]
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return fastDeepMerge<TextFieldProps>({
|
|
25
|
+
error: !!errorData,
|
|
26
|
+
helperText: errorData,
|
|
27
|
+
value: get,
|
|
28
|
+
onChange,
|
|
29
|
+
slotProps: {
|
|
30
|
+
htmlInput: {minLength, maxLength},
|
|
31
|
+
input: {startAdornment, endAdornment}
|
|
32
|
+
}
|
|
33
|
+
}, (props as TextFieldProps));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default useSplitSingleTextProps;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type {Dispatch, SetStateAction} from "react";
|
|
2
|
+
import {useCallback} from "react";
|
|
3
|
+
import {KeysWithValue} from "../../types";
|
|
4
|
+
|
|
5
|
+
const useObjToSingle = <Type extends object, Target>(
|
|
6
|
+
name: KeysWithValue<Type, Target> | string,
|
|
7
|
+
get: Type,
|
|
8
|
+
set: Dispatch<SetStateAction<Type>>
|
|
9
|
+
): [Target, Dispatch<SetStateAction<Target>>] => {
|
|
10
|
+
const value: Target = (get as Record<string, Target>)?.[name as string];
|
|
11
|
+
|
|
12
|
+
const setValue: Dispatch<SetStateAction<Target>> = useCallback((action: SetStateAction<Target>) => {
|
|
13
|
+
set((state) => {
|
|
14
|
+
const newValue = typeof action === "function"
|
|
15
|
+
? (action as (prev: Target) => Target)((state as Record<string, Target>)?.[name as string])
|
|
16
|
+
: action;
|
|
17
|
+
return ({ ...state, [name]: newValue });
|
|
18
|
+
});
|
|
19
|
+
}, [name, set]);
|
|
20
|
+
return [value, setValue];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default useObjToSingle;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {createContext} from "react";
|
|
2
|
+
import {ThemeProvider} from "@mui/material";
|
|
3
|
+
import type {DefaultTheme} from "@mui/system";
|
|
4
|
+
import {createDefaultProps} from "./createDefaultProps";
|
|
5
|
+
import {FastStartDefaultProps, FastStartProviderProps} from "../types";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const FastStartContext = createContext<FastStartDefaultProps>(createDefaultProps());
|
|
9
|
+
|
|
10
|
+
const FastStartProvider = <T = DefaultTheme>(props: FastStartProviderProps<T>) => {
|
|
11
|
+
const {
|
|
12
|
+
defaultProps,
|
|
13
|
+
...themeProps
|
|
14
|
+
} = props;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<FastStartContext value={defaultProps}>
|
|
18
|
+
<ThemeProvider<T> {...themeProps}/>
|
|
19
|
+
</FastStartContext>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
FastStartContext,
|
|
25
|
+
FastStartProvider
|
|
26
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type {TextFieldProps} from "@mui/material";
|
|
2
|
+
import {BaseNumberProps, FastStartDefaultProps} from "../types";
|
|
3
|
+
import {fastDeepMerge} from "../utils";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export const createDefaultProps = (
|
|
7
|
+
props?: FastStartDefaultProps | undefined
|
|
8
|
+
): FastStartDefaultProps => {
|
|
9
|
+
const textFieldProps: TextFieldProps & BaseNumberProps = {
|
|
10
|
+
fullWidth: true,
|
|
11
|
+
autoComplete: 'off',
|
|
12
|
+
variant: 'outlined',
|
|
13
|
+
size: 'small'
|
|
14
|
+
}
|
|
15
|
+
const floatProps: TextFieldProps & BaseNumberProps = Object.assign({
|
|
16
|
+
inputMode: 'decimal',
|
|
17
|
+
type: 'text',
|
|
18
|
+
step: 0.01,
|
|
19
|
+
def: 0
|
|
20
|
+
}, textFieldProps);
|
|
21
|
+
|
|
22
|
+
const integerProps: TextFieldProps & BaseNumberProps = Object.assign({
|
|
23
|
+
inputMode: 'numeric',
|
|
24
|
+
type: 'text',
|
|
25
|
+
step: 1,
|
|
26
|
+
def: 0
|
|
27
|
+
}, textFieldProps);
|
|
28
|
+
|
|
29
|
+
return fastDeepMerge({
|
|
30
|
+
Single: {
|
|
31
|
+
Float: {...floatProps},
|
|
32
|
+
Integer: {...integerProps},
|
|
33
|
+
Text: {...textFieldProps},
|
|
34
|
+
Checkbox: {size: 'small'},
|
|
35
|
+
CheckIcon: {size: 'small'},
|
|
36
|
+
},
|
|
37
|
+
Obj: {
|
|
38
|
+
Float: {...floatProps},
|
|
39
|
+
Integer: {...integerProps},
|
|
40
|
+
Text: {...textFieldProps},
|
|
41
|
+
Checkbox: {size: 'small'},
|
|
42
|
+
CheckIcon: {size: 'small'},
|
|
43
|
+
}
|
|
44
|
+
} as FastStartDefaultProps, props as FastStartDefaultProps);
|
|
45
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type {SlotProps, TextFieldOwnerState} from "@mui/material";
|
|
2
|
+
import type {Dispatch, SetStateAction} from "react";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import type {InputBaseProps} from "@mui/material/InputBase";
|
|
5
|
+
import type {InputLabelProps} from "@mui/material/InputLabel";
|
|
6
|
+
|
|
7
|
+
type HtmlInputType = SlotProps<React.ElementType<InputBaseProps['inputProps']>, {}, TextFieldOwnerState>;
|
|
8
|
+
type InputLabelType = SlotProps<React.ElementType<InputLabelProps>, {}, TextFieldOwnerState>;
|
|
9
|
+
type KeysWithValue<Type extends object, Target> = {
|
|
10
|
+
[K in keyof Type]: Type[K] extends Target ? K : never
|
|
11
|
+
}[keyof Type];
|
|
12
|
+
|
|
13
|
+
interface BaseProps<Type, Error> {
|
|
14
|
+
get: Type;
|
|
15
|
+
set: Dispatch<SetStateAction<Type>>;
|
|
16
|
+
label?: React.ReactNode;
|
|
17
|
+
errorData?: Error;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type BasePropertyProps<TYPE> = BaseProps<TYPE, string>;
|
|
21
|
+
|
|
22
|
+
interface BaseObjectProps<Type extends object, Target>
|
|
23
|
+
extends BaseProps<Type, Partial<Type> | object> {
|
|
24
|
+
name: KeysWithValue<Type, Target> | string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
interface BaseTextProps {
|
|
29
|
+
minLength?: number;
|
|
30
|
+
maxLength?: number;
|
|
31
|
+
startAdornment?: React.ReactNode;
|
|
32
|
+
endAdornment?: React.ReactNode;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface BaseCheckIconProps {
|
|
36
|
+
on: React.ReactNode;
|
|
37
|
+
off: React.ReactNode;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface BaseNumberProps extends BaseTextProps {
|
|
41
|
+
disappear?: boolean;
|
|
42
|
+
def?: number;
|
|
43
|
+
min?: number;
|
|
44
|
+
max?: number;
|
|
45
|
+
step?: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
interface BaseSelectProps<I> {
|
|
50
|
+
renderMenuItem?: (item: I) => React.ReactNode;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface BaseSelectItemProps<I> extends BaseSelectProps<I> {
|
|
54
|
+
items: I[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type {
|
|
58
|
+
KeysWithValue,
|
|
59
|
+
HtmlInputType,
|
|
60
|
+
InputLabelType,
|
|
61
|
+
BasePropertyProps,
|
|
62
|
+
BaseObjectProps,
|
|
63
|
+
BaseTextProps,
|
|
64
|
+
BaseCheckIconProps,
|
|
65
|
+
BaseNumberProps,
|
|
66
|
+
BaseSelectItemProps
|
|
67
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type {CheckboxProps, IconButtonProps, SelectProps, TextFieldProps, ThemeProviderProps} from "@mui/material";
|
|
2
|
+
import {
|
|
3
|
+
BaseCheckIconProps,
|
|
4
|
+
BaseNumberProps,
|
|
5
|
+
BaseObjectProps,
|
|
6
|
+
BasePropertyProps,
|
|
7
|
+
BaseSelectItemProps,
|
|
8
|
+
BaseTextProps
|
|
9
|
+
} from './props';
|
|
10
|
+
import type {DeepPartial} from './types';
|
|
11
|
+
|
|
12
|
+
export type SingleNumberProps = TextFieldProps & BaseNumberProps & BasePropertyProps<number>;
|
|
13
|
+
export type SingleTextProps = TextFieldProps & BaseTextProps & BasePropertyProps<string>;
|
|
14
|
+
export type SingleCheckboxProps = CheckboxProps & Omit<BasePropertyProps<boolean>, 'errorData'>;
|
|
15
|
+
export type SingleCheckIconProps = IconButtonProps & BaseCheckIconProps & Omit<BasePropertyProps<boolean>, 'errorData' | 'label'>;
|
|
16
|
+
|
|
17
|
+
export type ObjNumberProps<T extends object> = Omit<TextFieldProps, 'name'> & BaseNumberProps & BaseObjectProps<T, number>;
|
|
18
|
+
export type ObjTextProps<T extends object> = Omit<TextFieldProps, 'name'> & BaseTextProps & BaseObjectProps<T, string>;
|
|
19
|
+
export type ObjCheckboxProps<T extends object> = Omit<CheckboxProps, 'name'> & Omit<BaseObjectProps<T, boolean>, 'errorData'>;
|
|
20
|
+
export type ObjCheckIconProps<T extends object> = Omit<IconButtonProps, 'name'> & BaseCheckIconProps & Omit<BaseObjectProps<T, boolean>, 'errorData' | 'label'>;
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
type FastStartDefaultProps = DeepPartial<{
|
|
24
|
+
Single: {
|
|
25
|
+
Float: SingleNumberProps;
|
|
26
|
+
Integer: SingleNumberProps;
|
|
27
|
+
Text: SingleTextProps;
|
|
28
|
+
Checkbox: SingleCheckboxProps;
|
|
29
|
+
CheckIcon: SingleCheckIconProps;
|
|
30
|
+
},
|
|
31
|
+
Obj: {
|
|
32
|
+
Float: ObjNumberProps<object>;
|
|
33
|
+
Integer: ObjNumberProps<object>;
|
|
34
|
+
Text: ObjTextProps<object>;
|
|
35
|
+
Checkbox: ObjCheckboxProps<object>;
|
|
36
|
+
CheckIcon: ObjCheckIconProps<object>;
|
|
37
|
+
}
|
|
38
|
+
}>;
|
|
39
|
+
|
|
40
|
+
interface FastStartProviderProps<Theme> extends ThemeProviderProps<Theme> {
|
|
41
|
+
defaultProps: FastStartDefaultProps;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type {
|
|
45
|
+
FastStartDefaultProps,
|
|
46
|
+
FastStartProviderProps,
|
|
47
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
type CalculateNumber = number | null | undefined;
|
|
2
|
+
|
|
3
|
+
const floatCalculate = (
|
|
4
|
+
value: string | null,
|
|
5
|
+
min: CalculateNumber,
|
|
6
|
+
max: CalculateNumber,
|
|
7
|
+
def: CalculateNumber
|
|
8
|
+
): CalculateNumber => {
|
|
9
|
+
let calc: CalculateNumber = 0;
|
|
10
|
+
if (value == null || isEmpty(value)) {
|
|
11
|
+
calc = def;
|
|
12
|
+
} else {
|
|
13
|
+
for (const token of value.split(/(?=[+-])/g)) {
|
|
14
|
+
if (/^[+-]?\d+\.\d+$/.test(token)) {
|
|
15
|
+
calc += parseFloat(token);
|
|
16
|
+
} else if (/^[+-]?\d+$/.test(token)) {
|
|
17
|
+
calc += parseInt(token, 10);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (calc != null) {
|
|
23
|
+
if (max != null) calc = Math.min(max, calc);
|
|
24
|
+
if (min != null) calc = Math.min(min, calc);
|
|
25
|
+
}
|
|
26
|
+
return calc;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const integerCalculate = (
|
|
30
|
+
value: string | null,
|
|
31
|
+
min: CalculateNumber,
|
|
32
|
+
max: CalculateNumber,
|
|
33
|
+
def: CalculateNumber
|
|
34
|
+
): CalculateNumber => {
|
|
35
|
+
let calc: CalculateNumber = 0;
|
|
36
|
+
if (value == null || isEmpty(value)) {
|
|
37
|
+
calc = def;
|
|
38
|
+
} else {
|
|
39
|
+
for (const token of value.split(/(?=[+-])/g)) {
|
|
40
|
+
if (/^[+-]?\d+$/.test(token)) {
|
|
41
|
+
calc += parseInt(token, 10);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (calc != null) {
|
|
47
|
+
if (max != null) calc = Math.min(max, calc);
|
|
48
|
+
if (min != null) calc = Math.min(min, calc);
|
|
49
|
+
}
|
|
50
|
+
return calc;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const processFloat = (text: string): string => {
|
|
54
|
+
const value: string = text
|
|
55
|
+
.replace(/[^0-9+.-]/g, '')
|
|
56
|
+
.replace(/([+-]){2,}/g, (match, op) => op);
|
|
57
|
+
|
|
58
|
+
let result: string = '';
|
|
59
|
+
let token: string = '';
|
|
60
|
+
let decimalUsed: boolean = false;
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < value.length; i++) {
|
|
63
|
+
const char = value[i];
|
|
64
|
+
|
|
65
|
+
if (char >= '0' && char <= '9') {
|
|
66
|
+
token += char;
|
|
67
|
+
} else if (char === '.') {
|
|
68
|
+
if (!decimalUsed) {
|
|
69
|
+
if (token === '') {
|
|
70
|
+
token = '0';
|
|
71
|
+
}
|
|
72
|
+
token += '.';
|
|
73
|
+
decimalUsed = true;
|
|
74
|
+
}
|
|
75
|
+
} else if (char === '+' || char === '-') {
|
|
76
|
+
if (token !== '') {
|
|
77
|
+
result += token;
|
|
78
|
+
}
|
|
79
|
+
result += char;
|
|
80
|
+
token = '';
|
|
81
|
+
decimalUsed = false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return result + token;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const processInteger = (text: string): string => text
|
|
88
|
+
.replace(/[^0-9+-]/g, '')
|
|
89
|
+
.replace(/\./g, '')
|
|
90
|
+
.replace(/([+-]){2,}/g, (match, op) => op.charAt(0))
|
|
91
|
+
.replace(/^([+-]{2,})/, match => match.charAt(0));
|
|
92
|
+
|
|
93
|
+
function isEmpty(str: string): boolean {
|
|
94
|
+
return str.length === 0 || !str.trim();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export {
|
|
98
|
+
floatCalculate,
|
|
99
|
+
integerCalculate,
|
|
100
|
+
processFloat,
|
|
101
|
+
processInteger
|
|
102
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {BaseObjectProps, KeysWithValue} from "../../types";
|
|
2
|
+
|
|
3
|
+
function errorObjectToString<Type extends object, Target>(
|
|
4
|
+
name: KeysWithValue<Type, Target> | string | undefined,
|
|
5
|
+
data: BaseObjectProps<Type, Target>['errorData']
|
|
6
|
+
): string | undefined {
|
|
7
|
+
return (name != null && typeof data === 'object')
|
|
8
|
+
? (data as Record<string, string>)[name as string]
|
|
9
|
+
: undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
errorObjectToString
|
|
14
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {DeepPartial} from "../../types";
|
|
2
|
+
|
|
3
|
+
type AnyObj = Record<string, any>;
|
|
4
|
+
|
|
5
|
+
function isPlainObject(v: any): v is AnyObj {
|
|
6
|
+
return v !== null && typeof v === "object" && v.constructor === Object;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function isEmpty(v: object): boolean {
|
|
10
|
+
return Object.keys(v).length === 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function fastDeepMerge<T extends object>(target: DeepPartial<T> | undefined, source: T): T {
|
|
14
|
+
if (target === source || !isPlainObject(source) || isEmpty(source)) {
|
|
15
|
+
return target as T;
|
|
16
|
+
} else if (!isPlainObject(target) || isEmpty(target)) {
|
|
17
|
+
return source;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const result: AnyObj = {...target};
|
|
21
|
+
const stack: [AnyObj, AnyObj][] = [[result, source as AnyObj]];
|
|
22
|
+
|
|
23
|
+
while (stack.length) {
|
|
24
|
+
const [tNode, sNode] = stack.pop()!;
|
|
25
|
+
|
|
26
|
+
for (const key in sNode) {
|
|
27
|
+
if (!Object.prototype.hasOwnProperty.call(sNode, key)) continue;
|
|
28
|
+
|
|
29
|
+
const sVal = sNode[key];
|
|
30
|
+
const tVal = tNode[key];
|
|
31
|
+
|
|
32
|
+
if (isPlainObject(tVal) && isPlainObject(sVal)) {
|
|
33
|
+
const copy = {...tVal};
|
|
34
|
+
tNode[key] = copy;
|
|
35
|
+
stack.push([copy, sVal]);
|
|
36
|
+
} else {
|
|
37
|
+
tNode[key] = sVal;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result as T;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
fastDeepMerge
|
|
47
|
+
}
|
package/src.zip
ADDED
|
Binary file
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"useDefineForClassFields": true,
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
+
|
|
6
|
+
"allowImportingTsExtensions": true,
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
|
|
9
|
+
/* Build options */
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"declarationMap": true,
|
|
12
|
+
"emitDeclarationOnly": true,
|
|
13
|
+
"noEmit": false,
|
|
14
|
+
"rootDir": "src",
|
|
15
|
+
"outDir": "dist",
|
|
16
|
+
"declarationDir": "dist",
|
|
17
|
+
|
|
18
|
+
/* Bundler mode */
|
|
19
|
+
"strict": true,
|
|
20
|
+
"jsx": "react-jsx",
|
|
21
|
+
"moduleResolution": "bundler",
|
|
22
|
+
"module": "ESNext",
|
|
23
|
+
"target": "ES2022",
|
|
24
|
+
|
|
25
|
+
/* Interop */
|
|
26
|
+
"allowSyntheticDefaultImports": true,
|
|
27
|
+
"esModuleInterop": true,
|
|
28
|
+
|
|
29
|
+
/* Library options */
|
|
30
|
+
"skipLibCheck": true,
|
|
31
|
+
"skipDefaultLibCheck": true,
|
|
32
|
+
},
|
|
33
|
+
"include": ["src"],
|
|
34
|
+
}
|