Add IDs to UI components (#511)
* Add IDs to Menu and its sub-menus * Commit uncommitted * Added ID on Styles and Zoom menu * Added ID on Tools menu * Added ID on Context menu
This commit is contained in:
parent
5b521df51e
commit
dd1fb73876
24 changed files with 387 additions and 186 deletions
|
@ -163,44 +163,48 @@ const InnerMenu = React.memo(function InnerMenu({ onBlur }: InnerContextMenuProp
|
|||
tabIndex={-1}
|
||||
onBlur={onBlur}
|
||||
>
|
||||
<MenuContent>
|
||||
<MenuContent id="TD-ContextMenu">
|
||||
{hasSelection ? (
|
||||
<>
|
||||
<CMRowButton onClick={handleDuplicate} kbd="#D">
|
||||
<CMRowButton onClick={handleDuplicate} kbd="#D" id="TD-ContextMenu-Duplicate">
|
||||
Duplicate
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleFlipHorizontal} kbd="⇧H">
|
||||
<CMRowButton
|
||||
onClick={handleFlipHorizontal}
|
||||
kbd="⇧H"
|
||||
id="TD-ContextMenu-Flip_Horizontal"
|
||||
>
|
||||
Flip Horizontal
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleFlipVertical} kbd="⇧V">
|
||||
<CMRowButton onClick={handleFlipVertical} kbd="⇧V" id="TD-ContextMenu-Flip_Vertical">
|
||||
Flip Vertical
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleLock} kbd="#⇧L">
|
||||
<CMRowButton onClick={handleLock} kbd="#⇧L" id="TD-ContextMenu- Lock_Unlock">
|
||||
Lock / Unlock
|
||||
</CMRowButton>
|
||||
{(hasTwoOrMore || hasGroupSelected) && <Divider />}
|
||||
{hasTwoOrMore && (
|
||||
<CMRowButton onClick={handleGroup} kbd="#G">
|
||||
<CMRowButton onClick={handleGroup} kbd="#G" id="TD-ContextMenu-Group">
|
||||
Group
|
||||
</CMRowButton>
|
||||
)}
|
||||
{hasGroupSelected && (
|
||||
<CMRowButton onClick={handleGroup} kbd="#G">
|
||||
<CMRowButton onClick={handleGroup} kbd="#G" id="TD-ContextMenu-Ungroup">
|
||||
Ungroup
|
||||
</CMRowButton>
|
||||
)}
|
||||
<Divider />
|
||||
<ContextMenuSubMenu label="Move">
|
||||
<CMRowButton onClick={handleMoveToFront} kbd="⇧]">
|
||||
<ContextMenuSubMenu label="Move" id="TD-ContextMenu-Move">
|
||||
<CMRowButton onClick={handleMoveToFront} kbd="⇧]" id="TD-ContextMenu-Move-To_Front">
|
||||
To Front
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleMoveForward} kbd="]">
|
||||
<CMRowButton onClick={handleMoveForward} kbd="]" id="TD-ContextMenu-Move-Forward">
|
||||
Forward
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleMoveBackward} kbd="[">
|
||||
<CMRowButton onClick={handleMoveBackward} kbd="[" id="TD-ContextMenu-Move-Backward">
|
||||
Backward
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleMoveToBack} kbd="⇧[">
|
||||
<CMRowButton onClick={handleMoveToBack} kbd="⇧[" id="TD-ContextMenu-Move-To_Back">
|
||||
To Back
|
||||
</CMRowButton>
|
||||
</ContextMenuSubMenu>
|
||||
|
@ -211,53 +215,79 @@ const InnerMenu = React.memo(function InnerMenu({ onBlur }: InnerContextMenuProp
|
|||
{app.callbacks.onExport ? (
|
||||
<>
|
||||
<Divider />
|
||||
<ContextMenuSubMenu label="Export" size="small">
|
||||
<CMRowButton onClick={handleExportPNG}>PNG</CMRowButton>
|
||||
<CMRowButton onClick={handleExportJPG}>JPG</CMRowButton>
|
||||
<CMRowButton onClick={handleExportWEBP}>WEBP</CMRowButton>
|
||||
<CMRowButton onClick={handleExportSVG}>SVG</CMRowButton>
|
||||
<CMRowButton onClick={handleExportJSON}>JSON</CMRowButton>
|
||||
<ContextMenuSubMenu label="Export" size="small" id="TD-ContextMenu-Export">
|
||||
<CMRowButton onClick={handleExportPNG} id="TD-ContextMenu-Export-PNG">
|
||||
PNG
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleExportJPG} id="TD-ContextMenu-Export-JPG">
|
||||
JPG
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleExportWEBP} id="TD-ContextMenu-Export-WEBP">
|
||||
WEBP
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleExportSVG} id="TD-ContextMenu-Export-SVG">
|
||||
SVG
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleExportJSON} id="TD-ContextMenu-Export-JSON">
|
||||
JSON
|
||||
</CMRowButton>
|
||||
<Divider />
|
||||
<CMRowButton onClick={handleCopySvg} kbd="#⇧C">
|
||||
<CMRowButton
|
||||
onClick={handleCopySvg}
|
||||
kbd="#⇧C"
|
||||
id="TD-ContextMenu-Export-Copy_as_SVG"
|
||||
>
|
||||
Copy as SVG
|
||||
</CMRowButton>
|
||||
{isDebugMode && <CMRowButton onClick={handleCopyJson}>Copy as JSON</CMRowButton>}
|
||||
{isDebugMode && (
|
||||
<CMRowButton onClick={handleCopyJson} id="TD-ContextMenu-Export-Copy_as_JSON">
|
||||
Copy as JSON
|
||||
</CMRowButton>
|
||||
)}
|
||||
</ContextMenuSubMenu>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Divider />
|
||||
<CMRowButton onClick={handleCopySvg} kbd="#⇧C">
|
||||
<CMRowButton
|
||||
onClick={handleCopySvg}
|
||||
kbd="#⇧C"
|
||||
id="TD-ContextMenu-Export-Copy_as_SVG"
|
||||
>
|
||||
Copy as SVG
|
||||
</CMRowButton>
|
||||
{isDebugMode && <CMRowButton onClick={handleCopyJson}>Copy as JSON</CMRowButton>}
|
||||
{isDebugMode && (
|
||||
<CMRowButton onClick={handleCopyJson} id="TD-ContextMenu-Export-Copy_as_JSON">
|
||||
Copy as JSON
|
||||
</CMRowButton>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Divider />
|
||||
<CMRowButton onClick={handleCut} kbd="#X">
|
||||
<CMRowButton onClick={handleCut} kbd="#X" id="TD-ContextMenu-Cut">
|
||||
Cut
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleCopy} kbd="#C">
|
||||
<CMRowButton onClick={handleCopy} kbd="#C" id="TD-ContextMenu-Copy">
|
||||
Copy
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handlePaste} kbd="#V">
|
||||
<CMRowButton onClick={handlePaste} kbd="#V" id="TD-ContextMenu-Paste">
|
||||
Paste
|
||||
</CMRowButton>
|
||||
|
||||
<Divider />
|
||||
<CMRowButton onClick={handleDelete} kbd="⌫">
|
||||
<CMRowButton onClick={handleDelete} kbd="⌫" id="TD-ContextMenu-Delete">
|
||||
Delete
|
||||
</CMRowButton>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<CMRowButton onClick={handlePaste} kbd="#V">
|
||||
<CMRowButton onClick={handlePaste} kbd="#V" id="TD-ContextMenu-Paste">
|
||||
Paste
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleUndo} kbd="#Z">
|
||||
<CMRowButton onClick={handleUndo} kbd="#Z" id="TD-ContextMenu-Undo">
|
||||
Undo
|
||||
</CMRowButton>
|
||||
<CMRowButton onClick={handleRedo} kbd="#⇧Z">
|
||||
<CMRowButton onClick={handleRedo} kbd="#⇧Z" id="TD-ContextMenu-Redo">
|
||||
Redo
|
||||
</CMRowButton>
|
||||
</>
|
||||
|
@ -318,48 +348,68 @@ function AlignDistributeSubMenu({
|
|||
}, [app])
|
||||
|
||||
return (
|
||||
<RadixContextMenu.Root dir="ltr">
|
||||
<CMTriggerButton isSubmenu>Align / Distribute</CMTriggerButton>
|
||||
<RadixContextMenu.Content asChild sideOffset={2} alignOffset={-2}>
|
||||
<StyledGridContent numberOfSelected={hasThreeOrMore ? 'threeOrMore' : 'twoOrMore'}>
|
||||
<CMIconButton onClick={alignLeft}>
|
||||
<AlignLeftIcon />
|
||||
</CMIconButton>
|
||||
<CMIconButton onClick={alignCenterHorizontal}>
|
||||
<AlignCenterHorizontallyIcon />
|
||||
</CMIconButton>
|
||||
<CMIconButton onClick={alignRight}>
|
||||
<AlignRightIcon />
|
||||
</CMIconButton>
|
||||
<CMIconButton onClick={stretchHorizontally}>
|
||||
<StretchHorizontallyIcon />
|
||||
</CMIconButton>
|
||||
{hasThreeOrMore && (
|
||||
<CMIconButton onClick={distributeHorizontally}>
|
||||
<SpaceEvenlyHorizontallyIcon />
|
||||
<span id="TD-ContextMenu-Align_Duplicate">
|
||||
<RadixContextMenu.Root dir="ltr">
|
||||
<CMTriggerButton isSubmenu>Align / Distribute</CMTriggerButton>
|
||||
<RadixContextMenu.Content asChild sideOffset={2} alignOffset={-2}>
|
||||
<StyledGridContent numberOfSelected={hasThreeOrMore ? 'threeOrMore' : 'twoOrMore'}>
|
||||
<CMIconButton onClick={alignLeft} id="TD-ContextMenu-Align_Duplicate-AlignLeft">
|
||||
<AlignLeftIcon />
|
||||
</CMIconButton>
|
||||
)}
|
||||
<CMIconButton onClick={alignTop}>
|
||||
<AlignTopIcon />
|
||||
</CMIconButton>
|
||||
<CMIconButton onClick={alignCenterVertical}>
|
||||
<AlignCenterVerticallyIcon />
|
||||
</CMIconButton>
|
||||
<CMIconButton onClick={alignBottom}>
|
||||
<AlignBottomIcon />
|
||||
</CMIconButton>
|
||||
<CMIconButton onClick={stretchVertically}>
|
||||
<StretchVerticallyIcon />
|
||||
</CMIconButton>
|
||||
{hasThreeOrMore && (
|
||||
<CMIconButton onClick={distributeVertically}>
|
||||
<SpaceEvenlyVerticallyIcon />
|
||||
<CMIconButton
|
||||
onClick={alignCenterHorizontal}
|
||||
id="TD-ContextMenu-Align_Duplicate-AlignCenterHorizontal"
|
||||
>
|
||||
<AlignCenterHorizontallyIcon />
|
||||
</CMIconButton>
|
||||
)}
|
||||
<CMArrow offset={13} />
|
||||
</StyledGridContent>
|
||||
</RadixContextMenu.Content>
|
||||
</RadixContextMenu.Root>
|
||||
<CMIconButton onClick={alignRight} id="TD-ContextMenu-Align_Duplicate-AlignRight">
|
||||
<AlignRightIcon />
|
||||
</CMIconButton>
|
||||
<CMIconButton
|
||||
onClick={stretchHorizontally}
|
||||
id="TD-ContextMenu-Align_Duplicate-StretchHorizontal"
|
||||
>
|
||||
<StretchHorizontallyIcon />
|
||||
</CMIconButton>
|
||||
{hasThreeOrMore && (
|
||||
<CMIconButton
|
||||
onClick={distributeHorizontally}
|
||||
id="TD-ContextMenu-Align_Duplicate-SpaceEvenlyHorizontal"
|
||||
>
|
||||
<SpaceEvenlyHorizontallyIcon />
|
||||
</CMIconButton>
|
||||
)}
|
||||
<CMIconButton onClick={alignTop} id="TD-ContextMenu-Align_Duplicate-AlignTop">
|
||||
<AlignTopIcon />
|
||||
</CMIconButton>
|
||||
<CMIconButton
|
||||
onClick={alignCenterVertical}
|
||||
id="TD-ContextMenu-Align_Duplicate-AlignCenterVertical"
|
||||
>
|
||||
<AlignCenterVerticallyIcon />
|
||||
</CMIconButton>
|
||||
<CMIconButton onClick={alignBottom} id="TD-ContextMenu-Align_Duplicate-AlignBottom">
|
||||
<AlignBottomIcon />
|
||||
</CMIconButton>
|
||||
<CMIconButton
|
||||
onClick={stretchVertically}
|
||||
id="TD-ContextMenu-Align_Duplicate-StretchVertical"
|
||||
>
|
||||
<StretchVerticallyIcon />
|
||||
</CMIconButton>
|
||||
{hasThreeOrMore && (
|
||||
<CMIconButton
|
||||
onClick={distributeVertically}
|
||||
id="TD-ContextMenu-Align_Duplicate-SpaceEvenlyVertical"
|
||||
>
|
||||
<SpaceEvenlyVerticallyIcon />
|
||||
</CMIconButton>
|
||||
)}
|
||||
<CMArrow offset={13} />
|
||||
</StyledGridContent>
|
||||
</RadixContextMenu.Content>
|
||||
</RadixContextMenu.Root>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -420,23 +470,27 @@ export interface ContextMenuSubMenuProps {
|
|||
label: string
|
||||
size?: 'small'
|
||||
children: React.ReactNode
|
||||
id?: string
|
||||
}
|
||||
|
||||
export function ContextMenuSubMenu({
|
||||
children,
|
||||
label,
|
||||
size,
|
||||
id,
|
||||
}: ContextMenuSubMenuProps): JSX.Element {
|
||||
return (
|
||||
<RadixContextMenu.Root dir="ltr">
|
||||
<CMTriggerButton isSubmenu>{label}</CMTriggerButton>
|
||||
<RadixContextMenu.Content dir="ltr" sideOffset={2} alignOffset={-2} asChild>
|
||||
<MenuContent size={size}>
|
||||
{children}
|
||||
<CMArrow offset={13} />
|
||||
</MenuContent>
|
||||
</RadixContextMenu.Content>
|
||||
</RadixContextMenu.Root>
|
||||
<span id={id}>
|
||||
<RadixContextMenu.Root dir="ltr">
|
||||
<CMTriggerButton isSubmenu>{label}</CMTriggerButton>
|
||||
<RadixContextMenu.Content dir="ltr" sideOffset={2} alignOffset={-2} asChild>
|
||||
<MenuContent size={size}>
|
||||
{children}
|
||||
<CMArrow offset={13} />
|
||||
</MenuContent>
|
||||
</RadixContextMenu.Content>
|
||||
</RadixContextMenu.Root>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -458,9 +512,9 @@ function CMIconButton({ onSelect, ...rest }: ToolButtonProps): JSX.Element {
|
|||
|
||||
/* -------------------- RowButton ------------------- */
|
||||
|
||||
const CMRowButton = ({ ...rest }: RowButtonProps) => {
|
||||
const CMRowButton = ({ id, ...rest }: RowButtonProps) => {
|
||||
return (
|
||||
<RadixContextMenu.ContextMenuItem asChild>
|
||||
<RadixContextMenu.ContextMenuItem asChild id={id}>
|
||||
<RowButton {...rest} />
|
||||
</RadixContextMenu.ContextMenuItem>
|
||||
)
|
||||
|
|
|
@ -10,6 +10,7 @@ interface DMCheckboxItemProps {
|
|||
children: React.ReactNode
|
||||
variant?: RowButtonProps['variant']
|
||||
kbd?: string
|
||||
id?: string
|
||||
}
|
||||
|
||||
export function DMCheckboxItem({
|
||||
|
@ -18,6 +19,7 @@ export function DMCheckboxItem({
|
|||
variant,
|
||||
onCheckedChange,
|
||||
kbd,
|
||||
id,
|
||||
children,
|
||||
}: DMCheckboxItemProps): JSX.Element {
|
||||
return (
|
||||
|
@ -28,6 +30,7 @@ export function DMCheckboxItem({
|
|||
checked={checked}
|
||||
disabled={disabled}
|
||||
asChild
|
||||
id={id}
|
||||
>
|
||||
<RowButton kbd={kbd} variant={variant} hasIndicator>
|
||||
{children}
|
||||
|
|
|
@ -9,6 +9,7 @@ export interface DMContentProps {
|
|||
align?: 'start' | 'center' | 'end'
|
||||
sideOffset?: number
|
||||
children: React.ReactNode
|
||||
id?: string
|
||||
}
|
||||
|
||||
export function DMContent({
|
||||
|
@ -16,6 +17,7 @@ export function DMContent({
|
|||
children,
|
||||
align,
|
||||
variant,
|
||||
id,
|
||||
}: DMContentProps): JSX.Element {
|
||||
return (
|
||||
<Content
|
||||
|
@ -24,6 +26,7 @@ export function DMContent({
|
|||
sideOffset={sideOffset}
|
||||
onEscapeKeyDown={stopPropagation}
|
||||
asChild
|
||||
id={id}
|
||||
>
|
||||
<StyledContent variant={variant}>{children}</StyledContent>
|
||||
</Content>
|
||||
|
|
|
@ -4,10 +4,11 @@ import { RowButton, RowButtonProps } from '~components/Primitives/RowButton'
|
|||
|
||||
export function DMItem({
|
||||
onSelect,
|
||||
id,
|
||||
...rest
|
||||
}: RowButtonProps & { onSelect?: (event: Event) => void }): JSX.Element {
|
||||
}: RowButtonProps & { onSelect?: (event: Event) => void; id?: string }): JSX.Element {
|
||||
return (
|
||||
<Item dir="ltr" asChild onSelect={onSelect}>
|
||||
<Item dir="ltr" asChild onSelect={onSelect} id={id}>
|
||||
<RowButton {...rest} />
|
||||
</Item>
|
||||
)
|
||||
|
|
|
@ -8,6 +8,7 @@ export interface DMSubMenuProps {
|
|||
size?: 'small'
|
||||
disabled?: boolean
|
||||
children: React.ReactNode
|
||||
id?: string
|
||||
}
|
||||
|
||||
export function DMSubMenu({
|
||||
|
@ -15,20 +16,23 @@ export function DMSubMenu({
|
|||
size,
|
||||
disabled = false,
|
||||
label,
|
||||
id,
|
||||
}: DMSubMenuProps): JSX.Element {
|
||||
return (
|
||||
<Root dir="ltr">
|
||||
<TriggerItem dir="ltr" asChild>
|
||||
<RowButton disabled={disabled} hasArrow>
|
||||
{label}
|
||||
</RowButton>
|
||||
</TriggerItem>
|
||||
<Content dir="ltr" asChild sideOffset={2} alignOffset={-2}>
|
||||
<MenuContent size={size}>
|
||||
{children}
|
||||
<Arrow offset={13} />
|
||||
</MenuContent>
|
||||
</Content>
|
||||
</Root>
|
||||
<span id={id}>
|
||||
<Root dir="ltr">
|
||||
<TriggerItem dir="ltr" asChild>
|
||||
<RowButton disabled={disabled} hasArrow>
|
||||
{label}
|
||||
</RowButton>
|
||||
</TriggerItem>
|
||||
<Content dir="ltr" asChild sideOffset={2} alignOffset={-2}>
|
||||
<MenuContent size={size}>
|
||||
{children}
|
||||
<Arrow offset={13} />
|
||||
</MenuContent>
|
||||
</Content>
|
||||
</Root>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,11 +4,12 @@ import { ToolButton, ToolButtonProps } from '~components/Primitives/ToolButton'
|
|||
|
||||
interface DMTriggerIconProps extends ToolButtonProps {
|
||||
children: React.ReactNode
|
||||
id?: string
|
||||
}
|
||||
|
||||
export function DMTriggerIcon({ children, ...rest }: DMTriggerIconProps) {
|
||||
export function DMTriggerIcon({ id, children, ...rest }: DMTriggerIconProps) {
|
||||
return (
|
||||
<Trigger asChild>
|
||||
<Trigger asChild id={id}>
|
||||
<ToolButton {...rest}>{children}</ToolButton>
|
||||
</Trigger>
|
||||
)
|
||||
|
|
|
@ -17,6 +17,7 @@ export interface RowButtonProps {
|
|||
isWarning?: boolean
|
||||
hasIndicator?: boolean
|
||||
hasArrow?: boolean
|
||||
id?: string
|
||||
}
|
||||
|
||||
export const RowButton = React.forwardRef<HTMLButtonElement, RowButtonProps>(
|
||||
|
|
|
@ -14,6 +14,7 @@ export interface ToolButtonProps {
|
|||
isToolLocked?: boolean
|
||||
variant?: 'icon' | 'text' | 'circle' | 'primary'
|
||||
children: React.ReactNode
|
||||
id?: string
|
||||
onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>
|
||||
}
|
||||
|
||||
|
@ -30,6 +31,7 @@ export const ToolButton = React.forwardRef<HTMLButtonElement, ToolButtonProps>(
|
|||
isActive = false,
|
||||
isSponsor = false,
|
||||
onKeyDown,
|
||||
id,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
|
@ -46,6 +48,7 @@ export const ToolButton = React.forwardRef<HTMLButtonElement, ToolButtonProps>(
|
|||
onDoubleClick={onDoubleClick}
|
||||
onKeyDown={onKeyDown}
|
||||
bp={breakpoints}
|
||||
id={id}
|
||||
{...rest}
|
||||
>
|
||||
<StyledToolButtonInner>{children}</StyledToolButtonInner>
|
||||
|
|
|
@ -11,6 +11,7 @@ interface TooltipProps {
|
|||
children: React.ReactNode
|
||||
label: string
|
||||
kbd?: string
|
||||
id?: string
|
||||
side?: 'bottom' | 'left' | 'right' | 'top'
|
||||
}
|
||||
|
||||
|
@ -18,19 +19,22 @@ export function Tooltip({
|
|||
children,
|
||||
label,
|
||||
kbd: kbdProp,
|
||||
id,
|
||||
side = 'top',
|
||||
}: TooltipProps): JSX.Element {
|
||||
return (
|
||||
<RadixTooltip.Root>
|
||||
<RadixTooltip.Trigger dir="ltr" asChild={true}>
|
||||
<span>{children}</span>
|
||||
</RadixTooltip.Trigger>
|
||||
<StyledContent dir="ltr" side={side} sideOffset={8}>
|
||||
{label}
|
||||
{kbdProp ? <Kbd variant="tooltip">{kbdProp}</Kbd> : null}
|
||||
<StyledArrow />
|
||||
</StyledContent>
|
||||
</RadixTooltip.Root>
|
||||
<span id={id}>
|
||||
<RadixTooltip.Root>
|
||||
<RadixTooltip.Trigger dir="ltr" asChild={true}>
|
||||
<span>{children}</span>
|
||||
</RadixTooltip.Trigger>
|
||||
<StyledContent dir="ltr" side={side} sideOffset={8}>
|
||||
{label}
|
||||
{kbdProp ? <Kbd variant="tooltip">{kbdProp}</Kbd> : null}
|
||||
<StyledArrow />
|
||||
</StyledContent>
|
||||
</RadixTooltip.Root>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ export function ActionButton(): JSX.Element {
|
|||
|
||||
return (
|
||||
<DropdownMenu.Root dir="ltr" onOpenChange={handleMenuOpenChange}>
|
||||
<DropdownMenu.Trigger dir="ltr" asChild>
|
||||
<DropdownMenu.Trigger dir="ltr" asChild id="TD-Tools-Dots">
|
||||
<ToolButton variant="circle">
|
||||
<DotsHorizontalIcon />
|
||||
</ToolButton>
|
||||
|
@ -189,22 +189,22 @@ export function ActionButton(): JSX.Element {
|
|||
<>
|
||||
<ButtonsRow>
|
||||
<ToolButton variant="icon" disabled={!hasSelection} onClick={handleDuplicate}>
|
||||
<Tooltip label="Duplicate" kbd={`#D`}>
|
||||
<Tooltip label="Duplicate" kbd={`#D`} id="TD-Tools-Copy">
|
||||
<CopyIcon />
|
||||
</Tooltip>
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleRotate}>
|
||||
<Tooltip label="Rotate">
|
||||
<Tooltip label="Rotate" id="TD-Tools-Rotate">
|
||||
<RotateCounterClockwiseIcon />
|
||||
</Tooltip>
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleToggleLocked}>
|
||||
<Tooltip label="Toggle Locked" kbd={`#L`}>
|
||||
<Tooltip label="Toggle Locked" kbd={`#L`} id="TD-Tools-Lock">
|
||||
{isAllLocked ? <LockClosedIcon /> : <LockOpen1Icon />}
|
||||
</Tooltip>
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleToggleAspectRatio}>
|
||||
<Tooltip label="Toggle Aspect Ratio Lock">
|
||||
<Tooltip label="Toggle Aspect Ratio Lock" id="TD-Tools-AspectRatio">
|
||||
{isAllAspectLocked ? <AspectRatioIcon /> : <BoxIcon />}
|
||||
</Tooltip>
|
||||
</ToolButton>
|
||||
|
@ -212,70 +212,94 @@ export function ActionButton(): JSX.Element {
|
|||
disabled={!hasSelection || (!isAllGrouped && !hasMultipleSelection)}
|
||||
onClick={handleGroup}
|
||||
>
|
||||
<Tooltip label="Group" kbd={`#G`}>
|
||||
<Tooltip label="Group" kbd={`#G`} id="TD-Tools-Group">
|
||||
<GroupIcon />
|
||||
</Tooltip>
|
||||
</ToolButton>
|
||||
</ButtonsRow>
|
||||
<ButtonsRow>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleMoveToBack}>
|
||||
<Tooltip label="Move to Back" kbd={`#⇧[`}>
|
||||
<Tooltip label="Move to Back" kbd={`#⇧[`} id="TD-Tools-PinBottom">
|
||||
<PinBottomIcon />
|
||||
</Tooltip>
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleMoveBackward}>
|
||||
<Tooltip label="Move Backward" kbd={`#[`}>
|
||||
<Tooltip label="Move Backward" kbd={`#[`} id="TD-Tools-ArrowDown">
|
||||
<ArrowDownIcon />
|
||||
</Tooltip>
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleMoveForward}>
|
||||
<Tooltip label="Move Forward" kbd={`#]`}>
|
||||
<Tooltip label="Move Forward" kbd={`#]`} id="TD-Tools-ArrowUp">
|
||||
<ArrowUpIcon />
|
||||
</Tooltip>
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleMoveToFront}>
|
||||
<Tooltip label="Move to Front" kbd={`#⇧]`}>
|
||||
<Tooltip label="Move to Front" kbd={`#⇧]`} id="TD-Tools-PinTop">
|
||||
<PinTopIcon />
|
||||
</Tooltip>
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasSelection} onClick={handleResetAngle}>
|
||||
<Tooltip label="Reset Angle">
|
||||
<Tooltip label="Reset Angle" id="TD-Tools-ResetAngle">
|
||||
<AngleIcon />
|
||||
</Tooltip>
|
||||
</ToolButton>
|
||||
</ButtonsRow>
|
||||
<Divider />
|
||||
<ButtonsRow>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignLeft}>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignLeft} id="TD-Tools-AlignLeft">
|
||||
<AlignLeftIcon />
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignCenterHorizontal}>
|
||||
<ToolButton
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={alignCenterHorizontal}
|
||||
id="TD-Tools-AlignCenterHorizontal"
|
||||
>
|
||||
<AlignCenterHorizontallyIcon />
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignRight}>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignRight} id="TD-Tools-AlignRight">
|
||||
<AlignRightIcon />
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={stretchHorizontally}>
|
||||
<ToolButton
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={stretchHorizontally}
|
||||
id="TD-Tools-StretchHorizontal"
|
||||
>
|
||||
<StretchHorizontallyIcon />
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasThreeOrMore} onClick={distributeHorizontally}>
|
||||
<ToolButton
|
||||
disabled={!hasThreeOrMore}
|
||||
onClick={distributeHorizontally}
|
||||
id="TD-Tools-SpaceEvenlyHorizontal"
|
||||
>
|
||||
<SpaceEvenlyHorizontallyIcon />
|
||||
</ToolButton>
|
||||
</ButtonsRow>
|
||||
<ButtonsRow>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignTop}>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignTop} id="TD-Tools-AlignTop">
|
||||
<AlignTopIcon />
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignCenterVertical}>
|
||||
<ToolButton
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={alignCenterVertical}
|
||||
id="TD-Tools-AlignCenterVertical"
|
||||
>
|
||||
<AlignCenterVerticallyIcon />
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignBottom}>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={alignBottom} id="TD-Tools-AlignBottom">
|
||||
<AlignBottomIcon />
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasTwoOrMore} onClick={stretchVertically}>
|
||||
<ToolButton
|
||||
disabled={!hasTwoOrMore}
|
||||
onClick={stretchVertically}
|
||||
id="TD-Tools-tretchVertical"
|
||||
>
|
||||
<StretchVerticallyIcon />
|
||||
</ToolButton>
|
||||
<ToolButton disabled={!hasThreeOrMore} onClick={distributeVertically}>
|
||||
<ToolButton
|
||||
disabled={!hasThreeOrMore}
|
||||
onClick={distributeVertically}
|
||||
id="TD-Tools-SpaceEvenlyVertical"
|
||||
>
|
||||
<SpaceEvenlyVerticallyIcon />
|
||||
</ToolButton>
|
||||
</ButtonsRow>
|
||||
|
|
|
@ -17,7 +17,7 @@ export const BackToContent = React.memo(function BackToContent() {
|
|||
if (!isEmptyCanvas) return null
|
||||
|
||||
return (
|
||||
<BackToContentContainer>
|
||||
<BackToContentContainer id="TD-Tools-Back_to_content">
|
||||
<RowButton onClick={app.zoomToContent}>Back to content</RowButton>
|
||||
</BackToContentContainer>
|
||||
)
|
||||
|
|
|
@ -18,7 +18,7 @@ export function DeleteButton(): JSX.Element {
|
|||
)
|
||||
|
||||
return (
|
||||
<Tooltip label="Delete" kbd="⌫">
|
||||
<Tooltip label="Delete" kbd="⌫" id="TD-Delete">
|
||||
<ToolButton variant="circle" disabled={!hasSelection} onSelect={handleDelete}>
|
||||
<TrashIcon />
|
||||
</ToolButton>
|
||||
|
|
|
@ -13,7 +13,7 @@ export function LockButton(): JSX.Element {
|
|||
const isToolLocked = app.useStore(isToolLockedSelector)
|
||||
|
||||
return (
|
||||
<Tooltip label="Lock Tool" kbd="7">
|
||||
<Tooltip label="Lock Tool" kbd="7" id="TD-Lock">
|
||||
<ToolButton variant="circle" isActive={isToolLocked} onSelect={app.toggleToolLock}>
|
||||
{isToolLocked ? <LockClosedIcon /> : <LockOpen1Icon />}
|
||||
</ToolButton>
|
||||
|
|
|
@ -44,6 +44,7 @@ export const PenMenu = React.memo(function PenMenu({ activeTool }: ShapesMenuPro
|
|||
onDoubleClick={handleDoubleClick}
|
||||
onClick={selectShapeTool}
|
||||
isActive={penShapes.includes(activeTool as PenShape)}
|
||||
id="TD-Pen"
|
||||
>
|
||||
{penShapeIcons[lastActiveTool]}
|
||||
</ToolButton>
|
||||
|
@ -55,6 +56,7 @@ export const PenMenu = React.memo(function PenMenu({ activeTool }: ShapesMenuPro
|
|||
key={shape}
|
||||
label={shape[0].toUpperCase() + shape.slice(1)}
|
||||
kbd={(1 + i).toString()}
|
||||
id={`TD-Pen-${shape}`}
|
||||
>
|
||||
<DropdownMenu.Item asChild>
|
||||
<ToolButton
|
||||
|
|
|
@ -48,12 +48,13 @@ export const PrimaryTools = React.memo(function PrimaryTools(): JSX.Element {
|
|||
}, [app])
|
||||
|
||||
return (
|
||||
<Panel side="center">
|
||||
<Panel side="center" id="TD-PrimaryTools">
|
||||
<ToolButtonWithTooltip
|
||||
kbd={'1'}
|
||||
label={'select'}
|
||||
onClick={selectSelectTool}
|
||||
isActive={activeTool === 'select'}
|
||||
id="TD-PrimaryTools-CursorArrow"
|
||||
>
|
||||
<CursorArrowIcon />
|
||||
</ToolButtonWithTooltip>
|
||||
|
@ -62,6 +63,7 @@ export const PrimaryTools = React.memo(function PrimaryTools(): JSX.Element {
|
|||
label={TDShapeType.Draw}
|
||||
onClick={selectDrawTool}
|
||||
isActive={activeTool === TDShapeType.Draw}
|
||||
id="TD-PrimaryTools-Pencil"
|
||||
>
|
||||
<Pencil1Icon />
|
||||
</ToolButtonWithTooltip>
|
||||
|
@ -70,6 +72,7 @@ export const PrimaryTools = React.memo(function PrimaryTools(): JSX.Element {
|
|||
label={'eraser'}
|
||||
onClick={selectEraseTool}
|
||||
isActive={activeTool === 'erase'}
|
||||
id="TD-PrimaryTools-Eraser"
|
||||
>
|
||||
<EraserIcon />
|
||||
</ToolButtonWithTooltip>
|
||||
|
@ -80,6 +83,7 @@ export const PrimaryTools = React.memo(function PrimaryTools(): JSX.Element {
|
|||
onClick={selectArrowTool}
|
||||
isLocked={isToolLocked}
|
||||
isActive={activeTool === TDShapeType.Arrow}
|
||||
id="TD-PrimaryTools-ArrowTopRight"
|
||||
>
|
||||
<ArrowTopRightIcon />
|
||||
</ToolButtonWithTooltip>
|
||||
|
@ -89,6 +93,7 @@ export const PrimaryTools = React.memo(function PrimaryTools(): JSX.Element {
|
|||
onClick={selectTextTool}
|
||||
isLocked={isToolLocked}
|
||||
isActive={activeTool === TDShapeType.Text}
|
||||
id="TD-PrimaryTools-Text"
|
||||
>
|
||||
<TextIcon />
|
||||
</ToolButtonWithTooltip>
|
||||
|
@ -97,6 +102,7 @@ export const PrimaryTools = React.memo(function PrimaryTools(): JSX.Element {
|
|||
label={TDShapeType.Sticky}
|
||||
onClick={selectStickyTool}
|
||||
isActive={activeTool === TDShapeType.Sticky}
|
||||
id="TD-PrimaryTools-Pencil2"
|
||||
>
|
||||
<Pencil2Icon />
|
||||
</ToolButtonWithTooltip>
|
||||
|
|
|
@ -75,7 +75,7 @@ export const ShapesMenu = React.memo(function ShapesMenu({
|
|||
|
||||
return (
|
||||
<DropdownMenu.Root dir="ltr" onOpenChange={selectShapeTool}>
|
||||
<DropdownMenu.Trigger dir="ltr" asChild>
|
||||
<DropdownMenu.Trigger dir="ltr" asChild id="TD-PrimaryTools-Shapes">
|
||||
<ToolButton
|
||||
disabled={isActive && app.shiftKey} // otherwise this continuously opens and closes on "SpacePanning"
|
||||
variant="primary"
|
||||
|
@ -94,6 +94,7 @@ export const ShapesMenu = React.memo(function ShapesMenu({
|
|||
key={shape}
|
||||
label={shape[0].toUpperCase() + shape.slice(1)}
|
||||
kbd={(4 + i).toString()}
|
||||
id={`TD-PrimaryTools-Shapes-${shape}`}
|
||||
>
|
||||
<DropdownMenu.Item asChild>
|
||||
<ToolButton
|
||||
|
|
|
@ -13,7 +13,7 @@ export function StatusBar(): JSX.Element | null {
|
|||
const activeTool = app.useStore(activeToolSelector)
|
||||
|
||||
return (
|
||||
<StyledStatusBar bp={breakpoints}>
|
||||
<StyledStatusBar bp={breakpoints} id="TD-StatusBar">
|
||||
<StyledSection>
|
||||
{activeTool} | {status}
|
||||
</StyledSection>
|
||||
|
|
|
@ -20,7 +20,7 @@ export const ToolsPanel = React.memo(function ToolsPanel({ onBlur }: ToolsPanelP
|
|||
|
||||
return (
|
||||
<StyledToolsPanelContainer onBlur={onBlur}>
|
||||
<StyledCenterWrap>
|
||||
<StyledCenterWrap id="TD-Tools">
|
||||
<BackToContent />
|
||||
<StyledPrimaryTools>
|
||||
<ActionButton />
|
||||
|
|
|
@ -121,48 +121,58 @@ export const Menu = React.memo(function Menu({ showSponsorLink, readOnly }: Menu
|
|||
|
||||
return (
|
||||
<DropdownMenu.Root dir="ltr">
|
||||
<DMTriggerIcon isSponsor={showSponsorLink}>
|
||||
<DMTriggerIcon isSponsor={showSponsorLink} id="TD-MenuIcon">
|
||||
<HamburgerMenuIcon />
|
||||
</DMTriggerIcon>
|
||||
<DMContent variant="menu">
|
||||
<DMContent variant="menu" id="TD-Menu">
|
||||
{showFileMenu && (
|
||||
<DMSubMenu label="File...">
|
||||
<DMSubMenu label="File..." id="TD-MenuItem-File">
|
||||
{app.callbacks.onNewProject && (
|
||||
<DMItem onClick={onNewProject} kbd="#N">
|
||||
<DMItem onClick={onNewProject} kbd="#N" id="TD-MenuItem-File-New_Project">
|
||||
New Project
|
||||
</DMItem>
|
||||
)}
|
||||
{app.callbacks.onOpenProject && (
|
||||
<DMItem onClick={onOpenProject} kbd="#O">
|
||||
<DMItem onClick={onOpenProject} kbd="#O" id="TD-MenuItem-File-Open">
|
||||
Open...
|
||||
</DMItem>
|
||||
)}
|
||||
{app.callbacks.onSaveProject && (
|
||||
<DMItem onClick={onSaveProject} kbd="#S">
|
||||
<DMItem onClick={onSaveProject} kbd="#S" id="TD-MenuItem-File-Save">
|
||||
Save
|
||||
</DMItem>
|
||||
)}
|
||||
{app.callbacks.onSaveProjectAs && (
|
||||
<DMItem onClick={onSaveProjectAs} kbd="#⇧S">
|
||||
<DMItem onClick={onSaveProjectAs} kbd="#⇧S" id="TD-MenuItem-File-Save_As">
|
||||
Save As...
|
||||
</DMItem>
|
||||
)}
|
||||
{app.callbacks.onExport && (
|
||||
<>
|
||||
<Divider />
|
||||
<DMSubMenu label="Export" size="small">
|
||||
<DMItem onClick={handleExportPNG}>PNG</DMItem>
|
||||
<DMItem onClick={handleExportJPG}>JPG</DMItem>
|
||||
<DMItem onClick={handleExportWEBP}>WEBP</DMItem>
|
||||
<DMItem onClick={handleExportSVG}>SVG</DMItem>
|
||||
<DMItem onClick={handleExportJSON}>JSON</DMItem>
|
||||
<DMSubMenu label="Export" size="small" id="TD-MenuItem-File-Export">
|
||||
<DMItem onClick={handleExportPNG} id="TD-MenuItem-File-Export-PNG">
|
||||
PNG
|
||||
</DMItem>
|
||||
<DMItem onClick={handleExportJPG} id="TD-MenuItem-File-Export-JPG">
|
||||
JPG
|
||||
</DMItem>
|
||||
<DMItem onClick={handleExportWEBP} id="TD-MenuItem-File-Export-WEBP">
|
||||
WEBP
|
||||
</DMItem>
|
||||
<DMItem onClick={handleExportSVG} id="TD-MenuItem-File-Export-SVG">
|
||||
SVG
|
||||
</DMItem>
|
||||
<DMItem onClick={handleExportJSON} id="TD-MenuItem-File-Export-JSON">
|
||||
JSON
|
||||
</DMItem>
|
||||
</DMSubMenu>
|
||||
</>
|
||||
)}
|
||||
{!disableAssets && (
|
||||
<>
|
||||
<Divider />
|
||||
<DMItem onClick={handleUploadMedia} kbd="#U">
|
||||
<DMItem onClick={handleUploadMedia} kbd="#U" id="TD-MenuItem-File-Upload_Media">
|
||||
Upload Media
|
||||
</DMItem>
|
||||
</>
|
||||
|
@ -171,15 +181,31 @@ export const Menu = React.memo(function Menu({ showSponsorLink, readOnly }: Menu
|
|||
)}
|
||||
{!readOnly && (
|
||||
<>
|
||||
<DMSubMenu label="Edit...">
|
||||
<DMItem onSelect={preventEvent} onClick={app.undo} kbd="#Z">
|
||||
<DMSubMenu label="Edit..." id="TD-MenuItem-Edit">
|
||||
<DMItem
|
||||
onSelect={preventEvent}
|
||||
onClick={app.undo}
|
||||
kbd="#Z"
|
||||
id="TD-MenuItem-Edit-Undo"
|
||||
>
|
||||
Undo
|
||||
</DMItem>
|
||||
<DMItem onSelect={preventEvent} onClick={app.redo} kbd="#⇧Z">
|
||||
<DMItem
|
||||
onSelect={preventEvent}
|
||||
onClick={app.redo}
|
||||
kbd="#⇧Z"
|
||||
id="TD-MenuItem-Edit-Redo"
|
||||
>
|
||||
Redo
|
||||
</DMItem>
|
||||
<DMDivider dir="ltr" />
|
||||
<DMItem onSelect={preventEvent} disabled={!hasSelection} onClick={handleCut} kbd="#X">
|
||||
<DMItem
|
||||
onSelect={preventEvent}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleCut}
|
||||
kbd="#X"
|
||||
id="TD-MenuItem-Edit-Cut"
|
||||
>
|
||||
Cut
|
||||
</DMItem>
|
||||
<DMItem
|
||||
|
@ -187,10 +213,16 @@ export const Menu = React.memo(function Menu({ showSponsorLink, readOnly }: Menu
|
|||
disabled={!hasSelection}
|
||||
onClick={handleCopy}
|
||||
kbd="#C"
|
||||
id="TD-MenuItem-Edit-Copy"
|
||||
>
|
||||
Copy
|
||||
</DMItem>
|
||||
<DMItem onSelect={preventEvent} onClick={handlePaste} kbd="#V">
|
||||
<DMItem
|
||||
onSelect={preventEvent}
|
||||
onClick={handlePaste}
|
||||
kbd="#V"
|
||||
id="TD-MenuItem-Edit-Paste"
|
||||
>
|
||||
Paste
|
||||
</DMItem>
|
||||
<DMDivider dir="ltr" />
|
||||
|
@ -199,30 +231,45 @@ export const Menu = React.memo(function Menu({ showSponsorLink, readOnly }: Menu
|
|||
disabled={!hasSelection}
|
||||
onClick={handleCopySvg}
|
||||
kbd="#⇧C"
|
||||
id="TD-MenuItem-Edit-Copy_as_SVG"
|
||||
>
|
||||
Copy as SVG
|
||||
</DMItem>
|
||||
<DMItem onSelect={preventEvent} disabled={!hasSelection} onClick={handleCopyJson}>
|
||||
<DMItem
|
||||
onSelect={preventEvent}
|
||||
disabled={!hasSelection}
|
||||
onClick={handleCopyJson}
|
||||
id="TD-MenuItem-Edit-Copy_as_JSON"
|
||||
>
|
||||
Copy as JSON
|
||||
</DMItem>
|
||||
<DMDivider dir="ltr" />
|
||||
<DMItem onSelect={preventEvent} onClick={handleSelectAll} kbd="#A">
|
||||
<DMItem
|
||||
onSelect={preventEvent}
|
||||
onClick={handleSelectAll}
|
||||
kbd="#A"
|
||||
id="TD-MenuItem-Select_All"
|
||||
>
|
||||
Select All
|
||||
</DMItem>
|
||||
<DMItem onSelect={preventEvent} onClick={handleSelectNone}>
|
||||
<DMItem
|
||||
onSelect={preventEvent}
|
||||
onClick={handleSelectNone}
|
||||
id="TD-MenuItem-Select_None"
|
||||
>
|
||||
Select None
|
||||
</DMItem>
|
||||
</DMSubMenu>
|
||||
</>
|
||||
)}
|
||||
<a href="https://tldraw.com/r">
|
||||
<DMItem>Create a Multiplayer Room</DMItem>
|
||||
<DMItem id="TD-MenuItem-Create_a_Multiplayer_Room">Create a Multiplayer Room</DMItem>
|
||||
</a>
|
||||
<DMDivider dir="ltr" />
|
||||
<PreferencesMenu />
|
||||
<DMDivider dir="ltr" />
|
||||
<a href="https://github.com/Tldraw/Tldraw" target="_blank" rel="nofollow">
|
||||
<DMItem>
|
||||
<DMItem id="TD-MenuItem-Github">
|
||||
GitHub
|
||||
<SmallIcon>
|
||||
<GitHubLogoIcon />
|
||||
|
@ -230,7 +277,7 @@ export const Menu = React.memo(function Menu({ showSponsorLink, readOnly }: Menu
|
|||
</DMItem>
|
||||
</a>
|
||||
<a href="https://twitter.com/Tldraw" target="_blank" rel="nofollow">
|
||||
<DMItem>
|
||||
<DMItem id="TD-MenuItem-Twitter">
|
||||
Twitter
|
||||
<SmallIcon>
|
||||
<TwitterLogoIcon />
|
||||
|
@ -238,7 +285,7 @@ export const Menu = React.memo(function Menu({ showSponsorLink, readOnly }: Menu
|
|||
</DMItem>
|
||||
</a>
|
||||
<a href="https://discord.gg/SBBEVCA4PG" target="_blank" rel="nofollow">
|
||||
<DMItem>
|
||||
<DMItem id="TD-MenuItem-Discord">
|
||||
Discord
|
||||
<SmallIcon>
|
||||
<DiscordIcon />
|
||||
|
@ -247,7 +294,7 @@ export const Menu = React.memo(function Menu({ showSponsorLink, readOnly }: Menu
|
|||
</a>
|
||||
{showSponsorLink && (
|
||||
<a href="https://github.com/sponsors/steveruizok" target="_blank" rel="nofollow">
|
||||
<DMItem isSponsor>
|
||||
<DMItem isSponsor id="TD-MenuItem-Become_a_Sponsor">
|
||||
Become a Sponsor{' '}
|
||||
<SmallIcon>
|
||||
<HeartIcon />
|
||||
|
@ -258,9 +305,13 @@ export const Menu = React.memo(function Menu({ showSponsorLink, readOnly }: Menu
|
|||
{showSignInOutMenu && (
|
||||
<>
|
||||
<DMDivider dir="ltr" />{' '}
|
||||
{app.callbacks.onSignIn && <DMItem onSelect={handleSignIn}>Sign In</DMItem>}
|
||||
{app.callbacks.onSignIn && (
|
||||
<DMItem onSelect={handleSignIn} id="TD-MenuItem-Sign_in">
|
||||
Sign In
|
||||
</DMItem>
|
||||
)}
|
||||
{app.callbacks.onSignOut && (
|
||||
<DMItem onSelect={handleSignOut}>
|
||||
<DMItem onSelect={handleSignOut} id="TD-MenuItem-Sign_out">
|
||||
Sign Out
|
||||
<SmallIcon>
|
||||
<ExitIcon />
|
||||
|
|
|
@ -47,7 +47,7 @@ export function PageMenu(): JSX.Element {
|
|||
|
||||
return (
|
||||
<DropdownMenu.Root dir="ltr" open={isOpen} onOpenChange={handleOpenChange}>
|
||||
<DropdownMenu.Trigger dir="ltr" asChild>
|
||||
<DropdownMenu.Trigger dir="ltr" asChild id="TD-Page">
|
||||
<ToolButton variant="text">{currentPageName || 'Page'}</ToolButton>
|
||||
</DropdownMenu.Trigger>
|
||||
<DMContent variant="menu" align="start">
|
||||
|
|
|
@ -43,37 +43,65 @@ export function PreferencesMenu() {
|
|||
}, [app])
|
||||
|
||||
return (
|
||||
<DMSubMenu label="Preferences">
|
||||
<DMCheckboxItem checked={settings.isDarkMode} onCheckedChange={toggleDarkMode} kbd="#⇧D">
|
||||
<DMSubMenu label="Preferences" id="TD-MenuItem-Preferences">
|
||||
<DMCheckboxItem
|
||||
checked={settings.isDarkMode}
|
||||
onCheckedChange={toggleDarkMode}
|
||||
kbd="#⇧D"
|
||||
id="TD-MenuItem-Preferences-Dark_Mode"
|
||||
>
|
||||
Dark Mode
|
||||
</DMCheckboxItem>
|
||||
<DMCheckboxItem checked={settings.isFocusMode} onCheckedChange={toggleFocusMode} kbd="#.">
|
||||
<DMCheckboxItem
|
||||
checked={settings.isFocusMode}
|
||||
onCheckedChange={toggleFocusMode}
|
||||
kbd="#."
|
||||
id="TD-MenuItem-Preferences-Focus_Mode"
|
||||
>
|
||||
Focus Mode
|
||||
</DMCheckboxItem>
|
||||
<DMCheckboxItem checked={settings.isDebugMode} onCheckedChange={toggleDebugMode}>
|
||||
<DMCheckboxItem
|
||||
checked={settings.isDebugMode}
|
||||
onCheckedChange={toggleDebugMode}
|
||||
id="TD-MenuItem-Preferences-Debug_Mode"
|
||||
>
|
||||
Debug Mode
|
||||
</DMCheckboxItem>
|
||||
<DMDivider />
|
||||
<DMCheckboxItem checked={settings.showRotateHandles} onCheckedChange={toggleRotateHandle}>
|
||||
<DMCheckboxItem
|
||||
checked={settings.showRotateHandles}
|
||||
onCheckedChange={toggleRotateHandle}
|
||||
id="TD-MenuItem-Preferences-Rotate_Handles"
|
||||
>
|
||||
Rotate Handles
|
||||
</DMCheckboxItem>
|
||||
<DMCheckboxItem
|
||||
checked={settings.showBindingHandles}
|
||||
onCheckedChange={toggleBoundShapesHandle}
|
||||
id="TD-MenuItem-Preferences-Binding_Handles"
|
||||
>
|
||||
Binding Handles
|
||||
</DMCheckboxItem>
|
||||
<DMCheckboxItem checked={settings.showCloneHandles} onCheckedChange={toggleCloneControls}>
|
||||
<DMCheckboxItem
|
||||
checked={settings.showCloneHandles}
|
||||
onCheckedChange={toggleCloneControls}
|
||||
id="TD-MenuItem-Preferences-Clone_Handles"
|
||||
>
|
||||
Clone Handles
|
||||
</DMCheckboxItem>
|
||||
<DMCheckboxItem
|
||||
checked={settings.showGrid}
|
||||
onCheckedChange={toggleGrid}
|
||||
kbd="#⇧G"
|
||||
id="TD-MenuItem-Preferences-Grid"
|
||||
>
|
||||
Grid
|
||||
</DMCheckboxItem>
|
||||
<DMCheckboxItem checked={settings.isSnapping} onCheckedChange={toggleisSnapping}>
|
||||
<DMCheckboxItem
|
||||
checked={settings.isSnapping}
|
||||
onCheckedChange={toggleisSnapping}
|
||||
id="TD-MenuItem-Preferences-Always_Show_Snaps"
|
||||
>
|
||||
Always Show Snaps
|
||||
</DMCheckboxItem>
|
||||
</DMSubMenu>
|
||||
|
|
|
@ -167,7 +167,7 @@ export const StyleMenu = React.memo(function ColorMenu(): JSX.Element {
|
|||
)
|
||||
return (
|
||||
<DropdownMenu.Root dir="ltr" onOpenChange={handleMenuOpenChange}>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<DropdownMenu.Trigger asChild id="TD-Styles">
|
||||
<ToolButton variant="text">
|
||||
Styles
|
||||
<OverlapIcons
|
||||
|
@ -187,11 +187,16 @@ export const StyleMenu = React.memo(function ColorMenu(): JSX.Element {
|
|||
</ToolButton>
|
||||
</DropdownMenu.Trigger>
|
||||
<DMContent>
|
||||
<StyledRow variant="tall">
|
||||
<StyledRow variant="tall" id="TD-Styles-Color-Container">
|
||||
<span>Color</span>
|
||||
<ColorGrid>
|
||||
{Object.keys(strokes.light).map((style: string) => (
|
||||
<DropdownMenu.Item key={style} onSelect={preventEvent} asChild>
|
||||
<DropdownMenu.Item
|
||||
key={style}
|
||||
onSelect={preventEvent}
|
||||
asChild
|
||||
id={`TD-Styles-Color-Swatch-${style}`}
|
||||
>
|
||||
<ToolButton
|
||||
variant="icon"
|
||||
isActive={displayedStyle.color === style}
|
||||
|
@ -214,10 +219,11 @@ export const StyleMenu = React.memo(function ColorMenu(): JSX.Element {
|
|||
variant="styleMenu"
|
||||
checked={!!displayedStyle.isFilled}
|
||||
onCheckedChange={handleToggleFilled}
|
||||
id="TD-Styles-Fill"
|
||||
>
|
||||
Fill
|
||||
</DMCheckboxItem>
|
||||
<StyledRow>
|
||||
<StyledRow id="TD-Styles-Dash-Container">
|
||||
Dash
|
||||
<StyledGroup dir="ltr" value={displayedStyle.dash} onValueChange={handleDashChange}>
|
||||
{Object.values(DashStyle).map((style) => (
|
||||
|
@ -227,13 +233,14 @@ export const StyleMenu = React.memo(function ColorMenu(): JSX.Element {
|
|||
value={style}
|
||||
onSelect={preventEvent}
|
||||
bp={breakpoints}
|
||||
id={`TD-Styles-Dash-${style}`}
|
||||
>
|
||||
{DASH_ICONS[style as DashStyle]}
|
||||
</DMRadioItem>
|
||||
))}
|
||||
</StyledGroup>
|
||||
</StyledRow>
|
||||
<StyledRow>
|
||||
<StyledRow id="TD-Styles-Size-Container">
|
||||
Size
|
||||
<StyledGroup dir="ltr" value={displayedStyle.size} onValueChange={handleSizeChange}>
|
||||
{Object.values(SizeStyle).map((sizeStyle) => (
|
||||
|
@ -243,6 +250,7 @@ export const StyleMenu = React.memo(function ColorMenu(): JSX.Element {
|
|||
value={sizeStyle}
|
||||
onSelect={preventEvent}
|
||||
bp={breakpoints}
|
||||
id={`TD-Styles-Dash-${sizeStyle}`}
|
||||
>
|
||||
{SIZE_ICONS[sizeStyle as SizeStyle]}
|
||||
</DMRadioItem>
|
||||
|
@ -252,7 +260,7 @@ export const StyleMenu = React.memo(function ColorMenu(): JSX.Element {
|
|||
{(options === 'text' || options === 'label') && (
|
||||
<>
|
||||
<Divider />
|
||||
<StyledRow>
|
||||
<StyledRow id="TD-Styles-Font-Container">
|
||||
Font
|
||||
<StyledGroup dir="ltr" value={displayedStyle.font} onValueChange={handleFontChange}>
|
||||
{Object.values(FontStyle).map((fontStyle) => (
|
||||
|
@ -262,6 +270,7 @@ export const StyleMenu = React.memo(function ColorMenu(): JSX.Element {
|
|||
value={fontStyle}
|
||||
onSelect={preventEvent}
|
||||
bp={breakpoints}
|
||||
id={`TD-Styles-Font-${fontStyle}`}
|
||||
>
|
||||
<FontIcon fontStyle={fontStyle}>Aa</FontIcon>
|
||||
</DMRadioItem>
|
||||
|
@ -269,7 +278,7 @@ export const StyleMenu = React.memo(function ColorMenu(): JSX.Element {
|
|||
</StyledGroup>
|
||||
</StyledRow>
|
||||
{options === 'text' && (
|
||||
<StyledRow>
|
||||
<StyledRow id="TD-Styles-Align-Container">
|
||||
Align
|
||||
<StyledGroup
|
||||
dir="ltr"
|
||||
|
@ -283,6 +292,7 @@ export const StyleMenu = React.memo(function ColorMenu(): JSX.Element {
|
|||
value={style}
|
||||
onSelect={preventEvent}
|
||||
bp={breakpoints}
|
||||
id={`TD-Styles-Align-${style}`}
|
||||
>
|
||||
{ALIGN_ICONS[style]}
|
||||
</DMRadioItem>
|
||||
|
|
|
@ -32,7 +32,7 @@ export function TopPanel({
|
|||
return (
|
||||
<StyledTopPanel>
|
||||
{(showMenu || showPages) && (
|
||||
<Panel side="left">
|
||||
<Panel side="left" id="TD-MenuPanel">
|
||||
{showMenu && <Menu showSponsorLink={showSponsorLink} readOnly={readOnly} />}
|
||||
{showPages && <PageMenu />}
|
||||
</Panel>
|
||||
|
|
|
@ -16,25 +16,30 @@ export const ZoomMenu = React.memo(function ZoomMenu() {
|
|||
|
||||
return (
|
||||
<DropdownMenu.Root dir="ltr">
|
||||
<DropdownMenu.Trigger dir="ltr" asChild>
|
||||
<DropdownMenu.Trigger dir="ltr" asChild id="TD-Zoom">
|
||||
<FixedWidthToolButton onDoubleClick={app.resetZoom} variant="text">
|
||||
{Math.round(zoom * 100)}%
|
||||
</FixedWidthToolButton>
|
||||
</DropdownMenu.Trigger>
|
||||
<DMContent align="end">
|
||||
<DMItem onSelect={preventEvent} onClick={app.zoomIn} kbd="#+">
|
||||
<DMItem onSelect={preventEvent} onClick={app.zoomIn} kbd="#+" id="TD-Zoom-Zoom_In">
|
||||
Zoom In
|
||||
</DMItem>
|
||||
<DMItem onSelect={preventEvent} onClick={app.zoomOut} kbd="#−">
|
||||
<DMItem onSelect={preventEvent} onClick={app.zoomOut} kbd="#−" id="TD-Zoom-Zoom_Out">
|
||||
Zoom Out
|
||||
</DMItem>
|
||||
<DMItem onSelect={preventEvent} onClick={app.resetZoom} kbd="⇧0">
|
||||
<DMItem onSelect={preventEvent} onClick={app.resetZoom} kbd="⇧0" id="TD-Zoom-Zoom_To_100%">
|
||||
To 100%
|
||||
</DMItem>
|
||||
<DMItem onSelect={preventEvent} onClick={app.zoomToFit} kbd="⇧1">
|
||||
<DMItem onSelect={preventEvent} onClick={app.zoomToFit} kbd="⇧1" id="TD-Zoom-To_Fit">
|
||||
To Fit
|
||||
</DMItem>
|
||||
<DMItem onSelect={preventEvent} onClick={app.zoomToSelection} kbd="⇧2">
|
||||
<DMItem
|
||||
onSelect={preventEvent}
|
||||
onClick={app.zoomToSelection}
|
||||
kbd="⇧2"
|
||||
id="TD-Zoom-To_Selection"
|
||||
>
|
||||
To Selection
|
||||
</DMItem>
|
||||
</DMContent>
|
||||
|
|
Loading…
Reference in a new issue