pesona-ui 1.0.29 → 1.0.30
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.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useState, useRef, useMemo, forwardRef, useCallback } from 'react';
|
|
1
|
+
import React, { useEffect, useState, useRef, useMemo, forwardRef, useImperativeHandle, useCallback } from 'react';
|
|
2
2
|
import ReactDOM, { createPortal } from 'react-dom';
|
|
3
3
|
|
|
4
4
|
const Button = ({ type = 'button', className, children, ...rest }) => {
|
|
@@ -8189,95 +8189,44 @@ const useDropdownPositionAndScroll = (isOpen, dropdownOptionsRef) => {
|
|
|
8189
8189
|
|
|
8190
8190
|
const Select = forwardRef(({ name, label, message, selectLabel, size = 'md', floatingLabel = false, error, options, value = '', onChange, onBlur, required, disabled, }, ref) => {
|
|
8191
8191
|
const [isOpen, setIsOpen] = useState(false);
|
|
8192
|
-
const [
|
|
8192
|
+
const [internalValue, setInternalValue] = useState(value);
|
|
8193
8193
|
const dropdownRef = useRef(null);
|
|
8194
8194
|
const dropdownOptionsRef = useRef(null);
|
|
8195
|
-
const
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8195
|
+
const selectRef = useRef(null);
|
|
8196
|
+
// Update internal value when value prop changes
|
|
8197
|
+
useEffect(() => {
|
|
8198
|
+
setInternalValue(value);
|
|
8199
|
+
}, [value]);
|
|
8200
|
+
// Expose selectRef to parent via forwardRef
|
|
8201
|
+
useImperativeHandle(ref, () => selectRef.current);
|
|
8202
|
+
// Handle option click
|
|
8203
|
+
const handleOptionClick = (optionValue) => {
|
|
8204
|
+
setInternalValue(optionValue);
|
|
8205
|
+
// Trigger onChange
|
|
8206
|
+
onChange?.({
|
|
8207
|
+
target: { name, value: optionValue, type: 'select-one' },
|
|
8208
|
+
});
|
|
8209
|
+
if (selectRef.current) {
|
|
8210
|
+
selectRef.current.value = optionValue.toString();
|
|
8211
|
+
selectRef.current.dispatchEvent(new Event('change', { bubbles: true }));
|
|
8212
|
+
}
|
|
8208
8213
|
setIsOpen(false);
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
}, 0);
|
|
8212
|
-
}, [options, onChange, onBlur, createSyntheticEvent]);
|
|
8213
|
-
const handleOutsideClick = useCallback(() => {
|
|
8214
|
+
};
|
|
8215
|
+
useOutsideClick([dropdownRef], () => {
|
|
8214
8216
|
setIsOpen(false);
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
onBlur(createSyntheticEvent(value));
|
|
8218
|
-
}, 0);
|
|
8219
|
-
}
|
|
8220
|
-
}, [value, onBlur, createSyntheticEvent]);
|
|
8221
|
-
useOutsideClick([dropdownRef], handleOutsideClick);
|
|
8217
|
+
selectRef.current?.blur();
|
|
8218
|
+
});
|
|
8222
8219
|
useDropdownPositionAndScroll(isOpen, dropdownOptionsRef);
|
|
8223
|
-
const normalizedValue = useMemo(() => (value === null || value === undefined || value === '' ? '' : String(value)), [value]);
|
|
8224
|
-
const selectedOption = useMemo(() => options.find((opt) => String(opt.value) === normalizedValue), [options, normalizedValue]);
|
|
8225
|
-
const displayText = selectedOption?.label || selectLabel || 'Select an option';
|
|
8226
|
-
useEffect(() => {
|
|
8227
|
-
if (hiddenSelectRef.current)
|
|
8228
|
-
hiddenSelectRef.current.value = normalizedValue;
|
|
8229
|
-
}, [normalizedValue]);
|
|
8230
8220
|
useEffect(() => {
|
|
8231
|
-
|
|
8232
|
-
const index = options.findIndex((opt) => String(opt.value) === normalizedValue);
|
|
8233
|
-
setHighlightIndex(index >= 0 ? index : 0);
|
|
8234
|
-
}
|
|
8235
|
-
}, [isOpen, options, normalizedValue]);
|
|
8236
|
-
const handleKeyDown = useCallback((e) => {
|
|
8237
|
-
if (disabled)
|
|
8238
|
-
return;
|
|
8239
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
8240
|
-
e.preventDefault();
|
|
8241
|
-
if (isOpen && highlightIndex >= 0) {
|
|
8242
|
-
handleOptionSelect(options[highlightIndex].value);
|
|
8243
|
-
}
|
|
8244
|
-
else {
|
|
8245
|
-
setIsOpen((prev) => !prev);
|
|
8246
|
-
}
|
|
8247
|
-
}
|
|
8248
|
-
else if (e.key === 'Escape' && isOpen) {
|
|
8221
|
+
return () => {
|
|
8249
8222
|
setIsOpen(false);
|
|
8250
|
-
}
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
}
|
|
8256
|
-
else {
|
|
8257
|
-
setHighlightIndex((prev) => {
|
|
8258
|
-
const next = e.key === 'ArrowDown'
|
|
8259
|
-
? (prev + 1) % options.length
|
|
8260
|
-
: (prev - 1 + options.length) % options.length;
|
|
8261
|
-
return next;
|
|
8262
|
-
});
|
|
8263
|
-
}
|
|
8264
|
-
}
|
|
8265
|
-
}, [disabled, isOpen, highlightIndex, options, handleOptionSelect]);
|
|
8266
|
-
useEffect(() => {
|
|
8267
|
-
if (isOpen && dropdownOptionsRef.current && highlightIndex >= 0) {
|
|
8268
|
-
const optionElements = dropdownOptionsRef.current.querySelectorAll('.option');
|
|
8269
|
-
const highlighted = optionElements[highlightIndex];
|
|
8270
|
-
highlighted?.scrollIntoView({ block: 'nearest' });
|
|
8271
|
-
}
|
|
8272
|
-
}, [highlightIndex, isOpen]);
|
|
8223
|
+
};
|
|
8224
|
+
}, []);
|
|
8225
|
+
const displayText = internalValue
|
|
8226
|
+
? options.find((option) => option.value === internalValue)?.label
|
|
8227
|
+
: selectLabel || 'Select an option';
|
|
8273
8228
|
return (React.createElement(React.Fragment, null,
|
|
8274
|
-
React.createElement("select", { ref:
|
|
8275
|
-
hiddenSelectRef.current = el;
|
|
8276
|
-
if (typeof ref === 'function')
|
|
8277
|
-
ref(el);
|
|
8278
|
-
else if (ref)
|
|
8279
|
-
ref.current = el;
|
|
8280
|
-
}, name: name, value: normalizedValue, onChange: onChange, onBlur: onBlur, required: required, disabled: disabled, style: {
|
|
8229
|
+
React.createElement("select", { ref: selectRef, name: name, value: internalValue || '', onChange: onChange, onBlur: onBlur, required: required, disabled: disabled, style: {
|
|
8281
8230
|
position: 'absolute',
|
|
8282
8231
|
left: '-9999px',
|
|
8283
8232
|
opacity: 0,
|
|
@@ -8292,15 +8241,15 @@ const Select = forwardRef(({ name, label, message, selectLabel, size = 'md', flo
|
|
|
8292
8241
|
" ",
|
|
8293
8242
|
required && React.createElement("span", { className: "text-danger" }, "*"))),
|
|
8294
8243
|
React.createElement("div", { className: `dropdown-select-container ${size}`, ref: dropdownRef },
|
|
8295
|
-
React.createElement("div", { className: `dropdown-header ${isOpen ? 'open' : ''} ${disabled ? 'disabled' : ''}
|
|
8244
|
+
React.createElement("div", { className: `dropdown-header ${isOpen ? 'open' : ''} ${disabled ? 'disabled' : ''}`, onClick: () => !disabled && setIsOpen(!isOpen), "aria-haspopup": "listbox", "aria-expanded": isOpen },
|
|
8296
8245
|
React.createElement("span", { className: "label" }, displayText),
|
|
8297
8246
|
React.createElement(FiChevronDown, { className: "arrow" })),
|
|
8298
|
-
isOpen && (React.createElement("div", { className:
|
|
8247
|
+
isOpen && (React.createElement("div", { className: `dropdown-options scrollbar ${disabled ? 'disabled' : ''}`, ref: dropdownOptionsRef, role: "listbox" }, options.map((option, index) => (React.createElement("div", { key: `${option.value}-${index}`, className: `option ${internalValue === option.value ? 'selected' : ''}`, onClick: () => !disabled && handleOptionClick(option.value), role: "option", "aria-selected": internalValue === option.value }, option.label)))))),
|
|
8299
8248
|
label && floatingLabel && (React.createElement("label", { htmlFor: name },
|
|
8300
8249
|
label,
|
|
8301
8250
|
" ",
|
|
8302
8251
|
required && React.createElement("span", { className: "text-danger" }, "*"))),
|
|
8303
|
-
error ? (React.createElement("small", { className: "form-message text-danger"
|
|
8252
|
+
error ? (React.createElement("small", { className: "form-message text-danger" }, error)) : (message && React.createElement("small", { className: "form-message text-muted" }, message))));
|
|
8304
8253
|
});
|
|
8305
8254
|
Select.displayName = 'Select';
|
|
8306
8255
|
|
|
@@ -8648,12 +8597,15 @@ const RadioButtonGroup = React.forwardRef(({ name, label, message, size = 'md',
|
|
|
8648
8597
|
});
|
|
8649
8598
|
RadioButtonGroup.displayName = 'RadioButtonGroup';
|
|
8650
8599
|
|
|
8651
|
-
const SelectMultiple = forwardRef(({ name, label, message, selectLabel, floatingLabel = false, error, options, value = [], onChange, required, disabled, className, }, ref) => {
|
|
8600
|
+
const SelectMultiple = forwardRef(({ name, label, message, selectLabel, floatingLabel = false, error, options, value = [], onChange, onBlur, required, disabled, className, }, ref) => {
|
|
8652
8601
|
const [isOpen, setIsOpen] = useState(false);
|
|
8653
8602
|
const [selectedValues, setSelectedValues] = useState(value);
|
|
8654
8603
|
const dropdownRef = useRef(null);
|
|
8655
8604
|
const dropdownOptionsRef = useRef(null);
|
|
8656
|
-
|
|
8605
|
+
const inputRef = useRef(null);
|
|
8606
|
+
// expose to RHF
|
|
8607
|
+
useImperativeHandle(ref, () => inputRef.current);
|
|
8608
|
+
// update when external value changes
|
|
8657
8609
|
useEffect(() => {
|
|
8658
8610
|
if (JSON.stringify(value) !== JSON.stringify(selectedValues)) {
|
|
8659
8611
|
setSelectedValues(value);
|
|
@@ -8664,14 +8616,16 @@ const SelectMultiple = forwardRef(({ name, label, message, selectLabel, floating
|
|
|
8664
8616
|
? selectedValues.filter((val) => val !== optionValue)
|
|
8665
8617
|
: [...selectedValues, optionValue];
|
|
8666
8618
|
setSelectedValues(newSelectedValues);
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8619
|
+
onChange?.({
|
|
8620
|
+
target: {
|
|
8621
|
+
name,
|
|
8622
|
+
value: newSelectedValues,
|
|
8623
|
+
},
|
|
8624
|
+
});
|
|
8672
8625
|
};
|
|
8673
8626
|
useOutsideClick([dropdownRef], () => {
|
|
8674
8627
|
setIsOpen(false);
|
|
8628
|
+
inputRef.current?.blur();
|
|
8675
8629
|
});
|
|
8676
8630
|
useDropdownPositionAndScroll(isOpen, dropdownOptionsRef);
|
|
8677
8631
|
const selectedLabels = selectedValues
|
|
@@ -8679,12 +8633,13 @@ const SelectMultiple = forwardRef(({ name, label, message, selectLabel, floating
|
|
|
8679
8633
|
.filter(Boolean)
|
|
8680
8634
|
.join(', ');
|
|
8681
8635
|
return (React.createElement(React.Fragment, null,
|
|
8636
|
+
React.createElement("input", { type: "hidden", name: name, value: selectedValues.join(','), ref: inputRef, onBlur: onBlur, required: required }),
|
|
8682
8637
|
label && !floatingLabel && (React.createElement("label", { htmlFor: name },
|
|
8683
8638
|
label,
|
|
8684
8639
|
" ",
|
|
8685
8640
|
required && React.createElement("span", { className: "text-danger" }, "*"))),
|
|
8686
8641
|
React.createElement("div", { className: `dropdown-select-container ${className || ''}`, ref: dropdownRef },
|
|
8687
|
-
React.createElement("div", { className: `dropdown-header ${isOpen ? 'open' : ''} ${disabled ? 'disabled' : ''}`, onClick: () => !disabled && setIsOpen(!isOpen)
|
|
8642
|
+
React.createElement("div", { className: `dropdown-header ${isOpen ? 'open' : ''} ${disabled ? 'disabled' : ''}`, onClick: () => !disabled && setIsOpen(!isOpen) },
|
|
8688
8643
|
React.createElement("span", { className: "label" }, selectedLabels || selectLabel || 'Select an option'),
|
|
8689
8644
|
React.createElement(FiChevronDown, { className: `arrow ${isOpen ? 'open' : ''}` })),
|
|
8690
8645
|
isOpen && !disabled && (React.createElement("div", { className: "dropdown-options scrollbar", ref: dropdownOptionsRef, role: "listbox" }, options?.map((option) => (React.createElement("div", { key: option.value, className: `option ${selectedValues.includes(option.value) ? 'selected' : ''}` },
|