@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.
- package/dist/components/EmptyState.d.ts +1 -1
- package/dist/components/Entry.d.ts +27 -7
- package/dist/components/Modal.d.ts +36 -0
- package/dist/components/Tabs.d.ts +23 -8
- package/dist/components/index.d.ts +3 -2
- package/dist/index.cjs +32 -32
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +4209 -3711
- package/dist/patterns/Search/ResultRow.d.ts +16 -7
- package/dist/patterns/Search/SearchModal.d.ts +84 -2
- package/dist/patterns/Search/index.d.ts +2 -2
- package/dist/primitives/Badge.d.ts +7 -4
- package/dist/primitives/Button.d.ts +17 -8
- package/dist/primitives/button-styles.d.ts +4 -0
- package/dist/primitives/index.d.ts +4 -2
- package/dist/style.css +1 -1
- package/dist/tailwind-theme.d.ts +4 -4
- package/dist/theme-entry-BUK3MJUJ.mjs +261 -0
- package/dist/theme-entry-ygTpGaNC.js +1 -0
- package/dist/theme-entry.d.ts +2 -0
- package/dist/theme.cjs +1 -0
- package/dist/theme.d.ts +2 -0
- package/dist/theme.esm.js +5 -0
- package/package.json +10 -3
- package/src/components/EmptyState.tsx +2 -2
- package/src/components/Entry.tsx +119 -45
- package/src/components/Modal.tsx +141 -0
- package/src/components/Tabs.tsx +146 -48
- package/src/components/index.ts +43 -13
- package/src/icons/arrow-paths.ts +8 -8
- package/src/icons/chevron-paths.ts +17 -17
- package/src/icons/icons-data.ts +656 -656
- package/src/index.ts +76 -50
- package/src/patterns/Search/ResultRow.tsx +44 -52
- package/src/patterns/Search/SearchModal.tsx +310 -88
- package/src/patterns/Search/index.ts +31 -5
- package/src/patterns/Sidebar/assets/logo-compliance-mark.png +5 -5
- package/src/patterns/Sidebar/assets/logo-compliance-mask.png +13 -13
- package/src/patterns/Sidebar/assets/logo-compliance.svg +17 -17
- package/src/patterns/Sidebar/assets/logo-technical-avatar.svg +17 -17
- package/src/patterns/Sidebar/assets/logo-technical-mark.png +5 -5
- package/src/patterns/Sidebar/assets/logo-technical.svg +16 -16
- package/src/patterns/Skeleton/Skeleton.tsx +56 -57
- package/src/primitives/Badge.tsx +20 -10
- package/src/primitives/Button.tsx +206 -37
- package/src/primitives/button-styles.ts +92 -0
- package/src/primitives/index.ts +7 -2
- package/src/stories/canvases/ButtonsCanvas.tsx +94 -44
- package/src/stories/canvases/ButtonsMatrixCanvas.tsx +8 -7
- package/src/stories/canvases/ContentCanvas.tsx +157 -88
- package/src/stories/canvases/SearchCanvas.tsx +150 -65
- package/src/stories/canvases/figma-buttons-layout.ts +83 -0
- package/src/stories/canvases/helpers.tsx +26 -43
- package/src/stories/components/Buttons.stories.tsx +11 -11
- package/src/stories/components/Chat.stories.tsx +11 -11
- package/src/stories/components/Content.stories.tsx +11 -11
- package/src/stories/components/Core.stories.tsx +11 -11
- package/src/stories/components/DomainForms.stories.tsx +11 -11
- package/src/stories/components/Filters.stories.tsx +11 -11
- package/src/stories/components/Forms.stories.tsx +11 -11
- package/src/stories/components/Icons.stories.tsx +11 -11
- package/src/stories/components/Illustrations.stories.tsx +11 -11
- package/src/stories/components/Library.stories.tsx +11 -11
- package/src/stories/components/Modals.stories.tsx +11 -11
- package/src/stories/components/Report.stories.tsx +11 -11
- package/src/stories/components/ReportLayout.stories.tsx +11 -11
- package/src/stories/components/Search.stories.tsx +11 -11
- package/src/stories/components/Settings.stories.tsx +11 -11
- package/src/stories/components/Ships.stories.tsx +11 -11
- package/src/stories/components/SidebarLayouts.stories.tsx +11 -11
- package/src/stories/components/Skeletons.stories.tsx +11 -11
- package/src/stories/components/Workflows.stories.tsx +11 -11
- package/src/stories/style-guide/Buttons.stories.tsx +11 -11
- package/src/stories/style-guide/ColorTokens.stories.tsx +11 -11
- package/src/stories/style-guide/Colors.stories.tsx +11 -11
- package/src/stories/style-guide/RaiseLevels.stories.tsx +11 -11
- package/src/stories/style-guide/Typography.stories.tsx +11 -11
- package/src/tailwind-theme.ts +4 -4
- package/src/theme-entry.ts +2 -0
- package/tailwind.config.ts +12 -0
package/src/index.ts
CHANGED
|
@@ -1,50 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
export * from "./
|
|
6
|
-
export * from "./
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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 {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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 {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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 {
|
|
4
|
-
|
|
5
|
-
|
|
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>
|