diff --git a/.gitea/workflows/verify.yml b/.gitea/workflows/verify.yml new file mode 100644 index 0000000..b84a7cb --- /dev/null +++ b/.gitea/workflows/verify.yml @@ -0,0 +1,39 @@ +name: Verify + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +concurrency: + group: verify-${{ gitea.repository }}-${{ gitea.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + verify: + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + CI: "true" + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "22" + cache: npm + - name: Select declared npm version + run: npm install --global npm@11.17.0 + - name: Install dependencies + run: npm ci + - name: Audit runtime dependencies + run: npm audit --omit=dev --audit-level=moderate + - name: Check, test, and build + run: npm run check + - name: Install browser engines + run: npx playwright install --with-deps chromium firefox webkit + - name: Browser tests + run: npm run test:browser diff --git a/CHANGELOG.md b/CHANGELOG.md index 73928ba..c888bd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,19 @@ All notable changes follow Keep a Changelog. Versions follow Semantic Versioning. -## [Unreleased] +## [0.2.0] - 2026-09-02 + +### Added + +- Added source-fidelity duplicate and delete operations for safe, ID-free + subtrees, with reference guards and undo/redo integration. +- Declared SVG/project input, SVG/SVGZ/raster/project export and optional worker + capability profiles for Toolbox handoff. + +### Security + +- Updated DOMPurify to 3.4.14 so the sanitized SVG projection includes the + upstream namespace-confusion fix tracked as GHSA-55q2-fjhq-7xh7. ### Documentation @@ -26,4 +38,5 @@ Versioning. - Deterministic standalone release packaging and Toolbox Portal assembly smoke test. +[0.2.0]: https://git.add-ideas.de/lotobo/svg-tools/releases/tag/v0.2.0 [0.1.0]: https://git.add-ideas.de/lotobo/svg-tools/releases/tag/v0.1.0 diff --git a/README.md b/README.md index fcb86f6..54e8f0c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ editing projection, a canvas overlay and inspectors from that source. Files are processed in the browser; the app has no backend, upload endpoint, telemetry or runtime CDN dependency. -Version 0.1.0 delivers the structured viewer/editor milestone (MVP 1) and +Version 0.2.0 delivers the structured viewer/editor milestone (MVP 1) and tested vertical slices of the path, transform, reference, optimization, security, accessibility, animation and export milestones. The later milestone lists below remain a roadmap, not a claim of complete vector-editor coverage. @@ -26,7 +26,7 @@ lists below remain a roadmap, not a claim of complete vector-editor coverage. - No editor namespace or persistent editor attribute is added to normal SVG exports. -## Implemented in 0.1.0 +## Implemented in 0.2.0 - open, drop and paste SVG; magic-byte SVGZ import; new-document templates; - XML editor, ranged diagnostics, structure tree, filtering and synchronized @@ -34,6 +34,8 @@ lists below remain a roadmap, not a claim of complete vector-editor coverage. - safe canvas, zoom, pan, grid, selected bounds and last-valid state; - document dimensions, `viewBox`, `preserveAspectRatio`, arbitrary attributes, fill, stroke, opacity, rotate, flip, translate, scale and skew; +- undoable subtree duplicate/delete for ID-free nodes, with duplicate-ID and + external-reference guards rather than silently breaking the document; - exact undo/redo and explicit source-diff previews; - parsing of `M L H V C S Q T A Z`, absolute/relative and repeated groups; - anchors, cubic and quadratic controls, derived smooth controls, arc controls, @@ -69,7 +71,7 @@ derived control intentionally expands shorthand to explicit normalized geometry. Visual path edits currently serialize the selected `d` attribute in normalized absolute form; surrounding source is untouched. -Not yet implemented: multi-node modes, delete/convert/join/break/combine, +Not yet implemented: multi-node modes, path join/break/combine, subpath-start changes, a pen tool, snapping, simplification, boolean operations, round corners and stroke-to-path. diff --git a/SOURCE.md b/SOURCE.md index f8393c0..4d1c660 100644 --- a/SOURCE.md +++ b/SOURCE.md @@ -1,8 +1,8 @@ # Corresponding source and provenance -The corresponding source for SVG Tools 0.1.0 is: +The corresponding source for SVG Tools 0.2.0 is: -https://git.add-ideas.de/lotobo/svg-tools/src/tag/v0.1.0 +https://git.add-ideas.de/lotobo/svg-tools/src/tag/v0.2.0 Build from that tag with Node.js 22 and the exact `package-lock.json`: @@ -17,20 +17,20 @@ dependency inventory and notices. ## Revisions inspected -| Project | Revision/version inspected | Decision | -| ------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -| SVG Tools | empty public `lotobo/svg-tools` repository before this initial commit | implemented here | -| Toolbox SDK/contract/AppShell/testkit | `ef2dab4b46c61812c9a877d8a19fe497b4a4630a`, packages 0.2.3 | adopted | -| Toolbox Portal | `55b2b12434465511586eaa2d0a43e81770868738`, tag v0.9.3 | release/UX contract reference; Portal 0.10.0 integrates the artifact | -| SVG-Edit | `244a26c88e1ab1c32911c5b3637e214d7a7d8b25` | interaction/implementation reference only; no source copied | -| SVG Path Editor | `937d75a83b6be2bdda11d02b9b3594841315223a` | path interaction reference only; no source copied | -| SVGPathCommander | `9aa91dd2119ee6a65b1807d55d33e86b1ccb27fc` | inspected, not adopted; project-authored path core is smaller and source-ranged | -| SVGO | npm 4.0.2, published `gitHead` `b2309cf541aee11634eb653157b0ff86ab326e98` | adopted in a worker; GitHub clone was not required for shipped bytes | -| DOMPurify | `9365501773d6665aaf334d8afa55081b9930a684`, npm 3.4.12 | adopted as one layer of the projection policy | -| css-tree | npm 3.2.1 | adopted for parsed CSS policy/value checks | -| Boolean/geometry engine | none | not adopted; boolean operations are not claimed | -| Raster engine | browser SVG image decoder and Canvas 2D | no third-party raster engine shipped | -| Compression fallback | fflate 0.8.3 | adopted for bounded SVGZ read/write | +| Project | Revision/version inspected | Decision | +| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | +| SVG Tools | empty public `lotobo/svg-tools` repository before this initial commit | implemented here | +| Toolbox SDK/contract/AppShell/testkit | `bc91659a424aaaadc88fff3a98a2cc2412237386`, packages 0.3.0 | adopted | +| Toolbox Portal | `55b2b12434465511586eaa2d0a43e81770868738`, tag v0.9.3 | release/UX contract reference; Portal 0.10.0 integrates the artifact | +| SVG-Edit | `244a26c88e1ab1c32911c5b3637e214d7a7d8b25` | interaction/implementation reference only; no source copied | +| SVG Path Editor | `937d75a83b6be2bdda11d02b9b3594841315223a` | path interaction reference only; no source copied | +| SVGPathCommander | `9aa91dd2119ee6a65b1807d55d33e86b1ccb27fc` | inspected, not adopted; project-authored path core is smaller and source-ranged | +| SVGO | npm 4.0.2, published `gitHead` `b2309cf541aee11634eb653157b0ff86ab326e98` | adopted in a worker; GitHub clone was not required for shipped bytes | +| DOMPurify | npm 3.4.14, lockfile integrity `sha512-dVoH9z+MY+C9IilgGCk3YfFqjLi3fChm2OiKJMzh6axrJ5qwxqWaZamgmHrpv22CN/KdbZJuGEGgfQoL00LTdg==` | adopted as one layer of the projection policy | +| css-tree | npm 3.2.1 | adopted for parsed CSS policy/value checks | +| Boolean/geometry engine | none | not adopted; boolean operations are not claimed | +| Raster engine | browser SVG image decoder and Canvas 2D | no third-party raster engine shipped | +| Compression fallback | fflate 0.8.3 | adopted for bounded SVGZ read/write | Boxy SVG and SVGViewer were consulted only as public product references. Their source, assets, branding, layout and text were not copied. All test SVG strings diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 801f79d..c0fdf8e 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -14,8 +14,8 @@ the packages. | Project | Version | Licence | Role | Source | | ----------------------- | ------- | --------------------- | -------------------------------------------------------- | ------------------------------------------------- | -| Toolbox contract | 0.2.3 | Apache-2.0 | manifest/context types | https://git.add-ideas.de/lotobo/toolbox-sdk | -| Toolbox shell React | 0.2.3 | Apache-2.0 | shared app shell/theme/help/source actions | https://git.add-ideas.de/lotobo/toolbox-sdk | +| Toolbox contract | 0.3.0 | Apache-2.0 | manifest/context types | https://git.add-ideas.de/lotobo/toolbox-sdk | +| Toolbox shell React | 0.3.0 | Apache-2.0 | shared app shell/theme/help/source actions | https://git.add-ideas.de/lotobo/toolbox-sdk | | CodeMirror commands | 6.10.4 | MIT | editor commands/keymap | https://code.haverbeke.berlin/codemirror/commands | | CodeMirror XML language | 6.1.0 | MIT | XML language support | https://github.com/codemirror/lang-xml | | CodeMirror language | 6.12.4 | MIT | highlighting/folding | https://code.haverbeke.berlin/codemirror/language | @@ -24,7 +24,7 @@ the packages. | CodeMirror view | 6.43.6 | MIT | source editor UI | https://code.haverbeke.berlin/codemirror/view | | Lezer XML | 1.0.6 | MIT | ranged XML syntax diagnostics | https://github.com/lezer-parser/xml | | css-tree | 3.2.1 | MIT | parsed CSS security and animation-value checks | https://github.com/csstree/csstree | -| DOMPurify | 3.4.12 | MPL-2.0 OR Apache-2.0 | first sanitization layer | https://github.com/cure53/DOMPurify | +| DOMPurify | 3.4.14 | MPL-2.0 OR Apache-2.0 | first sanitization layer | https://github.com/cure53/DOMPurify | | fflate | 0.8.3 | MIT | bounded SVGZ decompression and deterministic compression | https://github.com/101arrowz/fflate | | React | 19.2.6 | MIT | application UI | https://github.com/facebook/react | | React DOM | 19.2.6 | MIT | browser rendering | https://github.com/facebook/react | @@ -67,7 +67,7 @@ as runtime modules in the release ZIP. | Package | Version | Licence | | ----------------------------- | ------- | ---------- | -| `@add-ideas/toolbox-testkit` | 0.2.3 | Apache-2.0 | +| `@add-ideas/toolbox-testkit` | 0.3.0 | Apache-2.0 | | `@eslint/js` | 10.0.1 | MIT | | `@playwright/test` | 1.61.1 | Apache-2.0 | | `@testing-library/jest-dom` | 6.9.1 | MIT | diff --git a/docs/REFERENCE_IMPLEMENTATIONS.md b/docs/REFERENCE_IMPLEMENTATIONS.md index bf73855..8e1973d 100644 --- a/docs/REFERENCE_IMPLEMENTATIONS.md +++ b/docs/REFERENCE_IMPLEMENTATIONS.md @@ -7,12 +7,12 @@ path, transform, security and test code is project-authored. | Reference | Exact revision/version | Licence | Purpose and decision | | ---------------- | ------------------------------------------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Toolbox SDK | `ef2dab4b46c61812c9a877d8a19fe497b4a4630a` / packages 0.2.3 | Apache-2.0 | Adopted through its published contract, AppShell and testkit APIs. | +| Toolbox SDK | `bc91659a424aaaadc88fff3a98a2cc2412237386` / packages 0.3.0 | Apache-2.0 | Adopted through its published contract, AppShell and testkit APIs. | | Toolbox Portal | `55b2b12434465511586eaa2d0a43e81770868738` (v0.9.3 before integration) | AGPL-3.0-only | Studied for release assembly, nested deployment, catalogue and shell conventions. SVG Tools is consumed only as an immutable release artifact. | | SVG-Edit | `244a26c88e1ab1c32911c5b3637e214d7a7d8b25` | MIT | Interaction and implementation reference only. Its canvas/document model was not adopted because canonical SVG source must remain authoritative. | | SVG Path Editor | `937d75a83b6be2bdda11d02b9b3594841315223a` | MIT | Path interaction reference only. Its source was not copied; SVG Tools uses its own source-ranged path model. | | SVGPathCommander | `9aa91dd2119ee6a65b1807d55d33e86b1ccb27fc` | MIT | Evaluated for parsing and geometry, then not shipped. The initial project-authored core is smaller and retains source-command fragments. | -| DOMPurify | `9365501773d6665aaf334d8afa55081b9930a684` / npm 3.4.12 | MPL-2.0 OR Apache-2.0 | Adopted as the first projection-sanitization layer, followed by application-owned SVG, URL and parsed-CSS policy checks. | +| DOMPurify | npm 3.4.14 / lockfile-pinned tarball integrity | MPL-2.0 OR Apache-2.0 | Adopted as the first projection-sanitization layer, followed by application-owned SVG, URL and parsed-CSS policy checks. | | SVGO | npm 4.0.2, published `gitHead` `b2309cf541aee11634eb653157b0ff86ab326e98` | MIT | Adopted behind a cancelable application worker. Direct GitHub cloning was unavailable in the build environment, so the exact locked npm source identity is recorded. | | css-tree | npm 3.2.1 | MIT | Adopted for stylesheet, declaration and animation-value parsing. | | fflate | npm 0.8.3 | MIT | Adopted for deterministic SVGZ output and bounded streaming decompression. | diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 8830dfc..d2de4b6 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -73,6 +73,10 @@ and DOMPurify remain dependency/security boundaries. Bounded data URLs may still decode expensive images within the raster-pixel limits. CSP header regressions can break the fixed controller even when the content remains inert. +DOMPurify is pinned in the lockfile and its SVG policy is covered by the +project-authored adversarial suite. Dependency updates must run both +`npm run test:security` and the browser tests before release. + Report vulnerabilities privately through the repository owner/contact before opening a public issue when disclosure could expose users. Include the SVG, browser, deployment headers and observed network/execution behavior without diff --git a/package-lock.json b/package-lock.json index 5f96238..fcc267c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "svg-tools", - "version": "0.1.0", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "svg-tools", - "version": "0.1.0", + "version": "0.2.0", "license": "GPL-3.0-or-later", "dependencies": { - "@add-ideas/toolbox-contract": "0.2.3", - "@add-ideas/toolbox-shell-react": "0.2.3", + "@add-ideas/toolbox-contract": "0.3.0", + "@add-ideas/toolbox-shell-react": "0.3.0", "@codemirror/commands": "6.10.4", "@codemirror/lang-xml": "6.1.0", "@codemirror/language": "6.12.4", @@ -19,14 +19,14 @@ "@codemirror/view": "6.43.6", "@lezer/xml": "1.0.6", "css-tree": "3.2.1", - "dompurify": "3.4.12", + "dompurify": "3.4.14", "fflate": "0.8.3", "react": "19.2.6", "react-dom": "19.2.6", "svgo": "4.0.2" }, "devDependencies": { - "@add-ideas/toolbox-testkit": "0.2.3", + "@add-ideas/toolbox-testkit": "0.3.0", "@eslint/js": "10.0.1", "@playwright/test": "1.61.1", "@testing-library/jest-dom": "6.9.1", @@ -54,18 +54,18 @@ } }, "node_modules/@add-ideas/toolbox-contract": { - "version": "0.2.3", - "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-contract/-/0.2.3/toolbox-contract-0.2.3.tgz", - "integrity": "sha512-T0PVSuMT40GjTDfQJhEEY3ZawQq8zz1/ry95JdKI6W39CdLacaRXdGnEpDCMHt+jUbf1Jz7Nat/M5dFCgKVM9A==", + "version": "0.3.0", + "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-contract/-/0.3.0/toolbox-contract-0.3.0.tgz", + "integrity": "sha512-dKrK7BjOFwqJaBfJuhKxZKIld4sH0AKjEn6a0yLnbdMUFY+fFv4VSLGV2tNSBD016gumc2iNqOjUj/ld7x4rtA==", "license": "Apache-2.0" }, "node_modules/@add-ideas/toolbox-shell-react": { - "version": "0.2.3", - "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-shell-react/-/0.2.3/toolbox-shell-react-0.2.3.tgz", - "integrity": "sha512-DT5lQDH48BFkFcmFLZnQh7+Cm73JzBPcmp5WzUXypfkUXpEyDYHzaXgmW4kZ0edSwh4RK4sPmx+JPtK0X4aKCQ==", + "version": "0.3.0", + "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-shell-react/-/0.3.0/toolbox-shell-react-0.3.0.tgz", + "integrity": "sha512-74p6JzAOG0YCAKdlc1hLofV4ZIko7vb448S75cIiM88PKm93EHl5VD7g8YVyfM56Ui97UY9dmy+Whiq4sGzpsg==", "license": "Apache-2.0", "dependencies": { - "@add-ideas/toolbox-contract": "0.2.3" + "@add-ideas/toolbox-contract": "0.3.0" }, "peerDependencies": { "react": ">=18 <20", @@ -73,13 +73,13 @@ } }, "node_modules/@add-ideas/toolbox-testkit": { - "version": "0.2.3", - "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-testkit/-/0.2.3/toolbox-testkit-0.2.3.tgz", - "integrity": "sha512-sq1MwhKWfFKen+N+124hl74qQimRSvmQ9sOU7jdcI+2qCKZ67+2B8rWyezeV80uTFu4Jv6deHksfYQ/tKNV6XQ==", + "version": "0.3.0", + "resolved": "https://git.add-ideas.de/api/packages/lotobo/npm/%40add-ideas%2Ftoolbox-testkit/-/0.3.0/toolbox-testkit-0.3.0.tgz", + "integrity": "sha512-4Fk+oSvZFspOMIXr8Xy040nhAaBsIQAzsGyXWSpjn3+k3yBKq7nB1r5zCHhsXzfdLzvPDAx2KcmSNOhM330D9w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@add-ideas/toolbox-contract": "0.2.3" + "@add-ideas/toolbox-contract": "0.3.0" }, "bin": { "toolbox-check": "dist/cli.js" @@ -2330,9 +2330,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.12", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.12.tgz", - "integrity": "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==", + "version": "3.4.14", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.14.tgz", + "integrity": "sha512-dVoH9z+MY+C9IilgGCk3YfFqjLi3fChm2OiKJMzh6axrJ5qwxqWaZamgmHrpv22CN/KdbZJuGEGgfQoL00LTdg==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" diff --git a/package.json b/package.json index 3fbae97..b823d64 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svg-tools", - "version": "0.1.0", + "version": "0.2.0", "description": "Inspect, edit, optimize and transform SVG documents locally in the browser.", "license": "GPL-3.0-or-later", "author": "Albrecht Degering", @@ -41,8 +41,8 @@ "release:artifact": "npm run check && npm run test:security && npm run test:browser && npm run package:release -- --force && npm run portal:smoke" }, "dependencies": { - "@add-ideas/toolbox-contract": "0.2.3", - "@add-ideas/toolbox-shell-react": "0.2.3", + "@add-ideas/toolbox-contract": "0.3.0", + "@add-ideas/toolbox-shell-react": "0.3.0", "@codemirror/commands": "6.10.4", "@codemirror/lang-xml": "6.1.0", "@codemirror/language": "6.12.4", @@ -51,14 +51,14 @@ "@codemirror/view": "6.43.6", "@lezer/xml": "1.0.6", "css-tree": "3.2.1", - "dompurify": "3.4.12", + "dompurify": "3.4.14", "fflate": "0.8.3", "react": "19.2.6", "react-dom": "19.2.6", "svgo": "4.0.2" }, "devDependencies": { - "@add-ideas/toolbox-testkit": "0.2.3", + "@add-ideas/toolbox-testkit": "0.3.0", "@eslint/js": "10.0.1", "@playwright/test": "1.61.1", "@testing-library/jest-dom": "6.9.1", diff --git a/playwright.config.ts b/playwright.config.ts index 60dbc27..86274d6 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -18,7 +18,25 @@ export default defineConfig({ timeout: 180_000, }, projects: [ - { name: "chromium", use: { ...devices["Desktop Chrome"] } }, - { name: "firefox", use: { ...devices["Desktop Firefox"] } }, + { + name: "chromium", + testIgnore: /responsive\.spec\.ts/, + use: { ...devices["Desktop Chrome"] }, + }, + { + name: "firefox", + testIgnore: /responsive\.spec\.ts/, + use: { ...devices["Desktop Firefox"] }, + }, + { + name: "webkit", + testIgnore: /responsive\.spec\.ts/, + use: { ...devices["Desktop Safari"] }, + }, + { + name: "mobile-chromium", + testMatch: /responsive\.spec\.ts/, + use: { ...devices["Pixel 5"] }, + }, ], }); diff --git a/public/toolbox-app.json b/public/toolbox-app.json index 8a6c8a8..8eb579b 100644 --- a/public/toolbox-app.json +++ b/public/toolbox-app.json @@ -3,7 +3,7 @@ "schemaVersion": 1, "id": "de.add-ideas.svg-tools", "name": "SVG Tools", - "version": "0.1.0", + "version": "0.2.0", "description": "Inspect, edit, optimize and transform SVG documents locally in the browser.", "entry": "./", "icon": "./favicon.svg", @@ -24,16 +24,26 @@ }, "requirements": { "secureContext": false, - "workers": true, + "workers": false, "indexedDb": false, "crossOriginIsolated": false, "topLevelContext": false }, - "privacy": { - "processing": "local", - "fileUploads": false, - "telemetry": false + "io": { + "accepts": [ + { "mediaType": "image/svg+xml", "extensions": [".svg", ".svgz"] }, + { "mediaType": "application/json", "extensions": [".svgtools.json"] } + ], + "produces": [ + { "mediaType": "image/svg+xml", "extensions": [".svg", ".svgz"] }, + { "mediaType": "image/png", "extensions": [".png"] }, + { "mediaType": "image/jpeg", "extensions": [".jpg"] }, + { "mediaType": "image/webp", "extensions": [".webp"] }, + { "mediaType": "application/json", "extensions": [".svgtools.json"] } + ] }, + "capabilities": { "required": [], "optional": ["workers", "canvas"] }, + "privacy": { "processing": "local", "fileUploads": true, "telemetry": false }, "source": { "repository": "https://git.add-ideas.de/lotobo/svg-tools", "license": "GPL-3.0-or-later" diff --git a/src/components/Inspector.tsx b/src/components/Inspector.tsx index a26bcdd..47d8c08 100644 --- a/src/components/Inspector.tsx +++ b/src/components/Inspector.tsx @@ -50,6 +50,8 @@ export interface InspectorProps { value: string | null, mergeKey?: string, ) => void; + onDuplicateNode: () => void; + onDeleteNode: () => void; onCommitPath: (data: string, label: string) => void; onTransformPreview: (matrix: Matrix | null) => void; onApplyTransform: (matrix: Matrix, mode: "attribute" | "bake") => void; @@ -186,9 +188,13 @@ function DocumentPanel({ function ElementPanel({ node, onSetAttribute, + onDuplicateNode, + onDeleteNode, }: { node: SemanticSvgNode | undefined; onSetAttribute: InspectorProps["onSetAttribute"]; + onDuplicateNode: () => void; + onDeleteNode: () => void; }) { const [newName, setNewName] = useState(""); const [newValue, setNewValue] = useState(""); @@ -207,6 +213,24 @@ function ElementPanel({ <{node.name}> {node.id ? `#${node.id}` : "No ID"} +