ui: replace invented modal with old-plugin style — MenuItem component + Modal (More menu)

This commit is contained in:
Hermes Agent committed 2026-09-19 13:06:04 +02:00
1 parent 0fdd6164ed
commit b796eae1eb
2 files changed
+109 -16

No files matched your search

+88
View File
@@ -0,0 +1,88 @@
import { h } from 'preact'
import type { ComponentChildren } from 'preact'
export type MenuItemProps = {
icon?: ComponentChildren
children: ComponentChildren
onClick: () => void
disabled?: boolean
}
export default function MenuItem ({ icon, children, onClick, disabled = false }: MenuItemProps) {
return (
<div
className={`menuitem ${disabled ? 'disabled' : ''}`}
tabIndex={disabled ? -1 : 0}
style={{
width: 'auto', // Width fits content
minWidth: 'var(--space-24)', // Minimum width like IconButton
height: 'var(--space-24)', // Fixed height like IconButton
border: 'var(--border-width-1) solid transparent',
borderRadius: 'var(--border-radius-4)',
cursor: disabled ? 'not-allowed' : 'pointer',
backgroundColor: 'transparent',
color: disabled ? 'var(--figma-color-icon-disabled)' : 'var(--figma-color-icon)',
transition: 'background-color 0.1s ease, border-color 0.1s ease',
padding: '0 var(--space-8)',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
gap: 'var(--space-8)',
whiteSpace: 'nowrap'
}}
onClick={disabled ? undefined : onClick}
onKeyDown={(e) => {
if (!disabled && (e.key === 'Enter' || e.key === ' ')) {
e.preventDefault()
onClick()
}
}}
>
{icon && (
<div
style={{
width: 'var(--space-16)',
height: 'var(--space-16)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
color: 'inherit'
}}
>
{icon}
</div>
)}
<div
style={{
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
fontSize: 'var(--font-size-12)',
fontFamily: 'var(--font-family)',
fontWeight: 'var(--font-weight-normal)',
color: disabled ? 'var(--figma-color-text-disabled)' : 'var(--figma-color-text)'
}}
>
{children}
</div>
<style>{`
.menuitem:not(.disabled):hover {
background-color: var(--figma-color-bg-hover, #e0e0e0) !important;
}
.menuitem:not(.disabled):focus-visible {
border-color: var(--figma-color-border-selected, #007acc) !important;
outline: none !important;
}
.menuitem:not(.disabled):active {
background-color: var(--figma-color-bg-hover, #d0d0d0) !important;
}
.menuitem {
box-sizing: border-box !important;
}
`}</style>
</div>
)
}
+21 -16
View File
@@ -5,7 +5,6 @@ import {
Muted,
VerticalSpace,
Divider,
Button,
Stack,
Modal,
IconButton,
@@ -18,6 +17,7 @@ import {
import { emit, on } from '@create-figma-plugin/utilities'
import { h, Fragment } from 'preact'
import { useState, useEffect, useRef } from 'preact/hooks'
import MenuItem from './MenuItem'
const MIN_WINDOW_SIZE = { width: 320, height: 200 }
// No static max: "maximize" targets the whole viewport (maxViewport from main),
@@ -353,22 +353,27 @@ function Plugin () {
<VerticalSpace space="small" />
<Muted style={{ fontSize: '11px' }}>Version {PLUGIN_VERSION}</Muted>
</Container>
{/* More-menu modal (opened by the three-dots button in the header) — stubs for now */}
{moreOpen && (
<Modal
title="Menu"
open={true}
position="right"
onCloseButtonClick={function () { setMoreOpen(false) }}
onOverlayClick={function () { setMoreOpen(false) }}
>
<Stack space="small">
<Muted>Stub actions</Muted>
<Button onClick={function () { setMoreOpen(false) }}>Stub action 1</Button>
<Button onClick={function () { setMoreOpen(false) }}>Stub action 2</Button>
{/* More-menu modal — old-plugin style: library Modal + Container + Stack of MenuItem */}
<Modal open={moreOpen} onClose={function () { setMoreOpen(false) }} onOverlayClick={function () { setMoreOpen(false) }}>
<Container space="extraSmall">
<VerticalSpace space="extraSmall" />
<Stack space="extraSmall">
<MenuItem
icon={<IconWand24 />}
onClick={function () { setMoreOpen(false) /* stub */ }}
>
Stub action 1
</MenuItem>
<MenuItem
icon={<IconComponent24 />}
onClick={function () { setMoreOpen(false) /* stub */ }}
>
Stub action 2
</MenuItem>
</Stack>
</Modal>
)}
</Container>
<VerticalSpace space="extraSmall" />
</Modal>
{/* Decorative drag-handle icon in the bottom-right corner (as in the old plugin).
pointerEvents:none — the actual drag is caught by the invisible corner div. */}
<div