| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 | 
							- import * as _ContextMenu from '@radix-ui/react-context-menu'
 - import * as _Dropdown from '@radix-ui/react-dropdown-menu'
 - import styled from 'styles'
 - import {
 -   IconWrapper,
 -   IconButton as _IconButton,
 -   RowButton,
 - } from 'components/shared'
 - import {
 -   commandKey,
 -   deepCompareArrays,
 -   getSelectedShapes,
 -   isMobile,
 - } from 'utils/utils'
 - import state, { useSelector } from 'state'
 - import {
 -   AlignType,
 -   DistributeType,
 -   MoveType,
 -   ShapeType,
 -   StretchType,
 - } from 'types'
 - import React, { useRef } from 'react'
 - import {
 -   ChevronRightIcon,
 -   AlignBottomIcon,
 -   AlignCenterHorizontallyIcon,
 -   AlignCenterVerticallyIcon,
 -   AlignLeftIcon,
 -   AlignRightIcon,
 -   AlignTopIcon,
 -   SpaceEvenlyHorizontallyIcon,
 -   SpaceEvenlyVerticallyIcon,
 -   StretchHorizontallyIcon,
 -   StretchVerticallyIcon,
 - } from '@radix-ui/react-icons'
 - 
 - function alignTop() {
 -   state.send('ALIGNED', { type: AlignType.Top })
 - }
 - 
 - function alignCenterVertical() {
 -   state.send('ALIGNED', { type: AlignType.CenterVertical })
 - }
 - 
 - function alignBottom() {
 -   state.send('ALIGNED', { type: AlignType.Bottom })
 - }
 - 
 - function stretchVertically() {
 -   state.send('STRETCHED', { type: StretchType.Vertical })
 - }
 - 
 - function distributeVertically() {
 -   state.send('DISTRIBUTED', { type: DistributeType.Vertical })
 - }
 - 
 - function alignLeft() {
 -   state.send('ALIGNED', { type: AlignType.Left })
 - }
 - 
 - function alignCenterHorizontal() {
 -   state.send('ALIGNED', { type: AlignType.CenterHorizontal })
 - }
 - 
 - function alignRight() {
 -   state.send('ALIGNED', { type: AlignType.Right })
 - }
 - 
 - function stretchHorizontally() {
 -   state.send('STRETCHED', { type: StretchType.Horizontal })
 - }
 - 
 - function distributeHorizontally() {
 -   state.send('DISTRIBUTED', { type: DistributeType.Horizontal })
 - }
 - 
 - export default function ContextMenu({
 -   children,
 - }: {
 -   children: React.ReactNode
 - }) {
 -   const selectedShapes = useSelector(
 -     (s) => getSelectedShapes(s.data),
 -     deepCompareArrays
 -   )
 - 
 -   const rContent = useRef<HTMLDivElement>(null)
 - 
 -   const hasGroupSelectd = selectedShapes.some((s) => s.type === ShapeType.Group)
 -   const hasTwoOrMore = selectedShapes.length > 1
 -   const hasThreeOrMore = selectedShapes.length > 2
 - 
 -   return (
 -     <_ContextMenu.Root>
 -       <_ContextMenu.Trigger>{children}</_ContextMenu.Trigger>
 -       <StyledContent ref={rContent} isMobile={isMobile()}>
 -         {selectedShapes.length ? (
 -           <>
 -             {/* <Button onSelect={() => state.send('COPIED')}>
 -               <span>Copy</span>
 -               <kbd>
 -                 <span>{commandKey()}</span>
 -                 <span>C</span>
 -               </kbd>
 -             </Button>
 -             <Button onSelect={() => state.send('CUT')}>
 -               <span>Cut</span>
 -               <kbd>
 -                 <span>{commandKey()}</span>
 -                 <span>X</span>
 -               </kbd>
 -             </Button>
 -              */}
 -             <Button onSelect={() => state.send('DUPLICATED')}>
 -               <span>Duplicate</span>
 -               <kbd>
 -                 <span>{commandKey()}</span>
 -                 <span>D</span>
 -               </kbd>
 -             </Button>
 -             <StyledDivider />
 -             {hasGroupSelectd ||
 -               (hasTwoOrMore && (
 -                 <>
 -                   {hasGroupSelectd && (
 -                     <Button onSelect={() => state.send('UNGROUPED')}>
 -                       <span>Ungroup</span>
 -                       <kbd>
 -                         <span>{commandKey()}</span>
 -                         <span>⇧</span>
 -                         <span>G</span>
 -                       </kbd>
 -                     </Button>
 -                   )}
 -                   {hasTwoOrMore && (
 -                     <Button onSelect={() => state.send('GROUPED')}>
 -                       <span>Group</span>
 -                       <kbd>
 -                         <span>{commandKey()}</span>
 -                         <span>G</span>
 -                       </kbd>
 -                     </Button>
 -                   )}
 -                 </>
 -               ))}
 -             <SubMenu label="Move">
 -               <Button
 -                 onSelect={() =>
 -                   state.send('MOVED', {
 -                     type: MoveType.ToFront,
 -                   })
 -                 }
 -               >
 -                 <span>To Front</span>
 -                 <kbd>
 -                   <span>{commandKey()}</span>
 -                   <span>⇧</span>
 -                   <span>]</span>
 -                 </kbd>
 -               </Button>
 - 
 -               <Button
 -                 onSelect={() =>
 -                   state.send('MOVED', {
 -                     type: MoveType.Forward,
 -                   })
 -                 }
 -               >
 -                 <span>Forward</span>
 -                 <kbd>
 -                   <span>{commandKey()}</span>
 -                   <span>]</span>
 -                 </kbd>
 -               </Button>
 -               <Button
 -                 onSelect={() =>
 -                   state.send('MOVED', {
 -                     type: MoveType.Backward,
 -                   })
 -                 }
 -               >
 -                 <span>Backward</span>
 -                 <kbd>
 -                   <span>{commandKey()}</span>
 -                   <span>[</span>
 -                 </kbd>
 -               </Button>
 -               <Button
 -                 onSelect={() =>
 -                   state.send('MOVED', {
 -                     type: MoveType.ToBack,
 -                   })
 -                 }
 -               >
 -                 <span>To Back</span>
 -                 <kbd>
 -                   <span>{commandKey()}</span>
 -                   <span>⇧</span>
 -                   <span>[</span>
 -                 </kbd>
 -               </Button>
 -             </SubMenu>
 -             {hasTwoOrMore && (
 -               <AlignDistributeSubMenu
 -                 hasTwoOrMore={hasTwoOrMore}
 -                 hasThreeOrMore={hasThreeOrMore}
 -               />
 -             )}
 -             <MoveToPageMenu />
 -             <StyledDivider />
 -             <Button onSelect={() => state.send('DELETED')}>
 -               <span>Delete</span>
 -               <kbd>
 -                 <span>⌫</span>
 -               </kbd>
 -             </Button>
 -           </>
 -         ) : (
 -           <>
 -             <Button onSelect={() => state.send('UNDO')}>
 -               <span>Undo</span>
 -               <kbd>
 -                 <span>{commandKey()}</span>
 -                 <span>Z</span>
 -               </kbd>
 -             </Button>
 -             <Button onSelect={() => state.send('REDO')}>
 -               <span>Redo</span>
 -               <kbd>
 -                 <span>{commandKey()}</span>
 -                 <span>⇧</span>
 -                 <span>Z</span>
 -               </kbd>
 -             </Button>
 -           </>
 -         )}
 -       </StyledContent>
 -     </_ContextMenu.Root>
 -   )
 - }
 - 
 - const StyledContent = styled(_ContextMenu.Content, {
 -   position: 'relative',
 -   backgroundColor: '$panel',
 -   borderRadius: '4px',
 -   overflow: 'hidden',
 -   pointerEvents: 'all',
 -   userSelect: 'none',
 -   zIndex: 200,
 -   padding: 3,
 -   boxShadow: '0px 2px 4px rgba(0,0,0,.2)',
 -   minWidth: 128,
 - 
 -   '& kbd': {
 -     marginLeft: '32px',
 -     fontSize: '$1',
 -     fontFamily: '$ui',
 -   },
 - 
 -   '& kbd > span': {
 -     display: 'inline-block',
 -     width: '12px',
 -   },
 - 
 -   variants: {
 -     isMobile: {
 -       true: {
 -         '& kbd': {
 -           display: 'none',
 -         },
 -       },
 -     },
 -   },
 - })
 - 
 - const StyledDivider = styled(_ContextMenu.Separator, {
 -   backgroundColor: '$hover',
 -   height: 1,
 -   margin: '3px -3px',
 - })
 - 
 - function Button({
 -   onSelect,
 -   children,
 -   disabled = false,
 - }: {
 -   onSelect: () => void
 -   disabled?: boolean
 -   children: React.ReactNode
 - }) {
 -   return (
 -     <_ContextMenu.Item
 -       as={RowButton}
 -       disabled={disabled}
 -       bp={{ '@initial': 'mobile', '@sm': 'small' }}
 -       onSelect={onSelect}
 -     >
 -       {children}
 -     </_ContextMenu.Item>
 -   )
 - }
 - 
 - function IconButton({
 -   onSelect,
 -   children,
 -   disabled = false,
 - }: {
 -   onSelect: () => void
 -   disabled?: boolean
 -   children: React.ReactNode
 - }) {
 -   return (
 -     <_ContextMenu.Item
 -       as={_IconButton}
 -       bp={{ '@initial': 'mobile', '@sm': 'small' }}
 -       disabled={disabled}
 -       onSelect={onSelect}
 -     >
 -       {children}
 -     </_ContextMenu.Item>
 -   )
 - }
 - 
 - function SubMenu({
 -   children,
 -   label,
 - }: {
 -   label: string
 -   children: React.ReactNode
 - }) {
 -   return (
 -     <_ContextMenu.Root>
 -       <_ContextMenu.TriggerItem
 -         as={RowButton}
 -         bp={{ '@initial': 'mobile', '@sm': 'small' }}
 -       >
 -         <span>{label}</span>
 -         <IconWrapper size="small">
 -           <ChevronRightIcon />
 -         </IconWrapper>
 -       </_ContextMenu.TriggerItem>
 -       <StyledContent sideOffset={2} alignOffset={-2} isMobile={isMobile()}>
 -         {children}
 -         <StyledArrow offset={13} />
 -       </StyledContent>
 -     </_ContextMenu.Root>
 -   )
 - }
 - 
 - function AlignDistributeSubMenu({
 -   hasTwoOrMore,
 -   hasThreeOrMore,
 - }: {
 -   hasTwoOrMore: boolean
 -   hasThreeOrMore: boolean
 - }) {
 -   return (
 -     <_ContextMenu.Root>
 -       <_ContextMenu.TriggerItem
 -         as={RowButton}
 -         bp={{ '@initial': 'mobile', '@sm': 'small' }}
 -       >
 -         <span>Align / Distribute</span>
 -         <IconWrapper size="small">
 -           <ChevronRightIcon />
 -         </IconWrapper>
 -       </_ContextMenu.TriggerItem>
 -       <StyledGrid
 -         sideOffset={2}
 -         alignOffset={-2}
 -         isMobile={isMobile()}
 -         selectedStyle={hasThreeOrMore ? 'threeOrMore' : 'twoOrMore'}
 -       >
 -         <IconButton onSelect={alignLeft}>
 -           <AlignLeftIcon />
 -         </IconButton>
 -         <IconButton onSelect={alignCenterHorizontal}>
 -           <AlignCenterHorizontallyIcon />
 -         </IconButton>
 -         <IconButton onSelect={alignRight}>
 -           <AlignRightIcon />
 -         </IconButton>
 -         <IconButton onSelect={stretchHorizontally}>
 -           <StretchHorizontallyIcon />
 -         </IconButton>
 -         {hasThreeOrMore && (
 -           <IconButton onSelect={distributeHorizontally}>
 -             <SpaceEvenlyHorizontallyIcon />
 -           </IconButton>
 -         )}
 - 
 -         <IconButton onSelect={alignTop}>
 -           <AlignTopIcon />
 -         </IconButton>
 -         <IconButton onSelect={alignCenterVertical}>
 -           <AlignCenterVerticallyIcon />
 -         </IconButton>
 -         <IconButton onSelect={alignBottom}>
 -           <AlignBottomIcon />
 -         </IconButton>
 -         <IconButton onSelect={stretchVertically}>
 -           <StretchVerticallyIcon />
 -         </IconButton>
 -         {hasThreeOrMore && (
 -           <IconButton onSelect={distributeVertically}>
 -             <SpaceEvenlyVerticallyIcon />
 -           </IconButton>
 -         )}
 -         <StyledArrow offset={13} />
 -       </StyledGrid>
 -     </_ContextMenu.Root>
 -   )
 - }
 - 
 - const StyledGrid = styled(StyledContent, {
 -   display: 'grid',
 -   variants: {
 -     selectedStyle: {
 -       threeOrMore: {
 -         gridTemplateColumns: 'repeat(5, auto)',
 -       },
 -       twoOrMore: {
 -         gridTemplateColumns: 'repeat(4, auto)',
 -       },
 -     },
 -   },
 - })
 - 
 - function MoveToPageMenu() {
 -   const documentPages = useSelector((s) => s.data.document.pages)
 -   const currentPageId = useSelector((s) => s.data.currentPageId)
 - 
 -   if (!documentPages[currentPageId]) return null
 - 
 -   const sorted = Object.values(documentPages)
 -     .sort((a, b) => a.childIndex - b.childIndex)
 -     .filter((a) => a.id !== currentPageId)
 - 
 -   if (sorted.length === 0) return null
 - 
 -   return (
 -     <_ContextMenu.Root>
 -       <_ContextMenu.TriggerItem
 -         as={RowButton}
 -         bp={{ '@initial': 'mobile', '@sm': 'small' }}
 -       >
 -         <span>Move To Page</span>
 -         <IconWrapper size="small">
 -           <ChevronRightIcon />
 -         </IconWrapper>
 -       </_ContextMenu.TriggerItem>
 -       <StyledContent sideOffset={2} alignOffset={-2} isMobile={isMobile()}>
 -         {sorted.map(({ id, name }) => (
 -           <Button
 -             key={id}
 -             disabled={id === currentPageId}
 -             onSelect={() => state.send('MOVED_TO_PAGE', { id })}
 -           >
 -             <span>{name}</span>
 -           </Button>
 -         ))}
 -         <StyledArrow offset={13} />
 -       </StyledContent>
 -     </_ContextMenu.Root>
 -   )
 - }
 - 
 - const StyledDialogContent = styled(_Dropdown.Content, {
 -   // position: 'fixed',
 -   // top: '50%',
 -   // left: '50%',
 -   // transform: 'translate(-50%, -50%)',
 -   // minWidth: 200,
 -   // maxWidth: 'fit-content',
 -   // maxHeight: '85vh',
 -   // marginTop: '-5vh',
 -   minWidth: 128,
 -   backgroundColor: '$panel',
 -   borderRadius: '4px',
 -   overflow: 'hidden',
 -   pointerEvents: 'all',
 -   userSelect: 'none',
 -   zIndex: 200,
 -   padding: 2,
 -   border: '1px solid $panel',
 -   boxShadow: '0px 2px 4px rgba(0,0,0,.2)',
 - 
 -   '&:focus': {
 -     outline: 'none',
 -   },
 - })
 - 
 - const StyledArrow = styled(_ContextMenu.Arrow, {
 -   fill: 'white',
 - })
 
 
  |