From 4d7d96eb7b444f60bb0bb2ce1aedaf047d1df8cb Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Wed, 14 Jun 2023 17:26:29 +0530 Subject: [PATCH] feat: add canvas-roundrect-polyfill package (#6675) * feat: add canvas-roundrect-polyfill instead of maintaining a copy of it and transplile it since its not transpiled in the package * transform canvas-roundrect-polyfill in jest --- package.json | 3 +- src/packages/excalidraw/webpack.dev.config.js | 3 +- .../excalidraw/webpack.prod.config.js | 4 +- src/renderer/renderScene.ts | 2 +- src/renderer/roundRect.polyfill.ts | 356 ------------------ yarn.lock | 5 + 6 files changed, 13 insertions(+), 360 deletions(-) delete mode 100644 src/renderer/roundRect.polyfill.ts diff --git a/package.json b/package.json index b5432d37..584bdcbc 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@testing-library/react": "12.1.5", "@tldraw/vec": "1.7.1", "browser-fs-access": "0.29.1", + "canvas-roundrect-polyfill": "0.0.1", "clsx": "1.1.1", "cross-env": "7.0.3", "fake-indexeddb": "3.1.7", @@ -107,7 +108,7 @@ "/src/packages/excalidraw/example" ], "transformIgnorePatterns": [ - "node_modules/(?!(roughjs|points-on-curve|path-data-parser|points-on-path|browser-fs-access)/)" + "node_modules/(?!(roughjs|points-on-curve|path-data-parser|points-on-path|browser-fs-access|canvas-roundrect-polyfill)/)" ], "resetMocks": false }, diff --git a/src/packages/excalidraw/webpack.dev.config.js b/src/packages/excalidraw/webpack.dev.config.js index 9e8180f5..e16d8da7 100644 --- a/src/packages/excalidraw/webpack.dev.config.js +++ b/src/packages/excalidraw/webpack.dev.config.js @@ -44,7 +44,8 @@ module.exports = { }, { test: /\.(ts|tsx|js|jsx|mjs)$/, - exclude: /node_modules\/(?!browser-fs-access)/, + exclude: + /node_modules\/(?!(browser-fs-access|canvas-roundrect-polyfill))/, use: [ { loader: "ts-loader", diff --git a/src/packages/excalidraw/webpack.prod.config.js b/src/packages/excalidraw/webpack.prod.config.js index 0450d36f..0a1e6361 100644 --- a/src/packages/excalidraw/webpack.prod.config.js +++ b/src/packages/excalidraw/webpack.prod.config.js @@ -46,7 +46,9 @@ module.exports = { }, { test: /\.(ts|tsx|js|jsx|mjs)$/, - exclude: /node_modules\/(?!browser-fs-access)/, + exclude: + /node_modules\/(?!(browser-fs-access|canvas-roundrect-polyfill))/, + use: [ { loader: "ts-loader", diff --git a/src/renderer/renderScene.ts b/src/renderer/renderScene.ts index 85e9eab1..16ca3eb1 100644 --- a/src/renderer/renderScene.ts +++ b/src/renderer/renderScene.ts @@ -56,7 +56,7 @@ import { getLinkHandleFromCoords, } from "../element/Hyperlink"; import { isLinearElement } from "../element/typeChecks"; -import "./roundRect.polyfill"; +import "canvas-roundrect-polyfill"; export const DEFAULT_SPACING = 2; diff --git a/src/renderer/roundRect.polyfill.ts b/src/renderer/roundRect.polyfill.ts deleted file mode 100644 index 10946a46..00000000 --- a/src/renderer/roundRect.polyfill.ts +++ /dev/null @@ -1,356 +0,0 @@ -// @ts-nocheck - -// source: https://github.com/Kaiido/roundRect/ -// rewritten to remove globalThis and Nullish coalescing assignment operator - -export {}; - -/* - * Implements the .roundRect() method of the CanvasPath mixin - * as introduced by https://github.com/whatwg/html/pull/6765 - */ -(() => { - Path2D.prototype.roundRect ??= roundRect; - if ( - typeof window !== "undefined" && - window.CanvasRenderingContext2D && - !window.CanvasRenderingContext2D.prototype.roundRect - ) { - window.CanvasRenderingContext2D.prototype.roundRect = roundRect; - } - if ( - typeof window !== "undefined" && - window.OffscreenCanvasRenderingContext2D && - !window.OffscreenCanvasRenderingContext2D.prototype.roundRect - ) { - window.OffscreenCanvasRenderingContext2D.prototype.roundRect = roundRect; - } - - function roundRect(x, y, w, h, radii) { - if (![x, y, w, h].every((input) => Number.isFinite(input))) { - return; - } - - radii = parseRadiiArgument(radii); - - let upperLeft; - let upperRight; - let lowerRight; - let lowerLeft; - - if (radii.length === 4) { - upperLeft = toCornerPoint(radii[0]); - upperRight = toCornerPoint(radii[1]); - lowerRight = toCornerPoint(radii[2]); - lowerLeft = toCornerPoint(radii[3]); - } else if (radii.length === 3) { - upperLeft = toCornerPoint(radii[0]); - upperRight = toCornerPoint(radii[1]); - lowerLeft = toCornerPoint(radii[1]); - lowerRight = toCornerPoint(radii[2]); - } else if (radii.length === 2) { - upperLeft = toCornerPoint(radii[0]); - lowerRight = toCornerPoint(radii[0]); - upperRight = toCornerPoint(radii[1]); - lowerLeft = toCornerPoint(radii[1]); - } else if (radii.length === 1) { - upperLeft = toCornerPoint(radii[0]); - upperRight = toCornerPoint(radii[0]); - lowerRight = toCornerPoint(radii[0]); - lowerLeft = toCornerPoint(radii[0]); - } else { - throw new RangeError( - `${getErrorMessageHeader(this)} ${ - radii.length - } is not a valid size for radii sequence.`, - ); - } - - const corners = [upperLeft, upperRight, lowerRight, lowerLeft]; - const negativeCorner = corners.find(({ x, y }) => x < 0 || y < 0); - - if ( - corners.some(({ x, y }) => !Number.isFinite(x) || !Number.isFinite(y)) - ) { - return; - } - - if (negativeCorner) { - throw new RangeError( - `${getErrorMessageHeader( - this, - )} Radius value ${negativeCorner} is negative.`, - ); - } - - fixOverlappingCorners(corners); - - if (w < 0 && h < 0) { - this.moveTo(x - upperLeft.x, y); - this.ellipse( - x + w + upperRight.x, - y - upperRight.y, - upperRight.x, - upperRight.y, - 0, - -Math.PI * 1.5, - -Math.PI, - ); - this.ellipse( - x + w + lowerRight.x, - y + h + lowerRight.y, - lowerRight.x, - lowerRight.y, - 0, - -Math.PI, - -Math.PI / 2, - ); - this.ellipse( - x - lowerLeft.x, - y + h + lowerLeft.y, - lowerLeft.x, - lowerLeft.y, - 0, - -Math.PI / 2, - 0, - ); - this.ellipse( - x - upperLeft.x, - y - upperLeft.y, - upperLeft.x, - upperLeft.y, - 0, - 0, - -Math.PI / 2, - ); - } else if (w < 0) { - this.moveTo(x - upperLeft.x, y); - this.ellipse( - x + w + upperRight.x, - y + upperRight.y, - upperRight.x, - upperRight.y, - 0, - -Math.PI / 2, - -Math.PI, - 1, - ); - this.ellipse( - x + w + lowerRight.x, - y + h - lowerRight.y, - lowerRight.x, - lowerRight.y, - 0, - -Math.PI, - -Math.PI * 1.5, - 1, - ); - this.ellipse( - x - lowerLeft.x, - y + h - lowerLeft.y, - lowerLeft.x, - lowerLeft.y, - 0, - Math.PI / 2, - 0, - 1, - ); - this.ellipse( - x - upperLeft.x, - y + upperLeft.y, - upperLeft.x, - upperLeft.y, - 0, - 0, - -Math.PI / 2, - 1, - ); - } else if (h < 0) { - this.moveTo(x + upperLeft.x, y); - this.ellipse( - x + w - upperRight.x, - y - upperRight.y, - upperRight.x, - upperRight.y, - 0, - Math.PI / 2, - 0, - 1, - ); - this.ellipse( - x + w - lowerRight.x, - y + h + lowerRight.y, - lowerRight.x, - lowerRight.y, - 0, - 0, - -Math.PI / 2, - 1, - ); - this.ellipse( - x + lowerLeft.x, - y + h + lowerLeft.y, - lowerLeft.x, - lowerLeft.y, - 0, - -Math.PI / 2, - -Math.PI, - 1, - ); - this.ellipse( - x + upperLeft.x, - y - upperLeft.y, - upperLeft.x, - upperLeft.y, - 0, - -Math.PI, - -Math.PI * 1.5, - 1, - ); - } else { - this.moveTo(x + upperLeft.x, y); - this.ellipse( - x + w - upperRight.x, - y + upperRight.y, - upperRight.x, - upperRight.y, - 0, - -Math.PI / 2, - 0, - ); - this.ellipse( - x + w - lowerRight.x, - y + h - lowerRight.y, - lowerRight.x, - lowerRight.y, - 0, - 0, - Math.PI / 2, - ); - this.ellipse( - x + lowerLeft.x, - y + h - lowerLeft.y, - lowerLeft.x, - lowerLeft.y, - 0, - Math.PI / 2, - Math.PI, - ); - this.ellipse( - x + upperLeft.x, - y + upperLeft.y, - upperLeft.x, - upperLeft.y, - 0, - Math.PI, - Math.PI * 1.5, - ); - } - - this.closePath(); - this.moveTo(x, y); - - function toDOMPointInit(value) { - const { x, y, z, w } = value; - return { x, y, z, w }; - } - - function parseRadiiArgument(value) { - // https://webidl.spec.whatwg.org/#es-union - // with 'optional (unrestricted double or DOMPointInit - // or sequence<(unrestricted double or DOMPointInit)>) radii = 0' - const type = typeof value; - - if (type === "undefined" || value === null) { - return [0]; - } - if (type === "function") { - return [NaN]; - } - if (type === "object") { - if (typeof value[Symbol.iterator] === "function") { - return [...value].map((elem) => { - // https://webidl.spec.whatwg.org/#es-union - // with '(unrestricted double or DOMPointInit)' - const elemType = typeof elem; - if (elemType === "undefined" || elem === null) { - return 0; - } - if (elemType === "function") { - return NaN; - } - if (elemType === "object") { - return toDOMPointInit(elem); - } - return toUnrestrictedNumber(elem); - }); - } - - return [toDOMPointInit(value)]; - } - - return [toUnrestrictedNumber(value)]; - } - - function toUnrestrictedNumber(value) { - return +value; - } - - function toCornerPoint(value) { - const asNumber = toUnrestrictedNumber(value); - if (Number.isFinite(asNumber)) { - return { - x: asNumber, - y: asNumber, - }; - } - if (Object(value) === value) { - return { - x: toUnrestrictedNumber(value.x ?? 0), - y: toUnrestrictedNumber(value.y ?? 0), - }; - } - - return { - x: NaN, - y: NaN, - }; - } - - function fixOverlappingCorners(corners) { - const [upperLeft, upperRight, lowerRight, lowerLeft] = corners; - const factors = [ - Math.abs(w) / (upperLeft.x + upperRight.x), - Math.abs(h) / (upperRight.y + lowerRight.y), - Math.abs(w) / (lowerRight.x + lowerLeft.x), - Math.abs(h) / (upperLeft.y + lowerLeft.y), - ]; - const minFactor = Math.min(...factors); - if (minFactor <= 1) { - for (const radii of corners) { - radii.x *= minFactor; - radii.y *= minFactor; - } - } - } - } - - function getErrorMessageHeader(instance) { - return `Failed to execute 'roundRect' on '${getConstructorName( - instance, - )}':`; - } - - function getConstructorName(instance) { - if (typeof window === "undefined") { - return "UNKNOWN"; - } - return Object(instance) === instance && instance instanceof Path2D - ? "Path2D" - : instance instanceof window?.CanvasRenderingContext2D - ? "CanvasRenderingContext2D" - : instance instanceof window?.OffscreenCanvasRenderingContext2D - ? "OffscreenCanvasRenderingContext2D" - : instance?.constructor.name || instance; - } -})(); diff --git a/yarn.lock b/yarn.lock index 7d385cce..2e3c1ea8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3830,6 +3830,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001478.tgz#0ef8a1cf8b16be47a0f9fc4ecfc952232724b32a" integrity sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw== +canvas-roundrect-polyfill@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/canvas-roundrect-polyfill/-/canvas-roundrect-polyfill-0.0.1.tgz#70bf107ebe2037f26d839d7f809a26f4a95f5696" + integrity sha512-yWq+R3U3jE+coOeEb3a3GgE2j/0MMiDKM/QpLb6h9ihf5fGY9UXtvK9o4vNqjWXoZz7/3EaSVU3IX53TvFFUOw== + case-sensitive-paths-webpack-plugin@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"