mui-fast-start 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/README.md +403 -403
- package/README_KR.md +403 -403
- package/dist/components/Object/Select/ObjSelectRecord.d.ts +2 -1
- package/dist/components/Object/Select/ObjSelectRecord.d.ts.map +1 -1
- package/dist/components/Single/Select/SingleSelectRecord.d.ts +2 -1
- package/dist/components/Single/Select/SingleSelectRecord.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/styles/FastStartProps.d.ts +2 -1
- package/dist/styles/FastStartProps.d.ts.map +1 -1
- package/dist/types/props.d.ts +1 -1
- package/dist/types/props.d.ts.map +1 -1
- package/dist/types/props.internal.d.ts +1 -1
- package/dist/types/props.internal.d.ts.map +1 -1
- package/dist/types/provider.d.ts +2 -1
- package/dist/types/provider.d.ts.map +1 -1
- package/examples/basic/README.md +73 -73
- package/examples/basic/eslint.config.js +23 -23
- package/examples/basic/index.html +13 -13
- package/examples/basic/package.json +37 -37
- package/examples/basic/src/App.css +4 -4
- package/examples/basic/src/App.tsx +28 -28
- package/examples/basic/src/index.css +29 -29
- package/examples/basic/src/main.tsx +50 -50
- package/examples/basic/src/pages/ObjPage.tsx +175 -175
- package/examples/basic/src/pages/SinglePage.tsx +137 -137
- package/examples/basic/tsconfig.app.json +43 -43
- package/examples/basic/tsconfig.json +7 -7
- package/examples/basic/tsconfig.node.json +40 -40
- package/examples/basic/vite.config.ts +28 -28
- package/mui-fast-start-0.1.4.tgz +0 -0
- package/package.json +67 -67
- package/src/components/Object/Checkbox/ObjCheckIcon.tsx +29 -29
- package/src/components/Object/Checkbox/ObjCheckbox.tsx +31 -31
- package/src/components/Object/Select/ObjSelectOne.tsx +33 -33
- package/src/components/Object/Select/ObjSelectRecord.tsx +33 -33
- package/src/components/Object/Textfield/ObjNumber.tsx +51 -51
- package/src/components/Object/Textfield/ObjText.tsx +29 -29
- package/src/components/Single/Checkbox/SingleCheckIcon.tsx +27 -27
- package/src/components/Single/Checkbox/SingleCheckbox.tsx +33 -33
- package/src/components/Single/Select/BaseSingleSelect.tsx +45 -45
- package/src/components/Single/Select/SingleSelectOne.tsx +56 -56
- package/src/components/Single/Select/SingleSelectRecord.tsx +51 -51
- package/src/components/Single/TextField/SingleNumber.tsx +18 -18
- package/src/components/Single/TextField/SingleText.tsx +13 -13
- package/src/components/index.ts +15 -15
- package/src/hooks/index.ts +3 -3
- package/src/hooks/splits/useSplitNumberProps.ts +161 -161
- package/src/hooks/splits/useSplitTextProps.ts +36 -36
- package/src/hooks/state/useObjToSingle.ts +24 -24
- package/src/index.ts +7 -7
- package/src/styles/FastStartProps.ts +82 -81
- package/src/styles/FastStartProvider.tsx +25 -25
- package/src/types/index.ts +3 -3
- package/src/types/props.internal.ts +21 -21
- package/src/types/props.ts +81 -81
- package/src/types/provider.ts +72 -71
- package/src/types/types.ts +9 -9
- package/src/utils/index.ts +2 -2
- package/src/utils/number/calculate.ts +102 -102
- package/src/utils/object/error.ts +15 -15
- package/src/utils/object/merge.ts +47 -47
- package/tsconfig.json +34 -34
- package/tsconfig.lib.json +9 -9
- package/vite.config.ts +35 -35
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import {MenuItem, SelectProps} from "@mui/material";
|
|
2
|
-
import {MfsSingleSelectOneProps} from "../../../types";
|
|
3
|
-
import React, {useContext, useMemo} from "react";
|
|
4
|
-
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
5
|
-
import BaseSingleSelect from "./BaseSingleSelect.tsx";
|
|
6
|
-
|
|
7
|
-
export type SingleSelectOneProps<Item> = SelectProps & MfsSingleSelectOneProps<Item>;
|
|
8
|
-
|
|
9
|
-
export const SingleSelectOne = <Item,>(customProps: SingleSelectOneProps<Item>) => {
|
|
10
|
-
const defaultProps = useContext(FastStartContext)?.Single?.MfsSelectOne;
|
|
11
|
-
const {
|
|
12
|
-
get, set, err, label,
|
|
13
|
-
items, renderMenuItem,
|
|
14
|
-
emptyItem, emptyValue,
|
|
15
|
-
getKey, ...props
|
|
16
|
-
} = defaultProps == null
|
|
17
|
-
? customProps
|
|
18
|
-
: Object.assign({...defaultProps}, customProps);
|
|
19
|
-
|
|
20
|
-
const getKeyOrValue = useMemo(() => (
|
|
21
|
-
getKey ?? ((item: Item) => item as string | number)
|
|
22
|
-
), [getKey]);
|
|
23
|
-
|
|
24
|
-
const onChange: SelectProps['onChange'] = (event) => {
|
|
25
|
-
const value = event.target.value;
|
|
26
|
-
if (getKey == null) {
|
|
27
|
-
set((value == "" ? emptyValue : value) as Item);
|
|
28
|
-
} else {
|
|
29
|
-
const item: Item | undefined = items.find((item: Item) => getKeyOrValue(item) === value);
|
|
30
|
-
set(item as Item);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const MenuItems = useMemo(() => {
|
|
35
|
-
if (renderMenuItem != null) {
|
|
36
|
-
return items.map(renderMenuItem);
|
|
37
|
-
} else {
|
|
38
|
-
return items.map((item) => {
|
|
39
|
-
const key = getKeyOrValue(item);
|
|
40
|
-
return <MenuItem key={key} value={key}>{key}</MenuItem>;
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
}, [getKeyOrValue, items, renderMenuItem]);
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<BaseSingleSelect
|
|
47
|
-
label={label}
|
|
48
|
-
items={MenuItems}
|
|
49
|
-
emptyItem={emptyItem}
|
|
50
|
-
get={get}
|
|
51
|
-
err={err}
|
|
52
|
-
onChange={onChange}
|
|
53
|
-
selectProps={props}
|
|
54
|
-
/>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
1
|
+
import {MenuItem, SelectProps} from "@mui/material";
|
|
2
|
+
import {MfsSingleSelectOneProps} from "../../../types";
|
|
3
|
+
import React, {useContext, useMemo} from "react";
|
|
4
|
+
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
5
|
+
import BaseSingleSelect from "./BaseSingleSelect.tsx";
|
|
6
|
+
|
|
7
|
+
export type SingleSelectOneProps<Item> = SelectProps & MfsSingleSelectOneProps<Item>;
|
|
8
|
+
|
|
9
|
+
export const SingleSelectOne = <Item,>(customProps: SingleSelectOneProps<Item>) => {
|
|
10
|
+
const defaultProps = useContext(FastStartContext)?.Single?.MfsSelectOne;
|
|
11
|
+
const {
|
|
12
|
+
get, set, err, label,
|
|
13
|
+
items, renderMenuItem,
|
|
14
|
+
emptyItem, emptyValue,
|
|
15
|
+
getKey, ...props
|
|
16
|
+
} = defaultProps == null
|
|
17
|
+
? customProps
|
|
18
|
+
: Object.assign({...defaultProps}, customProps);
|
|
19
|
+
|
|
20
|
+
const getKeyOrValue = useMemo(() => (
|
|
21
|
+
getKey ?? ((item: Item) => item as string | number)
|
|
22
|
+
), [getKey]);
|
|
23
|
+
|
|
24
|
+
const onChange: SelectProps['onChange'] = (event) => {
|
|
25
|
+
const value = event.target.value;
|
|
26
|
+
if (getKey == null) {
|
|
27
|
+
set((value == "" ? emptyValue : value) as Item);
|
|
28
|
+
} else {
|
|
29
|
+
const item: Item | undefined = items.find((item: Item) => getKeyOrValue(item) === value);
|
|
30
|
+
set(item as Item);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const MenuItems = useMemo(() => {
|
|
35
|
+
if (renderMenuItem != null) {
|
|
36
|
+
return items.map(renderMenuItem);
|
|
37
|
+
} else {
|
|
38
|
+
return items.map((item) => {
|
|
39
|
+
const key = getKeyOrValue(item);
|
|
40
|
+
return <MenuItem key={key} value={key}>{key}</MenuItem>;
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
}, [getKeyOrValue, items, renderMenuItem]);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<BaseSingleSelect
|
|
47
|
+
label={label}
|
|
48
|
+
items={MenuItems}
|
|
49
|
+
emptyItem={emptyItem}
|
|
50
|
+
get={get}
|
|
51
|
+
err={err}
|
|
52
|
+
onChange={onChange}
|
|
53
|
+
selectProps={props}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import {MenuItem, SelectProps} from "@mui/material";
|
|
2
|
-
import {MfsSingleSelectRecordProps} from "../../../types";
|
|
3
|
-
import React, {useContext, useMemo} from "react";
|
|
4
|
-
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
5
|
-
import BaseSingleSelect from "./BaseSingleSelect.tsx";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export const SingleSelectRecord = <
|
|
9
|
-
T extends Record<string,
|
|
10
|
-
Value = keyof T | undefined | null
|
|
11
|
-
>(customProps: SelectProps & MfsSingleSelectRecordProps<T, Value>) => {
|
|
12
|
-
const defaultProps = useContext(FastStartContext)?.Single?.MfsSelectRecord;
|
|
13
|
-
const {
|
|
14
|
-
get, set, err, label,
|
|
15
|
-
items, renderMenuItem,
|
|
16
|
-
emptyItem, emptyValue,
|
|
17
|
-
...props
|
|
18
|
-
} = defaultProps == null
|
|
19
|
-
? customProps
|
|
20
|
-
: Object.assign({...defaultProps}, customProps);
|
|
21
|
-
|
|
22
|
-
const onChange: SelectProps['onChange'] = (event) => {
|
|
23
|
-
const value = event.target.value;
|
|
24
|
-
set((value == "" ? emptyValue : value) as Value);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const MenuItems = useMemo(() => {
|
|
28
|
-
if (renderMenuItem != null) {
|
|
29
|
-
return Object.entries(items).map(([key, value], i) => (
|
|
30
|
-
renderMenuItem(key, value as T[keyof T], i)
|
|
31
|
-
));
|
|
32
|
-
} else {
|
|
33
|
-
return Object.entries(items).map(([key, value]) => (
|
|
34
|
-
<MenuItem key={key} value={key}>
|
|
35
|
-
{value
|
|
36
|
-
</MenuItem>
|
|
37
|
-
));
|
|
38
|
-
}
|
|
39
|
-
}, [items, renderMenuItem]);
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<BaseSingleSelect
|
|
43
|
-
label={label}
|
|
44
|
-
items={MenuItems}
|
|
45
|
-
emptyItem={emptyItem}
|
|
46
|
-
get={get}
|
|
47
|
-
err={err}
|
|
48
|
-
onChange={onChange}
|
|
49
|
-
selectProps={props}
|
|
50
|
-
/>
|
|
51
|
-
)
|
|
1
|
+
import {MenuItem, SelectProps} from "@mui/material";
|
|
2
|
+
import {MfsSingleSelectRecordProps} from "../../../types";
|
|
3
|
+
import React, {useContext, useMemo} from "react";
|
|
4
|
+
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
5
|
+
import BaseSingleSelect from "./BaseSingleSelect.tsx";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export const SingleSelectRecord = <
|
|
9
|
+
T extends Record<string, React.ReactNode>,
|
|
10
|
+
Value = keyof T | undefined | null
|
|
11
|
+
>(customProps: SelectProps & MfsSingleSelectRecordProps<T, Value>) => {
|
|
12
|
+
const defaultProps = useContext(FastStartContext)?.Single?.MfsSelectRecord;
|
|
13
|
+
const {
|
|
14
|
+
get, set, err, label,
|
|
15
|
+
items, renderMenuItem,
|
|
16
|
+
emptyItem, emptyValue,
|
|
17
|
+
...props
|
|
18
|
+
} = defaultProps == null
|
|
19
|
+
? customProps
|
|
20
|
+
: Object.assign({...defaultProps}, customProps);
|
|
21
|
+
|
|
22
|
+
const onChange: SelectProps['onChange'] = (event) => {
|
|
23
|
+
const value = event.target.value;
|
|
24
|
+
set((value == "" ? emptyValue : value) as Value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const MenuItems = useMemo(() => {
|
|
28
|
+
if (renderMenuItem != null) {
|
|
29
|
+
return Object.entries(items).map(([key, value], i) => (
|
|
30
|
+
renderMenuItem(key, value as T[keyof T], i)
|
|
31
|
+
));
|
|
32
|
+
} else {
|
|
33
|
+
return Object.entries(items).map(([key, value]) => (
|
|
34
|
+
<MenuItem key={key} value={key}>
|
|
35
|
+
{value}
|
|
36
|
+
</MenuItem>
|
|
37
|
+
));
|
|
38
|
+
}
|
|
39
|
+
}, [items, renderMenuItem]);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<BaseSingleSelect
|
|
43
|
+
label={label}
|
|
44
|
+
items={MenuItems}
|
|
45
|
+
emptyItem={emptyItem}
|
|
46
|
+
get={get}
|
|
47
|
+
err={err}
|
|
48
|
+
onChange={onChange}
|
|
49
|
+
selectProps={props}
|
|
50
|
+
/>
|
|
51
|
+
)
|
|
52
52
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {useContext} from "react";
|
|
2
|
-
import {TextField, TextFieldProps} from "@mui/material";
|
|
3
|
-
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
4
|
-
import {MfsSingleNumberProps} from "../../../types";
|
|
5
|
-
import {useSplitSingleFloatProps, useSplitSingleIntegerProps} from "../../../hooks";
|
|
6
|
-
|
|
7
|
-
export type SingleNumberProps = TextFieldProps & MfsSingleNumberProps;
|
|
8
|
-
|
|
9
|
-
export const SingleFloat = (customProps: SingleNumberProps) => {
|
|
10
|
-
const defaultProps = useContext(FastStartContext)?.Single?.MfsFloat;
|
|
11
|
-
const props = useSplitSingleFloatProps(defaultProps, customProps);
|
|
12
|
-
return <TextField {...props}/>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export const SingleInteger = (customProps: SingleNumberProps) => {
|
|
16
|
-
const defaultProps = useContext(FastStartContext)?.Single?.MfsInteger;
|
|
17
|
-
const props = useSplitSingleIntegerProps(defaultProps, customProps);
|
|
18
|
-
return <TextField {...props}/>;
|
|
1
|
+
import {useContext} from "react";
|
|
2
|
+
import {TextField, TextFieldProps} from "@mui/material";
|
|
3
|
+
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
4
|
+
import {MfsSingleNumberProps} from "../../../types";
|
|
5
|
+
import {useSplitSingleFloatProps, useSplitSingleIntegerProps} from "../../../hooks";
|
|
6
|
+
|
|
7
|
+
export type SingleNumberProps = TextFieldProps & MfsSingleNumberProps;
|
|
8
|
+
|
|
9
|
+
export const SingleFloat = (customProps: SingleNumberProps) => {
|
|
10
|
+
const defaultProps = useContext(FastStartContext)?.Single?.MfsFloat;
|
|
11
|
+
const props = useSplitSingleFloatProps(defaultProps, customProps);
|
|
12
|
+
return <TextField {...props}/>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const SingleInteger = (customProps: SingleNumberProps) => {
|
|
16
|
+
const defaultProps = useContext(FastStartContext)?.Single?.MfsInteger;
|
|
17
|
+
const props = useSplitSingleIntegerProps(defaultProps, customProps);
|
|
18
|
+
return <TextField {...props}/>;
|
|
19
19
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {useContext} from "react";
|
|
2
|
-
import useSplitTextProps from '../../../hooks/splits/useSplitTextProps.ts';
|
|
3
|
-
import {TextField, TextFieldProps} from "@mui/material";
|
|
4
|
-
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
5
|
-
import {MfsSingleTextProps} from "../../../types";
|
|
6
|
-
|
|
7
|
-
export type SingleTextProps = TextFieldProps & MfsSingleTextProps;
|
|
8
|
-
|
|
9
|
-
export const SingleText = (customProps: SingleTextProps) => {
|
|
10
|
-
const defaultProps = useContext(FastStartContext)?.Single?.MfsText;
|
|
11
|
-
const props = useSplitTextProps(defaultProps, customProps);
|
|
12
|
-
return <TextField {...props}/>;
|
|
13
|
-
}
|
|
1
|
+
import {useContext} from "react";
|
|
2
|
+
import useSplitTextProps from '../../../hooks/splits/useSplitTextProps.ts';
|
|
3
|
+
import {TextField, TextFieldProps} from "@mui/material";
|
|
4
|
+
import {FastStartContext} from "../../../styles/FastStartProvider.tsx";
|
|
5
|
+
import {MfsSingleTextProps} from "../../../types";
|
|
6
|
+
|
|
7
|
+
export type SingleTextProps = TextFieldProps & MfsSingleTextProps;
|
|
8
|
+
|
|
9
|
+
export const SingleText = (customProps: SingleTextProps) => {
|
|
10
|
+
const defaultProps = useContext(FastStartContext)?.Single?.MfsText;
|
|
11
|
+
const props = useSplitTextProps(defaultProps, customProps);
|
|
12
|
+
return <TextField {...props}/>;
|
|
13
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
// Single components
|
|
2
|
-
export { SingleCheckbox } from './Single/Checkbox/SingleCheckbox.tsx';
|
|
3
|
-
export { SingleCheckIcon } from './Single/Checkbox/SingleCheckIcon.tsx';
|
|
4
|
-
export { SingleFloat, SingleInteger } from './Single/TextField/SingleNumber.tsx';
|
|
5
|
-
export { SingleText } from './Single/TextField/SingleText.tsx';
|
|
6
|
-
export { SingleSelectOne } from './Single/Select/SingleSelectOne.tsx';
|
|
7
|
-
export { SingleSelectRecord } from './Single/Select/SingleSelectRecord.tsx';
|
|
8
|
-
|
|
9
|
-
// Object components
|
|
10
|
-
export { ObjCheckbox } from './Object/Checkbox/ObjCheckbox.tsx';
|
|
11
|
-
export { ObjCheckIcon } from './Object/Checkbox/ObjCheckIcon.tsx';
|
|
12
|
-
export { ObjFloat, ObjInteger } from './Object/Textfield/ObjNumber.tsx';
|
|
13
|
-
export { ObjText } from './Object/Textfield/ObjText.tsx';
|
|
14
|
-
export { ObjSelectOne } from './Object/Select/ObjSelectOne.tsx';
|
|
15
|
-
export { ObjSelectRecord } from './Object/Select/ObjSelectRecord.tsx';
|
|
1
|
+
// Single components
|
|
2
|
+
export { SingleCheckbox } from './Single/Checkbox/SingleCheckbox.tsx';
|
|
3
|
+
export { SingleCheckIcon } from './Single/Checkbox/SingleCheckIcon.tsx';
|
|
4
|
+
export { SingleFloat, SingleInteger } from './Single/TextField/SingleNumber.tsx';
|
|
5
|
+
export { SingleText } from './Single/TextField/SingleText.tsx';
|
|
6
|
+
export { SingleSelectOne } from './Single/Select/SingleSelectOne.tsx';
|
|
7
|
+
export { SingleSelectRecord } from './Single/Select/SingleSelectRecord.tsx';
|
|
8
|
+
|
|
9
|
+
// Object components
|
|
10
|
+
export { ObjCheckbox } from './Object/Checkbox/ObjCheckbox.tsx';
|
|
11
|
+
export { ObjCheckIcon } from './Object/Checkbox/ObjCheckIcon.tsx';
|
|
12
|
+
export { ObjFloat, ObjInteger } from './Object/Textfield/ObjNumber.tsx';
|
|
13
|
+
export { ObjText } from './Object/Textfield/ObjText.tsx';
|
|
14
|
+
export { ObjSelectOne } from './Object/Select/ObjSelectOne.tsx';
|
|
15
|
+
export { ObjSelectRecord } from './Object/Select/ObjSelectRecord.tsx';
|
package/src/hooks/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export * from './splits/useSplitNumberProps.ts';
|
|
2
|
-
export * from './splits/useSplitTextProps.ts';
|
|
3
|
-
export * from './state/useObjToSingle';
|
|
1
|
+
export * from './splits/useSplitNumberProps.ts';
|
|
2
|
+
export * from './splits/useSplitTextProps.ts';
|
|
3
|
+
export * from './state/useObjToSingle';
|
|
@@ -1,161 +1,161 @@
|
|
|
1
|
-
import type {TextFieldProps} from "@mui/material";
|
|
2
|
-
import {fastDeepMerge, floatCalculate, integerCalculate, processFloat, processInteger} from "../../utils";
|
|
3
|
-
import React, {useCallback, useState} from "react";
|
|
4
|
-
import {MfsSingleNumberProps} from "../../types";
|
|
5
|
-
import {SingleNumberProps} from "../../components/Single/TextField/SingleNumber.tsx";
|
|
6
|
-
|
|
7
|
-
type CalculateNumber = number | null | undefined;
|
|
8
|
-
type CalculateFunction = (
|
|
9
|
-
value: string | null,
|
|
10
|
-
min: CalculateNumber,
|
|
11
|
-
max: CalculateNumber,
|
|
12
|
-
def: CalculateNumber
|
|
13
|
-
) => CalculateNumber;
|
|
14
|
-
|
|
15
|
-
const useSplitNumberProps = (
|
|
16
|
-
defaultProps: Partial<MfsSingleNumberProps> | undefined,
|
|
17
|
-
customProps: SingleNumberProps,
|
|
18
|
-
process: (value: string) => string,
|
|
19
|
-
calculate: CalculateFunction,
|
|
20
|
-
lockKeys: string[] = []
|
|
21
|
-
): TextFieldProps => {
|
|
22
|
-
const [draft, setDraft] = useState<string | null>(null);
|
|
23
|
-
const {
|
|
24
|
-
get, set, err,
|
|
25
|
-
minLength, maxLength,
|
|
26
|
-
startAdornment, endAdornment,
|
|
27
|
-
def, min, max, step,
|
|
28
|
-
...props
|
|
29
|
-
} = (defaultProps == null)
|
|
30
|
-
? customProps
|
|
31
|
-
: Object.assign({...defaultProps}, customProps);
|
|
32
|
-
|
|
33
|
-
const getCalculate = (
|
|
34
|
-
value: string | null
|
|
35
|
-
) => calculate(value, min, max, def);
|
|
36
|
-
|
|
37
|
-
const getKeyboardValue = (
|
|
38
|
-
event: React.KeyboardEvent<HTMLInputElement>
|
|
39
|
-
) => {
|
|
40
|
-
const {value, valueAsNumber} = event.currentTarget;
|
|
41
|
-
return isNaN(valueAsNumber) ? getCalculate(value) : valueAsNumber;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const getProcess = useCallback(
|
|
45
|
-
(event: React.ChangeEvent<HTMLInputElement>): string => {
|
|
46
|
-
const target = event.currentTarget;
|
|
47
|
-
const value: string = process(target.value);
|
|
48
|
-
if (value != target.value) {
|
|
49
|
-
target.value = value;
|
|
50
|
-
}
|
|
51
|
-
return value;
|
|
52
|
-
},
|
|
53
|
-
[process]
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const onSelect = () => {
|
|
57
|
-
if (draft == null) setDraft(get.toString());
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const onChange = (
|
|
61
|
-
event: React.ChangeEvent<HTMLInputElement>
|
|
62
|
-
) => {
|
|
63
|
-
const result: string = getProcess(event);
|
|
64
|
-
const num: CalculateNumber = getCalculate(result);
|
|
65
|
-
if (num != null && !isNaN(num) && get != num) {
|
|
66
|
-
set(num);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
setDraft(event.currentTarget.value);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const onBlur = (
|
|
73
|
-
event: React.FocusEvent<HTMLInputElement>
|
|
74
|
-
) => {
|
|
75
|
-
const {value} = event.currentTarget;
|
|
76
|
-
|
|
77
|
-
setDraft(null);
|
|
78
|
-
const num: CalculateNumber = getCalculate(value);
|
|
79
|
-
if (get != num) set(num as number);
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const onKeyDown = (
|
|
83
|
-
event: React.KeyboardEvent<HTMLInputElement>
|
|
84
|
-
) => {
|
|
85
|
-
if (lockKeys.includes(event.key) || step == null) {
|
|
86
|
-
event.preventDefault();
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const input = event.currentTarget;
|
|
91
|
-
if (event.key === "ArrowUp") {
|
|
92
|
-
event.preventDefault();
|
|
93
|
-
const calNum: CalculateNumber = getKeyboardValue(event);
|
|
94
|
-
if (calNum == null) return;
|
|
95
|
-
|
|
96
|
-
const num: number = calNum + step;
|
|
97
|
-
if (max != null && num > max) {
|
|
98
|
-
input.value = max.toString();
|
|
99
|
-
} else {
|
|
100
|
-
input.value = digitRound(num, step).toString();
|
|
101
|
-
}
|
|
102
|
-
} else if (event.key === "ArrowDown") {
|
|
103
|
-
event.preventDefault();
|
|
104
|
-
const calNum: CalculateNumber = getKeyboardValue(event);
|
|
105
|
-
if (calNum == null) return;
|
|
106
|
-
|
|
107
|
-
const num: number = calNum - step;
|
|
108
|
-
if (min != null && num < min) {
|
|
109
|
-
input.value = min.toString();
|
|
110
|
-
} else {
|
|
111
|
-
input.value = digitRound(num, step).toString();
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
return fastDeepMerge<TextFieldProps>({
|
|
117
|
-
error: !!err,
|
|
118
|
-
helperText: err,
|
|
119
|
-
value: (draft == null ? get : draft),
|
|
120
|
-
onChange,
|
|
121
|
-
onSelect,
|
|
122
|
-
onBlur,
|
|
123
|
-
slotProps: {
|
|
124
|
-
htmlInput: {step, min, max, minLength, maxLength, onKeyDown},
|
|
125
|
-
inputLabel: (draft == null && (!get || isNaN(get))) ? {} : { shrink: true },
|
|
126
|
-
input: {startAdornment, endAdornment}
|
|
127
|
-
}
|
|
128
|
-
}, (props as TextFieldProps));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const digitRound = (num: number, step: number) => {
|
|
132
|
-
step = Math.abs(step);
|
|
133
|
-
if (step === 0) return num;
|
|
134
|
-
const decimals: number = -Math.floor(Math.log10(step));
|
|
135
|
-
if (decimals > 0) {
|
|
136
|
-
return Number(Math.round(num * Math.pow(10, decimals)) / Math.pow(10, decimals));
|
|
137
|
-
}
|
|
138
|
-
return num;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const useSplitSingleFloatProps = (
|
|
142
|
-
defaultProps: Partial<MfsSingleNumberProps> | undefined,
|
|
143
|
-
customProps: SingleNumberProps,
|
|
144
|
-
): TextFieldProps => useSplitNumberProps(
|
|
145
|
-
defaultProps, customProps,
|
|
146
|
-
processFloat, floatCalculate
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
const useSplitSingleIntegerProps = (
|
|
150
|
-
defaultProps: Partial<MfsSingleNumberProps> | undefined,
|
|
151
|
-
customProps: SingleNumberProps,
|
|
152
|
-
): TextFieldProps => useSplitNumberProps(
|
|
153
|
-
defaultProps, customProps,
|
|
154
|
-
processInteger, integerCalculate,
|
|
155
|
-
[".", "e", "E"]
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
export {
|
|
159
|
-
useSplitSingleFloatProps,
|
|
160
|
-
useSplitSingleIntegerProps
|
|
161
|
-
};
|
|
1
|
+
import type {TextFieldProps} from "@mui/material";
|
|
2
|
+
import {fastDeepMerge, floatCalculate, integerCalculate, processFloat, processInteger} from "../../utils";
|
|
3
|
+
import React, {useCallback, useState} from "react";
|
|
4
|
+
import {MfsSingleNumberProps} from "../../types";
|
|
5
|
+
import {SingleNumberProps} from "../../components/Single/TextField/SingleNumber.tsx";
|
|
6
|
+
|
|
7
|
+
type CalculateNumber = number | null | undefined;
|
|
8
|
+
type CalculateFunction = (
|
|
9
|
+
value: string | null,
|
|
10
|
+
min: CalculateNumber,
|
|
11
|
+
max: CalculateNumber,
|
|
12
|
+
def: CalculateNumber
|
|
13
|
+
) => CalculateNumber;
|
|
14
|
+
|
|
15
|
+
const useSplitNumberProps = (
|
|
16
|
+
defaultProps: Partial<MfsSingleNumberProps> | undefined,
|
|
17
|
+
customProps: SingleNumberProps,
|
|
18
|
+
process: (value: string) => string,
|
|
19
|
+
calculate: CalculateFunction,
|
|
20
|
+
lockKeys: string[] = []
|
|
21
|
+
): TextFieldProps => {
|
|
22
|
+
const [draft, setDraft] = useState<string | null>(null);
|
|
23
|
+
const {
|
|
24
|
+
get, set, err,
|
|
25
|
+
minLength, maxLength,
|
|
26
|
+
startAdornment, endAdornment,
|
|
27
|
+
def, min, max, step,
|
|
28
|
+
...props
|
|
29
|
+
} = (defaultProps == null)
|
|
30
|
+
? customProps
|
|
31
|
+
: Object.assign({...defaultProps}, customProps);
|
|
32
|
+
|
|
33
|
+
const getCalculate = (
|
|
34
|
+
value: string | null
|
|
35
|
+
) => calculate(value, min, max, def);
|
|
36
|
+
|
|
37
|
+
const getKeyboardValue = (
|
|
38
|
+
event: React.KeyboardEvent<HTMLInputElement>
|
|
39
|
+
) => {
|
|
40
|
+
const {value, valueAsNumber} = event.currentTarget;
|
|
41
|
+
return isNaN(valueAsNumber) ? getCalculate(value) : valueAsNumber;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const getProcess = useCallback(
|
|
45
|
+
(event: React.ChangeEvent<HTMLInputElement>): string => {
|
|
46
|
+
const target = event.currentTarget;
|
|
47
|
+
const value: string = process(target.value);
|
|
48
|
+
if (value != target.value) {
|
|
49
|
+
target.value = value;
|
|
50
|
+
}
|
|
51
|
+
return value;
|
|
52
|
+
},
|
|
53
|
+
[process]
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const onSelect = () => {
|
|
57
|
+
if (draft == null) setDraft(get.toString());
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const onChange = (
|
|
61
|
+
event: React.ChangeEvent<HTMLInputElement>
|
|
62
|
+
) => {
|
|
63
|
+
const result: string = getProcess(event);
|
|
64
|
+
const num: CalculateNumber = getCalculate(result);
|
|
65
|
+
if (num != null && !isNaN(num) && get != num) {
|
|
66
|
+
set(num);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setDraft(event.currentTarget.value);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const onBlur = (
|
|
73
|
+
event: React.FocusEvent<HTMLInputElement>
|
|
74
|
+
) => {
|
|
75
|
+
const {value} = event.currentTarget;
|
|
76
|
+
|
|
77
|
+
setDraft(null);
|
|
78
|
+
const num: CalculateNumber = getCalculate(value);
|
|
79
|
+
if (get != num) set(num as number);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const onKeyDown = (
|
|
83
|
+
event: React.KeyboardEvent<HTMLInputElement>
|
|
84
|
+
) => {
|
|
85
|
+
if (lockKeys.includes(event.key) || step == null) {
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const input = event.currentTarget;
|
|
91
|
+
if (event.key === "ArrowUp") {
|
|
92
|
+
event.preventDefault();
|
|
93
|
+
const calNum: CalculateNumber = getKeyboardValue(event);
|
|
94
|
+
if (calNum == null) return;
|
|
95
|
+
|
|
96
|
+
const num: number = calNum + step;
|
|
97
|
+
if (max != null && num > max) {
|
|
98
|
+
input.value = max.toString();
|
|
99
|
+
} else {
|
|
100
|
+
input.value = digitRound(num, step).toString();
|
|
101
|
+
}
|
|
102
|
+
} else if (event.key === "ArrowDown") {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
const calNum: CalculateNumber = getKeyboardValue(event);
|
|
105
|
+
if (calNum == null) return;
|
|
106
|
+
|
|
107
|
+
const num: number = calNum - step;
|
|
108
|
+
if (min != null && num < min) {
|
|
109
|
+
input.value = min.toString();
|
|
110
|
+
} else {
|
|
111
|
+
input.value = digitRound(num, step).toString();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return fastDeepMerge<TextFieldProps>({
|
|
117
|
+
error: !!err,
|
|
118
|
+
helperText: err,
|
|
119
|
+
value: (draft == null ? get : draft),
|
|
120
|
+
onChange,
|
|
121
|
+
onSelect,
|
|
122
|
+
onBlur,
|
|
123
|
+
slotProps: {
|
|
124
|
+
htmlInput: {step, min, max, minLength, maxLength, onKeyDown},
|
|
125
|
+
inputLabel: (draft == null && (!get || isNaN(get))) ? {} : { shrink: true },
|
|
126
|
+
input: {startAdornment, endAdornment}
|
|
127
|
+
}
|
|
128
|
+
}, (props as TextFieldProps));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const digitRound = (num: number, step: number) => {
|
|
132
|
+
step = Math.abs(step);
|
|
133
|
+
if (step === 0) return num;
|
|
134
|
+
const decimals: number = -Math.floor(Math.log10(step));
|
|
135
|
+
if (decimals > 0) {
|
|
136
|
+
return Number(Math.round(num * Math.pow(10, decimals)) / Math.pow(10, decimals));
|
|
137
|
+
}
|
|
138
|
+
return num;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const useSplitSingleFloatProps = (
|
|
142
|
+
defaultProps: Partial<MfsSingleNumberProps> | undefined,
|
|
143
|
+
customProps: SingleNumberProps,
|
|
144
|
+
): TextFieldProps => useSplitNumberProps(
|
|
145
|
+
defaultProps, customProps,
|
|
146
|
+
processFloat, floatCalculate
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const useSplitSingleIntegerProps = (
|
|
150
|
+
defaultProps: Partial<MfsSingleNumberProps> | undefined,
|
|
151
|
+
customProps: SingleNumberProps,
|
|
152
|
+
): TextFieldProps => useSplitNumberProps(
|
|
153
|
+
defaultProps, customProps,
|
|
154
|
+
processInteger, integerCalculate,
|
|
155
|
+
[".", "e", "E"]
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
export {
|
|
159
|
+
useSplitSingleFloatProps,
|
|
160
|
+
useSplitSingleIntegerProps
|
|
161
|
+
};
|