This repository has been archived by the owner on Feb 10, 2024. It is now read-only.
/
IntegerField.tsx
120 lines (104 loc) · 3.9 KB
/
IntegerField.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Copyright (c) 2022. Heusala Group Oy <info@heusalagroup.fi>. All rights reserved.
// Copyright (c) 2021. Sendanor <info@sendanor.fi>. All rights reserved.
import { ReactNode } from 'react';
import { IntegerFieldModel } from "../../../types/items/IntegerFieldModel";
import { LogService } from "../../../../core/LogService";
import { trim } from "../../../../core/functions/trim";
import { FormFieldState, stringifyFormFieldState } from "../../../types/FormFieldState";
import { ThemeService } from "../../../services/ThemeService";
import { stringifyStyleScheme, StyleScheme } from "../../../types/StyleScheme";
import {
FIELD_CLASS_NAME,
INTEGER_FIELD_CLASS_NAME
} from "../../../constants/hgClassName";
import { useNumberField } from "../../../hooks/field/useNumberField";
import { FieldChangeCallback } from "../../../hooks/field/useFieldChangeCallback";
import './IntegerField.scss';
import { isSafeInteger } from "../../../../core/types/Number";
const LOG = LogService.createLogger('IntegerField');
const DEFAULT_PLACEHOLDER = '123';
const COMPONENT_CLASS_NAME = INTEGER_FIELD_CLASS_NAME;
const COMPONENT_INPUT_TYPE = "text";
export interface IntegerFieldProps {
readonly className ?: string;
readonly style ?: StyleScheme;
readonly label ?: string;
readonly placeholder ?: string;
readonly model ?: IntegerFieldModel;
readonly value ?: number;
readonly change ?: FieldChangeCallback<number | undefined>;
readonly changeState ?: FieldChangeCallback<FormFieldState>;
readonly children ?: ReactNode;
}
export interface IntegerFieldProps {
}
export function IntegerField (props: IntegerFieldProps) {
const className = props?.className;
const styleScheme = props?.style ?? ThemeService.getStyleScheme();
const placeholder = props.placeholder ?? props.model?.placeholder ?? DEFAULT_PLACEHOLDER;
const label = props.label ?? props.model?.label ?? '';
const {
fieldState,
value,
onChangeCallback
} = useNumberField(
label,
props?.model?.key ?? '',
props?.change,
props?.changeState,
props?.value,
props?.model?.required ?? false,
props?.model?.minValue,
props?.model?.maxValue,
toInteger,
stringifyInteger
);
return (
<label
className={
`${COMPONENT_CLASS_NAME} ${FIELD_CLASS_NAME}`
+ ` ${FIELD_CLASS_NAME}-style-${stringifyStyleScheme(styleScheme)}`
+ ` ${FIELD_CLASS_NAME}-state-${stringifyFormFieldState(fieldState)}`
+ ` ${className ? ` ${className}` : ''}`
}
>
{label ? (
<span className={
COMPONENT_CLASS_NAME+'-label'
+ ` ${FIELD_CLASS_NAME}-label`
}>{label}</span>
) : null}
<input
className={
COMPONENT_CLASS_NAME+'-input'
+ ` ${FIELD_CLASS_NAME}-input`
}
type={COMPONENT_INPUT_TYPE}
autoComplete="off"
placeholder={placeholder}
value={value}
onChange={onChangeCallback}
readOnly={ props?.change === undefined }
/>
{props?.children}
</label>
);
}
function toInteger (value : string | undefined) : number | undefined {
try {
if (value === undefined) return undefined;
value = trim(value);
if (value === '') return undefined;
const parsedValue = parseInt(value, 10);
if ( !isSafeInteger(parsedValue) ) {
return undefined;
}
return parsedValue;
} catch (err) {
LOG.warn(`Error while parsing string as integer "${value}": `, err);
return undefined;
}
}
function stringifyInteger (value: number | undefined) : string {
return `${value ?? ''}`;
}