@plannotator/ui 0.22.0 → 0.23.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/components/OpenInAppButton.tsx +25 -29
- package/components/PopoutDialog.tsx +46 -32
- package/components/Popover.tsx +18 -12
- package/components/SearchableSelect.tsx +4 -7
- package/components/Tooltip.tsx +50 -20
- package/components/ui/badge.tsx +15 -10
- package/components/ui/button.tsx +10 -10
- package/components/ui/dialog.tsx +17 -17
- package/components/ui/dropdown-menu.tsx +80 -66
- package/components/ui/tabs.tsx +11 -11
- package/package.json +5 -12
- package/styles.css +1 -1
- package/theme.css +17 -0
|
@@ -212,22 +212,24 @@ export const OpenInAppButton: React.FC<OpenInAppButtonProps> = ({
|
|
|
212
212
|
)}
|
|
213
213
|
{/* Chevron (with primary) or standalone overflow (copy-only). */}
|
|
214
214
|
<DropdownMenu open={menuOpen} onOpenChange={setMenuOpen}>
|
|
215
|
-
<DropdownMenuTrigger
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
215
|
+
<DropdownMenuTrigger
|
|
216
|
+
render={
|
|
217
|
+
<button
|
|
218
|
+
type="button"
|
|
219
|
+
disabled={isDisabled}
|
|
220
|
+
className={`text-xs flex items-center py-1 transition-colors text-muted-foreground hover:text-foreground hover:bg-muted disabled:opacity-50 disabled:cursor-not-allowed ${
|
|
221
|
+
openable ? 'px-1 border-l border-border/50' : 'px-1.5'
|
|
222
|
+
}`}
|
|
223
|
+
title={openable ? 'Open in…' : 'File actions'}
|
|
224
|
+
aria-label={openable ? 'Choose app to open in' : 'File actions'}
|
|
225
|
+
/>
|
|
226
|
+
}
|
|
227
|
+
>
|
|
228
|
+
{openable ? (
|
|
229
|
+
<ChevronDown className="w-3 h-3" />
|
|
230
|
+
) : (
|
|
231
|
+
<MoreHorizontal className="w-3.5 h-3.5" />
|
|
232
|
+
)}
|
|
231
233
|
</DropdownMenuTrigger>
|
|
232
234
|
<DropdownMenuContent
|
|
233
235
|
align="end"
|
|
@@ -235,7 +237,7 @@ export const OpenInAppButton: React.FC<OpenInAppButtonProps> = ({
|
|
|
235
237
|
className="min-w-[12rem]"
|
|
236
238
|
// Don't snap focus (and its focus ring) back onto the trigger when
|
|
237
239
|
// the menu closes — that left-edge bar reads as a stray artifact.
|
|
238
|
-
|
|
240
|
+
finalFocus={false}
|
|
239
241
|
>
|
|
240
242
|
{openable &&
|
|
241
243
|
grouped.map((group, gi) => (
|
|
@@ -244,10 +246,8 @@ export const OpenInAppButton: React.FC<OpenInAppButtonProps> = ({
|
|
|
244
246
|
{group.map((app) => (
|
|
245
247
|
<DropdownMenuItem
|
|
246
248
|
key={app.id}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
selectApp(app.id);
|
|
250
|
-
}}
|
|
249
|
+
closeOnClick={false}
|
|
250
|
+
onClick={() => selectApp(app.id)}
|
|
251
251
|
className="text-xs"
|
|
252
252
|
>
|
|
253
253
|
<AppIcon id={app.icon} className="w-4 h-4" />
|
|
@@ -260,10 +260,8 @@ export const OpenInAppButton: React.FC<OpenInAppButtonProps> = ({
|
|
|
260
260
|
{openable && (filePath || diffText) && <DropdownMenuSeparator />}
|
|
261
261
|
{filePath && (
|
|
262
262
|
<DropdownMenuItem
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
void copyText(filePath);
|
|
266
|
-
}}
|
|
263
|
+
closeOnClick={false}
|
|
264
|
+
onClick={() => void copyText(filePath)}
|
|
267
265
|
className="text-xs"
|
|
268
266
|
>
|
|
269
267
|
<Copy className="w-4 h-4" />
|
|
@@ -272,10 +270,8 @@ export const OpenInAppButton: React.FC<OpenInAppButtonProps> = ({
|
|
|
272
270
|
)}
|
|
273
271
|
{diffText && (
|
|
274
272
|
<DropdownMenuItem
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
void copyText(diffText);
|
|
278
|
-
}}
|
|
273
|
+
closeOnClick={false}
|
|
274
|
+
onClick={() => void copyText(diffText)}
|
|
279
275
|
className="text-xs"
|
|
280
276
|
>
|
|
281
277
|
<Copy className="w-4 h-4" />
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useCallback } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import { Dialog } from '@base-ui/react/dialog';
|
|
3
3
|
|
|
4
4
|
const ANNOTATION_SELECTORS = [
|
|
5
5
|
'.annotation-toolbar',
|
|
@@ -14,7 +14,7 @@ interface PopoutDialogProps {
|
|
|
14
14
|
container?: HTMLElement | null;
|
|
15
15
|
className?: string;
|
|
16
16
|
children: React.ReactNode;
|
|
17
|
-
/** Extra data attributes to spread onto
|
|
17
|
+
/** Extra data attributes to spread onto the dialog popup */
|
|
18
18
|
dataAttributes?: Record<string, string>;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -36,55 +36,69 @@ export const PopoutDialog: React.FC<PopoutDialogProps> = ({
|
|
|
36
36
|
[onClose],
|
|
37
37
|
);
|
|
38
38
|
|
|
39
|
-
const
|
|
40
|
-
(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
const handleOpenChange = useCallback(
|
|
40
|
+
(next: boolean, eventDetails: Dialog.Root.ChangeEventDetails) => {
|
|
41
|
+
if (next) return;
|
|
42
|
+
// Interactions with annotation UI (toolbars/popovers portal outside the
|
|
43
|
+
// dialog) must not dismiss the popout — the Radix version guarded this
|
|
44
|
+
// via onInteractOutside preventDefault; Base UI expresses it as
|
|
45
|
+
// cancelling the outside-press/focus-out close reason.
|
|
46
|
+
if (eventDetails.reason === 'outside-press' || eventDetails.reason === 'focus-out') {
|
|
47
|
+
// For focus events the annotation UI may sit on either side of the
|
|
48
|
+
// event (target = element losing focus, relatedTarget = gaining), so
|
|
49
|
+
// guard both.
|
|
50
|
+
const event = eventDetails.event as Event | undefined;
|
|
51
|
+
const candidates = [
|
|
52
|
+
event?.target as Element | null,
|
|
53
|
+
(event as FocusEvent | undefined)?.relatedTarget as Element | null,
|
|
54
|
+
];
|
|
55
|
+
if (
|
|
56
|
+
candidates.some(
|
|
57
|
+
(el) => el instanceof Element && ANNOTATION_SELECTORS.some((sel) => el.closest(sel)),
|
|
58
|
+
)
|
|
59
|
+
) {
|
|
60
|
+
eventDetails.cancel();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
45
63
|
}
|
|
64
|
+
onClose();
|
|
46
65
|
},
|
|
47
|
-
[],
|
|
66
|
+
[onClose],
|
|
48
67
|
);
|
|
49
68
|
|
|
50
69
|
return (
|
|
51
|
-
<Dialog.Root
|
|
52
|
-
open={open}
|
|
53
|
-
onOpenChange={(next) => { if (!next) onClose(); }}
|
|
54
|
-
modal={false}
|
|
55
|
-
>
|
|
70
|
+
<Dialog.Root open={open} onOpenChange={handleOpenChange} modal={false}>
|
|
56
71
|
<Dialog.Portal container={container ?? undefined}>
|
|
57
|
-
{/*
|
|
58
|
-
div for the
|
|
59
|
-
|
|
60
|
-
interactive. */}
|
|
72
|
+
{/* Non-modal dialogs render no library backdrop, so we use a plain
|
|
73
|
+
div for the dark scrim + blur while keeping annotation toolbars
|
|
74
|
+
(which portal outside the dialog) interactive. */}
|
|
61
75
|
<div
|
|
62
76
|
className="fixed inset-0 z-50 bg-black/50 backdrop-blur-[2px]"
|
|
63
77
|
onClick={handleBackdropClick}
|
|
64
78
|
aria-hidden="true"
|
|
65
79
|
/>
|
|
66
|
-
<Dialog.
|
|
80
|
+
<Dialog.Popup
|
|
67
81
|
className={`fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2 bg-background border border-border rounded-xl shadow-2xl flex flex-col overflow-hidden ${className ?? 'w-[calc(100vw-4rem)] max-w-[min(calc(100vw-4rem),1500px)] max-h-[calc(100vh-4rem)]'}`}
|
|
68
82
|
data-popout="true"
|
|
69
|
-
|
|
70
|
-
onOpenAutoFocus={(e) => e.preventDefault()}
|
|
71
|
-
onInteractOutside={handleInteractOutside}
|
|
83
|
+
initialFocus={false}
|
|
72
84
|
{...dataAttributes}
|
|
73
85
|
>
|
|
74
86
|
<Dialog.Title className="sr-only">{title}</Dialog.Title>
|
|
75
|
-
<Dialog.Close
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
<Dialog.Close
|
|
88
|
+
render={
|
|
89
|
+
<button
|
|
90
|
+
className="absolute top-3 right-3 z-20 p-1.5 rounded-md text-muted-foreground/70 hover:bg-muted hover:text-foreground transition-colors"
|
|
91
|
+
aria-label="Close"
|
|
92
|
+
/>
|
|
93
|
+
}
|
|
94
|
+
>
|
|
95
|
+
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
|
96
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
97
|
+
</svg>
|
|
84
98
|
</Dialog.Close>
|
|
85
99
|
|
|
86
100
|
{children}
|
|
87
|
-
</Dialog.
|
|
101
|
+
</Dialog.Popup>
|
|
88
102
|
</Dialog.Portal>
|
|
89
103
|
</Dialog.Root>
|
|
90
104
|
);
|
package/components/Popover.tsx
CHANGED
|
@@ -1,27 +1,33 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Popover as PopoverPrimitive } from '@base-ui/react/popover';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
4
|
const Popover = PopoverPrimitive.Root;
|
|
5
5
|
const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
6
|
-
const PopoverAnchor = PopoverPrimitive.Anchor;
|
|
7
6
|
|
|
8
7
|
const PopoverContent = React.forwardRef<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
HTMLDivElement,
|
|
9
|
+
PopoverPrimitive.Popup.Props &
|
|
10
|
+
Pick<PopoverPrimitive.Positioner.Props, 'side' | 'sideOffset' | 'align' | 'alignOffset'>
|
|
11
|
+
>(({ className, side, align = 'center', sideOffset = 6, alignOffset, children, ...props }, ref) => (
|
|
12
12
|
<PopoverPrimitive.Portal>
|
|
13
|
-
<PopoverPrimitive.
|
|
14
|
-
|
|
13
|
+
<PopoverPrimitive.Positioner
|
|
14
|
+
side={side}
|
|
15
15
|
align={align}
|
|
16
16
|
sideOffset={sideOffset}
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
alignOffset={alignOffset}
|
|
18
|
+
className="isolate z-[100]"
|
|
19
19
|
>
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
<PopoverPrimitive.Popup
|
|
21
|
+
ref={ref}
|
|
22
|
+
className={`bg-popover text-popover-foreground border border-border/50 rounded-lg shadow-xl z-[100] outline-none origin-[var(--transform-origin)] transition-[opacity,scale] duration-150 ease-out data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95 ${className ?? ''}`}
|
|
23
|
+
{...props}
|
|
24
|
+
>
|
|
25
|
+
{children}
|
|
26
|
+
</PopoverPrimitive.Popup>
|
|
27
|
+
</PopoverPrimitive.Positioner>
|
|
22
28
|
</PopoverPrimitive.Portal>
|
|
23
29
|
));
|
|
24
30
|
|
|
25
31
|
PopoverContent.displayName = 'PopoverContent';
|
|
26
32
|
|
|
27
|
-
export { Popover, PopoverTrigger, PopoverContent
|
|
33
|
+
export { Popover, PopoverTrigger, PopoverContent };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useMemo, useRef, useCallback, type ReactNode } from 'react';
|
|
1
|
+
import React, { useState, useMemo, useRef, useCallback, type ReactElement, type ReactNode } from 'react';
|
|
2
2
|
import { Popover, PopoverTrigger, PopoverContent } from './Popover';
|
|
3
3
|
|
|
4
4
|
interface SearchableSelectProps<T extends { id: string }> {
|
|
@@ -7,7 +7,7 @@ interface SearchableSelectProps<T extends { id: string }> {
|
|
|
7
7
|
onSelect: (item: T) => void;
|
|
8
8
|
filterFn: (item: T, query: string) => boolean;
|
|
9
9
|
renderItem: (item: T, state: { isSelected: boolean; isFocused: boolean }) => ReactNode;
|
|
10
|
-
renderTrigger: (state: { open: boolean }) =>
|
|
10
|
+
renderTrigger: (state: { open: boolean }) => ReactElement;
|
|
11
11
|
headerContent?: ReactNode;
|
|
12
12
|
placeholder?: string;
|
|
13
13
|
emptyMessage?: string;
|
|
@@ -85,14 +85,11 @@ export function SearchableSelect<T extends { id: string }>({
|
|
|
85
85
|
|
|
86
86
|
return (
|
|
87
87
|
<Popover open={open} onOpenChange={handleOpenChange}>
|
|
88
|
-
<PopoverTrigger
|
|
88
|
+
<PopoverTrigger render={renderTrigger({ open })} />
|
|
89
89
|
<PopoverContent
|
|
90
90
|
align={align}
|
|
91
91
|
className={`${width} p-0`}
|
|
92
|
-
|
|
93
|
-
e.preventDefault();
|
|
94
|
-
inputRef.current?.focus();
|
|
95
|
-
}}
|
|
92
|
+
initialFocus={inputRef}
|
|
96
93
|
>
|
|
97
94
|
{/* Search row */}
|
|
98
95
|
<div className="flex items-center gap-2 border-b border-border/50 px-3 py-2">
|
package/components/Tooltip.tsx
CHANGED
|
@@ -1,11 +1,39 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
2
|
+
import { Tooltip as BaseTooltip } from '@base-ui/react/tooltip';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* TooltipProvider keeps the Radix-era prop names (`delayDuration`,
|
|
6
|
+
* `skipDelayDuration`, `disableHoverableContent`) as its public API and maps
|
|
7
|
+
* them onto Base UI's Provider (`delay`, `timeout`) — call sites in the apps
|
|
8
|
+
* stay unchanged. `disableHoverableContent` has no provider-level equivalent
|
|
9
|
+
* in Base UI (it moved to per-root `disableHoverablePopup`), so it is carried
|
|
10
|
+
* via context and applied to every Tooltip root under the provider.
|
|
11
|
+
*/
|
|
12
|
+
const DisableHoverablePopupContext = React.createContext(false);
|
|
13
|
+
|
|
14
|
+
interface TooltipProviderProps {
|
|
15
|
+
delayDuration?: number;
|
|
16
|
+
skipDelayDuration?: number;
|
|
17
|
+
disableHoverableContent?: boolean;
|
|
18
|
+
children?: React.ReactNode;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const TooltipProvider: React.FC<TooltipProviderProps> = ({
|
|
22
|
+
delayDuration,
|
|
23
|
+
skipDelayDuration,
|
|
24
|
+
disableHoverableContent = false,
|
|
25
|
+
children,
|
|
26
|
+
}) => (
|
|
27
|
+
<BaseTooltip.Provider delay={delayDuration} timeout={skipDelayDuration}>
|
|
28
|
+
<DisableHoverablePopupContext.Provider value={disableHoverableContent}>
|
|
29
|
+
{children}
|
|
30
|
+
</DisableHoverablePopupContext.Provider>
|
|
31
|
+
</BaseTooltip.Provider>
|
|
32
|
+
);
|
|
5
33
|
|
|
6
34
|
interface TooltipProps {
|
|
7
35
|
content: React.ReactNode;
|
|
8
|
-
children: React.
|
|
36
|
+
children: React.ReactElement;
|
|
9
37
|
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
10
38
|
align?: 'start' | 'center' | 'end';
|
|
11
39
|
delayDuration?: number;
|
|
@@ -26,20 +54,22 @@ export const Tooltip: React.FC<TooltipProps> = ({
|
|
|
26
54
|
delayDuration,
|
|
27
55
|
sideOffset = 8,
|
|
28
56
|
wide = false,
|
|
29
|
-
}) =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
align={align}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
}) => {
|
|
58
|
+
const disableHoverablePopup = React.useContext(DisableHoverablePopupContext);
|
|
59
|
+
return (
|
|
60
|
+
<BaseTooltip.Root disableHoverablePopup={disableHoverablePopup}>
|
|
61
|
+
<BaseTooltip.Trigger render={children} delay={delayDuration} />
|
|
62
|
+
<BaseTooltip.Portal>
|
|
63
|
+
<BaseTooltip.Positioner side={side} align={align} sideOffset={sideOffset} className="isolate z-50">
|
|
64
|
+
<BaseTooltip.Popup
|
|
65
|
+
className={`z-50 px-2 py-1 text-xs bg-popover text-popover-foreground border border-border rounded shadow-md origin-[var(--transform-origin)] transition-[opacity,scale] duration-150 ease-out data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95 ${
|
|
66
|
+
wide ? 'max-w-[260px] leading-snug whitespace-normal' : 'whitespace-nowrap'
|
|
67
|
+
}`}
|
|
68
|
+
>
|
|
69
|
+
{content}
|
|
70
|
+
</BaseTooltip.Popup>
|
|
71
|
+
</BaseTooltip.Positioner>
|
|
72
|
+
</BaseTooltip.Portal>
|
|
73
|
+
</BaseTooltip.Root>
|
|
74
|
+
);
|
|
75
|
+
};
|
package/components/ui/badge.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mergeProps } from "@base-ui/react/merge-props";
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
2
3
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
4
|
import type * as React from "react";
|
|
4
5
|
|
|
@@ -6,8 +7,9 @@ import { cn } from "../../lib/utils";
|
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Badge — small labelled token (status, category, count). Token-driven variants.
|
|
9
|
-
* Pass `
|
|
10
|
-
* for tighter inline badges
|
|
10
|
+
* Pass `render` (e.g. `render={<a href=... />}`) to render as a link/button.
|
|
11
|
+
* Override padding/size via className for tighter inline badges
|
|
12
|
+
* (e.g. `px-1.5 py-px text-[10px]`).
|
|
11
13
|
*/
|
|
12
14
|
const badgeVariants = cva(
|
|
13
15
|
"inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-auto whitespace-nowrap rounded-md border px-3 py-1 text-xs font-medium transition-[color,box-shadow] [&>svg]:size-3 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
@@ -31,14 +33,17 @@ const badgeVariants = cva(
|
|
|
31
33
|
function Badge({
|
|
32
34
|
className,
|
|
33
35
|
variant,
|
|
34
|
-
|
|
36
|
+
render,
|
|
35
37
|
...props
|
|
36
|
-
}:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
|
|
38
|
+
}: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
|
|
39
|
+
return useRender({
|
|
40
|
+
defaultTagName: "span",
|
|
41
|
+
render,
|
|
42
|
+
props: mergeProps<"span">(
|
|
43
|
+
{ "data-slot": "badge", className: cn(badgeVariants({ variant }), className) } as React.ComponentProps<"span">,
|
|
44
|
+
props,
|
|
45
|
+
),
|
|
46
|
+
});
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
export { Badge, badgeVariants };
|
package/components/ui/button.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Button as ButtonPrimitive } from "@base-ui/react/button";
|
|
2
2
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
3
|
import type * as React from "react";
|
|
4
4
|
|
|
@@ -7,7 +7,7 @@ import { cn } from "../../lib/utils";
|
|
|
7
7
|
/**
|
|
8
8
|
* Button — the canonical action primitive (shared by the frontend shell and the
|
|
9
9
|
* embedded plan/review apps). cva variants + sizes, optional `iconLeft`/`iconRight`
|
|
10
|
-
* slots, and `
|
|
10
|
+
* slots, and Base UI's `render` prop for polymorphism (e.g. `render={<a href=... />}`).
|
|
11
11
|
*
|
|
12
12
|
* `success` (solid, token-driven green) covers the plan app's Approve action; the
|
|
13
13
|
* Feedback action uses `outline`. (No `accent` variant — `text-accent` on `bg-accent`
|
|
@@ -51,32 +51,32 @@ function Button({
|
|
|
51
51
|
className,
|
|
52
52
|
variant,
|
|
53
53
|
size,
|
|
54
|
-
asChild = false,
|
|
55
54
|
iconLeft,
|
|
56
55
|
iconRight,
|
|
57
56
|
...props
|
|
58
|
-
}:
|
|
57
|
+
}: ButtonPrimitive.Props &
|
|
59
58
|
VariantProps<typeof buttonVariants> & {
|
|
60
|
-
asChild?: boolean;
|
|
61
59
|
iconLeft?: ButtonIcon;
|
|
62
60
|
iconRight?: ButtonIcon;
|
|
63
61
|
}) {
|
|
64
|
-
const Comp = asChild ? Slot : "button";
|
|
65
|
-
|
|
66
62
|
return (
|
|
67
|
-
<
|
|
63
|
+
<ButtonPrimitive
|
|
64
|
+
data-slot="button"
|
|
65
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
66
|
+
{...props}
|
|
67
|
+
>
|
|
68
68
|
{iconLeft ? (
|
|
69
69
|
<span data-slot="button-icon" data-side="left" aria-hidden="true" className="shrink-0">
|
|
70
70
|
{iconLeft}
|
|
71
71
|
</span>
|
|
72
72
|
) : null}
|
|
73
|
-
|
|
73
|
+
{children}
|
|
74
74
|
{iconRight ? (
|
|
75
75
|
<span data-slot="button-icon" data-side="right" aria-hidden="true" className="shrink-0">
|
|
76
76
|
{iconRight}
|
|
77
77
|
</span>
|
|
78
78
|
) : null}
|
|
79
|
-
</
|
|
79
|
+
</ButtonPrimitive>
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
82
|
|
package/components/ui/dialog.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
2
|
+
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
3
3
|
import { X } from "lucide-react";
|
|
4
4
|
import { cn } from "../../lib/utils";
|
|
5
5
|
|
|
@@ -9,31 +9,31 @@ const DialogPortal = DialogPrimitive.Portal;
|
|
|
9
9
|
const DialogClose = DialogPrimitive.Close;
|
|
10
10
|
|
|
11
11
|
const DialogOverlay = React.forwardRef<
|
|
12
|
-
React.ComponentRef<typeof DialogPrimitive.
|
|
13
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.
|
|
12
|
+
React.ComponentRef<typeof DialogPrimitive.Backdrop>,
|
|
13
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Backdrop>
|
|
14
14
|
>(({ className, ...props }, ref) => (
|
|
15
|
-
<DialogPrimitive.
|
|
15
|
+
<DialogPrimitive.Backdrop
|
|
16
16
|
ref={ref}
|
|
17
17
|
className={cn(
|
|
18
18
|
"fixed inset-0 z-[110] bg-black/55 backdrop-blur-[2px]",
|
|
19
|
-
"
|
|
20
|
-
"data-
|
|
19
|
+
"transition-opacity duration-200",
|
|
20
|
+
"data-starting-style:opacity-0 data-ending-style:opacity-0",
|
|
21
21
|
className,
|
|
22
22
|
)}
|
|
23
23
|
{...props}
|
|
24
24
|
/>
|
|
25
25
|
));
|
|
26
|
-
DialogOverlay.displayName =
|
|
26
|
+
DialogOverlay.displayName = "DialogOverlay";
|
|
27
27
|
|
|
28
28
|
const DialogContent = React.forwardRef<
|
|
29
|
-
React.ComponentRef<typeof DialogPrimitive.
|
|
30
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.
|
|
29
|
+
React.ComponentRef<typeof DialogPrimitive.Popup>,
|
|
30
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Popup> & {
|
|
31
31
|
hideClose?: boolean;
|
|
32
32
|
}
|
|
33
33
|
>(({ className, children, hideClose, ...props }, ref) => (
|
|
34
34
|
<DialogPortal>
|
|
35
35
|
<DialogOverlay />
|
|
36
|
-
<DialogPrimitive.
|
|
36
|
+
<DialogPrimitive.Popup
|
|
37
37
|
ref={ref}
|
|
38
38
|
className={cn(
|
|
39
39
|
"fixed top-[50%] left-[50%] z-[110] w-full translate-x-[-50%] translate-y-[-50%]",
|
|
@@ -41,9 +41,9 @@ const DialogContent = React.forwardRef<
|
|
|
41
41
|
"flex flex-col overflow-hidden",
|
|
42
42
|
"rounded-2xl border border-border bg-popover text-popover-foreground",
|
|
43
43
|
"shadow-[0_24px_80px_-36px_rgba(15,23,42,0.5)]",
|
|
44
|
-
"
|
|
45
|
-
"data-
|
|
46
|
-
"
|
|
44
|
+
"transition-[opacity,scale] duration-200",
|
|
45
|
+
"data-starting-style:opacity-0 data-starting-style:scale-95",
|
|
46
|
+
"data-ending-style:opacity-0 data-ending-style:scale-95",
|
|
47
47
|
className,
|
|
48
48
|
)}
|
|
49
49
|
{...props}
|
|
@@ -55,10 +55,10 @@ const DialogContent = React.forwardRef<
|
|
|
55
55
|
<span className="sr-only">Close</span>
|
|
56
56
|
</DialogPrimitive.Close>
|
|
57
57
|
)}
|
|
58
|
-
</DialogPrimitive.
|
|
58
|
+
</DialogPrimitive.Popup>
|
|
59
59
|
</DialogPortal>
|
|
60
60
|
));
|
|
61
|
-
DialogContent.displayName =
|
|
61
|
+
DialogContent.displayName = "DialogContent";
|
|
62
62
|
|
|
63
63
|
function DialogHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
64
64
|
return (
|
|
@@ -79,7 +79,7 @@ const DialogTitle = React.forwardRef<
|
|
|
79
79
|
{...props}
|
|
80
80
|
/>
|
|
81
81
|
));
|
|
82
|
-
DialogTitle.displayName =
|
|
82
|
+
DialogTitle.displayName = "DialogTitle";
|
|
83
83
|
|
|
84
84
|
const DialogDescription = React.forwardRef<
|
|
85
85
|
React.ComponentRef<typeof DialogPrimitive.Description>,
|
|
@@ -91,7 +91,7 @@ const DialogDescription = React.forwardRef<
|
|
|
91
91
|
{...props}
|
|
92
92
|
/>
|
|
93
93
|
));
|
|
94
|
-
DialogDescription.displayName =
|
|
94
|
+
DialogDescription.displayName = "DialogDescription";
|
|
95
95
|
|
|
96
96
|
export {
|
|
97
97
|
Dialog,
|