pesona-ui 1.0.29 → 1.0.31

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/index.cjs.js CHANGED
@@ -8189,120 +8189,55 @@ const useDropdownPositionAndScroll = (isOpen, dropdownOptionsRef) => {
8189
8189
  }, [isOpen, dropdownOptionsRef]);
8190
8190
  };
8191
8191
 
8192
- const Select = React.forwardRef(({ name, label, message, selectLabel, size = 'md', floatingLabel = false, error, options, value = '', onChange, onBlur, required, disabled, }, ref) => {
8192
+ const Select = React.forwardRef((props, ref) => {
8193
+ const { name, label, message, selectLabel = 'Select an option', size = 'md', floatingLabel = false, error, options, value = '', onChange, onBlur, required, disabled, } = props;
8193
8194
  const [isOpen, setIsOpen] = React.useState(false);
8194
- const [highlightIndex, setHighlightIndex] = React.useState(-1);
8195
8195
  const dropdownRef = React.useRef(null);
8196
8196
  const dropdownOptionsRef = React.useRef(null);
8197
- const hiddenSelectRef = React.useRef(null);
8198
- const shouldReturnNumber = React.useMemo(() => options.every((opt) => typeof opt.value === 'number'), [options]);
8199
- const coerceValue = React.useCallback((val) => (shouldReturnNumber ? Number(val) : val), [shouldReturnNumber]);
8200
- const createSyntheticEvent = React.useCallback((val) => ({
8201
- target: { name, value: coerceValue(val), type: 'select-one' },
8202
- currentTarget: { name, value: coerceValue(val), type: 'select-one' },
8203
- }), [name, coerceValue]);
8204
- const handleOptionSelect = React.useCallback((optionValue) => {
8205
- const selectedOption = options.find((opt) => opt.value === optionValue);
8206
- if (!selectedOption)
8207
- return;
8208
- hiddenSelectRef.current.value = String(selectedOption.value);
8209
- onChange?.(createSyntheticEvent(selectedOption.value));
8210
- setIsOpen(false);
8211
- setTimeout(() => {
8212
- onBlur?.(createSyntheticEvent(selectedOption.value));
8213
- }, 0);
8214
- }, [options, onChange, onBlur, createSyntheticEvent]);
8215
- const handleOutsideClick = React.useCallback(() => {
8197
+ const selectRef = React.useRef(null);
8198
+ React.useImperativeHandle(ref, () => selectRef.current);
8199
+ React.useEffect(() => setIsOpen(false), []);
8200
+ useOutsideClick([dropdownRef], () => {
8216
8201
  setIsOpen(false);
8217
- if (onBlur && value !== undefined && value !== null && value !== '') {
8218
- setTimeout(() => {
8219
- onBlur(createSyntheticEvent(value));
8220
- }, 0);
8221
- }
8222
- }, [value, onBlur, createSyntheticEvent]);
8223
- useOutsideClick([dropdownRef], handleOutsideClick);
8202
+ selectRef.current?.blur(); // Trigger onBlur RHF
8203
+ });
8224
8204
  useDropdownPositionAndScroll(isOpen, dropdownOptionsRef);
8225
- const normalizedValue = React.useMemo(() => (value === null || value === undefined || value === '' ? '' : String(value)), [value]);
8226
- const selectedOption = React.useMemo(() => options.find((opt) => String(opt.value) === normalizedValue), [options, normalizedValue]);
8227
- const displayText = selectedOption?.label || selectLabel || 'Select an option';
8228
- React.useEffect(() => {
8229
- if (hiddenSelectRef.current)
8230
- hiddenSelectRef.current.value = normalizedValue;
8231
- }, [normalizedValue]);
8232
- React.useEffect(() => {
8233
- if (isOpen) {
8234
- const index = options.findIndex((opt) => String(opt.value) === normalizedValue);
8235
- setHighlightIndex(index >= 0 ? index : 0);
8236
- }
8237
- }, [isOpen, options, normalizedValue]);
8238
- const handleKeyDown = React.useCallback((e) => {
8239
- if (disabled)
8240
- return;
8241
- if (e.key === 'Enter' || e.key === ' ') {
8242
- e.preventDefault();
8243
- if (isOpen && highlightIndex >= 0) {
8244
- handleOptionSelect(options[highlightIndex].value);
8245
- }
8246
- else {
8247
- setIsOpen((prev) => !prev);
8248
- }
8249
- }
8250
- else if (e.key === 'Escape' && isOpen) {
8251
- setIsOpen(false);
8252
- }
8253
- else if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
8254
- e.preventDefault();
8255
- if (!isOpen) {
8256
- setIsOpen(true);
8257
- }
8258
- else {
8259
- setHighlightIndex((prev) => {
8260
- const next = e.key === 'ArrowDown'
8261
- ? (prev + 1) % options.length
8262
- : (prev - 1 + options.length) % options.length;
8263
- return next;
8264
- });
8265
- }
8266
- }
8267
- }, [disabled, isOpen, highlightIndex, options, handleOptionSelect]);
8268
- React.useEffect(() => {
8269
- if (isOpen && dropdownOptionsRef.current && highlightIndex >= 0) {
8270
- const optionElements = dropdownOptionsRef.current.querySelectorAll('.option');
8271
- const highlighted = optionElements[highlightIndex];
8272
- highlighted?.scrollIntoView({ block: 'nearest' });
8205
+ const displayText = value
8206
+ ? options.find((opt) => opt.value === value)?.label
8207
+ : selectLabel;
8208
+ const handleOptionClick = (optionValue) => {
8209
+ const syntheticEvent = {
8210
+ target: {
8211
+ name,
8212
+ value: optionValue,
8213
+ },
8214
+ };
8215
+ onChange?.(syntheticEvent);
8216
+ // Change the select value to trigger onChange in RHF
8217
+ if (selectRef.current) {
8218
+ selectRef.current.value = String(optionValue);
8219
+ selectRef.current.dispatchEvent(new Event('change', { bubbles: true }));
8273
8220
  }
8274
- }, [highlightIndex, isOpen]);
8221
+ setIsOpen(false);
8222
+ };
8275
8223
  return (React.createElement(React.Fragment, null,
8276
- React.createElement("select", { ref: (el) => {
8277
- hiddenSelectRef.current = el;
8278
- if (typeof ref === 'function')
8279
- ref(el);
8280
- else if (ref)
8281
- ref.current = el;
8282
- }, name: name, value: normalizedValue, onChange: onChange, onBlur: onBlur, required: required, disabled: disabled, style: {
8283
- position: 'absolute',
8284
- left: '-9999px',
8285
- opacity: 0,
8286
- pointerEvents: 'none',
8287
- width: '1px',
8288
- height: '1px',
8289
- }, tabIndex: -1, "aria-hidden": "true" },
8224
+ React.createElement("select", { ref: selectRef, name: name, value: value, onChange: onChange, onBlur: onBlur, required: required, disabled: disabled, style: { position: 'absolute', left: '-9999px' }, tabIndex: -1, "aria-hidden": "true" },
8290
8225
  React.createElement("option", { value: "" }, "Select an option"),
8291
- options.map((option) => (React.createElement("option", { key: option.value, value: option.value }, option.label)))),
8226
+ options.map((opt) => (React.createElement("option", { key: opt.value, value: opt.value }, opt.label)))),
8292
8227
  label && !floatingLabel && (React.createElement("label", { htmlFor: name },
8293
8228
  label,
8294
8229
  " ",
8295
8230
  required && React.createElement("span", { className: "text-danger" }, "*"))),
8296
8231
  React.createElement("div", { className: `dropdown-select-container ${size}`, ref: dropdownRef },
8297
- React.createElement("div", { className: `dropdown-header ${isOpen ? 'open' : ''} ${disabled ? 'disabled' : ''} ${error ? 'error' : ''}`, onClick: () => !disabled && setIsOpen(!isOpen), onKeyDown: handleKeyDown, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-invalid": !!error, tabIndex: disabled ? -1 : 0, role: "combobox" },
8232
+ React.createElement("div", { className: `dropdown-header ${isOpen ? 'open' : ''} ${disabled ? 'disabled' : ''}`, onClick: () => !disabled && setIsOpen(!isOpen), "aria-haspopup": "listbox", "aria-expanded": isOpen },
8298
8233
  React.createElement("span", { className: "label" }, displayText),
8299
8234
  React.createElement(FiChevronDown, { className: "arrow" })),
8300
- isOpen && (React.createElement("div", { className: "dropdown-options scrollbar", ref: dropdownOptionsRef, role: "listbox" }, options.map((option, index) => (React.createElement("div", { key: `${option.value}-${index}`, className: `option ${String(value) === String(option.value) ? 'selected' : ''} ${highlightIndex === index ? 'highlight' : ''}`, onClick: () => !disabled && handleOptionSelect(option.value), role: "option", "aria-selected": String(value) === String(option.value), tabIndex: 0 }, option.label)))))),
8235
+ isOpen && (React.createElement("div", { className: "dropdown-options scrollbar", ref: dropdownOptionsRef, role: "listbox" }, options.map((opt) => (React.createElement("div", { key: opt.value, className: `option ${opt.value === value ? 'selected' : ''}`, onClick: () => handleOptionClick(opt.value), role: "option", "aria-selected": opt.value === value }, opt.label)))))),
8301
8236
  label && floatingLabel && (React.createElement("label", { htmlFor: name },
8302
8237
  label,
8303
8238
  " ",
8304
8239
  required && React.createElement("span", { className: "text-danger" }, "*"))),
8305
- error ? (React.createElement("small", { className: "form-message text-danger", role: "alert" }, error)) : (message && React.createElement("small", { className: "form-message text-muted" }, message))));
8240
+ error ? (React.createElement("small", { className: "form-message text-danger" }, error)) : (message && React.createElement("small", { className: "form-message text-muted" }, message))));
8306
8241
  });
8307
8242
  Select.displayName = 'Select';
8308
8243
 
@@ -8699,39 +8634,49 @@ const SelectMultiple = React.forwardRef(({ name, label, message, selectLabel, fl
8699
8634
  });
8700
8635
  SelectMultiple.displayName = 'SelectMultiple';
8701
8636
 
8702
- const SelectWithSearch = React.forwardRef(({ name, label, message, selectLabel, size = 'md', floatingLabel = false, error, options = [], value = '', onChange, required, disabled, selectSearch = '', setSelectSearch, isLoading = false, }, ref) => {
8637
+ const SelectWithSearch = React.forwardRef((props, ref) => {
8638
+ const { name, label, message, selectLabel = 'Select an option', size = 'md', floatingLabel = false, error, options = [], value = '', onChange, required, disabled, selectSearch = '', setSelectSearch, isLoading = false, } = props;
8703
8639
  const [isOpen, setIsOpen] = React.useState(false);
8704
8640
  const dropdownRef = React.useRef(null);
8705
8641
  const dropdownOptionsRef = React.useRef(null);
8642
+ const selectRef = React.useRef(null);
8643
+ React.useImperativeHandle(ref, () => selectRef.current);
8644
+ useOutsideClick([dropdownRef], () => setIsOpen(false));
8645
+ useDropdownPositionAndScroll(isOpen, dropdownOptionsRef);
8646
+ const displayText = value
8647
+ ? options.find((opt) => opt.value === value)?.label
8648
+ : selectLabel;
8706
8649
  const handleOptionClick = (optionValue) => {
8707
- if (onChange) {
8708
- onChange({
8709
- target: { name, value: optionValue },
8710
- });
8650
+ const syntheticEvent = {
8651
+ target: {
8652
+ name,
8653
+ value: optionValue,
8654
+ },
8655
+ };
8656
+ onChange?.(syntheticEvent);
8657
+ // Change the select value to trigger onChange in RHF
8658
+ if (selectRef.current) {
8659
+ selectRef.current.value = String(optionValue);
8660
+ selectRef.current.dispatchEvent(new Event('change', { bubbles: true }));
8711
8661
  }
8712
8662
  setIsOpen(false);
8713
8663
  };
8714
- useOutsideClick([dropdownRef], () => setIsOpen(false));
8715
- useDropdownPositionAndScroll(isOpen, dropdownOptionsRef);
8716
- React.useEffect(() => {
8717
- return () => setIsOpen(false);
8718
- }, []);
8719
- const displayText = value
8720
- ? options.find((option) => option.value === value)?.label
8721
- : selectLabel || 'Select an option';
8722
8664
  return (React.createElement(React.Fragment, null,
8665
+ React.createElement("select", { ref: selectRef, name: name, value: value, onChange: onChange, style: { position: 'absolute', left: '-9999px' }, tabIndex: -1, "aria-hidden": "true" },
8666
+ React.createElement("option", { value: "" }, "Select an option"),
8667
+ options.map((opt) => (React.createElement("option", { key: opt.value, value: opt.value }, opt.label)))),
8723
8668
  label && !floatingLabel && (React.createElement("label", { htmlFor: name },
8724
8669
  label,
8725
8670
  " ",
8726
8671
  required && React.createElement("span", { className: "text-danger" }, "*"))),
8727
8672
  React.createElement("div", { className: `dropdown-select-container ${size}`, ref: dropdownRef },
8728
- React.createElement("div", { className: `dropdown-header ${isOpen ? 'open' : ''} ${disabled ? 'disabled' : ''}`, onClick: () => !disabled && setIsOpen(!isOpen), ref: ref, "aria-haspopup": "listbox", "aria-expanded": isOpen },
8673
+ React.createElement("div", { className: `dropdown-header ${isOpen ? 'open' : ''} ${disabled ? 'disabled' : ''}`, onClick: () => !disabled && setIsOpen(!isOpen), "aria-haspopup": "listbox", "aria-expanded": isOpen },
8729
8674
  React.createElement("span", { className: "label" }, displayText),
8730
8675
  React.createElement(FiChevronDown, { className: "arrow" })),
8731
- isOpen && (React.createElement("div", { className: `dropdown-options scrollbar ${disabled ? 'disabled' : ''}`, ref: dropdownOptionsRef, role: "listbox" },
8676
+ isOpen && (React.createElement("div", { className: "dropdown-options scrollbar", ref: dropdownOptionsRef, role: "listbox" },
8732
8677
  React.createElement("div", { className: "search-input" },
8733
- React.createElement(Input, { name: "search", placeholder: "Ketik untuk mencari..", type: "search", autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: false, role: "textbox", value: selectSearch, autoFocus: true, onChange: (e) => setSelectSearch && setSelectSearch(e.currentTarget.value) })),
8734
- isLoading ? (React.createElement("div", { className: "p-10 text-center" }, "Loading options...")) : options.length === 0 ? (React.createElement("div", { className: "p-10 text-center" }, "Tidak ada hasil ditemukan")) : (options.map((option) => (React.createElement("div", { key: String(option.value), className: `option ${value === option.value ? 'selected' : ''}`, onClick: () => !disabled && handleOptionClick(String(option.value)), role: "option", "aria-selected": value === option.value }, option.label))))))),
8678
+ React.createElement(Input, { name: "search", placeholder: "Ketik untuk mencari..", type: "search", autoFocus: true, value: selectSearch, onChange: (e) => setSelectSearch?.(e.currentTarget.value) })),
8679
+ isLoading ? (React.createElement("div", { className: "p-10 text-center" }, "Loading options...")) : options.length === 0 ? (React.createElement("div", { className: "p-10 text-center" }, "Tidak ada hasil ditemukan")) : (options.map((opt) => (React.createElement("div", { key: opt.value, className: `option ${value === opt.value ? 'selected' : ''}`, onClick: () => handleOptionClick(opt.value), role: "option", "aria-selected": value === opt.value }, opt.label))))))),
8735
8680
  label && floatingLabel && (React.createElement("label", { htmlFor: name },
8736
8681
  label,
8737
8682
  " ",