From d0f202deab3e559f24c73a6dcd0149c467f6d2df Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Mon, 18 Apr 2022 15:35:45 +0900 Subject: [PATCH 01/67] init editor task queue state model --- editor/core/states/editor-state.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/editor/core/states/editor-state.ts b/editor/core/states/editor-state.ts index 855ec2f2..0ad5e552 100644 --- a/editor/core/states/editor-state.ts +++ b/editor/core/states/editor-state.ts @@ -28,6 +28,7 @@ export interface EditorState { code?: CodeRepository; editingModule?: EditingModule; devtoolsConsole?: DevtoolsConsole; + editorTaskQueue?: EditorTaskQueue; } export interface EditorSnapshot { @@ -131,3 +132,20 @@ export interface ConsoleLog { | "count" | "assert"; } + +export interface EditorTaskQueue { + isBusy: boolean; + tasks: EditorTask[]; +} + +export interface EditorTask { + id: string; + name: string; + description: string; + cancelable: boolean; + onCancel: () => void; + /** + * 0-1, if null, it is indeterminate + */ + progress: number | null; +} From d4e75821d1e135f0364dafe4a5ca8b50e59e9bef Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Mon, 18 Apr 2022 15:58:01 +0900 Subject: [PATCH 02/67] add action & reducer --- editor/core/actions/index.ts | 31 ++++++++++++++++++-- editor/core/reducers/editor-reducer.ts | 33 ++++++++++++++++++++++ editor/core/states/editor-initial-state.ts | 11 ++++++++ editor/core/states/editor-state.ts | 14 ++++++--- 4 files changed, 83 insertions(+), 6 deletions(-) diff --git a/editor/core/actions/index.ts b/editor/core/actions/index.ts index 54187be4..c537a789 100644 --- a/editor/core/actions/index.ts +++ b/editor/core/actions/index.ts @@ -1,5 +1,10 @@ import type { FrameworkConfig } from "@designto/config"; -import type { ConsoleLog, EditorState, ScenePreviewData } from "core/states"; +import type { + ConsoleLog, + EditorState, + EditorTask, + ScenePreviewData, +} from "core/states"; export type WorkspaceAction = // @@ -21,7 +26,8 @@ export type Action = | CanvasModeAction | PreviewAction | CodeEditorAction - | DevtoolsAction; + | DevtoolsAction + | EditorTaskAction; export type ActionType = Action["type"]; @@ -85,3 +91,24 @@ export interface DevtoolsConsoleAction { export interface DevtoolsConsoleClearAction { type: "devtools-console-clear"; } + +export type EditorTaskAction = + | EditorTaskPushAction + | EditorTaskPopAction + | EditorTaskUpdateProgressAction; + +export interface EditorTaskPushAction { + type: "editor-task-push"; + task: EditorTask; +} + +export interface EditorTaskPopAction { + type: "editor-task-pop"; + task: EditorTask | { id: string }; +} + +export interface EditorTaskUpdateProgressAction { + type: "editor-task-update-progress"; + id: string; + progress: number; +} diff --git a/editor/core/reducers/editor-reducer.ts b/editor/core/reducers/editor-reducer.ts index 91e2e05d..e6c89f25 100644 --- a/editor/core/reducers/editor-reducer.ts +++ b/editor/core/reducers/editor-reducer.ts @@ -10,6 +10,9 @@ import type { PreviewSetAction, DevtoolsConsoleAction, DevtoolsConsoleClearAction, + EditorTaskPushAction, + EditorTaskPopAction, + EditorTaskUpdateProgressAction, } from "core/actions"; import { EditorState } from "core/states"; import { useRouter } from "next/router"; @@ -184,6 +187,36 @@ export function editorReducer(state: EditorState, action: Action): EditorState { }); break; } + case "editor-task-push": { + const { task } = action; + const { id } = task; + // TODO: check id duplication + + return produce(state, (draft) => { + draft.editorTaskQueue.tasks.push(task); + }); + break; + } + case "editor-task-pop": { + const { task } = action; + const { id } = task; + + return produce(state, (draft) => { + draft.editorTaskQueue.tasks = draft.editorTaskQueue.tasks.filter( + (i) => i.id !== id + ); + // TODO: handle isBusy property by the task + }); + break; + } + case "editor-task-update-progress": { + const { id, progress } = action; + return produce(state, (draft) => { + draft.editorTaskQueue.tasks.find((i) => i.id !== id).progress = + progress; + }); + break; + } default: throw new Error(`Unhandled action type: ${action["type"]}`); } diff --git a/editor/core/states/editor-initial-state.ts b/editor/core/states/editor-initial-state.ts index 5ad68cf0..3b43d556 100644 --- a/editor/core/states/editor-initial-state.ts +++ b/editor/core/states/editor-initial-state.ts @@ -8,6 +8,7 @@ export function createInitialEditorState(editor: EditorSnapshot): EditorState { selectedLayersOnPreview: editor.selectedLayersOnPreview, design: editor.design, canvasMode: editor.canvasMode, + editorTaskQueue: editor.editorTaskQueue, }; } @@ -19,5 +20,15 @@ export function createPendingEditorState(): EditorState { selectedLayersOnPreview: [], design: null, canvasMode: "free", + editorTaskQueue: { + isBusy: true, + tasks: [ + { + id: "pending", + name: "loading", + progress: null, + }, + ], + }, }; } diff --git a/editor/core/states/editor-state.ts b/editor/core/states/editor-state.ts index 0ad5e552..f7cb99d5 100644 --- a/editor/core/states/editor-state.ts +++ b/editor/core/states/editor-state.ts @@ -28,7 +28,7 @@ export interface EditorState { code?: CodeRepository; editingModule?: EditingModule; devtoolsConsole?: DevtoolsConsole; - editorTaskQueue?: EditorTaskQueue; + editorTaskQueue: EditorTaskQueue; } export interface EditorSnapshot { @@ -38,6 +38,7 @@ export interface EditorSnapshot { selectedNodesInitial?: string[] | null; design: FigmaReflectRepository; canvasMode: TCanvasMode; + editorTaskQueue: EditorTaskQueue; } export interface FigmaReflectRepository { @@ -141,9 +142,14 @@ export interface EditorTaskQueue { export interface EditorTask { id: string; name: string; - description: string; - cancelable: boolean; - onCancel: () => void; + /** + * If the task is short-lived, wait this much ms before displaying it. + * @default 200 (0.2s) + */ + debounce?: number; + description?: string; + cancelable?: boolean; + onCancel?: () => void; /** * 0-1, if null, it is indeterminate */ From 504987743d18b42b5323ff0f89c9da769a4212d0 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Mon, 18 Apr 2022 16:17:48 +0900 Subject: [PATCH 03/67] add visual components (not tested) --- ...tor-progress-indicator-popover-content.tsx | 26 ++++++ ...itor-progress-indicator-trigger-button.tsx | 43 +++++++++ .../editor-progress-indicator.tsx | 27 ++++++ .../editor-task-item.tsx | 87 +++++++++++++++++++ .../editor-progress-indicator/index.ts | 4 + .../editor-progress-indicator/index.tsx | 12 +++ 6 files changed, 199 insertions(+) create mode 100644 editor/components/editor-progress-indicator/editor-progress-indicator-popover-content.tsx create mode 100644 editor/components/editor-progress-indicator/editor-progress-indicator-trigger-button.tsx create mode 100644 editor/components/editor-progress-indicator/editor-progress-indicator.tsx create mode 100644 editor/components/editor-progress-indicator/editor-task-item.tsx create mode 100644 editor/components/editor-progress-indicator/index.ts create mode 100644 editor/scaffolds/editor-progress-indicator/index.tsx diff --git a/editor/components/editor-progress-indicator/editor-progress-indicator-popover-content.tsx b/editor/components/editor-progress-indicator/editor-progress-indicator-popover-content.tsx new file mode 100644 index 00000000..2661ec87 --- /dev/null +++ b/editor/components/editor-progress-indicator/editor-progress-indicator-popover-content.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import styled from "@emotion/styled"; + +export function EditorProgressIndicatorPopoverContent({ + children, +}: { + children: React.ReactNode; +}) { + return {children}; +} + +const Container = styled.div` + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + flex: none; + gap: 32px; + box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.25); + border: solid 1px rgb(74, 73, 77); + border-radius: 12px; + background-color: rgba(30, 30, 30, 0.4); + box-sizing: border-box; + padding: 24px; + backdrop-filter: blur(32px); +`; diff --git a/editor/components/editor-progress-indicator/editor-progress-indicator-trigger-button.tsx b/editor/components/editor-progress-indicator/editor-progress-indicator-trigger-button.tsx new file mode 100644 index 00000000..00bfca80 --- /dev/null +++ b/editor/components/editor-progress-indicator/editor-progress-indicator-trigger-button.tsx @@ -0,0 +1,43 @@ +import React from "react"; +import styled from "@emotion/styled"; + +export function EditorProgressIndicatorButton({ + isBusy = false, +}: { + isBusy?: boolean; +}) { + return ( + + + + + {isBusy && } + + ); +} + +const Container = styled.div` + display: flex; + justify-content: flex-start; + flex-direction: column; + align-items: center; + flex: none; + gap: 2px; + box-sizing: border-box; +`; + +const IndicatorLine = styled.div` + width: 20px; + height: 4px; + background-color: rgb(37, 98, 255); + border-radius: 7px; +`; diff --git a/editor/components/editor-progress-indicator/editor-progress-indicator.tsx b/editor/components/editor-progress-indicator/editor-progress-indicator.tsx new file mode 100644 index 00000000..479f5162 --- /dev/null +++ b/editor/components/editor-progress-indicator/editor-progress-indicator.tsx @@ -0,0 +1,27 @@ +import React from "react"; +import styled from "@emotion/styled"; +import { EditorTaskItem } from "./editor-task-item"; +import { EditorProgressIndicatorButton } from "./editor-progress-indicator-trigger-button"; +import { EditorProgressIndicatorPopoverContent } from "./editor-progress-indicator-popover-content"; +import * as Popover from "@radix-ui/react-popover"; + +export function EditorProgressIndicator({ + isBusy, + tasks, +}: { + isBusy: boolean; + tasks: any[]; +}) { + return ( + + + + + + {tasks.map((task, index) => ( + + ))} + + + ); +} diff --git a/editor/components/editor-progress-indicator/editor-task-item.tsx b/editor/components/editor-progress-indicator/editor-task-item.tsx new file mode 100644 index 00000000..5e386398 --- /dev/null +++ b/editor/components/editor-progress-indicator/editor-task-item.tsx @@ -0,0 +1,87 @@ +import React from "react"; +import styled from "@emotion/styled"; + +export function EditorTaskItem({ + label, + description, +}: { + label: string; + description?: string; +}) { + return ( + + + {label} + + + + + {description} + + ); +} + +const RootWrapperProgressingItemReadonly = styled.div` + display: flex; + justify-content: center; + flex-direction: column; + align-items: flex-start; + flex: none; + gap: 4px; + min-height: 100vh; + box-sizing: border-box; +`; + +const TitleAndValueContainer = styled.div` + display: flex; + justify-content: flex-start; + flex-direction: row; + align-items: center; + gap: 4px; + align-self: stretch; + box-sizing: border-box; + flex-shrink: 0; +`; + +const ThisLabel = styled.span` + color: white; + text-overflow: ellipsis; + font-size: 12px; + font-family: Roboto, sans-serif; + font-weight: 400; + text-align: left; + width: 80px; +`; + +const ProgressBar = styled.div` + display: flex; + justify-content: center; + flex-direction: column; + align-items: flex-start; + flex: 1; + gap: 10px; + border-radius: 7px; + width: 203px; + height: 4px; + background-color: rgba(255, 255, 255, 0.5); + box-sizing: border-box; +`; + +const Value = styled.div` + height: 4px; + background-color: rgb(37, 98, 255); + border-radius: 4px; + align-self: stretch; + flex-shrink: 0; + flex: 1; +`; + +const ThisDescription = styled.span` + color: rgba(255, 255, 255, 0.5); + text-overflow: ellipsis; + font-size: 10px; + font-weight: 400; + text-align: left; + align-self: stretch; + flex-shrink: 0; +`; diff --git a/editor/components/editor-progress-indicator/index.ts b/editor/components/editor-progress-indicator/index.ts new file mode 100644 index 00000000..e814dc4b --- /dev/null +++ b/editor/components/editor-progress-indicator/index.ts @@ -0,0 +1,4 @@ +export { EditorProgressIndicator } from "./editor-progress-indicator"; +export { EditorProgressIndicatorPopoverContent } from "./editor-progress-indicator-popover-content"; +export { EditorProgressIndicatorButton } from "./editor-progress-indicator-trigger-button"; +export { EditorTaskItem } from "./editor-task-item"; diff --git a/editor/scaffolds/editor-progress-indicator/index.tsx b/editor/scaffolds/editor-progress-indicator/index.tsx new file mode 100644 index 00000000..c16c1f11 --- /dev/null +++ b/editor/scaffolds/editor-progress-indicator/index.tsx @@ -0,0 +1,12 @@ +import { EditorProgressIndicator as Base } from "components/editor-progress-indicator"; +import { useDispatch } from "core/dispatch"; +import { useEditorState } from "core/states"; + +export function EditorProgressIndicator() { + const dispatch = useDispatch(); + const [state] = useEditorState(); + + const { editorTaskQueue } = state; + + return ; +} From ff0e2b3e8f8585f0c12762dfcc6242b31a2e96cd Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Mon, 18 Apr 2022 16:42:27 +0900 Subject: [PATCH 04/67] add popover --- .../editor-progress-indicator.tsx | 17 +++++++---- .../editor-task-item.tsx | 30 +++++-------------- ...editor-appbar-fragment-for-code-editor.tsx | 2 ++ editor/pages/files/[key]/index.tsx | 10 +++++++ editor/scaffolds/appbar/index.tsx | 19 ++++++++++++ editor/scaffolds/code/index.tsx | 2 -- editor/scaffolds/editor/editor.tsx | 2 ++ 7 files changed, 52 insertions(+), 30 deletions(-) create mode 100644 editor/scaffolds/appbar/index.tsx diff --git a/editor/components/editor-progress-indicator/editor-progress-indicator.tsx b/editor/components/editor-progress-indicator/editor-progress-indicator.tsx index 479f5162..2a88db98 100644 --- a/editor/components/editor-progress-indicator/editor-progress-indicator.tsx +++ b/editor/components/editor-progress-indicator/editor-progress-indicator.tsx @@ -17,11 +17,18 @@ export function EditorProgressIndicator({ - - {tasks.map((task, index) => ( - - ))} - + + + {tasks.map((task, index) => ( + + ))} + + ); } diff --git a/editor/components/editor-progress-indicator/editor-task-item.tsx b/editor/components/editor-progress-indicator/editor-task-item.tsx index 5e386398..e1702c6a 100644 --- a/editor/components/editor-progress-indicator/editor-task-item.tsx +++ b/editor/components/editor-progress-indicator/editor-task-item.tsx @@ -1,20 +1,21 @@ import React from "react"; import styled from "@emotion/styled"; +import LinearProgress from "@mui/material/LinearProgress"; export function EditorTaskItem({ label, description, + progress, }: { label: string; description?: string; + progress: number | null; }) { return ( {label} - - - + {description} @@ -28,7 +29,6 @@ const RootWrapperProgressingItemReadonly = styled.div` align-items: flex-start; flex: none; gap: 4px; - min-height: 100vh; box-sizing: border-box; `; @@ -53,27 +53,11 @@ const ThisLabel = styled.span` width: 80px; `; -const ProgressBar = styled.div` - display: flex; - justify-content: center; - flex-direction: column; - align-items: flex-start; - flex: 1; - gap: 10px; - border-radius: 7px; - width: 203px; - height: 4px; - background-color: rgba(255, 255, 255, 0.5); - box-sizing: border-box; -`; - -const Value = styled.div` +const ColoredLinearProgress = styled(LinearProgress)` height: 4px; + width: 203px; + border-radius: 7px; background-color: rgb(37, 98, 255); - border-radius: 4px; - align-self: stretch; - flex-shrink: 0; - flex: 1; `; const ThisDescription = styled.span` diff --git a/editor/components/editor/editor-appbar/editor-appbar-fragment-for-code-editor.tsx b/editor/components/editor/editor-appbar/editor-appbar-fragment-for-code-editor.tsx index c11f393a..966e72ac 100644 --- a/editor/components/editor/editor-appbar/editor-appbar-fragment-for-code-editor.tsx +++ b/editor/components/editor/editor-appbar/editor-appbar-fragment-for-code-editor.tsx @@ -4,6 +4,7 @@ import { useRouter } from "next/router"; import { EditorAppbarIconButton } from "./editor-appbar-icon-button"; import { GithubIcon, NotificationBellIcon } from "icons"; import { EditorFrameworkConfigOnAppbar } from "../editor-framework-config-on-appbar"; +import { EditorProgressIndicator } from "scaffolds/editor-progress-indicator"; export function AppbarFragmentForCodeEditor() { const router = useRouter(); @@ -20,6 +21,7 @@ export function AppbarFragmentForCodeEditor() { )} + { window.open("https://github.com/gridaco/designto-code/", "_blank"); diff --git a/editor/pages/files/[key]/index.tsx b/editor/pages/files/[key]/index.tsx index e3169c2d..39d9fb0d 100644 --- a/editor/pages/files/[key]/index.tsx +++ b/editor/pages/files/[key]/index.tsx @@ -103,6 +103,16 @@ function SetupEditor({ selectedNodesInitial: initialSelections, selectedPage: warmup.selectedPage(prevstate, pages, nodeid && [nodeid]), selectedLayersOnPreview: [], + editorTaskQueue: { + isBusy: true, + tasks: [ + { + id: "refetch-file", + name: "refreshing..", + progress: null, + }, + ], + }, design: { name: file.name, input: null, diff --git a/editor/scaffolds/appbar/index.tsx b/editor/scaffolds/appbar/index.tsx new file mode 100644 index 00000000..288b8e94 --- /dev/null +++ b/editor/scaffolds/appbar/index.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import { EditorAppbarFragments } from "components/editor"; +/** + * a scaffold App bar linked with editor state + */ +export function Appbar() { + return ( +
+ + + +
+ ); +} diff --git a/editor/scaffolds/code/index.tsx b/editor/scaffolds/code/index.tsx index 11a41cf6..22a084d3 100644 --- a/editor/scaffolds/code/index.tsx +++ b/editor/scaffolds/code/index.tsx @@ -2,7 +2,6 @@ import React, { useEffect, useRef, useState } from "react"; import styled from "@emotion/styled"; import { useRouter } from "next/router"; import { CodeEditor } from "components/code-editor"; -import { EditorAppbarFragments } from "components/editor"; import { get_framework_config } from "query/to-code-options-from-query"; import { CodeOptionsControl } from "components/codeui-code-options-control"; import { designToCode, Result } from "@designto/code"; @@ -131,7 +130,6 @@ export function CodeSegment() { const { code, scaffold, name: componentName } = result ?? {}; return ( - , }} + appbar={} // rightbar={} > From 43f74321f672a0abc6d315263370e5d284dea4fb Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Mon, 18 Apr 2022 17:06:12 +0900 Subject: [PATCH 05/67] sanitize view --- .../editor-appbar-fragment-for-canvas.tsx | 1 - ...editor-appbar-fragment-for-code-editor.tsx | 18 ++++++++++----- .../editor/editor-appbar/editor-appbar.tsx | 6 ++--- .../default-editor-workspace-layout.tsx | 22 ++++++++++++++++++- editor/scaffolds/appbar/index.tsx | 11 +++++++--- editor/scaffolds/editor/editor.tsx | 3 ++- 6 files changed, 47 insertions(+), 14 deletions(-) diff --git a/editor/components/editor/editor-appbar/editor-appbar-fragment-for-canvas.tsx b/editor/components/editor/editor-appbar/editor-appbar-fragment-for-canvas.tsx index 33bc1523..aad350d8 100644 --- a/editor/components/editor/editor-appbar/editor-appbar-fragment-for-canvas.tsx +++ b/editor/components/editor/editor-appbar/editor-appbar-fragment-for-canvas.tsx @@ -20,7 +20,6 @@ const RootWrapperAppbarFragmentForCanvas = styled.div` align-items: center; gap: 10px; align-self: stretch; - background-color: ${colors.color_editor_bg_on_dark}; box-sizing: border-box; padding: 10px 24px; `; diff --git a/editor/components/editor/editor-appbar/editor-appbar-fragment-for-code-editor.tsx b/editor/components/editor/editor-appbar/editor-appbar-fragment-for-code-editor.tsx index 966e72ac..78a794ea 100644 --- a/editor/components/editor/editor-appbar/editor-appbar-fragment-for-code-editor.tsx +++ b/editor/components/editor/editor-appbar/editor-appbar-fragment-for-code-editor.tsx @@ -1,17 +1,22 @@ import React from "react"; import styled from "@emotion/styled"; -import { useRouter } from "next/router"; import { EditorAppbarIconButton } from "./editor-appbar-icon-button"; import { GithubIcon, NotificationBellIcon } from "icons"; import { EditorFrameworkConfigOnAppbar } from "../editor-framework-config-on-appbar"; import { EditorProgressIndicator } from "scaffolds/editor-progress-indicator"; +import { colors } from "theme"; -export function AppbarFragmentForCodeEditor() { - const router = useRouter(); +export function AppbarFragmentForCodeEditor({ + background = false, +}: { + background?: boolean; +}) { const hasNotification = false; return ( - + {/* disable temporarily */}
{/* */} @@ -34,7 +39,9 @@ export function AppbarFragmentForCodeEditor() { ); } -const RootWrapperAppbarFragmentForCodeEditor = styled.div` +const RootWrapperAppbarFragmentForCodeEditor = styled.div<{ + background: React.CSSProperties["background"]; +}>` z-index: 10; display: flex; justify-content: center; @@ -48,6 +55,7 @@ const RootWrapperAppbarFragmentForCodeEditor = styled.div` padding-top: 14px; padding-left: 12px; padding-right: 20px; + background: ${(props) => props.background}; `; const AppbarActions = styled.div` diff --git a/editor/components/editor/editor-appbar/editor-appbar.tsx b/editor/components/editor/editor-appbar/editor-appbar.tsx index 7a842d92..9c3331a8 100644 --- a/editor/components/editor/editor-appbar/editor-appbar.tsx +++ b/editor/components/editor/editor-appbar/editor-appbar.tsx @@ -7,9 +7,9 @@ import { AppbarFragmentForCodeEditor } from "./editor-appbar-fragment-for-code-e export function Appbar() { return ( - - - + + + ); } diff --git a/editor/layouts/default-editor-workspace-layout.tsx b/editor/layouts/default-editor-workspace-layout.tsx index 1c8a1bdb..0b92b385 100644 --- a/editor/layouts/default-editor-workspace-layout.tsx +++ b/editor/layouts/default-editor-workspace-layout.tsx @@ -14,7 +14,14 @@ type SidebarElementSignature = export function DefaultEditorWorkspaceLayout(props: { leftbar?: SidebarElementSignature; rightbar?: SidebarElementSignature; + /** + * global area appbar + */ appbar?: JSX.Element; + /** + * content area appbar + */ + contentAreaAppbar?: JSX.Element; children: JSX.Element | Array; display?: "none" | "initial"; // set to none when to hide. backgroundColor?: string; @@ -30,7 +37,20 @@ export function DefaultEditorWorkspaceLayout(props: { {props.leftbar && ( )} - {props.children} + {props.contentAreaAppbar ? ( +
+ {props.contentAreaAppbar} + {props.children} +
+ ) : ( + {props.children} + )} {props.rightbar && ( )} diff --git a/editor/scaffolds/appbar/index.tsx b/editor/scaffolds/appbar/index.tsx index 288b8e94..0095f8b4 100644 --- a/editor/scaffolds/appbar/index.tsx +++ b/editor/scaffolds/appbar/index.tsx @@ -1,9 +1,16 @@ import React from "react"; import { EditorAppbarFragments } from "components/editor"; +import { useEditorState } from "core/states"; /** * a scaffold App bar linked with editor state */ export function Appbar() { + const [state] = useEditorState(); + + const isCodeEditorShown = state.selectedNodes.length > 0; + + console.log("Appbar", isCodeEditorShown); + return (
- - - +
); } diff --git a/editor/scaffolds/editor/editor.tsx b/editor/scaffolds/editor/editor.tsx index f9b11953..d37c0c2a 100644 --- a/editor/scaffolds/editor/editor.tsx +++ b/editor/scaffolds/editor/editor.tsx @@ -47,7 +47,8 @@ export function Editor({ maxWidth: 600, children: , }} - appbar={} + contentAreaAppbar={} + // appbar={} // rightbar={} > From 3c3af89d2a498ab912aff867d87725866b1200e9 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Mon, 18 Apr 2022 17:15:15 +0900 Subject: [PATCH 06/67] fix styles --- ...editor-progress-indicator-popover-content.tsx | 4 ++-- .../editor-progress-indicator.tsx | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/editor/components/editor-progress-indicator/editor-progress-indicator-popover-content.tsx b/editor/components/editor-progress-indicator/editor-progress-indicator-popover-content.tsx index 2661ec87..47075257 100644 --- a/editor/components/editor-progress-indicator/editor-progress-indicator-popover-content.tsx +++ b/editor/components/editor-progress-indicator/editor-progress-indicator-popover-content.tsx @@ -16,10 +16,10 @@ const Container = styled.div` align-items: center; flex: none; gap: 32px; - box-shadow: 0px 4px 24px 0px rgba(0, 0, 0, 0.25); + box-shadow: 0px 16px 24px 0px rgba(0, 0, 0, 0.25); border: solid 1px rgb(74, 73, 77); border-radius: 12px; - background-color: rgba(30, 30, 30, 0.4); + background-color: rgba(30, 30, 30, 0.8); box-sizing: border-box; padding: 24px; backdrop-filter: blur(32px); diff --git a/editor/components/editor-progress-indicator/editor-progress-indicator.tsx b/editor/components/editor-progress-indicator/editor-progress-indicator.tsx index 2a88db98..791f91d3 100644 --- a/editor/components/editor-progress-indicator/editor-progress-indicator.tsx +++ b/editor/components/editor-progress-indicator/editor-progress-indicator.tsx @@ -14,10 +14,14 @@ export function EditorProgressIndicator({ }) { return ( - + - - + + {tasks.map((task, index) => ( ); } + +const StyledTrigger = styled(Popover.Trigger)` + outline: none; + border: none; + background: none; +`; From df8c7f070fee1e825830a52af686ca69b092d689 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Mon, 18 Apr 2022 17:32:57 +0900 Subject: [PATCH 07/67] update messages --- editor/pages/files/[key]/index.tsx | 23 +++++++++++++---------- editor/scaffolds/appbar/index.tsx | 2 -- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/editor/pages/files/[key]/index.tsx b/editor/pages/files/[key]/index.tsx index 39d9fb0d..86ecc6c5 100644 --- a/editor/pages/files/[key]/index.tsx +++ b/editor/pages/files/[key]/index.tsx @@ -43,6 +43,8 @@ export default function FileEntryEditor() { ); } +const action_fetchfile_id = "fetchfile"; + function SetupEditor({ filekey, nodeid, @@ -103,16 +105,6 @@ function SetupEditor({ selectedNodesInitial: initialSelections, selectedPage: warmup.selectedPage(prevstate, pages, nodeid && [nodeid]), selectedLayersOnPreview: [], - editorTaskQueue: { - isBusy: true, - tasks: [ - { - id: "refetch-file", - name: "refreshing..", - progress: null, - }, - ], - }, design: { name: file.name, input: null, @@ -122,6 +114,17 @@ function SetupEditor({ pages: pages, }, canvasMode: initialCanvasMode, + editorTaskQueue: { + isBusy: true, + tasks: [ + { + id: action_fetchfile_id, + name: "Figma File", + description: "Refreshing remote file", + progress: null, + }, + ], + }, }; } diff --git a/editor/scaffolds/appbar/index.tsx b/editor/scaffolds/appbar/index.tsx index 0095f8b4..ef012673 100644 --- a/editor/scaffolds/appbar/index.tsx +++ b/editor/scaffolds/appbar/index.tsx @@ -9,8 +9,6 @@ export function Appbar() { const isCodeEditorShown = state.selectedNodes.length > 0; - console.log("Appbar", isCodeEditorShown); - return (
Date: Tue, 19 Apr 2022 04:24:28 +0900 Subject: [PATCH 08/67] use user defined canvas color --- .../canvas-event-target.tsx | 1 - .../editor-canvas/canvas/canvas.tsx | 19 +++++++++++++++++++ editor/core/states/editor-state.ts | 10 ++++++++-- editor/scaffolds/canvas/canvas.tsx | 12 +++++++++--- editor/scaffolds/editor/warmup.ts | 6 ++++-- externals/design-sdk | 2 +- 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/editor-packages/editor-canvas/canvas-event-target/canvas-event-target.tsx b/editor-packages/editor-canvas/canvas-event-target/canvas-event-target.tsx index 97c21e56..7aa7ce70 100644 --- a/editor-packages/editor-canvas/canvas-event-target/canvas-event-target.tsx +++ b/editor-packages/editor-canvas/canvas-event-target/canvas-event-target.tsx @@ -201,7 +201,6 @@ export function CanvasEventTarget({ style={{ position: "absolute", inset: 0, - background: "transparent", overflow: "hidden", touchAction: "none", cursor: isSpacebarPressed ? "grab" : "default", diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index 671d6e14..a85f9e68 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -30,6 +30,7 @@ const MIN_ZOOM = 0.02; interface CanvasState { pageid: string; filekey: string; + backgroundColor?: React.CSSProperties["backgroundColor"]; nodes: ReflectSceneNode[]; highlightedLayer?: string; selectedNodes: string[]; @@ -91,6 +92,7 @@ export function Canvas({ selectedNodes, readonly = true, config = default_canvas_preferences, + backgroundColor, ...props }: { viewbound: Box; @@ -389,6 +391,7 @@ export function Canvas({ renderFrameTitle={props.renderFrameTitle} /> + {items} @@ -440,6 +443,22 @@ function DisableBackdropFilter({ children }: { children: React.ReactNode }) { ); } +function CanvasBackground({ backgroundColor }: { backgroundColor?: string }) { + return ( +
+ ); +} + function auto_initial_transform( viewbound: Box, nodes: ReflectSceneNode[] diff --git a/editor/core/states/editor-state.ts b/editor/core/states/editor-state.ts index 8bbe99a8..415e3477 100644 --- a/editor/core/states/editor-state.ts +++ b/editor/core/states/editor-state.ts @@ -1,6 +1,6 @@ import type { ReflectSceneNode } from "@design-sdk/figma-node"; import type { FrameworkConfig } from "@designto/config"; -import type { WidgetKey } from "@reflect-ui/core"; +import type { RGBA, WidgetKey } from "@reflect-ui/core"; import type { ComponentNode } from "@design-sdk/figma-types"; import type { DesignInput } from "@designto/config/input"; @@ -50,7 +50,13 @@ export interface FigmaReflectRepository { key: string; // TODO: - pages: { id: string; name: string; children: ReflectSceneNode[] }[]; + pages: { + id: string; + name: string; + children: ReflectSceneNode[]; + backgroundColor: RGBA; + flowStartingPoints: any[]; + }[]; components: { [key: string]: ComponentNode }; // styles: { [key: string]: {} }; input: DesignInput; diff --git a/editor/scaffolds/canvas/canvas.tsx b/editor/scaffolds/canvas/canvas.tsx index 2c1739be..07da0430 100644 --- a/editor/scaffolds/canvas/canvas.tsx +++ b/editor/scaffolds/canvas/canvas.tsx @@ -31,9 +31,8 @@ export function VisualContentArea() { canvasMode_previous, } = state; - const thisPageNodes = selectedPage - ? design.pages.find((p) => p.id == selectedPage).children.filter(Boolean) - : []; + const thisPage = design?.pages?.find((p) => p.id == selectedPage); + const thisPageNodes = selectedPage ? thisPage.children.filter(Boolean) : []; const isEmptyPage = thisPageNodes?.length === 0; @@ -73,6 +72,12 @@ export function VisualContentArea() { [dispatch] ); + const _bg = + thisPage?.backgroundColor && + `rgba(${thisPage.backgroundColor.r * 255}, ${ + thisPage.backgroundColor.g * 255 + }, ${thisPage.backgroundColor.b * 255}, ${thisPage.backgroundColor.a})`; + return ( {/* */} @@ -113,6 +118,7 @@ export function VisualContentArea() { ]} filekey={state.design.key} pageid={selectedPage} + backgroundColor={_bg} selectedNodes={selectedNodes} highlightedLayer={highlightedLayer} onSelectNode={(...nodes) => { diff --git a/editor/scaffolds/editor/warmup.ts b/editor/scaffolds/editor/warmup.ts index 382f9916..7b9f6ecc 100644 --- a/editor/scaffolds/editor/warmup.ts +++ b/editor/scaffolds/editor/warmup.ts @@ -8,7 +8,7 @@ import { createInitialWorkspaceState } from "core/states"; import { workspaceReducer } from "core/reducers"; import { PendingState } from "core/utility-types"; import { WorkspaceAction } from "core/actions"; -import { FileResponse } from "@design-sdk/figma-remote-types"; +import type { Canvas, FileResponse } from "@design-sdk/figma-remote-types"; import { convert } from "@design-sdk/figma-node-conversion"; import { mapper } from "@design-sdk/figma-remote"; import { visit } from "tree-visit"; @@ -42,13 +42,15 @@ export function initialReducer( } export function pagesFrom(file: FileResponse): FigmaReflectRepository["pages"] { - return file.document.children.map((page) => ({ + return file.document.children.map((page: Canvas) => ({ id: page.id, name: page.name, children: page["children"]?.map((child) => { const _mapped = mapper.mapFigmaRemoteToFigma(child); return convert.intoReflectNode(_mapped); }), + flowStartingPoints: page.flowStartingPoints, + backgroundColor: page.backgroundColor, type: "design", })); } diff --git a/externals/design-sdk b/externals/design-sdk index 50c261ac..fb847ef7 160000 --- a/externals/design-sdk +++ b/externals/design-sdk @@ -1 +1 @@ -Subproject commit 50c261ac07ecce5a0550c0fd3cd81cf2c2c86fcc +Subproject commit fb847ef7cbf1671ec0e3ceb011bf79e2c3cec4d8 From 599698c673362c14791e2b12980a8d56ac9e0f6c Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Tue, 19 Apr 2022 05:29:51 +0900 Subject: [PATCH 09/67] add transform outline --- .../editor-canvas/hud/hud-surface.tsx | 20 ++++- .../editor-canvas/overlay/handle.tsx | 67 +++++++++++++++ .../overlay/hover-outline-hightlight.tsx | 8 +- .../editor-canvas/overlay/index.ts | 3 +- .../editor-canvas/overlay/outline-side.tsx | 22 +++-- ...ght.tsx => select-hightlight-readonly.tsx} | 72 +++++----------- .../overlay/select-hightlight.tsx | 84 +++++++++++++++++++ editor/scaffolds/canvas/canvas.tsx | 1 + 8 files changed, 213 insertions(+), 64 deletions(-) create mode 100644 editor-packages/editor-canvas/overlay/handle.tsx rename editor-packages/editor-canvas/overlay/{readonly-select-hightlight.tsx => select-hightlight-readonly.tsx} (75%) create mode 100644 editor-packages/editor-canvas/overlay/select-hightlight.tsx diff --git a/editor-packages/editor-canvas/hud/hud-surface.tsx b/editor-packages/editor-canvas/hud/hud-surface.tsx index 193414c9..4ff4f899 100644 --- a/editor-packages/editor-canvas/hud/hud-surface.tsx +++ b/editor-packages/editor-canvas/hud/hud-surface.tsx @@ -1,5 +1,9 @@ import React from "react"; -import { HoverOutlineHighlight, ReadonlySelectHightlight } from "../overlay"; +import { + HoverOutlineHighlight, + ReadonlySelectHightlight, + SelectHightlight, +} from "../overlay"; import { FrameTitle, FrameTitleProps } from "../frame-title"; import type { XY, XYWH } from "../types"; import { Marquee } from "../marquee"; @@ -129,7 +133,19 @@ export function HudSurface({ /> ); } else { - // TODO: support non readonly canvas + return ( + { + // console.log("resize", anchor, e); + }} + key={s.id} + type="xywhr" + xywh={xywh} + rotation={s.rotation} + zoom={zoom} + width={1} + /> + ); } })} diff --git a/editor-packages/editor-canvas/overlay/handle.tsx b/editor-packages/editor-canvas/overlay/handle.tsx new file mode 100644 index 00000000..22617cf4 --- /dev/null +++ b/editor-packages/editor-canvas/overlay/handle.tsx @@ -0,0 +1,67 @@ +import React from "react"; +export function Handle({ + color, + anchor, + box, + outlineWidth = 1, + outlineColor, + size = 4, + borderRadius = 0, + cursor, + readonly, +}: { + color: string; + /** + * the width of the outline + */ + outlineWidth: number; + outlineColor: string; + size: number; + anchor: "nw" | "ne" | "sw" | "se"; + box: [number, number, number, number]; + borderRadius?: React.CSSProperties["borderRadius"]; + cursor?: React.CSSProperties["cursor"]; + readonly?: boolean; +}) { + let dx = 0; + let dy = 0; + switch (anchor) { + case "nw": + dx = box[0]; + dy = box[1]; + break; + case "ne": + dx = box[2]; + dy = box[1]; + break; + case "sw": + dx = box[0]; + dy = box[3]; + break; + case "se": + dx = box[2]; + dy = box[3]; + break; + } + + // translate x, y + const [tx, ty] = [dx - size / 2 - outlineWidth, dy - size / 2 - outlineWidth]; + + return ( +
+ ); +} diff --git a/editor-packages/editor-canvas/overlay/hover-outline-hightlight.tsx b/editor-packages/editor-canvas/overlay/hover-outline-hightlight.tsx index b5b9b6db..0a878bcf 100644 --- a/editor-packages/editor-canvas/overlay/hover-outline-hightlight.tsx +++ b/editor-packages/editor-canvas/overlay/hover-outline-hightlight.tsx @@ -19,10 +19,10 @@ export function HoverOutlineHighlight({ width = 1, ...props }: OutlineProps) { return ( - - - - + + + + ); } diff --git a/editor-packages/editor-canvas/overlay/index.ts b/editor-packages/editor-canvas/overlay/index.ts index 576ab0ac..738ec8e9 100644 --- a/editor-packages/editor-canvas/overlay/index.ts +++ b/editor-packages/editor-canvas/overlay/index.ts @@ -1,2 +1,3 @@ export * from "./hover-outline-hightlight"; -export * from "./readonly-select-hightlight"; +export * from "./select-hightlight"; +export * from "./select-hightlight-readonly"; diff --git a/editor-packages/editor-canvas/overlay/outline-side.tsx b/editor-packages/editor-canvas/overlay/outline-side.tsx index e93476b3..2bfc4054 100644 --- a/editor-packages/editor-canvas/overlay/outline-side.tsx +++ b/editor-packages/editor-canvas/overlay/outline-side.tsx @@ -1,3 +1,4 @@ +import React from "react"; import { color_layer_highlight } from "../theme"; export function OulineSide({ @@ -7,46 +8,50 @@ export function OulineSide({ width = 1, box, color = color_layer_highlight, + readonly = true, + cursor, }: { wh: [number, number]; box: [number, number, number, number]; zoom: number; - orientation: "l" | "t" | "r" | "b"; + orientation: "w" | "n" | "e" | "s"; width?: number; color?: string; + readonly?: boolean; + cursor?: React.CSSProperties["cursor"]; }) { const d = 100; const [w, h] = wh; // is vertical line - const isvert = orientation === "l" || orientation === "r"; + const isvert = orientation === "w" || orientation === "e"; const l_scalex = isvert ? width / d : (w / d) * zoom; const l_scaley = isvert ? (h / d) * zoom : width / d; let trans = { x: 0, y: 0 }; switch (orientation) { - case "l": { + case "w": { trans = { x: box[0] - d / 2, y: box[1] + (d * l_scaley - d) / 2, }; break; } - case "r": { + case "e": { trans = { x: box[2] - d / 2, y: box[1] + (d * l_scaley - d) / 2, }; break; } - case "t": { + case "n": { trans = { x: box[0] + (d * l_scalex - d) / 2, y: box[1] - d / 2, }; break; } - case "b": { + case "s": { trans = { x: box[0] + (d * l_scalex - d) / 2, y: box[3] - d / 2, @@ -62,10 +67,11 @@ export function OulineSide({ width: d, height: d, opacity: 1, - pointerEvents: "none", + pointerEvents: readonly ? "none" : "all", + cursor: cursor, willChange: "transform", transformOrigin: "0px, 0px", - transform: `translateX(${trans.x}px) translateY(${trans.y}px) translateZ(0px) scaleX(${l_scalex}) scaleY(${l_scaley})`, + transform: `translate3d(${trans.x}px, ${trans.y}px, 0) scaleX(${l_scalex}) scaleY(${l_scaley})`, backgroundColor: color, }} /> diff --git a/editor-packages/editor-canvas/overlay/readonly-select-hightlight.tsx b/editor-packages/editor-canvas/overlay/select-hightlight-readonly.tsx similarity index 75% rename from editor-packages/editor-canvas/overlay/readonly-select-hightlight.tsx rename to editor-packages/editor-canvas/overlay/select-hightlight-readonly.tsx index 27ab07db..d2b26686 100644 --- a/editor-packages/editor-canvas/overlay/readonly-select-hightlight.tsx +++ b/editor-packages/editor-canvas/overlay/select-hightlight-readonly.tsx @@ -4,6 +4,7 @@ import { color_layer_readonly_highlight } from "../theme"; import { get_boinding_box } from "./math"; import { OulineSide } from "./outline-side"; import { OverlayContainer } from "./overlay-container"; +import { Handle } from "./handle"; export function ReadonlySelectHightlight({ width = 1, @@ -64,34 +65,34 @@ export function ReadonlySelectHightlight({ <> <> - - - - + + + + ); @@ -103,7 +104,7 @@ function SideCenterEmp({ box, size = 3, }: { - side: "l" | "r" | "t" | "b"; + side: "w" | "e" | "n" | "s"; color: string; box: [number, number, number, number]; size?: number; @@ -111,19 +112,19 @@ function SideCenterEmp({ let dx = 0; let dy = 0; switch (side) { - case "l": + case "w": dx = box[0]; dy = box[1] + (box[3] - box[1]) / 2; break; - case "r": + case "e": dx = box[2]; dy = box[1] + (box[3] - box[1]) / 2; break; - case "t": + case "n": dx = box[0] + (box[2] - box[0]) / 2; dy = box[1]; break; - case "b": + case "s": dx = box[0] + (box[2] - box[0]) / 2; dy = box[3]; break; @@ -166,43 +167,16 @@ function ReadonlyHandle({ anchor: "nw" | "ne" | "sw" | "se"; box: [number, number, number, number]; }) { - let dx = 0; - let dy = 0; - switch (anchor) { - case "nw": - dx = box[0]; - dy = box[1]; - break; - case "ne": - dx = box[2]; - dy = box[1]; - break; - case "sw": - dx = box[0]; - dy = box[3]; - break; - case "se": - dx = box[2]; - dy = box[3]; - break; - } - - // translate x, y - const [tx, ty] = [dx - size / 2 - outlineWidth, dy - size / 2 - outlineWidth]; - return ( -
); } diff --git a/editor-packages/editor-canvas/overlay/select-hightlight.tsx b/editor-packages/editor-canvas/overlay/select-hightlight.tsx new file mode 100644 index 00000000..1362ca6e --- /dev/null +++ b/editor-packages/editor-canvas/overlay/select-hightlight.tsx @@ -0,0 +1,84 @@ +import React, { useRef } from "react"; +import type { OutlineProps } from "./types"; +import { color_layer_highlight } from "../theme"; +import { get_boinding_box } from "./math"; +import { OulineSide } from "./outline-side"; +import { OverlayContainer } from "./overlay-container"; +import { Handle } from "./handle"; +import { useDrag } from "@use-gesture/react"; +import type { OnDragHandler } from "../canvas-event-target"; + +export function SelectHightlight({ + width = 1, + onResize, + ...props +}: OutlineProps & { + onResize?: (anchor: "nw" | "ne" | "sw" | "se", e) => void; +}) { + const { xywh, zoom, rotation } = props; + const bbox = get_boinding_box({ xywh, scale: zoom }); + const wh: [number, number] = [xywh[2], xywh[3]]; + + const sideprops = { + wh: wh, + zoom: props.zoom, + width: width, + readonly: false, + box: bbox, + color: color_layer_highlight, + }; + + const onresizecb = (anchor: "nw" | "ne" | "sw" | "se") => (e) => { + if (onResize) { + onResize(anchor, e); + } + }; + + return ( + + <> + + + + + + <> + + + + + + + ); +} + +function ResizeHandle({ + anchor, + box, + onDrag, +}: { + anchor: "nw" | "ne" | "sw" | "se"; + box: [number, number, number, number]; + onDrag: OnDragHandler; +}) { + const ref = useRef(); + useDrag(onDrag, { + target: ref, + }); + + return ( +
+ +
+ ); +} diff --git a/editor/scaffolds/canvas/canvas.tsx b/editor/scaffolds/canvas/canvas.tsx index 07da0430..9ce586db 100644 --- a/editor/scaffolds/canvas/canvas.tsx +++ b/editor/scaffolds/canvas/canvas.tsx @@ -139,6 +139,7 @@ export function VisualContentArea() { ); }} + readonly={false} config={{ can_highlight_selected_layer: true, marquee: { From ff6dbfcde736f4dd2f20e0411ccdd7c73785f169 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Tue, 19 Apr 2022 07:00:09 +0900 Subject: [PATCH 10/67] update transform highlight --- .../editor-canvas/hud/hud-surface.tsx | 4 - .../editor-canvas/overlay/handle.tsx | 18 +-- .../overlay/select-hightlight.tsx | 118 ++++++++++++------ 3 files changed, 90 insertions(+), 50 deletions(-) diff --git a/editor-packages/editor-canvas/hud/hud-surface.tsx b/editor-packages/editor-canvas/hud/hud-surface.tsx index 4ff4f899..67c30d2e 100644 --- a/editor-packages/editor-canvas/hud/hud-surface.tsx +++ b/editor-packages/editor-canvas/hud/hud-surface.tsx @@ -135,15 +135,11 @@ export function HudSurface({ } else { return ( { - // console.log("resize", anchor, e); - }} key={s.id} type="xywhr" xywh={xywh} rotation={s.rotation} zoom={zoom} - width={1} /> ); } diff --git a/editor-packages/editor-canvas/overlay/handle.tsx b/editor-packages/editor-canvas/overlay/handle.tsx index 22617cf4..b5c93c95 100644 --- a/editor-packages/editor-canvas/overlay/handle.tsx +++ b/editor-packages/editor-canvas/overlay/handle.tsx @@ -1,10 +1,10 @@ -import React from "react"; -export function Handle({ +import React, { forwardRef } from "react"; +export const Handle = forwardRef(function ({ color, anchor, box, outlineWidth = 1, - outlineColor, + outlineColor = "transparent", size = 4, borderRadius = 0, cursor, @@ -14,8 +14,8 @@ export function Handle({ /** * the width of the outline */ - outlineWidth: number; - outlineColor: string; + outlineWidth?: number; + outlineColor?: string; size: number; anchor: "nw" | "ne" | "sw" | "se"; box: [number, number, number, number]; @@ -54,14 +54,14 @@ export function Handle({ borderRadius: borderRadius, width: size, height: size, - border: `${outlineColor} solid ${outlineWidth}px`, + border: outlineWidth && `${outlineColor} solid ${outlineWidth}px`, willChange: "transform", transform: `translate3d(${tx}px, ${ty}px, 0)`, backgroundColor: color, cursor: cursor, - zIndex: 1, - pointerEvents: readonly ? "none" : "all", + zIndex: 2, + pointerEvents: readonly ? "none" : "auto", }} /> ); -} +}); diff --git a/editor-packages/editor-canvas/overlay/select-hightlight.tsx b/editor-packages/editor-canvas/overlay/select-hightlight.tsx index 1362ca6e..e4752bd6 100644 --- a/editor-packages/editor-canvas/overlay/select-hightlight.tsx +++ b/editor-packages/editor-canvas/overlay/select-hightlight.tsx @@ -5,16 +5,12 @@ import { get_boinding_box } from "./math"; import { OulineSide } from "./outline-side"; import { OverlayContainer } from "./overlay-container"; import { Handle } from "./handle"; -import { useDrag } from "@use-gesture/react"; +import { useGesture } from "@use-gesture/react"; import type { OnDragHandler } from "../canvas-event-target"; export function SelectHightlight({ - width = 1, - onResize, ...props -}: OutlineProps & { - onResize?: (anchor: "nw" | "ne" | "sw" | "se", e) => void; -}) { +}: Omit & {}) { const { xywh, zoom, rotation } = props; const bbox = get_boinding_box({ xywh, scale: zoom }); const wh: [number, number] = [xywh[2], xywh[3]]; @@ -22,39 +18,72 @@ export function SelectHightlight({ const sideprops = { wh: wh, zoom: props.zoom, - width: width, + width: 1, readonly: false, box: bbox, color: color_layer_highlight, }; - const onresizecb = (anchor: "nw" | "ne" | "sw" | "se") => (e) => { - if (onResize) { - onResize(anchor, e); - } - }; - return ( + {/* TODO: add rotation knob */} + {/* <> + + + + + */} <> - - - - + + + + <> - - - - + + + + ); } +const resize_cursor_map = { + nw: "nwse-resize", + ne: "nesw-resize", + sw: "nesw-resize", + se: "nwse-resize", + w: "ew-resize", + n: "ns-resize", + s: "ns-resize", + e: "ew-resize", +}; + function ResizeHandle({ anchor, box, +}: { + anchor: "nw" | "ne" | "sw" | "se"; + box: [number, number, number, number]; +}) { + return ( + + ); +} + +function RotateHandle({ + anchor, + box, onDrag, }: { anchor: "nw" | "ne" | "sw" | "se"; @@ -62,23 +91,38 @@ function ResizeHandle({ onDrag: OnDragHandler; }) { const ref = useRef(); - useDrag(onDrag, { - target: ref, - }); + useGesture( + { + onDragStart: (e) => { + e.event.stopPropagation(); + }, + onDragEnd: (e) => { + e.event.stopPropagation(); + }, + onDrag: (e) => { + onDrag(e); + e.event.stopPropagation(); + }, + }, + { + target: ref, + eventOptions: { + capture: false, + }, + } + ); return ( -
- -
+ ); } From bd1233b1632ca5b2e7c970cf9e2a631cd31223aa Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Tue, 19 Apr 2022 08:06:53 +0900 Subject: [PATCH 11/67] add grouped highlight --- .../editor-canvas/canvas/canvas.tsx | 13 ++ .../editor-canvas/hud/hud-surface.tsx | 111 +++++++++++++----- .../editor-canvas/math/bounding-box.ts | 90 ++++++++++++++ .../editor-canvas/math/center-of.ts | 24 +--- editor-packages/editor-canvas/math/index.ts | 1 + .../overlay/hover-outline-hightlight.tsx | 4 +- .../editor-canvas/overlay/index.ts | 1 + editor-packages/editor-canvas/overlay/math.ts | 18 --- .../select-highlight-in-selection-group.tsx | 34 ++++++ .../overlay/select-hightlight-readonly.tsx | 4 +- .../overlay/select-hightlight.tsx | 4 +- editor-packages/editor-canvas/types/index.ts | 25 +++- editor/pages/canvas-server/index.tsx | 5 +- editor/scaffolds/canvas/canvas.tsx | 3 + 14 files changed, 262 insertions(+), 75 deletions(-) create mode 100644 editor-packages/editor-canvas/math/bounding-box.ts delete mode 100644 editor-packages/editor-canvas/overlay/math.ts create mode 100644 editor-packages/editor-canvas/overlay/select-highlight-in-selection-group.tsx diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index a85f9e68..27796777 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -56,6 +56,7 @@ type CanvasCustomRenderers = HudCustomRenderers & { interface CanvsPreferences { can_highlight_selected_layer?: boolean; marquee: MarqueeOprions; + grouping: GroupingOptions; } interface MarqueeOprions { @@ -67,11 +68,22 @@ interface MarqueeOprions { disabled?: boolean; } +interface GroupingOptions { + /** + * disable grouping - multiple selections will not be grouped. + * @default false + **/ + disabled?: boolean; +} + const default_canvas_preferences: CanvsPreferences = { can_highlight_selected_layer: false, marquee: { disabled: false, }, + grouping: { + disabled: false, + }, }; interface HovringNode { @@ -367,6 +379,7 @@ export function Canvas({ hide={is_canvas_transforming} readonly={readonly} disableMarquee={config.marquee.disabled} + disableGrouping={config.grouping.disabled} marquee={marquee} labelDisplayNodes={nodes} selectedNodes={selected_nodes} diff --git a/editor-packages/editor-canvas/hud/hud-surface.tsx b/editor-packages/editor-canvas/hud/hud-surface.tsx index 67c30d2e..d95a8c91 100644 --- a/editor-packages/editor-canvas/hud/hud-surface.tsx +++ b/editor-packages/editor-canvas/hud/hud-surface.tsx @@ -2,11 +2,13 @@ import React from "react"; import { HoverOutlineHighlight, ReadonlySelectHightlight, + InSelectionGroupSelectHighlight, SelectHightlight, } from "../overlay"; import { FrameTitle, FrameTitleProps } from "../frame-title"; import type { XY, XYWH } from "../types"; import { Marquee } from "../marquee"; +import { boundingbox, box_to_xywh } from "../math"; interface HudControls { onSelectNode: (node: string) => void; onHoverNode: (node: string) => void; @@ -37,6 +39,7 @@ export function HudSurface({ labelDisplayNodes, selectedNodes, readonly, + disableGrouping = false, onSelectNode, onHoverNode, marquee, @@ -52,6 +55,7 @@ export function HudSurface({ hide: boolean; marquee?: XYWH; disableMarquee?: boolean; + disableGrouping?: boolean; readonly: boolean; } & HudControls & HudCustomRenderers) { @@ -113,43 +117,88 @@ export function HudSurface({ /> ); })} - {selectedNodes && - selectedNodes.map((s) => { - const xywh: [number, number, number, number] = [ - s.absoluteX, - s.absoluteY, - s.width, - s.height, - ]; - if (readonly) { - return ( - - ); - } else { - return ( - - ); - } - })} + {selectedNodes?.length && + (disableGrouping ? ( + selectedNodes.map((s) => { + const xywh: [number, number, number, number] = [ + s.absoluteX, + s.absoluteY, + s.width, + s.height, + ]; + if (readonly) { + return ( + + ); + } else { + return ( + + ); + } + }) + ) : ( + + ))} )}
); } +function SelectionGroupHighlight({ + selections, + zoom, +}: { + selections: DisplayNodeMeta[]; + zoom: number; +}) { + const box = boundingbox( + selections.map((d) => { + return [d.absoluteX, d.absoluteY, d.width, d.height, d.rotation]; + }), + 2 + ); + + const xywh = box_to_xywh(box); + + return ( + <> + <> + {selections.map((s) => { + return ( + + ); + })} + + + + ); +} + const frame_title_default_renderer = (p: FrameTitleProps) => ( ); diff --git a/editor-packages/editor-canvas/math/bounding-box.ts b/editor-packages/editor-canvas/math/bounding-box.ts new file mode 100644 index 00000000..a6edc10d --- /dev/null +++ b/editor-packages/editor-canvas/math/bounding-box.ts @@ -0,0 +1,90 @@ +import type { XYWH, X1Y1X2Y2, Box, XYWHR } from "../types"; + +export function xywh_to_bounding_box({ + xywh, + scale, +}: { + xywh: XYWH; + scale: number; +}): Box { + const [x, y, w, h] = xywh; + + // return the bounding box in [number, number, number, number] form with givven x, y, w, h, rotation and scale. + const [x1, y1, x2, y2] = [ + x * scale, + y * scale, + x * scale + w * scale, + y * scale + h * scale, + ]; + return [x1, y1, x2, y2]; +} + +type BoundingBoxInput = + | (Box & { type?: 0 }) + | (XYWH & { type?: 1 }) + | (XYWHR & { type?: 2 }); + +export function boundingbox( + rects: BoundingBoxInput[], + t?: BoundingBoxInput["type"] +): Box { + let x1 = Infinity; + let y1 = Infinity; + let x2 = -Infinity; + let y2 = -Infinity; + for (const rect of rects) { + const [_x1, _y1, _x2, _y2] = to_box(rect, t); + x1 = Math.min(x1, _x1); + y1 = Math.min(y1, _y1); + x2 = Math.max(x2, _x2); + y2 = Math.max(y2, _y2); + } + return [x1, y1, x2, y2]; +} + +/** + // TODO: handle rotation. (no rotation for now) + * + * @param rect + * @returns + */ +const to_box = (rect: BoundingBoxInput, t?: BoundingBoxInput["type"]): Box => { + let _x1, + _y1, + _x2, + _y2, + _r = 0; + + switch (rect.type ?? t) { + case 0: { + [_x1, _y1, _x2, _y2] = rect; + } + case 1: { + const [x, y, w, h] = rect; + _x1 = x; + _y1 = y; + _x2 = x + w; + _y2 = y + h; + } + case 2: { + const [x, y, w, h, r] = rect; + _x1 = x; + _y1 = y; + _x2 = x + w; + _y2 = y + h; + _r = r; + } + } + + return [_x1, _y1, _x2, _y2]; +}; + +export function box_to_xywh(box: Box): XYWH { + const [x1, y1, x2, y2] = box; + return [x1, y1, x2 - x1, y2 - y1]; +} + +export function box_to_xywhr(box: Box): XYWHR { + const [x1, y1, x2, y2] = box; + return [x1, y1, x2 - x1, y2 - y1, 0]; +} diff --git a/editor-packages/editor-canvas/math/center-of.ts b/editor-packages/editor-canvas/math/center-of.ts index 8b23ee4c..9c9e46e3 100644 --- a/editor-packages/editor-canvas/math/center-of.ts +++ b/editor-packages/editor-canvas/math/center-of.ts @@ -1,4 +1,5 @@ -import type { Box, XY } from "../types"; +import type { Box, XY, XYWHR } from "../types"; +import { boundingbox } from "./bounding-box"; type Rect = { x: number; @@ -24,6 +25,9 @@ export function centerOf( translate: XY; scale: number; } { + const xywhrs = rects.map((r) => { + return [r.x, r.y, r.width, r.height, r.rotation] as XYWHR; + }); if (!rects || rects.length === 0) { return { box: viewbound, @@ -36,7 +40,7 @@ export function centerOf( }; } - const [x1, y1, x2, y2] = bound(...rects); + const [x1, y1, x2, y2] = boundingbox(xywhrs, 2); // box containing the rects. const box: Box = [x1, y1, x2, y2]; // center of the box, viewbound not considered. @@ -63,22 +67,6 @@ export function centerOf( }; } -function bound(...rects: Rect[]): Box { - let x1 = Infinity; - let y1 = Infinity; - let x2 = -Infinity; - let y2 = -Infinity; - for (const rect of rects) { - const { x, y, width: w, height: h } = rect; - // TODO: handle rotation. (no rotation for now) - x1 = Math.min(x1, x); - y1 = Math.min(y1, y); - x2 = Math.max(x2, x + w); - y2 = Math.max(y2, y + h); - } - return [x1, y1, x2, y2]; -} - function rotate(x: number, y: number, r: number): [number, number] { const cos = Math.cos(r); const sin = Math.sin(r); diff --git a/editor-packages/editor-canvas/math/index.ts b/editor-packages/editor-canvas/math/index.ts index 70d1cd75..5cf8cf7e 100644 --- a/editor-packages/editor-canvas/math/index.ts +++ b/editor-packages/editor-canvas/math/index.ts @@ -1,3 +1,4 @@ +export * from "./bounding-box"; export * from "./target-of-area"; export * from "./target-of-point"; export * from "./center-of"; diff --git a/editor-packages/editor-canvas/overlay/hover-outline-hightlight.tsx b/editor-packages/editor-canvas/overlay/hover-outline-hightlight.tsx index 0a878bcf..91fae0c9 100644 --- a/editor-packages/editor-canvas/overlay/hover-outline-hightlight.tsx +++ b/editor-packages/editor-canvas/overlay/hover-outline-hightlight.tsx @@ -1,13 +1,13 @@ import React from "react"; import { color_layer_highlight } from "../theme"; -import { get_boinding_box } from "./math"; +import { xywh_to_bounding_box } from "../math"; import { OulineSide } from "./outline-side"; import { OverlayContainer } from "./overlay-container"; import type { OutlineProps } from "./types"; export function HoverOutlineHighlight({ width = 1, ...props }: OutlineProps) { const { xywh, zoom, rotation } = props; - const bbox = get_boinding_box({ xywh, scale: zoom }); + const bbox = xywh_to_bounding_box({ xywh, scale: zoom }); const wh: [number, number] = [xywh[2], xywh[3]]; const vprops = { wh: wh, diff --git a/editor-packages/editor-canvas/overlay/index.ts b/editor-packages/editor-canvas/overlay/index.ts index 738ec8e9..0edc8078 100644 --- a/editor-packages/editor-canvas/overlay/index.ts +++ b/editor-packages/editor-canvas/overlay/index.ts @@ -1,3 +1,4 @@ export * from "./hover-outline-hightlight"; +export * from "./select-highlight-in-selection-group"; export * from "./select-hightlight"; export * from "./select-hightlight-readonly"; diff --git a/editor-packages/editor-canvas/overlay/math.ts b/editor-packages/editor-canvas/overlay/math.ts deleted file mode 100644 index 9c391b42..00000000 --- a/editor-packages/editor-canvas/overlay/math.ts +++ /dev/null @@ -1,18 +0,0 @@ -export function get_boinding_box({ - xywh, - scale, -}: { - xywh: [number, number, number, number]; - scale: number; -}): [number, number, number, number] { - const [x, y, w, h] = xywh; - - // return the bounding box in [number, number, number, number] form with givven x, y, w, h, rotation and scale. - const [x1, y1, x2, y2] = [ - x * scale, - y * scale, - x * scale + w * scale, - y * scale + h * scale, - ]; - return [x1, y1, x2, y2]; -} diff --git a/editor-packages/editor-canvas/overlay/select-highlight-in-selection-group.tsx b/editor-packages/editor-canvas/overlay/select-highlight-in-selection-group.tsx new file mode 100644 index 00000000..4facd9d2 --- /dev/null +++ b/editor-packages/editor-canvas/overlay/select-highlight-in-selection-group.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import type { OutlineProps } from "./types"; +import { color_layer_readonly_highlight } from "../theme"; +import { xywh_to_bounding_box } from "../math"; +import { OulineSide } from "./outline-side"; +import { OverlayContainer } from "./overlay-container"; + +export function InSelectionGroupSelectHighlight({ + width = 0.3, + ...props +}: OutlineProps) { + const { xywh, zoom, rotation } = props; + const bbox = xywh_to_bounding_box({ xywh, scale: zoom }); + const wh: [number, number] = [xywh[2], xywh[3]]; + + const sideprops = { + wh: wh, + zoom: props.zoom, + width: width, + box: bbox, + color: color_layer_readonly_highlight, + }; + + return ( + + <> + + + + + + + ); +} diff --git a/editor-packages/editor-canvas/overlay/select-hightlight-readonly.tsx b/editor-packages/editor-canvas/overlay/select-hightlight-readonly.tsx index d2b26686..656eaf1a 100644 --- a/editor-packages/editor-canvas/overlay/select-hightlight-readonly.tsx +++ b/editor-packages/editor-canvas/overlay/select-hightlight-readonly.tsx @@ -1,7 +1,7 @@ import React from "react"; import type { OutlineProps } from "./types"; import { color_layer_readonly_highlight } from "../theme"; -import { get_boinding_box } from "./math"; +import { xywh_to_bounding_box } from "../math"; import { OulineSide } from "./outline-side"; import { OverlayContainer } from "./overlay-container"; import { Handle } from "./handle"; @@ -11,7 +11,7 @@ export function ReadonlySelectHightlight({ ...props }: OutlineProps) { const { xywh, zoom, rotation } = props; - const bbox = get_boinding_box({ xywh, scale: zoom }); + const bbox = xywh_to_bounding_box({ xywh, scale: zoom }); const wh: [number, number] = [xywh[2], xywh[3]]; const handle_outline_width = width; diff --git a/editor-packages/editor-canvas/overlay/select-hightlight.tsx b/editor-packages/editor-canvas/overlay/select-hightlight.tsx index e4752bd6..8bd4669b 100644 --- a/editor-packages/editor-canvas/overlay/select-hightlight.tsx +++ b/editor-packages/editor-canvas/overlay/select-hightlight.tsx @@ -1,7 +1,7 @@ import React, { useRef } from "react"; import type { OutlineProps } from "./types"; import { color_layer_highlight } from "../theme"; -import { get_boinding_box } from "./math"; +import { xywh_to_bounding_box } from "../math"; import { OulineSide } from "./outline-side"; import { OverlayContainer } from "./overlay-container"; import { Handle } from "./handle"; @@ -12,7 +12,7 @@ export function SelectHightlight({ ...props }: Omit & {}) { const { xywh, zoom, rotation } = props; - const bbox = get_boinding_box({ xywh, scale: zoom }); + const bbox = xywh_to_bounding_box({ xywh, scale: zoom }); const wh: [number, number] = [xywh[2], xywh[3]]; const sideprops = { diff --git a/editor-packages/editor-canvas/types/index.ts b/editor-packages/editor-canvas/types/index.ts index 907c5e37..edc030df 100644 --- a/editor-packages/editor-canvas/types/index.ts +++ b/editor-packages/editor-canvas/types/index.ts @@ -1,10 +1,33 @@ +/** + * represents a point with x and y + */ export type XY = [number, number]; + +/** + * represents a rectangle with x, y, width, height + */ export type XYWH = [number, number, number, number]; + +/** + * represents a rectangle with x, y, width, height, rotation + */ +export type XYWHR = [number, number, number, number, number]; + +/** + * represents a rectangle with x1, y1, x2, y2 + */ +export type X1Y1X2Y2 = [number, number, number, number]; + export type CanvasTransform = { scale: number; xy: XY; }; -export type Box = [number, number, number, number]; + +/** + * a bounding box with x1, y1, x2, y2 + */ +export type Box = X1Y1X2Y2; + export interface Tree { id: string; /** diff --git a/editor/pages/canvas-server/index.tsx b/editor/pages/canvas-server/index.tsx index a7bd1f8b..25deb849 100644 --- a/editor/pages/canvas-server/index.tsx +++ b/editor/pages/canvas-server/index.tsx @@ -69,7 +69,10 @@ export default function CanvasServerPage() { config={{ can_highlight_selected_layer: true, marquee: { - disabled: true, + disabled: false, + }, + grouping: { + disabled: false, }, }} renderFrameTitle={(p) => ( diff --git a/editor/scaffolds/canvas/canvas.tsx b/editor/scaffolds/canvas/canvas.tsx index 9ce586db..1eaec972 100644 --- a/editor/scaffolds/canvas/canvas.tsx +++ b/editor/scaffolds/canvas/canvas.tsx @@ -145,6 +145,9 @@ export function VisualContentArea() { marquee: { disabled: false, }, + grouping: { + disabled: false, + }, }} renderFrameTitle={(p) => ( Date: Tue, 19 Apr 2022 08:18:26 +0900 Subject: [PATCH 12/67] ignore hover on selected nodes --- editor-packages/editor-canvas/canvas/canvas.tsx | 1 + editor-packages/editor-canvas/hud/hud-surface.tsx | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index 27796777..140fc932 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -211,6 +211,7 @@ export function Canvas({ offset: nonscaled_offset, margin: LAYER_HOVER_HIT_MARGIN, reverse: true, + ignore: (n) => selectedNodes.includes(n.id), }); if (!hovering) { diff --git a/editor-packages/editor-canvas/hud/hud-surface.tsx b/editor-packages/editor-canvas/hud/hud-surface.tsx index d95a8c91..6c1000f6 100644 --- a/editor-packages/editor-canvas/hud/hud-surface.tsx +++ b/editor-packages/editor-canvas/hud/hud-surface.tsx @@ -117,8 +117,8 @@ export function HudSurface({ /> ); })} - {selectedNodes?.length && - (disableGrouping ? ( + {selectedNodes?.length ? ( + disableGrouping ? ( selectedNodes.map((s) => { const xywh: [number, number, number, number] = [ s.absoluteX, @@ -151,7 +151,10 @@ export function HudSurface({ }) ) : ( - ))} + ) + ) : ( + <> + )} )}
From dd713de2adc9ecce163cd711d57acbd2480a4a7a Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Tue, 19 Apr 2022 17:07:00 +0900 Subject: [PATCH 13/67] add move node --- .../editor-canvas/canvas/canvas.tsx | 64 ++++++++++++++++++- .../editor-canvas/core/actions/index.ts | 0 .../editor-canvas/core/dispatch/index.ts | 0 .../editor-canvas/core/reducer/index.ts | 0 .../editor-canvas/core/states/index.ts | 0 .../editor-canvas/math/bounding-box.ts | 8 ++- editor/core/actions/index.ts | 9 +++ editor/core/reducers/editor-reducer.ts | 28 +++++++- editor/scaffolds/canvas/canvas.tsx | 8 +++ 9 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 editor-packages/editor-canvas/core/actions/index.ts create mode 100644 editor-packages/editor-canvas/core/dispatch/index.ts create mode 100644 editor-packages/editor-canvas/core/reducer/index.ts create mode 100644 editor-packages/editor-canvas/core/states/index.ts diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index 140fc932..aedbe3ed 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -14,6 +14,8 @@ import { centerOf, edge_scrolling, target_of_area, + boundingbox, + is_point_inside_box, } from "../math"; import { utils } from "@design-sdk/core"; import { LazyFrame } from "@code-editor/canvas/lazy-frame"; @@ -95,6 +97,9 @@ export function Canvas({ viewbound, renderItem, onSelectNode, + onMoveNodeStart, + onMoveNode, + onMoveNodeEnd, onClearSelection, filekey, pageid, @@ -109,6 +114,9 @@ export function Canvas({ }: { viewbound: Box; onSelectNode?: (...node: ReflectSceneNode[]) => void; + onMoveNodeStart?: (...node: string[]) => void; + onMoveNode?: (delta: XY, ...node: string[]) => void; + onMoveNodeEnd?: (delta: XY, ...node: string[]) => void; onClearSelection?: () => void; } & CanvasCustomRenderers & CanvasState & { @@ -150,7 +158,8 @@ export function Canvas({ ? [offset[0] / zoom, offset[1] / zoom] : [0, 0]; const [isPanning, setIsPanning] = useState(false); - const [isDraggomg, setIsDragging] = useState(false); + const [isDraggimg, setIsDragging] = useState(false); + const [isMovingSelections, setIsMovingSelections] = useState(false); const [marquee, setMarquee] = useState(null); const cvtransform: CanvasTransform = { @@ -200,7 +209,7 @@ export function Canvas({ }, [marquee]); const onPointerMove: OnPointerMoveHandler = (state) => { - if (isPanning || isZooming || isDraggomg) { + if (isPanning || isZooming || isDraggimg) { // don't perform hover calculation while transforming. return; } @@ -230,9 +239,16 @@ export function Canvas({ }; const onPointerDown: OnPointerDownHandler = (state) => { + const [x, y] = [state.event.clientX, state.event.clientY]; + if (isPanning || isZooming) { return; } + + if (shouldStartMoveSelections([x, y])) { + return; // don't do anything. onDrag will handle this. only block the event. + } + if (hoveringLayer) { switch (hoveringLayer.reason) { case "frame-title": @@ -274,7 +290,6 @@ export function Canvas({ }; const onDragStart: OnDragHandler = (s) => { - onClearSelection(); setIsDragging(true); setHoveringLayer(null); @@ -282,9 +297,35 @@ export function Canvas({ const [x, y] = s.initial; const [ox, oy] = offset; const [x1, y1] = [x - ox, y - oy]; + + // if dragging a selection group bounding box, move the selected items. + if (shouldStartMoveSelections([x, y])) { + setIsMovingSelections(true); + onMoveNodeStart?.(...selectedNodes); + return; + } + + // else, clear and start a marquee + onClearSelection(); setMarquee([x1, y1, 0, 0]); }; + const shouldStartMoveSelections = ([cx, cy]) => { + // x, y is a client x, y. + const [ox, oy] = offset; + [cx, cy] = [cx - ox, cy - oy]; + const [x, y] = [cx / zoom, cy / zoom]; + + const box = boundingbox( + selected_nodes.map((d) => { + return [d.absoluteX, d.absoluteY, d.width, d.height, d.rotation]; + }), + 2 + ); + + return is_point_inside_box([x, y], box); + }; + const onDrag: OnDragHandler = (s) => { const [ox, oy] = offset; const [x, y] = [ @@ -296,6 +337,11 @@ export function Canvas({ const [x1, y1] = [x - ox, y - oy]; + if (isMovingSelections) { + const [dx, dy] = s.delta; + onMoveNode?.([dx / zoom, dy / zoom], ...selectedNodes); + } + if (marquee) { const [w, h] = [ x1 - marquee[0], // w @@ -315,6 +361,18 @@ export function Canvas({ const onDragEnd: OnDragHandler = (s) => { setMarquee(null); setIsDragging(false); + if (isMovingSelections) { + const [ix, iy] = s.initial; + const [fx, fy] = [ + //@ts-ignore + s.event.clientX, + //@ts-ignore + s.event.clientY, + ]; + + onMoveNodeEnd?.([(fx - ix) / zoom, (fy - iy) / zoom], ...selectedNodes); + setIsMovingSelections(false); + } }; const is_canvas_transforming = isPanning || isZooming; diff --git a/editor-packages/editor-canvas/core/actions/index.ts b/editor-packages/editor-canvas/core/actions/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/editor-packages/editor-canvas/core/dispatch/index.ts b/editor-packages/editor-canvas/core/dispatch/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/editor-packages/editor-canvas/core/reducer/index.ts b/editor-packages/editor-canvas/core/reducer/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/editor-packages/editor-canvas/core/states/index.ts b/editor-packages/editor-canvas/core/states/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/editor-packages/editor-canvas/math/bounding-box.ts b/editor-packages/editor-canvas/math/bounding-box.ts index a6edc10d..2a852d1e 100644 --- a/editor-packages/editor-canvas/math/bounding-box.ts +++ b/editor-packages/editor-canvas/math/bounding-box.ts @@ -1,4 +1,4 @@ -import type { XYWH, X1Y1X2Y2, Box, XYWHR } from "../types"; +import type { XYWH, Box, XYWHR, XY } from "../types"; export function xywh_to_bounding_box({ xywh, @@ -42,6 +42,12 @@ export function boundingbox( return [x1, y1, x2, y2]; } +export function is_point_inside_box(point: XY, box: Box) { + const [x, y] = point; + const [x1, y1, x2, y2] = box; + return x >= x1 && x <= x2 && y >= y1 && y <= y2; +} + /** // TODO: handle rotation. (no rotation for now) * diff --git a/editor/core/actions/index.ts b/editor/core/actions/index.ts index 4dc3a79e..d521a13d 100644 --- a/editor/core/actions/index.ts +++ b/editor/core/actions/index.ts @@ -18,6 +18,7 @@ export type Action = | PageAction | SelectNodeAction | HighlightLayerAction + | CanvasEditAction | CanvasModeAction | PreviewAction | CodeEditorAction; @@ -30,6 +31,14 @@ export interface SelectNodeAction { node: string | string[]; } +export type CanvasEditAction = TranslateNodeAction; + +export interface TranslateNodeAction { + type: "node-transform-translate"; + translate: [number, number]; + node: string[]; +} + export type PageAction = SelectPageAction; export interface SelectPageAction { diff --git a/editor/core/reducers/editor-reducer.ts b/editor/core/reducers/editor-reducer.ts index 91ddaa7c..4a49436d 100644 --- a/editor/core/reducers/editor-reducer.ts +++ b/editor/core/reducers/editor-reducer.ts @@ -6,6 +6,7 @@ import type { CodeEditorEditComponentCodeAction, CanvasModeSwitchAction, CanvasModeGobackAction, + TranslateNodeAction, PreviewBuildingStateUpdateAction, PreviewSetAction, } from "core/actions"; @@ -13,6 +14,7 @@ import { EditorState } from "core/states"; import { useRouter } from "next/router"; import { CanvasStateStore } from "@code-editor/canvas/stores"; import assert from "assert"; +import { find_node_by_id_under_inpage_nodes } from "@design-sdk/core/utils/query"; const _editor_path_name = "/files/[key]/"; @@ -23,10 +25,18 @@ export function editorReducer(state: EditorState, action: Action): EditorState { switch (action.type) { case "select-node": { const { node } = action; + const ids = Array.isArray(node) ? node : [node]; + + const current_node = state.selectedNodes; + + if (ids.length > 1 && ids.length === current_node.length) { + // the selection event is always triggered by user, which means selecting same amount of nodes (greater thatn 1, and having a different node array is impossible.) + return; + } + console.clear(); console.info("cleard console by editorReducer#select-node"); - const ids = Array.isArray(node) ? node : [node]; const primary = ids?.[0]; // update router @@ -84,6 +94,22 @@ export function editorReducer(state: EditorState, action: Action): EditorState { draft.selectedNodes = last_known_selections_of_this_page; }); } + case "node-transform-translate": { + const { translate, node } = action; + + return produce(state, (draft) => { + const page = draft.design.pages.find( + (p) => p.id === state.selectedPage + ); + + node + .map((n) => find_node_by_id_under_inpage_nodes(n, page.children)) + .map((n) => { + n.x += translate[0]; + n.y += translate[1]; + }); + }); + } case "code-editor-edit-component-code": { const { ...rest } = action; return produce(state, (draft) => { diff --git a/editor/scaffolds/canvas/canvas.tsx b/editor/scaffolds/canvas/canvas.tsx index 1eaec972..afa4c219 100644 --- a/editor/scaffolds/canvas/canvas.tsx +++ b/editor/scaffolds/canvas/canvas.tsx @@ -124,6 +124,14 @@ export function VisualContentArea() { onSelectNode={(...nodes) => { dispatch({ type: "select-node", node: nodes.map((n) => n.id) }); }} + onMoveNodeEnd={([x, y], ...nodes) => { + dispatch({ + type: "node-transform-translate", + node: nodes, + translate: [x, y], + }); + }} + onMoveNode={() => {}} onClearSelection={() => { dispatch({ type: "select-node", node: null }); }} From d56eddd950bd3d3b09cd868bb176a30ad47ec6b4 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Tue, 19 Apr 2022 18:29:52 +0900 Subject: [PATCH 14/67] qf --- .../editor-services-prettier/index.ts | 52 +++++++++++-------- editor/core/reducers/editor-reducer.ts | 2 +- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/editor-packages/editor-services-prettier/index.ts b/editor-packages/editor-services-prettier/index.ts index 847f96d5..d1e4acd0 100644 --- a/editor-packages/editor-services-prettier/index.ts +++ b/editor-packages/editor-services-prettier/index.ts @@ -10,16 +10,20 @@ export function registerDocumentPrettier(editor, monaco) { const dartFormattingEditProvider = { provideDocumentFormattingEdits: (model, options, token) => { - const raw = model.getValue(); - const { code, error } = formatDartCode(raw); - if (error) return []; - __dangerous__lastFormattedValue__global = code; - return [ - { - range: model.getFullModelRange(), - text: code, - }, - ]; + try { + const raw = model.getValue(); + const { code, error } = formatDartCode(raw); + if (error) return []; + __dangerous__lastFormattedValue__global = code; + return [ + { + range: model.getFullModelRange(), + text: code, + }, + ]; + } catch (_) { + // ignore. this is caused by disposed model + } }, }; @@ -31,19 +35,23 @@ export function registerDocumentPrettier(editor, monaco) { ); } - const { canceled, error, pretty } = await prettierWorker?.emit({ - text: model.getValue(), - language: model._languageId, - }); + try { + const { canceled, error, pretty } = await prettierWorker?.emit({ + text: model.getValue(), + language: model._languageId, + }); - if (canceled || error) return []; - __dangerous__lastFormattedValue__global = pretty; - return [ - { - range: model.getFullModelRange(), - text: pretty, - }, - ]; + if (canceled || error) return []; + __dangerous__lastFormattedValue__global = pretty; + return [ + { + range: model.getFullModelRange(), + text: pretty, + }, + ]; + } catch (_) { + // ignore. this is caused by disposed model + } }, }; diff --git a/editor/core/reducers/editor-reducer.ts b/editor/core/reducers/editor-reducer.ts index 4a49436d..9bf831c0 100644 --- a/editor/core/reducers/editor-reducer.ts +++ b/editor/core/reducers/editor-reducer.ts @@ -31,7 +31,7 @@ export function editorReducer(state: EditorState, action: Action): EditorState { if (ids.length > 1 && ids.length === current_node.length) { // the selection event is always triggered by user, which means selecting same amount of nodes (greater thatn 1, and having a different node array is impossible.) - return; + return produce(state, (draft) => {}); } console.clear(); From 6f0bdebed8c17323275b73e297ff9920d6f665ac Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Wed, 20 Apr 2022 16:11:51 +0900 Subject: [PATCH 15/67] add size meter label --- .../editor-canvas/hud/hud-surface.tsx | 20 ++++++ .../editor-canvas/math/bounding-box.ts | 13 ++++ .../editor-canvas/overlay/index.ts | 1 + .../overlay/size-meter-label-box.tsx | 70 +++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 editor-packages/editor-canvas/overlay/size-meter-label-box.tsx diff --git a/editor-packages/editor-canvas/hud/hud-surface.tsx b/editor-packages/editor-canvas/hud/hud-surface.tsx index 6c1000f6..bcb47e13 100644 --- a/editor-packages/editor-canvas/hud/hud-surface.tsx +++ b/editor-packages/editor-canvas/hud/hud-surface.tsx @@ -4,6 +4,7 @@ import { ReadonlySelectHightlight, InSelectionGroupSelectHighlight, SelectHightlight, + SizeMeterLabelBox, } from "../overlay"; import { FrameTitle, FrameTitleProps } from "../frame-title"; import type { XY, XYWH } from "../types"; @@ -164,9 +165,11 @@ export function HudSurface({ function SelectionGroupHighlight({ selections, zoom, + disableSizeDisplay = false, }: { selections: DisplayNodeMeta[]; zoom: number; + disableSizeDisplay?: boolean; }) { const box = boundingbox( selections.map((d) => { @@ -176,6 +179,7 @@ function SelectionGroupHighlight({ ); const xywh = box_to_xywh(box); + const [x, y, w, h] = xywh; return ( <> @@ -191,6 +195,22 @@ function SelectionGroupHighlight({ ); })} + <> + {!disableSizeDisplay ? ( + + ) : ( + <> + )} + xywh_to_bounding_box({ xywh, scale: zoom }), + [xywh, zoom] + ); + + const [x1, y1, x2, y2] = bbox; + const bottomY = y2; + const boxWidth = x2 - x1; // use this to center position the label + + const text = `${+size.width.toFixed(2)} x ${+size.height.toFixed()}`; + + return ( +
+ + + +
+ ); +} + +const Container = styled.div` + display: flex; + border-radius: 4px; + background-color: rgb(0, 87, 255); + box-sizing: border-box; + overflow: auto; + padding: 2px 4px; +`; + +const Label = styled.span` + width: max-content; + color: white; + text-overflow: ellipsis; + font-size: 10px; + font-family: Inter, sans-serif; + font-weight: 500; + text-align: center; +`; From bac24d327f92ba27a715e18a3ed531d10e76c8cf Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Wed, 20 Apr 2022 17:00:18 +0900 Subject: [PATCH 16/67] add shift+0 - zoom to fit command on canvas --- .../canvas-event-target/canvas-event-target.tsx | 6 ++++++ editor-packages/editor-canvas/canvas/canvas.tsx | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/editor-packages/editor-canvas/canvas-event-target/canvas-event-target.tsx b/editor-packages/editor-canvas/canvas-event-target/canvas-event-target.tsx index 7aa7ce70..a7116eee 100644 --- a/editor-packages/editor-canvas/canvas-event-target/canvas-event-target.tsx +++ b/editor-packages/editor-canvas/canvas-event-target/canvas-event-target.tsx @@ -25,6 +25,7 @@ export type OnPointerDownHandler = ( const ZOOM_WITH_SCROLL_SENSITIVITY = 0.001; export function CanvasEventTarget({ + onZoomToFit, onPanning, onPanningStart, onPanningEnd, @@ -40,6 +41,7 @@ export function CanvasEventTarget({ onDragEnd, children, }: { + onZoomToFit?: () => void; onPanning: OnPanningHandler; onPanningStart: OnPanningHandler; onPanningEnd: OnPanningHandler; @@ -69,6 +71,10 @@ export function CanvasEventTarget({ if (e.code === "Space") { setIsSpacebarPressed(true); } + // if shift + 0 + else if (e.code === "Digit0" && e.shiftKey) { + onZoomToFit?.(); + } }; const ku = (e) => { if (e.code === "Space") { diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index aedbe3ed..9ef02099 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -416,6 +416,10 @@ export function Canvas({ setIsPanning(false); _canvas_state_store.saveLastTransform(cvtransform); }} + onZoomToFit={() => { + setZoom(1); + _canvas_state_store.saveLastTransform(cvtransform); + }} onZooming={onZooming} onZoomingStart={() => { setIsZooming(true); From 38805bf3143172035099e9fb74442022e32a39e3 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Wed, 20 Apr 2022 17:07:06 +0900 Subject: [PATCH 17/67] optimized size meter view w/o flex box --- .../overlay/size-meter-label-box.tsx | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx b/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx index 4373674f..8713ab30 100644 --- a/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx +++ b/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx @@ -3,6 +3,8 @@ import styled from "@emotion/styled"; import type { XYWH } from "../types"; import { xywh_to_bounding_box } from "../math"; +const font_size = 10; + export function SizeMeterLabelBox({ size, anchor = "s", @@ -29,42 +31,33 @@ export function SizeMeterLabelBox({ const boxWidth = x2 - x1; // use this to center position the label const text = `${+size.width.toFixed(2)} x ${+size.height.toFixed()}`; + const labelwidth = (text.length * font_size) / 1.8; // a view width assumption (we will not use flex box for faster painting) + const viewwidth = labelwidth + 4; // 4 is for horizontal padding + + const [tx, ty] = [x1 + boxWidth / 2 - viewwidth / 2, y2 + margin]; return (
- - - + {text}
); } - -const Container = styled.div` - display: flex; - border-radius: 4px; - background-color: rgb(0, 87, 255); - box-sizing: border-box; - overflow: auto; - padding: 2px 4px; -`; - -const Label = styled.span` - width: max-content; - color: white; - text-overflow: ellipsis; - font-size: 10px; - font-family: Inter, sans-serif; - font-weight: 500; - text-align: center; -`; From 1cfd49e623fea2a4af31fc3bd64ad1102f278d28 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Wed, 20 Apr 2022 17:20:08 +0900 Subject: [PATCH 18/67] init core-drafting docs --- .../editor-canvas/core/drafting/README.md | 0 .../editor-canvas/core/drafting/index.ts | 0 .../core/drafting/transform-drafting.ts | 0 .../editor-canvas/docs/core-drafting.md | 20 +++++++++++++++++++ 4 files changed, 20 insertions(+) create mode 100644 editor-packages/editor-canvas/core/drafting/README.md create mode 100644 editor-packages/editor-canvas/core/drafting/index.ts create mode 100644 editor-packages/editor-canvas/core/drafting/transform-drafting.ts create mode 100644 editor-packages/editor-canvas/docs/core-drafting.md diff --git a/editor-packages/editor-canvas/core/drafting/README.md b/editor-packages/editor-canvas/core/drafting/README.md new file mode 100644 index 00000000..e69de29b diff --git a/editor-packages/editor-canvas/core/drafting/index.ts b/editor-packages/editor-canvas/core/drafting/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/editor-packages/editor-canvas/core/drafting/transform-drafting.ts b/editor-packages/editor-canvas/core/drafting/transform-drafting.ts new file mode 100644 index 00000000..e69de29b diff --git a/editor-packages/editor-canvas/docs/core-drafting.md b/editor-packages/editor-canvas/docs/core-drafting.md new file mode 100644 index 00000000..65d6b4d3 --- /dev/null +++ b/editor-packages/editor-canvas/docs/core-drafting.md @@ -0,0 +1,20 @@ +# State (property drafting) + +There are properties that are highly likely to be updated every frame (e.g. position, rotation, scale, etc.). +This are performed by drag-related user input, and this properties will not be modified direcly to the design model. + +The final callback to the higher state holder will be called once after this operation is complete. + +## The properties are.. + +**transform** + +- x +- y +- width +- height +- rotation + +**style** + +- color From e5efe761613e4e1531966661c02777897c35f0bf Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Thu, 21 Apr 2022 12:22:50 +0900 Subject: [PATCH 19/67] wip --- .../editor-canvas/canvas/canvas.tsx | 1 + .../editor-canvas/core/drafting/README.md | 1 + .../core/drafting/transform-drafting.ts | 41 +++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index 9ef02099..a947caf2 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -418,6 +418,7 @@ export function Canvas({ }} onZoomToFit={() => { setZoom(1); + // setOffset([newx, newy]); // TODO: set offset to center of the viewport _canvas_state_store.saveLastTransform(cvtransform); }} onZooming={onZooming} diff --git a/editor-packages/editor-canvas/core/drafting/README.md b/editor-packages/editor-canvas/core/drafting/README.md index e69de29b..31b8de9a 100644 --- a/editor-packages/editor-canvas/core/drafting/README.md +++ b/editor-packages/editor-canvas/core/drafting/README.md @@ -0,0 +1 @@ +# Properties drafting diff --git a/editor-packages/editor-canvas/core/drafting/transform-drafting.ts b/editor-packages/editor-canvas/core/drafting/transform-drafting.ts index e69de29b..f3e0204e 100644 --- a/editor-packages/editor-canvas/core/drafting/transform-drafting.ts +++ b/editor-packages/editor-canvas/core/drafting/transform-drafting.ts @@ -0,0 +1,41 @@ +// move +// resize + +// width +// height +// x +// y +// rotation + +abstract class DraftingStore { + readonly store = new Map(); + + abstract update(id: string, draft: T); + + abstract get(id: string): T; +} + +interface Transform { + x: number; + y: number; + width: number; + height: number; + rotation: number; +} + +class TransformDraftingStore extends DraftingStore { + constructor(draftingStore: DraftingStore) { + super(); + } + + update(id: string, transform: Transform) { + this.store.set(id, transform); + } + + get(id: string): Transform { + return this.store.get(id); + } +} + +// const store = new TransformDraftingStore(); +// export function From d1099b18cf2e01ea059873868f20c8b71a34a4cf Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Fri, 22 Apr 2022 11:22:32 +0900 Subject: [PATCH 20/67] distroy web workers on editor dispose --- .../index.ts | 8 ++++++++ .../code-editor/monaco-utils/register.ts | 20 +++++++++++++++---- editor/components/code-editor/monaco.tsx | 6 +++++- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/editor-packages/editor-services-jsx-syntax-highlight/index.ts b/editor-packages/editor-services-jsx-syntax-highlight/index.ts index 6f8b0a0f..df30d42e 100644 --- a/editor-packages/editor-services-jsx-syntax-highlight/index.ts +++ b/editor-packages/editor-services-jsx-syntax-highlight/index.ts @@ -54,4 +54,12 @@ export function registerJsxHighlighter( oldDecor = editor.deltaDecorations(oldDecor, decorations); }); }); + + return { + dispose() { + if (syntaxWorker) { + syntaxWorker.terminate(); + } + }, + }; } diff --git a/editor/components/code-editor/monaco-utils/register.ts b/editor/components/code-editor/monaco-utils/register.ts index b56784c7..561c3454 100644 --- a/editor/components/code-editor/monaco-utils/register.ts +++ b/editor/components/code-editor/monaco-utils/register.ts @@ -1,12 +1,24 @@ import * as monaco from "monaco-editor"; -import { Monaco, OnMount } from "@monaco-editor/react"; +import { Monaco } from "@monaco-editor/react"; import { registerDocumentPrettier } from "@code-editor/prettier-services"; import { registerJsxHighlighter } from "@code-editor/jsx-syntax-highlight-services"; type CompilerOptions = monaco.languages.typescript.CompilerOptions; -export const initEditor: OnMount = (editor, monaco) => { - registerJsxHighlighter(editor, monaco); - registerDocumentPrettier(editor, monaco); +export const initEditor = ( + editor: monaco.editor.IStandaloneCodeEditor, + monaco: Monaco +) => { + const { dispose: disposeJsxHighlighter } = registerJsxHighlighter( + editor, + monaco + ); + + const { dispose: disposePrettier } = registerDocumentPrettier(editor, monaco); + + return () => { + disposeJsxHighlighter(); + disposePrettier(); + }; }; export const initMonaco = (monaco: Monaco) => { diff --git a/editor/components/code-editor/monaco.tsx b/editor/components/code-editor/monaco.tsx index 919011a0..ea199449 100644 --- a/editor/components/code-editor/monaco.tsx +++ b/editor/components/code-editor/monaco.tsx @@ -29,7 +29,7 @@ export function MonacoEditor(props: MonacoEditorProps) { instance.current = { editor, format }; - register.initEditor(editor, monaco); + const dispose = register.initEditor(editor, monaco); editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, function () { format.run(); @@ -65,6 +65,10 @@ export function MonacoEditor(props: MonacoEditorProps) { editor.onDidChangeModelContent(() => debounce(() => editor.saveViewState(), 200) ); + + editor.onDidDispose(() => { + dispose(); + }); }; return ( From 43fc7fb52f0769ad6f3eae85c4b910cf27e93caf Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Fri, 22 Apr 2022 11:22:38 +0900 Subject: [PATCH 21/67] safety --- editor/scaffolds/editor/editor-preview-provider.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/editor/scaffolds/editor/editor-preview-provider.tsx b/editor/scaffolds/editor/editor-preview-provider.tsx index 93aee854..c36237f9 100644 --- a/editor/scaffolds/editor/editor-preview-provider.tsx +++ b/editor/scaffolds/editor/editor-preview-provider.tsx @@ -173,6 +173,7 @@ export function EditorPreviewDataProvider({ // // ------ for esbuild ----- useEffect(() => { if ( + !target || !state.editingModule || // now only react is supported. state.editingModule.framework !== "react" From 4e183698cffbbe278a623c301b0a35eb970621f7 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Fri, 22 Apr 2022 12:40:21 +0900 Subject: [PATCH 22/67] add dummy auth state to workspace state --- editor/core/states/workspace-state.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/editor/core/states/workspace-state.ts b/editor/core/states/workspace-state.ts index 21ca4492..d62cd1cc 100644 --- a/editor/core/states/workspace-state.ts +++ b/editor/core/states/workspace-state.ts @@ -8,6 +8,16 @@ export interface WorkspaceState { */ highlightedLayer?: string; preferences: WorkspacePreferences; + + /** + * figma authentication data store state + * @deprecated - not implemented + */ + authenticationFigma?: { + name?: string; + accessToken?: string; + personalAccessToken?: string; + }; } export interface WorkspacePreferences { From 0ed282d17bf55a73d5e3a28ef265ece9e2ec9ee9 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Fri, 22 Apr 2022 12:40:50 +0900 Subject: [PATCH 23/67] split & cleanup --- editor/pages/canvas-server/index.tsx | 13 +- editor/scaffolds/canvas/canvas.tsx | 30 +- .../{preview => preview-canvas}/README.md | 0 editor/scaffolds/preview-canvas/cache.ts | 16 + .../canvas-preview-worker-messenger.ts | 49 +++ .../editor-canvas-preview-provider.tsx | 24 ++ .../preview-canvas/image-preview.tsx | 70 ++++ editor/scaffolds/preview-canvas/index.ts | 2 + .../preview-canvas/preview-content.tsx | 44 +++ editor/scaffolds/preview-canvas/prop-type.ts | 8 + editor/scaffolds/preview-canvas/util.ts | 8 + .../preview-canvas/vanilla-preview-async.tsx | 151 ++++++++ .../vanilla-preview-webworker.tsx | 33 ++ .../workers/canvas-preview.worker.js | 103 ++++++ editor/scaffolds/preview/index.tsx | 347 ------------------ .../preview/workers/vanilla.worker.js | 78 ---- 16 files changed, 524 insertions(+), 452 deletions(-) rename editor/scaffolds/{preview => preview-canvas}/README.md (100%) create mode 100644 editor/scaffolds/preview-canvas/cache.ts create mode 100644 editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts create mode 100644 editor/scaffolds/preview-canvas/editor-canvas-preview-provider.tsx create mode 100644 editor/scaffolds/preview-canvas/image-preview.tsx create mode 100644 editor/scaffolds/preview-canvas/index.ts create mode 100644 editor/scaffolds/preview-canvas/preview-content.tsx create mode 100644 editor/scaffolds/preview-canvas/prop-type.ts create mode 100644 editor/scaffolds/preview-canvas/util.ts create mode 100644 editor/scaffolds/preview-canvas/vanilla-preview-async.tsx create mode 100644 editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx create mode 100644 editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js delete mode 100644 editor/scaffolds/preview/index.tsx delete mode 100644 editor/scaffolds/preview/workers/vanilla.worker.js diff --git a/editor/pages/canvas-server/index.tsx b/editor/pages/canvas-server/index.tsx index 25deb849..4197a46a 100644 --- a/editor/pages/canvas-server/index.tsx +++ b/editor/pages/canvas-server/index.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"; import { D2CVanillaPreview, WebWorkerD2CVanillaPreview, -} from "scaffolds/preview"; +} from "scaffolds/preview-canvas"; import { Canvas } from "@code-editor/canvas"; import useMeasure from "react-use-measure"; import { FrameTitleRenderer } from "scaffolds/canvas/render/frame-title"; @@ -17,17 +17,6 @@ export default function CanvasServerPage() { const [canvasSizingRef, canvasBounds] = useMeasure(); const [selectedPage, setSelectedPage] = useState(null); - // useEffect(() => { - // const handler = (e) => { - // // - // }; - - // window.addEventListener("message", handler); - // return () => { - // window.removeEventListener("message", handler); - // }; - // }, []); - // const thisPageNodes = selectedPage // ? design.pages.find((p) => p.id == selectedPage).children.filter(Boolean) // : []; diff --git a/editor/scaffolds/canvas/canvas.tsx b/editor/scaffolds/canvas/canvas.tsx index afa4c219..d6bd4b90 100644 --- a/editor/scaffolds/canvas/canvas.tsx +++ b/editor/scaffolds/canvas/canvas.tsx @@ -5,7 +5,7 @@ import { useEditorState, useWorkspace } from "core/states"; import { D2CVanillaPreview, WebWorkerD2CVanillaPreview, -} from "scaffolds/preview"; +} from "scaffolds/preview-canvas"; import useMeasure from "react-use-measure"; import { useDispatch } from "core/dispatch"; import { FrameTitleRenderer } from "./render/frame-title"; @@ -124,14 +124,14 @@ export function VisualContentArea() { onSelectNode={(...nodes) => { dispatch({ type: "select-node", node: nodes.map((n) => n.id) }); }} - onMoveNodeEnd={([x, y], ...nodes) => { - dispatch({ - type: "node-transform-translate", - node: nodes, - translate: [x, y], - }); - }} - onMoveNode={() => {}} + // onMoveNodeEnd={([x, y], ...nodes) => { + // dispatch({ + // type: "node-transform-translate", + // node: nodes, + // translate: [x, y], + // }); + // }} + // onMoveNode={() => {}} onClearSelection={() => { dispatch({ type: "select-node", node: null }); }} @@ -139,12 +139,12 @@ export function VisualContentArea() { // initialTransform={ } // TODO: if the initial selection is provided from first load, from the query param, we have to focus to fit that node. renderItem={(p) => { return ( - // - + + // ); }} readonly={false} diff --git a/editor/scaffolds/preview/README.md b/editor/scaffolds/preview-canvas/README.md similarity index 100% rename from editor/scaffolds/preview/README.md rename to editor/scaffolds/preview-canvas/README.md diff --git a/editor/scaffolds/preview-canvas/cache.ts b/editor/scaffolds/preview-canvas/cache.ts new file mode 100644 index 00000000..b0b6170a --- /dev/null +++ b/editor/scaffolds/preview-canvas/cache.ts @@ -0,0 +1,16 @@ +import type { Result } from "@designto/code"; + +type TResultCache = Result & { __image: boolean }; + +export const cache = { + set: (key: string, value: TResultCache) => { + sessionStorage.setItem(key, JSON.stringify(value)); + }, + get: (key: string): TResultCache => { + const value = sessionStorage.getItem(key); + return value ? JSON.parse(value) : null; + }, +}; + +export const cachekey = (target: { filekey; id }) => + target ? `${target.filekey}-${target.id}-${new Date().getMinutes()}` : null; diff --git a/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts b/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts new file mode 100644 index 00000000..48e4de2e --- /dev/null +++ b/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts @@ -0,0 +1,49 @@ +import { createWorkerQueue } from "@code-editor/webworker-services-core"; +import type { Result } from "@designto/code"; + +let previewworker: Worker; +export function initialize(filekey: string, authentication) { + // initialize the worker and set the preferences. + if (!previewworker) { + const { worker } = createWorkerQueue( + new Worker(new URL("./workers/vanilla.worker.js", import.meta.url)) + ); + + previewworker = worker; + } + + previewworker.postMessage({ + $type: "init", + filekey, + authentication, + }); + + return () => { + if (previewworker) { + previewworker.terminate(); + } + }; +} + +export function preview( + node: string, + onResult: (result: Result) => void, + onError?: (error: Error) => void +) { + previewworker.postMessage({ + $type: "preview", + node, + }); + + previewworker.addEventListener("message", (e) => { + // TODO: add id matcher (?) + switch (e.data.$type) { + case "result": + onResult(e.data); + break; + case "error": + onError(new Error(e.data.message)); + break; + } + }); +} diff --git a/editor/scaffolds/preview-canvas/editor-canvas-preview-provider.tsx b/editor/scaffolds/preview-canvas/editor-canvas-preview-provider.tsx new file mode 100644 index 00000000..8b3194f7 --- /dev/null +++ b/editor/scaffolds/preview-canvas/editor-canvas-preview-provider.tsx @@ -0,0 +1,24 @@ +import React, { useEffect } from "react"; +import { useFigmaAccessToken } from "hooks/use-figma-access-token"; +import { initialize } from "scaffolds/preview-canvas/canvas-preview-worker-messenger"; +import { useEditorState } from "core/states"; + +export function EditorCanvasPreviewProvider({ + children, +}: { + children?: React.ReactNode; +}) { + const [state] = useEditorState(); + const fat = useFigmaAccessToken(); + + useEffect(() => { + if ( + state.design.key && + (fat.personalAccessToken || !fat.accessToken.loading) + ) { + initialize(state.design.key, fat); + } + }, [fat, state.design.key]); + + return <>{children}; +} diff --git a/editor/scaffolds/preview-canvas/image-preview.tsx b/editor/scaffolds/preview-canvas/image-preview.tsx new file mode 100644 index 00000000..14fa30cf --- /dev/null +++ b/editor/scaffolds/preview-canvas/image-preview.tsx @@ -0,0 +1,70 @@ +import React, { useState, useEffect } from "react"; +import { remote } from "@design-sdk/figma"; + +const DEV_ONLY_FIGMA_PAT = + process.env.NEXT_PUBLIC_DEVELOPER_FIGMA_PERSONAL_ACCESS_TOKEN; + +export function FigmaFrameImageView({ + filekey, + nodeid, + zoom, +}: { + filekey: string; + nodeid: string; + zoom: number; +}) { + // fetch image + const [image_1, setImage_1] = useState(); + const [image_s, setImage_s] = useState(); + + useEffect(() => { + // fetch image from figma + // fetch smaller one first, then fatch the full scaled. + remote + .fetchNodeAsImage( + filekey, + { personalAccessToken: DEV_ONLY_FIGMA_PAT }, + nodeid + // scale = 1 + ) + .then((r) => { + console.log("fetched image from figma", r); + setImage_1(r.__default); + setImage_s(r.__default); + }); + }, [filekey, nodeid]); + + let imgscale: 1 | 0.2 = 1; + if (zoom > 1) { + return null; + } else if (zoom <= 1 && zoom > 0.3) { + imgscale = 1; + // display 1 scaled image + } else { + // display 0.2 scaled image + imgscale = 0.2; + } + + return ( +
+ +
+ ); +} diff --git a/editor/scaffolds/preview-canvas/index.ts b/editor/scaffolds/preview-canvas/index.ts new file mode 100644 index 00000000..042ca293 --- /dev/null +++ b/editor/scaffolds/preview-canvas/index.ts @@ -0,0 +1,2 @@ +export { D2CVanillaPreview } from "./vanilla-preview-async"; +export { WebWorkerD2CVanillaPreview } from "./vanilla-preview-webworker"; diff --git a/editor/scaffolds/preview-canvas/preview-content.tsx b/editor/scaffolds/preview-canvas/preview-content.tsx new file mode 100644 index 00000000..fb7a8b0e --- /dev/null +++ b/editor/scaffolds/preview-canvas/preview-content.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { VanillaRunner } from "components/app-runner/vanilla-app-runner"; + +export function PreviewContent({ + width, + height, + backgroundColor, + id, + source, + name, +}: { + width: number; + height: number; + backgroundColor: string; + id: string; + source: string; + name: string; +}) { + return ( +
+ {source && ( + + )} +
+ ); +} diff --git a/editor/scaffolds/preview-canvas/prop-type.ts b/editor/scaffolds/preview-canvas/prop-type.ts new file mode 100644 index 00000000..7e856a35 --- /dev/null +++ b/editor/scaffolds/preview-canvas/prop-type.ts @@ -0,0 +1,8 @@ +import type { ReflectSceneNode } from "@design-sdk/figma-node"; +import type { FrameOptimizationFactors } from "@code-editor/canvas/frame"; + +export type VanillaPreviewProps = { + target: ReflectSceneNode & { + filekey: string; + }; +} & FrameOptimizationFactors; diff --git a/editor/scaffolds/preview-canvas/util.ts b/editor/scaffolds/preview-canvas/util.ts new file mode 100644 index 00000000..70ea6024 --- /dev/null +++ b/editor/scaffolds/preview-canvas/util.ts @@ -0,0 +1,8 @@ +import { colorFromFills } from "@design-sdk/core/utils/colors"; +import type { ReflectSceneNode } from "@design-sdk/figma-node"; + +export const blurred_bg_fill = (target: ReflectSceneNode) => { + const __bg = colorFromFills(target.fills); + const bg_color_str = __bg ? "#" + __bg.hex : "transparent"; + return bg_color_str; +}; diff --git a/editor/scaffolds/preview-canvas/vanilla-preview-async.tsx b/editor/scaffolds/preview-canvas/vanilla-preview-async.tsx new file mode 100644 index 00000000..d7e99b22 --- /dev/null +++ b/editor/scaffolds/preview-canvas/vanilla-preview-async.tsx @@ -0,0 +1,151 @@ +import React, { useEffect, useState } from "react"; +import { config } from "@designto/config"; +import { preview_presets } from "@grida/builder-config-preset"; +import { designToCode, Result } from "@designto/code"; +import { MainImageRepository } from "@design-sdk/core/assets-repository"; +import { cachekey, cache } from "./cache"; +import { blurred_bg_fill } from "./util"; +import { PreviewContent } from "./preview-content"; +import type { VanillaPreviewProps } from "./prop-type"; + +const placeholderimg = + "https://bridged-service-static.s3.us-west-1.amazonaws.com/placeholder-images/image-placeholder-bw-tile-100.png"; + +const build_config: config.BuildConfiguration = { + ...config.default_build_configuration, + disable_components: true, + disable_detection: true, + disable_flags_support: true, +}; + +const framework_config: config.VanillaPreviewFrameworkConfig = { + ...preview_presets.default, + additional_css_declaration: { + declarations: [ + { + key: { + name: "body", + selector: "tag", + }, + style: { + contain: "layout style paint", + }, + }, + ], + }, +}; + +export function D2CVanillaPreview({ + target, + isZooming, + isPanning, +}: VanillaPreviewProps) { + const [preview, setPreview] = useState(); + const key = cachekey(target); + + const on_preview_result = (result: Result, __image: boolean) => { + if (preview) { + if (preview.code === result.code) { + return; + } + } + setPreview(result); + cache.set(target.filekey, { ...result, __image }); + }; + + const hide_preview = isZooming || isPanning; + + useEffect(() => { + if (hide_preview) { + // don't make preview if zooming. + return; + } + + if (preview) { + return; + } + + const d2c_firstload = () => { + return designToCode({ + input: _input, + build_config: build_config, + framework: framework_config, + asset_config: { + skip_asset_replacement: false, + asset_repository: MainImageRepository.instance, + custom_asset_replacement: { + type: "static", + resource: placeholderimg, + }, + }, + }); + }; + + const d2c_imageload = () => { + if (!MainImageRepository.instance.empty) { + designToCode({ + input: _input, + build_config: build_config, + framework: framework_config, + asset_config: { asset_repository: MainImageRepository.instance }, + }) + .then((r) => { + on_preview_result(r, true); + }) + .catch((e) => { + console.error( + "error while making preview with image repo provided.", + e + ); + }); + } + }; + + const _input = target + ? { + id: target.id, + name: target.name, + entry: target, + } + : null; + + const cached = cache.get(key); + if (cached) { + setPreview(cached); + if (cached.__image) { + return; + } + if (_input) { + d2c_imageload(); + } + } else { + if (_input) { + d2c_firstload() + .then((r) => { + on_preview_result(r, false); + // if the result contains a image and needs to be fetched, + if (r.code.raw.includes(placeholderimg)) { + // TODO: we don't yet have other way to know if image is used, other than checking if placeholder image is used. - this needs to be updated in d2c module to include used images meta in the result. + d2c_imageload(); + } + }) + .catch(console.error); + } + } + }, [target?.id, isZooming, isPanning]); + + const bg_color_str = blurred_bg_fill(target); + + return ( + + ); +} diff --git a/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx b/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx new file mode 100644 index 00000000..d0496fde --- /dev/null +++ b/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx @@ -0,0 +1,33 @@ +import React, { useEffect, useState } from "react"; +import type { Result } from "@designto/code"; +import { PreviewContent } from "./preview-content"; +import type { VanillaPreviewProps } from "./prop-type"; +import { blurred_bg_fill } from "./util"; +import { cachekey, cache } from "./cache"; +import { preview as wwpreview } from "./canvas-preview-worker-messenger"; + +export function WebWorkerD2CVanillaPreview({ target }: VanillaPreviewProps) { + const [preview, setPreview] = useState(); + const bg_color_str = blurred_bg_fill(target); + + useEffect(() => { + if (preview) { + return; + } + + wwpreview(target.id, setPreview); + }, [target?.id]); + + return ( + + ); +} diff --git a/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js b/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js new file mode 100644 index 00000000..7022a7ba --- /dev/null +++ b/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js @@ -0,0 +1,103 @@ +import { designToCode } from "@designto/code"; +import { + ImageRepository, + MainImageRepository, +} from "@design-sdk/core/assets-repository"; +import { RemoteImageRepositories } from "@design-sdk/figma-remote/lib/asset-repository/image-repository"; +import { config } from "@designto/config"; +import { preview_presets } from "@grida/builder-config-preset"; + +const placeholderimg = + "https://bridged-service-static.s3.us-west-1.amazonaws.com/placeholder-images/image-placeholder-bw-tile-100.png"; + +// : config.BuildConfiguration +const build_config = { + ...config.default_build_configuration, + disable_components: true, + disable_detection: true, + disable_flags_support: true, +}; + +// : config.VanillaPreviewFrameworkConfig +const framework_config = { + ...preview_presets.default, + additional_css_declaration: { + declarations: [ + { + key: { + name: "body", + selector: "tag", + }, + style: { + contain: "layout style paint", + }, + }, + ], + }, +}; + +function initialize({ filekey, authentication }) { + // ------- setup image repo with auth + filekey ------- + MainImageRepository.instance = new RemoteImageRepositories(filekey, { + authentication: authentication, + }); + + MainImageRepository.instance.register( + new ImageRepository( + "fill-later-assets", + "grida://assets-reservation/images/" + ) + ); + // ---------------------------------------------------- + + // setup indexed db connection for reading the file. + // ⛔️ the assumbtion is that file does not change during the app is running. + + // 1. read the raw data from indexed db + // 2. format the data to reflect + // 3. set the data status as 'ready' + // (the below requests can be operated after when this processes are complete) +} + +addEventListener("message", async (event) => { + function respond(data) { + setTimeout(() => { + postMessage({ $type: "result", ...data }); + }, 0); + } + + switch (event.data.$type) { + case "initialize": { + initialize({ + filekey: event.data.filekey, + authentication: event.data.authentication, + }); + return; + } + case "preview": { + try { + const { node } = event.data; + + const result = await designToCode({ + input: input, + build_config: build_config, + framework: framework_config, + asset_config: { + skip_asset_replacement: false, + asset_repository: MainImageRepository.instance, + custom_asset_replacement: { + type: "static", + resource: placeholderimg, + }, + }, + }); + + respond(result); + } catch (error) { + respond({ error }); + } + + break; + } + } +}); diff --git a/editor/scaffolds/preview/index.tsx b/editor/scaffolds/preview/index.tsx deleted file mode 100644 index cb8a51a8..00000000 --- a/editor/scaffolds/preview/index.tsx +++ /dev/null @@ -1,347 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { preview_presets } from "@grida/builder-config-preset"; -import { designToCode, Result } from "@designto/code"; -import { config } from "@designto/config"; -import { MainImageRepository } from "@design-sdk/core/assets-repository"; -import type { ReflectSceneNode } from "@design-sdk/figma-node"; -import { VanillaRunner } from "components/app-runner/vanilla-app-runner"; -import { colorFromFills } from "@design-sdk/core/utils/colors"; -import type { FrameOptimizationFactors } from "@code-editor/canvas/frame"; -import { remote } from "@design-sdk/figma"; - -const DEV_ONLY_FIGMA_PAT = - process.env.NEXT_PUBLIC_DEVELOPER_FIGMA_PERSONAL_ACCESS_TOKEN; - -const placeholderimg = - "https://bridged-service-static.s3.us-west-1.amazonaws.com/placeholder-images/image-placeholder-bw-tile-100.png"; - -const build_config: config.BuildConfiguration = { - ...config.default_build_configuration, - disable_components: true, - disable_detection: true, - disable_flags_support: true, -}; - -const framework_config: config.VanillaPreviewFrameworkConfig = { - ...preview_presets.default, - additional_css_declaration: { - declarations: [ - { - key: { - name: "body", - selector: "tag", - }, - style: { - contain: "layout style paint", - }, - }, - ], - }, -}; - -type TResultCache = Result & { __image: boolean }; -const cache = { - set: (key: string, value: TResultCache) => { - sessionStorage.setItem(key, JSON.stringify(value)); - }, - get: (key: string): TResultCache => { - const value = sessionStorage.getItem(key); - return value ? JSON.parse(value) : null; - }, -}; - -const cachekey = (target: { filekey; id }) => - target ? `${target.filekey}-${target.id}-${new Date().getMinutes()}` : null; - -const blurred_bg_fill = (target: ReflectSceneNode) => { - const __bg = colorFromFills(target.fills); - const bg_color_str = __bg ? "#" + __bg.hex : "transparent"; - return bg_color_str; -}; - -type VanillaPreviewProps = { - target: ReflectSceneNode & { - filekey: string; - }; -} & FrameOptimizationFactors; - -export function D2CVanillaPreview({ - target, - isZooming, - isPanning, -}: VanillaPreviewProps) { - const [preview, setPreview] = useState(); - const key = cachekey(target); - - const on_preview_result = (result: Result, __image: boolean) => { - if (preview) { - if (preview.code === result.code) { - return; - } - } - setPreview(result); - cache.set(target.filekey, { ...result, __image }); - }; - - const hide_preview = isZooming || isPanning; - - useEffect(() => { - if (hide_preview) { - // don't make preview if zooming. - return; - } - - if (preview) { - return; - } - - const d2c_firstload = () => { - return designToCode({ - input: _input, - build_config: build_config, - framework: framework_config, - asset_config: { - skip_asset_replacement: false, - asset_repository: MainImageRepository.instance, - custom_asset_replacement: { - type: "static", - resource: placeholderimg, - }, - }, - }); - }; - - const d2c_imageload = () => { - if (!MainImageRepository.instance.empty) { - designToCode({ - input: _input, - build_config: build_config, - framework: framework_config, - asset_config: { asset_repository: MainImageRepository.instance }, - }) - .then((r) => { - on_preview_result(r, true); - }) - .catch((e) => { - console.error( - "error while making preview with image repo provided.", - e - ); - }); - } - }; - - const _input = target - ? { - id: target.id, - name: target.name, - entry: target, - } - : null; - - const cached = cache.get(key); - if (cached) { - setPreview(cached); - if (cached.__image) { - return; - } - if (_input) { - d2c_imageload(); - } - } else { - if (_input) { - d2c_firstload() - .then((r) => { - on_preview_result(r, false); - // if the result contains a image and needs to be fetched, - if (r.code.raw.includes(placeholderimg)) { - // TODO: we don't yet have other way to know if image is used, other than checking if placeholder image is used. - this needs to be updated in d2c module to include used images meta in the result. - d2c_imageload(); - } - }) - .catch(console.error); - } - } - }, [target?.id, isZooming, isPanning]); - - const bg_color_str = blurred_bg_fill(target); - - return ( - - ); -} - -import { createWorkerQueue } from "@code-editor/webworker-services-core"; -import { useFigmaAccessToken } from "hooks/use-figma-access-token"; - -export function WebWorkerD2CVanillaPreview({ target }: VanillaPreviewProps) { - const [preview, setPreview] = useState(); - const bg_color_str = blurred_bg_fill(target); - - const fat = useFigmaAccessToken(); - - useEffect(() => { - if (preview) { - return; - } - - const { worker, terminate } = createWorkerQueue( - new Worker(new URL("./workers/vanilla.worker.js", import.meta.url)) - ); - - const input = target - ? { - id: target.id, - name: target.name, - entry: target, - } - : null; - - // TODO: this is not production ready - worker.postMessage({ - input, - authentication: fat, - filekey: target.filekey, - }); - - worker.addEventListener("message", (e) => { - // console.log(target.id, e.data.id); - // if (((e.data as Result).id = target.id)) { - setPreview(e.data as Result); - // } - }); - - () => { - terminate(); - }; - }, [target?.id]); - - return ( - - ); -} - -function PreviewContent({ - width, - height, - backgroundColor, - id, - source, - name, -}: { - width: number; - height: number; - backgroundColor: string; - id: string; - source: string; - name: string; -}) { - return ( -
- {source && ( - - )} -
- ); -} - -function FigmaFrameImageView({ - filekey, - nodeid, - zoom, -}: { - filekey: string; - nodeid: string; - zoom: number; -}) { - // fetch image - const [image_1, setImage_1] = useState(); - const [image_s, setImage_s] = useState(); - - useEffect(() => { - // fetch image from figma - // fetch smaller one first, then fatch the full scaled. - remote - .fetchNodeAsImage( - filekey, - { personalAccessToken: DEV_ONLY_FIGMA_PAT }, - nodeid - // scale = 1 - ) - .then((r) => { - console.log("fetched image from figma", r); - setImage_1(r.__default); - setImage_s(r.__default); - }); - }, [filekey, nodeid]); - - let imgscale: 1 | 0.2 = 1; - if (zoom > 1) { - return null; - } else if (zoom <= 1 && zoom > 0.3) { - imgscale = 1; - // display 1 scaled image - } else { - // display 0.2 scaled image - imgscale = 0.2; - } - - return ( -
- -
- ); -} diff --git a/editor/scaffolds/preview/workers/vanilla.worker.js b/editor/scaffolds/preview/workers/vanilla.worker.js deleted file mode 100644 index 9ddfef0b..00000000 --- a/editor/scaffolds/preview/workers/vanilla.worker.js +++ /dev/null @@ -1,78 +0,0 @@ -import { designToCode } from "@designto/code"; -import { - ImageRepository, - MainImageRepository, -} from "@design-sdk/core/assets-repository"; -import { RemoteImageRepositories } from "@design-sdk/figma-remote/lib/asset-repository/image-repository"; -import { config } from "@designto/config"; -import { preview_presets } from "@grida/builder-config-preset"; - -const placeholderimg = - "https://bridged-service-static.s3.us-west-1.amazonaws.com/placeholder-images/image-placeholder-bw-tile-100.png"; - -// : config.BuildConfiguration -const build_config = { - ...config.default_build_configuration, - disable_components: true, - disable_detection: true, - disable_flags_support: true, -}; - -// : config.VanillaPreviewFrameworkConfig -const framework_config = { - ...preview_presets.default, - additional_css_declaration: { - declarations: [ - { - key: { - name: "body", - selector: "tag", - }, - style: { - contain: "layout style paint", - }, - }, - ], - }, -}; - -addEventListener("message", async (event) => { - function respond(data) { - setTimeout(() => { - postMessage({ type: "response", ...data }); - }, 0); - } - - try { - const { input, authentication, filekey } = event.data; - - MainImageRepository.instance = new RemoteImageRepositories(filekey, { - authentication: authentication, - }); - - MainImageRepository.instance.register( - new ImageRepository( - "fill-later-assets", - "grida://assets-reservation/images/" - ) - ); - - const result = await designToCode({ - input: input, - build_config: build_config, - framework: framework_config, - asset_config: { - skip_asset_replacement: false, - asset_repository: MainImageRepository.instance, - custom_asset_replacement: { - type: "static", - resource: placeholderimg, - }, - }, - }); - - respond(result); - } catch (error) { - respond({ error }); - } -}); From da552cbc07e9cddb8c5e92250542ce6efbb30484 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Fri, 22 Apr 2022 12:56:15 +0900 Subject: [PATCH 24/67] add wwpreview provider --- editor/scaffolds/canvas/canvas.tsx | 128 +++++++++--------- .../canvas-preview-worker-messenger.ts | 2 +- .../workers/canvas-preview.worker.js | 5 + 3 files changed, 73 insertions(+), 62 deletions(-) diff --git a/editor/scaffolds/canvas/canvas.tsx b/editor/scaffolds/canvas/canvas.tsx index d6bd4b90..5202406f 100644 --- a/editor/scaffolds/canvas/canvas.tsx +++ b/editor/scaffolds/canvas/canvas.tsx @@ -12,6 +12,7 @@ import { FrameTitleRenderer } from "./render/frame-title"; import { IsolateModeCanvas } from "./isolate-mode"; import { Dialog } from "@material-ui/core"; import { FullScreenPreview } from "scaffolds/preview-full-screen"; +import { EditorCanvasPreviewProvider } from "scaffolds/preview-canvas/editor-canvas-preview-provider"; /** * Statefull canvas segment that contains canvas as a child, with state-data connected. @@ -103,70 +104,75 @@ export function VisualContentArea() { onEnterFullscreen={startFullscreenPreviewMode} /> )} -
- { - dispatch({ type: "select-node", node: nodes.map((n) => n.id) }); + +
{ - // dispatch({ - // type: "node-transform-translate", - // node: nodes, - // translate: [x, y], - // }); - // }} - // onMoveNode={() => {}} - onClearSelection={() => { - dispatch({ type: "select-node", node: null }); - }} - nodes={thisPageNodes} - // initialTransform={ } // TODO: if the initial selection is provided from first load, from the query param, we have to focus to fit that node. - renderItem={(p) => { - return ( - + { + dispatch({ + type: "select-node", + node: nodes.map((n) => n.id), + }); + }} + // onMoveNodeEnd={([x, y], ...nodes) => { + // dispatch({ + // type: "node-transform-translate", + // node: nodes, + // translate: [x, y], + // }); + // }} + // onMoveNode={() => {}} + onClearSelection={() => { + dispatch({ type: "select-node", node: null }); + }} + nodes={thisPageNodes} + // initialTransform={ } // TODO: if the initial selection is provided from first load, from the query param, we have to focus to fit that node. + renderItem={(p) => { + return ( + + // + ); + }} + readonly={false} + config={{ + can_highlight_selected_layer: true, + marquee: { + disabled: false, + }, + grouping: { + disabled: false, + }, + }} + renderFrameTitle={(p) => ( + - // - ); - }} - readonly={false} - config={{ - can_highlight_selected_layer: true, - marquee: { - disabled: false, - }, - grouping: { - disabled: false, - }, - }} - renderFrameTitle={(p) => ( - - )} - /> -
+ )} + /> +
+ )}
diff --git a/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts b/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts index 48e4de2e..96f6a6e3 100644 --- a/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts +++ b/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts @@ -6,7 +6,7 @@ export function initialize(filekey: string, authentication) { // initialize the worker and set the preferences. if (!previewworker) { const { worker } = createWorkerQueue( - new Worker(new URL("./workers/vanilla.worker.js", import.meta.url)) + new Worker(new URL("./workers/canvas-preview.worker.js", import.meta.url)) ); previewworker = worker; diff --git a/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js b/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js index 7022a7ba..aec8702d 100644 --- a/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js +++ b/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js @@ -37,6 +37,7 @@ const framework_config = { }; function initialize({ filekey, authentication }) { + console.info("initializing.. wwpreview"); // ------- setup image repo with auth + filekey ------- MainImageRepository.instance = new RemoteImageRepositories(filekey, { authentication: authentication, @@ -57,6 +58,9 @@ function initialize({ filekey, authentication }) { // 2. format the data to reflect // 3. set the data status as 'ready' // (the below requests can be operated after when this processes are complete) + // indexedDB.open("").onsuccess = (event) => { + // // + // }; } addEventListener("message", async (event) => { @@ -78,6 +82,7 @@ addEventListener("message", async (event) => { try { const { node } = event.data; + throw "not ready"; const result = await designToCode({ input: input, build_config: build_config, From 0b2119728d22919e2d120ba78b1b6ab06797ddde Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Fri, 22 Apr 2022 13:01:06 +0900 Subject: [PATCH 25/67] match interface --- .../code-editor/monaco-utils/register-preset-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/components/code-editor/monaco-utils/register-preset-types.ts b/editor/components/code-editor/monaco-utils/register-preset-types.ts index e9c61041..3e29f689 100644 --- a/editor/components/code-editor/monaco-utils/register-preset-types.ts +++ b/editor/components/code-editor/monaco-utils/register-preset-types.ts @@ -17,5 +17,5 @@ const react_preset_dependencies = [ */ export function registerPresetTypes() { // load the react presets - loadTypes(react_preset_dependencies); + return loadTypes(react_preset_dependencies); } From 40476ee3a81b764e375990ffa4d6a44be6a20226 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Fri, 22 Apr 2022 13:50:21 +0900 Subject: [PATCH 26/67] prevent same selection triggering state update --- editor/core/reducers/editor-reducer.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/editor/core/reducers/editor-reducer.ts b/editor/core/reducers/editor-reducer.ts index d2fcc6fe..0f75afef 100644 --- a/editor/core/reducers/editor-reducer.ts +++ b/editor/core/reducers/editor-reducer.ts @@ -31,6 +31,15 @@ export function editorReducer(state: EditorState, action: Action): EditorState { const current_node = state.selectedNodes; + if ( + ids.length <= 1 && + current_node.length <= 1 && + ids[0] === current_node[0] + ) { + // same selection (no selection or same 1 selection) + return produce(state, (draft) => {}); + } + if (ids.length > 1 && ids.length === current_node.length) { // the selection event is always triggered by user, which means selecting same amount of nodes (greater thatn 1, and having a different node array is impossible.) return produce(state, (draft) => {}); From bbfc2aa569a3ddbd8051ac39688df46d360247e6 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Fri, 22 Apr 2022 15:02:59 +0900 Subject: [PATCH 27/67] made figma file store as a package --- .../editor-store-figma-file}/figma-file-store.ts | 2 +- .../editor-store-figma-file}/index.ts | 0 editor-packages/editor-store-figma-file/package.json | 4 ++++ editor/pages/files/index.tsx | 2 +- editor/repository/figma-design-repository/index.ts | 5 +---- editor/repository/workspace-repository/index.ts | 5 +---- editor/store/index.ts | 1 + 7 files changed, 9 insertions(+), 10 deletions(-) rename {editor/store/fimga-file-store => editor-packages/editor-store-figma-file}/figma-file-store.ts (97%) rename {editor/store/fimga-file-store => editor-packages/editor-store-figma-file}/index.ts (100%) create mode 100644 editor-packages/editor-store-figma-file/package.json diff --git a/editor/store/fimga-file-store/figma-file-store.ts b/editor-packages/editor-store-figma-file/figma-file-store.ts similarity index 97% rename from editor/store/fimga-file-store/figma-file-store.ts rename to editor-packages/editor-store-figma-file/figma-file-store.ts index f4dbbca2..ce603552 100644 --- a/editor/store/fimga-file-store/figma-file-store.ts +++ b/editor-packages/editor-store-figma-file/figma-file-store.ts @@ -1,5 +1,5 @@ import { openDB, IDBPDatabase } from "idb"; -import { FileResponse } from "@design-sdk/figma-remote-api"; +import type { FileResponse } from "@design-sdk/figma-remote-api"; // #region global db initialization const __db_pref = { name: "fimga-file-store", version: 1 }; diff --git a/editor/store/fimga-file-store/index.ts b/editor-packages/editor-store-figma-file/index.ts similarity index 100% rename from editor/store/fimga-file-store/index.ts rename to editor-packages/editor-store-figma-file/index.ts diff --git a/editor-packages/editor-store-figma-file/package.json b/editor-packages/editor-store-figma-file/package.json new file mode 100644 index 00000000..299c259c --- /dev/null +++ b/editor-packages/editor-store-figma-file/package.json @@ -0,0 +1,4 @@ +{ + "name": "@editor/figma-file-store", + "version": "0.0.0" +} \ No newline at end of file diff --git a/editor/pages/files/index.tsx b/editor/pages/files/index.tsx index 8ec7c948..4ccae5ee 100644 --- a/editor/pages/files/index.tsx +++ b/editor/pages/files/index.tsx @@ -8,7 +8,7 @@ import { HomeSidebar, } from "components/home"; import { WorkspaceRepository } from "repository"; -import { FileResponseRecord } from "store/fimga-file-store/figma-file-store"; +import { FileResponseRecord } from "@editor/figma-file-store"; import { colors } from "theme"; export default function FilesPage() { diff --git a/editor/repository/figma-design-repository/index.ts b/editor/repository/figma-design-repository/index.ts index 27695a6c..ead1055a 100644 --- a/editor/repository/figma-design-repository/index.ts +++ b/editor/repository/figma-design-repository/index.ts @@ -1,9 +1,6 @@ import { fetch } from "@design-sdk/figma-remote"; import { FileResponse } from "@design-sdk/figma-remote-types"; -import { - FigmaFileStore, - FileResponseRecord, -} from "store/fimga-file-store/figma-file-store"; +import { FigmaFileStore, FileResponseRecord } from "@editor/figma-file-store"; export type TFetchFileForApp = ( | fetch.FetchFileGeneratorReturnType diff --git a/editor/repository/workspace-repository/index.ts b/editor/repository/workspace-repository/index.ts index c03388d5..98bb2503 100644 --- a/editor/repository/workspace-repository/index.ts +++ b/editor/repository/workspace-repository/index.ts @@ -1,7 +1,4 @@ -import { - FigmaFilesStore, - FileResponseRecord, -} from "store/fimga-file-store/figma-file-store"; +import { FigmaFilesStore, FileResponseRecord } from "@editor/figma-file-store"; export type LastUsedFileDisplay = FileResponseRecord & { type: "file" } & { lastUsed: Date; diff --git a/editor/store/index.ts b/editor/store/index.ts index c5235dc3..9b865148 100644 --- a/editor/store/index.ts +++ b/editor/store/index.ts @@ -1 +1,2 @@ +export * from "@editor/figma-file-store"; export * from "./remote-design-session-cache-store"; From 7006705a98640403cfa046a5d29d3275409b2b13 Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Fri, 22 Apr 2022 15:03:59 +0900 Subject: [PATCH 28/67] wip: wwpreview without queue, w 50ms delay --- .../editor-canvas/canvas/canvas.tsx | 6 +- editor/scaffolds/canvas/canvas.tsx | 131 +++++++++--------- editor/scaffolds/editor/_providers.tsx | 7 +- .../canvas-preview-worker-messenger.ts | 46 ++++-- .../editor-canvas-preview-provider.tsx | 14 +- editor/scaffolds/preview-canvas/prop-type.ts | 1 + .../vanilla-preview-webworker.tsx | 16 ++- .../workers/canvas-preview.worker.js | 81 +++++++++-- 8 files changed, 199 insertions(+), 103 deletions(-) diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index a947caf2..75fd3150 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -50,7 +50,7 @@ interface CanvasState { type CanvasCustomRenderers = HudCustomRenderers & { renderItem: ( p: { - node: ReflectSceneNode & { filekey: string }; + node: ReflectSceneNode & { filekey: string; page: string }; } & FrameOptimizationFactors ) => React.ReactNode; }; @@ -383,13 +383,15 @@ export function Canvas({ const items = useMemo(() => { return nodes?.map((node) => { node["filekey"] = filekey; + node["page"] = pageid; + return ( {/* 👇 dev only (for performance tracking) 👇 */} {/*
*/} {/* 👆 ----------------------------------- 👆 */} {renderItem({ - node: node as ReflectSceneNode & { filekey: string }, + node: node as ReflectSceneNode & { filekey: string; page: string }, zoom, // ? use scaled_zoom ? inViewport: true, // TODO: isZooming: isZooming, diff --git a/editor/scaffolds/canvas/canvas.tsx b/editor/scaffolds/canvas/canvas.tsx index 796f5b90..63a7b848 100644 --- a/editor/scaffolds/canvas/canvas.tsx +++ b/editor/scaffolds/canvas/canvas.tsx @@ -12,7 +12,6 @@ import { FrameTitleRenderer } from "./render/frame-title"; import { IsolateModeCanvas } from "./isolate-mode"; import { Dialog } from "@mui/material"; import { FullScreenPreview } from "scaffolds/preview-full-screen"; -import { EditorCanvasPreviewProvider } from "scaffolds/preview-canvas/editor-canvas-preview-provider"; /** * Statefull canvas segment that contains canvas as a child, with state-data connected. @@ -104,75 +103,73 @@ export function VisualContentArea() { onEnterFullscreen={startFullscreenPreviewMode} /> )} - -
+ { + dispatch({ + type: "select-node", + node: nodes.map((n) => n.id), + }); }} - > - { - dispatch({ - type: "select-node", - node: nodes.map((n) => n.id), - }); - }} - // onMoveNodeEnd={([x, y], ...nodes) => { - // dispatch({ - // type: "node-transform-translate", - // node: nodes, - // translate: [x, y], - // }); - // }} - // onMoveNode={() => {}} - onClearSelection={() => { - dispatch({ type: "select-node", node: null }); - }} - nodes={thisPageNodes} - // initialTransform={ } // TODO: if the initial selection is provided from first load, from the query param, we have to focus to fit that node. - renderItem={(p) => { - return ( - - // - ); - }} - readonly={false} - config={{ - can_highlight_selected_layer: true, - marquee: { - disabled: false, - }, - grouping: { - disabled: false, - }, - }} - renderFrameTitle={(p) => ( - { + // dispatch({ + // type: "node-transform-translate", + // node: nodes, + // translate: [x, y], + // }); + // }} + // onMoveNode={() => {}} + onClearSelection={() => { + dispatch({ type: "select-node", node: [] }); + }} + nodes={thisPageNodes} + // initialTransform={ } // TODO: if the initial selection is provided from first load, from the query param, we have to focus to fit that node. + renderItem={(p) => { + return ( + - )} - /> -
-
+ // + ); + }} + readonly={false} + config={{ + can_highlight_selected_layer: true, + marquee: { + disabled: false, + }, + grouping: { + disabled: false, + }, + }} + renderFrameTitle={(p) => ( + + )} + /> +
)} diff --git a/editor/scaffolds/editor/_providers.tsx b/editor/scaffolds/editor/_providers.tsx index 7ad76825..1fa593c0 100644 --- a/editor/scaffolds/editor/_providers.tsx +++ b/editor/scaffolds/editor/_providers.tsx @@ -2,12 +2,17 @@ import React from "react"; import { useHotkeys } from "react-hotkeys-hook"; import { EditorImageRepositoryProvider } from "./editor-image-repository-provider"; import { EditorPreviewDataProvider } from "./editor-preview-provider"; +import { EditorCanvasPreviewProvider } from "scaffolds/preview-canvas/editor-canvas-preview-provider"; export function EditorDefaultProviders(props: { children: React.ReactNode }) { return ( - {props.children} + + + {props.children} + + ); diff --git a/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts b/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts index 96f6a6e3..dfc98577 100644 --- a/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts +++ b/editor/scaffolds/preview-canvas/canvas-preview-worker-messenger.ts @@ -2,7 +2,10 @@ import { createWorkerQueue } from "@code-editor/webworker-services-core"; import type { Result } from "@designto/code"; let previewworker: Worker; -export function initialize(filekey: string, authentication) { +export function initialize( + { filekey, authentication }: { filekey: string; authentication }, + onReady: () => void +) { // initialize the worker and set the preferences. if (!previewworker) { const { worker } = createWorkerQueue( @@ -13,11 +16,17 @@ export function initialize(filekey: string, authentication) { } previewworker.postMessage({ - $type: "init", + $type: "initialize", filekey, authentication, }); + previewworker.addEventListener("message", (e) => { + if (e.data.$type === "data-readt") { + onReady(); + } + }); + return () => { if (previewworker) { previewworker.terminate(); @@ -26,24 +35,33 @@ export function initialize(filekey: string, authentication) { } export function preview( - node: string, + { target, page }: { target: string; page: string }, onResult: (result: Result) => void, onError?: (error: Error) => void ) { previewworker.postMessage({ $type: "preview", - node, + page, + target, }); - previewworker.addEventListener("message", (e) => { - // TODO: add id matcher (?) - switch (e.data.$type) { - case "result": - onResult(e.data); - break; - case "error": - onError(new Error(e.data.message)); - break; + const handler = (e) => { + const id = e.data.id; + if (target === id) { + switch (e.data.$type) { + case "result": + onResult(e.data); + break; + case "error": + onError(new Error(e.data.message)); + break; + } } - }); + }; + + previewworker.addEventListener("message", handler); + + return () => { + previewworker.removeEventListener("message", handler); + }; } diff --git a/editor/scaffolds/preview-canvas/editor-canvas-preview-provider.tsx b/editor/scaffolds/preview-canvas/editor-canvas-preview-provider.tsx index 8b3194f7..7c49031e 100644 --- a/editor/scaffolds/preview-canvas/editor-canvas-preview-provider.tsx +++ b/editor/scaffolds/preview-canvas/editor-canvas-preview-provider.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from "react"; import { useFigmaAccessToken } from "hooks/use-figma-access-token"; -import { initialize } from "scaffolds/preview-canvas/canvas-preview-worker-messenger"; import { useEditorState } from "core/states"; +import { initialize } from "./canvas-preview-worker-messenger"; export function EditorCanvasPreviewProvider({ children, @@ -13,12 +13,18 @@ export function EditorCanvasPreviewProvider({ useEffect(() => { if ( - state.design.key && + state.design?.key && (fat.personalAccessToken || !fat.accessToken.loading) ) { - initialize(state.design.key, fat); + const authentication = { + personalAccessToken: fat.personalAccessToken, + accessToken: fat.accessToken.token, + }; + initialize({ filekey: state.design.key, authentication }, () => { + // + }); } - }, [fat, state.design.key]); + }, [fat.personalAccessToken, fat.accessToken.token, state.design?.key]); return <>{children}; } diff --git a/editor/scaffolds/preview-canvas/prop-type.ts b/editor/scaffolds/preview-canvas/prop-type.ts index 7e856a35..0d39baa7 100644 --- a/editor/scaffolds/preview-canvas/prop-type.ts +++ b/editor/scaffolds/preview-canvas/prop-type.ts @@ -3,6 +3,7 @@ import type { FrameOptimizationFactors } from "@code-editor/canvas/frame"; export type VanillaPreviewProps = { target: ReflectSceneNode & { + page: string; filekey: string; }; } & FrameOptimizationFactors; diff --git a/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx b/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx index d0496fde..2cef7a22 100644 --- a/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx +++ b/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx @@ -15,7 +15,21 @@ export function WebWorkerD2CVanillaPreview({ target }: VanillaPreviewProps) { return; } - wwpreview(target.id, setPreview); + let dispose; + + setTimeout(() => { + dispose = wwpreview( + { + page: target.page, + target: target.id, + }, + setPreview + ); + }, 50); + + return () => { + dispose?.(); + }; }, [target?.id]); return ( diff --git a/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js b/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js index aec8702d..2025cc75 100644 --- a/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js +++ b/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js @@ -6,6 +6,9 @@ import { import { RemoteImageRepositories } from "@design-sdk/figma-remote/lib/asset-repository/image-repository"; import { config } from "@designto/config"; import { preview_presets } from "@grida/builder-config-preset"; +import { FigmaFileStore } from "@editor/figma-file-store"; +import { convert } from "@design-sdk/figma-node-conversion"; +import { mapper } from "@design-sdk/figma-remote"; const placeholderimg = "https://bridged-service-static.s3.us-west-1.amazonaws.com/placeholder-images/image-placeholder-bw-tile-100.png"; @@ -36,6 +39,9 @@ const framework_config = { }, }; +let initialized = false; +let pages = []; + function initialize({ filekey, authentication }) { console.info("initializing.. wwpreview"); // ------- setup image repo with auth + filekey ------- @@ -54,13 +60,31 @@ function initialize({ filekey, authentication }) { // setup indexed db connection for reading the file. // ⛔️ the assumbtion is that file does not change during the app is running. + const store = new FigmaFileStore(filekey); // 1. read the raw data from indexed db - // 2. format the data to reflect - // 3. set the data status as 'ready' + store.get().then((raw) => { + // 2. format the data to reflect + pages = pagesFrom(raw); + + // 3. set the data status as 'ready' + initialized = true; + postMessage({ $type: "data-ready" }); + }); // (the below requests can be operated after when this processes are complete) - // indexedDB.open("").onsuccess = (event) => { - // // - // }; +} + +function pagesFrom(file) { + return file.document.children.map((page) => ({ + id: page.id, + name: page.name, + children: page["children"]?.map((child) => { + const _mapped = mapper.mapFigmaRemoteToFigma(child); + return convert.intoReflectNode(_mapped); + }), + flowStartingPoints: page.flowStartingPoints, + backgroundColor: page.backgroundColor, + type: "design", + })); } addEventListener("message", async (event) => { @@ -70,21 +94,39 @@ addEventListener("message", async (event) => { }, 0); } + if (event.data.$type === "initialize") { + initialize({ + filekey: event.data.filekey, + authentication: event.data.authentication, + }); + return; + } + + if (!initialized) { + return; + } + switch (event.data.$type) { case "initialize": { - initialize({ - filekey: event.data.filekey, - authentication: event.data.authentication, - }); - return; + // unreachable + break; } case "preview": { try { - const { node } = event.data; + // requires all 2 data for faster query + const { page, target } = event.data; + const node = pages + .find((p) => p.id === page) + .children.find((c) => c.id === target); + + const _input = { + id: node.id, + name: node.name, + entry: node, + }; - throw "not ready"; const result = await designToCode({ - input: input, + input: _input, build_config: build_config, framework: framework_config, asset_config: { @@ -98,8 +140,19 @@ addEventListener("message", async (event) => { }); respond(result); + + const result_w_img = await designToCode({ + input: _input, + build_config: build_config, + framework: framework_config, + asset_config: { + asset_repository: MainImageRepository.instance, + }, + }); + + respond(result_w_img); } catch (error) { - respond({ error }); + // respond({ error }); } break; From 028c42dd0dc3d9ddfa9b9355009b256f8a2fe348 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Fri, 22 Apr 2022 15:09:52 +0900 Subject: [PATCH 29/67] extract constants --- .../editor-canvas/canvas/canvas.tsx | 41 ++++++++++--------- editor-packages/editor-canvas/k/index.ts | 6 +++ 2 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 editor-packages/editor-canvas/k/index.ts diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index a947caf2..3fe24331 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -22,12 +22,15 @@ import { LazyFrame } from "@code-editor/canvas/lazy-frame"; import { HudCustomRenderers, HudSurface } from "../hud"; import type { Box, XY, CanvasTransform, XYWH } from "../types"; import type { FrameOptimizationFactors } from "../frame"; -const designq = utils.query; +import { TransformDraftingStore } from "../drafting"; +import { + CANVAS_LAYER_HOVER_HIT_MARGIN, + CANVAS_INITIAL_XY, + CANVAS_INITIAL_SCALE, + CANVAS_MIN_ZOOM, +} from "../k"; -const INITIAL_SCALE = 0.5; -const INITIAL_XY: XY = [0, 0]; -const LAYER_HOVER_HIT_MARGIN = 3.5; -const MIN_ZOOM = 0.02; +const designq = utils.query; interface CanvasState { pageid: string; @@ -122,11 +125,6 @@ export function Canvas({ CanvasState & { config?: CanvsPreferences; }) { - const _canvas_state_store = useMemo( - () => new CanvasStateStore(filekey, pageid), - [filekey, pageid] - ); - useEffect(() => { if (transformIntitialized) { return; @@ -162,6 +160,16 @@ export function Canvas({ const [isMovingSelections, setIsMovingSelections] = useState(false); const [marquee, setMarquee] = useState(null); + const is_canvas_transforming = isPanning || isZooming; + const selected_nodes = selectedNodes + ?.map((id) => designq.find_node_by_id_under_inpage_nodes(id, nodes)) + .filter(Boolean); + + const _canvas_state_store = useMemo( + () => new CanvasStateStore(filekey, pageid), + [filekey, pageid] + ); + const cvtransform: CanvasTransform = { scale: zoom, xy: offset, @@ -218,7 +226,7 @@ export function Canvas({ tree: nodes, zoom: zoom, offset: nonscaled_offset, - margin: LAYER_HOVER_HIT_MARGIN, + margin: CANVAS_LAYER_HOVER_HIT_MARGIN, reverse: true, ignore: (n) => selectedNodes.includes(n.id), }); @@ -277,7 +285,7 @@ export function Canvas({ // the origin point of the zooming point in x, y const [ox, oy]: XY = state.origin; - const newzoom = Math.max(zoom + zoomdelta, MIN_ZOOM); + const newzoom = Math.max(zoom + zoomdelta, CANVAS_MIN_ZOOM); // calculate the offset that should be applied with scale with css transform. const [newx, newy] = [ @@ -375,11 +383,6 @@ export function Canvas({ } }; - const is_canvas_transforming = isPanning || isZooming; - const selected_nodes = selectedNodes - ?.map((id) => designq.find_node_by_id_under_inpage_nodes(id, nodes)) - .filter(Boolean); - const items = useMemo(() => { return nodes?.map((node) => { node["filekey"] = filekey; @@ -541,8 +544,8 @@ function auto_initial_transform( nodes: ReflectSceneNode[] ): CanvasTransform { const _default = { - scale: INITIAL_SCALE, - xy: INITIAL_XY, + scale: CANVAS_INITIAL_SCALE, + xy: CANVAS_INITIAL_XY, }; if (!nodes || viewbound_not_measured(viewbound)) { diff --git a/editor-packages/editor-canvas/k/index.ts b/editor-packages/editor-canvas/k/index.ts new file mode 100644 index 00000000..45a7c562 --- /dev/null +++ b/editor-packages/editor-canvas/k/index.ts @@ -0,0 +1,6 @@ +import type { XY } from "../types"; + +export const CANVAS_INITIAL_SCALE = 0.5; +export const CANVAS_INITIAL_XY: XY = [0, 0]; +export const CANVAS_LAYER_HOVER_HIT_MARGIN = 3.5; +export const CANVAS_MIN_ZOOM = 0.02; From 7601d80e44b2c5940352783933712503cfc7decd Mon Sep 17 00:00:00 2001 From: "UZU, J" Date: Fri, 22 Apr 2022 16:46:03 +0900 Subject: [PATCH 30/67] qf --- editor-packages/editor-canvas/canvas/canvas.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index a3f75adf..930e96c2 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -22,7 +22,7 @@ import { LazyFrame } from "@code-editor/canvas/lazy-frame"; import { HudCustomRenderers, HudSurface } from "../hud"; import type { Box, XY, CanvasTransform, XYWH } from "../types"; import type { FrameOptimizationFactors } from "../frame"; -import { TransformDraftingStore } from "../drafting"; +// import { TransformDraftingStore } from "../drafting"; import { CANVAS_LAYER_HOVER_HIT_MARGIN, CANVAS_INITIAL_XY, From 03196c709fc6bc8a1e11a837240afd2098a41a44 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 25 Apr 2022 20:13:59 +0900 Subject: [PATCH 31/67] update drafting --- .../editor-canvas/core/drafting/index.ts | 0 .../core/drafting/transform-drafting.ts | 41 ------------- .../{core => }/drafting/README.md | 0 editor-packages/editor-canvas/drafting/_.ts | 16 ++++++ .../editor-canvas/drafting/index.ts | 1 + .../drafting/transform-drafting.ts | 57 +++++++++++++++++++ 6 files changed, 74 insertions(+), 41 deletions(-) delete mode 100644 editor-packages/editor-canvas/core/drafting/index.ts delete mode 100644 editor-packages/editor-canvas/core/drafting/transform-drafting.ts rename editor-packages/editor-canvas/{core => }/drafting/README.md (100%) create mode 100644 editor-packages/editor-canvas/drafting/_.ts create mode 100644 editor-packages/editor-canvas/drafting/index.ts create mode 100644 editor-packages/editor-canvas/drafting/transform-drafting.ts diff --git a/editor-packages/editor-canvas/core/drafting/index.ts b/editor-packages/editor-canvas/core/drafting/index.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/editor-packages/editor-canvas/core/drafting/transform-drafting.ts b/editor-packages/editor-canvas/core/drafting/transform-drafting.ts deleted file mode 100644 index f3e0204e..00000000 --- a/editor-packages/editor-canvas/core/drafting/transform-drafting.ts +++ /dev/null @@ -1,41 +0,0 @@ -// move -// resize - -// width -// height -// x -// y -// rotation - -abstract class DraftingStore { - readonly store = new Map(); - - abstract update(id: string, draft: T); - - abstract get(id: string): T; -} - -interface Transform { - x: number; - y: number; - width: number; - height: number; - rotation: number; -} - -class TransformDraftingStore extends DraftingStore { - constructor(draftingStore: DraftingStore) { - super(); - } - - update(id: string, transform: Transform) { - this.store.set(id, transform); - } - - get(id: string): Transform { - return this.store.get(id); - } -} - -// const store = new TransformDraftingStore(); -// export function diff --git a/editor-packages/editor-canvas/core/drafting/README.md b/editor-packages/editor-canvas/drafting/README.md similarity index 100% rename from editor-packages/editor-canvas/core/drafting/README.md rename to editor-packages/editor-canvas/drafting/README.md diff --git a/editor-packages/editor-canvas/drafting/_.ts b/editor-packages/editor-canvas/drafting/_.ts new file mode 100644 index 00000000..d32c40a7 --- /dev/null +++ b/editor-packages/editor-canvas/drafting/_.ts @@ -0,0 +1,16 @@ +export abstract class DraftingStore { + readonly store = new Map(); + lastUpdated: number; + + constructor() { + this.lastUpdated = Date.now(); + } + + abstract update(id: string, draft: T); + + abstract get(id: string): T; + + updated() { + this.lastUpdated = Date.now(); + } +} diff --git a/editor-packages/editor-canvas/drafting/index.ts b/editor-packages/editor-canvas/drafting/index.ts new file mode 100644 index 00000000..ab76e45e --- /dev/null +++ b/editor-packages/editor-canvas/drafting/index.ts @@ -0,0 +1 @@ +export * from "./transform-drafting"; diff --git a/editor-packages/editor-canvas/drafting/transform-drafting.ts b/editor-packages/editor-canvas/drafting/transform-drafting.ts new file mode 100644 index 00000000..3521a27d --- /dev/null +++ b/editor-packages/editor-canvas/drafting/transform-drafting.ts @@ -0,0 +1,57 @@ +import type { XY } from "../types"; +import { DraftingStore } from "./_"; +// move +// resize + +// width +// height +// x +// y +// rotation + +interface Transform { + x: number; + y: number; + width: number; + height: number; + rotation: number; +} + +export class TransformDraftingStore extends DraftingStore { + constructor(transforrms: (Transform & { id: string })[]) { + super(); + + transforrms.forEach((transform) => { + this.store.set(transform.id, TransformDraftingStore.flat(transform)); + }); + } + + static flat(t: Transform): Transform { + return { + x: t.x, + y: t.y, + width: t.width, + height: t.height, + rotation: t.rotation, + }; + } + + moveBy(delta: XY) { + Object.keys(this.store).forEach((id) => { + this.store[id].x += delta[0]; + this.store[id].y += delta[1]; + }); + this.updated(); + } + + update(id: string, transform: Transform) { + this.store.set(id, TransformDraftingStore.flat(transform)); + this.updated(); + } + + get(id: string, fallback?: Transform): Transform { + return this.store.get(id) ?? fallback; + } +} + +// export function From 251ba504a7adae9f31f273fde8cac96d7954baa7 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 25 Apr 2022 20:14:04 +0900 Subject: [PATCH 32/67] add types --- editor-packages/editor-canvas/types/index.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/editor-packages/editor-canvas/types/index.ts b/editor-packages/editor-canvas/types/index.ts index edc030df..793db67e 100644 --- a/editor-packages/editor-canvas/types/index.ts +++ b/editor-packages/editor-canvas/types/index.ts @@ -42,3 +42,13 @@ export interface Tree { height: number; children?: Tree[] | undefined; } + +export const directions_cardinal = ["n", "e", "s", "w"] as const; +export type CardinalDirection = typeof directions_cardinal[number]; +export const directions_ordinal = ["ne", "se", "sw", "nw"] as const; +export type OrdinalDirection = typeof directions_ordinal[number]; +export const directions_compass: CompassDirection[] = [ + ...directions_cardinal, + ...directions_cardinal, +]; +export type CompassDirection = CardinalDirection | OrdinalDirection; From 4674a768ede92a9f0d015fdf9776a69a8e05d9b8 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 25 Apr 2022 20:14:13 +0900 Subject: [PATCH 33/67] add resize docs --- .../editor-canvas/docs/feature-resize.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 editor-packages/editor-canvas/docs/feature-resize.md diff --git a/editor-packages/editor-canvas/docs/feature-resize.md b/editor-packages/editor-canvas/docs/feature-resize.md new file mode 100644 index 00000000..a1ac9d26 --- /dev/null +++ b/editor-packages/editor-canvas/docs/feature-resize.md @@ -0,0 +1,14 @@ +# Resizing selection (s) + +Group resizing alg + +``` +| a ---- b ---- c | +``` + +In above scenario, width of a as x, is scaled in + +- origin width of selection as w1 +- new width of selection as w2 + +x = x \* w2 / w1 From a53e6cbcdabb069a9b84c67b8d089dff1e06dc6e Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 25 Apr 2022 20:15:02 +0900 Subject: [PATCH 34/67] update reducer placeholding --- .../{core/actions/index.ts => reducer/history-reducer.ts} | 0 editor-packages/editor-canvas/{core/dispatch => reducer}/index.ts | 0 .../{core/reducer/index.ts => reducer/interaction-reducer.ts} | 0 .../{core/states/index.ts => reducer/node-property-reducer.ts} | 0 editor-packages/editor-canvas/reducer/node-reducer.ts | 0 editor-packages/editor-canvas/reducer/node-style-reducer.ts | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename editor-packages/editor-canvas/{core/actions/index.ts => reducer/history-reducer.ts} (100%) rename editor-packages/editor-canvas/{core/dispatch => reducer}/index.ts (100%) rename editor-packages/editor-canvas/{core/reducer/index.ts => reducer/interaction-reducer.ts} (100%) rename editor-packages/editor-canvas/{core/states/index.ts => reducer/node-property-reducer.ts} (100%) create mode 100644 editor-packages/editor-canvas/reducer/node-reducer.ts create mode 100644 editor-packages/editor-canvas/reducer/node-style-reducer.ts diff --git a/editor-packages/editor-canvas/core/actions/index.ts b/editor-packages/editor-canvas/reducer/history-reducer.ts similarity index 100% rename from editor-packages/editor-canvas/core/actions/index.ts rename to editor-packages/editor-canvas/reducer/history-reducer.ts diff --git a/editor-packages/editor-canvas/core/dispatch/index.ts b/editor-packages/editor-canvas/reducer/index.ts similarity index 100% rename from editor-packages/editor-canvas/core/dispatch/index.ts rename to editor-packages/editor-canvas/reducer/index.ts diff --git a/editor-packages/editor-canvas/core/reducer/index.ts b/editor-packages/editor-canvas/reducer/interaction-reducer.ts similarity index 100% rename from editor-packages/editor-canvas/core/reducer/index.ts rename to editor-packages/editor-canvas/reducer/interaction-reducer.ts diff --git a/editor-packages/editor-canvas/core/states/index.ts b/editor-packages/editor-canvas/reducer/node-property-reducer.ts similarity index 100% rename from editor-packages/editor-canvas/core/states/index.ts rename to editor-packages/editor-canvas/reducer/node-property-reducer.ts diff --git a/editor-packages/editor-canvas/reducer/node-reducer.ts b/editor-packages/editor-canvas/reducer/node-reducer.ts new file mode 100644 index 00000000..e69de29b diff --git a/editor-packages/editor-canvas/reducer/node-style-reducer.ts b/editor-packages/editor-canvas/reducer/node-style-reducer.ts new file mode 100644 index 00000000..e69de29b From 6720b2a1c13506e6f02d17e230b06794dcd99813 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 18:22:51 +0900 Subject: [PATCH 35/67] add global stylesheet --- editor/pages/_app.tsx | 29 +---------------------------- editor/styles/global.css | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 28 deletions(-) create mode 100644 editor/styles/global.css diff --git a/editor/pages/_app.tsx b/editor/pages/_app.tsx index 4081dbd7..27e8848e 100644 --- a/editor/pages/_app.tsx +++ b/editor/pages/_app.tsx @@ -6,6 +6,7 @@ import { EditorThemeProvider } from "@editor-ui/theme"; import { MuiThemeProvider } from "theme/mui"; import { colors } from "theme"; import { useRouter } from "next/router"; +import "../styles/global.css"; function GlobalCss() { return ( @@ -15,34 +16,6 @@ function GlobalCss() { background-color: ${colors.color_editor_bg_on_dark}; touch-action: none; } - - body { - margin: 0px; - padding: 0; - font-family: "Helvetica Nueue", "Roboto", sans-serif; - - /* for editor canvas */ - overscroll-behavior-x: none; - overscroll-behavior-y: none; - } - - iframe { - border: none; - } - - h1, - h2, - h3, - h4, - h5, - h6, - p { - color: black; - } - - a { - color: blue; - } `} /> ); diff --git a/editor/styles/global.css b/editor/styles/global.css new file mode 100644 index 00000000..4a78ecbb --- /dev/null +++ b/editor/styles/global.css @@ -0,0 +1,31 @@ +body { + margin: 0px; + padding: 0; + font-family: "Helvetica Nueue", "Roboto", sans-serif; + + /* for editor canvas */ + overscroll-behavior-x: none; + overscroll-behavior-y: none; +} + +iframe { + border: none; +} + +h1, +h2, +h3, +h4, +h5, +h6, +p { + color: black; +} + +a { + color: blue; +} + +.white { + color: #fff; +} From b2b6629f8bacb32ecdb39797789769e3269fec55 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 18:23:35 +0900 Subject: [PATCH 36/67] inspector setup --- .../inspector/default-inspector.tsx | 3 - editor/components/inspector/index.ts | 3 +- .../inspector/inspector-readonly-property.tsx | 63 +++++++++++++++++++ .../inspector/inspector-section.tsx | 37 +++++++++++ editor/scaffolds/editor/editor.tsx | 4 +- 5 files changed, 105 insertions(+), 5 deletions(-) delete mode 100644 editor/components/inspector/default-inspector.tsx create mode 100644 editor/components/inspector/inspector-readonly-property.tsx create mode 100644 editor/components/inspector/inspector-section.tsx diff --git a/editor/components/inspector/default-inspector.tsx b/editor/components/inspector/default-inspector.tsx deleted file mode 100644 index fff42386..00000000 --- a/editor/components/inspector/default-inspector.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export function DefaultInspector() { - return <>INSPECTOR; -} diff --git a/editor/components/inspector/index.ts b/editor/components/inspector/index.ts index 73fc361c..f59bfce3 100644 --- a/editor/components/inspector/index.ts +++ b/editor/components/inspector/index.ts @@ -1 +1,2 @@ -export * from "./default-inspector"; +export * from "./inspector-section"; +export * from "./inspector-readonly-property"; diff --git a/editor/components/inspector/inspector-readonly-property.tsx b/editor/components/inspector/inspector-readonly-property.tsx new file mode 100644 index 00000000..30f28e1a --- /dev/null +++ b/editor/components/inspector/inspector-readonly-property.tsx @@ -0,0 +1,63 @@ +import styled from "@emotion/styled"; +import React from "react"; + +export function ReadonlyProperty({ + label, + value, + unit, +}: { + label: string; + value: number | string; + unit?: "px"; +}) { + const snippet = pretty(value, unit); + const onclick = () => { + navigator.clipboard.writeText(snippet); + }; + + return ( + + + {snippet} + + ); +} + +const pretty = (value: number | string, unit?: "px" | any): string => { + switch (unit) { + case "px": + // round to 2 decimals + return Math.round((value as number) * 100) / 100 + "px"; + default: + return value?.toString() || ""; + } +}; + +const PropertyLineContainer = styled.div` + display: flex; + flex: 1; + gap: 8px; + background: transparent; + padding: 2px; + + label { + font-size: 14px; + color: rgba(255, 255, 255, 0.5); + } + + span { + font-size: 14px; + color: white; + } + + transition: all 0.2s ease; + + &:hover { + background: rgba(255, 255, 255, 0.1); + } + + cursor: pointer; + &:active { + background: rgba(255, 255, 255, 0.2); + } +`; diff --git a/editor/components/inspector/inspector-section.tsx b/editor/components/inspector/inspector-section.tsx new file mode 100644 index 00000000..377c1adf --- /dev/null +++ b/editor/components/inspector/inspector-section.tsx @@ -0,0 +1,37 @@ +import React, { CSSProperties } from "react"; + +export function InspectorSection({ + children, + label, + contentPadding = "8px", +}: React.PropsWithChildren<{ + label: string; + contentPadding?: CSSProperties["padding"]; +}>) { + return ( +
+ {label} +
+ {children} +
+
+ ); +} + +export function InfoSectionLabel({ children }: { children: React.ReactNode }) { + return ( +
+ {children} +
+ ); +} diff --git a/editor/scaffolds/editor/editor.tsx b/editor/scaffolds/editor/editor.tsx index c20db22f..375c98b5 100644 --- a/editor/scaffolds/editor/editor.tsx +++ b/editor/scaffolds/editor/editor.tsx @@ -8,6 +8,7 @@ import { EditorSidebar } from "components/editor"; import { useEditorState } from "core/states"; import { Canvas } from "scaffolds/canvas"; import { CodeSegment } from "scaffolds/code"; +import { Inspector } from "scaffolds/inspector"; import { EditorSkeleton } from "./skeleton"; import { colors } from "theme"; @@ -63,7 +64,8 @@ export function Editor({ zIndex={1} backgroundColor={colors.color_editor_bg_on_dark} > - + + {/* */} {/* {wstate.preferences.debug_mode && ( From 14b6f1af9616c195de4409b677ee89a548e5a3df Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 18:23:50 +0900 Subject: [PATCH 37/67] add info inspector --- editor/scaffolds/inspector/section-info.tsx | 33 +++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 editor/scaffolds/inspector/section-info.tsx diff --git a/editor/scaffolds/inspector/section-info.tsx b/editor/scaffolds/inspector/section-info.tsx new file mode 100644 index 00000000..d427e0fc --- /dev/null +++ b/editor/scaffolds/inspector/section-info.tsx @@ -0,0 +1,33 @@ +import styled from "@emotion/styled"; +import { useTargetContainer } from "hooks/use-target-node"; + +import React from "react"; +export function InfoSection() { + const { target } = useTargetContainer(); + return ( +
+ {target?.name} + {"No description"} +
+ ); +} + +const Section = styled.section` + margin-top: 24px; + display: flex; + flex-direction: column; + padding: 8px; +`; + +const SceneTitle = styled.h4` + margin: 0; + color: white; + cursor: default; + font-weight: normal; +`; + +const SceneDescription = styled.p` + margin: 0; + font-size: 14px; + color: rgba(255, 255, 255, 0.5); +`; From 2de0f0378aafc43979671b142ce607498a257f7b Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 18:23:58 +0900 Subject: [PATCH 38/67] add color inspector --- editor/scaffolds/inspector/section-colors.tsx | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 editor/scaffolds/inspector/section-colors.tsx diff --git a/editor/scaffolds/inspector/section-colors.tsx b/editor/scaffolds/inspector/section-colors.tsx new file mode 100644 index 00000000..790cadf8 --- /dev/null +++ b/editor/scaffolds/inspector/section-colors.tsx @@ -0,0 +1,99 @@ +import React from "react"; +import styled from "@emotion/styled"; +import type { SolidPaint, Paint } from "@design-sdk/figma-types"; +import { InspectorSection } from "components/inspector"; +import { useTargetContainer } from "hooks/use-target-node"; + +export function ColorsSection() { + const { target } = useTargetContainer(); + const colors: ReadonlyArray = target?.fills?.filter( + (fill) => fill.visible + ) as ReadonlyArray; + + return ( + + + {colors?.map((c) => { + switch (c.type) { + case "SOLID": + return ; + case "GRADIENT_RADIAL": + case "GRADIENT_ANGULAR": + case "GRADIENT_DIAMOND": + case "GRADIENT_LINEAR": + return <>G; + } + })} + + + ); +} + +const ChipsContainer = styled.div` + display: flex; + flex-direction: row; + gap: 4px; +`; + +function ColorChip({ + color, + snippet, + outline = false, +}: { + color: { r: number; g: number; b: number; o: number }; + snippet?: string; + outline?: boolean; +}) { + const [hover, setHover] = React.useState(false); + + const rgba = `rgba(${rd(color.r * 255)}, ${rd(color.g * 255)}, ${rd( + color.b * 255 + )}, ${rd(color.o)})`; + + const text = snippet || rgba; + const onclick = () => { + // copy to clipboard + navigator.clipboard.writeText(text); + // show toast (todo) + }; + + return ( + setHover(true)} + onMouseLeave={() => setHover(false)} + > +
+ + + ); +} + +const rd = (d) => Math.round((d + Number.EPSILON) * 100) / 100; + +const ColorChipContainer = styled.div` + cursor: pointer; + background: transparent; + display: flex; + flex-direction: row; + gap: 2px; + align-items: center; + transition: all 0.2s ease; +`; From 8d94712601f5974a68825e0fd0c7a261ba109fed Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 18:24:03 +0900 Subject: [PATCH 39/67] add content inspector --- .../scaffolds/inspector/section-content.tsx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 editor/scaffolds/inspector/section-content.tsx diff --git a/editor/scaffolds/inspector/section-content.tsx b/editor/scaffolds/inspector/section-content.tsx new file mode 100644 index 00000000..3e4a1e56 --- /dev/null +++ b/editor/scaffolds/inspector/section-content.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import styled from "@emotion/styled"; +import { InspectorSection } from "components/inspector"; +import { useTargetContainer } from "hooks/use-target-node"; + +export function ContentSection() { + const { target } = useTargetContainer(); + + if (target?.type === "TEXT") { + return ( + + {target.data} + + ); + } else { + return <>; + } +} + +const TextContentContainer = styled.div` + display: flex; + padding: 8px; + color: white; + border-radius: 2px; + background: rgba(255, 255, 255, 0.1); +`; From 551c94c618f0ff6fccb8a3c8c0b3df1f96d51cd6 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 18:24:25 +0900 Subject: [PATCH 40/67] wip add layoyt & text inspector --- editor/scaffolds/inspector/inspector.tsx | 29 +++++++++++++----- editor/scaffolds/inspector/readme.md | 10 +++++++ editor/scaffolds/inspector/section-layout.tsx | 28 +++++++++++++++++ .../inspector/section-typography.tsx | 30 +++++++++++++++++++ 4 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 editor/scaffolds/inspector/readme.md create mode 100644 editor/scaffolds/inspector/section-layout.tsx create mode 100644 editor/scaffolds/inspector/section-typography.tsx diff --git a/editor/scaffolds/inspector/inspector.tsx b/editor/scaffolds/inspector/inspector.tsx index 1f05069e..6ea7b31e 100644 --- a/editor/scaffolds/inspector/inspector.tsx +++ b/editor/scaffolds/inspector/inspector.tsx @@ -2,22 +2,37 @@ import React from "react"; import styled from "@emotion/styled"; import { useEditorState } from "core/states"; import { colors } from "theme"; +import { useTargetContainer } from "hooks/use-target-node"; + +import { InfoSection } from "./section-info"; +import { LayoutSection } from "./section-layout"; +import { ColorsSection } from "./section-colors"; +import { ContentSection } from "./section-content"; +import { TypographySection } from "./section-typography"; + export function InspectorSegment() { + const { target } = useTargetContainer(); const [state] = useEditorState(); - return ( - - file: {state.design.key} - {/* todo */} - - ); + if (target) { + return ( + + + + + + + + ); + } + + return <>; } const InspectorContainer = styled.div` display: flex; z-index: 1; flex-direction: column; - width: 200px; height: 100%; background-color: ${colors.color_editor_bg_on_dark}; `; diff --git a/editor/scaffolds/inspector/readme.md b/editor/scaffolds/inspector/readme.md new file mode 100644 index 00000000..8a4f7ca7 --- /dev/null +++ b/editor/scaffolds/inspector/readme.md @@ -0,0 +1,10 @@ +# Inspector + +The scene inspector initially placed on the right side panel of the editor showing informations of the scene node. + +The Inspector contains below features. + +- General Information +- Export assets +- Code Snippets +- Styles diff --git a/editor/scaffolds/inspector/section-layout.tsx b/editor/scaffolds/inspector/section-layout.tsx new file mode 100644 index 00000000..cdf0b434 --- /dev/null +++ b/editor/scaffolds/inspector/section-layout.tsx @@ -0,0 +1,28 @@ +import styled from "@emotion/styled"; +import { InspectorSection, ReadonlyProperty } from "components/inspector"; +import { useTargetContainer } from "hooks/use-target-node"; +import React from "react"; + +export function LayoutSection() { + const { target, root } = useTargetContainer(); + const isroot = root?.id === target?.id; + + return ( + + + + + + + + + + + ); +} + +const Line = styled.div` + display: flex; + flex-direction: row; + width: 100%; +`; diff --git a/editor/scaffolds/inspector/section-typography.tsx b/editor/scaffolds/inspector/section-typography.tsx new file mode 100644 index 00000000..c2712c80 --- /dev/null +++ b/editor/scaffolds/inspector/section-typography.tsx @@ -0,0 +1,30 @@ +import { InspectorSection, ReadonlyProperty } from "components/inspector"; +import { useTargetContainer } from "hooks/use-target-node"; +import React from "react"; + +export function TypographySection() { + const { target } = useTargetContainer(); + + if (target?.type !== "TEXT") { + return <>; + } + + return ( + +
+ + + + + {/* target.lineHeight */} + +
+
+ ); +} From ebca98997ab4eb6232d0fc1080739273cce119c0 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 22:30:17 +0900 Subject: [PATCH 41/67] fix warnings --- editor/pages/_app.tsx | 32 ++++++++++++------------- packages/designto-code/version/index.ts | 5 ++-- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/editor/pages/_app.tsx b/editor/pages/_app.tsx index 27e8848e..7d9458d7 100644 --- a/editor/pages/_app.tsx +++ b/editor/pages/_app.tsx @@ -43,41 +43,39 @@ function HeadInjection() { name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> - - {/* region Google analytics */} {/* https://stackoverflow.com/a/62552263 */} - {/* end region */} ); diff --git a/packages/designto-code/version/index.ts b/packages/designto-code/version/index.ts index 1b1083d4..236eb35a 100644 --- a/packages/designto-code/version/index.ts +++ b/packages/designto-code/version/index.ts @@ -1,3 +1,4 @@ -import { version, license } from "../package.json"; +import pkg from "../package.json"; -export { version, license }; +export const version = pkg.version; +export const license = pkg.license; From 79e3a0e62425af0a9bcc0cf7aeb9744a4e410b24 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 22:30:29 +0900 Subject: [PATCH 42/67] add assest section --- editor/scaffolds/inspector/inspector.tsx | 2 + editor/scaffolds/inspector/section-assets.tsx | 43 +++++++++++++++++++ editor/scaffolds/inspector/section-colors.tsx | 14 +++--- 3 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 editor/scaffolds/inspector/section-assets.tsx diff --git a/editor/scaffolds/inspector/inspector.tsx b/editor/scaffolds/inspector/inspector.tsx index 6ea7b31e..e723adf3 100644 --- a/editor/scaffolds/inspector/inspector.tsx +++ b/editor/scaffolds/inspector/inspector.tsx @@ -9,6 +9,7 @@ import { LayoutSection } from "./section-layout"; import { ColorsSection } from "./section-colors"; import { ContentSection } from "./section-content"; import { TypographySection } from "./section-typography"; +import { AssetsSection } from "./section-assets"; export function InspectorSegment() { const { target } = useTargetContainer(); @@ -20,6 +21,7 @@ export function InspectorSegment() { + diff --git a/editor/scaffolds/inspector/section-assets.tsx b/editor/scaffolds/inspector/section-assets.tsx new file mode 100644 index 00000000..7adad247 --- /dev/null +++ b/editor/scaffolds/inspector/section-assets.tsx @@ -0,0 +1,43 @@ +import { InspectorSection } from "components/inspector"; +import { useTargetContainer } from "hooks/use-target-node"; +import React from "react"; + +export function AssetsSection() { + // if the node itself is exportable + // if the node has a complex gradient which is more effective to use asset than style code + // if the node has a image fill + + const { target } = useTargetContainer(); + if (!(target?.images?.length > 0)) { + return <>; + } + + return ( + + {target.images.map((img) => ( + + ))} + + ); +} + +function Preview({ src }: { src: string }) { + return ( +
+ +
+ ); +} diff --git a/editor/scaffolds/inspector/section-colors.tsx b/editor/scaffolds/inspector/section-colors.tsx index 790cadf8..b3b4cd48 100644 --- a/editor/scaffolds/inspector/section-colors.tsx +++ b/editor/scaffolds/inspector/section-colors.tsx @@ -4,12 +4,18 @@ import type { SolidPaint, Paint } from "@design-sdk/figma-types"; import { InspectorSection } from "components/inspector"; import { useTargetContainer } from "hooks/use-target-node"; +const rd = (d) => Math.round((d + Number.EPSILON) * 100) / 100; + export function ColorsSection() { const { target } = useTargetContainer(); const colors: ReadonlyArray = target?.fills?.filter( (fill) => fill.visible ) as ReadonlyArray; + if (!(colors?.length > 0)) { + return <>; + } + return ( @@ -58,7 +64,7 @@ function ColorChip({ }; return ( - setHover(true)} onMouseLeave={() => setHover(false)} @@ -82,13 +88,11 @@ function ColorChip({ > {text} - + ); } -const rd = (d) => Math.round((d + Number.EPSILON) * 100) / 100; - -const ColorChipContainer = styled.div` +const ChipContainer = styled.div` cursor: pointer; background: transparent; display: flex; From c060ddf44b74a1dbe0a7d11b3dc5c6e6708f0892 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 22:30:36 +0900 Subject: [PATCH 43/67] add ui deps --- editor/package.json | 4 ++ yarn.lock | 130 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 121 insertions(+), 13 deletions(-) diff --git a/editor/package.json b/editor/package.json index b8d21c91..15215952 100644 --- a/editor/package.json +++ b/editor/package.json @@ -19,11 +19,15 @@ "@emotion/css": "^11.5.0", "@emotion/react": "^11.1.5", "@emotion/styled": "^11.1.5", + "@floating-ui/core": "^1.0.1", + "@floating-ui/react-dom": "^1.0.0", + "@floating-ui/react-dom-interactions": "^0.10.2", "@modulz/design-system": "^0.6.1", "@monaco-editor/react": "^4.4.1", "@mui/icons-material": "^5.6.1", "@mui/lab": "^5.0.0-alpha.77", "@mui/material": "^5.6.1", + "@radix-ui/react-toast": "^1.1.1", "@reflect-blocks/figma-embed": "^0.0.5", "@use-gesture/react": "^10.2.11", "@visx/gradient": "^1.7.0", diff --git a/yarn.lock b/yarn.lock index e0cbaef8..cea7c0cf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2440,6 +2440,11 @@ resolved "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz" integrity sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg== +"@floating-ui/core@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.0.1.tgz#00e64d74e911602c8533957af0cce5af6b2e93c8" + integrity sha512-bO37brCPfteXQfFY0DyNDGB3+IMe4j150KFQcgJ5aBP295p9nBGeHEs/p0czrRbtlHq4Px/yoPXO/+dOCcF4uA== + "@floating-ui/dom@^0.5.3": version "0.5.4" resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz" @@ -2447,6 +2452,21 @@ dependencies: "@floating-ui/core" "^0.7.3" +"@floating-ui/dom@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.0.3.tgz#b439c8a66436c2cae8d97e889f0b76cce757a6ec" + integrity sha512-6H1kwjkOZKabApNtXRiYHvMmYJToJ1DV7rQ3xc/WJpOABhQIOJJOdz2AOejj8X+gcybaFmBpisVTZxBZAM3V0w== + dependencies: + "@floating-ui/core" "^1.0.1" + +"@floating-ui/react-dom-interactions@^0.10.2": + version "0.10.2" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom-interactions/-/react-dom-interactions-0.10.2.tgz#1a9c86f8bb9aa36b5926ae03d96de78579d2a70d" + integrity sha512-KhF+UN+MVqUx1bG1fe0aAiBl1hbz07Uin6UW70mxwUDhaGpitM16CYvGri1EqGY4hnWK8TQknDSP8iQFOxjhsg== + dependencies: + "@floating-ui/react-dom" "^1.0.0" + aria-hidden "^1.1.3" + "@floating-ui/react-dom@0.7.2": version "0.7.2" resolved "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-0.7.2.tgz" @@ -2455,6 +2475,13 @@ "@floating-ui/dom" "^0.5.3" use-isomorphic-layout-effect "^1.1.1" +"@floating-ui/react-dom@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-1.0.0.tgz#e0975966694433f1f0abffeee5d8e6bb69b7d16e" + integrity sha512-uiOalFKPG937UCLm42RxjESTWUVpbbatvlphQAU6bsv+ence6IoVG8JOUZcy8eW81NkU+Idiwvx10WFLmR4MIg== + dependencies: + "@floating-ui/dom" "^1.0.0" + "@flutter-builder/flutter-material-icons@0.0.6": version "0.0.6" resolved "https://registry.npmjs.org/@flutter-builder/flutter-material-icons/-/flutter-material-icons-0.0.6.tgz" @@ -4119,6 +4146,17 @@ "@radix-ui/react-primitive" "1.0.0-rc.1" "@radix-ui/react-slot" "1.0.0-rc.1" +"@radix-ui/react-collection@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.1.tgz#259506f97c6703b36291826768d3c1337edd1de5" + integrity sha512-uuiFbs+YCKjn3X1DTSx9G7BHApu4GHbi3kgiwsnFUbOKCrwejAJv4eE4Vc8C0Oaxt9T0aV4ox0WCOdx+39Xo+g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-context" "1.0.0" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/react-slot" "1.0.1" + "@radix-ui/react-compose-refs@0.0.5": version "0.0.5" resolved "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-0.0.5.tgz" @@ -4339,6 +4377,18 @@ "@radix-ui/react-use-callback-ref" "1.0.0" "@radix-ui/react-use-escape-keydown" "1.0.0" +"@radix-ui/react-dismissable-layer@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.2.tgz#f04d1061bddf00b1ca304148516b9ddc62e45fb2" + integrity sha512-WjJzMrTWROozDqLB0uRWYvj4UuXsM/2L19EmQ3Au+IJWqwvwq9Bwd+P8ivo0Deg9JDPArR1I6MbWNi1CmXsskg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.0" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-use-escape-keydown" "1.0.2" + "@radix-ui/react-dropdown-menu@^0.1.6": version "0.1.6" resolved "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.6.tgz" @@ -4693,6 +4743,14 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-primitive" "1.0.0" +"@radix-ui/react-portal@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.1.tgz#169c5a50719c2bb0079cf4c91a27aa6d37e5dd33" + integrity sha512-NY2vUWI5WENgAT1nfC6JS7RU5xRYBfjZVLq0HmgEN1Ezy3rk/UruMV4+Rd0F40PEaFC5SrLS1ixYvcYIQrb4Ig== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/react-portal@next": version "1.0.0-rc.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.0.0-rc.1.tgz#38026a446fca88bd728bbbfeed1d41e75076584b" @@ -4801,6 +4859,14 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-slot" "1.0.0-rc.1" +"@radix-ui/react-primitive@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.1.tgz#c1ebcce283dd2f02e4fbefdaa49d1cb13dbc990a" + integrity sha512-fHbmislWVkZaIdeF6GZxF0A/NH/3BjrGIYj+Ae6eTmTCr7EB0RQAAVEiqsXK6p3/JcRqVSBQoceZroj30Jj3XA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-slot" "1.0.1" + "@radix-ui/react-progress@^0.0.13": version "0.0.13" resolved "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-0.0.13.tgz" @@ -5010,6 +5076,14 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-compose-refs" "1.0.0-rc.1" +"@radix-ui/react-slot@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.1.tgz#e7868c669c974d649070e9ecbec0b367ee0b4d81" + integrity sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-switch@next": version "1.0.0-rc.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-switch/-/react-switch-1.0.0-rc.1.tgz#c536ce377595da42e995db45a40d2c7ca5ea5c4b" @@ -5040,6 +5114,25 @@ "@radix-ui/react-roving-focus" "1.0.0-rc.1" "@radix-ui/react-use-controllable-state" "1.0.0-rc.1" +"@radix-ui/react-toast@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toast/-/react-toast-1.1.1.tgz#ba2c821f4e6ee42ff89b2d7e955d5b02b16ff55f" + integrity sha512-0wNOO9/O1jNvJQOVJD62HoquYqsC8KhWvRgmZ2vlw/5PW/K88mcS2G0gKCrWtcAC33rLttPU1JPd4SF+qzCZ6A== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.0" + "@radix-ui/react-collection" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.0" + "@radix-ui/react-context" "1.0.0" + "@radix-ui/react-dismissable-layer" "1.0.2" + "@radix-ui/react-portal" "1.0.1" + "@radix-ui/react-presence" "1.0.0" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-use-controllable-state" "1.0.0" + "@radix-ui/react-use-layout-effect" "1.0.0" + "@radix-ui/react-visually-hidden" "1.0.1" + "@radix-ui/react-toggle@next": version "1.0.0-rc.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle/-/react-toggle-1.0.0-rc.1.tgz#51fe7374f886fcb28c84e5bfb284135c7c810431" @@ -5229,6 +5322,14 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-callback-ref" "1.0.0" +"@radix-ui/react-use-escape-keydown@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz#09ab6455ab240b4f0a61faf06d4e5132c4d639f6" + integrity sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.0" + "@radix-ui/react-use-layout-effect@0.0.5": version "0.0.5" resolved "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.0.5.tgz" @@ -5358,6 +5459,14 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-primitive" "1.0.0" +"@radix-ui/react-visually-hidden@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.1.tgz#9a4ac4fc97ae8d72a10e727f16b3121b5f0aa469" + integrity sha512-K1hJcCMfWfiYUibRqf3V8r5Drpyf7rh44jnrwAbdvI5iCCijilBBeyQv9SKidYNZIopMdCyR9FnIjkHxHN0FcQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.1" + "@radix-ui/rect@0.0.5": version "0.0.5" resolved "https://registry.npmjs.org/@radix-ui/rect/-/rect-0.0.5.tgz" @@ -7592,6 +7701,13 @@ aria-hidden@^1.1.1: dependencies: tslib "^1.0.0" +aria-hidden@^1.1.3: + version "1.2.1" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.1.tgz#ad8c1edbde360b454eb2bf717ea02da00bfee0f8" + integrity sha512-PN344VAf9j1EAi+jyVHOJ8XidQdPVssGco39eNcsGdM4wcsILtxrKLkbuiMfLWYROK1FjRQasMWCBttrhjnr6A== + dependencies: + tslib "^2.0.0" + aria-query@^4.2.2: version "4.2.2" resolved "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz" @@ -8715,11 +8831,6 @@ chrome-trace-event@^1.0.2: resolved "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz" integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== -ci-info@^1.5.0: - version "1.6.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz" - integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== - ci-info@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" @@ -12532,8 +12643,6 @@ is-ci@^1.0.10: version "1.2.1" resolved "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz" integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== - dependencies: - ci-info "^1.5.0" is-ci@^2.0.0: version "2.0.0" @@ -18203,13 +18312,8 @@ tar-fs@^1.15.3: version "1.16.3" resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz" integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== - dependencies: - chownr "^1.0.1" - mkdirp "^0.5.1" - pump "^1.0.0" - tar-stream "^1.1.2" -tar-stream@^1.1.2, tar-stream@^1.5.4: +tar-stream@^1.5.4: version "1.6.2" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz" integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== From c81612686263bd7767fc3b8eac917fb863146a13 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 23:08:03 +0900 Subject: [PATCH 44/67] add toaster --- editor/package.json | 1 + editor/scaffolds/editor/_providers.tsx | 5 ++++- editor/scaffolds/editor/editor-toast-provider.tsx | 11 +++++++++++ yarn.lock | 12 ++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 editor/scaffolds/editor/editor-toast-provider.tsx diff --git a/editor/package.json b/editor/package.json index 15215952..f952bb0d 100644 --- a/editor/package.json +++ b/editor/package.json @@ -47,6 +47,7 @@ "re-resizable": "^6.9.1", "react": "^18.0.0", "react-dom": "^18.0.0", + "react-hot-toast": "^2.4.0", "react-hotkeys-hook": "^3.4.4", "react-json-tree": "^0.15.0", "react-resizable": "^3.0.1", diff --git a/editor/scaffolds/editor/_providers.tsx b/editor/scaffolds/editor/_providers.tsx index 7ad76825..6bd3f746 100644 --- a/editor/scaffolds/editor/_providers.tsx +++ b/editor/scaffolds/editor/_providers.tsx @@ -2,12 +2,15 @@ import React from "react"; import { useHotkeys } from "react-hotkeys-hook"; import { EditorImageRepositoryProvider } from "./editor-image-repository-provider"; import { EditorPreviewDataProvider } from "./editor-preview-provider"; +import { ToastProvider } from "./editor-toast-provider"; export function EditorDefaultProviders(props: { children: React.ReactNode }) { return ( - {props.children} + + {props.children} + ); diff --git a/editor/scaffolds/editor/editor-toast-provider.tsx b/editor/scaffolds/editor/editor-toast-provider.tsx new file mode 100644 index 00000000..fb6e407f --- /dev/null +++ b/editor/scaffolds/editor/editor-toast-provider.tsx @@ -0,0 +1,11 @@ +import React from "react"; +import { Toaster } from "react-hot-toast"; + +export function ToastProvider({ children }: React.PropsWithChildren<{}>) { + return ( + <> + {children} + + + ); +} diff --git a/yarn.lock b/yarn.lock index cea7c0cf..eb1794a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11788,6 +11788,11 @@ globby@^9.2.0: pify "^4.0.1" slash "^2.0.0" +goober@^2.1.10: + version "2.1.11" + resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.11.tgz#bbd71f90d2df725397340f808dbe7acc3118e610" + integrity sha512-5SS2lmxbhqH0u9ABEWq7WPU69a4i2pYcHeCxqaNq6Cw3mnrF0ghWNM4tEGid4dKy8XNIAUbuThuozDHHKJVh3A== + got@^6.7.1: version "6.7.1" resolved "https://registry.npmjs.org/got/-/got-6.7.1.tgz" @@ -16553,6 +16558,13 @@ react-element-to-jsx-string@^14.3.4: is-plain-object "5.0.0" react-is "17.0.2" +react-hot-toast@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.0.tgz#b91e7a4c1b6e3068fc599d3d83b4fb48668ae51d" + integrity sha512-qnnVbXropKuwUpriVVosgo8QrB+IaPJCpL8oBI6Ov84uvHZ5QQcTp2qg6ku2wNfgJl6rlQXJIQU5q+5lmPOutA== + dependencies: + goober "^2.1.10" + react-hotkeys-hook@^3.4.4: version "3.4.7" resolved "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.7.tgz" From 5f5df5a5f77c37694d815fa2c2c62af254a04d10 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Mon, 24 Oct 2022 23:08:08 +0900 Subject: [PATCH 45/67] add toasts --- .../inspector/inspector-readonly-property.tsx | 99 +++++++++++++------ editor/scaffolds/inspector/section-colors.tsx | 3 +- .../scaffolds/inspector/section-content.tsx | 17 +++- .../inspector/section-typography.tsx | 37 ++++++- editor/utils/clipboard/index.ts | 11 +++ 5 files changed, 129 insertions(+), 38 deletions(-) create mode 100644 editor/utils/clipboard/index.ts diff --git a/editor/components/inspector/inspector-readonly-property.tsx b/editor/components/inspector/inspector-readonly-property.tsx index 30f28e1a..61d938da 100644 --- a/editor/components/inspector/inspector-readonly-property.tsx +++ b/editor/components/inspector/inspector-readonly-property.tsx @@ -1,38 +1,30 @@ import styled from "@emotion/styled"; -import React from "react"; - -export function ReadonlyProperty({ - label, - value, - unit, -}: { - label: string; - value: number | string; - unit?: "px"; -}) { - const snippet = pretty(value, unit); - const onclick = () => { - navigator.clipboard.writeText(snippet); - }; +import React, { CSSProperties } from "react"; +import { copy } from "utils/clipboard"; +export function PropertyContainer({ + children, + disabled, + onClick, + background, +}: React.PropsWithChildren<{ + onClick?: () => void; + disabled?: boolean; + background?: CSSProperties["background"]; +}>) { return ( - - - {snippet} + + {children} ); } -const pretty = (value: number | string, unit?: "px" | any): string => { - switch (unit) { - case "px": - // round to 2 decimals - return Math.round((value as number) * 100) / 100 + "px"; - default: - return value?.toString() || ""; - } -}; - const PropertyLineContainer = styled.div` display: flex; flex: 1; @@ -53,11 +45,58 @@ const PropertyLineContainer = styled.div` transition: all 0.2s ease; &:hover { - background: rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.1) !important; } cursor: pointer; &:active { - background: rgba(255, 255, 255, 0.2); + background: rgba(255, 255, 255, 0.2) !important; + } + + &[data-disabled="true"] { + opacity: 0.5; + cursor: not-allowed; } `; + +export function ReadonlyProperty({ + label, + value, + unit, + hideEmpty, +}: { + label: string; + value: number | string; + unit?: "px" | "%"; + hideEmpty?: boolean; +}) { + const snippet = pretty(value, unit); + const onclick = () => { + copy(snippet, { notify: true }); + }; + + if (hideEmpty && !value) { + return <>; + } + + return ( + + + {snippet} + + ); +} + +// round to 2 decimals +const rd = (d) => Math.round((d as number) * 100) / 100; + +const pretty = (value: number | string, unit?: "px" | "%"): string => { + switch (unit) { + case "px": + return rd(value) + "px"; + case "%": + return rd(value) + "%"; + default: + return value?.toString() || ""; + } +}; diff --git a/editor/scaffolds/inspector/section-colors.tsx b/editor/scaffolds/inspector/section-colors.tsx index b3b4cd48..1c435754 100644 --- a/editor/scaffolds/inspector/section-colors.tsx +++ b/editor/scaffolds/inspector/section-colors.tsx @@ -3,6 +3,7 @@ import styled from "@emotion/styled"; import type { SolidPaint, Paint } from "@design-sdk/figma-types"; import { InspectorSection } from "components/inspector"; import { useTargetContainer } from "hooks/use-target-node"; +import { copy } from "utils/clipboard"; const rd = (d) => Math.round((d + Number.EPSILON) * 100) / 100; @@ -59,7 +60,7 @@ function ColorChip({ const text = snippet || rgba; const onclick = () => { // copy to clipboard - navigator.clipboard.writeText(text); + copy(text, { notify: true }); // show toast (todo) }; diff --git a/editor/scaffolds/inspector/section-content.tsx b/editor/scaffolds/inspector/section-content.tsx index 3e4a1e56..e4fc5d96 100644 --- a/editor/scaffolds/inspector/section-content.tsx +++ b/editor/scaffolds/inspector/section-content.tsx @@ -1,15 +1,25 @@ import React from "react"; import styled from "@emotion/styled"; -import { InspectorSection } from "components/inspector"; +import { InspectorSection, PropertyContainer } from "components/inspector"; import { useTargetContainer } from "hooks/use-target-node"; +import { copy } from "utils/clipboard"; export function ContentSection() { const { target } = useTargetContainer(); if (target?.type === "TEXT") { + const txt = target.data; + return ( - {target.data} + { + copy(txt, { notify: true }); + }} + > + {txt} + ); } else { @@ -21,6 +31,5 @@ const TextContentContainer = styled.div` display: flex; padding: 8px; color: white; - border-radius: 2px; - background: rgba(255, 255, 255, 0.1); + width: 100%; `; diff --git a/editor/scaffolds/inspector/section-typography.tsx b/editor/scaffolds/inspector/section-typography.tsx index c2712c80..47b9788e 100644 --- a/editor/scaffolds/inspector/section-typography.tsx +++ b/editor/scaffolds/inspector/section-typography.tsx @@ -1,6 +1,8 @@ +import React from "react"; import { InspectorSection, ReadonlyProperty } from "components/inspector"; import { useTargetContainer } from "hooks/use-target-node"; -import React from "react"; +import type { ReflectTextNode } from "@design-sdk/figma-node"; +import { roundNumber } from "@reflect-ui/uiutils"; export function TypographySection() { const { target } = useTargetContainer(); @@ -9,6 +11,8 @@ export function TypographySection() { return <>; } + const _lh = lineheight(target.lineHeight); + return (
- - {/* target.lineHeight */} +
); } + +function lineheight(lh: ReflectTextNode["lineHeight"]): { + value: number | string; + unit?: "px" | "%"; +} { + if (typeof lh === "number") { + return { + value: lh, + unit: "px", + }; + } + + if (typeof lh === "string") { + if (lh.endsWith("%")) { + return { + value: Number(lh.split("%")[0]), + unit: "%", + }; + } + } + + return { value: lh as string }; +} diff --git a/editor/utils/clipboard/index.ts b/editor/utils/clipboard/index.ts new file mode 100644 index 00000000..9c75a8ad --- /dev/null +++ b/editor/utils/clipboard/index.ts @@ -0,0 +1,11 @@ +import toast from "react-hot-toast"; + +export function copy(data: string, options?: { notify?: boolean }): void { + // Copy the data to the clipboard + navigator.clipboard.writeText(data); + + if (options?.notify) { + // Notify the user that the data has been copied + toast.success("Copied to clipboard"); + } +} From d9a3356bf5eb202db35728336da82cc2d51af67e Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 01:13:36 +0900 Subject: [PATCH 46/67] fix node selection query --- .../editor-canvas/canvas/canvas.tsx | 10 +- editor/scaffolds/inspector/section-info.tsx | 8 +- editor/utils/get-target-node.ts | 13 +- packages/designto-code/package.json | 27 +-- yarn.lock | 205 +++++++++--------- 5 files changed, 137 insertions(+), 126 deletions(-) diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index 1e07a39f..81cf6839 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -15,7 +15,7 @@ import { edge_scrolling, target_of_area, } from "../math"; -import { find_node_by_id_under_inpage_nodes } from "@design-sdk/core/utils"; +import q from "@design-sdk/query"; import { LazyFrame } from "@code-editor/canvas/lazy-frame"; import { HudCustomRenderers, HudSurface } from "../hud"; import type { Box, XY, CanvasTransform, XYWH } from "../types"; @@ -147,7 +147,9 @@ export function Canvas({ xy: offset, }; - const node = (id) => find_node_by_id_under_inpage_nodes(id, nodes); + const qdoc = useMemo(() => q.document(nodes), [nodes]); + + const node = (id) => qdoc.getNodeById(id); const onSelectNode = (...nodes: ReflectSceneNode[]) => { _cb_onSelectNode?.(...nodes.filter(Boolean)); @@ -311,9 +313,11 @@ export function Canvas({ const is_canvas_transforming = isPanning || isZooming; const selected_nodes = selectedNodes - ?.map((id) => find_node_by_id_under_inpage_nodes(id, nodes)) + ?.map((id) => qdoc.getNodeById(id)) .filter(Boolean); + console.log({ selectedNodes, highlightedLayer, selected_nodes }); + const items = useMemo(() => { return nodes?.map((node) => { return ( diff --git a/editor/scaffolds/inspector/section-info.tsx b/editor/scaffolds/inspector/section-info.tsx index d427e0fc..1525c645 100644 --- a/editor/scaffolds/inspector/section-info.tsx +++ b/editor/scaffolds/inspector/section-info.tsx @@ -6,7 +6,7 @@ export function InfoSection() { const { target } = useTargetContainer(); return (
- {target?.name} + {"No description"}
); @@ -19,8 +19,12 @@ const Section = styled.section` padding: 8px; `; -const SceneTitle = styled.h4` +const SceneTitle = styled.input` margin: 0; + background: transparent; + font-size: 18px; + outline: none; + border: none; color: white; cursor: default; font-weight: normal; diff --git a/editor/utils/get-target-node.ts b/editor/utils/get-target-node.ts index daf6a86c..c10d6c76 100644 --- a/editor/utils/get-target-node.ts +++ b/editor/utils/get-target-node.ts @@ -1,9 +1,7 @@ import type { EditorState } from "core/states"; import { DesignInput } from "@grida/builder-config/input"; -import { - find_node_by_id_under_inpage_nodes, - find_node_by_id_under_entry, -} from "@design-sdk/core/utils"; +import type { ReflectSceneNode } from "@design-sdk/figma-node"; +import q from "@design-sdk/query"; export function getTargetContainer(state: EditorState) { const thisPageNodes = state.selectedPage @@ -17,8 +15,8 @@ export function getTargetContainer(state: EditorState) { return { target: null, root: null }; } - const container_of_target = - find_node_by_id_under_inpage_nodes(targetId, thisPageNodes) || null; + const { root: container_of_target } = + q.getNodeAndRootByIdFrom(targetId, thisPageNodes) || null; const root = thisPageNodes ? container_of_target && @@ -34,7 +32,6 @@ export function getTargetContainer(state: EditorState) { })) : state.design?.input; - const target = - find_node_by_id_under_entry(targetId, root?.entry) ?? root?.entry; + const target = q.getNodeByIdFrom(targetId, root?.entry) ?? root?.entry; return { root, target }; } diff --git a/packages/designto-code/package.json b/packages/designto-code/package.json index dee597b4..53f7fcad 100644 --- a/packages/designto-code/package.json +++ b/packages/designto-code/package.json @@ -7,19 +7,20 @@ "scripts": {}, "dependencies": { "@coli.codes/escape-string": "^0.0.24", - "@design-sdk/asset-repository": "^0.0.35", - "@design-sdk/core": "^0.0.35", - "@design-sdk/diff": "^0.0.35", - "@design-sdk/figma": "^0.0.35", - "@design-sdk/figma-auth-store": "^0.0.21", - "@design-sdk/figma-node": "^0.0.35", - "@design-sdk/figma-node-conversion": "^0.0.35", - "@design-sdk/figma-node-repository": "^0.0.35", - "@design-sdk/figma-remote": "^0.0.35", - "@design-sdk/figma-remote-types": "^0.0.35", - "@design-sdk/figma-url": "^0.0.35", - "@design-sdk/flags": "^0.0.35", - "@design-sdk/url-analysis": "^0.0.35", + "@design-sdk/asset-repository": "^0.0.37", + "@design-sdk/core": "^0.0.37", + "@design-sdk/query": "^0.0.37", + "@design-sdk/diff": "^0.0.37", + "@design-sdk/figma": "^0.0.37", + "@design-sdk/figma-auth-store": "^0.0.37", + "@design-sdk/figma-node": "^0.0.37", + "@design-sdk/figma-node-conversion": "^0.0.37", + "@design-sdk/figma-node-repository": "^0.0.37", + "@design-sdk/figma-remote": "^0.0.37", + "@design-sdk/figma-remote-types": "^0.0.37", + "@design-sdk/figma-url": "^0.0.37", + "@design-sdk/flags": "^0.0.37", + "@design-sdk/url-analysis": "^0.0.37", "@designto/flutter": "0.0.1", "@designto/react": "0.0.0", "@designto/react-native": "0.0.0", diff --git a/yarn.lock b/yarn.lock index eb1794a2..b0c814ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1380,71 +1380,71 @@ resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@design-sdk/asset-repository@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/asset-repository/-/asset-repository-0.0.35.tgz#d624daee80cfed6a5ae687ea80f731fb17800cd3" - integrity sha512-MSdJa1Mn3zsP6/kD6f/0U8eJYNm3FUPRpxpIQ8MT0wFslaIY4DAQoHG2Lifdpm/6RWNl4aN8tGwt4lMoos97AQ== +"@design-sdk/asset-repository@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/asset-repository/-/asset-repository-0.0.37.tgz#d656b6a30811f0088a0eb094bbbbac83885c10fa" + integrity sha512-vBKr7xN8oGaAxr/f9cx7j9IIevLO062OaJBBntGZsg7dn3BT3enhqh0vdK6LS5GpRu18KsO2ei7gOQhrxv6sFg== dependencies: "@base-sdk/hosting" "^0.1.2" -"@design-sdk/core-flags-dashdash@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/core-flags-dashdash/-/core-flags-dashdash-0.0.35.tgz#228d44a866606593701874944a3e478b66ba5055" - integrity sha512-As62p1qn1C+0EImZVlCOkkTzsn+t9OxPArUIWu38IqqWhQBAIIKhUHD3HnYKHnecfNVRbLXbjH3OTAsDfJgksg== +"@design-sdk/core-flags-dashdash@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/core-flags-dashdash/-/core-flags-dashdash-0.0.37.tgz#5cac517c14b8a0c4a12207312d04c590eefc65e3" + integrity sha512-D6pssKOQUjD/GhiBj/dBxfBViVE4Kw8mzFV5ML4HMmvx8fER3JwAIqDoNRrP4Y7b9a7JkFND7PqoyXqCshyKYg== -"@design-sdk/core@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/core/-/core-0.0.35.tgz#a323718fef848512f404c7a6f3b5eccbede63f75" - integrity sha512-P7wsR99nBJcWH4wjH2govUQkyyO+Uqp27lM6m/FPcMBNlTtAXcqkM/0BQhpvJinX5s2l7Hz2FajZ/bHBPU478g== +"@design-sdk/core@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/core/-/core-0.0.37.tgz#076964310efd53e716bc966c91777fe18677a19d" + integrity sha512-qpmff4xKmvBDa3xsKCBTRB3InnIXC2FyaaJYj+cETvZQRr/tL/E8fqcSMchzQzycrSmxNsBnv+qC14i+bPIgVw== dependencies: "@base-sdk/base" "0.1.4" - "@design-sdk/figma-node" "^0.0.35" - "@design-sdk/figma-types" "^0.0.35" - "@design-sdk/figma-utils" "^0.0.35" + "@design-sdk/figma-node" "^0.0.37" + "@design-sdk/figma-types" "^0.0.37" + "@design-sdk/figma-utils" "^0.0.37" "@design-sdk/flags" "^0.0.17" "@reflect-ui/core" "0.0.5" "@reflect-ui/namings" "0.0.3" -"@design-sdk/diff@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/diff/-/diff-0.0.35.tgz#54045950fee1f1424a7434ca0cd3907243fb80e9" - integrity sha512-jbck3beqAe4NvegT3RJdJdNSEbzmex/lXCzhny7VEvyrL9NIpg3V9G2zZVrOV3HrzLGczcduQazeiuBjDIL6og== +"@design-sdk/diff@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/diff/-/diff-0.0.37.tgz#28adc4245dc1c1694147690451d59ebc61492b4a" + integrity sha512-LfCUW6hYOJHlah78lgwY5Y73C16jHj9LAEaL4vDolT8a59mF59ZZOwKXA2Z0MoJC2TEBdBEeOBzmj83Pq3jBZA== dependencies: - "@design-sdk/figma-types" "^0.0.35" - "@design-sdk/figma-xpath" "^0.0.35" + "@design-sdk/figma-types" "^0.0.37" + "@design-sdk/figma-xpath" "^0.0.37" -"@design-sdk/figma-auth-store@^0.0.21": - version "0.0.21" - resolved "https://registry.npmjs.org/@design-sdk/figma-auth-store/-/figma-auth-store-0.0.21.tgz" - integrity sha512-e6E4ruQvv4QU4nv7ecO+09YvSiN+LzaWwPIbHG2exXQRIiSnYtz1YllCQUPE3QMIOG1AmQ99OQjMPQO7MOGsZA== +"@design-sdk/figma-auth-store@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-auth-store/-/figma-auth-store-0.0.37.tgz#02149d452ca65e0ab390518d98f4b887345a11fb" + integrity sha512-ghv33tV24EO13H2BZhY99krB0Mb4tFyAsKGRhGQGIMWD+Y/JLjknx6M5uIrEPwSW6dQ5JqRI84cAcUwC/jCAfA== "@design-sdk/figma-core@^0.0.25": version "0.0.25" resolved "https://registry.yarnpkg.com/@design-sdk/figma-core/-/figma-core-0.0.25.tgz#7fa28cc7d6e45cd713c5f268d42e4dd4f2b41590" integrity sha512-6OF7eUbDOlR4/BFtd2FRyDvvUf777OGNbVbNScUOv3Fk/kUXBzMTXX6ZdoRlTx887v/vo3+Lh0D31SG1sm80aA== -"@design-sdk/figma-node-conversion@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-node-conversion/-/figma-node-conversion-0.0.35.tgz#efd59645b360d103a3e9949e128d04bca81959ac" - integrity sha512-2KKcvN6FybWWktOTExLI4yft7FqbgKnbh0A+2RTr4ggm66My9ILZoFPjlm0ofVmK87uuyUtMZbmIal0XjVar+w== +"@design-sdk/figma-node-conversion@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-node-conversion/-/figma-node-conversion-0.0.37.tgz#82b6a488b794b98affb8968f6007410fbdc6f2ca" + integrity sha512-n4Rni4jPSlyazdP8OFp4PIIf6oFxb1BLtpdlyZOhjiLvQs9gXweiIR5Ctdpeag5Ck8Dqr+Ygp1EvYYfdP10K3g== dependencies: - "@design-sdk/figma-node" "^0.0.35" - "@design-sdk/figma-types" "^0.0.35" - "@design-sdk/figma-utils" "^0.0.35" - "@design-sdk/flags" "^0.0.35" + "@design-sdk/figma-node" "^0.0.37" + "@design-sdk/figma-types" "^0.0.37" + "@design-sdk/figma-utils" "^0.0.37" + "@design-sdk/flags" "^0.0.37" "@reflect-ui/cg" "^0.0.5" "@reflect-ui/core" "^0.0.5" "@reflect-ui/font-utils" "^0.0.5" -"@design-sdk/figma-node-repository@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-node-repository/-/figma-node-repository-0.0.35.tgz#d3782b861d24afb7b7a5d671889a6c046e7ab4c3" - integrity sha512-uu2PB7/OH9hgSOAiXTFsJj7qxcClRktOW6ol4B67jIwpP4B5O//YAQilU+ELxgTuSh8Y9P7CSq6GeoxVc/zJFg== +"@design-sdk/figma-node-repository@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-node-repository/-/figma-node-repository-0.0.37.tgz#daac04f5fb36aa8374b6173e1338fa200c0f3b2b" + integrity sha512-npf3AF7HV+brBmDk5bujYkQ8v2uuwORBorMGHn2bcd7/fsH4yIG7yp7qHuR2tXAqthYJk7L9yzO/mPx1GN+UYg== dependencies: - "@design-sdk/figma-node" "^0.0.35" - "@design-sdk/figma-types" "^0.0.35" + "@design-sdk/figma-node" "^0.0.37" + "@design-sdk/figma-types" "^0.0.37" -"@design-sdk/figma-node@0.0.25", "@design-sdk/figma-node@^0.0.35": +"@design-sdk/figma-node@0.0.25", "@design-sdk/figma-node@^0.0.37": version "0.0.25" resolved "https://registry.yarnpkg.com/@design-sdk/figma-node/-/figma-node-0.0.25.tgz#c95484cc4b003667ae93e95fa3b585b9fa0b740a" integrity sha512-GCA5cGDXhvGUQddmSIZgPMhH0eGip9S0yDSQiys1XiKnXsB/CM8/5C+JVosHR1WFMHSlJfU+ytA4IH2yhfysUQ== @@ -1453,36 +1453,36 @@ "@design-sdk/figma-utils" "^0.0.25" "@reflect-ui/font-utils" "^0.0.1" -"@design-sdk/figma-remote-api@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-remote-api/-/figma-remote-api-0.0.35.tgz#b2122734b79876b080e30abddc96f576bd31eb31" - integrity sha512-aqMu+/i8Oqv8UtbUSlK8K6pRvos5PCbuT65kR0pF2hay4X6nWJh0ErfjKqHcEeYxZB/MYFo00ZyiQ+Y78bV2Tw== - -"@design-sdk/figma-remote-types@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-remote-types/-/figma-remote-types-0.0.35.tgz#e1312c92183c95c14249dad96fd88fa894591d43" - integrity sha512-XJRD5Ogz9bqRsKgPo8kN0ULBipxooKDy/N/VuKQNGNZWvtfI1TsAYrYSQ8MU25vgw5DJlyStg+jgOKaFHKvBrg== - -"@design-sdk/figma-remote@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-remote/-/figma-remote-0.0.35.tgz#bcf065ca755464c53a4bdf3298ffba235df66521" - integrity sha512-8c9BO6xjmKROw30Rcc5/XmuESNz3qdPWzXNou4j6DfmafwWuCH/t/rFKEmJ3CF/LFaFUcnjsx8HkX3FmUAdbxQ== - dependencies: - "@design-sdk/asset-repository" "^0.0.35" - "@design-sdk/figma-node" "^0.0.35" - "@design-sdk/figma-node-conversion" "^0.0.35" - "@design-sdk/figma-remote-api" "^0.0.35" - "@design-sdk/figma-utils" "^0.0.35" - -"@design-sdk/figma-types@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-types/-/figma-types-0.0.35.tgz#fa773d8912c0f7d5714715782393132b0d1ea21d" - integrity sha512-WBrMvJ1KLmER5UpBM/LDfM55jdK5GWTepRPJJ+ZDsNAov1Apy+u66q6Q4zhBwAGNnjIC3ERb7WW5KUI1mJ/t1Q== - -"@design-sdk/figma-url@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-url/-/figma-url-0.0.35.tgz#351f2f94d9661f9c4ee3c5eca7d5a43759702298" - integrity sha512-6+n1yUkucC0HJbhipzfQhSFvh4YR+fq1MVTxzPiPOkD5lMU/BQwKHrjj4mMoD4jvd7vBLS7lMxODOfNs/Tmr5A== +"@design-sdk/figma-remote-api@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-remote-api/-/figma-remote-api-0.0.37.tgz#ff5cf0f052141a3e79e1b390f7b548e8d893e21d" + integrity sha512-PeIrwMBN8rDSx7CqvQmKLbg5qaEXNXn566ZZNQjD9KMEwWYGfdDai/MCiS1nj/7plI9W5VaAM9JWCd+TmNMtSQ== + +"@design-sdk/figma-remote-types@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-remote-types/-/figma-remote-types-0.0.37.tgz#90308ff0f29caed0d438384328432fbf63e36aa5" + integrity sha512-BRF7t3nJqK5zT5tHY5qBElRdFywMStVJDG4tHhRkGxudDVaVJ5P+ceDSdGdU2NFhkLGk1vvVmpxCVb3t29PWzQ== + +"@design-sdk/figma-remote@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-remote/-/figma-remote-0.0.37.tgz#40d9a67b4209b5dee2d4bf11f8edd99e6cdb9f24" + integrity sha512-jEsqcFi+EuGw/oSxp+BIrry1Jtzs9UtSSJP+vAIAUj+6eT4coPhm5MHjWLS1LOTocW1cHlUJjKAH7drDUttR0A== + dependencies: + "@design-sdk/asset-repository" "^0.0.37" + "@design-sdk/figma-node" "^0.0.37" + "@design-sdk/figma-node-conversion" "^0.0.37" + "@design-sdk/figma-remote-api" "^0.0.37" + "@design-sdk/figma-utils" "^0.0.37" + +"@design-sdk/figma-types@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-types/-/figma-types-0.0.37.tgz#a8f85d0dce5e73c277669e1b1f6d6fb45be22a35" + integrity sha512-mRq2qDgUjeNvpWJCxtBemIEADuSNBOX+OMfs80v4l4qS7HNDVOYkv5/oRgd7fXuVqzI6dHrCq2SH/DwHdrZfVA== + +"@design-sdk/figma-url@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-url/-/figma-url-0.0.37.tgz#fd02241908955bca086172c23df97c65b4869c64" + integrity sha512-hYJEhhAe8YyGWHU/FiFoqww037fXqM3WAMaUUNr9o0PjUh3a3gMTIaoymhWRA22JJCmznjHSqX3Cs8+kCu4Oag== "@design-sdk/figma-url@^0.0.4": version "0.0.4" @@ -1494,27 +1494,27 @@ resolved "https://registry.yarnpkg.com/@design-sdk/figma-utils/-/figma-utils-0.0.25.tgz#7b7f6632fd8689ef713b27b34a61257accc2052e" integrity sha512-HarFMa14L9zqg8rhLaCTXhTKFd6tlBno1mnSc/vl8ZVilmdq32OFFlmqS4MjyvrTfyAvbwlEMAhxV1SUQhFhRg== -"@design-sdk/figma-utils@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-utils/-/figma-utils-0.0.35.tgz#fdb5e457f490fa73745409b9f9bdcc6f48b14cc0" - integrity sha512-xOFZ4hj9o3cq7Oys9PoX5cdZWbwYtgubsUhAhlNvhukEsVaoiBlScKZR5Dcg0JjDuAYF/s6sX8fG1c+nLNPF9w== - -"@design-sdk/figma-xpath@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-xpath/-/figma-xpath-0.0.35.tgz#cb483bb19daec9c208706c034b2ec34b8fc01a82" - integrity sha512-cok3ShuUrC64R2HX/0U3YSbfK6+REKPTHJLL7vERLyMqYZG89BNHPILXrWd/VpIDKyc2dbN3bDuvZX/zERNaVQ== - -"@design-sdk/figma@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/figma/-/figma-0.0.35.tgz#8bc4d89a81770a68f8f5409ad2bca6328aac9eba" - integrity sha512-TCHsyxHD6RYkyPVXFCbdyFLRFe2JAbFZx+obUVDuhXtKf1aCYR2CUzkT1xQVBCVdXmbiNyBP0FmUY5EFsp3TAw== - dependencies: - "@design-sdk/asset-repository" "^0.0.35" - "@design-sdk/figma-node" "^0.0.35" - "@design-sdk/figma-node-conversion" "^0.0.35" - "@design-sdk/figma-remote" "^0.0.35" - "@design-sdk/figma-types" "^0.0.35" - "@design-sdk/figma-url" "^0.0.35" +"@design-sdk/figma-utils@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-utils/-/figma-utils-0.0.37.tgz#a3ee7512c635b67c6b76ebf4a753dbb3aaa435c3" + integrity sha512-zo+LtckfWx+3Bnhl6zj442cmSTpKGbguhcSKLtaM7ywFsMztx0zy4VMlOrr6C3A2UbGgh2y4BnSkzDE+00EIBA== + +"@design-sdk/figma-xpath@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-xpath/-/figma-xpath-0.0.37.tgz#c2918e254c3f56542120e89bbc0f8be1f0c3db47" + integrity sha512-x3FS3985h61Pa9lXHGPxLKdKoBEnCg2ifQYQvxiNVDOQ3lxVskidCv4uBXjPcMLWuQYluaN7ECmlEPA6O0BxkQ== + +"@design-sdk/figma@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma/-/figma-0.0.37.tgz#5ea13332beb87ccda4956f7a66688c2ea3e9eebd" + integrity sha512-HlIVLur5PUgT920JQhtyjHLqlCwZhj0RooNdAw+uylKcecz9D1Nz1m03Kt2kMUeQ9GN3eXvR94qbSR1fb+riRg== + dependencies: + "@design-sdk/asset-repository" "^0.0.37" + "@design-sdk/figma-node" "^0.0.37" + "@design-sdk/figma-node-conversion" "^0.0.37" + "@design-sdk/figma-remote" "^0.0.37" + "@design-sdk/figma-types" "^0.0.37" + "@design-sdk/figma-url" "^0.0.37" "@reflect-ui/uiutils" "0.1.2-1" "@design-sdk/flags@^0.0.17": @@ -1522,17 +1522,22 @@ resolved "https://registry.npmjs.org/@design-sdk/flags/-/flags-0.0.17.tgz" integrity sha512-GRb24/NmZwd/O4UZHoDeOTebd8uU+u/oF5+P9OvrPYgds7CeWHftYeuu/RtXMn3i5GBXiMYw1W2r6mRCj486KQ== -"@design-sdk/flags@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/flags/-/flags-0.0.35.tgz#279c2cbef97bb114ed15151f9d753c6c6dee06c8" - integrity sha512-X8cvcC/8RjUHvOjlwpqgPGpaTHCAoGsrFG/Vz4hK9gl6MFSwu3TSbPaQPSmagBwd0J28rDquIS9xMMWxWKFJyg== +"@design-sdk/flags@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/flags/-/flags-0.0.37.tgz#9b9bae2b2050cff7b616ec5dbccfbb0faf354b4c" + integrity sha512-ydMETYCeHREit9lbZSulgWhMSc+dtjM8kf1NJqOrPwMA01uO/5AX51Fc9KZ8kT2fAJdClEGVVf4xIbZFb2Hf5Q== dependencies: - "@design-sdk/core-flags-dashdash" "^0.0.35" + "@design-sdk/core-flags-dashdash" "^0.0.37" -"@design-sdk/url-analysis@^0.0.35": - version "0.0.35" - resolved "https://registry.yarnpkg.com/@design-sdk/url-analysis/-/url-analysis-0.0.35.tgz#64819b2926f12372c57c472947a2f8342aa5a6b3" - integrity sha512-jrJPKtIsmeWvVYBzEbOk8ksUukDjRHPwuMRDlhfQr16kTc5eZ0N0kKF/7Mvzhh4XS9B3R1gvH5sF2qDlQrjHkA== +"@design-sdk/query@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/query/-/query-0.0.37.tgz#5b28fb74608de20b213103a636506c25f5242b16" + integrity sha512-XI+GzPSzHQt4UqU0GbJqeaCWzA/e0dxJiKV/+8M8+MPlTdSiosu+uWBNfpcKbx3FsxwNIsLGmG3P4eBzemRhSQ== + +"@design-sdk/url-analysis@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/url-analysis/-/url-analysis-0.0.37.tgz#cfd0725c42f63d50dcc611d8cd9f8f5a730e80d6" + integrity sha512-6G8Wtb0wsjxU2qmG0OYHsuA+IpOusBAu1ND39nVvRnKaXAR5ArO8BX5WctIwSDYvfFgSZu36QMtgcDKHF7olvw== "@discoveryjs/json-ext@^0.5.3": version "0.5.7" From 6056ef24369043b49201cb2485cab858cd635634 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 01:57:12 +0900 Subject: [PATCH 47/67] add tsconfig --- editor-packages/editor-canvas/tsconfig.json | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 editor-packages/editor-canvas/tsconfig.json diff --git a/editor-packages/editor-canvas/tsconfig.json b/editor-packages/editor-canvas/tsconfig.json new file mode 100644 index 00000000..35f5aaab --- /dev/null +++ b/editor-packages/editor-canvas/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es2015", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": false, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "baseUrl": "." + }, + "include": ["**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} From ce1139554ec36c7e95c686639ab2049d5c40d7ea Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 02:12:51 +0900 Subject: [PATCH 48/67] fix build --- editor/core/actions/index.ts | 2 +- editor/scaffolds/code/index.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/editor/core/actions/index.ts b/editor/core/actions/index.ts index 3b57fb45..50846655 100644 --- a/editor/core/actions/index.ts +++ b/editor/core/actions/index.ts @@ -1,4 +1,4 @@ -import type { FrameworkConfig } from "@designto/config"; +import type { FrameworkConfig } from "@grida/builder-config"; import type { ConsoleLog, EditorState, diff --git a/editor/scaffolds/code/index.tsx b/editor/scaffolds/code/index.tsx index 44f1ad53..3b50e54c 100644 --- a/editor/scaffolds/code/index.tsx +++ b/editor/scaffolds/code/index.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from "react"; import styled from "@emotion/styled"; import { useRouter } from "next/router"; import { CodeEditor } from "components/code-editor"; +import { EditorAppbarFragments } from "components/editor"; import { get_framework_config } from "query/to-code-options-from-query"; import { CodeOptionsControl } from "components/codeui-code-options-control"; import { designToCode, Result } from "@designto/code"; From 892aca47611ae12f2de2bbca40da551435d9309a Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 04:02:13 +0900 Subject: [PATCH 49/67] fix build --- editor/core/reducers/editor-reducer.ts | 4 ++-- editor/scaffolds/editor/warmup.ts | 2 +- .../preview-canvas/image-preview.tsx | 24 +++++++++---------- editor/scaffolds/preview-canvas/prop-type.ts | 5 +--- editor/scaffolds/preview-canvas/util.ts | 2 +- .../preview-canvas/vanilla-preview-async.tsx | 6 ++--- .../vanilla-preview-webworker.tsx | 3 ++- .../workers/canvas-preview.worker.js | 6 ++--- 8 files changed, 24 insertions(+), 28 deletions(-) diff --git a/editor/core/reducers/editor-reducer.ts b/editor/core/reducers/editor-reducer.ts index a1d310ad..78bb3752 100644 --- a/editor/core/reducers/editor-reducer.ts +++ b/editor/core/reducers/editor-reducer.ts @@ -18,8 +18,8 @@ import type { import { EditorState } from "core/states"; import { useRouter } from "next/router"; import { CanvasStateStore } from "@code-editor/canvas/stores"; +import q from "@design-sdk/query"; import assert from "assert"; -import { find_node_by_id_under_inpage_nodes } from "@design-sdk/core/utils/query"; const _editor_path_name = "/files/[key]/"; @@ -117,7 +117,7 @@ export function editorReducer(state: EditorState, action: Action): EditorState { ); node - .map((n) => find_node_by_id_under_inpage_nodes(n, page.children)) + .map((n) => q.getNodeByIdFrom(n, page.children)) .map((n) => { n.x += translate[0]; n.y += translate[1]; diff --git a/editor/scaffolds/editor/warmup.ts b/editor/scaffolds/editor/warmup.ts index 60871d4d..e7a18631 100644 --- a/editor/scaffolds/editor/warmup.ts +++ b/editor/scaffolds/editor/warmup.ts @@ -45,7 +45,7 @@ export function pagesFrom( filekey: string, file: FileResponse ): FigmaReflectRepository["pages"] { - return file.document.children.map((page) => ({ + return (file.document.children as Array).map((page) => ({ id: page.id, name: page.name, children: page["children"]?.map((child) => { diff --git a/editor/scaffolds/preview-canvas/image-preview.tsx b/editor/scaffolds/preview-canvas/image-preview.tsx index 14fa30cf..bf7a14c2 100644 --- a/editor/scaffolds/preview-canvas/image-preview.tsx +++ b/editor/scaffolds/preview-canvas/image-preview.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { remote } from "@design-sdk/figma"; +import { fetchNodeAsImage } from "@design-sdk/figma-remote"; const DEV_ONLY_FIGMA_PAT = process.env.NEXT_PUBLIC_DEVELOPER_FIGMA_PERSONAL_ACCESS_TOKEN; @@ -20,18 +20,16 @@ export function FigmaFrameImageView({ useEffect(() => { // fetch image from figma // fetch smaller one first, then fatch the full scaled. - remote - .fetchNodeAsImage( - filekey, - { personalAccessToken: DEV_ONLY_FIGMA_PAT }, - nodeid - // scale = 1 - ) - .then((r) => { - console.log("fetched image from figma", r); - setImage_1(r.__default); - setImage_s(r.__default); - }); + fetchNodeAsImage( + filekey, + { personalAccessToken: DEV_ONLY_FIGMA_PAT }, + nodeid + // scale = 1 + ).then((r) => { + console.log("fetched image from figma", r); + setImage_1(r.__default); + setImage_s(r.__default); + }); }, [filekey, nodeid]); let imgscale: 1 | 0.2 = 1; diff --git a/editor/scaffolds/preview-canvas/prop-type.ts b/editor/scaffolds/preview-canvas/prop-type.ts index 0d39baa7..c02c8b82 100644 --- a/editor/scaffolds/preview-canvas/prop-type.ts +++ b/editor/scaffolds/preview-canvas/prop-type.ts @@ -2,8 +2,5 @@ import type { ReflectSceneNode } from "@design-sdk/figma-node"; import type { FrameOptimizationFactors } from "@code-editor/canvas/frame"; export type VanillaPreviewProps = { - target: ReflectSceneNode & { - page: string; - filekey: string; - }; + target: ReflectSceneNode; } & FrameOptimizationFactors; diff --git a/editor/scaffolds/preview-canvas/util.ts b/editor/scaffolds/preview-canvas/util.ts index 70ea6024..7df37353 100644 --- a/editor/scaffolds/preview-canvas/util.ts +++ b/editor/scaffolds/preview-canvas/util.ts @@ -1,4 +1,4 @@ -import { colorFromFills } from "@design-sdk/core/utils/colors"; +import { colorFromFills } from "@design-sdk/core/utils"; import type { ReflectSceneNode } from "@design-sdk/figma-node"; export const blurred_bg_fill = (target: ReflectSceneNode) => { diff --git a/editor/scaffolds/preview-canvas/vanilla-preview-async.tsx b/editor/scaffolds/preview-canvas/vanilla-preview-async.tsx index d7e99b22..4d58c01f 100644 --- a/editor/scaffolds/preview-canvas/vanilla-preview-async.tsx +++ b/editor/scaffolds/preview-canvas/vanilla-preview-async.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useState } from "react"; -import { config } from "@designto/config"; +import { config } from "@grida/builder-config"; import { preview_presets } from "@grida/builder-config-preset"; import { designToCode, Result } from "@designto/code"; -import { MainImageRepository } from "@design-sdk/core/assets-repository"; +import { MainImageRepository } from "@design-sdk/asset-repository"; import { cachekey, cache } from "./cache"; import { blurred_bg_fill } from "./util"; import { PreviewContent } from "./preview-content"; @@ -50,7 +50,7 @@ export function D2CVanillaPreview({ } } setPreview(result); - cache.set(target.filekey, { ...result, __image }); + cache.set(target.filekey as string, { ...result, __image }); }; const hide_preview = isZooming || isPanning; diff --git a/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx b/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx index 2cef7a22..362546bd 100644 --- a/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx +++ b/editor/scaffolds/preview-canvas/vanilla-preview-webworker.tsx @@ -20,7 +20,8 @@ export function WebWorkerD2CVanillaPreview({ target }: VanillaPreviewProps) { setTimeout(() => { dispose = wwpreview( { - page: target.page, + page: "", // TODO: + // page: target.page, target: target.id, }, setPreview diff --git a/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js b/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js index 2025cc75..46157bc1 100644 --- a/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js +++ b/editor/scaffolds/preview-canvas/workers/canvas-preview.worker.js @@ -2,9 +2,9 @@ import { designToCode } from "@designto/code"; import { ImageRepository, MainImageRepository, -} from "@design-sdk/core/assets-repository"; -import { RemoteImageRepositories } from "@design-sdk/figma-remote/lib/asset-repository/image-repository"; -import { config } from "@designto/config"; +} from "@design-sdk/asset-repository"; +import { RemoteImageRepositories } from "@design-sdk/figma-remote/asset-repository"; +import { config } from "@grida/builder-config"; import { preview_presets } from "@grida/builder-config-preset"; import { FigmaFileStore } from "@editor/figma-file-store"; import { convert } from "@design-sdk/figma-node-conversion"; From f07afd60675eb1c67d941901d68b373abcbdbe28 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 04:26:31 +0900 Subject: [PATCH 50/67] disable chrome default gesture --- editor/styles/global.css | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/editor/styles/global.css b/editor/styles/global.css index 4a78ecbb..e1991479 100644 --- a/editor/styles/global.css +++ b/editor/styles/global.css @@ -2,11 +2,17 @@ body { margin: 0px; padding: 0; font-family: "Helvetica Nueue", "Roboto", sans-serif; +} - /* for editor canvas */ +/* for editor canvas */ +html { + overscroll-behavior-x: none; +} +body { overscroll-behavior-x: none; - overscroll-behavior-y: none; + touch-action: none; } +/* ----------------- */ iframe { border: none; From 2360dbbf1acca256de33d03e77e490645d7f4366 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 04:26:46 +0900 Subject: [PATCH 51/67] update readonly canvas --- .../editor-canvas/canvas/canvas.tsx | 2 -- .../editor-canvas/hud/hud-surface.tsx | 32 ++++++++++++----- editor/scaffolds/canvas/canvas.tsx | 35 ++++++++++--------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index 5471898e..4fd713a2 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -392,8 +392,6 @@ export function Canvas({ ?.map((id) => qdoc.getNodeById(id)) .filter(Boolean); - console.log({ selectedNodes, highlightedLayer, selected_nodes }); - const items = useMemo(() => { return nodes?.map((node) => { return ( diff --git a/editor-packages/editor-canvas/hud/hud-surface.tsx b/editor-packages/editor-canvas/hud/hud-surface.tsx index 17342972..1c8524fd 100644 --- a/editor-packages/editor-canvas/hud/hud-surface.tsx +++ b/editor-packages/editor-canvas/hud/hud-surface.tsx @@ -151,7 +151,11 @@ export function HudSurface({ } }) ) : ( - + ) ) : ( <> @@ -166,7 +170,9 @@ function SelectionGroupHighlight({ selections, zoom, disableSizeDisplay = false, + readonly, }: { + readonly: boolean; selections: DisplayNodeMeta[]; zoom: number; disableSizeDisplay?: boolean; @@ -211,13 +217,23 @@ function SelectionGroupHighlight({ <> )} - + {readonly ? ( + + ) : ( + + )} ); } diff --git a/editor/scaffolds/canvas/canvas.tsx b/editor/scaffolds/canvas/canvas.tsx index 10a6ef84..dbe0cf29 100644 --- a/editor/scaffolds/canvas/canvas.tsx +++ b/editor/scaffolds/canvas/canvas.tsx @@ -2,7 +2,10 @@ import React, { useCallback } from "react"; import styled from "@emotion/styled"; import { Canvas } from "@code-editor/canvas"; import { useEditorState, useWorkspace } from "core/states"; -import { WebWorkerD2CVanillaPreview } from "scaffolds/preview-canvas"; +import { + WebWorkerD2CVanillaPreview, + D2CVanillaPreview, +} from "scaffolds/preview-canvas"; import useMeasure from "react-use-measure"; import { useDispatch } from "core/dispatch"; import { FrameTitleRenderer } from "./render/frame-title"; @@ -119,18 +122,15 @@ export function VisualContentArea() { selectedNodes={selectedNodes} highlightedLayer={highlightedLayer} onSelectNode={(...nodes) => { + dispatch({ type: "select-node", node: nodes.map((n) => n.id) }); + }} + onMoveNodeEnd={([x, y], ...nodes) => { dispatch({ - type: "select-node", - node: nodes.map((n) => n?.id), + type: "node-transform-translate", + node: nodes, + translate: [x, y], }); }} - // onMoveNodeEnd={([x, y], ...nodes) => { - // dispatch({ - // type: "node-transform-translate", - // node: nodes, - // translate: [x, y], - // }); - // }} // onMoveNode={() => {}} onClearSelection={() => { dispatch({ type: "select-node", node: [] }); @@ -139,15 +139,16 @@ export function VisualContentArea() { // initialTransform={ } // TODO: if the initial selection is provided from first load, from the query param, we have to focus to fit that node. renderItem={(p) => { return ( - - // + // + ); }} - readonly={false} + // readonly={false} + readonly config={{ can_highlight_selected_layer: true, marquee: { From 24d4ab01a24552ee97b19a64c857a5cb885b304b Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 04:34:00 +0900 Subject: [PATCH 52/67] fix typo --- editor-packages/editor-canvas/canvas/canvas.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index 4fd713a2..5337a95c 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -158,7 +158,7 @@ export function Canvas({ ? [offset[0] / zoom, offset[1] / zoom] : [0, 0]; const [isPanning, setIsPanning] = useState(false); - const [isDraggimg, setIsDragging] = useState(false); + const [isDragging, setIsDragging] = useState(false); const [isMovingSelections, setIsMovingSelections] = useState(false); const [marquee, setMarquee] = useState(null); @@ -220,7 +220,7 @@ export function Canvas({ }, [marquee]); const onPointerMove: OnPointerMoveHandler = (state) => { - if (isPanning || isZooming || isDraggimg) { + if (isPanning || isZooming || isDragging) { // don't perform hover calculation while transforming. return; } From 076eaf0e9f06b1516fc8d3461f58dbb4ccec6f25 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 14:14:33 +0900 Subject: [PATCH 53/67] extract context menu provider --- .../editor-canvas/canvas/canvas.tsx | 49 +++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index 5337a95c..4cb753fb 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -231,7 +231,7 @@ export function Canvas({ offset: nonscaled_offset, margin: CANVAS_LAYER_HOVER_HIT_MARGIN, reverse: true, - ignore: (n) => selectedNodes.includes(n.id), + // ignore: (n) => selectedNodes.includes(n.id), }); if (!hovering) { @@ -256,7 +256,7 @@ export function Canvas({ return; } - if (shouldStartMoveSelections([x, y])) { + if (!readonly && shouldStartMoveSelections([x, y])) { return; // don't do anything. onDrag will handle this. only block the event. } @@ -311,7 +311,7 @@ export function Canvas({ const [x1, y1] = [x - ox, y - oy]; // if dragging a selection group bounding box, move the selected items. - if (shouldStartMoveSelections([x, y])) { + if (!readonly && shouldStartMoveSelections([x, y])) { setIsMovingSelections(true); onMoveNodeStart?.(...selectedNodes); return; @@ -418,21 +418,7 @@ export function Canvas({ return ( <> - { - console.log("exec canvas cmd", v); - }} - > + { - onSelectNode(node(id)); + onSelectNode?.(node(id)); }} renderFrameTitle={props.renderFrameTitle} /> - + {items} @@ -513,6 +500,28 @@ const Container = styled.div<{ width: number; height: number }>` height: ${(p) => p.height}px; `; +function ContextMenuProvider({ children }: React.PropsWithChildren<{}>) { + return ( + { + console.log("exec canvas cmd", v); + }} + > + {children} + + ); +} + function noduplicates( a: ReflectSceneNode[], b: ReflectSceneNode[] From 9824e21d3e18ec3a6fd69278fdd3bd4f27d83b5a Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 16:27:53 +0900 Subject: [PATCH 54/67] add spacing guide math --- .../editor-canvas/math/bounding-box.ts | 13 ++++ .../editor-canvas/math/guide-spacing.ts | 78 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 editor-packages/editor-canvas/math/guide-spacing.ts diff --git a/editor-packages/editor-canvas/math/bounding-box.ts b/editor-packages/editor-canvas/math/bounding-box.ts index da3f427c..a45c7f62 100644 --- a/editor-packages/editor-canvas/math/bounding-box.ts +++ b/editor-packages/editor-canvas/math/bounding-box.ts @@ -107,3 +107,16 @@ export function box_to_xywhr(box: Box): XYWHR { const [x1, y1, x2, y2] = box; return [x1, y1, x2 - x1, y2 - y1, 0]; } + +/** + * intersection of two boxes in format of [x1, y1, x2, y2] + */ +export function intersection(a: Box, b: Box): Box { + const [x1, y1, x2, y2] = a; + const [x3, y3, x4, y4] = b; + const x5 = Math.max(x1, x3); + const y5 = Math.max(y1, y3); + const x6 = Math.min(x2, x4); + const y6 = Math.min(y2, y4); + return [x5, y5, x6, y6]; +} diff --git a/editor-packages/editor-canvas/math/guide-spacing.ts b/editor-packages/editor-canvas/math/guide-spacing.ts new file mode 100644 index 00000000..6d1b9874 --- /dev/null +++ b/editor-packages/editor-canvas/math/guide-spacing.ts @@ -0,0 +1,78 @@ +import { intersection } from "./bounding-box"; +import type { Box } from "../types"; + +/** + * The spacing guide display infromation interface. + * + * the top, right, bottom, left spacing is relative to box. + * + * the box is usually calculated with two givven input a and b. and its intersection or the origin (a) + */ +interface SpacingGuide { + box: Box; + /** + * top, right, bottom, left + */ + spacing: [number, number, number, number]; +} + +/** + * + * calculates the base box and the spacing of t, r, b, l with givven a and b boxes. + * + * the a and b boxes are formed with [x, y, x2, y2] format. + * + * - if the two boxes does not intersect, the base box will be the origin (a). + * - if one of the box is contained in another in the space grid, the base box will be the contained (smaller) box. + * - if the two boxes intersect, the base box will be the intersection of the two boxes. + * + * the top, right, bottom, left spacing is relative to the base box. + * + * [t, r, b, l] + * t = abs(t1 - t2) + * r = abs(r1 - r2) + * b = abs(b1 - b2) + * l = abs(l1 - l2) + * + * For example + * - a = [10, 10, 20, 20], b = [20, 20, 30, 30], then the spacing is [10, 0, 0, 10] and the base box is [10, 10, 20, 20] + * - a = [10, 10, 20, 20], b = [15, 15, 25, 25], then the spacing is [5, 5, 5, 5] and the base box is [15, 15, 20, 20] + * - a = [450, 450, 550, 550], b = [0, 0, 1000, 1000], then the spacing is [450, 540, 540, 450] and the base box is [450, 450, 550, 550] + * - a = [0, 0, 1000, 1000], b = [450, 450, 550, 550], then the spacing is [450, 540, 540, 450] and the base box is [450, 450, 550, 550] + * - a = [0, 0, 50, 50], b = [0, 0, 20, 20], then the spacing is [0, 30, 30, 0] and the base box is [0, 0, 20, 20] + * + */ +export function spacing_guide(a: Box, b: Box): SpacingGuide { + let box: Box; + + // no intersection + if (a[0] > b[2] || a[2] < b[0] || a[1] > b[3] || a[3] < b[1]) { + box = a; + } + + // a contains b + else if (a[0] <= b[0] && a[1] <= b[1] && a[2] >= b[2] && a[3] >= b[3]) { + box = b; + } + + // b contains a + else if (a[0] >= b[0] && a[1] >= b[1] && a[2] <= b[2] && a[3] <= b[3]) { + box = a; + } + + // intersection + else { + // calculate the intersection of two boxes as a coordinate [x, y, x2, y2] + box = intersection(a, b); + } + + // calculate the spacing of t, r, b, l + const spacing: [number, number, number, number] = [ + Math.abs(a[1] - b[1]), + Math.abs(a[2] - b[2]), + Math.abs(a[3] - b[3]), + Math.abs(a[0] - b[0]), + ]; + + return { box, spacing }; +} From 9ed85ba9dec47f18c5f05e6e9aa48d56c4f8c801 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 16:28:25 +0900 Subject: [PATCH 55/67] chore --- editor-packages/editor-canvas/overlay/handle.tsx | 4 +++- editor-packages/editor-canvas/overlay/k.ts | 3 +++ editor/scaffolds/inspector/section-layout.tsx | 15 ++++++++++----- editor/scaffolds/preview-canvas/cache.ts | 6 +++++- 4 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 editor-packages/editor-canvas/overlay/k.ts diff --git a/editor-packages/editor-canvas/overlay/handle.tsx b/editor-packages/editor-canvas/overlay/handle.tsx index b5c93c95..32cf1574 100644 --- a/editor-packages/editor-canvas/overlay/handle.tsx +++ b/editor-packages/editor-canvas/overlay/handle.tsx @@ -1,4 +1,6 @@ import React, { forwardRef } from "react"; +import * as k from "./k"; + export const Handle = forwardRef(function ({ color, anchor, @@ -59,7 +61,7 @@ export const Handle = forwardRef(function ({ transform: `translate3d(${tx}px, ${ty}px, 0)`, backgroundColor: color, cursor: cursor, - zIndex: 2, + zIndex: k.Z_INDEX_GUIDE_POSITION, pointerEvents: readonly ? "none" : "auto", }} /> diff --git a/editor-packages/editor-canvas/overlay/k.ts b/editor-packages/editor-canvas/overlay/k.ts new file mode 100644 index 00000000..2efc0016 --- /dev/null +++ b/editor-packages/editor-canvas/overlay/k.ts @@ -0,0 +1,3 @@ +export const Z_INDEX_HANDLE = 2; +export const Z_INDEX_GUIDE_POSITION = 3; +export const Z_INDEX_GUIDE_SPACING = 4; diff --git a/editor/scaffolds/inspector/section-layout.tsx b/editor/scaffolds/inspector/section-layout.tsx index cdf0b434..e2898f00 100644 --- a/editor/scaffolds/inspector/section-layout.tsx +++ b/editor/scaffolds/inspector/section-layout.tsx @@ -5,17 +5,22 @@ import React from "react"; export function LayoutSection() { const { target, root } = useTargetContainer(); - const isroot = root?.id === target?.id; + + if (!target) { + return <>; + } + + const { isRoot, x, y, width, height } = target; return ( - - + + - - + + ); diff --git a/editor/scaffolds/preview-canvas/cache.ts b/editor/scaffolds/preview-canvas/cache.ts index b0b6170a..0580c6e0 100644 --- a/editor/scaffolds/preview-canvas/cache.ts +++ b/editor/scaffolds/preview-canvas/cache.ts @@ -4,7 +4,11 @@ type TResultCache = Result & { __image: boolean }; export const cache = { set: (key: string, value: TResultCache) => { - sessionStorage.setItem(key, JSON.stringify(value)); + try { + sessionStorage.setItem(key, JSON.stringify(value)); + } catch (e) { + // - TypeError: Converting circular structure to JSON + } }, get: (key: string): TResultCache => { const value = sessionStorage.getItem(key); From 069415e1ba976fd153c3d7600e28a29007fbea98 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 16:47:31 +0900 Subject: [PATCH 56/67] add jest testing --- editor-packages/editor-canvas/jest.config.js | 3 + .../editor-canvas/math/guide-spacing.test.ts | 47 + .../editor-canvas/math/guide-spacing.ts | 8 +- editor-packages/editor-canvas/math/index.ts | 3 +- editor-packages/editor-canvas/package.json | 11 +- yarn.lock | 1164 ++++++++++++++++- 6 files changed, 1190 insertions(+), 46 deletions(-) create mode 100644 editor-packages/editor-canvas/jest.config.js create mode 100644 editor-packages/editor-canvas/math/guide-spacing.test.ts diff --git a/editor-packages/editor-canvas/jest.config.js b/editor-packages/editor-canvas/jest.config.js new file mode 100644 index 00000000..08e581c5 --- /dev/null +++ b/editor-packages/editor-canvas/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: "ts-jest", +}; diff --git a/editor-packages/editor-canvas/math/guide-spacing.test.ts b/editor-packages/editor-canvas/math/guide-spacing.test.ts new file mode 100644 index 00000000..c751f71b --- /dev/null +++ b/editor-packages/editor-canvas/math/guide-spacing.test.ts @@ -0,0 +1,47 @@ +import { spacing_guide } from "./guide-spacing"; + +// tests +// - a = [10, 10, 20, 20], b = [20, 20, 30, 30], then the spacing is [10, 10, 10, 10] and the base box is [20, 20, 20, 20] +// - a = [10, 10, 20, 20], b = [15, 15, 25, 25], then the spacing is [5, 5, 5, 5] and the base box is [15, 15, 20, 20] +// - a = [450, 450, 550, 550], b = [0, 0, 1000, 1000], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] +// - a = [0, 0, 1000, 1000], b = [450, 450, 550, 550], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] +// - a = [0, 0, 50, 50], b = [0, 0, 20, 20], then the spacing is [0, 30, 30, 0] and the base box is [0, 0, 20, 20] + +test("spacing guide (not intersecting)", () => { + expect(spacing_guide([10, 10, 20, 20], [20, 20, 30, 30])).toStrictEqual({ + box: [20, 20, 20, 20], + spacing: [10, 10, 10, 10], + }); +}); + +test("spacing guide (intersecting)", () => { + expect(spacing_guide([10, 10, 20, 20], [15, 15, 25, 25])).toStrictEqual({ + box: [15, 15, 20, 20], + spacing: [5, 5, 5, 5], + }); +}); + +test("spacing guide (b contains a)", () => { + expect(spacing_guide([450, 450, 550, 550], [0, 0, 1000, 1000])).toStrictEqual( + { + box: [450, 450, 550, 550], + spacing: [450, 450, 450, 450], + } + ); +}); + +test("spacing guide (a contains b)", () => { + expect(spacing_guide([0, 0, 1000, 1000], [450, 450, 550, 550])).toStrictEqual( + { + box: [450, 450, 550, 550], + spacing: [450, 450, 450, 450], + } + ); +}); + +test("spacing guide (not intersecting)", () => { + expect(spacing_guide([0, 0, 50, 50], [0, 0, 20, 20])).toStrictEqual({ + box: [0, 0, 20, 20], + spacing: [0, 30, 30, 0], + }); +}); diff --git a/editor-packages/editor-canvas/math/guide-spacing.ts b/editor-packages/editor-canvas/math/guide-spacing.ts index 6d1b9874..40f739f4 100644 --- a/editor-packages/editor-canvas/math/guide-spacing.ts +++ b/editor-packages/editor-canvas/math/guide-spacing.ts @@ -35,17 +35,17 @@ interface SpacingGuide { * l = abs(l1 - l2) * * For example - * - a = [10, 10, 20, 20], b = [20, 20, 30, 30], then the spacing is [10, 0, 0, 10] and the base box is [10, 10, 20, 20] + * - a = [10, 10, 20, 20], b = [20, 20, 30, 30], then the spacing is [10, 10, 10, 10] and the base box is [20, 20, 20, 20] * - a = [10, 10, 20, 20], b = [15, 15, 25, 25], then the spacing is [5, 5, 5, 5] and the base box is [15, 15, 20, 20] - * - a = [450, 450, 550, 550], b = [0, 0, 1000, 1000], then the spacing is [450, 540, 540, 450] and the base box is [450, 450, 550, 550] - * - a = [0, 0, 1000, 1000], b = [450, 450, 550, 550], then the spacing is [450, 540, 540, 450] and the base box is [450, 450, 550, 550] + * - a = [450, 450, 550, 550], b = [0, 0, 1000, 1000], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] + * - a = [0, 0, 1000, 1000], b = [450, 450, 550, 550], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] * - a = [0, 0, 50, 50], b = [0, 0, 20, 20], then the spacing is [0, 30, 30, 0] and the base box is [0, 0, 20, 20] * */ export function spacing_guide(a: Box, b: Box): SpacingGuide { let box: Box; - // no intersection + // no intersection (if the interecting space is 0, it is also considered as no intersection) if (a[0] > b[2] || a[2] < b[0] || a[1] > b[3] || a[3] < b[1]) { box = a; } diff --git a/editor-packages/editor-canvas/math/index.ts b/editor-packages/editor-canvas/math/index.ts index 5cf8cf7e..f3460953 100644 --- a/editor-packages/editor-canvas/math/index.ts +++ b/editor-packages/editor-canvas/math/index.ts @@ -1,5 +1,6 @@ export * from "./bounding-box"; export * from "./target-of-area"; export * from "./target-of-point"; +export * from "./guide-spacing" export * from "./center-of"; -export * from "./viewbound-edge-scrolling"; +export * from "./viewbound-edge-scrolling"; \ No newline at end of file diff --git a/editor-packages/editor-canvas/package.json b/editor-packages/editor-canvas/package.json index b935d34c..d219ad72 100644 --- a/editor-packages/editor-canvas/package.json +++ b/editor-packages/editor-canvas/package.json @@ -2,7 +2,16 @@ "name": "@code-editor/canvas", "version": "0.0.0", "main": "index.ts", + "scripts": { + "test": "jest" + }, "dependencies": { "react-in-viewport": "^1.0.0-alpha.20" + }, + "devDependencies": { + "@types/jest": "^29.2.0", + "jest": "^29.2.2", + "ts-jest": "^29.0.3", + "typescript": "^4.8.4" } -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index b0c814ca..d71f936b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -36,7 +36,7 @@ "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" chokidar "^3.4.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3": version "7.18.6" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== @@ -48,6 +48,11 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz" integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== +"@babel/compat-data@^7.19.3": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.4.tgz#95c86de137bf0317f3a570e1b6e996b427299747" + integrity sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw== + "@babel/core@7.12.9": version "7.12.9" resolved "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz" @@ -91,6 +96,27 @@ json5 "^2.2.1" semver "^6.3.0" +"@babel/core@^7.11.6": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.19.6.tgz#7122ae4f5c5a37c0946c066149abd8e75f81540f" + integrity sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.19.6" + "@babel/helper-compilation-targets" "^7.19.3" + "@babel/helper-module-transforms" "^7.19.6" + "@babel/helpers" "^7.19.4" + "@babel/parser" "^7.19.6" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.6" + "@babel/types" "^7.19.4" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" + "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.18.9": version "7.18.9" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz" @@ -100,6 +126,15 @@ "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" +"@babel/generator@^7.19.6", "@babel/generator@^7.7.2": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.6.tgz#9e481a3fe9ca6261c972645ae3904ec0f9b34a1d" + integrity sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA== + dependencies: + "@babel/types" "^7.19.4" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz" @@ -125,6 +160,16 @@ browserslist "^4.20.2" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.19.3": + version "7.19.3" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz#a10a04588125675d7c7ae299af86fa1b2ee038ca" + integrity sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg== + dependencies: + "@babel/compat-data" "^7.19.3" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.21.3" + semver "^6.3.0" + "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.18.9": version "7.18.9" resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz" @@ -192,6 +237,14 @@ "@babel/template" "^7.18.6" "@babel/types" "^7.18.9" +"@babel/helper-function-name@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" + integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== + dependencies: + "@babel/template" "^7.18.10" + "@babel/types" "^7.19.0" + "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" @@ -227,6 +280,20 @@ "@babel/traverse" "^7.18.9" "@babel/types" "^7.18.9" +"@babel/helper-module-transforms@^7.19.6": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz#6c52cc3ac63b70952d33ee987cbee1c9368b533f" + integrity sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.19.4" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.6" + "@babel/types" "^7.19.4" + "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz" @@ -272,6 +339,13 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-simple-access@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz#be553f4951ac6352df2567f7daa19a0ee15668e7" + integrity sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg== + dependencies: + "@babel/types" "^7.19.4" + "@babel/helper-skip-transparent-expression-wrappers@^7.18.9": version "7.18.9" resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz" @@ -286,11 +360,21 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-string-parser@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" + integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== + "@babel/helper-validator-identifier@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz" integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g== +"@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + "@babel/helper-validator-option@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" @@ -315,6 +399,15 @@ "@babel/traverse" "^7.18.9" "@babel/types" "^7.18.9" +"@babel/helpers@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.19.4.tgz#42154945f87b8148df7203a25c31ba9a73be46c5" + integrity sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw== + dependencies: + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.19.4" + "@babel/types" "^7.19.4" + "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" @@ -324,6 +417,11 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/parser@^7.1.0", "@babel/parser@^7.18.10", "@babel/parser@^7.19.6": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.6.tgz#b923430cb94f58a7eae8facbffa9efd19130e7f8" + integrity sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA== + "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.14.7", "@babel/parser@^7.18.6", "@babel/parser@^7.18.9": version "7.18.9" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz" @@ -509,7 +607,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.12.13": +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== @@ -565,6 +670,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" @@ -579,14 +691,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-jsx@^7.17.12", "@babel/plugin-syntax-jsx@^7.18.6", "@babel/plugin-syntax-jsx@^7.2.0": +"@babel/plugin-syntax-jsx@^7.17.12", "@babel/plugin-syntax-jsx@^7.18.6", "@babel/plugin-syntax-jsx@^7.2.0", "@babel/plugin-syntax-jsx@^7.7.2": version "7.18.6" resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz" integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -600,7 +712,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.4": +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -635,14 +747,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-top-level-await@^7.14.5": +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": version "7.14.5" resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.18.6": +"@babel/plugin-syntax-typescript@^7.18.6", "@babel/plugin-syntax-typescript@^7.7.2": version "7.18.6" resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz" integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA== @@ -1130,6 +1242,15 @@ "@babel/parser" "^7.18.6" "@babel/types" "^7.18.6" +"@babel/template@^7.18.10", "@babel/template@^7.3.3": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71" + integrity sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.18.10" + "@babel/types" "^7.18.10" + "@babel/traverse@^7.1.6", "@babel/traverse@^7.12.11", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.18.9": version "7.18.9" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz" @@ -1146,6 +1267,31 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.19.4", "@babel/traverse@^7.19.6", "@babel/traverse@^7.7.2": + version "7.19.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.6.tgz#7b4c865611df6d99cb131eec2e8ac71656a490dc" + integrity sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.19.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.19.6" + "@babel/types" "^7.19.4" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.19.0", "@babel/types@^7.19.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.4.tgz#0dd5c91c573a202d600490a35b33246fed8a41c7" + integrity sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw== + dependencies: + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" + to-fast-properties "^2.0.0" + "@babel/types@^7.12.11", "@babel/types@^7.12.7", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.2.0", "@babel/types@^7.4.4": version "7.18.9" resolved "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz" @@ -1418,10 +1564,10 @@ resolved "https://registry.yarnpkg.com/@design-sdk/figma-auth-store/-/figma-auth-store-0.0.37.tgz#02149d452ca65e0ab390518d98f4b887345a11fb" integrity sha512-ghv33tV24EO13H2BZhY99krB0Mb4tFyAsKGRhGQGIMWD+Y/JLjknx6M5uIrEPwSW6dQ5JqRI84cAcUwC/jCAfA== -"@design-sdk/figma-core@^0.0.25": - version "0.0.25" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-core/-/figma-core-0.0.25.tgz#7fa28cc7d6e45cd713c5f268d42e4dd4f2b41590" - integrity sha512-6OF7eUbDOlR4/BFtd2FRyDvvUf777OGNbVbNScUOv3Fk/kUXBzMTXX6ZdoRlTx887v/vo3+Lh0D31SG1sm80aA== +"@design-sdk/figma-core@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-core/-/figma-core-0.0.37.tgz#3934d7d49ec048476d2693f18a7ee85964359794" + integrity sha512-hYD1DKXnNVb0xP4MyaoAQcQVY0Cb/MTBmn9EbWpoSSoNmxpEGHGPdU0ETV5A+nFdBU6L3BN+RIP7wRjNPCrvpA== "@design-sdk/figma-node-conversion@^0.0.37": version "0.0.37" @@ -1444,13 +1590,13 @@ "@design-sdk/figma-node" "^0.0.37" "@design-sdk/figma-types" "^0.0.37" -"@design-sdk/figma-node@0.0.25", "@design-sdk/figma-node@^0.0.37": - version "0.0.25" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-node/-/figma-node-0.0.25.tgz#c95484cc4b003667ae93e95fa3b585b9fa0b740a" - integrity sha512-GCA5cGDXhvGUQddmSIZgPMhH0eGip9S0yDSQiys1XiKnXsB/CM8/5C+JVosHR1WFMHSlJfU+ytA4IH2yhfysUQ== +"@design-sdk/figma-node@^0.0.37": + version "0.0.37" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-node/-/figma-node-0.0.37.tgz#906ccf274c4ae227fab6881a679aee973fe1a038" + integrity sha512-X66YaFpkro1LK/9L93UIxodQv29cJxauoHuWZUIB60nj7Wt57i4GLE/sV4j1laUYHt/751mvjFBMibZzxPcIyw== dependencies: - "@design-sdk/figma-core" "^0.0.25" - "@design-sdk/figma-utils" "^0.0.25" + "@design-sdk/figma-core" "^0.0.37" + "@design-sdk/figma-utils" "^0.0.37" "@reflect-ui/font-utils" "^0.0.1" "@design-sdk/figma-remote-api@^0.0.37": @@ -1489,11 +1635,6 @@ resolved "https://registry.npmjs.org/@design-sdk/figma-url/-/figma-url-0.0.4.tgz" integrity sha512-9wvaecM9vVxI97CNfnckv0S9yi/ES3zuwQBa0ZfM5eQNbZlAgqTwBIi/Q/xsx7d+aePeGs+nEo2UhR52Rd+xNg== -"@design-sdk/figma-utils@^0.0.25": - version "0.0.25" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-utils/-/figma-utils-0.0.25.tgz#7b7f6632fd8689ef713b27b34a61257accc2052e" - integrity sha512-HarFMa14L9zqg8rhLaCTXhTKFd6tlBno1mnSc/vl8ZVilmdq32OFFlmqS4MjyvrTfyAvbwlEMAhxV1SUQhFhRg== - "@design-sdk/figma-utils@^0.0.37": version "0.0.37" resolved "https://registry.yarnpkg.com/@design-sdk/figma-utils/-/figma-utils-0.0.37.tgz#a3ee7512c635b67c6b76ebf4a753dbb3aaa435c3" @@ -2564,6 +2705,129 @@ resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== +"@jest/console@^29.2.1": + version "29.2.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.2.1.tgz#5f2c62dcdd5ce66e94b6d6729e021758bceea090" + integrity sha512-MF8Adcw+WPLZGBiNxn76DOuczG3BhODTcMlDCA4+cFi41OkaY/lyI0XUUhi73F88Y+7IHoGmD80pN5CtxQUdSw== + dependencies: + "@jest/types" "^29.2.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.2.1" + jest-util "^29.2.1" + slash "^3.0.0" + +"@jest/core@^29.2.2": + version "29.2.2" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.2.2.tgz#207aa8973d9de8769f9518732bc5f781efc3ffa7" + integrity sha512-susVl8o2KYLcZhhkvSB+b7xX575CX3TmSvxfeDjpRko7KmT89rHkXj6XkDkNpSeFMBzIENw5qIchO9HC9Sem+A== + dependencies: + "@jest/console" "^29.2.1" + "@jest/reporters" "^29.2.2" + "@jest/test-result" "^29.2.1" + "@jest/transform" "^29.2.2" + "@jest/types" "^29.2.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.2.0" + jest-config "^29.2.2" + jest-haste-map "^29.2.1" + jest-message-util "^29.2.1" + jest-regex-util "^29.2.0" + jest-resolve "^29.2.2" + jest-resolve-dependencies "^29.2.2" + jest-runner "^29.2.2" + jest-runtime "^29.2.2" + jest-snapshot "^29.2.2" + jest-util "^29.2.1" + jest-validate "^29.2.2" + jest-watcher "^29.2.2" + micromatch "^4.0.4" + pretty-format "^29.2.1" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.2.2": + version "29.2.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.2.2.tgz#481e729048d42e87d04842c38aa4d09c507f53b0" + integrity sha512-OWn+Vhu0I1yxuGBJEFFekMYc8aGBGrY4rt47SOh/IFaI+D7ZHCk7pKRiSoZ2/Ml7b0Ony3ydmEHRx/tEOC7H1A== + dependencies: + "@jest/fake-timers" "^29.2.2" + "@jest/types" "^29.2.1" + "@types/node" "*" + jest-mock "^29.2.2" + +"@jest/expect-utils@^29.2.2": + version "29.2.2" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.2.2.tgz#460a5b5a3caf84d4feb2668677393dd66ff98665" + integrity sha512-vwnVmrVhTmGgQzyvcpze08br91OL61t9O0lJMDyb6Y/D8EKQ9V7rGUb/p7PDt0GPzK0zFYqXWFo4EO2legXmkg== + dependencies: + jest-get-type "^29.2.0" + +"@jest/expect@^29.2.2": + version "29.2.2" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.2.2.tgz#81edbd33afbde7795ca07ff6b4753d15205032e4" + integrity sha512-zwblIZnrIVt8z/SiEeJ7Q9wKKuB+/GS4yZe9zw7gMqfGf4C5hBLGrVyxu1SzDbVSqyMSlprKl3WL1r80cBNkgg== + dependencies: + expect "^29.2.2" + jest-snapshot "^29.2.2" + +"@jest/fake-timers@^29.2.2": + version "29.2.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.2.2.tgz#d8332e6e3cfa99cde4bc87d04a17d6b699deb340" + integrity sha512-nqaW3y2aSyZDl7zQ7t1XogsxeavNpH6kkdq+EpXncIDvAkjvFD7hmhcIs1nWloengEWUoWqkqSA6MSbf9w6DgA== + dependencies: + "@jest/types" "^29.2.1" + "@sinonjs/fake-timers" "^9.1.2" + "@types/node" "*" + jest-message-util "^29.2.1" + jest-mock "^29.2.2" + jest-util "^29.2.1" + +"@jest/globals@^29.2.2": + version "29.2.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.2.2.tgz#205ff1e795aa774301c2c0ba0be182558471b845" + integrity sha512-/nt+5YMh65kYcfBhj38B3Hm0Trk4IsuMXNDGKE/swp36yydBWfz3OXkLqkSvoAtPW8IJMSJDFCbTM2oj5SNprw== + dependencies: + "@jest/environment" "^29.2.2" + "@jest/expect" "^29.2.2" + "@jest/types" "^29.2.1" + jest-mock "^29.2.2" + +"@jest/reporters@^29.2.2": + version "29.2.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.2.2.tgz#69b395f79c3a97ce969ce05ccf1a482e5d6de290" + integrity sha512-AzjL2rl2zJC0njIzcooBvjA4sJjvdoq98sDuuNs4aNugtLPSQ+91nysGKRF0uY1to5k0MdGMdOBggUsPqvBcpA== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.2.1" + "@jest/test-result" "^29.2.1" + "@jest/transform" "^29.2.2" + "@jest/types" "^29.2.1" + "@jridgewell/trace-mapping" "^0.3.15" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.2.1" + jest-util "^29.2.1" + jest-worker "^29.2.1" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + "@jest/schemas@^28.1.3": version "28.1.3" resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz" @@ -2571,6 +2835,42 @@ dependencies: "@sinclair/typebox" "^0.24.1" +"@jest/schemas@^29.0.0": + version "29.0.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.0.0.tgz#5f47f5994dd4ef067fb7b4188ceac45f77fe952a" + integrity sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA== + dependencies: + "@sinclair/typebox" "^0.24.1" + +"@jest/source-map@^29.2.0": + version "29.2.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.2.0.tgz#ab3420c46d42508dcc3dc1c6deee0b613c235744" + integrity sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ== + dependencies: + "@jridgewell/trace-mapping" "^0.3.15" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.2.1": + version "29.2.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.2.1.tgz#f42dbf7b9ae465d0a93eee6131473b8bb3bd2edb" + integrity sha512-lS4+H+VkhbX6z64tZP7PAUwPqhwj3kbuEHcaLuaBuB+riyaX7oa1txe0tXgrFj5hRWvZKvqO7LZDlNWeJ7VTPA== + dependencies: + "@jest/console" "^29.2.1" + "@jest/types" "^29.2.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.2.2": + version "29.2.2" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.2.2.tgz#4ac7487b237e517a1f55e7866fb5553f6e0168b9" + integrity sha512-Cuc1znc1pl4v9REgmmLf0jBd3Y65UXJpioGYtMr/JNpQEIGEzkmHhy6W6DLbSsXeUA13TDzymPv0ZGZ9jH3eIw== + dependencies: + "@jest/test-result" "^29.2.1" + graceful-fs "^4.2.9" + jest-haste-map "^29.2.1" + slash "^3.0.0" + "@jest/transform@^26.6.2": version "26.6.2" resolved "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz" @@ -2592,6 +2892,27 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" +"@jest/transform@^29.2.2": + version "29.2.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.2.2.tgz#dfc03fc092b31ffea0c55917728e75bfcf8b5de6" + integrity sha512-aPe6rrletyuEIt2axxgdtxljmzH8O/nrov4byy6pDw9S8inIrTV+2PnjyP/oFHMSynzGxJ2s6OHowBNMXp/Jzg== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.2.1" + "@jridgewell/trace-mapping" "^0.3.15" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.2.1" + jest-regex-util "^29.2.0" + jest-util "^29.2.1" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.1" + "@jest/types@^26.6.2": version "26.6.2" resolved "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz" @@ -2603,6 +2924,18 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@jest/types@^29.2.1": + version "29.2.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.2.1.tgz#ec9c683094d4eb754e41e2119d8bdaef01cf6da0" + integrity sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw== + dependencies: + "@jest/schemas" "^29.0.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/gen-mapping@^0.1.0": version "0.1.1" resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" @@ -2620,7 +2953,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@^3.0.3": +"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== @@ -2638,7 +2971,7 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== @@ -2651,6 +2984,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.15": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" + integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + "@lerna/add@4.0.0": version "4.0.0" resolved "https://registry.npmjs.org/@lerna/add/-/add-4.0.0.tgz" @@ -5591,7 +5932,19 @@ resolved "https://registry.npmjs.org/@reflect-ui/cg/-/cg-0.0.5.tgz" integrity sha512-rqqaumLDgk9dGtPgkYy9h5PLlNv8ZVEz/+ktOcJpJE6v9fAQOSH1Wh5WAehpiZTQtKe944GzrFMsb/g8pTabWg== -"@reflect-ui/core@0.0.2-rc.7", "@reflect-ui/core@0.0.5", "@reflect-ui/core@0.0.9", "@reflect-ui/core@^0.0.5", "@reflect-ui/core@^0.0.9": +"@reflect-ui/core@0.0.2-rc.7": + version "0.0.2-rc.7" + resolved "https://registry.yarnpkg.com/@reflect-ui/core/-/core-0.0.2-rc.7.tgz#9d531f5a0b9caab31e7563020044b753700e2bbc" + integrity sha512-EqF4SRU57bfa5DOPET1rv5lROFyMVHLv1xTEIlN6N2gDpXt71QceImWfQp3z3Khqnb4R/p9OhNK6DXGUpozWKw== + +"@reflect-ui/core@0.0.5", "@reflect-ui/core@^0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@reflect-ui/core/-/core-0.0.5.tgz#f50ae00e64300c4b698ab5c5374c6ac3bb5de873" + integrity sha512-lA6AYHCF8aSyOvGXbJZcmlB5ccxCaznhxvD8Hg1UjVdhcbLhMWDbzoYqbrkqh+R4im3KnYw5n6pWSSdoWioYhA== + dependencies: + "@reflect-ui/uiutils" "^0.1.2-1" + +"@reflect-ui/core@^0.0.9": version "0.0.9" resolved "https://registry.yarnpkg.com/@reflect-ui/core/-/core-0.0.9.tgz#7283a2a3a1edde16282559d11f02e23d3bceda36" integrity sha512-MNJq+Pc45qZ0IvTYuvzCW2nxupVRfMtmin9vepABo2h1sTKdAmCK2kPfVLea6TNiF1baJDeQg7IyAN45JMuFdA== @@ -5638,6 +5991,20 @@ resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.21.tgz" integrity sha512-II2SIjvxBVJmrGkkZYza/BqNjwx3PWROIA8CZ0/Hn7LV0Mv0CVpZxoyHGBVsQqfFLMv9DmArIeRHTwo76bE6oA== +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^9.1.2": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" + integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== + dependencies: + "@sinonjs/commons" "^1.7.0" + "@stitches/react@1.2.8", "@stitches/react@^1.2.8": version "1.2.8" resolved "https://registry.npmjs.org/@stitches/react/-/react-1.2.8.tgz" @@ -6526,6 +6893,39 @@ resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz" integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== +"@types/babel__core@^7.1.14": + version "7.1.19" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.18.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.18.2.tgz#235bf339d17185bdec25e024ca19cce257cc7309" + integrity sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg== + dependencies: + "@babel/types" "^7.3.0" + "@types/base16@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@types/base16/-/base16-1.0.2.tgz" @@ -6667,7 +7067,7 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/graceful-fs@^4.1.2": +"@types/graceful-fs@^4.1.2", "@types/graceful-fs@^4.1.3": version "4.1.5" resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz" integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== @@ -6725,6 +7125,14 @@ jest-matcher-utils "^28.0.0" pretty-format "^28.0.0" +"@types/jest@^29.2.0": + version "29.2.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.2.0.tgz#fa98e08b46ab119f1a74a9552c48c589f5378a96" + integrity sha512-KO7bPV21d65PKwv3LLsD8Jn3E05pjNjRZvkm+YTacWhVmykAb07wW6IkZUmQAltwQafNcDUEUrMO2h3jeBSisg== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + "@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": version "7.0.11" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz" @@ -6863,6 +7271,11 @@ dependencies: "@types/pouchdb-core" "*" +"@types/prettier@^2.1.5": + version "2.7.1" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.1.tgz#dfd20e2dc35f027cdd6c1908e80a5ddc7499670e" + integrity sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow== + "@types/pretty-hrtime@^1.0.0": version "1.0.1" resolved "https://registry.npmjs.org/@types/pretty-hrtime/-/pretty-hrtime-1.0.1.tgz" @@ -6965,6 +7378,11 @@ resolved "https://registry.npmjs.org/@types/spark-md5/-/spark-md5-3.0.2.tgz" integrity sha512-82E/lVRaqelV9qmRzzJ1PKTpyrpnT7mwdneKNJB9hUtypZDMggloDfFUCIqRRx3lYRxteCwXSq9c+W71Vf0QnQ== +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + "@types/tapable@^1", "@types/tapable@^1.0.5": version "1.0.8" resolved "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.8.tgz" @@ -7027,6 +7445,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^17.0.8": + version "17.0.13" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.13.tgz#34cced675ca1b1d51fcf4d34c3c6f0fa142a5c76" + integrity sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg== + dependencies: + "@types/yargs-parser" "*" + "@use-gesture/core@10.2.17": version "10.2.17" resolved "https://registry.npmjs.org/@use-gesture/core/-/core-10.2.17.tgz" @@ -7993,6 +8418,19 @@ babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" +babel-jest@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.2.2.tgz#2c15abd8c2081293c9c3f4f80a4ed1d51542fee5" + integrity sha512-kkq2QSDIuvpgfoac3WZ1OOcHsQQDU5xYk2Ql7tLdJ8BVAYbefEXal+NfS45Y5LVZA7cxC8KYcQMObpCt1J025w== + dependencies: + "@jest/transform" "^29.2.2" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.2.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + babel-loader@^8.0.0, babel-loader@^8.2.3: version "8.2.5" resolved "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz" @@ -8030,7 +8468,7 @@ babel-plugin-extract-import-names@1.6.22: dependencies: "@babel/helper-plugin-utils" "7.10.4" -babel-plugin-istanbul@^6.0.0: +babel-plugin-istanbul@^6.0.0, babel-plugin-istanbul@^6.1.1: version "6.1.1" resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== @@ -8041,6 +8479,16 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" +babel-plugin-jest-hoist@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz#23ee99c37390a98cfddf3ef4a78674180d823094" + integrity sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + babel-plugin-macros@^3.0.1, babel-plugin-macros@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz" @@ -8102,6 +8550,32 @@ babel-plugin-react-docgen@^4.2.1: lodash "^4.17.15" react-docgen "^5.0.0" +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz#3048bea3a1af222e3505e4a767a974c95a7620dc" + integrity sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA== + dependencies: + babel-plugin-jest-hoist "^29.2.0" + babel-preset-current-node-syntax "^1.0.0" + bail@^1.0.0: version "1.0.5" resolved "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz" @@ -8412,6 +8886,23 @@ browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^ node-releases "^2.0.6" update-browserslist-db "^1.0.5" +browserslist@^4.21.3: + version "4.21.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" + integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== + dependencies: + caniuse-lite "^1.0.30001400" + electron-to-chromium "^1.4.251" + node-releases "^2.0.6" + update-browserslist-db "^1.0.9" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + bser@2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" @@ -8704,6 +9195,11 @@ caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.300013 resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz" integrity sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ== +caniuse-lite@^1.0.30001400: + version "1.0.30001425" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001425.tgz#52917791a453eb3265143d2cd08d80629e82c735" + integrity sha512-/pzFv0OmNG6W0ym80P3NtapU0QEiDS3VuYAZMGoLLqiC7f6FJFe1MjpQDREGApeenD9wloeytmVDj+JLXPC6qw== + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz" @@ -8767,6 +9263,11 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + character-entities-legacy@^1.0.0: version "1.1.4" resolved "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz" @@ -8841,6 +9342,11 @@ ci-info@^2.0.0: resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.2.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.5.0.tgz#bfac2a29263de4c829d806b1ab478e35091e171f" + integrity sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz" @@ -8849,6 +9355,11 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz" @@ -8933,6 +9444,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + clone-buffer@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz" @@ -8969,6 +9489,11 @@ cmd-shim@^4.1.0: dependencies: mkdirp-infer-owner "^2.0.0" +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" @@ -9032,6 +9557,11 @@ collapse-white-space@^1.0.2: resolved "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz" integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz" @@ -9676,7 +10206,7 @@ cssesc@^3.0.0: resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -csstype@3.1.0, csstype@^3.0.10, csstype@^3.0.2, csstype@^3.0.4, csstype@^3.0.8, csstype@^3.1.0: +csstype@^3.0.10, csstype@^3.0.2, csstype@^3.0.4, csstype@^3.0.8, csstype@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== @@ -10039,6 +10569,11 @@ detect-indent@^6.0.0: resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== +detect-newline@^3.0.0: + version "3.1.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.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz" @@ -10085,6 +10620,11 @@ diff-sequences@^28.1.1: resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz" integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== +diff-sequences@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.2.0.tgz#4c55b5b40706c7b5d2c5c75999a50c56d214e8f6" + integrity sha512-413SY5JpYeSBZxmenGEmCVQ8mCgtFJF0w9PROdaS6z987XC2Pd2GOKqOITLtMftmyFZqgtCOb/QA7/Z3ZXfzIw== + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz" @@ -10260,6 +10800,11 @@ electron-to-chromium@^1.4.202: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.204.tgz" integrity sha512-5Ojjtw9/c9HCXtMVE6SXVSHSNjmbFOXpKprl6mY/5moLSxLeWatuYA7KTD+RzJMxLRH6yNNQrqGz9p6IoNBMgw== +electron-to-chromium@^1.4.251: + version "1.4.284" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" + integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== + elliptic@^6.5.3: version "6.5.4" resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" @@ -10273,6 +10818,11 @@ elliptic@^6.5.3: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" @@ -10547,6 +11097,11 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" @@ -10714,6 +11269,11 @@ execa@^5.0.0, execa@^5.1.1: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz" @@ -10734,6 +11294,17 @@ expand-tilde@^1.2.2: dependencies: os-homedir "^1.0.1" +expect@^29.0.0, expect@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.2.2.tgz#ba2dd0d7e818727710324a6e7f13dd0e6d086106" + integrity sha512-hE09QerxZ5wXiOhqkXy5d2G9ar+EqOyifnCXCpMNu+vZ6DG9TJ6CO2c2kPDSLqERTTWrO7OZj8EkYHQqSd78Yw== + dependencies: + "@jest/expect-utils" "^29.2.2" + jest-get-type "^29.2.0" + jest-matcher-utils "^29.2.2" + jest-message-util "^29.2.1" + jest-util "^29.2.1" + express@4.17.1: version "4.17.1" resolved "https://registry.npmjs.org/express/-/express-4.17.1.tgz" @@ -10898,7 +11469,7 @@ fast-json-parse@^1.0.3: resolved "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz" integrity sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw== -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -11413,7 +11984,7 @@ fsevents@^1.2.7: bindings "^1.5.0" nan "^2.12.1" -fsevents@^2.1.2, fsevents@~2.3.2: +fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -12779,6 +13350,11 @@ is-function@^1.0.2: resolved "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz" integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + is-generator-function@^1.0.7: version "1.0.10" resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz" @@ -13132,6 +13708,17 @@ istanbul-lib-instrument@^5.0.4: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + istanbul-lib-report@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" @@ -13141,7 +13728,16 @@ istanbul-lib-report@^3.0.0: make-dir "^3.0.0" supports-color "^7.1.0" -istanbul-reports@^3.1.4: +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3, istanbul-reports@^3.1.4: version "3.1.5" resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== @@ -13171,6 +13767,85 @@ iterate-value@^1.0.2: es-get-iterator "^1.0.2" iterate-iterator "^1.0.1" +jest-changed-files@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.2.0.tgz#b6598daa9803ea6a4dce7968e20ab380ddbee289" + integrity sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-circus@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.2.2.tgz#1dc4d35fd49bf5e64d3cc505fb2db396237a6dfa" + integrity sha512-upSdWxx+Mh4DV7oueuZndJ1NVdgtTsqM4YgywHEx05UMH5nxxA2Qu9T9T9XVuR021XxqSoaKvSmmpAbjwwwxMw== + dependencies: + "@jest/environment" "^29.2.2" + "@jest/expect" "^29.2.2" + "@jest/test-result" "^29.2.1" + "@jest/types" "^29.2.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^29.2.1" + jest-matcher-utils "^29.2.2" + jest-message-util "^29.2.1" + jest-runtime "^29.2.2" + jest-snapshot "^29.2.2" + jest-util "^29.2.1" + p-limit "^3.1.0" + pretty-format "^29.2.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.2.2.tgz#feaf0aa57d327e80d4f2f18d5f8cd2e77cac5371" + integrity sha512-R45ygnnb2CQOfd8rTPFR+/fls0d+1zXS6JPYTBBrnLPrhr58SSuPTiA5Tplv8/PXpz4zXR/AYNxmwIj6J6nrvg== + dependencies: + "@jest/core" "^29.2.2" + "@jest/test-result" "^29.2.1" + "@jest/types" "^29.2.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^29.2.2" + jest-util "^29.2.1" + jest-validate "^29.2.2" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-config@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.2.2.tgz#bf98623a46454d644630c1f0de8bba3f495c2d59" + integrity sha512-Q0JX54a5g1lP63keRfKR8EuC7n7wwny2HoTRDb8cx78IwQOiaYUVZAdjViY3WcTxpR02rPUpvNVmZ1fkIlZPcw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.2.2" + "@jest/types" "^29.2.1" + babel-jest "^29.2.2" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.2.2" + jest-environment-node "^29.2.2" + jest-get-type "^29.2.0" + jest-regex-util "^29.2.0" + jest-resolve "^29.2.2" + jest-runner "^29.2.2" + jest-util "^29.2.1" + jest-validate "^29.2.2" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.2.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" + jest-diff@^28.1.3: version "28.1.3" resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz" @@ -13181,11 +13856,56 @@ jest-diff@^28.1.3: jest-get-type "^28.0.2" pretty-format "^28.1.3" +jest-diff@^29.2.1: + version "29.2.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.2.1.tgz#027e42f5a18b693fb2e88f81b0ccab533c08faee" + integrity sha512-gfh/SMNlQmP3MOUgdzxPOd4XETDJifADpT937fN1iUGz+9DgOu2eUPHH25JDkLVcLwwqxv3GzVyK4VBUr9fjfA== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.2.0" + jest-get-type "^29.2.0" + pretty-format "^29.2.1" + +jest-docblock@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.2.0.tgz#307203e20b637d97cee04809efc1d43afc641e82" + integrity sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.2.1: + version "29.2.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.2.1.tgz#6b0a88ee85c2ba27b571a6010c2e0c674f5c9b29" + integrity sha512-sGP86H/CpWHMyK3qGIGFCgP6mt+o5tu9qG4+tobl0LNdgny0aitLXs9/EBacLy3Bwqy+v4uXClqJgASJWcruYw== + dependencies: + "@jest/types" "^29.2.1" + chalk "^4.0.0" + jest-get-type "^29.2.0" + jest-util "^29.2.1" + pretty-format "^29.2.1" + +jest-environment-node@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.2.2.tgz#a64b272773870c3a947cd338c25fd34938390bc2" + integrity sha512-B7qDxQjkIakQf+YyrqV5dICNs7tlCO55WJ4OMSXsqz1lpI/0PmeuXdx2F7eU8rnPbRkUR/fItSSUh0jvE2y/tw== + dependencies: + "@jest/environment" "^29.2.2" + "@jest/fake-timers" "^29.2.2" + "@jest/types" "^29.2.1" + "@types/node" "*" + jest-mock "^29.2.2" + jest-util "^29.2.1" + jest-get-type@^28.0.2: version "28.0.2" resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz" integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== +jest-get-type@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.2.0.tgz#726646f927ef61d583a3b3adb1ab13f3a5036408" + integrity sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA== + jest-haste-map@^26.6.2: version "26.6.2" resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz" @@ -13207,6 +13927,33 @@ jest-haste-map@^26.6.2: optionalDependencies: fsevents "^2.1.2" +jest-haste-map@^29.2.1: + version "29.2.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.2.1.tgz#f803fec57f8075e6c55fb5cd551f99a72471c699" + integrity sha512-wF460rAFmYc6ARcCFNw4MbGYQjYkvjovb9GBT+W10Um8q5nHq98jD6fHZMDMO3tA56S8XnmNkM8GcA8diSZfnA== + dependencies: + "@jest/types" "^29.2.1" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.2.0" + jest-util "^29.2.1" + jest-worker "^29.2.1" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.2.1: + version "29.2.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.2.1.tgz#ec551686b7d512ec875616c2c3534298b1ffe2fc" + integrity sha512-1YvSqYoiurxKOJtySc+CGVmw/e1v4yNY27BjWTVzp0aTduQeA7pdieLiW05wTYG/twlKOp2xS/pWuikQEmklug== + dependencies: + jest-get-type "^29.2.0" + pretty-format "^29.2.1" + jest-matcher-utils@^28.0.0: version "28.1.3" resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz" @@ -13217,11 +13964,133 @@ jest-matcher-utils@^28.0.0: jest-get-type "^28.0.2" pretty-format "^28.1.3" +jest-matcher-utils@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.2.2.tgz#9202f8e8d3a54733266784ce7763e9a08688269c" + integrity sha512-4DkJ1sDPT+UX2MR7Y3od6KtvRi9Im1ZGLGgdLFLm4lPexbTaCgJW5NN3IOXlQHF7NSHY/VHhflQ+WoKtD/vyCw== + dependencies: + chalk "^4.0.0" + jest-diff "^29.2.1" + jest-get-type "^29.2.0" + pretty-format "^29.2.1" + +jest-message-util@^29.2.1: + version "29.2.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.2.1.tgz#3a51357fbbe0cc34236f17a90d772746cf8d9193" + integrity sha512-Dx5nEjw9V8C1/Yj10S/8ivA8F439VS8vTq1L7hEgwHFn9ovSKNpYW/kwNh7UglaEgXO42XxzKJB+2x0nSglFVw== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.2.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.2.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.2.2.tgz#9045618b3f9d27074bbcf2d55bdca6a5e2e8bca7" + integrity sha512-1leySQxNAnivvbcx0sCB37itu8f4OX2S/+gxLAV4Z62shT4r4dTG9tACDywUAEZoLSr36aYUTsVp3WKwWt4PMQ== + dependencies: + "@jest/types" "^29.2.1" + "@types/node" "*" + jest-util "^29.2.1" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + jest-regex-util@^26.0.0: version "26.0.0" resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== +jest-regex-util@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.2.0.tgz#82ef3b587e8c303357728d0322d48bbfd2971f7b" + integrity sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA== + +jest-resolve-dependencies@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.2.2.tgz#1f444766f37a25f1490b5137408b6ff746a05d64" + integrity sha512-wWOmgbkbIC2NmFsq8Lb+3EkHuW5oZfctffTGvwsA4JcJ1IRk8b2tg+hz44f0lngvRTeHvp3Kyix9ACgudHH9aQ== + dependencies: + jest-regex-util "^29.2.0" + jest-snapshot "^29.2.2" + +jest-resolve@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.2.2.tgz#ad6436053b0638b41e12bbddde2b66e1397b35b5" + integrity sha512-3gaLpiC3kr14rJR3w7vWh0CBX2QAhfpfiQTwrFPvVrcHe5VUBtIXaR004aWE/X9B2CFrITOQAp5gxLONGrk6GA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.2.1" + jest-pnp-resolver "^1.2.2" + jest-util "^29.2.1" + jest-validate "^29.2.2" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.2.2.tgz#6b5302ed15eba8bf05e6b14d40f1e8d469564da3" + integrity sha512-1CpUxXDrbsfy9Hr9/1zCUUhT813kGGK//58HeIw/t8fa/DmkecEwZSWlb1N/xDKXg3uCFHQp1GCvlSClfImMxg== + dependencies: + "@jest/console" "^29.2.1" + "@jest/environment" "^29.2.2" + "@jest/test-result" "^29.2.1" + "@jest/transform" "^29.2.2" + "@jest/types" "^29.2.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.2.0" + jest-environment-node "^29.2.2" + jest-haste-map "^29.2.1" + jest-leak-detector "^29.2.1" + jest-message-util "^29.2.1" + jest-resolve "^29.2.2" + jest-runtime "^29.2.2" + jest-util "^29.2.1" + jest-watcher "^29.2.2" + jest-worker "^29.2.1" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.2.2.tgz#4068ee82423769a481460efd21d45a8efaa5c179" + integrity sha512-TpR1V6zRdLynckKDIQaY41od4o0xWL+KOPUCZvJK2bu5P1UXhjobt5nJ2ICNeIxgyj9NGkO0aWgDqYPVhDNKjA== + dependencies: + "@jest/environment" "^29.2.2" + "@jest/fake-timers" "^29.2.2" + "@jest/globals" "^29.2.2" + "@jest/source-map" "^29.2.0" + "@jest/test-result" "^29.2.1" + "@jest/transform" "^29.2.2" + "@jest/types" "^29.2.1" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.2.1" + jest-message-util "^29.2.1" + jest-mock "^29.2.2" + jest-regex-util "^29.2.0" + jest-resolve "^29.2.2" + jest-snapshot "^29.2.2" + jest-util "^29.2.1" + slash "^3.0.0" + strip-bom "^4.0.0" + jest-serializer@^26.6.2: version "26.6.2" resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz" @@ -13230,6 +14099,36 @@ jest-serializer@^26.6.2: "@types/node" "*" graceful-fs "^4.2.4" +jest-snapshot@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.2.2.tgz#1016ce60297b77382386bad561107174604690c2" + integrity sha512-GfKJrpZ5SMqhli3NJ+mOspDqtZfJBryGA8RIBxF+G+WbDoC7HCqKaeAss4Z/Sab6bAW11ffasx8/vGsj83jyjA== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.2.2" + "@jest/transform" "^29.2.2" + "@jest/types" "^29.2.1" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.2.2" + graceful-fs "^4.2.9" + jest-diff "^29.2.1" + jest-get-type "^29.2.0" + jest-haste-map "^29.2.1" + jest-matcher-utils "^29.2.2" + jest-message-util "^29.2.1" + jest-util "^29.2.1" + natural-compare "^1.4.0" + pretty-format "^29.2.1" + semver "^7.3.5" + jest-util@^26.6.2: version "26.6.2" resolved "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz" @@ -13242,6 +14141,44 @@ jest-util@^26.6.2: is-ci "^2.0.0" micromatch "^4.0.2" +jest-util@^29.0.0, jest-util@^29.2.1: + version "29.2.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.2.1.tgz#f26872ba0dc8cbefaba32c34f98935f6cf5fc747" + integrity sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g== + dependencies: + "@jest/types" "^29.2.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.2.2.tgz#e43ce1931292dfc052562a11bc681af3805eadce" + integrity sha512-eJXATaKaSnOuxNfs8CLHgdABFgUrd0TtWS8QckiJ4L/QVDF4KVbZFBBOwCBZHOS0Rc5fOxqngXeGXE3nGQkpQA== + dependencies: + "@jest/types" "^29.2.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.2.0" + leven "^3.1.0" + pretty-format "^29.2.1" + +jest-watcher@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.2.2.tgz#7093d4ea8177e0a0da87681a9e7b09a258b9daf7" + integrity sha512-j2otfqh7mOvMgN2WlJ0n7gIx9XCMWntheYGlBK7+5g3b1Su13/UAK7pdKGyd4kDlrLwtH2QPvRv5oNIxWvsJ1w== + dependencies: + "@jest/test-result" "^29.2.1" + "@jest/types" "^29.2.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.2.1" + string-length "^4.0.1" + jest-worker@^26.5.0, jest-worker@^26.6.2: version "26.6.2" resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz" @@ -13260,6 +14197,26 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" +jest-worker@^29.2.1: + version "29.2.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.2.1.tgz#8ba68255438252e1674f990f0180c54dfa26a3b1" + integrity sha512-ROHTZ+oj7sBrgtv46zZ84uWky71AoYi0vEV9CdEtc1FQunsoAGe5HbQmW76nI5QWdvECVPrSi1MCVUmizSavMg== + dependencies: + "@types/node" "*" + jest-util "^29.2.1" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.2.2: + version "29.2.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.2.2.tgz#24da83cbbce514718acd698926b7679109630476" + integrity sha512-r+0zCN9kUqoON6IjDdjbrsWobXM/09Nd45kIPRD8kloaRh1z5ZCMdVsgLXGxmlL7UpAJsvCYOQNO+NjvG/gqiQ== + dependencies: + "@jest/core" "^29.2.2" + "@jest/types" "^29.2.1" + import-local "^3.0.2" + jest-cli "^29.2.2" + js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz" @@ -13488,6 +14445,11 @@ lerna@^4.0.0: import-local "^3.0.2" npmlog "^4.1.2" +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + levn@~0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" @@ -13672,6 +14634,11 @@ lodash.ismatch@^4.4.0: resolved "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz" integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g== +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" @@ -13808,6 +14775,11 @@ make-dir@^3.0.0, make-dir@^3.0.2, make-dir@^3.1.0: dependencies: semver "^6.0.0" +make-error@1.x: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + make-fetch-happen@^2.4.13: version "2.6.0" resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-2.6.0.tgz" @@ -14450,6 +15422,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + negotiator@0.6.3, negotiator@^0.6.2: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" @@ -15110,7 +16087,7 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -15370,7 +16347,7 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0: +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -15532,7 +16509,7 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.0, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.0, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -15569,7 +16546,7 @@ pinkie@^2.0.0: resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== -pirates@^4.0.1, pirates@^4.0.5: +pirates@^4.0.1, pirates@^4.0.4, pirates@^4.0.5: version "4.0.5" resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== @@ -16108,6 +17085,15 @@ pretty-format@^28.0.0, pretty-format@^28.1.3: ansi-styles "^5.0.0" react-is "^18.0.0" +pretty-format@^29.0.0, pretty-format@^29.2.1: + version "29.2.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.2.1.tgz#86e7748fe8bbc96a6a4e04fa99172630907a9611" + integrity sha512-Y41Sa4aLCtKAXvwuIpTvcFBkyeYp2gdFWzXGA+ZNES3VwURIB165XO/z7CjETwzCCS53MjW/rLMyyqEnTtaOfA== + dependencies: + "@jest/schemas" "^29.0.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + pretty-hrtime@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz" @@ -16185,7 +17171,7 @@ promise.prototype.finally@^3.1.0: define-properties "^1.1.3" es-abstract "^1.19.1" -prompts@^2.4.0: +prompts@^2.0.1, prompts@^2.4.0: version "2.4.2" resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== @@ -17223,7 +18209,12 @@ resolve-url@^0.2.1: resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz" integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== -resolve@^1.10.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.3.2: +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + +resolve@^1.10.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.3.2: version "1.22.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -17489,6 +18480,13 @@ semver@7.0.0: resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== +semver@7.x: + version "7.3.8" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" + integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== + dependencies: + lru-cache "^6.0.0" + semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: version "6.3.0" resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" @@ -17676,7 +18674,7 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -17833,6 +18831,14 @@ source-map-resolve@^0.6.0: atob "^2.1.2" decode-uri-component "^0.2.0" +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-support@^0.5.16, source-map-support@~0.5.12, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" @@ -17988,6 +18994,13 @@ stable@^0.1.8: resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + stackframe@^1.3.4: version "1.3.4" resolved "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz" @@ -18063,6 +19076,14 @@ strict-uri-encode@^2.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz" integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" @@ -18222,6 +19243,11 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" @@ -18678,6 +19704,20 @@ ts-dedent@^2.0.0: resolved "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz" integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== +ts-jest@^29.0.3: + version "29.0.3" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.0.3.tgz#63ea93c5401ab73595440733cefdba31fcf9cb77" + integrity sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.1" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "^21.0.1" + ts-pnp@^1.1.6: version "1.2.0" resolved "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz" @@ -18812,6 +19852,11 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.18.0: version "0.18.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz" @@ -18867,6 +19912,11 @@ typescript@^4.2.3, typescript@^4.4.4, typescript@^4.7.4: resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz" integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== +typescript@^4.8.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + uglify-js@^3.1.4: version "3.16.3" resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.3.tgz" @@ -19103,6 +20153,14 @@ update-browserslist-db@^1.0.5: escalade "^3.1.1" picocolors "^1.0.0" +update-browserslist-db@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" + integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + update-notifier@^2.2.0: version "2.5.0" resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz" @@ -19261,7 +20319,7 @@ uuid@^3.3.2: resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -v8-to-istanbul@^9.0.0: +v8-to-istanbul@^9.0.0, v8-to-istanbul@^9.0.1: version "9.0.1" resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz" integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== @@ -19337,7 +20395,7 @@ vuvuzela@1.0.3: resolved "https://registry.npmjs.org/vuvuzela/-/vuvuzela-1.0.3.tgz" integrity sha512-Tm7jR1xTzBbPW+6y1tknKiEhz04Wf/1iZkcTJjSFcpNko43+dFW6+OOeQe9taJIug3NdfUAjFKgUSyQrIKaDvQ== -walker@^1.0.7, walker@~1.0.5: +walker@^1.0.7, walker@^1.0.8, walker@~1.0.5: version "1.0.8" resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== @@ -19666,6 +20724,14 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +write-file-atomic@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + write-json-file@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz" @@ -19766,6 +20832,11 @@ yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^20.2.9: resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.0.0, yargs-parser@^21.0.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs@^16.2.0: version "16.2.0" resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" @@ -19779,6 +20850,19 @@ yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.3.1: + version "17.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.0.tgz#e134900fc1f218bc230192bdec06a0a5f973e46c" + integrity sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" From 1d2eabba1245960f7a609a4307663528223b77c7 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 18:31:13 +0900 Subject: [PATCH 57/67] update guide math to nearest value --- .../editor-canvas/math/guide-spacing.test.ts | 12 +++++++-- .../editor-canvas/math/guide-spacing.ts | 26 ++++++++++--------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/editor-packages/editor-canvas/math/guide-spacing.test.ts b/editor-packages/editor-canvas/math/guide-spacing.test.ts index c751f71b..b41ae956 100644 --- a/editor-packages/editor-canvas/math/guide-spacing.test.ts +++ b/editor-packages/editor-canvas/math/guide-spacing.test.ts @@ -1,11 +1,12 @@ import { spacing_guide } from "./guide-spacing"; // tests -// - a = [10, 10, 20, 20], b = [20, 20, 30, 30], then the spacing is [10, 10, 10, 10] and the base box is [20, 20, 20, 20] +// - a = [10, 10, 20, 20], b = [20, 20, 30, 30], then the spacing is [10, 0, 0, 10] and the base box is [20, 20, 20, 20] // - a = [10, 10, 20, 20], b = [15, 15, 25, 25], then the spacing is [5, 5, 5, 5] and the base box is [15, 15, 20, 20] // - a = [450, 450, 550, 550], b = [0, 0, 1000, 1000], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] // - a = [0, 0, 1000, 1000], b = [450, 450, 550, 550], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] // - a = [0, 0, 50, 50], b = [0, 0, 20, 20], then the spacing is [0, 30, 30, 0] and the base box is [0, 0, 20, 20] +// - a = [10, 10, 20, 20], b = [30, 30, 40, 40], then the spacing is [20, 10, 10, 20] and the base box is [10, 10, 20, 20] test("spacing guide (not intersecting)", () => { expect(spacing_guide([10, 10, 20, 20], [20, 20, 30, 30])).toStrictEqual({ @@ -39,9 +40,16 @@ test("spacing guide (a contains b)", () => { ); }); -test("spacing guide (not intersecting)", () => { +test("spacing guide (a contains b)", () => { expect(spacing_guide([0, 0, 50, 50], [0, 0, 20, 20])).toStrictEqual({ box: [0, 0, 20, 20], spacing: [0, 30, 30, 0], }); }); + +test("spacing guide (not intersecting)", () => { + expect(spacing_guide([10, 10, 20, 20], [30, 30, 40, 40])).toStrictEqual({ + box: [10, 10, 20, 20], + spacing: [20, 10, 10, 20], + }); +}); diff --git a/editor-packages/editor-canvas/math/guide-spacing.ts b/editor-packages/editor-canvas/math/guide-spacing.ts index 40f739f4..cb9cf866 100644 --- a/editor-packages/editor-canvas/math/guide-spacing.ts +++ b/editor-packages/editor-canvas/math/guide-spacing.ts @@ -18,7 +18,7 @@ interface SpacingGuide { /** * - * calculates the base box and the spacing of t, r, b, l with givven a and b boxes. + * calculates the base box and the spacing of **nearest** t, r, b, l with givven a and b boxes. * * the a and b boxes are formed with [x, y, x2, y2] format. * @@ -28,23 +28,21 @@ interface SpacingGuide { * * the top, right, bottom, left spacing is relative to the base box. * - * [t, r, b, l] - * t = abs(t1 - t2) - * r = abs(r1 - r2) - * b = abs(b1 - b2) - * l = abs(l1 - l2) - * * For example - * - a = [10, 10, 20, 20], b = [20, 20, 30, 30], then the spacing is [10, 10, 10, 10] and the base box is [20, 20, 20, 20] + * - a = [10, 10, 20, 20], b = [20, 20, 30, 30], then the spacing is [10, 0, 0, 10] and the base box is [20, 20, 20, 20] * - a = [10, 10, 20, 20], b = [15, 15, 25, 25], then the spacing is [5, 5, 5, 5] and the base box is [15, 15, 20, 20] * - a = [450, 450, 550, 550], b = [0, 0, 1000, 1000], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] * - a = [0, 0, 1000, 1000], b = [450, 450, 550, 550], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] * - a = [0, 0, 50, 50], b = [0, 0, 20, 20], then the spacing is [0, 30, 30, 0] and the base box is [0, 0, 20, 20] + * - a = [10, 10, 20, 20], b = [30, 30, 40, 40], then the spacing is [20, 10, 10, 20] and the base box is [10, 10, 20, 20] * */ export function spacing_guide(a: Box, b: Box): SpacingGuide { let box: Box; + const [a_x, a_y, a_x2, a_y2] = a; + const [b_x, b_y, b_x2, b_y2] = b; + // no intersection (if the interecting space is 0, it is also considered as no intersection) if (a[0] > b[2] || a[2] < b[0] || a[1] > b[3] || a[3] < b[1]) { box = a; @@ -68,11 +66,15 @@ export function spacing_guide(a: Box, b: Box): SpacingGuide { // calculate the spacing of t, r, b, l const spacing: [number, number, number, number] = [ - Math.abs(a[1] - b[1]), - Math.abs(a[2] - b[2]), - Math.abs(a[3] - b[3]), - Math.abs(a[0] - b[0]), + nearest(a_y, b_y, b_y2), + nearest(a_x2, b_x, b_x2), + nearest(a_y2, b_y, b_y2), + nearest(a_x, b_x, b_x2), ]; return { box, spacing }; } + +const nearest = (a: number, ...b: number[]) => { + return Math.min(...b.map((v) => Math.abs(v - a))); +}; From 012122e65e0f7fc28fb941334709849685425e9d Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 18:31:54 +0900 Subject: [PATCH 58/67] add initial positioning guide --- .../editor-canvas/canvas/canvas.tsx | 94 ++++++++- .../editor-canvas/hud/hud-surface.tsx | 197 +++++++++++------- .../editor-canvas/math/bounding-box.ts | 5 + .../overlay/guide-positioning/index.tsx | 108 ++++++++++ .../editor-canvas/overlay/index.ts | 1 + 5 files changed, 327 insertions(+), 78 deletions(-) create mode 100644 editor-packages/editor-canvas/overlay/guide-positioning/index.tsx diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index 4cb753fb..8069c1e6 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -388,9 +388,19 @@ export function Canvas({ }; const is_canvas_transforming = isPanning || isZooming; - const selected_nodes = selectedNodes - ?.map((id) => qdoc.getNodeById(id)) - .filter(Boolean); + const selected_nodes = useMemo( + () => selectedNodes?.map((id) => qdoc.getNodeById(id)).filter(Boolean), + [selectedNodes] + ); + + const position_guides = useMemo( + () => + position_guide({ + selections: selected_nodes, + hover: hoveringLayer?.node, + }), + [selectedNodes, hoveringLayer?.node?.id] + ); const items = useMemo(() => { return nodes?.map((node) => { @@ -463,7 +473,7 @@ export function Canvas({ marquee={marquee} labelDisplayNodes={nodes} selectedNodes={selected_nodes} - positionGuides={[]} // TODO: + positionGuides={position_guides} highlights={ hoveringLayer?.node ? (config.can_highlight_selected_layer @@ -500,6 +510,82 @@ const Container = styled.div<{ width: number; height: number }>` height: ${(p) => p.height}px; `; +/** + * 1. container positioning guide (static per selection) + * 2. relative positioning to target (hovering layer) guide + */ +function position_guide({ + selections, + hover, +}: { + selections: ReflectSceneNode[]; + hover: ReflectSceneNode; +}) { + if (selections.length === 0) { + return []; + } + + const guides = []; + const a = boundingbox( + selections.map((s) => [ + s.absoluteX, + s.absoluteY, + s.width, + s.height, + s.rotation, + ]), + 2 + ); + + if (selections.length === 1) { + const parent = selections[0].parent; + if (parent) { + const parent_box = boundingbox( + [ + [ + parent.absoluteX, + parent.absoluteY, + parent.width, + parent.height, + parent.rotation, + ], + ], + 2 + ); + const guide_relative_to_parent = { + a: a, + b: parent_box, + }; + + guides.push(guide_relative_to_parent); + } + } + + if (hover) { + const hover_box = boundingbox( + [ + [ + hover.absoluteX, + hover.absoluteY, + hover.width, + hover.height, + hover.rotation, + ], + ], + 2 + ); + + const guide_relative_to_hover = { + a: a, + b: hover_box, + }; + + guides.push(guide_relative_to_hover); + } + + return guides; +} + function ContextMenuProvider({ children }: React.PropsWithChildren<{}>) { return ( } {!hide && ( <> - {labelDisplayNodes && - labelDisplayNodes.map((node) => { - const absxy: XY = [node.absoluteX * zoom, node.absoluteY * zoom]; - return renderFrameTitle({ - id: node.id, - name: node.name, - xy: absxy, - wh: [node.width, node.height], - zoom: zoom, - selected: selectedNodes.some( - (selectedNode) => selectedNode.id === node.id - ), - onSelect: () => onSelectNode(node.id), - onHoverChange: (hv) => { - if (hv) { - onHoverNode(node.id); - } else { - onHoverNode(null); - } - }, - highlight: !![...highlights, ...selectedNodes].find( - (n) => n.id === node.id - ), - }); - })} + {labelDisplayNodes && ( +
+ {labelDisplayNodes.map((node) => { + const absxy: XY = [ + node.absoluteX * zoom, + node.absoluteY * zoom, + ]; + return renderFrameTitle({ + id: node.id, + name: node.name, + xy: absxy, + wh: [node.width, node.height], + zoom: zoom, + selected: selectedNodes.some( + (selectedNode) => selectedNode.id === node.id + ), + onSelect: () => onSelectNode(node.id), + onHoverChange: (hv) => { + if (hv) { + onHoverNode(node.id); + } else { + onHoverNode(null); + } + }, + highlight: !![...highlights, ...selectedNodes].find( + (n) => n.id === node.id + ), + }); + })} +
+ )} {highlights && highlights.map((h) => { return ( @@ -118,47 +135,18 @@ export function HudSurface({ /> ); })} - {selectedNodes?.length ? ( - disableGrouping ? ( - selectedNodes.map((s) => { - const xywh: [number, number, number, number] = [ - s.absoluteX, - s.absoluteY, - s.width, - s.height, - ]; - if (readonly) { - return ( - - ); - } else { - return ( - - ); - } - }) - ) : ( - - ) - ) : ( - <> + + {selectedNodes.length > 0 && ( + + )} + + {positionGuides.length > 0 && ( + )} )} @@ -166,17 +154,78 @@ export function HudSurface({ ); } -function SelectionGroupHighlight({ +/** + * this only supports readonly mode for now. + */ +function PositionGuides({ + guides, + zoom, +}: { + guides: PositionGuideMeta[]; + zoom: number; +}) { + return ( + <> + {guides.map((guide) => { + return ; + })} + + ); +} + +// interface PositioningGuidePreferences{ +// } + +function SelectionsHighlight({ selections, zoom, disableSizeDisplay = false, + disableGrouping, readonly, }: { readonly: boolean; selections: DisplayNodeMeta[]; zoom: number; + disableGrouping?: boolean; disableSizeDisplay?: boolean; }) { + if (disableGrouping) { + return ( + <> + {selections.map((s) => { + const xywh: [number, number, number, number] = [ + s.absoluteX, + s.absoluteY, + s.width, + s.height, + ]; + if (readonly) { + return ( + + ); + } else { + return ( + + ); + } + })} + + ); + } + const box = boundingbox( selections.map((d) => { return [d.absoluteX, d.absoluteY, d.width, d.height, d.rotation]; diff --git a/editor-packages/editor-canvas/math/bounding-box.ts b/editor-packages/editor-canvas/math/bounding-box.ts index a45c7f62..ddd03791 100644 --- a/editor-packages/editor-canvas/math/bounding-box.ts +++ b/editor-packages/editor-canvas/math/bounding-box.ts @@ -120,3 +120,8 @@ export function intersection(a: Box, b: Box): Box { const y6 = Math.min(y2, y4); return [x5, y5, x6, y6]; } + +export function scale(box: Box, scale: number): Box { + const [x1, y1, x2, y2] = box; + return [x1 * scale, y1 * scale, x2 * scale, y2 * scale]; +} diff --git a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx new file mode 100644 index 00000000..66e15de8 --- /dev/null +++ b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx @@ -0,0 +1,108 @@ +import React from "react"; +import { box_to_xywh, scale, spacing_guide } from "../../math"; +import type { Box } from "../../types"; +import * as k from "../k"; + +export function PositionGuide({ + a, + b, + zoom, +}: { + a: Box; + b: Box; + zoom: number; +}) { + const { spacing, box: __box } = spacing_guide(a, b); + const box = scale(__box, zoom); + const [_t, _r, _b, _l] = spacing; + + return ( +
+ + + + +
+ ); +} + +function SpacingGuideLine({ + length, + zoom, + side, + box, + width = 1, +}: { + width?: number; + length: number; + box: Box; + zoom: number; + side: "t" | "r" | "b" | "l"; +}) { + const d = 100; + + // is vertical line + const isvert = side === "t" || side === "b"; + const l_scalex = isvert ? width / d : (length / d) * zoom; + const l_scaley = isvert ? (length / d) * zoom : width / d; + const [, , w, h] = box_to_xywh(box); + + let trans = { x: 0, y: 0 }; + switch (side) { + case "t": { + trans = { + x: box[0] + (d * l_scalex - d) / 2 + w / 2, + y: box[1] - d / 2 - (length / 2) * zoom, + }; + break; + } + case "r": { + trans = { + x: box[2] - d / 2 + (length / 2) * zoom, + y: box[1] + (d * l_scaley - d) / 2 + h / 2, + }; + break; + } + case "b": { + trans = { + x: box[0] + (d * l_scalex - d) / 2 + w / 2, + y: box[3] - d / 2 + (length / 2) * zoom, + }; + break; + } + case "l": { + trans = { + x: box[0] - d / 2 - (length / 2) * zoom, + y: box[1] + (d * l_scaley - d) / 2 + h / 2, + }; + break; + } + } + + return ( +
+ ); +} + +function AuxiliaryLine() {} diff --git a/editor-packages/editor-canvas/overlay/index.ts b/editor-packages/editor-canvas/overlay/index.ts index 80998c4e..49009619 100644 --- a/editor-packages/editor-canvas/overlay/index.ts +++ b/editor-packages/editor-canvas/overlay/index.ts @@ -1,3 +1,4 @@ +export * from "./guide-positioning"; export * from "./hover-outline-hightlight"; export * from "./select-highlight-in-selection-group"; export * from "./select-hightlight"; From ab11fd6367281f593d87730b6246236507f6ada8 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 18:50:51 +0900 Subject: [PATCH 59/67] wip spacing label --- .../overlay/guide-positioning/index.tsx | 26 ++++++++++-- .../overlay/guide-positioning/readme.md | 1 + editor-packages/editor-canvas/overlay/k.ts | 1 + .../overlay/size-meter-label-box.tsx | 15 +++++-- yarn.lock | 41 ++++++++----------- 5 files changed, 52 insertions(+), 32 deletions(-) create mode 100644 editor-packages/editor-canvas/overlay/guide-positioning/readme.md diff --git a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx index 66e15de8..07e73d13 100644 --- a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx +++ b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx @@ -2,6 +2,7 @@ import React from "react"; import { box_to_xywh, scale, spacing_guide } from "../../math"; import type { Box } from "../../types"; import * as k from "../k"; +import { SizeMeterLabelBox } from "../size-meter-label-box"; export function PositionGuide({ a, @@ -15,6 +16,17 @@ export function PositionGuide({ const { spacing, box: __box } = spacing_guide(a, b); const box = scale(__box, zoom); const [_t, _r, _b, _l] = spacing; + const sizemeterprops = (size: number) => { + // TODO: drop the xywh use + let xywh = box_to_xywh(box); + + return { + size: Math.round(size * 10) / 10 + "px", + background: "orange", + zoom: 1, + xywh, + }; + }; return (
- - - - + + + + + + + +
); } @@ -38,7 +54,9 @@ function SpacingGuideLine({ side, box, width = 1, + label, }: { + label?: boolean; width?: number; length: number; box: Box; diff --git a/editor-packages/editor-canvas/overlay/guide-positioning/readme.md b/editor-packages/editor-canvas/overlay/guide-positioning/readme.md new file mode 100644 index 00000000..f1a4b6dc --- /dev/null +++ b/editor-packages/editor-canvas/overlay/guide-positioning/readme.md @@ -0,0 +1 @@ +- relative position guide diff --git a/editor-packages/editor-canvas/overlay/k.ts b/editor-packages/editor-canvas/overlay/k.ts index 2efc0016..059e1c03 100644 --- a/editor-packages/editor-canvas/overlay/k.ts +++ b/editor-packages/editor-canvas/overlay/k.ts @@ -1,3 +1,4 @@ export const Z_INDEX_HANDLE = 2; export const Z_INDEX_GUIDE_POSITION = 3; export const Z_INDEX_GUIDE_SPACING = 4; +export const Z_INDEX_GUIDE_LABEL = 5; diff --git a/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx b/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx index 8713ab30..a9d80b6c 100644 --- a/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx +++ b/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from "react"; -import styled from "@emotion/styled"; import type { XYWH } from "../types"; import { xywh_to_bounding_box } from "../math"; +import * as k from "./k"; const font_size = 10; @@ -11,8 +11,10 @@ export function SizeMeterLabelBox({ margin = 0, xywh, zoom, + background = "rgb(0, 87, 255)", }: { - size: { width: number; height: number }; + background?: React.CSSProperties["background"]; + size: string | { width: number; height: number }; anchor?: "w" | "n" | "s" | "e"; margin?: number; } & { @@ -30,7 +32,11 @@ export function SizeMeterLabelBox({ const bottomY = y2; const boxWidth = x2 - x1; // use this to center position the label - const text = `${+size.width.toFixed(2)} x ${+size.height.toFixed()}`; + const text = + typeof size === "string" + ? size + : `${+size.width.toFixed(2)} x ${+size.height.toFixed()}`; + const labelwidth = (text.length * font_size) / 1.8; // a view width assumption (we will not use flex box for faster painting) const viewwidth = labelwidth + 4; // 4 is for horizontal padding @@ -48,13 +54,14 @@ export function SizeMeterLabelBox({ boxSizing: "border-box", whiteSpace: "nowrap", borderRadius: 4, - background: "rgb(0, 87, 255)", + background: background, padding: "2px 4px", color: "white", fontSize: font_size, fontFamily: "Inter, sans-serif", fontWeight: 500, textAlign: "center", + zIndex: k.Z_INDEX_GUIDE_LABEL, }} > {text} diff --git a/yarn.lock b/yarn.lock index d71f936b..00c72d92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1564,10 +1564,10 @@ resolved "https://registry.yarnpkg.com/@design-sdk/figma-auth-store/-/figma-auth-store-0.0.37.tgz#02149d452ca65e0ab390518d98f4b887345a11fb" integrity sha512-ghv33tV24EO13H2BZhY99krB0Mb4tFyAsKGRhGQGIMWD+Y/JLjknx6M5uIrEPwSW6dQ5JqRI84cAcUwC/jCAfA== -"@design-sdk/figma-core@^0.0.37": - version "0.0.37" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-core/-/figma-core-0.0.37.tgz#3934d7d49ec048476d2693f18a7ee85964359794" - integrity sha512-hYD1DKXnNVb0xP4MyaoAQcQVY0Cb/MTBmn9EbWpoSSoNmxpEGHGPdU0ETV5A+nFdBU6L3BN+RIP7wRjNPCrvpA== +"@design-sdk/figma-core@^0.0.25": + version "0.0.25" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-core/-/figma-core-0.0.25.tgz#7fa28cc7d6e45cd713c5f268d42e4dd4f2b41590" + integrity sha512-6OF7eUbDOlR4/BFtd2FRyDvvUf777OGNbVbNScUOv3Fk/kUXBzMTXX6ZdoRlTx887v/vo3+Lh0D31SG1sm80aA== "@design-sdk/figma-node-conversion@^0.0.37": version "0.0.37" @@ -1590,13 +1590,13 @@ "@design-sdk/figma-node" "^0.0.37" "@design-sdk/figma-types" "^0.0.37" -"@design-sdk/figma-node@^0.0.37": - version "0.0.37" - resolved "https://registry.yarnpkg.com/@design-sdk/figma-node/-/figma-node-0.0.37.tgz#906ccf274c4ae227fab6881a679aee973fe1a038" - integrity sha512-X66YaFpkro1LK/9L93UIxodQv29cJxauoHuWZUIB60nj7Wt57i4GLE/sV4j1laUYHt/751mvjFBMibZzxPcIyw== +"@design-sdk/figma-node@0.0.25", "@design-sdk/figma-node@^0.0.37": + version "0.0.25" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-node/-/figma-node-0.0.25.tgz#c95484cc4b003667ae93e95fa3b585b9fa0b740a" + integrity sha512-GCA5cGDXhvGUQddmSIZgPMhH0eGip9S0yDSQiys1XiKnXsB/CM8/5C+JVosHR1WFMHSlJfU+ytA4IH2yhfysUQ== dependencies: - "@design-sdk/figma-core" "^0.0.37" - "@design-sdk/figma-utils" "^0.0.37" + "@design-sdk/figma-core" "^0.0.25" + "@design-sdk/figma-utils" "^0.0.25" "@reflect-ui/font-utils" "^0.0.1" "@design-sdk/figma-remote-api@^0.0.37": @@ -1635,6 +1635,11 @@ resolved "https://registry.npmjs.org/@design-sdk/figma-url/-/figma-url-0.0.4.tgz" integrity sha512-9wvaecM9vVxI97CNfnckv0S9yi/ES3zuwQBa0ZfM5eQNbZlAgqTwBIi/Q/xsx7d+aePeGs+nEo2UhR52Rd+xNg== +"@design-sdk/figma-utils@^0.0.25": + version "0.0.25" + resolved "https://registry.yarnpkg.com/@design-sdk/figma-utils/-/figma-utils-0.0.25.tgz#7b7f6632fd8689ef713b27b34a61257accc2052e" + integrity sha512-HarFMa14L9zqg8rhLaCTXhTKFd6tlBno1mnSc/vl8ZVilmdq32OFFlmqS4MjyvrTfyAvbwlEMAhxV1SUQhFhRg== + "@design-sdk/figma-utils@^0.0.37": version "0.0.37" resolved "https://registry.yarnpkg.com/@design-sdk/figma-utils/-/figma-utils-0.0.37.tgz#a3ee7512c635b67c6b76ebf4a753dbb3aaa435c3" @@ -5932,19 +5937,7 @@ resolved "https://registry.npmjs.org/@reflect-ui/cg/-/cg-0.0.5.tgz" integrity sha512-rqqaumLDgk9dGtPgkYy9h5PLlNv8ZVEz/+ktOcJpJE6v9fAQOSH1Wh5WAehpiZTQtKe944GzrFMsb/g8pTabWg== -"@reflect-ui/core@0.0.2-rc.7": - version "0.0.2-rc.7" - resolved "https://registry.yarnpkg.com/@reflect-ui/core/-/core-0.0.2-rc.7.tgz#9d531f5a0b9caab31e7563020044b753700e2bbc" - integrity sha512-EqF4SRU57bfa5DOPET1rv5lROFyMVHLv1xTEIlN6N2gDpXt71QceImWfQp3z3Khqnb4R/p9OhNK6DXGUpozWKw== - -"@reflect-ui/core@0.0.5", "@reflect-ui/core@^0.0.5": - version "0.0.5" - resolved "https://registry.yarnpkg.com/@reflect-ui/core/-/core-0.0.5.tgz#f50ae00e64300c4b698ab5c5374c6ac3bb5de873" - integrity sha512-lA6AYHCF8aSyOvGXbJZcmlB5ccxCaznhxvD8Hg1UjVdhcbLhMWDbzoYqbrkqh+R4im3KnYw5n6pWSSdoWioYhA== - dependencies: - "@reflect-ui/uiutils" "^0.1.2-1" - -"@reflect-ui/core@^0.0.9": +"@reflect-ui/core@0.0.2-rc.7", "@reflect-ui/core@0.0.5", "@reflect-ui/core@0.0.9", "@reflect-ui/core@^0.0.5", "@reflect-ui/core@^0.0.9": version "0.0.9" resolved "https://registry.yarnpkg.com/@reflect-ui/core/-/core-0.0.9.tgz#7283a2a3a1edde16282559d11f02e23d3bceda36" integrity sha512-MNJq+Pc45qZ0IvTYuvzCW2nxupVRfMtmin9vepABo2h1sTKdAmCK2kPfVLea6TNiF1baJDeQg7IyAN45JMuFdA== @@ -10206,7 +10199,7 @@ cssesc@^3.0.0: resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -csstype@^3.0.10, csstype@^3.0.2, csstype@^3.0.4, csstype@^3.0.8, csstype@^3.1.0: +csstype@3.1.0, csstype@^3.0.10, csstype@^3.0.2, csstype@^3.0.4, csstype@^3.0.8, csstype@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== From 942039d6c841080296b78f683719b1f7c0e0f789 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 20:03:06 +0900 Subject: [PATCH 60/67] add lenght meter label --- .../editor-canvas/hud/hud-surface.tsx | 7 +- .../editor-canvas/math/guide-spacing.ts | 19 ++++ .../overlay/guide-positioning/index.tsx | 103 +++++++++++++---- .../editor-canvas/overlay/index.ts | 2 +- .../editor-canvas/overlay/meter-label.tsx | 106 ++++++++++++++++++ .../overlay/size-meter-label-box.tsx | 70 ------------ 6 files changed, 210 insertions(+), 97 deletions(-) create mode 100644 editor-packages/editor-canvas/overlay/meter-label.tsx delete mode 100644 editor-packages/editor-canvas/overlay/size-meter-label-box.tsx diff --git a/editor-packages/editor-canvas/hud/hud-surface.tsx b/editor-packages/editor-canvas/hud/hud-surface.tsx index 38b42ab8..b489e3c9 100644 --- a/editor-packages/editor-canvas/hud/hud-surface.tsx +++ b/editor-packages/editor-canvas/hud/hud-surface.tsx @@ -4,7 +4,7 @@ import { ReadonlySelectHightlight, InSelectionGroupSelectHighlight, SelectHightlight, - SizeMeterLabelBox, + SizeMeterLabel, PositionGuide, } from "../overlay"; import { FrameTitle, FrameTitleProps } from "../frame-title"; @@ -252,10 +252,9 @@ function SelectionsHighlight({ <> {!disableSizeDisplay ? ( - = b[2] && a[3] >= b[3]) { box = b; + + return { + box, + spacing: [ + Math.abs(a[1] - b[1]), + Math.abs(a[2] - b[2]), + Math.abs(a[3] - b[3]), + Math.abs(a[0] - b[0]), + ], + }; } // b contains a else if (a[0] >= b[0] && a[1] >= b[1] && a[2] <= b[2] && a[3] <= b[3]) { box = a; + return { + box, + spacing: [ + Math.abs(a[1] - b[1]), + Math.abs(a[2] - b[2]), + Math.abs(a[3] - b[3]), + Math.abs(a[0] - b[0]), + ], + }; } // intersection diff --git a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx index 07e73d13..882ceb21 100644 --- a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx +++ b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx @@ -2,7 +2,7 @@ import React from "react"; import { box_to_xywh, scale, spacing_guide } from "../../math"; import type { Box } from "../../types"; import * as k from "../k"; -import { SizeMeterLabelBox } from "../size-meter-label-box"; +import { MeterLabel } from "../meter-label"; export function PositionGuide({ a, @@ -16,17 +16,8 @@ export function PositionGuide({ const { spacing, box: __box } = spacing_guide(a, b); const box = scale(__box, zoom); const [_t, _r, _b, _l] = spacing; - const sizemeterprops = (size: number) => { - // TODO: drop the xywh use - let xywh = box_to_xywh(box); - return { - size: Math.round(size * 10) / 10 + "px", - background: "orange", - zoom: 1, - xywh, - }; - }; + console.log(spacing); return (
- - - - - - - - + + + + + + + + + + + + + + + +
); } +function Conditional({ + length, + children, +}: React.PropsWithChildren<{ length }>) { + if (length > 0) { + return <>{children}; + } + return <>; +} + +function SpacingMeterLabel({ + side, + length, + box, + zoom, +}: { + side: Side; + length: number; + box: Box; + zoom: number; +}) { + const [x, y, x2, y2] = box; + + let tx = x + (x2 - x) / 2; + let ty = y + (y2 - y) / 2; + switch (side) { + case "t": + ty = y - length / 2; + break; + case "r": + tx = x2 + length / 2; + break; + case "b": + ty = y2 + length / 2; + break; + case "l": + tx = x - length / 2; + break; + } + + return ( + + ); +} + +const __label_anchor_map = { + t: "e", + r: "s", + b: "e", + l: "s", +} as const; + +type Side = "t" | "r" | "b" | "l"; + function SpacingGuideLine({ length, zoom, side, box, width = 1, - label, }: { - label?: boolean; width?: number; length: number; box: Box; zoom: number; - side: "t" | "r" | "b" | "l"; + side: Side; }) { const d = 100; diff --git a/editor-packages/editor-canvas/overlay/index.ts b/editor-packages/editor-canvas/overlay/index.ts index 49009619..db0c9a19 100644 --- a/editor-packages/editor-canvas/overlay/index.ts +++ b/editor-packages/editor-canvas/overlay/index.ts @@ -3,4 +3,4 @@ export * from "./hover-outline-hightlight"; export * from "./select-highlight-in-selection-group"; export * from "./select-hightlight"; export * from "./select-hightlight-readonly"; -export * from "./size-meter-label-box"; +export * from "./meter-label"; diff --git a/editor-packages/editor-canvas/overlay/meter-label.tsx b/editor-packages/editor-canvas/overlay/meter-label.tsx new file mode 100644 index 00000000..54411200 --- /dev/null +++ b/editor-packages/editor-canvas/overlay/meter-label.tsx @@ -0,0 +1,106 @@ +import React from "react"; +import type { Box } from "../types"; +import * as k from "./k"; + +const font_size = 10; + +export function SizeMeterLabel({ + size, + margin = 0, + box, + zoom, +}: { + size: { width: number; height: number }; + margin?: number; +} & { + box: Box; + zoom: number; +}) { + const [x1, y1, x2, y2] = box; + const bottomY = y2; + const boxWidth = x2 - x1; // use this to center position the label + + const text = `${+size.width.toFixed(2)} x ${+size.height.toFixed()}`; + + return ( + + ); +} + +export function MeterLabel({ + x, + y, + background, + label, + anchor, + zoom, + margin = 0, +}: { + x: number; + y: number; + background?: React.CSSProperties["background"]; + label: string; + anchor: "w" | "n" | "s" | "e"; + margin?: number; + zoom: number; +}) { + const labelwidth = (label.length * font_size) / 1.8; // a view width assumption (we will not use flex box for faster painting) + const viewwidth = labelwidth + 4; // 4 is for horizontal padding + const viewheight = font_size + 4; // 4 is for vertical padding + + let t = [0, 0]; + switch (anchor) { + case "s": { + t = [x * zoom - viewwidth / 2, y * zoom + margin]; + break; + } + case "n": { + t = [x * zoom - viewwidth / 2, y * zoom - margin]; + break; + } + case "e": { + t = [x * zoom + margin, y * zoom - viewheight / 2]; + break; + } + case "w": { + t = [x * zoom - margin, y * zoom - viewheight / 2]; + break; + } + } + + const [tx, ty] = t; + + return ( +
+ {label} +
+ ); +} diff --git a/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx b/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx deleted file mode 100644 index a9d80b6c..00000000 --- a/editor-packages/editor-canvas/overlay/size-meter-label-box.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React, { useMemo } from "react"; -import type { XYWH } from "../types"; -import { xywh_to_bounding_box } from "../math"; -import * as k from "./k"; - -const font_size = 10; - -export function SizeMeterLabelBox({ - size, - anchor = "s", - margin = 0, - xywh, - zoom, - background = "rgb(0, 87, 255)", -}: { - background?: React.CSSProperties["background"]; - size: string | { width: number; height: number }; - anchor?: "w" | "n" | "s" | "e"; - margin?: number; -} & { - xywh: XYWH; - zoom: number; -}) { - // TODO: add anchor handling - - const bbox = useMemo( - () => xywh_to_bounding_box({ xywh, scale: zoom }), - [xywh, zoom] - ); - - const [x1, y1, x2, y2] = bbox; - const bottomY = y2; - const boxWidth = x2 - x1; // use this to center position the label - - const text = - typeof size === "string" - ? size - : `${+size.width.toFixed(2)} x ${+size.height.toFixed()}`; - - const labelwidth = (text.length * font_size) / 1.8; // a view width assumption (we will not use flex box for faster painting) - const viewwidth = labelwidth + 4; // 4 is for horizontal padding - - const [tx, ty] = [x1 + boxWidth / 2 - viewwidth / 2, y2 + margin]; - - return ( -
- {text} -
- ); -} From 255ceffabc627e538efab7535ab1a7a276880056 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 21:17:24 +0900 Subject: [PATCH 61/67] update spacing math to be more scenario specific --- .../editor-canvas/math/guide-spacing.test.ts | 6 +- .../editor-canvas/math/guide-spacing.ts | 101 ++++++++++++------ 2 files changed, 71 insertions(+), 36 deletions(-) diff --git a/editor-packages/editor-canvas/math/guide-spacing.test.ts b/editor-packages/editor-canvas/math/guide-spacing.test.ts index b41ae956..e3c0c007 100644 --- a/editor-packages/editor-canvas/math/guide-spacing.test.ts +++ b/editor-packages/editor-canvas/math/guide-spacing.test.ts @@ -6,12 +6,12 @@ import { spacing_guide } from "./guide-spacing"; // - a = [450, 450, 550, 550], b = [0, 0, 1000, 1000], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] // - a = [0, 0, 1000, 1000], b = [450, 450, 550, 550], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] // - a = [0, 0, 50, 50], b = [0, 0, 20, 20], then the spacing is [0, 30, 30, 0] and the base box is [0, 0, 20, 20] -// - a = [10, 10, 20, 20], b = [30, 30, 40, 40], then the spacing is [20, 10, 10, 20] and the base box is [10, 10, 20, 20] +// - a = [10, 10, 20, 20], b = [30, 30, 40, 40], then the spacing is [-20, 10, 10, -20] and the base box is [10, 10, 20, 20] test("spacing guide (not intersecting)", () => { expect(spacing_guide([10, 10, 20, 20], [20, 20, 30, 30])).toStrictEqual({ box: [20, 20, 20, 20], - spacing: [10, 10, 10, 10], + spacing: [10, 0, 0, 10], }); }); @@ -50,6 +50,6 @@ test("spacing guide (a contains b)", () => { test("spacing guide (not intersecting)", () => { expect(spacing_guide([10, 10, 20, 20], [30, 30, 40, 40])).toStrictEqual({ box: [10, 10, 20, 20], - spacing: [20, 10, 10, 20], + spacing: [-20, 10, 10, -20], }); }); diff --git a/editor-packages/editor-canvas/math/guide-spacing.ts b/editor-packages/editor-canvas/math/guide-spacing.ts index d6a7cc97..7e9611f4 100644 --- a/editor-packages/editor-canvas/math/guide-spacing.ts +++ b/editor-packages/editor-canvas/math/guide-spacing.ts @@ -34,66 +34,101 @@ interface SpacingGuide { * - a = [450, 450, 550, 550], b = [0, 0, 1000, 1000], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] * - a = [0, 0, 1000, 1000], b = [450, 450, 550, 550], then the spacing is [450, 450, 450, 450] and the base box is [450, 450, 550, 550] * - a = [0, 0, 50, 50], b = [0, 0, 20, 20], then the spacing is [0, 30, 30, 0] and the base box is [0, 0, 20, 20] - * - a = [10, 10, 20, 20], b = [30, 30, 40, 40], then the spacing is [20, 10, 10, 20] and the base box is [10, 10, 20, 20] + * - a = [10, 10, 20, 20], b = [30, 30, 40, 40], then the spacing is [-20, 10, 10, -20] and the base box is [10, 10, 20, 20] * */ export function spacing_guide(a: Box, b: Box): SpacingGuide { - let box: Box; - const [a_x, a_y, a_x2, a_y2] = a; const [b_x, b_y, b_x2, b_y2] = b; // no intersection (if the interecting space is 0, it is also considered as no intersection) if (a[0] > b[2] || a[2] < b[0] || a[1] > b[3] || a[3] < b[1]) { - box = a; + let t = 0; + let r = 0; + let b = 0; + let l = 0; + + // if x axis is not intersecting + if (!segments_intersect(a_x, a_x2, b_x, b_x2)) { + // if a is on the left of b (whille no intersection in x axis) + if (a_x < b_x) { + r = b_x - a_x2; // + + l = a_x - b_x; // - + } + + // if a is on the right of b + if (a_x > b_x) { + l = a_x - b_x2; // + + r = b_x2 - a_x2; // - + } + } + + // if y axis is not intersecting + if (!segments_intersect(a_y, a_y2, b_y, b_y2)) { + // if a is on the top of b + if (a_y < b_y) { + b = b_y - a_y2; // + + t = a_y - b_y; // - + } + + // if a is on the bottom of b + if (a_y > b_y) { + t = a_y - b_y2; // + + b = b_y2 - a_y2; // - + } + } + + return { + box: a, + spacing: [t, r, b, l], + }; } // a contains b else if (a[0] <= b[0] && a[1] <= b[1] && a[2] >= b[2] && a[3] >= b[3]) { - box = b; - return { - box, - spacing: [ - Math.abs(a[1] - b[1]), - Math.abs(a[2] - b[2]), - Math.abs(a[3] - b[3]), - Math.abs(a[0] - b[0]), - ], + box: b, + spacing: container_spacing(a, b), }; } // b contains a else if (a[0] >= b[0] && a[1] >= b[1] && a[2] <= b[2] && a[3] <= b[3]) { - box = a; return { - box, - spacing: [ - Math.abs(a[1] - b[1]), - Math.abs(a[2] - b[2]), - Math.abs(a[3] - b[3]), - Math.abs(a[0] - b[0]), - ], + box: a, + spacing: container_spacing(a, b), }; } // intersection else { - // calculate the intersection of two boxes as a coordinate [x, y, x2, y2] - box = intersection(a, b); + return { + // calculate the intersection of two boxes as a coordinate [x, y, x2, y2] + box: intersection(a, b), + // calculate the spacing of t, r, b, l + spacing: [ + nearest(a_y, b_y, b_y2), + nearest(a_x2, b_x, b_x2), + nearest(a_y2, b_y, b_y2), + nearest(a_x, b_x, b_x2), + ], + }; } - - // calculate the spacing of t, r, b, l - const spacing: [number, number, number, number] = [ - nearest(a_y, b_y, b_y2), - nearest(a_x2, b_x, b_x2), - nearest(a_y2, b_y, b_y2), - nearest(a_x, b_x, b_x2), - ]; - - return { box, spacing }; } const nearest = (a: number, ...b: number[]) => { return Math.min(...b.map((v) => Math.abs(v - a))); }; + +const container_spacing = (a: Box, b: Box) => + [ + Math.abs(a[1] - b[1]), + Math.abs(a[2] - b[2]), + Math.abs(a[3] - b[3]), + Math.abs(a[0] - b[0]), + ] as [number, number, number, number]; + +/** + * https://eli.thegreenplace.net/2008/08/15/intersection-of-1d-segments + */ +const segments_intersect = (x1, x2, y1, y2) => x2 >= y1 && y2 >= x1; From 4f3503065104a299a9b45adf06d05baf447f8c8e Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 21:17:44 +0900 Subject: [PATCH 62/67] checkpoint: space inspection --- .../editor-canvas/canvas/canvas.tsx | 46 ++++++++++--------- .../overlay/guide-positioning/index.tsx | 28 +++++++++-- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/editor-packages/editor-canvas/canvas/canvas.tsx b/editor-packages/editor-canvas/canvas/canvas.tsx index 8069c1e6..7fcb82fb 100644 --- a/editor-packages/editor-canvas/canvas/canvas.tsx +++ b/editor-packages/editor-canvas/canvas/canvas.tsx @@ -537,6 +537,30 @@ function position_guide({ 2 ); + if (hover) { + const hover_box = boundingbox( + [ + [ + hover.absoluteX, + hover.absoluteY, + hover.width, + hover.height, + hover.rotation, + ], + ], + 2 + ); + + const guide_relative_to_hover = { + a: a, + b: hover_box, + }; + + // if hovering layer - do not show spacing to the parent, + // return only spacing of selection to hover + return [guide_relative_to_hover]; + } + if (selections.length === 1) { const parent = selections[0].parent; if (parent) { @@ -561,28 +585,6 @@ function position_guide({ } } - if (hover) { - const hover_box = boundingbox( - [ - [ - hover.absoluteX, - hover.absoluteY, - hover.width, - hover.height, - hover.rotation, - ], - ], - 2 - ); - - const guide_relative_to_hover = { - a: a, - b: hover_box, - }; - - guides.push(guide_relative_to_hover); - } - return guides; } diff --git a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx index 882ceb21..b83c0ee7 100644 --- a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx +++ b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx @@ -17,8 +17,6 @@ export function PositionGuide({ const box = scale(__box, zoom); const [_t, _r, _b, _l] = spacing; - console.log(spacing); - return (
) { +}: React.PropsWithChildren<{ + length: number; +}>) { if (length > 0) { return <>{children}; } @@ -89,7 +89,7 @@ function SpacingMeterLabel({ return ( + ); +} From 20360cc6f5d56adbc917947d65399f2059d1e546 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Tue, 25 Oct 2022 21:54:16 +0900 Subject: [PATCH 63/67] wip --- .../editor-canvas/hud/hud-surface.tsx | 10 +-- .../editor-canvas/math/guide-spacing.ts | 12 ++-- .../overlay/guide-positioning/index.tsx | 62 ++++++++++++++++--- 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/editor-packages/editor-canvas/hud/hud-surface.tsx b/editor-packages/editor-canvas/hud/hud-surface.tsx index b489e3c9..78ac51e4 100644 --- a/editor-packages/editor-canvas/hud/hud-surface.tsx +++ b/editor-packages/editor-canvas/hud/hud-surface.tsx @@ -91,6 +91,11 @@ export function HudSurface({ {!disableMarquee && marquee && } {!hide && ( <> + {/* position guide above all other generic overlays */} + {positionGuides.length > 0 && ( + + )} + {labelDisplayNodes && (
{labelDisplayNodes.map((node) => { @@ -122,6 +127,7 @@ export function HudSurface({ })}
)} + {highlights && highlights.map((h) => { return ( @@ -144,10 +150,6 @@ export function HudSurface({ disableGrouping={disableGrouping} /> )} - - {positionGuides.length > 0 && ( - - )} )} diff --git a/editor-packages/editor-canvas/math/guide-spacing.ts b/editor-packages/editor-canvas/math/guide-spacing.ts index 7e9611f4..76df7fd7 100644 --- a/editor-packages/editor-canvas/math/guide-spacing.ts +++ b/editor-packages/editor-canvas/math/guide-spacing.ts @@ -41,15 +41,18 @@ export function spacing_guide(a: Box, b: Box): SpacingGuide { const [a_x, a_y, a_x2, a_y2] = a; const [b_x, b_y, b_x2, b_y2] = b; - // no intersection (if the interecting space is 0, it is also considered as no intersection) - if (a[0] > b[2] || a[2] < b[0] || a[1] > b[3] || a[3] < b[1]) { + const intersects_x = segments_intersect(a_x, a_x2, b_x, b_x2); + const intersects_y = segments_intersect(a_y, a_y2, b_y, b_y2); + + // no intersection + if (!(intersects_x && intersects_y)) { let t = 0; let r = 0; let b = 0; let l = 0; // if x axis is not intersecting - if (!segments_intersect(a_x, a_x2, b_x, b_x2)) { + if (!intersects_x) { // if a is on the left of b (whille no intersection in x axis) if (a_x < b_x) { r = b_x - a_x2; // + @@ -64,7 +67,7 @@ export function spacing_guide(a: Box, b: Box): SpacingGuide { } // if y axis is not intersecting - if (!segments_intersect(a_y, a_y2, b_y, b_y2)) { + if (!intersects_y) { // if a is on the top of b if (a_y < b_y) { b = b_y - a_y2; // + @@ -102,6 +105,7 @@ export function spacing_guide(a: Box, b: Box): SpacingGuide { // intersection else { + // TODO: this needs a case handling return { // calculate the intersection of two boxes as a coordinate [x, y, x2, y2] box: intersection(a, b), diff --git a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx index b83c0ee7..35937dd8 100644 --- a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx +++ b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx @@ -182,22 +182,70 @@ function SpacingGuideLine({ ); } -function AuxiliaryLine() { +/* +; + +function AuxiliaryLine({ + point, + side, + b, + zoom, + width = 1, +}: { + // target raycast point. if the point intersects with the target, the line will not be drawn. + point: XY; + // original side of the guide. the auxiliary line will be drawn in other orientation (90 / -90). + side: Side; + // the target box that the a box is being positioned against. + b: Box; + zoom: number; + width?: number; +}) { + const d = 100; + + const isvert = side === "r" || side === "l"; + const l_scalex = isvert ? width / d : (length / d) * zoom; + const l_scaley = isvert ? (length / d) * zoom : width / d; + const box = scale(b, zoom); + const [bx, by, bx2, by2] = box; + const [, , w, h] = box_to_xywh(box); + + let trans = { x: 0, y: 0 }; + return (
); } + +const __gradient_dash_direction = { + t: "to right", + r: "to bottom", + b: "to right", + l: "to bottom", +} as const; +*/ From 532196438568a56cc45f0a1f19e14156200377a4 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Wed, 26 Oct 2022 14:45:34 +0900 Subject: [PATCH 64/67] add auxilary line --- .../overlay/guide-positioning/index.tsx | 274 +++++++++--------- .../overlay/guide-positioning/math.ts | 127 ++++++++ editor-packages/editor-canvas/overlay/k.ts | 1 + .../editor-canvas/overlay/meter-label.tsx | 5 +- .../editor-canvas/overlay/outline-side.tsx | 1 - 5 files changed, 275 insertions(+), 133 deletions(-) create mode 100644 editor-packages/editor-canvas/overlay/guide-positioning/math.ts diff --git a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx index 35937dd8..dd0e424e 100644 --- a/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx +++ b/editor-packages/editor-canvas/overlay/guide-positioning/index.tsx @@ -1,8 +1,9 @@ import React from "react"; -import { box_to_xywh, scale, spacing_guide } from "../../math"; -import type { Box } from "../../types"; +import { scale, spacing_guide } from "../../math"; +import type { Box, XY } from "../../types"; import * as k from "../k"; import { MeterLabel } from "../meter-label"; +import { auxiliary_line_xylr, guide_line_xylr } from "./math"; export function PositionGuide({ a, @@ -14,8 +15,16 @@ export function PositionGuide({ zoom: number; }) { const { spacing, box: __box } = spacing_guide(a, b); - const box = scale(__box, zoom); - const [_t, _r, _b, _l] = spacing; + const [st, sr, sb, sl] = spacing; + + const [tx, ty, tx2, ty2, tl, tr] = guide_line_xylr(__box, "t", st); + const [rx, ry, rx2, ry2, rl, rr] = guide_line_xylr(__box, "r", sr); + const [bx, by, bx2, by2, bl, br] = guide_line_xylr(__box, "b", sb); + const [lx, ly, lx2, ly2, ll, lr] = guide_line_xylr(__box, "l", sl); + const [tax, tay, , , tal, tar] = auxiliary_line_xylr([tx2, ty2], b, "t"); + const [rax, ray, , , ral, rar] = auxiliary_line_xylr([rx2, ry2], b, "r"); + const [bax, bay, , , bal, bar] = auxiliary_line_xylr([bx2, by2], b, "b"); + const [lax, lay, , , lal, lar] = auxiliary_line_xylr([lx2, ly2], b, "l"); return (
- - - + + + + + + - - - + + + + + + - - - + + + + + + - - - + + + + + +
); @@ -96,6 +141,7 @@ function SpacingMeterLabel({ margin={4} anchor={__label_anchor_map[side]} zoom={zoom} + zIndex={k.Z_INDEX_GUIDE_SPACING_LABEL} /> ); } @@ -109,143 +155,109 @@ const __label_anchor_map = { type Side = "t" | "r" | "b" | "l"; -function SpacingGuideLine({ - length, - zoom, - side, - box, - width = 1, -}: { - width?: number; - length: number; - box: Box; +interface GuideLineProps { + x: number; + y: number; zoom: number; - side: Side; -}) { - const d = 100; - - // is vertical line - const isvert = side === "t" || side === "b"; - const l_scalex = isvert ? width / d : (length / d) * zoom; - const l_scaley = isvert ? (length / d) * zoom : width / d; - const [, , w, h] = box_to_xywh(box); + length: number; + direction: "n" | "s" | "e" | "w" | number; + width?: number; + color: React.CSSProperties["color"]; + dashed?: boolean; +} - let trans = { x: 0, y: 0 }; - switch (side) { - case "t": { - trans = { - x: box[0] + (d * l_scalex - d) / 2 + w / 2, - y: box[1] - d / 2 - (length / 2) * zoom, - }; - break; - } - case "r": { - trans = { - x: box[2] - d / 2 + (length / 2) * zoom, - y: box[1] + (d * l_scaley - d) / 2 + h / 2, - }; - break; - } - case "b": { - trans = { - x: box[0] + (d * l_scalex - d) / 2 + w / 2, - y: box[3] - d / 2 + (length / 2) * zoom, - }; - break; - } - case "l": { - trans = { - x: box[0] - d / 2 - (length / 2) * zoom, - y: box[1] + (d * l_scaley - d) / 2 + h / 2, - }; - break; - } - } +function GuideLine({ + x, + y, + zoom, + direction, + length, + width, + color = "orange", + dashed, +}: GuideLineProps) { + const tl = length * zoom; + const tx = x * zoom; + const ty = y * zoom; + const tr = + typeof direction === "number" + ? direction + : __line_rotation_by_direction_map[direction]; return (
); } -/* -; +const __line_rotation_by_direction_map = { + n: 180, + e: 270, + s: 0, + w: 90, +} as const; -function AuxiliaryLine({ - point, - side, - b, +function SpacingGuideLine({ + length, + x, + y, + rotation, zoom, - width = 1, }: { - // target raycast point. if the point intersects with the target, the line will not be drawn. - point: XY; - // original side of the guide. the auxiliary line will be drawn in other orientation (90 / -90). - side: Side; - // the target box that the a box is being positioned against. - b: Box; + x: number; + y: number; + length: number; + rotation: number; zoom: number; - width?: number; }) { - const d = 100; - - const isvert = side === "r" || side === "l"; - const l_scalex = isvert ? width / d : (length / d) * zoom; - const l_scaley = isvert ? (length / d) * zoom : width / d; - const box = scale(b, zoom); - const [bx, by, bx2, by2] = box; - const [, , w, h] = box_to_xywh(box); - - let trans = { x: 0, y: 0 }; - return ( -
); } -const __gradient_dash_direction = { - t: "to right", - r: "to bottom", - b: "to right", - l: "to bottom", -} as const; -*/ +function AuxiliaryLine({ + length, + x, + y, + rotation, + zoom, +}: { + x: number; + y: number; + length: number; + rotation: number; + zoom: number; +}) { + return ( + + ); +} diff --git a/editor-packages/editor-canvas/overlay/guide-positioning/math.ts b/editor-packages/editor-canvas/overlay/guide-positioning/math.ts new file mode 100644 index 00000000..bf4811e1 --- /dev/null +++ b/editor-packages/editor-canvas/overlay/guide-positioning/math.ts @@ -0,0 +1,127 @@ +import type { Box, XY } from "../../types"; +type Side = "t" | "r" | "b" | "l"; +type LineXYXYLR = [number, number, number, number, number, number]; +/** + * guide line representation with x, y, x2, y2, length, and rotation + */ +export function guide_line_xylr( + box: Box, + side: Side, + length: number, + zoom: number = 1 +): LineXYXYLR { + const [x, y, x2, y2] = box; + // lenght of the line (height in css) + const tl = length * zoom; + // transform x + let tx = 0; + // transform y + let ty = 0; + // transform rotation + let tr = deg(side, length); + + let tx2 = 0; + let ty2 = 0; + + switch (side) { + case "t": + tx = (x + (x2 - x) / 2) * zoom; + ty = y * zoom; + tx2 = tx; + ty2 = y - tl; + break; + case "r": + tx = x2 * zoom; + ty = (y + (y2 - y) / 2) * zoom; + tx2 = x2 + tl; + ty2 = ty; + break; + case "b": + tx = (x + (x2 - x) / 2) * zoom; + ty = y2 * zoom; + tx2 = tx; + ty2 = y2 + tl; + break; + case "l": + tx = x * zoom; + ty = (y + (y2 - y) / 2) * zoom; + tx2 = tx - tl; + ty2 = ty; + break; + } + + return [tx, ty, tx2, ty2, tl, tr]; +} + +const deg = (side: Side, length: number) => { + let r: number = __line_rotation_by_side_map[side]; + if (length < 0) { + r = r * -1; + } + return r; +}; + +const __line_rotation_by_side_map = { + t: 180, + r: 270, + b: 0, + l: 90, +} as const; + +export function auxiliary_line_xylr( + point: XY, + b: Box, + side: Side, + zoom: number = 1 +): LineXYXYLR { + let [bx, by, bx2, by2] = b; + const [rx, ry] = point; + + const tx = rx * zoom; + const ty = ry * zoom; + // prettier-ignore + let tx2, ty2, tl, tr = 0; + + if (point_hits_box(point, b)) { + return [point[0], point[1], NaN, NaN, 0, 0]; + } else { + switch (side) { + case "b": + case "t": + // the point is to the left of the target box, which means the line should be drawn to the righ + if (rx < bx) { + tl = (bx - rx) * zoom; + tr = -90; + } else { + tl = (rx - bx2) * zoom; + tr = 90; + } + break; + + case "r": + case "l": + // the point is below the target box, which means the line should be drawn to the above + if (ry > by2) { + tl = (ry - by2) * zoom; + tr = 180; + } else { + tl = (by2 - ry) * zoom; + tr = 0; + } + break; + } + + return [tx, ty, tx2, ty2, tl, tr]; + } +} + +/** + * check if point meets the box + * @returns + */ +function point_hits_box(point: XY, box: Box): boolean { + const [x, y, x2, y2] = box; + const [px, py] = point; + const hits = px >= x && px <= x2 && py >= y && py <= y2; + return hits; +} diff --git a/editor-packages/editor-canvas/overlay/k.ts b/editor-packages/editor-canvas/overlay/k.ts index 059e1c03..122c890f 100644 --- a/editor-packages/editor-canvas/overlay/k.ts +++ b/editor-packages/editor-canvas/overlay/k.ts @@ -2,3 +2,4 @@ export const Z_INDEX_HANDLE = 2; export const Z_INDEX_GUIDE_POSITION = 3; export const Z_INDEX_GUIDE_SPACING = 4; export const Z_INDEX_GUIDE_LABEL = 5; +export const Z_INDEX_GUIDE_SPACING_LABEL = 6; diff --git a/editor-packages/editor-canvas/overlay/meter-label.tsx b/editor-packages/editor-canvas/overlay/meter-label.tsx index 54411200..ca6eed2f 100644 --- a/editor-packages/editor-canvas/overlay/meter-label.tsx +++ b/editor-packages/editor-canvas/overlay/meter-label.tsx @@ -31,6 +31,7 @@ export function SizeMeterLabel({ anchor="s" margin={margin} zoom={zoom} + zIndex={k.Z_INDEX_GUIDE_LABEL} /> ); } @@ -43,6 +44,7 @@ export function MeterLabel({ anchor, zoom, margin = 0, + zIndex = k.Z_INDEX_GUIDE_LABEL, }: { x: number; y: number; @@ -51,6 +53,7 @@ export function MeterLabel({ anchor: "w" | "n" | "s" | "e"; margin?: number; zoom: number; + zIndex?: number; }) { const labelwidth = (label.length * font_size) / 1.8; // a view width assumption (we will not use flex box for faster painting) const viewwidth = labelwidth + 4; // 4 is for horizontal padding @@ -97,7 +100,7 @@ export function MeterLabel({ fontFamily: "Inter, sans-serif", fontWeight: 500, textAlign: "center", - zIndex: k.Z_INDEX_GUIDE_LABEL, + zIndex: zIndex, }} > {label} diff --git a/editor-packages/editor-canvas/overlay/outline-side.tsx b/editor-packages/editor-canvas/overlay/outline-side.tsx index 2bfc4054..857c027c 100644 --- a/editor-packages/editor-canvas/overlay/outline-side.tsx +++ b/editor-packages/editor-canvas/overlay/outline-side.tsx @@ -70,7 +70,6 @@ export function OulineSide({ pointerEvents: readonly ? "none" : "all", cursor: cursor, willChange: "transform", - transformOrigin: "0px, 0px", transform: `translate3d(${trans.x}px, ${trans.y}px, 0) scaleX(${l_scalex}) scaleY(${l_scaley})`, backgroundColor: color, }} From 161bdfcca701e7b78809e8d10d11ee3d972e8933 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Wed, 26 Oct 2022 15:49:54 +0900 Subject: [PATCH 65/67] update inspector styles --- editor/components/code-editor/monaco.tsx | 9 ++- .../inspector/inspector-readonly-property.tsx | 3 +- .../inspector/inspector-section.tsx | 79 +++++++++++++++---- editor/scaffolds/inspector/index.ts | 2 +- editor/scaffolds/inspector/inspector.tsx | 6 +- editor/scaffolds/inspector/section-assets.tsx | 2 +- editor/scaffolds/inspector/section-code.tsx | 77 ++++++++++++++++++ editor/scaffolds/inspector/section-colors.tsx | 2 +- .../scaffolds/inspector/section-content.tsx | 2 +- editor/scaffolds/inspector/section-info.tsx | 4 +- editor/scaffolds/inspector/section-layout.tsx | 19 +++-- 11 files changed, 173 insertions(+), 32 deletions(-) create mode 100644 editor/scaffolds/inspector/section-code.tsx diff --git a/editor/components/code-editor/monaco.tsx b/editor/components/code-editor/monaco.tsx index ea199449..45cb5e74 100644 --- a/editor/components/code-editor/monaco.tsx +++ b/editor/components/code-editor/monaco.tsx @@ -8,14 +8,18 @@ import { debounce } from "utils/debounce"; import { downloadFile } from "utils/download"; type ICodeEditor = monaco.editor.IStandaloneCodeEditor; - +type Options = Omit< + monaco.editor.IStandaloneEditorConstructionOptions, + "readOnly" +>; export interface MonacoEditorProps { value?: string; language?: string; onChange?: OnChange; width?: number | string; height?: number | string; - options?: monaco.editor.IStandaloneEditorConstructionOptions; + options?: Options; + readonly?: boolean; } export function MonacoEditor(props: MonacoEditorProps) { @@ -92,6 +96,7 @@ export function MonacoEditor(props: MonacoEditorProps) { options={{ ...props.options, // overrided default options + readOnly: props.readonly, wordWrap: "off", unusualLineTerminators: "off", }} diff --git a/editor/components/inspector/inspector-readonly-property.tsx b/editor/components/inspector/inspector-readonly-property.tsx index 61d938da..f121a87d 100644 --- a/editor/components/inspector/inspector-readonly-property.tsx +++ b/editor/components/inspector/inspector-readonly-property.tsx @@ -30,7 +30,8 @@ const PropertyLineContainer = styled.div` flex: 1; gap: 8px; background: transparent; - padding: 2px; + padding: 4px; + border-radius: 4px; label { font-size: 14px; diff --git a/editor/components/inspector/inspector-section.tsx b/editor/components/inspector/inspector-section.tsx index 377c1adf..9f612d2c 100644 --- a/editor/components/inspector/inspector-section.tsx +++ b/editor/components/inspector/inspector-section.tsx @@ -1,16 +1,46 @@ +import styled from "@emotion/styled"; import React, { CSSProperties } from "react"; +const _theme_section_border = "1px solid rgba(255, 255, 255, 0.05)"; + export function InspectorSection({ children, label, - contentPadding = "8px", + contentPadding = "14px 14px 14px 24px", + actions, + border, + borderTop, + borderBottom, }: React.PropsWithChildren<{ label: string; contentPadding?: CSSProperties["padding"]; + actions?: React.ReactNode; + border?: { top?: boolean; bottom?: boolean } | boolean; + borderTop?: boolean; + borderBottom?: boolean; }>) { + const _border_top = + borderTop === true + ? true + : typeof border === "boolean" + ? border + : border?.top === true; + const _border_bottom = + borderBottom === true + ? true + : typeof border === "boolean" + ? border + : border?.bottom === true; + return ( -
- {label} +
+
+ {label} + {actions && <>{actions}} +
{children}
-
+
); } -export function InfoSectionLabel({ children }: { children: React.ReactNode }) { - return ( -
- {children} -
- ); -} +const InfoSectionLabel = styled.h6` + color: white; + font-size: 12px; + font-weight: 500; + margin: 0; + cursor: default; +`; + +const Header = styled.header` + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding-left: 14px; + padding-right: 14px; +`; + +const Section = styled.section<{ + borderTop: React.CSSProperties["borderTop"]; + borderBottom: React.CSSProperties["borderBottom"]; +}>` + display: flex; + flex-direction: column; + padding-top: 12px; + padding-bottom: 16px; + border-top: ${(props) => props.borderTop}; + border-bottom: ${(props) => props.borderBottom}; +`; diff --git a/editor/scaffolds/inspector/index.ts b/editor/scaffolds/inspector/index.ts index 16d4afc4..552418b7 100644 --- a/editor/scaffolds/inspector/index.ts +++ b/editor/scaffolds/inspector/index.ts @@ -1 +1 @@ -export { InspectorSegment as Inspector } from "./inspector"; +export { Inspector as Inspector } from "./inspector"; diff --git a/editor/scaffolds/inspector/inspector.tsx b/editor/scaffolds/inspector/inspector.tsx index e723adf3..c96dc2a4 100644 --- a/editor/scaffolds/inspector/inspector.tsx +++ b/editor/scaffolds/inspector/inspector.tsx @@ -10,8 +10,9 @@ import { ColorsSection } from "./section-colors"; import { ContentSection } from "./section-content"; import { TypographySection } from "./section-typography"; import { AssetsSection } from "./section-assets"; +import { CodeSection } from "./section-code"; -export function InspectorSegment() { +export function Inspector() { const { target } = useTargetContainer(); const [state] = useEditorState(); @@ -19,11 +20,13 @@ export function InspectorSegment() { return ( +
+ ); } @@ -34,6 +37,7 @@ export function InspectorSegment() { const InspectorContainer = styled.div` display: flex; z-index: 1; + overflow-y: scroll; flex-direction: column; height: 100%; background-color: ${colors.color_editor_bg_on_dark}; diff --git a/editor/scaffolds/inspector/section-assets.tsx b/editor/scaffolds/inspector/section-assets.tsx index 7adad247..ae9f61af 100644 --- a/editor/scaffolds/inspector/section-assets.tsx +++ b/editor/scaffolds/inspector/section-assets.tsx @@ -13,7 +13,7 @@ export function AssetsSection() { } return ( - + {target.images.map((img) => ( ))} diff --git a/editor/scaffolds/inspector/section-code.tsx b/editor/scaffolds/inspector/section-code.tsx new file mode 100644 index 00000000..69a2306e --- /dev/null +++ b/editor/scaffolds/inspector/section-code.tsx @@ -0,0 +1,77 @@ +import React, { useEffect, useState } from "react"; +import { designToCode, Result } from "@designto/code"; +import { config } from "@grida/builder-config"; +import { useTargetContainer } from "hooks/use-target-node"; +import { useWorkspaceState } from "core/states"; +import { MonacoEditor } from "components/code-editor"; +import { InspectorSection } from "components/inspector"; +import { Button } from "@editor-ui/button"; +import styled from "@emotion/styled"; + +export function CodeSection() { + const wstate = useWorkspaceState(); + const { target, root } = useTargetContainer(); + const [result, setResult] = useState(); + + const on_result = (result: Result) => { + setResult(result); + }; + + const on_open = () => {}; + + useEffect(() => { + if (target) { + const _input = { + id: target.id, + name: target.name, + entry: target, + repository: root.repository, + }; + const build_config = { + ...config.default_build_configuration, + disable_components: true, + }; + + designToCode({ + input: _input, + framework: wstate.preferences.framework_config, + asset_config: { skip_asset_replacement: true }, + build_config: build_config, + }) + .then(on_result) + .catch(console.error); + } + }, [target?.id]); + + const { code, scaffold, name: componentName, framework } = result ?? {}; + if (code) { + return ( + + + + } + > + + + ); + } + + return <>; +} diff --git a/editor/scaffolds/inspector/section-colors.tsx b/editor/scaffolds/inspector/section-colors.tsx index 1c435754..eb4585a3 100644 --- a/editor/scaffolds/inspector/section-colors.tsx +++ b/editor/scaffolds/inspector/section-colors.tsx @@ -18,7 +18,7 @@ export function ColorsSection() { } return ( - + {colors?.map((c) => { switch (c.type) { diff --git a/editor/scaffolds/inspector/section-content.tsx b/editor/scaffolds/inspector/section-content.tsx index e4fc5d96..a21b5a46 100644 --- a/editor/scaffolds/inspector/section-content.tsx +++ b/editor/scaffolds/inspector/section-content.tsx @@ -11,7 +11,7 @@ export function ContentSection() { const txt = target.data; return ( - + { diff --git a/editor/scaffolds/inspector/section-info.tsx b/editor/scaffolds/inspector/section-info.tsx index 1525c645..0e9a1454 100644 --- a/editor/scaffolds/inspector/section-info.tsx +++ b/editor/scaffolds/inspector/section-info.tsx @@ -16,11 +16,11 @@ const Section = styled.section` margin-top: 24px; display: flex; flex-direction: column; - padding: 8px; + padding: 14px; `; const SceneTitle = styled.input` - margin: 0; + margin: 4px 0; background: transparent; font-size: 18px; outline: none; diff --git a/editor/scaffolds/inspector/section-layout.tsx b/editor/scaffolds/inspector/section-layout.tsx index e2898f00..392e88f5 100644 --- a/editor/scaffolds/inspector/section-layout.tsx +++ b/editor/scaffolds/inspector/section-layout.tsx @@ -12,15 +12,21 @@ export function LayoutSection() { const { isRoot, x, y, width, height } = target; + // round to 2 decimal places + const dx = rd(x); + const dy = rd(y); + const dw = rd(width); + const dh = rd(height); + return ( - + - - + + - - + + ); @@ -29,5 +35,8 @@ export function LayoutSection() { const Line = styled.div` display: flex; flex-direction: row; + gap: 4px; width: 100%; `; + +const rd = (v: number) => Math.round(v * 100) / 100; From 75afd85e16cfd1964dd92debb5598c49c120c83b Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Wed, 26 Oct 2022 16:13:48 +0900 Subject: [PATCH 66/67] add editor mode state --- editor/core/actions/index.ts | 28 ++++++++++------ editor/core/reducers/editor-reducer.ts | 37 +++++++++++++++++---- editor/core/states/editor-initial-state.ts | 2 ++ editor/core/states/editor-state.ts | 11 +++++- editor/scaffolds/code/index.tsx | 4 +-- editor/scaffolds/editor/editor.tsx | 18 ++++++++-- editor/scaffolds/inspector/section-code.tsx | 7 ++-- 7 files changed, 81 insertions(+), 26 deletions(-) diff --git a/editor/core/actions/index.ts b/editor/core/actions/index.ts index 091014a1..854cbd95 100644 --- a/editor/core/actions/index.ts +++ b/editor/core/actions/index.ts @@ -7,10 +7,9 @@ import type { } from "core/states"; export type WorkspaceAction = - // | HistoryAction - // - | HighlightLayerAction; + | HighlightLayerAction + | EditorModeAction; export type HistoryAction = // @@ -28,10 +27,17 @@ export type Action = | PreviewAction | CodeEditorAction | DevtoolsAction - | EditorTaskAction; + | BackgroundTaskAction + | EditorModeAction; export type ActionType = Action["type"]; +export type EditorModeAction = EditorModeSwitchAction; +export type EditorModeSwitchAction = { + type: "mode"; + mode: EditorState["mode"]; +}; + export type HierarchyAction = SelectNodeAction; export interface SelectNodeAction { type: "select-node"; @@ -101,22 +107,22 @@ export interface DevtoolsConsoleClearAction { type: "devtools-console-clear"; } -export type EditorTaskAction = - | EditorTaskPushAction - | EditorTaskPopAction - | EditorTaskUpdateProgressAction; +export type BackgroundTaskAction = + | BackgroundTaskPushAction + | BackgroundTaskPopAction + | BackgroundTaskUpdateProgressAction; -export interface EditorTaskPushAction { +export interface BackgroundTaskPushAction { type: "editor-task-push"; task: EditorTask; } -export interface EditorTaskPopAction { +export interface BackgroundTaskPopAction { type: "editor-task-pop"; task: EditorTask | { id: string }; } -export interface EditorTaskUpdateProgressAction { +export interface BackgroundTaskUpdateProgressAction { type: "editor-task-update-progress"; id: string; progress: number; diff --git a/editor/core/reducers/editor-reducer.ts b/editor/core/reducers/editor-reducer.ts index 78bb3752..1594fd3f 100644 --- a/editor/core/reducers/editor-reducer.ts +++ b/editor/core/reducers/editor-reducer.ts @@ -11,9 +11,10 @@ import type { PreviewSetAction, DevtoolsConsoleAction, DevtoolsConsoleClearAction, - EditorTaskPushAction, - EditorTaskPopAction, - EditorTaskUpdateProgressAction, + BackgroundTaskPushAction, + BackgroundTaskPopAction, + BackgroundTaskUpdateProgressAction, + EditorModeSwitchAction, } from "core/actions"; import { EditorState } from "core/states"; import { useRouter } from "next/router"; @@ -28,6 +29,22 @@ export function editorReducer(state: EditorState, action: Action): EditorState { const filekey = state.design.key; switch (action.type) { + case "mode": { + const { mode } = action; + return produce(state, (draft) => { + switch (mode) { + case "code": + draft.canvasMode = "isolated-view"; + break; + case "inspect": + case "view": + default: + draft.canvasMode = "free"; + } + + draft.mode = mode; + }); + } case "select-node": { const { node } = action; const ids = Array.isArray(node) ? node : [node]; @@ -145,6 +162,14 @@ export function editorReducer(state: EditorState, action: Action): EditorState { }); return produce(state, (draft) => { + if (mode === "isolated-view") { + // on isolation mode, switch the editor mode to code. + draft.mode = "code"; + } else { + // needs to be fixed once more modes are added. + draft.mode = "view"; + } + draft.canvasMode_previous = draft.canvasMode; draft.canvasMode = mode; }); @@ -226,7 +251,7 @@ export function editorReducer(state: EditorState, action: Action): EditorState { break; } case "editor-task-push": { - const { task } = action; + const { task } = action; const { id } = task; // TODO: check id duplication @@ -236,7 +261,7 @@ export function editorReducer(state: EditorState, action: Action): EditorState { break; } case "editor-task-pop": { - const { task } = action; + const { task } = action; const { id } = task; return produce(state, (draft) => { @@ -248,7 +273,7 @@ export function editorReducer(state: EditorState, action: Action): EditorState { break; } case "editor-task-update-progress": { - const { id, progress } = action; + const { id, progress } = action; return produce(state, (draft) => { draft.editorTaskQueue.tasks.find((i) => i.id !== id).progress = progress; diff --git a/editor/core/states/editor-initial-state.ts b/editor/core/states/editor-initial-state.ts index 3b43d556..0c1eeea1 100644 --- a/editor/core/states/editor-initial-state.ts +++ b/editor/core/states/editor-initial-state.ts @@ -7,6 +7,7 @@ export function createInitialEditorState(editor: EditorSnapshot): EditorState { selectedNodesInitial: editor.selectedNodes, selectedLayersOnPreview: editor.selectedLayersOnPreview, design: editor.design, + mode: "view", canvasMode: editor.canvasMode, editorTaskQueue: editor.editorTaskQueue, }; @@ -19,6 +20,7 @@ export function createPendingEditorState(): EditorState { selectedNodesInitial: null, selectedLayersOnPreview: [], design: null, + mode: "view", canvasMode: "free", editorTaskQueue: { isBusy: true, diff --git a/editor/core/states/editor-state.ts b/editor/core/states/editor-state.ts index ebd32524..8cd81a25 100644 --- a/editor/core/states/editor-state.ts +++ b/editor/core/states/editor-state.ts @@ -6,11 +6,19 @@ import type { DesignInput } from "@grida/builder-config/input"; /** * View mode of the canvas. - * - full - default + * - free - default * - isolated - focus to one scene */ type TCanvasMode = "free" | "isolated-view" | "fullscreen-preview"; +/** + * Task mode of the editor. + * - view - default + * - code - with coding editor + * - inspect - with inspector + */ +type TUserTaskMode = "view" | "code" | "inspect"; + export interface EditorState { selectedPage: string; selectedNodes: string[]; @@ -22,6 +30,7 @@ export interface EditorState { */ selectedNodesInitial?: string[] | null; design: FigmaReflectRepository; + mode: TUserTaskMode; canvasMode: TCanvasMode; canvasMode_previous?: TCanvasMode; currentPreview?: ScenePreviewData; diff --git a/editor/scaffolds/code/index.tsx b/editor/scaffolds/code/index.tsx index 3b50e54c..cbc7c8d0 100644 --- a/editor/scaffolds/code/index.tsx +++ b/editor/scaffolds/code/index.tsx @@ -2,7 +2,6 @@ import React, { useEffect, useRef, useState } from "react"; import styled from "@emotion/styled"; import { useRouter } from "next/router"; import { CodeEditor } from "components/code-editor"; -import { EditorAppbarFragments } from "components/editor"; import { get_framework_config } from "query/to-code-options-from-query"; import { CodeOptionsControl } from "components/codeui-code-options-control"; import { designToCode, Result } from "@designto/code"; @@ -33,7 +32,7 @@ const preset_store = { }, }; -export function CodeSegment() { +export function Code() { const router = useRouter(); const [result, setResult] = useState(); const dispatch = useDispatch(); @@ -147,7 +146,6 @@ export function CodeSegment() { const { code, scaffold, name: componentName, framework } = result ?? {}; return ( - - - {/* */} + {/* {wstate.preferences.debug_mode && ( @@ -88,3 +87,16 @@ export function Editor({ ); } + +function RightPanelContent() { + const [state] = useEditorState(); + + switch (state.mode) { + case "code": + return ; + case "inspect": + case "view": + default: + return ; + } +} diff --git a/editor/scaffolds/inspector/section-code.tsx b/editor/scaffolds/inspector/section-code.tsx index 69a2306e..ec13412a 100644 --- a/editor/scaffolds/inspector/section-code.tsx +++ b/editor/scaffolds/inspector/section-code.tsx @@ -6,18 +6,21 @@ import { useWorkspaceState } from "core/states"; import { MonacoEditor } from "components/code-editor"; import { InspectorSection } from "components/inspector"; import { Button } from "@editor-ui/button"; -import styled from "@emotion/styled"; +import { useDispatch } from "core/dispatch"; export function CodeSection() { const wstate = useWorkspaceState(); const { target, root } = useTargetContainer(); const [result, setResult] = useState(); + const dispatch = useDispatch(); const on_result = (result: Result) => { setResult(result); }; - const on_open = () => {}; + const on_open = () => { + dispatch({ type: "mode", mode: "code" }); + }; useEffect(() => { if (target) { From 73e3e429ef7234dc8432b8a2a2f53b2a24adcab7 Mon Sep 17 00:00:00 2001 From: softmarshmallow Date: Wed, 26 Oct 2022 16:31:39 +0900 Subject: [PATCH 67/67] cleanup --- editor/scaffolds/editor/editor.tsx | 4 ---- editor/scaffolds/inspector/section-code.tsx | 2 +- editor/styles/global.css | 4 ++++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/editor/scaffolds/editor/editor.tsx b/editor/scaffolds/editor/editor.tsx index c0c42805..4d1df928 100644 --- a/editor/scaffolds/editor/editor.tsx +++ b/editor/scaffolds/editor/editor.tsx @@ -11,7 +11,6 @@ import { Code } from "scaffolds/code"; import { Inspector } from "scaffolds/inspector"; import { EditorSkeleton } from "./skeleton"; import { colors } from "theme"; -import { Appbar } from "scaffolds/appbar"; export function Editor({ loading = false, @@ -48,9 +47,6 @@ export function Editor({ maxWidth: 600, children: , }} - contentAreaAppbar={} - // appbar={} - // rightbar={} > diff --git a/editor/scaffolds/inspector/section-code.tsx b/editor/scaffolds/inspector/section-code.tsx index ec13412a..8b240f71 100644 --- a/editor/scaffolds/inspector/section-code.tsx +++ b/editor/scaffolds/inspector/section-code.tsx @@ -65,7 +65,7 @@ export function CodeSection() { readonly width={"100%"} value={code.raw} - height={400} + height={target.isRoot ? 800 : 400} options={{ lineNumbers: "off", glyphMargin: false, diff --git a/editor/styles/global.css b/editor/styles/global.css index e1991479..5f28f0be 100644 --- a/editor/styles/global.css +++ b/editor/styles/global.css @@ -6,11 +6,15 @@ body { /* for editor canvas */ html { + overflow: hidden; + height: 100%; overscroll-behavior-x: none; } body { overscroll-behavior-x: none; touch-action: none; + height: 100%; + overflow: auto; } /* ----------------- */