Skip to content

Commit

Permalink
feat: Added searchValue and onSearchValueChange props on SearchSelect (
Browse files Browse the repository at this point in the history
…#944)

* Adds searchValue and onSearchValueChange props

---------

Co-authored-by: severinlandolt <sev.landolt@gmail.com>
  • Loading branch information
perryraskin and severinlandolt committed Feb 3, 2024
1 parent c58653c commit f945686
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Expand Up @@ -3,4 +3,5 @@ dist
.DS_Store
storybook-static
package-lock.json
.vscode
.vscode
yarn.lock
16 changes: 12 additions & 4 deletions src/components/input-elements/SearchSelect/SearchSelect.tsx
@@ -1,5 +1,5 @@
"use client";
import React, { isValidElement, useMemo, useRef, useState } from "react";
import React, { isValidElement, useMemo, useRef } from "react";
import { useInternalState } from "hooks";
import { Combobox, Transition } from "@headlessui/react";
import { ArrowDownHeadIcon, XCircleIcon } from "assets";
Expand All @@ -16,6 +16,8 @@ const makeSearchSelectClassName = makeClassName("SearchSelect");
export interface SearchSelectProps extends React.HTMLAttributes<HTMLInputElement> {
defaultValue?: string;
name?: string;
searchValue?: string;
onSearchValueChange?: (value: string) => void;
value?: string;
onValueChange?: (value: string) => void;
placeholder?: string;
Expand All @@ -33,6 +35,8 @@ const makeSelectClassName = makeClassName("SearchSelect");
const SearchSelect = React.forwardRef<HTMLInputElement, SearchSelectProps>((props, ref) => {
const {
defaultValue = "",
searchValue,
onSearchValueChange,
value,
onValueChange,
placeholder = "Select...",
Expand All @@ -50,7 +54,7 @@ const SearchSelect = React.forwardRef<HTMLInputElement, SearchSelectProps>((prop
} = props;
const comboboxButtonRef = useRef<HTMLButtonElement | null>(null);

const [searchQuery, setSearchQuery] = useState("");
const [searchQuery, setSearchQuery] = useInternalState("", searchValue);
const [selectedValue, setSelectedValue] = useInternalState(defaultValue, value);

const Icon = icon;
Expand All @@ -62,14 +66,15 @@ const SearchSelect = React.forwardRef<HTMLInputElement, SearchSelectProps>((prop
}, [children]);

const filteredOptions = useMemo(
() => getFilteredOptions(searchQuery, reactElementChildren),
() => getFilteredOptions(searchQuery ?? "", reactElementChildren),
[searchQuery, reactElementChildren],
);

const handleReset = () => {
setSelectedValue("");
setSearchQuery("");
onValueChange?.("");
onSearchValueChange?.("");
};

return (
Expand Down Expand Up @@ -166,7 +171,10 @@ const SearchSelect = React.forwardRef<HTMLInputElement, SearchSelectProps>((prop
getSelectButtonColors(hasValue(value), disabled),
)}
placeholder={placeholder}
onChange={(event) => setSearchQuery(event.target.value)}
onChange={(event) => {
onSearchValueChange?.(event.target.value);
setSearchQuery(event.target.value);
}}
displayValue={(value: string) => valueToNameMapping.get(value) ?? ""}
/>
<div className={tremorTwMerge("absolute inset-y-0 right-0 flex items-center pr-2.5")}>
Expand Down
8 changes: 8 additions & 0 deletions src/stories/input-elements/SearchSelect.stories.tsx
Expand Up @@ -6,6 +6,7 @@ import {
SimpleSearchSelectControlled,
SimpleSearchSelectWithStaticAndDynamicChildren,
SimpleSearchSelectForm,
SimpleSearchSelectServerSideRendering,
} from "./helpers/SimpleSearchSelect";

import { CalendarIcon } from "assets";
Expand Down Expand Up @@ -84,3 +85,10 @@ export const Form: Story = {
required: true,
},
};

export const ServerSideRendering: Story = {
render: SimpleSearchSelectServerSideRendering,
args: {
required: true,
},
};
55 changes: 55 additions & 0 deletions src/stories/input-elements/helpers/SimpleSearchSelect.tsx
Expand Up @@ -97,3 +97,58 @@ export function SimpleSearchSelectControlled() {
</div>
);
}

export function SimpleSearchSelectServerSideRendering() {
const [searchQuery, setSearchQuery] = React.useState("");

interface User {
id: number;
name: string;
email: string;
}
const [options, setOptions] = React.useState<User[]>([]);

const [value, setValue] = React.useState<string>();

const handleSearchQueryChange = (query: string) => {
setSearchQuery(query);
};

const handleValueChange = (newValue: string) => {
setValue(newValue);
};

const handleReset = () => {
setValue("");
};

React.useEffect(() => {
if (searchQuery) {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((data) => {
setOptions(data);
})
.catch((error) => console.error("Error fetching user data:", error));
}
}, [searchQuery]);

return (
<div className="space-y-4">
<SearchSelect
value={value}
onValueChange={handleValueChange}
searchValue={searchQuery}
onSearchValueChange={handleSearchQueryChange}
>
{options.map((option) => (
<SearchSelectItem key={option.id} value={option.id.toString()}>
{`${option.name} (${option.email})`}
</SearchSelectItem>
))}
</SearchSelect>
<Button onClick={handleReset}>Reset</Button>
<p>Selected User ID: {value}</p>
</div>
);
}

0 comments on commit f945686

Please sign in to comment.