Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: arrow-popup
Browse files Browse the repository at this point in the history
pubuzhixing8 committed Jul 1, 2024
1 parent 02736d4 commit a4195f7
Showing 5 changed files with 169 additions and 43 deletions.
78 changes: 78 additions & 0 deletions packages/drawnix/src/components/arrow-popup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import classNames from 'classnames';
import { Island } from './island';
import Stack from './stack';
import { ToolButton } from './tool-button';
import { StraightArrowIcon, ElbowArrowIcon, CurveArrowIcon } from './icons';
import { useBoard } from '@plait/react-board';
import { BoardTransforms, PlaitBoard } from '@plait/core';
import * as Popover from '@radix-ui/react-popover';
import React from 'react';
import { BoardCreationMode, setCreationMode } from '@plait/common';
import { LineShape } from '@plait/draw';

export interface ArrowProps {
icon: React.ReactNode;
title: string;
pointer: LineShape;
}

const ARROWS: ArrowProps[] = [
{
icon: StraightArrowIcon,
title: 'Straight Arrow Line',
pointer: LineShape.straight,
},
{
icon: ElbowArrowIcon,
title: 'Elbow Arrow Line',
pointer: LineShape.elbow,
},
{
icon: CurveArrowIcon,
title: 'Curve Arrow Line',
pointer: LineShape.curve,
},
];

export const ArrowPopupContent: React.FC = () => {
const board = useBoard();
const container = PlaitBoard.getBoardContainer(board);

const onPointerDown = (pointer: LineShape) => {
setCreationMode(board, BoardCreationMode.drawing);
BoardTransforms.updatePointerType(board, pointer);
};

const onPointerUp = () => {};

return (
<Popover.Portal container={container}>
<Popover.Content sideOffset={12}>
<Island padding={1}>
<Stack.Row gap={1}>
{ARROWS.map((arrow, index) => {
return (
<ToolButton
key={index}
className={classNames({ fillable: false })}
type="icon"
size={'small'}
visible={true}
icon={arrow.icon}
title={arrow.title}
aria-label={arrow.title}
onPointerDown={() => {
onPointerDown(arrow.pointer);
}}
onPointerUp={() => {
onPointerUp();
}}
/>
);
})}
</Stack.Row>
</Island>
</Popover.Content>
</Popover.Portal>
);
};
88 changes: 60 additions & 28 deletions packages/drawnix/src/components/draw-toolbar.tsx
Original file line number Diff line number Diff line change
@@ -18,13 +18,20 @@ import { BoardCreationMode, setCreationMode } from '@plait/common';
import { BasicShapes } from '@plait/draw';
import * as Popover from '@radix-ui/react-popover';
import { useSetState } from 'ahooks';
import { ShapePickerPopupContent } from './shape-picker';
import { ShapePopupContent } from './shape-popup';
import { ArrowPopupContent } from './arrow-popup';

export enum PopupKey {
'shape' = 'shape',
'arrow' = 'arrow',
}

type AppToolButtonProps = {
title?: string;
name?: string;
icon: React.ReactNode;
pointer?: DrawnixPointerType;
popupKey?: PopupKey;
};

const isBasicPointer = (pointer: string) => {
@@ -54,27 +61,39 @@ export const BUTTONS: AppToolButtonProps[] = [
pointer: BasicShapes.text,
title: 'Text',
},
// {
// name: 'shape',
// icon: ShapeIcon,
// title: 'Shape',
// },
{
icon: StraightArrowLineIcon,
title: 'Arrow Line',
popupKey: PopupKey.arrow,
},
{
icon: ShapeIcon,
title: 'Shape',
popupKey: PopupKey.shape,
},
];

export const renderPopupContent = (key: PopupKey) => {
switch (key) {
case PopupKey.shape:
return <ShapePopupContent></ShapePopupContent>;
case PopupKey.arrow:
return <ArrowPopupContent></ArrowPopupContent>;
default:
break;
}
};

export type DrawToolbarProps = {
setPointer: (pointer: DrawnixPointerType) => void;
};

export const DrawToolbar: React.FC<DrawToolbarProps> = ({ setPointer }) => {
const board = useBoard();

const [state, setState] = useSetState<{ isShapePicker: boolean }>({
isShapePicker: false,
});
const [state, setState] = useSetState<{
popupKey: PopupKey | undefined;
}>({ popupKey: undefined });

const onChange = (pointer: DrawnixPointerType) => {
BoardTransforms.updatePointerType(board, pointer);
@@ -92,13 +111,44 @@ export const DrawToolbar: React.FC<DrawToolbarProps> = ({ setPointer }) => {
};

const isChecked = (button: AppToolButtonProps) => {
return PlaitBoard.isPointer(board, button.pointer) && !state.isShapePicker;
return (
PlaitBoard.isPointer(board, button.pointer) &&
state.popupKey === undefined
);
};

return (
<Island padding={1} className={classNames('draw-toolbar')}>
<Stack.Row gap={1}>
{BUTTONS.map((button, index) => {
if (button.popupKey) {
return (
<Popover.Root
key={index}
onOpenChange={(open) => {
if (open) {
setState({ popupKey: button.popupKey });
} else {
setState({ popupKey: undefined });
}
}}
>
<Popover.Trigger asChild>
<ToolButton
className={classNames('Shape', { fillable: false })}
type="icon"
visible={true}
selected={state.popupKey === button.popupKey}
icon={button.icon}
title={`Shape`}
aria-label={`Shape`}
/>
</Popover.Trigger>
{renderPopupContent(button.popupKey)}
</Popover.Root>
);
}

const buttonComp = (
<ToolButton
key={index}
@@ -127,24 +177,6 @@ export const DrawToolbar: React.FC<DrawToolbarProps> = ({ setPointer }) => {
);
return buttonComp;
})}
<Popover.Root
onOpenChange={(open) => {
setState({ isShapePicker: open });
}}
>
<Popover.Trigger asChild>
<ToolButton
className={classNames('Shape', { fillable: false })}
type="icon"
visible={true}
selected={state.isShapePicker}
icon={ShapeIcon}
title={`Shape`}
aria-label={`Shape`}
/>
</Popover.Trigger>
<ShapePickerPopupContent></ShapePickerPopupContent>
</Popover.Root>
</Stack.Row>
</Island>
);
27 changes: 27 additions & 0 deletions packages/drawnix/src/components/icons.tsx
Original file line number Diff line number Diff line change
@@ -107,3 +107,30 @@ export const RoundRectangleIcon = createIcon(
</g>
</svg>
);

export const StraightArrowIcon = createIcon(
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" version="1.1">
<g stroke="none" fill="currentColor">
<path
d="M8.55595221,-1.5261864 C8.88741773,-1.5261864 9.15621426,-1.25765205 9.15653772,-0.926186684 L9.16739175,10.3828136 L10.9946787,10.3836977 C11.2708211,10.3836977 11.4946787,10.6075553 11.4946787,10.8836977 C11.4946787,10.9607525 11.4768694,11.0367648 11.4426413,11.1058002 L8.8378495,16.3594519 C8.7642512,16.5078936 8.58425218,16.5685662 8.43581043,16.4949679 C8.37895485,16.4667786 8.33250284,16.4212859 8.30313336,16.3650308 L5.56226325,11.1150985 C5.43446412,10.8703088 5.52930372,10.5682659 5.77409341,10.4404667 C5.84552557,10.4031736 5.92491301,10.3836977 6.0054942,10.3836977 L7.96739175,10.3828136 L7.95653772,-0.926186684 C7.95621467,-1.25723416 8.22431979,-1.52586306 8.55536727,-1.52618611 Z"
transform="translate(8.500035, 7.500035) rotate(-135.000000) translate(-8.500035, -7.500035) "
/>
</g>
</svg>
);

export const ElbowArrowIcon = createIcon(
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" version="1.1">
<g stroke="none" fill="currentColor">
<path d="M10.0153197,2.75391207 C10.0923746,2.75391207 10.1683869,2.77172133 10.2374222,2.80594949 L15.4910739,5.41074126 C15.6395156,5.48433956 15.7001882,5.66433859 15.6265899,5.81278033 C15.5984006,5.86963592 15.5529079,5.91608792 15.4966529,5.9454574 L10.2467205,8.68632752 C10.0019308,8.81412664 9.69988791,8.71928704 9.57208878,8.47449735 C9.53479568,8.40306519 9.51531974,8.32367776 9.51531974,8.24309656 L9.51458753,6.62591207 L6.16858753,6.62651279 L6.16914066,12.0061269 C6.16914066,12.3043606 5.95155104,12.5517736 5.66646377,12.5982739 L5.56914066,12.6061269 L0.534587532,12.6061269 C0.203216682,12.6061269 -0.0654124678,12.3374977 -0.0654124678,12.0061269 C-0.0654124678,11.674756 0.203216682,11.4061269 0.534587532,11.4061269 L4.96858753,11.4055128 L4.96914066,6.02651279 C4.96914066,5.72827903 5.18673027,5.48086604 5.47181754,5.43436578 L5.56914066,5.42651279 L9.51458753,5.42591207 L9.51531974,3.25391207 C9.51531974,2.9777697 9.73917736,2.75391207 10.0153197,2.75391207 Z" />
</g>
</svg>
);

export const CurveArrowIcon = createIcon(
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" version="1.1">
<g stroke="none" fill="currentColor">
<path d="M10.0153197,2.75391207 C10.0923746,2.75391207 10.1683869,2.77172133 10.2374222,2.80594949 L15.4910739,5.41074126 C15.6395156,5.48433956 15.7001882,5.66433859 15.6265899,5.81278033 C15.5984006,5.86963592 15.5529079,5.91608792 15.4966529,5.9454574 L10.2467205,8.68632752 C10.0019308,8.81412664 9.69988791,8.71928704 9.57208878,8.47449735 C9.53479568,8.40306519 9.51531974,8.32367776 9.51531974,8.24309656 L9.51423005,6.39035523 C5.97984781,6.85936966 3.21691607,9.08498364 1.18879108,13.1285821 C1.04022695,13.4247836 0.679673152,13.5444674 0.383471635,13.3959033 C0.0872701176,13.2473391 -0.0324136308,12.8867853 0.116150501,12.5905838 C2.34388813,8.14900524 5.48945543,5.65776043 9.51468497,5.18078677 L9.51531974,3.25391207 C9.51531974,2.9777697 9.73917736,2.75391207 10.0153197,2.75391207 Z" />
</g>
</svg>
);
Empty file.
Original file line number Diff line number Diff line change
@@ -3,12 +3,6 @@ import { Island } from './island';
import Stack from './stack';
import { ToolButton } from './tool-button';
import {
HandIcon,
MindIcon,
SelectionIcon,
ShapeIcon,
TextIcon,
StraightArrowLineIcon,
RectangleIcon,
EllipseIcon,
TriangleIcon,
@@ -19,8 +13,6 @@ import {
import { useBoard } from '@plait/react-board';
import { BoardTransforms, PlaitBoard } from '@plait/core';
import * as Popover from '@radix-ui/react-popover';

import './shape-picker.scss';
import React from 'react';
import { DrawnixPointerType } from '../drawnix';
import { BoardCreationMode, setCreationMode } from '@plait/common';
@@ -75,16 +67,13 @@ const SHAPES: ShapeProps[] = [

const ROW_SHAPES = splitRows(SHAPES, 5);

export type ShapePickerProps = {};

export const ShapePickerPopupContent: React.FC<ShapePickerProps> = () => {
export const ShapePopupContent: React.FC = () => {
const board = useBoard();
const container = PlaitBoard.getBoardContainer(board);

const onPointerDown = (pointer: DrawnixPointerType) => {
setCreationMode(board, BoardCreationMode.dnd);
BoardTransforms.updatePointerType(board, pointer);
// setPointer(pointer);
};

const onPointerUp = () => {
@@ -96,14 +85,14 @@ export const ShapePickerPopupContent: React.FC<ShapePickerProps> = () => {
<Popover.Content sideOffset={12}>
<Island padding={1}>
<Stack.Col gap={1}>
{ROW_SHAPES.map((shapes, rowIndex) => {
{ROW_SHAPES.map((rowShapes, rowIndex) => {
return (
<Stack.Row gap={1} key={rowIndex}>
{shapes.map((shape, index) => {
{rowShapes.map((shape, index) => {
return (
<ToolButton
key={index}
className={classNames('Shape', { fillable: false })}
className={classNames({ fillable: false })}
type="icon"
size={'small'}
visible={true}

0 comments on commit a4195f7

Please sign in to comment.