Skip to content

Commit

Permalink
SearchInput: add component
Browse files Browse the repository at this point in the history
  • Loading branch information
MikkelHansenAbtion committed Nov 20, 2024
1 parent 83ad0b8 commit bbe5844
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 0 deletions.
21 changes: 21 additions & 0 deletions components/SearchInput/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.SearchInput {
@apply flex items-center max-w-xs pl-2 overflow-hidden;
@apply border border-solid border-neutral rounded-lg;

&__input {
@apply font-light rounded-lg focus:outline-none;
@apply h-8 grow focus:border-primary;
}

&__magnifier {
@apply p-1 h-8 w-8 cursor-pointer rounded;
}

&__magnifier > svg {
@apply m-auto;
}

&__magnifier:hover {
@apply bg-primary-50;
}
}
42 changes: 42 additions & 0 deletions components/SearchInput/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import userEvent from "@testing-library/user-event"
import React from "react"
import { act, render, waitFor } from "@testing-library/react"
import SearchInput from "."

describe(SearchInput, () => {
it("returns the search on enter", async () => {
const mockFn = jest.fn()
const { container } = render(
<SearchInput searchPhrase={mockFn} initialValue="" />
)

const input = container.querySelector(".SearchInput__input")
if (input)
await act(async () => {
await userEvent.type(input, "Search type phrase")
await userEvent.type(input, "{enter}")
})

expect(mockFn).toHaveBeenLastCalledWith("Search type phrase")
})

it("returns the search on click", async () => {
const mockFn = jest.fn()
const { container } = render(
<SearchInput searchPhrase={mockFn} initialValue="" />
)

const input = container.querySelector(".SearchInput__input")
if (input)
await act(async () => {
await userEvent.type(input, "Search click phrase")
})

const magnifier = container.querySelector(".SearchInput__magnifier")
if (magnifier) await userEvent.click(magnifier)

await waitFor(() => {
expect(mockFn).toHaveBeenLastCalledWith("Search click phrase")
})
})
})
40 changes: 40 additions & 0 deletions components/SearchInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { useState } from "react"
import IconMagnifyingGlass from "@heroicons/react/20/solid/MagnifyingGlassIcon"

import "./index.scss"

export type SearchInputProps = {
searchPhrase: (search: string) => void
initialValue: string
placeholder?: string
}

export default function SearchInput({
searchPhrase,
initialValue: setSearchPhrase,
placeholder = "Search",
}: SearchInputProps): JSX.Element {
const [search, setSearch] = useState(setSearchPhrase)

const onChange = (event: React.ChangeEvent<HTMLInputElement>) =>
setSearch(event.target.value)

const onSubmit = (event: React.FormEvent) => {
event.preventDefault()
searchPhrase(search)
}

return (
<form className="SearchInput" onSubmit={onSubmit}>
<input
placeholder={placeholder}
className="SearchInput__input"
value={search}
onChange={onChange}
/>
<button className="SearchInput__magnifier">
<IconMagnifyingGlass />
</button>
</form>
)
}
22 changes: 22 additions & 0 deletions stories/components/SearchInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { type Meta, type StoryObj } from "@storybook/react"
import SearchInput, { SearchInputProps } from "~/components/SearchInput"

const meta = {
title: "Toolbox/SearchInput",
component: SearchInput,
} satisfies Meta<typeof SearchInput>
export default meta

export const Default: StoryObj<typeof meta> = {
args: {
initialValue: "",
placeholder: "Search",
} as SearchInputProps,
}

export const InitialValue: StoryObj<typeof meta> = {
args: {
initialValue: "Initial value",
placeholder: "Search",
} as SearchInputProps,
}

0 comments on commit bbe5844

Please sign in to comment.