diff --git a/package-lock.json b/package-lock.json index bc89f1f..7dcc50e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "react": "^18.2", "react-dom": "^18.2", "slugify": "^1.6", - "svg-path-commander": "^2.0" + "svg-path-parser": "^1.1" }, "devDependencies": { "@figma/eslint-plugin-figma-plugins": "^0.15", @@ -20,6 +20,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.3", "@types/react": "^18.2", "@types/react-dom": "^18.2", + "@types/svg-path-parser": "^1.1", "@typescript-eslint/eslint-plugin": "^7.5", "@typescript-eslint/parser": "^7.5", "@vitejs/plugin-react-swc": "^3.6", @@ -2014,11 +2015,6 @@ "@swc/counter": "^0.1.3" } }, - "node_modules/@thednp/dommatrix": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@thednp/dommatrix/-/dommatrix-2.0.6.tgz", - "integrity": "sha512-DXQq4Rs/akYzeXYGkNy3KiJ4JoD8+SYr1QRWTXtAGoZ0+vJcyBt0aeqA1K4CxPaBaIfKdOTE+Te1HV9sAQ4I4A==" - }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.0.tgz", @@ -2085,6 +2081,12 @@ "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, + "node_modules/@types/svg-path-parser": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@types/svg-path-parser/-/svg-path-parser-1.1.6.tgz", + "integrity": "sha512-3sw6pk91pEtW6W7hRrJ9ZkAgPiJSaNdh7iY8rVOy7buajpQuy2J9A0ZUaiOVcbFvl0p7J+Ne4012muCE/MB+hQ==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz", @@ -6488,17 +6490,10 @@ "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", "dev": true }, - "node_modules/svg-path-commander": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/svg-path-commander/-/svg-path-commander-2.0.9.tgz", - "integrity": "sha512-VfRLznHewlpQvuahtBK0MT/PlWAapbTx8RSytqgaVwD3US2keKcc3WYYlBBk4vIOR+jB3nQu/NAVlWHKlo0Fjw==", - "dependencies": { - "@thednp/dommatrix": "^2.0.6" - }, - "engines": { - "node": ">=16", - "pnpm": ">=8.6.0" - } + "node_modules/svg-path-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/svg-path-parser/-/svg-path-parser-1.1.0.tgz", + "integrity": "sha512-jGCUqcQyXpfe38R7RFfhrMyfXcBmpMNJI/B+4CE9/Unkh98UporAc461GTthv+TVDuZXsBx7/WiwJb1Oh4tt4A==" }, "node_modules/svg-tags": { "version": "1.0.0", diff --git a/package.json b/package.json index 49f6e47..e378efb 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "react": "^18.2", "react-dom": "^18.2", "slugify": "^1.6", - "svg-path-commander": "^2.0" + "svg-path-parser": "^1.1" }, "devDependencies": { "@figma/eslint-plugin-figma-plugins": "^0.15", @@ -36,6 +36,7 @@ "@types/react-dom": "^18.2", "@typescript-eslint/eslint-plugin": "^7.5", "@typescript-eslint/parser": "^7.5", + "@types/svg-path-parser": "^1.1", "@vitejs/plugin-react-swc": "^3.6", "concurrently": "^8.2", "esbuild": "^0.20", diff --git a/plugin-src/translators/translateVectorPaths.ts b/plugin-src/translators/translateVectorPaths.ts index 5579f10..f24a411 100644 --- a/plugin-src/translators/translateVectorPaths.ts +++ b/plugin-src/translators/translateVectorPaths.ts @@ -1,4 +1,4 @@ -import SVGPathCommander from 'svg-path-commander'; +import { CurveToCommand, LineToCommand, MoveToCommand, parseSVG } from 'svg-path-parser'; import { Segment } from '@ui/lib/types/path/PathContent'; @@ -17,44 +17,53 @@ export const translateVectorPaths = ( }; const translateVectorPath = (path: VectorPath, baseX: number, baseY: number): Segment[] => { - const segments: Segment[] = []; + const normalizedPaths = parseSVG(path.data); - const normalizedPath = SVGPathCommander.normalizePath(path.data); - - for (const [command, ...rest] of normalizedPath) { - switch (command) { - case 'M': - segments.push({ - command: 'move-to', - params: { x: (rest[0] ?? 0) + baseX, y: (rest[1] ?? 0) + baseY } - }); - break; - case 'L': - segments.push({ - command: 'line-to', - params: { x: (rest[0] ?? 0) + baseX, y: (rest[1] ?? 0) + baseY } - }); - break; - case 'C': - segments.push({ - command: 'curve-to', - params: { - c1x: (rest[0] ?? 0) + baseX, - c1y: (rest[1] ?? 0) + baseY, - c2x: (rest[2] ?? 0) + baseX, - c2y: (rest[3] ?? 0) + baseY, - x: (rest[4] ?? 0) + baseX, - y: (rest[5] ?? 0) + baseY - } - }); - break; - case 'Z': - segments.push({ + return normalizedPaths.map(command => { + switch (command.command) { + case 'moveto': + return translateMoveToCommand(command, baseX, baseY); + case 'lineto': + return translateLineToCommand(command, baseX, baseY); + case 'curveto': + return translateCurveToCommand(command, baseX, baseY); + case 'closepath': + default: + return { command: 'close-path' - }); - break; + }; } - } - - return segments; + }); +}; + +const translateMoveToCommand = (command: MoveToCommand, baseX: number, baseY: number): Segment => { + return { + command: 'move-to', + params: { x: command.x + baseX, y: command.y + baseY } + }; +}; + +const translateLineToCommand = (command: LineToCommand, baseX: number, baseY: number): Segment => { + return { + command: 'line-to', + params: { x: command.x + baseX, y: command.y + baseY } + }; +}; + +const translateCurveToCommand = ( + command: CurveToCommand, + baseX: number, + baseY: number +): Segment => { + return { + command: 'curve-to', + params: { + c1x: command.x1 + baseX, + c1y: command.y1 + baseY, + c2x: command.x2 + baseX, + c2y: command.y2 + baseY, + x: command.x + baseX, + y: command.y + baseY + } + }; };