@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.
@@ -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
- onChange?: (value: string | number | (string | number)[], data?: any) => any;
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
- // ## change value handler
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
- if (value) {
35
- inputHandler.setValue(value);
36
- Array.isArray(dataOptions) && setInputShowValue((newOption ? [newOption, ...dataOptions] : dataOptions)?.find((option) => option.value == value)?.label || "");
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
- else {
40
- inputHandler.setValue("");
41
- setInputShowValue("");
42
- }
43
- }, [value, dataOptions]);
62
+ setDataOptions(base);
63
+ }, [optionsKey, includedOptionsKey, exceptOptionsKey]);
64
+ const dataOptionsKey = dataOptions.map((op) => String(op.value)).join("|");
44
65
  // =========================>
45
- // ## options handler
66
+ // ## change value handler
46
67
  // =========================>
47
68
  (0, react_1.useEffect)(() => {
48
- options?.length && setDataOptions([...options, ...includedOptions].filter((op) => !exceptOptions?.includes(op.value)));
49
- }, [options]);
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)(jsx_runtime_1.Fragment, { 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: [(0, jsx_runtime_1.jsx)("input", { type: "hidden", value: !multiple ? String(inputHandler.value) : Array().concat(inputHandler.value).map((val) => String(val)), name: name }), (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", 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 : inputShowValue), onChange: (e) => {
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
- inputHandler.setFocus(false);
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")), children: (0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { icon: "solid/chevron-down" }) })] }), !!dataOptions?.length && showOption && !loadingOption && !!filteredOptions?.length && ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("ul", { className: (0, _utils_1.cn)("input-suggest-container scroll-sm", inputHandler.focus && "input-suggest-container-active", (0, _utils_1.pcn)(className, "suggest")), children: (newOption ? [newOption, ...filteredOptions] : filteredOptions).map((option, key) => {
240
- const selected = !!((typeof inputHandler.value == "string" || typeof inputHandler.value == "number") && inputHandler.value == option.value) ||
241
- (Array.isArray(inputHandler.value) && Array().concat(inputHandler.value).find((val) => val == option.value));
242
- 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: () => {
243
- setKeydown(true);
244
- setTimeout(() => inputHandler.setFocus(true), 110);
245
- }, onMouseUp: () => {
246
- setKeydown(false);
247
- setActiveOption(key);
248
- setFilteredOptions([]);
249
- setShowOption(false);
250
- if (!multiple) {
251
- setInputShowValue(option.label);
252
- serverSearchable && setKeyword(option.label);
253
- inputHandler.setValue(option.value);
254
- onChange?.(option.value, option);
255
- }
256
- else {
257
- const values = Array.isArray(inputHandler.value)
258
- ? Array().concat(inputHandler.value).filter((val) => val != option.value)
259
- : [];
260
- setInputShowValue("");
261
- serverSearchable && setKeyword("");
262
- if (Array.isArray(inputHandler.value) && Array().concat(inputHandler.value).find((val) => val == option.value)) {
263
- inputHandler.setValue(values);
264
- onChange?.(values);
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
- inputHandler.setValue([...Array().concat(values), option.value]);
268
- onChange?.([...Array().concat(values), option.value]);
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
- setTimeout(() => inputHandler.setFocus(false), 120);
272
- }, children: [selected && ((0, jsx_runtime_1.jsx)(skalfa_icon_1.Icon, { icon: "solid/check", className: "select-suggest-check" })), option.label] }, key));
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;