authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-22 21:33:01-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-22 21:33:01-07:00
log361b047f5f559abccacc802cd5ab9992b01473ea
tree9c076940d77bbf97bf45a9efba075736937141f3
parent266d70cc4d887b7459ec6557c430ec7bb92bd3fc
signature Signed by PGP key B5690EEEBB952194

refactor(web): ui components drop their secondary className props (#13193)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

30 files changed, 127 insertions(+), 205 deletions(-)

apps/web/src/components/ChatView.tsx-1
...@@ -10378,7 +10378,6 @@ export default function ChatView(props: ChatViewProps) {...@@ -10378,7 +10378,6 @@ export default function ChatView(props: ChatViewProps) {
10378 <RightPanelSheet10378 <RightPanelSheet
10379 animationDurationMs={panelAnimationsActive ? panelAnimationDurationMs : 0}10379 animationDurationMs={panelAnimationsActive ? panelAnimationDurationMs : 0}
10380 open={rightPanelOpen}10380 open={rightPanelOpen}
10381 underFloatingPreview={previewMiniPlayerVisible}
10382 onClose={closePreviewPanel}10381 onClose={closePreviewPanel}
10383 >10382 >
10384 <RightPanelTabs10383 <RightPanelTabs
apps/web/src/components/CommandPalette.tsx-3
...@@ -2966,9 +2966,6 @@ function OpenCommandPaletteDialog(props: {...@@ -2966,9 +2966,6 @@ function OpenCommandPaletteDialog(props: {
2966 })2966 })
2967 : undefined,2967 : undefined,
2968 placeholder: inputPlaceholder,2968 placeholder: inputPlaceholder,
2969 wrapperClassName: isSubmenu
2970 ? "[&_[data-slot=autocomplete-start-addon]]:pointer-events-auto"
2971 : undefined,
2972 ...(isSubmenu2969 ...(isSubmenu
2973 ? {2970 ? {
2974 startAddon: (2971 startAddon: (
apps/web/src/components/DiffPanel.tsx-2
...@@ -775,7 +775,6 @@ export default function DiffPanel({...@@ -775,7 +775,6 @@ export default function DiffPanel({
775 <ComboboxList className="max-h-64 min-w-0 overflow-x-hidden">775 <ComboboxList className="max-h-64 min-w-0 overflow-x-hidden">
776 <ComboboxItem776 <ComboboxItem
777 className="w-full min-w-0 grid-cols-[1rem_minmax(0,1fr)]"777 className="w-full min-w-0 grid-cols-[1rem_minmax(0,1fr)]"
778 contentClassName="w-full min-w-0 overflow-hidden"
779 value={AUTOMATIC_BASE_REF}778 value={AUTOMATIC_BASE_REF}
780 >779 >
781 <span className="block min-w-0 truncate">Automatic</span>780 <span className="block min-w-0 truncate">Automatic</span>
...@@ -788,7 +787,6 @@ export default function DiffPanel({...@@ -788,7 +787,6 @@ export default function DiffPanel({
788 <ComboboxItem787 <ComboboxItem
789 key={choice.id}788 key={choice.id}
790 className="w-full min-w-0 grid-cols-[1rem_minmax(0,1fr)]"789 className="w-full min-w-0 grid-cols-[1rem_minmax(0,1fr)]"
791 contentClassName="w-full min-w-0 overflow-hidden"
792 value={item}790 value={item}
793 >791 >
794 <div className="grid w-full min-w-0 grid-cols-[minmax(0,1fr)_2rem] items-center overflow-hidden">792 <div className="grid w-full min-w-0 grid-cols-[minmax(0,1fr)_2rem] items-center overflow-hidden">
apps/web/src/components/RightPanelSheet.tsx+1-11
...@@ -1,16 +1,12 @@...@@ -1,16 +1,12 @@
1import { type ReactNode } from "react";1import { type ReactNode } from "react";
22
3import {3import { RIGHT_PANEL_SHEET_CLASS_NAME } from "../rightPanelLayout";
4 RIGHT_PANEL_SHEET_CLASS_NAME,
5 RIGHT_PANEL_SHEET_LAYER_CLASS_NAME,
6} from "../rightPanelLayout";
7import { Sheet, SheetPopup } from "./ui/sheet";4import { Sheet, SheetPopup } from "./ui/sheet";
85
9export function RightPanelSheet(props: {6export function RightPanelSheet(props: {
10 animationDurationMs: number;7 animationDurationMs: number;
11 children: ReactNode;8 children: ReactNode;
12 open: boolean;9 open: boolean;
13 underFloatingPreview?: boolean;
14 onClose: () => void;10 onClose: () => void;
15}) {11}) {
16 return (12 return (
...@@ -27,12 +23,6 @@ export function RightPanelSheet(props: {...@@ -27,12 +23,6 @@ export function RightPanelSheet(props: {
27 side="right"23 side="right"
28 showCloseButton={false}24 showCloseButton={false}
29 keepMounted25 keepMounted
30 {...(props.underFloatingPreview
31 ? {
32 backdropClassName: RIGHT_PANEL_SHEET_LAYER_CLASS_NAME,
33 viewportClassName: RIGHT_PANEL_SHEET_LAYER_CLASS_NAME,
34 }
35 : {})}
36 className={RIGHT_PANEL_SHEET_CLASS_NAME}26 className={RIGHT_PANEL_SHEET_CLASS_NAME}
37 >27 >
38 {props.children}28 {props.children}
apps/web/src/components/Sidebar.tsx+15-24
...@@ -235,7 +235,7 @@ import {...@@ -235,7 +235,7 @@ import {
235import { SidebarContent, SidebarGroup, useSidebar } from "./ui/sidebar";235import { SidebarContent, SidebarGroup, useSidebar } from "./ui/sidebar";
236import { SidebarChromeFooter, SidebarChromeHeader } from "./sidebar/SidebarChrome";236import { SidebarChromeFooter, SidebarChromeHeader } from "./sidebar/SidebarChrome";
237import { SidebarHeaderIconButton, SidebarThreadHeader } from "./sidebar/SidebarThreadHeader";237import { SidebarHeaderIconButton, SidebarThreadHeader } from "./sidebar/SidebarThreadHeader";
238import { Popover, PopoverPopup, PopoverTrigger } from "./ui/popover";238import { Menu, MenuItem, MenuPopup, MenuSeparator, MenuShortcut, MenuTrigger } from "./ui/menu";
239import { Tooltip, TooltipPopup, TooltipProvider, TooltipTrigger } from "./ui/tooltip";239import { Tooltip, TooltipPopup, TooltipProvider, TooltipTrigger } from "./ui/tooltip";
240import { MiddleTruncate } from "./ui/middle-truncate";240import { MiddleTruncate } from "./ui/middle-truncate";
241import {241import {
...@@ -440,7 +440,7 @@ function SidebarThreadTooltip({...@@ -440,7 +440,7 @@ function SidebarThreadTooltip({
440 * Controlled by the row (which also uses the open state to pin its hover440 * Controlled by the row (which also uses the open state to pin its hover
441 * actions while the menu is up).441 * actions while the menu is up).
442 */442 */
443function SnoozePopoverButton(props: {443function SnoozeMenuButton(props: {
444 open: boolean;444 open: boolean;
445 onOpenChange: (open: boolean) => void;445 onOpenChange: (open: boolean) => void;
446 onSnooze: (preset: Pick<SnoozePreset, "snoozedUntil">) => void;446 onSnooze: (preset: Pick<SnoozePreset, "snoozedUntil">) => void;
...@@ -454,11 +454,11 @@ function SnoozePopoverButton(props: {...@@ -454,11 +454,11 @@ function SnoozePopoverButton(props: {
454 [open, timestampFormat],454 [open, timestampFormat],
455 );455 );
456 return (456 return (
457 <Popover open={open} onOpenChange={onOpenChange}>457 <Menu open={open} onOpenChange={onOpenChange}>
458 <Tooltip>458 <Tooltip>
459 <TooltipTrigger459 <TooltipTrigger
460 render={460 render={
461 <PopoverTrigger461 <MenuTrigger
462 render={462 render={
463 <button463 <button
464 type="button"464 type="button"
...@@ -475,39 +475,31 @@ function SnoozePopoverButton(props: {...@@ -475,39 +475,31 @@ function SnoozePopoverButton(props: {
475 </TooltipTrigger>475 </TooltipTrigger>
476 <TooltipPopup>Snooze thread</TooltipPopup>476 <TooltipPopup>Snooze thread</TooltipPopup>
477 </Tooltip>477 </Tooltip>
478 <PopoverPopup side="bottom" align="end" width="sm" viewportClassName="p-1">478 <MenuPopup side="bottom" align="end">
479 {presets.map((preset) => (479 {presets.map((preset) => (
480 <button480 <MenuItem
481 key={preset.id}481 key={preset.id}
482 type="button"
483 onClick={(event) => {482 onClick={(event) => {
484 event.stopPropagation();483 event.stopPropagation();
485 onOpenChange(false);
486 onSnooze(preset);484 onSnooze(preset);
487 }}485 }}
488 className="flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs text-foreground/90 hover:bg-accent hover:text-foreground"
489 >486 >
490 <span className="flex-1">{preset.label}</span>487 {preset.label}
491 <span className="font-mono text-[10px] text-muted-foreground/60 tabular-nums">488 <MenuShortcut>{preset.whenLabel}</MenuShortcut>
492 {preset.whenLabel}489 </MenuItem>
493 </span>
494 </button>
495 ))}490 ))}
496 <div className="my-1 border-t border-border/60" />491 <MenuSeparator />
497 <button492 <MenuItem
498 type="button"
499 className="flex w-full cursor-pointer rounded-md px-2 py-1.5 text-left text-xs text-foreground/90 hover:bg-accent hover:text-foreground"
500 onClick={async (event) => {493 onClick={async (event) => {
501 event.stopPropagation();494 event.stopPropagation();
502 onOpenChange(false);
503 const choice = await requestCustomSnooze();495 const choice = await requestCustomSnooze();
504 if (choice) onSnooze(choice);496 if (choice) onSnooze(choice);
505 }}497 }}
506 >498 >
507 Custom…499 Custom…
508 </button>500 </MenuItem>
509 </PopoverPopup>501 </MenuPopup>
510 </Popover>502 </Menu>
511 );503 );
512}504}
513505
...@@ -1883,7 +1875,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {...@@ -1883,7 +1875,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: {
1883 </Tooltip>1875 </Tooltip>
1884 ) : null}1876 ) : null}
1885 {showSnoozeButton ? (1877 {showSnoozeButton ? (
1886 <SnoozePopoverButton1878 <SnoozeMenuButton
1887 open={snoozeMenuOpen}1879 open={snoozeMenuOpen}
1888 onOpenChange={setSnoozeMenuOpen}1880 onOpenChange={setSnoozeMenuOpen}
1889 onSnooze={handleSnoozePreset}1881 onSnooze={handleSnoozePreset}
...@@ -4492,7 +4484,6 @@ export default function Sidebar() {...@@ -4492,7 +4484,6 @@ export default function Sidebar() {
4492 hideIndicator4484 hideIndicator
4493 value={item}4485 value={item}
4494 className="font-medium"4486 className="font-medium"
4495 contentClassName="flex min-w-0 items-center gap-2"
4496 onContextMenu={(event) => {4487 onContextMenu={(event) => {
4497 if (project) handleProjectSettings(event, project);4488 if (project) handleProjectSettings(event, project);
4498 }}4489 }}
apps/web/src/components/chat/AssistantCitationChip.tsx+1-1
...@@ -171,7 +171,7 @@ export function AssistantCitationChip({...@@ -171,7 +171,7 @@ export function AssistantCitationChip({
171 }}171 }}
172 aria-label="Edit citation comment"172 aria-label="Edit citation comment"
173 width="md"173 width="md"
174 viewportClassName="p-3"174 padding="compact"
175 onPointerDown={(event) => event.stopPropagation()}175 onPointerDown={(event) => event.stopPropagation()}
176 >176 >
177 <AssistantCitationCommentEditor177 <AssistantCitationCommentEditor
apps/web/src/components/chat/ContextWindowMeter.tsx+1-1
...@@ -88,7 +88,7 @@ export function ContextWindowMeter(props: {...@@ -88,7 +88,7 @@ export function ContextWindowMeter(props: {
88 tooltipStyle88 tooltipStyle
89 side="top"89 side="top"
90 align="end"90 align="end"
91 viewportClassName="p-0"91 padding="none"
92 width="sm"92 width="sm"
93 className="text-left whitespace-normal"93 className="text-left whitespace-normal"
94 >94 >
apps/web/src/components/chat/ExpandedImageDialog.tsx-2
...@@ -179,8 +179,6 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({...@@ -179,8 +179,6 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({
179 variant="media"179 variant="media"
180 showCloseButton={false}180 showCloseButton={false}
181 bottomStickOnMobile={false}181 bottomStickOnMobile={false}
182 backdropClassName="z-[60]"
183 viewportClassName="z-[60] grid-rows-1 place-items-center px-4 py-6 [-webkit-app-region:no-drag]"
184 className="row-start-1 max-h-[92vh] w-[92vw] max-w-[92vw] items-center overflow-visible [--media-width:92vw] [--media-height:min(86vh,calc(100vh-160px))] sm:[--media-width:calc(92vw-96px)]"182 className="row-start-1 max-h-[92vh] w-[92vw] max-w-[92vw] items-center overflow-visible [--media-width:92vw] [--media-height:min(86vh,calc(100vh-160px))] sm:[--media-width:calc(92vw-96px)]"
185 onKeyDown={onKeyDown}183 onKeyDown={onKeyDown}
186 initialFocus={closeButtonRef}184 initialFocus={closeButtonRef}
apps/web/src/components/chat/MessagesTimeline.tsx+1-1
...@@ -2567,7 +2567,7 @@ function BackgroundWorktreeSetupChip({ snapshot }: { snapshot: WorktreeSetupSnap...@@ -2567,7 +2567,7 @@ function BackgroundWorktreeSetupChip({ snapshot }: { snapshot: WorktreeSetupSnap
2567 align="end"2567 align="end"
2568 width="lg"2568 width="lg"
2569 className="surface-glass!"2569 className="surface-glass!"
2570 viewportClassName="py-3 [--viewport-inline-padding:--spacing(3)]"2570 padding="compact"
2571 >2571 >
2572 <WorktreeSetupCard2572 <WorktreeSetupCard
2573 snapshot={snapshot}2573 snapshot={snapshot}
apps/web/src/components/chat/ModelListRow.tsx-1
...@@ -52,7 +52,6 @@ export const ModelListRow = memo(function ModelListRow(props: {...@@ -52,7 +52,6 @@ export const ModelListRow = memo(function ModelListRow(props: {
52 index={props.index}52 index={props.index}
53 value={modelPickerModelKey(props.instanceId, props.model.slug)}53 value={modelPickerModelKey(props.instanceId, props.model.slug)}
54 disabled={Boolean(props.disabledReason)}54 disabled={Boolean(props.disabledReason)}
55 contentClassName="flex w-full items-center gap-3"
56 className={cn(55 className={cn(
57 "group relative w-full !min-w-0 max-w-full cursor-pointer rounded-md px-2 py-2 transition-[background-color,box-shadow,color]",56 "group relative w-full !min-w-0 max-w-full cursor-pointer rounded-md px-2 py-2 transition-[background-color,box-shadow,color]",
58 "hover:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] data-highlighted:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] data-selected:bg-foreground/[0.08] data-selected:text-foreground data-selected:ring-0 [&[data-highlighted][data-selected]]:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))]",57 "hover:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] data-highlighted:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))] data-selected:bg-foreground/[0.08] data-selected:text-foreground data-selected:ring-0 [&[data-highlighted][data-selected]]:bg-[color-mix(in_srgb,var(--popover)_90%,var(--contrast-foreground))]",
apps/web/src/components/chat/ModelPickerContent.tsx+57-73
...@@ -8,7 +8,7 @@ import { resolveSelectableModel } from "@t3tools/shared/model";...@@ -8,7 +8,7 @@ import { resolveSelectableModel } from "@t3tools/shared/model";
8import { useAtomValue } from "@effect/atom-react";8import { useAtomValue } from "@effect/atom-react";
9import { LegendList, type LegendListRef } from "@legendapp/list/react";9import { LegendList, type LegendListRef } from "@legendapp/list/react";
10import { memo, useMemo, useState, useCallback, useEffect, useLayoutEffect, useRef } from "react";10import { memo, useMemo, useState, useCallback, useEffect, useLayoutEffect, useRef } from "react";
11import { ChevronRightIcon, SearchIcon } from "lucide-react";11import { ChevronRightIcon } from "lucide-react";
12import { ModelListRow } from "./ModelListRow";12import { ModelListRow } from "./ModelListRow";
13import { ModelPickerSidebar } from "./ModelPickerSidebar";13import { ModelPickerSidebar } from "./ModelPickerSidebar";
14import { getProviderStatusMessage, hasProviderSetup } from "./ProviderStatusBanner";14import { getProviderStatusMessage, hasProviderSetup } from "./ProviderStatusBanner";
...@@ -22,7 +22,7 @@ import { buildModelPickerSearchText, scoreModelPickerSearch } from "./modelPicke...@@ -22,7 +22,7 @@ import { buildModelPickerSearchText, scoreModelPickerSearch } from "./modelPicke
22import {22import {
23 Combobox,23 Combobox,
24 ComboboxEmpty,24 ComboboxEmpty,
25 ComboboxInput,25 ComboboxSearchInput,
26 ComboboxItem,26 ComboboxItem,
27 ComboboxListVirtualized,27 ComboboxListVirtualized,
28} from "../ui/combobox";28} from "../ui/combobox";
...@@ -882,77 +882,62 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {...@@ -882,77 +882,62 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
882 showSidebar && "border-l border-border/70",882 showSidebar && "border-l border-border/70",
883 )}883 )}
884 >884 >
885 {/* Search bar */}885 <ComboboxSearchInput
886 <div className="px-2 pt-2">886 ref={searchInputRef}
887 <div className="border-b border-border/70 pb-2.5 transition-colors focus-within:border-ring">887 placeholder="Search models..."
888 <ComboboxInput888 value={searchQuery}
889 ref={searchInputRef}889 onChange={(e) => setSearchQuery(e.target.value)}
890 className="[&_input]:h-6.5 [&_input]:font-sans [&_input]:leading-6.5"890 onKeyDown={(e) => {
891 inputClassName="rounded-none bg-transparent text-sm"891 if (
892 placeholder="Search models..."892 showSidebar &&
893 showTrigger={false}893 !e.altKey &&
894 startAddon={894 !e.ctrlKey &&
895 <SearchIcon className="-translate-x-0.5 size-4 shrink-0 text-muted-foreground opacity-70" />895 !e.metaKey &&
896 }896 ((e.key === "ArrowLeft" && !e.shiftKey && searchQuery.length === 0) ||
897 value={searchQuery}897 (e.key === "Tab" && e.shiftKey))
898 onChange={(e) => setSearchQuery(e.target.value)}898 ) {
899 onKeyDown={(e) => {899 const sidebar = e.currentTarget
900 if (900 .closest("[data-model-picker-content]")
901 showSidebar &&901 ?.querySelector("[data-model-picker-sidebar]");
902 !e.altKey &&902 const button =
903 !e.ctrlKey &&903 sidebar?.querySelector<HTMLButtonElement>(
904 !e.metaKey &&904 'button[aria-pressed="true"]:not(:disabled)',
905 ((e.key === "ArrowLeft" && !e.shiftKey && searchQuery.length === 0) ||905 ) ?? sidebar?.querySelector<HTMLButtonElement>("button:not(:disabled)");
906 (e.key === "Tab" && e.shiftKey))906 if (button) {
907 ) {907 e.preventDefault();
908 const sidebar = e.currentTarget
909 .closest("[data-model-picker-content]")
910 ?.querySelector("[data-model-picker-sidebar]");
911 const button =
912 sidebar?.querySelector<HTMLButtonElement>(
913 'button[aria-pressed="true"]:not(:disabled)',
914 ) ?? sidebar?.querySelector<HTMLButtonElement>("button:not(:disabled)");
915 if (button) {
916 e.preventDefault();
917 e.stopPropagation();
918 button.focus();
919 return;
920 }
921 }
922 if (e.key === "Escape") {
923 e.preventDefault();
924 e.stopPropagation();
925 props.onRequestClose?.();
926 return;
927 }
928 if (e.key === "Enter" && highlightedModelKeyRef.current) {
929 (
930 e as typeof e & { preventBaseUIHandler?: () => void }
931 ).preventBaseUIHandler?.();
932 e.preventDefault();
933 e.stopPropagation();
934 const legacyInstanceId = parseModelPickerLegacySectionKey(
935 highlightedModelKeyRef.current,
936 );
937 if (legacyInstanceId) {
938 toggleLegacySection(legacyInstanceId);
939 return;
940 }
941 const model = parseModelPickerModelKey(highlightedModelKeyRef.current);
942 if (model) {
943 handleModelSelect(model.slug, model.instanceId, e.shiftKey);
944 }
945 return;
946 }
947 e.stopPropagation();908 e.stopPropagation();
948 }}909 button.focus();
949 onMouseDown={(e) => e.stopPropagation()}910 return;
950 onTouchStart={(e) => e.stopPropagation()}911 }
951 size="sm"912 }
952 unstyled913 if (e.key === "Escape") {
953 />914 e.preventDefault();
954 </div>915 e.stopPropagation();
955 </div>916 props.onRequestClose?.();
917 return;
918 }
919 if (e.key === "Enter" && highlightedModelKeyRef.current) {
920 (e as typeof e & { preventBaseUIHandler?: () => void }).preventBaseUIHandler?.();
921 e.preventDefault();
922 e.stopPropagation();
923 const legacyInstanceId = parseModelPickerLegacySectionKey(
924 highlightedModelKeyRef.current,
925 );
926 if (legacyInstanceId) {
927 toggleLegacySection(legacyInstanceId);
928 return;
929 }
930 const model = parseModelPickerModelKey(highlightedModelKeyRef.current);
931 if (model) {
932 handleModelSelect(model.slug, model.instanceId, e.shiftKey);
933 }
934 return;
935 }
936 e.stopPropagation();
937 }}
938 onMouseDown={(e) => e.stopPropagation()}
939 onTouchStart={(e) => e.stopPropagation()}
940 />
956941
957 {/* Model list */}942 {/* Model list */}
958 <div className="relative min-h-0 flex-1 overflow-hidden pr-px">943 <div className="relative min-h-0 flex-1 overflow-hidden pr-px">
...@@ -971,7 +956,6 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {...@@ -971,7 +956,6 @@ export const ModelPickerContent = memo(function ModelPickerContent(props: {
971 value={modelKey}956 value={modelKey}
972 aria-expanded={legacySection.isExpanded}957 aria-expanded={legacySection.isExpanded}
973 className="group w-full cursor-pointer rounded-md px-2 py-2"958 className="group w-full cursor-pointer rounded-md px-2 py-2"
974 contentClassName="flex w-full items-center gap-3"
975 >959 >
976 <div className="min-w-0 flex-1 text-left">960 <div className="min-w-0 flex-1 text-left">
977 <div className="text-xs font-medium leading-snug">Legacy models</div>961 <div className="text-xs font-medium leading-snug">Legacy models</div>
apps/web/src/components/chat/ProviderModelPicker.tsx+2-2
...@@ -284,8 +284,8 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: {...@@ -284,8 +284,8 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: {
284 <PopoverPopup284 <PopoverPopup
285 {...(props.isComposerOwned ? composerFloatingLayerProps : {})}285 {...(props.isComposerOwned ? composerFloatingLayerProps : {})}
286 align="start"286 align="start"
287 className="before:hidden [--viewport-inline-padding:0]"287 className="before:hidden"
288 viewportClassName="overflow-hidden! rounded-[calc(var(--radius-lg)-1px)] p-0 [clip-path:inset(0_round_calc(var(--radius-lg)-1px))]"288 padding="none"
289 >289 >
290 <ModelPickerContent290 <ModelPickerContent
291 activeInstanceId={activeInstanceId}291 activeInstanceId={activeInstanceId}
apps/web/src/components/chat/SnapShotAttachmentDetails.tsx+2-7
...@@ -163,13 +163,8 @@ export function SnapShotContentsButton({...@@ -163,13 +163,8 @@ export function SnapShotContentsButton({
163 </TooltipTrigger>163 </TooltipTrigger>
164 <TooltipPopup side={side}>{tooltip}</TooltipPopup>164 <TooltipPopup side={side}>{tooltip}</TooltipPopup>
165 </Tooltip>165 </Tooltip>
166 <PopoverPopup166 <PopoverPopup side={side} align="center" width="md">
167 side={side}167 <div className="max-h-[min(28rem,70vh)] space-y-2 overflow-y-auto">
168 align="center"
169 width="md"
170 viewportClassName="max-h-[min(28rem,70vh)]"
171 >
172 <div className="space-y-2">
173 <PopoverTitle>Accessibility data</PopoverTitle>168 <PopoverTitle>Accessibility data</PopoverTitle>
174 {accessibilityDetails ? (169 {accessibilityDetails ? (
175 <SnapShotAccessibilityData170 <SnapShotAccessibilityData
apps/web/src/components/chat/TerminalContextInlineChip.tsx-2
...@@ -23,8 +23,6 @@ export function TerminalContextInlineChip(props: TerminalContextInlineChipProps)...@@ -23,8 +23,6 @@ export function TerminalContextInlineChip(props: TerminalContextInlineChipProps)
23 icon={<TerminalIcon />}23 icon={<TerminalIcon />}
24 label={label}24 label={label}
25 accessibleLabel={`Terminal excerpt, ${label}`}25 accessibleLabel={`Terminal excerpt, ${label}`}
26 popupClassName="w-[min(40rem,calc(100vw-2rem))]"
27 viewportClassName="overflow-hidden p-2"
28 >26 >
29 <div className="overflow-hidden rounded-md border border-border/70 bg-background/80">27 <div className="overflow-hidden rounded-md border border-border/70 bg-background/80">
30 <div className="flex items-center gap-2 border-b border-border/70 px-3 py-2">28 <div className="flex items-center gap-2 border-b border-border/70 px-3 py-2">
apps/web/src/components/contextChipParts.tsx+1-9
...@@ -8,7 +8,6 @@ import {...@@ -8,7 +8,6 @@ import {
8 type ReactNode,8 type ReactNode,
9} from "react";9} from "react";
1010
11import { cn } from "~/lib/utils";
12import { PULL_REQUEST_STATE_PRESENTATION } from "~/components/pullRequest/pullRequestIcons";11import { PULL_REQUEST_STATE_PRESENTATION } from "~/components/pullRequest/pullRequestIcons";
13import type { PullRequestContextDisplayState } from "~/lib/composerContextRecords";12import type { PullRequestContextDisplayState } from "~/lib/composerContextRecords";
14import { PierreEntryIcon } from "./chat/PierreEntryIcon";13import { PierreEntryIcon } from "./chat/PierreEntryIcon";
...@@ -70,8 +69,6 @@ export function ContextChipPopover(props: {...@@ -70,8 +69,6 @@ export function ContextChipPopover(props: {
70 copyMarkdown?: string;69 copyMarkdown?: string;
71 accessibleLabel: string;70 accessibleLabel: string;
72 children: ReactNode;71 children: ReactNode;
73 popupClassName?: string;
74 viewportClassName?: string;
75}) {72}) {
76 return (73 return (
77 <Popover>74 <Popover>
...@@ -88,12 +85,7 @@ export function ContextChipPopover(props: {...@@ -88,12 +85,7 @@ export function ContextChipPopover(props: {
88 {props.icon}85 {props.icon}
89 <ContextChipLabel>{props.label}</ContextChipLabel>86 <ContextChipLabel>{props.label}</ContextChipLabel>
90 </PopoverTrigger>87 </PopoverTrigger>
91 <PopoverPopup88 <PopoverPopup side="top" width="lg" padding="compact">
92 side="top"
93 width="lg"
94 className={props.popupClassName}
95 viewportClassName={cn("overflow-x-auto p-2", props.viewportClassName)}
96 >
97 <PopoverTitle className="sr-only">{props.accessibleLabel}</PopoverTitle>89 <PopoverTitle className="sr-only">{props.accessibleLabel}</PopoverTitle>
98 {props.children}90 {props.children}
99 </PopoverPopup>91 </PopoverPopup>
apps/web/src/components/preview/previewMiniPlayerLayout.ts+1-1
...@@ -11,7 +11,7 @@ import type { DeviceScreenSize } from "@t3tools/client-runtime/device/stream";...@@ -11,7 +11,7 @@ import type { DeviceScreenSize } from "@t3tools/client-runtime/device/stream";
1111
12export const PREVIEW_MINI_PLAYER_EDGE_GAP = 12;12export const PREVIEW_MINI_PLAYER_EDGE_GAP = 12;
13export const PREVIEW_MINI_PLAYER_CORNER_RADIUS = 12;13export const PREVIEW_MINI_PLAYER_CORNER_RADIUS = 12;
14// The mini-player shell straddles this webview at 47 and 49; dialogs begin at 50.14// The mini-player shell straddles this webview at 47 and 49: above --z-sheet, under dialogs (50).
15export const PREVIEW_MINI_PLAYER_WEBVIEW_Z_INDEX = 48;15export const PREVIEW_MINI_PLAYER_WEBVIEW_Z_INDEX = 48;
16// A fresh player is the largest box at the source aspect ratio that fits here.16// A fresh player is the largest box at the source aspect ratio that fits here.
17const PREVIEW_MINI_PLAYER_DEFAULT_BOX = { width: 320, height: 320 } as const;17const PREVIEW_MINI_PLAYER_DEFAULT_BOX = { width: 320, height: 320 } as const;
apps/web/src/components/pullRequest/PullRequestCandidatePicker.tsx-1
...@@ -147,7 +147,6 @@ export function PullRequestCandidatePicker<T>({...@@ -147,7 +147,6 @@ export function PullRequestCandidatePicker<T>({
147 index={index}147 index={index}
148 value={keys[index]}148 value={keys[index]}
149 disabled={disabled}149 disabled={disabled}
150 contentClassName="flex min-w-0 items-center gap-2"
151 >150 >
152 {children(candidate)}151 {children(candidate)}
153 </ComboboxItem>152 </ComboboxItem>
apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx+1-6
...@@ -388,12 +388,7 @@ function PullRequestBaseFreshnessWarning({...@@ -388,12 +388,7 @@ function PullRequestBaseFreshnessWarning({
388 {children}388 {children}
389 <TriangleAlertIcon aria-hidden className={cn("size-3.5 shrink-0", iconClassName)} />389 <TriangleAlertIcon aria-hidden className={cn("size-3.5 shrink-0", iconClassName)} />
390 </PopoverTrigger>390 </PopoverTrigger>
391 <PopoverPopup391 <PopoverPopup align="start" side="bottom" className="max-w-80" padding="compact">
392 align="start"
393 side="bottom"
394 className="max-w-80"
395 viewportClassName="py-2.5 [--viewport-inline-padding:--spacing(3)]"
396 >
397 <p className="text-xs text-foreground">{summary}</p>392 <p className="text-xs text-foreground">{summary}</p>
398 <p className="mt-0.5 text-xs text-muted-foreground">Changes can be cleanly merged.</p>393 <p className="mt-0.5 text-xs text-muted-foreground">Changes can be cleanly merged.</p>
399 {/* Each way the host offers and this reader may take, as its own button: a split button394 {/* Each way the host offers and this reader may take, as its own button: a split button
apps/web/src/components/pullRequest/PullRequestReactions.tsx+1-1
...@@ -134,7 +134,7 @@ export function PullRequestReactionBar({...@@ -134,7 +134,7 @@ export function PullRequestReactionBar({
134 >134 >
135 <SmilePlusIcon aria-hidden className="size-3.5" />135 <SmilePlusIcon aria-hidden className="size-3.5" />
136 </PopoverTrigger>136 </PopoverTrigger>
137 <PopoverPopup align="start" side="top" viewportClassName="py-2">137 <PopoverPopup align="start" side="top" padding="compact">
138 <div className="flex items-center gap-0.5">138 <div className="flex items-center gap-0.5">
139 {PULL_REQUEST_REACTION_ORDER.map((content) => {139 {PULL_REQUEST_REACTION_ORDER.map((content) => {
140 const reacted =140 const reacted =
apps/web/src/components/settings/SettingInheritance.tsx+1-5
...@@ -223,11 +223,7 @@ export function SettingInheritance({...@@ -223,11 +223,7 @@ export function SettingInheritance({
223 </TooltipTrigger>223 </TooltipTrigger>
224 <TooltipPopup side="top">{overrideSummary}</TooltipPopup>224 <TooltipPopup side="top">{overrideSummary}</TooltipPopup>
225 </Tooltip>225 </Tooltip>
226 <PopoverPopup226 <PopoverPopup align="start" width="md" padding="none">
227 align="start"
228 width="md"
229 viewportClassName="p-0 [--viewport-inline-padding:0px]"
230 >
231 <div className="divide-y divide-border/60">227 <div className="divide-y divide-border/60">
232 {chains.map(({ target, environment, machine, layers }) => (228 {chains.map(({ target, environment, machine, layers }) => (
233 <section229 <section
apps/web/src/components/ui/autocomplete.tsx+1-1
...@@ -30,7 +30,7 @@ function AutocompleteInput({...@@ -30,7 +30,7 @@ function AutocompleteInput({
30 {startAddon && (30 {startAddon && (
31 <div31 <div
32 aria-hidden="true"32 aria-hidden="true"
33 className="[&_svg]:-mx-0.5 pointer-events-none absolute inset-y-0 start-px z-10 flex items-center ps-[calc(--spacing(3)-1px)] opacity-80 has-[+[data-size=sm]]:ps-[calc(--spacing(2.5)-1px)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4"33 className="[&_svg]:-mx-0.5 pointer-events-none has-[button]:pointer-events-auto absolute inset-y-0 start-px z-10 flex items-center ps-[calc(--spacing(3)-1px)] opacity-80 has-[+[data-size=sm]]:ps-[calc(--spacing(2.5)-1px)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4"
34 data-slot="autocomplete-start-addon"34 data-slot="autocomplete-start-addon"
35 >35 >
36 {startAddon}36 {startAddon}
apps/web/src/components/ui/combobox.tsx+6-10
...@@ -30,7 +30,6 @@ function Combobox<Value, Multiple extends boolean | undefined = false>(...@@ -30,7 +30,6 @@ function Combobox<Value, Multiple extends boolean | undefined = false>(
3030
31function ComboboxInput({31function ComboboxInput({
32 className,32 className,
33 inputClassName,
34 showTrigger = true,33 showTrigger = true,
35 showClear = false,34 showClear = false,
36 startAddon,35 startAddon,
...@@ -38,7 +37,6 @@ function ComboboxInput({...@@ -38,7 +37,6 @@ function ComboboxInput({
38 unstyled = false,37 unstyled = false,
39 ...props38 ...props
40}: Omit<ComboboxPrimitive.Input.Props, "size"> & {39}: Omit<ComboboxPrimitive.Input.Props, "size"> & {
41 inputClassName?: string;
42 showTrigger?: boolean;40 showTrigger?: boolean;
43 showClear?: boolean;41 showClear?: boolean;
44 startAddon?: React.ReactNode;42 startAddon?: React.ReactNode;
...@@ -71,7 +69,10 @@ function ComboboxInput({...@@ -71,7 +69,10 @@ function ComboboxInput({
71 data-slot="combobox-input"69 data-slot="combobox-input"
72 render={70 render={
73 <Input71 <Input
74 className={cn("has-disabled:opacity-100", inputClassName)}72 className={cn(
73 "has-disabled:opacity-100",
74 unstyled && "rounded-none bg-transparent text-sm",
75 )}
75 nativeInput76 nativeInput
76 size={sizeValue}77 size={sizeValue}
77 unstyled={unstyled}78 unstyled={unstyled}
...@@ -116,7 +117,6 @@ function ComboboxSearchInput(props: React.ComponentProps<typeof ComboboxInput>)...@@ -116,7 +117,6 @@ function ComboboxSearchInput(props: React.ComponentProps<typeof ComboboxInput>)
116 <ComboboxInput117 <ComboboxInput
117 {...props}118 {...props}
118 className="[&_input]:h-6.5 [&_input]:ps-5 [&_input]:font-sans [&_input]:leading-6.5"119 className="[&_input]:h-6.5 [&_input]:ps-5 [&_input]:font-sans [&_input]:leading-6.5"
119 inputClassName="rounded-none bg-transparent text-sm"
120 showTrigger={false}120 showTrigger={false}
121 size="sm"121 size="sm"
122 unstyled122 unstyled
...@@ -185,12 +185,10 @@ function ComboboxPopup({...@@ -185,12 +185,10 @@ function ComboboxPopup({
185185
186function ComboboxItem({186function ComboboxItem({
187 className,187 className,
188 contentClassName,
189 children,188 children,
190 hideIndicator: _hideIndicator = false,189 hideIndicator: _hideIndicator = false,
191 ...props190 ...props
192}: ComboboxPrimitive.Item.Props & {191}: ComboboxPrimitive.Item.Props & {
193 contentClassName?: string;
194 hideIndicator?: boolean;192 hideIndicator?: boolean;
195}) {193}) {
196 return (194 return (
...@@ -202,11 +200,9 @@ function ComboboxItem({...@@ -202,11 +200,9 @@ function ComboboxItem({
202 data-slot="combobox-item"200 data-slot="combobox-item"
203 {...props}201 {...props}
204 >202 >
203 {/* Children lay out as one row: a label that truncates, then any trailing meta. */}
205 <div204 <div
206 className={cn(205 className="flex min-w-0 flex-1 items-center gap-2 [&_svg:not([class*='text-'])]:text-muted-foreground"
207 "min-w-0 flex-1 [&_svg:not([class*='text-'])]:text-muted-foreground",
208 contentClassName,
209 )}
210 data-slot="combobox-item-content"206 data-slot="combobox-item-content"
211 >207 >
212 {children}208 {children}
apps/web/src/components/ui/command.tsx+2-10
...@@ -93,19 +93,11 @@ function Command({...@@ -93,19 +93,11 @@ function Command({
9393
94function CommandInput({94function CommandInput({
95 className,95 className,
96 wrapperClassName,
97 placeholder,96 placeholder,
98 ...props97 ...props
99}: React.ComponentProps<typeof AutocompleteInput> & {98}: React.ComponentProps<typeof AutocompleteInput>) {
100 wrapperClassName?: string | undefined;
101}) {
102 return (99 return (
103 <div100 <div className="px-[var(--command-shell-inset)] py-1.5 [&_[data-slot=autocomplete-start-addon]]:ps-[calc(var(--command-shell-inset)+0.0625rem)]">
104 className={cn(
105 "px-[var(--command-shell-inset)] py-1.5 [&_[data-slot=autocomplete-start-addon]]:ps-[calc(var(--command-shell-inset)+0.0625rem)]",
106 wrapperClassName,
107 )}
108 >
109 <AutocompleteInput101 <AutocompleteInput
110 autoFocus102 autoFocus
111 className={cn(103 className={cn(
apps/web/src/components/ui/dialog.tsx+4-6
...@@ -61,24 +61,22 @@ function DialogPopup({...@@ -61,24 +61,22 @@ function DialogPopup({
61 children,61 children,
62 showCloseButton = true,62 showCloseButton = true,
63 bottomStickOnMobile = true,63 bottomStickOnMobile = true,
64 backdropClassName,
65 viewportClassName,
66 variant = "default",64 variant = "default",
67 ...props65 ...props
68}: DialogPrimitive.Popup.Props & {66}: DialogPrimitive.Popup.Props & {
69 showCloseButton?: boolean;67 showCloseButton?: boolean;
70 bottomStickOnMobile?: boolean;68 bottomStickOnMobile?: boolean;
71 backdropClassName?: string;
72 viewportClassName?: string;
73 variant?: "default" | "media";69 variant?: "default" | "media";
74}) {70}) {
75 return (71 return (
76 <DialogPortal>72 <DialogPortal>
77 <DialogBackdrop className={backdropClassName} variant={variant} />73 {/* Media opens from inside other overlays (a composer chip, a popover), so it sits above them. */}
74 <DialogBackdrop className={variant === "media" ? "z-[60]" : undefined} variant={variant} />
78 <DialogViewport75 <DialogViewport
79 className={cn(76 className={cn(
80 bottomStickOnMobile && "max-sm:grid-rows-[1fr_auto] max-sm:p-0 max-sm:pt-12",77 bottomStickOnMobile && "max-sm:grid-rows-[1fr_auto] max-sm:p-0 max-sm:pt-12",
81 viewportClassName,78 variant === "media" &&
79 "z-[60] grid-rows-1 place-items-center px-4 py-6 [-webkit-app-region:no-drag]",
82 )}80 )}
83 >81 >
84 <DialogPrimitive.Popup82 <DialogPrimitive.Popup
apps/web/src/components/ui/popover.tsx+15-6
...@@ -25,10 +25,19 @@ const popoverPopupWidthClassName = {...@@ -25,10 +25,19 @@ const popoverPopupWidthClassName = {
25 lg: "w-96",25 lg: "w-96",
26} as const;26} as const;
2727
28// The inset around the content. "compact" suits dense content (a list, a code excerpt, a
29// row of reactions); "none" is for content that draws its own frame edge to edge.
30const popoverViewportPaddingClassName = {
31 default: "py-4 [--viewport-inline-padding:--spacing(4)]",
32 compact: "py-2 [--viewport-inline-padding:--spacing(3)]",
33 // Rounded to the popup so edge-to-edge content clips to its corners.
34 none: "rounded-[calc(var(--radius-lg)-1px)] py-0 [--viewport-inline-padding:0px]",
35} as const;
36
28function PopoverPopup({37function PopoverPopup({
29 children,38 children,
30 className,39 className,
31 viewportClassName,40 padding = "default",
32 width = "auto",41 width = "auto",
33 side = "bottom",42 side = "bottom",
34 align = "center",43 align = "center",
...@@ -39,7 +48,7 @@ function PopoverPopup({...@@ -39,7 +48,7 @@ function PopoverPopup({
39 anchor,48 anchor,
40 ...props49 ...props
41}: PopoverPrimitive.Popup.Props & {50}: PopoverPrimitive.Popup.Props & {
42 viewportClassName?: string;51 padding?: keyof typeof popoverViewportPaddingClassName;
43 side?: PopoverPrimitive.Positioner.Props["side"];52 side?: PopoverPrimitive.Positioner.Props["side"];
44 align?: PopoverPrimitive.Positioner.Props["align"];53 align?: PopoverPrimitive.Positioner.Props["align"];
45 sideOffset?: PopoverPrimitive.Positioner.Props["sideOffset"];54 sideOffset?: PopoverPrimitive.Positioner.Props["sideOffset"];
...@@ -78,11 +87,11 @@ function PopoverPopup({...@@ -78,11 +87,11 @@ function PopoverPopup({
78 >87 >
79 <Viewport88 <Viewport
80 className={cn(89 className={cn(
81 "relative size-full max-h-(--available-height) overflow-clip px-(--viewport-inline-padding) py-4 [--viewport-inline-padding:--spacing(4)] has-data-[slot=calendar]:p-2 data-instant:transition-none **:data-current:data-ending-style:opacity-0 **:data-current:data-starting-style:opacity-0 **:data-previous:data-ending-style:opacity-0 **:data-previous:data-starting-style:opacity-0 **:data-current:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-current:opacity-100 **:data-previous:opacity-100 **:data-current:transition-opacity **:data-previous:transition-opacity",90 "relative size-full max-h-(--available-height) overflow-clip px-(--viewport-inline-padding) has-data-[slot=calendar]:p-2 data-instant:transition-none **:data-current:data-ending-style:opacity-0 **:data-current:data-starting-style:opacity-0 **:data-previous:data-ending-style:opacity-0 **:data-previous:data-starting-style:opacity-0 **:data-current:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-current:opacity-100 **:data-previous:opacity-100 **:data-current:transition-opacity **:data-previous:transition-opacity",
82 tooltipStyle91 tooltipStyle && padding === "default"
83 ? "py-1 [--viewport-inline-padding:--spacing(2)]"92 ? "py-1 [--viewport-inline-padding:--spacing(2)]"
84 : "not-data-transitioning:overflow-y-auto",93 : popoverViewportPaddingClassName[padding],
85 viewportClassName,94 !tooltipStyle && "not-data-transitioning:overflow-y-auto",
86 )}95 )}
87 data-slot="popover-viewport"96 data-slot="popover-viewport"
88 >97 >
apps/web/src/components/ui/select.tsx-3
...@@ -102,7 +102,6 @@ function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {...@@ -102,7 +102,6 @@ function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {
102102
103function SelectPopup({103function SelectPopup({
104 className,104 className,
105 popupClassName,
106 children,105 children,
107 side = "bottom",106 side = "bottom",
108 sideOffset = 4,107 sideOffset = 4,
...@@ -113,7 +112,6 @@ function SelectPopup({...@@ -113,7 +112,6 @@ function SelectPopup({
113 anchor,112 anchor,
114 ...props113 ...props
115}: SelectPrimitive.Popup.Props & {114}: SelectPrimitive.Popup.Props & {
116 popupClassName?: string;
117 side?: SelectPrimitive.Positioner.Props["side"];115 side?: SelectPrimitive.Positioner.Props["side"];
118 sideOffset?: SelectPrimitive.Positioner.Props["sideOffset"];116 sideOffset?: SelectPrimitive.Positioner.Props["sideOffset"];
119 align?: SelectPrimitive.Positioner.Props["align"];117 align?: SelectPrimitive.Positioner.Props["align"];
...@@ -149,7 +147,6 @@ function SelectPopup({...@@ -149,7 +147,6 @@ function SelectPopup({
149 className={cn(147 className={cn(
150 "dropdown-glass relative h-full rounded-lg shadow-[0_16px_40px_-18px_rgb(0_0_0/55%)] dark:shadow-[0_18px_44px_-18px_rgb(0_0_0/80%)]",148 "dropdown-glass relative h-full rounded-lg shadow-[0_16px_40px_-18px_rgb(0_0_0/55%)] dark:shadow-[0_18px_44px_-18px_rgb(0_0_0/80%)]",
151 matchTriggerWidth && "min-w-(--anchor-width)",149 matchTriggerWidth && "min-w-(--anchor-width)",
152 popupClassName,
153 )}150 )}
154 >151 >
155 <SelectPrimitive.List152 <SelectPrimitive.List
apps/web/src/components/ui/sheet.tsx+10-12
...@@ -10,11 +10,13 @@ const Sheet = SheetPrimitive.Root;...@@ -10,11 +10,13 @@ const Sheet = SheetPrimitive.Root;
1010
11const SheetPortal = SheetPrimitive.Portal;11const SheetPortal = SheetPrimitive.Portal;
1212
13// Sheets are docked panels, not dialogs: their layer (--z-sheet) sits under dialogs that open
14// from inside them and under anything the app floats above panels.
13function SheetBackdrop({ className, ...props }: SheetPrimitive.Backdrop.Props) {15function SheetBackdrop({ className, ...props }: SheetPrimitive.Backdrop.Props) {
14 return (16 return (
15 <SheetPrimitive.Backdrop17 <SheetPrimitive.Backdrop
16 className={cn(18 className={cn(
17 "fixed inset-0 z-50 bg-background/60 backdrop-blur-xs transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0",19 "fixed inset-0 z-(--z-sheet) bg-background/60 backdrop-blur-xs transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0",
18 className,20 className,
19 )}21 )}
20 data-slot="sheet-backdrop"22 data-slot="sheet-backdrop"
...@@ -35,7 +37,7 @@ function SheetViewport({...@@ -35,7 +37,7 @@ function SheetViewport({
35 return (37 return (
36 <SheetPrimitive.Viewport38 <SheetPrimitive.Viewport
37 className={cn(39 className={cn(
38 "fixed inset-0 z-50 grid",40 "fixed inset-0 z-(--z-sheet) grid",
39 side === "bottom" && "grid grid-rows-[1fr_auto] pt-12",41 side === "bottom" && "grid grid-rows-[1fr_auto] pt-12",
40 side === "top" && "grid grid-rows-[auto_1fr] pb-12",42 side === "top" && "grid grid-rows-[auto_1fr] pb-12",
41 side === "left" && "flex justify-start",43 side === "left" && "flex justify-start",
...@@ -55,8 +57,6 @@ function SheetPopup({...@@ -55,8 +57,6 @@ function SheetPopup({
55 showCloseButton = true,57 showCloseButton = true,
56 keepMounted = false,58 keepMounted = false,
57 transitionDurationMs,59 transitionDurationMs,
58 backdropClassName,
59 viewportClassName,
60 side = "right",60 side = "right",
61 variant = "default",61 variant = "default",
62 style,62 style,
...@@ -65,8 +65,6 @@ function SheetPopup({...@@ -65,8 +65,6 @@ function SheetPopup({
65 showCloseButton?: boolean;65 showCloseButton?: boolean;
66 keepMounted?: boolean;66 keepMounted?: boolean;
67 transitionDurationMs?: number;67 transitionDurationMs?: number;
68 backdropClassName?: string;
69 viewportClassName?: string;
70 side?: "right" | "left" | "top" | "bottom";68 side?: "right" | "left" | "top" | "bottom";
71 variant?: "default" | "inset";69 variant?: "default" | "inset";
72}) {70}) {
...@@ -79,14 +77,14 @@ function SheetPopup({...@@ -79,14 +77,14 @@ function SheetPopup({
79 return (77 return (
80 <SheetPortal keepMounted={keepMounted}>78 <SheetPortal keepMounted={keepMounted}>
81 <SheetBackdrop79 <SheetBackdrop
82 className={cn(80 className={
83 instant &&81 instant
84 "transition-none! data-ending-style:opacity-100! data-starting-style:opacity-100!",82 ? "transition-none! data-ending-style:opacity-100! data-starting-style:opacity-100!"
85 backdropClassName,83 : undefined
86 )}84 }
87 style={transitionStyle}85 style={transitionStyle}
88 />86 />
89 <SheetViewport className={viewportClassName} side={side} variant={variant}>87 <SheetViewport side={side} variant={variant}>
90 <SheetPrimitive.Popup88 <SheetPrimitive.Popup
91 className={cn(89 className={cn(
92 "relative flex max-h-full min-h-0 w-full min-w-0 flex-col bg-popover not-dark:bg-clip-padding text-popover-foreground shadow-lg/5 transition-[opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:opacity-0 data-starting-style:opacity-0 max-sm:before:hidden dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",90 "relative flex max-h-full min-h-0 w-full min-w-0 flex-col bg-popover not-dark:bg-clip-padding text-popover-foreground shadow-lg/5 transition-[opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:opacity-0 data-starting-style:opacity-0 max-sm:before:hidden dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
apps/web/src/index.css+3
...@@ -101,6 +101,9 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil...@@ -101,6 +101,9 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil
101 --command-shell-inset: 0.5rem;101 --command-shell-inset: 0.5rem;
102 --command-content-inset: 1rem;102 --command-content-inset: 1rem;
103 --floating-content-inset: 0.75rem;103 --floating-content-inset: 0.75rem;
104 /* App layer order: docked sheets, then the floating preview player (47–49, see
105 previewMiniPlayerLayout.ts), then dialogs and popovers (50 and up). */
106 --z-sheet: 46;
104 --glass-blur: 12px;107 --glass-blur: 12px;
105 --glass-opacity: 80%;108 --glass-opacity: 80%;
106 --glass-saturation: 1.14;109 --glass-saturation: 1.14;
apps/web/src/rightPanelLayout.ts-2
...@@ -1,5 +1,3 @@...@@ -1,5 +1,3 @@
1export const RIGHT_PANEL_INLINE_LAYOUT_MEDIA_QUERY = "(max-width: 980px)";1export const RIGHT_PANEL_INLINE_LAYOUT_MEDIA_QUERY = "(max-width: 980px)";
2// Applied only while a floating preview overlaps the compact sheet.
3export const RIGHT_PANEL_SHEET_LAYER_CLASS_NAME = "z-[35]";
4export const RIGHT_PANEL_SHEET_CLASS_NAME =2export const RIGHT_PANEL_SHEET_CLASS_NAME =
5 "w-[min(42vw,28rem)] min-w-80 max-w-[28rem] p-0 max-[760px]:w-[min(88vw,24rem)] max-[760px]:min-w-0 wco:mt-[env(titlebar-area-height)] wco:h-[calc(100%-env(titlebar-area-height))] wco:max-h-[calc(100%-env(titlebar-area-height))]";3 "w-[min(42vw,28rem)] min-w-80 max-w-[28rem] p-0 max-[760px]:w-[min(88vw,24rem)] max-[760px]:min-w-0 wco:mt-[env(titlebar-area-height)] wco:h-[calc(100%-env(titlebar-area-height))] wco:max-h-[calc(100%-env(titlebar-area-height))]";
scripts/lint-restyle-ceiling.ts+1-1
...@@ -8,7 +8,7 @@ import * as NodeURL from "node:url";...@@ -8,7 +8,7 @@ import * as NodeURL from "node:url";
8// components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the8// components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the
9// count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you9// count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you
10// migrate a file, and delete this script when the rule becomes an error.10// migrate a file, and delete this script when the rule becomes an error.
11export const RESTYLE_CEILING = 603;11export const RESTYLE_CEILING = 582;
1212
13const RULE = "shadcn(no-restyle)";13const RULE = "shadcn(no-restyle)";
1414