@lateralus-ai/shipping-ui 2.0.0-dev.3 → 2.0.0-dev.5
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/index.cjs +3 -3
- package/dist/index.esm.js +40 -14
- package/dist/tailwind-theme.d.ts +4 -4
- package/dist/{theme-entry-CxDa1D0_.mjs → theme-entry-BUK3MJUJ.mjs} +4 -4
- package/dist/{theme-entry-D2X3Ptjf.js → theme-entry-ygTpGaNC.js} +1 -1
- package/dist/theme.cjs +1 -1
- package/dist/theme.esm.js +1 -1
- package/package.json +128 -128
- package/src/components/Tabs.tsx +148 -139
- package/src/components/index.ts +42 -42
- package/src/index.ts +74 -74
- package/src/patterns/Search/ResultRow.tsx +58 -58
- package/src/patterns/Search/SearchModal.tsx +304 -292
- package/src/patterns/Search/index.ts +31 -31
- package/src/patterns/Skeleton/Skeleton.tsx +56 -56
- package/src/stories/canvases/ContentCanvas.tsx +114 -114
- package/src/stories/canvases/SearchCanvas.tsx +150 -150
- package/src/tailwind-theme.ts +4 -4
|
@@ -1,292 +1,304 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ChangeEvent,
|
|
3
|
-
type InputHTMLAttributes,
|
|
4
|
-
type ReactNode,
|
|
5
|
-
} from "react";
|
|
6
|
-
import {
|
|
7
|
-
Modal,
|
|
8
|
-
ModalBody,
|
|
9
|
-
ModalContent,
|
|
10
|
-
ModalDescription,
|
|
11
|
-
ModalTitle,
|
|
12
|
-
type ModalContentProps,
|
|
13
|
-
type ModalProps,
|
|
14
|
-
} from "../../components/Modal";
|
|
15
|
-
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../components/Tabs";
|
|
16
|
-
import { cn } from "../../utils/cn";
|
|
17
|
-
import { ResultRow, type ResultRowProps } from "./ResultRow";
|
|
18
|
-
import { SectionHeader } from "./SectionHeader";
|
|
19
|
-
import { Skeleton } from "../Skeleton";
|
|
20
|
-
|
|
21
|
-
export type SearchModalState = "idle" | "loading" | "results";
|
|
22
|
-
|
|
23
|
-
export type SearchFilterTab = {
|
|
24
|
-
value: string;
|
|
25
|
-
label: string;
|
|
26
|
-
count?: number;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export type SearchModalProps = ModalProps & {
|
|
30
|
-
/** Panel state when using the built-in layout helpers. */
|
|
31
|
-
state?: SearchModalState;
|
|
32
|
-
className?: string;
|
|
33
|
-
contentClassName?: string;
|
|
34
|
-
showOverlay?: boolean;
|
|
35
|
-
overlayClassName?: string;
|
|
36
|
-
children?: ReactNode;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const DEFAULT_FILTERS: SearchFilterTab[] = [
|
|
40
|
-
{ value: "all", label: "All", count: 0 },
|
|
41
|
-
{ value: "reports", label: "Reports", count: 0 },
|
|
42
|
-
{ value: "chats", label: "Chats", count: 0 },
|
|
43
|
-
{ value: "issues", label: "Issues", count: 0 },
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Search dialog composed on Modal.
|
|
48
|
-
* Use compound parts (Input / Body / Filters / Results) for app wiring,
|
|
49
|
-
* or pass `state` + demo children for Storybook.
|
|
50
|
-
*/
|
|
51
|
-
export const SearchModal = ({
|
|
52
|
-
state,
|
|
53
|
-
className,
|
|
54
|
-
contentClassName,
|
|
55
|
-
showOverlay = true,
|
|
56
|
-
overlayClassName,
|
|
57
|
-
children,
|
|
58
|
-
...modalProps
|
|
59
|
-
}: SearchModalProps) => (
|
|
60
|
-
<Modal {...modalProps}>
|
|
61
|
-
<ModalContent
|
|
62
|
-
showOverlay={showOverlay}
|
|
63
|
-
overlayClassName={overlayClassName}
|
|
64
|
-
className={cn(
|
|
65
|
-
"flex max-h-[min(80vh,640px)] w-[min(100vw-2rem,700px)] max-w-[768px] flex-col p-0",
|
|
66
|
-
contentClassName,
|
|
67
|
-
)}
|
|
68
|
-
aria-label="Search"
|
|
69
|
-
data-state={state}
|
|
70
|
-
>
|
|
71
|
-
<ModalTitle className="sr-only">Search</ModalTitle>
|
|
72
|
-
<ModalDescription className="sr-only">
|
|
73
|
-
Search reports, chats, or issues
|
|
74
|
-
</ModalDescription>
|
|
75
|
-
<div className={cn("flex min-h-0 flex-1 flex-col", className)}>
|
|
76
|
-
{children}
|
|
77
|
-
</div>
|
|
78
|
-
</ModalContent>
|
|
79
|
-
</Modal>
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
export type SearchModalInputProps = Omit<
|
|
83
|
-
InputHTMLAttributes<HTMLInputElement>,
|
|
84
|
-
"type"
|
|
85
|
-
> & {
|
|
86
|
-
className?: string;
|
|
87
|
-
wrapperClassName?: string;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export const SearchModalInput = ({
|
|
91
|
-
className,
|
|
92
|
-
wrapperClassName,
|
|
93
|
-
placeholder = "Search reports, chats, or issues…",
|
|
94
|
-
...props
|
|
95
|
-
}: SearchModalInputProps) => (
|
|
96
|
-
<div
|
|
97
|
-
className={cn(
|
|
98
|
-
"shrink-0 p-3",
|
|
99
|
-
wrapperClassName,
|
|
100
|
-
)}
|
|
101
|
-
>
|
|
102
|
-
<div className="flex min-h-10 items-center px-3">
|
|
103
|
-
<input
|
|
104
|
-
type="search"
|
|
105
|
-
placeholder={placeholder}
|
|
106
|
-
className={cn(
|
|
107
|
-
"w-full bg-transparent text-caption-1 text-display-on-light-primary",
|
|
108
|
-
"placeholder:text-display-on-light-tertiary focus:outline-none",
|
|
109
|
-
className,
|
|
110
|
-
)}
|
|
111
|
-
aria-label="Search query"
|
|
112
|
-
{...props}
|
|
113
|
-
/>
|
|
114
|
-
</div>
|
|
115
|
-
</div>
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
export const SearchModalDivider = ({ className }: { className?: string }) => (
|
|
119
|
-
<div
|
|
120
|
-
className={cn("h-px w-full shrink-0 bg-divider-primary", className)}
|
|
121
|
-
aria-hidden
|
|
122
|
-
/>
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
export type SearchModalBodyProps = {
|
|
126
|
-
children: ReactNode;
|
|
127
|
-
className?: string;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
export const SearchModalBody = ({
|
|
131
|
-
children,
|
|
132
|
-
className,
|
|
133
|
-
}: SearchModalBodyProps) => (
|
|
134
|
-
<ModalBody
|
|
135
|
-
{
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
export
|
|
195
|
-
|
|
196
|
-
children
|
|
197
|
-
className
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
className
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
export
|
|
257
|
-
state
|
|
258
|
-
query
|
|
259
|
-
onQueryChange
|
|
260
|
-
filter
|
|
261
|
-
onFilterChange
|
|
262
|
-
filters
|
|
263
|
-
recentItems
|
|
264
|
-
resultItems
|
|
265
|
-
className
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
1
|
+
import {
|
|
2
|
+
type ChangeEvent,
|
|
3
|
+
type InputHTMLAttributes,
|
|
4
|
+
type ReactNode,
|
|
5
|
+
} from "react";
|
|
6
|
+
import {
|
|
7
|
+
Modal,
|
|
8
|
+
ModalBody,
|
|
9
|
+
ModalContent,
|
|
10
|
+
ModalDescription,
|
|
11
|
+
ModalTitle,
|
|
12
|
+
type ModalContentProps,
|
|
13
|
+
type ModalProps,
|
|
14
|
+
} from "../../components/Modal";
|
|
15
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../components/Tabs";
|
|
16
|
+
import { cn } from "../../utils/cn";
|
|
17
|
+
import { ResultRow, type ResultRowProps } from "./ResultRow";
|
|
18
|
+
import { SectionHeader } from "./SectionHeader";
|
|
19
|
+
import { Skeleton } from "../Skeleton";
|
|
20
|
+
|
|
21
|
+
export type SearchModalState = "idle" | "loading" | "results";
|
|
22
|
+
|
|
23
|
+
export type SearchFilterTab = {
|
|
24
|
+
value: string;
|
|
25
|
+
label: string;
|
|
26
|
+
count?: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type SearchModalProps = ModalProps & {
|
|
30
|
+
/** Panel state when using the built-in layout helpers. */
|
|
31
|
+
state?: SearchModalState;
|
|
32
|
+
className?: string;
|
|
33
|
+
contentClassName?: string;
|
|
34
|
+
showOverlay?: boolean;
|
|
35
|
+
overlayClassName?: string;
|
|
36
|
+
children?: ReactNode;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const DEFAULT_FILTERS: SearchFilterTab[] = [
|
|
40
|
+
{ value: "all", label: "All", count: 0 },
|
|
41
|
+
{ value: "reports", label: "Reports", count: 0 },
|
|
42
|
+
{ value: "chats", label: "Chats", count: 0 },
|
|
43
|
+
{ value: "issues", label: "Issues", count: 0 },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Search dialog composed on Modal.
|
|
48
|
+
* Use compound parts (Input / Body / Filters / Results) for app wiring,
|
|
49
|
+
* or pass `state` + demo children for Storybook.
|
|
50
|
+
*/
|
|
51
|
+
export const SearchModal = ({
|
|
52
|
+
state,
|
|
53
|
+
className,
|
|
54
|
+
contentClassName,
|
|
55
|
+
showOverlay = true,
|
|
56
|
+
overlayClassName,
|
|
57
|
+
children,
|
|
58
|
+
...modalProps
|
|
59
|
+
}: SearchModalProps) => (
|
|
60
|
+
<Modal {...modalProps}>
|
|
61
|
+
<ModalContent
|
|
62
|
+
showOverlay={showOverlay}
|
|
63
|
+
overlayClassName={overlayClassName}
|
|
64
|
+
className={cn(
|
|
65
|
+
"flex max-h-[min(80vh,640px)] w-[min(100vw-2rem,700px)] max-w-[768px] flex-col p-0",
|
|
66
|
+
contentClassName,
|
|
67
|
+
)}
|
|
68
|
+
aria-label="Search"
|
|
69
|
+
data-state={state}
|
|
70
|
+
>
|
|
71
|
+
<ModalTitle className="sr-only">Search</ModalTitle>
|
|
72
|
+
<ModalDescription className="sr-only">
|
|
73
|
+
Search reports, chats, or issues
|
|
74
|
+
</ModalDescription>
|
|
75
|
+
<div className={cn("flex min-h-0 flex-1 flex-col", className)}>
|
|
76
|
+
{children}
|
|
77
|
+
</div>
|
|
78
|
+
</ModalContent>
|
|
79
|
+
</Modal>
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
export type SearchModalInputProps = Omit<
|
|
83
|
+
InputHTMLAttributes<HTMLInputElement>,
|
|
84
|
+
"type"
|
|
85
|
+
> & {
|
|
86
|
+
className?: string;
|
|
87
|
+
wrapperClassName?: string;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const SearchModalInput = ({
|
|
91
|
+
className,
|
|
92
|
+
wrapperClassName,
|
|
93
|
+
placeholder = "Search reports, chats, or issues…",
|
|
94
|
+
...props
|
|
95
|
+
}: SearchModalInputProps) => (
|
|
96
|
+
<div
|
|
97
|
+
className={cn(
|
|
98
|
+
"shrink-0 p-3",
|
|
99
|
+
wrapperClassName,
|
|
100
|
+
)}
|
|
101
|
+
>
|
|
102
|
+
<div className="flex min-h-10 items-center px-3">
|
|
103
|
+
<input
|
|
104
|
+
type="search"
|
|
105
|
+
placeholder={placeholder}
|
|
106
|
+
className={cn(
|
|
107
|
+
"w-full bg-transparent text-caption-1 text-display-on-light-primary",
|
|
108
|
+
"placeholder:text-display-on-light-tertiary focus:outline-none",
|
|
109
|
+
className,
|
|
110
|
+
)}
|
|
111
|
+
aria-label="Search query"
|
|
112
|
+
{...props}
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
export const SearchModalDivider = ({ className }: { className?: string }) => (
|
|
119
|
+
<div
|
|
120
|
+
className={cn("h-px w-full shrink-0 bg-divider-primary", className)}
|
|
121
|
+
aria-hidden
|
|
122
|
+
/>
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
export type SearchModalBodyProps = {
|
|
126
|
+
children: ReactNode;
|
|
127
|
+
className?: string;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export const SearchModalBody = ({
|
|
131
|
+
children,
|
|
132
|
+
className,
|
|
133
|
+
}: SearchModalBodyProps) => (
|
|
134
|
+
<ModalBody
|
|
135
|
+
className={cn(
|
|
136
|
+
"flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden p-2",
|
|
137
|
+
className,
|
|
138
|
+
)}
|
|
139
|
+
>
|
|
140
|
+
{children}
|
|
141
|
+
</ModalBody>
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
export type SearchModalFiltersProps = {
|
|
145
|
+
tabs?: SearchFilterTab[];
|
|
146
|
+
value: string;
|
|
147
|
+
onValueChange: (value: string) => void;
|
|
148
|
+
children?: ReactNode;
|
|
149
|
+
className?: string;
|
|
150
|
+
listClassName?: string;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Pill-style filter tabs for the results state.
|
|
155
|
+
* Children render below the tab list (typically a single filtered results list).
|
|
156
|
+
* For per-tab panels, nest `SearchModalFilterPanel` (TabsContent) as children.
|
|
157
|
+
*/
|
|
158
|
+
export const SearchModalFilters = ({
|
|
159
|
+
tabs = DEFAULT_FILTERS,
|
|
160
|
+
value,
|
|
161
|
+
onValueChange,
|
|
162
|
+
children,
|
|
163
|
+
className,
|
|
164
|
+
listClassName,
|
|
165
|
+
}: SearchModalFiltersProps) => (
|
|
166
|
+
<Tabs
|
|
167
|
+
type="pills"
|
|
168
|
+
value={value}
|
|
169
|
+
onValueChange={onValueChange}
|
|
170
|
+
className={cn("min-h-0 flex-1 gap-0", className)}
|
|
171
|
+
>
|
|
172
|
+
<TabsList
|
|
173
|
+
className={cn(
|
|
174
|
+
"w-full shrink-0 bg-background-primary p-2",
|
|
175
|
+
listClassName,
|
|
176
|
+
)}
|
|
177
|
+
>
|
|
178
|
+
{tabs.map((tab) => (
|
|
179
|
+
<TabsTrigger key={tab.value} value={tab.value} count={tab.count}>
|
|
180
|
+
{tab.label}
|
|
181
|
+
</TabsTrigger>
|
|
182
|
+
))}
|
|
183
|
+
</TabsList>
|
|
184
|
+
<div className="min-h-0 flex-1 overflow-y-auto">{children}</div>
|
|
185
|
+
</Tabs>
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
export type SearchModalFilterPanelProps = {
|
|
189
|
+
value: string;
|
|
190
|
+
children: ReactNode;
|
|
191
|
+
className?: string;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export const SearchModalFilterPanel = ({
|
|
195
|
+
value,
|
|
196
|
+
children,
|
|
197
|
+
className,
|
|
198
|
+
}: SearchModalFilterPanelProps) => (
|
|
199
|
+
<TabsContent value={value} className={className}>
|
|
200
|
+
{children}
|
|
201
|
+
</TabsContent>
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
export type SearchModalResultsProps = {
|
|
205
|
+
items?: ResultRowProps[];
|
|
206
|
+
children?: ReactNode;
|
|
207
|
+
className?: string;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
export const SearchModalResults = ({
|
|
211
|
+
items,
|
|
212
|
+
children,
|
|
213
|
+
className,
|
|
214
|
+
}: SearchModalResultsProps) => (
|
|
215
|
+
<div className={cn("flex flex-col", className)}>
|
|
216
|
+
{items?.map((item, index) => (
|
|
217
|
+
<ResultRow key={index} {...item} />
|
|
218
|
+
))}
|
|
219
|
+
{children}
|
|
220
|
+
</div>
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
export type SearchModalIdleProps = {
|
|
224
|
+
label?: string;
|
|
225
|
+
items?: ResultRowProps[];
|
|
226
|
+
children?: ReactNode;
|
|
227
|
+
className?: string;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export const SearchModalIdle = ({
|
|
231
|
+
label = "Recently viewed",
|
|
232
|
+
items,
|
|
233
|
+
children,
|
|
234
|
+
className,
|
|
235
|
+
}: SearchModalIdleProps) => (
|
|
236
|
+
<div className={cn("flex min-h-0 flex-1 flex-col p-1", className)}>
|
|
237
|
+
<SectionHeader
|
|
238
|
+
label={label}
|
|
239
|
+
className="shrink-0 px-3 py-1 text-caption-2 font-normal normal-case tracking-[0.01em] text-display-on-light-secondary"
|
|
240
|
+
/>
|
|
241
|
+
<div className="min-h-0 flex-1 overflow-y-auto">
|
|
242
|
+
<SearchModalResults items={items}>{children}</SearchModalResults>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
export type SearchModalLoadingProps = {
|
|
248
|
+
className?: string;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export const SearchModalLoading = ({ className }: SearchModalLoadingProps) => (
|
|
252
|
+
<Skeleton variant="search" className={cn("rounded-none", className)} />
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
/** Convenience controlled panel for Storybook / simple embeds. */
|
|
256
|
+
export type SearchModalPanelProps = {
|
|
257
|
+
state?: SearchModalState;
|
|
258
|
+
query?: string;
|
|
259
|
+
onQueryChange?: (query: string) => void;
|
|
260
|
+
filter?: string;
|
|
261
|
+
onFilterChange?: (filter: string) => void;
|
|
262
|
+
filters?: SearchFilterTab[];
|
|
263
|
+
recentItems?: ResultRowProps[];
|
|
264
|
+
resultItems?: ResultRowProps[];
|
|
265
|
+
className?: string;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export const SearchModalPanel = ({
|
|
269
|
+
state = "idle",
|
|
270
|
+
query = "",
|
|
271
|
+
onQueryChange,
|
|
272
|
+
filter = "all",
|
|
273
|
+
onFilterChange,
|
|
274
|
+
filters = DEFAULT_FILTERS,
|
|
275
|
+
recentItems,
|
|
276
|
+
resultItems,
|
|
277
|
+
className,
|
|
278
|
+
}: SearchModalPanelProps) => {
|
|
279
|
+
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
280
|
+
onQueryChange?.(event.target.value);
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
return (
|
|
284
|
+
<div className={cn("flex min-h-0 flex-1 flex-col", className)} data-state={state}>
|
|
285
|
+
<SearchModalInput value={query} onChange={handleChange} />
|
|
286
|
+
<SearchModalDivider />
|
|
287
|
+
<SearchModalBody className={state === "loading" ? "p-0" : undefined}>
|
|
288
|
+
{state === "idle" && <SearchModalIdle items={recentItems} />}
|
|
289
|
+
{state === "loading" && <SearchModalLoading />}
|
|
290
|
+
{state === "results" && (
|
|
291
|
+
<SearchModalFilters
|
|
292
|
+
tabs={filters}
|
|
293
|
+
value={filter}
|
|
294
|
+
onValueChange={(next) => onFilterChange?.(next)}
|
|
295
|
+
>
|
|
296
|
+
<SearchModalResults items={resultItems} />
|
|
297
|
+
</SearchModalFilters>
|
|
298
|
+
)}
|
|
299
|
+
</SearchModalBody>
|
|
300
|
+
</div>
|
|
301
|
+
);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
export type { ModalContentProps };
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
export { Pill, type PillProps, type PillSize, type PillState } from "./Pill";
|
|
2
|
-
export { PillInfo, type PillInfoProps, type PillInfoType } from "./PillInfo";
|
|
3
|
-
export {
|
|
4
|
-
ResultRow,
|
|
5
|
-
type ResultRowProps,
|
|
6
|
-
type ResultRowState,
|
|
7
|
-
type ResultRowVariant,
|
|
8
|
-
} from "./ResultRow";
|
|
9
|
-
export {
|
|
10
|
-
SearchModal,
|
|
11
|
-
SearchModalBody,
|
|
12
|
-
SearchModalDivider,
|
|
13
|
-
SearchModalFilterPanel,
|
|
14
|
-
SearchModalFilters,
|
|
15
|
-
SearchModalIdle,
|
|
16
|
-
SearchModalInput,
|
|
17
|
-
SearchModalLoading,
|
|
18
|
-
SearchModalPanel,
|
|
19
|
-
SearchModalResults,
|
|
20
|
-
type SearchFilterTab,
|
|
21
|
-
type SearchModalBodyProps,
|
|
22
|
-
type SearchModalFiltersProps,
|
|
23
|
-
type SearchModalIdleProps,
|
|
24
|
-
type SearchModalInputProps,
|
|
25
|
-
type SearchModalLoadingProps,
|
|
26
|
-
type SearchModalPanelProps,
|
|
27
|
-
type SearchModalProps,
|
|
28
|
-
type SearchModalResultsProps,
|
|
29
|
-
type SearchModalState,
|
|
30
|
-
} from "./SearchModal";
|
|
31
|
-
export { SectionHeader, type SectionHeaderProps } from "./SectionHeader";
|
|
1
|
+
export { Pill, type PillProps, type PillSize, type PillState } from "./Pill";
|
|
2
|
+
export { PillInfo, type PillInfoProps, type PillInfoType } from "./PillInfo";
|
|
3
|
+
export {
|
|
4
|
+
ResultRow,
|
|
5
|
+
type ResultRowProps,
|
|
6
|
+
type ResultRowState,
|
|
7
|
+
type ResultRowVariant,
|
|
8
|
+
} from "./ResultRow";
|
|
9
|
+
export {
|
|
10
|
+
SearchModal,
|
|
11
|
+
SearchModalBody,
|
|
12
|
+
SearchModalDivider,
|
|
13
|
+
SearchModalFilterPanel,
|
|
14
|
+
SearchModalFilters,
|
|
15
|
+
SearchModalIdle,
|
|
16
|
+
SearchModalInput,
|
|
17
|
+
SearchModalLoading,
|
|
18
|
+
SearchModalPanel,
|
|
19
|
+
SearchModalResults,
|
|
20
|
+
type SearchFilterTab,
|
|
21
|
+
type SearchModalBodyProps,
|
|
22
|
+
type SearchModalFiltersProps,
|
|
23
|
+
type SearchModalIdleProps,
|
|
24
|
+
type SearchModalInputProps,
|
|
25
|
+
type SearchModalLoadingProps,
|
|
26
|
+
type SearchModalPanelProps,
|
|
27
|
+
type SearchModalProps,
|
|
28
|
+
type SearchModalResultsProps,
|
|
29
|
+
type SearchModalState,
|
|
30
|
+
} from "./SearchModal";
|
|
31
|
+
export { SectionHeader, type SectionHeaderProps } from "./SectionHeader";
|