Skip to content

Commit d587f1a

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
refactor(emcn): centralize overlay action buttons
1 parent 0b7c6ae commit d587f1a

6 files changed

Lines changed: 92 additions & 37 deletions

File tree

‎apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-view/trace-view.tsx‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
DropdownMenuSeparator,
1616
DropdownMenuTrigger,
1717
Duplicate,
18+
OverlayActionButton,
1819
Search as SearchIcon,
1920
Tooltip,
2021
useCopyToClipboard,
@@ -504,39 +505,35 @@ function DetailCodeSection({
504505
<div className='absolute top-[7px] right-[6px] z-10 flex gap-1'>
505506
<Tooltip.Root>
506507
<Tooltip.Trigger asChild>
507-
<Button
508+
<OverlayActionButton
508509
aria-label={copied ? 'Copied' : 'Copy'}
509510
type='button'
510-
variant='default'
511511
onClick={(e) => {
512512
e.stopPropagation()
513513
handleCopy()
514514
}}
515-
className='size-[20px] cursor-pointer border-[var(--border-1)] bg-transparent p-0 backdrop-blur-xs hover-hover:bg-[var(--surface-3)]'
516515
>
517516
{copied ? (
518517
<Check className='size-[10px] text-[var(--text-success)]' />
519518
) : (
520519
<Clipboard className='size-[10px]' />
521520
)}
522-
</Button>
521+
</OverlayActionButton>
523522
</Tooltip.Trigger>
524523
<Tooltip.Content side='top'>{copied ? 'Copied' : 'Copy'}</Tooltip.Content>
525524
</Tooltip.Root>
526525
<Tooltip.Root>
527526
<Tooltip.Trigger asChild>
528-
<Button
527+
<OverlayActionButton
529528
aria-label='Search'
530529
type='button'
531-
variant='default'
532530
onClick={(e) => {
533531
e.stopPropagation()
534532
activateSearch()
535533
}}
536-
className='size-[20px] cursor-pointer border-[var(--border-1)] bg-transparent p-0 backdrop-blur-xs hover-hover:bg-[var(--surface-3)]'
537534
>
538535
<Search className='size-[10px]' />
539-
</Button>
536+
</OverlayActionButton>
540537
</Tooltip.Trigger>
541538
<Tooltip.Content side='top'>Search</Tooltip.Content>
542539
</Tooltip.Root>

‎apps/sim/app/workspace/[workspaceId]/logs/components/log-details/log-details.tsx‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
Duplicate,
2828
Eye,
2929
handleKeyboardActivation,
30+
OverlayActionButton,
3031
Redo,
3132
Search as SearchIcon,
3233
Tooltip,
@@ -168,39 +169,35 @@ export const WorkflowOutputSection = memo(
168169
<div className='absolute top-[7px] right-[6px] z-10 flex gap-1'>
169170
<Tooltip.Root>
170171
<Tooltip.Trigger asChild>
171-
<Button
172+
<OverlayActionButton
172173
aria-label={copied ? 'Copied' : 'Copy'}
173174
type='button'
174-
variant='default'
175175
onClick={(e) => {
176176
e.stopPropagation()
177177
handleCopy()
178178
}}
179-
className='size-[20px] cursor-pointer border-[var(--border-1)] bg-transparent p-0 backdrop-blur-xs hover-hover:bg-[var(--surface-3)]'
180179
>
181180
{copied ? (
182181
<Check className='size-[10px] text-[var(--text-success)]' />
183182
) : (
184183
<Clipboard className='size-[10px]' />
185184
)}
186-
</Button>
185+
</OverlayActionButton>
187186
</Tooltip.Trigger>
188187
<Tooltip.Content side='top'>{copied ? 'Copied' : 'Copy'}</Tooltip.Content>
189188
</Tooltip.Root>
190189
<Tooltip.Root>
191190
<Tooltip.Trigger asChild>
192-
<Button
191+
<OverlayActionButton
193192
aria-label='Search'
194193
type='button'
195-
variant='default'
196194
onClick={(e) => {
197195
e.stopPropagation()
198196
activateSearch()
199197
}}
200-
className='size-[20px] cursor-pointer border-[var(--border-1)] bg-transparent p-0 backdrop-blur-xs hover-hover:bg-[var(--surface-3)]'
201198
>
202199
<Search className='size-[10px]' />
203-
</Button>
200+
</OverlayActionButton>
204201
</Tooltip.Trigger>
205202
<Tooltip.Content side='top'>Search</Tooltip.Content>
206203
</Tooltip.Root>

‎apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/general/general.tsx‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import { useId, useState } from 'react'
44
import {
5-
Button,
65
ChipButtonGroup,
76
ChipButtonGroupItem,
87
ChipConfirmModal,
@@ -12,6 +11,7 @@ import {
1211
cn,
1312
Expand,
1413
Label,
14+
OverlayActionButton,
1515
Skeleton,
1616
Tooltip,
1717
} from '@sim/emcn'
@@ -241,15 +241,15 @@ export function GeneralDeploy({
241241
</div>
242242
<Tooltip.Root>
243243
<Tooltip.Trigger asChild>
244-
<Button
244+
<OverlayActionButton
245245
aria-label='See preview'
246246
type='button'
247-
variant='default'
247+
size='md'
248248
onClick={() => setShowExpandedPreview(true)}
249-
className='absolute right-[8px] bottom-2 z-10 size-[28px] cursor-pointer bg-transparent p-0 backdrop-blur-xs hover-hover:bg-[var(--surface-3)]'
249+
className='absolute right-[8px] bottom-2 z-10'
250250
>
251251
<Expand className='size-[14px]' />
252-
</Button>
252+
</OverlayActionButton>
253253
</Tooltip.Trigger>
254254
<Tooltip.Content side='top'>See preview</Tooltip.Content>
255255
</Tooltip.Root>

‎apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-editor/preview-editor.tsx‎

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
Input,
1313
Label,
1414
OverflowText,
15+
OverlayActionButton,
1516
Tooltip,
1617
} from '@sim/emcn'
1718
import {
@@ -1235,41 +1236,39 @@ function PreviewEditorContent({
12351236
<div className='absolute top-[7px] right-[6px] z-10 flex gap-1'>
12361237
<Tooltip.Root>
12371238
<Tooltip.Trigger asChild>
1238-
<Button
1239+
<OverlayActionButton
12391240
aria-label={copiedSection === 'input' ? 'Copied' : 'Copy'}
12401241
type='button'
1241-
variant='ghost'
1242+
surface='uniform'
12421243
onClick={(e) => {
12431244
e.stopPropagation()
12441245
handleCopySection(formatValueAsJson(executionData.input), 'input')
12451246
}}
1246-
className='size-[20px] cursor-pointer border border-[var(--border-1)] bg-transparent p-0 backdrop-blur-xs hover-hover:bg-[var(--surface-4)]'
12471247
>
12481248
{copiedSection === 'input' ? (
12491249
<Check className='size-[10px] text-[var(--text-success)]' />
12501250
) : (
12511251
<Clipboard className='size-[10px]' />
12521252
)}
1253-
</Button>
1253+
</OverlayActionButton>
12541254
</Tooltip.Trigger>
12551255
<Tooltip.Content side='top'>
12561256
{copiedSection === 'input' ? 'Copied' : 'Copy'}
12571257
</Tooltip.Content>
12581258
</Tooltip.Root>
12591259
<Tooltip.Root>
12601260
<Tooltip.Trigger asChild>
1261-
<Button
1261+
<OverlayActionButton
12621262
aria-label='Search'
12631263
type='button'
1264-
variant='ghost'
1264+
surface='uniform'
12651265
onClick={(e) => {
12661266
e.stopPropagation()
12671267
activateSearch()
12681268
}}
1269-
className='size-[20px] cursor-pointer border border-[var(--border-1)] bg-transparent p-0 backdrop-blur-xs hover-hover:bg-[var(--surface-4)]'
12701269
>
12711270
<Search className='size-[10px]' />
1272-
</Button>
1271+
</OverlayActionButton>
12731272
</Tooltip.Trigger>
12741273
<Tooltip.Content side='top'>Search</Tooltip.Content>
12751274
</Tooltip.Root>
@@ -1309,41 +1308,39 @@ function PreviewEditorContent({
13091308
<div className='absolute top-[7px] right-[6px] z-10 flex gap-1'>
13101309
<Tooltip.Root>
13111310
<Tooltip.Trigger asChild>
1312-
<Button
1311+
<OverlayActionButton
13131312
aria-label={copiedSection === 'output' ? 'Copied' : 'Copy'}
13141313
type='button'
1315-
variant='ghost'
1314+
surface='uniform'
13161315
onClick={(e) => {
13171316
e.stopPropagation()
13181317
handleCopySection(formatValueAsJson(executionData.output), 'output')
13191318
}}
1320-
className='size-[20px] cursor-pointer border border-[var(--border-1)] bg-transparent p-0 backdrop-blur-xs hover-hover:bg-[var(--surface-4)]'
13211319
>
13221320
{copiedSection === 'output' ? (
13231321
<Check className='size-[10px] text-[var(--text-success)]' />
13241322
) : (
13251323
<Clipboard className='size-[10px]' />
13261324
)}
1327-
</Button>
1325+
</OverlayActionButton>
13281326
</Tooltip.Trigger>
13291327
<Tooltip.Content side='top'>
13301328
{copiedSection === 'output' ? 'Copied' : 'Copy'}
13311329
</Tooltip.Content>
13321330
</Tooltip.Root>
13331331
<Tooltip.Root>
13341332
<Tooltip.Trigger asChild>
1335-
<Button
1333+
<OverlayActionButton
13361334
aria-label='Search'
13371335
type='button'
1338-
variant='ghost'
1336+
surface='uniform'
13391337
onClick={(e) => {
13401338
e.stopPropagation()
13411339
activateSearch()
13421340
}}
1343-
className='size-[20px] cursor-pointer border border-[var(--border-1)] bg-transparent p-0 backdrop-blur-xs hover-hover:bg-[var(--surface-4)]'
13441341
>
13451342
<Search className='size-[10px]' />
1346-
</Button>
1343+
</OverlayActionButton>
13471344
</Tooltip.Trigger>
13481345
<Tooltip.Content side='top'>Search</Tooltip.Content>
13491346
</Tooltip.Root>

‎packages/emcn/src/components/index.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ export {
196196
overflowTextClipClass,
197197
overflowTextFadeClass,
198198
} from './overflow-text/overflow-text'
199+
export {
200+
OverlayActionButton,
201+
type OverlayActionButtonProps,
202+
overlayActionButtonVariants,
203+
} from './overlay-action-button/overlay-action-button'
199204
export {
200205
Popover,
201206
PopoverAnchor,
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { forwardRef } from 'react'
2+
import { cva, type VariantProps } from 'class-variance-authority'
3+
import { cn } from '../../lib/cn'
4+
import { Button, type ButtonProps } from '../button/button'
5+
6+
/** Transparent, bordered icon action over code or preview content. */
7+
export const overlayActionButtonVariants = cva(
8+
'cursor-pointer border border-[var(--border)] bg-transparent p-0 backdrop-blur-xs',
9+
{
10+
variants: {
11+
size: {
12+
sm: 'size-[20px]',
13+
md: 'size-[28px]',
14+
},
15+
surface: {
16+
adaptive:
17+
'hover-hover:bg-[var(--surface-3)] dark:hover-hover:bg-[var(--surface-5)] hover-hover:border-[var(--border)]',
18+
uniform: 'hover-hover:bg-[var(--surface-4)]',
19+
},
20+
},
21+
defaultVariants: { size: 'sm', surface: 'adaptive' },
22+
}
23+
)
24+
25+
export interface OverlayActionButtonProps
26+
extends Omit<ButtonProps, 'variant' | 'size' | 'iconPadding'> {
27+
/** Accessible name for the icon action; tooltip content is supplied separately. */
28+
'aria-label': string
29+
/** 20px by default; `md` provides the 28px preview action. */
30+
size?: NonNullable<VariantProps<typeof overlayActionButtonVariants>['size']>
31+
/**
32+
* `adaptive` uses surface-3 on hover in light mode and surface-5 in dark mode.
33+
* `uniform` uses surface-4 on hover in both themes.
34+
* @default 'adaptive'
35+
*/
36+
surface?: NonNullable<VariantProps<typeof overlayActionButtonVariants>['surface']>
37+
}
38+
39+
/**
40+
* Icon action floating over content. Owns geometry, border, blur and hover treatment;
41+
* callers supply positioning, icons, labels and command behavior.
42+
* Forwards the native button ref and props for tooltip `asChild` composition.
43+
* Native form behavior is inherited from Button; pass `type` when it must be explicit.
44+
*
45+
* @example <OverlayActionButton aria-label='Copy' type='button' onClick={onCopy}><Clipboard className='size-[10px]' /></OverlayActionButton>
46+
*/
47+
export const OverlayActionButton = forwardRef<HTMLButtonElement, OverlayActionButtonProps>(
48+
({ size, surface, className, ...props }, ref) => (
49+
<Button
50+
{...props}
51+
ref={ref}
52+
variant='ghost'
53+
size='md'
54+
className={cn(overlayActionButtonVariants({ size, surface }), className)}
55+
/>
56+
)
57+
)
58+
59+
OverlayActionButton.displayName = 'OverlayActionButton'

0 commit comments

Comments
 (0)