@lateralus-ai/shipping-ui 2.0.0-dev.0 → 2.0.0-dev.11

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.
Files changed (80) hide show
  1. package/dist/components/EmptyState.d.ts +1 -1
  2. package/dist/components/Entry.d.ts +27 -7
  3. package/dist/components/Modal.d.ts +36 -0
  4. package/dist/components/Tabs.d.ts +23 -8
  5. package/dist/components/index.d.ts +3 -2
  6. package/dist/index.cjs +32 -32
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.esm.js +4209 -3711
  9. package/dist/patterns/Search/ResultRow.d.ts +16 -7
  10. package/dist/patterns/Search/SearchModal.d.ts +84 -2
  11. package/dist/patterns/Search/index.d.ts +2 -2
  12. package/dist/primitives/Badge.d.ts +7 -4
  13. package/dist/primitives/Button.d.ts +17 -8
  14. package/dist/primitives/button-styles.d.ts +4 -0
  15. package/dist/primitives/index.d.ts +4 -2
  16. package/dist/style.css +1 -1
  17. package/dist/tailwind-theme.d.ts +4 -4
  18. package/dist/theme-entry-BUK3MJUJ.mjs +261 -0
  19. package/dist/theme-entry-ygTpGaNC.js +1 -0
  20. package/dist/theme-entry.d.ts +2 -0
  21. package/dist/theme.cjs +1 -0
  22. package/dist/theme.d.ts +2 -0
  23. package/dist/theme.esm.js +5 -0
  24. package/package.json +10 -3
  25. package/src/components/EmptyState.tsx +2 -2
  26. package/src/components/Entry.tsx +119 -45
  27. package/src/components/Modal.tsx +141 -0
  28. package/src/components/Tabs.tsx +146 -48
  29. package/src/components/index.ts +43 -13
  30. package/src/icons/arrow-paths.ts +8 -8
  31. package/src/icons/chevron-paths.ts +17 -17
  32. package/src/icons/icons-data.ts +656 -656
  33. package/src/index.ts +76 -50
  34. package/src/patterns/Search/ResultRow.tsx +44 -52
  35. package/src/patterns/Search/SearchModal.tsx +310 -88
  36. package/src/patterns/Search/index.ts +31 -5
  37. package/src/patterns/Sidebar/assets/logo-compliance-mark.png +5 -5
  38. package/src/patterns/Sidebar/assets/logo-compliance-mask.png +13 -13
  39. package/src/patterns/Sidebar/assets/logo-compliance.svg +17 -17
  40. package/src/patterns/Sidebar/assets/logo-technical-avatar.svg +17 -17
  41. package/src/patterns/Sidebar/assets/logo-technical-mark.png +5 -5
  42. package/src/patterns/Sidebar/assets/logo-technical.svg +16 -16
  43. package/src/patterns/Skeleton/Skeleton.tsx +56 -57
  44. package/src/primitives/Badge.tsx +20 -10
  45. package/src/primitives/Button.tsx +206 -37
  46. package/src/primitives/button-styles.ts +92 -0
  47. package/src/primitives/index.ts +7 -2
  48. package/src/stories/canvases/ButtonsCanvas.tsx +94 -44
  49. package/src/stories/canvases/ButtonsMatrixCanvas.tsx +8 -7
  50. package/src/stories/canvases/ContentCanvas.tsx +157 -88
  51. package/src/stories/canvases/SearchCanvas.tsx +150 -65
  52. package/src/stories/canvases/figma-buttons-layout.ts +83 -0
  53. package/src/stories/canvases/helpers.tsx +26 -43
  54. package/src/stories/components/Buttons.stories.tsx +11 -11
  55. package/src/stories/components/Chat.stories.tsx +11 -11
  56. package/src/stories/components/Content.stories.tsx +11 -11
  57. package/src/stories/components/Core.stories.tsx +11 -11
  58. package/src/stories/components/DomainForms.stories.tsx +11 -11
  59. package/src/stories/components/Filters.stories.tsx +11 -11
  60. package/src/stories/components/Forms.stories.tsx +11 -11
  61. package/src/stories/components/Icons.stories.tsx +11 -11
  62. package/src/stories/components/Illustrations.stories.tsx +11 -11
  63. package/src/stories/components/Library.stories.tsx +11 -11
  64. package/src/stories/components/Modals.stories.tsx +11 -11
  65. package/src/stories/components/Report.stories.tsx +11 -11
  66. package/src/stories/components/ReportLayout.stories.tsx +11 -11
  67. package/src/stories/components/Search.stories.tsx +11 -11
  68. package/src/stories/components/Settings.stories.tsx +11 -11
  69. package/src/stories/components/Ships.stories.tsx +11 -11
  70. package/src/stories/components/SidebarLayouts.stories.tsx +11 -11
  71. package/src/stories/components/Skeletons.stories.tsx +11 -11
  72. package/src/stories/components/Workflows.stories.tsx +11 -11
  73. package/src/stories/style-guide/Buttons.stories.tsx +11 -11
  74. package/src/stories/style-guide/ColorTokens.stories.tsx +11 -11
  75. package/src/stories/style-guide/Colors.stories.tsx +11 -11
  76. package/src/stories/style-guide/RaiseLevels.stories.tsx +11 -11
  77. package/src/stories/style-guide/Typography.stories.tsx +11 -11
  78. package/src/tailwind-theme.ts +4 -4
  79. package/src/theme-entry.ts +2 -0
  80. package/tailwind.config.ts +12 -0
package/src/index.ts CHANGED
@@ -1,50 +1,76 @@
1
- export { theme as tailwindTheme } from "./tailwind-theme";
2
-
3
- export * from "./tokens";
4
- export * from "./icons";
5
- export * from "./primitives";
6
- export * from "./illustrations";
7
-
8
- export {
9
- Input,
10
- ReportInput,
11
- InputType,
12
- Chip,
13
- Checkbox,
14
- Tab,
15
- Tabs,
16
- Header,
17
- Entry,
18
- EmptyState,
19
- ModalPanel,
20
- PdfViewer,
21
- ImageViewer,
22
- DocumentEditor,
23
- } from "./components";
24
-
25
- export type {
26
- InputProps,
27
- InputState,
28
- ReportInputProps,
29
- ReportInputState,
30
- InputTypeProps,
31
- InputTypeKind,
32
- InputTypeState,
33
- ChipProps,
34
- ChipVariant,
35
- CheckboxProps,
36
- TabProps,
37
- TabState,
38
- TabsProps,
39
- TabsItem,
40
- TabsType,
41
- HeaderProps,
42
- HeaderVariant,
43
- EntryProps,
44
- EntryType,
45
- EntryState,
46
- EmptyStateProps,
47
- } from "./components";
48
-
49
- export * as Patterns from "./patterns";
50
- export * as Domain from "./domain";
1
+ import "./style.css";
2
+
3
+ export { theme as tailwindTheme } from "./tailwind-theme";
4
+
5
+ export * from "./tokens";
6
+ export * from "./icons";
7
+ export * from "./primitives";
8
+ export * from "./illustrations";
9
+
10
+ export {
11
+ Input,
12
+ ReportInput,
13
+ InputType,
14
+ Chip,
15
+ Checkbox,
16
+ Tab,
17
+ Tabs,
18
+ TabsList,
19
+ TabsTrigger,
20
+ TabsContent,
21
+ Header,
22
+ Entry,
23
+ EmptyState,
24
+ Modal,
25
+ ModalTrigger,
26
+ ModalClose,
27
+ ModalPortal,
28
+ ModalOverlay,
29
+ ModalContent,
30
+ ModalTitle,
31
+ ModalDescription,
32
+ ModalHeaderSlot,
33
+ ModalBody,
34
+ ModalPanel,
35
+ PdfViewer,
36
+ ImageViewer,
37
+ DocumentEditor,
38
+ } from "./components";
39
+
40
+ export type {
41
+ InputProps,
42
+ InputState,
43
+ ReportInputProps,
44
+ ReportInputState,
45
+ InputTypeProps,
46
+ InputTypeKind,
47
+ InputTypeState,
48
+ ChipProps,
49
+ ChipVariant,
50
+ CheckboxProps,
51
+ TabProps,
52
+ TabState,
53
+ TabsProps,
54
+ TabsListProps,
55
+ TabsTriggerProps,
56
+ TabsContentProps,
57
+ TabsItem,
58
+ TabsType,
59
+ TabsAppearance,
60
+ HeaderProps,
61
+ HeaderVariant,
62
+ EntryProps,
63
+ EntryType,
64
+ EntryState,
65
+ EntryVariant,
66
+ EmptyStateProps,
67
+ ModalProps,
68
+ ModalOverlayProps,
69
+ ModalContentProps,
70
+ ModalTitleProps,
71
+ ModalDescriptionProps,
72
+ ModalBodyProps,
73
+ } from "./components";
74
+
75
+ export * as Patterns from "./patterns";
76
+ export * as Domain from "./domain";
@@ -1,52 +1,44 @@
1
- import { type ReactNode } from "react";
2
- import { ChatIcon, IssuesIcon, ReportIcon } from "../../icons";
3
- import { cn } from "../../utils/cn";
4
-
5
- export type ResultRowVariant = "report" | "chat" | "issue";
6
- export type ResultRowState = "idle";
7
-
8
- export type ResultRowProps = {
9
- variant?: ResultRowVariant;
10
- state?: ResultRowState;
11
- title?: string;
12
- subtitle?: string;
13
- className?: string;
14
- };
15
-
16
- const variantIcons: Record<ResultRowVariant, ReactNode> = {
17
- report: <ReportIcon className="size-5" />,
18
- chat: <ChatIcon className="size-5" />,
19
- issue: <IssuesIcon className="size-5" />,
20
- };
21
-
22
- const variantColors: Record<ResultRowVariant, string> = {
23
- report: "text-meta-blue",
24
- chat: "text-meta-purple",
25
- issue: "text-meta-red",
26
- };
27
-
28
- export const ResultRow = ({
29
- variant = "report",
30
- state = "idle",
31
- title = "Search result",
32
- subtitle,
33
- className,
34
- }: ResultRowProps) => (
35
- <button
36
- type="button"
37
- className={cn(
38
- "flex w-full items-center gap-3 rounded-control px-3 py-2 text-left transition-colors hover:bg-background-hover",
39
- className,
40
- )}
41
- data-variant={variant}
42
- data-state={state}
43
- >
44
- <span className={cn("shrink-0", variantColors[variant])}>{variantIcons[variant]}</span>
45
- <div className="min-w-0 flex-1">
46
- <p className="truncate text-caption-1-em text-display-on-light-primary">{title}</p>
47
- {subtitle && (
48
- <p className="truncate text-caption-2 text-display-on-light-tertiary">{subtitle}</p>
49
- )}
50
- </div>
51
- </button>
52
- );
1
+ import { type ReactNode } from "react";
2
+ import {
3
+ Entry,
4
+ type EntryProps,
5
+ type EntryState,
6
+ type EntryVariant,
7
+ } from "../../components/Entry";
8
+
9
+ /** @deprecated Prefer `EntryVariant`. */
10
+ export type ResultRowVariant = EntryVariant;
11
+ /** @deprecated Prefer `EntryState`. */
12
+ export type ResultRowState = EntryState;
13
+
14
+ export type ResultRowProps = {
15
+ variant?: EntryVariant;
16
+ state?: EntryState;
17
+ title?: ReactNode;
18
+ subtitle?: ReactNode;
19
+ onClick?: () => void;
20
+ className?: string;
21
+ };
22
+
23
+ /**
24
+ * @deprecated Prefer `Entry` — ResultRow is a thin alias for search lists.
25
+ */
26
+ export const ResultRow = ({
27
+ variant = "report",
28
+ state = "idle",
29
+ title = "Search result",
30
+ subtitle,
31
+ onClick,
32
+ className,
33
+ }: ResultRowProps) => (
34
+ <Entry
35
+ variant={variant}
36
+ state={state}
37
+ title={title}
38
+ subtitle={subtitle}
39
+ onClick={onClick}
40
+ className={className}
41
+ />
42
+ );
43
+
44
+ export type { EntryProps };
@@ -1,88 +1,310 @@
1
- import { SearchIcon } from "../../icons";
2
- import { cn } from "../../utils/cn";
3
- import { Pill } from "./Pill";
4
- import { ResultRow } from "./ResultRow";
5
- import { SectionHeader } from "./SectionHeader";
6
-
7
- export type SearchModalState = "idle" | "loading" | "results";
8
-
9
- export type SearchModalProps = {
10
- state?: SearchModalState;
11
- className?: string;
12
- };
13
-
14
- const placeholderResults = [
15
- { variant: "report" as const, title: "Hull inspection report Q3", subtitle: "MV Atlantic Star" },
16
- { variant: "chat" as const, title: "Port state control discussion", subtitle: "2 days ago" },
17
- { variant: "issue" as const, title: "Critical valve malfunction", subtitle: "Open · High priority" },
18
- ];
19
-
20
- export const SearchModal = ({ state = "idle", className }: SearchModalProps) => (
21
- <div
22
- className={cn(
23
- "w-full max-w-xl overflow-hidden rounded-lg border border-divider-primary bg-background-primary shadow-raise2",
24
- className,
25
- )}
26
- role="dialog"
27
- aria-label="Search"
28
- data-state={state}
29
- >
30
- <div className="flex items-center gap-2 border-b border-divider-primary px-4 py-3">
31
- <SearchIcon className="size-5 shrink-0 text-display-on-light-quaternary" />
32
- <input
33
- type="search"
34
- placeholder="Search reports, chats, and issues..."
35
- className="flex-1 bg-transparent text-body text-display-on-light-primary placeholder:text-display-on-light-quaternary focus:outline-none"
36
- aria-label="Search query"
37
- readOnly
38
- defaultValue={state === "results" ? "inspection" : ""}
39
- />
40
- {state === "loading" && (
41
- <span className="size-4 animate-spin rounded-full border-2 border-divider-primary border-t-blue-600" />
42
- )}
43
- </div>
44
-
45
- <div className="flex gap-2 px-4 py-2">
46
- <Pill state={state === "results" ? "active" : "idle"} size="small">
47
- All
48
- </Pill>
49
- <Pill state="idle" size="small">
50
- Reports
51
- </Pill>
52
- <Pill state="idle" size="small">
53
- Chats
54
- </Pill>
55
- <Pill state="idle" size="small">
56
- Issues
57
- </Pill>
58
- </div>
59
-
60
- <div className="max-h-80 overflow-y-auto px-2 pb-2">
61
- {state === "idle" && (
62
- <p className="px-2 py-8 text-center text-caption-2 text-display-on-light-tertiary">
63
- Start typing to search across your workspace
64
- </p>
65
- )}
66
-
67
- {state === "loading" && (
68
- <p className="px-2 py-8 text-center text-caption-2 text-display-on-light-tertiary">
69
- Searching...
70
- </p>
71
- )}
72
-
73
- {state === "results" && (
74
- <>
75
- <SectionHeader label="Results" />
76
- {placeholderResults.map((result) => (
77
- <ResultRow
78
- key={result.title}
79
- variant={result.variant}
80
- title={result.title}
81
- subtitle={result.subtitle}
82
- />
83
- ))}
84
- </>
85
- )}
86
- </div>
87
- </div>
88
- );
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 { Badge } from "../../primitives/Badge";
17
+ import { cn } from "../../utils/cn";
18
+ import { ResultRow, type ResultRowProps } from "./ResultRow";
19
+ import { SectionHeader } from "./SectionHeader";
20
+ import { Skeleton } from "../Skeleton";
21
+
22
+ export type SearchModalState = "idle" | "loading" | "results";
23
+
24
+ export type SearchFilterTab = {
25
+ value: string;
26
+ label: string;
27
+ count?: number;
28
+ };
29
+
30
+ export type SearchModalProps = ModalProps & {
31
+ /** Panel state when using the built-in layout helpers. */
32
+ state?: SearchModalState;
33
+ className?: string;
34
+ contentClassName?: string;
35
+ showOverlay?: boolean;
36
+ overlayClassName?: string;
37
+ children?: ReactNode;
38
+ };
39
+
40
+ const DEFAULT_FILTERS: SearchFilterTab[] = [
41
+ { value: "all", label: "All", count: 0 },
42
+ { value: "reports", label: "Reports", count: 0 },
43
+ { value: "chats", label: "Chats", count: 0 },
44
+ { value: "issues", label: "Issues", count: 0 },
45
+ ];
46
+
47
+ /**
48
+ * Search dialog composed on Modal.
49
+ * Use compound parts (Input / Body / Filters / Results) for app wiring,
50
+ * or pass `state` + demo children for Storybook.
51
+ */
52
+ export const SearchModal = ({
53
+ state,
54
+ className,
55
+ contentClassName,
56
+ showOverlay = true,
57
+ overlayClassName,
58
+ children,
59
+ ...modalProps
60
+ }: SearchModalProps) => (
61
+ <Modal {...modalProps}>
62
+ <ModalContent
63
+ showOverlay={showOverlay}
64
+ overlayClassName={overlayClassName}
65
+ className={cn(
66
+ "flex max-h-[min(80vh,640px)] w-[min(100vw-2rem,700px)] max-w-[768px] flex-col p-0",
67
+ contentClassName,
68
+ )}
69
+ aria-label="Search"
70
+ data-state={state}
71
+ >
72
+ <ModalTitle className="sr-only">Search</ModalTitle>
73
+ <ModalDescription className="sr-only">
74
+ Search reports, chats, or issues
75
+ </ModalDescription>
76
+ <div className={cn("flex min-h-0 flex-1 flex-col", className)}>
77
+ {children}
78
+ </div>
79
+ </ModalContent>
80
+ </Modal>
81
+ );
82
+
83
+ export type SearchModalInputProps = Omit<
84
+ InputHTMLAttributes<HTMLInputElement>,
85
+ "type"
86
+ > & {
87
+ className?: string;
88
+ wrapperClassName?: string;
89
+ };
90
+
91
+ export const SearchModalInput = ({
92
+ className,
93
+ wrapperClassName,
94
+ placeholder = "Search reports, chats, or issues…",
95
+ ...props
96
+ }: SearchModalInputProps) => (
97
+ <div
98
+ className={cn(
99
+ "shrink-0 p-3",
100
+ wrapperClassName,
101
+ )}
102
+ >
103
+ <div className="flex min-h-10 items-center px-3">
104
+ <input
105
+ type="search"
106
+ placeholder={placeholder}
107
+ className={cn(
108
+ "w-full bg-transparent text-caption-1 text-display-on-light-primary",
109
+ "placeholder:text-display-on-light-tertiary focus:outline-none",
110
+ className,
111
+ )}
112
+ aria-label="Search query"
113
+ {...props}
114
+ />
115
+ </div>
116
+ </div>
117
+ );
118
+
119
+ export const SearchModalDivider = ({ className }: { className?: string }) => (
120
+ <div
121
+ className={cn("h-px w-full shrink-0 bg-divider-primary", className)}
122
+ aria-hidden
123
+ />
124
+ );
125
+
126
+ export type SearchModalBodyProps = {
127
+ children: ReactNode;
128
+ className?: string;
129
+ };
130
+
131
+ export const SearchModalBody = ({
132
+ children,
133
+ className,
134
+ }: SearchModalBodyProps) => (
135
+ <ModalBody
136
+ className={cn(
137
+ "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden p-2",
138
+ className,
139
+ )}
140
+ >
141
+ {children}
142
+ </ModalBody>
143
+ );
144
+
145
+ export type SearchModalFiltersProps = {
146
+ tabs?: SearchFilterTab[];
147
+ value: string;
148
+ onValueChange: (value: string) => void;
149
+ children?: ReactNode;
150
+ className?: string;
151
+ listClassName?: string;
152
+ };
153
+
154
+ /**
155
+ * Pill-style filter tabs for the results state.
156
+ * Children render below the tab list (typically a single filtered results list).
157
+ * For per-tab panels, nest `SearchModalFilterPanel` (TabsContent) as children.
158
+ */
159
+ export const SearchModalFilters = ({
160
+ tabs = DEFAULT_FILTERS,
161
+ value,
162
+ onValueChange,
163
+ children,
164
+ className,
165
+ listClassName,
166
+ }: SearchModalFiltersProps) => (
167
+ <Tabs
168
+ type="pills"
169
+ value={value}
170
+ onValueChange={onValueChange}
171
+ className={cn("min-h-0 flex-1 gap-0", className)}
172
+ >
173
+ <TabsList
174
+ className={cn(
175
+ "w-full shrink-0 bg-background-primary p-2",
176
+ listClassName,
177
+ )}
178
+ >
179
+ {tabs.map((tab) => (
180
+ <TabsTrigger key={tab.value} value={tab.value}>
181
+ {tab.label}
182
+ {typeof tab.count === "number" && (
183
+ <Badge color="blue">
184
+ {tab.count > 99 ? "99+" : tab.count}
185
+ </Badge>
186
+ )}
187
+ </TabsTrigger>
188
+ ))}
189
+ </TabsList>
190
+ <div className="min-h-0 flex-1 overflow-y-auto">{children}</div>
191
+ </Tabs>
192
+ );
193
+
194
+ export type SearchModalFilterPanelProps = {
195
+ value: string;
196
+ children: ReactNode;
197
+ className?: string;
198
+ };
199
+
200
+ export const SearchModalFilterPanel = ({
201
+ value,
202
+ children,
203
+ className,
204
+ }: SearchModalFilterPanelProps) => (
205
+ <TabsContent value={value} className={className}>
206
+ {children}
207
+ </TabsContent>
208
+ );
209
+
210
+ export type SearchModalResultsProps = {
211
+ items?: ResultRowProps[];
212
+ children?: ReactNode;
213
+ className?: string;
214
+ };
215
+
216
+ export const SearchModalResults = ({
217
+ items,
218
+ children,
219
+ className,
220
+ }: SearchModalResultsProps) => (
221
+ <div className={cn("flex flex-col", className)}>
222
+ {items?.map((item, index) => (
223
+ <ResultRow key={index} {...item} />
224
+ ))}
225
+ {children}
226
+ </div>
227
+ );
228
+
229
+ export type SearchModalIdleProps = {
230
+ label?: string;
231
+ items?: ResultRowProps[];
232
+ children?: ReactNode;
233
+ className?: string;
234
+ };
235
+
236
+ export const SearchModalIdle = ({
237
+ label = "Recently viewed",
238
+ items,
239
+ children,
240
+ className,
241
+ }: SearchModalIdleProps) => (
242
+ <div className={cn("flex min-h-0 flex-1 flex-col p-1", className)}>
243
+ <SectionHeader
244
+ label={label}
245
+ className="shrink-0 px-3 py-1 text-caption-2 font-normal normal-case tracking-[0.01em] text-display-on-light-secondary"
246
+ />
247
+ <div className="min-h-0 flex-1 overflow-y-auto">
248
+ <SearchModalResults items={items}>{children}</SearchModalResults>
249
+ </div>
250
+ </div>
251
+ );
252
+
253
+ export type SearchModalLoadingProps = {
254
+ className?: string;
255
+ };
256
+
257
+ export const SearchModalLoading = ({ className }: SearchModalLoadingProps) => (
258
+ <Skeleton variant="search" className={cn("rounded-none", className)} />
259
+ );
260
+
261
+ /** Convenience controlled panel for Storybook / simple embeds. */
262
+ export type SearchModalPanelProps = {
263
+ state?: SearchModalState;
264
+ query?: string;
265
+ onQueryChange?: (query: string) => void;
266
+ filter?: string;
267
+ onFilterChange?: (filter: string) => void;
268
+ filters?: SearchFilterTab[];
269
+ recentItems?: ResultRowProps[];
270
+ resultItems?: ResultRowProps[];
271
+ className?: string;
272
+ };
273
+
274
+ export const SearchModalPanel = ({
275
+ state = "idle",
276
+ query = "",
277
+ onQueryChange,
278
+ filter = "all",
279
+ onFilterChange,
280
+ filters = DEFAULT_FILTERS,
281
+ recentItems,
282
+ resultItems,
283
+ className,
284
+ }: SearchModalPanelProps) => {
285
+ const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
286
+ onQueryChange?.(event.target.value);
287
+ };
288
+
289
+ return (
290
+ <div className={cn("flex min-h-0 flex-1 flex-col", className)} data-state={state}>
291
+ <SearchModalInput value={query} onChange={handleChange} />
292
+ <SearchModalDivider />
293
+ <SearchModalBody className={state === "loading" ? "p-0" : undefined}>
294
+ {state === "idle" && <SearchModalIdle items={recentItems} />}
295
+ {state === "loading" && <SearchModalLoading />}
296
+ {state === "results" && (
297
+ <SearchModalFilters
298
+ tabs={filters}
299
+ value={filter}
300
+ onValueChange={(next) => onFilterChange?.(next)}
301
+ >
302
+ <SearchModalResults items={resultItems} />
303
+ </SearchModalFilters>
304
+ )}
305
+ </SearchModalBody>
306
+ </div>
307
+ );
308
+ };
309
+
310
+ export type { ModalContentProps };
@@ -1,5 +1,31 @@
1
- export { Pill, type PillProps, type PillSize, type PillState } from "./Pill";
2
- export { PillInfo, type PillInfoProps, type PillInfoType } from "./PillInfo";
3
- export { ResultRow, type ResultRowProps, type ResultRowState, type ResultRowVariant } from "./ResultRow";
4
- export { SearchModal, type SearchModalProps, type SearchModalState } from "./SearchModal";
5
- 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";
@@ -1,5 +1,5 @@
1
- <svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <g id="Logo">
3
- <path id="Glyph" d="M9.89258 5.62793L13.2041 14.625H11.9316L9.20117 11.8926H9.03223L6.29785 14.623C6.29785 14.623 6.29573 14.6211 6.29395 14.6211V14.625H5.0625L8.38867 5.62793H9.89258ZM9.01172 7.12305L7.16016 12.2334L8.87109 10.5234H9.36133L11.0762 12.2402L9.23828 7.12305H9.01172ZM12.6904 3.375V4.64355H5.61328V3.375H12.6904Z" fill="var(--fill-0, #262420)"/>
4
- </g>
5
- </svg>
1
+ <svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g id="Logo">
3
+ <path id="Glyph" d="M9.89258 5.62793L13.2041 14.625H11.9316L9.20117 11.8926H9.03223L6.29785 14.623C6.29785 14.623 6.29573 14.6211 6.29395 14.6211V14.625H5.0625L8.38867 5.62793H9.89258ZM9.01172 7.12305L7.16016 12.2334L8.87109 10.5234H9.36133L11.0762 12.2402L9.23828 7.12305H9.01172ZM12.6904 3.375V4.64355H5.61328V3.375H12.6904Z" fill="var(--fill-0, #262420)"/>
4
+ </g>
5
+ </svg>