@vvedantb/ui 0.17.0 → 0.18.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/README.md +253 -3
- package/package.json +13 -5
- package/shell/src/SidebarResize.tsx +1 -4
- package/src/ai-elements/__snapshots__/queue.test.tsx.snap +11 -0
- package/src/ai-elements/activity-question-utils.ts +26 -0
- package/src/ai-elements/activity-question.tsx +159 -0
- package/src/ai-elements/activity-shared.tsx +459 -0
- package/src/ai-elements/activity-step-detail.tsx +115 -0
- package/src/ai-elements/activity-step-label.ts +981 -0
- package/src/ai-elements/activity-tasks-utils.ts +199 -0
- package/src/ai-elements/activity-tasks.tsx +770 -0
- package/src/ai-elements/artifact.tsx +162 -52
- package/src/ai-elements/attachments.tsx +62 -32
- package/src/ai-elements/code-block.tsx +76 -22
- package/src/ai-elements/context.tsx +370 -0
- package/src/ai-elements/conversation.tsx +186 -62
- package/src/ai-elements/file-chip.tsx +53 -0
- package/src/ai-elements/message.tsx +161 -50
- package/src/ai-elements/model-picker-content.tsx +505 -0
- package/src/ai-elements/model-picker-types.ts +56 -0
- package/src/ai-elements/model-picker.tsx +301 -0
- package/src/ai-elements/model-selector.tsx +102 -21
- package/src/ai-elements/plan.tsx +130 -0
- package/src/ai-elements/prompt-input-settings.tsx +144 -0
- package/src/ai-elements/prompt-input-speech.tsx +189 -0
- package/src/ai-elements/prompt-input-traits.tsx +281 -0
- package/src/ai-elements/prompt-input.tsx +320 -134
- package/src/ai-elements/provider-icon.tsx +133 -0
- package/src/ai-elements/queue.tsx +293 -9
- package/src/ai-elements/shimmer.tsx +72 -1
- package/src/ai-elements/simple-model-ladder.tsx +108 -0
- package/src/ai-elements/test-results.tsx +510 -0
- package/src/ai-elements/trace.tsx +243 -0
- package/src/ai-elements/use-streaming-disclosure.ts +50 -0
- package/src/ai-elements/web-preview.tsx +349 -0
- package/src/composer/input-area/ComposerSlashMenu.tsx +1 -1
- package/src/index.ts +66 -12
- package/src/kibo/avatar-stack.tsx +40 -0
- package/src/kibo/contribution-graph.tsx +539 -0
- package/src/kibo/cursor.tsx +72 -0
- package/src/kibo/gantt-features.tsx +439 -0
- package/src/kibo/gantt-header.tsx +181 -0
- package/src/kibo/gantt-provider.tsx +657 -0
- package/src/kibo/gantt-sidebar.tsx +157 -0
- package/src/kibo/gantt-timeline.tsx +154 -0
- package/src/kibo/index.ts +151 -0
- package/src/kibo/kanban.tsx +338 -0
- package/src/kibo/kanbanDropTarget.ts +25 -0
- package/src/kibo/list.tsx +162 -0
- package/src/kibo/theme-switcher.tsx +109 -0
- package/src/kibo/video-player.tsx +237 -0
- package/src/markdown/Markdown.tsx +112 -0
- package/src/markdown/MarkdownBlockquote.tsx +45 -0
- package/src/markdown/MarkdownCodeBlock.tsx +197 -0
- package/src/markdown/MarkdownInlineCode.tsx +40 -0
- package/src/markdown/MarkdownLink.tsx +92 -0
- package/src/markdown/codeFence.ts +57 -0
- package/src/markdown/codeHighlight.ts +138 -0
- package/src/markdown/incrementalBlocks.ts +182 -0
- package/src/markdown/index.ts +3 -0
- package/src/markdown/markdownClipboard.ts +178 -0
- package/src/markdown/mermaid.ts +155 -0
- package/src/markdown/rehypeGithubAlerts.ts +80 -0
- package/src/motion/presets.ts +24 -0
- package/src/ui/__snapshots__/alt-wrappers.test.tsx.snap +19 -0
- package/src/ui/__snapshots__/sonner-dom.test.tsx.snap +5 -0
- package/src/ui/_menu-parts.tsx +29 -0
- package/src/ui/accordion.alt.tsx +46 -53
- package/src/ui/accordion.tsx +59 -10
- package/src/ui/avatar.tsx +56 -0
- package/src/ui/badge.tsx +45 -21
- package/src/ui/border-beam.tsx +97 -0
- package/src/ui/button-group.tsx +50 -21
- package/src/ui/button.tsx +67 -45
- package/src/ui/calendar.tsx +48 -5
- package/src/ui/card.tsx +77 -8
- package/src/ui/carousel.tsx +60 -0
- package/src/ui/centered-spinner.tsx +30 -0
- package/src/ui/checkbox.tsx +34 -16
- package/src/ui/clear-input.alt.tsx +33 -75
- package/src/ui/clear-input.tsx +140 -15
- package/src/ui/collapsible.tsx +40 -2
- package/src/ui/command.tsx +143 -70
- package/src/ui/context-menu.tsx +159 -93
- package/src/ui/crossfade-icon.tsx +123 -0
- package/src/ui/dialog.tsx +154 -70
- package/src/ui/dropdown-menu.tsx +177 -117
- package/src/ui/hover-card.tsx +59 -17
- package/src/ui/input-group.alt.tsx +83 -83
- package/src/ui/input-group.tsx +129 -58
- package/src/ui/input.tsx +13 -4
- package/src/ui/label.tsx +11 -8
- package/src/ui/list-row.tsx +232 -0
- package/src/ui/loading-state.tsx +215 -0
- package/src/ui/popover.tsx +56 -23
- package/src/ui/progress.tsx +28 -16
- package/src/ui/refresh-spin-icon.tsx +41 -0
- package/src/ui/search-input.tsx +66 -15
- package/src/ui/select.tsx +171 -100
- package/src/ui/separator.tsx +23 -14
- package/src/ui/slider.tsx +21 -7
- package/src/ui/sonner.tsx +68 -30
- package/src/ui/spinner.tsx +229 -11
- package/src/ui/status-dot.tsx +84 -0
- package/src/ui/surface.tsx +49 -0
- package/src/ui/switch.tsx +29 -15
- package/src/ui/table.tsx +38 -16
- package/src/ui/tabs.tsx +123 -35
- package/src/ui/tabsSliding.ts +33 -1
- package/src/ui/textarea.tsx +13 -4
- package/src/ui/tooltip.tsx +50 -14
- package/src/ui/ui-config.tsx +149 -0
- package/src/utils/cat-color.ts +123 -0
- package/src/utils/dayjs.ts +6 -0
- package/src/utils/gesture.ts +59 -0
- package/src/utils/runtimeVisibility.ts +167 -0
- package/src/utils/sharedClock.ts +96 -0
- package/src/utils/surface-radius.ts +16 -0
- package/src/utils/useDragSensors.ts +58 -0
- package/tokens/examples/tokens-moved/Fixture.tsx +283 -0
- package/tokens/examples/tokens-moved/README.md +20 -0
- package/tokens/examples/tokens-moved/index.html +12 -0
- package/tokens/examples/tokens-moved/main.tsx +6 -0
- package/tokens/examples/tokens-moved/package.json +14 -0
- package/tokens/examples/tokens-moved/styles.css +12 -0
- package/tokens/examples/tokens-moved/tsconfig.json +14 -0
- package/tokens/examples/tokens-moved/vite.config.ts +11 -0
- package/tokens/src/css/border-beam.css +116 -0
- package/tokens/src/css/compat-shadcn-rgb.css +6 -0
- package/tokens/src/css/markdown.css +318 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { m, AnimatePresence, type Transition } from "motion/react";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_TRANSITION: Transition = {
|
|
5
|
+
type: "spring",
|
|
6
|
+
duration: 0.3,
|
|
7
|
+
bounce: 0,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const SOFT_EASE: [number, number, number, number] = [0.22, 1, 0.36, 1];
|
|
11
|
+
const SOFT_TRANSITION: Transition = {
|
|
12
|
+
duration: 0.15,
|
|
13
|
+
ease: SOFT_EASE,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const DEFAULT_ICON_MOTION = {
|
|
17
|
+
initial: { scale: 0.25, opacity: 0, filter: "blur(4px)" },
|
|
18
|
+
animate: { scale: 1, opacity: 1, filter: "blur(0px)" },
|
|
19
|
+
exit: { scale: 0.25, opacity: 0, filter: "blur(4px)" },
|
|
20
|
+
transition: DEFAULT_TRANSITION,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Near-imperceptible swap for high-frequency toggles (150ms, no blur). */
|
|
24
|
+
const SOFT_ICON_MOTION = {
|
|
25
|
+
initial: { scale: 0.96, opacity: 0 },
|
|
26
|
+
animate: { scale: 1, opacity: 1 },
|
|
27
|
+
exit: { scale: 0.96, opacity: 0 },
|
|
28
|
+
transition: SOFT_TRANSITION,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
interface CrossfadeIconProps {
|
|
32
|
+
show: boolean;
|
|
33
|
+
whenTrue: ReactNode;
|
|
34
|
+
whenFalse: ReactNode;
|
|
35
|
+
trueKey?: string;
|
|
36
|
+
falseKey?: string;
|
|
37
|
+
className?: string;
|
|
38
|
+
/** `soft` = opacity + scale(0.96→1), no blur — for tens/day toggles. */
|
|
39
|
+
variant?: "default" | "soft";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Cross-fades between two icons in the same slot. */
|
|
43
|
+
export function CrossfadeIcon({
|
|
44
|
+
show,
|
|
45
|
+
whenTrue,
|
|
46
|
+
whenFalse,
|
|
47
|
+
trueKey = "on",
|
|
48
|
+
falseKey = "off",
|
|
49
|
+
className = "relative flex size-5 items-center justify-center",
|
|
50
|
+
variant = "default",
|
|
51
|
+
}: CrossfadeIconProps) {
|
|
52
|
+
const motion = variant === "soft" ? SOFT_ICON_MOTION : DEFAULT_ICON_MOTION;
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<span className={className}>
|
|
56
|
+
<AnimatePresence initial={false}>
|
|
57
|
+
{show ? (
|
|
58
|
+
<m.span
|
|
59
|
+
key={trueKey}
|
|
60
|
+
className="absolute inset-0 flex items-center justify-center"
|
|
61
|
+
initial={motion.initial}
|
|
62
|
+
animate={motion.animate}
|
|
63
|
+
exit={motion.exit}
|
|
64
|
+
transition={motion.transition}
|
|
65
|
+
>
|
|
66
|
+
{whenTrue}
|
|
67
|
+
</m.span>
|
|
68
|
+
) : (
|
|
69
|
+
<m.span
|
|
70
|
+
key={falseKey}
|
|
71
|
+
className="absolute inset-0 flex items-center justify-center"
|
|
72
|
+
initial={motion.initial}
|
|
73
|
+
animate={motion.animate}
|
|
74
|
+
exit={motion.exit}
|
|
75
|
+
transition={motion.transition}
|
|
76
|
+
>
|
|
77
|
+
{whenFalse}
|
|
78
|
+
</m.span>
|
|
79
|
+
)}
|
|
80
|
+
</AnimatePresence>
|
|
81
|
+
</span>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Cross-fades between any number of keyed icons in the same slot.
|
|
87
|
+
*
|
|
88
|
+
* `CrossfadeIcon` covers the two-state case, which is most of them. A control
|
|
89
|
+
* that cycles through three or more states (the composer's submit button:
|
|
90
|
+
* send, submitting, streaming, error) needs the key to come from the state
|
|
91
|
+
* rather than from a boolean.
|
|
92
|
+
*/
|
|
93
|
+
export function CrossfadeIconSlot({
|
|
94
|
+
iconKey,
|
|
95
|
+
children,
|
|
96
|
+
className = "relative flex size-4 items-center justify-center",
|
|
97
|
+
variant = "soft",
|
|
98
|
+
}: {
|
|
99
|
+
/** Identity of the icon currently shown; a change triggers the swap. */
|
|
100
|
+
iconKey: string;
|
|
101
|
+
children: ReactNode;
|
|
102
|
+
className?: string;
|
|
103
|
+
variant?: "default" | "soft";
|
|
104
|
+
}) {
|
|
105
|
+
const motion = variant === "soft" ? SOFT_ICON_MOTION : DEFAULT_ICON_MOTION;
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<span className={className}>
|
|
109
|
+
<AnimatePresence initial={false}>
|
|
110
|
+
<m.span
|
|
111
|
+
key={iconKey}
|
|
112
|
+
className="absolute inset-0 flex items-center justify-center"
|
|
113
|
+
initial={motion.initial}
|
|
114
|
+
animate={motion.animate}
|
|
115
|
+
exit={motion.exit}
|
|
116
|
+
transition={motion.transition}
|
|
117
|
+
>
|
|
118
|
+
{children}
|
|
119
|
+
</m.span>
|
|
120
|
+
</AnimatePresence>
|
|
121
|
+
</span>
|
|
122
|
+
);
|
|
123
|
+
}
|
package/src/ui/dialog.tsx
CHANGED
|
@@ -11,29 +11,69 @@ import {
|
|
|
11
11
|
treeHasDialogDescription,
|
|
12
12
|
useCompactOverlay,
|
|
13
13
|
} from "./overlay-a11y";
|
|
14
|
+
import { useCn, useUiConfig } from "./ui-config";
|
|
15
|
+
|
|
16
|
+
/** App defaults for `Dialog*` (see `UiConfigProvider`). */
|
|
17
|
+
export interface DialogConfig {
|
|
18
|
+
/** Replaces the built-in classes of a part. */
|
|
19
|
+
classes?: {
|
|
20
|
+
trigger?: string;
|
|
21
|
+
overlay?: string;
|
|
22
|
+
/** Content classes shared by both layouts. */
|
|
23
|
+
content?: string;
|
|
24
|
+
/** Content layout classes for the centred dialog. */
|
|
25
|
+
centered?: string;
|
|
26
|
+
/** Content layout classes for the compact bottom sheet. */
|
|
27
|
+
compact?: string;
|
|
28
|
+
close?: string;
|
|
29
|
+
header?: string;
|
|
30
|
+
body?: string;
|
|
31
|
+
footer?: string;
|
|
32
|
+
title?: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
};
|
|
35
|
+
/** Default for `DialogContent` `viewportAware`. */
|
|
36
|
+
viewportAware?: boolean;
|
|
37
|
+
}
|
|
14
38
|
|
|
15
39
|
const Dialog = DialogPrimitive.Root;
|
|
16
|
-
const DialogTrigger = DialogPrimitive.Trigger;
|
|
17
40
|
const DialogPortal = DialogPrimitive.Portal;
|
|
18
41
|
const DialogClose = DialogPrimitive.Close;
|
|
19
42
|
|
|
43
|
+
const DialogTrigger = React.forwardRef<
|
|
44
|
+
React.ComponentRef<typeof DialogPrimitive.Trigger>,
|
|
45
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>
|
|
46
|
+
>((props, ref) => {
|
|
47
|
+
const trigger = useUiConfig("Dialog")?.classes?.trigger;
|
|
48
|
+
const merge = useCn();
|
|
49
|
+
// Without config, pass props untouched: Radix's Slot turns an explicit
|
|
50
|
+
// `className={undefined}` into `class=""`.
|
|
51
|
+
if (trigger === undefined) return <DialogPrimitive.Trigger ref={ref} {...props} />;
|
|
52
|
+
const { className, ...rest } = props;
|
|
53
|
+
return <DialogPrimitive.Trigger ref={ref} className={merge(trigger, className)} {...rest} />;
|
|
54
|
+
});
|
|
55
|
+
DialogTrigger.displayName = DialogPrimitive.Trigger.displayName;
|
|
56
|
+
|
|
20
57
|
const overlayMotionClass =
|
|
21
58
|
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 motion-reduce:animate-none motion-reduce:data-[state=open]:animate-none motion-reduce:data-[state=closed]:animate-none";
|
|
22
59
|
|
|
23
60
|
const DialogOverlay = React.forwardRef<
|
|
24
61
|
React.ComponentRef<typeof DialogPrimitive.Overlay>,
|
|
25
62
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
|
26
|
-
>(({ className, ...props }, ref) =>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
className
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
63
|
+
>(({ className, ...props }, ref) => {
|
|
64
|
+
const overlay = useUiConfig("Dialog")?.classes?.overlay;
|
|
65
|
+
const merge = useCn();
|
|
66
|
+
return (
|
|
67
|
+
<DialogPrimitive.Overlay
|
|
68
|
+
ref={ref}
|
|
69
|
+
className={merge(
|
|
70
|
+
overlay ?? ["fixed inset-0 z-50 bg-backdrop backdrop-blur-md", overlayMotionClass],
|
|
71
|
+
className,
|
|
72
|
+
)}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
});
|
|
37
77
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
38
78
|
|
|
39
79
|
const DEFAULT_ALERT_DESCRIPTION = "This action needs confirmation.";
|
|
@@ -42,6 +82,12 @@ const DialogContent = React.forwardRef<
|
|
|
42
82
|
React.ComponentRef<typeof DialogPrimitive.Content>,
|
|
43
83
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
|
|
44
84
|
hideCloseButton?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Bottom sheet on compact viewports, visual-viewport sizing, keyboard-aware
|
|
87
|
+
* scrolling and the body pointer-events fix. Default `true`. `false` keeps a
|
|
88
|
+
* centred dialog at every size and leaves the viewport and body alone.
|
|
89
|
+
*/
|
|
90
|
+
viewportAware?: boolean;
|
|
45
91
|
}
|
|
46
92
|
>(
|
|
47
93
|
(
|
|
@@ -49,6 +95,7 @@ const DialogContent = React.forwardRef<
|
|
|
49
95
|
className,
|
|
50
96
|
children,
|
|
51
97
|
hideCloseButton,
|
|
98
|
+
viewportAware: viewportAwareProp,
|
|
52
99
|
role,
|
|
53
100
|
onOpenAutoFocus,
|
|
54
101
|
"aria-describedby": ariaDescribedBy,
|
|
@@ -56,7 +103,12 @@ const DialogContent = React.forwardRef<
|
|
|
56
103
|
},
|
|
57
104
|
ref,
|
|
58
105
|
) => {
|
|
59
|
-
const
|
|
106
|
+
const config = useUiConfig("Dialog");
|
|
107
|
+
const classes = config?.classes;
|
|
108
|
+
const merge = useCn();
|
|
109
|
+
const viewportAware = viewportAwareProp ?? config?.viewportAware ?? true;
|
|
110
|
+
const compactViewport = useCompactOverlay();
|
|
111
|
+
const compact = viewportAware && compactViewport;
|
|
60
112
|
const isAlert = role === "alertdialog";
|
|
61
113
|
const contentNodeRef = React.useRef<HTMLDivElement | null>(null);
|
|
62
114
|
const surfaceCleanupRef = React.useRef<(() => void) | null>(null);
|
|
@@ -88,6 +140,10 @@ const DialogContent = React.forwardRef<
|
|
|
88
140
|
if (!compact) {
|
|
89
141
|
surfaceCleanupRef.current = connectModalSurface(node);
|
|
90
142
|
}
|
|
143
|
+
if (!viewportAware) {
|
|
144
|
+
assignRef(ref, node);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
91
147
|
const viewport = connectOverlayViewport(node);
|
|
92
148
|
const keyboard = connectKeyboardScroll(node);
|
|
93
149
|
const pointerEvents = connectBodyPointerEventsFix();
|
|
@@ -100,7 +156,7 @@ const DialogContent = React.forwardRef<
|
|
|
100
156
|
|
|
101
157
|
assignRef(ref, node);
|
|
102
158
|
},
|
|
103
|
-
[ref, compact],
|
|
159
|
+
[ref, compact, viewportAware],
|
|
104
160
|
);
|
|
105
161
|
|
|
106
162
|
React.useLayoutEffect(() => {
|
|
@@ -134,10 +190,11 @@ const DialogContent = React.forwardRef<
|
|
|
134
190
|
: {})}
|
|
135
191
|
onOpenAutoFocus={handleOpenAutoFocus}
|
|
136
192
|
data-compact={compact ? "true" : undefined}
|
|
137
|
-
className={
|
|
138
|
-
|
|
193
|
+
className={merge(
|
|
194
|
+
classes?.content ??
|
|
195
|
+
"glass-panel-strong z-50 flex w-full flex-col gap-4 p-6 text-overlay-foreground smooth-shadow-ring-xl",
|
|
139
196
|
compact
|
|
140
|
-
? cn(
|
|
197
|
+
? classes?.compact ?? cn(
|
|
141
198
|
"overflow-y-auto fixed inset-x-0 top-auto w-full max-w-none rounded-t-2xl rounded-b-none pt-3",
|
|
142
199
|
"max-h-[var(--overlay-vv-height,100dvh)]",
|
|
143
200
|
"bottom-[var(--overlay-vv-bottom,0px)]",
|
|
@@ -146,7 +203,8 @@ const DialogContent = React.forwardRef<
|
|
|
146
203
|
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:slide-in-from-bottom data-[state=closed]:slide-out-to-bottom",
|
|
147
204
|
"motion-reduce:animate-none motion-reduce:data-[state=open]:animate-none motion-reduce:data-[state=closed]:animate-none",
|
|
148
205
|
)
|
|
149
|
-
:
|
|
206
|
+
: classes?.centered ??
|
|
207
|
+
"t-modal fixed left-1/2 top-1/2 max-h-[90dvh] max-w-lg max-sm:w-[calc(100vw-2rem)] overflow-y-auto rounded-lg",
|
|
150
208
|
className,
|
|
151
209
|
)}
|
|
152
210
|
{...props}
|
|
@@ -170,10 +228,13 @@ const DialogContent = React.forwardRef<
|
|
|
170
228
|
{children}
|
|
171
229
|
{!hideCloseButton && (
|
|
172
230
|
<DialogPrimitive.Close
|
|
173
|
-
className={
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
231
|
+
className={
|
|
232
|
+
classes?.close ??
|
|
233
|
+
cn(
|
|
234
|
+
"absolute right-2 top-2 inline-flex h-11 w-11 items-center justify-center rounded-lg text-overlay-foreground/70 transition-[background-color,transform] hover:bg-surface-tertiary/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring disabled:pointer-events-none",
|
|
235
|
+
"motion-reduce:transition-none",
|
|
236
|
+
)
|
|
237
|
+
}
|
|
177
238
|
>
|
|
178
239
|
<IconX className="h-4 w-4" />
|
|
179
240
|
<span className="sr-only">Close</span>
|
|
@@ -189,26 +250,34 @@ DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
|
189
250
|
const DialogHeader = ({
|
|
190
251
|
className,
|
|
191
252
|
...props
|
|
192
|
-
}: React.HTMLAttributes<HTMLDivElement>) =>
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
)
|
|
253
|
+
}: React.HTMLAttributes<HTMLDivElement>) => {
|
|
254
|
+
const header = useUiConfig("Dialog")?.classes?.header;
|
|
255
|
+
const merge = useCn();
|
|
256
|
+
return (
|
|
257
|
+
<div
|
|
258
|
+
className={merge(header ?? "flex flex-col gap-1.5 pr-10 text-left", className)}
|
|
259
|
+
{...props}
|
|
260
|
+
/>
|
|
261
|
+
);
|
|
262
|
+
};
|
|
198
263
|
DialogHeader.displayName = "DialogHeader";
|
|
199
264
|
|
|
200
265
|
const DialogBody = ({
|
|
201
266
|
className,
|
|
202
267
|
...props
|
|
203
|
-
}: React.HTMLAttributes<HTMLDivElement>) =>
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
)
|
|
268
|
+
}: React.HTMLAttributes<HTMLDivElement>) => {
|
|
269
|
+
const body = useUiConfig("Dialog")?.classes?.body;
|
|
270
|
+
const merge = useCn();
|
|
271
|
+
return (
|
|
272
|
+
<div
|
|
273
|
+
className={merge(
|
|
274
|
+
body ?? "min-h-11 flex-1 overflow-y-auto overscroll-contain",
|
|
275
|
+
className,
|
|
276
|
+
)}
|
|
277
|
+
{...props}
|
|
278
|
+
/>
|
|
279
|
+
);
|
|
280
|
+
};
|
|
212
281
|
DialogBody.displayName = "DialogBody";
|
|
213
282
|
|
|
214
283
|
// no fill of its own: the footer is not sticky, so it shows the content's
|
|
@@ -218,49 +287,64 @@ DialogBody.displayName = "DialogBody";
|
|
|
218
287
|
const DialogFooter = ({
|
|
219
288
|
className,
|
|
220
289
|
...props
|
|
221
|
-
}: React.HTMLAttributes<HTMLDivElement>) =>
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
"
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
290
|
+
}: React.HTMLAttributes<HTMLDivElement>) => {
|
|
291
|
+
const footer = useUiConfig("Dialog")?.classes?.footer;
|
|
292
|
+
const merge = useCn();
|
|
293
|
+
return (
|
|
294
|
+
<div
|
|
295
|
+
data-slot="dialog-footer"
|
|
296
|
+
className={merge(
|
|
297
|
+
footer ?? [
|
|
298
|
+
"mt-auto flex flex-col-reverse gap-2 pt-2 sm:flex-row sm:justify-end",
|
|
299
|
+
"pb-[max(0px,env(safe-area-inset-bottom,0px))]",
|
|
300
|
+
"[&_button]:max-sm:min-h-11",
|
|
301
|
+
],
|
|
302
|
+
className,
|
|
303
|
+
)}
|
|
304
|
+
{...props}
|
|
305
|
+
/>
|
|
306
|
+
);
|
|
307
|
+
};
|
|
233
308
|
DialogFooter.displayName = "DialogFooter";
|
|
234
309
|
|
|
235
310
|
const DialogTitle = React.forwardRef<
|
|
236
311
|
React.ComponentRef<typeof DialogPrimitive.Title>,
|
|
237
312
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
|
238
|
-
>(({ className, ...props }, ref) =>
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
)
|
|
313
|
+
>(({ className, ...props }, ref) => {
|
|
314
|
+
const title = useUiConfig("Dialog")?.classes?.title;
|
|
315
|
+
const merge = useCn();
|
|
316
|
+
return (
|
|
317
|
+
<DialogPrimitive.Title
|
|
318
|
+
ref={ref}
|
|
319
|
+
className={merge(
|
|
320
|
+
title ?? "text-lg font-semibold tracking-normal text-foreground text-balance",
|
|
321
|
+
className,
|
|
322
|
+
)}
|
|
323
|
+
{...props}
|
|
324
|
+
/>
|
|
325
|
+
);
|
|
326
|
+
});
|
|
248
327
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
249
328
|
|
|
250
329
|
const DialogDescription = React.forwardRef<
|
|
251
330
|
React.ComponentRef<typeof DialogPrimitive.Description>,
|
|
252
331
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
|
253
|
-
>(({ className, ...props }, ref) =>
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
className
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
332
|
+
>(({ className, ...props }, ref) => {
|
|
333
|
+
const description = useUiConfig("Dialog")?.classes?.description;
|
|
334
|
+
const merge = useCn();
|
|
335
|
+
return (
|
|
336
|
+
<DialogPrimitive.Description
|
|
337
|
+
ref={ref}
|
|
338
|
+
className={merge(
|
|
339
|
+
description ??
|
|
340
|
+
// `--muted` is ~3.5:1 on overlay; mix toward overlay-foreground for 4.5:1.
|
|
341
|
+
"text-sm leading-relaxed text-[color-mix(in_oklch,var(--color-popover-foreground,var(--overlay-foreground))_72%,var(--color-popover,var(--overlay)))]",
|
|
342
|
+
className,
|
|
343
|
+
)}
|
|
344
|
+
{...props}
|
|
345
|
+
/>
|
|
346
|
+
);
|
|
347
|
+
});
|
|
264
348
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
265
349
|
|
|
266
350
|
const DialogRawContent = DialogPrimitive.Content;
|