Skip to content

Commit

Permalink
add selection prefill
Browse files Browse the repository at this point in the history
  • Loading branch information
julianbenegas committed May 11, 2024
1 parent 97c1ce1 commit 825278c
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 91 deletions.
129 changes: 80 additions & 49 deletions packages/basehub/src/react/search/primitive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -520,62 +520,93 @@ const Root = <
* Input
* -----------------------------------------------------------------------------------------------*/

const useIsoLayoutEffect =
typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;

const Input = React.forwardRef<
HTMLInputElement,
Omit<JSX.IntrinsicElements["input"] & { asChild?: boolean }, "ref">
>(({ asChild, onChange, onKeyDown, ...props }, ref) => {
const { id, query, onQueryChange, onIndexChange, recentSearches, result } =
useContext();
const Comp = asChild ? Slot : "input";
Omit<
JSX.IntrinsicElements["input"] & {
asChild?: boolean;
disableSelectionPrefill?: boolean;
},
"ref"
>
>(
(
{ asChild, onChange, onKeyDown, disableSelectionPrefill, ...props },
ref
) => {
const { id, query, onQueryChange, onIndexChange, recentSearches, result } =
useContext();
const Comp = asChild ? Slot : "input";

return (
<Comp
{...props}
value={query}
onChange={(e) => {
onChange?.(e as React.ChangeEvent<HTMLInputElement>);
if (e.target instanceof HTMLInputElement) {
onQueryChange(e.target.value);
}
}}
onKeyDown={(e) => {
onKeyDown?.(e as React.KeyboardEvent<HTMLInputElement>);
// handle arrow keys and enter
if (e.key === "ArrowDown") {
e.preventDefault();
onIndexChange({ type: "incr", scrollIntoView: true });
} else if (e.key === "ArrowUp") {
e.preventDefault();
onIndexChange({ type: "decr", scrollIntoView: true });
} else if (e.key === "Enter") {
e.preventDefault();
const selectedNode = document.querySelector<HTMLElement>(
`[data-basehub-hit-for="${id}"], [data-selected="true"]`
);
if (selectedNode) {
const href = selectedNode.getAttribute("href");
if (href) {
if (e.metaKey) {
window.open(href, "_blank");
} else {
window.location.href = href;
}
if (recentSearches) {
const hit = result?.hits.find(
(h) => h._key === selectedNode.dataset.basehubHitKey
);
if (hit) {
recentSearches.add(hit);
const onQueryChangeRef = React.useRef(onQueryChange);
onQueryChangeRef.current = onQueryChange;

const queryRef = React.useRef(query);
queryRef.current = query;

useIsoLayoutEffect(() => {
if (!onQueryChangeRef.current) return;
const defaultQuery = disableSelectionPrefill
? ""
: window.getSelection()?.toString() || "";

if (queryRef.current === defaultQuery) return;

onQueryChangeRef.current(defaultQuery);
}, [disableSelectionPrefill]);

return (
<Comp
{...props}
value={query}
onChange={(e) => {
onChange?.(e as React.ChangeEvent<HTMLInputElement>);
if (e.target instanceof HTMLInputElement) {
onQueryChange(e.target.value);
}
}}
onKeyDown={(e) => {
onKeyDown?.(e as React.KeyboardEvent<HTMLInputElement>);
// handle arrow keys and enter
if (e.key === "ArrowDown") {
e.preventDefault();
onIndexChange({ type: "incr", scrollIntoView: true });
} else if (e.key === "ArrowUp") {
e.preventDefault();
onIndexChange({ type: "decr", scrollIntoView: true });
} else if (e.key === "Enter") {
e.preventDefault();
const selectedNode = document.querySelector<HTMLElement>(
`[data-basehub-hit-for="${id}"], [data-selected="true"]`
);
if (selectedNode) {
const href = selectedNode.getAttribute("href");
if (href) {
if (e.metaKey) {
window.open(href, "_blank");
} else {
window.location.href = href;
}
if (recentSearches) {
const hit = result?.hits.find(
(h) => h._key === selectedNode.dataset.basehubHitKey
);
if (hit) {
recentSearches.add(hit);
}
}
}
}
}
}
}}
ref={ref}
/>
);
});
}}
ref={ref}
/>
);
}
);

/* -------------------------------------------------------------------------------------------------
* Placeholder
Expand Down
86 changes: 44 additions & 42 deletions playground/src/app/search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { SearchBox, useSearch } from "../../../.basehub/react-search";
import s from "./search.module.css";

export const Search = () => {
const [count, setCount] = useState(0);
const [open, setOpen] = useState(false);

const search = useSearch<{ some: "thing" }>({
_searchKey: "somet",
_searchKey: null,
queryBy: ["_title", "content"],
saveRecentSearches: {
getStorage: () => window.localStorage,
Expand All @@ -19,66 +19,68 @@ export const Search = () => {
<>
<button
onClick={() => {
setCount(count + 1);
setOpen((p) => !p);
}}
>
Counter {count}
TOGGLE
</button>
<br />
<SearchBox.Root search={search}>
<SearchBox.Input />
<SearchBox.Placeholder asChild>
{open && (
<SearchBox.Root search={search}>
<SearchBox.Input autoFocus />
<SearchBox.Placeholder asChild>
<SearchBox.HitsList asChild>
<ul>
<h3>Recent Searches</h3>
{search.recentSearches?.hits?.map((hit) => {
return (
<li key={hit._key}>
<SearchBox.HitItem
hit={hit}
href={`/doc/${hit.document._id}`}
className={s.hit}
>
<SearchBox.HitSnippet fieldPath="_title" />
<SearchBox.HitSnippet fieldPath="content" />
</SearchBox.HitItem>

<button
onClick={() => {
search.recentSearches?.remove(hit._key);
}}
>
X
</button>
</li>
);
})}
</ul>
</SearchBox.HitsList>
</SearchBox.Placeholder>
<SearchBox.Empty>
<div>No results found for {search.query}</div>
</SearchBox.Empty>
<SearchBox.HitsList asChild>
<ul>
<h3>Recent Searches</h3>
{search.recentSearches?.hits?.map((hit) => {
<ul style={{ maxHeight: 200, overflowY: "auto" }}>
{search.result?.hits.map((hit) => {
return (
<li key={hit._key}>
<SearchBox.HitItem
key={hit._key}
hit={hit}
href={`/doc/${hit.document._id}`}
className={s.hit}
>
<SearchBox.HitSnippet fieldPath="_title" />
<SearchBox.HitSnippet fieldPath="content" />
</SearchBox.HitItem>

<button
onClick={() => {
search.recentSearches?.remove(hit._key);
}}
>
X
</button>
</li>
);
})}
</ul>
</SearchBox.HitsList>
</SearchBox.Placeholder>
<SearchBox.Empty>
<div>No results found for {search.query}</div>
</SearchBox.Empty>
<SearchBox.HitsList asChild>
<ul style={{ maxHeight: 200, overflowY: "auto" }}>
{search.result?.hits.map((hit) => {
return (
<li key={hit._key}>
<SearchBox.HitItem
key={hit._key}
hit={hit}
href={`/doc/${hit.document._id}`}
className={s.hit}
>
<SearchBox.HitSnippet fieldPath="_title" />
<SearchBox.HitSnippet fieldPath="content" />
</SearchBox.HitItem>
</li>
);
})}
</ul>
</SearchBox.HitsList>
</SearchBox.Root>
</SearchBox.Root>
)}
</>
);
};

0 comments on commit 825278c

Please sign in to comment.