open menus refactor (#1400)

This PR makes a change to how open menus are handled.

### Change Type

- [x] `minor` — New Feature
This commit is contained in:
Steve Ruiz 2023-05-17 15:30:28 +01:00 committed by GitHub
parent 7131ab597c
commit 9101dcfd44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 33 additions and 20 deletions

View file

@ -0,0 +1,4 @@
<svg width="30" height="31" viewBox="0 0 30 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 2V4H18V2H8ZM6 1.5C6 0.671573 6.67157 0 7.5 0H18.5C19.3284 0 20 0.671572 20 1.5V2H21C22.6569 2 24 3.34315 24 5V14H22V5C22 4.44772 21.5523 4 21 4H20V4.5C20 5.32843 19.3284 6 18.5 6H7.5C6.67157 6 6 5.32843 6 4.5V4H5C4.44771 4 4 4.44772 4 5V25C4 25.5523 4.44772 26 5 26H12V28H5C3.34315 28 2 26.6569 2 25V5C2 3.34314 3.34315 2 5 2H6V1.5Z" fill="black"/>
<path d="M27.5197 17.173C28.0099 17.4936 28.1475 18.1509 27.827 18.6411L20.6149 29.6713C20.445 29.9313 20.1696 30.1037 19.8615 30.143C19.5534 30.1823 19.2436 30.0846 19.0138 29.8757L14.3472 25.6333C13.9137 25.2393 13.8818 24.5685 14.2758 24.1351C14.6698 23.7017 15.3406 23.6697 15.774 24.0638L19.5203 27.4694L26.0516 17.4803C26.3721 16.9901 27.0294 16.8525 27.5197 17.173Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 893 B

View file

@ -50,6 +50,7 @@ export function getAssetUrlsByImport(opts?: AssetUrlOptions): {
'chevron-up': string
'chevrons-ne': string
'chevrons-sw': string
'clipboard-copied': string
'clipboard-copy': string
code: string
collab: string

View file

@ -61,6 +61,7 @@ import iconsChevronRight from './icons/icon/chevron-right.svg'
import iconsChevronUp from './icons/icon/chevron-up.svg'
import iconsChevronsNe from './icons/icon/chevrons-ne.svg'
import iconsChevronsSw from './icons/icon/chevrons-sw.svg'
import iconsClipboardCopied from './icons/icon/clipboard-copied.svg'
import iconsClipboardCopy from './icons/icon/clipboard-copy.svg'
import iconsCode from './icons/icon/code.svg'
import iconsCollab from './icons/icon/collab.svg'
@ -287,6 +288,7 @@ export function getAssetUrlsByImport(opts) {
'chevron-up': formatAssetUrl(iconsChevronUp, opts),
'chevrons-ne': formatAssetUrl(iconsChevronsNe, opts),
'chevrons-sw': formatAssetUrl(iconsChevronsSw, opts),
'clipboard-copied': formatAssetUrl(iconsClipboardCopied, opts),
'clipboard-copy': formatAssetUrl(iconsClipboardCopy, opts),
code: formatAssetUrl(iconsCode, opts),
collab: formatAssetUrl(iconsCollab, opts),

View file

@ -50,6 +50,7 @@ export function getAssetUrlsByMetaUrl(opts?: AssetUrlOptions): {
'chevron-up': string
'chevrons-ne': string
'chevrons-sw': string
'clipboard-copied': string
'clipboard-copy': string
code: string
collab: string

View file

@ -193,6 +193,10 @@ export function getAssetUrlsByMetaUrl(opts) {
new URL('./icons/icon/chevrons-sw.svg', import.meta.url).href,
opts
),
'clipboard-copied': formatAssetUrl(
new URL('./icons/icon/clipboard-copied.svg', import.meta.url).href,
opts
),
'clipboard-copy': formatAssetUrl(
new URL('./icons/icon/clipboard-copy.svg', import.meta.url).href,
opts

View file

@ -551,10 +551,9 @@ export const NavigationZone: NamedExoticComponent<object>;
function RadioItem({ children, onSelect, ...rest }: DropdownMenuCheckboxItemProps): JSX.Element;
// @public (undocumented)
function Root({ id, open, children, modal, }: {
function Root({ id, children, modal, }: {
id: string;
children: any;
open?: boolean;
modal?: boolean;
}): JSX.Element;
@ -584,10 +583,9 @@ export interface SliderProps {
export const StylePanel: ({ isMobile }: StylePanelProps) => JSX.Element | null;
// @public (undocumented)
function Sub({ id, children, open }: {
function Sub({ id, children }: {
id: string;
children: any;
open?: boolean;
}): JSX.Element;
// @public (undocumented)
@ -743,10 +741,10 @@ export type TLUiEventHandler<T extends keyof TLUiEventMap = keyof TLUiEventMap>
export type TLUiEventSource = 'actions-menu' | 'context-menu' | 'debug-panel' | 'dialog' | 'export-menu' | 'help-menu' | 'helper-buttons' | 'kbd' | 'menu' | 'navigation-zone' | 'page-menu' | 'people-menu' | 'quick-actions' | 'share-menu' | 'toolbar' | 'unknown' | 'zoom-menu';
// @public (undocumented)
export type TLUiIconType = 'align-bottom-center' | 'align-bottom-left' | 'align-bottom-right' | 'align-bottom' | 'align-center-center' | 'align-center-horizontal' | 'align-center-left' | 'align-center-right' | 'align-center-vertical' | 'align-left' | 'align-right' | 'align-top-center' | 'align-top-left' | 'align-top-right' | 'align-top' | 'arrow-left' | 'arrowhead-arrow' | 'arrowhead-bar' | 'arrowhead-diamond' | 'arrowhead-dot' | 'arrowhead-none' | 'arrowhead-square' | 'arrowhead-triangle-inverted' | 'arrowhead-triangle' | 'aspect-ratio' | 'avatar' | 'blob' | 'bring-forward' | 'bring-to-front' | 'check' | 'checkbox-checked' | 'checkbox-empty' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'chevron-up' | 'chevrons-ne' | 'chevrons-sw' | 'clipboard-copy' | 'code' | 'collab' | 'color' | 'comment' | 'cross-2' | 'cross' | 'dash-dashed' | 'dash-dotted' | 'dash-draw' | 'dash-solid' | 'discord' | 'distribute-horizontal' | 'distribute-vertical' | 'dot' | 'dots-horizontal' | 'dots-vertical' | 'drag-handle-dots' | 'duplicate' | 'edit' | 'external-link' | 'file' | 'fill-none' | 'fill-pattern' | 'fill-semi' | 'fill-solid' | 'follow' | 'following' | 'font-draw' | 'font-mono' | 'font-sans' | 'font-serif' | 'geo-arrow-down' | 'geo-arrow-left' | 'geo-arrow-right' | 'geo-arrow-up' | 'geo-check-box' | 'geo-diamond' | 'geo-ellipse' | 'geo-hexagon' | 'geo-octagon' | 'geo-oval' | 'geo-pentagon' | 'geo-rectangle' | 'geo-rhombus-2' | 'geo-rhombus' | 'geo-star' | 'geo-trapezoid' | 'geo-triangle' | 'geo-x-box' | 'github' | 'group' | 'hidden' | 'image' | 'info-circle' | 'leading' | 'link' | 'lock-small' | 'lock' | 'menu' | 'minus' | 'mixed' | 'pack' | 'page' | 'plus' | 'question-mark-circle' | 'question-mark' | 'redo' | 'reset-zoom' | 'rotate-ccw' | 'rotate-cw' | 'ruler' | 'search' | 'send-backward' | 'send-to-back' | 'settings-horizontal' | 'settings-vertical-1' | 'settings-vertical' | 'share-1' | 'share-2' | 'size-extra-large' | 'size-large' | 'size-medium' | 'size-small' | 'spline-cubic' | 'spline-line' | 'stack-horizontal' | 'stack-vertical' | 'stretch-horizontal' | 'stretch-vertical' | 'text-align-center' | 'text-align-justify' | 'text-align-left' | 'text-align-right' | 'tool-arrow' | 'tool-embed' | 'tool-eraser' | 'tool-frame' | 'tool-hand' | 'tool-highlighter' | 'tool-line' | 'tool-media' | 'tool-note' | 'tool-pencil' | 'tool-pointer' | 'tool-text' | 'trash' | 'triangle-down' | 'triangle-up' | 'twitter' | 'undo' | 'ungroup' | 'unlock-small' | 'unlock' | 'visible' | 'warning-triangle' | 'zoom-in' | 'zoom-out';
export type TLUiIconType = 'align-bottom-center' | 'align-bottom-left' | 'align-bottom-right' | 'align-bottom' | 'align-center-center' | 'align-center-horizontal' | 'align-center-left' | 'align-center-right' | 'align-center-vertical' | 'align-left' | 'align-right' | 'align-top-center' | 'align-top-left' | 'align-top-right' | 'align-top' | 'arrow-left' | 'arrowhead-arrow' | 'arrowhead-bar' | 'arrowhead-diamond' | 'arrowhead-dot' | 'arrowhead-none' | 'arrowhead-square' | 'arrowhead-triangle-inverted' | 'arrowhead-triangle' | 'aspect-ratio' | 'avatar' | 'blob' | 'bring-forward' | 'bring-to-front' | 'check' | 'checkbox-checked' | 'checkbox-empty' | 'chevron-down' | 'chevron-left' | 'chevron-right' | 'chevron-up' | 'chevrons-ne' | 'chevrons-sw' | 'clipboard-copied' | 'clipboard-copy' | 'code' | 'collab' | 'color' | 'comment' | 'cross-2' | 'cross' | 'dash-dashed' | 'dash-dotted' | 'dash-draw' | 'dash-solid' | 'discord' | 'distribute-horizontal' | 'distribute-vertical' | 'dot' | 'dots-horizontal' | 'dots-vertical' | 'drag-handle-dots' | 'duplicate' | 'edit' | 'external-link' | 'file' | 'fill-none' | 'fill-pattern' | 'fill-semi' | 'fill-solid' | 'follow' | 'following' | 'font-draw' | 'font-mono' | 'font-sans' | 'font-serif' | 'geo-arrow-down' | 'geo-arrow-left' | 'geo-arrow-right' | 'geo-arrow-up' | 'geo-check-box' | 'geo-diamond' | 'geo-ellipse' | 'geo-hexagon' | 'geo-octagon' | 'geo-oval' | 'geo-pentagon' | 'geo-rectangle' | 'geo-rhombus-2' | 'geo-rhombus' | 'geo-star' | 'geo-trapezoid' | 'geo-triangle' | 'geo-x-box' | 'github' | 'group' | 'hidden' | 'image' | 'info-circle' | 'leading' | 'link' | 'lock-small' | 'lock' | 'menu' | 'minus' | 'mixed' | 'pack' | 'page' | 'plus' | 'question-mark-circle' | 'question-mark' | 'redo' | 'reset-zoom' | 'rotate-ccw' | 'rotate-cw' | 'ruler' | 'search' | 'send-backward' | 'send-to-back' | 'settings-horizontal' | 'settings-vertical-1' | 'settings-vertical' | 'share-1' | 'share-2' | 'size-extra-large' | 'size-large' | 'size-medium' | 'size-small' | 'spline-cubic' | 'spline-line' | 'stack-horizontal' | 'stack-vertical' | 'stretch-horizontal' | 'stretch-vertical' | 'text-align-center' | 'text-align-justify' | 'text-align-left' | 'text-align-right' | 'tool-arrow' | 'tool-embed' | 'tool-eraser' | 'tool-frame' | 'tool-hand' | 'tool-highlighter' | 'tool-line' | 'tool-media' | 'tool-note' | 'tool-pencil' | 'tool-pointer' | 'tool-text' | 'trash' | 'triangle-down' | 'triangle-up' | 'twitter' | 'undo' | 'ungroup' | 'unlock-small' | 'unlock' | 'visible' | 'warning-triangle' | 'zoom-in' | 'zoom-out';
// @public (undocumented)
export const TLUiIconTypes: readonly ["align-bottom-center", "align-bottom-left", "align-bottom-right", "align-bottom", "align-center-center", "align-center-horizontal", "align-center-left", "align-center-right", "align-center-vertical", "align-left", "align-right", "align-top-center", "align-top-left", "align-top-right", "align-top", "arrow-left", "arrowhead-arrow", "arrowhead-bar", "arrowhead-diamond", "arrowhead-dot", "arrowhead-none", "arrowhead-square", "arrowhead-triangle-inverted", "arrowhead-triangle", "aspect-ratio", "avatar", "blob", "bring-forward", "bring-to-front", "check", "checkbox-checked", "checkbox-empty", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "chevrons-ne", "chevrons-sw", "clipboard-copy", "code", "collab", "color", "comment", "cross-2", "cross", "dash-dashed", "dash-dotted", "dash-draw", "dash-solid", "discord", "distribute-horizontal", "distribute-vertical", "dot", "dots-horizontal", "dots-vertical", "drag-handle-dots", "duplicate", "edit", "external-link", "file", "fill-none", "fill-pattern", "fill-semi", "fill-solid", "follow", "following", "font-draw", "font-mono", "font-sans", "font-serif", "geo-arrow-down", "geo-arrow-left", "geo-arrow-right", "geo-arrow-up", "geo-check-box", "geo-diamond", "geo-ellipse", "geo-hexagon", "geo-octagon", "geo-oval", "geo-pentagon", "geo-rectangle", "geo-rhombus-2", "geo-rhombus", "geo-star", "geo-trapezoid", "geo-triangle", "geo-x-box", "github", "group", "hidden", "image", "info-circle", "leading", "link", "lock-small", "lock", "menu", "minus", "mixed", "pack", "page", "plus", "question-mark-circle", "question-mark", "redo", "reset-zoom", "rotate-ccw", "rotate-cw", "ruler", "search", "send-backward", "send-to-back", "settings-horizontal", "settings-vertical-1", "settings-vertical", "share-1", "share-2", "size-extra-large", "size-large", "size-medium", "size-small", "spline-cubic", "spline-line", "stack-horizontal", "stack-vertical", "stretch-horizontal", "stretch-vertical", "text-align-center", "text-align-justify", "text-align-left", "text-align-right", "tool-arrow", "tool-embed", "tool-eraser", "tool-frame", "tool-hand", "tool-highlighter", "tool-line", "tool-media", "tool-note", "tool-pencil", "tool-pointer", "tool-text", "trash", "triangle-down", "triangle-up", "twitter", "undo", "ungroup", "unlock-small", "unlock", "visible", "warning-triangle", "zoom-in", "zoom-out"];
export const TLUiIconTypes: readonly ["align-bottom-center", "align-bottom-left", "align-bottom-right", "align-bottom", "align-center-center", "align-center-horizontal", "align-center-left", "align-center-right", "align-center-vertical", "align-left", "align-right", "align-top-center", "align-top-left", "align-top-right", "align-top", "arrow-left", "arrowhead-arrow", "arrowhead-bar", "arrowhead-diamond", "arrowhead-dot", "arrowhead-none", "arrowhead-square", "arrowhead-triangle-inverted", "arrowhead-triangle", "aspect-ratio", "avatar", "blob", "bring-forward", "bring-to-front", "check", "checkbox-checked", "checkbox-empty", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "chevrons-ne", "chevrons-sw", "clipboard-copied", "clipboard-copy", "code", "collab", "color", "comment", "cross-2", "cross", "dash-dashed", "dash-dotted", "dash-draw", "dash-solid", "discord", "distribute-horizontal", "distribute-vertical", "dot", "dots-horizontal", "dots-vertical", "drag-handle-dots", "duplicate", "edit", "external-link", "file", "fill-none", "fill-pattern", "fill-semi", "fill-solid", "follow", "following", "font-draw", "font-mono", "font-sans", "font-serif", "geo-arrow-down", "geo-arrow-left", "geo-arrow-right", "geo-arrow-up", "geo-check-box", "geo-diamond", "geo-ellipse", "geo-hexagon", "geo-octagon", "geo-oval", "geo-pentagon", "geo-rectangle", "geo-rhombus-2", "geo-rhombus", "geo-star", "geo-trapezoid", "geo-triangle", "geo-x-box", "github", "group", "hidden", "image", "info-circle", "leading", "link", "lock-small", "lock", "menu", "minus", "mixed", "pack", "page", "plus", "question-mark-circle", "question-mark", "redo", "reset-zoom", "rotate-ccw", "rotate-cw", "ruler", "search", "send-backward", "send-to-back", "settings-horizontal", "settings-vertical-1", "settings-vertical", "share-1", "share-2", "size-extra-large", "size-large", "size-medium", "size-small", "spline-cubic", "spline-line", "stack-horizontal", "stack-vertical", "stretch-horizontal", "stretch-vertical", "text-align-center", "text-align-justify", "text-align-left", "text-align-right", "tool-arrow", "tool-embed", "tool-eraser", "tool-frame", "tool-hand", "tool-highlighter", "tool-line", "tool-media", "tool-note", "tool-pencil", "tool-pointer", "tool-text", "trash", "triangle-down", "triangle-up", "twitter", "undo", "ungroup", "unlock-small", "unlock", "visible", "warning-triangle", "zoom-in", "zoom-out"];
// @public (undocumented)
export const ToastsContext: Context<ToastsContextType>;
@ -1043,7 +1041,7 @@ export function useMenuClipboardEvents(source: TLUiEventSource): {
};
// @public (undocumented)
export function useMenuIsOpen(id: string, cb?: (isOpen: boolean) => void): (isOpen: boolean) => void;
export function useMenuIsOpen(id: string, cb?: (isOpen: boolean) => void): readonly [boolean, (isOpen: boolean) => void];
// @public (undocumented)
export function useMenuSchema(): MenuSchema;

View file

@ -25,7 +25,7 @@ export const ContextMenu = function ContextMenu({ children }: { children: any })
const app = useApp()
const contextMenuSchema = useContextMenuSchema()
const handleOpenChange = useMenuIsOpen('context menu')
const [_, handleOpenChange] = useMenuIsOpen('context menu')
// If every item in the menu is readonly, then we don't want to show the menu
const isReadonly = useReadonly()
@ -58,7 +58,7 @@ function ContextMenuContent() {
const app = useApp()
const msg = useTranslation()
const menuSchema = useContextMenuSchema()
const handleSubOpenChange = useMenuIsOpen('context menu sub')
const [_, handleSubOpenChange] = useMenuIsOpen('context menu sub')
const isReadonly = useReadonly()
const { paste } = useMenuClipboardEvents('context-menu')

View file

@ -27,11 +27,11 @@ export interface HelpMenuProps {
export const HelpMenu = React.memo(function HelpMenu() {
const container = useContainer()
const msg = useTranslation()
const onOpenChange = useMenuIsOpen('help menu')
const [isOpen, onOpenChange] = useMenuIsOpen('help menu')
return (
<div className="tlui-help-menu">
<Root dir="ltr" onOpenChange={onOpenChange} modal={false}>
<Root dir="ltr" open={isOpen} onOpenChange={onOpenChange} modal={false}>
<Trigger
className="tlui-button tlui-help-menu__button"
dir="ltr"

View file

@ -8,16 +8,14 @@ import { Icon } from './Icon'
/** @public */
export function Root({
id,
open,
children,
modal = false,
}: {
id: string
children: any
open?: boolean
modal?: boolean
}) {
const onOpenChange = useMenuIsOpen(id)
const [open, onOpenChange] = useMenuIsOpen(id)
return (
<DropdownMenu.Root open={open} dir="ltr" modal={modal} onOpenChange={onOpenChange}>
@ -68,8 +66,8 @@ export function Content({
}
/** @public */
export function Sub({ id, children, open }: { id: string; children: any; open?: boolean }) {
const onOpenChange = useMenuIsOpen(id)
export function Sub({ id, children }: { id: string; children: any }) {
const [open, onOpenChange] = useMenuIsOpen(id)
return (
<DropdownMenu.Sub open={open} onOpenChange={onOpenChange}>

View file

@ -10,11 +10,11 @@ type PopoverProps = {
onOpenChange?: (isOpen: boolean) => void
}
export const Popover: FC<PopoverProps> = ({ id, open, children, onOpenChange }) => {
const handleOpenChange = useMenuIsOpen(id, onOpenChange)
export const Popover: FC<PopoverProps> = ({ id, children, onOpenChange }) => {
const [isOpen, handleOpenChange] = useMenuIsOpen(id, onOpenChange)
return (
<PopoverPrimitive.Root onOpenChange={handleOpenChange} open={open}>
<PopoverPrimitive.Root onOpenChange={handleOpenChange} open={isOpen}>
<div className="tlui-popover">{children}</div>
</PopoverPrimitive.Root>
)

View file

@ -1,5 +1,6 @@
import { useApp } from '@tldraw/editor'
import { useCallback, useEffect, useRef } from 'react'
import { useValue } from 'signia-react'
import { useEvents } from './useEventsProvider'
/** @public */
@ -62,5 +63,7 @@ export function useMenuIsOpen(id: string, cb?: (isOpen: boolean) => void) {
}
}, [app, id, trackEvent])
return onOpenChange
const isOpen = useValue('is menu open', () => app.openMenus.includes(id), [app, id])
return [isOpen, onOpenChange] as const
}

View file

@ -41,6 +41,7 @@ export type TLUiIconType =
| 'chevron-up'
| 'chevrons-ne'
| 'chevrons-sw'
| 'clipboard-copied'
| 'clipboard-copy'
| 'code'
| 'collab'
@ -200,6 +201,7 @@ export const TLUiIconTypes = [
'chevron-up',
'chevrons-ne',
'chevrons-sw',
'clipboard-copied',
'clipboard-copy',
'code',
'collab',