@ceed/ads 1.35.0 → 1.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/SearchBar/SearchBar.d.ts +6 -5
- package/dist/components/SearchBar/index.d.ts +3 -2
- package/dist/components/index.d.ts +1 -2
- package/dist/components/inputs/SearchBar.md +127 -50
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +3 -3
- package/dist/index.cjs +22 -22
- package/dist/index.js +22 -22
- package/framer/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type BoxProps } from '@mui/joy/Box';
|
|
2
3
|
export type SearchBarSlot = 'root';
|
|
3
4
|
export interface SearchBarOption {
|
|
4
5
|
label: string;
|
|
5
6
|
value: string;
|
|
6
7
|
placeholder?: string;
|
|
7
8
|
}
|
|
8
|
-
export interface SearchBarProps extends Omit<
|
|
9
|
-
|
|
9
|
+
export interface SearchBarProps extends Omit<BoxProps, 'onChange'> {
|
|
10
|
+
showSelect?: boolean;
|
|
10
11
|
options?: SearchBarOption[];
|
|
12
|
+
placeholder?: string;
|
|
11
13
|
value: string;
|
|
12
14
|
onChange: (value: string) => void;
|
|
13
15
|
onSearch?: (params: {
|
|
@@ -15,6 +17,5 @@ export interface SearchBarProps extends Omit<React.HTMLAttributes<HTMLDivElement
|
|
|
15
17
|
inputValue: string;
|
|
16
18
|
}) => void;
|
|
17
19
|
}
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
export declare const SearchBar: React.ForwardRefExoticComponent<SearchBarProps & React.RefAttributes<HTMLDivElement>>;
|
|
20
|
+
export type SearchBarOwnerState = Required<Pick<SearchBarProps, 'showSelect'>>;
|
|
21
|
+
export declare const SearchBar: React.ForwardRefExoticComponent<Omit<SearchBarProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
import { SearchBar } from './SearchBar';
|
|
2
|
+
export * from './SearchBar';
|
|
3
|
+
export default SearchBar;
|
|
@@ -49,8 +49,7 @@ export { ProfileMenu } from './ProfileMenu';
|
|
|
49
49
|
export { Radio, RadioGroup } from './Radio';
|
|
50
50
|
export { RadioTileGroup } from './RadioTileGroup';
|
|
51
51
|
export { RadioList } from './RadioList';
|
|
52
|
-
export { SearchBar } from './SearchBar';
|
|
53
|
-
export type { SearchBarOption, SearchBarOwnerState, SearchBarProps, SearchBarSlot } from './SearchBar';
|
|
52
|
+
export { SearchBar, type SearchBarProps, type SearchBarOwnerState, type SearchBarSlot, type SearchBarOption, } from './SearchBar';
|
|
54
53
|
export { Select, Option } from './Select';
|
|
55
54
|
export { Sheet } from './Sheet';
|
|
56
55
|
export { Stack } from './Stack';
|
|
@@ -2,58 +2,89 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
A search input component
|
|
6
|
-
|
|
7
|
-
> 💡 **Placeholder guidance**
|
|
8
|
-
>
|
|
9
|
-
> When `options` are provided, each option can include a `placeholder` field to hint at the expected input format for that category. This helps users understand what value to enter.
|
|
10
|
-
>
|
|
11
|
-
> - Account #: `e.g. 1234567`
|
|
12
|
-
> - Jira Issue #: `e.g. PROC-1234`
|
|
5
|
+
A search input component combining a text field and a search button. Optionally includes a category Select that lets users narrow results by keyword type. Hovering over the input while it has a value reveals a clear (✕) button to reset the field. Sizes to its content by default (`inline-flex`) and accepts all `Box` props for layout control.
|
|
13
6
|
|
|
14
7
|
```tsx
|
|
15
|
-
<SearchBar
|
|
8
|
+
<SearchBar value={value} onChange={setValue} />
|
|
16
9
|
```
|
|
17
10
|
|
|
18
|
-
| Field
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
| options
|
|
22
|
-
|
|
|
23
|
-
|
|
|
24
|
-
|
|
|
11
|
+
| Field | Description | Default |
|
|
12
|
+
| ----------- | ----------- | ------- |
|
|
13
|
+
| showSelect | — | — |
|
|
14
|
+
| options | — | — |
|
|
15
|
+
| placeholder | — | — |
|
|
16
|
+
| value | — | — |
|
|
17
|
+
| onChange | — | — |
|
|
18
|
+
| onSearch | — | — |
|
|
25
19
|
|
|
26
20
|
## Usage
|
|
27
21
|
|
|
28
22
|
```tsx
|
|
29
23
|
import { SearchBar } from '@ceed/ads';
|
|
30
24
|
|
|
25
|
+
// Basic
|
|
26
|
+
<SearchBar value={query} onChange={setQuery} onSearch={({ inputValue }) => fetch(inputValue)} />
|
|
27
|
+
|
|
28
|
+
// With category Select
|
|
31
29
|
<SearchBar
|
|
32
|
-
|
|
33
|
-
onChange={setQuery}
|
|
30
|
+
showSelect
|
|
34
31
|
options={[
|
|
35
32
|
{ label: 'Account #', value: 'account', placeholder: 'e.g. 1234567' },
|
|
36
33
|
{ label: 'Jira Issue #', value: 'jira', placeholder: 'e.g. PROC-1234' },
|
|
37
34
|
]}
|
|
38
|
-
|
|
35
|
+
value={query}
|
|
36
|
+
onChange={setQuery}
|
|
37
|
+
onSearch={({ selectValue, inputValue }) => fetch(selectValue, inputValue)}
|
|
39
38
|
/>
|
|
40
39
|
```
|
|
41
40
|
|
|
42
|
-
##
|
|
41
|
+
## With Select
|
|
42
|
+
|
|
43
|
+
Use `showSelect` together with `options` to display a category Select to the left of the text input. The selected category is passed as `selectValue` in the `onSearch` callback.
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
<SearchBar showSelect options={SAMPLE_OPTIONS} value={value} onChange={setValue} />
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Clearable Input
|
|
50
|
+
|
|
51
|
+
When the input has a value, hovering over the component reveals a clear (✕) button at the right of the text field. Clicking it calls `onChange('')` without triggering `onSearch`.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
<Stack alignItems="flex-start" gap={2}>
|
|
55
|
+
<Typography level="body-sm">Hover over the input to reveal the clear (✕) button.</Typography>
|
|
56
|
+
<SearchBar value={value} onChange={setValue} />
|
|
57
|
+
</Stack>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Placeholder
|
|
43
61
|
|
|
44
|
-
|
|
62
|
+
Each `SearchBarOption` can include a `placeholder` field that is shown in the text input while that category is selected. Pass a `placeholder` prop directly to override the option-level placeholder for all categories.
|
|
45
63
|
|
|
46
64
|
```tsx
|
|
47
|
-
<
|
|
65
|
+
<Stack alignItems="flex-start" gap={3}>
|
|
66
|
+
<Stack alignItems="flex-start" gap={1}>
|
|
67
|
+
<Typography level="body-xs" fontWeight="md">
|
|
68
|
+
No placeholder prop — uses the active option's placeholder
|
|
69
|
+
</Typography>
|
|
70
|
+
<SearchBar showSelect options={SAMPLE_OPTIONS} value={value} onChange={setValue} />
|
|
71
|
+
</Stack>
|
|
72
|
+
<Stack alignItems="flex-start" gap={1}>
|
|
73
|
+
<Typography level="body-xs" fontWeight="md">
|
|
74
|
+
placeholder="Search by keyword" — overrides option-level placeholder
|
|
75
|
+
</Typography>
|
|
76
|
+
<SearchBar showSelect options={SAMPLE_OPTIONS} placeholder="Search by keyword" value={value} onChange={setValue} />
|
|
77
|
+
</Stack>
|
|
78
|
+
</Stack>
|
|
48
79
|
```
|
|
49
80
|
|
|
50
81
|
## onSearch
|
|
51
82
|
|
|
52
|
-
`onSearch` fires when the search button is clicked or the Enter key is pressed. It receives
|
|
83
|
+
`onSearch` fires when the search button is clicked or the Enter key is pressed. It receives `inputValue` (always present) and `selectValue` (only present when `showSelect` is `true`).
|
|
53
84
|
|
|
54
85
|
```tsx
|
|
55
|
-
<Stack gap={2}>
|
|
56
|
-
<SearchBar options={SAMPLE_OPTIONS} value={value} onChange={setValue} onSearch={setLastSearch} />
|
|
86
|
+
<Stack alignItems="flex-start" gap={2}>
|
|
87
|
+
<SearchBar showSelect options={SAMPLE_OPTIONS} value={value} onChange={setValue} onSearch={setLastSearch} />
|
|
57
88
|
<Typography level="body-sm">value: "{value}"</Typography>
|
|
58
89
|
{lastSearch && <Typography level="body-sm">
|
|
59
90
|
onSearch: [{lastSearch.selectValue}] "{lastSearch.inputValue}"
|
|
@@ -61,43 +92,89 @@ Use `hideSelect` to hide the category Select and render a narrower input-only la
|
|
|
61
92
|
</Stack>
|
|
62
93
|
```
|
|
63
94
|
|
|
64
|
-
|
|
95
|
+
When `showSelect` is `false`, `selectValue` is omitted from the payload entirely — not `undefined` as a key, but absent.
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
<Stack alignItems="flex-start" gap={2}>
|
|
99
|
+
<Typography level="body-sm">
|
|
100
|
+
When <code>showSelect</code> is <code>false</code>, <code>selectValue</code> is omitted from the{' '}
|
|
101
|
+
<code>onSearch</code> payload.
|
|
102
|
+
</Typography>
|
|
103
|
+
<SearchBar value={value} onChange={setValue} onSearch={setLastSearch} />
|
|
104
|
+
{lastSearch && <Stack alignItems="flex-start" gap={0.5}>
|
|
105
|
+
<Typography level="body-sm">inputValue: "{lastSearch.inputValue}"</Typography>
|
|
106
|
+
<Typography level="body-sm" sx={{
|
|
107
|
+
color: lastSearch.selectValue === undefined ? 'success.500' : 'danger.500'
|
|
108
|
+
}}>
|
|
109
|
+
selectValue: {lastSearch.selectValue === undefined ? 'undefined ✅' : `"${lastSearch.selectValue}" ❌`}
|
|
110
|
+
</Typography>
|
|
111
|
+
</Stack>}
|
|
112
|
+
</Stack>
|
|
113
|
+
```
|
|
65
114
|
|
|
66
|
-
|
|
67
|
-
| ------------ | ---------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
68
|
-
| `value` | `string` | — | Current text input value |
|
|
69
|
-
| `onChange` | `(value: string) => void` | — | Called when the text input value changes |
|
|
70
|
-
| `onSearch` | `(params: { selectValue?: string; inputValue: string }) => void` | — | Called on search button click or Enter key |
|
|
71
|
-
| `hideSelect` | `boolean` | `false` | Hide the category Select and show a narrower input-only layout |
|
|
72
|
-
| `options` | `SearchBarOption[]` | — | List of selectable categories rendered in the category Select. Each item may include a `placeholder` hint shown in the text input when that category is active. Required when `hideSelect` is `false`. |
|
|
115
|
+
## Width
|
|
73
116
|
|
|
74
|
-
|
|
117
|
+
SearchBar sizes to its content by default. Pass any `Box` width prop to constrain or stretch it.
|
|
75
118
|
|
|
76
|
-
|
|
119
|
+
```tsx
|
|
120
|
+
<Stack alignItems="flex-start" gap={3}>
|
|
121
|
+
<Stack alignItems="flex-start" gap={1}>
|
|
122
|
+
<Typography level="body-xs" fontWeight="md">
|
|
123
|
+
width="100%" — stretches to parent width
|
|
124
|
+
</Typography>
|
|
125
|
+
<Box sx={{
|
|
126
|
+
border: '1px dashed',
|
|
127
|
+
borderColor: 'neutral.300',
|
|
128
|
+
padding: 1
|
|
129
|
+
}}>
|
|
130
|
+
<SearchBar width="100%" value={value} onChange={setValue} />
|
|
131
|
+
</Box>
|
|
132
|
+
</Stack>
|
|
133
|
+
<Stack alignItems="flex-start" gap={1}>
|
|
134
|
+
<Typography level="body-xs" fontWeight="md">
|
|
135
|
+
width={400} — fixed 400px
|
|
136
|
+
</Typography>
|
|
137
|
+
<SearchBar width={400} value={value} onChange={setValue} />
|
|
138
|
+
</Stack>
|
|
139
|
+
<Stack alignItems="flex-start" gap={1}>
|
|
140
|
+
<Typography level="body-xs" fontWeight="md">
|
|
141
|
+
No width prop — sizes to content (inline-flex default)
|
|
142
|
+
</Typography>
|
|
143
|
+
<SearchBar value={value} onChange={setValue} />
|
|
144
|
+
</Stack>
|
|
145
|
+
</Stack>
|
|
146
|
+
```
|
|
77
147
|
|
|
78
|
-
|
|
148
|
+
## Props and Customization
|
|
79
149
|
|
|
80
|
-
|
|
|
81
|
-
| ------------- |
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
150
|
+
| Prop | Type | Default | Description |
|
|
151
|
+
| ------------- | ---------------------------------------------------------------- | ------- | ----------------------------------------------------------------------------------- |
|
|
152
|
+
| `value` | `string` | — | Current value of the text input. Required. |
|
|
153
|
+
| `onChange` | `(value: string) => void` | — | Called when the text input value changes. Required. |
|
|
154
|
+
| `onSearch` | `(params: { selectValue?: string; inputValue: string }) => void` | — | Called on search button click or Enter key. |
|
|
155
|
+
| `showSelect` | `boolean` | `false` | Show the category Select alongside the input. |
|
|
156
|
+
| `options` | `SearchBarOption[]` | — | Category options for the Select. Required when `showSelect` is `true`. |
|
|
157
|
+
| `placeholder` | `string` | — | Placeholder text for the input. Takes priority over the option-level `placeholder`. |
|
|
85
158
|
|
|
86
|
-
|
|
159
|
+
> **Note**: Also accepts all `Box` props (`width`, `sx`, `className`, `style`, etc.).
|
|
87
160
|
|
|
88
|
-
|
|
89
|
-
| ------------------------ | ------------------------------------- | ----------------------------------------------- |
|
|
90
|
-
| `--ceed-SearchBar-width` | `300px` / `220px` (when `hideSelect`) | Component width; override per instance via `sx` |
|
|
161
|
+
### SearchBarOption
|
|
91
162
|
|
|
92
|
-
|
|
163
|
+
| Field | Type | Required | Description |
|
|
164
|
+
| ------------- | -------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
165
|
+
| `label` | `string` | ✓ | Display text shown in the Select dropdown. |
|
|
166
|
+
| `value` | `string` | ✓ | Identifier passed as `selectValue` in the `onSearch` callback. |
|
|
167
|
+
| `placeholder` | `string` | — | Hint text shown in the input while this category is selected (e.g. `"e.g. PROC-1234"`). Overridden by the top-level `placeholder` prop. |
|
|
93
168
|
|
|
94
169
|
## Best Practices
|
|
95
170
|
|
|
96
|
-
- Always provide
|
|
97
|
-
-
|
|
98
|
-
-
|
|
171
|
+
- Always provide `options` when `showSelect` is `true` — the Select renders nothing if `options` is omitted.
|
|
172
|
+
- Add a `placeholder` to each option to show the expected input format for that category.
|
|
173
|
+
- Use the top-level `placeholder` prop only when a single hint applies regardless of category.
|
|
174
|
+
- Prefer handling `onSearch` over `onChange` for server-side queries — fire the request once on explicit submission rather than on every keystroke.
|
|
99
175
|
|
|
100
176
|
## Accessibility
|
|
101
177
|
|
|
102
178
|
- The search button has `aria-label="Search"` and the clear button has `aria-label="Clear"`.
|
|
103
|
-
- The text input is a native `<input>` element
|
|
179
|
+
- The text input is a native `<input>` element; pressing Enter triggers `onSearch`.
|
|
180
|
+
- The clear button uses `onMouseDown` with `e.preventDefault()` to prevent the input from losing focus when clicked.
|