mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix(ui): unify overlays to shared z-50 tier, stack by portal order
All default-portalled overlays (Dialog, Popover, DropdownMenu, ContextMenu, Select) now share z-50, with stacking determined by portal mount order. This fixes resource popovers covering confirm dialogs opened from them. Exceptions: - Tooltip at z-90 (pointer-events-none, must stay readable) - Tours at z-70 (pointer-events-none spotlight) - Onboarding at z-100 (full-screen with private z-110–z-150 ladder) Preemptive modals keep z-140/z-150 to clear onboarding. Updated STYLEGUIDE.md with new policy.
This commit is contained in:
@@ -106,6 +106,20 @@ Orca uses shadows sparingly. Three levels in practice:
|
||||
|
||||
Don't add a fourth level. If something needs more emphasis than "floating," you're probably reaching for the focus `ring` instead.
|
||||
|
||||
### Overlay z-order
|
||||
|
||||
Every default-portalled overlay — modal (`Dialog`, `Sheet`, command palette) and non-modal (`Popover`, `DropdownMenu`, `ContextMenu`, `Select`, `HoverCard`) — sits on one `z-50` tier, and stacking follows portal mount order: whatever mounts last paints on top. A confirm opened from a popover covers it; a picker opened from a dialog covers that. Ranked tiers cannot express this, because the two directions need opposite orders — so don't reintroduce per-layer gaps (`z-[60]`/`z-[70]`) or per-instance escalations to clear a sibling overlay. Components using a custom portal container own that container's stacking context.
|
||||
|
||||
Three deliberate exceptions to that shared tier:
|
||||
|
||||
- `Tooltip` at `z-[90]` — `pointer-events-none`, so it never blocks anything and must stay readable over whatever it describes. Don't override it per instance outside the onboarding ladder.
|
||||
- Contextual tours at `z-[70]` — a `pointer-events-none` spotlight that has to be visible over the very surface it points at. Its `z-[75]` rings and `z-[80]` panel are scoped inside their own stacking context, so they claim no global level.
|
||||
- The onboarding flow at `z-[100]`, an inline full-screen overlay that portalled content cannot reach. Its surfaces climb a private `z-[110]`–`z-[150]` ladder, and the two preemptive prompts that must interrupt onboarding (`SshPassphraseDialog`, `link-routing-preference-dialog`) top it out at `!z-[140]`/`!z-[150]`.
|
||||
|
||||
Separately, a few transient full-screen layers sit above everything by design — the recent-tab switcher, drag ghosts, and the sidebar-resize capture shim. They are momentary and mostly `pointer-events-none`, so they never participate in overlay stacking.
|
||||
|
||||
Outside those cases, a value above `z-50` is a smell: it pins a surface above the shared tier, so anything opened _from_ it renders behind it. Any new one must name the surface it clears in a `Why` comment.
|
||||
|
||||
## Components
|
||||
|
||||
Use the shadcn primitives in `src/renderer/src/components/ui/` before writing anything custom. The shadcn-style wrappers in this folder follow a consistent pattern:
|
||||
|
||||
@@ -103,7 +103,7 @@ function AgentDefaultContextMenu({
|
||||
return (
|
||||
<ContextMenu>
|
||||
<ContextMenuTrigger asChild>{children}</ContextMenuTrigger>
|
||||
<ContextMenuContent className="z-[70]">
|
||||
<ContextMenuContent>
|
||||
<ContextMenuItem onSelect={onSetDefault} disabled={isDefault}>
|
||||
<Star className="size-3.5" />
|
||||
{isDefault
|
||||
@@ -139,8 +139,6 @@ function renderItem({
|
||||
</CommandItem>
|
||||
)
|
||||
return (
|
||||
// Why: z-[70] sits above PopoverContent's z-[60] so the right-click menu
|
||||
// renders in front of the still-open combobox popover instead of behind it.
|
||||
<AgentDefaultContextMenu key={key} isDefault={isDefault} onSetDefault={onSetDefault}>
|
||||
{row}
|
||||
</AgentDefaultContextMenu>
|
||||
|
||||
@@ -126,6 +126,8 @@ export function LinkRoutingPreferenceDialogProvider({
|
||||
open={activeRequest !== null}
|
||||
onOpenChange={(open) => !open && settleActiveRequest(false)}
|
||||
>
|
||||
{/* Why: a terminal link can fire mid-onboarding, so this prompt must clear
|
||||
the onboarding overlay (z-100) rather than the default dialog z-50. */}
|
||||
<DialogContent
|
||||
showCloseButton={false}
|
||||
overlayClassName="!z-[140]"
|
||||
|
||||
@@ -112,8 +112,8 @@ export function SshPassphraseDialog(): React.JSX.Element | null {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={(isOpen) => !isOpen && void handleCancel()}>
|
||||
{/* Why: a credential prompt is a preemptive modal that must sit above any
|
||||
open popover/menu (popover z-60, menus z-70) — the default dialog z-50
|
||||
would let a still-open picker cover the focused input. */}
|
||||
open surface — including the onboarding overlay (z-100) — so it keeps
|
||||
its elevated tier instead of the default dialog z-50. */}
|
||||
<DialogContent
|
||||
showCloseButton={false}
|
||||
overlayClassName="!z-[140]"
|
||||
|
||||
@@ -249,8 +249,6 @@ export function JiraIntegrationCard(): React.JSX.Element {
|
||||
open={dialogOpen}
|
||||
onOpenChange={setDialogOpen}
|
||||
onConnected={() => setTestResultBySite({})}
|
||||
overlayClassName="z-[110]"
|
||||
contentClassName="z-[120]"
|
||||
/>
|
||||
</IntegrationCardShell>
|
||||
)
|
||||
|
||||
@@ -221,8 +221,6 @@ export function LinearIntegrationCard(): React.JSX.Element {
|
||||
onOpenChange={setDialogOpen}
|
||||
connectLabel="Add Linear access"
|
||||
onConnected={() => setTestResultByWorkspace({})}
|
||||
overlayClassName="z-[110]"
|
||||
contentClassName="z-[120]"
|
||||
/>
|
||||
</IntegrationCardShell>
|
||||
)
|
||||
|
||||
@@ -57,6 +57,7 @@ export default function WorkspaceStatusAppearancePopover({
|
||||
align="end"
|
||||
side="left"
|
||||
sideOffset={8}
|
||||
// Why: the board keeps this picker above its sheet-local surface.
|
||||
className="z-[80] w-72 p-2"
|
||||
data-workspace-status-appearance-popover=""
|
||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||
|
||||
@@ -147,9 +147,9 @@ export function UsagePercentageDisplayChangeNotice({
|
||||
? createPortal(
|
||||
<div
|
||||
role="status"
|
||||
// Why: dropdowns/context menus use z-[70]; this callout must sit
|
||||
// under them so status-bar provider menus stay clickable.
|
||||
className="status-bar-change-notice-card fixed z-[50] w-[320px] max-w-[calc(100vw-16px)] rounded-lg p-3.5"
|
||||
// Why: stays on the shared z-50 tier so a status-bar menu opened over
|
||||
// this callout still portals above it and stays clickable.
|
||||
className="status-bar-change-notice-card fixed z-50 w-[320px] max-w-[calc(100vw-16px)] rounded-lg p-3.5"
|
||||
style={{
|
||||
bottom: anchorPosition.bottom,
|
||||
left: anchorPosition.left
|
||||
|
||||
@@ -59,7 +59,7 @@ function PortAction({
|
||||
<TooltipTrigger asChild>
|
||||
{disabled ? <span className="inline-flex">{button}</span> : button}
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={4} className="z-[70]">
|
||||
<TooltipContent side="top" sideOffset={4}>
|
||||
{tooltipLabel}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
@@ -157,7 +157,7 @@ export function renderResourceUsageSummary({
|
||||
{formatCpu(totalCpu)}
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={6} className="z-[70] max-w-xs">
|
||||
<TooltipContent side="top" sideOffset={6} className="max-w-xs">
|
||||
{translate(
|
||||
'auto.components.status.bar.ResourceUsageStatusSegment.1fedf94eae',
|
||||
'Combined CPU load. Values above 100% mean more than one core is working at once.'
|
||||
@@ -177,7 +177,7 @@ export function renderResourceUsageSummary({
|
||||
</span>
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={6} className="z-[70] max-w-xs">
|
||||
<TooltipContent side="top" sideOffset={6} className="max-w-xs">
|
||||
{memoryMetricCopy.description}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
@@ -199,7 +199,7 @@ export function renderResourceUsageSummary({
|
||||
</span>
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={6} className="z-[70] max-w-xs">
|
||||
<TooltipContent side="top" sideOffset={6} className="max-w-xs">
|
||||
{commitMetricCopy.description}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
@@ -225,11 +225,7 @@ export function WorktreeRow({
|
||||
<Trash2 className="size-3" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent
|
||||
side="top"
|
||||
sideOffset={4}
|
||||
className="z-[70] max-w-[200px] text-pretty"
|
||||
>
|
||||
<TooltipContent side="top" sideOffset={4} className="max-w-[200px]">
|
||||
{isMainWorktree
|
||||
? translate(
|
||||
'auto.components.status.bar.ResourceUsageStatusSegment.946724a70a',
|
||||
|
||||
@@ -126,7 +126,7 @@ export function TabBarStaticCreateMenu({
|
||||
<DropdownMenuShortcut>{newSimulatorShortcut}</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right" sideOffset={8} className="z-[80]">
|
||||
<TooltipContent side="right" sideOffset={8}>
|
||||
{translate(
|
||||
'auto.components.tab.bar.TabBar.aea43b5748',
|
||||
'Open the existing emulator tab.'
|
||||
|
||||
@@ -58,7 +58,7 @@ function ContextMenuSubContent({
|
||||
<ContextMenuPrimitive.SubContent
|
||||
data-slot="context-menu-sub-content"
|
||||
className={cn(
|
||||
'z-[70] min-w-[11rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-[11px] border border-black/14 bg-[rgba(255,255,255,0.10)] p-[4px] text-popover-foreground shadow-[0_12px_28px_rgba(0,0,0,0.22),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.12)] dark:shadow-[0_16px_34px_rgba(0,0,0,0.40),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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]:duration-150 data-[state=open]:zoom-in-[0.98]',
|
||||
'z-50 min-w-[11rem] origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded-[11px] border border-black/14 bg-[rgba(255,255,255,0.10)] p-[4px] text-popover-foreground shadow-[0_12px_28px_rgba(0,0,0,0.22),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.12)] dark:shadow-[0_16px_34px_rgba(0,0,0,0.40),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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]:duration-150 data-[state=open]:zoom-in-[0.98]',
|
||||
className
|
||||
)}
|
||||
// Why: submenu content must portal out of the scrollable parent menu so
|
||||
@@ -79,8 +79,9 @@ function ContextMenuContent({
|
||||
<ContextMenuPrimitive.Portal>
|
||||
<ContextMenuPrimitive.Content
|
||||
data-slot="context-menu-content"
|
||||
// Why: all overlays share z-50; portal mount order decides. Never escalate.
|
||||
className={cn(
|
||||
'z-[70] max-h-(--radix-context-menu-content-available-height) min-w-[11rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto scrollbar-sleek rounded-[11px] border border-black/14 bg-[rgba(255,255,255,0.10)] p-[4px] text-popover-foreground shadow-[0_12px_28px_rgba(0,0,0,0.22),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.12)] dark:shadow-[0_16px_34px_rgba(0,0,0,0.40),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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]:duration-150 data-[state=open]:zoom-in-[0.98]',
|
||||
'z-50 max-h-(--radix-context-menu-content-available-height) min-w-[11rem] origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto scrollbar-sleek rounded-[11px] border border-black/14 bg-[rgba(255,255,255,0.10)] p-[4px] text-popover-foreground shadow-[0_12px_28px_rgba(0,0,0,0.22),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.12)] dark:shadow-[0_16px_34px_rgba(0,0,0,0.40),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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]:duration-150 data-[state=open]:zoom-in-[0.98]',
|
||||
className
|
||||
)}
|
||||
// Why: same no-drag fix as DropdownMenuContent — titlebar drag regions
|
||||
|
||||
@@ -34,6 +34,7 @@ function DialogOverlay({
|
||||
// Why: in dark mode the canvas is already near-black, so a flat 50% black
|
||||
// scrim disappears into the background. A deeper scrim + 2px backdrop
|
||||
// blur lifts the canvas behind the dialog without needing per-mode colors.
|
||||
// Why: all overlays share z-50; portal mount order decides. Never escalate.
|
||||
className={cn(
|
||||
'fixed inset-0 z-50 bg-black/55 backdrop-blur-[2px] data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0',
|
||||
className
|
||||
|
||||
@@ -31,8 +31,9 @@ function DropdownMenuContent({
|
||||
<DropdownMenuPrimitive.Content
|
||||
data-slot="dropdown-menu-content"
|
||||
sideOffset={sideOffset}
|
||||
// Why: all overlays share z-50; portal mount order decides. Never escalate.
|
||||
className={cn(
|
||||
'z-[70] max-h-(--radix-dropdown-menu-content-available-height) min-w-[11rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto scrollbar-sleek rounded-[11px] border border-black/14 bg-[rgba(255,255,255,0.82)] p-[4px] text-black dark:text-white shadow-[0_12px_28px_rgba(0,0,0,0.22),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.72)] dark:shadow-[0_16px_34px_rgba(0,0,0,0.40),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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]:duration-150 data-[state=open]:zoom-in-[0.98]',
|
||||
'z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[11rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto scrollbar-sleek rounded-[11px] border border-black/14 bg-[rgba(255,255,255,0.82)] p-[4px] text-black dark:text-white shadow-[0_12px_28px_rgba(0,0,0,0.22),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.72)] dark:shadow-[0_16px_34px_rgba(0,0,0,0.40),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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]:duration-150 data-[state=open]:zoom-in-[0.98]',
|
||||
className
|
||||
)}
|
||||
// Why: Electron's -webkit-app-region: drag on the titlebar captures
|
||||
@@ -211,7 +212,7 @@ function DropdownMenuSubContent({
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
data-slot="dropdown-menu-sub-content"
|
||||
className={cn(
|
||||
'z-[70] min-w-[11rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-[11px] border border-black/14 bg-[rgba(255,255,255,0.82)] p-[4px] text-black dark:text-white shadow-[0_12px_28px_rgba(0,0,0,0.22),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.72)] dark:shadow-[0_16px_34px_rgba(0,0,0,0.40),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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]:duration-150 data-[state=open]:zoom-in-[0.98]',
|
||||
'z-50 min-w-[11rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-[11px] border border-black/14 bg-[rgba(255,255,255,0.82)] p-[4px] text-black dark:text-white shadow-[0_12px_28px_rgba(0,0,0,0.22),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.72)] dark:shadow-[0_16px_34px_rgba(0,0,0,0.40),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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]:duration-150 data-[state=open]:zoom-in-[0.98]',
|
||||
className
|
||||
)}
|
||||
// Why: same no-drag fix as DropdownMenuContent — titlebar drag region
|
||||
|
||||
@@ -167,8 +167,9 @@ function PopoverContent({
|
||||
// 14% border, dual shadow, and 2xl backdrop blur. bg-popover equals
|
||||
// the canvas in dark mode (#171717 vs #0a0a0a) and border-border/50
|
||||
// is too faint to read, so the popover blended into the background.
|
||||
// Why: all overlays share z-50; portal mount order decides. Never escalate.
|
||||
className={cn(
|
||||
'z-[60] overflow-hidden rounded-md border border-black/14 bg-[rgba(255,255,255,0.82)] text-popover-foreground shadow-[0_16px_36px_rgba(0,0,0,0.24),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl outline-none dark:border-white/14 dark:bg-[rgba(0,0,0,0.72)] dark:shadow-[0_20px_44px_rgba(0,0,0,0.42),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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',
|
||||
'z-50 overflow-hidden rounded-md border border-black/14 bg-[rgba(255,255,255,0.82)] text-popover-foreground shadow-[0_16px_36px_rgba(0,0,0,0.24),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl outline-none dark:border-white/14 dark:bg-[rgba(0,0,0,0.72)] dark:shadow-[0_20px_44px_rgba(0,0,0,0.42),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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',
|
||||
className
|
||||
)}
|
||||
ref={setContentRef}
|
||||
|
||||
@@ -72,8 +72,9 @@ function SelectContent({
|
||||
// 14% border, dual shadow, and 2xl backdrop blur. The previous
|
||||
// border-border/50 + bg-popover made the option list blend into the
|
||||
// dark canvas (#171717 vs #0a0a0a) with a near-invisible border.
|
||||
// Why: all overlays share z-50; portal mount order decides. Never escalate.
|
||||
className={cn(
|
||||
'relative z-[70] max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto scrollbar-sleek rounded-md border border-black/14 bg-[rgba(255,255,255,0.82)] text-popover-foreground shadow-[0_16px_36px_rgba(0,0,0,0.24),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.72)] dark:shadow-[0_20px_44px_rgba(0,0,0,0.42),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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',
|
||||
'relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto scrollbar-sleek rounded-md border border-black/14 bg-[rgba(255,255,255,0.82)] text-popover-foreground shadow-[0_16px_36px_rgba(0,0,0,0.24),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.72)] dark:shadow-[0_20px_44px_rgba(0,0,0,0.42),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 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',
|
||||
position === 'popper' &&
|
||||
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
||||
className
|
||||
|
||||
Reference in New Issue
Block a user