@superxd-studio/adptr 0.5.0
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/GENERATIVE.md +101 -0
- package/INTERACTIONS.md +51 -0
- package/LICENSE +21 -0
- package/README.md +57 -0
- package/REUSE.md +170 -0
- package/REVIEW.md +68 -0
- package/THIRD-PARTY-NOTICES.md +28 -0
- package/ai-sdk/index.js +96 -0
- package/assets/ibm-plex-mono-cyrillic-400-normal.woff2 +0 -0
- package/assets/ibm-plex-mono-cyrillic-500-normal.woff2 +0 -0
- package/assets/ibm-plex-mono-cyrillic-ext-400-normal.woff2 +0 -0
- package/assets/ibm-plex-mono-cyrillic-ext-500-normal.woff2 +0 -0
- package/assets/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/assets/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/assets/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
- package/assets/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
- package/assets/ibm-plex-mono-vietnamese-400-normal.woff2 +0 -0
- package/assets/ibm-plex-mono-vietnamese-500-normal.woff2 +0 -0
- package/assets/instrument-sans-latin-ext-wght-normal.woff2 +0 -0
- package/assets/instrument-sans-latin-wght-normal.woff2 +0 -0
- package/assistant-ui/index.js +139 -0
- package/chunks/callout-DKMHSnjc.js +342 -0
- package/chunks/canvas-BJ15-XxE.js +598 -0
- package/chunks/controller-Cfpg0C7v.js +180 -0
- package/chunks/core-BCqVRLUy.js +312 -0
- package/chunks/text-field-BLtoaZFn.js +41 -0
- package/chunks/types-BGF7r1my.js +115 -0
- package/chunks/ui-9DyNsYXY.js +967 -0
- package/core/index.js +4 -0
- package/custom/index.js +64 -0
- package/examples/ai-sdk-backend/package.json +11 -0
- package/examples/ai-sdk-backend/server.mjs +316 -0
- package/examples/custom-backend/copy.mjs +7 -0
- package/examples/custom-backend/server.mjs +118 -0
- package/examples/generative/specs.json +2094 -0
- package/examples/review-backend/copy.mjs +27 -0
- package/examples/review-backend/package.json +11 -0
- package/examples/review-backend/server.mjs +276 -0
- package/examples/web-ai-sdk/index.html +12 -0
- package/examples/web-ai-sdk/package.json +21 -0
- package/examples/web-ai-sdk/src/copy.ts +1 -0
- package/examples/web-ai-sdk/src/main.tsx +64 -0
- package/examples/web-ai-sdk/tsconfig.json +13 -0
- package/examples/web-generative/index.html +12 -0
- package/examples/web-generative/package.json +23 -0
- package/examples/web-generative/src/copy.ts +42 -0
- package/examples/web-generative/src/main.tsx +74 -0
- package/examples/web-generative/tsconfig.json +14 -0
- package/examples/web-independent/index.html +12 -0
- package/examples/web-independent/package.json +20 -0
- package/examples/web-independent/src/main.tsx +32 -0
- package/examples/web-independent/tsconfig.json +14 -0
- package/examples/web-interactions/index.html +12 -0
- package/examples/web-interactions/package.json +21 -0
- package/examples/web-interactions/src/copy.ts +215 -0
- package/examples/web-interactions/src/examples.tsx +628 -0
- package/examples/web-interactions/src/main.tsx +116 -0
- package/examples/web-interactions/tsconfig.json +14 -0
- package/examples/web-review/index.html +12 -0
- package/examples/web-review/package.json +20 -0
- package/examples/web-review/src/main.tsx +59 -0
- package/examples/web-review/tsconfig.json +14 -0
- package/fonts.css +117 -0
- package/generative/index.js +1560 -0
- package/interactions/index.js +1591 -0
- package/langgraph-review/index.js +36 -0
- package/licenses/ai-sdk.txt +13 -0
- package/licenses/assistant-ui-generative.txt +21 -0
- package/licenses/assistant-ui.txt +23 -0
- package/licenses/ibm-plex-mono.txt +93 -0
- package/licenses/instrument-sans.txt +93 -0
- package/licenses/internationalized-date.txt +201 -0
- package/licenses/langgraph.txt +21 -0
- package/licenses/lucide.txt +43 -0
- package/licenses/react-markdown.txt +21 -0
- package/licenses/remark-gfm.txt +22 -0
- package/licenses/zod.txt +21 -0
- package/package.json +138 -0
- package/review/index.js +31 -0
- package/source/components/avatar.tsx +50 -0
- package/source/components/button.tsx +155 -0
- package/source/components/callout.tsx +65 -0
- package/source/components/canvas/connector.tsx +14 -0
- package/source/components/canvas/copy.ts +34 -0
- package/source/components/canvas/index.tsx +257 -0
- package/source/components/canvas/recorder.ts +36 -0
- package/source/components/date-time-field.tsx +77 -0
- package/source/components/flow-motion.tsx +109 -0
- package/source/components/icons.tsx +275 -0
- package/source/components/responsive-overlay.tsx +91 -0
- package/source/components/scenario-picker/copy.ts +5 -0
- package/source/components/scenario-picker/index.tsx +142 -0
- package/source/components/scroll-area.tsx +59 -0
- package/source/components/search-picker.tsx +127 -0
- package/source/components/segmented-control.tsx +123 -0
- package/source/components/skeleton.tsx +11 -0
- package/source/components/spinner.tsx +19 -0
- package/source/components/superxd-arrow.tsx +22 -0
- package/source/components/switch.tsx +45 -0
- package/source/components/text-field.tsx +81 -0
- package/source/components/thinking.tsx +16 -0
- package/source/components/ui/copy.ts +12 -0
- package/source/components/ui/display.tsx +276 -0
- package/source/components/ui/navigation.tsx +346 -0
- package/source/components/ui/portal-theme.tsx +28 -0
- package/source/components/ui/selection.tsx +336 -0
- package/source/lib/cn.ts +23 -0
- package/source/reusable/ai-sdk/index.ts +114 -0
- package/source/reusable/assistant-ui/index.tsx +266 -0
- package/source/reusable/core/attachments.ts +163 -0
- package/source/reusable/core/index.ts +417 -0
- package/source/reusable/custom/index.ts +90 -0
- package/source/reusable/generative/actions.ts +188 -0
- package/source/reusable/generative/copy.ts +47 -0
- package/source/reusable/generative/data.tsx +126 -0
- package/source/reusable/generative/index.tsx +517 -0
- package/source/reusable/generative/schema.ts +327 -0
- package/source/reusable/generative/timeline.tsx +214 -0
- package/source/reusable/generative/vocabulary.tsx +847 -0
- package/source/reusable/interactions/agent.ts +259 -0
- package/source/reusable/interactions/artifact.ts +236 -0
- package/source/reusable/interactions/context.tsx +38 -0
- package/source/reusable/interactions/copy.ts +117 -0
- package/source/reusable/interactions/feedback.ts +73 -0
- package/source/reusable/interactions/index.ts +11 -0
- package/source/reusable/interactions/presentation.tsx +483 -0
- package/source/reusable/interactions/store.ts +74 -0
- package/source/reusable/interactions/threads.ts +126 -0
- package/source/reusable/interactions/web.tsx +574 -0
- package/source/reusable/langgraph-review/index.ts +73 -0
- package/source/reusable/review/controller.ts +263 -0
- package/source/reusable/review/index.ts +47 -0
- package/source/reusable/review/types.ts +189 -0
- package/source/reusable/ui/index.ts +25 -0
- package/source/reusable/uploads/index.ts +48 -0
- package/source/reusable/web/attachments/copy.ts +23 -0
- package/source/reusable/web/attachments/index.tsx +233 -0
- package/source/reusable/web/copy.ts +22 -0
- package/source/reusable/web/index.tsx +470 -0
- package/source/reusable/web/message/copy.ts +26 -0
- package/source/reusable/web/message/index.tsx +388 -0
- package/source/reusable/web/message/streaming.ts +64 -0
- package/source/reusable/web/message/styles.css +21 -0
- package/source/reusable/web/review/copy.ts +78 -0
- package/source/reusable/web/review/flow.ts +24 -0
- package/source/reusable/web/review/index.tsx +506 -0
- package/source/reusable/web/styles.ts +2 -0
- package/source/styles/library.css +612 -0
- package/source/styles/theme.css +228 -0
- package/styles.css +3 -0
- package/styles.d.ts +1 -0
- package/types/components/avatar.d.ts +14 -0
- package/types/components/button.d.ts +36 -0
- package/types/components/callout.d.ts +19 -0
- package/types/components/canvas/connector.d.ts +2 -0
- package/types/components/canvas/copy.d.ts +34 -0
- package/types/components/canvas/index.d.ts +33 -0
- package/types/components/canvas/recorder.d.ts +10 -0
- package/types/components/date-time-field.d.ts +11 -0
- package/types/components/flow-motion.d.ts +38 -0
- package/types/components/icons.d.ts +138 -0
- package/types/components/responsive-overlay.d.ts +15 -0
- package/types/components/scenario-picker/copy.d.ts +5 -0
- package/types/components/scenario-picker/index.d.ts +14 -0
- package/types/components/scroll-area.d.ts +14 -0
- package/types/components/search-picker.d.ts +27 -0
- package/types/components/segmented-control.d.ts +23 -0
- package/types/components/skeleton.d.ts +4 -0
- package/types/components/spinner.d.ts +4 -0
- package/types/components/superxd-arrow.d.ts +5 -0
- package/types/components/switch.d.ts +8 -0
- package/types/components/text-field.d.ts +19 -0
- package/types/components/thinking.d.ts +8 -0
- package/types/components/ui/copy.d.ts +12 -0
- package/types/components/ui/display.d.ts +50 -0
- package/types/components/ui/navigation.d.ts +63 -0
- package/types/components/ui/portal-theme.d.ts +8 -0
- package/types/components/ui/selection.d.ts +37 -0
- package/types/lib/cn.d.ts +3 -0
- package/types/reusable/ai-sdk/index.d.ts +15 -0
- package/types/reusable/assistant-ui/index.d.ts +12 -0
- package/types/reusable/core/attachments.d.ts +54 -0
- package/types/reusable/core/index.d.ts +107 -0
- package/types/reusable/custom/index.d.ts +14 -0
- package/types/reusable/generative/actions.d.ts +45 -0
- package/types/reusable/generative/copy.d.ts +48 -0
- package/types/reusable/generative/data.d.ts +4 -0
- package/types/reusable/generative/index.d.ts +30 -0
- package/types/reusable/generative/schema.d.ts +303 -0
- package/types/reusable/generative/timeline.d.ts +21 -0
- package/types/reusable/generative/vocabulary.d.ts +34 -0
- package/types/reusable/interactions/agent.d.ts +98 -0
- package/types/reusable/interactions/artifact.d.ts +118 -0
- package/types/reusable/interactions/context.d.ts +130 -0
- package/types/reusable/interactions/copy.d.ts +115 -0
- package/types/reusable/interactions/feedback.d.ts +34 -0
- package/types/reusable/interactions/index.d.ts +10 -0
- package/types/reusable/interactions/presentation.d.ts +97 -0
- package/types/reusable/interactions/store.d.ts +29 -0
- package/types/reusable/interactions/threads.d.ts +38 -0
- package/types/reusable/interactions/web.d.ts +22 -0
- package/types/reusable/langgraph-review/index.d.ts +5 -0
- package/types/reusable/review/controller.d.ts +52 -0
- package/types/reusable/review/index.d.ts +12 -0
- package/types/reusable/review/types.d.ts +61 -0
- package/types/reusable/ui/index.d.ts +19 -0
- package/types/reusable/uploads/index.d.ts +11 -0
- package/types/reusable/web/attachments/copy.d.ts +25 -0
- package/types/reusable/web/attachments/index.d.ts +24 -0
- package/types/reusable/web/copy.d.ts +24 -0
- package/types/reusable/web/index.d.ts +41 -0
- package/types/reusable/web/message/copy.d.ts +27 -0
- package/types/reusable/web/message/index.d.ts +56 -0
- package/types/reusable/web/message/streaming.d.ts +27 -0
- package/types/reusable/web/review/copy.d.ts +72 -0
- package/types/reusable/web/review/flow.d.ts +3 -0
- package/types/reusable/web/review/index.d.ts +38 -0
- package/types/reusable/web/styles.d.ts +2 -0
- package/ui/index.js +4 -0
- package/uploads/index.js +34 -0
- package/web/index.js +931 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import type { SVGProps } from "react";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Icons drawn from Lucide (https://lucide.dev), ISC licence:
|
|
6
|
+
* Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part
|
|
7
|
+
* of Feather (MIT). All other copyright (c) for Lucide are held by Lucide
|
|
8
|
+
* Contributors 2022. Permission to use, copy, modify, and/or distribute this
|
|
9
|
+
* software for any purpose with or without fee is hereby granted.
|
|
10
|
+
*
|
|
11
|
+
* Complete Lucide ISC and Feather MIT notices are in licenses/lucide.txt;
|
|
12
|
+
* retain those notices when copying or distributing these paths.
|
|
13
|
+
*
|
|
14
|
+
* Icons are decorative by default (hidden from screen readers). Give the
|
|
15
|
+
* control around an icon its own label. Stroke width comes from the
|
|
16
|
+
* --icon-stroke token.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export type IconProps = Omit<SVGProps<SVGSVGElement>, "children">;
|
|
20
|
+
|
|
21
|
+
function createIcon(name: string, paths: React.ReactNode) {
|
|
22
|
+
function Icon({ className, ...props }: IconProps) {
|
|
23
|
+
return (
|
|
24
|
+
<svg
|
|
25
|
+
viewBox="0 0 24 24"
|
|
26
|
+
fill="none"
|
|
27
|
+
stroke="currentColor"
|
|
28
|
+
strokeLinecap="round"
|
|
29
|
+
strokeLinejoin="round"
|
|
30
|
+
aria-hidden="true"
|
|
31
|
+
focusable="false"
|
|
32
|
+
className={cn("size-4 shrink-0 [stroke-width:var(--icon-stroke)]", className)}
|
|
33
|
+
{...props}
|
|
34
|
+
>
|
|
35
|
+
{paths}
|
|
36
|
+
</svg>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
Icon.displayName = `Icon${name}`;
|
|
40
|
+
return Icon;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const IconClock = createIcon(
|
|
44
|
+
"Clock",
|
|
45
|
+
<>
|
|
46
|
+
<circle cx="12" cy="12" r="10" />
|
|
47
|
+
<path d="M12 6v6l4 2" />
|
|
48
|
+
</>,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export const IconVideo = createIcon(
|
|
52
|
+
"Video",
|
|
53
|
+
<>
|
|
54
|
+
<path d="m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5" />
|
|
55
|
+
<rect x="2" y="6" width="14" height="12" rx="2" />
|
|
56
|
+
</>,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
export const IconGlobe = createIcon(
|
|
60
|
+
"Globe",
|
|
61
|
+
<>
|
|
62
|
+
<circle cx="12" cy="12" r="10" />
|
|
63
|
+
<path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" />
|
|
64
|
+
<path d="M2 12h20" />
|
|
65
|
+
</>,
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
export const IconCalendar = createIcon(
|
|
69
|
+
"Calendar",
|
|
70
|
+
<>
|
|
71
|
+
<path d="M8 2v4" />
|
|
72
|
+
<path d="M16 2v4" />
|
|
73
|
+
<rect width="18" height="18" x="3" y="4" rx="2" />
|
|
74
|
+
<path d="M3 10h18" />
|
|
75
|
+
</>,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
export const IconCalendarPlus = createIcon(
|
|
79
|
+
"CalendarPlus",
|
|
80
|
+
<>
|
|
81
|
+
<path d="M8 2v4" />
|
|
82
|
+
<path d="M16 2v4" />
|
|
83
|
+
<path d="M21 13V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8" />
|
|
84
|
+
<path d="M3 10h18" />
|
|
85
|
+
<path d="M16 19h6" />
|
|
86
|
+
<path d="M19 16v6" />
|
|
87
|
+
</>,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
export const IconGrid = createIcon(
|
|
91
|
+
"Grid",
|
|
92
|
+
<>
|
|
93
|
+
<rect width="18" height="18" x="3" y="3" rx="2" />
|
|
94
|
+
<path d="M3 9h18" />
|
|
95
|
+
<path d="M3 15h18" />
|
|
96
|
+
<path d="M9 3v18" />
|
|
97
|
+
<path d="M15 3v18" />
|
|
98
|
+
</>,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
export const IconColumns = createIcon(
|
|
102
|
+
"Columns",
|
|
103
|
+
<>
|
|
104
|
+
<rect width="18" height="18" x="3" y="3" rx="2" />
|
|
105
|
+
<path d="M9 3v18" />
|
|
106
|
+
<path d="M15 3v18" />
|
|
107
|
+
</>,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
export const IconChevronLeft = createIcon("ChevronLeft", <path d="m15 18-6-6 6-6" />);
|
|
111
|
+
export const IconChevronRight = createIcon("ChevronRight", <path d="m9 18 6-6-6-6" />);
|
|
112
|
+
export const IconChevronDown = createIcon("ChevronDown", <path d="m6 9 6 6 6-6" />);
|
|
113
|
+
export const IconArrowUp = createIcon("ArrowUp", <path d="m5 12 7-7 7 7M12 5v14" />);
|
|
114
|
+
export const IconDownload = createIcon(
|
|
115
|
+
"Download",
|
|
116
|
+
<>
|
|
117
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
|
|
118
|
+
<path d="m7 10 5 5 5-5M12 15V3" />
|
|
119
|
+
</>,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
export const IconArrowDown = createIcon("ArrowDown", <path d="m5 12 7 7 7-7M12 5v14" />);
|
|
123
|
+
export const IconSquare = createIcon("Square", <rect x="6" y="6" width="12" height="12" rx="2" />);
|
|
124
|
+
export const IconCopy = createIcon(
|
|
125
|
+
"Copy",
|
|
126
|
+
<>
|
|
127
|
+
<rect x="9" y="9" width="13" height="13" rx="2" />
|
|
128
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
|
129
|
+
</>,
|
|
130
|
+
);
|
|
131
|
+
export const IconEdit = createIcon(
|
|
132
|
+
"Edit",
|
|
133
|
+
<>
|
|
134
|
+
<path d="M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L9 17l-4 1 1-4Z" />
|
|
135
|
+
<path d="m15 5 3 3" />
|
|
136
|
+
</>,
|
|
137
|
+
);
|
|
138
|
+
export const IconCheck = createIcon("Check", <path d="M20 6 9 17l-5-5" />);
|
|
139
|
+
|
|
140
|
+
export const IconX = createIcon(
|
|
141
|
+
"X",
|
|
142
|
+
<>
|
|
143
|
+
<path d="M18 6 6 18" />
|
|
144
|
+
<path d="m6 6 12 12" />
|
|
145
|
+
</>,
|
|
146
|
+
);
|
|
147
|
+
export const IconPaperclip = createIcon(
|
|
148
|
+
"Paperclip",
|
|
149
|
+
<path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l9.9-9.9a4 4 0 0 1 5.66 5.66l-9.9 9.9a2 2 0 0 1-2.83-2.83l9.2-9.19" />,
|
|
150
|
+
);
|
|
151
|
+
export const IconFile = createIcon(
|
|
152
|
+
"File",
|
|
153
|
+
<>
|
|
154
|
+
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" />
|
|
155
|
+
<path d="M14 2v6h6M8 13h8M8 17h5" />
|
|
156
|
+
</>,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
export const IconArrowLeft = createIcon(
|
|
160
|
+
"ArrowLeft",
|
|
161
|
+
<>
|
|
162
|
+
<path d="m12 19-7-7 7-7" />
|
|
163
|
+
<path d="M19 12H5" />
|
|
164
|
+
</>,
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
export const IconInfo = createIcon(
|
|
168
|
+
"Info",
|
|
169
|
+
<>
|
|
170
|
+
<circle cx="12" cy="12" r="10" />
|
|
171
|
+
<path d="M12 16v-4" />
|
|
172
|
+
<path d="M12 8h.01" />
|
|
173
|
+
</>,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
export const IconAlert = createIcon(
|
|
177
|
+
"Alert",
|
|
178
|
+
<>
|
|
179
|
+
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" />
|
|
180
|
+
<path d="M12 9v4" />
|
|
181
|
+
<path d="M12 17h.01" />
|
|
182
|
+
</>,
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
export const IconCircleCheck = createIcon(
|
|
186
|
+
"CircleCheck",
|
|
187
|
+
<>
|
|
188
|
+
<circle cx="12" cy="12" r="10" />
|
|
189
|
+
<path d="m9 12 2 2 4-4" />
|
|
190
|
+
</>,
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
export const IconCircleAlert = createIcon(
|
|
194
|
+
"CircleAlert",
|
|
195
|
+
<>
|
|
196
|
+
<circle cx="12" cy="12" r="10" />
|
|
197
|
+
<path d="M12 8v4" />
|
|
198
|
+
<path d="M12 16h.01" />
|
|
199
|
+
</>,
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
export const IconHourglass = createIcon(
|
|
203
|
+
"Hourglass",
|
|
204
|
+
<>
|
|
205
|
+
<path d="M5 22h14" />
|
|
206
|
+
<path d="M5 2h14" />
|
|
207
|
+
<path d="M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22" />
|
|
208
|
+
<path d="M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2" />
|
|
209
|
+
</>,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
export const IconMapPin = createIcon(
|
|
213
|
+
"MapPin",
|
|
214
|
+
<>
|
|
215
|
+
<path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0" />
|
|
216
|
+
<circle cx="12" cy="10" r="3" />
|
|
217
|
+
</>,
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
export const IconSearch = createIcon(
|
|
221
|
+
"Search",
|
|
222
|
+
<>
|
|
223
|
+
<circle cx="11" cy="11" r="8" />
|
|
224
|
+
<path d="m21 21-4.3-4.3" />
|
|
225
|
+
</>,
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
export const IconRotate = createIcon(
|
|
229
|
+
"Rotate",
|
|
230
|
+
<>
|
|
231
|
+
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
|
|
232
|
+
<path d="M3 3v5h5" />
|
|
233
|
+
</>,
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
export const IconUser = createIcon(
|
|
237
|
+
"User",
|
|
238
|
+
<>
|
|
239
|
+
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
|
|
240
|
+
<circle cx="12" cy="7" r="4" />
|
|
241
|
+
</>,
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
export const IconMail = createIcon(
|
|
245
|
+
"Mail",
|
|
246
|
+
<>
|
|
247
|
+
<rect width="20" height="16" x="2" y="4" rx="2" />
|
|
248
|
+
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" />
|
|
249
|
+
</>,
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
export const IconPlus = createIcon(
|
|
253
|
+
"Plus",
|
|
254
|
+
<>
|
|
255
|
+
<path d="M5 12h14" />
|
|
256
|
+
<path d="M12 5v14" />
|
|
257
|
+
</>,
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
export const IconSun = createIcon(
|
|
261
|
+
"Sun",
|
|
262
|
+
<>
|
|
263
|
+
<circle cx="12" cy="12" r="4" />
|
|
264
|
+
<path d="M12 2v2" />
|
|
265
|
+
<path d="M12 20v2" />
|
|
266
|
+
<path d="m4.93 4.93 1.41 1.41" />
|
|
267
|
+
<path d="m17.66 17.66 1.41 1.41" />
|
|
268
|
+
<path d="M2 12h2" />
|
|
269
|
+
<path d="M20 12h2" />
|
|
270
|
+
<path d="m6.34 17.66-1.41 1.41" />
|
|
271
|
+
<path d="m19.07 4.93-1.41 1.41" />
|
|
272
|
+
</>,
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
export const IconMoon = createIcon("Moon", <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useSyncExternalStore, type ReactNode, type RefObject } from "react";
|
|
2
|
+
import { Dialog, Modal, ModalOverlay, Popover } from "react-aria-components";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
|
|
5
|
+
const mobileQuery = "(max-width: 639px)";
|
|
6
|
+
const sideQuery = "(min-width: 960px)";
|
|
7
|
+
/** Shared by anchored content and its read-only canvas presentation. */
|
|
8
|
+
export const overlaySurfaceClassName =
|
|
9
|
+
"flex min-h-0 flex-col overflow-hidden bg-surface text-fg shadow-dialog";
|
|
10
|
+
function subscribe(callback: () => void) {
|
|
11
|
+
const queries = [window.matchMedia(mobileQuery), window.matchMedia(sideQuery)];
|
|
12
|
+
queries.forEach((query) => query.addEventListener("change", callback));
|
|
13
|
+
return () => queries.forEach((query) => query.removeEventListener("change", callback));
|
|
14
|
+
}
|
|
15
|
+
function presentation() {
|
|
16
|
+
return window.matchMedia(mobileQuery).matches
|
|
17
|
+
? "drawer"
|
|
18
|
+
: window.matchMedia(sideQuery).matches
|
|
19
|
+
? "side"
|
|
20
|
+
: "below";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ResponsiveOverlayProps {
|
|
24
|
+
isOpen: boolean;
|
|
25
|
+
onOpenChange: (open: boolean) => void;
|
|
26
|
+
triggerRef: RefObject<HTMLElement | null>;
|
|
27
|
+
"aria-label": string;
|
|
28
|
+
/** Keep an in-flight mutation visible until the adapter reports its result. */
|
|
29
|
+
isDismissDisabled?: boolean;
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
className?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The same contextual content, anchored on desktop and in a bottom drawer on phones. */
|
|
35
|
+
export function ResponsiveOverlay({
|
|
36
|
+
isOpen,
|
|
37
|
+
onOpenChange,
|
|
38
|
+
triggerRef,
|
|
39
|
+
"aria-label": label,
|
|
40
|
+
isDismissDisabled = false,
|
|
41
|
+
children,
|
|
42
|
+
className,
|
|
43
|
+
}: ResponsiveOverlayProps) {
|
|
44
|
+
const layout = useSyncExternalStore(subscribe, presentation, () => "side");
|
|
45
|
+
const dialog = (
|
|
46
|
+
<Dialog aria-label={label} className="flex min-h-0 flex-1 flex-col outline-none">
|
|
47
|
+
{children}
|
|
48
|
+
</Dialog>
|
|
49
|
+
);
|
|
50
|
+
const surface = overlaySurfaceClassName;
|
|
51
|
+
if (layout === "drawer") {
|
|
52
|
+
return (
|
|
53
|
+
<ModalOverlay
|
|
54
|
+
isOpen={isOpen}
|
|
55
|
+
onOpenChange={onOpenChange}
|
|
56
|
+
isDismissable={!isDismissDisabled}
|
|
57
|
+
isKeyboardDismissDisabled={isDismissDisabled}
|
|
58
|
+
className="fixed inset-0 z-50 flex items-end justify-center bg-overlay data-entering:animate-fade-in data-exiting:animate-fade-out"
|
|
59
|
+
>
|
|
60
|
+
<Modal
|
|
61
|
+
data-presentation="drawer"
|
|
62
|
+
className={cn(
|
|
63
|
+
surface,
|
|
64
|
+
"max-h-[calc(100dvh-1rem)] w-full rounded-t-surface pb-[env(safe-area-inset-bottom)] data-entering:animate-drawer-settle data-exiting:animate-drawer-out",
|
|
65
|
+
className,
|
|
66
|
+
)}
|
|
67
|
+
>
|
|
68
|
+
{dialog}
|
|
69
|
+
</Modal>
|
|
70
|
+
</ModalOverlay>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
return (
|
|
74
|
+
<Popover
|
|
75
|
+
isOpen={isOpen}
|
|
76
|
+
onOpenChange={onOpenChange}
|
|
77
|
+
triggerRef={triggerRef}
|
|
78
|
+
placement={layout === "side" ? "right" : "bottom start"}
|
|
79
|
+
isKeyboardDismissDisabled={isDismissDisabled}
|
|
80
|
+
shouldCloseOnInteractOutside={() => !isDismissDisabled}
|
|
81
|
+
data-presentation="popover"
|
|
82
|
+
className={cn(
|
|
83
|
+
surface,
|
|
84
|
+
"z-50 max-h-[min(48rem,calc(100dvh-2rem))] w-96 max-w-[calc(100vw-2rem)] origin-(--trigger-anchor-point) rounded-surface border border-line shadow-popover data-entering:animate-pop-in data-exiting:animate-pop-out",
|
|
85
|
+
className,
|
|
86
|
+
)}
|
|
87
|
+
>
|
|
88
|
+
{dialog}
|
|
89
|
+
</Popover>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { useRef, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Autocomplete,
|
|
4
|
+
Input,
|
|
5
|
+
ListBox,
|
|
6
|
+
ListBoxItem,
|
|
7
|
+
Popover,
|
|
8
|
+
SearchField,
|
|
9
|
+
Select,
|
|
10
|
+
SelectValue,
|
|
11
|
+
Text,
|
|
12
|
+
useFilter,
|
|
13
|
+
} from "react-aria-components";
|
|
14
|
+
import { Button } from "../button";
|
|
15
|
+
import { IconCheck, IconChevronDown, IconSearch } from "../icons";
|
|
16
|
+
import { cn } from "../../lib/cn.js";
|
|
17
|
+
import { scenarioPickerCopy as copy } from "./copy";
|
|
18
|
+
|
|
19
|
+
export interface ScenarioOption<K extends string> {
|
|
20
|
+
id: K;
|
|
21
|
+
label: string;
|
|
22
|
+
description: string;
|
|
23
|
+
isDisabled?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Chooses demo conditions. The demo owner controls resetting and request cleanup. */
|
|
27
|
+
export function ScenarioPicker<K extends string>({
|
|
28
|
+
label,
|
|
29
|
+
value,
|
|
30
|
+
onChange,
|
|
31
|
+
options,
|
|
32
|
+
isDisabled = false,
|
|
33
|
+
}: {
|
|
34
|
+
label: string;
|
|
35
|
+
value: K;
|
|
36
|
+
onChange: (value: K) => void;
|
|
37
|
+
options: ScenarioOption<K>[];
|
|
38
|
+
isDisabled?: boolean;
|
|
39
|
+
}) {
|
|
40
|
+
const root = useRef<HTMLDivElement>(null);
|
|
41
|
+
const [isOpen, setOpen] = useState(false);
|
|
42
|
+
const [isDark, setDark] = useState(false);
|
|
43
|
+
const { contains } = useFilter({ sensitivity: "base" });
|
|
44
|
+
const selected = options.find((option) => option.id === value);
|
|
45
|
+
const list = (
|
|
46
|
+
<ListBox
|
|
47
|
+
items={options}
|
|
48
|
+
className="p-1 outline-none"
|
|
49
|
+
renderEmptyState={() => <p className="px-3 py-5 type-body text-fg-subtle">{copy.empty}</p>}
|
|
50
|
+
>
|
|
51
|
+
{(option) => (
|
|
52
|
+
<ListBoxItem
|
|
53
|
+
id={option.id}
|
|
54
|
+
textValue={`${option.label} ${option.description}`}
|
|
55
|
+
isDisabled={option.isDisabled}
|
|
56
|
+
className="group flex cursor-pointer items-start gap-3 rounded-cell px-3 py-2.5 text-fg-emphasis outline-none data-disabled:cursor-not-allowed data-disabled:opacity-50 data-focus-visible:focus-ring data-focused:bg-surface-subtle"
|
|
57
|
+
>
|
|
58
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1">
|
|
59
|
+
<Text slot="label" className="type-label">
|
|
60
|
+
{option.label}
|
|
61
|
+
</Text>
|
|
62
|
+
<Text slot="description" className="type-caption font-normal text-fg-subtle">
|
|
63
|
+
{option.description}
|
|
64
|
+
</Text>
|
|
65
|
+
</div>
|
|
66
|
+
<IconCheck className="invisible mt-0.5 size-4 shrink-0 group-data-selected:visible" />
|
|
67
|
+
</ListBoxItem>
|
|
68
|
+
)}
|
|
69
|
+
</ListBox>
|
|
70
|
+
);
|
|
71
|
+
return (
|
|
72
|
+
<Select
|
|
73
|
+
ref={root}
|
|
74
|
+
aria-label={label}
|
|
75
|
+
value={value}
|
|
76
|
+
onChange={(next) => {
|
|
77
|
+
const option = options.find((option) => option.id === next);
|
|
78
|
+
if (option && option.id !== value && !option.isDisabled) onChange(option.id);
|
|
79
|
+
}}
|
|
80
|
+
isOpen={isOpen}
|
|
81
|
+
onOpenChange={(open) => {
|
|
82
|
+
// Portals sit outside scoped preview themes; retain the trigger's theme.
|
|
83
|
+
if (open) setDark(Boolean(root.current?.closest(".dark")));
|
|
84
|
+
setOpen(open);
|
|
85
|
+
}}
|
|
86
|
+
isDisabled={isDisabled}
|
|
87
|
+
className="max-w-full min-w-0 self-start"
|
|
88
|
+
>
|
|
89
|
+
<Button size="sm" aria-label={label} className="max-w-full min-w-0 justify-between">
|
|
90
|
+
<span className="font-normal text-fg-subtle">{copy.label}:</span>
|
|
91
|
+
<SelectValue className="min-w-0 truncate">{selected?.label}</SelectValue>
|
|
92
|
+
<IconChevronDown className="size-3.5 shrink-0 text-fg-subtle" />
|
|
93
|
+
</Button>
|
|
94
|
+
<Popover
|
|
95
|
+
placement="bottom start"
|
|
96
|
+
offset={6}
|
|
97
|
+
className={cn(
|
|
98
|
+
"z-50 w-80 max-w-[calc(100vw-2rem)] origin-(--trigger-anchor-point) overflow-hidden rounded-surface border border-line-subtle bg-surface text-fg shadow-popover outline-none data-entering:animate-pop-in data-exiting:animate-pop-out",
|
|
99
|
+
isDark && "dark",
|
|
100
|
+
)}
|
|
101
|
+
>
|
|
102
|
+
<div
|
|
103
|
+
onKeyDownCapture={(event) => {
|
|
104
|
+
if (event.key === "Escape") {
|
|
105
|
+
event.preventDefault();
|
|
106
|
+
event.stopPropagation();
|
|
107
|
+
setOpen(false);
|
|
108
|
+
}
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
{options.length > 6 ? (
|
|
112
|
+
<Autocomplete filter={contains}>
|
|
113
|
+
<SearchField
|
|
114
|
+
aria-label={copy.search}
|
|
115
|
+
autoFocus
|
|
116
|
+
className="border-b border-line-subtle"
|
|
117
|
+
>
|
|
118
|
+
<div className="flex items-center gap-2 px-3">
|
|
119
|
+
<IconSearch className="size-4 shrink-0 text-fg-subtle" />
|
|
120
|
+
<Input
|
|
121
|
+
placeholder={copy.search}
|
|
122
|
+
className="h-control-md w-full min-w-0 bg-transparent type-body text-fg-emphasis outline-none placeholder:text-fg-subtle [&::-webkit-search-cancel-button]:hidden"
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
</SearchField>
|
|
126
|
+
<div
|
|
127
|
+
role="region"
|
|
128
|
+
aria-label={label}
|
|
129
|
+
tabIndex={0}
|
|
130
|
+
className="max-h-[min(24rem,60dvh)] overflow-y-auto outline-none focus-visible:focus-ring"
|
|
131
|
+
>
|
|
132
|
+
{list}
|
|
133
|
+
</div>
|
|
134
|
+
</Autocomplete>
|
|
135
|
+
) : (
|
|
136
|
+
<div className="max-h-[min(24rem,60dvh)] overflow-y-auto">{list}</div>
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
139
|
+
</Popover>
|
|
140
|
+
</Select>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useEffect, useRef, useState, type ReactNode } from "react";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
|
|
4
|
+
export interface ScrollAreaProps {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
/** Label for keyboard users when the area scrolls (it becomes focusable). */
|
|
8
|
+
label?: string;
|
|
9
|
+
/** Scroll to this position (in pixels) when it first appears or changes. */
|
|
10
|
+
scrollTo?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A scrolling box whose edges fade when there's more to see, so a list cut
|
|
15
|
+
* off by the edge reads as "keep scrolling" rather than "broken".
|
|
16
|
+
*/
|
|
17
|
+
export function ScrollArea({ children, className, label, scrollTo }: ScrollAreaProps) {
|
|
18
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
19
|
+
const [edges, setEdges] = useState({ top: false, bottom: false });
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const el = ref.current;
|
|
23
|
+
if (!el) return;
|
|
24
|
+
const update = () =>
|
|
25
|
+
setEdges({
|
|
26
|
+
top: el.scrollTop > 1,
|
|
27
|
+
bottom: el.scrollTop + el.clientHeight < el.scrollHeight - 1,
|
|
28
|
+
});
|
|
29
|
+
// A ResizeObserver reports once as soon as it starts, which sets the first state.
|
|
30
|
+
const resize = new ResizeObserver(update);
|
|
31
|
+
resize.observe(el);
|
|
32
|
+
for (const child of el.children) resize.observe(child);
|
|
33
|
+
el.addEventListener("scroll", update, { passive: true });
|
|
34
|
+
return () => {
|
|
35
|
+
resize.disconnect();
|
|
36
|
+
el.removeEventListener("scroll", update);
|
|
37
|
+
};
|
|
38
|
+
}, []);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (scrollTo !== undefined && ref.current) ref.current.scrollTop = scrollTo;
|
|
42
|
+
}, [scrollTo]);
|
|
43
|
+
|
|
44
|
+
const fade = "1.5rem";
|
|
45
|
+
const mask = `linear-gradient(to bottom, ${edges.top ? "transparent" : "black"} 0, black ${edges.top ? fade : "0"}, black calc(100% - ${edges.bottom ? fade : "0px"}), ${edges.bottom ? "transparent" : "black"} 100%)`;
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div
|
|
49
|
+
ref={ref}
|
|
50
|
+
tabIndex={edges.top || edges.bottom ? 0 : undefined}
|
|
51
|
+
role={edges.top || edges.bottom ? "region" : undefined}
|
|
52
|
+
aria-label={edges.top || edges.bottom ? label : undefined}
|
|
53
|
+
className={cn("overflow-y-auto overscroll-contain rounded-[2px]", className)}
|
|
54
|
+
style={{ maskImage: mask, WebkitMaskImage: mask }}
|
|
55
|
+
>
|
|
56
|
+
{children}
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|