Skip to content

Commit

Permalink
Components: Introducing SearchField (#3119)
Browse files Browse the repository at this point in the history
Co-authored-by: sarahgm <[email protected]>
  • Loading branch information
OsamaAbdellateef and sarahgm authored Jul 25, 2023
1 parent f429948 commit 3ec37df
Show file tree
Hide file tree
Showing 13 changed files with 479 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SearchField } from '@marigold/components/src/SearchField';

export default () => <SearchField label="search" />;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SearchField } from '@marigold/components/src/SearchField';

export default () => <SearchField label="search" disabled />;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { SearchField } from '@marigold/components/src/SearchField';

export default () => (
<SearchField label="search" error errorMessage="Oops something went wrong" />
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { SearchField } from '@marigold/components/src/SearchField';

export default () => (
<SearchField label="search" value="Can't edit this value" readOnly />
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { SearchField } from '@marigold/components/src/SearchField';

export default () => <SearchField label="search" required />;
145 changes: 145 additions & 0 deletions docs/content/components/search-field/search-field.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
---
title: SearchField
group: Form
caption: Component which allows user to enter and clear a search query.
---

The `<SearchField>` component is a versatile UI element that enables users to search for specific information within a given context or data set. It offers a user-friendly input field specifically designed for search queries, often accompanied by a search icon or button to initiate the search action.

`<SearchField>` consists of an input element, a label, and an optional clear button. `<SearchField>` automatically manages the labeling and relationships between the elements, and handles keyboard events. Users can press the Escape key to clear the `<SearchField>`, or the Enter key to trigger the `onSubmit` event.

## Usage

### Import

To import the component you just have to use this code below.

```tsx onlyCode
import { SearchField } from '@marigold/components';
```

### Props

<PropsTable
props={[
{
property: 'label',
type: 'ReactNode',
description:
"The label text. If you don't want to visually display a label, provide an `aria-label` or `aria-labelledby` attribute for accessibility.",
default: 'none',
},
{
property: 'description',
type: 'ReactNode',
description: 'A helpful text.',
default: 'none',
},
{
property: 'errorMessage',
type: 'ReactNode',
description: 'An error message.',
default: 'none',
},
{
property: 'error',
type: 'boolean',
description:
'If `true`, the field is considered invalid and if set the `errorMessage` is shown instead of the `description`.',
default: 'false',
},
{
property: 'value',
type: 'string',
description: 'The value of the input field.',
default: 'none',
},
{
property: 'disabled',
type: 'boolean',
description: 'If `true`, the input is disabled.',
default: 'false',
},
{
property: 'required',
type: 'boolean',
description: 'If `true`, the input is required',
default: 'false',
},
{
property: 'validationState',
type: 'ValidationState',
description:
'Whether the input should display its "valid" or "invalid" visual styling.',
default: 'none',
},
{
property: 'autoFocus',
type: 'boolean',
description: 'Whether the element should receive focus on render.',
default: 'none',
},
{
property: 'autoComplete',
type: 'string',
description:
'Describes the type of autocomplete functionality the input should provide if any.',
default: 'none',
},
{
property: 'readOnly',
type: 'boolean',
description: 'If `true`, the input is readOnly.',
default: 'false',
},
{
property: 'type',
type: 'string',
description: 'The type of the input field.',
default: 'text',
},
{
property: 'onChange',
type: 'function',
description:
"A callback function that is called with the input's current value when the input `value` changes.",
default: 'none',
},
{
property: 'width',
type: 'string',
description: 'Control the `width` of the field.',
default: '100%',
},
]}
/>

## Examples

### Simple Search Field

This is how a basic `<SearchField>` looks like.

<ComponentDemo file="./search-field-basic.demo.tsx" />

### Disabled Search Field

If you want to implement a disabled `<SearchField>` you have to add the `disabled` property.

<ComponentDemo file="./search-field-disabled.demo.tsx" />

### Required Search Field

The `required` property adds an required icon to the label.

<ComponentDemo file="./search-field-req.demo.tsx" />

### Text Field with an Error

The example shows how to set the `error` and `errorMessage` properties. If you fill in the field correctly, it will disappear automatically.

<ComponentDemo file="./search-field-error.demo.tsx" />

### Text Field with readOnly

<ComponentDemo file="./search-field-readoOnly.demo.tsx" />
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
"@marigold/jest-config": "workspace:*",
"@marigold/prettier-config": "workspace:*",
"@marigold/tsconfig": "workspace:*",
"@react-aria/searchfield": "3.5.3",
"@react-stately/searchfield": "3.4.3",
"@testing-library/dom": "9.3.1",
"@testing-library/jest-dom": "5.17.0",
"@testing-library/react": "14.0.0",
Expand Down
11 changes: 3 additions & 8 deletions packages/components/src/Autocomplete/Autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Popover } from '../Overlay';
import { ClearButton } from './ClearButton';

// Search Icon
// ---------------
//----------------
const SearchIcon = (props: { className?: string }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
Expand Down Expand Up @@ -118,10 +118,9 @@ export const Autocomplete = ({
},
state
);

// TODO: until `react-aria` gives us error and description props.
const errorMessageProps = { 'aria-invalid': error };
const { isDisabled, ...restClearButtonProps } = clearButtonProps;

return (
<>
<FieldBase
Expand All @@ -130,15 +129,10 @@ export const Autocomplete = ({
description={props.description}
error={error}
errorMessage={props.errorMessage}
errorMessageProps={errorMessageProps}
disabled={disabled}
width={width}
>
<Input
/**
* We use `size` for styles which is a string, not like
* the regular HTML attribute, which is a number
*/
{...(inputProps as any)}
ref={inputRef}
icon={<SearchIcon />}
Expand All @@ -153,6 +147,7 @@ export const Autocomplete = ({
}
/>
</FieldBase>

<Popover
state={state}
ref={popoverRef}
Expand Down
76 changes: 76 additions & 0 deletions packages/components/src/SearchField/SearchField.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* eslint-disable react-hooks/rules-of-hooks */
import React, { useState } from 'react';
import { Meta, StoryObj } from '@storybook/react';

import { SearchField } from './SearchField';

const meta = {
title: 'Components/SearchField',
argTypes: {
label: {
control: {
type: 'text',
},
description: 'The label',
},
description: {
control: {
type: 'text',
},
description: 'Help Text',
defaultValue: 'This is a help text description',
},
error: {
control: {
type: 'boolean',
},
description: 'Is the input invalid?',
},
errorMessage: {
control: {
type: 'text',
},
description: 'Error Message',
defaultValue: 'Something went wrong',
},
width: {
control: {
type: 'text',
},
description: 'The width of the field',
},
},
args: {
label: 'Select Favorite:',
description: 'This is a help text description',
errorMessage: 'Something went wrong',
},
} satisfies Meta<typeof SearchField>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Basic: Story = {
render: args => <SearchField required label="search field" {...args} />,
};

export const Controlled: Story = {
render: args => {
const [value, setValue] = useState('');
return (
<>
<SearchField
value={value}
onChange={setValue}
required
label="search field"
{...args}
/>
<pre>
<strong>Input Value:</strong>
{value}
</pre>
</>
);
},
};
Loading

2 comments on commit 3ec37df

@vercel
Copy link

@vercel vercel bot commented on 3ec37df Jul 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

marigold-docs – ./

marigold-docs.vercel.app
marigold-docs-marigold.vercel.app
marigold-docs-git-main-marigold.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 3ec37df Jul 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

marigold-storybook – ./

marigold-storybook-marigold.vercel.app
marigold-storybook-git-main-marigold.vercel.app
marigold-latest.vercel.app

Please sign in to comment.