authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-22 21:33:02-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-22 21:33:02-07:00
log21079391c72d1eeaa3c40f1cc5eb3e78abf0a846
tree9357229f586b780c41e9de0ed7922b2d2533ac89
parent866fc907592c9746b407484087d66c409e8034fa
signature Signed by PGP key B5690EEEBB952194

refactor(web): field controls stop restyling Input, Select, Combobox and Command (#13206)

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

24 files changed, 72 insertions(+), 90 deletions(-)

apps/web/src/browser/BrowserDeviceToolbar.tsx+9-10
...@@ -189,10 +189,7 @@ export function BrowserDeviceToolbar({...@@ -189,10 +189,7 @@ export function BrowserDeviceToolbar({
189 <SelectTrigger189 <SelectTrigger
190 variant="ghost"190 variant="ghost"
191 size="xs"191 size="xs"
192 className={cn(192 className={cn("shrink-0 justify-between", width >= 440 ? "w-36" : "w-24")}
193 "shrink-0 justify-between px-1.5 font-medium",
194 width >= 440 ? "w-36" : "w-24",
195 )}
196 aria-label="Browser device preset"193 aria-label="Browser device preset"
197 >194 >
198 <SelectValue />195 <SelectValue />
...@@ -227,7 +224,8 @@ export function BrowserDeviceToolbar({...@@ -227,7 +224,8 @@ export function BrowserDeviceToolbar({
227 nativeInput224 nativeInput
228 type="number"225 type="number"
229 inputMode="numeric"226 inputMode="numeric"
230 size="sm"227 size="compact"
228 font="mono"
231 min={PREVIEW_VIEWPORT_MIN_DIMENSION}229 min={PREVIEW_VIEWPORT_MIN_DIMENSION}
232 max={PREVIEW_VIEWPORT_MAX_DIMENSION}230 max={PREVIEW_VIEWPORT_MAX_DIMENSION}
233 value={presentedSize.width}231 value={presentedSize.width}
...@@ -245,8 +243,8 @@ export function BrowserDeviceToolbar({...@@ -245,8 +243,8 @@ export function BrowserDeviceToolbar({
245 aria-label="Viewport width"243 aria-label="Viewport width"
246 aria-invalid={!customValid}244 aria-invalid={!customValid}
247 className={cn(245 className={cn(
248 "h-6 rounded-md text-center tabular-nums [&_[data-slot=input]]:h-full [&_[data-slot=input]]:px-1 [&_[data-slot=input]]:text-xs [&_[data-slot=input]]:leading-none [&_[data-slot=input]::-webkit-inner-spin-button]:appearance-none [&_[data-slot=input]]:[appearance:textfield]",246 "text-center [&_[data-slot=input]::-webkit-inner-spin-button]:appearance-none [&_[data-slot=input]]:[appearance:textfield]",
249 width >= 360 ? "w-14" : "w-11",247 width >= 360 ? "w-14" : "w-13",
250 )}248 )}
251 />249 />
252 <span className="text-xs text-muted-foreground">×</span>250 <span className="text-xs text-muted-foreground">×</span>
...@@ -254,7 +252,8 @@ export function BrowserDeviceToolbar({...@@ -254,7 +252,8 @@ export function BrowserDeviceToolbar({
254 nativeInput252 nativeInput
255 type="number"253 type="number"
256 inputMode="numeric"254 inputMode="numeric"
257 size="sm"255 size="compact"
256 font="mono"
258 min={PREVIEW_VIEWPORT_MIN_DIMENSION}257 min={PREVIEW_VIEWPORT_MIN_DIMENSION}
259 max={PREVIEW_VIEWPORT_MAX_DIMENSION}258 max={PREVIEW_VIEWPORT_MAX_DIMENSION}
260 value={presentedSize.height}259 value={presentedSize.height}
...@@ -272,8 +271,8 @@ export function BrowserDeviceToolbar({...@@ -272,8 +271,8 @@ export function BrowserDeviceToolbar({
272 aria-label="Viewport height"271 aria-label="Viewport height"
273 aria-invalid={!customValid}272 aria-invalid={!customValid}
274 className={cn(273 className={cn(
275 "h-6 rounded-md text-center tabular-nums [&_[data-slot=input]]:h-full [&_[data-slot=input]]:px-1 [&_[data-slot=input]]:text-xs [&_[data-slot=input]]:leading-none [&_[data-slot=input]::-webkit-inner-spin-button]:appearance-none [&_[data-slot=input]]:[appearance:textfield]",274 "text-center [&_[data-slot=input]::-webkit-inner-spin-button]:appearance-none [&_[data-slot=input]]:[appearance:textfield]",
276 width >= 360 ? "w-14" : "w-11",275 width >= 360 ? "w-14" : "w-13",
277 )}276 )}
278 />277 />
279 </form>278 </form>
apps/web/src/components/BranchToolbarBranchSelector.tsx+2-5
...@@ -704,7 +704,6 @@ export function BranchToolbarBranchSelector({...@@ -704,7 +704,6 @@ export function BranchToolbarBranchSelector({
704 key={itemValue}704 key={itemValue}
705 index={index}705 index={index}
706 value={itemValue}706 value={itemValue}
707 className="pe-2"
708 onClick={() => selectPickerItem(itemValue)}707 onClick={() => selectPickerItem(itemValue)}
709 >708 >
710 <div className="flex min-w-0 items-center gap-2 py-1">709 <div className="flex min-w-0 items-center gap-2 py-1">
...@@ -726,7 +725,6 @@ export function BranchToolbarBranchSelector({...@@ -726,7 +725,6 @@ export function BranchToolbarBranchSelector({
726 key={itemValue}725 key={itemValue}
727 index={index}726 index={index}
728 value={itemValue}727 value={itemValue}
729 className="pe-1.5"
730 onClick={() => selectPickerItem(itemValue)}728 onClick={() => selectPickerItem(itemValue)}
731 >729 >
732 <span className="truncate">Create new ref &quot;{newRefName}&quot;</span>730 <span className="truncate">Create new ref &quot;{newRefName}&quot;</span>
...@@ -754,7 +752,6 @@ export function BranchToolbarBranchSelector({...@@ -754,7 +752,6 @@ export function BranchToolbarBranchSelector({
754 key={itemValue}752 key={itemValue}
755 index={index}753 index={index}
756 value={itemValue}754 value={itemValue}
757 className="pe-1.5"
758 onClick={() => selectPickerItem(itemValue)}755 onClick={() => selectPickerItem(itemValue)}
759 onContextMenu={(event) => handleBranchContextMenu(event, itemValue)}756 onContextMenu={(event) => handleBranchContextMenu(event, itemValue)}
760 >757 >
...@@ -809,10 +806,10 @@ export function BranchToolbarBranchSelector({...@@ -809,10 +806,10 @@ export function BranchToolbarBranchSelector({
809 onContextMenu={(event) => handleBranchContextMenu(event, resolvedActiveBranch)}806 onContextMenu={(event) => handleBranchContextMenu(event, resolvedActiveBranch)}
810 >807 >
811 <ComboboxTrigger808 <ComboboxTrigger
812 render={<Button variant="ghost" size="xs" />}809 render={<ComposerControl size="xs" />}
813 // No press-scale: the popup aligns live to this trigger, so a810 // No press-scale: the popup aligns live to this trigger, so a
814 // momentary 0.97 shrink would drag the open popup ~3px sideways.811 // momentary 0.97 shrink would drag the open popup ~3px sideways.
815 className="min-w-0 max-w-full font-normal text-muted-foreground/70 text-xs! hover:text-foreground/80 active:scale-100"812 className="min-w-0 max-w-full active:scale-100"
816 disabled={isInitialBranchesLoadPending || isBranchActionPending}813 disabled={isInitialBranchesLoadPending || isBranchActionPending}
817 >814 >
818 <GitBranchIcon className="size-3 shrink-0 opacity-70" />815 <GitBranchIcon className="size-3 shrink-0 opacity-70" />
apps/web/src/components/BranchToolbarEnvModeSelector.tsx+1-1
...@@ -110,7 +110,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe...@@ -110,7 +110,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe
110 <SelectTrigger110 <SelectTrigger
111 variant="ghost"111 variant="ghost"
112 size="xs"112 size="xs"
113 className="min-w-0 shrink font-normal text-xs!"113 className="min-w-0 shrink"
114 aria-label="Workspace"114 aria-label="Workspace"
115 data-composer-shortcut="composer.workspace"115 data-composer-shortcut="composer.workspace"
116 data-composer-context-control116 data-composer-context-control
apps/web/src/components/BranchToolbarEnvironmentSelector.tsx+1-1
...@@ -102,7 +102,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir...@@ -102,7 +102,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir
102 <SelectTrigger102 <SelectTrigger
103 variant="ghost"103 variant="ghost"
104 size="xs"104 size="xs"
105 className="min-w-0 max-w-full font-normal text-xs!"105 className="min-w-0 max-w-full"
106 aria-label="Run on"106 aria-label="Run on"
107 data-composer-shortcut="composer.host"107 data-composer-shortcut="composer.host"
108 data-composer-context-control108 data-composer-context-control
apps/web/src/components/CommandPalette.tsx+1-1
...@@ -650,7 +650,7 @@ function CommandPaletteDialog(props: {...@@ -650,7 +650,7 @@ function CommandPaletteDialog(props: {
650 ? "Search project contents"650 ? "Search project contents"
651 : "Command palette"651 : "Command palette"
652 }652 }
653 className={cn("overflow-hidden p-0", props.mode === "content" && "h-105")}653 className={cn("overflow-hidden", props.mode === "content" && "h-105")}
654 data-command-palette="true"654 data-command-palette="true"
655 data-palette-mode={props.mode}655 data-palette-mode={props.mode}
656 data-testid="command-palette"656 data-testid="command-palette"
apps/web/src/components/CommandPaletteContent.tsx+1-1
...@@ -50,7 +50,7 @@ export function CommandPaletteContent({...@@ -50,7 +50,7 @@ export function CommandPaletteContent({
50 {inputAccessory}50 {inputAccessory}
51 </div>51 </div>
52 <CommandPanel className={panelClassName}>{children}</CommandPanel>52 <CommandPanel className={panelClassName}>{children}</CommandPanel>
53 <CommandFooter className="gap-3 max-sm:flex-col max-sm:items-start">53 <CommandFooter className="max-sm:flex-col max-sm:items-start">
54 <div className="flex items-center gap-3">54 <div className="flex items-center gap-3">
55 <KbdGroup>55 <KbdGroup>
56 <Kbd>56 <Kbd>
apps/web/src/components/CommandPaletteResults.tsx+1-2
...@@ -41,7 +41,7 @@ export function CommandPaletteResults(props: CommandPaletteResultsProps) {...@@ -41,7 +41,7 @@ export function CommandPaletteResults(props: CommandPaletteResultsProps) {
41 <CommandList>41 <CommandList>
42 {props.groups.map((group) => (42 {props.groups.map((group) => (
43 <CommandGroup items={group.items} key={group.value}>43 <CommandGroup items={group.items} key={group.value}>
44 <CommandGroupLabel className="ps-[9px]">{group.label}</CommandGroupLabel>44 <CommandGroupLabel>{group.label}</CommandGroupLabel>
45 <CommandCollection>45 <CommandCollection>
46 {(item) =>46 {(item) =>
47 item.disabled ? (47 item.disabled ? (
...@@ -109,7 +109,6 @@ function CommandPaletteResultRow(props: {...@@ -109,7 +109,6 @@ function CommandPaletteResultRow(props: {
109 <CommandItem109 <CommandItem
110 value={props.item.value}110 value={props.item.value}
111 active={props.isActive}111 active={props.isActive}
112 className="gap-2"
113 onMouseDown={(event) => {112 onMouseDown={(event) => {
114 event.preventDefault();113 event.preventDefault();
115 }}114 }}
apps/web/src/components/CustomSnoozeDialog.tsx-1
...@@ -169,7 +169,6 @@ function CustomSnoozeDialog() {...@@ -169,7 +169,6 @@ function CustomSnoozeDialog() {
169 ) : (169 ) : (
170 <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">170 <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
171 <NumberField171 <NumberField
172 className="gap-1.5"
173 id={`${id}-amount`}172 id={`${id}-amount`}
174 min={0}173 min={0}
175 step="any"174 step="any"
apps/web/src/components/DiffPanel.tsx+2-1
...@@ -749,7 +749,8 @@ export default function DiffPanel({...@@ -749,7 +749,8 @@ export default function DiffPanel({
749 }}749 }}
750 >750 >
751 <ComboboxTrigger751 <ComboboxTrigger
752 className="inline-flex min-w-0 max-w-48 items-center gap-1 overflow-hidden rounded-md px-1.5 py-1 outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"752 render={<Button variant="ghost-muted" size="xs" />}
753 className="min-w-0 max-w-48"
753 aria-label={`Change comparison target. Currently ${selectedGitSource.baseRef}`}754 aria-label={`Change comparison target. Currently ${selectedGitSource.baseRef}`}
754 >755 >
755 <span className="min-w-0 truncate">{selectedGitSource.baseRef}</span>756 <span className="min-w-0 truncate">{selectedGitSource.baseRef}</span>
apps/web/src/components/LegacySidebar.tsx+4-5
...@@ -2784,7 +2784,7 @@ function ProjectSortMenu({...@@ -2784,7 +2784,7 @@ function ProjectSortMenu({
2784 <div className="px-2 py-1">2784 <div className="px-2 py-1">
2785 <NumberField2785 <NumberField
2786 aria-label="Visible thread count"2786 aria-label="Visible thread count"
2787 className="w-28 gap-0"2787 className="w-28"
2788 max={MAX_SIDEBAR_THREAD_PREVIEW_COUNT}2788 max={MAX_SIDEBAR_THREAD_PREVIEW_COUNT}
2789 min={MIN_SIDEBAR_THREAD_PREVIEW_COUNT}2789 min={MIN_SIDEBAR_THREAD_PREVIEW_COUNT}
2790 onValueChange={handleThreadPreviewCountChange}2790 onValueChange={handleThreadPreviewCountChange}
...@@ -2792,14 +2792,13 @@ function ProjectSortMenu({...@@ -2792,14 +2792,13 @@ function ProjectSortMenu({
2792 step={1}2792 step={1}
2793 value={threadPreviewCount}2793 value={threadPreviewCount}
2794 >2794 >
2795 <NumberFieldGroup className="h-7 rounded-md sm:h-6.5">2795 <NumberFieldGroup>
2796 <NumberFieldDecrement2796 <NumberFieldDecrement
2797 aria-label="Decrease visible thread count"2797 aria-label="Decrease visible thread count"
2798 className="px-2 sm:px-2 [&_svg]:size-3.5"2798 className="[&_svg]:size-3.5"
2799 />2799 />
2800 <NumberFieldInput2800 <NumberFieldInput
2801 aria-label="Visible thread count"2801 aria-label="Visible thread count"
2802 className="h-7 w-9 grow-0 px-0 text-xs leading-7 sm:h-6.5 sm:leading-6.5"
2803 inputMode="numeric"2802 inputMode="numeric"
2804 onKeyDownCapture={(event) => {2803 onKeyDownCapture={(event) => {
2805 event.stopPropagation();2804 event.stopPropagation();
...@@ -2807,7 +2806,7 @@ function ProjectSortMenu({...@@ -2807,7 +2806,7 @@ function ProjectSortMenu({
2807 />2806 />
2808 <NumberFieldIncrement2807 <NumberFieldIncrement
2809 aria-label="Increase visible thread count"2808 aria-label="Increase visible thread count"
2810 className="px-2 sm:px-2 [&_svg]:size-3.5"2809 className="[&_svg]:size-3.5"
2811 />2810 />
2812 </NumberFieldGroup>2811 </NumberFieldGroup>
2813 </NumberField>2812 </NumberField>
apps/web/src/components/Sidebar.tsx-1
...@@ -4483,7 +4483,6 @@ export default function Sidebar() {...@@ -4483,7 +4483,6 @@ export default function Sidebar() {
4483 key={item.value}4483 key={item.value}
4484 hideIndicator4484 hideIndicator
4485 value={item}4485 value={item}
4486 className="font-medium"
4487 onContextMenu={(event) => {4486 onContextMenu={(event) => {
4488 if (project) handleProjectSettings(event, project);4487 if (project) handleProjectSettings(event, project);
4489 }}4488 }}
apps/web/src/components/chat/ComposerCommandMenu.tsx-1
...@@ -162,7 +162,6 @@ const ComposerCommandMenuItem = memo(function ComposerCommandMenuItem(props: {...@@ -162,7 +162,6 @@ const ComposerCommandMenuItem = memo(function ComposerCommandMenuItem(props: {
162 value={props.item.id}162 value={props.item.id}
163 data-composer-item-id={props.item.id}163 data-composer-item-id={props.item.id}
164 active={props.isActive}164 active={props.isActive}
165 className="gap-3 rounded-lg px-3 py-2!"
166 onMouseMove={() => {165 onMouseMove={() => {
167 if (!props.isActive) props.onHighlight(props.item.id);166 if (!props.isActive) props.onHighlight(props.item.id);
168 }}167 }}
apps/web/src/components/preview/PreviewChromeRow.tsx+20-25
...@@ -181,11 +181,6 @@ export function PreviewChromeRow({...@@ -181,11 +181,6 @@ export function PreviewChromeRow({
181 <InputGroupInput181 <InputGroupInput
182 ref={inputRef}182 ref={inputRef}
183 value={inputFocused ? draft : url}183 value={inputFocused ? draft : url}
184 className={cn(
185 onOpenInBrowser &&
186 !inputFocused &&
187 "group-hover/address:pe-7 transition-[padding]",
188 )}
189 onChange={(event) => setDraft(event.target.value)}184 onChange={(event) => setDraft(event.target.value)}
190 onFocus={() => {185 onFocus={() => {
191 setDraft(url);186 setDraft(url);
...@@ -213,26 +208,26 @@ export function PreviewChromeRow({...@@ -213,26 +208,26 @@ export function PreviewChromeRow({
213 />208 />
214 </Tooltip>209 </Tooltip>
215 {onOpenInBrowser && !inputFocused ? (210 {onOpenInBrowser && !inputFocused ? (
216 <InputGroupAddon211 <InputGroupAddon align="inline-end">
217 align="inline-end"212 {/* Revealed on hover so a resting address bar reads as plain text. */}
218 className="pointer-events-none absolute inset-y-0 right-0 opacity-0 transition-opacity group-hover/address:pointer-events-auto group-hover/address:opacity-100"213 <span className="pointer-events-none flex opacity-0 transition-opacity focus-within:pointer-events-auto focus-within:opacity-100 group-hover/address:pointer-events-auto group-hover/address:opacity-100">
219 >214 <Tooltip>
220 <Tooltip>215 <TooltipTrigger
221 <TooltipTrigger216 render={
222 render={217 <Button
223 <Button218 variant="ghost"
224 variant="ghost"219 size="icon-xs"
225 size="icon-xs"220 onClick={onOpenInBrowser}
226 onClick={onOpenInBrowser}221 aria-label="Open in system browser"
227 aria-label="Open in system browser"222 type="button"
228 type="button"223 />
229 />224 }
230 }225 >
231 >226 <ExternalLink />
232 <ExternalLink />227 </TooltipTrigger>
233 </TooltipTrigger>228 <TooltipPopup>Open in system browser</TooltipPopup>
234 <TooltipPopup>Open in system browser</TooltipPopup>229 </Tooltip>
235 </Tooltip>230 </span>
236 </InputGroupAddon>231 </InputGroupAddon>
237 ) : null}232 ) : null}
238 </InputGroup>233 </InputGroup>
apps/web/src/components/search/ProjectContentSearchDialog.tsx+4-2
...@@ -89,11 +89,13 @@ function EmptyContentSearchDialog() {...@@ -89,11 +89,13 @@ function EmptyContentSearchDialog() {
89 footerActionLabel="Open file"89 footerActionLabel="Open file"
90 inputProps={{ disabled: true, placeholder: "Search project contents…" }}90 inputProps={{ disabled: true, placeholder: "Search project contents…" }}
91 mode="none"91 mode="none"
92 panelClassName="flex min-h-0 flex-1 items-center justify-center px-6 text-center text-sm text-muted-foreground"92 panelClassName="flex min-h-0 flex-1 items-center justify-center"
93 testId="project-content-search"93 testId="project-content-search"
94 value=""94 value=""
95 >95 >
96 Open a project to search its files.96 <p className="px-6 text-center text-muted-foreground text-sm">
97 Open a project to search its files.
98 </p>
97 </CommandPaletteContent>99 </CommandPaletteContent>
98 );100 );
99}101}
apps/web/src/components/settings/AddProviderInstanceDialog.tsx-2
...@@ -306,7 +306,6 @@ export function AddProviderInstanceDialog({...@@ -306,7 +306,6 @@ export function AddProviderInstanceDialog({
306 <label className={cn("grid gap-2", wizardStep !== 1 && "hidden")}>306 <label className={cn("grid gap-2", wizardStep !== 1 && "hidden")}>
307 <span className="text-xs font-medium text-foreground">Label</span>307 <span className="text-xs font-medium text-foreground">Label</span>
308 <Input308 <Input
309 className="bg-background"
310 placeholder="e.g. Work"309 placeholder="e.g. Work"
311 value={label}310 value={label}
312 onChange={(event) => setLabel(event.target.value)}311 onChange={(event) => setLabel(event.target.value)}
...@@ -319,7 +318,6 @@ export function AddProviderInstanceDialog({...@@ -319,7 +318,6 @@ export function AddProviderInstanceDialog({
319 <label className={cn("grid gap-2", wizardStep !== 1 && "hidden")}>318 <label className={cn("grid gap-2", wizardStep !== 1 && "hidden")}>
320 <span className="text-xs font-medium text-foreground">Instance ID</span>319 <span className="text-xs font-medium text-foreground">Instance ID</span>
321 <Input320 <Input
322 className="bg-background"
323 placeholder={`${driver}_work`}321 placeholder={`${driver}_work`}
324 value={instanceId}322 value={instanceId}
325 onChange={(event) => {323 onChange={(event) => {
apps/web/src/components/settings/ConnectionsSettings.tsx+2-3
...@@ -833,7 +833,6 @@ const PairingLinkListRow = memo(function PairingLinkListRow({...@@ -833,7 +833,6 @@ const PairingLinkListRow = memo(function PairingLinkListRow({
833 readOnly833 readOnly
834 value={revealValue}834 value={revealValue}
835 rows={isRevealValueUrl ? 4 : 3}835 rows={isRevealValueUrl ? 4 : 3}
836 className="text-xs leading-relaxed"
837 onFocus={(event) => event.currentTarget.select()}836 onFocus={(event) => event.currentTarget.select()}
838 onClick={(event) => event.currentTarget.select()}837 onClick={(event) => event.currentTarget.select()}
839 />838 />
...@@ -2734,7 +2733,7 @@ export function ConnectionsSettings() {...@@ -2734,7 +2733,7 @@ export function ConnectionsSettings() {
2734 <AutocompleteItem2733 <AutocompleteItem
2735 key={`${target.alias}:${target.hostname}:${target.port ?? ""}`}2734 key={`${target.alias}:${target.hostname}:${target.port ?? ""}`}
2736 value={target}2735 value={target}
2737 className="h-8 min-h-8 gap-2 whitespace-nowrap"2736 className="h-8 min-h-8 whitespace-nowrap"
2738 >2737 >
2739 <span className="min-w-0 truncate text-sm font-medium">2738 <span className="min-w-0 truncate text-sm font-medium">
2740 {target.alias}2739 {target.alias}
...@@ -2754,7 +2753,7 @@ export function ConnectionsSettings() {...@@ -2754,7 +2753,7 @@ export function ConnectionsSettings() {
2754 })}2753 })}
2755 </AutocompleteList>2754 </AutocompleteList>
2756 ) : (2755 ) : (
2757 <AutocompleteEmpty className="break-all px-3 py-2 text-xs">2756 <AutocompleteEmpty className="break-all">
2758 No hosts match "{savedBackendSshHost.trim()}".2757 No hosts match "{savedBackendSshHost.trim()}".
2759 </AutocompleteEmpty>2758 </AutocompleteEmpty>
2760 )}2759 )}
apps/web/src/components/settings/KeybindingsSettings.tsx+17-18
...@@ -42,6 +42,7 @@ import { useSettingsScope } from "./SettingsScopeContext";...@@ -42,6 +42,7 @@ import { useSettingsScope } from "./SettingsScopeContext";
42import { Badge } from "../ui/badge";42import { Badge } from "../ui/badge";
43import { Button } from "../ui/button";43import { Button } from "../ui/button";
44import { Input } from "../ui/input";44import { Input } from "../ui/input";
45import { InputGroup, InputGroupAddon, InputGroupInput } from "../ui/input-group";
45import { Kbd, KbdGroup } from "../ui/kbd";46import { Kbd, KbdGroup } from "../ui/kbd";
46import { Menu, MenuItem, MenuPopup, MenuTrigger } from "../ui/menu";47import { Menu, MenuItem, MenuPopup, MenuTrigger } from "../ui/menu";
47import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";48import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
...@@ -143,9 +144,11 @@ function ExpandableHeaderSearch({...@@ -143,9 +144,11 @@ function ExpandableHeaderSearch({
143 }144 }
144145
145 return (146 return (
146 <div className="relative">147 <InputGroup className="w-44">
147 <SearchIcon className="pointer-events-none absolute top-1/2 left-2 size-3 -translate-y-1/2 text-muted-foreground" />148 <InputGroupAddon>
148 <Input149 <SearchIcon aria-hidden className="size-3" />
150 </InputGroupAddon>
151 <InputGroupInput
149 ref={inputRef}152 ref={inputRef}
150 autoFocus153 autoFocus
151 type="search"154 type="search"
...@@ -163,10 +166,9 @@ function ExpandableHeaderSearch({...@@ -163,10 +166,9 @@ function ExpandableHeaderSearch({
163 }}166 }}
164 placeholder="Search keybindings"167 placeholder="Search keybindings"
165 aria-label="Search keybindings"168 aria-label="Search keybindings"
166 className="w-44 [&_[data-slot=input]]:pl-7"
167 size="sm"169 size="sm"
168 />170 />
169 </div>171 </InputGroup>
170 );172 );
171}173}
172174
...@@ -319,7 +321,7 @@ function WhenVariableSelect({...@@ -319,7 +321,7 @@ function WhenVariableSelect({
319 return (321 return (
320 <Select value={value} onValueChange={(nextValue) => nextValue && onChange(nextValue)}>322 <Select value={value} onValueChange={(nextValue) => nextValue && onChange(nextValue)}>
321 <SelectTrigger size="compact" className="min-w-0 flex-1">323 <SelectTrigger size="compact" className="min-w-0 flex-1">
322 <SelectValue placeholder="Condition" className="leading-7" />324 <SelectValue placeholder="Condition" />
323 {unknownIdentifiers && unknownIdentifiers.length > 0 ? (325 {unknownIdentifiers && unknownIdentifiers.length > 0 ? (
324 <UnknownWhenVariableWarning identifiers={unknownIdentifiers} focusable={false} />326 <UnknownWhenVariableWarning identifiers={unknownIdentifiers} focusable={false} />
325 ) : null}327 ) : null}
...@@ -649,25 +651,22 @@ function WhenExpressionBuilder({...@@ -649,25 +651,22 @@ function WhenExpressionBuilder({
649 </div>651 </div>
650652
651 <div className="space-y-1.5">653 <div className="space-y-1.5">
652 <div className="relative">654 <InputGroup>
653 <Input655 <InputGroupInput
654 value={expressionDraft}656 value={expressionDraft}
655 onChange={(event) => updateExpressionDraft(event.currentTarget.value)}657 onChange={(event) => updateExpressionDraft(event.currentTarget.value)}
656 placeholder="Always"658 placeholder="Always"
657 aria-invalid={Boolean(parseError)}659 aria-invalid={Boolean(parseError)}
658 aria-label="When expression"660 aria-label="When expression"
659 className={cn(661 size="compact"
660 "h-7 rounded-md font-mono text-[12px] leading-7 sm:h-7 sm:leading-7",662 font="mono"
661 unknownIdentifiers.length > 0 && "pr-9",
662 parseError && "border-destructive/70 focus-visible:border-destructive",
663 )}
664 />663 />
665 {unknownIdentifiers.length > 0 ? (664 {unknownIdentifiers.length > 0 ? (
666 <span className="absolute inset-y-0 right-2 flex items-center">665 <InputGroupAddon align="inline-end">
667 <UnknownWhenVariableWarning identifiers={unknownIdentifiers} />666 <UnknownWhenVariableWarning identifiers={unknownIdentifiers} />
668 </span>667 </InputGroupAddon>
669 ) : null}668 ) : null}
670 </div>669 </InputGroup>
671 {parseError ? (670 {parseError ? (
672 <div className="flex items-center gap-1.5 text-[11px] text-destructive">671 <div className="flex items-center gap-1.5 text-[11px] text-destructive">
673 <CircleXIcon className="size-3.5" />672 <CircleXIcon className="size-3.5" />
...@@ -858,7 +857,7 @@ function KeybindingKeyControl({...@@ -858,7 +857,7 @@ function KeybindingKeyControl({
858 placeholder={isRecording ? "Press shortcut" : "Unassigned"}857 placeholder={isRecording ? "Press shortcut" : "Unassigned"}
859 size="sm"858 size="sm"
860 font="mono"859 font="mono"
861 className={cn("w-44", isRecording && "border-primary/70 bg-primary/5")}860 className="w-44"
862 onFocus={() => setDraft({ isRecording: true })}861 onFocus={() => setDraft({ isRecording: true })}
863 onBlur={() => setDraft({ isRecording: false })}862 onBlur={() => setDraft({ isRecording: false })}
864 onChange={(event) => setDraft({ keyDraft: event.currentTarget.value })}863 onChange={(event) => setDraft({ keyDraft: event.currentTarget.value })}
...@@ -1168,7 +1167,7 @@ function NewKeybindingKeyInput({...@@ -1168,7 +1167,7 @@ function NewKeybindingKeyInput({
1168 placeholder={draft.isRecording ? "Press shortcut" : "Unassigned"}1167 placeholder={draft.isRecording ? "Press shortcut" : "Unassigned"}
1169 size="sm"1168 size="sm"
1170 font="mono"1169 font="mono"
1171 className={cn(draft.isRecording && "border-primary/70 bg-primary/5", className)}1170 className={className}
1172 onFocus={() => draft.setDraft({ isRecording: true })}1171 onFocus={() => draft.setDraft({ isRecording: true })}
1173 onBlur={() => draft.setDraft({ isRecording: false })}1172 onBlur={() => draft.setDraft({ isRecording: false })}
1174 onChange={(event) => draft.setDraft({ keyDraft: event.currentTarget.value })}1173 onChange={(event) => draft.setDraft({ keyDraft: event.currentTarget.value })}
apps/web/src/components/settings/ProjectFaviconPickerDialog.tsx+1-1
...@@ -71,7 +71,7 @@ export function ProjectFaviconPickerDialog(props: {...@@ -71,7 +71,7 @@ export function ProjectFaviconPickerDialog(props: {
71 {props.open ? (71 {props.open ? (
72 <CommandDialogPopup72 <CommandDialogPopup
73 aria-label="Choose project icon"73 aria-label="Choose project icon"
74 className="overflow-hidden p-0"74 className="overflow-hidden"
75 onBackdropPointerDown={() => props.onOpenChange(false)}75 onBackdropPointerDown={() => props.onOpenChange(false)}
76 >76 >
77 <CommandPaletteContent77 <CommandPaletteContent
apps/web/src/components/settings/ProviderAccentColorPicker.tsx+1-2
...@@ -46,7 +46,7 @@ function ProviderCustomColorPanel(props: {...@@ -46,7 +46,7 @@ function ProviderCustomColorPanel(props: {
46 />46 />
47 <Input47 <Input
48 nativeInput48 nativeInput
49 size="sm"49 size="compact"
50 value={hexDraft ?? currentColor}50 value={hexDraft ?? currentColor}
51 onChange={(event) => {51 onChange={(event) => {
52 const nextColor = event.currentTarget.value;52 const nextColor = event.currentTarget.value;
...@@ -57,7 +57,6 @@ function ProviderCustomColorPanel(props: {...@@ -57,7 +57,6 @@ function ProviderCustomColorPanel(props: {
57 }}57 }}
58 onBlur={() => setHexDraft(null)}58 onBlur={() => setHexDraft(null)}
59 font="mono"59 font="mono"
60 className="text-xs"
61 aria-label="Custom hex accent color"60 aria-label="Custom hex accent color"
62 spellCheck={false}61 spellCheck={false}
63 />62 />
apps/web/src/components/settings/ProviderSettingsForm.tsx-1
...@@ -388,7 +388,6 @@ function ProviderSettingsFieldRow({...@@ -388,7 +388,6 @@ function ProviderSettingsFieldRow({
388 ) : (388 ) : (
389 <Input389 <Input
390 id={inputId}390 id={inputId}
391 className="bg-background"
392 type={type}391 type={type}
393 autoComplete={field.control === "password" ? "off" : undefined}392 autoComplete={field.control === "password" ? "off" : undefined}
394 value={readProviderConfigString(value, field.key)}393 value={readProviderConfigString(value, field.key)}
apps/web/src/components/settings/StorageSettings.tsx+1-1
...@@ -62,7 +62,7 @@ function RetentionControl({...@@ -62,7 +62,7 @@ function RetentionControl({
62 <NumberFieldInput62 <NumberFieldInput
63 aria-label={`${label} in days`}63 aria-label={`${label} in days`}
64 size={new Intl.NumberFormat().format(draft ?? value).length}64 size={new Intl.NumberFormat().format(draft ?? value).length}
65 className="field-sizing-content w-auto min-w-[1ch] grow-0 text-right in-data-[size=sm]:px-1"65 className="field-sizing-content w-auto min-w-[1ch] grow-0 text-right"
66 />66 />
67 <span aria-hidden="true" className="self-center pr-2 text-xs">67 <span aria-hidden="true" className="self-center pr-2 text-xs">
68 days68 days
apps/web/src/components/settings/ThemeColorPicker.tsx+2-3
...@@ -353,15 +353,14 @@ export const ThemeColorField = memo(function ThemeColorField({...@@ -353,15 +353,14 @@ export const ThemeColorField = memo(function ThemeColorField({
353 <Input353 <Input
354 aria-invalid={!isColorValue}354 aria-invalid={!isColorValue}
355 aria-label={`${label} hex value`}355 aria-label={`${label} hex value`}
356 className="w-28 shrink-0 rounded-md border-0 bg-black/10 text-xs text-foreground shadow-none focus-within:bg-black/15 focus-within:ring-0 dark:bg-black/20 dark:focus-within:bg-black/25 [&_[data-slot=input]]:text-right"356 className="w-28 shrink-0 [&_[data-slot=input]]:text-right"
357 font="mono"357 font="mono"
358 id={`${role}-hex`}358 id={`${role}-hex`}
359 nativeInput359 nativeInput
360 onChange={(event) => onChange(role, event.currentTarget.value)}360 onChange={(event) => onChange(role, event.currentTarget.value)}
361 onFocus={() => onSelect?.(role)}361 onFocus={() => onSelect?.(role)}
362 onPointerDown={() => onSelect?.(role)}362 onPointerDown={() => onSelect?.(role)}
363 size="sm"363 size="compact"
364 unstyled
365 value={editorValue}364 value={editorValue}
366 />365 />
367 </div>366 </div>
apps/web/src/components/ui/autocomplete.tsx+1-1
...@@ -125,7 +125,7 @@ function AutocompleteItem({ className, children, ...props }: AutocompletePrimiti...@@ -125,7 +125,7 @@ function AutocompleteItem({ className, children, ...props }: AutocompletePrimiti
125 return (125 return (
126 <AutocompletePrimitive.Item126 <AutocompletePrimitive.Item
127 className={cn(127 className={cn(
128 "flex min-h-8 cursor-default select-none items-center rounded-sm px-2 py-1 text-base outline-none hover:bg-accent data-disabled:pointer-events-none data-selected:bg-accent/50 data-selected:text-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground [&[data-highlighted][data-selected]]:bg-accent [&[data-highlighted][data-selected]]:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='text-'])]:text-muted-foreground",128 "flex min-h-8 cursor-default select-none items-center gap-2 rounded-sm px-2 py-1 text-base outline-none hover:bg-accent data-disabled:pointer-events-none data-selected:bg-accent/50 data-selected:text-foreground data-highlighted:bg-accent data-highlighted:text-accent-foreground [&[data-highlighted][data-selected]]:bg-accent [&[data-highlighted][data-selected]]:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='text-'])]:text-muted-foreground",
129 className,129 className,
130 )}130 )}
131 data-slot="autocomplete-item"131 data-slot="autocomplete-item"
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 = 499;11export const RESTYLE_CEILING = 402;
1212
13const RULE = "shadcn(no-restyle)";13const RULE = "shadcn(no-restyle)";
1414