@softize/opus 15.2.2 → 16.1.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/CHANGELOG.md +60 -18
- package/bin/lib/check.mjs +98 -15
- package/bin/lib/copy.mjs +811 -314
- package/bin/lib/gen-manifest.mjs +24 -23
- package/bin/lib/gen-runner.mjs +188 -148
- package/docs/adr/0010-page-header-owns-page-chrome.md +3 -4
- package/docs/adr/0011-page-shell-coordinates-persistent-page-chrome.md +5 -3
- package/docs/adr/0012-modal-header-only-names-the-surface.md +45 -0
- package/docs/adr/0013-presentation-is-a-portable-action-oriented-artifact.md +92 -0
- package/docs/code-style.md +24 -19
- package/package.json +5 -1
- package/registry/skills/build-opus-ui/references/ui-patterns.md +43 -26
- package/src/core/presentation.ts +512 -0
- package/src/presentation/index.ts +1 -0
- package/src/ui/components/patterns/action-list-dialog.tsx +26 -9
- package/src/ui/components/patterns/confirm.tsx +34 -29
- package/src/ui/components/patterns/form-dialog.tsx +20 -8
- package/src/ui/components/patterns/list.tsx +26 -9
- package/src/ui/components/patterns/page.tsx +99 -139
- package/src/ui/components/patterns/presentation.tsx +539 -0
- package/src/ui/components/patterns/sidebar.tsx +3 -3
- package/src/ui/components/patterns/trigger.tsx +38 -17
- package/src/ui/components/primitives/button-group.tsx +53 -43
- package/src/ui/components/primitives/command.tsx +30 -72
- package/src/ui/components/primitives/dialog.tsx +23 -89
- package/src/ui/components/primitives/drawer.tsx +8 -34
- package/src/ui/docs/content/action-form-dialog.md +12 -10
- package/src/ui/docs/content/action-list-dialog.md +22 -17
- package/src/ui/docs/content/button.md +52 -35
- package/src/ui/docs/content/communication.md +26 -26
- package/src/ui/docs/content/dialog.md +173 -154
- package/src/ui/docs/content/drawer.md +12 -11
- package/src/ui/docs/content/page.md +72 -91
- package/src/ui/docs/content/presentation.md +188 -0
- package/src/ui/docs/registry.tsx +6 -0
- package/src/ui/meta.ts +8 -2
- package/src/ui/react.tsx +16 -3
|
@@ -1,71 +1,80 @@
|
|
|
1
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
2
|
-
import { Slot } from "radix-ui"
|
|
1
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2
|
+
import { Slot } from "radix-ui";
|
|
3
3
|
|
|
4
|
-
import { cn } from
|
|
5
|
-
import { Separator } from
|
|
4
|
+
import { cn } from "../../lib/cn.ts";
|
|
5
|
+
import { Separator } from "./separator.tsx";
|
|
6
6
|
|
|
7
7
|
const buttonGroupVariants = cva(
|
|
8
8
|
"flex w-fit items-stretch has-[>[data-slot=button-group]]:gap-2 [&>*]:focus-visible:relative [&>*]:focus-visible:z-10 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
|
|
9
9
|
{
|
|
10
10
|
variants: {
|
|
11
11
|
orientation: {
|
|
12
|
-
horizontal:
|
|
13
|
-
vertical:
|
|
12
|
+
horizontal: "",
|
|
13
|
+
vertical: "flex-col",
|
|
14
14
|
},
|
|
15
15
|
mode: {
|
|
16
|
-
connected:
|
|
17
|
-
spaced:
|
|
16
|
+
connected: "",
|
|
17
|
+
spaced: "gap-1",
|
|
18
18
|
},
|
|
19
19
|
shape: {
|
|
20
|
-
default:
|
|
21
|
-
pill:
|
|
20
|
+
default: "",
|
|
21
|
+
pill: "rounded-full",
|
|
22
|
+
},
|
|
23
|
+
distribution: {
|
|
24
|
+
content: "",
|
|
25
|
+
equal:
|
|
26
|
+
"w-full flex-col-reverse gap-2 sm:flex-row [&>*]:min-w-0 [&>*]:w-full [&>*]:flex-1",
|
|
22
27
|
},
|
|
23
28
|
},
|
|
24
29
|
compoundVariants: [
|
|
25
30
|
{
|
|
26
|
-
orientation:
|
|
27
|
-
mode:
|
|
31
|
+
orientation: "horizontal",
|
|
32
|
+
mode: "connected",
|
|
28
33
|
className:
|
|
29
|
-
|
|
34
|
+
"[&>*:not(:first-child)]:rounded-l-none [&>*:not(:first-child)]:border-l-0 [&>*:not(:last-child)]:rounded-r-none",
|
|
30
35
|
},
|
|
31
36
|
{
|
|
32
|
-
orientation:
|
|
33
|
-
mode:
|
|
37
|
+
orientation: "vertical",
|
|
38
|
+
mode: "connected",
|
|
34
39
|
className:
|
|
35
|
-
|
|
40
|
+
"[&>*:not(:first-child)]:rounded-t-none [&>*:not(:first-child)]:border-t-0 [&>*:not(:last-child)]:rounded-b-none",
|
|
36
41
|
},
|
|
37
42
|
{
|
|
38
|
-
orientation:
|
|
39
|
-
mode:
|
|
40
|
-
shape:
|
|
41
|
-
className:
|
|
43
|
+
orientation: "horizontal",
|
|
44
|
+
mode: "connected",
|
|
45
|
+
shape: "pill",
|
|
46
|
+
className:
|
|
47
|
+
"[&>*:first-child]:rounded-l-full [&>*:last-child]:rounded-r-full [&>[data-slot=select]:first-child_[data-slot=select-control]]:rounded-l-full [&>[data-slot=select]:last-child_[data-slot=select-control]]:rounded-r-full [&>[data-slot=select-wrapper]:first-child_[data-slot=select]]:rounded-l-full [&>[data-slot=select-wrapper]:last-child_[data-slot=select]]:rounded-r-full",
|
|
42
48
|
},
|
|
43
49
|
{
|
|
44
|
-
orientation:
|
|
45
|
-
mode:
|
|
46
|
-
shape:
|
|
47
|
-
className:
|
|
50
|
+
orientation: "vertical",
|
|
51
|
+
mode: "connected",
|
|
52
|
+
shape: "pill",
|
|
53
|
+
className:
|
|
54
|
+
"[&>*:first-child]:rounded-t-full [&>*:last-child]:rounded-b-full [&>[data-slot=select]:first-child_[data-slot=select-control]]:rounded-t-full [&>[data-slot=select]:last-child_[data-slot=select-control]]:rounded-b-full [&>[data-slot=select-wrapper]:first-child_[data-slot=select]]:rounded-t-full [&>[data-slot=select-wrapper]:last-child_[data-slot=select]]:rounded-b-full",
|
|
48
55
|
},
|
|
49
56
|
{
|
|
50
|
-
mode:
|
|
51
|
-
shape:
|
|
57
|
+
mode: "spaced",
|
|
58
|
+
shape: "pill",
|
|
52
59
|
className:
|
|
53
|
-
|
|
60
|
+
"[&>*]:rounded-full [&>[data-slot=select]_[data-slot=select-control]]:rounded-full [&>[data-slot=select-wrapper]_[data-slot=select]]:rounded-full",
|
|
54
61
|
},
|
|
55
62
|
],
|
|
56
63
|
defaultVariants: {
|
|
57
64
|
orientation: "horizontal",
|
|
58
|
-
mode:
|
|
65
|
+
mode: "connected",
|
|
59
66
|
shape: "default",
|
|
67
|
+
distribution: "content",
|
|
60
68
|
},
|
|
61
|
-
}
|
|
62
|
-
)
|
|
69
|
+
},
|
|
70
|
+
);
|
|
63
71
|
|
|
64
72
|
function ButtonGroup({
|
|
65
73
|
className,
|
|
66
74
|
orientation,
|
|
67
75
|
mode,
|
|
68
76
|
shape,
|
|
77
|
+
distribution,
|
|
69
78
|
...props
|
|
70
79
|
}: React.ComponentProps<"div"> & VariantProps<typeof buttonGroupVariants>) {
|
|
71
80
|
return (
|
|
@@ -75,17 +84,18 @@ function ButtonGroup({
|
|
|
75
84
|
data-orientation={orientation}
|
|
76
85
|
data-mode={mode}
|
|
77
86
|
data-shape={shape}
|
|
87
|
+
data-distribution={distribution}
|
|
78
88
|
className={cn(
|
|
79
|
-
buttonGroupVariants({ orientation, mode, shape }),
|
|
80
|
-
mode !==
|
|
81
|
-
(orientation ===
|
|
82
|
-
?
|
|
83
|
-
:
|
|
89
|
+
buttonGroupVariants({ orientation, mode, shape, distribution }),
|
|
90
|
+
mode !== "spaced" &&
|
|
91
|
+
(orientation === "vertical"
|
|
92
|
+
? "[&>[data-slot=select]:not(:first-child)_[data-slot=select-control]]:rounded-t-none [&>[data-slot=select]:not(:first-child)_[data-slot=select-control]]:border-t-0 [&>[data-slot=select]:not(:last-child)_[data-slot=select-control]]:rounded-b-none [&>[data-slot=select-wrapper]:not(:first-child)_[data-slot=select]]:rounded-t-none [&>[data-slot=select-wrapper]:not(:first-child)_[data-slot=select]]:border-t-0 [&>[data-slot=select-wrapper]:not(:last-child)_[data-slot=select]]:rounded-b-none"
|
|
93
|
+
: "[&>[data-slot=select]:not(:first-child)_[data-slot=select-control]]:rounded-l-none [&>[data-slot=select]:not(:first-child)_[data-slot=select-control]]:border-l-0 [&>[data-slot=select]:not(:last-child)_[data-slot=select-control]]:rounded-r-none [&>[data-slot=select-wrapper]:not(:first-child)_[data-slot=select]]:rounded-l-none [&>[data-slot=select-wrapper]:not(:first-child)_[data-slot=select]]:border-l-0 [&>[data-slot=select-wrapper]:not(:last-child)_[data-slot=select]]:rounded-r-none"),
|
|
84
94
|
className,
|
|
85
95
|
)}
|
|
86
96
|
{...props}
|
|
87
97
|
/>
|
|
88
|
-
)
|
|
98
|
+
);
|
|
89
99
|
}
|
|
90
100
|
|
|
91
101
|
function ButtonGroupText({
|
|
@@ -93,19 +103,19 @@ function ButtonGroupText({
|
|
|
93
103
|
asChild = false,
|
|
94
104
|
...props
|
|
95
105
|
}: React.ComponentProps<"div"> & {
|
|
96
|
-
asChild?: boolean
|
|
106
|
+
asChild?: boolean;
|
|
97
107
|
}) {
|
|
98
|
-
const Comp = asChild ? Slot.Root : "div"
|
|
108
|
+
const Comp = asChild ? Slot.Root : "div";
|
|
99
109
|
|
|
100
110
|
return (
|
|
101
111
|
<Comp
|
|
102
112
|
className={cn(
|
|
103
113
|
"flex items-center gap-2 rounded-md border bg-muted px-4 text-sm font-medium [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
|
|
104
|
-
className
|
|
114
|
+
className,
|
|
105
115
|
)}
|
|
106
116
|
{...props}
|
|
107
117
|
/>
|
|
108
|
-
)
|
|
118
|
+
);
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
function ButtonGroupSeparator({
|
|
@@ -119,11 +129,11 @@ function ButtonGroupSeparator({
|
|
|
119
129
|
orientation={orientation}
|
|
120
130
|
className={cn(
|
|
121
131
|
"relative m-0! self-stretch bg-input data-[orientation=vertical]:h-auto",
|
|
122
|
-
className
|
|
132
|
+
className,
|
|
123
133
|
)}
|
|
124
134
|
{...props}
|
|
125
135
|
/>
|
|
126
|
-
)
|
|
136
|
+
);
|
|
127
137
|
}
|
|
128
138
|
|
|
129
139
|
export {
|
|
@@ -131,4 +141,4 @@ export {
|
|
|
131
141
|
ButtonGroupSeparator,
|
|
132
142
|
ButtonGroupText,
|
|
133
143
|
buttonGroupVariants,
|
|
134
|
-
}
|
|
144
|
+
};
|
|
@@ -1,26 +1,17 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import { Command as CommandPrimitive } from
|
|
3
|
-
import { SearchIcon } from
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { Command as CommandPrimitive } from 'cmdk'
|
|
3
|
+
import { SearchIcon } from 'lucide-react'
|
|
4
4
|
|
|
5
5
|
import { cn } from '../../lib/cn.ts'
|
|
6
|
-
import {
|
|
7
|
-
Dialog,
|
|
8
|
-
DialogContent,
|
|
9
|
-
DialogDescription,
|
|
10
|
-
DialogHeader,
|
|
11
|
-
DialogTitle,
|
|
12
|
-
} from './dialog.tsx'
|
|
6
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from './dialog.tsx'
|
|
13
7
|
|
|
14
|
-
function Command({
|
|
15
|
-
className,
|
|
16
|
-
...props
|
|
17
|
-
}: React.ComponentProps<typeof CommandPrimitive>) {
|
|
8
|
+
function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {
|
|
18
9
|
return (
|
|
19
10
|
<CommandPrimitive
|
|
20
11
|
data-slot="command"
|
|
21
12
|
className={cn(
|
|
22
|
-
|
|
23
|
-
className
|
|
13
|
+
'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
|
|
14
|
+
className,
|
|
24
15
|
)}
|
|
25
16
|
{...props}
|
|
26
17
|
/>
|
|
@@ -28,8 +19,8 @@ function Command({
|
|
|
28
19
|
}
|
|
29
20
|
|
|
30
21
|
function CommandDialog({
|
|
31
|
-
title =
|
|
32
|
-
description =
|
|
22
|
+
title = 'Paleta de comandos',
|
|
23
|
+
description = 'Busque um comando para executar…',
|
|
33
24
|
children,
|
|
34
25
|
className,
|
|
35
26
|
showCloseButton = true,
|
|
@@ -40,15 +31,17 @@ function CommandDialog({
|
|
|
40
31
|
className?: string
|
|
41
32
|
showCloseButton?: boolean
|
|
42
33
|
}) {
|
|
34
|
+
const descriptionId = React.useId()
|
|
43
35
|
return (
|
|
44
36
|
<Dialog {...props}>
|
|
45
37
|
<DialogHeader className="sr-only">
|
|
46
38
|
<DialogTitle>{title}</DialogTitle>
|
|
47
|
-
<
|
|
39
|
+
<p id={descriptionId}>{description}</p>
|
|
48
40
|
</DialogHeader>
|
|
49
41
|
<DialogContent
|
|
50
|
-
className={cn(
|
|
42
|
+
className={cn('overflow-hidden p-0', className)}
|
|
51
43
|
showCloseButton={showCloseButton}
|
|
44
|
+
aria-describedby={descriptionId}
|
|
52
45
|
>
|
|
53
46
|
<Command className="**:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
|
54
47
|
{children}
|
|
@@ -58,21 +51,15 @@ function CommandDialog({
|
|
|
58
51
|
)
|
|
59
52
|
}
|
|
60
53
|
|
|
61
|
-
function CommandInput({
|
|
62
|
-
className,
|
|
63
|
-
...props
|
|
64
|
-
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
|
|
54
|
+
function CommandInput({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Input>) {
|
|
65
55
|
return (
|
|
66
|
-
<div
|
|
67
|
-
data-slot="command-input-wrapper"
|
|
68
|
-
className="flex h-9 items-center gap-2 border-b px-3"
|
|
69
|
-
>
|
|
56
|
+
<div data-slot="command-input-wrapper" className="flex h-9 items-center gap-2 border-b px-3">
|
|
70
57
|
<SearchIcon className="size-4 shrink-0 opacity-50" />
|
|
71
58
|
<CommandPrimitive.Input
|
|
72
59
|
data-slot="command-input"
|
|
73
60
|
className={cn(
|
|
74
|
-
|
|
75
|
-
className
|
|
61
|
+
'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
|
|
62
|
+
className,
|
|
76
63
|
)}
|
|
77
64
|
{...props}
|
|
78
65
|
/>
|
|
@@ -80,90 +67,61 @@ function CommandInput({
|
|
|
80
67
|
)
|
|
81
68
|
}
|
|
82
69
|
|
|
83
|
-
function CommandList({
|
|
84
|
-
className,
|
|
85
|
-
...props
|
|
86
|
-
}: React.ComponentProps<typeof CommandPrimitive.List>) {
|
|
70
|
+
function CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {
|
|
87
71
|
return (
|
|
88
72
|
<CommandPrimitive.List
|
|
89
73
|
data-slot="command-list"
|
|
90
|
-
className={cn(
|
|
91
|
-
"max-h-[18.75rem] scroll-py-1 overflow-x-hidden overflow-y-auto",
|
|
92
|
-
className
|
|
93
|
-
)}
|
|
74
|
+
className={cn('max-h-[18.75rem] scroll-py-1 overflow-x-hidden overflow-y-auto', className)}
|
|
94
75
|
{...props}
|
|
95
76
|
/>
|
|
96
77
|
)
|
|
97
78
|
}
|
|
98
79
|
|
|
99
|
-
function CommandEmpty({
|
|
100
|
-
...props
|
|
101
|
-
}: React.ComponentProps<typeof CommandPrimitive.Empty>) {
|
|
102
|
-
return (
|
|
103
|
-
<CommandPrimitive.Empty
|
|
104
|
-
data-slot="command-empty"
|
|
105
|
-
className="py-6 text-center text-sm"
|
|
106
|
-
{...props}
|
|
107
|
-
/>
|
|
108
|
-
)
|
|
80
|
+
function CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
|
|
81
|
+
return <CommandPrimitive.Empty data-slot="command-empty" className="py-6 text-center text-sm" {...props} />
|
|
109
82
|
}
|
|
110
83
|
|
|
111
|
-
function CommandGroup({
|
|
112
|
-
className,
|
|
113
|
-
...props
|
|
114
|
-
}: React.ComponentProps<typeof CommandPrimitive.Group>) {
|
|
84
|
+
function CommandGroup({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Group>) {
|
|
115
85
|
return (
|
|
116
86
|
<CommandPrimitive.Group
|
|
117
87
|
data-slot="command-group"
|
|
118
88
|
className={cn(
|
|
119
|
-
|
|
120
|
-
className
|
|
89
|
+
'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',
|
|
90
|
+
className,
|
|
121
91
|
)}
|
|
122
92
|
{...props}
|
|
123
93
|
/>
|
|
124
94
|
)
|
|
125
95
|
}
|
|
126
96
|
|
|
127
|
-
function CommandSeparator({
|
|
128
|
-
className,
|
|
129
|
-
...props
|
|
130
|
-
}: React.ComponentProps<typeof CommandPrimitive.Separator>) {
|
|
97
|
+
function CommandSeparator({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
|
|
131
98
|
return (
|
|
132
99
|
<CommandPrimitive.Separator
|
|
133
100
|
data-slot="command-separator"
|
|
134
|
-
className={cn(
|
|
101
|
+
className={cn('-mx-1 h-px bg-border', className)}
|
|
135
102
|
{...props}
|
|
136
103
|
/>
|
|
137
104
|
)
|
|
138
105
|
}
|
|
139
106
|
|
|
140
|
-
function CommandItem({
|
|
141
|
-
className,
|
|
142
|
-
...props
|
|
143
|
-
}: React.ComponentProps<typeof CommandPrimitive.Item>) {
|
|
107
|
+
function CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) {
|
|
144
108
|
return (
|
|
145
109
|
<CommandPrimitive.Item
|
|
146
110
|
data-slot="command-item"
|
|
147
111
|
className={cn(
|
|
148
112
|
"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
149
|
-
className
|
|
113
|
+
className,
|
|
150
114
|
)}
|
|
151
115
|
{...props}
|
|
152
116
|
/>
|
|
153
117
|
)
|
|
154
118
|
}
|
|
155
119
|
|
|
156
|
-
function CommandShortcut({
|
|
157
|
-
className,
|
|
158
|
-
...props
|
|
159
|
-
}: React.ComponentProps<"span">) {
|
|
120
|
+
function CommandShortcut({ className, ...props }: React.ComponentProps<'span'>) {
|
|
160
121
|
return (
|
|
161
122
|
<span
|
|
162
123
|
data-slot="command-shortcut"
|
|
163
|
-
className={cn(
|
|
164
|
-
"ml-auto text-xs tracking-widest text-muted-foreground",
|
|
165
|
-
className
|
|
166
|
-
)}
|
|
124
|
+
className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}
|
|
167
125
|
{...props}
|
|
168
126
|
/>
|
|
169
127
|
)
|
|
@@ -12,26 +12,22 @@ interface DialogContextValue {
|
|
|
12
12
|
onResult?: (result: string) => void
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const DialogContext = React.createContext<DialogContextValue>({
|
|
15
|
+
const DialogContext = React.createContext<DialogContextValue>({
|
|
16
|
+
mode: 'default',
|
|
17
|
+
})
|
|
16
18
|
|
|
17
19
|
function useDialogContext(): DialogContextValue {
|
|
18
20
|
return React.useContext(DialogContext)
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
export interface DialogProps
|
|
22
|
-
extends React.ComponentProps<typeof DialogPrimitive.Root> {
|
|
23
|
+
export interface DialogProps extends React.ComponentProps<typeof DialogPrimitive.Root> {
|
|
23
24
|
/** `alert` exige uma resposta explícita e deriva `role="alertdialog"`. */
|
|
24
25
|
mode?: DialogMode
|
|
25
26
|
/** Recebe o `result` do `DialogClose` acionado. */
|
|
26
27
|
onResult?: (result: string) => void
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
export function Dialog({
|
|
30
|
-
mode = 'default',
|
|
31
|
-
onResult,
|
|
32
|
-
modal,
|
|
33
|
-
...props
|
|
34
|
-
}: DialogProps) {
|
|
30
|
+
export function Dialog({ mode = 'default', onResult, modal, ...props }: DialogProps) {
|
|
35
31
|
const context = React.useMemo(() => ({ mode, onResult }), [mode, onResult])
|
|
36
32
|
|
|
37
33
|
return (
|
|
@@ -45,9 +41,7 @@ export function Dialog({
|
|
|
45
41
|
)
|
|
46
42
|
}
|
|
47
43
|
|
|
48
|
-
export function DialogTrigger({
|
|
49
|
-
...props
|
|
50
|
-
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
44
|
+
export function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
51
45
|
const { mode } = useDialogContext()
|
|
52
46
|
return mode === 'alert' ? (
|
|
53
47
|
<AlertDialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
@@ -56,9 +50,7 @@ export function DialogTrigger({
|
|
|
56
50
|
)
|
|
57
51
|
}
|
|
58
52
|
|
|
59
|
-
export function DialogPortal({
|
|
60
|
-
...props
|
|
61
|
-
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
53
|
+
export function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
62
54
|
const { mode } = useDialogContext()
|
|
63
55
|
return mode === 'alert' ? (
|
|
64
56
|
<AlertDialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
|
@@ -67,20 +59,14 @@ export function DialogPortal({
|
|
|
67
59
|
)
|
|
68
60
|
}
|
|
69
61
|
|
|
70
|
-
export interface DialogCloseProps
|
|
71
|
-
extends React.ComponentProps<typeof DialogPrimitive.Close> {
|
|
62
|
+
export interface DialogCloseProps extends React.ComponentProps<typeof DialogPrimitive.Close> {
|
|
72
63
|
/** No modo `alert`, registra este controle como destino inicial seguro do foco. */
|
|
73
64
|
initialFocus?: boolean
|
|
74
65
|
/** Resposta entregue a `Dialog.onResult` antes do fechamento. */
|
|
75
66
|
result?: string
|
|
76
67
|
}
|
|
77
68
|
|
|
78
|
-
export function DialogClose({
|
|
79
|
-
initialFocus = false,
|
|
80
|
-
result,
|
|
81
|
-
onClick,
|
|
82
|
-
...props
|
|
83
|
-
}: DialogCloseProps) {
|
|
69
|
+
export function DialogClose({ initialFocus = false, result, onClick, ...props }: DialogCloseProps) {
|
|
84
70
|
const root = useDialogContext()
|
|
85
71
|
const handleClick: React.MouseEventHandler<HTMLButtonElement> = (event) => {
|
|
86
72
|
onClick?.(event)
|
|
@@ -88,9 +74,7 @@ export function DialogClose({
|
|
|
88
74
|
}
|
|
89
75
|
|
|
90
76
|
if (root.mode === 'alert') {
|
|
91
|
-
const ClosePrimitive = initialFocus
|
|
92
|
-
? AlertDialogPrimitive.Cancel
|
|
93
|
-
: AlertDialogPrimitive.Action
|
|
77
|
+
const ClosePrimitive = initialFocus ? AlertDialogPrimitive.Cancel : AlertDialogPrimitive.Action
|
|
94
78
|
return (
|
|
95
79
|
<ClosePrimitive
|
|
96
80
|
data-slot="dialog-close"
|
|
@@ -115,24 +99,13 @@ export function DialogClose({
|
|
|
115
99
|
export const overlayClasses =
|
|
116
100
|
'fixed inset-0 z-50 bg-black/30 backdrop-blur-xs data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0'
|
|
117
101
|
|
|
118
|
-
export function DialogOverlay({
|
|
119
|
-
className,
|
|
120
|
-
...props
|
|
121
|
-
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
102
|
+
export function DialogOverlay({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
122
103
|
const { mode } = useDialogContext()
|
|
123
104
|
const overlay = cn(overlayClasses, className)
|
|
124
105
|
return mode === 'alert' ? (
|
|
125
|
-
<AlertDialogPrimitive.Overlay
|
|
126
|
-
data-slot="dialog-overlay"
|
|
127
|
-
className={overlay}
|
|
128
|
-
{...props}
|
|
129
|
-
/>
|
|
106
|
+
<AlertDialogPrimitive.Overlay data-slot="dialog-overlay" className={overlay} {...props} />
|
|
130
107
|
) : (
|
|
131
|
-
<DialogPrimitive.Overlay
|
|
132
|
-
data-slot="dialog-overlay"
|
|
133
|
-
className={overlay}
|
|
134
|
-
{...props}
|
|
135
|
-
/>
|
|
108
|
+
<DialogPrimitive.Overlay data-slot="dialog-overlay" className={overlay} {...props} />
|
|
136
109
|
)
|
|
137
110
|
}
|
|
138
111
|
|
|
@@ -140,6 +113,7 @@ export function DialogContent({
|
|
|
140
113
|
className,
|
|
141
114
|
children,
|
|
142
115
|
showCloseButton,
|
|
116
|
+
'aria-describedby': ariaDescribedBy,
|
|
143
117
|
...props
|
|
144
118
|
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
145
119
|
/** Mostra o “X” no modo padrão. O modo `alert` exige uma resposta identificável. */
|
|
@@ -158,6 +132,7 @@ export function DialogContent({
|
|
|
158
132
|
data-slot="dialog-content"
|
|
159
133
|
data-mode="alert"
|
|
160
134
|
className={cn(contentClasses, 'grid max-w-xs gap-4 p-6', className)}
|
|
135
|
+
aria-describedby={ariaDescribedBy}
|
|
161
136
|
{...props}
|
|
162
137
|
>
|
|
163
138
|
{children}
|
|
@@ -172,11 +147,8 @@ export function DialogContent({
|
|
|
172
147
|
<DialogPrimitive.Content
|
|
173
148
|
data-slot="dialog-content"
|
|
174
149
|
data-mode="default"
|
|
175
|
-
className={cn(
|
|
176
|
-
|
|
177
|
-
'flex max-h-[85vh] flex-col sm:max-w-lg',
|
|
178
|
-
className,
|
|
179
|
-
)}
|
|
150
|
+
className={cn(contentClasses, 'flex max-h-[85vh] flex-col sm:max-w-lg', className)}
|
|
151
|
+
aria-describedby={ariaDescribedBy}
|
|
180
152
|
{...props}
|
|
181
153
|
>
|
|
182
154
|
{children}
|
|
@@ -197,10 +169,7 @@ export function DialogContent({
|
|
|
197
169
|
)
|
|
198
170
|
}
|
|
199
171
|
|
|
200
|
-
export function DialogHeader({
|
|
201
|
-
className,
|
|
202
|
-
...props
|
|
203
|
-
}: React.ComponentProps<'div'>) {
|
|
172
|
+
export function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
|
204
173
|
const { mode } = useDialogContext()
|
|
205
174
|
return (
|
|
206
175
|
<div
|
|
@@ -216,10 +185,7 @@ export function DialogHeader({
|
|
|
216
185
|
)
|
|
217
186
|
}
|
|
218
187
|
|
|
219
|
-
export function DialogMedia({
|
|
220
|
-
className,
|
|
221
|
-
...props
|
|
222
|
-
}: React.ComponentProps<'div'>) {
|
|
188
|
+
export function DialogMedia({ className, ...props }: React.ComponentProps<'div'>) {
|
|
223
189
|
return (
|
|
224
190
|
<div
|
|
225
191
|
data-slot="dialog-media"
|
|
@@ -232,27 +198,18 @@ export function DialogMedia({
|
|
|
232
198
|
)
|
|
233
199
|
}
|
|
234
200
|
|
|
235
|
-
export function DialogBody({
|
|
236
|
-
className,
|
|
237
|
-
...props
|
|
238
|
-
}: React.ComponentProps<'div'>) {
|
|
201
|
+
export function DialogBody({ className, ...props }: React.ComponentProps<'div'>) {
|
|
239
202
|
const { mode } = useDialogContext()
|
|
240
203
|
return (
|
|
241
204
|
<div
|
|
242
205
|
data-slot="dialog-body"
|
|
243
|
-
className={cn(
|
|
244
|
-
mode === 'alert' ? 'min-w-0' : 'min-h-0 flex-1 overflow-y-auto p-5',
|
|
245
|
-
className,
|
|
246
|
-
)}
|
|
206
|
+
className={cn(mode === 'alert' ? 'min-w-0' : 'min-h-0 flex-1 overflow-y-auto p-5', className)}
|
|
247
207
|
{...props}
|
|
248
208
|
/>
|
|
249
209
|
)
|
|
250
210
|
}
|
|
251
211
|
|
|
252
|
-
export function DialogFooter({
|
|
253
|
-
className,
|
|
254
|
-
...props
|
|
255
|
-
}: React.ComponentProps<'div'>) {
|
|
212
|
+
export function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
|
256
213
|
const { mode } = useDialogContext()
|
|
257
214
|
return (
|
|
258
215
|
<div
|
|
@@ -268,10 +225,7 @@ export function DialogFooter({
|
|
|
268
225
|
)
|
|
269
226
|
}
|
|
270
227
|
|
|
271
|
-
export function DialogTitle({
|
|
272
|
-
className,
|
|
273
|
-
...props
|
|
274
|
-
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
228
|
+
export function DialogTitle({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
275
229
|
const { mode } = useDialogContext()
|
|
276
230
|
return mode === 'alert' ? (
|
|
277
231
|
<AlertDialogPrimitive.Title
|
|
@@ -287,23 +241,3 @@ export function DialogTitle({
|
|
|
287
241
|
/>
|
|
288
242
|
)
|
|
289
243
|
}
|
|
290
|
-
|
|
291
|
-
export function DialogDescription({
|
|
292
|
-
className,
|
|
293
|
-
...props
|
|
294
|
-
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
295
|
-
const { mode } = useDialogContext()
|
|
296
|
-
return mode === 'alert' ? (
|
|
297
|
-
<AlertDialogPrimitive.Description
|
|
298
|
-
data-slot="dialog-description"
|
|
299
|
-
className={cn('text-sm text-muted-foreground', className)}
|
|
300
|
-
{...props}
|
|
301
|
-
/>
|
|
302
|
-
) : (
|
|
303
|
-
<DialogPrimitive.Description
|
|
304
|
-
data-slot="dialog-description"
|
|
305
|
-
className={cn('text-sm text-muted-foreground', className)}
|
|
306
|
-
{...props}
|
|
307
|
-
/>
|
|
308
|
-
)
|
|
309
|
-
}
|