@softize/opus 12.11.0 → 13.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 +76 -0
- package/PROMOTED.md +46 -0
- package/README.md +28 -19
- package/bin/cli.mjs +87 -216
- package/bin/lib/check.mjs +2 -7
- package/bin/lib/cli-shared.mjs +131 -0
- package/bin/lib/copy.mjs +1 -5
- package/bin/lib/db.mjs +16 -74
- package/bin/lib/gen-openapi.mjs +3 -3
- package/bin/lib/gen-runner.mjs +1 -1
- package/bin/lib/gen.mjs +14 -69
- package/bin/lib/mcp.mjs +3 -1
- package/bin/lib/seed.mjs +5 -62
- package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +93 -10
- package/docs/adr/0007-toast-actions-form-an-ordered-collection.md +63 -0
- package/docs/adr/0008-hierarchical-navigation-is-composed-at-the-consumer-boundary.md +71 -0
- package/docs/ownership-vs-shadcn-lock.md +2 -3
- package/docs/protocol.md +7 -7
- package/docs/radius-scale.md +1 -1
- package/docs/releasing.md +8 -2
- package/package.json +7 -3
- package/registry/skills/maintain-opus-docs/SKILL.md +83 -0
- package/registry/skills/maintain-opus-docs/agents/openai.yaml +4 -0
- package/registry/skills/maintain-opus-docs/references/editorial-standard.md +85 -0
- package/registry/skills/maintain-opus-docs/references/evaluations.md +34 -0
- package/registry/skills/maintain-opus-docs/scripts/audit-docs.mjs +81 -0
- package/registry/templates/app/package.json +1 -1
- package/registry/templates/app/src/main.tsx +4 -4
- package/src/audit/drivers/console.ts +1 -0
- package/src/auth/drivers/better-auth.ts +1 -0
- package/src/auth/drivers/jwt.ts +1 -0
- package/src/cache/drivers/memory.ts +1 -0
- package/src/client/drivers/fetch.ts +2 -1
- package/src/core/actions.ts +6 -1
- package/src/core/audit.ts +9 -3
- package/src/core/contracts.ts +7 -0
- package/src/core/domain.ts +1 -1
- package/src/core/errors.ts +18 -15
- package/src/core/index.ts +4 -2
- package/src/core/package-version.ts +26 -0
- package/src/core/reactions.ts +1 -1
- package/src/core/runtime.ts +33 -23
- package/src/core/schedules.ts +1 -1
- package/src/core/types.ts +2 -2
- package/src/dsl/eval.ts +2 -2
- package/src/dsl/kysely.ts +2 -2
- package/src/dsl/loads.ts +1 -1
- package/src/dsl/parser.ts +5 -5
- package/src/events/drivers/mitt.ts +1 -0
- package/src/mcp/index.ts +2 -1
- package/src/observability/drivers/opentelemetry.ts +1 -0
- package/src/queue/drivers/bullmq.ts +3 -3
- package/src/scheduler/drivers/node-cron.ts +3 -2
- package/src/scheduler/every.ts +7 -7
- package/src/schema/openapi.ts +3 -3
- package/src/seed/index.ts +29 -0
- package/src/server/drivers/fastify.ts +5 -2
- package/src/server/drivers/node.ts +9 -6
- package/src/server/index.ts +3 -1
- package/src/storage/drivers/fs.ts +1 -0
- package/src/testing/index.ts +3 -3
- package/src/ui/components/patterns/confirm.tsx +142 -42
- package/src/ui/components/patterns/content-header.tsx +7 -1
- package/src/ui/components/patterns/data-state.tsx +1 -1
- package/src/ui/components/patterns/dock.tsx +20 -3
- package/src/ui/components/patterns/form.tsx +12 -8
- package/src/ui/components/patterns/list.tsx +36 -41
- package/src/ui/components/patterns/page-state.tsx +2 -2
- package/src/ui/components/patterns/page.tsx +19 -1
- package/src/ui/components/patterns/shell-nav.tsx +10 -3
- package/src/ui/components/patterns/sidebar.tsx +43 -32
- package/src/ui/components/patterns/trigger.tsx +39 -38
- package/src/ui/components/patterns/view.tsx +26 -17
- package/src/ui/components/primitives/alert.tsx +14 -8
- package/src/ui/components/primitives/ask.tsx +3 -3
- package/src/ui/components/primitives/badge.tsx +11 -6
- package/src/ui/components/primitives/breadcrumb.tsx +2 -2
- package/src/ui/components/primitives/button.tsx +16 -3
- package/src/ui/components/primitives/calendar.tsx +28 -2
- package/src/ui/components/primitives/carousel.tsx +3 -3
- package/src/ui/components/primitives/chat.tsx +1 -1
- package/src/ui/components/primitives/checkbox.tsx +1 -1
- package/src/ui/components/primitives/command.tsx +2 -2
- package/src/ui/components/primitives/control.ts +12 -0
- package/src/ui/components/primitives/copyable.tsx +1 -1
- package/src/ui/components/primitives/dialog.tsx +202 -40
- package/src/ui/components/primitives/dot.tsx +5 -0
- package/src/ui/components/primitives/drawer.tsx +18 -8
- package/src/ui/components/primitives/empty.tsx +3 -3
- package/src/ui/components/primitives/field.tsx +3 -3
- package/src/ui/components/primitives/icon-picker.tsx +3 -1
- package/src/ui/components/primitives/input-group.tsx +1 -1
- package/src/ui/components/primitives/input-otp.tsx +1 -1
- package/src/ui/components/primitives/input.tsx +2 -2
- package/src/ui/components/primitives/item.tsx +3 -3
- package/src/ui/components/primitives/progress.tsx +32 -3
- package/src/ui/components/primitives/radio-group.tsx +1 -1
- package/src/ui/components/primitives/resizable.tsx +3 -1
- package/src/ui/components/primitives/select.tsx +5 -5
- package/src/ui/components/primitives/slider.tsx +5 -1
- package/src/ui/components/primitives/sonner.tsx +190 -8
- package/src/ui/components/primitives/switch.tsx +1 -0
- package/src/ui/components/primitives/tabs.tsx +1 -0
- package/src/ui/components/primitives/textarea.tsx +1 -1
- package/src/ui/components/primitives/toggle.tsx +1 -1
- package/src/ui/components/primitives/tooltip.tsx +1 -0
- package/src/ui/docs/DocBrowser.tsx +102 -23
- package/src/ui/docs/changelog.tsx +1 -1
- package/src/ui/docs/content/accordion.md +22 -16
- package/src/ui/docs/content/action-form-card.md +8 -8
- package/src/ui/docs/content/action-form-dialog.md +9 -9
- package/src/ui/docs/content/action-form.md +37 -36
- package/src/ui/docs/content/action-list-dialog.md +11 -6
- package/src/ui/docs/content/action-list.md +73 -39
- package/src/ui/docs/content/action-trigger.md +29 -15
- package/src/ui/docs/content/action-view.md +17 -10
- package/src/ui/docs/content/actions.md +9 -9
- package/src/ui/docs/content/ai.md +3 -3
- package/src/ui/docs/content/alert.md +14 -12
- package/src/ui/docs/content/ask.md +11 -0
- package/src/ui/docs/content/aspect-ratio.md +4 -4
- package/src/ui/docs/content/audit.md +2 -2
- package/src/ui/docs/content/auth.md +3 -3
- package/src/ui/docs/content/avatar.md +34 -14
- package/src/ui/docs/content/badge.md +3 -3
- package/src/ui/docs/content/breadcrumb.md +13 -8
- package/src/ui/docs/content/button.md +81 -6
- package/src/ui/docs/content/calendar.md +18 -5
- package/src/ui/docs/content/card.md +27 -1
- package/src/ui/docs/content/carousel.md +16 -11
- package/src/ui/docs/content/chat.md +23 -3
- package/src/ui/docs/content/checkbox.md +7 -7
- package/src/ui/docs/content/cli.md +74 -22
- package/src/ui/docs/content/collapsible.md +8 -8
- package/src/ui/docs/content/command.md +16 -8
- package/src/ui/docs/content/composer.md +17 -2
- package/src/ui/docs/content/content.md +17 -2
- package/src/ui/docs/content/copyable.md +12 -3
- package/src/ui/docs/content/customization.md +5 -5
- package/src/ui/docs/content/cycle.md +3 -3
- package/src/ui/docs/content/data-state.md +11 -12
- package/src/ui/docs/content/data.md +26 -33
- package/src/ui/docs/content/detail.md +22 -4
- package/src/ui/docs/content/dialog.md +339 -31
- package/src/ui/docs/content/dictionary-value.md +17 -10
- package/src/ui/docs/content/dock.md +11 -3
- package/src/ui/docs/content/dot.md +8 -0
- package/src/ui/docs/content/drawer.md +27 -14
- package/src/ui/docs/content/empty-value.md +2 -2
- package/src/ui/docs/content/empty.md +19 -12
- package/src/ui/docs/content/events.md +4 -4
- package/src/ui/docs/content/field.md +34 -12
- package/src/ui/docs/content/getting-started.md +3 -3
- package/src/ui/docs/content/icon-picker.md +19 -4
- package/src/ui/docs/content/input-otp.md +20 -12
- package/src/ui/docs/content/input.md +121 -9
- package/src/ui/docs/content/item.md +27 -13
- package/src/ui/docs/content/kbd.md +19 -11
- package/src/ui/docs/content/label.md +12 -3
- package/src/ui/docs/content/log.md +4 -4
- package/src/ui/docs/content/markdown.md +7 -6
- package/src/ui/docs/content/mcp.md +13 -15
- package/src/ui/docs/content/menu.md +40 -16
- package/src/ui/docs/content/metric-card.md +13 -0
- package/src/ui/docs/content/observability.md +2 -2
- package/src/ui/docs/content/page.md +59 -6
- package/src/ui/docs/content/pagination.md +22 -17
- package/src/ui/docs/content/popover.md +22 -8
- package/src/ui/docs/content/progress.md +15 -16
- package/src/ui/docs/content/queue.md +5 -5
- package/src/ui/docs/content/radio-group.md +20 -12
- package/src/ui/docs/content/router.md +11 -6
- package/src/ui/docs/content/scheduler.md +4 -5
- package/src/ui/docs/content/scroll-area.md +12 -7
- package/src/ui/docs/content/select.md +47 -34
- package/src/ui/docs/content/semantic-context.md +2 -2
- package/src/ui/docs/content/separator.md +5 -5
- package/src/ui/docs/content/sidebar.md +329 -54
- package/src/ui/docs/content/skeleton.md +9 -2
- package/src/ui/docs/content/slider.md +8 -7
- package/src/ui/docs/content/spinner.md +8 -8
- package/src/ui/docs/content/split.md +29 -5
- package/src/ui/docs/content/storage.md +6 -8
- package/src/ui/docs/content/switch.md +8 -7
- package/src/ui/docs/content/table.md +13 -3
- package/src/ui/docs/content/tabs.md +28 -14
- package/src/ui/docs/content/testing.md +9 -11
- package/src/ui/docs/content/textarea.md +12 -4
- package/src/ui/docs/content/toast.md +47 -13
- package/src/ui/docs/content/toggle.md +75 -7
- package/src/ui/docs/content/tokens.md +7 -7
- package/src/ui/docs/content/tooltip.md +19 -11
- package/src/ui/docs/content/truncate.md +15 -8
- package/src/ui/docs/content/ui.md +24 -9
- package/src/ui/docs/content/upgrading.md +7 -8
- package/src/ui/docs/doc-client.tsx +5 -5
- package/src/ui/docs/doc.tsx +26 -14
- package/src/ui/docs/registry.tsx +25 -42
- package/src/ui/docs/standalone.tsx +2 -2
- package/src/ui/drivers/react.tsx +17 -12
- package/src/ui/lib/action-errors.ts +45 -0
- package/src/ui/lib/zod-pt-br.ts +31 -4
- package/src/ui/meta.ts +65 -95
- package/src/ui/react.tsx +17 -16
- package/src/ui/theme.css +60 -8
- package/src/vite/design.ts +6 -18
- package/src/ui/components/primitives/alert-dialog.tsx +0 -192
- package/src/ui/docs/content/alert-dialog.md +0 -73
- package/src/ui/docs/content/button-group.md +0 -71
- package/src/ui/docs/content/confirm.md +0 -120
- package/src/ui/docs/content/input-group.md +0 -79
- package/src/ui/docs/content/page-state.md +0 -45
- package/src/ui/docs/content/toggle-group.md +0 -81
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ChevronLeftIcon,
|
|
5
5
|
ChevronRightIcon,
|
|
6
6
|
} from "lucide-react";
|
|
7
|
+
import { ptBR } from "date-fns/locale";
|
|
7
8
|
import {
|
|
8
9
|
DayPicker,
|
|
9
10
|
getDefaultClassNames,
|
|
@@ -13,12 +14,34 @@ import {
|
|
|
13
14
|
import { cn } from "../../lib/cn.ts";
|
|
14
15
|
import { Button, buttonVariants } from "./button.tsx";
|
|
15
16
|
|
|
17
|
+
/** Rótulos acessíveis da navegação em pt-BR — o react-day-picker só traduz nomes de mês e
|
|
18
|
+
* dia pelo `locale`; os aria-labels dos controles continuariam em inglês. */
|
|
19
|
+
const LABELS_PT_BR: NonNullable<React.ComponentProps<typeof DayPicker>["labels"]> = {
|
|
20
|
+
labelPrevious: () => "Mês anterior",
|
|
21
|
+
labelNext: () => "Próximo mês",
|
|
22
|
+
labelMonthDropdown: () => "Escolher o mês",
|
|
23
|
+
labelYearDropdown: () => "Escolher o ano",
|
|
24
|
+
labelDayButton: (date, modifiers, options) => {
|
|
25
|
+
const day = date.toLocaleDateString(options?.locale?.code ?? "pt-BR", {
|
|
26
|
+
weekday: "long",
|
|
27
|
+
day: "numeric",
|
|
28
|
+
month: "long",
|
|
29
|
+
year: "numeric",
|
|
30
|
+
});
|
|
31
|
+
const prefix = modifiers.today ? "Hoje, " : "";
|
|
32
|
+
const suffix = modifiers.selected ? ", selecionado" : "";
|
|
33
|
+
return `${prefix}${day}${suffix}`;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
16
37
|
function Calendar({
|
|
17
38
|
className,
|
|
18
39
|
classNames,
|
|
19
40
|
showOutsideDays = true,
|
|
20
41
|
captionLayout = "label",
|
|
21
42
|
buttonVariant = "ghost",
|
|
43
|
+
locale = ptBR,
|
|
44
|
+
labels,
|
|
22
45
|
formatters,
|
|
23
46
|
components,
|
|
24
47
|
...props
|
|
@@ -30,6 +53,8 @@ function Calendar({
|
|
|
30
53
|
return (
|
|
31
54
|
<DayPicker
|
|
32
55
|
showOutsideDays={showOutsideDays}
|
|
56
|
+
locale={locale}
|
|
57
|
+
labels={{ ...LABELS_PT_BR, ...labels }}
|
|
33
58
|
className={cn(
|
|
34
59
|
"group/calendar bg-background p-3 [--cell-size:--spacing(8)] [[data-slot=card-body]_&]:bg-transparent [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
|
|
35
60
|
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
|
@@ -38,8 +63,9 @@ function Calendar({
|
|
|
38
63
|
)}
|
|
39
64
|
captionLayout={captionLayout}
|
|
40
65
|
formatters={{
|
|
41
|
-
|
|
42
|
-
|
|
66
|
+
// O dateLib já carrega o `locale` em vigor: o dropdown fala a mesma língua da legenda.
|
|
67
|
+
formatMonthDropdown: (date, dateLib) =>
|
|
68
|
+
dateLib?.format(date, "LLL") ?? date.toLocaleString("pt-BR", { month: "short" }),
|
|
43
69
|
...formatters,
|
|
44
70
|
}}
|
|
45
71
|
classNames={{
|
|
@@ -120,7 +120,7 @@ function Carousel({
|
|
|
120
120
|
onKeyDownCapture={handleKeyDown}
|
|
121
121
|
className={cn("relative", className)}
|
|
122
122
|
role="region"
|
|
123
|
-
aria-roledescription="
|
|
123
|
+
aria-roledescription="carrossel"
|
|
124
124
|
data-slot="carousel"
|
|
125
125
|
{...props}
|
|
126
126
|
>
|
|
@@ -194,7 +194,7 @@ function CarouselPrevious({
|
|
|
194
194
|
{...props}
|
|
195
195
|
>
|
|
196
196
|
<ArrowLeft />
|
|
197
|
-
<span className="sr-only">
|
|
197
|
+
<span className="sr-only">Slide anterior</span>
|
|
198
198
|
</Button>
|
|
199
199
|
)
|
|
200
200
|
}
|
|
@@ -224,7 +224,7 @@ function CarouselNext({
|
|
|
224
224
|
{...props}
|
|
225
225
|
>
|
|
226
226
|
<ArrowRight />
|
|
227
|
-
<span className="sr-only">
|
|
227
|
+
<span className="sr-only">Próximo slide</span>
|
|
228
228
|
</Button>
|
|
229
229
|
)
|
|
230
230
|
}
|
|
@@ -193,7 +193,7 @@ const ChatTranscript = React.memo(function ChatTranscript({
|
|
|
193
193
|
return (
|
|
194
194
|
<div
|
|
195
195
|
key={i}
|
|
196
|
-
className="max-w-[88%] self-start rounded-xl border border-
|
|
196
|
+
className="max-w-[88%] self-start rounded-xl border border-context-danger-border bg-context-danger-subtle px-3.5 py-2.5 text-sm text-context-danger-emphasis"
|
|
197
197
|
>
|
|
198
198
|
{item.content}
|
|
199
199
|
</div>
|
|
@@ -12,7 +12,7 @@ function Checkbox({
|
|
|
12
12
|
<CheckboxPrimitive.Root
|
|
13
13
|
data-slot="checkbox"
|
|
14
14
|
className={cn(
|
|
15
|
-
"peer size-4 shrink-0 rounded-[0.25rem] border border-input transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[0.1875rem] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-
|
|
15
|
+
"peer size-4 shrink-0 rounded-[0.25rem] border border-input transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[0.1875rem] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-context-danger aria-invalid:ring-context-danger/20 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:bg-input/30 dark:aria-invalid:ring-context-danger/40 dark:data-[state=checked]:bg-primary",
|
|
16
16
|
className
|
|
17
17
|
)}
|
|
18
18
|
{...props}
|
|
@@ -28,8 +28,8 @@ function Command({
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function CommandDialog({
|
|
31
|
-
title = "
|
|
32
|
-
description = "
|
|
31
|
+
title = "Paleta de comandos",
|
|
32
|
+
description = "Busque um comando para executar…",
|
|
33
33
|
children,
|
|
34
34
|
className,
|
|
35
35
|
showCloseButton = true,
|
|
@@ -1,2 +1,14 @@
|
|
|
1
1
|
/** Geometria compartilhada pelos controles inline da casa. */
|
|
2
2
|
export type ControlShape = 'default' | 'pill'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Anel de foco da casa: fino (0.1875rem), translúcido e encostado na borda — sem offset.
|
|
6
|
+
* Todo controle focável usa esta constante; espessuras próprias (`ring-2`, `ring-4`) ou
|
|
7
|
+
* `ring-offset-*` quebram a leitura de "foco" que o tema calibrou (ver theme.css, `--ring`).
|
|
8
|
+
*/
|
|
9
|
+
export const focusRing =
|
|
10
|
+
'focus-visible:border-ring focus-visible:ring-[0.1875rem] focus-visible:ring-ring/50'
|
|
11
|
+
|
|
12
|
+
/** O mesmo anel, disparado por um descendente focado (grupos que envolvem um campo). */
|
|
13
|
+
export const focusRingWithin =
|
|
14
|
+
'focus-within:border-ring focus-within:ring-[0.1875rem] focus-within:ring-ring/50'
|
|
@@ -44,7 +44,7 @@ export function Copyable({
|
|
|
44
44
|
{...props}
|
|
45
45
|
>
|
|
46
46
|
{children}
|
|
47
|
-
{copied ? <CheckIcon className="size-3.5 text-
|
|
47
|
+
{copied ? <CheckIcon className="size-3.5 text-context-success-emphasis" /> : <CopyIcon className="size-3.5" />}
|
|
48
48
|
</button>
|
|
49
49
|
)
|
|
50
50
|
}
|
|
@@ -1,35 +1,136 @@
|
|
|
1
1
|
import * as React from 'react'
|
|
2
2
|
import * as DialogPrimitive from '@radix-ui/react-dialog'
|
|
3
|
+
import { AlertDialog as AlertDialogPrimitive } from 'radix-ui'
|
|
3
4
|
import { XIcon } from 'lucide-react'
|
|
4
5
|
import { cn } from '../../lib/cn.ts'
|
|
6
|
+
import { focusRing } from './control.ts'
|
|
5
7
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
+
export type DialogMode = 'default' | 'alert'
|
|
9
|
+
|
|
10
|
+
interface DialogContextValue {
|
|
11
|
+
mode: DialogMode
|
|
12
|
+
onResult?: (result: string) => void
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const DialogContext = React.createContext<DialogContextValue>({ mode: 'default' })
|
|
16
|
+
|
|
17
|
+
function useDialogContext(): DialogContextValue {
|
|
18
|
+
return React.useContext(DialogContext)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface DialogProps
|
|
22
|
+
extends React.ComponentProps<typeof DialogPrimitive.Root> {
|
|
23
|
+
/** `alert` exige uma resposta explícita e deriva `role="alertdialog"`. */
|
|
24
|
+
mode?: DialogMode
|
|
25
|
+
/** Recebe o `result` do `DialogClose` acionado. */
|
|
26
|
+
onResult?: (result: string) => void
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function Dialog({
|
|
30
|
+
mode = 'default',
|
|
31
|
+
onResult,
|
|
32
|
+
modal,
|
|
33
|
+
...props
|
|
34
|
+
}: DialogProps) {
|
|
35
|
+
const context = React.useMemo(() => ({ mode, onResult }), [mode, onResult])
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<DialogContext.Provider value={context}>
|
|
39
|
+
{mode === 'alert' ? (
|
|
40
|
+
<AlertDialogPrimitive.Root data-slot="dialog" {...props} />
|
|
41
|
+
) : (
|
|
42
|
+
<DialogPrimitive.Root data-slot="dialog" modal={modal} {...props} />
|
|
43
|
+
)}
|
|
44
|
+
</DialogContext.Provider>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function DialogTrigger({
|
|
49
|
+
...props
|
|
50
|
+
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
51
|
+
const { mode } = useDialogContext()
|
|
52
|
+
return mode === 'alert' ? (
|
|
53
|
+
<AlertDialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
54
|
+
) : (
|
|
55
|
+
<DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
56
|
+
)
|
|
8
57
|
}
|
|
9
58
|
|
|
10
|
-
export function
|
|
11
|
-
|
|
59
|
+
export function DialogPortal({
|
|
60
|
+
...props
|
|
61
|
+
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
62
|
+
const { mode } = useDialogContext()
|
|
63
|
+
return mode === 'alert' ? (
|
|
64
|
+
<AlertDialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
|
65
|
+
) : (
|
|
66
|
+
<DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
|
67
|
+
)
|
|
12
68
|
}
|
|
13
69
|
|
|
14
|
-
export
|
|
15
|
-
|
|
70
|
+
export interface DialogCloseProps
|
|
71
|
+
extends React.ComponentProps<typeof DialogPrimitive.Close> {
|
|
72
|
+
/** No modo `alert`, registra este controle como destino inicial seguro do foco. */
|
|
73
|
+
initialFocus?: boolean
|
|
74
|
+
/** Resposta entregue a `Dialog.onResult` antes do fechamento. */
|
|
75
|
+
result?: string
|
|
16
76
|
}
|
|
17
77
|
|
|
18
|
-
export function DialogClose({
|
|
19
|
-
|
|
78
|
+
export function DialogClose({
|
|
79
|
+
initialFocus = false,
|
|
80
|
+
result,
|
|
81
|
+
onClick,
|
|
82
|
+
...props
|
|
83
|
+
}: DialogCloseProps) {
|
|
84
|
+
const root = useDialogContext()
|
|
85
|
+
const handleClick: React.MouseEventHandler<HTMLButtonElement> = (event) => {
|
|
86
|
+
onClick?.(event)
|
|
87
|
+
if (!event.defaultPrevented && result !== undefined) root.onResult?.(result)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (root.mode === 'alert') {
|
|
91
|
+
const ClosePrimitive = initialFocus
|
|
92
|
+
? AlertDialogPrimitive.Cancel
|
|
93
|
+
: AlertDialogPrimitive.Action
|
|
94
|
+
return (
|
|
95
|
+
<ClosePrimitive
|
|
96
|
+
data-slot="dialog-close"
|
|
97
|
+
data-initial-focus={initialFocus || undefined}
|
|
98
|
+
onClick={handleClick}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<DialogPrimitive.Close
|
|
106
|
+
data-slot="dialog-close"
|
|
107
|
+
data-initial-focus={initialFocus || undefined}
|
|
108
|
+
onClick={handleClick}
|
|
109
|
+
{...props}
|
|
110
|
+
/>
|
|
111
|
+
)
|
|
20
112
|
}
|
|
21
113
|
|
|
114
|
+
/** Véu compartilhado por Dialog e Drawer: mesmo escurecimento, desfoque e animação. */
|
|
115
|
+
export const overlayClasses =
|
|
116
|
+
'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
|
+
|
|
22
118
|
export function DialogOverlay({
|
|
23
119
|
className,
|
|
24
120
|
...props
|
|
25
121
|
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
26
|
-
|
|
122
|
+
const { mode } = useDialogContext()
|
|
123
|
+
const overlay = cn(overlayClasses, className)
|
|
124
|
+
return mode === 'alert' ? (
|
|
125
|
+
<AlertDialogPrimitive.Overlay
|
|
126
|
+
data-slot="dialog-overlay"
|
|
127
|
+
className={overlay}
|
|
128
|
+
{...props}
|
|
129
|
+
/>
|
|
130
|
+
) : (
|
|
27
131
|
<DialogPrimitive.Overlay
|
|
28
132
|
data-slot="dialog-overlay"
|
|
29
|
-
className={
|
|
30
|
-
'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',
|
|
31
|
-
className,
|
|
32
|
-
)}
|
|
133
|
+
className={overlay}
|
|
33
134
|
{...props}
|
|
34
135
|
/>
|
|
35
136
|
)
|
|
@@ -38,32 +139,54 @@ export function DialogOverlay({
|
|
|
38
139
|
export function DialogContent({
|
|
39
140
|
className,
|
|
40
141
|
children,
|
|
41
|
-
showCloseButton
|
|
142
|
+
showCloseButton,
|
|
42
143
|
...props
|
|
43
144
|
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
44
|
-
/** Mostra o
|
|
145
|
+
/** Mostra o “X” no modo padrão. O modo `alert` exige uma resposta identificável. */
|
|
45
146
|
showCloseButton?: boolean
|
|
46
147
|
}) {
|
|
148
|
+
const { mode } = useDialogContext()
|
|
149
|
+
const showClose = showCloseButton ?? mode !== 'alert'
|
|
150
|
+
const contentClasses =
|
|
151
|
+
'fixed left-[50%] top-[50%] z-50 w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] overflow-clip rounded-xl border border-border bg-background text-foreground shadow-lg duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95'
|
|
152
|
+
|
|
153
|
+
if (mode === 'alert') {
|
|
154
|
+
return (
|
|
155
|
+
<DialogPortal>
|
|
156
|
+
<DialogOverlay />
|
|
157
|
+
<AlertDialogPrimitive.Content
|
|
158
|
+
data-slot="dialog-content"
|
|
159
|
+
data-mode="alert"
|
|
160
|
+
className={cn(contentClasses, 'grid max-w-xs gap-4 p-6', className)}
|
|
161
|
+
{...props}
|
|
162
|
+
>
|
|
163
|
+
{children}
|
|
164
|
+
</AlertDialogPrimitive.Content>
|
|
165
|
+
</DialogPortal>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
47
169
|
return (
|
|
48
170
|
<DialogPortal>
|
|
49
171
|
<DialogOverlay />
|
|
50
|
-
{/* Superfície elevada: mantemos bg-card (divergência da casa; o shadcn usa bg-background). */}
|
|
51
172
|
<DialogPrimitive.Content
|
|
52
173
|
data-slot="dialog-content"
|
|
174
|
+
data-mode="default"
|
|
53
175
|
className={cn(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// precisa negar margem pra escapar de um p-6 embutido.
|
|
57
|
-
"fixed left-[50%] top-[50%] z-50 flex max-h-[85vh] w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] flex-col overflow-clip rounded-xl bg-card text-card-foreground shadow-lg duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg",
|
|
176
|
+
contentClasses,
|
|
177
|
+
'flex max-h-[85vh] flex-col sm:max-w-lg',
|
|
58
178
|
className,
|
|
59
179
|
)}
|
|
60
180
|
{...props}
|
|
61
181
|
>
|
|
62
182
|
{children}
|
|
63
|
-
{
|
|
183
|
+
{showClose && (
|
|
64
184
|
<DialogPrimitive.Close
|
|
65
185
|
data-slot="dialog-close"
|
|
66
|
-
className=
|
|
186
|
+
className={cn(
|
|
187
|
+
"absolute right-4 top-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-hidden disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
188
|
+
focusRing,
|
|
189
|
+
)}
|
|
67
190
|
>
|
|
68
191
|
<XIcon />
|
|
69
192
|
<span className="sr-only">Fechar</span>
|
|
@@ -74,17 +197,18 @@ export function DialogContent({
|
|
|
74
197
|
)
|
|
75
198
|
}
|
|
76
199
|
|
|
77
|
-
export function DialogHeader({
|
|
200
|
+
export function DialogHeader({
|
|
201
|
+
className,
|
|
202
|
+
...props
|
|
203
|
+
}: React.ComponentProps<'div'>) {
|
|
204
|
+
const { mode } = useDialogContext()
|
|
78
205
|
return (
|
|
79
206
|
<div
|
|
80
207
|
data-slot="dialog-header"
|
|
81
|
-
// Fixo (shrink-0), com divisor embaixo (border-b). p-5: padding igual nos quatro
|
|
82
|
-
// lados, casando com o body. O :has tira o divisor quando o header é seguido
|
|
83
|
-
// DIRETO pelo footer (confirm sem body) — senão o border-b dele encostaria no
|
|
84
|
-
// A compensação coincide com a soma das hairlines; o divisor fica no footer.
|
|
85
208
|
className={cn(
|
|
86
|
-
|
|
87
|
-
|
|
209
|
+
mode === 'alert'
|
|
210
|
+
? 'grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=dialog-media]:grid-rows-[auto_auto_1fr]'
|
|
211
|
+
: 'flex shrink-0 flex-col gap-2 border-b p-5 text-center sm:text-left [&:has(+[data-slot=dialog-footer])]:border-b-0',
|
|
88
212
|
className,
|
|
89
213
|
)}
|
|
90
214
|
{...props}
|
|
@@ -92,27 +216,51 @@ export function DialogHeader({ className, ...props }: React.ComponentProps<'div'
|
|
|
92
216
|
)
|
|
93
217
|
}
|
|
94
218
|
|
|
95
|
-
export function
|
|
219
|
+
export function DialogMedia({
|
|
220
|
+
className,
|
|
221
|
+
...props
|
|
222
|
+
}: React.ComponentProps<'div'>) {
|
|
223
|
+
return (
|
|
224
|
+
<div
|
|
225
|
+
data-slot="dialog-media"
|
|
226
|
+
className={cn(
|
|
227
|
+
'mb-2 inline-flex size-16 items-center justify-center rounded-md bg-muted *:[svg:not([class*="size-"])]:size-8',
|
|
228
|
+
className,
|
|
229
|
+
)}
|
|
230
|
+
{...props}
|
|
231
|
+
/>
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function DialogBody({
|
|
236
|
+
className,
|
|
237
|
+
...props
|
|
238
|
+
}: React.ComponentProps<'div'>) {
|
|
239
|
+
const { mode } = useDialogContext()
|
|
96
240
|
return (
|
|
97
241
|
<div
|
|
98
242
|
data-slot="dialog-body"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
243
|
+
className={cn(
|
|
244
|
+
mode === 'alert' ? 'min-w-0' : 'min-h-0 flex-1 overflow-y-auto p-5',
|
|
245
|
+
className,
|
|
246
|
+
)}
|
|
102
247
|
{...props}
|
|
103
248
|
/>
|
|
104
249
|
)
|
|
105
250
|
}
|
|
106
251
|
|
|
107
|
-
export function DialogFooter({
|
|
252
|
+
export function DialogFooter({
|
|
253
|
+
className,
|
|
254
|
+
...props
|
|
255
|
+
}: React.ComponentProps<'div'>) {
|
|
256
|
+
const { mode } = useDialogContext()
|
|
108
257
|
return (
|
|
109
258
|
<div
|
|
110
259
|
data-slot="dialog-footer"
|
|
111
|
-
// Faixa destacada (divergência da casa, ao estilo do site do shadcn): borda em cima
|
|
112
|
-
// + fundo muted. Sangra até as bordas sozinha — o content não tem padding, então não
|
|
113
|
-
// há -mx pra compensar; o recorte do content arredonda o canto de baixo.
|
|
114
260
|
className={cn(
|
|
115
|
-
|
|
261
|
+
mode === 'alert'
|
|
262
|
+
? 'grid grid-cols-2 gap-2 [&>*:only-child]:col-span-full'
|
|
263
|
+
: 'flex shrink-0 flex-col-reverse gap-2 border-t bg-muted/30 px-5 py-4 sm:flex-row sm:justify-end',
|
|
116
264
|
className,
|
|
117
265
|
)}
|
|
118
266
|
{...props}
|
|
@@ -124,7 +272,14 @@ export function DialogTitle({
|
|
|
124
272
|
className,
|
|
125
273
|
...props
|
|
126
274
|
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
127
|
-
|
|
275
|
+
const { mode } = useDialogContext()
|
|
276
|
+
return mode === 'alert' ? (
|
|
277
|
+
<AlertDialogPrimitive.Title
|
|
278
|
+
data-slot="dialog-title"
|
|
279
|
+
className={cn('text-lg font-semibold', className)}
|
|
280
|
+
{...props}
|
|
281
|
+
/>
|
|
282
|
+
) : (
|
|
128
283
|
<DialogPrimitive.Title
|
|
129
284
|
data-slot="dialog-title"
|
|
130
285
|
className={cn('text-lg font-semibold leading-none', className)}
|
|
@@ -137,7 +292,14 @@ export function DialogDescription({
|
|
|
137
292
|
className,
|
|
138
293
|
...props
|
|
139
294
|
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
140
|
-
|
|
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
|
+
) : (
|
|
141
303
|
<DialogPrimitive.Description
|
|
142
304
|
data-slot="dialog-description"
|
|
143
305
|
className={cn('text-sm text-muted-foreground', className)}
|
|
@@ -5,6 +5,11 @@ import { cn } from '../../lib/cn.ts'
|
|
|
5
5
|
|
|
6
6
|
export type DotContext = UiContext
|
|
7
7
|
export type DotVariant = 'solid' | 'outline'
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated Aliases de migração: `default` → `context="primary"`, `secondary` →
|
|
10
|
+
* `context="neutral"`, `destructive` → `context="danger"`; `success`, `warning` e `info` → o
|
|
11
|
+
* `context` homônimo. Declare `context` + `variant`.
|
|
12
|
+
*/
|
|
8
13
|
export type LegacyDotVariant =
|
|
9
14
|
| 'default'
|
|
10
15
|
| 'secondary'
|
|
@@ -3,6 +3,8 @@ import { XIcon } from "lucide-react";
|
|
|
3
3
|
import { Dialog as DrawerPrimitive } from "radix-ui";
|
|
4
4
|
|
|
5
5
|
import { cn } from "../../lib/cn.ts";
|
|
6
|
+
import { focusRing } from "./control.ts";
|
|
7
|
+
import { overlayClasses } from "./dialog.tsx";
|
|
6
8
|
|
|
7
9
|
function Drawer({
|
|
8
10
|
...props
|
|
@@ -36,7 +38,7 @@ function DrawerOverlay({
|
|
|
36
38
|
<DrawerPrimitive.Overlay
|
|
37
39
|
data-slot="drawer-overlay"
|
|
38
40
|
className={cn(
|
|
39
|
-
|
|
41
|
+
overlayClasses,
|
|
40
42
|
className,
|
|
41
43
|
)}
|
|
42
44
|
{...props}
|
|
@@ -60,7 +62,7 @@ function DrawerContent({
|
|
|
60
62
|
<DrawerPrimitive.Content
|
|
61
63
|
data-slot="drawer-content"
|
|
62
64
|
className={cn(
|
|
63
|
-
"fixed z-50 flex flex-col
|
|
65
|
+
"fixed z-50 flex flex-col bg-background shadow-lg transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500",
|
|
64
66
|
side === "right" &&
|
|
65
67
|
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
|
|
66
68
|
side === "left" &&
|
|
@@ -75,9 +77,14 @@ function DrawerContent({
|
|
|
75
77
|
>
|
|
76
78
|
{children}
|
|
77
79
|
{showCloseButton && (
|
|
78
|
-
<DrawerPrimitive.Close
|
|
80
|
+
<DrawerPrimitive.Close
|
|
81
|
+
className={cn(
|
|
82
|
+
"absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-hidden disabled:pointer-events-none data-[state=open]:bg-secondary",
|
|
83
|
+
focusRing,
|
|
84
|
+
)}
|
|
85
|
+
>
|
|
79
86
|
<XIcon className="size-4" />
|
|
80
|
-
<span className="sr-only">
|
|
87
|
+
<span className="sr-only">Fechar</span>
|
|
81
88
|
</DrawerPrimitive.Close>
|
|
82
89
|
)}
|
|
83
90
|
</DrawerPrimitive.Content>
|
|
@@ -89,7 +96,7 @@ function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
89
96
|
return (
|
|
90
97
|
<div
|
|
91
98
|
data-slot="drawer-header"
|
|
92
|
-
className={cn("flex flex-col gap-
|
|
99
|
+
className={cn("flex shrink-0 flex-col gap-2 border-b p-5", className)}
|
|
93
100
|
{...props}
|
|
94
101
|
/>
|
|
95
102
|
);
|
|
@@ -99,7 +106,7 @@ function DrawerBody({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
99
106
|
return (
|
|
100
107
|
<div
|
|
101
108
|
data-slot="drawer-body"
|
|
102
|
-
className={cn("min-h-0 flex-1 overflow-y-auto p-
|
|
109
|
+
className={cn("min-h-0 flex-1 overflow-y-auto p-5", className)}
|
|
103
110
|
{...props}
|
|
104
111
|
/>
|
|
105
112
|
);
|
|
@@ -109,7 +116,10 @@ function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
109
116
|
return (
|
|
110
117
|
<div
|
|
111
118
|
data-slot="drawer-footer"
|
|
112
|
-
className={cn(
|
|
119
|
+
className={cn(
|
|
120
|
+
"mt-auto flex shrink-0 flex-col-reverse gap-2 border-t bg-muted/30 px-5 py-4 sm:flex-row sm:justify-end",
|
|
121
|
+
className,
|
|
122
|
+
)}
|
|
113
123
|
{...props}
|
|
114
124
|
/>
|
|
115
125
|
);
|
|
@@ -122,7 +132,7 @@ function DrawerTitle({
|
|
|
122
132
|
return (
|
|
123
133
|
<DrawerPrimitive.Title
|
|
124
134
|
data-slot="drawer-title"
|
|
125
|
-
className={cn("font-semibold text-foreground", className)}
|
|
135
|
+
className={cn("text-lg font-semibold leading-none text-foreground", className)}
|
|
126
136
|
{...props}
|
|
127
137
|
/>
|
|
128
138
|
);
|
|
@@ -81,10 +81,10 @@ function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
|
|
|
81
81
|
)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
function
|
|
84
|
+
function EmptyActions({ className, ...props }: React.ComponentProps<"div">) {
|
|
85
85
|
return (
|
|
86
86
|
<div
|
|
87
|
-
data-slot="empty-
|
|
87
|
+
data-slot="empty-actions"
|
|
88
88
|
className={cn(
|
|
89
89
|
"flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance",
|
|
90
90
|
className
|
|
@@ -99,6 +99,6 @@ export {
|
|
|
99
99
|
EmptyHeader,
|
|
100
100
|
EmptyTitle,
|
|
101
101
|
EmptyDescription,
|
|
102
|
-
|
|
102
|
+
EmptyActions,
|
|
103
103
|
EmptyMedia,
|
|
104
104
|
}
|
|
@@ -53,7 +53,7 @@ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
const fieldVariants = cva(
|
|
56
|
-
"group/field flex w-full data-[invalid=true]:text-
|
|
56
|
+
"group/field flex w-full data-[invalid=true]:text-context-danger-emphasis",
|
|
57
57
|
{
|
|
58
58
|
variants: {
|
|
59
59
|
orientation: {
|
|
@@ -113,7 +113,7 @@ function FieldLabel({
|
|
|
113
113
|
<Label
|
|
114
114
|
data-slot="field-label"
|
|
115
115
|
className={cn(
|
|
116
|
-
"group/field-label peer/field-label flex w-fit gap-2 text-xs leading-snug font-medium text-muted-foreground group-data-[invalid=true]/field:text-
|
|
116
|
+
"group/field-label peer/field-label flex w-fit gap-2 text-xs leading-snug font-medium text-muted-foreground group-data-[invalid=true]/field:text-context-danger-emphasis group-data-[disabled=true]/field:opacity-50",
|
|
117
117
|
"has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-4",
|
|
118
118
|
"has-[>[data-slot=field]]:has-data-[state=checked]:border-primary has-[>[data-slot=field]]:has-data-[state=checked]:bg-primary/5 dark:has-[>[data-slot=field]]:has-data-[state=checked]:bg-primary/10",
|
|
119
119
|
className
|
|
@@ -224,7 +224,7 @@ function FieldError({
|
|
|
224
224
|
<div
|
|
225
225
|
role="alert"
|
|
226
226
|
data-slot="field-error"
|
|
227
|
-
className={cn("text-sm font-normal text-
|
|
227
|
+
className={cn("text-sm font-normal text-context-danger-emphasis", className)}
|
|
228
228
|
{...props}
|
|
229
229
|
>
|
|
230
230
|
{content}
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
type LucideIcon,
|
|
47
47
|
} from 'lucide-react'
|
|
48
48
|
import { cn } from '../../lib/cn.ts'
|
|
49
|
+
import { focusRing } from './control.ts'
|
|
49
50
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from './command.tsx'
|
|
50
51
|
import { Popover, PopoverContent, PopoverTrigger } from './popover.tsx'
|
|
51
52
|
|
|
@@ -141,7 +142,8 @@ export function IconPicker({
|
|
|
141
142
|
aria-describedby={ariaDescribedBy}
|
|
142
143
|
data-slot="icon-picker"
|
|
143
144
|
className={cn(
|
|
144
|
-
'flex h-10 w-full items-center gap-2 rounded-md border border-input bg-transparent px-3 text-sm outline-none transition-[color,box-shadow]
|
|
145
|
+
'flex h-10 w-full items-center gap-2 rounded-md border border-input bg-transparent px-3 text-sm outline-none transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50 dark:bg-input/30',
|
|
146
|
+
focusRing,
|
|
145
147
|
className,
|
|
146
148
|
)}
|
|
147
149
|
>
|
|
@@ -27,7 +27,7 @@ function InputGroup({ className, shape = 'default', ...props }: React.ComponentP
|
|
|
27
27
|
"has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-[0.1875rem] has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50",
|
|
28
28
|
|
|
29
29
|
// Error state.
|
|
30
|
-
"has-[[data-slot][aria-invalid=true]]:border-
|
|
30
|
+
"has-[[data-slot][aria-invalid=true]]:border-context-danger has-[[data-slot][aria-invalid=true]]:ring-context-danger/20 dark:has-[[data-slot][aria-invalid=true]]:ring-context-danger/40",
|
|
31
31
|
|
|
32
32
|
className
|
|
33
33
|
)}
|
|
@@ -49,7 +49,7 @@ function InputOTPSlot({
|
|
|
49
49
|
data-slot="input-otp-slot"
|
|
50
50
|
data-active={isActive}
|
|
51
51
|
className={cn(
|
|
52
|
-
"relative flex h-9 w-9 items-center justify-center border-y border-r border-input text-sm transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md aria-invalid:border-
|
|
52
|
+
"relative flex h-9 w-9 items-center justify-center border-y border-r border-input text-sm transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md aria-invalid:border-context-danger data-[active=true]:z-10 data-[active=true]:border-ring data-[active=true]:ring-[0.1875rem] data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-context-danger data-[active=true]:aria-invalid:ring-context-danger/20 dark:bg-input/30 dark:data-[active=true]:aria-invalid:ring-context-danger/40",
|
|
53
53
|
className
|
|
54
54
|
)}
|
|
55
55
|
{...props}
|