From 04747937a2251e3df074304d9da4703cd9b8cf98 Mon Sep 17 00:00:00 2001 From: Saxon Fletcher Date: Mon, 7 Sep 2026 09:48:01 +1000 Subject: [PATCH 1/2] fix(ui-patterns): align badges and input in the tiny multi-select trigger (#49986) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What's changed **Before** image **After** image Independent of the Explorer/assistant stack. `MultiSelectorTrigger` with `size="tiny"` had badges and the inline input overflowing the 26px control. The trigger now stretches its children (`items-stretch`), badges are `h-full py-0 leading-none` with a tighter `gap-0.5`, the input/label drop their extra padding and line-height, and the chevron self-centers. Other sizes are unchanged (`isTiny` guards every new class). Also drops a redundant `text-sm` from `MultiSelectorInput`, which `MultiSelectorInputVariants` already sets per size. ## How to test 1. Design system (`pnpm dev:design-system`) or anywhere Studio uses `` (e.g. Logs filters): with 1–3 values selected the badges sit inside the 26px control with no clipping; the placeholder and chevron are vertically centered. 2. `size="small"` / default still look the same as on `master`. 3. `pnpm --filter ui-patterns exec vitest --run src/multi-select` passes. ## Summary by CodeRabbit - **Style** - Improved the compact multi-select control layout, including spacing, alignment, selected-value badges, input sizing, and dropdown indicator positioning. - Adjusted placeholder spacing when the tiny control has no selected values. - **Tests** - Updated coverage to verify compact spacing and sizing when the tiny multi-select control displays a selected value. --------- Co-authored-by: Cursor --- .../src/multi-select/multi-select.test.tsx | 6 +- .../src/multi-select/multi-select.tsx | 116 +++++++++++++++--- 2 files changed, 105 insertions(+), 17 deletions(-) diff --git a/packages/ui-patterns/src/multi-select/multi-select.test.tsx b/packages/ui-patterns/src/multi-select/multi-select.test.tsx index 5dfed06154b94..50d3ae3e5281c 100644 --- a/packages/ui-patterns/src/multi-select/multi-select.test.tsx +++ b/packages/ui-patterns/src/multi-select/multi-select.test.tsx @@ -50,12 +50,14 @@ function MultiSelectDemo() { describe('multi-select', () => { it('supports the tiny control size', () => { render( - undefined}> + undefined}> ) - expect(screen.getByRole('combobox')).toHaveClass('h-[26px]', 'p-0.5') + const trigger = screen.getByRole('combobox') + expect(trigger).toHaveClass('h-[26px]', 'p-0.5') + expect(trigger.firstElementChild).toHaveClass('gap-0.5') }) it('renders selected values with a custom label', () => { diff --git a/packages/ui-patterns/src/multi-select/multi-select.tsx b/packages/ui-patterns/src/multi-select/multi-select.tsx index d19adecb19170..2cc2a4c5970a1 100644 --- a/packages/ui-patterns/src/multi-select/multi-select.tsx +++ b/packages/ui-patterns/src/multi-select/multi-select.tsx @@ -229,14 +229,97 @@ export interface MultiSelectorTriggerProps extends React.HTMLAttributes React.ReactNode } +// The tiny control has no vertical padding to spare, so its children stretch to the +// control height and drop their line-height; the larger sizes center normally. const MultiSelectorTriggerVariants = cva('', { variants: { size: { - tiny: 'h-[26px] p-0.5 text-xs', - small: 'min-h-[34px] px-3 py-1.5 text-sm', - medium: 'min-h-[38px] px-4 py-2 text-sm', - large: 'min-h-[42px] px-4 py-2 text-base', - xlarge: 'min-h-[50px] px-6 py-3 text-base', + tiny: 'h-[26px] p-0.5 text-xs items-stretch', + small: 'min-h-[34px] px-3 py-1.5 text-sm items-center', + medium: 'min-h-[38px] px-4 py-2 text-sm items-center', + large: 'min-h-[42px] px-4 py-2 text-base items-center', + xlarge: 'min-h-[50px] px-6 py-3 text-base items-center', + }, + }, + defaultVariants: { + size: SIZE_VARIANTS_DEFAULT, + }, +}) + +const MultiSelectorBadgesVariants = cva('flex overflow-hidden flex-1 min-w-0', { + variants: { + size: { + tiny: 'h-full min-h-0 items-center gap-0.5', + small: 'gap-1 -ml-1', + medium: 'gap-1 -ml-1', + large: 'gap-1 -ml-1', + xlarge: 'gap-1 -ml-1', + }, + }, + defaultVariants: { + size: SIZE_VARIANTS_DEFAULT, + }, +}) + +const MultiSelectorBadgeVariants = cva( + 'rounded-sm shrink-0 px-1.5 bg-surface-75 dark:bg-white/5 normal-case tracking-normal text-xs', + { + variants: { + size: { + tiny: 'h-full py-0 leading-none', + small: '', + medium: '', + large: '', + xlarge: '', + }, + }, + defaultVariants: { + size: SIZE_VARIANTS_DEFAULT, + }, + } +) + +const MultiSelectorLabelVariants = cva( + 'text-foreground-muted whitespace-nowrap opacity-0 transition-opacity hidden', + { + variants: { + size: { + tiny: 'leading-none', + small: 'ml-1 leading-5.5', + medium: 'ml-1 leading-5.5', + large: 'ml-1 leading-5.5', + xlarge: 'ml-1 leading-5.5', + }, + }, + defaultVariants: { + size: SIZE_VARIANTS_DEFAULT, + }, + } +) + +const MultiSelectorInlineInputWrapperVariants = cva('px-0 flex-1 border-none truncate min-w-0', { + variants: { + size: { + tiny: 'h-full', + small: '', + medium: '', + large: '', + xlarge: '', + }, + }, + defaultVariants: { + size: SIZE_VARIANTS_DEFAULT, + }, +}) + +const MultiSelectorInlineInputVariants = cva('py-0 truncate', { + variants: { + size: { + tiny: 'px-0', + small: 'px-1', + medium: 'px-1', + large: 'px-1', + xlarge: 'px-1', }, }, defaultVariants: { @@ -277,6 +360,7 @@ const MultiSelectorTrigger = React.forwardRef { if (!inputRef?.current || !badgesRef.current) return @@ -290,8 +374,7 @@ const MultiSelectorTrigger = React.forwardRef = React.useCallback( (event) => { @@ -326,7 +409,7 @@ const MultiSelectorTrigger = React.forwardRef 0 ? 'bg-field' : 'bg-control-raised', @@ -343,8 +426,7 @@ const MultiSelectorTrigger = React.forwardRef )} @@ -406,7 +492,7 @@ const MultiSelectorTrigger = React.forwardRef )} @@ -494,7 +580,7 @@ const MultiSelectorInput = React.forwardRef< wrapperClassName={wrapperClassName} className={cn( MultiSelectorInputVariants({ size }), - 'text-sm bg-transparent h-full grow border-none outline-hidden placeholder:text-foreground-muted flex-1', + 'bg-transparent h-full grow border-none outline-hidden placeholder:text-foreground-muted flex-1', activeIndex !== -1 && 'caret-transparent', className )} From 79964102d369991a3b3adda27dc1f528c3a77457 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Mon, 7 Sep 2026 12:42:18 +0900 Subject: [PATCH 2/2] Bump reviewdog action misspell (#50071) ## Context Our `avoid-typos` GHA which uses `reviewdog/action-misspell` is currently failing with a 404 while fetching some files to build the Docker container as per [here](https://github.com/supabase/supabase/actions/runs/34074954209/job/101604888827) for example. ```E: Failed to fetch http://deb.debian.org/debian-security/.../perl-modules-5.32... 404 Not Found``` Happening as v1.26.3's Dockerfile builds on `debian:bullseye-slim`, which is now EOL as of 31st Aug 2026 ([ref](https://www.debian.org/News/2026/20260831)). `bullseye-security` apt mirror has dropped the pinned perl package version, so the action's Docker image can no longer build [v1.28.0](https://github.com/reviewdog/action-misspell/releases/tag/v1.28.0) (Published on 6th Sept) switches the base image to `debian:bookworm-slim`, which resolves this ## Changes involved: - Bumps reviewdog/action-misspell from v1.26.3 to v1.28.0 in `avoid-typos.yml`. ## Summary by CodeRabbit * **Chores** * Corrected the pinned revision used by automated spelling checks. * No changes to application functionality or end-user behavior. --- .github/workflows/avoid-typos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/avoid-typos.yml b/.github/workflows/avoid-typos.yml index 8d171f231b05d..e0a35fb9d2a7b 100644 --- a/.github/workflows/avoid-typos.yml +++ b/.github/workflows/avoid-typos.yml @@ -21,7 +21,7 @@ jobs: with: persist-credentials: false - name: misspell - uses: reviewdog/action-misspell@9daa94af4357dddb6fd3775de806bc0a8e98d3e4 # v1.26.3 + uses: reviewdog/action-misspell@ba7ac4030fa6812f8c8b2d4e516af8bc99553c32 # v1.28.0 with: github_token: ${{ secrets.github_token }} locale: 'US'