Skip to content

Commit 9b939f4

Browse files
committed
fix: align table menu styling
1 parent acc4f1d commit 9b939f4

5 files changed

Lines changed: 17 additions & 18 deletions

File tree

.claude/rules/emcn-components.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The menu surface intentionally diverges from the pill: `dropdown-menu.tsx` items
3232
- **`ChipDatePicker`** — chip-styled date field.
3333
- **`ChipTimePicker`** — minute-granular time sibling of `ChipDatePicker`, a `ChipInput` that leniently parses typed input (`9:47`, `947`, `2:05pm`, `14:30`), commits on Enter/blur, and re-renders the canonical `9:47 AM` label.
3434
- **`DropdownMenu`** — the canonical context/action menu (Radix-backed). Not a chip, but the standard menu for command/action lists; reach for it instead of a hand-rolled popover. Its surface intentionally diverges from the chip pill (`text-small`, `gap-2`) — keep them distinct. For a pill that opens a value picker, use `ChipDropdown`/`ChipSelect` instead.
35-
- **`OverflowText`** — the canonical single-line overflow treatment for read-only human labels and titles. It owns `min-w-0`, fade-only clipping (never an ellipsis), the conditional 18px edge mask, and the full-value floating tooltip; consumers pass only layout/typography through `className`. `overflowTextClipClass` and `overflowTextFadeClass` are the complete base/faded treatments for the rare component that must own measurement itself; never pair either with `truncate`, `text-ellipsis`, or hover-time mask removal. Use `DropdownMenuItemLabel` for a menu label beside icons, checks, or actions. A non-editable `Combobox` passes the full visual value through `overlayLabel`; the combobox owns the visual overlay's fade and keeps its one accessible tooltip on the interactive layer. Keep ordinary `truncate` only for editable values, code/log/path content, dense or virtualized grids, and rich composite content that cannot supply a plain tooltip label. Multiline copy uses an intentional `line-clamp-*` treatment instead.
35+
- **`OverflowText`** — the canonical single-line overflow treatment for read-only human labels and titles. It owns `min-w-0`, fade-only clipping (never an ellipsis), the conditional 16px edge mask, and the full-value floating tooltip; consumers pass only layout/typography through `className`. `overflowTextClipClass` and `overflowTextFadeClass` are the complete base/faded treatments for the rare component that must own measurement itself; never pair either with `truncate`, `text-ellipsis`, or hover-time mask removal. Use `DropdownMenuItemLabel` for a menu label beside icons, checks, or actions. A non-editable `Combobox` passes the full visual value through `overlayLabel`; the combobox owns the visual overlay's fade and keeps its one accessible tooltip on the interactive layer. Keep ordinary `truncate` only for editable values, code/log/path content, dense or virtualized grids, and rich composite content that cannot supply a plain tooltip label. Multiline copy uses an intentional `line-clamp-*` treatment instead.
3636

3737
## Modal keyboard defaults
3838

apps/sim/app/workspace/[workspaceId]/components/resource/components/resource-header/resource-header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ function BreadcrumbLocationPopover({
562562
border
563563
className={cn(
564564
POPOVER_ANIMATION_CLASSES,
565-
'bg-[var(--bg)] p-1.5 text-[var(--text-body)] shadow-sm'
565+
'bg-[var(--bg)] p-1.5 text-[var(--text-body)] shadow-sm dark:[--surface-hover:var(--surface-4)]'
566566
)}
567567
onMouseEnter={openPopover}
568568
onMouseLeave={scheduleClose}

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/views-menu/views-menu.tsx

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
chipContentLabelClass,
99
chipVariants,
1010
cn,
11+
dropdownMenuRowClass,
1112
OverflowText,
1213
POPOVER_ANIMATION_CLASSES,
1314
Popover,
@@ -27,7 +28,7 @@ export const ALL_ROWS_VIEW_LABEL = 'All'
2728
/** Matches the breadcrumb location popover's hover-intent grace period. */
2829
const POPOVER_CLOSE_DELAY_MS = 120
2930

30-
/** Rendered width of one action button (`p-1` + `size-3` glyph) plus its `gap-0.5`.
31+
/** Rendered width of one 20px action button plus its `gap-0.5`.
3132
* The row reserves `actionCount` of these, so keep it in step with the button
3233
* classes below — the overlay is absolutely positioned and can't size the spacer. */
3334
const VIEW_ACTION_SLOT_PX = 22
@@ -137,16 +138,16 @@ export const ViewsMenu = memo(function ViewsMenu({
137138
border
138139
className={cn(
139140
POPOVER_ANIMATION_CLASSES,
140-
'bg-[var(--bg)] p-1.5 text-[var(--text-body)] shadow-sm'
141+
'bg-[var(--bg)] p-1 text-[var(--text-body)] shadow-sm dark:bg-[var(--bg)]'
141142
)}
142143
onMouseEnter={openPopover}
143144
onMouseLeave={scheduleClose}
144145
onFocusCapture={cancelScheduledClose}
145146
>
146-
<PopoverSection className='px-1.5 py-0.5 text-[var(--text-muted)] text-xs'>
147+
<PopoverSection className='flex h-[28px] items-center px-2 py-0 text-[var(--text-muted)] text-caption'>
147148
Views
148149
</PopoverSection>
149-
<div className='flex flex-col gap-0.5'>
150+
<div className='flex flex-col'>
150151
{!hasDefaultView && (
151152
<ViewRow
152153
label={ALL_ROWS_VIEW_LABEL}
@@ -194,13 +195,10 @@ export const ViewsMenu = memo(function ViewsMenu({
194195
</div>
195196
{canEdit && (
196197
<>
197-
<div className='my-1 h-px bg-[var(--border)]' />
198-
<PopoverItem
199-
onClick={() => runAndClose(onNewView)}
200-
className='h-7 items-center gap-1.5 px-1.5 py-0 text-xs'
201-
>
198+
<div className='my-1 h-px bg-[var(--border-1)]' />
199+
<PopoverItem onClick={() => runAndClose(onNewView)} className={dropdownMenuRowClass}>
202200
<span className='flex size-[14px] shrink-0 items-center justify-center'>
203-
<Plus className='size-3 text-[var(--text-icon)]' />
201+
<Plus className='size-[14px] text-[var(--text-icon)]' />
204202
</span>
205203
<OverflowText label='New view' className='flex-1 text-left' />
206204
</PopoverItem>
@@ -268,10 +266,10 @@ function ViewRow({ label, isActive, onSelect, defaultState, actions }: ViewRowPr
268266
<PopoverItem
269267
active={isActive}
270268
onClick={onSelect}
271-
className='h-7 min-w-0 flex-1 items-center gap-1.5 px-1.5 py-0 text-xs'
269+
className={cn(dropdownMenuRowClass, 'flex-1')}
272270
>
273271
<span className='flex size-[14px] shrink-0 items-center justify-center'>
274-
{isActive && <Check className='size-3 text-[var(--text-icon)]' />}
272+
{isActive && <Check className='size-[14px] text-[var(--text-icon)]' />}
275273
</span>
276274
<OverflowText label={label} className='flex-1 text-left' />
277275
{actionCount > 0 && (
@@ -283,7 +281,7 @@ function ViewRow({ label, isActive, onSelect, defaultState, actions }: ViewRowPr
283281
)}
284282
</PopoverItem>
285283
{actionCount > 0 && (
286-
<div className='pointer-events-none absolute right-1.5 flex items-center gap-0.5'>
284+
<div className='pointer-events-none absolute right-1 flex items-center gap-0.5'>
287285
{actions?.map((action) => {
288286
// Disabled via aria-disabled, not the `disabled` attribute: the button
289287
// must keep receiving hover and focus events so the tooltip can explain
@@ -311,7 +309,7 @@ function ViewRow({ label, isActive, onSelect, defaultState, actions }: ViewRowPr
311309
: 'group-focus-within/view:opacity-100 group-hover/view:opacity-100'
312310
)}
313311
>
314-
<action.icon className='size-3' />
312+
<action.icon className='size-[14px]' />
315313
</Button>
316314
)
317315
return action.disabledReason ? (
@@ -344,7 +342,7 @@ function ViewRow({ label, isActive, onSelect, defaultState, actions }: ViewRowPr
344342
defaultState.onSetDefault?.()
345343
}}
346344
>
347-
<Pin className={cn('size-3', defaultState.isDefault && 'fill-current')} />
345+
<Pin className={cn('size-[14px]', defaultState.isDefault && 'fill-current')} />
348346
</Button>
349347
)}
350348
</div>

packages/emcn/src/components/overflow-text/overflow-text.test.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ describe('OverflowText', () => {
100100
expect(label.classList.contains('text-sm')).toBe(true)
101101
expect(label.className).toContain('-webkit-mask-image:linear-gradient')
102102
expect(label.className).toContain('mask-image:linear-gradient')
103+
expect(label.className).toContain('100%_-_16px')
103104

104105
act(() => {
105106
label.dispatchEvent(

packages/emcn/src/components/overflow-text/overflow-text.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212

1313
/** Complete fade-only clipping treatment for measured special cases. */
1414
export const overflowTextFadeClass =
15-
'overflow-hidden text-clip whitespace-nowrap [-webkit-mask-image:linear-gradient(to_right,black_calc(100%_-_18px),transparent)] [mask-image:linear-gradient(to_right,black_calc(100%_-_18px),transparent)]'
15+
'overflow-hidden text-clip whitespace-nowrap [-webkit-mask-image:linear-gradient(to_right,black_calc(100%_-_16px),transparent)] [mask-image:linear-gradient(to_right,black_calc(100%_-_16px),transparent)]'
1616

1717
/** Fade-free clipping for externally measured labels and rich-content overflow exceptions. */
1818
export const overflowTextClipClass = 'block min-w-0 overflow-hidden text-clip whitespace-nowrap'

0 commit comments

Comments
 (0)