Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/assets/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@
}

/* PrimeReact AutoComplete styling */
.p-autocomplete {
display: flex;
align-items: center;
width: 100%;
min-height: var(--sl-input-height-medium);
background-color: var(--sl-input-background-color);
border: solid var(--sl-input-border-width) var(--sl-input-border-color);
border-radius: 0.25rem;
color: var(--sl-input-color);
}

.p-autocomplete-item.p-highlight {
background: var(--sl-color-primary-600);
color: var(--sl-color-neutral-0);
Expand All @@ -35,6 +46,15 @@
background-color: var(--sl-color-neutral-100);
color: var(--sl-color-neutral-1000);
}
.p-autocomplete-input:focus {
outline: none !important;
box-shadow: none !important;
}

.p-autocomplete:focus-within:not(.p-disabled):not(.error) {
border-color: var(--sl-input-border-color-focus);
box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-input-focus-ring-color);
}

body {
width: 100%;
Expand Down
34 changes: 30 additions & 4 deletions src/components/RLAutocomplete/RLAutocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const RLAutocomplete = forwardRef<RLAutocompleteRef, RLAutocompleteProps>
) => {
const autocompleteRef = useRef<AutoComplete>(null)
const [inputModel, setInputModel] = useState<RLSelectOptionType | string | undefined>(undefined)
const [suggestions, setSuggestions] = useState<RLSelectOptionType[]>(options)
const { errorMessage, isValid, validate } = useValidation({ rules, externalError: error })

// Sync inputModel with value
Expand All @@ -49,6 +50,10 @@ export const RLAutocomplete = forwardRef<RLAutocompleteRef, RLAutocompleteProps>
}
}, [value, options, forceSelection])

useEffect(() => {
setSuggestions(options)
}, [options])

useEffect(() => {
if (value !== undefined) {
validate(value)
Expand Down Expand Up @@ -83,33 +88,53 @@ export const RLAutocomplete = forwardRef<RLAutocompleteRef, RLAutocompleteProps>
}

const handleClick = (evt: React.MouseEvent) => {
setSuggestions(options)
autocompleteRef.current?.show()
onClick?.(evt.nativeEvent)
}

const handleFocus = (evt: React.FocusEvent) => {
setSuggestions(options)
autocompleteRef.current?.show()
onFocus?.(evt.nativeEvent)
}

const handleBlur = (evt: React.FocusEvent) => {
if (inputModel === null && value) {
const selectedOption = options.find(
(option) => option.value === value
)
if (selectedOption) {
setInputModel(selectedOption)
}
}
onBlur?.(evt.nativeEvent)
}

const handleComplete = (evt: AutoCompleteCompleteEvent) => {
if (onComplete) {
onComplete(evt)
} else {
const query = (evt.query ?? '').toString().toLowerCase()
if (!query) {
setSuggestions(options)
} else {
setSuggestions(options.filter((o) => (o.text ?? '')?.toString().toLowerCase().includes(query)))
}
}
}

const optionTemplate = (option: RLSelectOptionType) => (
const optionTemplate = (option: RLSelectOptionType) => {
const selectedValue = (typeof inputModel === 'object') ? inputModel?.value : undefined

return (
<div className="flex items-center gap-2 min-h-[1lh]">
<span className="w-4">
{value === option.value && <RLIcon className="pt-1" name="check" />}
{selectedValue === option.value && <RLIcon className="pt-1" name="check" />}
</span>
<span>{option.text}</span>
</div>
)
)}

return (
<div className="relative">
Expand All @@ -124,8 +149,9 @@ export const RLAutocomplete = forwardRef<RLAutocompleteRef, RLAutocompleteProps>
className={errorMessage ? 'error' : ''}
value={inputModel}
field="text"
suggestions={options}
suggestions={suggestions}
emptyMessage={emptySearchMessage}
showEmptyMessage={true}
placeholder={placeholder}
disabled={disabled}
forceSelection={forceSelection}
Expand Down