From 6c8499309e942c43532d05f3788eada4636f03a6 Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Wed, 26 May 2021 11:34:10 +0100 Subject: [PATCH] Adds style panel, styles --- components/canvas/misc.tsx | 1 - components/editor.tsx | 22 +- components/panel.tsx | 7 +- components/shared.tsx | 2 +- components/style-panel/color-picker.tsx | 127 +++++++ components/style-panel/style-panel.tsx | 119 +++++++ lib/code/index.ts | 6 +- lib/code/rectangle.ts | 1 + lib/shape-utils/circle.tsx | 7 +- lib/shape-utils/dot.tsx | 5 + lib/shape-utils/ellipse.tsx | 9 +- lib/shape-utils/index.tsx | 7 + lib/shape-utils/line.tsx | 5 + lib/shape-utils/polyline.tsx | 5 + lib/shape-utils/ray.tsx | 5 + lib/shape-utils/rectangle.tsx | 16 +- .../{ShapeTest.tsx => utils-next.tsx} | 0 package.json | 5 +- state/commands/index.ts | 2 + state/commands/style.ts | 36 ++ state/data.ts | 60 ++-- state/state.ts | 172 +++++---- styles/stitches.config.ts | 1 + types.ts | 7 +- utils/utils.ts | 8 +- yarn.lock | 325 +++++++++++++++++- 26 files changed, 819 insertions(+), 141 deletions(-) create mode 100644 components/style-panel/color-picker.tsx create mode 100644 components/style-panel/style-panel.tsx rename lib/shape-utils/{ShapeTest.tsx => utils-next.tsx} (100%) create mode 100644 state/commands/style.ts diff --git a/components/canvas/misc.tsx b/components/canvas/misc.tsx index 7f2235f04..adc556e28 100644 --- a/components/canvas/misc.tsx +++ b/components/canvas/misc.tsx @@ -3,7 +3,6 @@ import styled from "styles" const DotCircle = styled("circle", { transform: "scale(var(--scale))", strokeWidth: "2", - fill: "#000", }) export { DotCircle } diff --git a/components/editor.tsx b/components/editor.tsx index 046376942..3be353162 100644 --- a/components/editor.tsx +++ b/components/editor.tsx @@ -6,6 +6,7 @@ import Toolbar from "./toolbar" import CodePanel from "./code-panel/code-panel" import ControlsPanel from "./controls-panel/controls-panel" import styled from "styles" +import StylePanel from "./style-panel/style-panel" export default function Editor() { useKeyboardEvents() @@ -20,6 +21,9 @@ export default function Editor() { + + + ) } @@ -32,11 +36,11 @@ const Layout = styled("div", { right: 0, display: "grid", gridTemplateRows: "40px 1fr 40px", - gridTemplateColumns: "auto 1fr", + gridTemplateColumns: "minmax(50%, 400px) 1fr auto", gridTemplateAreas: ` - "toolbar toolbar" - "leftPanels main" - "statusbar statusbar" + "toolbar toolbar toolbar" + "leftPanels main rightPanels" + "statusbar statusbar statusbar" `, }) @@ -47,3 +51,13 @@ const LeftPanels = styled("main", { padding: 8, gap: 8, }) + +const RightPanels = styled("main", { + display: "grid", + gridArea: "rightPanels", + gridTemplateRows: "auto", + height: "fit-content", + justifyContent: "flex-end", + padding: 8, + gap: 8, +}) diff --git a/components/panel.tsx b/components/panel.tsx index c772427d3..3c74c9989 100644 --- a/components/panel.tsx +++ b/components/panel.tsx @@ -13,7 +13,10 @@ export const Root = styled("div", { variants: { isOpen: { - true: {}, + true: { + width: "auto", + minWidth: 300, + }, false: { height: 34, width: 34, @@ -28,7 +31,7 @@ export const Layout = styled("div", { gridTemplateRows: "auto 1fr", gridAutoRows: "28px", height: "100%", - width: 560, + width: "100%", minWidth: "100%", maxWidth: 560, overflow: "hidden", diff --git a/components/shared.tsx b/components/shared.tsx index 3f806eb56..2860d0276 100644 --- a/components/shared.tsx +++ b/components/shared.tsx @@ -16,7 +16,7 @@ export const IconButton = styled("button", { cursor: "pointer", "&:hover:not(:disabled)": { - backgroundColor: "$panel", + backgroundColor: "$hover", }, "&:disabled": { diff --git a/components/style-panel/color-picker.tsx b/components/style-panel/color-picker.tsx new file mode 100644 index 000000000..c958e3b03 --- /dev/null +++ b/components/style-panel/color-picker.tsx @@ -0,0 +1,127 @@ +import * as DropdownMenu from "@radix-ui/react-dropdown-menu" +import { Square } from "react-feather" +import { colors } from "state/data" +import styled from "styles" + +interface Props { + label: string + color: string + onChange: (color: string) => void +} + +export default function ColorPicker({ label, color, onChange }: Props) { + return ( + + +

{label}

+ +
+ + {Object.entries(colors).map(([name, color]) => ( + onChange(color)}> + + + ))} + +
+ ) +} + +function ColorIcon({ color }: { color: string }) { + return ( + + ) +} + +const Colors = styled(DropdownMenu.Content, { + display: "grid", + padding: 4, + gridTemplateColumns: "repeat(6, 1fr)", + border: "1px solid $border", + backgroundColor: "$panel", + borderRadius: 4, + boxShadow: "0px 5px 15px -5px hsla(206,22%,7%,.15)", +}) + +const ColorButton = styled(DropdownMenu.Item, { + position: "relative", + cursor: "pointer", + height: 32, + width: 32, + border: "none", + padding: "none", + background: "none", + display: "flex", + alignItems: "center", + justifyContent: "center", + + "&::before": { + content: "''", + position: "absolute", + top: 4, + left: 4, + right: 4, + bottom: 4, + pointerEvents: "none", + zIndex: 0, + }, + + "&:hover::before": { + backgroundColor: "$hover", + borderRadius: 4, + }, + + "& svg": { + position: "relative", + stroke: "rgba(0,0,0,.2)", + strokeWidth: 1, + zIndex: 1, + }, +}) + +const CurrentColor = styled(DropdownMenu.Trigger, { + position: "relative", + display: "flex", + width: "100%", + background: "none", + border: "none", + cursor: "pointer", + outline: "none", + alignItems: "center", + justifyContent: "space-between", + padding: "8px 8px 8px 12px", + + "&::before": { + content: "''", + position: "absolute", + top: 4, + left: 4, + right: 4, + bottom: 4, + pointerEvents: "none", + zIndex: -1, + }, + + "&:hover::before": { + backgroundColor: "$hover", + borderRadius: 4, + }, + + "& h3": { + fontFamily: "$ui", + fontSize: "$2", + fontWeight: "$1", + margin: 0, + padding: 0, + }, + + "& svg": { + position: "relative", + stroke: "rgba(0,0,0,.2)", + strokeWidth: 1, + zIndex: 1, + }, +}) diff --git a/components/style-panel/style-panel.tsx b/components/style-panel/style-panel.tsx new file mode 100644 index 000000000..e543fea5e --- /dev/null +++ b/components/style-panel/style-panel.tsx @@ -0,0 +1,119 @@ +import styled from "styles" +import state, { useSelector } from "state" +import * as Panel from "components/panel" +import { useRef } from "react" +import { IconButton } from "components/shared" +import { Circle, Square, Trash, X } from "react-feather" +import { deepCompare, deepCompareArrays, getSelectedShapes } from "utils/utils" +import { colors } from "state/data" + +import ColorPicker from "./color-picker" +import { ShapeByType, ShapeStyles } from "types" + +export default function StylePanel() { + const rContainer = useRef(null) + const isOpen = useSelector((s) => s.data.settings.isStyleOpen) + + return ( + + {isOpen ? ( + + ) : ( + state.send("TOGGLED_STYLE_PANEL_OPEN")}> + + + )} + + ) +} + +// This panel is going to be hard to keep cool, as we're selecting computed +// information, based on the user's current selection. We might have to keep +// track of this data manually within our state. + +function SelectedShapeStyles({}: {}) { + const selectedIds = useSelector( + (s) => Array.from(s.data.selectedIds.values()), + deepCompareArrays + ) + + const shapesStyle = useSelector((s) => { + const { currentStyle } = s.data + const shapes = getSelectedShapes(s.data) + + if (shapes.length === 0) { + return currentStyle + } + + const style: Partial = {} + const overrides = new Set([]) + + for (const shape of shapes) { + for (let key in currentStyle) { + if (overrides.has(key)) continue + if (style[key] === undefined) { + style[key] = shape.style[key] + } else { + if (style[key] === shape.style[key]) continue + style[key] = currentStyle[key] + overrides.add(key) + } + } + } + + return style + }, deepCompare) + + return ( + + + state.send("TOGGLED_STYLE_PANEL_OPEN")}> + + +

Style

+ + state.send("DELETED")}> + + + +
+ + + state.send("CHANGED_STYLE", { fill: color })} + /> + state.send("CHANGED_STYLE", { stroke: color })} + /> + + +
+ ) +} + +const StylePanelRoot = styled(Panel.Root, { + maxWidth: 260, + position: "relative", + + variants: { + isOpen: { + true: { + width: "auto", + minWidth: 300, + }, + false: { + height: 34, + width: 34, + }, + }, + }, +}) + +const ColorsRow = styled("div", { + display: "grid", + gridTemplateColumns: "1fr 1fr", +}) diff --git a/lib/code/index.ts b/lib/code/index.ts index a3bc45293..b22548c78 100644 --- a/lib/code/index.ts +++ b/lib/code/index.ts @@ -29,12 +29,12 @@ export default class CodeShape { } moveTo(point: Vector) { - this.utils.translate(this._shape, vectorToPoint(point)) + this.utils.translateTo(this._shape, vectorToPoint(point)) return this } translate(delta: Vector) { - this.utils.translate( + this.utils.translateTo( this._shape, vec.add(this._shape.point, vectorToPoint(delta)) ) @@ -42,7 +42,7 @@ export default class CodeShape { } rotate(rotation: number) { - this.utils.rotate(this._shape, rotation) + this.utils.rotateTo(this._shape, rotation) return this } diff --git a/lib/code/rectangle.ts b/lib/code/rectangle.ts index f2edc525d..bd7d8ba19 100644 --- a/lib/code/rectangle.ts +++ b/lib/code/rectangle.ts @@ -18,6 +18,7 @@ export default class Rectangle extends CodeShape { point: [0, 0], size: [100, 100], rotation: 0, + radius: 2, style: { fill: "#c6cacb", stroke: "#000", diff --git a/lib/shape-utils/circle.tsx b/lib/shape-utils/circle.tsx index ebf3f6942..098ff4254 100644 --- a/lib/shape-utils/circle.tsx +++ b/lib/shape-utils/circle.tsx @@ -20,7 +20,7 @@ const circle = registerShapeUtils({ childIndex: 0, point: [0, 0], rotation: 0, - radius: 20, + radius: 1, style: { fill: "#c6cacb", stroke: "#000", @@ -33,6 +33,11 @@ const circle = registerShapeUtils({ return }, + applyStyles(shape, style) { + Object.assign(shape.style, style) + return this + }, + getBounds(shape) { if (!this.boundsCache.has(shape)) { const { radius } = shape diff --git a/lib/shape-utils/dot.tsx b/lib/shape-utils/dot.tsx index 757c02820..cba7cf8b9 100644 --- a/lib/shape-utils/dot.tsx +++ b/lib/shape-utils/dot.tsx @@ -32,6 +32,11 @@ const dot = registerShapeUtils({ return }, + applyStyles(shape, style) { + Object.assign(shape.style, style) + return this + }, + getBounds(shape) { if (!this.boundsCache.has(shape)) { const bounds = { diff --git a/lib/shape-utils/ellipse.tsx b/lib/shape-utils/ellipse.tsx index 7ad6446ae..6e7e57d55 100644 --- a/lib/shape-utils/ellipse.tsx +++ b/lib/shape-utils/ellipse.tsx @@ -24,8 +24,8 @@ const ellipse = registerShapeUtils({ parentId: "page0", childIndex: 0, point: [0, 0], - radiusX: 20, - radiusY: 20, + radiusX: 1, + radiusY: 1, rotation: 0, style: { fill: "#c6cacb", @@ -41,6 +41,11 @@ const ellipse = registerShapeUtils({ ) }, + applyStyles(shape, style) { + Object.assign(shape.style, style) + return this + }, + getBounds(shape) { if (!this.boundsCache.has(shape)) { const { radiusX, radiusY } = shape diff --git a/lib/shape-utils/index.tsx b/lib/shape-utils/index.tsx index c431952b0..054b407d7 100644 --- a/lib/shape-utils/index.tsx +++ b/lib/shape-utils/index.tsx @@ -7,6 +7,7 @@ import { Corner, Edge, ShapeByType, + ShapeStyles, } from "types" import circle from "./circle" import dot from "./dot" @@ -40,6 +41,12 @@ export interface ShapeUtility> { // Create a new shape. create(props: Partial): K + applyStyles( + this: ShapeUtility, + shape: K, + style: ShapeStyles + ): ShapeUtility + // Set the shape's point. translateTo(this: ShapeUtility, shape: K, delta: number[]): ShapeUtility diff --git a/lib/shape-utils/line.tsx b/lib/shape-utils/line.tsx index eec8f7763..dfe7c80d2 100644 --- a/lib/shape-utils/line.tsx +++ b/lib/shape-utils/line.tsx @@ -41,6 +41,11 @@ const line = registerShapeUtils({ ) }, + applyStyles(shape, style) { + Object.assign(shape.style, style) + return this + }, + getBounds(shape) { if (!this.boundsCache.has(shape)) { const bounds = { diff --git a/lib/shape-utils/polyline.tsx b/lib/shape-utils/polyline.tsx index 8703a57b2..b6019283c 100644 --- a/lib/shape-utils/polyline.tsx +++ b/lib/shape-utils/polyline.tsx @@ -33,6 +33,11 @@ const polyline = registerShapeUtils({ return }, + applyStyles(shape, style) { + Object.assign(shape.style, style) + return this + }, + getBounds(shape) { if (!this.boundsCache.has(shape)) { const bounds = getBoundsFromPoints(shape.points) diff --git a/lib/shape-utils/ray.tsx b/lib/shape-utils/ray.tsx index 9f9017586..750eb648f 100644 --- a/lib/shape-utils/ray.tsx +++ b/lib/shape-utils/ray.tsx @@ -41,6 +41,11 @@ const ray = registerShapeUtils({ ) }, + applyStyles(shape, style) { + Object.assign(shape.style, style) + return this + }, + getRotatedBounds(shape) { return this.getBounds(shape) }, diff --git a/lib/shape-utils/rectangle.tsx b/lib/shape-utils/rectangle.tsx index 3af8a9ee6..a0c98f313 100644 --- a/lib/shape-utils/rectangle.tsx +++ b/lib/shape-utils/rectangle.tsx @@ -22,6 +22,7 @@ const rectangle = registerShapeUtils({ childIndex: 0, point: [0, 0], size: [1, 1], + radius: 2, rotation: 0, style: { fill: "#c6cacb", @@ -31,10 +32,16 @@ const rectangle = registerShapeUtils({ } }, - render({ id, size, parentId, childIndex }) { + render({ id, size, radius, childIndex }) { return ( - + ({ ) }, + applyStyles(shape, style) { + Object.assign(shape.style, style) + return this + }, + getBounds(shape) { if (!this.boundsCache.has(shape)) { const [width, height] = shape.size diff --git a/lib/shape-utils/ShapeTest.tsx b/lib/shape-utils/utils-next.tsx similarity index 100% rename from lib/shape-utils/ShapeTest.tsx rename to lib/shape-utils/utils-next.tsx diff --git a/package.json b/package.json index 592c7d63f..3c75afe29 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ }, "dependencies": { "@monaco-editor/react": "^4.1.3", + "@radix-ui/react-dropdown-menu": "^0.0.19", "@state-designer/react": "^1.7.1", "@stitches/react": "^0.1.9", "framer-motion": "^4.1.16", @@ -16,15 +17,15 @@ "next": "10.2.0", "perfect-freehand": "^0.4.7", "prettier": "^2.3.0", + "react": "17.0.2", "react-dom": "17.0.2", "react-feather": "^2.0.9", - "react": "17.0.2", "uuid": "^8.3.2" }, "devDependencies": { "@types/next": "^9.0.0", - "@types/react-dom": "^17.0.3", "@types/react": "^17.0.5", + "@types/react-dom": "^17.0.3", "@types/uuid": "^8.3.0", "cypress": "^7.3.0", "monaco-editor": "^0.24.0", diff --git a/state/commands/index.ts b/state/commands/index.ts index a64a04744..6556cc486 100644 --- a/state/commands/index.ts +++ b/state/commands/index.ts @@ -5,6 +5,7 @@ import generate from "./generate" import direct from "./direct" import rotate from "./rotate" import move from "./move" +import style from "./style" import deleteSelected from "./delete-selected" const commands = { @@ -15,6 +16,7 @@ const commands = { direct, rotate, move, + style, deleteSelected, } diff --git a/state/commands/style.ts b/state/commands/style.ts new file mode 100644 index 000000000..3601997a8 --- /dev/null +++ b/state/commands/style.ts @@ -0,0 +1,36 @@ +import Command from "./command" +import history from "../history" +import { Data, ShapeStyles } from "types" +import { getPage, getSelectedShapes } from "utils/utils" +import { getShapeUtils } from "lib/shape-utils" +import { current } from "immer" + +export default function styleCommand(data: Data, styles: ShapeStyles) { + const { currentPageId } = data + const initialShapes = getSelectedShapes(current(data)) + + history.execute( + data, + new Command({ + name: "changed_style", + category: "canvas", + manualSelection: true, + do(data) { + const { shapes } = getPage(data, currentPageId) + + for (const { id } of initialShapes) { + const shape = shapes[id] + getShapeUtils(shape).applyStyles(shape, styles) + } + }, + undo(data) { + const { shapes } = getPage(data, currentPageId) + + for (const { id, style } of initialShapes) { + const shape = shapes[id] + getShapeUtils(shape).applyStyles(shape, style) + } + }, + }) + ) +} diff --git a/state/data.ts b/state/data.ts index 758185f4d..daf51a747 100644 --- a/state/data.ts +++ b/state/data.ts @@ -15,11 +15,6 @@ export const defaultDocument: Data["document"] = { childIndex: 3, point: [300, 300], direction: [0.5, 0.5], - style: { - fill: "#AAA", - stroke: "#c6cacb", - strokeWidth: 1, - }, }), // shape3: shapeUtils[ShapeType.Dot].create({ // id: "shape3", @@ -38,11 +33,6 @@ export const defaultDocument: Data["document"] = { childIndex: 1, point: [100, 600], radius: 50, - style: { - fill: "#AAA", - stroke: "#c6cacb", - strokeWidth: 1, - }, }), shape5: shapeUtils[ShapeType.Ellipse].create({ id: "shape5", @@ -51,11 +41,6 @@ export const defaultDocument: Data["document"] = { point: [400, 600], radiusX: 50, radiusY: 30, - style: { - fill: "#AAA", - stroke: "#c6cacb", - strokeWidth: 1, - }, }), // shape7: shapeUtils[ShapeType.Ellipse].create({ // id: "shape7", @@ -88,18 +73,18 @@ export const defaultDocument: Data["document"] = { // strokeLinejoin: "round", // }, // }), - shape1: shapeUtils[ShapeType.Rectangle].create({ - id: "shape1", - name: "Shape 1", - childIndex: 1, - point: [400, 600], - size: [200, 200], - style: { - fill: "#AAA", - stroke: "#c6cacb", - strokeWidth: 1, - }, - }), + // shape1: shapeUtils[ShapeType.Rectangle].create({ + // id: "shape1", + // name: "Shape 1", + // childIndex: 1, + // point: [400, 600], + // size: [200, 200], + // style: { + // fill: "#AAA", + // stroke: "#c6cacb", + // strokeWidth: 1, + // }, + // }), // shape6: shapeUtils[ShapeType.Line].create({ // id: "shape6", // name: "Shape 6", @@ -152,3 +137,24 @@ new Polyline({ }, }, } + +export const colors = { + transparent: "transparent", + white: "rgba(248, 249, 250, 1.000)", + lightGray: "rgba(224, 226, 230, 1.000)", + gray: "rgba(172, 181, 189, 1.000)", + darkGray: "rgba(52, 58, 64, 1.000)", + black: "rgba(0,0,0, 1.000)", + lime: "rgba(115, 184, 23, 1.000)", + green: "rgba(54, 178, 77, 1.000)", + teal: "rgba(9, 167, 120, 1.000)", + cyan: "rgba(14, 152, 173, 1.000)", + blue: "rgba(28, 126, 214, 1.000)", + indigo: "rgba(66, 99, 235, 1.000)", + violet: "rgba(112, 72, 232, 1.000)", + grape: "rgba(174, 62, 200, 1.000)", + pink: "rgba(214, 51, 108, 1.000)", + red: "rgba(240, 63, 63, 1.000)", + orange: "rgba(247, 103, 6, 1.000)", + yellow: "rgba(245, 159, 0, 1.000)", +} diff --git a/state/state.ts b/state/state.ts index 505c67d6a..9e0233145 100644 --- a/state/state.ts +++ b/state/state.ts @@ -1,18 +1,23 @@ import { createSelectorHook, createState } from "@state-designer/react" +import * as vec from "utils/vec" +import inputs from "./inputs" +import { colors, defaultDocument } from "./data" +import { createShape, getShapeUtils } from "lib/shape-utils" +import history from "state/history" +import * as Sessions from "./sessions" +import commands from "./commands" +import { updateFromCode } from "lib/code/generate" import { clamp, - getBoundsCenter, getChildren, getCommonBounds, + getCurrent, getPage, getSelectedBounds, - getSelectedShapes, getShape, - getSiblings, screenToWorld, setZoomCSS, } from "utils/utils" -import * as vec from "utils/vec" import { Data, PointerInfo, @@ -22,14 +27,8 @@ import { Edge, CodeControl, MoveType, + ShapeStyles, } from "types" -import inputs from "./inputs" -import { defaultDocument } from "./data" -import shapeUtilityMap, { getShapeUtils } from "lib/shape-utils" -import history from "state/history" -import * as Sessions from "./sessions" -import commands from "./commands" -import { updateFromCode } from "lib/code/generate" const initialData: Data = { isReadOnly: false, @@ -37,6 +36,11 @@ const initialData: Data = { fontSize: 13, isDarkMode: false, isCodeOpen: false, + isStyleOpen: false, + }, + currentStyle: { + fill: colors.lightGray, + stroke: colors.darkGray, }, camera: { point: [0, 0], @@ -71,6 +75,8 @@ const state = createState({ SELECTED_POLYLINE_TOOL: { unless: "isReadOnly", to: "polyline" }, SELECTED_RECTANGLE_TOOL: { unless: "isReadOnly", to: "rectangle" }, TOGGLED_CODE_PANEL_OPEN: "toggleCodePanel", + TOGGLED_STYLE_PANEL_OPEN: "toggleStylePanel", + CHANGED_STYLE: ["updateStyles", "applyStylesToSelection"], RESET_CAMERA: "resetCamera", ZOOMED_TO_FIT: "zoomCameraToFit", ZOOMED_TO_SELECTION: { @@ -442,48 +448,23 @@ const state = createState({ }, }, results: { - // Dot - newDot(data, payload: PointerInfo) { - return shapeUtilityMap[ShapeType.Dot].create({ - point: screenToWorld(payload.point, data), - }) + newDot() { + return ShapeType.Dot }, - - // Ray - newRay(data, payload: PointerInfo) { - return shapeUtilityMap[ShapeType.Ray].create({ - point: screenToWorld(payload.point, data), - }) + newRay() { + return ShapeType.Ray }, - - // Line - newLine(data, payload: PointerInfo) { - return shapeUtilityMap[ShapeType.Line].create({ - point: screenToWorld(payload.point, data), - direction: [0, 1], - }) + newLine() { + return ShapeType.Line }, - - newCircle(data, payload: PointerInfo) { - return shapeUtilityMap[ShapeType.Circle].create({ - point: screenToWorld(payload.point, data), - radius: 1, - }) + newCircle() { + return ShapeType.Circle }, - - newEllipse(data, payload: PointerInfo) { - return shapeUtilityMap[ShapeType.Ellipse].create({ - point: screenToWorld(payload.point, data), - radiusX: 1, - radiusY: 1, - }) + newEllipse() { + return ShapeType.Ellipse }, - - newRectangle(data, payload: PointerInfo) { - return shapeUtilityMap[ShapeType.Rectangle].create({ - point: screenToWorld(payload.point, data), - size: [1, 1], - }) + newRectangle() { + return ShapeType.Rectangle }, }, conditions: { @@ -528,7 +509,12 @@ const state = createState({ }, actions: { /* --------------------- Shapes --------------------- */ - createShape(data, payload, shape: Shape) { + createShape(data, payload, type: ShapeType) { + const shape = createShape(type, { + point: screenToWorld(payload.point, data), + style: getCurrent(data.currentStyle), + }) + const siblings = getChildren(data, shape.parentId) const childIndex = siblings.length ? siblings[siblings.length - 1].childIndex + 1 @@ -710,41 +696,6 @@ const state = createState({ document.documentElement.style.setProperty("--camera-zoom", "1") }, - zoomCameraToSelection(data) { - const { camera } = data - - const bounds = getSelectedBounds(data) - - const zoom = - bounds.width < bounds.height - ? (window.innerWidth - 128) / bounds.width - : (window.innerHeight - 128) / bounds.height - - const mx = window.innerWidth - bounds.width * zoom - const my = window.innerHeight - bounds.height * zoom - - camera.zoom = zoom - - camera.point = vec.add( - [-bounds.minX, -bounds.minY], - [mx / 2 / zoom, my / 2 / zoom] - ) - - setZoomCSS(camera.zoom) - }, - zoomCameraToSelectionActual(data) { - const { camera } = data - - const bounds = getSelectedBounds(data) - - const mx = window.innerWidth - bounds.width - const my = window.innerHeight - bounds.height - - camera.zoom = 1 - - camera.point = vec.add([-bounds.minX, -bounds.minY], [mx / 2, my / 2]) - setZoomCSS(camera.zoom) - }, zoomCameraToActual(data) { const { camera } = data @@ -757,6 +708,37 @@ const state = createState({ setZoomCSS(camera.zoom) }, + zoomCameraToSelectionActual(data) { + const { camera } = data + + const bounds = getSelectedBounds(data) + + const mx = (window.innerWidth - bounds.width) / 2 + const my = (window.innerHeight - bounds.height) / 2 + + camera.zoom = 1 + camera.point = vec.add([-bounds.minX, -bounds.minY], [mx, my]) + + setZoomCSS(camera.zoom) + }, + zoomCameraToSelection(data) { + const { camera } = data + + const bounds = getSelectedBounds(data) + + const zoom = + bounds.width > bounds.height + ? (window.innerWidth - 128) / bounds.width + : (window.innerHeight - 128) / bounds.height + + const mx = (window.innerWidth - bounds.width * zoom) / 2 / zoom + const my = (window.innerHeight - bounds.height * zoom) / 2 / zoom + + camera.zoom = zoom + camera.point = vec.add([-bounds.minX, -bounds.minY], [mx, my]) + + setZoomCSS(camera.zoom) + }, zoomCameraToFit(data) { const { camera } = data const page = getPage(data) @@ -774,7 +756,7 @@ const state = createState({ ) const zoom = - bounds.width < bounds.height + bounds.width > bounds.height ? (window.innerWidth - 128) / bounds.width : (window.innerHeight - 128) / bounds.height @@ -788,12 +770,10 @@ const state = createState({ }, zoomCamera(data, payload: { delta: number; point: number[] }) { const { camera } = data + const next = camera.zoom - (payload.delta / 100) * camera.zoom + const p0 = screenToWorld(payload.point, data) - camera.zoom = clamp( - camera.zoom - (payload.delta / 100) * camera.zoom, - 0.1, - 3 - ) + camera.zoom = clamp(next, 0.1, 3) const p1 = screenToWorld(payload.point, data) camera.point = vec.add(camera.point, vec.sub(p1, p0)) @@ -832,6 +812,18 @@ const state = createState({ history.redo(data) }, + /* --------------------- Styles --------------------- */ + + toggleStylePanel(data) { + data.settings.isStyleOpen = !data.settings.isStyleOpen + }, + updateStyles(data, payload: Partial) { + Object.assign(data.currentStyle, payload) + }, + applyStylesToSelection(data, payload: Partial) { + commands.style(data, payload) + }, + /* ---------------------- Code ---------------------- */ closeCodePanel(data) { data.settings.isCodeOpen = false diff --git a/styles/stitches.config.ts b/styles/stitches.config.ts index 34cf15186..097ed7471 100644 --- a/styles/stitches.config.ts +++ b/styles/stitches.config.ts @@ -14,6 +14,7 @@ const { styled, global, css, theme, getCssString } = createCss({ boundsBg: "rgba(65, 132, 244, 0.100)", border: "#aaa", panel: "#fefefe", + hover: "#efefef", text: "#000", input: "#f3f3f3", inputBorder: "#ddd", diff --git a/types.ts b/types.ts index ca4ab53b6..14344687b 100644 --- a/types.ts +++ b/types.ts @@ -12,7 +12,9 @@ export interface Data { fontSize: number isDarkMode: boolean isCodeOpen: boolean + isStyleOpen: boolean } + currentStyle: ShapeStyles camera: { point: number[] zoom: number @@ -59,6 +61,8 @@ export enum ShapeType { // Cubic = "cubic", // Conic = "conic", +export type ShapeStyles = Partial> + export interface BaseShape { id: string type: ShapeType @@ -68,7 +72,7 @@ export interface BaseShape { name: string point: number[] rotation: number - style: Partial> + style: ShapeStyles } export interface DotShape extends BaseShape { @@ -104,6 +108,7 @@ export interface PolylineShape extends BaseShape { export interface RectangleShape extends BaseShape { type: ShapeType.Rectangle size: number[] + radius: number } export type MutableShape = diff --git a/utils/utils.ts b/utils/utils.ts index 30aa63b2d..88f8cb0b6 100644 --- a/utils/utils.ts +++ b/utils/utils.ts @@ -1,6 +1,6 @@ import Vector from "lib/code/vector" import React from "react" -import { Data, Bounds, Edge, Corner, Shape } from "types" +import { Data, Bounds, Edge, Corner, Shape, ShapeStyles } from "types" import * as vec from "./vec" import _isMobile from "ismobilejs" import { getShapeUtils } from "lib/shape-utils" @@ -1486,3 +1486,9 @@ export function forceIntegerChildIndices(shapes: Shape[]) { export function setZoomCSS(zoom: number) { document.documentElement.style.setProperty("--camera-zoom", zoom.toString()) } + +export function getCurrent(source: T): T { + return Object.fromEntries( + Object.entries(source).map(([key, value]) => [key, value]) + ) as T +} diff --git a/yarn.lock b/yarn.lock index 7a104c3be..d4d8846c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -879,7 +879,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.13.10", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== @@ -1259,6 +1259,258 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.14.0.tgz#c67fc20a4d891447ca1a855d7d70fa79a3533001" integrity sha512-sDOAZcYwynHFTbLo6n8kIbLiVF3a3BLkrmehJUyEbT9F+Smbi47kLGS2gG2g0fjBLR/Lr1InPD7kXL7FaTqEkw== +"@radix-ui/popper@0.0.10": + version "0.0.10" + resolved "https://registry.yarnpkg.com/@radix-ui/popper/-/popper-0.0.10.tgz#9f707d9cec8762423f81acaf8e650e40a554cb73" + integrity sha512-YFKuPqQPKscreQid7NuB4it3PMzSwGg03vgrud6sVliHkI43QNAOHyrHyMNo015jg6QK5GVDn+7J2W5uygqSGA== + dependencies: + "@babel/runtime" "^7.13.10" + csstype "^3.0.4" + +"@radix-ui/primitive@0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-0.0.5.tgz#8464fb4db04401bde72d36e27e05714080668d40" + integrity sha512-VeL6A5LpKYRJhDDj5tCTnzP3zm+FnvybsAkgBHQ4LUPPBnqRdWLoyKpZhlwFze/z22QHINaTIcE9Z/fTcrUR1g== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-arrow@0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-0.0.13.tgz#06b5a17f33bbc1af1c88d2827f25f37be95daa38" + integrity sha512-BHBAULgQYmj36BrJ+1AGhC5p4QjJaE+szJgJ1a1EYOM3G6QOeIQKYvIm8TPEdKAiJhAivK+jZFccsE4Blzqc9g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-polymorphic" "0.0.11" + "@radix-ui/react-primitive" "0.0.13" + +"@radix-ui/react-collection@0.0.12": + version "0.0.12" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-0.0.12.tgz#5cd09312cdec34fdbbe1d31affaba69eb768e342" + integrity sha512-jUP99/wCHpXm7ytbmpcjhhxFHBsr2lptEzKO8DUkD2CrJBS4Q3XHMKBDOvNQQzIqJhsz0A5JP6Fo0Vgd8Ld3FQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "0.0.5" + "@radix-ui/react-slot" "0.0.10" + +"@radix-ui/react-compose-refs@0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-0.0.5.tgz#0f71f0de1dec341f30cebd420b6bc3d12a3037dd" + integrity sha512-O9mH9X/2EwuAEEoZXrU4alcrRbAhhZHGpIJ5bOH6rmRcokhaoWRBY1tOEe2lgHdb/bkKrY+viLi4Zq8Ju6/09Q== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-context@0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-0.0.5.tgz#7c15f46795d7765dabfaf6f9c53791ad28c521c2" + integrity sha512-bwrzAc0qc2EPepSTLBT4+93uCiI9wP78VSmPg2K+k71O/vpx7dPs0VqrewwCBNCHT54NIwaRr2hEsm2uqYi02A== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-dismissable-layer@0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.0.13.tgz#7c4be6170a14d8a66c48680a8a8c987bc29bcf05" + integrity sha512-g0zhxdZzCJhVeRumaU8ODptRFhYorSRPsLwD30sz9slYaW0yg6lHvMQicRNtgFX0WnsbmrUVY6NMrwWpSHJXbg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-body-pointer-events" "0.0.6" + "@radix-ui/react-use-callback-ref" "0.0.5" + "@radix-ui/react-use-escape-keydown" "0.0.6" + +"@radix-ui/react-dropdown-menu@^0.0.19": + version "0.0.19" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.0.19.tgz#fbc3106bcda65d3060b280f4af3a9c45324ab474" + integrity sha512-7UhT6PIXl9fr8Ai9DkXMtxPNQFh8emrklgY5jcad9NHKWAztgfL6Fm+Ns0GEYUkd5OpJLEaIj/EUkwFM73SrGw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.0.5" + "@radix-ui/react-compose-refs" "0.0.5" + "@radix-ui/react-context" "0.0.5" + "@radix-ui/react-id" "0.0.6" + "@radix-ui/react-menu" "0.0.18" + "@radix-ui/react-polymorphic" "0.0.11" + "@radix-ui/react-primitive" "0.0.13" + "@radix-ui/react-use-controllable-state" "0.0.6" + +"@radix-ui/react-focus-guards@0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-0.0.7.tgz#285ed081c877587acd4ee7e6d8260bdf9044e922" + integrity sha512-enAsmrUunptHVzPLTuZqwTP/X3WFBnyJ/jP9W+0g+bRvI3o7V1kxNc+T2Rp1eRTFBW+lUNnt08qkugPytyTRog== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-focus-scope@0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-0.0.13.tgz#06dd6781d457b272601d4c087ac1240907824443" + integrity sha512-PelAuc+7HSGruBraSzuHogwaKqCvmO288ecIm3cCAkrJqPQ7hoKSd/LfLfoa/EvjqK9azmm7NQ6LSPoteQvOGQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "0.0.5" + +"@radix-ui/react-id@0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.0.6.tgz#c4b27d11861805e91ac296e7758ab47e3947b65c" + integrity sha512-PzmraF34fYggsYvTIZVJ5S68WMp3aKUN3HkSmGnz4zn9zpRjkAbbg7Xn3ueQI3FQsLWKgyUfnpsmWFDndpcqYg== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-menu@0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-0.0.18.tgz#b36f7657eb6757c623ffc688c48a4781ffd82351" + integrity sha512-js5hFzoxNOnHV8g7RPoPl/GncUCW2aCOuNt9Qh6WznRmxmsETPUWZZe4kADJnZmYbIxG07EEl0iv3E1rmsqNMw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.0.5" + "@radix-ui/react-collection" "0.0.12" + "@radix-ui/react-compose-refs" "0.0.5" + "@radix-ui/react-context" "0.0.5" + "@radix-ui/react-dismissable-layer" "0.0.13" + "@radix-ui/react-focus-guards" "0.0.7" + "@radix-ui/react-focus-scope" "0.0.13" + "@radix-ui/react-polymorphic" "0.0.11" + "@radix-ui/react-popper" "0.0.16" + "@radix-ui/react-portal" "0.0.13" + "@radix-ui/react-presence" "0.0.14" + "@radix-ui/react-primitive" "0.0.13" + "@radix-ui/react-roving-focus" "0.0.13" + "@radix-ui/react-slot" "0.0.10" + "@radix-ui/react-use-callback-ref" "0.0.5" + aria-hidden "^1.1.1" + react-remove-scroll "^2.4.0" + +"@radix-ui/react-polymorphic@0.0.11": + version "0.0.11" + resolved "https://registry.yarnpkg.com/@radix-ui/react-polymorphic/-/react-polymorphic-0.0.11.tgz#23f26b14e67a0e57cd981c37618d603b952af80d" + integrity sha512-CztM4962esOx3i1ls6GuY9RBYIY2Df1Bmp5emHRTxZi8owyCZwZYPctYaDuMO0qIGikPiKD8HBion/m7VWUyEA== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-popper@0.0.16": + version "0.0.16" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-0.0.16.tgz#62cccb7d920dc89e076bbdc3421db8c84078f428" + integrity sha512-njciQ/eIKaDF9h+27Pwi1H6NliQbzTgaHOsT0w/Lxx4vfMe8zcHtiEigYVGErNR4zAYlbW72KzLjtngtNnaorg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/popper" "0.0.10" + "@radix-ui/react-arrow" "0.0.13" + "@radix-ui/react-compose-refs" "0.0.5" + "@radix-ui/react-context" "0.0.5" + "@radix-ui/react-polymorphic" "0.0.11" + "@radix-ui/react-primitive" "0.0.13" + "@radix-ui/react-use-rect" "0.0.7" + "@radix-ui/react-use-size" "0.0.6" + "@radix-ui/rect" "0.0.5" + +"@radix-ui/react-portal@0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-0.0.13.tgz#8e60e9ee9b1594f98ee4a8f24a9851ef7ef2ad31" + integrity sha512-Mw5hrxds2T9HTGwdDbvlKGvTUfcuKhPtqxLnizOrM685e80j+pfjAAfMSXSyfmra9KFQvk3XxmUP0d4U6+kzMg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-polymorphic" "0.0.11" + "@radix-ui/react-primitive" "0.0.13" + "@radix-ui/react-use-layout-effect" "0.0.5" + +"@radix-ui/react-presence@0.0.14": + version "0.0.14" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-0.0.14.tgz#6a86058bbbf46234dd8840dacd620b3ac5797025" + integrity sha512-ufof9B76DHXV0sC8H7Lswh2AepdJFG8qEtF32JWrbA9N1bl2Jnf9px76KsagyC0MA8crGEZO5A96wizGuSgGWQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "0.0.5" + +"@radix-ui/react-primitive@0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-0.0.13.tgz#79c606c3e7da9c377b77a7b3f4ec879b45de47a2" + integrity sha512-6xxWzw67t7ZuN9Ikn9NNQdb/HSF7dNHPN3kPcgjiVgTEZa3tKk1xjSxGjjQztE61g9GrnTLpu7mBjmEuZDI/lA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-polymorphic" "0.0.11" + +"@radix-ui/react-roving-focus@0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-0.0.13.tgz#c72f503832577979c4caa9efcfd59140730c2f80" + integrity sha512-jTx3TBMYEdj9SFzRDryO62M9ZK28pYvKKxj/mxWMpMbIjF4q6L+yJmDxtv6glHgCRkwBEyulFVGCjjDg+qxYRA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.0.5" + "@radix-ui/react-collection" "0.0.12" + "@radix-ui/react-compose-refs" "0.0.5" + "@radix-ui/react-context" "0.0.5" + "@radix-ui/react-id" "0.0.6" + "@radix-ui/react-polymorphic" "0.0.11" + "@radix-ui/react-primitive" "0.0.13" + "@radix-ui/react-use-callback-ref" "0.0.5" + "@radix-ui/react-use-controllable-state" "0.0.6" + +"@radix-ui/react-slot@0.0.10": + version "0.0.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-0.0.10.tgz#27a17cad7064872117aeb68113fa934bc5d34c37" + integrity sha512-p0jJj6lTz1RV2imavnclk8Gda002ZSDR4/zPJ4EQBhspGnx7Y8l6G59c8lxJrT7c7F46F2eRNjpTTjFqqir6EQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.0.5" + "@radix-ui/react-compose-refs" "0.0.5" + +"@radix-ui/react-use-body-pointer-events@0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.0.6.tgz#30b21301880417e7dbb345871ff5a83f2abe0d8d" + integrity sha512-ouYb7u1+K9TsiEcNs3HceNUBUgB2PV41EyD5O6y6ZPMxl1lW/QAy5dfyfJMRyaRWQ6kxwmGoKlCSb4uPTruzuQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "0.0.5" + +"@radix-ui/react-use-callback-ref@0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-0.0.5.tgz#fa8db050229cda573dfeeae213d74ef06f6130db" + integrity sha512-z1AI221vmq9f3vsDyrCsGLCatKagbM1YeCGdRMhMsUBzFFCaJ+Axyoe/ndVqW8wwsraGWr1zYVAhIEdlC0GvPg== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-controllable-state@0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-0.0.6.tgz#c4b16bc911a25889333388a684a04df937e5fec7" + integrity sha512-fBk4hUSKc4N7X/NAaifWYfKKfNuOB9xvj0MBQQYS5oOTNRgg4y8/Ax3jZ0adsplXDm7ix75sxqWm0nrvUoAjcw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "0.0.5" + +"@radix-ui/react-use-escape-keydown@0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-0.0.6.tgz#1ad1c81b99961b7dbe376ef54151ebc8bef627a0" + integrity sha512-MJpVj21BYwWllmp2xbXPqpKPssJ1WWrZi+Qx7PY5hVcBhQr5Jo6yKwIX677pH5Yql95ENTTT5LW3q+LVFYIISw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "0.0.5" + +"@radix-ui/react-use-layout-effect@0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.0.5.tgz#cbbd059090edc765749da00d9f562a9abd43cbac" + integrity sha512-bNPW2JNOr/p2hXr0hfKKqrEy5deNSRF17sw3l9Z7qlEnvIbBtQ7iwY/wrxIz5P7XFyYGoXodIUDH5G8PEucE3A== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-rect@0.0.7": + version "0.0.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-0.0.7.tgz#e3a55fa7183ef436042198787bf38f8c9befcc14" + integrity sha512-OmaeFTgyiGNAchaxzDu+kFLz4Ly8RUcT5nwfoz4Nddd86I8Zdq93iNFnOpVLoVYqBnFEmvR6zexHXNFATrMbbQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/rect" "0.0.5" + +"@radix-ui/react-use-size@0.0.6": + version "0.0.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-0.0.6.tgz#998eaf6e8871b868f81f3b7faac06c3e896c37a0" + integrity sha512-kP4RIb2I5oHQzwzXJ21Hu8htNqf+sdaRzywxQpbj+hmqeUhpvIkhoq+ShNWV9wE/3c1T7gPnka8/nKYsKaKdCg== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/rect@0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-0.0.5.tgz#6000d8d800288114af4bbc5863e6b58755d7d978" + integrity sha512-gXw171KbjyttA7K1DRIvPguLmKsg8raitB67MIcsdZwcquy+a1O2w3xY21NIKEqGhJwqJkECPUmMJDXgMNYuAg== + dependencies: + "@babel/runtime" "^7.13.10" + "@rollup/plugin-babel@^5.1.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz#9cb1c5146ddd6a4968ad96f209c50c62f92f9879" @@ -1731,6 +1983,13 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +aria-hidden@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.1.3.tgz#bb48de18dc84787a3c6eee113709c473c64ec254" + integrity sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA== + dependencies: + tslib "^1.0.0" + aria-query@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" @@ -2800,7 +3059,7 @@ cssstyle@^2.0.0: dependencies: cssom "~0.3.6" -csstype@^3.0.2: +csstype@^3.0.2, csstype@^3.0.4: version "3.0.8" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340" integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw== @@ -2993,6 +3252,11 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + diff-sequences@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" @@ -3818,6 +4082,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + get-orientation@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/get-orientation/-/get-orientation-1.1.2.tgz#20507928951814f8a91ded0a0e67b29dfab98947" @@ -4213,6 +4482,13 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -5349,7 +5625,7 @@ lolex@^5.0.0: dependencies: "@sinonjs/commons" "^1.7.0" -loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -6388,6 +6664,34 @@ react-refresh@0.8.3: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== +react-remove-scroll-bar@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.2.0.tgz#d4d545a7df024f75d67e151499a6ab5ac97c8cdd" + integrity sha512-UU9ZBP1wdMR8qoUs7owiVcpaPwsQxUDC2lypP6mmixaGlARZa7ZIBx1jcuObLdhMOvCsnZcvetOho0wzPa9PYg== + dependencies: + react-style-singleton "^2.1.0" + tslib "^1.0.0" + +react-remove-scroll@^2.4.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.4.2.tgz#5b7e3eb8c3389d3636234716d2feb618729fc4d9" + integrity sha512-mMSIZYQF3jS2uRJXeFDRaVGA+BGs/hIryV64YUKsHFtpgwZloOUcdu0oW8K6OU8uLHt/kM5d0lUZbdpIVwgXtQ== + dependencies: + react-remove-scroll-bar "^2.1.0" + react-style-singleton "^2.1.0" + tslib "^1.0.0" + use-callback-ref "^1.2.3" + use-sidecar "^1.0.1" + +react-style-singleton@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66" + integrity sha512-jNRp07Jza6CBqdRKNgGhT3u9umWvils1xsuMOjZlghBDH2MU0PL2WZor4PGYjXpnRCa9DQSlHMs/xnABWOwYbA== + dependencies: + get-nonce "^1.0.0" + invariant "^2.2.4" + tslib "^1.0.0" + react@17.0.2: version "17.0.2" resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" @@ -7696,7 +8000,7 @@ tslib@2.0.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== -tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.0.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -7880,6 +8184,19 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" +use-callback-ref@^1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5" + integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg== + +use-sidecar@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.5.tgz#ffff2a17c1df42e348624b699ba6e5c220527f2b" + integrity sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA== + dependencies: + detect-node-es "^1.1.0" + tslib "^1.9.3" + use-subscription@1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1"