@skalfa/skalfa-component 1.0.23 → 1.0.25
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/input/Input.component.js +1 -1
- package/dist/input/InputCheckbox.component.js +1 -1
- package/dist/input/InputCurrency.component.js +1 -1
- package/dist/input/InputDate.component.js +1 -1
- package/dist/input/InputDatetime.component.js +1 -1
- package/dist/input/InputDocument.component.js +1 -1
- package/dist/input/InputImage.component.js +1 -1
- package/dist/input/InputNumber.component.js +1 -1
- package/dist/input/InputPassword.component.js +1 -1
- package/dist/input/InputRadio.component.js +1 -1
- package/dist/input/InputTime.component.js +1 -1
- package/dist/input/Select.component.d.ts +5 -3
- package/dist/input/Select.component.js +155 -54
- package/dist/supervision/FormSupervision.component.d.ts +16 -1
- package/dist/supervision/FormSupervision.component.js +129 -10
- package/package.json +1 -1
- package/src/input/Input.component.tsx +1 -1
- package/src/input/InputCheckbox.component.tsx +1 -1
- package/src/input/InputCurrency.component.tsx +1 -1
- package/src/input/InputDate.component.tsx +1 -1
- package/src/input/InputDatetime.component.tsx +1 -1
- package/src/input/InputDocument.component.tsx +1 -1
- package/src/input/InputImage.component.tsx +1 -1
- package/src/input/InputNumber.component.tsx +1 -1
- package/src/input/InputPassword.component.tsx +1 -1
- package/src/input/InputRadio.component.tsx +1 -1
- package/src/input/InputTime.component.tsx +1 -1
- package/src/input/Select.component.tsx +195 -35
- package/src/supervision/FormSupervision.component.tsx +196 -32
|
@@ -15,7 +15,7 @@ function InputComponent({ label, tip, leftIcon, rightIcon, className = "", value
|
|
|
15
15
|
// =========================>
|
|
16
16
|
// ## Initial
|
|
17
17
|
// =========================>
|
|
18
|
-
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, props.type == "file");
|
|
18
|
+
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, props.type == "file", unregister);
|
|
19
19
|
const randomId = (0, _utils_1.useInputRandomId)();
|
|
20
20
|
// =========================>
|
|
21
21
|
// ## Invalid handler
|
|
@@ -14,7 +14,7 @@ function InputCheckboxComponent({ name, label, tip, vertical, className = "", cl
|
|
|
14
14
|
// =========================>
|
|
15
15
|
// ## initial
|
|
16
16
|
// =========================>
|
|
17
|
-
const inputHandler = (0, _utils_1.useInputHandler)(name, value, validations, register, false);
|
|
17
|
+
const inputHandler = (0, _utils_1.useInputHandler)(name, value, validations, register, false, unregister);
|
|
18
18
|
// =========================>
|
|
19
19
|
// ## Invalid handler
|
|
20
20
|
// =========================>
|
|
@@ -9,7 +9,7 @@ function InputCurrencyComponent({ label, tip, leftIcon, rightIcon, value, invali
|
|
|
9
9
|
// =========================>
|
|
10
10
|
// ## Initial
|
|
11
11
|
// =========================>
|
|
12
|
-
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false);
|
|
12
|
+
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false, unregister);
|
|
13
13
|
const randomId = (0, _utils_1.useInputRandomId)();
|
|
14
14
|
// =========================>
|
|
15
15
|
// ## Invalid handler
|
|
@@ -19,7 +19,7 @@ function InputDateComponent({ label, tip, leftIcon, rightIcon, value, invalid, v
|
|
|
19
19
|
// =========================>
|
|
20
20
|
// ## Initial
|
|
21
21
|
// =========================>
|
|
22
|
-
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false);
|
|
22
|
+
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false, unregister);
|
|
23
23
|
const randomId = (0, _utils_1.useInputRandomId)();
|
|
24
24
|
// =========================>
|
|
25
25
|
// ## Invalid handler
|
|
@@ -20,7 +20,7 @@ function InputDatetimeComponent({ label, tip, leftIcon, rightIcon, value, invali
|
|
|
20
20
|
// =========================>
|
|
21
21
|
// ## Initial
|
|
22
22
|
// =========================>
|
|
23
|
-
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false);
|
|
23
|
+
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false, unregister);
|
|
24
24
|
const randomId = (0, _utils_1.useInputRandomId)();
|
|
25
25
|
// =========================>
|
|
26
26
|
// ## Invalid handler
|
|
@@ -23,7 +23,7 @@ function InputDocumentComponent({ label, tip, leftIcon, rightIcon, className = "
|
|
|
23
23
|
// =========================>
|
|
24
24
|
// ## Initial
|
|
25
25
|
// =========================>
|
|
26
|
-
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, props.type == "file");
|
|
26
|
+
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, props.type == "file", unregister);
|
|
27
27
|
const randomId = (0, _utils_1.useInputRandomId)();
|
|
28
28
|
// =========================>
|
|
29
29
|
// ## Invalid handler
|
|
@@ -17,7 +17,7 @@ const InputImageComponent = ({ name, label, tip, value, disabled, aspect = "1/1"
|
|
|
17
17
|
const [drag, setDrag] = (0, react_1.useState)(false);
|
|
18
18
|
const [cropSrc, setCropSrc] = (0, react_1.useState)(null);
|
|
19
19
|
const [openCrop, setOpenCrop] = (0, react_1.useState)(false);
|
|
20
|
-
const inputHandler = (0, _utils_1.useInputHandler)(name, value, validations, register, true);
|
|
20
|
+
const inputHandler = (0, _utils_1.useInputHandler)(name, value, validations, register, true, unregister);
|
|
21
21
|
const [invalidMessage, setInvalidMessage] = (0, _utils_1.useValidation)(inputHandler.value, validations, invalid, inputHandler.idle);
|
|
22
22
|
(0, react_1.useEffect)(() => {
|
|
23
23
|
if (value) {
|
|
@@ -9,7 +9,7 @@ function InputNumberComponent({ label, tip, leftIcon, rightIcon, value, invalid,
|
|
|
9
9
|
// =========================>
|
|
10
10
|
// ## Initial
|
|
11
11
|
// =========================>
|
|
12
|
-
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false);
|
|
12
|
+
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false, unregister);
|
|
13
13
|
const randomId = (0, _utils_1.useInputRandomId)();
|
|
14
14
|
// =========================>
|
|
15
15
|
// ## Invalid handler
|
|
@@ -15,7 +15,7 @@ function InputPasswordComponent({ label, tip, leftIcon, rightIcon, value, invali
|
|
|
15
15
|
// =========================>
|
|
16
16
|
// ## Initial
|
|
17
17
|
// =========================>
|
|
18
|
-
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false);
|
|
18
|
+
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false, unregister);
|
|
19
19
|
const randomId = (0, _utils_1.useInputRandomId)();
|
|
20
20
|
const randomConfirmId = (0, _utils_1.useInputRandomId)();
|
|
21
21
|
// =========================>
|
|
@@ -12,7 +12,7 @@ function InputRadioComponent({ name, label, tip, vertical, value, disabled, inva
|
|
|
12
12
|
// =========================>
|
|
13
13
|
// ## Initial
|
|
14
14
|
// =========================>
|
|
15
|
-
const inputHandler = (0, _utils_1.useInputHandler)(name, value, validations, register, false);
|
|
15
|
+
const inputHandler = (0, _utils_1.useInputHandler)(name, value, validations, register, false, unregister);
|
|
16
16
|
// =========================>
|
|
17
17
|
// ## Invalid handler
|
|
18
18
|
// =========================>
|
|
@@ -15,7 +15,7 @@ function InputTimeComponent({ label, tip, leftIcon, rightIcon, value, invalid, v
|
|
|
15
15
|
// =========================>
|
|
16
16
|
// ## Initial
|
|
17
17
|
// =========================>
|
|
18
|
-
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false);
|
|
18
|
+
const inputHandler = (0, _utils_1.useInputHandler)(props.name, value, validations, register, false, unregister);
|
|
19
19
|
const randomId = (0, _utils_1.useInputRandomId)();
|
|
20
20
|
// =========================>
|
|
21
21
|
// ## Invalid handler
|
|
@@ -13,7 +13,7 @@ export interface SelectProps {
|
|
|
13
13
|
tip?: string | ReactNode;
|
|
14
14
|
leftIcon?: any;
|
|
15
15
|
rightIcon?: any;
|
|
16
|
-
value?: string | number | (string | number)[]
|
|
16
|
+
value?: string | number | (string | number)[] | Record<string, any>;
|
|
17
17
|
invalid?: string;
|
|
18
18
|
disabled?: boolean;
|
|
19
19
|
validations?: ValidationRules;
|
|
@@ -36,7 +36,9 @@ export interface SelectProps {
|
|
|
36
36
|
tempOptions?: SelectOptionProps[];
|
|
37
37
|
newOption?: SelectOptionProps;
|
|
38
38
|
maxShowOption?: number;
|
|
39
|
-
|
|
39
|
+
creatable?: boolean | string;
|
|
40
|
+
creatableLabel?: string;
|
|
41
|
+
onChange?: (value: any, data?: any) => any;
|
|
40
42
|
register?: (name: string, validations?: ValidationRules) => void;
|
|
41
43
|
unregister?: (name: string) => void;
|
|
42
44
|
onFocus?: () => void;
|
|
@@ -44,4 +46,4 @@ export interface SelectProps {
|
|
|
44
46
|
/** Use custom class with: "label::", "tip::", "error::", "icon::", "suggest::", "suggest-item::". */
|
|
45
47
|
className?: string;
|
|
46
48
|
}
|
|
47
|
-
export declare function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, value, invalid, disabled, validations, multiple, autoFocus, clearable, options, searchable, serverOptionControl, idbOptionControl, serverSearchable, includedOptions, exceptOptions, tempOptions, newOption, maxShowOption, register, unregister, onChange, onFocus, onBlur, className, }: SelectProps): import("@types/react").JSX.Element;
|
|
49
|
+
export declare function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, value, invalid, disabled, validations, multiple, autoFocus, clearable, options, searchable, serverOptionControl, idbOptionControl, serverSearchable, includedOptions, exceptOptions, tempOptions, newOption, maxShowOption, creatable, creatableLabel, register, unregister, onChange, onFocus, onBlur, className, }: SelectProps): import("@types/react").JSX.Element;
|
|
@@ -6,8 +6,9 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
6
6
|
const skalfa_icon_1 = require("@skalfa/skalfa-icon");
|
|
7
7
|
const react_1 = require("react");
|
|
8
8
|
const _utils_1 = require("@utils");
|
|
9
|
+
const OutsideClick_component_1 = require("../wrap/OutsideClick.component");
|
|
9
10
|
;
|
|
10
|
-
function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, value, invalid, disabled, validations, multiple, autoFocus, clearable, options = [], searchable, serverOptionControl, idbOptionControl, serverSearchable, includedOptions = [], exceptOptions = [], tempOptions, newOption, maxShowOption = 10, register, unregister, onChange, onFocus, onBlur, className = "", }) {
|
|
11
|
+
function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, value, invalid, disabled, validations, multiple, autoFocus, clearable, options = [], searchable, serverOptionControl, idbOptionControl, serverSearchable, includedOptions = [], exceptOptions = [], tempOptions, newOption, maxShowOption = 10, creatable, creatableLabel, register, unregister, onChange, onFocus, onBlur, className = "", }) {
|
|
11
12
|
const [inputShowValue, setInputShowValue] = (0, react_1.useState)("");
|
|
12
13
|
const [keydown, setKeydown] = (0, react_1.useState)(false);
|
|
13
14
|
const [useTemp, setUseTemp] = (0, react_1.useState)(true);
|
|
@@ -18,39 +19,73 @@ function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, v
|
|
|
18
19
|
const [showOption, setShowOption] = (0, react_1.useState)(false);
|
|
19
20
|
const [keyword, setKeyword] = (0, react_1.useState)("");
|
|
20
21
|
const [keywordSearch] = (0, _utils_1.useLazySearch)(keyword);
|
|
22
|
+
const creatableKey = typeof creatable === "string" ? (creatable || "name") : (creatable ? "name" : null);
|
|
23
|
+
const [isCreatingNew, setIsCreatingNew] = (0, react_1.useState)(false);
|
|
24
|
+
const [customText, setCustomText] = (0, react_1.useState)("");
|
|
25
|
+
const [dropdownCustomText, setDropdownCustomText] = (0, react_1.useState)("");
|
|
26
|
+
const isFocusingCreatable = (0, react_1.useRef)(false);
|
|
27
|
+
const handleCreateNewSubmit = () => {
|
|
28
|
+
if (!dropdownCustomText.trim() || !creatableKey)
|
|
29
|
+
return;
|
|
30
|
+
isFocusingCreatable.current = false;
|
|
31
|
+
const valText = dropdownCustomText.trim();
|
|
32
|
+
setIsCreatingNew(true);
|
|
33
|
+
setCustomText(valText);
|
|
34
|
+
setInputShowValue(valText);
|
|
35
|
+
setShowOption(false);
|
|
36
|
+
setFilteredOptions([]);
|
|
37
|
+
const objVal = { [creatableKey]: valText };
|
|
38
|
+
inputHandler.setValue(objVal);
|
|
39
|
+
inputHandler.setIdle(false);
|
|
40
|
+
onChange?.(objVal);
|
|
41
|
+
};
|
|
21
42
|
// =========================>
|
|
22
43
|
// ## Initial
|
|
23
44
|
// =========================>
|
|
24
|
-
const inputHandler = (0, _utils_1.useInputHandler)(name, value, validations, register, false);
|
|
45
|
+
const inputHandler = (0, _utils_1.useInputHandler)(name, value, validations, register, false, unregister);
|
|
25
46
|
const randomId = (0, _utils_1.useInputRandomId)();
|
|
26
47
|
// =========================>
|
|
27
48
|
// ## Invalid handler
|
|
28
49
|
// =========================>
|
|
29
50
|
const [invalidMessage] = (0, _utils_1.useValidation)(inputHandler.value, validations, invalid, inputHandler.idle);
|
|
30
51
|
// =========================>
|
|
31
|
-
// ##
|
|
52
|
+
// ## options handler
|
|
32
53
|
// =========================>
|
|
54
|
+
const optionsKey = typeof options === "object" ? JSON.stringify(options) : String(options || "");
|
|
55
|
+
const includedOptionsKey = typeof includedOptions === "object" ? JSON.stringify(includedOptions) : String(includedOptions || "");
|
|
56
|
+
const exceptOptionsKey = typeof exceptOptions === "object" ? JSON.stringify(exceptOptions) : String(exceptOptions || "");
|
|
33
57
|
(0, react_1.useEffect)(() => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
inputHandler.setIdle(false);
|
|
58
|
+
let base = options?.length ? [...options, ...includedOptions] : [...includedOptions];
|
|
59
|
+
if (exceptOptions?.length) {
|
|
60
|
+
base = base.filter((op) => !exceptOptions.includes(op.value));
|
|
38
61
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
}, [value, dataOptions]);
|
|
62
|
+
setDataOptions(base);
|
|
63
|
+
}, [optionsKey, includedOptionsKey, exceptOptionsKey]);
|
|
64
|
+
const dataOptionsKey = dataOptions.map((op) => String(op.value)).join("|");
|
|
44
65
|
// =========================>
|
|
45
|
-
// ##
|
|
66
|
+
// ## change value handler
|
|
46
67
|
// =========================>
|
|
47
68
|
(0, react_1.useEffect)(() => {
|
|
48
|
-
|
|
49
|
-
|
|
69
|
+
const currentVal = inputHandler.value;
|
|
70
|
+
if (currentVal && typeof currentVal === "object" && !Array.isArray(currentVal) && creatableKey && creatableKey in currentVal) {
|
|
71
|
+
setIsCreatingNew(true);
|
|
72
|
+
const text = String(currentVal[creatableKey] || "");
|
|
73
|
+
setCustomText(text);
|
|
74
|
+
setInputShowValue(text);
|
|
75
|
+
}
|
|
76
|
+
else if (currentVal !== undefined && currentVal !== null && currentVal !== "" && typeof currentVal !== "object") {
|
|
77
|
+
setIsCreatingNew(false);
|
|
78
|
+
const matched = (newOption ? [newOption, ...dataOptions] : dataOptions)?.find((option) => option.value == currentVal);
|
|
79
|
+
setInputShowValue(matched?.label || currentVal);
|
|
80
|
+
}
|
|
81
|
+
else if (!currentVal && !isCreatingNew) {
|
|
82
|
+
setInputShowValue("");
|
|
83
|
+
}
|
|
84
|
+
}, [inputHandler.value, dataOptionsKey, creatableKey]);
|
|
50
85
|
const filterOption = (e) => {
|
|
51
|
-
if (dataOptions?.length) {
|
|
86
|
+
if (dataOptions?.length || creatableKey) {
|
|
52
87
|
let newFilteredOptions = [];
|
|
53
|
-
if (searchable && !serverSearchable) {
|
|
88
|
+
if (searchable && !serverSearchable && dataOptions?.length) {
|
|
54
89
|
if (e.target.value) {
|
|
55
90
|
newFilteredOptions = dataOptions.filter((Option) => Option.label?.toLowerCase().indexOf(e.target.value.toLowerCase()) > -1).slice(0, maxShowOption);
|
|
56
91
|
}
|
|
@@ -59,7 +94,7 @@ function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, v
|
|
|
59
94
|
}
|
|
60
95
|
}
|
|
61
96
|
else {
|
|
62
|
-
newFilteredOptions = dataOptions;
|
|
97
|
+
newFilteredOptions = dataOptions || [];
|
|
63
98
|
}
|
|
64
99
|
setActiveOption(-1);
|
|
65
100
|
setFilteredOptions(newFilteredOptions);
|
|
@@ -73,6 +108,16 @@ function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, v
|
|
|
73
108
|
setActiveOption(-1);
|
|
74
109
|
setFilteredOptions([]);
|
|
75
110
|
setShowOption(false);
|
|
111
|
+
if (resultValue?.value === "__CREATE_NEW__" && creatableKey) {
|
|
112
|
+
setIsCreatingNew(true);
|
|
113
|
+
setCustomText("");
|
|
114
|
+
setInputShowValue("");
|
|
115
|
+
const objVal = { [creatableKey]: "" };
|
|
116
|
+
inputHandler.setValue(objVal);
|
|
117
|
+
onChange?.(objVal, resultValue);
|
|
118
|
+
e.preventDefault();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
76
121
|
if (!multiple) {
|
|
77
122
|
setInputShowValue(resultValue?.label || inputShowValue);
|
|
78
123
|
inputHandler.setValue(resultValue?.value || inputShowValue);
|
|
@@ -176,25 +221,42 @@ function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, v
|
|
|
176
221
|
}
|
|
177
222
|
}
|
|
178
223
|
}, [keywordSearch, serverOptionControl?.path, serverOptionControl?.url]);
|
|
179
|
-
return ((0, jsx_runtime_1.jsx)(
|
|
224
|
+
return ((0, jsx_runtime_1.jsx)(OutsideClick_component_1.OutsideClickComponent, { onOutsideClick: () => {
|
|
225
|
+
isFocusingCreatable.current = false;
|
|
226
|
+
setShowOption(false);
|
|
227
|
+
inputHandler.setFocus(false);
|
|
228
|
+
}, children: (0, jsx_runtime_1.jsxs)("div", { className: "input-container", children: [(0, jsx_runtime_1.jsxs)("label", { htmlFor: randomId, className: (0, _utils_1.cn)("input-label", disabled && "input-label-disabled", inputHandler.focus && "input-label-focus", invalidMessage && "input-label-error", (0, _utils_1.pcn)(className, "label"), disabled && (0, _utils_1.pcn)(className, "label", "disabled"), inputHandler.focus && (0, _utils_1.pcn)(className, "label", "focus"), invalidMessage && (0, _utils_1.pcn)(className, "label", "error")), children: [label, validations && _utils_1.validation.hasRules(validations, "required") && (0, jsx_runtime_1.jsx)("span", { className: "text-danger ml-1", children: "*" })] }), tip && ((0, jsx_runtime_1.jsx)("small", { className: (0, _utils_1.cn)("input-tip", disabled && "input-tip-disabled", (0, _utils_1.pcn)(className, "tip"), disabled && (0, _utils_1.pcn)(className, "tip", "disabled")), children: tip })), (0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [isCreatingNew && typeof inputHandler.value === "object" && inputHandler.value !== null ? (Object.entries(inputHandler.value).map(([subK, subV]) => ((0, jsx_runtime_1.jsx)("input", { type: "hidden", name: `${name.endsWith("_id") ? name.slice(0, -3) : name}[${subK}]`, value: String(subV ?? "") }, subK)))) : ((0, jsx_runtime_1.jsx)("input", { type: "hidden", value: !multiple ? (typeof inputHandler.value === "object" ? JSON.stringify(inputHandler.value) : String(inputHandler.value ?? "")) : Array().concat(inputHandler.value).map((val) => String(val)), name: name })), isCreatingNew && ((0, jsx_runtime_1.jsx)("div", { className: "absolute left-1.5 top-1/2 -translate-y-1/2 bg-stroke text-sm px-3.5 py-1.5 rounded-lg select-none pointer-events-none z-10 font-normal", children: "Baru" })), (0, jsx_runtime_1.jsx)("input", { type: "text", readOnly: !searchable, id: randomId, placeholder: !inputHandler.value || (Array.isArray(inputHandler.value) && !inputHandler.value.length) ? placeholder : "", disabled: disabled, className: (0, _utils_1.cn)("input cursor-pointer", leftIcon && "input-with-left-icon", rightIcon && "input-with-right-icon", isCreatingNew && "pl-[4.8rem]", invalidMessage && "input-error", (0, _utils_1.pcn)(className, "input"), invalidMessage && (0, _utils_1.pcn)(className, "input", "error")), value: (useTemp && tempOptions ? tempOptions.at(0)?.label : serverSearchable ? keyword : (isCreatingNew ? customText : inputShowValue)), onChange: (e) => {
|
|
180
229
|
setUseTemp(false);
|
|
181
230
|
searchable && setInputShowValue(e.target.value);
|
|
182
231
|
serverSearchable && setKeyword(e.target.value);
|
|
183
232
|
inputHandler.setIdle(false);
|
|
184
|
-
dataOptions?.length && filterOption(e);
|
|
233
|
+
(dataOptions?.length || creatableKey) && filterOption(e);
|
|
185
234
|
}, onFocus: (e) => {
|
|
186
235
|
setUseTemp(false);
|
|
187
236
|
inputHandler.setFocus(true);
|
|
188
237
|
onFocus?.();
|
|
189
|
-
dataOptions?.length && filterOption(e);
|
|
238
|
+
(dataOptions?.length || creatableKey) && filterOption(e);
|
|
190
239
|
searchable && e.target.select();
|
|
191
240
|
}, onBlur: (e) => {
|
|
192
241
|
setUseTemp(false);
|
|
242
|
+
if (isFocusingCreatable.current)
|
|
243
|
+
return;
|
|
244
|
+
if (isCreatingNew) {
|
|
245
|
+
setTimeout(() => {
|
|
246
|
+
if (!isFocusingCreatable.current) {
|
|
247
|
+
inputHandler.setFocus(false);
|
|
248
|
+
}
|
|
249
|
+
}, 100);
|
|
250
|
+
onBlur?.();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
193
253
|
const value = e.target.value;
|
|
194
254
|
const valueOption = dataOptions?.find((option) => option.label?.toLowerCase() == value?.toLowerCase());
|
|
195
255
|
if (!keydown) {
|
|
196
256
|
if (!multiple) {
|
|
197
257
|
setTimeout(() => {
|
|
258
|
+
if (isFocusingCreatable.current)
|
|
259
|
+
return;
|
|
198
260
|
if (valueOption?.value) {
|
|
199
261
|
setInputShowValue(valueOption.label);
|
|
200
262
|
inputHandler.setValue(valueOption.value);
|
|
@@ -216,7 +278,9 @@ function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, v
|
|
|
216
278
|
}
|
|
217
279
|
}
|
|
218
280
|
setTimeout(() => {
|
|
219
|
-
|
|
281
|
+
if (!isFocusingCreatable.current) {
|
|
282
|
+
inputHandler.setFocus(false);
|
|
283
|
+
}
|
|
220
284
|
}, 100);
|
|
221
285
|
onBlur?.();
|
|
222
286
|
}, onKeyDown: (e) => {
|
|
@@ -233,42 +297,79 @@ function SelectComponent({ name, label, placeholder, tip, leftIcon, rightIcon, v
|
|
|
233
297
|
}
|
|
234
298
|
} })] }, key));
|
|
235
299
|
}) }) })), leftIcon && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { className: (0, _utils_1.cn)("input-icon", "input-icon-left", disabled && "input-icon-disabled", inputHandler.focus && "input-icon-focus", (0, _utils_1.pcn)(className, "icon"), disabled && (0, _utils_1.pcn)(className, "icon", "disabled"), inputHandler.focus && (0, _utils_1.pcn)(className, "icon", "focus")), icon: leftIcon })), !multiple && clearable && inputHandler.value && ((0, jsx_runtime_1.jsx)("div", { className: (0, _utils_1.cn)("input-icon", "input-icon-clear", disabled && "input-icon-disabled", (0, _utils_1.pcn)(className, "icon"), disabled && (0, _utils_1.pcn)(className, "icon", "disabled")), onClick: () => {
|
|
300
|
+
setIsCreatingNew(false);
|
|
301
|
+
setCustomText("");
|
|
302
|
+
setDropdownCustomText("");
|
|
236
303
|
setInputShowValue("");
|
|
237
304
|
inputHandler.setValue("");
|
|
238
305
|
onChange?.("");
|
|
239
|
-
}, children: (0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { icon: "solid/times" }) })), (0, jsx_runtime_1.jsx)("label", { htmlFor: randomId, className: (0, _utils_1.cn)("input-icon", "input-icon-right", "select-icon-dropdown", disabled && "input-icon-disabled", (0, _utils_1.pcn)(className, "icon"), disabled && (0, _utils_1.pcn)(className, "icon", "disabled")),
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
306
|
+
}, children: (0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { icon: "solid/times" }) })), (0, jsx_runtime_1.jsx)("label", { htmlFor: randomId, className: (0, _utils_1.cn)("input-icon", "input-icon-right", "select-icon-dropdown cursor-pointer", disabled && "input-icon-disabled", (0, _utils_1.pcn)(className, "icon"), disabled && (0, _utils_1.pcn)(className, "icon", "disabled")), onClick: (e) => {
|
|
307
|
+
(dataOptions?.length || creatableKey) && filterOption(e);
|
|
308
|
+
}, children: (0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { icon: "solid/chevron-down" }) })] }), (!!dataOptions?.length || creatableKey) && showOption && !loadingOption && ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsxs)("ul", { className: (0, _utils_1.cn)("input-suggest-container scroll-sm", inputHandler.focus && "input-suggest-container-active", (0, _utils_1.pcn)(className, "suggest")), children: [creatableKey && ((0, jsx_runtime_1.jsxs)("li", { className: "p-2 border-b border-stroke flex items-center gap-2 cursor-default bg-white sticky top-0 z-10 mb-2", onMouseDown: (e) => {
|
|
309
|
+
isFocusingCreatable.current = true;
|
|
310
|
+
e.stopPropagation();
|
|
311
|
+
}, onMouseUp: (e) => {
|
|
312
|
+
e.stopPropagation();
|
|
313
|
+
}, onClick: (e) => {
|
|
314
|
+
e.stopPropagation();
|
|
315
|
+
}, children: [(0, jsx_runtime_1.jsx)("input", { type: "text", className: "input flex-1 text-sm py-1.5 px-3 rounded-lg border border-stroke focus:outline-none focus:border-primary placeholder:text-slate-300 text-slate-700 bg-white", placeholder: creatableLabel || "Masukkan pilihan baru...", value: dropdownCustomText, onMouseDown: (e) => {
|
|
316
|
+
isFocusingCreatable.current = true;
|
|
317
|
+
e.stopPropagation();
|
|
318
|
+
}, onFocus: () => {
|
|
319
|
+
isFocusingCreatable.current = true;
|
|
320
|
+
}, onBlur: () => {
|
|
321
|
+
setTimeout(() => {
|
|
322
|
+
if (!isFocusingCreatable.current) {
|
|
323
|
+
setShowOption(false);
|
|
324
|
+
inputHandler.setFocus(false);
|
|
325
|
+
}
|
|
326
|
+
}, 200);
|
|
327
|
+
}, onChange: (e) => setDropdownCustomText(e.target.value), onKeyDown: (e) => {
|
|
328
|
+
e.stopPropagation();
|
|
329
|
+
if (e.key === "Enter") {
|
|
330
|
+
e.preventDefault();
|
|
331
|
+
handleCreateNewSubmit();
|
|
332
|
+
}
|
|
333
|
+
} }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "bg-light-primary text-primary p-2 rounded-lg flex items-center justify-center transition-colors shrink-0 shadow-sm cursor-pointer border-none", onMouseDown: (e) => {
|
|
334
|
+
isFocusingCreatable.current = true;
|
|
335
|
+
e.stopPropagation();
|
|
336
|
+
}, onClick: (e) => {
|
|
337
|
+
e.stopPropagation();
|
|
338
|
+
handleCreateNewSubmit();
|
|
339
|
+
}, children: (0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { icon: "solid/check", className: "w-4 h-4" }) })] })), (newOption ? [newOption, ...filteredOptions] : filteredOptions).map((option, key) => {
|
|
340
|
+
const selected = !isCreatingNew && (!!((typeof inputHandler.value == "string" || typeof inputHandler.value == "number") && inputHandler.value == option.value) ||
|
|
341
|
+
(Array.isArray(inputHandler.value) && Array().concat(inputHandler.value).find((val) => val == option.value)));
|
|
342
|
+
return ((0, jsx_runtime_1.jsxs)("li", { className: (0, _utils_1.cn)("input-suggest", (key == activeOption || selected) && "input-suggest-active", (0, _utils_1.pcn)(className, "suggest-item"), (key == activeOption || selected) && (0, _utils_1.pcn)(className, "suggest-item", "active")), onMouseDown: () => {
|
|
343
|
+
setKeydown(true);
|
|
344
|
+
setTimeout(() => inputHandler.setFocus(true), 110);
|
|
345
|
+
}, onMouseUp: () => {
|
|
346
|
+
setKeydown(false);
|
|
347
|
+
setActiveOption(key);
|
|
348
|
+
setFilteredOptions([]);
|
|
349
|
+
setShowOption(false);
|
|
350
|
+
setIsCreatingNew(false);
|
|
351
|
+
if (!multiple) {
|
|
352
|
+
setInputShowValue(option.label);
|
|
353
|
+
serverSearchable && setKeyword(option.label);
|
|
354
|
+
inputHandler.setValue(option.value);
|
|
355
|
+
onChange?.(option.value, option);
|
|
265
356
|
}
|
|
266
357
|
else {
|
|
267
|
-
|
|
268
|
-
|
|
358
|
+
const values = Array.isArray(inputHandler.value)
|
|
359
|
+
? Array().concat(inputHandler.value).filter((val) => val != option.value)
|
|
360
|
+
: [];
|
|
361
|
+
setInputShowValue("");
|
|
362
|
+
serverSearchable && setKeyword("");
|
|
363
|
+
if (Array.isArray(inputHandler.value) && Array().concat(inputHandler.value).find((val) => val == option.value)) {
|
|
364
|
+
inputHandler.setValue(values);
|
|
365
|
+
onChange?.(values);
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
inputHandler.setValue([...Array().concat(values), option.value]);
|
|
369
|
+
onChange?.([...Array().concat(values), option.value]);
|
|
370
|
+
}
|
|
269
371
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}) }) })), invalidMessage && ((0, jsx_runtime_1.jsx)("small", { className: (0, _utils_1.cn)("input-error-message", (0, _utils_1.pcn)(className, "error")), children: invalidMessage }))] }) }));
|
|
372
|
+
setTimeout(() => inputHandler.setFocus(false), 120);
|
|
373
|
+
}, children: [selected && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { icon: "solid/check", className: "select-suggest-check" })), option.label] }, key));
|
|
374
|
+
})] }) })), invalidMessage && ((0, jsx_runtime_1.jsx)("small", { className: (0, _utils_1.cn)("input-error-message", (0, _utils_1.pcn)(className, "error")), children: invalidMessage }))] }) }));
|
|
274
375
|
}
|
|
@@ -24,6 +24,7 @@ type ClusterConstruction = {
|
|
|
24
24
|
tip: string;
|
|
25
25
|
fields: FormType[];
|
|
26
26
|
wrap: boolean;
|
|
27
|
+
min?: number;
|
|
27
28
|
/** Use custom class with: "label::", "tip::", "error::", "icon::", "suggest::", "suggest-item::". */
|
|
28
29
|
className: string;
|
|
29
30
|
};
|
|
@@ -44,12 +45,26 @@ type ConstructionMap = {
|
|
|
44
45
|
custom: formCustomConstructionProps;
|
|
45
46
|
};
|
|
46
47
|
type TypeKeys = keyof ConstructionMap;
|
|
48
|
+
export type WatchContext = {
|
|
49
|
+
values: Record<string, any>;
|
|
50
|
+
self: string;
|
|
51
|
+
prev: WatchAction;
|
|
52
|
+
};
|
|
53
|
+
export type WatchAction = {
|
|
54
|
+
disabled?: boolean;
|
|
55
|
+
hidden?: boolean;
|
|
56
|
+
value?: any;
|
|
57
|
+
required?: boolean;
|
|
58
|
+
readonly?: boolean;
|
|
59
|
+
reset?: boolean;
|
|
60
|
+
};
|
|
47
61
|
export interface FormType<T extends TypeKeys = keyof ConstructionMap> {
|
|
48
62
|
col?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | string;
|
|
49
63
|
className?: string;
|
|
50
64
|
construction?: ConstructionMap[T];
|
|
51
65
|
type?: T;
|
|
52
|
-
onHide?: (values: any) => boolean;
|
|
66
|
+
onHide?: (values: Record<string, any>) => boolean;
|
|
67
|
+
onWatch?: (ctx: WatchContext) => WatchAction | undefined;
|
|
53
68
|
}
|
|
54
69
|
export interface formSupervisionProps {
|
|
55
70
|
title?: string;
|