authorgravatar for jakeleventhal@me.comJake Leventhal <jakeleventhal@me.com> 2026-10-03 20:10:58-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-03 21:10:58-03:00
logf2cc80a7a44ee05c1f39442779f2b719e31faeb5
tree07756e7afceb14f517345132523aed31b5349a8d
parent44bd4c9cafa61a415f76fbb261f321a158660577
signature Signed by PGP key B5690EEEBB952194

feat(web): morph composer and panel action icons (#14924)

Co-authored-by: maria-rcks <maria@kuuro.net>

31 files changed, 278 insertions(+), 230 deletions(-)

apps/web/package.json+2
...@@ -48,8 +48,10 @@...@@ -48,8 +48,10 @@
48 "jose": "catalog:",48 "jose": "catalog:",
49 "jsonc-parser": "3.3.1",49 "jsonc-parser": "3.3.1",
50 "jszip": "3.10.1",50 "jszip": "3.10.1",
51 "lucide": "^0.564.0",
51 "lucide-react": "^0.564.0",52 "lucide-react": "^0.564.0",
52 "mermaid": "^11.17.2",53 "mermaid": "^11.17.2",
54 "morphicons": "^1.7.1",
53 "react": "19.2.6",55 "react": "19.2.6",
54 "react-dom": "19.2.6",56 "react-dom": "19.2.6",
55 "react-markdown": "^10.1.0",57 "react-markdown": "^10.1.0",
apps/web/src/components/ChatMarkdown.tsx+5-7
...@@ -5,10 +5,8 @@ import {...@@ -5,10 +5,8 @@ import {
5 encodeComposerContextClipboardHtml,5 encodeComposerContextClipboardHtml,
6} from "@t3tools/shared/composerContextClipboard";6} from "@t3tools/shared/composerContextClipboard";
7import {7import {
8 CheckIcon,
9 ChevronRightIcon,8 ChevronRightIcon,
10 CodeIcon,9 CodeIcon,
11 CopyIcon,
12 FileSpreadsheetIcon,10 FileSpreadsheetIcon,
13 FileTextIcon,11 FileTextIcon,
14 GlobeIcon,12 GlobeIcon,
...@@ -16,10 +14,8 @@ import {...@@ -16,10 +14,8 @@ import {
16 InfoIcon,14 InfoIcon,
17 LightbulbIcon,15 LightbulbIcon,
18 MailIcon,16 MailIcon,
19 Maximize2Icon,
20 MessageSquareIcon,17 MessageSquareIcon,
21 MessageSquareWarningIcon,18 MessageSquareWarningIcon,
22 Minimize2Icon,
23 OctagonAlertIcon,19 OctagonAlertIcon,
24 PlayIcon,20 PlayIcon,
25 PresentationIcon,21 PresentationIcon,
...@@ -29,6 +25,7 @@ import {...@@ -29,6 +25,7 @@ import {
29 WrapTextIcon,25 WrapTextIcon,
30 type LucideIcon,26 type LucideIcon,
31} from "lucide-react";27} from "lucide-react";
28import { Check, Copy, Maximize2, Minimize2 } from "lucide";
32import type {29import type {
33 AssetResource,30 AssetResource,
34 EnvironmentId,31 EnvironmentId,
...@@ -123,6 +120,7 @@ import {...@@ -123,6 +120,7 @@ import {
123import { hasSpecificPierreIconForFileName, syntheticFileNameForLanguageId } from "../pierre-icons";120import { hasSpecificPierreIconForFileName, syntheticFileNameForLanguageId } from "../pierre-icons";
124import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";121import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";
125import { Button } from "./ui/button";122import { Button } from "./ui/button";
123import { MorphIcon } from "~/components/MorphIcon";
126import { ContextChip } from "./ContextChip";124import { ContextChip } from "./ContextChip";
127import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from "./ui/collapsible";125import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from "./ui/collapsible";
128import { ScrollArea } from "./ui/scroll-area";126import { ScrollArea } from "./ui/scroll-area";
...@@ -849,7 +847,7 @@ function MarkdownTable({ children, ...props }: React.ComponentProps<"table">) {...@@ -849,7 +847,7 @@ function MarkdownTable({ children, ...props }: React.ComponentProps<"table">) {
849 />847 />
850 }848 }
851 >849 >
852 {expanded ? <Minimize2Icon className="size-3" /> : <Maximize2Icon className="size-3" />}850 <MorphIcon className="size-3" icon={expanded ? Minimize2 : Maximize2} />
853 </TooltipTrigger>851 </TooltipTrigger>
854 <TooltipPopup side="top">{expandLabel}</TooltipPopup>852 <TooltipPopup side="top">{expandLabel}</TooltipPopup>
855 </Tooltip>853 </Tooltip>
...@@ -869,7 +867,7 @@ function MarkdownTable({ children, ...props }: React.ComponentProps<"table">) {...@@ -869,7 +867,7 @@ function MarkdownTable({ children, ...props }: React.ComponentProps<"table">) {
869 />867 />
870 }868 }
871 >869 >
872 {copied ? <CheckIcon className="size-3" /> : <CopyIcon className="size-3" />}870 <MorphIcon className="size-3" icon={copied ? Check : Copy} />
873 </TooltipTrigger>871 </TooltipTrigger>
874 <TooltipPopup side="top">{copyLabel}</TooltipPopup>872 <TooltipPopup side="top">{copyLabel}</TooltipPopup>
875 </Tooltip>873 </Tooltip>
...@@ -1063,7 +1061,7 @@ function MarkdownCodeBlock({...@@ -1063,7 +1061,7 @@ function MarkdownCodeBlock({
1063 />1061 />
1064 }1062 }
1065 >1063 >
1066 {copied ? <CheckIcon className="size-3" /> : <CopyIcon className="size-3" />}1064 <MorphIcon className="size-3" icon={copied ? Check : Copy} />
1067 </TooltipTrigger>1065 </TooltipTrigger>
1068 <TooltipPopup side="top">{copyLabel}</TooltipPopup>1066 <TooltipPopup side="top">{copyLabel}</TooltipPopup>
1069 </Tooltip>1067 </Tooltip>
apps/web/src/components/DiffFilePathCopyButton.tsx+7-2
...@@ -1,12 +1,14 @@...@@ -1,12 +1,14 @@
1import { CheckIcon, CopyIcon } from "lucide-react";1import { Check, Copy } from "lucide";
2import { useRef } from "react";2import { useRef } from "react";
3import { useCopyToClipboard } from "../hooks/useCopyToClipboard";3import { useCopyToClipboard } from "../hooks/useCopyToClipboard";
4import { cn } from "../lib/utils";
4import {5import {
5 ANCHORED_COPY_TOAST_TIMEOUT_MS,6 ANCHORED_COPY_TOAST_TIMEOUT_MS,
6 showAnchoredCopyErrorToast,7 showAnchoredCopyErrorToast,
7 showAnchoredCopySuccessToast,8 showAnchoredCopySuccessToast,
8} from "./ui/anchoredCopyToast";9} from "./ui/anchoredCopyToast";
9import { Button } from "./ui/button";10import { Button } from "./ui/button";
11import { MorphIcon } from "~/components/MorphIcon";
10import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";12import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";
1113
12export function DiffFilePathCopyButton({ filePath }: { filePath: string }) {14export function DiffFilePathCopyButton({ filePath }: { filePath: string }) {
...@@ -30,7 +32,10 @@ export function DiffFilePathCopyButton({ filePath }: { filePath: string }) {...@@ -30,7 +32,10 @@ export function DiffFilePathCopyButton({ filePath }: { filePath: string }) {
30 />32 />
31 }33 }
32 >34 >
33 {isCopied ? <CheckIcon className="size-3 text-success" /> : <CopyIcon className="size-3" />}35 <MorphIcon
36 className={cn("size-3", isCopied && "text-success")}
37 icon={isCopied ? Check : Copy}
38 />
34 </TooltipTrigger>39 </TooltipTrigger>
35 <TooltipPopup>40 <TooltipPopup>
36 <p>{isCopied ? "Copied" : "Copy path"}</p>41 <p>{isCopied ? "Copied" : "Copy path"}</p>
apps/web/src/components/DiffPanel.tsx+10-17
...@@ -12,15 +12,13 @@ import {...@@ -12,15 +12,13 @@ import {
12 ArrowRightIcon,12 ArrowRightIcon,
13 CheckIcon,13 CheckIcon,
14 ChevronDownIcon,14 ChevronDownIcon,
15 ChevronRightIcon,
16 ChevronsDownUpIcon,
17 ChevronsUpDownIcon,
18 Columns2Icon,15 Columns2Icon,
19 FolderTreeIcon,16 FolderTreeIcon,
20 PilcrowIcon,17 PilcrowIcon,
21 Rows3Icon,18 Rows3Icon,
22 TextWrapIcon,19 TextWrapIcon,
23} from "lucide-react";20} from "lucide-react";
21import { ChevronDown, ChevronRight, ChevronsDownUp, ChevronsUpDown } from "lucide";
24import * as Schema from "effect/Schema";22import * as Schema from "effect/Schema";
25import * as DateTime from "effect/DateTime";23import * as DateTime from "effect/DateTime";
26import { useCallback, useEffect, useMemo, useRef, useState } from "react";24import { useCallback, useEffect, useMemo, useRef, useState } from "react";
...@@ -58,6 +56,7 @@ import { AnnotatableCodeView, type AnnotatableCodeViewHandle } from "./diffs/Ann...@@ -58,6 +56,7 @@ import { AnnotatableCodeView, type AnnotatableCodeViewHandle } from "./diffs/Ann
58import { DiffFileTree } from "./diffs/DiffFileTree";56import { DiffFileTree } from "./diffs/DiffFileTree";
59import { diffFileTreeEntries } from "./diffs/diffFileTree.logic";57import { diffFileTreeEntries } from "./diffs/diffFileTree.logic";
60import { Button } from "./ui/button";58import { Button } from "./ui/button";
59import { MorphIcon } from "~/components/MorphIcon";
61import { ToggleGroup, Toggle } from "./ui/toggle-group";60import { ToggleGroup, Toggle } from "./ui/toggle-group";
62import { Switch } from "./ui/switch";61import { Switch } from "./ui/switch";
63import {62import {
...@@ -873,11 +872,10 @@ export default function DiffPanel({...@@ -873,11 +872,10 @@ export default function DiffPanel({
873 />872 />
874 }873 }
875 >874 >
876 {allDiffFilesCollapsed ? (875 <MorphIcon
877 <ChevronsUpDownIcon className="size-3.5" />876 className="size-3.5"
878 ) : (877 icon={allDiffFilesCollapsed ? ChevronsUpDown : ChevronsDownUp}
879 <ChevronsDownUpIcon className="size-3.5" />878 />
880 )}
881 </TooltipTrigger>879 </TooltipTrigger>
882 <TooltipPopup side="top">880 <TooltipPopup side="top">
883 {allDiffFilesCollapsed ? "Expand all files" : "Collapse all files"}881 {allDiffFilesCollapsed ? "Expand all files" : "Collapse all files"}
...@@ -1133,15 +1131,10 @@ export default function DiffPanel({...@@ -1133,15 +1131,10 @@ export default function DiffPanel({
1133 />1131 />
1134 }1132 }
1135 >1133 >
1136 {collapsed ? (1134 <MorphIcon
1137 <ChevronRightIcon1135 className={cn("size-4", getDiffCollapseIconClassName(fileDiff))}
1138 className={cn("size-4", getDiffCollapseIconClassName(fileDiff))}1136 icon={collapsed ? ChevronRight : ChevronDown}
1139 />1137 />
1140 ) : (
1141 <ChevronDownIcon
1142 className={cn("size-4", getDiffCollapseIconClassName(fileDiff))}
1143 />
1144 )}
1145 </TooltipTrigger>1138 </TooltipTrigger>
1146 <TooltipPopup side="top">1139 <TooltipPopup side="top">
1147 {collapsed ? "Expand diff" : "Collapse diff"}1140 {collapsed ? "Expand diff" : "Collapse diff"}
apps/web/src/components/MorphIcon.tsx created+6
...@@ -0,0 +1,6 @@
1import { MorphIcon as BaseMorphIcon, type MorphIconProps } from "morphicons/react";
2
3/** Renders `lucide` icon data and morphs between shapes when `icon` changes. */
4export function MorphIcon({ reducedMotion = "user", ...props }: MorphIconProps) {
5 return <BaseMorphIcon reducedMotion={reducedMotion} {...props} />;
6}
apps/web/src/components/RightPanelTabs.tsx+6-7
...@@ -23,9 +23,8 @@ import {...@@ -23,9 +23,8 @@ import {
23 Globe2,23 Globe2,
24 Plus,24 Plus,
25 TerminalSquare,25 TerminalSquare,
26 Volume2,
27 VolumeOff,
28} from "lucide-react";26} from "lucide-react";
27import { Volume2, VolumeOff } from "lucide";
29import {28import {
30 type KeyboardEvent as ReactKeyboardEvent,29 type KeyboardEvent as ReactKeyboardEvent,
31 type MouseEvent as ReactMouseEvent,30 type MouseEvent as ReactMouseEvent,
...@@ -44,6 +43,7 @@ import type { RightPanelSurface } from "~/rightPanelStore";...@@ -44,6 +43,7 @@ import type { RightPanelSurface } from "~/rightPanelStore";
44import { cn } from "~/lib/utils";43import { cn } from "~/lib/utils";
45import { readLocalApi } from "~/localApi";44import { readLocalApi } from "~/localApi";
46import { Button } from "~/components/ui/button";45import { Button } from "~/components/ui/button";
46import { MorphIcon } from "~/components/MorphIcon";
47import { AndroidIcon, AppleIcon } from "~/components/Icons";47import { AndroidIcon, AppleIcon } from "~/components/Icons";
48import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip";48import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip";
49import { Kbd } from "~/components/ui/kbd";49import { Kbd } from "~/components/ui/kbd";
...@@ -1149,11 +1149,10 @@ export function RightPanelTabs(props: RightPanelTabsProps) {...@@ -1149,11 +1149,10 @@ export function RightPanelTabs(props: RightPanelTabsProps) {
1149 .catch(() => undefined);1149 .catch(() => undefined);
1150 }}1150 }}
1151 >1151 >
1152 {audio === "muted" ? (1152 <MorphIcon
1153 <VolumeOff className="size-3" />1153 className="size-3"
1154 ) : (1154 icon={audio === "muted" ? VolumeOff : Volume2}
1155 <Volume2 className="size-3" />1155 />
1156 )}
1157 </button>1156 </button>
1158 }1157 }
1159 />1158 />
apps/web/src/components/chat/ChangedFilesTree.tsx+11-18
...@@ -6,20 +6,15 @@ import {...@@ -6,20 +6,15 @@ import {
6 summarizeTurnDiffStats,6 summarizeTurnDiffStats,
7 type TurnDiffTreeNode,7 type TurnDiffTreeNode,
8} from "../../lib/turnDiffTree";8} from "../../lib/turnDiffTree";
9import {9import { ChevronRightIcon, FileDiffIcon } from "lucide-react";
10 ChevronsDownUpIcon,10import { ChevronsDownUp, ChevronsUpDown, Folder, FolderClosed } from "lucide";
11 ChevronsUpDownIcon,
12 ChevronRightIcon,
13 FileDiffIcon,
14 FolderIcon,
15 FolderClosedIcon,
16} from "lucide-react";
17import { cn } from "~/lib/utils";11import { cn } from "~/lib/utils";
18import { DiffStatLabel, hasNonZeroStat } from "./DiffStatLabel";12import { DiffStatLabel, hasNonZeroStat } from "./DiffStatLabel";
19import { PierreEntryIcon } from "./PierreEntryIcon";13import { PierreEntryIcon } from "./PierreEntryIcon";
20import { Button } from "../ui/button";14import { Button } from "../ui/button";
21import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";15import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
22import { MiddleTruncate } from "../ui/middle-truncate";16import { MiddleTruncate } from "../ui/middle-truncate";
17import { MorphIcon } from "~/components/MorphIcon";
2318
24const EMPTY_DIRECTORY_OVERRIDES: Record<string, boolean> = {};19const EMPTY_DIRECTORY_OVERRIDES: Record<string, boolean> = {};
2520
...@@ -86,11 +81,10 @@ export const ChangedFilesCard = memo(function ChangedFilesCard(props: {...@@ -86,11 +81,10 @@ export const ChangedFilesCard = memo(function ChangedFilesCard(props: {
86 />81 />
87 }82 }
88 >83 >
89 {allDirectoriesExpanded ? (84 <MorphIcon
90 <ChevronsDownUpIcon className="size-3" />85 className="size-3"
91 ) : (86 icon={allDirectoriesExpanded ? ChevronsDownUp : ChevronsUpDown}
92 <ChevronsUpDownIcon className="size-3" />87 />
93 )}
94 </TooltipTrigger>88 </TooltipTrigger>
95 <TooltipPopup side="top">89 <TooltipPopup side="top">
96 {allDirectoriesExpanded ? "Collapse all folders" : "Expand all folders"}90 {allDirectoriesExpanded ? "Collapse all folders" : "Expand all folders"}
...@@ -195,11 +189,10 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: {...@@ -195,11 +189,10 @@ export const ChangedFilesTree = memo(function ChangedFilesTree(props: {
195 isExpanded && "rotate-90",189 isExpanded && "rotate-90",
196 )}190 )}
197 />191 />
198 {isExpanded ? (192 <MorphIcon
199 <FolderIcon className="size-3.5 shrink-0 text-muted-foreground/75" />193 className="size-3.5 shrink-0 text-muted-foreground/75"
200 ) : (194 icon={isExpanded ? Folder : FolderClosed}
201 <FolderClosedIcon className="size-3.5 shrink-0 text-muted-foreground/75" />195 />
202 )}
203 <span className="truncate font-mono text-2xs text-muted-foreground/90 group-hover:text-foreground/90">196 <span className="truncate font-mono text-2xs text-muted-foreground/90 group-hover:text-foreground/90">
204 {node.name}197 {node.name}
205 </span>198 </span>
apps/web/src/components/chat/ComposerPrimaryActions.tsx+4-11
...@@ -1,12 +1,7 @@...@@ -1,12 +1,7 @@
1import { memo, type MouseEventHandler, type PointerEventHandler } from "react";1import { memo, type MouseEventHandler, type PointerEventHandler } from "react";
2import {2import { CheckIcon, ChevronDownIcon, ChevronLeftIcon, PlayIcon } from "lucide-react";
3 CheckIcon,3import { CornerUpRight, ListPlus } from "lucide";
4 ChevronDownIcon,4import { MorphIcon } from "~/components/MorphIcon";
5 ChevronLeftIcon,
6 CornerUpRightIcon,
7 ListPlusIcon,
8 PlayIcon,
9} from "lucide-react";
10import { useEnvironmentIdentificationMode } from "~/hooks/useSettings";5import { useEnvironmentIdentificationMode } from "~/hooks/useSettings";
11import { cn } from "~/lib/utils";6import { cn } from "~/lib/utils";
12import { useShortcutModifierState } from "../../shortcutModifierState";7import { useShortcutModifierState } from "../../shortcutModifierState";
...@@ -315,10 +310,8 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({...@@ -315,10 +310,8 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({
315 <PlayIcon className="size-4 fill-current" aria-hidden="true" />310 <PlayIcon className="size-4 fill-current" aria-hidden="true" />
316 ) : isEditingQueuedMessage ? (311 ) : isEditingQueuedMessage ? (
317 <CheckIcon className="size-4" aria-hidden="true" />312 <CheckIcon className="size-4" aria-hidden="true" />
318 ) : isQueuing ? (
319 <ListPlusIcon className="size-4" aria-hidden="true" />
320 ) : isRunning ? (313 ) : isRunning ? (
321 <CornerUpRightIcon className="size-4" aria-hidden="true" />314 <MorphIcon className="size-4" icon={isQueuing ? ListPlus : CornerUpRight} />
322 ) : (315 ) : (
323 <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">316 <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
324 <path317 <path
apps/web/src/components/chat/ExpandedImageDialog.tsx+8-3
...@@ -7,8 +7,10 @@ import {...@@ -7,8 +7,10 @@ import {
7 type ReactNode,7 type ReactNode,
8 type KeyboardEvent,8 type KeyboardEvent,
9} from "react";9} from "react";
10import { ChevronLeftIcon, ChevronRightIcon, ImageIcon, TextIcon, XIcon } from "lucide-react";10import { ChevronLeftIcon, ChevronRightIcon, XIcon } from "lucide-react";
11import { Image as ImageGlyph, Text as TextGlyph } from "lucide";
11import { Button } from "../ui/button";12import { Button } from "../ui/button";
13import { MorphIcon } from "~/components/MorphIcon";
12import { Dialog, DialogPopup, DialogTitle } from "../ui/dialog";14import { Dialog, DialogPopup, DialogTitle } from "../ui/dialog";
13import type { ExpandedImageItem, ExpandedImagePreview } from "./ExpandedImagePreview";15import type { ExpandedImageItem, ExpandedImagePreview } from "./ExpandedImagePreview";
14import { resolveExternalWebLinkHost } from "./externalLinkContextMenu";16import { resolveExternalWebLinkHost } from "./externalLinkContextMenu";
...@@ -165,7 +167,6 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({...@@ -165,7 +167,6 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({
165 : accessibilityDetails?.format === "json"167 : accessibilityDetails?.format === "json"
166 ? "Show accessibility JSON"168 ? "Show accessibility JSON"
167 : "Show extracted text";169 : "Show extracted text";
168 const ContentsIcon = showingAccessibilityDetails ? ImageIcon : TextIcon;
169170
170 return (171 return (
171 <Dialog172 <Dialog
...@@ -260,7 +261,11 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({...@@ -260,7 +261,11 @@ export const ExpandedImageDialog = memo(function ExpandedImageDialog({
260 />261 />
261 }262 }
262 >263 >
263 <ContentsIcon className="size-3" aria-hidden="true" />264 <MorphIcon
265 className="size-3"
266 aria-hidden="true"
267 icon={showingAccessibilityDetails ? ImageGlyph : TextGlyph}
268 />
264 </TooltipTrigger>269 </TooltipTrigger>
265 <TooltipPopup side="top">{contentsLabel}</TooltipPopup>270 <TooltipPopup side="top">{contentsLabel}</TooltipPopup>
266 </Tooltip>271 </Tooltip>
apps/web/src/components/chat/MessageCopyButton.tsx+7-2
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1import { memo, useRef } from "react";1import { memo, useRef } from "react";
2import { CopyIcon, CheckIcon } from "lucide-react";2import { Check, Copy } from "lucide";
3import { Button } from "../ui/button";3import { Button } from "../ui/button";
4import { MorphIcon } from "~/components/MorphIcon";
5import { cn } from "~/lib/utils";
4import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";6import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";
5import {7import {
6 ANCHORED_COPY_TOAST_TIMEOUT_MS,8 ANCHORED_COPY_TOAST_TIMEOUT_MS,
...@@ -47,7 +49,10 @@ export const MessageCopyButton = memo(function MessageCopyButton({...@@ -47,7 +49,10 @@ export const MessageCopyButton = memo(function MessageCopyButton({
47 />49 />
48 }50 }
49 >51 >
50 {isCopied ? <CheckIcon className="size-3 text-primary" /> : <CopyIcon className="size-3" />}52 <MorphIcon
53 className={cn("size-3", isCopied && "text-primary")}
54 icon={isCopied ? Check : Copy}
55 />
51 </TooltipTrigger>56 </TooltipTrigger>
52 <TooltipPopup>57 <TooltipPopup>
53 <p>Copy message</p>58 <p>Copy message</p>
apps/web/src/components/chat/MessagesTimeline.tsx+7-4
...@@ -140,12 +140,14 @@ import {...@@ -140,12 +140,14 @@ import {
140 XIcon,140 XIcon,
141 ZapIcon,141 ZapIcon,
142} from "lucide-react";142} from "lucide-react";
143import { ChevronDown, ChevronRight } from "lucide";
143import type {144import type {
144 ComposerContextId,145 ComposerContextId,
145 ComposerContextRecord,146 ComposerContextRecord,
146 KnownComposerContextRecord,147 KnownComposerContextRecord,
147} from "@t3tools/contracts";148} from "@t3tools/contracts";
148import { Button, InlineButton } from "../ui/button";149import { Button, InlineButton } from "../ui/button";
150import { MorphIcon } from "~/components/MorphIcon";
149import { useAssetUrlRefresh, useAssetUrls, useAssetUrlState } from "../../assets/assetUrls";151import { useAssetUrlRefresh, useAssetUrls, useAssetUrlState } from "../../assets/assetUrls";
150import { MediaVideoPlayer } from "../media/MediaVideoPlayer";152import { MediaVideoPlayer } from "../media/MediaVideoPlayer";
151import { getVirtualizedScrollFadeClassName } from "../ui/scroll-area";153import { getVirtualizedScrollFadeClassName } from "../ui/scroll-area";
...@@ -2426,7 +2428,6 @@ function TimelineRowTimestamp({...@@ -2426,7 +2428,6 @@ function TimelineRowTimestamp({
24262428
2427function TurnFoldTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "turn-fold" }> }) {2429function TurnFoldTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "turn-fold" }> }) {
2428 const ctx = use(TimelineRowCtx);2430 const ctx = use(TimelineRowCtx);
2429 const Icon = row.expanded ? ChevronDownIcon : ChevronRightIcon;
24302431
2431 return (2432 return (
2432 <div className="group/timeline-row relative flex items-center gap-1 border-b border-border/60 pb-2 pe-0.5 pt-1">2433 <div className="group/timeline-row relative flex items-center gap-1 border-b border-border/60 pb-2 pe-0.5 pt-1">
...@@ -2438,7 +2439,7 @@ function TurnFoldTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "turn-...@@ -2438,7 +2439,7 @@ function TurnFoldTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "turn-
2438 className="flex cursor-pointer select-none items-center gap-1 rounded-md px-1 text-sm leading-relaxed text-muted-foreground tabular-nums transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70"2439 className="flex cursor-pointer select-none items-center gap-1 rounded-md px-1 text-sm leading-relaxed text-muted-foreground tabular-nums transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70"
2439 >2440 >
2440 <span>{row.label}</span>2441 <span>{row.label}</span>
2441 <Icon className="size-3.5" />2442 <MorphIcon className="size-3.5" icon={row.expanded ? ChevronDown : ChevronRight} />
2442 </button>2443 </button>
2443 <TimelineRowTimestamp2444 <TimelineRowTimestamp
2444 createdAt={row.createdAt}2445 createdAt={row.createdAt}
...@@ -2451,7 +2452,6 @@ function TurnFoldTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "turn-...@@ -2451,7 +2452,6 @@ function TurnFoldTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "turn-
24512452
2452function AttemptFoldTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "attempt-fold" }> }) {2453function AttemptFoldTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "attempt-fold" }> }) {
2453 const ctx = use(TimelineRowCtx);2454 const ctx = use(TimelineRowCtx);
2454 const Icon = row.expanded ? ChevronDownIcon : ChevronRightIcon;
24552455
2456 return (2456 return (
2457 <button2457 <button
...@@ -2462,7 +2462,10 @@ function AttemptFoldTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "at...@@ -2462,7 +2462,10 @@ function AttemptFoldTimelineRow({ row }: { row: Extract<TimelineRow, { kind: "at
2462 onClick={() => ctx.onToggleAttemptFold(row.attemptId)}2462 onClick={() => ctx.onToggleAttemptFold(row.attemptId)}
2463 className="flex w-full cursor-pointer select-none items-center gap-2 rounded-md border border-border/60 bg-muted/20 px-2.5 py-2 text-left transition-colors hover:bg-muted/35 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70"2463 className="flex w-full cursor-pointer select-none items-center gap-2 rounded-md border border-border/60 bg-muted/20 px-2.5 py-2 text-left transition-colors hover:bg-muted/35 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring/70"
2464 >2464 >
2465 <Icon className="size-3.5 shrink-0 text-muted-foreground" />2465 <MorphIcon
2466 className="size-3.5 shrink-0 text-muted-foreground"
2467 icon={row.expanded ? ChevronDown : ChevronRight}
2468 />
2466 <span className="text-xs font-medium text-foreground/80">{row.label}</span>2469 <span className="text-xs font-medium text-foreground/80">{row.label}</span>
2467 <span className="text-2xs text-muted-foreground">Partial output retained</span>2470 <span className="text-2xs text-muted-foreground">Partial output retained</span>
2468 </button>2471 </button>
apps/web/src/components/chat/PanelLayoutControls.tsx+4-12
...@@ -1,10 +1,6 @@...@@ -1,10 +1,6 @@
1import {1import { PanelBottomIcon, PanelRightIcon, SquareMenuIcon } from "lucide-react";
2 Maximize2Icon,2import { Maximize2, Minimize2 } from "lucide";
3 Minimize2Icon,3import { MorphIcon } from "~/components/MorphIcon";
4 PanelBottomIcon,
5 PanelRightIcon,
6 SquareMenuIcon,
7} from "lucide-react";
8import { memo, type ReactElement } from "react";4import { memo, type ReactElement } from "react";
95
10import type { ThreadPanelPresentation } from "../../rightPanelLayout";6import type { ThreadPanelPresentation } from "../../rightPanelLayout";
...@@ -163,11 +159,7 @@ export const RightPanelMaximizeControl = memo(function RightPanelMaximizeControl...@@ -163,11 +159,7 @@ export const RightPanelMaximizeControl = memo(function RightPanelMaximizeControl
163 variant="ghost"159 variant="ghost"
164 size="sm"160 size="sm"
165 >161 >
166 {maximized ? (162 <MorphIcon className="size-4" icon={maximized ? Minimize2 : Maximize2} />
167 <Minimize2Icon className="size-4" />
168 ) : (
169 <Maximize2Icon className="size-4" />
170 )}
171 </Toggle>163 </Toggle>
172 }164 }
173 />165 />
apps/web/src/components/chat/ThreadDetailsPrRows.tsx+3-6
...@@ -5,7 +5,7 @@ import {...@@ -5,7 +5,7 @@ import {
5 threadPullRequestKeyOf,5 threadPullRequestKeyOf,
6 visibleThreadPullRequests,6 visibleThreadPullRequests,
7} from "@t3tools/shared/threadPullRequests";7} from "@t3tools/shared/threadPullRequests";
8import { MinusIcon, PlusIcon } from "lucide-react";8import { Minus, Plus } from "lucide";
9import { useState, type ComponentProps, type MouseEvent as ReactMouseEvent } from "react";9import { useState, type ComponentProps, type MouseEvent as ReactMouseEvent } from "react";
1010
11import { findProjectOnChangeRequestHost, parseChangeRequestUrl } from "~/lib/openPullRequestLink";11import { findProjectOnChangeRequestHost, parseChangeRequestUrl } from "~/lib/openPullRequestLink";
...@@ -13,6 +13,7 @@ import { findProjectOnChangeRequestHost, parseChangeRequestUrl } from "~/lib/ope...@@ -13,6 +13,7 @@ import { findProjectOnChangeRequestHost, parseChangeRequestUrl } from "~/lib/ope
13import { useProjects } from "~/state/entities";13import { useProjects } from "~/state/entities";
1414
15import { pullRequestListLines } from "../pullRequest/pullRequestListLines";15import { pullRequestListLines } from "../pullRequest/pullRequestListLines";
16import { MorphIcon } from "~/components/MorphIcon";
16import { linkedPullRequestSnapshotStatus, prStatusIndicator } from "../ThreadStatusIndicators";17import { linkedPullRequestSnapshotStatus, prStatusIndicator } from "../ThreadStatusIndicators";
1718
18import { ThreadDetailsPrRow } from "./ThreadDetailsPrRow";19import { ThreadDetailsPrRow } from "./ThreadDetailsPrRow";
...@@ -96,11 +97,7 @@ export function ThreadDetailsPrRows({...@@ -96,11 +97,7 @@ export function ThreadDetailsPrRows({
96 tone="muted"97 tone="muted"
97 className="w-full active:scale-100"98 className="w-full active:scale-100"
98 >99 >
99 {expanded ? (100 <MorphIcon aria-hidden className="size-4 shrink-0" icon={expanded ? Minus : Plus} />
100 <MinusIcon aria-hidden className="size-4 shrink-0" />
101 ) : (
102 <PlusIcon aria-hidden className="size-4 shrink-0" />
103 )}
104 {expanded ? "Show less" : `Show ${rest.length} more`}101 {expanded ? "Show less" : `Show ${rest.length} more`}
105 </ThreadDetailsControl>102 </ThreadDetailsControl>
106 </>103 </>
apps/web/src/components/chat/WorktreeSetupCard.tsx+3-3
...@@ -6,8 +6,6 @@ import {...@@ -6,8 +6,6 @@ import {
6import { formatDuration } from "@t3tools/shared/orchestrationTiming";6import { formatDuration } from "@t3tools/shared/orchestrationTiming";
7import {7import {
8 CheckIcon,8 CheckIcon,
9 ChevronDownIcon,
10 ChevronRightIcon,
11 CircleAlertIcon,9 CircleAlertIcon,
12 CircleIcon,10 CircleIcon,
13 LaptopIcon,11 LaptopIcon,
...@@ -15,9 +13,11 @@ import {...@@ -15,9 +13,11 @@ import {
15 TerminalIcon,13 TerminalIcon,
16 XIcon,14 XIcon,
17} from "lucide-react";15} from "lucide-react";
16import { ChevronDown, ChevronRight } from "lucide";
18import { useEffect, useState, type ReactNode } from "react";17import { useEffect, useState, type ReactNode } from "react";
1918
20import { Button } from "~/components/ui/button";19import { Button } from "~/components/ui/button";
20import { MorphIcon } from "~/components/MorphIcon";
21import { Spinner } from "~/components/ui/spinner";21import { Spinner } from "~/components/ui/spinner";
22import { MiddleTruncate } from "../ui/middle-truncate";22import { MiddleTruncate } from "../ui/middle-truncate";
23import { observeVisibleAnimation } from "~/lib/visibleAnimation";23import { observeVisibleAnimation } from "~/lib/visibleAnimation";
...@@ -409,7 +409,7 @@ export function WorktreeSetupCard({...@@ -409,7 +409,7 @@ export function WorktreeSetupCard({
409 aria-expanded={detailsOpen}409 aria-expanded={detailsOpen}
410 onClick={() => setDetailsOpen((open) => !open)}410 onClick={() => setDetailsOpen((open) => !open)}
411 >411 >
412 {detailsOpen ? <ChevronDownIcon aria-hidden /> : <ChevronRightIcon aria-hidden />}412 <MorphIcon aria-hidden icon={detailsOpen ? ChevronDown : ChevronRight} />
413 Details413 Details
414 </Button>414 </Button>
415 {showTerminal ? (415 {showTerminal ? (
apps/web/src/components/device/DeviceControlsRail.tsx+3-3
...@@ -6,7 +6,6 @@ import {...@@ -6,7 +6,6 @@ import {
6 Keyboard,6 Keyboard,
7 Box,7 Box,
8 Maximize,8 Maximize,
9 Moon,
10 MoreHorizontal,9 MoreHorizontal,
11 PictureInPicture2,10 PictureInPicture2,
12 Power,11 Power,
...@@ -14,12 +13,13 @@ import {...@@ -14,12 +13,13 @@ import {
14 SlidersHorizontal,13 SlidersHorizontal,
15 Smartphone,14 Smartphone,
16 Square,15 Square,
17 Sun,
18 Type,16 Type,
19 X,17 X,
20} from "lucide-react";18} from "lucide-react";
19import { Moon, Sun } from "lucide";
21import type { ReactNode } from "react";20import type { ReactNode } from "react";
22import { Button } from "~/components/ui/button";21import { Button } from "~/components/ui/button";
22import { MorphIcon } from "~/components/MorphIcon";
23import {23import {
24 Menu,24 Menu,
25 MenuItem,25 MenuItem,
...@@ -132,7 +132,7 @@ export function DeviceControlsRail(props: {...@@ -132,7 +132,7 @@ export function DeviceControlsRail(props: {
132 disabled={controls.disabled || !settings?.appearance}132 disabled={controls.disabled || !settings?.appearance}
133 onClick={() => void controls.act({ type: "setAppearance", value: nextAppearance })}133 onClick={() => void controls.act({ type: "setAppearance", value: nextAppearance })}
134 >134 >
135 {settings?.appearance === "dark" ? <Sun /> : <Moon />}135 <MorphIcon icon={settings?.appearance === "dark" ? Sun : Moon} />
136 </RailButton>136 </RailButton>
137 <Menu>137 <Menu>
138 <MenuTrigger138 <MenuTrigger
apps/web/src/components/device/DeviceSetup.tsx+5-3
...@@ -1,10 +1,12 @@...@@ -1,10 +1,12 @@
1import { DeviceHostUpdates } from "./DeviceHostUpdates";1import { DeviceHostUpdates } from "./DeviceHostUpdates";
2import type { DevicePlatform, DeviceServiceState, EnvironmentId } from "@t3tools/contracts";2import type { DevicePlatform, DeviceServiceState, EnvironmentId } from "@t3tools/contracts";
3import { Check, CircleAlert } from "lucide-react";3import { Check } from "lucide-react";
4import { Check as CheckGlyph, CircleAlert } from "lucide";
4import { useState } from "react";5import { useState } from "react";
56
6import { Button } from "~/components/ui/button";7import { Button } from "~/components/ui/button";
7import { DialogClose } from "~/components/ui/dialog";8import { DialogClose } from "~/components/ui/dialog";
9import { MorphIcon } from "~/components/MorphIcon";
8import { WizardHeader, WizardPanel, WizardSteps, WizardFooter } from "~/components/ui/wizard";10import { WizardHeader, WizardPanel, WizardSteps, WizardFooter } from "~/components/ui/wizard";
9import { Spinner } from "~/components/ui/spinner";11import { Spinner } from "~/components/ui/spinner";
10import { Switch } from "~/components/ui/switch";12import { Switch } from "~/components/ui/switch";
...@@ -287,16 +289,16 @@ export function PlatformStatus(props: {...@@ -287,16 +289,16 @@ export function PlatformStatus(props: {
287 readonly status: { readonly ready: boolean; readonly message: string };289 readonly status: { readonly ready: boolean; readonly message: string };
288 readonly compact?: boolean;290 readonly compact?: boolean;
289}) {291}) {
290 const Icon = props.status.ready ? Check : CircleAlert;
291 return (292 return (
292 <div293 <div
293 className={cn("flex gap-2", !props.compact && "rounded-md border border-border/60 px-3 py-2")}294 className={cn("flex gap-2", !props.compact && "rounded-md border border-border/60 px-3 py-2")}
294 >295 >
295 <Icon296 <MorphIcon
296 className={cn(297 className={cn(
297 "mt-0.5 size-4 shrink-0",298 "mt-0.5 size-4 shrink-0",
298 props.status.ready ? "text-success" : "text-muted-foreground",299 props.status.ready ? "text-success" : "text-muted-foreground",
299 )}300 )}
301 icon={props.status.ready ? CheckGlyph : CircleAlert}
300 />302 />
301 <div className={cn(props.compact && props.status.ready && "flex items-center gap-2")}>303 <div className={cn(props.compact && props.status.ready && "flex items-center gap-2")}>
302 <p className="font-medium">{props.platform}</p>304 <p className="font-medium">{props.platform}</p>
apps/web/src/components/diffs/DiffFileTree.tsx+6-6
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1import type { GitStatusEntry } from "@pierre/trees";1import type { GitStatusEntry } from "@pierre/trees";
2import { FileTree, useFileTree, useFileTreeSelector } from "@pierre/trees/react";2import { FileTree, useFileTree, useFileTreeSelector } from "@pierre/trees/react";
3import { ChevronsDownUpIcon, ChevronsUpDownIcon } from "lucide-react";3import { ChevronsDownUp, ChevronsUpDown } from "lucide";
4import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";4import { useEffect, useMemo, useRef, useState, type ReactNode } from "react";
55
6import { useTheme } from "~/hooks/useTheme";6import { useTheme } from "~/hooks/useTheme";
...@@ -10,6 +10,7 @@ import { PIERRE_TREE_UNSAFE_CSS, pierreTreeStyle } from "~/pierre-tree-theme";...@@ -10,6 +10,7 @@ import { PIERRE_TREE_UNSAFE_CSS, pierreTreeStyle } from "~/pierre-tree-theme";
1010
11import { areAllDirectoriesExpanded, setAllDirectoriesExpanded } from "../files/fileTreeExpansion";11import { areAllDirectoriesExpanded, setAllDirectoriesExpanded } from "../files/fileTreeExpansion";
12import { Button } from "../ui/button";12import { Button } from "../ui/button";
13import { MorphIcon } from "~/components/MorphIcon";
13import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";14import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
14import {15import {
15 buildDiffFileTreeUpdates,16 buildDiffFileTreeUpdates,
...@@ -189,11 +190,10 @@ export function DiffFileTree({...@@ -189,11 +190,10 @@ export function DiffFileTree({
189 />190 />
190 }191 }
191 >192 >
192 {allDirectoriesExpanded ? (193 <MorphIcon
193 <ChevronsDownUpIcon className="size-3.5" />194 className="size-3.5"
194 ) : (195 icon={allDirectoriesExpanded ? ChevronsDownUp : ChevronsUpDown}
195 <ChevronsUpDownIcon className="size-3.5" />196 />
196 )}
197 </TooltipTrigger>197 </TooltipTrigger>
198 <TooltipPopup>198 <TooltipPopup>
199 {allDirectoriesExpanded ? "Collapse all folders" : "Expand all folders"}199 {allDirectoriesExpanded ? "Collapse all folders" : "Expand all folders"}
apps/web/src/components/files/AttachmentFilePreview.tsx+8-20
...@@ -3,22 +3,13 @@ import type { EnvironmentId } from "@t3tools/contracts";...@@ -3,22 +3,13 @@ import type { EnvironmentId } from "@t3tools/contracts";
3import { formatAttachmentSize } from "@t3tools/client-runtime/state/attachments";3import { formatAttachmentSize } from "@t3tools/client-runtime/state/attachments";
4import { readFilePreviewResponse } from "@t3tools/client-runtime/file-preview";4import { readFilePreviewResponse } from "@t3tools/client-runtime/file-preview";
5import { filePreviewKind, FILE_TEXT_PREVIEW_MAX_BYTES } from "@t3tools/shared/filePreview";5import { filePreviewKind, FILE_TEXT_PREVIEW_MAX_BYTES } from "@t3tools/shared/filePreview";
6import {6import { ChevronRightIcon, DownloadIcon, Trash2Icon, WrapTextIcon, XIcon } from "lucide-react";
7 CheckIcon,7import { Check, Code2, Copy, Eye, Table2 } from "lucide";
8 ChevronRightIcon,
9 Code2,
10 CopyIcon,
11 DownloadIcon,
12 Eye,
13 Table2,
14 Trash2Icon,
15 WrapTextIcon,
16 XIcon,
17} from "lucide-react";
18import { lazy, Suspense, useEffect, useMemo, useRef, useState } from "react";8import { lazy, Suspense, useEffect, useMemo, useRef, useState } from "react";
199
20import { useAssetUrlRefresh } from "~/assets/assetUrls";10import { useAssetUrlRefresh } from "~/assets/assetUrls";
21import ChatMarkdown from "~/components/ChatMarkdown";11import ChatMarkdown from "~/components/ChatMarkdown";
12import { MorphIcon } from "~/components/MorphIcon";
22import { ScrollArea } from "~/components/ui/scroll-area";13import { ScrollArea } from "~/components/ui/scroll-area";
23import { toastManager } from "~/components/ui/toast";14import { toastManager } from "~/components/ui/toast";
24import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";15import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";
...@@ -305,13 +296,10 @@ export function AttachmentFilePreview(props: {...@@ -305,13 +296,10 @@ export function AttachmentFilePreview(props: {
305 pressed={rendered}296 pressed={rendered}
306 onPress={() => setRendered((value) => !value)}297 onPress={() => setRendered((value) => !value)}
307 >298 >
308 {rendered ? (299 <MorphIcon
309 <Code2 className="size-3.5" />300 className="size-3.5"
310 ) : renderedMode === "table" ? (301 icon={rendered ? Code2 : renderedMode === "table" ? Table2 : Eye}
311 <Table2 className="size-3.5" />302 />
312 ) : (
313 <Eye className="size-3.5" />
314 )}
315 </FileSurfaceAction>303 </FileSurfaceAction>
316 ) : null}304 ) : null}
317 {showsRawText ? (305 {showsRawText ? (
...@@ -328,7 +316,7 @@ export function AttachmentFilePreview(props: {...@@ -328,7 +316,7 @@ export function AttachmentFilePreview(props: {
328 label={isCopied ? "Copied" : content.truncated ? "Copy preview" : "Copy contents"}316 label={isCopied ? "Copied" : content.truncated ? "Copy preview" : "Copy contents"}
329 onPress={() => copyToClipboard(content.text, undefined)}317 onPress={() => copyToClipboard(content.text, undefined)}
330 >318 >
331 {isCopied ? <CheckIcon className="size-3.5" /> : <CopyIcon className="size-3.5" />}319 <MorphIcon className="size-3.5" icon={isCopied ? Check : Copy} />
332 </FileSurfaceAction>320 </FileSurfaceAction>
333 ) : null}321 ) : null}
334 {url ? (322 {url ? (
apps/web/src/components/files/FileBrowserPanel.tsx+6-6
...@@ -6,11 +6,12 @@ import type {...@@ -6,11 +6,12 @@ import type {
6import type { EnvironmentId, ProjectEntry } from "@t3tools/contracts";6import type { EnvironmentId, ProjectEntry } from "@t3tools/contracts";
7import { FileTree, useFileTree, useFileTreeSearch, useFileTreeSelector } from "@pierre/trees/react";7import { FileTree, useFileTree, useFileTreeSearch, useFileTreeSelector } from "@pierre/trees/react";
8import { serializeComposerFileLink } from "@t3tools/shared/composerTrigger";8import { serializeComposerFileLink } from "@t3tools/shared/composerTrigger";
9import { ChevronsDownUpIcon, ChevronsUpDownIcon } from "lucide-react";9import { ChevronsDownUp, ChevronsUpDown } from "lucide";
10import { useEffect, useMemo, useRef, useState } from "react";10import { useEffect, useMemo, useRef, useState } from "react";
1111
12import { Button } from "~/components/ui/button";12import { Button } from "~/components/ui/button";
13import { InputGroup, InputGroupInput } from "~/components/ui/input-group";13import { InputGroup, InputGroupInput } from "~/components/ui/input-group";
14import { MorphIcon } from "~/components/MorphIcon";
14import { toastManager } from "~/components/ui/toast";15import { toastManager } from "~/components/ui/toast";
15import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip";16import { Tooltip, TooltipPopup, TooltipTrigger } from "~/components/ui/tooltip";
16import { useComposerHandleContext } from "~/composerHandleContext";17import { useComposerHandleContext } from "~/composerHandleContext";
...@@ -516,11 +517,10 @@ export default function FileBrowserPanel({...@@ -516,11 +517,10 @@ export default function FileBrowserPanel({
516 />517 />
517 }518 }
518 >519 >
519 {allDirectoriesExpanded ? (520 <MorphIcon
520 <ChevronsDownUpIcon className="size-3.5" />521 className="size-3.5"
521 ) : (522 icon={allDirectoriesExpanded ? ChevronsDownUp : ChevronsUpDown}
522 <ChevronsUpDownIcon className="size-3.5" />523 />
523 )}
524 </TooltipTrigger>524 </TooltipTrigger>
525 <TooltipPopup>525 <TooltipPopup>
526 {expandAll || allDirectoriesExpanded ? "Collapse all folders" : "Expand all folders"}526 {expandAll || allDirectoriesExpanded ? "Collapse all folders" : "Expand all folders"}
apps/web/src/components/files/FilePreviewPanel.tsx+7-8
...@@ -21,7 +21,8 @@ import {...@@ -21,7 +21,8 @@ import {
21 squashAtomCommandFailure,21 squashAtomCommandFailure,
22} from "@t3tools/client-runtime/state/runtime";22} from "@t3tools/client-runtime/state/runtime";
23import { mediaFileReference } from "@t3tools/client-runtime/media-reference";23import { mediaFileReference } from "@t3tools/client-runtime/media-reference";
24import { Code2, Eye, FolderTree, Globe2, Table2, WrapTextIcon } from "lucide-react";24import { FolderTree, Globe2, WrapTextIcon } from "lucide-react";
25import { Code2, Eye, Table2 } from "lucide";
25import * as Schema from "effect/Schema";26import * as Schema from "effect/Schema";
26import { useCallback, useEffect, useMemo, useRef, useState } from "react";27import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2728
...@@ -30,6 +31,7 @@ import { useAssetUrlRefresh, useAssetUrlState } from "~/assets/assetUrls";...@@ -30,6 +31,7 @@ import { useAssetUrlRefresh, useAssetUrlState } from "~/assets/assetUrls";
30import { OpenInPicker } from "~/components/chat/OpenInPicker";31import { OpenInPicker } from "~/components/chat/OpenInPicker";
31import { MediaVideoPlayer } from "~/components/media/MediaVideoPlayer";32import { MediaVideoPlayer } from "~/components/media/MediaVideoPlayer";
32import { MediaActions, type MediaActionSource } from "~/components/media/MediaActions";33import { MediaActions, type MediaActionSource } from "~/components/media/MediaActions";
34import { MorphIcon } from "~/components/MorphIcon";
33import { useRemoteOpenState } from "~/remoteOpen";35import { useRemoteOpenState } from "~/remoteOpen";
34import { useClientSettings, useUpdateClientSettings } from "~/hooks/useSettings";36import { useClientSettings, useUpdateClientSettings } from "~/hooks/useSettings";
35import { useTheme } from "~/hooks/useTheme";37import { useTheme } from "~/hooks/useTheme";
...@@ -1140,13 +1142,10 @@ export default function FilePreviewPanel({...@@ -1140,13 +1142,10 @@ export default function FilePreviewPanel({
1140 );1142 );
1141 }}1143 }}
1142 >1144 >
1143 {rendered ? (1145 <MorphIcon
1144 <Code2 className="size-3.5" />1146 className="size-3.5"
1145 ) : renderedMode === "table" ? (1147 icon={rendered ? Code2 : renderedMode === "table" ? Table2 : Eye}
1146 <Table2 className="size-3.5" />1148 />
1147 ) : (
1148 <Eye className="size-3.5" />
1149 )}
1150 </FileSurfaceAction>1149 </FileSurfaceAction>
1151 ) : null}1150 ) : null}
1152 {showsRawText ? (1151 {showsRawText ? (
apps/web/src/components/onboarding/WelcomeWizard.tsx+3-2
...@@ -26,11 +26,11 @@ import {...@@ -26,11 +26,11 @@ import {
26 CheckIcon,26 CheckIcon,
27 ChevronRightIcon,27 ChevronRightIcon,
28 CloudIcon,28 CloudIcon,
29 CopyIcon,
30 LinkIcon,29 LinkIcon,
31 MonitorIcon,30 MonitorIcon,
32 TerminalIcon,31 TerminalIcon,
33} from "lucide-react";32} from "lucide-react";
33import { Check, Copy } from "lucide";
34import { useCallback, useEffect, useMemo, useRef, useState } from "react";34import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3535
36import { TYPOGRAPHY_ADVANCED_STORAGE_KEY } from "../../appearanceFonts";36import { TYPOGRAPHY_ADVANCED_STORAGE_KEY } from "../../appearanceFonts";
...@@ -77,6 +77,7 @@ import { T3Wordmark } from "../T3Wordmark";...@@ -77,6 +77,7 @@ import { T3Wordmark } from "../T3Wordmark";
77import { Alert, AlertDescription } from "../ui/alert";77import { Alert, AlertDescription } from "../ui/alert";
78import { Button } from "../ui/button";78import { Button } from "../ui/button";
79import { Checkbox } from "../ui/checkbox";79import { Checkbox } from "../ui/checkbox";
80import { MorphIcon } from "~/components/MorphIcon";
80import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from "../ui/collapsible";81import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from "../ui/collapsible";
81import { Input } from "../ui/input";82import { Input } from "../ui/input";
82import { Tooltip, TooltipTrigger, TooltipPopup } from "../ui/tooltip";83import { Tooltip, TooltipTrigger, TooltipPopup } from "../ui/tooltip";
...@@ -1744,7 +1745,7 @@ function CommandBlock({...@@ -1744,7 +1745,7 @@ function CommandBlock({
1744 aria-label="Copy command"1745 aria-label="Copy command"
1745 onClick={() => copyToClipboard(command, undefined)}1746 onClick={() => copyToClipboard(command, undefined)}
1746 >1747 >
1747 {isCopied ? <CheckIcon className="size-3.5" /> : <CopyIcon className="size-3.5" />}1748 <MorphIcon className="size-3.5" icon={isCopied ? Check : Copy} />
1748 </Button>1749 </Button>
1749 </div>1750 </div>
1750 );1751 );
apps/web/src/components/pullRequest/PullRequestCodeTab.tsx+7-12
...@@ -13,8 +13,6 @@ import type {...@@ -13,8 +13,6 @@ import type {
13import {13import {
14 ChevronDownIcon,14 ChevronDownIcon,
15 ChevronRightIcon,15 ChevronRightIcon,
16 ChevronsDownUpIcon,
17 ChevronsUpDownIcon,
18 Columns2Icon,16 Columns2Icon,
19 FolderTreeIcon,17 FolderTreeIcon,
20 InfoIcon,18 InfoIcon,
...@@ -24,6 +22,7 @@ import {...@@ -24,6 +22,7 @@ import {
24 TextWrapIcon,22 TextWrapIcon,
25 TriangleAlertIcon,23 TriangleAlertIcon,
26} from "lucide-react";24} from "lucide-react";
25import { ChevronDown, ChevronRight, ChevronsDownUp, ChevronsUpDown } from "lucide";
27import { useAtomRefresh } from "@effect/atom-react";26import { useAtomRefresh } from "@effect/atom-react";
28import * as Schema from "effect/Schema";27import * as Schema from "effect/Schema";
29import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";28import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
...@@ -64,6 +63,7 @@ import { useCodeViewFileReveal } from "../diffs/useCodeViewFileReveal";...@@ -64,6 +63,7 @@ import { useCodeViewFileReveal } from "../diffs/useCodeViewFileReveal";
64import { diffFileTreeEntries } from "../diffs/diffFileTree.logic";63import { diffFileTreeEntries } from "../diffs/diffFileTree.logic";
65import { StyledDiffCodeView } from "../diffs/StyledDiffCodeView";64import { StyledDiffCodeView } from "../diffs/StyledDiffCodeView";
66import { Button } from "../ui/button";65import { Button } from "../ui/button";
66import { MorphIcon } from "~/components/MorphIcon";
67import { Checkbox } from "../ui/checkbox";67import { Checkbox } from "../ui/checkbox";
68import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from "../ui/collapsible";68import { Collapsible, CollapsiblePanel, CollapsibleTrigger } from "../ui/collapsible";
69import {69import {
...@@ -791,11 +791,7 @@ function PullRequestCodeTab({...@@ -791,11 +791,7 @@ function PullRequestCodeTab({
791 toggleFile(item.id);791 toggleFile(item.id);
792 }}792 }}
793 >793 >
794 {collapsed ? (794 <MorphIcon className="size-4" icon={collapsed ? ChevronRight : ChevronDown} />
795 <ChevronRightIcon className="size-4" />
796 ) : (
797 <ChevronDownIcon className="size-4" />
798 )}
799 </Button>795 </Button>
800 );796 );
801 },797 },
...@@ -1249,11 +1245,10 @@ function PullRequestCodeTab({...@@ -1249,11 +1245,10 @@ function PullRequestCodeTab({
1249 />1245 />
1250 }1246 }
1251 >1247 >
1252 {allFilesCollapsed ? (1248 <MorphIcon
1253 <ChevronsUpDownIcon className="size-3.5" />1249 className="size-3.5"
1254 ) : (1250 icon={allFilesCollapsed ? ChevronsUpDown : ChevronsDownUp}
1255 <ChevronsDownUpIcon className="size-3.5" />1251 />
1256 )}
1257 </TooltipTrigger>1252 </TooltipTrigger>
1258 <TooltipPopup side="top">1253 <TooltipPopup side="top">
1259 {allFilesCollapsed ? "Expand all files" : "Collapse all files"}1254 {allFilesCollapsed ? "Expand all files" : "Collapse all files"}
apps/web/src/components/pullRequest/PullRequestReviewAnnotation.tsx+7-12
...@@ -9,19 +9,15 @@ import type {...@@ -9,19 +9,15 @@ import type {
9 PullRequestThreadCommentsResult,9 PullRequestThreadCommentsResult,
10 PullRequestThreadComment,10 PullRequestThreadComment,
11} from "@t3tools/contracts";11} from "@t3tools/contracts";
12import {12import { HammerIcon, MessageSquareIcon, Trash2Icon } from "lucide-react";
13 CheckCircle2Icon,13import { Circle, CircleCheck } from "lucide";
14 CircleIcon,
15 HammerIcon,
16 MessageSquareIcon,
17 Trash2Icon,
18} from "lucide-react";
19import { useRef, useState } from "react";14import { useRef, useState } from "react";
2015
21import { formatRelativeTimeLabel } from "~/timestampFormat";16import { formatRelativeTimeLabel } from "~/timestampFormat";
22import { cn } from "~/lib/utils";17import { cn } from "~/lib/utils";
2318
24import { Button } from "../ui/button";19import { Button } from "../ui/button";
20import { MorphIcon } from "~/components/MorphIcon";
25import { PullRequestEditButton } from "./PullRequestEditButton";21import { PullRequestEditButton } from "./PullRequestEditButton";
26import { Textarea } from "../ui/textarea";22import { Textarea } from "../ui/textarea";
27import { isCommentSubmitShortcut } from "../diffs/commentSubmitShortcut";23import { isCommentSubmitShortcut } from "../diffs/commentSubmitShortcut";
...@@ -219,11 +215,10 @@ export function ReviewThreadCard({...@@ -219,11 +215,10 @@ export function ReviewThreadCard({
219 onPointerDown={(event) => event.stopPropagation()}215 onPointerDown={(event) => event.stopPropagation()}
220 >216 >
221 <div className="flex items-center gap-2 text-xs text-muted-foreground">217 <div className="flex items-center gap-2 text-xs text-muted-foreground">
222 {thread.isResolved ? (218 <MorphIcon
223 <CheckCircle2Icon className="size-3.5 text-success-foreground" />219 className={cn("size-3.5", thread.isResolved && "text-success-foreground")}
224 ) : (220 icon={thread.isResolved ? CircleCheck : Circle}
225 <CircleIcon className="size-3.5" />221 />
226 )}
227 <button222 <button
228 type="button"223 type="button"
229 className="hover:text-foreground"224 className="hover:text-foreground"
apps/web/src/components/settings/DiagnosticsSettings.tsx+4-10
...@@ -1,13 +1,7 @@...@@ -1,13 +1,7 @@
1import { ProcessSignalActions } from "./ProcessSignalActions";1import { ProcessSignalActions } from "./ProcessSignalActions";
2import { RefreshIcon } from "~/components/ui/refresh-icon";2import { RefreshIcon } from "~/components/ui/refresh-icon";
3import {3import { AlertTriangleIcon, CopyIcon, FolderOpenIcon, InfoIcon } from "lucide-react";
4 AlertTriangleIcon,4import { ChevronDown, ChevronRight } from "lucide";
5 ChevronDownIcon,
6 ChevronRightIcon,
7 CopyIcon,
8 FolderOpenIcon,
9 InfoIcon,
10} from "lucide-react";
11import {5import {
12 isAtomCommandInterrupted,6 isAtomCommandInterrupted,
13 squashAtomCommandFailure,7 squashAtomCommandFailure,
...@@ -30,6 +24,7 @@ import { serverEnvironment } from "../../state/server";...@@ -30,6 +24,7 @@ import { serverEnvironment } from "../../state/server";
30import { shellEnvironment } from "../../state/shell";24import { shellEnvironment } from "../../state/shell";
31import { useCopyToClipboard } from "../../hooks/useCopyToClipboard";25import { useCopyToClipboard } from "../../hooks/useCopyToClipboard";
32import { Button } from "../ui/button";26import { Button } from "../ui/button";
27import { MorphIcon } from "~/components/MorphIcon";
33import { ScrollArea } from "../ui/scroll-area";28import { ScrollArea } from "../ui/scroll-area";
34import { Toggle, ToggleGroup } from "../ui/toggle-group";29import { Toggle, ToggleGroup } from "../ui/toggle-group";
35import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";30import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
...@@ -268,7 +263,6 @@ function ProcessNameCell({...@@ -268,7 +263,6 @@ function ProcessNameCell({
268}) {263}) {
269 const name = formatProcessName(process.command);264 const name = formatProcessName(process.command);
270 const hasChildren = process.childPids.length > 0;265 const hasChildren = process.childPids.length > 0;
271 const ChevronIcon = isExpanded ? ChevronDownIcon : ChevronRightIcon;
272266
273 return (267 return (
274 <div268 <div
...@@ -282,7 +276,7 @@ function ProcessNameCell({...@@ -282,7 +276,7 @@ function ProcessNameCell({
282 aria-label={isExpanded ? `Collapse ${name}` : `Expand ${name}`}276 aria-label={isExpanded ? `Collapse ${name}` : `Expand ${name}`}
283 onClick={() => onToggle(process.pid)}277 onClick={() => onToggle(process.pid)}
284 >278 >
285 <ChevronIcon className="size-3.5" />279 <MorphIcon className="size-3.5" icon={isExpanded ? ChevronDown : ChevronRight} />
286 </Button>280 </Button>
287 ) : (281 ) : (
288 <span className="size-5 shrink-0" aria-hidden="true" />282 <span className="size-5 shrink-0" aria-hidden="true" />
apps/web/src/components/settings/ProviderInstanceCard.tsx+6-7
...@@ -7,13 +7,12 @@ import {...@@ -7,13 +7,12 @@ import {
7 ArrowUpCircleIcon,7 ArrowUpCircleIcon,
8 CopyIcon,8 CopyIcon,
9 DownloadIcon,9 DownloadIcon,
10 LockIcon,
11 LockOpenIcon,
12 ExternalLinkIcon,10 ExternalLinkIcon,
13 PlusIcon,11 PlusIcon,
14 Trash2Icon,12 Trash2Icon,
15 XIcon,13 XIcon,
16} from "lucide-react";14} from "lucide-react";
15import { Lock as LockGlyph, LockOpen } from "lucide";
17import * as Arr from "effect/Array";16import * as Arr from "effect/Array";
18import * as Result from "effect/Result";17import * as Result from "effect/Result";
19import { useEffect, useRef, useState, type ReactElement, type ReactNode } from "react";18import { useEffect, useRef, useState, type ReactElement, type ReactNode } from "react";
...@@ -41,6 +40,7 @@ import { useCopyToClipboard } from "../../hooks/useCopyToClipboard";...@@ -41,6 +40,7 @@ import { useCopyToClipboard } from "../../hooks/useCopyToClipboard";
41import { normalizeProviderAccentColor } from "../../providerInstances";40import { normalizeProviderAccentColor } from "../../providerInstances";
42import { Badge } from "../ui/badge";41import { Badge } from "../ui/badge";
43import { Button } from "../ui/button";42import { Button } from "../ui/button";
43import { MorphIcon } from "~/components/MorphIcon";
44import { DraftInput } from "../ui/draft-input";44import { DraftInput } from "../ui/draft-input";
45import { Popover, PopoverPopup, PopoverTrigger } from "../ui/popover";45import { Popover, PopoverPopup, PopoverTrigger } from "../ui/popover";
46import { Switch } from "../ui/switch";46import { Switch } from "../ui/switch";
...@@ -438,11 +438,10 @@ function ProviderEnvironmentSection(props: {...@@ -438,11 +438,10 @@ function ProviderEnvironmentSection(props: {
438 aria-pressed={variable.sensitive}438 aria-pressed={variable.sensitive}
439 aria-label={`Mark environment variable ${variable.name || index + 1} as sensitive`}439 aria-label={`Mark environment variable ${variable.name || index + 1} as sensitive`}
440 >440 >
441 {variable.sensitive ? (441 <MorphIcon
442 <LockIcon className="size-3" />442 className="size-3"
443 ) : (443 icon={variable.sensitive ? LockGlyph : LockOpen}
444 <LockOpenIcon className="size-3" />444 />
445 )}
446 </Button>445 </Button>
447 }446 }
448 />447 />
apps/web/src/components/settings/ResourceTelemetryDiagnostics.tsx+3-4
...@@ -4,14 +4,13 @@ import {...@@ -4,14 +4,13 @@ import {
4 ActivityIcon,4 ActivityIcon,
5 AlertTriangleIcon,5 AlertTriangleIcon,
6 BatteryIcon,6 BatteryIcon,
7 ChevronDownIcon,
8 ChevronRightIcon,
9 CpuIcon,7 CpuIcon,
10 DatabaseIcon,8 DatabaseIcon,
11 GaugeIcon,9 GaugeIcon,
12 HardDriveIcon,10 HardDriveIcon,
13 MemoryStickIcon,11 MemoryStickIcon,
14} from "lucide-react";12} from "lucide-react";
13import { ChevronDown, ChevronRight } from "lucide";
15import type {14import type {
16 BackgroundBooleanState,15 BackgroundBooleanState,
17 EnvironmentId,16 EnvironmentId,
...@@ -44,6 +43,7 @@ import { serverEnvironment } from "../../state/server";...@@ -44,6 +43,7 @@ import { serverEnvironment } from "../../state/server";
44import { useAtomCommand } from "../../state/use-atom-command";43import { useAtomCommand } from "../../state/use-atom-command";
45import { formatRelativeTime } from "../../timestampFormat";44import { formatRelativeTime } from "../../timestampFormat";
46import { Button } from "../ui/button";45import { Button } from "../ui/button";
46import { MorphIcon } from "~/components/MorphIcon";
47import { ScrollArea } from "../ui/scroll-area";47import { ScrollArea } from "../ui/scroll-area";
48import { Toggle, ToggleGroup } from "../ui/toggle-group";48import { Toggle, ToggleGroup } from "../ui/toggle-group";
49import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";49import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
...@@ -480,7 +480,6 @@ function ProcessTreeName({...@@ -480,7 +480,6 @@ function ProcessTreeName({
480}) {480}) {
481 const name = formatProcessName(process);481 const name = formatProcessName(process);
482 const hasChildren = process.childPids.length > 0;482 const hasChildren = process.childPids.length > 0;
483 const ChevronIcon = collapsed ? ChevronRightIcon : ChevronDownIcon;
484 return (483 return (
485 <div484 <div
486 className="grid min-w-0 grid-cols-[1.25rem_0.375rem_minmax(0,1fr)] items-center gap-2"485 className="grid min-w-0 grid-cols-[1.25rem_0.375rem_minmax(0,1fr)] items-center gap-2"
...@@ -493,7 +492,7 @@ function ProcessTreeName({...@@ -493,7 +492,7 @@ function ProcessTreeName({
493 onClick={() => onToggle(process)}492 onClick={() => onToggle(process)}
494 aria-label={collapsed ? `Expand ${name}` : `Collapse ${name}`}493 aria-label={collapsed ? `Expand ${name}` : `Collapse ${name}`}
495 >494 >
496 <ChevronIcon className="size-3.5" />495 <MorphIcon className="size-3.5" icon={collapsed ? ChevronRight : ChevronDown} />
497 </Button>496 </Button>
498 ) : (497 ) : (
499 <span className="size-5" aria-hidden />498 <span className="size-5" aria-hidden />
apps/web/src/components/settings/ThemeEditorPanel.tsx+4-9
...@@ -1,11 +1,5 @@...@@ -1,11 +1,5 @@
1import {1import { MousePointer2Icon, PaintbrushIcon, PlusIcon, XIcon } from "lucide-react";
2 ChevronDownIcon,2import { ChevronDown, ChevronUp } from "lucide";
3 ChevronUpIcon,
4 MousePointer2Icon,
5 PaintbrushIcon,
6 PlusIcon,
7 XIcon,
8} from "lucide-react";
9import {3import {
10 useCallback,4 useCallback,
11 useEffect,5 useEffect,
...@@ -36,6 +30,7 @@ import {...@@ -36,6 +30,7 @@ import {
36} from "../../themePalette";30} from "../../themePalette";
37import { cn } from "../../lib/utils";31import { cn } from "../../lib/utils";
38import { Button } from "../ui/button";32import { Button } from "../ui/button";
33import { MorphIcon } from "~/components/MorphIcon";
39import { Input } from "../ui/input";34import { Input } from "../ui/input";
40import { Switch } from "../ui/switch";35import { Switch } from "../ui/switch";
41import { Toggle, ToggleGroup } from "../ui/toggle-group";36import { Toggle, ToggleGroup } from "../ui/toggle-group";
...@@ -1221,7 +1216,7 @@ export function ThemeEditorPanel({...@@ -1221,7 +1216,7 @@ export function ThemeEditorPanel({
1221 variant="ghost"1216 variant="ghost"
1222 onClick={() => setIsMinimized(!isMinimized)}1217 onClick={() => setIsMinimized(!isMinimized)}
1223 >1218 >
1224 {isMinimized ? <ChevronUpIcon /> : <ChevronDownIcon />}1219 <MorphIcon icon={isMinimized ? ChevronUp : ChevronDown} />
1225 </Button>1220 </Button>
1226 <Button1221 <Button
1227 aria-label="Close the theme editor"1222 aria-label="Close the theme editor"
apps/web/src/components/ui/sidebar.tsx+3-2
...@@ -1,11 +1,12 @@...@@ -1,11 +1,12 @@
1import { mergeProps } from "@base-ui/react/merge-props";1import { mergeProps } from "@base-ui/react/merge-props";
2import { useRender } from "@base-ui/react/use-render";2import { useRender } from "@base-ui/react/use-render";
3import { cva, type VariantProps } from "class-variance-authority";3import { cva, type VariantProps } from "class-variance-authority";
4import { PanelLeftCloseIcon, PanelLeftIcon } from "lucide-react";4import { PanelLeft, PanelLeftClose } from "lucide";
5import * as React from "react";5import * as React from "react";
6import { cn } from "~/lib/utils";6import { cn } from "~/lib/utils";
7import { Button } from "~/components/ui/button";7import { Button } from "~/components/ui/button";
8import { Input, type InputProps } from "~/components/ui/input";8import { Input, type InputProps } from "~/components/ui/input";
9import { MorphIcon } from "~/components/MorphIcon";
9import { ScrollArea } from "~/components/ui/scroll-area";10import { ScrollArea } from "~/components/ui/scroll-area";
10import {11import {
11 Sheet,12 Sheet,
...@@ -342,7 +343,7 @@ function SidebarTrigger({ className, onClick, ...props }: React.ComponentProps<t...@@ -342,7 +343,7 @@ function SidebarTrigger({ className, onClick, ...props }: React.ComponentProps<t
342 variant="ghost"343 variant="ghost"
343 {...props}344 {...props}
344 >345 >
345 {isOpen ? <PanelLeftCloseIcon className="size-4" /> : <PanelLeftIcon className="size-4" />}346 <MorphIcon className="size-4" icon={isOpen ? PanelLeftClose : PanelLeft} />
346 <span className="sr-only">Toggle Sidebar</span>347 <span className="sr-only">Toggle Sidebar</span>
347 </Button>348 </Button>
348 );349 );
apps/web/src/components/ui/toast.tsx+18-30
...@@ -14,20 +14,12 @@ import {...@@ -14,20 +14,12 @@ import {
14} from "react";14} from "react";
15import { useParams } from "@tanstack/react-router";15import { useParams } from "@tanstack/react-router";
16import { type ScopedThreadRef, type ThreadId } from "@t3tools/contracts";16import { type ScopedThreadRef, type ThreadId } from "@t3tools/contracts";
17import {17import { CircleAlertIcon, CircleCheckIcon, InfoIcon, TriangleAlertIcon, XIcon } from "lucide-react";
18 CheckIcon,18import { Check, ChevronDown, ChevronUp, Copy } from "lucide";
19 ChevronDownIcon,
20 ChevronUpIcon,
21 CircleAlertIcon,
22 CircleCheckIcon,
23 CopyIcon,
24 InfoIcon,
25 TriangleAlertIcon,
26 XIcon,
27} from "lucide-react";
2819
29import { cn } from "~/lib/utils";20import { cn } from "~/lib/utils";
30import { Button, buttonVariants } from "~/components/ui/button";21import { Button, buttonVariants } from "~/components/ui/button";
22import { MorphIcon } from "~/components/MorphIcon";
31import { useComposerDraftStore } from "~/composerDraftStore";23import { useComposerDraftStore } from "~/composerDraftStore";
32import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";24import { useCopyToClipboard } from "~/hooks/useCopyToClipboard";
33import { resolveThreadRouteTarget } from "~/threadRoutes";25import { resolveThreadRouteTarget } from "~/threadRoutes";
...@@ -135,7 +127,10 @@ function CopyErrorButton({ text }: { text: string }) {...@@ -135,7 +127,10 @@ function CopyErrorButton({ text }: { text: string }) {
135 />127 />
136 }128 }
137 >129 >
138 {isCopied ? <CheckIcon className="size-3 text-success" /> : <CopyIcon className="size-3" />}130 <MorphIcon
131 className={cn("size-3", isCopied && "text-success")}
132 icon={isCopied ? Check : Copy}
133 />
139 </TooltipTrigger>134 </TooltipTrigger>
140 <TooltipPopup side="top">{label}</TooltipPopup>135 <TooltipPopup side="top">{label}</TooltipPopup>
141 </Tooltip>136 </Tooltip>
...@@ -165,11 +160,11 @@ function ToastExpandableSection({...@@ -165,11 +160,11 @@ function ToastExpandableSection({
165 onClick={() => setOpen((prev) => !prev)}160 onClick={() => setOpen((prev) => !prev)}
166 type="button"161 type="button"
167 >162 >
168 {open ? (163 <MorphIcon
169 <ChevronUpIcon className="size-3.5 shrink-0 opacity-80" strokeWidth={2.25} />164 className="size-3.5 shrink-0 opacity-80"
170 ) : (165 icon={open ? ChevronUp : ChevronDown}
171 <ChevronDownIcon className="size-3.5 shrink-0 opacity-80" strokeWidth={2.25} />166 strokeWidth={2.25}
172 )}167 />
173 {open ? collapseLabel : expandLabel}168 {open ? collapseLabel : expandLabel}
174 </button>169 </button>
175 {open ? <div className={toastExpandablePanelClassName}>{children}</div> : null}170 {open ? <div className={toastExpandablePanelClassName}>{children}</div> : null}
...@@ -249,19 +244,12 @@ function ToastDescriptionAndExpandable({...@@ -249,19 +244,12 @@ function ToastDescriptionAndExpandable({
249 data-slot="toast-description"244 data-slot="toast-description"
250 />245 />
251 </div>246 </div>
252 {open ? (247 <MorphIcon
253 <ChevronUpIcon248 aria-hidden
254 aria-hidden249 className="mt-0.5 size-3.5 shrink-0 text-muted-foreground opacity-80"
255 className="mt-0.5 size-3.5 shrink-0 text-muted-foreground opacity-80"250 icon={open ? ChevronUp : ChevronDown}
256 strokeWidth={2.25}251 strokeWidth={2.25}
257 />252 />
258 ) : (
259 <ChevronDownIcon
260 aria-hidden
261 className="mt-0.5 size-3.5 shrink-0 text-muted-foreground opacity-80"
262 strokeWidth={2.25}
263 />
264 )}
265 </TooltipTrigger>253 </TooltipTrigger>
266 <TooltipPopup side="top">{open ? collapseLabel : expandLabel}</TooltipPopup>254 <TooltipPopup side="top">{open ? collapseLabel : expandLabel}</TooltipPopup>
267 </Tooltip>255 </Tooltip>
apps/web/src/routes/__root.tsx+4-2
...@@ -11,7 +11,7 @@ import {...@@ -11,7 +11,7 @@ import {
11 useNavigate,11 useNavigate,
12 useRouter,12 useRouter,
13} from "@tanstack/react-router";13} from "@tanstack/react-router";
14import { CheckIcon, CopyIcon } from "lucide-react";14import { Check, Copy } from "lucide";
15import { useEffect, useEffectEvent, useMemo, useRef, useState } from "react";15import { useEffect, useEffectEvent, useMemo, useRef, useState } from "react";
1616
17import { APP_BASE_NAME, APP_DISPLAY_NAME, APP_STAGE_LABEL, APP_VERSION } from "../branding";17import { APP_BASE_NAME, APP_DISPLAY_NAME, APP_STAGE_LABEL, APP_VERSION } from "../branding";
...@@ -40,6 +40,7 @@ import { useCopyToClipboard } from "../hooks/useCopyToClipboard";...@@ -40,6 +40,7 @@ import { useCopyToClipboard } from "../hooks/useCopyToClipboard";
40import { useDefaultThemeAdoption } from "../hooks/useDefaultTheme";40import { useDefaultThemeAdoption } from "../hooks/useDefaultTheme";
41import { useEnvironmentThemeSync } from "../hooks/useEnvironmentTheme";41import { useEnvironmentThemeSync } from "../hooks/useEnvironmentTheme";
42import { Button } from "../components/ui/button";42import { Button } from "../components/ui/button";
43import { MorphIcon } from "~/components/MorphIcon";
43import { StandalonePage, StandalonePageHeader } from "../components/ui/standalone-page";44import { StandalonePage, StandalonePageHeader } from "../components/ui/standalone-page";
44import {45import {
45 AnchoredToastProvider,46 AnchoredToastProvider,
...@@ -49,6 +50,7 @@ import {...@@ -49,6 +50,7 @@ import {
49} from "../components/ui/toast";50} from "../components/ui/toast";
50import { resolveAndPersistPreferredEditor } from "../editorPreferences";51import { resolveAndPersistPreferredEditor } from "../editorPreferences";
51import { isElectron } from "../env";52import { isElectron } from "../env";
53import { cn } from "../lib/utils";
52import { applyAppearanceFontVariables } from "~/appearanceFonts";54import { applyAppearanceFontVariables } from "~/appearanceFonts";
53import { applyAppearanceContrast } from "~/appearanceContrast";55import { applyAppearanceContrast } from "~/appearanceContrast";
54import { useClientSettings } from "../hooks/useSettings";56import { useClientSettings } from "../hooks/useSettings";
...@@ -418,7 +420,7 @@ function CopyErrorButton({ report }: { report: string }) {...@@ -418,7 +420,7 @@ function CopyErrorButton({ report }: { report: string }) {
418420
419 return (421 return (
420 <Button size="sm" variant="outline" onClick={() => copyToClipboard(report)}>422 <Button size="sm" variant="outline" onClick={() => copyToClipboard(report)}>
421 {isCopied ? <CheckIcon className="text-success" /> : <CopyIcon />}423 <MorphIcon className={cn(isCopied && "text-success")} icon={isCopied ? Check : Copy} />
422 {isCopied ? "Copied" : "Copy error"}424 {isCopied ? "Copied" : "Copy error"}
423 </Button>425 </Button>
424 );426 );
pnpm-lock.yaml+101-2
...@@ -640,7 +640,7 @@ importers:...@@ -640,7 +640,7 @@ importers:
640 version: 0.9.0640 version: 0.9.0
641 '@legendapp/list':641 '@legendapp/list':
642 specifier: 'catalog:'642 specifier: 'catalog:'
643 version: 3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)643 version: 3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.2.6(react@19.2.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)
644 '@noble/hashes':644 '@noble/hashes':
645 specifier: 'catalog:'645 specifier: 'catalog:'
646 version: 1.8.0646 version: 1.8.0
...@@ -716,12 +716,18 @@ importers:...@@ -716,12 +716,18 @@ importers:
716 jszip:716 jszip:
717 specifier: 3.10.1717 specifier: 3.10.1
718 version: 3.10.1718 version: 3.10.1
719 lucide:
720 specifier: ^0.564.0
721 version: 0.564.0
719 lucide-react:722 lucide-react:
720 specifier: ^0.564.0723 specifier: ^0.564.0
721 version: 0.564.0(react@19.2.6)724 version: 0.564.0(react@19.2.6)
722 mermaid:725 mermaid:
723 specifier: ^11.17.2726 specifier: ^11.17.2
724 version: 11.17.2727 version: 11.17.2
728 morphicons:
729 specifier: ^1.7.1
730 version: 1.7.1(react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)
725 react:731 react:
726 specifier: 19.2.6732 specifier: 19.2.6
727 version: 19.2.6733 version: 19.2.6
...@@ -8814,6 +8820,9 @@ packages:...@@ -8814,6 +8820,9 @@ packages:
8814 peerDependencies:8820 peerDependencies:
8815 react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.08821 react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
88168822
8823 lucide@0.564.0:
8824 resolution: {integrity: sha512-FasyXKHWon773WIl3HeCQpd5xS6E0aLjqxiQStlHNKktni+HDncc1sqY+6vRUbCfmDsIaKQz43EEQLAUDLZO0g==}
8825
8817 lz-string@1.5.0:8826 lz-string@1.5.0:
8818 resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}8827 resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
8819 hasBin: true8828 hasBin: true
...@@ -9200,6 +9209,26 @@ packages:...@@ -9200,6 +9209,26 @@ packages:
9200 socks:9209 socks:
9201 optional: true9210 optional: true
92029211
9212 morphicons@1.7.1:
9213 resolution: {integrity: sha512-q5ylxy5/d7vBg0OAzanlooXf05PekovMYDuuQVpr6vAQZxl99lrJbaIi+jJ32PXQf9WEEaDO2pbNBsx1ZhEnFQ==}
9214 peerDependencies:
9215 react: '>=18'
9216 react-native: '>=0.71'
9217 react-native-svg: '>=14'
9218 svelte: '>=5'
9219 vue: '>=3.3'
9220 peerDependenciesMeta:
9221 react:
9222 optional: true
9223 react-native:
9224 optional: true
9225 react-native-svg:
9226 optional: true
9227 svelte:
9228 optional: true
9229 vue:
9230 optional: true
9231
9203 mrmime@2.0.1:9232 mrmime@2.0.1:
9204 resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}9233 resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
9205 engines: {node: '>=10'}9234 engines: {node: '>=10'}
...@@ -13988,12 +14017,13 @@ snapshots:...@@ -13988,12 +14017,13 @@ snapshots:
13988 dependencies:14017 dependencies:
13989 jsbi: 4.3.214018 jsbi: 4.3.2
1399014019
13991 '@legendapp/list@3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':14020 '@legendapp/list@3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.2.6(react@19.2.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)':
13992 dependencies:14021 dependencies:
13993 react: 19.2.614022 react: 19.2.6
13994 use-sync-external-store: 1.6.0(react@19.2.6)14023 use-sync-external-store: 1.6.0(react@19.2.6)
13995 optionalDependencies:14024 optionalDependencies:
13996 react-dom: 19.2.6(react@19.2.6)14025 react-dom: 19.2.6(react@19.2.6)
14026 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)
1399714027
13998 '@legendapp/list@3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)':14028 '@legendapp/list@3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)':
13999 dependencies:14029 dependencies:
...@@ -14921,6 +14951,16 @@ snapshots:...@@ -14921,6 +14951,16 @@ snapshots:
1492114951
14922 '@react-native/normalize-colors@0.88.0-rc.3': {}14952 '@react-native/normalize-colors@0.88.0-rc.3': {}
1492314953
14954 '@react-native/virtualized-lists@0.88.0-rc.3(@types/react@19.3.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)':
14955 dependencies:
14956 invariant: 2.2.4
14957 nullthrows: 1.1.1
14958 react: 19.2.6
14959 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)
14960 optionalDependencies:
14961 '@types/react': 19.3.0
14962 optional: true
14963
14924 '@react-native/virtualized-lists@0.88.0-rc.3(@types/react@19.3.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)':14964 '@react-native/virtualized-lists@0.88.0-rc.3(@types/react@19.3.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)':
14925 dependencies:14965 dependencies:
14926 invariant: 2.2.414966 invariant: 2.2.4
...@@ -19285,6 +19325,8 @@ snapshots:...@@ -19285,6 +19325,8 @@ snapshots:
19285 dependencies:19325 dependencies:
19286 react: 19.2.619326 react: 19.2.6
1928719327
19328 lucide@0.564.0: {}
19329
19288 lz-string@1.5.0: {}19330 lz-string@1.5.0: {}
1928919331
19290 magic-string@0.30.21:19332 magic-string@0.30.21:
...@@ -19986,6 +20028,12 @@ snapshots:...@@ -19986,6 +20028,12 @@ snapshots:
19986 socks: 2.8.920028 socks: 2.8.9
19987 optional: true20029 optional: true
1998820030
20031 morphicons@1.7.1(react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6):
20032 optionalDependencies:
20033 react: 19.2.6
20034 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)
20035 react-native-svg: 15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)
20036
19989 mrmime@2.0.1: {}20037 mrmime@2.0.1: {}
1999020038
19991 ms@2.0.0: {}20039 ms@2.0.0: {}
...@@ -20885,6 +20933,14 @@ snapshots:...@@ -20885,6 +20933,14 @@ snapshots:
20885 react: 19.3.020933 react: 19.3.0
20886 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)20934 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)
2088720935
20936 react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6):
20937 dependencies:
20938 css-select: 5.2.2
20939 css-tree: 1.1.3
20940 react: 19.2.6
20941 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)
20942 optional: true
20943
20888 react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0):20944 react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0):
20889 dependencies:20945 dependencies:
20890 css-select: 5.2.220946 css-select: 5.2.2
...@@ -20928,6 +20984,49 @@ snapshots:...@@ -20928,6 +20984,49 @@ snapshots:
20928 transitivePeerDependencies:20984 transitivePeerDependencies:
20929 - supports-color20985 - supports-color
2093020986
20987 react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6):
20988 dependencies:
20989 '@react-native/asset-utils': 0.88.0-rc.3
20990 '@react-native/codegen': 0.88.0-rc.3(@babel/core@7.29.7)
20991 '@react-native/community-cli-plugin': 0.88.0-rc.3(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(utf-8-validate@6.0.6)
20992 '@react-native/gradle-plugin': 0.88.0-rc.3
20993 '@react-native/normalize-colors': 0.88.0-rc.3
20994 '@react-native/virtualized-lists': 0.88.0-rc.3(@types/react@19.3.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)
20995 anser: 1.4.10
20996 ansi-regex: 5.0.1
20997 base64-js: 1.5.1
20998 flow-enums-runtime: 0.0.6
20999 flow-parser: 0.327.0
21000 hermes-compiler: 260318099.0.4
21001 invariant: 2.2.4
21002 memoize-one: 5.2.1
21003 metro-runtime: 0.87.1
21004 metro-source-map: 0.87.1
21005 nullthrows: 1.1.1
21006 pretty-format: 29.7.0
21007 promise: 8.3.0
21008 react: 19.2.6
21009 react-devtools-core: 6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6)
21010 react-refresh: 0.14.2
21011 regenerator-runtime: 0.13.11
21012 scheduler: 0.28.0
21013 semver: 7.8.5
21014 stacktrace-parser: 0.1.11
21015 tinyglobby: 0.2.17
21016 whatwg-fetch: 3.6.20
21017 ws: 7.5.11(bufferutil@4.1.0)(utf-8-validate@6.0.6)
21018 yargs: 17.7.2
21019 optionalDependencies:
21020 '@types/react': 19.3.0
21021 transitivePeerDependencies:
21022 - '@babel/core'
21023 - '@react-native-community/cli'
21024 - '@react-native/metro-config'
21025 - bufferutil
21026 - supports-color
21027 - utf-8-validate
21028 optional: true
21029
20931 react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6):21030 react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6):
20932 dependencies:21031 dependencies:
20933 '@react-native/asset-utils': 0.88.0-rc.321032 '@react-native/asset-utils': 0.88.0-rc.3