Skip to content

Commit 269b65c

Browse files
pratikbuildsTheGreatAxios
authored andcommitted
Improve plugin drawer input behavior
1 parent b19ca3b commit 269b65c

4 files changed

Lines changed: 33 additions & 17 deletions

File tree

‎apps/web/src/app.css‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ html {
3838
outline-offset: 2px;
3939
}
4040

41-
/* Inputs already have a visible control boundary. Color that edge on focus so
42-
the focus treatment reads as one control, not a second outline outside it. */
43-
[data-slot="input"]:focus-visible {
41+
/* Inputs in side drawers already have a visible control boundary. Color that
42+
edge on focus so the focus treatment reads as one control, not a second
43+
outline outside it. */
44+
[data-slot="dialog-content"][data-side="right"]
45+
[data-slot="input"]:focus-visible {
4446
outline: none;
4547
border-color: var(--accent-rail, var(--primary));
4648
}

‎packages/plugins-ui/src/mcp-preset-cards.tsx‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export function McpPresetCard({
7575
readonly preset: McpPreset;
7676
readonly toolCount: number | undefined;
7777
readonly onChanged: (toolCount?: number) => void;
78-
readonly onOpen: () => void;
78+
readonly onOpen: (trigger: HTMLButtonElement) => void;
7979
}) {
8080
const [busy, setBusy] = useState(false);
8181
const [error, setError] = useState<string | null>(() =>
@@ -95,13 +95,13 @@ export function McpPresetCard({
9595
.finally(() => setBusy(false));
9696
}
9797

98-
function handleConnect() {
98+
function handleConnect(trigger: HTMLButtonElement) {
9999
if (preset.connectionMode === "oauth") {
100100
window.location.href = mcpOAuthStartPath(tenantId, preset.slug);
101101
return;
102102
}
103103
if (preset.connectionMode === "token") {
104-
onOpen();
104+
onOpen(trigger);
105105
return;
106106
}
107107
submitConnect();
@@ -153,7 +153,7 @@ export function McpPresetCard({
153153
size="sm"
154154
variant="ghost"
155155
aria-label={`Manage ${preset.displayName}`}
156-
onClick={onOpen}
156+
onClick={(event) => onOpen(event.currentTarget)}
157157
>
158158
Manage
159159
<span className="sr-only"> {preset.displayName}</span>
@@ -165,7 +165,7 @@ export function McpPresetCard({
165165
variant="ghost"
166166
disabled={busy}
167167
aria-label={`Connect ${preset.displayName}`}
168-
onClick={handleConnect}
168+
onClick={(event) => handleConnect(event.currentTarget)}
169169
>
170170
{busy ? "Connecting…" : "Connect"}
171171
</Button>

‎packages/plugins-ui/src/plugin-connect-panel.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,14 +312,14 @@ function McpPresetPanelContent({
312312
className="flex flex-col gap-1.5 text-sm font-medium"
313313
htmlFor={tokenFieldId}
314314
>
315-
API key
315+
Personal access token
316316
<Input
317317
id={tokenFieldId}
318318
type="password"
319319
value={token}
320320
placeholder="Paste your access token"
321321
disabled={busy}
322-
autoComplete="off"
322+
autoComplete="new-password"
323323
onChange={(event) => {
324324
setToken(event.target.value);
325325
setError(null);

‎packages/plugins-ui/src/plugins-gallery.tsx‎

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useMemo, useState } from "react";
1+
import { useEffect, useMemo, useRef, useState } from "react";
22

33
import { Lightning } from "@corbits/icons";
44
import { EmptyState, FilterChip, Tabs } from "@corbits/react-ui";
@@ -133,6 +133,7 @@ function PluginCatalogPanel({
133133
readonly onOpenPreset: (
134134
preset: McpPreset,
135135
toolCount: number | undefined,
136+
trigger: HTMLButtonElement,
136137
) => void;
137138
readonly onOpenPlugin: (plugin: ResolvedPlugin) => void;
138139
}) {
@@ -181,8 +182,8 @@ function PluginCatalogPanel({
181182
preset={entry.preset}
182183
toolCount={toolCounts.get(entry.id)}
183184
onChanged={(toolCount) => onPresetChanged(entry.id, toolCount)}
184-
onOpen={() =>
185-
onOpenPreset(entry.preset, toolCounts.get(entry.id))
185+
onOpen={(trigger) =>
186+
onOpenPreset(entry.preset, toolCounts.get(entry.id), trigger)
186187
}
187188
/>
188189
) : (
@@ -296,9 +297,22 @@ export function PluginsGallery({
296297
const [openPreset, setOpenPreset] = useState<{
297298
readonly preset: McpPreset;
298299
readonly toolCount: number | undefined;
300+
readonly trigger: HTMLButtonElement;
299301
} | null>(null);
302+
const presetFocusTrigger = useRef<HTMLButtonElement | null>(null);
300303
const presetCatalog = useMcpPresetCatalog(tenantId);
301304

305+
useEffect(() => {
306+
if (openPreset !== null) return;
307+
presetFocusTrigger.current?.focus();
308+
presetFocusTrigger.current = null;
309+
}, [openPreset]);
310+
311+
function closePreset() {
312+
presetFocusTrigger.current = openPreset?.trigger ?? null;
313+
setOpenPreset(null);
314+
}
315+
302316
const nativeEntries = useMemo<readonly PluginCatalogEntry[]>(
303317
() =>
304318
plugins
@@ -398,8 +412,8 @@ export function PluginsGallery({
398412
onFilterChange={setActiveFilter}
399413
toolCounts={presetCatalog.toolCounts}
400414
onPresetChanged={presetCatalog.handleChanged}
401-
onOpenPreset={(preset, toolCount) =>
402-
setOpenPreset({ preset, toolCount })
415+
onOpenPreset={(preset, toolCount, trigger) =>
416+
setOpenPreset({ preset, toolCount, trigger })
403417
}
404418
onOpenPlugin={onOpenPlugin}
405419
/>
@@ -427,11 +441,11 @@ export function PluginsGallery({
427441
toolCount: openPreset.toolCount,
428442
}
429443
}
430-
onClose={() => setOpenPreset(null)}
444+
onClose={closePreset}
431445
onChanged={(toolCount) => {
432446
if (openPreset === null) return;
433447
presetCatalog.handleChanged(openPreset.preset.slug, toolCount);
434-
setOpenPreset(null);
448+
closePreset();
435449
}}
436450
/>
437451
</div>

0 commit comments

Comments
 (0)