From 5652b8e01b335b0186dcf1f92545cbf0b09987e1 Mon Sep 17 00:00:00 2001 From: chao Date: Thu, 24 Apr 2025 01:16:48 +0800 Subject: [PATCH] =?UTF-8?q?feats:=20=E4=B8=BA=20snow-shot=20=E9=80=82?= =?UTF-8?q?=E9=85=8D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/common/src/constants.ts | 1 + packages/element/src/Shape.ts | 2 + packages/element/src/comparisons.ts | 9 +- packages/element/src/newElement.ts | 20 ++ packages/element/src/renderElement.ts | 3 + packages/element/src/shapes.ts | 1 + packages/element/src/typeChecks.ts | 12 + packages/element/src/types.ts | 8 +- packages/excalidraw/actions/actionAlign.tsx | 284 +++++++++++++----- packages/excalidraw/actions/actionBlur.tsx | 48 +++ .../actions/actionDeleteSelected.tsx | 44 ++- .../excalidraw/actions/actionDistribute.tsx | 102 +++++-- .../actions/actionDuplicateSelection.tsx | 48 ++- packages/excalidraw/actions/actionGroup.tsx | 98 ++++-- packages/excalidraw/actions/actionHistory.tsx | 21 +- packages/excalidraw/actions/actionLink.tsx | 18 ++ .../excalidraw/actions/actionProperties.tsx | 7 +- packages/excalidraw/actions/index.ts | 2 + packages/excalidraw/actions/types.ts | 3 +- packages/excalidraw/appState.ts | 2 + packages/excalidraw/components/Actions.tsx | 196 ++++++++---- packages/excalidraw/components/App.tsx | 30 +- packages/excalidraw/components/Range.tsx | 77 ++++- packages/excalidraw/components/shapes.tsx | 9 +- packages/excalidraw/data/restore.ts | 2 + packages/excalidraw/history.ts | 15 + packages/excalidraw/index.tsx | 119 +++++--- packages/excalidraw/locales/en.json | 3 + packages/excalidraw/locales/zh-CN.json | 3 + packages/excalidraw/locales/zh-TW.json | 2 + .../excalidraw/renderer/staticSvgScene.ts | 1 + packages/excalidraw/scene/types.ts | 1 + packages/excalidraw/tests/helpers/api.ts | 10 +- packages/excalidraw/types.ts | 25 +- packages/utils/src/shape.ts | 2 + 35 files changed, 942 insertions(+), 286 deletions(-) create mode 100644 packages/excalidraw/actions/actionBlur.tsx diff --git a/packages/common/src/constants.ts b/packages/common/src/constants.ts index cd3bd7a15..a7da91434 100644 --- a/packages/common/src/constants.ts +++ b/packages/common/src/constants.ts @@ -438,6 +438,7 @@ export const TOOL_TYPE = { magicframe: "magicframe", embeddable: "embeddable", laser: "laser", + blur: "blur", } as const; export const EDITOR_LS_KEYS = { diff --git a/packages/element/src/Shape.ts b/packages/element/src/Shape.ts index 4def41957..1f6de9ec8 100644 --- a/packages/element/src/Shape.ts +++ b/packages/element/src/Shape.ts @@ -98,6 +98,7 @@ export const generateRoughOptions = ( case "iframe": case "embeddable": case "diamond": + case "blur": case "ellipse": { options.fillStyle = element.fillStyle; options.fill = isTransparent(element.backgroundColor) @@ -326,6 +327,7 @@ export const _generateElementShape = ( switch (element.type) { case "rectangle": case "iframe": + case "blur": case "embeddable": { let shape: ElementShapes[typeof element.type]; // this is for rendering the stroke/bg of the embeddable, especially diff --git a/packages/element/src/comparisons.ts b/packages/element/src/comparisons.ts index 75fac889d..3aee07b05 100644 --- a/packages/element/src/comparisons.ts +++ b/packages/element/src/comparisons.ts @@ -10,7 +10,10 @@ export const hasBackground = (type: ElementOrToolType) => type === "freedraw"; export const hasStrokeColor = (type: ElementOrToolType) => - type !== "image" && type !== "frame" && type !== "magicframe"; + type !== "image" && + type !== "frame" && + type !== "magicframe" && + type !== "blur"; export const hasStrokeWidth = (type: ElementOrToolType) => type === "rectangle" || @@ -39,6 +42,10 @@ export const canChangeRoundness = (type: ElementOrToolType) => type === "diamond" || type === "image"; +export const canChangeBlur = (type: ElementOrToolType) => type === "blur"; + +export const canChangeLayer = (type: ElementOrToolType) => type !== "blur"; + export const toolIsArrow = (type: ElementOrToolType) => type === "arrow"; export const canHaveArrowheads = (type: ElementOrToolType) => type === "arrow"; diff --git a/packages/element/src/newElement.ts b/packages/element/src/newElement.ts index 53a2f05ae..5b9d252df 100644 --- a/packages/element/src/newElement.ts +++ b/packages/element/src/newElement.ts @@ -46,6 +46,7 @@ import type { ExcalidrawArrowElement, FixedSegment, ExcalidrawElbowArrowElement, + ExcalidrawBlurElement, } from "./types"; export type ElementConstructorOpts = MarkOptional< @@ -212,6 +213,25 @@ export const newMagicFrameElement = ( return frameElement; }; +export const newBlurElement = ( + opts: { + blur: number; + } & ElementConstructorOpts, +): NonDeleted => { + const blurElement = newElementWith( + { + ..._newElementBase("blur", opts), + type: "blur", + blur: opts.blur, + fillStyle: "solid", + backgroundColor: "#000000", + }, + {}, + ); + + return blurElement; +}; + /** computes element x/y offset based on textAlign/verticalAlign */ const getTextElementPositionOffsets = ( opts: { diff --git a/packages/element/src/renderElement.ts b/packages/element/src/renderElement.ts index c8091e8ed..36f6d3bdf 100644 --- a/packages/element/src/renderElement.ts +++ b/packages/element/src/renderElement.ts @@ -404,6 +404,8 @@ const drawElementOnCanvas = ( rc.draw(ShapeCache.get(element)!); break; } + case "blur": + break; case "arrow": case "line": { context.lineJoin = "round"; @@ -814,6 +816,7 @@ export const renderElement = ( case "image": case "text": case "iframe": + case "blur": case "embeddable": { // TODO investigate if we can do this in situ. Right now we need to call // beforehand because math helpers (such as getElementAbsoluteCoords) diff --git a/packages/element/src/shapes.ts b/packages/element/src/shapes.ts index 96542c538..cd690e728 100644 --- a/packages/element/src/shapes.ts +++ b/packages/element/src/shapes.ts @@ -58,6 +58,7 @@ export const getElementShape = ( case "embeddable": case "image": case "iframe": + case "blur": case "text": case "selection": return getPolygonShape(element); diff --git a/packages/element/src/typeChecks.ts b/packages/element/src/typeChecks.ts index 54619726d..9369b6c60 100644 --- a/packages/element/src/typeChecks.ts +++ b/packages/element/src/typeChecks.ts @@ -28,6 +28,7 @@ import type { PointBinding, FixedPointBinding, ExcalidrawFlowchartNodeElement, + ExcalidrawBlurElement, } from "./types"; export const isInitializedImageElement = ( @@ -107,6 +108,12 @@ export const isLinearElement = ( return element != null && isLinearElementType(element.type); }; +export const isBlurElement = ( + element?: ExcalidrawElement | null, +): element is ExcalidrawBlurElement => { + return element != null && isBlurElementType(element.type); +}; + export const isArrowElement = ( element?: ExcalidrawElement | null, ): element is ExcalidrawArrowElement => { @@ -127,6 +134,10 @@ export const isLinearElementType = ( ); }; +export const isBlurElementType = (elementType: ElementOrToolType): boolean => { + return elementType === "blur"; +}; + export const isBindingElement = ( element?: ExcalidrawElement | null, includeLocked = true, @@ -231,6 +242,7 @@ export const isExcalidrawElement = ( case "frame": case "magicframe": case "image": + case "blur": case "selection": { return true; } diff --git a/packages/element/src/types.ts b/packages/element/src/types.ts index 3b40135d5..fd00f8a28 100644 --- a/packages/element/src/types.ts +++ b/packages/element/src/types.ts @@ -89,6 +89,11 @@ export type ExcalidrawRectangleElement = _ExcalidrawElementBase & { type: "rectangle"; }; +export type ExcalidrawBlurElement = _ExcalidrawElementBase & { + type: "blur"; + blur: number; +}; + export type ExcalidrawDiamondElement = _ExcalidrawElementBase & { type: "diamond"; }; @@ -212,7 +217,8 @@ export type ExcalidrawElement = | ExcalidrawFrameElement | ExcalidrawMagicFrameElement | ExcalidrawIframeElement - | ExcalidrawEmbeddableElement; + | ExcalidrawEmbeddableElement + | ExcalidrawBlurElement; export type ExcalidrawNonSelectionElement = Exclude< ExcalidrawElement, diff --git a/packages/excalidraw/actions/actionAlign.tsx b/packages/excalidraw/actions/actionAlign.tsx index 46023d61e..3226cc815 100644 --- a/packages/excalidraw/actions/actionAlign.tsx +++ b/packages/excalidraw/actions/actionAlign.tsx @@ -8,6 +8,8 @@ import { KEYS, arrayToMap, getShortcutKey } from "@excalidraw/common"; import { alignElements } from "@excalidraw/element/align"; +import { useContext } from "react"; + import type { ExcalidrawElement } from "@excalidraw/element/types"; import type { Alignment } from "@excalidraw/element/align"; @@ -27,9 +29,14 @@ import { t } from "../i18n"; import { isSomeElementSelected } from "../scene"; import { CaptureUpdateAction } from "../store"; -import { register } from "./register"; +import { + ExcalidrawPropsCustomOptionsContext, + type AppClassProperties, + type AppState, + type UIAppState, +} from "../types"; -import type { AppClassProperties, AppState, UIAppState } from "../types"; +import { register } from "./register"; export const alignActionsPredicate = ( appState: UIAppState, @@ -87,19 +94,40 @@ export const actionAlignTop = register({ }, keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.shiftKey && event.key === KEYS.ARROW_UP, - PanelComponent: ({ elements, appState, updateData, app }) => ( -