raft-ui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/dist/cn.d.mts +2 -0
- package/dist/cn.mjs +2 -0
- package/dist/index.d.mts +2710 -0
- package/dist/index.mjs +4821 -0
- package/dist/label-DWq4ia5I.mjs +115 -0
- package/dist/styled-props-B3SNekJg.d.mts +16 -0
- package/dist/wip.d.mts +1238 -0
- package/dist/wip.mjs +1416 -0
- package/package.json +70 -0
- package/src/components/avatar/avatar.tsx +375 -0
- package/src/components/avatar/index.ts +17 -0
- package/src/components/badge/badge.tsx +393 -0
- package/src/components/badge/index.ts +2 -0
- package/src/components/banner/banner.tsx +269 -0
- package/src/components/banner/index.ts +8 -0
- package/src/components/bottom-sheet/bottom-sheet.tsx +152 -0
- package/src/components/bottom-sheet/index.ts +22 -0
- package/src/components/button/button.tsx +497 -0
- package/src/components/button/index.ts +2 -0
- package/src/components/checkbox/checkbox-indicator.tsx +128 -0
- package/src/components/checkbox/checkbox.tsx +350 -0
- package/src/components/checkbox/index.ts +2 -0
- package/src/components/combobox/combobox.tsx +603 -0
- package/src/components/combobox/index.ts +52 -0
- package/src/components/context-menu/context-menu.tsx +380 -0
- package/src/components/context-menu/index.ts +34 -0
- package/src/components/conversation-preview-card/conversation-preview-card.tsx +336 -0
- package/src/components/conversation-preview-card/index.ts +32 -0
- package/src/components/description-list/description-list.tsx +116 -0
- package/src/components/description-list/index.ts +14 -0
- package/src/components/dropdown-menu/dropdown-menu.tsx +405 -0
- package/src/components/dropdown-menu/index.ts +38 -0
- package/src/components/empty-state/empty-state.tsx +177 -0
- package/src/components/empty-state/index.ts +16 -0
- package/src/components/field/field.tsx +125 -0
- package/src/components/field/index.ts +18 -0
- package/src/components/inline-code/index.ts +2 -0
- package/src/components/inline-code/inline-code.tsx +33 -0
- package/src/components/input/index.ts +2 -0
- package/src/components/input/input.tsx +76 -0
- package/src/components/input-group/index.ts +7 -0
- package/src/components/input-group/input-group.tsx +215 -0
- package/src/components/kbd/index.ts +2 -0
- package/src/components/kbd/kbd.tsx +43 -0
- package/src/components/label/index.ts +7 -0
- package/src/components/label/label.tsx +99 -0
- package/src/components/lightbox/index.ts +24 -0
- package/src/components/lightbox/lightbox.tsx +245 -0
- package/src/components/list-item/index.ts +20 -0
- package/src/components/list-item/list-item.tsx +263 -0
- package/src/components/media-list-item/index.ts +20 -0
- package/src/components/media-list-item/media-list-item.tsx +169 -0
- package/src/components/notification-center/index.ts +39 -0
- package/src/components/notification-center/notification-center.tsx +558 -0
- package/src/components/panel-header/index.ts +22 -0
- package/src/components/panel-header/panel-header.tsx +199 -0
- package/src/components/popover/index.ts +30 -0
- package/src/components/popover/popover.tsx +248 -0
- package/src/components/preview-shell/index.ts +2 -0
- package/src/components/preview-shell/preview-shell.tsx +51 -0
- package/src/components/quoted-message-card/index.ts +36 -0
- package/src/components/quoted-message-card/quoted-message-card.tsx +391 -0
- package/src/components/radio-group/index.ts +6 -0
- package/src/components/radio-group/radio-group.tsx +119 -0
- package/src/components/section-header/index.ts +16 -0
- package/src/components/section-header/section-header.tsx +117 -0
- package/src/components/section-label/index.ts +2 -0
- package/src/components/section-label/section-label.tsx +38 -0
- package/src/components/segmented-control/index.ts +12 -0
- package/src/components/segmented-control/segmented-control.tsx +129 -0
- package/src/components/select/index.ts +40 -0
- package/src/components/select/select.tsx +382 -0
- package/src/components/spinner/index.ts +2 -0
- package/src/components/spinner/spinner.tsx +228 -0
- package/src/components/status/index.ts +2 -0
- package/src/components/status/status.tsx +152 -0
- package/src/components/tabs/index.ts +24 -0
- package/src/components/tabs/tabs.tsx +417 -0
- package/src/components/text/index.ts +2 -0
- package/src/components/text/text.tsx +130 -0
- package/src/components/textarea/index.ts +2 -0
- package/src/components/textarea/textarea.tsx +136 -0
- package/src/components/toggle-group/index.ts +12 -0
- package/src/components/toggle-group/toggle-group.tsx +111 -0
- package/src/components/tooltip/index.ts +14 -0
- package/src/components/tooltip/tooltip.tsx +186 -0
- package/src/fonts/brutal.css +2 -0
- package/src/index.ts +404 -0
- package/src/legacy/AttentionDot.tsx +28 -0
- package/src/legacy/AvatarListRow.tsx +87 -0
- package/src/legacy/AvatarSlot.tsx +157 -0
- package/src/legacy/Badge.tsx +95 -0
- package/src/legacy/Banner.tsx +74 -0
- package/src/legacy/BottomSheet.tsx +76 -0
- package/src/legacy/CheckMarker.tsx +72 -0
- package/src/legacy/Checkbox.tsx +81 -0
- package/src/legacy/ConversationPreviewCard.tsx +169 -0
- package/src/legacy/DismissBackdrop.tsx +68 -0
- package/src/legacy/EmptyState.tsx +63 -0
- package/src/legacy/ExperimentalBadge.tsx +19 -0
- package/src/legacy/FormField.tsx +106 -0
- package/src/legacy/KeyValueRow.tsx +67 -0
- package/src/legacy/Lightbox.tsx +119 -0
- package/src/legacy/NotificationCenter.tsx +217 -0
- package/src/legacy/PanelHeader.tsx +94 -0
- package/src/legacy/PreviewShell.tsx +40 -0
- package/src/legacy/QuotedMessageCard.tsx +181 -0
- package/src/legacy/ReorderablePanelTabs.tsx +151 -0
- package/src/legacy/SandboxedPreviewFrame.tsx +59 -0
- package/src/legacy/SearchInput.tsx +23 -0
- package/src/legacy/SectionEyebrow.tsx +60 -0
- package/src/legacy/SectionHeader.tsx +68 -0
- package/src/legacy/SegmentedControl.tsx +74 -0
- package/src/legacy/SlugInput.tsx +29 -0
- package/src/legacy/Spinner.tsx +89 -0
- package/src/legacy/StatusDot.tsx +51 -0
- package/src/legacy/SurfaceListItem.tsx +32 -0
- package/src/legacy/Textarea.tsx +137 -0
- package/src/legacy/button.tsx +100 -0
- package/src/legacy/context-menu-divider.tsx +12 -0
- package/src/legacy/menu-item.tsx +66 -0
- package/src/legacy/selection-popover.tsx +212 -0
- package/src/legacy/server-switcher-menu.tsx +203 -0
- package/src/legacy/source.css +240 -0
- package/src/lib/cn.ts +1 -0
- package/src/lib/styled-props.ts +11 -0
- package/src/lib/theme/theme-context.ts +28 -0
- package/src/lib/theme/theme-provider.tsx +181 -0
- package/src/lib/theme/use-theme.ts +12 -0
- package/src/lib/tv.ts +29 -0
- package/src/lib/without-children.ts +6 -0
- package/src/styles.css +467 -0
- package/src/wip.ts +255 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import { MessageSquare } from "lucide-react";
|
|
2
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
3
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
4
|
+
import { tv } from "../../lib/tv.ts";
|
|
5
|
+
import { PreviewShell, type PreviewShellProps } from "../preview-shell/preview-shell.tsx";
|
|
6
|
+
import { useThemeFamily } from "../../lib/theme/use-theme.ts";
|
|
7
|
+
|
|
8
|
+
// A quoted-message preview routed through PreviewShell. The source's app-domain
|
|
9
|
+
// fields (channel object, author fetching, markdown rendering, attachments
|
|
10
|
+
// derivation) are now composed by the caller; this file owns only the visual
|
|
11
|
+
// slots and their brutal/elegant styling hooks.
|
|
12
|
+
const quotedMessageCard = tv({
|
|
13
|
+
slots: {
|
|
14
|
+
root: ["group block w-full text-left"],
|
|
15
|
+
body: ["px-2.5 py-2 sm:px-3 sm:py-2.5"],
|
|
16
|
+
unavailable: ["text-[13px] leading-snug"],
|
|
17
|
+
header: ["mb-1 flex items-start gap-2 sm:mb-1.5"],
|
|
18
|
+
meta: ["flex min-w-0 flex-1 flex-wrap items-center gap-x-1.5 gap-y-1 text-xs leading-none"],
|
|
19
|
+
channel: ["inline-flex items-center gap-1 font-bold", "[&_svg]:size-[11px] [&_svg]:shrink-0"],
|
|
20
|
+
separator: ["text-foreground/30"],
|
|
21
|
+
author: ["inline-flex min-w-0 items-center gap-1.5"],
|
|
22
|
+
authorName: ["truncate font-bold"],
|
|
23
|
+
authorSubtitle: ["truncate font-mono text-[10px]"],
|
|
24
|
+
thread: ["inline-flex items-center gap-1 font-bold", "[&_svg]:size-2.5 [&_svg]:shrink-0"],
|
|
25
|
+
tag: [
|
|
26
|
+
"inline-flex items-center gap-1 border-[1.5px] border-line-strong px-1.5 py-0.5",
|
|
27
|
+
"text-[11px] font-bold leading-none",
|
|
28
|
+
],
|
|
29
|
+
timestamp: ["shrink-0 font-mono text-[10px]"],
|
|
30
|
+
contentWrap: ["min-w-0"],
|
|
31
|
+
content: ["line-clamp-2 text-xs leading-snug sm:text-[13px]"],
|
|
32
|
+
attachments: ["mt-2 flex flex-wrap gap-1.5"],
|
|
33
|
+
},
|
|
34
|
+
variants: {
|
|
35
|
+
theme: {
|
|
36
|
+
brutal: {
|
|
37
|
+
channel: "text-foreground/70",
|
|
38
|
+
authorName: "text-foreground/70",
|
|
39
|
+
authorSubtitle: "text-foreground/40",
|
|
40
|
+
thread: "text-accent-400",
|
|
41
|
+
timestamp: "text-foreground/40",
|
|
42
|
+
content: "text-foreground-strong",
|
|
43
|
+
},
|
|
44
|
+
// Elegant styling is deferred; see the component TODO.
|
|
45
|
+
elegant: {},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export type QuotedMessageCardProps = PreviewShellProps;
|
|
51
|
+
|
|
52
|
+
export function QuotedMessageCard({
|
|
53
|
+
className,
|
|
54
|
+
"data-testid": testId = "quoted-message-card",
|
|
55
|
+
...props
|
|
56
|
+
}: QuotedMessageCardProps) {
|
|
57
|
+
const { root } = quotedMessageCard();
|
|
58
|
+
return <PreviewShell data-testid={testId} className={root({ className })} {...props} />;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type QuotedMessageCardBodyProps = useRender.ComponentProps<"div">;
|
|
62
|
+
|
|
63
|
+
export function QuotedMessageCardBody({ className, render, ...props }: QuotedMessageCardBodyProps) {
|
|
64
|
+
const { body } = quotedMessageCard();
|
|
65
|
+
const defaultProps: useRender.ElementProps<"div"> = {
|
|
66
|
+
className: body({ className }),
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
return useRender({
|
|
70
|
+
defaultTagName: "div",
|
|
71
|
+
render,
|
|
72
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
73
|
+
state: {
|
|
74
|
+
slot: "quoted-message-card-body",
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type QuotedMessageCardUnavailableProps = useRender.ComponentProps<"div">;
|
|
80
|
+
|
|
81
|
+
export function QuotedMessageCardUnavailable({
|
|
82
|
+
className,
|
|
83
|
+
render,
|
|
84
|
+
...props
|
|
85
|
+
}: QuotedMessageCardUnavailableProps) {
|
|
86
|
+
const { unavailable } = quotedMessageCard();
|
|
87
|
+
const defaultProps: useRender.ElementProps<"div"> = {
|
|
88
|
+
className: unavailable({ className }),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return useRender({
|
|
92
|
+
defaultTagName: "div",
|
|
93
|
+
render,
|
|
94
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
95
|
+
state: {
|
|
96
|
+
slot: "quoted-message-card-unavailable",
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type QuotedMessageCardHeaderProps = useRender.ComponentProps<"div">;
|
|
102
|
+
|
|
103
|
+
export function QuotedMessageCardHeader({
|
|
104
|
+
className,
|
|
105
|
+
render,
|
|
106
|
+
...props
|
|
107
|
+
}: QuotedMessageCardHeaderProps) {
|
|
108
|
+
const { header } = quotedMessageCard();
|
|
109
|
+
const defaultProps: useRender.ElementProps<"div"> = {
|
|
110
|
+
className: header({ className }),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return useRender({
|
|
114
|
+
defaultTagName: "div",
|
|
115
|
+
render,
|
|
116
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
117
|
+
state: {
|
|
118
|
+
slot: "quoted-message-card-header",
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export type QuotedMessageCardMetaProps = useRender.ComponentProps<"div">;
|
|
124
|
+
|
|
125
|
+
export function QuotedMessageCardMeta({ className, render, ...props }: QuotedMessageCardMetaProps) {
|
|
126
|
+
const { meta } = quotedMessageCard();
|
|
127
|
+
const defaultProps: useRender.ElementProps<"div"> = {
|
|
128
|
+
className: meta({ className }),
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return useRender({
|
|
132
|
+
defaultTagName: "div",
|
|
133
|
+
render,
|
|
134
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
135
|
+
state: {
|
|
136
|
+
slot: "quoted-message-card-meta",
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export type QuotedMessageCardChannelProps = useRender.ComponentProps<"span">;
|
|
142
|
+
|
|
143
|
+
export function QuotedMessageCardChannel({
|
|
144
|
+
className,
|
|
145
|
+
render,
|
|
146
|
+
...props
|
|
147
|
+
}: QuotedMessageCardChannelProps) {
|
|
148
|
+
const theme = useThemeFamily();
|
|
149
|
+
const { channel } = quotedMessageCard({ theme });
|
|
150
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
151
|
+
className: channel({ className }),
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
return useRender({
|
|
155
|
+
defaultTagName: "span",
|
|
156
|
+
render,
|
|
157
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
158
|
+
state: {
|
|
159
|
+
slot: "quoted-message-card-channel",
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export type QuotedMessageCardSeparatorProps = useRender.ComponentProps<"span">;
|
|
165
|
+
|
|
166
|
+
export function QuotedMessageCardSeparator({
|
|
167
|
+
className,
|
|
168
|
+
render,
|
|
169
|
+
...props
|
|
170
|
+
}: QuotedMessageCardSeparatorProps) {
|
|
171
|
+
const { separator } = quotedMessageCard();
|
|
172
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
173
|
+
className: separator({ className }),
|
|
174
|
+
children: "·",
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
return useRender({
|
|
178
|
+
defaultTagName: "span",
|
|
179
|
+
render,
|
|
180
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
181
|
+
state: {
|
|
182
|
+
slot: "quoted-message-card-separator",
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export type QuotedMessageCardAuthorProps = useRender.ComponentProps<"span">;
|
|
188
|
+
|
|
189
|
+
export function QuotedMessageCardAuthor({
|
|
190
|
+
className,
|
|
191
|
+
render,
|
|
192
|
+
...props
|
|
193
|
+
}: QuotedMessageCardAuthorProps) {
|
|
194
|
+
const { author } = quotedMessageCard();
|
|
195
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
196
|
+
className: author({ className }),
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
return useRender({
|
|
200
|
+
defaultTagName: "span",
|
|
201
|
+
render,
|
|
202
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
203
|
+
state: {
|
|
204
|
+
slot: "quoted-message-card-author",
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export type QuotedMessageCardAuthorNameProps = useRender.ComponentProps<"span">;
|
|
210
|
+
|
|
211
|
+
export function QuotedMessageCardAuthorName({
|
|
212
|
+
className,
|
|
213
|
+
render,
|
|
214
|
+
...props
|
|
215
|
+
}: QuotedMessageCardAuthorNameProps) {
|
|
216
|
+
const theme = useThemeFamily();
|
|
217
|
+
const { authorName } = quotedMessageCard({ theme });
|
|
218
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
219
|
+
className: authorName({ className }),
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
return useRender({
|
|
223
|
+
defaultTagName: "span",
|
|
224
|
+
render,
|
|
225
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
226
|
+
state: {
|
|
227
|
+
slot: "quoted-message-card-author-name",
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export type QuotedMessageCardAuthorSubtitleProps = useRender.ComponentProps<"span">;
|
|
233
|
+
|
|
234
|
+
export function QuotedMessageCardAuthorSubtitle({
|
|
235
|
+
className,
|
|
236
|
+
render,
|
|
237
|
+
...props
|
|
238
|
+
}: QuotedMessageCardAuthorSubtitleProps) {
|
|
239
|
+
const theme = useThemeFamily();
|
|
240
|
+
const { authorSubtitle } = quotedMessageCard({ theme });
|
|
241
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
242
|
+
className: authorSubtitle({ className }),
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
return useRender({
|
|
246
|
+
defaultTagName: "span",
|
|
247
|
+
render,
|
|
248
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
249
|
+
state: {
|
|
250
|
+
slot: "quoted-message-card-author-subtitle",
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export type QuotedMessageCardThreadProps = useRender.ComponentProps<"span">;
|
|
256
|
+
|
|
257
|
+
export function QuotedMessageCardThread({
|
|
258
|
+
className,
|
|
259
|
+
render,
|
|
260
|
+
children = "Thread",
|
|
261
|
+
...props
|
|
262
|
+
}: QuotedMessageCardThreadProps) {
|
|
263
|
+
const theme = useThemeFamily();
|
|
264
|
+
const { thread } = quotedMessageCard({ theme });
|
|
265
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
266
|
+
className: thread({ className }),
|
|
267
|
+
children: (
|
|
268
|
+
<>
|
|
269
|
+
<MessageSquare />
|
|
270
|
+
{children}
|
|
271
|
+
</>
|
|
272
|
+
),
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
return useRender({
|
|
276
|
+
defaultTagName: "span",
|
|
277
|
+
render,
|
|
278
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
279
|
+
state: {
|
|
280
|
+
slot: "quoted-message-card-thread",
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export type QuotedMessageCardTagProps = useRender.ComponentProps<"span">;
|
|
286
|
+
|
|
287
|
+
export function QuotedMessageCardTag({ className, render, ...props }: QuotedMessageCardTagProps) {
|
|
288
|
+
const { tag } = quotedMessageCard();
|
|
289
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
290
|
+
className: tag({ className }),
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
return useRender({
|
|
294
|
+
defaultTagName: "span",
|
|
295
|
+
render,
|
|
296
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
297
|
+
state: {
|
|
298
|
+
slot: "quoted-message-card-tag",
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export type QuotedMessageCardTimestampProps = useRender.ComponentProps<"span">;
|
|
304
|
+
|
|
305
|
+
export function QuotedMessageCardTimestamp({
|
|
306
|
+
className,
|
|
307
|
+
render,
|
|
308
|
+
...props
|
|
309
|
+
}: QuotedMessageCardTimestampProps) {
|
|
310
|
+
const theme = useThemeFamily();
|
|
311
|
+
const { timestamp } = quotedMessageCard({ theme });
|
|
312
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
313
|
+
className: timestamp({ className }),
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
return useRender({
|
|
317
|
+
defaultTagName: "span",
|
|
318
|
+
render,
|
|
319
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
320
|
+
state: {
|
|
321
|
+
slot: "quoted-message-card-timestamp",
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export type QuotedMessageCardContentWrapProps = useRender.ComponentProps<"div">;
|
|
327
|
+
|
|
328
|
+
export function QuotedMessageCardContentWrap({
|
|
329
|
+
className,
|
|
330
|
+
render,
|
|
331
|
+
...props
|
|
332
|
+
}: QuotedMessageCardContentWrapProps) {
|
|
333
|
+
const { contentWrap } = quotedMessageCard();
|
|
334
|
+
const defaultProps: useRender.ElementProps<"div"> = {
|
|
335
|
+
className: contentWrap({ className }),
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
return useRender({
|
|
339
|
+
defaultTagName: "div",
|
|
340
|
+
render,
|
|
341
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
342
|
+
state: {
|
|
343
|
+
slot: "quoted-message-card-content-wrap",
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export type QuotedMessageCardContentProps = useRender.ComponentProps<"div">;
|
|
349
|
+
|
|
350
|
+
export function QuotedMessageCardContent({
|
|
351
|
+
className,
|
|
352
|
+
render,
|
|
353
|
+
...props
|
|
354
|
+
}: QuotedMessageCardContentProps) {
|
|
355
|
+
const theme = useThemeFamily();
|
|
356
|
+
const { content } = quotedMessageCard({ theme });
|
|
357
|
+
const defaultProps: useRender.ElementProps<"div"> = {
|
|
358
|
+
className: content({ className }),
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
return useRender({
|
|
362
|
+
defaultTagName: "div",
|
|
363
|
+
render,
|
|
364
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
365
|
+
state: {
|
|
366
|
+
slot: "quoted-message-card-content",
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export type QuotedMessageCardAttachmentsProps = useRender.ComponentProps<"div">;
|
|
372
|
+
|
|
373
|
+
export function QuotedMessageCardAttachments({
|
|
374
|
+
className,
|
|
375
|
+
render,
|
|
376
|
+
...props
|
|
377
|
+
}: QuotedMessageCardAttachmentsProps) {
|
|
378
|
+
const { attachments } = quotedMessageCard();
|
|
379
|
+
const defaultProps: useRender.ElementProps<"div"> = {
|
|
380
|
+
className: attachments({ className }),
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
return useRender({
|
|
384
|
+
defaultTagName: "div",
|
|
385
|
+
render,
|
|
386
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
387
|
+
state: {
|
|
388
|
+
slot: "quoted-message-card-attachments",
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Radio as BaseRadio } from "@base-ui/react/radio";
|
|
2
|
+
import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group";
|
|
3
|
+
import { tv } from "../../lib/tv.ts";
|
|
4
|
+
import { cn } from "../../lib/cn.ts";
|
|
5
|
+
import type { StyledProps } from "../../lib/styled-props.ts";
|
|
6
|
+
import { useThemeFamily } from "../../lib/theme/use-theme.ts";
|
|
7
|
+
|
|
8
|
+
const radioGroup = tv({
|
|
9
|
+
slots: {
|
|
10
|
+
root: [
|
|
11
|
+
"grid w-full gap-2",
|
|
12
|
+
"data-[disabled]:[&>label]:cursor-not-allowed data-[disabled]:[&>label]:text-foreground-disabled",
|
|
13
|
+
"data-[disabled]:[&>label_*]:text-foreground-disabled",
|
|
14
|
+
],
|
|
15
|
+
item: [
|
|
16
|
+
"relative inline-flex shrink-0 touch-manipulation items-center justify-center rounded-full outline-none",
|
|
17
|
+
"data-[disabled]:cursor-not-allowed",
|
|
18
|
+
"after:absolute after:-inset-x-3 after:-inset-y-2 after:content-['']",
|
|
19
|
+
],
|
|
20
|
+
indicator: ["pointer-events-none flex size-full items-center justify-center"],
|
|
21
|
+
dot: ["block rounded-full bg-current"],
|
|
22
|
+
},
|
|
23
|
+
variants: {
|
|
24
|
+
theme: {
|
|
25
|
+
brutal: {
|
|
26
|
+
root: ["font-sans [&>label]:font-medium"],
|
|
27
|
+
item: [
|
|
28
|
+
"size-4 border-2 border-line-strong bg-layer-panel text-foreground-strong",
|
|
29
|
+
"hover:bg-primary-400/30 data-[checked]:bg-primary-400",
|
|
30
|
+
"data-[disabled]:border-line-muted data-[disabled]:bg-layer-muted data-[disabled]:text-line data-[disabled]:hover:bg-layer-muted",
|
|
31
|
+
"data-[checked]:data-[disabled]:bg-layer-muted",
|
|
32
|
+
"focus-visible:ring-2 focus-visible:ring-line-focus focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
33
|
+
],
|
|
34
|
+
dot: "size-1.5",
|
|
35
|
+
},
|
|
36
|
+
elegant: {
|
|
37
|
+
root: "gap-2.5",
|
|
38
|
+
item: [
|
|
39
|
+
"size-3.5 bg-layer-panel text-foreground-inverse",
|
|
40
|
+
"shadow-[inset_0_1px_0.5px_oklch(1_0_0_/_0.05),0_1px_1.5px_-1px_oklch(0_0_0_/_0.035),0_0_0_1px_var(--line-subtle)]",
|
|
41
|
+
"hover:bg-foreground/[0.04] data-[checked]:bg-foreground-strong",
|
|
42
|
+
"data-[checked]:shadow-[0_1px_1.5px_-1px_oklch(0_0_0_/_0.08),0_0_0_1px_oklch(0_0_0_/_0.68)]",
|
|
43
|
+
"data-[disabled]:bg-layer-muted data-[disabled]:text-line data-[disabled]:shadow-[0_1px_1px_-1px_oklch(0_0_0_/_0.02),0_0_0_1px_var(--line-subtle)] data-[disabled]:hover:bg-layer-muted",
|
|
44
|
+
"data-[checked]:data-[disabled]:bg-layer-muted data-[checked]:data-[disabled]:shadow-[0_1px_1px_-1px_oklch(0_0_0_/_0.02),0_0_0_1px_var(--line-subtle)]",
|
|
45
|
+
"active:scale-[0.96] data-[disabled]:active:scale-100 motion-reduce:active:scale-100",
|
|
46
|
+
"focus-visible:ring-2 focus-visible:ring-line-focus focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
47
|
+
],
|
|
48
|
+
dot: "size-1.5",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export type RadioGroupProps<T extends string = string> = StyledProps<
|
|
55
|
+
Omit<BaseRadioGroup.Props<T>, "aria-label">
|
|
56
|
+
> & {
|
|
57
|
+
ariaLabel?: string;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export function RadioGroup<T extends string = string>({
|
|
61
|
+
ariaLabel,
|
|
62
|
+
className,
|
|
63
|
+
...props
|
|
64
|
+
}: RadioGroupProps<T>) {
|
|
65
|
+
const theme = useThemeFamily();
|
|
66
|
+
const { root } = radioGroup({ theme });
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<BaseRadioGroup
|
|
70
|
+
aria-label={ariaLabel}
|
|
71
|
+
data-slot="radio-group"
|
|
72
|
+
className={root({ className })}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type RadioGroupIndicatorProps = StyledProps<BaseRadio.Indicator.Props>;
|
|
79
|
+
|
|
80
|
+
export function RadioGroupIndicator({ className, children, ...props }: RadioGroupIndicatorProps) {
|
|
81
|
+
const theme = useThemeFamily();
|
|
82
|
+
const { indicator, dot } = radioGroup({ theme });
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<BaseRadio.Indicator
|
|
86
|
+
data-slot="radio-group-indicator"
|
|
87
|
+
className={indicator({ className })}
|
|
88
|
+
{...props}
|
|
89
|
+
>
|
|
90
|
+
{children ?? <span data-slot="radio-group-dot" className={dot()} />}
|
|
91
|
+
</BaseRadio.Indicator>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export type RadioGroupItemProps<T extends string = string> = StyledProps<
|
|
96
|
+
BaseRadio.Root.Props<T>
|
|
97
|
+
> & {
|
|
98
|
+
appearance?: "default" | "none";
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export function RadioGroupItem<T extends string = string>({
|
|
102
|
+
appearance = "default",
|
|
103
|
+
className,
|
|
104
|
+
children,
|
|
105
|
+
...props
|
|
106
|
+
}: RadioGroupItemProps<T>) {
|
|
107
|
+
const theme = useThemeFamily();
|
|
108
|
+
const { item } = radioGroup({ theme });
|
|
109
|
+
const itemClassName =
|
|
110
|
+
appearance === "none"
|
|
111
|
+
? cn("sr-only", "data-[disabled]:cursor-not-allowed", className)
|
|
112
|
+
: item({ className });
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<BaseRadio.Root data-slot="radio-group-item" className={itemClassName} {...props}>
|
|
116
|
+
{children ?? (appearance === "default" ? <RadioGroupIndicator /> : null)}
|
|
117
|
+
</BaseRadio.Root>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export {
|
|
2
|
+
SectionHeader,
|
|
3
|
+
SectionHeaderActions,
|
|
4
|
+
SectionHeaderContent,
|
|
5
|
+
SectionHeaderCount,
|
|
6
|
+
SectionHeaderIcon,
|
|
7
|
+
SectionHeaderTitle,
|
|
8
|
+
} from "./section-header.tsx";
|
|
9
|
+
export type {
|
|
10
|
+
SectionHeaderActionsProps,
|
|
11
|
+
SectionHeaderContentProps,
|
|
12
|
+
SectionHeaderCountProps,
|
|
13
|
+
SectionHeaderIconProps,
|
|
14
|
+
SectionHeaderProps,
|
|
15
|
+
SectionHeaderTitleProps,
|
|
16
|
+
} from "./section-header.tsx";
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
3
|
+
import { tv } from "../../lib/tv.ts";
|
|
4
|
+
import { SectionLabel, type SectionLabelProps } from "../section-label/section-label.tsx";
|
|
5
|
+
|
|
6
|
+
const sectionHeader = tv({
|
|
7
|
+
slots: {
|
|
8
|
+
root: ["flex items-center justify-between gap-2"],
|
|
9
|
+
content: ["flex min-w-0 items-center gap-2"],
|
|
10
|
+
icon: ["shrink-0 text-foreground/60", "[&_svg]:size-4 [&_svg]:shrink-0"],
|
|
11
|
+
count: ["ml-2 font-mono text-foreground/40"],
|
|
12
|
+
actions: ["flex shrink-0 items-center gap-1.5"],
|
|
13
|
+
},
|
|
14
|
+
variants: {
|
|
15
|
+
theme: {
|
|
16
|
+
brutal: {},
|
|
17
|
+
// Elegant styling is deferred; see the component TODO.
|
|
18
|
+
elegant: {},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export type SectionHeaderProps = useRender.ComponentProps<"div">;
|
|
24
|
+
|
|
25
|
+
export function SectionHeader({ className, render, ...props }: SectionHeaderProps) {
|
|
26
|
+
const { root } = sectionHeader();
|
|
27
|
+
const defaultProps: useRender.ElementProps<"div"> = {
|
|
28
|
+
className: root({ className }),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return useRender({
|
|
32
|
+
defaultTagName: "div",
|
|
33
|
+
render,
|
|
34
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
35
|
+
state: {
|
|
36
|
+
slot: "section-header",
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type SectionHeaderContentProps = useRender.ComponentProps<"div">;
|
|
42
|
+
|
|
43
|
+
export function SectionHeaderContent({ className, render, ...props }: SectionHeaderContentProps) {
|
|
44
|
+
const { content } = sectionHeader();
|
|
45
|
+
const defaultProps: useRender.ElementProps<"div"> = {
|
|
46
|
+
className: content({ className }),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return useRender({
|
|
50
|
+
defaultTagName: "div",
|
|
51
|
+
render,
|
|
52
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
53
|
+
state: {
|
|
54
|
+
slot: "section-header-content",
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type SectionHeaderIconProps = useRender.ComponentProps<"span">;
|
|
60
|
+
|
|
61
|
+
export function SectionHeaderIcon({ className, render, ...props }: SectionHeaderIconProps) {
|
|
62
|
+
const { icon } = sectionHeader();
|
|
63
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
64
|
+
className: icon({ className }),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return useRender({
|
|
68
|
+
defaultTagName: "span",
|
|
69
|
+
render,
|
|
70
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
71
|
+
state: {
|
|
72
|
+
slot: "section-header-icon",
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type SectionHeaderTitleProps = SectionLabelProps;
|
|
78
|
+
|
|
79
|
+
export function SectionHeaderTitle({ render, ...props }: SectionHeaderTitleProps) {
|
|
80
|
+
return <SectionLabel render={render ?? <div />} {...props} data-slot="section-header-title" />;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type SectionHeaderCountProps = useRender.ComponentProps<"span">;
|
|
84
|
+
|
|
85
|
+
export function SectionHeaderCount({ className, render, ...props }: SectionHeaderCountProps) {
|
|
86
|
+
const { count } = sectionHeader();
|
|
87
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
88
|
+
className: count({ className }),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return useRender({
|
|
92
|
+
defaultTagName: "span",
|
|
93
|
+
render,
|
|
94
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
95
|
+
state: {
|
|
96
|
+
slot: "section-header-count",
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type SectionHeaderActionsProps = useRender.ComponentProps<"div">;
|
|
102
|
+
|
|
103
|
+
export function SectionHeaderActions({ className, render, ...props }: SectionHeaderActionsProps) {
|
|
104
|
+
const { actions } = sectionHeader();
|
|
105
|
+
const defaultProps: useRender.ElementProps<"div"> = {
|
|
106
|
+
className: actions({ className }),
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return useRender({
|
|
110
|
+
defaultTagName: "div",
|
|
111
|
+
render,
|
|
112
|
+
props: mergeProps<"div">(defaultProps, props),
|
|
113
|
+
state: {
|
|
114
|
+
slot: "section-header-actions",
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
3
|
+
import { tv } from "../../lib/tv.ts";
|
|
4
|
+
import { useThemeFamily } from "../../lib/theme/use-theme.ts";
|
|
5
|
+
|
|
6
|
+
const sectionLabel = tv({
|
|
7
|
+
slots: {
|
|
8
|
+
root: ["text-xs font-bold uppercase tracking-widest"],
|
|
9
|
+
},
|
|
10
|
+
variants: {
|
|
11
|
+
theme: {
|
|
12
|
+
brutal: {
|
|
13
|
+
root: "text-foreground/60",
|
|
14
|
+
},
|
|
15
|
+
// Elegant styling is deferred; see the component TODO.
|
|
16
|
+
elegant: {},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export type SectionLabelProps = useRender.ComponentProps<"span">;
|
|
22
|
+
|
|
23
|
+
export function SectionLabel({ className, render, ...props }: SectionLabelProps) {
|
|
24
|
+
const theme = useThemeFamily();
|
|
25
|
+
const { root } = sectionLabel({ theme });
|
|
26
|
+
const defaultProps: useRender.ElementProps<"span"> = {
|
|
27
|
+
className: root({ className }),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return useRender({
|
|
31
|
+
defaultTagName: "span",
|
|
32
|
+
render,
|
|
33
|
+
props: mergeProps<"span">(defaultProps, props),
|
|
34
|
+
state: {
|
|
35
|
+
slot: "section-label",
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export {
|
|
2
|
+
SegmentedControl,
|
|
3
|
+
SegmentedControlCount,
|
|
4
|
+
SegmentedControlItem,
|
|
5
|
+
SegmentedControlLabel,
|
|
6
|
+
} from "./segmented-control.tsx";
|
|
7
|
+
export type {
|
|
8
|
+
SegmentedControlCountProps,
|
|
9
|
+
SegmentedControlItemProps,
|
|
10
|
+
SegmentedControlLabelProps,
|
|
11
|
+
SegmentedControlProps,
|
|
12
|
+
} from "./segmented-control.tsx";
|