Skip to content

Commit

Permalink
Merge pull request #87 from Lemoncode/feature/#66-z-index-properties
Browse files Browse the repository at this point in the history
Feature/#66 z index properties
  • Loading branch information
brauliodiez authored Jul 31, 2024
2 parents e1a92d2 + 7387052 commit 5377768
Show file tree
Hide file tree
Showing 17 changed files with 275 additions and 53 deletions.
28 changes: 28 additions & 0 deletions src/common/components/icons/bring-forward-icon.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const BringForwardIcon = () => {
return (
<svg
id="icon"
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 32 32"
>
<path d="M12,15H10V12a2.0023,2.0023,0,0,1,2-2h3v2H12Z" />
<path d="M15,30H12a2.0023,2.0023,0,0,1-2-2V25h2v3h3Z" />
<rect x="18" y="28" width="4" height="2" />
<path d="M28,30H25V28h3V25h2v3A2.0023,2.0023,0,0,1,28,30Z" />
<rect x="10" y="18" width="2" height="4" />
<rect x="28" y="18" width="2" height="4" />
<path d="M30,15H28V12H25V10h3a2.0023,2.0023,0,0,1,2,2Z" />
<rect x="18" y="10" width="4" height="2" />
<path d="M8,22H4a2.0023,2.0023,0,0,1-2-2V4A2.0023,2.0023,0,0,1,4,2H20a2.0023,2.0023,0,0,1,2,2V8H20V4H4V20H8Z" />
<rect
id="_Transparent_Rectangle_"
data-name="&lt;Transparent Rectangle&gt;"
width="1.2em"
height="1.2em"
fill="none"
/>
</svg>
);
};
20 changes: 20 additions & 0 deletions src/common/components/icons/bring-to-front-icon.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const BringToFrontIcon = () => {
return (
<svg
id="icon"
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 32 32"
>
<path d="M28,10H22V4a2.0023,2.0023,0,0,0-2-2H4A2.0023,2.0023,0,0,0,2,4V20a2.0023,2.0023,0,0,0,2,2h6v6a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V12A2,2,0,0,0,28,10ZM4,20,3.9985,4H20v6H12a2,2,0,0,0-2,2v8Z" />
<rect
id="_Transparent_Rectangle_"
data-name="&lt;Transparent Rectangle&gt;"
width="1.2em"
height="1.2em"
fill="none"
/>
</svg>
);
};
4 changes: 4 additions & 0 deletions src/common/components/icons/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
export * from './about-icon.component';
export * from './bring-forward-icon.component';
export * from './bring-to-front-icon.component';
export * from './send-backward-icon.component';
export * from './send-to-back-icon.component';
25 changes: 25 additions & 0 deletions src/common/components/icons/send-backward-icon.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export const SendBackwardIcon = () => {
return (
<svg
id="icon"
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 32 32"
>
<path d="M4,7H2V4A2.0023,2.0023,0,0,1,4,2H7V4H4Z" />
<path d="M7,22H4a2.0023,2.0023,0,0,1-2-2V17H4v3H7Z" />
<rect x="2" y="10" width="2" height="4" />
<path d="M22,7H20V4H17V2h3a2.0023,2.0023,0,0,1,2,2Z" />
<rect x="10" y="2" width="4" height="2" />
<path d="M28,30H12a2.0023,2.0023,0,0,1-2-2V12a2.0023,2.0023,0,0,1,2-2H28a2.0023,2.0023,0,0,1,2,2V28A2.0023,2.0023,0,0,1,28,30ZM12,12V28H28V12Z" />
<rect
id="_Transparent_Rectangle_"
data-name="&lt;Transparent Rectangle&gt;"
width="1.2em"
height="1.2em"
fill="none"
/>
</svg>
);
};
20 changes: 20 additions & 0 deletions src/common/components/icons/send-to-back-icon.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const SendToBackIcon = () => {
return (
<svg
id="icon"
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 32 32"
>
<path d="M28,10H22V4a2,2,0,0,0-2-2H4A2,2,0,0,0,2,4V20a2,2,0,0,0,2,2h6v6a2.0023,2.0023,0,0,0,2,2H28a2.0023,2.0023,0,0,0,2-2V12A2.0023,2.0023,0,0,0,28,10ZM12,28V12H28l.0015,16Z" />
<rect
id="_Transparent_Rectangle_"
data-name="&lt;Transparent Rectangle&gt;"
width="1.2em"
height="1.2em"
fill="none"
/>
</svg>
);
};
3 changes: 3 additions & 0 deletions src/core/providers/canvas/canvas.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { ShapeModel, ShapeRefs, ShapeType } from '@/core/model';
import Konva from 'konva';
import { Node, NodeConfig } from 'konva/lib/Node';

export type ZIndexAction = 'top' | 'bottom' | 'up' | 'down';

export interface SelectionInfo {
transformerRef: React.RefObject<Konva.Transformer>;
shapeRefs: React.MutableRefObject<ShapeRefs>;
Expand All @@ -14,6 +16,7 @@ export interface SelectionInfo {
selectedShapeRef: React.MutableRefObject<Node<NodeConfig> | null>;
selectedShapeId: string;
selectedShapeType: ShapeType | null;
setZIndexOnSelected: (action: ZIndexAction) => void;
}

export interface CanvasContextModel {
Expand Down
3 changes: 2 additions & 1 deletion src/core/providers/canvas/canvas.provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import { ShapeModel } from '@/core/model';
import { CanvasContext } from './canvas.context';
import { useSelection } from './use-selection.hook';
import { ZIndexAction } from './canvas.model';

interface Props {
children: React.ReactNode;
Expand All @@ -12,7 +13,7 @@ export const CanvasProvider: React.FC<Props> = props => {
const [shapes, setShapes] = React.useState<ShapeModel[]>([]);
const [scale, setScale] = React.useState(1);

const selectionInfo = useSelection(shapes);
const selectionInfo = useSelection(shapes, setShapes);

return (
<CanvasContext.Provider
Expand Down
15 changes: 13 additions & 2 deletions src/core/providers/canvas/use-selection.hook.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { useEffect, useRef, useState } from 'react';
import Konva from 'konva';
import { ShapeModel, ShapeRefs, ShapeType } from '@/core/model';
import { SelectionInfo } from './canvas.model';
import { SelectionInfo, ZIndexAction } from './canvas.model';
import { performZIndexAction } from './zindex.util';

export const useSelection = (shapes: ShapeModel[]): SelectionInfo => {
export const useSelection = (
shapes: ShapeModel[],
setShapes: React.Dispatch<React.SetStateAction<ShapeModel[]>>
): SelectionInfo => {
const transformerRef = useRef<Konva.Transformer>(null);
const shapeRefs = useRef<ShapeRefs>({});
const selectedShapeRef = useRef<Konva.Node | null>(null);
Expand Down Expand Up @@ -41,6 +45,12 @@ export const useSelection = (shapes: ShapeModel[]): SelectionInfo => {
}
};

const setZIndexOnSelected = (action: ZIndexAction) => {
setShapes(prevShapes =>
performZIndexAction(selectedShapeId, action, prevShapes)
);
};

return {
transformerRef,
shapeRefs,
Expand All @@ -49,5 +59,6 @@ export const useSelection = (shapes: ShapeModel[]): SelectionInfo => {
selectedShapeRef,
selectedShapeId,
selectedShapeType,
setZIndexOnSelected,
};
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ShapeModel } from '@/core/model';
import { ZIndexAction } from './canvas.model';

// TOO Add Unit tests to all these methods: #65
export const moveZIndexToTop = (
const moveZIndexToTop = (
selectedShapeId: string,
shapeCollection: ShapeModel[]
): ShapeModel[] => {
Expand All @@ -16,7 +17,7 @@ export const moveZIndexToTop = (
: shapeCollection;
};

export const moveZIndexToBottom = (
const moveZIndexToBottom = (
selectedShapeId: string,
shapeCollection: ShapeModel[]
): ShapeModel[] => {
Expand All @@ -31,7 +32,7 @@ export const moveZIndexToBottom = (
: shapeCollection;
};

export const moveZIndexDownOneLevel = (
const moveZIndexDownOneLevel = (
selectedShapeId: string,
shapeCollection: ShapeModel[]
): ShapeModel[] => {
Expand All @@ -54,7 +55,7 @@ export const moveZIndexDownOneLevel = (
: shapeCollection;
};

export const moveZIndexTopOneLevel = (
const moveZIndexTopOneLevel = (
selectedShapeId: string,
shapeCollection: ShapeModel[]
): ShapeModel[] => {
Expand All @@ -76,3 +77,23 @@ export const moveZIndexTopOneLevel = (
]
: shapeCollection;
};

export const performZIndexAction = (
selectedShapeId: string,
action: ZIndexAction,
shapes: ShapeModel[]
): ShapeModel[] => {
switch (action) {
case 'top':
return moveZIndexToTop(selectedShapeId, shapes);
break;
case 'bottom':
return moveZIndexToBottom(selectedShapeId, shapes);
break;
case 'up':
return moveZIndexTopOneLevel(selectedShapeId, shapes);
break;
case 'down':
return moveZIndexDownOneLevel(selectedShapeId, shapes);
}
};
40 changes: 0 additions & 40 deletions src/pods/canvas/canvas.pod.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@ import { renderShapeComponent } from './shape-renderer';
import { useDropShape } from './use-drop-shape.hook';
import { useMonitorShape } from './use-monitor-shape.hook';
import classes from './canvas.pod.module.css';
import {
moveZIndexDownOneLevel,
moveZIndexToBottom,
moveZIndexTopOneLevel,
moveZIndexToTop,
} from './zindex.util';
import { ShapeModel } from '@/core/model';

export const CanvasPod = () => {
Expand Down Expand Up @@ -48,10 +42,6 @@ export const CanvasPod = () => {
);
};

const handleZIndexChange = (shapeCollection: ShapeModel[]) => {
setShapes(shapeCollection);
};

{
/* TODO: add other animation for isDraggerOver */
}
Expand All @@ -61,36 +51,6 @@ export const CanvasPod = () => {
ref={dropRef}
style={{ opacity: isDraggedOver ? 0.5 : 1 }}
>
{/*TODO: move buttons to app props panel*/}
<button
onClick={() =>
handleZIndexChange(moveZIndexToBottom(selectedShapeId, shapes))
}
>
Move to Bottom
</button>
<button
onClick={() =>
handleZIndexChange(moveZIndexToTop(selectedShapeId, shapes))
}
>
Move to Top
</button>
<button
onClick={() =>
handleZIndexChange(moveZIndexDownOneLevel(selectedShapeId, shapes))
}
>
Move to Bottom One Level
</button>
<button
onClick={() =>
handleZIndexChange(moveZIndexTopOneLevel(selectedShapeId, shapes))
}
>
Move to Top One Level
</button>

{/*TODO: move size to canvas provider?*/}
<Stage
width={3000}
Expand Down
15 changes: 15 additions & 0 deletions src/pods/properties/components/zindex/zindex-button.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import classes from './zindex-option.module.css';

interface ButtonProps {
onClick: () => void;
Icon: React.ComponentType;
}

export const ZIndexButton: React.FC<ButtonProps> = props => {
const { onClick, Icon } = props;
return (
<button onClick={onClick} className={classes.button}>
<Icon />
</button>
);
};
49 changes: 49 additions & 0 deletions src/pods/properties/components/zindex/zindex-option.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
SelectionInfo,
ZIndexAction,
} from '@/core/providers/canvas/canvas.model';
import classes from './zindex-option.module.css';
import {
BringForwardIcon,
BringToFrontIcon,
SendBackwardIcon,
SendToBackIcon,
} from '@/common/components/icons';
import { ZIndexButton } from './zindex-button.component';

interface LayerOption {
position: ZIndexAction;
Icon: React.ComponentType;
}

const layersOptions: LayerOption[] = [
{ position: 'top', Icon: BringToFrontIcon },
{ position: 'up', Icon: BringForwardIcon },
{ position: 'down', Icon: SendBackwardIcon },
{ position: 'bottom', Icon: SendToBackIcon },
];

interface Props {
selectionInfo: SelectionInfo;
}

export const ZIndexOptions: React.FC<Props> = props => {
const { selectionInfo } = props;

const handleZIndexChange = (position: ZIndexAction) => {
selectionInfo?.setZIndexOnSelected(position);
};

return (
<div className={classes.container}>
<p>Layering</p>
{layersOptions.map(({ position, Icon }) => (
<ZIndexButton
key={position}
onClick={() => handleZIndexChange(position)}
Icon={Icon}
/>
))}
</div>
);
};
31 changes: 31 additions & 0 deletions src/pods/properties/components/zindex/zindex-option.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.container {
display: flex;
gap: 0.5em;
align-items: center;
padding: var(--space-xs) var(--space-md);
border-bottom: 1px solid var(--primary-300);
}

.container :first-child {
flex: 1;
}

.button {
border: none;
color: var(--text-color);
background-color: inherit;
padding: var(--space-xs);
border-radius: var(--border-radius-s);
font-size: var(--fs-xs);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--space-s);
transition: all 0.3s ease-in-out;
cursor: pointer;
}

.button:hover {
background-color: var(--primary-100);
}
1 change: 1 addition & 0 deletions src/pods/properties/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './properties.pod';
Loading

0 comments on commit 5377768

Please sign in to comment.