From b92cd2fa0ee2e042725b4e1268ca0dfe7bb549a3 Mon Sep 17 00:00:00 2001 From: gjulivan Date: Wed, 4 Mar 2026 15:22:22 +0100 Subject: [PATCH 1/7] feat(signature): initial version of signature web widget --- .../signature-web/.prettierignore | 4 - .../customWidgets/signature-web/CHANGELOG.md | 27 -- .../customWidgets/signature-web/README.md | 1 - .../signature-web/cypress/.eslintrc.json | 4 - .../cypress/integration/Signature.spec.js | 11 - .../signature-web/cypress/support/e2e.js | 1 - .../signature-web/dependencies.json | 1 - .../signature-web/dependencies.txt | 67 ----- .../customWidgets/signature-web/package.json | 67 ----- .../signature-web/scripts/build.ts | 43 --- .../scripts/generate-dependencies.js | 268 ------------------ .../signature-web/scripts/tsconfig.json | 3 - .../signature-web/src/Signature.icon.dark.png | Bin 1801 -> 0 bytes .../signature-web/src/Signature.icon.png | Bin 1879 -> 0 bytes .../signature-web/src/Signature.tile.dark.png | Bin 6466 -> 0 bytes .../signature-web/src/Signature.tile.png | Bin 6633 -> 0 bytes .../signature-web/src/Signature.webmodeler.ts | 54 ---- .../signature-web/src/Signature.xml | 87 ------ .../src/components/Signature.tsx | 118 -------- .../src/components/SignatureContainer.ts | 202 ------------- .../signature-web/webpack.config.js | 96 ------- .../signature-web/.prettierrc.js | 0 .../signature-web/CHANGELOG.md | 41 +++ .../pluggableWidgets/signature-web/README.md | 3 + .../signature-web/cypress.config.cjs | 1 + .../signature-web/eslint.config.mjs | 0 .../mendix-pluggable-widgets-tools.tgz | Bin 0 -> 63447 bytes .../signature-web/package.json | 66 +++++ .../signature-web/rollup.config.mjs | 5 + .../src/Signature.editorConfig.ts | 36 +++ .../src/Signature.editorPreview.tsx | 8 + .../signature-web/src/Signature.icon.dark.png | Bin 0 -> 1295 bytes .../signature-web/src/Signature.icon.png | Bin 0 -> 1333 bytes .../signature-web/src/Signature.tile.dark.png | Bin 0 -> 3686 bytes .../signature-web/src/Signature.tile.png | Bin 0 -> 3715 bytes .../signature-web/src/Signature.tsx | 18 ++ .../signature-web/src/Signature.xml | 87 ++++++ .../src/__tests__/AppEvents.spec.tsx | 34 +++ .../src/assets/Signature.icon.active.svg | 3 + .../src/assets/Signature.icon.dark.active.svg | 3 + .../src/assets/Signature.icon.dark.svg | 3 + .../src/assets/Signature.icon.svg | 3 + .../signature-web/src/assets/icons.tsx | 15 + .../signature-web/src/components/Alert.tsx | 0 .../signature-web/src/components/Grid.tsx | 0 .../src/components/Signature.tsx | 99 +++++++ .../src/components/SizeContainer.ts | 0 .../signature-web/src/package.xml | 4 +- .../signature-web/src/ui/Signature.scss | 0 .../signature-web/src/ui/SignaturePreview.css | 22 ++ .../signature-web/src/utils/Utils.ts | 0 .../src/utils/useResizeObserver.ts | 0 .../signature-web/tsconfig.json | 22 +- .../signature-web/typings/SignatureProps.d.ts | 59 ++++ .../signature-web/typings/declare-svg.ts | 4 + 55 files changed, 524 insertions(+), 1066 deletions(-) delete mode 100644 packages/customWidgets/signature-web/.prettierignore delete mode 100644 packages/customWidgets/signature-web/CHANGELOG.md delete mode 100644 packages/customWidgets/signature-web/README.md delete mode 100644 packages/customWidgets/signature-web/cypress/.eslintrc.json delete mode 100644 packages/customWidgets/signature-web/cypress/integration/Signature.spec.js delete mode 100644 packages/customWidgets/signature-web/cypress/support/e2e.js delete mode 100644 packages/customWidgets/signature-web/dependencies.json delete mode 100644 packages/customWidgets/signature-web/dependencies.txt delete mode 100644 packages/customWidgets/signature-web/package.json delete mode 100755 packages/customWidgets/signature-web/scripts/build.ts delete mode 100755 packages/customWidgets/signature-web/scripts/generate-dependencies.js delete mode 100644 packages/customWidgets/signature-web/scripts/tsconfig.json delete mode 100644 packages/customWidgets/signature-web/src/Signature.icon.dark.png delete mode 100644 packages/customWidgets/signature-web/src/Signature.icon.png delete mode 100644 packages/customWidgets/signature-web/src/Signature.tile.dark.png delete mode 100644 packages/customWidgets/signature-web/src/Signature.tile.png delete mode 100644 packages/customWidgets/signature-web/src/Signature.webmodeler.ts delete mode 100644 packages/customWidgets/signature-web/src/Signature.xml delete mode 100644 packages/customWidgets/signature-web/src/components/Signature.tsx delete mode 100644 packages/customWidgets/signature-web/src/components/SignatureContainer.ts delete mode 100644 packages/customWidgets/signature-web/webpack.config.js rename packages/{customWidgets => pluggableWidgets}/signature-web/.prettierrc.js (100%) create mode 100644 packages/pluggableWidgets/signature-web/CHANGELOG.md create mode 100644 packages/pluggableWidgets/signature-web/README.md create mode 100644 packages/pluggableWidgets/signature-web/cypress.config.cjs rename packages/{customWidgets => pluggableWidgets}/signature-web/eslint.config.mjs (100%) create mode 100644 packages/pluggableWidgets/signature-web/mendix-pluggable-widgets-tools.tgz create mode 100644 packages/pluggableWidgets/signature-web/package.json create mode 100644 packages/pluggableWidgets/signature-web/rollup.config.mjs create mode 100644 packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts create mode 100644 packages/pluggableWidgets/signature-web/src/Signature.editorPreview.tsx create mode 100644 packages/pluggableWidgets/signature-web/src/Signature.icon.dark.png create mode 100644 packages/pluggableWidgets/signature-web/src/Signature.icon.png create mode 100644 packages/pluggableWidgets/signature-web/src/Signature.tile.dark.png create mode 100644 packages/pluggableWidgets/signature-web/src/Signature.tile.png create mode 100644 packages/pluggableWidgets/signature-web/src/Signature.tsx create mode 100644 packages/pluggableWidgets/signature-web/src/Signature.xml create mode 100644 packages/pluggableWidgets/signature-web/src/__tests__/AppEvents.spec.tsx create mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.icon.active.svg create mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.active.svg create mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.svg create mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.icon.svg create mode 100644 packages/pluggableWidgets/signature-web/src/assets/icons.tsx rename packages/{customWidgets => pluggableWidgets}/signature-web/src/components/Alert.tsx (100%) rename packages/{customWidgets => pluggableWidgets}/signature-web/src/components/Grid.tsx (100%) create mode 100644 packages/pluggableWidgets/signature-web/src/components/Signature.tsx rename packages/{customWidgets => pluggableWidgets}/signature-web/src/components/SizeContainer.ts (100%) rename packages/{customWidgets => pluggableWidgets}/signature-web/src/package.xml (69%) rename packages/{customWidgets => pluggableWidgets}/signature-web/src/ui/Signature.scss (100%) create mode 100644 packages/pluggableWidgets/signature-web/src/ui/SignaturePreview.css rename packages/{customWidgets => pluggableWidgets}/signature-web/src/utils/Utils.ts (100%) rename packages/{customWidgets => pluggableWidgets}/signature-web/src/utils/useResizeObserver.ts (100%) rename packages/{customWidgets => pluggableWidgets}/signature-web/tsconfig.json (63%) create mode 100644 packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts create mode 100644 packages/pluggableWidgets/signature-web/typings/declare-svg.ts diff --git a/packages/customWidgets/signature-web/.prettierignore b/packages/customWidgets/signature-web/.prettierignore deleted file mode 100644 index 1b45dc70bf..0000000000 --- a/packages/customWidgets/signature-web/.prettierignore +++ /dev/null @@ -1,4 +0,0 @@ -dist -node_modules -tests - diff --git a/packages/customWidgets/signature-web/CHANGELOG.md b/packages/customWidgets/signature-web/CHANGELOG.md deleted file mode 100644 index 27766cd15d..0000000000 --- a/packages/customWidgets/signature-web/CHANGELOG.md +++ /dev/null @@ -1,27 +0,0 @@ -# Changelog - -All notable changes to this widget will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -## [1.0.8] - 2026-02-20 - -### Fixed - -- We fixed and issue with the widget not working correctly in some newer version of Studio Pro. - -### Added - -- We added a license file and a readme documenting all open source dependencies used in this package. - -## [1.0.7] - 2025-01-15 - -### Changed - -- We updated the light and dark icons and tiles for the widget. - -### Fixed - -- We fixed an issue where the widget was failing to save signatures on Hybrid apps. diff --git a/packages/customWidgets/signature-web/README.md b/packages/customWidgets/signature-web/README.md deleted file mode 100644 index 3d5647cf4c..0000000000 --- a/packages/customWidgets/signature-web/README.md +++ /dev/null @@ -1 +0,0 @@ -Please see [Signature](https://docs.mendix.com/appstore/widgets/signature) in the Mendix documentation for details. diff --git a/packages/customWidgets/signature-web/cypress/.eslintrc.json b/packages/customWidgets/signature-web/cypress/.eslintrc.json deleted file mode 100644 index e98e5a04cb..0000000000 --- a/packages/customWidgets/signature-web/cypress/.eslintrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "root": true, - "extends": ["@mendix/eslint-config-web-widgets/cypress"] -} diff --git a/packages/customWidgets/signature-web/cypress/integration/Signature.spec.js b/packages/customWidgets/signature-web/cypress/integration/Signature.spec.js deleted file mode 100644 index f6de512d27..0000000000 --- a/packages/customWidgets/signature-web/cypress/integration/Signature.spec.js +++ /dev/null @@ -1,11 +0,0 @@ -describe("Signature", () => { - it("renders canvas", () => { - cy.visit("/"); - cy.get(".widget-signature-canvas").should("be.visible"); - }); - - it("renders grid", () => { - cy.visit("/p/GridSize"); - cy.get(".widget-signature-grid").get("svg").should("be.visible"); - }); -}); diff --git a/packages/customWidgets/signature-web/cypress/support/e2e.js b/packages/customWidgets/signature-web/cypress/support/e2e.js deleted file mode 100644 index 5f49ab7003..0000000000 --- a/packages/customWidgets/signature-web/cypress/support/e2e.js +++ /dev/null @@ -1 +0,0 @@ -import "../../../../../configs/e2e/cypress/support/command"; diff --git a/packages/customWidgets/signature-web/dependencies.json b/packages/customWidgets/signature-web/dependencies.json deleted file mode 100644 index 3184818562..0000000000 --- a/packages/customWidgets/signature-web/dependencies.json +++ /dev/null @@ -1 +0,0 @@ -[{ "classnames": { "version": "2.5.1", "url": null } }, { "signature_pad": { "version": "5.1.3", "url": null } }] diff --git a/packages/customWidgets/signature-web/dependencies.txt b/packages/customWidgets/signature-web/dependencies.txt deleted file mode 100644 index 532a7495d2..0000000000 --- a/packages/customWidgets/signature-web/dependencies.txt +++ /dev/null @@ -1,67 +0,0 @@ -Name: classnames -Version: 2.5.1 -License: MIT -Private: false -Description: A simple utility for conditionally joining classNames together -Repository: git+https://github.com/JedWatson/classnames.git -Author: Jed Watson -Homepage: https://github.com/JedWatson/classnames#readme -License Copyright: -=== - -The MIT License (MIT) - -Copyright (c) 2018 Jed Watson - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ---- - -Name: signature_pad -Version: 5.1.3 -License: MIT -Private: false -Description: Library for drawing smooth signatures. -Repository: git+https://github.com/szimek/signature_pad.git -Author: Szymon Nowak (https://github.com/szimek) -Homepage: https://github.com/szimek/signature_pad -License Copyright: -=== - -MIT License - -Copyright (c) 2018 Szymon Nowak - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/customWidgets/signature-web/package.json b/packages/customWidgets/signature-web/package.json deleted file mode 100644 index 2e16f88806..0000000000 --- a/packages/customWidgets/signature-web/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "@mendix/signature-web", - "widgetName": "Signature", - "version": "1.0.8", - "description": "A signature pad for capturing signatures", - "copyright": "© Mendix Technology BV 2025. All rights reserved.", - "license": "Apache-2.0", - "repository": { - "type": "git", - "url": "https://github.com/mendix/web-widgets.git" - }, - "mxpackage": { - "name": "Signature", - "type": "widget", - "mpkName": "Signature.mpk" - }, - "packagePath": "com.mendix.widget.custom", - "marketplace": { - "minimumMXVersion": "7.13.1", - "appName": "Signature", - "appNumber": 107984 - }, - "testProject": { - "githubUrl": "https://github.com/mendix/testProjects", - "branchName": "signature-web" - }, - "scripts": { - "build": "ts-node --project scripts/tsconfig.json scripts/build.ts development", - "create-gh-release": "rui-create-gh-release", - "format": "prettier --ignore-path ./node_modules/@mendix/prettier-config-web-widgets/global-prettierignore --write .", - "lint": "eslint src/ package.json", - "publish-marketplace": "rui-publish-marketplace", - "release": "node scripts/generate-dependencies.js && ts-node --project scripts/tsconfig.json scripts/build.ts production", - "test": "echo 'TODO: Migrate tests'", - "update-changelog": "rui-update-changelog-widget", - "verify": "rui-verify-package-format" - }, - "dependencies": { - "classnames": "^2.5.1", - "signature_pad": "5.1.3" - }, - "devDependencies": { - "@mendix/automation-utils": "workspace:*", - "@mendix/eslint-config-web-widgets": "workspace:*", - "@mendix/pluggable-widgets-tools": "*", - "@mendix/prettier-config-web-widgets": "workspace:*", - "copy-webpack-plugin": "^11.0.0", - "css-loader": "^6.7.3", - "eslint": "^9.39.3", - "jest-canvas-mock": "^2.4.0", - "loader-utils": "1.4.2", - "mendix-client": "^7.15.8", - "mini-css-extract-plugin": "^2.7.2", - "sass-loader": "^13.2.0", - "to-string-loader": "^1.1.6", - "ts-loader": "^9.4.2", - "ts-node": "^10.9.2", - "typescript": "<5.2.0", - "webpack": "^5.75.0", - "webpack-cli": "^5.0.1" - }, - "jest": { - "setupFiles": [ - "jest-canvas-mock" - ] - } -} diff --git a/packages/customWidgets/signature-web/scripts/build.ts b/packages/customWidgets/signature-web/scripts/build.ts deleted file mode 100755 index 766f3b4a88..0000000000 --- a/packages/customWidgets/signature-web/scripts/build.ts +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env ts-node-script - -import { cp, mkdir, zip, exec } from "@mendix/automation-utils/shell"; -import { logStep, removeDist, runWidgetSteps, WidgetStepParams } from "@mendix/automation-utils/steps"; -import { dirname, join } from "node:path"; - -const [, , env] = process.argv; -const isProd = env === "production"; -const copyToProject = !isProd && process.env.MX_PROJECT_PATH; - -async function createMPK({ config }: WidgetStepParams): Promise { - logStep("Create mpk"); - const { paths, output } = config; - mkdir("-p", dirname(output.files.mpk)); - await zip(paths.tmp, output.files.mpk); -} - -async function main(): Promise { - await runWidgetSteps({ - packagePath: process.cwd(), - steps: [ - removeDist, - async () => { - logStep("Bundling"); - await exec(`webpack -c webpack.config.js`); - }, - createMPK, - async ({ config }) => { - if (copyToProject) { - logStep("Copy widget to targetProject"); - const dir = join(config.paths.targetProject, "widgets"); - mkdir("-p", dir); - cp(config.output.files.mpk, dir); - } - } - ] - }); -} - -main().catch(err => { - console.error(err); - process.exit(1); -}); diff --git a/packages/customWidgets/signature-web/scripts/generate-dependencies.js b/packages/customWidgets/signature-web/scripts/generate-dependencies.js deleted file mode 100755 index d094ec90a5..0000000000 --- a/packages/customWidgets/signature-web/scripts/generate-dependencies.js +++ /dev/null @@ -1,268 +0,0 @@ -#!/usr/bin/env node - -const { execSync } = require("child_process"); -const fs = require("fs"); -const path = require("path"); - -/** - * Generate dependencies.json and dependencies.txt from package.json using pnpm to get actual installed versions - * - * Usage: node generate-dependencies.js [path-to-package.json] - */ - -function getPackageJsonPath() { - const arg = process.argv[2]; - if (arg) { - return path.resolve(arg); - } - // Default to package.json in current directory - return path.resolve(process.cwd(), "package.json"); -} - -function readPackageJson(packageJsonPath) { - if (!fs.existsSync(packageJsonPath)) { - console.error(`Error: package.json not found at ${packageJsonPath}`); - process.exit(1); - } - - try { - const content = fs.readFileSync(packageJsonPath, "utf8"); - return JSON.parse(content); - } catch (error) { - console.error(`Error reading or parsing package.json: ${error.message}`); - process.exit(1); - } -} - -function getInstalledVersion(packageName, packageDir) { - try { - // Use pnpm list to get the actual installed version - // --depth 0 to only show direct dependencies - // --json for parseable output - const output = execSync(`pnpm list "${packageName}" --depth 0 --json`, { - cwd: packageDir, - encoding: "utf8", - stdio: ["pipe", "pipe", "pipe"] - }); - - const result = JSON.parse(output); - - // pnpm list returns an array of project results - if (Array.isArray(result) && result.length > 0) { - const dependencies = result[0].dependencies || {}; - if (dependencies[packageName]) { - const version = dependencies[packageName].version; - // Remove any leading 'v' if present - return version.replace(/^v/, ""); - } - } - - return null; - } catch (error) { - // If pnpm list fails, try reading from node_modules - try { - const nodeModulesPath = path.join(packageDir, "node_modules", packageName, "package.json"); - if (fs.existsSync(nodeModulesPath)) { - const pkgContent = JSON.parse(fs.readFileSync(nodeModulesPath, "utf8")); - return pkgContent.version; - } - } catch (innerError) { - // Ignore - } - - console.warn(`Warning: Could not determine installed version for ${packageName}`); - return null; - } -} - -function getPackageMetadata(packageName, version) { - try { - // Use pnpm view to get package metadata from npm registry - const output = execSync(`pnpm view "${packageName}@${version}" --json`, { - encoding: "utf8", - stdio: ["pipe", "pipe", "pipe"] - }); - - const metadata = JSON.parse(output); - - return { - name: metadata.name || packageName, - version: metadata.version || version, - license: metadata.license || "UNKNOWN", - private: metadata.private || false, - description: metadata.description || "", - repository: formatRepository(metadata.repository), - author: metadata.author || "", - homepage: metadata.homepage || "" - }; - } catch (error) { - console.warn(`Warning: Could not fetch metadata for ${packageName}@${version}`); - return { - name: packageName, - version: version, - license: "UNKNOWN", - private: false, - description: "", - repository: "", - author: "", - homepage: "" - }; - } -} - -function formatRepository(repo) { - if (!repo) return "undefined"; - if (typeof repo === "string") return repo; - if (repo.url) return repo.url; - return "undefined"; -} - -function getLicenseText(packageName, version, packageDir) { - // Try to find LICENSE file in node_modules - const possiblePaths = [ - path.join(packageDir, "node_modules", packageName, "LICENSE"), - path.join(packageDir, "node_modules", packageName, "LICENSE.md"), - path.join(packageDir, "node_modules", packageName, "LICENSE.txt"), - path.join(packageDir, "node_modules", packageName, "license"), - path.join(packageDir, "node_modules", packageName, "license.md"), - path.join(packageDir, "node_modules", packageName, "license.txt") - ]; - - for (const licensePath of possiblePaths) { - if (fs.existsSync(licensePath)) { - try { - return fs.readFileSync(licensePath, "utf8").trim(); - } catch (error) { - // Continue to next path - } - } - } - - // If not found in node_modules, try pnpm's virtual store - const pnpmStorePath = path.join( - packageDir, - "..", - "..", - "node_modules", - ".pnpm", - `${packageName}@${version}`, - "node_modules", - packageName - ); - - for (const filename of ["LICENSE", "LICENSE.md", "LICENSE.txt", "license", "license.md", "license.txt"]) { - const licensePath = path.join(pnpmStorePath, filename); - if (fs.existsSync(licensePath)) { - try { - return fs.readFileSync(licensePath, "utf8").trim(); - } catch (error) { - // Continue - } - } - } - - return null; -} - -function generateDependenciesJson(packageJsonPath) { - const packageJson = readPackageJson(packageJsonPath); - const packageDir = path.dirname(packageJsonPath); - - const dependencies = packageJson.dependencies || {}; - const dependencyNames = Object.keys(dependencies); - - if (dependencyNames.length === 0) { - console.log("No dependencies found in package.json"); - return { jsonData: [], detailedData: [] }; - } - - console.log(`Found ${dependencyNames.length} dependencies, resolving versions...`); - - const jsonData = []; - const detailedData = []; - - for (const depName of dependencyNames) { - const version = getInstalledVersion(depName, packageDir); - - if (version) { - // Add to JSON format - jsonData.push({ - [depName]: { - version: version, - url: null - } - }); - - // Fetch metadata for TXT format - const metadata = getPackageMetadata(depName, version); - const licenseText = getLicenseText(depName, version, packageDir); - - detailedData.push({ - ...metadata, - licenseText - }); - - console.log(` ✓ ${depName}@${version}`); - } else { - console.warn(` ✗ ${depName} - version not found`); - } - } - - return { jsonData, detailedData }; -} - -function generateDependenciesTxt(detailedData) { - const sections = []; - - for (const dep of detailedData) { - const lines = []; - - lines.push(`Name: ${dep.name}`); - lines.push(`Version: ${dep.version}`); - lines.push(`License: ${dep.license}`); - lines.push(`Private: ${dep.private}`); - lines.push(`Description: ${dep.description}`); - lines.push(`Repository: ${dep.repository}`); - - if (dep.author) { - lines.push(`Author: ${dep.author}`); - } - - if (dep.homepage) { - lines.push(`Homepage: ${dep.homepage}`); - } - - if (dep.licenseText) { - lines.push("License Copyright:"); - lines.push("==="); - lines.push(""); - lines.push(dep.licenseText); - } - - sections.push(lines.join("\n")); - } - - return sections.join("\n\n---\n\n"); -} - -function main() { - const packageJsonPath = getPackageJsonPath(); - const jsonOutputPath = path.join(process.cwd(), "dependencies.json"); - const txtOutputPath = path.join(process.cwd(), "dependencies.txt"); - - console.log(`Reading package.json from: ${packageJsonPath}`); - - const { jsonData, detailedData } = generateDependenciesJson(packageJsonPath); - - // Write dependencies.json - fs.writeFileSync(jsonOutputPath, JSON.stringify(jsonData)); - console.log(`\n✓ Generated dependencies.json at: ${jsonOutputPath}`); - console.log(` Total dependencies: ${jsonData.length}`); - - // Write dependencies.txt - const txtContent = generateDependenciesTxt(detailedData); - fs.writeFileSync(txtOutputPath, txtContent + "\n"); - console.log(`✓ Generated dependencies.txt at: ${txtOutputPath}`); -} - -main(); diff --git a/packages/customWidgets/signature-web/scripts/tsconfig.json b/packages/customWidgets/signature-web/scripts/tsconfig.json deleted file mode 100644 index eeb4a6cc48..0000000000 --- a/packages/customWidgets/signature-web/scripts/tsconfig.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "@mendix/automation-utils/tsconfig" -} diff --git a/packages/customWidgets/signature-web/src/Signature.icon.dark.png b/packages/customWidgets/signature-web/src/Signature.icon.dark.png deleted file mode 100644 index 137bba05250fd4e17e26acc66d52563d4a55de5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1801 zcmV+k2ln`hP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw0000^WmrjOO-%qQ0000800aRV z00jU50096106qa500jU50096107d~Q00RI3009630006L00RI3009620000000000 z0AK(B009610AK(B00DOe-{$}T21-dpK~#7F?OI!I+eQ@SP>loeW30_Nx5#!#8|^;i&3HUMZ?#$j>Q7pp z6afStz`8Nu&iD5Aj$`I{!%v2Qgy3CZqg zwgQNij=~a<1iXx8a^72VAL>6V?Lf1T1f&HoP{9lOqD~UQ&>|UC3P(Uz@B}hR)K|$U z6amwKCtwqO6=P((Fa+cTzN@0`bUK#WC$|ehKp1!!YU5mYWrKC~2z{emE?-BHuy6vR zj0f2DH~=yFZXk?WW1$4Z8Be=Skvt4Qgnr;Qn5?m`deFiM2s55CJQ(>wHdIGKls+=V z=OJsf<#nmf)Q)+yql_0B9_Dmm3%&h$g)%+Fga-2b7wGJI1Ct7oC-kXHvxW_FevJjrHAS-wYsJfHxP#W+w7i9X56fH9IAUG}f zH2T8r)t%Q7CCHsA0cngE2FWsweircbteFvz#&{XDsHf4-3Vvn;q%mFqmSr0KX~55f zfHcO-phZ26{ZXd1yph+pj0YZ^5UrXM_L&|8{UOw-h6aALwV;Kdq50_uUdBgW%ot{#9L_jv#w zej8>$9^k{)PSc+o0rcHX34r$Q?rvXaOi{p-ZMhu*d~&iBus-l~XJh;YUQtOlmARRN zn7U5dc5VdV!FBcF_~Ya`yke7%27c=_jYSUuKUAu%&n-sAdj$b-9Um&cc^#Sx zykLOy-^10|hot}K>1X*{o@VK(x)OQ7%Xh;wZtx>|d9IA^zu<{o`KbtizTKzY1z`6d zmk2P@*52g4memSTk0s#c`(X!Bswu2BS?Lh6Wm&+}E@?er=Z`y!mypLZ!=g!UA@C!o@$vQA zVA8V`LhAuexqRpY52(uso_0`60OL-R21S9}pDx?Zf5#?j6S@8VVT*C&Z?7A!|LN7U z4X?dqmB2M+$-f~;iso&jMIak0S zH&`FHMgu?J(P1V#qZlFdiy}1yu)b_ubr{?^;r8mz6Zm1d()jr6S`SBucHBoMXJ&_V z<@Mw0G@r6kdMBBM7s>I?wPpM5U7MNaiEJ2dg*F1*m%o0i_9w5!9W_xB;N>Ip->qO? z%WFZ;mr;6zlno2+V_}^i4b#LIB%=m`E$B)f$a)Xs$HwQ^YrZ9?X#@yxBl>vw)&Jn= zN9e!{4Uo_Vfj&aTSQhy(b~Zr3Ad9X}CvXI42ayRL>n7{_c#qs(-g$W*jze3G2l9A| zI>%gIHQ81Qo!F@X4-gt|M(7x4s;i4}S2F(Q(<}F^`?__FDLmmDjz$mI|6z>ZP<+v? zpS3TP09w#JpCzNt-H#ydRY&I$fsG^5^V77(P%xXURj2hQ#YPTcyO|?523Y$R{a?As rZq1R?U)FaJ0e&S{46GPfECc@nL#e%**k1?c00000NkvXXu0mjf0o^E( diff --git a/packages/customWidgets/signature-web/src/Signature.icon.png b/packages/customWidgets/signature-web/src/Signature.icon.png deleted file mode 100644 index 52babd516fb707ef31328f96fa1d273a431e527b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1879 zcmV-d2dMaoP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw0000^WmrjOO-%qQ0000800aRV z00jU50096106qa500jU50096107d~Q00RI3009630006L00RI3009620000000000 z0AK(B009610AK(B00DOe-{$}T2AD}iK~#7F?ONS#6Gs%Dvuo3$1~rIq?>s@>C%}1v z8qr9kH!%{adeJt{6U010oI4aMVJ=FzC?Pxn?i)ByfVplFD@YY+?45qc@tB#}AA9X} zyh%M$GG~6y_=n zCjrlPV^)jKS68-2!H{_ZqQDc;gXjB?s4LxNDaAd2ZR>!^m(}m@-Y@BOVREJkhy(w} z)4du4;-Gi%>`|lp#p$;wwz*EFE>T&@QF&$w7zMlz>afx9NJ{pEK?1n%289SAlLRCM zudsE#?6j2J&kI&LP|O?w;(aYLn<;wz$D-q=b8Qx#8z`=2uKIKY*_e2`R-2z zyG}1>f`BOSFx2b#PD3|1OpehPE_GkUkuY-t;*1B_#bE%3=rdo1xG`o*zzD|20*KP* zqcAIK>5PPOWl^i^i8CW0%6LBE;c4%QWoTd)qAK_3G9D}arYu31YY(D=KXS_P$ z-C4Wez^Q)SvaXGz?}|(QEdWHjnV3AK&n+QicsM>^*R{^w14aSQ20q{atr9kiyq-q^ z&to`5bJJ-5Ur3PkIY|n{261j4kQBT!JAwq&EMmb+ zGG?4)z$4CwfN{YOPzuMGNmZW+eDCpj&knBB4}z0|Poh6?dwb@s;HU`Xe5$)Z661BF zl$=C=9Pm>mAc^q`u%0K;9~b=82uNbQ4qC}c^d|v76#|kNuK??L68%ZR^Y5m=4U)7E zAE8^74qD0Q4L)@OR#!KQLJD*5jfubtIOj>gbN^G{fUuPt^nboL{hh zsHvaLt+qiiDR@@o+hBe!fY|2pIN(_?RRW}>A`hw(zpqnrR6Y)PHI^cQgxng1Xr-s; zIlVBcOoDFdW4IK4f>V7a0k6jBzYGn;9o0T8Pt^n9Plg9{PW?Ag2BZN#YV0KSshtG* z-VKkcueBc!JbSCQtbk{GQd|O^f_1WPDZreUu|v3daZC6Pyu`2QZ7h!)#O!gBmQy1D zYpG=a`0cfgI_kd>B+s@-i5`T|Xr)z>|Ru2dG?Px*IxU5MPqDY1#2 zqJ?+&N1cxgt;55*F;0li)T>7FfThjj9T;E5Wu$Ps?n_wJFf99+D;hTo{Na+1&r~EG z5q0qa)0Jj_zc$peP#8+U&CTP-h+P$BEIH0PFDy99bO zFL>sSMJ0F3o?W7xg*vXZ$TGykH$ z-c>c{EgY6sr1YQYmDq1~dNIPNoP8lc006agvvPheFmuZ7(XXiYh1|k1dFAi=wPx4p zR&6qIYy6mXEuGlnV)dkO6Q|M}oBuqXh8F>^nU;S2P{aMywoxmoMvi>>SAC(yv&cZg zW}d<8OQydoywb-4DaMJC0djjzbPBlME_8kR8iBaz2+3b~pw9Tnq1pN5u6Pfx>O)Q> z2MA!-M&y2thEUg!__f~5>)=&CkWj-L9FtJhI7SWvmO(&!4AoGTz!K&^A#u~>G!az)bR2QS@kJYUVlk2c9+?A{E8G%EXB~zVc|9V>T^@0ye~{D|e#GXn zFm#E>=fvaTLdC=M;*Z)w`fnh=M$CEB75SD|PtV=YesTVP&cK|3IRl>=_z#YlH^4)9 R{+R#(002ovPDHLkV1fk9QTG4< diff --git a/packages/customWidgets/signature-web/src/Signature.tile.dark.png b/packages/customWidgets/signature-web/src/Signature.tile.dark.png deleted file mode 100644 index 767c36c05f6a70daa82f76c2c1314f83eadab240..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6466 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 diff --git a/packages/customWidgets/signature-web/src/Signature.tile.png b/packages/customWidgets/signature-web/src/Signature.tile.png deleted file mode 100644 index b6cd04a2e2c91b22ad157590ddef7da8f3afc6e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6633 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 = { - [P in keyof T]: any; -}; - -export class preview extends Component { - render(): ReactNode { - return createElement(Signature, this.transformProps(this.props)); - } - - private transformProps(props: SignatureContainerProps): SignatureProps { - return { - className: props.class, - heightUnit: props.heightUnit, - height: props.height, - widthUnit: props.widthUnit, - width: props.width, - gridCellWidth: props.gridCellWidth, - gridCellHeight: props.gridCellHeight, - gridBorderColor: props.gridBorderColor, - gridBorderWidth: props.gridBorderWidth, - penColor: props.penColor, - penType: props.penType, - showGrid: props.showGrid, - clearSignature: false, - readOnly: false, - wrapperStyle: Utils.parseStyle(props.style) - }; - } -} - -export function getPreviewCss(): string { - return require("./ui/Signature.scss"); -} - -export function getVisibleProperties( - valueMap: SignatureContainerProps, - visibilityMap: VisibilityMap -): VisibilityMap { - if (!valueMap.showGrid) { - visibilityMap.gridBorderColor = false; - visibilityMap.gridBorderWidth = false; - visibilityMap.gridCellHeight = false; - visibilityMap.gridCellWidth = false; - } - - return visibilityMap; -} diff --git a/packages/customWidgets/signature-web/src/Signature.xml b/packages/customWidgets/signature-web/src/Signature.xml deleted file mode 100644 index bbafe26d42..0000000000 --- a/packages/customWidgets/signature-web/src/Signature.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - Signature - A signature pad for capturing signatures - - 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 - - - - Type - Pen - - - Fountain pen - Ball point pen - Highlight marker - - - - Color - Pen - Color of the line e.g. green, #00FF00, rgb(0,255,0) - - - Has signature - Canvas - Optional boolean attribute, which will be set to true after the canvas is signed. When the attribute is set to false, the signature is cleared, but will not clear the stored image - - - - - - Width unit - Canvas - - - Percentage - Pixels - - - - Width - Canvas - - - - Height unit - Canvas - 'Percentage of width' is the aspect ratio, 'Pixels' is absolute. Warning: When using 'Percentage of parent' the parent container must have an absolute height, else nothing is displayed. - - Percentage of width - Pixels - Percentage of parent - - - - Height - Canvas - - - - Show background grid - Grid - - - - Line color - Grid - - - - Cell height - Grid - Grid column size - - - Cell width - Grid - Grid row size - - - Line width - Grid - Grid border line width (pixels) - - - diff --git a/packages/customWidgets/signature-web/src/components/Signature.tsx b/packages/customWidgets/signature-web/src/components/Signature.tsx deleted file mode 100644 index 23f2f552f6..0000000000 --- a/packages/customWidgets/signature-web/src/components/Signature.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { PureComponent, ReactNode } from "react"; -import SignaturePad, { Options } from "signature_pad"; -import classNames from "classnames"; - -import { Alert } from "./Alert"; -import { Grid } from "./Grid"; -import { Dimensions, SizeContainer } from "./SizeContainer"; - -import "../ui/Signature.scss"; - -export interface SignatureProps extends Dimensions { - className: string; - alertMessage?: string; - clearSignature: boolean; - showGrid: boolean; - gridCellWidth: number; - gridCellHeight: number; - gridBorderColor: string; - gridBorderWidth: number; - penType: penOptions; - penColor: string; - onSignEndAction?: (imageUrl?: string) => void; - wrapperStyle?: object; - readOnly: boolean; -} - -export type penOptions = "fountain" | "ballpoint" | "marker"; - -export class Signature extends PureComponent { - private canvasNode: HTMLCanvasElement | null = null; - private signaturePad: SignaturePad | undefined; - - render(): ReactNode { - const { className, alertMessage, wrapperStyle } = this.props; - - return ( - - {alertMessage} - - { - this.canvasNode = node; - }} - /> - - ); - } - - componentDidMount(): void { - if (this.canvasNode) { - this.signaturePad = new SignaturePad(this.canvasNode, { - penColor: this.props.penColor, - ...this.signaturePadOptions() - }); - this.signaturePad.addEventListener("endStroke", this.handleSignEnd); - if (this.props.readOnly) { - this.signaturePad.off(); - } - } - } - - componentWillUnmount(): void { - this.signaturePad?.removeEventListener("endStroked", this.handleSignEnd); - } - - UNSAFE_componentWillReceiveProps(nextProps: SignatureProps): void { - if (this.signaturePad) { - const { clearSignature, readOnly } = this.props; - if (nextProps.clearSignature !== clearSignature && clearSignature) { - this.signaturePad.clear(); - } - if (nextProps.readOnly !== readOnly) { - if (nextProps.readOnly) { - this.signaturePad.off(); - } else { - this.signaturePad.on(); - } - } - } - } - - private onResize = (): void => { - if (this.canvasNode && this.signaturePad) { - const data = this.signaturePad.toData(); - this.canvasNode.width = - this.canvasNode && this.canvasNode.parentElement ? this.canvasNode.parentElement.offsetWidth : 0; - this.canvasNode.height = - this.canvasNode && this.canvasNode.parentElement ? this.canvasNode.parentElement.offsetHeight : 0; - this.signaturePad.clear(); - this.signaturePad.fromData(data); - } - }; - - private signaturePadOptions(): Options { - let options: Options = {}; - if (this.props.penType === "fountain") { - options = { minWidth: 0.6, maxWidth: 2.6, velocityFilterWeight: 0.6 }; - } else if (this.props.penType === "ballpoint") { - options = { minWidth: 1.4, maxWidth: 1.5, velocityFilterWeight: 1.5 }; - } else if (this.props.penType === "marker") { - options = { minWidth: 2, maxWidth: 4, velocityFilterWeight: 0.9 }; - } - return options; - } - - private handleSignEnd = (): void => { - if (this.props.onSignEndAction && this.signaturePad) { - this.props.onSignEndAction(this.signaturePad.toDataURL()); - } - }; -} diff --git a/packages/customWidgets/signature-web/src/components/SignatureContainer.ts b/packages/customWidgets/signature-web/src/components/SignatureContainer.ts deleted file mode 100644 index 6cb94d6166..0000000000 --- a/packages/customWidgets/signature-web/src/components/SignatureContainer.ts +++ /dev/null @@ -1,202 +0,0 @@ -import { Component, createElement, ReactNode } from "react"; - -import { Dimensions } from "./SizeContainer"; -import Utils from "../utils/Utils"; -import { penOptions, Signature } from "./Signature"; - -interface WrapperProps { - class: string; - mxObject?: mendix.lib.MxObject; - mxform: mxui.lib.form._FormBase; - style?: string; - friendlyId: string; - readOnly: boolean; -} - -export interface SignatureContainerProps extends WrapperProps, Dimensions { - hasSignatureAttribute: string; - showGrid: boolean; - gridBorderColor: string; - gridCellHeight: number; - gridCellWidth: number; - gridBorderWidth: number; - penType: penOptions; - penColor: string; -} - -interface SignatureContainerState { - alertMessage: string; - hasSignature: boolean; -} - -export default class SignatureContainer extends Component { - private subscriptionHandles: number[] = []; - private base64Uri = ""; - private formHandle?: number; - - readonly state = { - alertMessage: "", - hasSignature: false - }; - - constructor(props: SignatureContainerProps) { - super(props); - this.resetSubscriptions(props.mxObject); - } - - render(): ReactNode { - return createElement(Signature, { - ...(this.props as SignatureContainerProps), - wrapperStyle: Utils.parseStyle(this.props.style), - readOnly: this.isReadOnly(), - alertMessage: this.state.alertMessage, - clearSignature: this.state.hasSignature, - onSignEndAction: this.handleSignEnd, - className: this.props.class - }); - } - - UNSAFE_componentWillReceiveProps(newProps: SignatureContainerProps): void { - if (newProps.mxObject) { - const alertMessage = this.validateProps(newProps.mxObject); - - if (alertMessage) { - this.setState({ alertMessage }); - } - } - } - - componentDidUpdate(): void { - this.resetSubscriptions(this.props.mxObject); - } - - componentDidMount(): void { - this.formHandle = this.props.mxform.listen("submit", callback => this.saveDocument(callback)); - } - - componentWillUnmount(): void { - if (this.formHandle) { - this.props.mxform.unlisten(this.formHandle); - } - this.subscriptionHandles.forEach(window.mx.data.unsubscribe); - } - - private handleSignEnd = (base64Uri: string): void => { - const { mxObject } = this.props; - - if (mxObject && !this.state.hasSignature) { - mxObject.set(this.props.hasSignatureAttribute, true); - } - this.base64Uri = base64Uri; - if (base64Uri) { - this.setState({ hasSignature: true }); - } - }; - - private isReadOnly(): boolean { - const { mxObject, readOnly } = this.props; - - return !mxObject || readOnly || mxObject.isReadonlyAttr("Contents"); - } - - private saveDocument(callback: () => void): void { - if (this.base64Uri && this.state.hasSignature && this.props.mxObject) { - const error = function (callback: any): void { - return mx.ui.error("Error saving signature: " + callback.message); - }; - // @ts-expect-error cordova specific code - const cdv = window.cordova; - if (cdv) { - // @ts-expect-error cordova specific code - const options = new FileUploadOptions(); - options.fileKey = "blob"; - options.fileName = this.generateFileName(this.props.mxObject); - options.mimeType = "image/png"; - options.chunkedMode = false; - const headers = { - Accept: "application/json", - // @ts-expect-error cordova specific code - "X-Csrf-Token": mx.session.sessionData.csrftoken, - "X-Mx-ReqToken": new Date().getTime() - }; - options.headers = headers; - const isHttps = mx.remoteUrl.includes("https"); - const remoteUrlWithoutScheme = decodeURIComponent(mx.remoteUrl.replace(/.*_http[s]?_proxy_/, "")); - const remoteUrl = (isHttps ? "https://" : "http://") + remoteUrlWithoutScheme; - const guid = this.props.mxObject.getGuid(); - const dataUri = this.base64Uri; - - mx.data.commit({ - mxobj: this.props.mxObject, - callback() { - // @ts-expect-error cordova specific code - const ft = new FileTransfer(); - const fileUploadUrl = remoteUrl + "file?guid=" + guid; - ft.upload(dataUri, fileUploadUrl, callback, error, options); - }, - error - }); - } else { - mx.data.saveDocument( - this.props.mxObject.getGuid(), - this.generateFileName(this.props.mxObject), - {}, - Utils.convertUrlToBlob(this.base64Uri), - callback, - error => mx.ui.error("Error saving signature: " + error.message) - ); - } - } else { - callback(); - } - } - - private generateFileName(mxObject: mendix.lib.MxObject): string { - const currentName = mxObject.get("Name") as string; - if (currentName) { - return currentName; - } - return `signature${Math.floor(Math.random() * 1000000)}.png`; - } - - validateProps(mxObject: mendix.lib.MxObject): string { - let errorMessage = ""; - - if (mxObject && !mxObject.inheritsFrom("System.Image")) { - errorMessage = `${this.props.friendlyId}: ${mxObject.getEntity()} does not inherit from "System.Image".`; - } - - return errorMessage; - } - - private resetSubscriptions(mxObject?: mendix.lib.MxObject): void { - this.subscriptionHandles.forEach(window.mx.data.unsubscribe); - this.subscriptionHandles = []; - - if (mxObject) { - this.subscriptionHandles.push( - window.mx.data.subscribe({ - guid: mxObject.getGuid(), - callback: () => this.updateCanvasState() - }) - ); - this.subscriptionHandles.push( - mx.data.subscribe({ - guid: mxObject.getGuid(), - attr: this.props.hasSignatureAttribute, - callback: () => this.updateCanvasState() - }) - ); - } - } - - private updateCanvasState = (): void => { - const { mxObject, hasSignatureAttribute } = this.props; - if (hasSignatureAttribute) { - const hasSignature = !!mxObject && (mxObject.get(hasSignatureAttribute) as boolean); - if (this.state.hasSignature !== hasSignature) { - this.setState({ hasSignature }); - } - } - }; -} diff --git a/packages/customWidgets/signature-web/webpack.config.js b/packages/customWidgets/signature-web/webpack.config.js deleted file mode 100644 index ea880ebf8c..0000000000 --- a/packages/customWidgets/signature-web/webpack.config.js +++ /dev/null @@ -1,96 +0,0 @@ -const webpack = require("webpack"); -const path = require("path"); -const CopyWebpackPlugin = require("copy-webpack-plugin"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); - -const name = "signature"; -const widgetName = "Signature"; - -const widgetConfig = { - mode: "production", - devtool: false, - externals: ["react", "react-dom", "react/jsx-runtime"], - entry: "./src/components/SignatureContainer.ts", - output: { - path: path.resolve(__dirname, "dist/tmp"), - filename: `com/mendix/widget/custom/${name}/${widgetName}.js`, - libraryTarget: "amd", - publicPath: "/widgets/" - }, - resolve: { - extensions: [".ts", ".js", ".tsx", ".jsx"], - alias: { - tests: path.resolve(__dirname, "./tests") - } - }, - module: { - rules: [ - { - test: /\.tsx?$/, - use: "ts-loader" - }, - { - test: /\.(sa|sc|c)ss$/, - use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"] - } - ] - }, - plugins: [ - new MiniCssExtractPlugin({ - filename: `com/mendix/widget/custom/${name}/ui/${widgetName}.css` - }), - new CopyWebpackPlugin({ - patterns: [ - { - from: path.join(process.cwd(), "src/**/*.xml").replace(/\\/g, "/"), - toType: "template", - to: "./[name][ext]" - }, - { - from: `src/${widgetName}.@(tile|icon)@(.dark|).png`, - to: "./[name][ext]", - toType: "template" - }, - { - from: `dependencies.(json|txt)`, - to: "./[name][ext]", - toType: "template" - }, - { - from: `../../../LICENSE`, - to: "./License.txt", - toType: "template" - } - ] - }) - ] -}; - -const previewConfig = { - mode: "production", - devtool: false, - externals: ["react", "react-dom"], - entry: `./src/${widgetName}.webmodeler.ts`, - output: { - path: path.resolve(__dirname, "dist/tmp"), - filename: `${widgetName}.webmodeler.js`, - libraryTarget: "commonjs" - }, - resolve: { - extensions: [".ts", ".js", ".tsx", ".jsx"] - }, - module: { - rules: [ - { - test: /\.tsx?$/, - loader: "ts-loader" - }, - { - test: /\.(sa|sc|c)ss$/, - use: ["to-string-loader", "css-loader", "sass-loader"] - } - ] - } -}; - -module.exports = [widgetConfig, previewConfig]; diff --git a/packages/customWidgets/signature-web/.prettierrc.js b/packages/pluggableWidgets/signature-web/.prettierrc.js similarity index 100% rename from packages/customWidgets/signature-web/.prettierrc.js rename to packages/pluggableWidgets/signature-web/.prettierrc.js diff --git a/packages/pluggableWidgets/signature-web/CHANGELOG.md b/packages/pluggableWidgets/signature-web/CHANGELOG.md new file mode 100644 index 0000000000..cb0f65ef9b --- /dev/null +++ b/packages/pluggableWidgets/signature-web/CHANGELOG.md @@ -0,0 +1,41 @@ +# Changelog + +All notable changes to this widget will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.3.0] - 2026-02-25 + +### Fixed + +- We fixed an issue with burst action execution which was still happening in some cases. + +## [1.2.0] - 2025-11-07 + +### Fixed + +- We fixed an issue with burst executon in inactive tabs. + +### Changed + +- Repeated execution is not executing next action if previous execution is not yet finished. + +## [1.1.0] - 2025-08-12 + +### Added + +- Added support for using expressions to configure both delay and repeat interval values during component load. Expression support was also extended to delay values when attributes change dynamically. + +## [1.0.1] - 2024-04-25 + +### Fixed + +- We fixed issues where event not fired with MF/NF having parameters. + +## [1.0.0] - 2024-03-19 + +### Added + +- initial version of app events with component load and attribute change listener. diff --git a/packages/pluggableWidgets/signature-web/README.md b/packages/pluggableWidgets/signature-web/README.md new file mode 100644 index 0000000000..4247327a94 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/README.md @@ -0,0 +1,3 @@ + + +Please see [App Events](https://docs.mendix.com/appstore/widgets/) in the Mendix documentation for details. diff --git a/packages/pluggableWidgets/signature-web/cypress.config.cjs b/packages/pluggableWidgets/signature-web/cypress.config.cjs new file mode 100644 index 0000000000..f5388c3dfd --- /dev/null +++ b/packages/pluggableWidgets/signature-web/cypress.config.cjs @@ -0,0 +1 @@ +module.exports = require("@mendix/run-e2e/cypress.config.cjs"); diff --git a/packages/customWidgets/signature-web/eslint.config.mjs b/packages/pluggableWidgets/signature-web/eslint.config.mjs similarity index 100% rename from packages/customWidgets/signature-web/eslint.config.mjs rename to packages/pluggableWidgets/signature-web/eslint.config.mjs diff --git a/packages/pluggableWidgets/signature-web/mendix-pluggable-widgets-tools.tgz b/packages/pluggableWidgets/signature-web/mendix-pluggable-widgets-tools.tgz new file mode 100644 index 0000000000000000000000000000000000000000..93ea04ec327c8cd94c4c63ad547bf99bb69098ee GIT binary patch literal 63447 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 Q6$~IsNuoVN-F|@jA9Mu*vj6}9 literal 0 HcmV?d00001 diff --git a/packages/pluggableWidgets/signature-web/package.json b/packages/pluggableWidgets/signature-web/package.json new file mode 100644 index 0000000000..6524437ebf --- /dev/null +++ b/packages/pluggableWidgets/signature-web/package.json @@ -0,0 +1,66 @@ +{ + "name": "@mendix/signature-web", + "widgetName": "Signature", + "version": "1.0.0", + "description": "Signature widget for Mendix Web", + "copyright": "© Mendix Technology BV 2026. All rights reserved.", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/mendix/web-widgets.git" + }, + "config": { + "developmentPort": 3000, + "mendixHost": "http://localhost:8080" + }, + "mxpackage": { + "name": "Signature", + "type": "widget", + "mpkName": "com.mendix.widget.web.signature.mpk" + }, + "packagePath": "com.mendix.widget.web", + "marketplace": { + "minimumMXVersion": "10.8.0", + "appNumber": 107984, + "appName": "Signature", + "reactReady": true + }, + "testProject": { + "githubUrl": "https://github.com/mendix/testProjects", + "branchName": "signature-web" + }, + "scripts": { + "build": "pluggable-widgets-tools build:web", + "create-gh-release": "rui-create-gh-release", + "create-translation": "rui-create-translation", + "dev": "pluggable-widgets-tools start:web", + "e2e": "echo \"Skipping this e2e test\"", + "e2edev": "run-e2e dev --with-preps", + "format": "prettier --ignore-path ./node_modules/@mendix/prettier-config-web-widgets/global-prettierignore --write .", + "lint": "eslint src/ package.json", + "publish-marketplace": "rui-publish-marketplace", + "release": "pluggable-widgets-tools release:web", + "start": "pluggable-widgets-tools start:server", + "test": "pluggable-widgets-tools test:unit:web:enzyme-free", + "update-changelog": "rui-update-changelog-widget", + "verify": "rui-verify-package-format" + }, + "dependencies": { + "@uiw/react-signature": "^1.3.4", + "classnames": "^2.5.1", + "react-resize-detector": "^12.3.0", + "signature_pad": "^5.1.3" + }, + "devDependencies": { + "@mendix/automation-utils": "workspace:*", + "@mendix/eslint-config-web-widgets": "workspace:*", + "@mendix/pluggable-widgets-tools": "file:mendix-pluggable-widgets-tools.tgz", + "@mendix/prettier-config-web-widgets": "workspace:*", + "@mendix/run-e2e": "workspace:^*", + "@mendix/widget-plugin-component-kit": "workspace:*", + "@mendix/widget-plugin-hooks": "workspace:*", + "@mendix/widget-plugin-platform": "workspace:*", + "@mendix/widget-plugin-test-utils": "workspace:*", + "cross-env": "^7.0.3" + } +} diff --git a/packages/pluggableWidgets/signature-web/rollup.config.mjs b/packages/pluggableWidgets/signature-web/rollup.config.mjs new file mode 100644 index 0000000000..688a1a7197 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/rollup.config.mjs @@ -0,0 +1,5 @@ +import copyFiles from "@mendix/rollup-web-widgets/copyFiles.mjs"; + +export default args => { + return copyFiles(args); +}; diff --git a/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts b/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts new file mode 100644 index 0000000000..ec064b474c --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts @@ -0,0 +1,36 @@ +import { Properties } from "@mendix/pluggable-widgets-tools"; +import { + container, + rowLayout, + structurePreviewPalette, + StructurePreviewProps, + svgImage, + text +} from "@mendix/widget-plugin-platform/preview/structure-preview-api"; +import { SignaturePreviewProps } from "../typings/SignatureProps"; + +import SignaturePreviewSVG from "./assets/Signature.icon.svg"; +import SignaturePreviewDarkSVG from "./assets/Signature.icon.dark.svg"; + +export function getProperties( + _values: SignaturePreviewProps, + defaultProperties: Properties /* , target: Platform*/ +): Properties { + return defaultProperties; +} + +export function getPreview(_values: SignaturePreviewProps, isDarkMode: boolean): StructurePreviewProps { + const palette = structurePreviewPalette[isDarkMode ? "dark" : "light"]; + const normalSVG = isDarkMode ? SignaturePreviewDarkSVG : SignaturePreviewSVG; + const variant = normalSVG; + const doc = decodeURIComponent(variant.replace("data:image/svg+xml,", "")); + + return rowLayout({ columnSize: "grow", borders: true, backgroundColor: palette.background.containerFill })( + container()(), + rowLayout({ grow: 2, padding: 8 })( + svgImage({ width: 15, height: 15 })(doc), + text({ fontColor: palette.text.primary, grow: 10 })("Signature") + ), + container()() + ); +} diff --git a/packages/pluggableWidgets/signature-web/src/Signature.editorPreview.tsx b/packages/pluggableWidgets/signature-web/src/Signature.editorPreview.tsx new file mode 100644 index 0000000000..797c62a13a --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/Signature.editorPreview.tsx @@ -0,0 +1,8 @@ +import { ReactElement } from "react"; +import "./ui/SignaturePreview.css"; +import { SignaturePreviewProps } from "typings/SignatureProps"; +import classNames from "classnames"; + +export function preview(_props: SignaturePreviewProps): ReactElement { + return
{"Signature"}
; +} diff --git a/packages/pluggableWidgets/signature-web/src/Signature.icon.dark.png b/packages/pluggableWidgets/signature-web/src/Signature.icon.dark.png new file mode 100644 index 0000000000000000000000000000000000000000..2b3844754aa3e569becba64208cf2704f8b8709e GIT binary patch literal 1295 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC{d9b;hE;^%b*2hb1<+l zN-=;;U<6`2Mrks064nT^tz$3Dlfr0M`2s2LA=932ciP6)=F{Fa=ZIpN3Z36+-)&&lB-Es%r zJ@O{VEwnbDz2o#X#;!RE=Xixg@}~Qm^=^J8_(*w&`ilMuuD3;U70cW<@&qk&=`x<8 z6vD*wS^3{y%gZ*urBRzcL1?op@Wz!fyF*1yjn^kbv3-7lz;W z&T~v?ITiT#mxBSL;hz3?zAaX*>s7a9$9u(HixvLIbK}nHE%7zlr?(&9tex@bcvb3= z<&XH(*njbEC_Pv1pO-cLM3a)jwC|-3sku{E=^L0|cy9dR@l6-`&$;Y^0?F@xOZ-W; z`lHfv=lXl!sXOlRvh){a3167@eWME7`ok0XY$xH%4jiJ*+yBn76{a;(PWq#L{icQ+8?=`Qc%Gzw( z%b9WO_X>Zl(r}XqPsx}l{ZohRY{LJnn^gN^`;U)$?_+G0Z+}`R?ltcn%bwS(d%pBB z+-P5{b{Re+2%#XI+`@Ay#|2F&ND@o}!)eG()zx%DPVON*@J%0Yg zvkuYQTQ(ouc`e@j?So38xmzbqax-DNr1CreKvZtzkK=wN*Vv|*ED~gB;OCut@>yh^ zaA#j)^HSkfhWQ`zwJvTR@PO<8pV<8$?<;zgd^IJ{1N!xGY3FWuS4ckLRVe%Gxf2O}bXtiShFxmYr+B#%4! zne4{uHG% zSJoF%{%SzO?!bh-W;|yFazYx`eNAEd^ttKGXQw@NUXk;-YwYhEUjV`n{EjyS&mT^? R1S;qlJYD@<);T3K0RVU@AP)cl literal 0 HcmV?d00001 diff --git a/packages/pluggableWidgets/signature-web/src/Signature.icon.png b/packages/pluggableWidgets/signature-web/src/Signature.icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d2bce0c63462d5cad4b320eaa259009ffc8ac2b8 GIT binary patch literal 1333 zcmYLJdsNa_0KPvFU!l&_d@u!9^Vt$K3RxC9O>90$v@%mrOKp~*=(6SmS?Xy`v5bRR z7Uj}h=8Fn7O`1*3QgW7$QhGR*T4feK28#P(op#Up?)TmA`|dsG{&DXyYLK6yfwchu zz|f!K69O|?13evh{(XP43?}V(uRt#V>Uk>`qLJ_#8%qfZ1mK800Gy)$C}E2u2Otdx zz$*p-q!IuuSZABJZ-RsLeY^bQ0t10Fto494WDPVYKrl8#=+Am94*ot~ zq3O_@-H}0P{1-RMZ8_d9Gk9ZU6_bS^db<|==5Uz^J=bArZE%pAJkwL~sV5L-*QDE5 z9*TQuA5}Xzd!z%sW~Khs>`wQm8Hv1jlbE?Dc6Hx9^IVOkp_hn6OXsQ@Mww^tb@KFS z`Q7QkGn4whNg?3eR=V<$<0_%z!d&hM71Kh9=zcUTUVHw}t}>%pSF)_}Y($somFnuw z&BZv$M5ba#_4LU5)Vh;6$*WARxN-a?sB`B$iGaPa`un{giJ5%Q9b)VQVmLe9A^Mmd z0Co7~(t!?<+p;JHjOgVK!Ajb(yo(Kyal!Lb3=v*X;rNw^kiTQeFwY>r*9@kQRpr@2ijHHI;t%*doRajq;kV_E6hP;o65Lc z+UeqSzs$38uOMx#{!0{jQ06*7yB9%=_N81s(@iFW{36-&jy&thX(qdaOXf~NW#C#jY~%#(s_bbQTywu(dHU+>)Dc@<`*(A8pgWn zxC`HO_xDxOM$;Xok1cs)7O0%U;HkZUaw$*wB2W=*BbSqgy6*xGV( z_!`X1rDc7G*|6VMKm(Mezk&>-T z2X#qhT8y{q6?R#bz4CdKVn!61SETm7npA+CRz`UIV^_}pYbKm253Oow)v{k)stv*0 zz7HGO}1epq#Jyp`ir53nU1$FF4Qin~Pcr$!h^o z9;{9c>n~}_L6J=tpKcS5wI4@u3e*XkCI`{yO-^OGfmKRTR`W$m3pW7@q~A;#U}rZQ y;JI#jMv{r_BPmYfJh9pMcFu6msOBwaV&54LWTfPIbZs2f{3rgtK|VF!4DNqn**b^- literal 0 HcmV?d00001 diff --git a/packages/pluggableWidgets/signature-web/src/Signature.tile.dark.png b/packages/pluggableWidgets/signature-web/src/Signature.tile.dark.png new file mode 100644 index 0000000000000000000000000000000000000000..38a629ddd0f66555094598fafb66322492b07398 GIT binary patch literal 3686 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 literal 0 HcmV?d00001 diff --git a/packages/pluggableWidgets/signature-web/src/Signature.tsx b/packages/pluggableWidgets/signature-web/src/Signature.tsx new file mode 100644 index 0000000000..025f5335f4 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/Signature.tsx @@ -0,0 +1,18 @@ +import { ReactElement, useCallback } from "react"; +import { SignatureContainerProps } from "../typings/SignatureProps"; +import { SignatureComponent } from "./components/Signature"; +import "./ui/Signature.scss"; + +export default function Signature(props: SignatureContainerProps): ReactElement { + const { class: className } = props; + const handleSignEnd = useCallback(() => {}, []); + return ( + + ); +} diff --git a/packages/pluggableWidgets/signature-web/src/Signature.xml b/packages/pluggableWidgets/signature-web/src/Signature.xml new file mode 100644 index 0000000000..edc13dad99 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/Signature.xml @@ -0,0 +1,87 @@ + + + Signature + Signature + https://docs.mendix.com/appstore/widgets/signature + + + + + Image value + + + + Has signature + Optional boolean attribute, which will be set to true after the canvas is signed. When the attribute is set to false, the signature is cleared, but will not clear the stored image + + + + + + + + Type + + + Fountain pen + Ball point pen + Highlight marker + + + + Color + Color of the line e.g. green, #00FF00, rgb(0,255,0) + + + + + + Width unit + + + Percentage + Pixels + + + + Width + + + + Height unit + 'Percentage of width' is the aspect ratio, 'Pixels' is absolute. Warning: When using 'Percentage of parent' the parent container must have an absolute height, else nothing is displayed. + + Percentage of width + Pixels + Percentage of parent + + + + Height + + + + + + Show background grid + + + + Line color + + + + Cell height + Grid column size + + + Cell width + Grid row size + + + Line width + Grid border line width (pixels) + + + + diff --git a/packages/pluggableWidgets/signature-web/src/__tests__/AppEvents.spec.tsx b/packages/pluggableWidgets/signature-web/src/__tests__/AppEvents.spec.tsx new file mode 100644 index 0000000000..02e155aa25 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/__tests__/AppEvents.spec.tsx @@ -0,0 +1,34 @@ +import { actionValue, dynamicValue } from "@mendix/widget-plugin-test-utils"; +import "@testing-library/jest-dom"; +import { render } from "@testing-library/react"; +import { EventsContainerProps } from "../../typings/EventsProps"; +import Events from "../Events"; + +describe("App events (load)", () => { + let defaultProps: EventsContainerProps; + beforeEach(() => { + defaultProps = { + name: "app events", + class: "app-events", + onComponentLoad: actionValue(), + componentLoadDelayParameterType: "number", + componentLoadDelay: 0, + componentLoadDelayExpression: dynamicValue(), + componentLoadRepeat: false, + componentLoadRepeatIntervalParameterType: "number", + componentLoadRepeatInterval: 0, + componentLoadRepeatIntervalExpression: dynamicValue(), + onEventChangeAttribute: undefined, + onEventChange: undefined, + onEventChangeDelayParameterType: "number", + onEventChangeDelay: 0, + onEventChangeDelayExpression: dynamicValue() + }; + }); + it("render app events", async () => { + const component = render(); + const renderedDiv = await component.container.querySelector(".widget-events"); + + expect(renderedDiv).toBeEmptyDOMElement(); + }); +}); diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.active.svg b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.active.svg new file mode 100644 index 0000000000..549a748d04 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.active.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.active.svg b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.active.svg new file mode 100644 index 0000000000..2cde472fd8 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.active.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.svg b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.svg new file mode 100644 index 0000000000..e32ab55af4 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.svg b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.svg new file mode 100644 index 0000000000..15cba120d4 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/pluggableWidgets/signature-web/src/assets/icons.tsx b/packages/pluggableWidgets/signature-web/src/assets/icons.tsx new file mode 100644 index 0000000000..c9c1c4b118 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/assets/icons.tsx @@ -0,0 +1,15 @@ +import { ReactElement } from "react"; +export function EventsIcon({ isActive }: { isActive?: boolean }): ReactElement { + return ( + + + + + + ); +} diff --git a/packages/customWidgets/signature-web/src/components/Alert.tsx b/packages/pluggableWidgets/signature-web/src/components/Alert.tsx similarity index 100% rename from packages/customWidgets/signature-web/src/components/Alert.tsx rename to packages/pluggableWidgets/signature-web/src/components/Alert.tsx diff --git a/packages/customWidgets/signature-web/src/components/Grid.tsx b/packages/pluggableWidgets/signature-web/src/components/Grid.tsx similarity index 100% rename from packages/customWidgets/signature-web/src/components/Grid.tsx rename to packages/pluggableWidgets/signature-web/src/components/Grid.tsx diff --git a/packages/pluggableWidgets/signature-web/src/components/Signature.tsx b/packages/pluggableWidgets/signature-web/src/components/Signature.tsx new file mode 100644 index 0000000000..0d248f9d88 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/components/Signature.tsx @@ -0,0 +1,99 @@ +import classNames from "classnames"; +import { ReactElement, useEffect, useRef } from "react"; +// import ReactResizeDetector from "react-resize-detector"; +import SignaturePad, { Options } from "signature_pad"; + +import { Alert } from "./Alert"; +import { Grid } from "./Grid"; +import { Dimensions, SizeContainer } from "./SizeContainer"; +import { SignatureContainerProps } from "typings/SignatureProps"; +import Utils from "../utils/Utils"; + +export type penOptions = "fountain" | "ballpoint" | "marker"; + +export interface SignatureProps extends Dimensions, SignatureContainerProps { + className: string; + alertMessage?: string; + clearSignature: boolean; + showGrid: boolean; + gridCellWidth: number; + gridCellHeight: number; + gridBorderColor: string; + gridBorderWidth: number; + penType: penOptions; + penColor: string; + onSignEndAction?: (imageUrl?: string) => void; + wrapperStyle?: object; + readOnly: boolean; +} + +export function SignatureComponent(props: SignatureProps): ReactElement { + const { className, alertMessage, wrapperStyle } = props; + const canvasRef = useRef(null); + const signaturePadRef = useRef(null); + + const handleSignEnd = (): void => { + const imageDataUrl = signaturePadRef.current?.toDataURL(); + + if (imageDataUrl) { + props.imageSource.setValue(Utils.convertUrlToBlob(imageDataUrl)); + } + // Trigger microflow to update signature attribute + if (props.onSignEndAction) { + props.onSignEndAction(signaturePadRef.current?.toDataURL()); + } + }; + + const signaturePadOptions = (): Options => { + let options: Options = {}; + if (props.penType === "fountain") { + options = { minWidth: 0.6, maxWidth: 2.6, velocityFilterWeight: 0.6 }; + } else if (props.penType === "ballpoint") { + options = { minWidth: 1.4, maxWidth: 1.5, velocityFilterWeight: 1.5 }; + } else if (props.penType === "marker") { + options = { minWidth: 2, maxWidth: 4, velocityFilterWeight: 0.9 }; + } + return options; + }; + + useEffect(() => { + if (canvasRef.current) { + signaturePadRef.current = new SignaturePad(canvasRef.current, { + penColor: props.penColor, + ...signaturePadOptions() + }); + signaturePadRef.current.addEventListener("endStroke", handleSignEnd); + if (props.readOnly) { + signaturePadRef.current?.off(); + } + } + }, []); + + const onResize = (): void => { + if (canvasRef.current) { + const data = signaturePadRef.current?.toData(); + canvasRef.current.width = + canvasRef.current && canvasRef.current.parentElement ? canvasRef.current.parentElement.offsetWidth : 0; + canvasRef.current.height = + canvasRef.current && canvasRef.current.parentElement ? canvasRef.current.parentElement.offsetHeight : 0; + signaturePadRef.current?.clear(); + if (data) { + signaturePadRef.current?.fromData(data); + } + } + }; + + return ( + + {alertMessage} + + + + ); +} diff --git a/packages/customWidgets/signature-web/src/components/SizeContainer.ts b/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts similarity index 100% rename from packages/customWidgets/signature-web/src/components/SizeContainer.ts rename to packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts diff --git a/packages/customWidgets/signature-web/src/package.xml b/packages/pluggableWidgets/signature-web/src/package.xml similarity index 69% rename from packages/customWidgets/signature-web/src/package.xml rename to packages/pluggableWidgets/signature-web/src/package.xml index c6977cb8b1..4be148fd4a 100644 --- a/packages/customWidgets/signature-web/src/package.xml +++ b/packages/pluggableWidgets/signature-web/src/package.xml @@ -1,11 +1,11 @@ - + - + diff --git a/packages/customWidgets/signature-web/src/ui/Signature.scss b/packages/pluggableWidgets/signature-web/src/ui/Signature.scss similarity index 100% rename from packages/customWidgets/signature-web/src/ui/Signature.scss rename to packages/pluggableWidgets/signature-web/src/ui/Signature.scss diff --git a/packages/pluggableWidgets/signature-web/src/ui/SignaturePreview.css b/packages/pluggableWidgets/signature-web/src/ui/SignaturePreview.css new file mode 100644 index 0000000000..1ca1d4921c --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/ui/SignaturePreview.css @@ -0,0 +1,22 @@ +.widget-events-preview { + font-size: 12px; + color: #6b707b; + border: 1px solid #d9dbdd; + min-height: 5px; + min-width: 100%; + text-align: center; + padding: 8px; + display: flex; + justify-content: center; + background-color: #fff; +} + +.widget-events-preview.active { + background-color: var(--color-alpha-grey-2); +} + +.widget-events-icon-container { + display: flex; + justify-content: center; + align-items: center; +} diff --git a/packages/customWidgets/signature-web/src/utils/Utils.ts b/packages/pluggableWidgets/signature-web/src/utils/Utils.ts similarity index 100% rename from packages/customWidgets/signature-web/src/utils/Utils.ts rename to packages/pluggableWidgets/signature-web/src/utils/Utils.ts diff --git a/packages/customWidgets/signature-web/src/utils/useResizeObserver.ts b/packages/pluggableWidgets/signature-web/src/utils/useResizeObserver.ts similarity index 100% rename from packages/customWidgets/signature-web/src/utils/useResizeObserver.ts rename to packages/pluggableWidgets/signature-web/src/utils/useResizeObserver.ts diff --git a/packages/customWidgets/signature-web/tsconfig.json b/packages/pluggableWidgets/signature-web/tsconfig.json similarity index 63% rename from packages/customWidgets/signature-web/tsconfig.json rename to packages/pluggableWidgets/signature-web/tsconfig.json index b6e01a9e22..7aa60df0c9 100644 --- a/packages/customWidgets/signature-web/tsconfig.json +++ b/packages/pluggableWidgets/signature-web/tsconfig.json @@ -1,15 +1,15 @@ { + "include": ["./src", "./typings"], "compilerOptions": { - "rootDir": "./", - "outDir": "dist/tsc/", + "baseUrl": "./", "noEmitOnError": true, "sourceMap": true, "module": "esnext", - "target": "es5", - "lib": ["es2015", "dom"], + "target": "es6", + "lib": ["esnext", "dom"], + "types": ["jest", "node"], "moduleResolution": "node", "declaration": false, - "removeComments": true, "noLib": false, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, @@ -18,11 +18,13 @@ "skipLibCheck": true, "noUnusedLocals": true, "noUnusedParameters": true, + "jsx": "react-jsx", "allowSyntheticDefaultImports": true, "esModuleInterop": true, - "jsx": "react-jsx" - }, - "files": ["./node_modules/mendix-client/index.d.ts"], - "include": ["./src", "./typings"], - "exclude": ["dist/", "node_modules/", "tests/", "scripts/"] + "useUnknownInCatchVariables": false, + "exactOptionalPropertyTypes": false, + "paths": { + "react-hot-loader/root": ["./hot-typescript.ts"] + } + } } diff --git a/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts b/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts new file mode 100644 index 0000000000..be5646bfc3 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts @@ -0,0 +1,59 @@ +/** + * This file was generated from Signature.xml + * WARNING: All changes made to this file will be overwritten + * @author Mendix Widgets Framework Team + */ +import { CSSProperties } from "react"; +import { EditableValue, EditableImageValue, WebImage } from "mendix"; + +export type PenTypeEnum = "fountain" | "ballpoint" | "marker"; + +export type WidthUnitEnum = "percentage" | "pixels"; + +export type HeightUnitEnum = "percentageOfWidth" | "pixels" | "percentageOfParent"; + +export interface SignatureContainerProps { + name: string; + class: string; + style?: CSSProperties; + tabIndex?: number; + imageSource: EditableImageValue; + hasSignatureAttribute?: EditableValue; + penType: PenTypeEnum; + penColor: string; + widthUnit: WidthUnitEnum; + width: number; + heightUnit: HeightUnitEnum; + height: number; + showGrid: boolean; + gridBorderColor: string; + gridCellHeight: number; + gridCellWidth: number; + gridBorderWidth: number; +} + +export interface SignaturePreviewProps { + /** + * @deprecated Deprecated since version 9.18.0. Please use class property instead. + */ + className: string; + class: string; + style: string; + styleObject?: CSSProperties; + readOnly: boolean; + renderMode: "design" | "xray" | "structure"; + translate: (text: string) => string; + imageSource: { type: "static"; imageUrl: string; } | { type: "dynamic"; entity: string; } | null; + hasSignatureAttribute: string; + penType: PenTypeEnum; + penColor: string; + widthUnit: WidthUnitEnum; + width: number | null; + heightUnit: HeightUnitEnum; + height: number | null; + showGrid: boolean; + gridBorderColor: string; + gridCellHeight: number | null; + gridCellWidth: number | null; + gridBorderWidth: number | null; +} diff --git a/packages/pluggableWidgets/signature-web/typings/declare-svg.ts b/packages/pluggableWidgets/signature-web/typings/declare-svg.ts new file mode 100644 index 0000000000..e6958d5a9f --- /dev/null +++ b/packages/pluggableWidgets/signature-web/typings/declare-svg.ts @@ -0,0 +1,4 @@ +declare module "*.svg" { + const content: string; + export = content; +} From 8141869b1cfb4e0595c0814e1011fb20029e9a08 Mon Sep 17 00:00:00 2001 From: gjulivan Date: Fri, 13 Mar 2026 10:52:23 +0100 Subject: [PATCH 2/7] feat(signature): refactoring and rearrange codes --- .../src/components/Signature.tsx | 77 +- .../src/components/SizeContainer.ts | 12 +- .../signature-web/src/utils/customTypes.ts | 30 + .../src/utils/useSignaturePad.ts | 76 ++ pnpm-lock.yaml | 872 +++--------------- 5 files changed, 246 insertions(+), 821 deletions(-) create mode 100644 packages/pluggableWidgets/signature-web/src/utils/customTypes.ts create mode 100644 packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts diff --git a/packages/pluggableWidgets/signature-web/src/components/Signature.tsx b/packages/pluggableWidgets/signature-web/src/components/Signature.tsx index 0d248f9d88..8ae76c77bd 100644 --- a/packages/pluggableWidgets/signature-web/src/components/Signature.tsx +++ b/packages/pluggableWidgets/signature-web/src/components/Signature.tsx @@ -1,85 +1,40 @@ import classNames from "classnames"; -import { ReactElement, useEffect, useRef } from "react"; -// import ReactResizeDetector from "react-resize-detector"; -import SignaturePad, { Options } from "signature_pad"; +import { ReactElement } from "react"; +import { useSignaturePad } from "src/utils/useSignaturePad"; +import Utils from "../utils/Utils"; +import { SignatureProps } from "../utils/customTypes"; import { Alert } from "./Alert"; import { Grid } from "./Grid"; -import { Dimensions, SizeContainer } from "./SizeContainer"; -import { SignatureContainerProps } from "typings/SignatureProps"; -import Utils from "../utils/Utils"; - -export type penOptions = "fountain" | "ballpoint" | "marker"; - -export interface SignatureProps extends Dimensions, SignatureContainerProps { - className: string; - alertMessage?: string; - clearSignature: boolean; - showGrid: boolean; - gridCellWidth: number; - gridCellHeight: number; - gridBorderColor: string; - gridBorderWidth: number; - penType: penOptions; - penColor: string; - onSignEndAction?: (imageUrl?: string) => void; - wrapperStyle?: object; - readOnly: boolean; -} +import { SizeContainer } from "./SizeContainer"; export function SignatureComponent(props: SignatureProps): ReactElement { - const { className, alertMessage, wrapperStyle } = props; - const canvasRef = useRef(null); - const signaturePadRef = useRef(null); - - const handleSignEnd = (): void => { - const imageDataUrl = signaturePadRef.current?.toDataURL(); + const { className, alertMessage, wrapperStyle, imageSource, hasSignatureAttribute, onSignEndAction } = props; + const handleSignEnd = (imageDataUrl?: string): void => { if (imageDataUrl) { - props.imageSource.setValue(Utils.convertUrlToBlob(imageDataUrl)); + imageSource.setValue(Utils.convertUrlToBlob(imageDataUrl)); } - // Trigger microflow to update signature attribute - if (props.onSignEndAction) { - props.onSignEndAction(signaturePadRef.current?.toDataURL()); + + if (hasSignatureAttribute) { + hasSignatureAttribute.setValue(true); } - }; - const signaturePadOptions = (): Options => { - let options: Options = {}; - if (props.penType === "fountain") { - options = { minWidth: 0.6, maxWidth: 2.6, velocityFilterWeight: 0.6 }; - } else if (props.penType === "ballpoint") { - options = { minWidth: 1.4, maxWidth: 1.5, velocityFilterWeight: 1.5 }; - } else if (props.penType === "marker") { - options = { minWidth: 2, maxWidth: 4, velocityFilterWeight: 0.9 }; + // Trigger microflow to update signature attribute + if (onSignEndAction) { + onSignEndAction(imageDataUrl); } - return options; }; - useEffect(() => { - if (canvasRef.current) { - signaturePadRef.current = new SignaturePad(canvasRef.current, { - penColor: props.penColor, - ...signaturePadOptions() - }); - signaturePadRef.current.addEventListener("endStroke", handleSignEnd); - if (props.readOnly) { - signaturePadRef.current?.off(); - } - } - }, []); + const { canvasRef, signaturePadRef } = useSignaturePad(props, handleSignEnd); const onResize = (): void => { if (canvasRef.current) { - const data = signaturePadRef.current?.toData(); canvasRef.current.width = canvasRef.current && canvasRef.current.parentElement ? canvasRef.current.parentElement.offsetWidth : 0; canvasRef.current.height = canvasRef.current && canvasRef.current.parentElement ? canvasRef.current.parentElement.offsetHeight : 0; - signaturePadRef.current?.clear(); - if (data) { - signaturePadRef.current?.fromData(data); - } + signaturePadRef.current?.redraw(); } }; diff --git a/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts b/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts index 1292751c64..5e73057bf5 100644 --- a/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts +++ b/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts @@ -1,17 +1,7 @@ import { createElement, CSSProperties, FC, PropsWithChildren } from "react"; import classNames from "classnames"; import { useResizeObserver } from "../utils/useResizeObserver"; - -export type HeightUnitType = "percentageOfWidth" | "percentageOfParent" | "pixels"; - -export type WidthUnitType = "percentage" | "pixels"; - -export interface Dimensions { - widthUnit: WidthUnitType; - width: number; - heightUnit: HeightUnitType; - height: number; -} +import { Dimensions, HeightUnitType, WidthUnitType } from "../utils/customTypes"; export interface SizeProps extends Dimensions, PropsWithChildren { className: string; diff --git a/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts b/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts new file mode 100644 index 0000000000..7b98fb953a --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts @@ -0,0 +1,30 @@ +import { SignatureContainerProps } from "typings/SignatureProps"; + +export type HeightUnitType = "percentageOfWidth" | "percentageOfParent" | "pixels"; + +export type WidthUnitType = "percentage" | "pixels"; + +export interface Dimensions { + widthUnit: WidthUnitType; + width: number; + heightUnit: HeightUnitType; + height: number; +} + +export type penOptions = "fountain" | "ballpoint" | "marker"; + +export interface SignatureProps extends Dimensions, SignatureContainerProps { + className: string; + alertMessage?: string; + clearSignature: boolean; + showGrid: boolean; + gridCellWidth: number; + gridCellHeight: number; + gridBorderColor: string; + gridBorderWidth: number; + penType: penOptions; + penColor: string; + onSignEndAction?: (imageUrl?: string) => void; + wrapperStyle?: object; + readOnly: boolean; +} diff --git a/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts b/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts new file mode 100644 index 0000000000..bacbf0e485 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts @@ -0,0 +1,76 @@ +import { RefObject, useCallback, useEffect, useMemo, useRef } from "react"; +import SignaturePad, { Options } from "signature_pad"; +import { SignatureProps } from "./customTypes"; + +export function useSignaturePad( + props: Pick, + onSignEnd?: (imageDataURL?: string) => void +): { + signaturePadRef: RefObject; + canvasRef: RefObject; +} { + const { readOnly, imageSource, hasSignatureAttribute, penType, penColor } = props; + const signaturePadRef = useRef(null); + const canvasRef = useRef(null); + const hasSignature = useRef(false); + + useEffect(() => { + if (readOnly) { + signaturePadRef.current?.off(); + } else { + signaturePadRef.current?.on(); + } + }, [readOnly]); + + useEffect(() => { + if (imageSource?.status === "available" && imageSource.value?.uri && signaturePadRef.current?.isEmpty()) { + signaturePadRef.current?.fromDataURL(imageSource.value.uri); + } + }, [imageSource]); + + useEffect(() => { + if (hasSignatureAttribute?.status === "available") { + if (hasSignatureAttribute?.value !== hasSignature.current) { + if (hasSignature.current === true) { + signaturePadRef.current?.clear(); + } + hasSignature.current = !!hasSignatureAttribute?.value; + } + } + }, [hasSignatureAttribute?.status, hasSignatureAttribute?.value]); + + const signaturePadOptions: Options = useMemo(() => { + let options: Options = {}; + if (penType === "fountain") { + options = { minWidth: 0.6, maxWidth: 2.6, velocityFilterWeight: 0.6 }; + } else if (penType === "ballpoint") { + options = { minWidth: 1.4, maxWidth: 1.5, velocityFilterWeight: 1.5 }; + } else if (penType === "marker") { + options = { minWidth: 2, maxWidth: 4, velocityFilterWeight: 0.9 }; + } + return options; + }, [penType]); + + const handleSignEnd = useCallback(() => { + const imageDataUrl = signaturePadRef.current?.toDataURL(); + + if (imageDataUrl && onSignEnd) { + onSignEnd(imageDataUrl); + } + }, [onSignEnd]); + + useEffect(() => { + if (canvasRef.current) { + signaturePadRef.current = new SignaturePad(canvasRef.current, { + penColor, + ...signaturePadOptions + }); + signaturePadRef.current.addEventListener("endStroke", handleSignEnd); + if (readOnly) { + signaturePadRef.current?.off(); + } + } + }, [handleSignEnd, penColor, readOnly, signaturePadOptions]); + + return { signaturePadRef, canvasRef }; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eb562c6e32..ea87af6750 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -245,70 +245,6 @@ importers: specifier: ^5.0.1 version: 5.0.1 - packages/customWidgets/signature-web: - dependencies: - classnames: - specifier: ^2.5.1 - version: 2.5.1 - signature_pad: - specifier: 5.1.3 - version: 5.1.3 - devDependencies: - '@mendix/automation-utils': - specifier: workspace:* - version: link:../../../automation/utils - '@mendix/eslint-config-web-widgets': - specifier: workspace:* - version: link:../../shared/eslint-config-web-widgets - '@mendix/pluggable-widgets-tools': - specifier: 11.8.0 - version: 11.8.0(@jest/transform@29.7.0)(@jest/types@30.2.0)(@swc/core@1.13.5)(@types/babel__core@7.20.5)(@types/node@22.14.1)(eslint@9.39.3(jiti@2.6.1))(jest-util@30.2.0)(prettier@3.8.1)(react-dom@18.3.1(react@18.3.1))(react-native@0.82.0(@babel/core@7.29.0)(@types/react@19.2.2)(react@18.3.1))(react@18.3.1)(tslib@2.8.1) - '@mendix/prettier-config-web-widgets': - specifier: workspace:* - version: link:../../shared/prettier-config-web-widgets - copy-webpack-plugin: - specifier: ^11.0.0 - version: 11.0.0(webpack@5.102.1) - css-loader: - specifier: ^6.7.3 - version: 6.11.0(webpack@5.102.1) - eslint: - specifier: ^9.39.3 - version: 9.39.3(jiti@2.6.1) - jest-canvas-mock: - specifier: ^2.4.0 - version: 2.5.2 - loader-utils: - specifier: ^1.4.2 - version: 1.4.2 - mendix-client: - specifier: ^7.15.8 - version: 7.15.8 - mini-css-extract-plugin: - specifier: ^2.7.2 - version: 2.9.4(webpack@5.102.1) - sass-loader: - specifier: ^13.2.0 - version: 13.3.3(sass@1.93.2)(webpack@5.102.1) - to-string-loader: - specifier: ^1.1.6 - version: 1.2.0 - ts-loader: - specifier: ^9.4.2 - version: 9.5.4(typescript@5.9.3)(webpack@5.102.1) - ts-node: - specifier: 10.9.2 - version: 10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3) - typescript: - specifier: '>5.8.0' - version: 5.9.3 - webpack: - specifier: ^5.75.0 - version: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - webpack-cli: - specifier: ^5.0.1 - version: 5.1.4(webpack@5.102.1) - packages/modules/calendar: dependencies: '@mendix/calendar-web': @@ -2299,6 +2235,52 @@ importers: specifier: ^7.0.3 version: 7.0.3 + packages/pluggableWidgets/signature-web: + dependencies: + '@uiw/react-signature': + specifier: ^1.3.4 + version: 1.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + classnames: + specifier: ^2.5.1 + version: 2.5.1 + react-resize-detector: + specifier: ^12.3.0 + version: 12.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + signature_pad: + specifier: ^5.1.3 + version: 5.1.3 + devDependencies: + '@mendix/automation-utils': + specifier: workspace:* + version: link:../../../automation/utils + '@mendix/eslint-config-web-widgets': + specifier: workspace:* + version: link:../../shared/eslint-config-web-widgets + '@mendix/pluggable-widgets-tools': + specifier: 11.8.0 + version: 11.8.0(@jest/transform@29.7.0)(@jest/types@30.2.0)(@swc/core@1.13.5)(@types/babel__core@7.20.5)(@types/node@22.14.1)(eslint@9.39.3(jiti@2.6.1))(jest-util@30.2.0)(prettier@3.8.1)(react-dom@18.3.1(react@18.3.1))(react-native@0.82.0(@babel/core@7.29.0)(@types/react@19.2.2)(react@18.3.1))(react@18.3.1)(tslib@2.8.1) + '@mendix/prettier-config-web-widgets': + specifier: workspace:* + version: link:../../shared/prettier-config-web-widgets + '@mendix/run-e2e': + specifier: workspace:^* + version: link:../../../automation/run-e2e + '@mendix/widget-plugin-component-kit': + specifier: workspace:* + version: link:../../shared/widget-plugin-component-kit + '@mendix/widget-plugin-hooks': + specifier: workspace:* + version: link:../../shared/widget-plugin-hooks + '@mendix/widget-plugin-platform': + specifier: workspace:* + version: link:../../shared/widget-plugin-platform + '@mendix/widget-plugin-test-utils': + specifier: workspace:* + version: link:../../shared/widget-plugin-test-utils + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + packages/pluggableWidgets/skiplink-web: dependencies: '@floating-ui/react': @@ -3952,10 +3934,6 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@discoveryjs/json-ext@0.5.7': - resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} - engines: {node: '>=10.0.0'} - '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -4951,15 +4929,9 @@ packages: '@types/deep-equal@1.0.4': resolution: {integrity: sha512-tqdiS4otQP4KmY0PR3u6KbZ5EWvhNdUoS/jc93UuK23C220lOZ/9TvjfxdPcKvqwwDVtmtSCrnr0p/2dirAxkA==} - '@types/dojo@1.9.48': - resolution: {integrity: sha512-+/wltO++J0mmLoPa+mqElzilBahIfSY5Lz3o7RJkyIB0GDPnWhw3RUxU+xuZRCJE7uOFnNgqTdL76n/E0wDJ5w==} - '@types/enzyme@3.10.19': resolution: {integrity: sha512-kIfCo6/DdpgCHgmrLgPTugjzbZ46BUK8S2IP0kYo8+62LD2l1k8mSVsc+zQYNTdjDRoh2E9Spxu6F1NnEiW38Q==} - '@types/eslint-scope@3.7.7': - resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} - '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} @@ -5216,91 +5188,21 @@ packages: react: '>=18.0.0 <19.0.0' react-dom: '>=18.0.0 <19.0.0' - '@vis.gl/react-google-maps@0.8.3': - resolution: {integrity: sha512-iubZIH9MJSkJA9NCMwKkMlHb/iNSeXzVRE7fPVhkKJPId6TBvQcpKA98tirUXi2AfEkYL+IVcE3doL6WdeQ2QA==} + '@uiw/react-signature@1.3.4': + resolution: {integrity: sha512-jmukgdpHJJMJ5aDYi7ijv85tVc5MADkof6JOoQm8a3wQ37qi3GG34YMTEKjQFXqOnjU0/gnbxrTR4DA+Lp4btg==} peerDependencies: react: '>=18.0.0 <19.0.0' react-dom: '>=18.0.0 <19.0.0' - '@webassemblyjs/ast@1.14.1': - resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} - - '@webassemblyjs/floating-point-hex-parser@1.13.2': - resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} - - '@webassemblyjs/helper-api-error@1.13.2': - resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} - - '@webassemblyjs/helper-buffer@1.14.1': - resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} - - '@webassemblyjs/helper-numbers@1.13.2': - resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} - - '@webassemblyjs/helper-wasm-bytecode@1.13.2': - resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} - - '@webassemblyjs/helper-wasm-section@1.14.1': - resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} - - '@webassemblyjs/ieee754@1.13.2': - resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} - - '@webassemblyjs/leb128@1.13.2': - resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} - - '@webassemblyjs/utf8@1.13.2': - resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} - - '@webassemblyjs/wasm-edit@1.14.1': - resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} - - '@webassemblyjs/wasm-gen@1.14.1': - resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} - - '@webassemblyjs/wasm-opt@1.14.1': - resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} - - '@webassemblyjs/wasm-parser@1.14.1': - resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} - - '@webassemblyjs/wast-printer@1.14.1': - resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} - - '@webpack-cli/configtest@2.1.1': - resolution: {integrity: sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==} - engines: {node: '>=14.15.0'} - peerDependencies: - webpack: 5.x.x - webpack-cli: 5.x.x - - '@webpack-cli/info@2.0.2': - resolution: {integrity: sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==} - engines: {node: '>=14.15.0'} - peerDependencies: - webpack: 5.x.x - webpack-cli: 5.x.x - - '@webpack-cli/serve@2.0.5': - resolution: {integrity: sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==} - engines: {node: '>=14.15.0'} + '@vis.gl/react-google-maps@0.8.3': + resolution: {integrity: sha512-iubZIH9MJSkJA9NCMwKkMlHb/iNSeXzVRE7fPVhkKJPId6TBvQcpKA98tirUXi2AfEkYL+IVcE3doL6WdeQ2QA==} peerDependencies: - webpack: 5.x.x - webpack-cli: 5.x.x - webpack-dev-server: '*' - peerDependenciesMeta: - webpack-dev-server: - optional: true + react: '>=18.0.0 <19.0.0' + react-dom: '>=18.0.0 <19.0.0' '@xml-tools/parser@1.0.11': resolution: {integrity: sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==} - '@xtuc/ieee754@1.2.0': - resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} - - '@xtuc/long@4.2.2': - resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - '@zxing/library@0.21.3': resolution: {integrity: sha512-hZHqFe2JyH/ZxviJZosZjV+2s6EDSY0O24R+FQmlWZBZXP9IqMo7S3nb3+2LBWxodJQkSurdQGnqE7KXqrYgow==} engines: {node: '>= 10.4.0'} @@ -5334,12 +5236,6 @@ packages: acorn-globals@7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} - acorn-import-phases@1.0.4: - resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} - engines: {node: '>=10.13.0'} - peerDependencies: - acorn: ^8.14.0 - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -5372,14 +5268,6 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ajv-formats@2.1.1: - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -5388,11 +5276,6 @@ packages: ajv: optional: true - ajv-keywords@5.1.0: - resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} - peerDependencies: - ajv: ^8.8.2 - ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -5641,10 +5524,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - baseline-browser-mapping@2.8.16: - resolution: {integrity: sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==} - hasBin: true - big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} @@ -5700,11 +5579,6 @@ packages: brandi@5.0.0: resolution: {integrity: sha512-oztvITQgvuFb2K+NWdHLx0mMH8TGO3ASrQ43FZzmfiq5rCj0DRlsuZ6Efi/yeu3hyGx/Y+Z1xLGp2qzDWpiNYA==} - browserslist@4.26.3: - resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - browserslist@4.28.1: resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -5757,9 +5631,6 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001750: - resolution: {integrity: sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==} - caniuse-lite@1.0.30001778: resolution: {integrity: sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==} @@ -5811,10 +5682,6 @@ packages: engines: {node: '>=12.13.0'} hasBin: true - chrome-trace-event@1.0.4: - resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} - engines: {node: '>=6.0'} - chromium-edge-launcher@0.2.0: resolution: {integrity: sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==} @@ -5916,9 +5783,6 @@ packages: colorette@1.4.0: resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - colors@1.4.0: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} engines: {node: '>=0.1.90'} @@ -6024,12 +5888,6 @@ packages: engines: {node: '>=10'} hasBin: true - copy-webpack-plugin@11.0.0: - resolution: {integrity: sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==} - engines: {node: '>= 14.15.0'} - peerDependencies: - webpack: ^5.1.0 - core-js-compat@3.46.0: resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==} @@ -6118,18 +5976,6 @@ packages: css-global-keywords@1.0.1: resolution: {integrity: sha512-X1xgQhkZ9n94WDwntqst5D/FKkmiU0GlJSFZSV3kLvyJ1WC5VeyoXDOuleUD+SIuH9C7W05is++0Woh0CGfKjQ==} - css-loader@6.11.0: - resolution: {integrity: sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==} - engines: {node: '>= 12.13.0'} - peerDependencies: - '@rspack/core': 0.x || 1.x - webpack: ^5.0.0 - peerDependenciesMeta: - '@rspack/core': - optional: true - webpack: - optional: true - css-select@4.3.0: resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} @@ -6155,9 +6001,6 @@ packages: engines: {node: '>=4'} hasBin: true - cssfontparser@1.2.1: - resolution: {integrity: sha512-6tun4LoZnj7VN6YeegOVb67KBX/7JJsqvj+pv3ZA7F878/eN33AbGa5b/S/wXxS/tcp8nc40xRUrsPlxIyNUPg==} - cssnano-preset-default@5.2.14: resolution: {integrity: sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==} engines: {node: ^10 || ^12 || >=14.0} @@ -6518,9 +6361,6 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.237: - resolution: {integrity: sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==} - electron-to-chromium@1.5.313: resolution: {integrity: sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==} @@ -6558,10 +6398,6 @@ packages: end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - enhanced-resolve@5.18.3: - resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} - engines: {node: '>=10.13.0'} - enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} @@ -6581,11 +6417,6 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} - envinfo@7.18.0: - resolution: {integrity: sha512-02QGCLRW+Jb8PC270ic02lat+N57iBaWsvHjcJViqp6UVupRB+Vsg7brYPTqEFXvsdTql3KnSczv5ModZFpl8Q==} - engines: {node: '>=4'} - hasBin: true - errno@0.1.8: resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} hasBin: true @@ -6615,9 +6446,6 @@ packages: resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -6634,6 +6462,9 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + es-toolkit@1.45.1: + resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==} + es5-ext@0.10.64: resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} engines: {node: '>=0.10'} @@ -6957,10 +6788,6 @@ packages: resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} hasBin: true - fastest-levenshtein@1.0.16: - resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} - engines: {node: '>= 4.9.1'} - fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} @@ -7199,9 +7026,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me @@ -7253,10 +7077,6 @@ packages: resolution: {integrity: sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==} engines: {node: '>=8'} - globby@13.2.2: - resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - glsl-inject-defines@1.0.3: resolution: {integrity: sha512-W49jIhuDtF6w+7wCMcClk27a2hq8znvHtlGnrYkSWEr8tHe9eA2dcnohlcAmxLYBSpSSdzOkRdyPTrx9fw49+A==} @@ -7526,10 +7346,6 @@ packages: resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} - interpret@3.1.1: - resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} - engines: {node: '>=10.13.0'} - invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} @@ -7813,9 +7629,6 @@ packages: resolution: {integrity: sha512-YIThBuHzaIIcjxeuLmPD40SjxkEcc8i//sGMDKCgkRMVgIwRJf5qyExtlJpQeh7pkeoBSOe6lQEdg+/9uKg9mw==} hasBin: true - jest-canvas-mock@2.5.2: - resolution: {integrity: sha512-vgnpPupjOL6+L5oJXzxTxFrlGEIbHdZqFU+LFNdtLxZ3lRDCl17FlTMM7IatoRQkrcyOTMlDinjUguqmQ6bR2A==} - jest-changed-files@29.7.0: resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7972,10 +7785,6 @@ packages: resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-worker@27.5.1: - resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} - engines: {node: '>= 10.13.0'} - jest-worker@29.7.0: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8164,10 +7973,6 @@ packages: engines: {node: '>=8.0.0'} hasBin: true - loader-runner@4.3.1: - resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} - engines: {node: '>=6.11.5'} - loader-utils@1.4.2: resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==} engines: {node: '>=4.0.0'} @@ -8361,9 +8166,6 @@ packages: memoize-one@6.0.0: resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} - mendix-client@7.15.8: - resolution: {integrity: sha512-RazCdCHoLVNKUUeKDkSkIL6Lxx6fUaa4iiy+Ltp9ra8mLQhwyNqD33TIN7YZJ3HDjHc3eWh9cjiZWwh6Jg/cQg==} - mendix@10.24.75382: resolution: {integrity: sha512-ICMxqkWUejsc3KeFD9BJYvC+T4soi/NB2iapwWPC7oN0lCrFx36upzwI4rU77oMdRHsrVSsFVYLBy7sJJOABHw==} @@ -8498,12 +8300,6 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - mini-css-extract-plugin@2.9.4: - resolution: {integrity: sha512-ZWYT7ln73Hptxqxk2DxPU9MmapXRhxkJD6tkSR04dnQxm8BGu2hzgKLugK5yySD97u/8yy7Ma7E76k9ZdvtjkQ==} - engines: {node: '>= 12.13.0'} - peerDependencies: - webpack: ^5.0.0 - mini-svg-data-uri@1.4.4: resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} hasBin: true @@ -8571,9 +8367,6 @@ packages: moment@2.30.1: resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} - moo-color@1.0.3: - resolution: {integrity: sha512-i/+ZKXMDf6aqYtBhuOcej71YSlbjT3wCO/4H1j8rPvxDJEifdwgg5MaFyu6iYAT8GBZJg2z0dkgK4YMzvURALQ==} - mouse-change@1.4.0: resolution: {integrity: sha512-vpN0s+zLL2ykyyUDh+fayu9Xkor5v/zRD9jhSqjRS1cJTGS0+oakVZzNm5n19JvvEj0you+MXlYTpNxUDQUjkQ==} @@ -8660,9 +8453,6 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.23: - resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} - node-releases@2.0.36: resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} @@ -8923,6 +8713,9 @@ packages: engines: {node: '>=10'} hasBin: true + perfect-freehand@1.2.3: + resolution: {integrity: sha512-bHZSfqDHGNlPpgH2yxXgPHlQSPpEbo+qg7li0M78J9vNAi2yjwLeA4x79BEQhX44lEWpCLSFCeRZwpw0niiXPA==} + performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} @@ -9519,6 +9312,12 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} + react-resize-detector@12.3.0: + resolution: {integrity: sha512-mIDOVrTHKGnKe6qEUWi8dFdfHM5CPyTOpqoHctdMQf89Ljm/0qqDIzkP3vTRZZJi9/raaMiRxDEOqO4you5x+A==} + peerDependencies: + react: '>=18.0.0 <19.0.0' + react-dom: '>=18.0.0 <19.0.0' + react-test-renderer@19.2.4: resolution: {integrity: sha512-Ttl5D7Rnmi6JGMUpri4UjB4BAN0FPs4yRDnu2XSsigCWOLm11o8GwRlVsh27ER+4WFqsGtrBuuv5zumUaRCmKw==} peerDependencies: @@ -9562,10 +9361,6 @@ packages: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} - rechoir@0.8.0: - resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} - engines: {node: '>= 10.13.0'} - recursive-copy@2.0.14: resolution: {integrity: sha512-K8WNY8f8naTpfbA+RaXmkaQuD1IeW9EgNEfyGxSqqTQukpVtoOKros9jUqbpEsSw59YOmpd8nCBgtqJZy5nvog==} @@ -9782,25 +9577,6 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sass-loader@13.3.3: - resolution: {integrity: sha512-mt5YN2F1MOZr3d/wBRcZxeFgwgkH44wVc2zohO2YF6JiOMkiXe4BYRZpSu2sO1g71mo/j16txzUhsKZlqjVGzA==} - engines: {node: '>= 14.15.0'} - peerDependencies: - fibers: '>= 3.1.0' - node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - sass: ^1.3.0 - sass-embedded: '*' - webpack: ^5.0.0 - peerDependenciesMeta: - fibers: - optional: true - node-sass: - optional: true - sass: - optional: true - sass-embedded: - optional: true - sass@1.93.2: resolution: {integrity: sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==} engines: {node: '>=14.0.0'} @@ -9823,10 +9599,6 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - schema-utils@4.3.3: - resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} - engines: {node: '>= 10.13.0'} - semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -9971,10 +9743,6 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - slash@4.0.0: - resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} - engines: {node: '>=12'} - smob@1.5.0: resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} @@ -10007,10 +9775,6 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} - spawn-command@0.0.2: resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} @@ -10245,10 +10009,6 @@ packages: tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} - engines: {node: '>=6'} - tar-fs@2.1.4: resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} @@ -10256,22 +10016,6 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} - terser-webpack-plugin@5.3.14: - resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@swc/core': '*' - esbuild: '*' - uglify-js: '*' - webpack: ^5.1.0 - peerDependenciesMeta: - '@swc/core': - optional: true - esbuild: - optional: true - uglify-js: - optional: true - terser@5.44.0: resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==} engines: {node: '>=10'} @@ -10341,9 +10085,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - to-string-loader@1.2.0: - resolution: {integrity: sha512-KsWUL8FccgBW9FPFm4vYoQbOOcO5m6hKOGYoXjbseD9/4Ft+ravXN5jolQ9kTKYcK4zPt1j+khx97GPGnVoi6A==} - toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -10404,13 +10145,6 @@ packages: jest-util: optional: true - ts-loader@9.5.4: - resolution: {integrity: sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==} - engines: {node: '>=12.0.0'} - peerDependencies: - typescript: '>5.8.0' - webpack: ^5.0.0 - ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -10596,12 +10330,6 @@ packages: unquote@1.1.1: resolution: {integrity: sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==} - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -10679,10 +10407,6 @@ packages: warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} - watchpack@2.4.4: - resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} - engines: {node: '>=10.13.0'} - wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} @@ -10703,41 +10427,6 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} - webpack-cli@5.1.4: - resolution: {integrity: sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==} - engines: {node: '>=14.15.0'} - hasBin: true - peerDependencies: - '@webpack-cli/generators': '*' - webpack: 5.x.x - webpack-bundle-analyzer: '*' - webpack-dev-server: '*' - peerDependenciesMeta: - '@webpack-cli/generators': - optional: true - webpack-bundle-analyzer: - optional: true - webpack-dev-server: - optional: true - - webpack-merge@5.10.0: - resolution: {integrity: sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==} - engines: {node: '>=10.0.0'} - - webpack-sources@3.3.3: - resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} - engines: {node: '>=10.13.0'} - - webpack@5.102.1: - resolution: {integrity: sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} @@ -10783,9 +10472,6 @@ packages: engines: {node: ^16.13.0 || >=18.0.0} hasBin: true - wildcard@2.0.1: - resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} - word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -11011,8 +10697,8 @@ snapshots: '@babel/generator@7.28.3': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 @@ -11229,22 +10915,22 @@ snapshots: '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.29.0)': dependencies: @@ -11269,67 +10955,67 @@ snapshots: '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': dependencies: @@ -11872,8 +11558,8 @@ snapshots: '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.29.0 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@babel/template@7.28.6': dependencies: @@ -12134,8 +11820,6 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@discoveryjs/json-ext@0.5.7': {} - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.3(jiti@2.6.1))': dependencies: eslint: 9.39.3(jiti@2.6.1) @@ -13364,24 +13048,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.29.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.29.0 '@types/big.js@6.2.2': {} @@ -13399,22 +13083,16 @@ snapshots: '@types/deep-equal@1.0.4': {} - '@types/dojo@1.9.48': {} - '@types/enzyme@3.10.19': dependencies: '@types/cheerio': 0.22.35 '@types/react': 19.2.2 - '@types/eslint-scope@3.7.7': - dependencies: - '@types/eslint': 9.6.1 - '@types/estree': 1.0.8 - '@types/eslint@9.6.1': dependencies: '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 + optional: true '@types/estree@1.0.8': {} @@ -13772,6 +13450,13 @@ snapshots: - '@codemirror/lint' - '@codemirror/search' + '@uiw/react-signature@1.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.28.6 + perfect-freehand: 1.2.3 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + '@vis.gl/react-google-maps@0.8.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@types/google.maps': 3.58.1 @@ -13779,105 +13464,10 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@webassemblyjs/ast@1.14.1': - dependencies: - '@webassemblyjs/helper-numbers': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - - '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - - '@webassemblyjs/helper-api-error@1.13.2': {} - - '@webassemblyjs/helper-buffer@1.14.1': {} - - '@webassemblyjs/helper-numbers@1.13.2': - dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.13.2 - '@webassemblyjs/helper-api-error': 1.13.2 - '@xtuc/long': 4.2.2 - - '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} - - '@webassemblyjs/helper-wasm-section@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/wasm-gen': 1.14.1 - - '@webassemblyjs/ieee754@1.13.2': - dependencies: - '@xtuc/ieee754': 1.2.0 - - '@webassemblyjs/leb128@1.13.2': - dependencies: - '@xtuc/long': 4.2.2 - - '@webassemblyjs/utf8@1.13.2': {} - - '@webassemblyjs/wasm-edit@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/helper-wasm-section': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-opt': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - '@webassemblyjs/wast-printer': 1.14.1 - - '@webassemblyjs/wasm-gen@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wasm-opt@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - - '@webassemblyjs/wasm-parser@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-api-error': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wast-printer@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@xtuc/long': 4.2.2 - - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.102.1)': - dependencies: - webpack: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.102.1) - - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.102.1)': - dependencies: - webpack: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.102.1) - - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.102.1)': - dependencies: - webpack: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.102.1) - '@xml-tools/parser@1.0.11': dependencies: chevrotain: 7.1.1 - '@xtuc/ieee754@1.2.0': {} - - '@xtuc/long@4.2.2': {} - '@zxing/library@0.21.3': dependencies: ts-custom-error: 3.3.1 @@ -13912,10 +13502,6 @@ snapshots: acorn: 8.15.0 acorn-walk: 8.3.4 - acorn-import-phases@1.0.4(acorn@8.15.0): - dependencies: - acorn: 8.15.0 - acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -13942,19 +13528,10 @@ snapshots: agent-base@7.1.4: {} - ajv-formats@2.1.1(ajv@8.17.1): - optionalDependencies: - ajv: 8.17.1 - ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 - ajv-keywords@5.1.0(ajv@8.17.1): - dependencies: - ajv: 8.17.1 - fast-deep-equal: 3.1.3 - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -14169,7 +13746,7 @@ snapshots: babel-plugin-istanbul@6.1.1: dependencies: - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-instrument: 5.2.1 @@ -14179,8 +13756,8 @@ snapshots: babel-plugin-jest-hoist@29.6.3: dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.28.0 @@ -14257,8 +13834,6 @@ snapshots: baseline-browser-mapping@2.10.0: {} - baseline-browser-mapping@2.8.16: {} - big.js@5.2.2: {} big.js@6.2.2: {} @@ -14322,14 +13897,6 @@ snapshots: brandi@5.0.0: {} - browserslist@4.26.3: - dependencies: - baseline-browser-mapping: 2.8.16 - caniuse-lite: 1.0.30001750 - electron-to-chromium: 1.5.237 - node-releases: 2.0.23 - update-browserslist-db: 1.1.3(browserslist@4.26.3) - browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.10.0 @@ -14382,13 +13949,11 @@ snapshots: caniuse-api@3.0.0: dependencies: - browserslist: 4.26.3 - caniuse-lite: 1.0.30001750 + browserslist: 4.28.1 + caniuse-lite: 1.0.30001778 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001750: {} - caniuse-lite@1.0.30001778: {} canvas-fit@1.5.0: @@ -14451,8 +14016,6 @@ snapshots: transitivePeerDependencies: - supports-color - chrome-trace-event@1.0.4: {} - chromium-edge-launcher@0.2.0: dependencies: '@types/node': 22.14.1 @@ -14568,8 +14131,6 @@ snapshots: colorette@1.4.0: {} - colorette@2.0.20: {} - colors@1.4.0: {} combined-stream@1.0.8: @@ -14676,16 +14237,6 @@ snapshots: glob: 10.5.0 glob-parent: 6.0.2 - copy-webpack-plugin@11.0.0(webpack@5.102.1): - dependencies: - fast-glob: 3.3.3 - glob-parent: 6.0.2 - globby: 13.2.2 - normalize-path: 3.0.0 - schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - webpack: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - core-js-compat@3.46.0: dependencies: browserslist: 4.28.1 @@ -14783,19 +14334,6 @@ snapshots: css-global-keywords@1.0.1: {} - css-loader@6.11.0(webpack@5.102.1): - dependencies: - icss-utils: 5.1.0(postcss@8.5.6) - postcss: 8.5.6 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.6) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.6) - postcss-modules-scope: 3.2.1(postcss@8.5.6) - postcss-modules-values: 4.0.0(postcss@8.5.6) - postcss-value-parser: 4.2.0 - semver: 7.7.3 - optionalDependencies: - webpack: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - css-select@4.3.0: dependencies: boolbase: 1.0.0 @@ -14819,8 +14357,6 @@ snapshots: cssesc@3.0.0: {} - cssfontparser@1.2.1: {} - cssnano-preset-default@5.2.14(postcss@8.5.6): dependencies: css-declaration-sorter: 6.4.1(postcss@8.5.6) @@ -15201,8 +14737,6 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.237: {} - electron-to-chromium@1.5.313: {} element-size@1.1.1: {} @@ -15229,11 +14763,6 @@ snapshots: dependencies: once: 1.4.0 - enhanced-resolve@5.18.3: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 @@ -15247,8 +14776,6 @@ snapshots: env-paths@2.2.1: {} - envinfo@7.18.0: {} - errno@0.1.8: dependencies: prr: 1.0.1 @@ -15353,8 +14880,6 @@ snapshots: iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 - es-module-lexer@1.7.0: {} - es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -15376,6 +14901,8 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + es-toolkit@1.45.1: {} + es5-ext@0.10.64: dependencies: es6-iterator: 2.0.3 @@ -15789,8 +15316,6 @@ snapshots: dependencies: strnum: 1.1.2 - fastest-levenshtein@1.0.16: {} - fastq@1.19.1: dependencies: reusify: 1.1.0 @@ -16067,8 +15592,6 @@ snapshots: dependencies: is-glob: 4.0.3 - glob-to-regexp@0.4.1: {} - glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -16137,14 +15660,6 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 - globby@13.2.2: - dependencies: - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 4.0.0 - glsl-inject-defines@1.0.3: dependencies: glsl-token-inject-block: 1.1.0 @@ -16440,8 +15955,6 @@ snapshots: interpret@1.4.0: {} - interpret@3.1.1: {} - invariant@2.2.4: dependencies: loose-envify: 1.4.0 @@ -16648,7 +16161,7 @@ snapshots: istanbul-lib-instrument@5.2.1: dependencies: '@babel/core': 7.29.0 - '@babel/parser': 7.28.4 + '@babel/parser': 7.29.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -16658,7 +16171,7 @@ snapshots: istanbul-lib-instrument@6.0.3: dependencies: '@babel/core': 7.29.0 - '@babel/parser': 7.28.4 + '@babel/parser': 7.29.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 7.7.4 @@ -16710,11 +16223,6 @@ snapshots: glob: 7.2.3 jasmine-core: 3.99.1 - jest-canvas-mock@2.5.2: - dependencies: - cssfontparser: 1.2.1 - moo-color: 1.0.3 - jest-changed-files@29.7.0: dependencies: execa: 5.1.1 @@ -17092,12 +16600,6 @@ snapshots: jest-util: 29.7.0 string-length: 4.0.2 - jest-worker@27.5.1: - dependencies: - '@types/node': 22.14.1 - merge-stream: 2.0.0 - supports-color: 8.1.1 - jest-worker@29.7.0: dependencies: '@types/node': 22.14.1 @@ -17321,8 +16823,6 @@ snapshots: - bufferutil - utf-8-validate - loader-runner@4.3.1: {} - loader-utils@1.4.2: dependencies: big.js: 5.2.2 @@ -17537,11 +17037,6 @@ snapshots: memoize-one@6.0.0: {} - mendix-client@7.15.8: - dependencies: - '@types/big.js': 6.2.2 - '@types/dojo': 1.9.48 - mendix@10.24.75382: dependencies: '@types/big.js': 6.2.2 @@ -17768,12 +17263,6 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.9.4(webpack@5.102.1): - dependencies: - schema-utils: 4.3.3 - tapable: 2.3.0 - webpack: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - mini-svg-data-uri@1.4.4: {} minimatch@10.2.4: @@ -17840,10 +17329,6 @@ snapshots: moment@2.30.1: {} - moo-color@1.0.3: - dependencies: - color-name: 1.1.4 - mouse-change@1.4.0: dependencies: mouse-event: 1.0.5 @@ -17913,8 +17398,6 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.23: {} - node-releases@2.0.36: {} nopt@7.2.1: @@ -18176,6 +17659,8 @@ snapshots: peggy@1.2.0: {} + perfect-freehand@1.2.3: {} + performance-now@2.1.0: {} pick-by-alias@1.2.0: {} @@ -18286,7 +17771,7 @@ snapshots: postcss-colormin@5.3.1(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.28.1 caniuse-api: 3.0.0 colord: 2.9.3 postcss: 8.5.6 @@ -18294,7 +17779,7 @@ snapshots: postcss-convert-values@5.1.3(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.28.1 postcss: 8.5.6 postcss-value-parser: 4.2.0 @@ -18344,7 +17829,7 @@ snapshots: postcss-merge-rules@5.1.4(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.28.1 caniuse-api: 3.0.0 cssnano-utils: 3.1.0(postcss@8.5.6) postcss: 8.5.6 @@ -18364,7 +17849,7 @@ snapshots: postcss-minify-params@5.1.4(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.28.1 cssnano-utils: 3.1.0(postcss@8.5.6) postcss: 8.5.6 postcss-value-parser: 4.2.0 @@ -18438,7 +17923,7 @@ snapshots: postcss-normalize-unicode@5.1.1(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.28.1 postcss: 8.5.6 postcss-value-parser: 4.2.0 @@ -18461,7 +17946,7 @@ snapshots: postcss-reduce-initial@5.1.2(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.28.1 caniuse-api: 3.0.0 postcss: 8.5.6 @@ -18913,6 +18398,12 @@ snapshots: react-refresh@0.14.2: {} + react-resize-detector@12.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + es-toolkit: 1.45.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-test-renderer@19.2.4(react@18.3.1): dependencies: react: 18.3.1 @@ -19301,13 +18792,6 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@13.3.3(sass@1.93.2)(webpack@5.102.1): - dependencies: - neo-async: 2.6.2 - webpack: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - optionalDependencies: - sass: 1.93.2 - sass@1.93.2: dependencies: chokidar: 4.0.3 @@ -19330,13 +18814,6 @@ snapshots: scheduler@0.27.0: {} - schema-utils@4.3.3: - dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) - semver@5.7.2: {} semver@6.3.1: {} @@ -19517,8 +18994,6 @@ snapshots: slash@3.0.0: {} - slash@4.0.0: {} - smob@1.5.0: {} sort-object-keys@1.1.3: {} @@ -19551,8 +19026,6 @@ snapshots: source-map@0.6.1: {} - source-map@0.7.6: {} - spawn-command@0.0.2: {} spdx-compare@1.0.0: @@ -19744,7 +19217,7 @@ snapshots: stylehacks@5.1.1(postcss@8.5.6): dependencies: - browserslist: 4.26.3 + browserslist: 4.28.1 postcss: 8.5.6 postcss-selector-parser: 6.1.2 @@ -19811,8 +19284,6 @@ snapshots: tabbable@6.2.0: {} - tapable@2.3.0: {} - tar-fs@2.1.4: dependencies: chownr: 1.1.4 @@ -19829,17 +19300,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - terser-webpack-plugin@5.3.14(@swc/core@1.13.5)(webpack@5.102.1): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - terser: 5.44.0 - webpack: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - optionalDependencies: - '@swc/core': 1.13.5 - terser@5.44.0: dependencies: '@jridgewell/source-map': 0.3.11 @@ -19907,10 +19367,6 @@ snapshots: dependencies: is-number: 7.0.0 - to-string-loader@1.2.0: - dependencies: - loader-utils: 1.4.2 - toidentifier@1.0.1: {} topojson-client@3.1.0: @@ -19958,16 +19414,6 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.29.0) jest-util: 30.2.0 - ts-loader@9.5.4(typescript@5.9.3)(webpack@5.102.1): - dependencies: - chalk: 4.1.2 - enhanced-resolve: 5.18.3 - micromatch: 4.0.8 - semver: 7.7.3 - source-map: 0.7.6 - typescript: 5.9.3 - webpack: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -20154,12 +19600,6 @@ snapshots: unquote@1.1.1: {} - update-browserslist-db@1.1.3(browserslist@4.26.3): - dependencies: - browserslist: 4.26.3 - escalade: 3.2.0 - picocolors: 1.1.1 - update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 @@ -20236,11 +19676,6 @@ snapshots: dependencies: loose-envify: 1.4.0 - watchpack@2.4.4: - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - wcwidth@1.0.1: dependencies: defaults: 1.0.4 @@ -20257,65 +19692,6 @@ snapshots: webidl-conversions@7.0.0: {} - webpack-cli@5.1.4(webpack@5.102.1): - dependencies: - '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.102.1) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.102.1) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack@5.102.1) - colorette: 2.0.20 - commander: 10.0.1 - cross-spawn: 7.0.6 - envinfo: 7.18.0 - fastest-levenshtein: 1.0.16 - import-local: 3.2.0 - interpret: 3.1.1 - rechoir: 0.8.0 - webpack: 5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4) - webpack-merge: 5.10.0 - - webpack-merge@5.10.0: - dependencies: - clone-deep: 4.0.1 - flat: 5.0.2 - wildcard: 2.0.1 - - webpack-sources@3.3.3: {} - - webpack@5.102.1(@swc/core@1.13.5)(webpack-cli@5.1.4): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.26.3 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.18.3 - es-module-lexer: 1.7.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35(patch_hash=f54449b9273bc9e74fb67a14fcd001639d788d038b7eb0b5f43c10dff2b1adfb) - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.14(@swc/core@1.13.5)(webpack@5.102.1) - watchpack: 2.4.4 - webpack-sources: 3.3.3 - optionalDependencies: - webpack-cli: 5.1.4(webpack@5.102.1) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - whatwg-encoding@2.0.0: dependencies: iconv-lite: 0.6.3 @@ -20383,8 +19759,6 @@ snapshots: dependencies: isexe: 3.1.5 - wildcard@2.0.1: {} - word-wrap@1.2.5: {} wordwrap@1.0.0: {} From 75c0d01060e3f1ff2e43b2963f6a19fb401db634 Mon Sep 17 00:00:00 2001 From: gjulivan Date: Mon, 16 Mar 2026 14:12:29 +0100 Subject: [PATCH 3/7] chore: update signature widget --- .../src/Signature.editorConfig.ts | 24 +++- .../signature-web/src/Signature.icon.dark.png | Bin 1295 -> 1801 bytes .../signature-web/src/Signature.icon.png | Bin 1333 -> 1879 bytes .../signature-web/src/Signature.tile.dark.png | Bin 3686 -> 6466 bytes .../signature-web/src/Signature.tile.png | Bin 3715 -> 6633 bytes .../signature-web/src/Signature.xml | 90 ++++++++++----- .../src/assets/Signature.icon.dark.png | Bin 0 -> 1801 bytes .../src/assets/Signature.icon.png | Bin 0 -> 1879 bytes .../src/components/Signature.tsx | 18 +-- .../src/components/SizeContainer.ts | 69 +++++------- .../signature-web/src/utils/customTypes.ts | 18 +-- .../signature-web/src/utils/dimensions.ts | 53 +++++++++ .../src/utils/useSignaturePad.ts | 105 ++++++++++++------ .../signature-web/typings/SignatureProps.d.ts | 20 +++- 14 files changed, 268 insertions(+), 129 deletions(-) create mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.png create mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.icon.png create mode 100644 packages/pluggableWidgets/signature-web/src/utils/dimensions.ts diff --git a/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts b/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts index ec064b474c..599266b7a4 100644 --- a/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts +++ b/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts @@ -1,4 +1,4 @@ -import { Properties } from "@mendix/pluggable-widgets-tools"; +import { hidePropertiesIn, hidePropertyIn, Properties } from "@mendix/pluggable-widgets-tools"; import { container, rowLayout, @@ -13,9 +13,29 @@ import SignaturePreviewSVG from "./assets/Signature.icon.svg"; import SignaturePreviewDarkSVG from "./assets/Signature.icon.dark.svg"; export function getProperties( - _values: SignaturePreviewProps, + values: SignaturePreviewProps, defaultProperties: Properties /* , target: Platform*/ ): Properties { + if (values.heightUnit === "percentageOfWidth") { + hidePropertyIn(defaultProperties, values, "height"); + } else { + hidePropertiesIn(defaultProperties, values, [ + "minHeight", + "minHeightUnit", + "maxHeight", + "maxHeightUnit", + "OverflowY" + ]); + } + + if (values.minHeightUnit === "none") { + hidePropertyIn(defaultProperties, values, "minHeight"); + } + + if (values.maxHeightUnit === "none") { + hidePropertiesIn(defaultProperties, values, ["maxHeight", "OverflowY"]); + } + return defaultProperties; } diff --git a/packages/pluggableWidgets/signature-web/src/Signature.icon.dark.png b/packages/pluggableWidgets/signature-web/src/Signature.icon.dark.png index 2b3844754aa3e569becba64208cf2704f8b8709e..137bba05250fd4e17e26acc66d52563d4a55de5c 100644 GIT binary patch delta 1698 zcmV;T23`4&3W*MoB#|^M0Zx%&GJgUS00RI30096200000000000AK(B009610AK(B z00DOe-{$}T21-dpK~#7F?OI!I+eQ@SP>BUW;Li8< z_Ksubc*9SIfP~;(VB`_Q;jjU3usx(96*Hv2P~B<3li@fHwMwOOk_1HI2?zrZkf(5U zHX4mK9LH&)Jx~B2U0ht$m4CiKv(N-Yf#2WXZxb2{dItvwT?D}A8WOewh?S1Q5|9ME zjAe4(TXG-jKP&A(vycR&1usy+3;Lo?62Z_S8C42LKvwVsGD*}|$tV;7(|{*n6MYq9 zWVJjrHAS-wYsJfHxP#W+w7i9X56fH9IAUG}fH2T8r)t%Q7 zCCHsA0cngE2FWsweircbteFvz#&{XDsHf4-3Vvn;q%mFqmVad${b|6@gn%^0%b-O) zjsCRY>6y7-g9tc*t0pQ43E(8>4W6EvD*<@ztfh&-WPm7Xz>^NX``Zxo^GZ^pJq1*9 zC7@I)S@Pnj_vGAM8S|QH!IL6=4W{=3fF4jg3wYAYl>qF1jTRLJM%{>dn9KrRtR+Z5 z`#1^FLQj@uxqmTj9R$!@npaHI)MjvE!ZhH;8bku>fw&{a<7BQLfF1XF03LoDW{sc9RYlDvJ|jB@N{Qm`~_Z7Nj8E z1mMAS_2KyAoktGI&ER#$&fq=*i?|!0e`kmeLB!$E{O4c#uEMWl6ew9 zuAR65xQ)qgvR+?_9~3h&=#L=^JMZr5oSVNtRI07dEk?$B1p#m!A1c3j9hwTfV1V=A z!`0Y_r2psXXZc&6X6dQA5_!POcf&Jo@FRM8u8i)#;E7%NsR)3+-KX6JVD}%F2r$yt z-sHZP)qe_6k0s#c`(X!Bswu2BS?Lh6Wm&+}E@?er=Z`y!mypLZ!=g!UA@C!o@$vQAVA8V` zLhAuexqRpY52(uso_0`60OL-R21S9}pDx?Ze}Bg&Y7@Er{$Y!8<8QAUuK(%PvkkAk zWR<`*XmV$Z`y7Myl45p~C8KnLd(q;IAr~f z<$oJod?P@BYEsmlFRn}MwvRM*4I1Bmd#@%`>a>Nlbp+V5CFI_6ThyuF-B~$Tz#unR zAGbyWKi|<|COe}TA@qwPH3YD}Y+Q91+&SU)>dq7RVY$-y`0H8^M~8OYM^QdJp5r#^={-z9pw=1PE{=`gr)&|KR9H z=)emNkkAH!K0?J<7WpuCHbB52i>^*5a0F-vkqI8_ChPlnkKA6~d3hd=LtBjp@_%@W zI>%gIHQ81Qo!F@X4-gt|M(7x4s;i4}S2F(Q(<}F^`?__FDLmmDjz$mI|6z>ZP<+v? zpS3TP09w#JpCzNt-H#ydRY&I$fsG^5^V77(P%xXURj2hQ#YPTcyO|?523Y$R{a?As sZq1R?U)FaJ0e&S{46GPfECc@nLlddJn%G|l<^TWy07*qoM6N<$g8P~ucK`qY delta 1186 zcmeC=>*t!F!poBG=E>3EntGHc38lSU<2hDW;M@p08*R<9+AZi417mGm~pB$pELsl3!|rtV@L(# z+bHk6+Xe!vtqUCNy5$bKd*szmkXvYNK6}UMYm8lU6wdJqiR4Z9HS68{O7M~L4)qoN z6I^eLY-IN1zI>eQf6t?> zQ(jqaUiWm`l*#G&`Rg=`gij@1zt!G<_+b1}HNgXmvnJ^3#hC4Qwpd6ZsIaGPSA7r1 z{P6D&v*p9xlo|G}Z;=S(T@%Is$@5|VrtPalCOk9SyMIb&#m2vB+ju7aHjtgi_@HxJ z*-Vv3Ua#3r7rQi^{rzHX!iQ-Yi%wjg+2z!b`u_5s)J`?N_sW8ASV~U*4&-<->HAI2 z7qcKlBob&$Td{R*?7_!Wt#-r^3|Yjl}zefYQj$OV5O(HxcW1{p=9kR0t|FdpV?ThU{ zKI*-Xu~okPX`Q&&ymu^nUa#)?(#LS4eX*9KTyfmaD#?lq_2+oya@RRBsJfqjS@`_b zold`XJKx-%%@EYL?-Jkd+_*H3zT+MxtG+y(^WFG>>IpOc{SWsa{Gl*E+IH{r%J~1= z?31q~rPox~FSvjF?zg^%U0w3``1uphIz(@8*?e&4wRrQl4=RP`Zk;sA&4lTa%J2LG zQMr*nj{B8dW1C{KNRXj{pLg!bXOVTnoqdVTONCn*=6}f7y0|gHtZk9N1FrvnV)uW% zujo#`rka}?=N!4l>U-ay`4Bw?E z-?eLe`dzn{9E^zkvHspyZ=UX4HpY-NHlCFVvyy!obxm`~dye$8FOToK2mm8?G)V9^-c+*XZ zB;^GX|JuY}Y?=B(etM@l|tnH zy;Zl;dvroDK=7ZAd$=CMl}aN<)raTHN?ciAMER=$O}hgV_L}jW703x`SobxB>C@+? rGoPLI)OkhDs@>C%}1v8qr9kH!%{adeJt{ z6U010oI4aMVJ=FzC?Pxn?i)ByfVplFD@YY+?45qc@tB#}AA9X}yh%M$GJj`&&iH)a zoH;W)yF$#2+aprU{4x|Hsq48Ux~>ckt{{ zqx;3_w^*R{^w14aSQ20q{atr9kiyq-q^&to`5bJJ-5Ur3PkIY|n{261j4kQBT!JAwq&EMmb+GG?4)z$4Cw zfN{YOPzuMGNmZW+eDCpj&knBB4}z0|Poh6?dwb@s;HU`Xe1EFDKoaA1qm-OPe;n{r zB_N6M3b39h(H|H5)CfpoybfB)N%SWHKNSL!7_R{9c@q6e!SnB?zYUVK4}F2Xs#TH&F(p0X}N%B=xDC1o_?#kE*Y= z9}hfxtG29wXM0jy0-b_&vTiBBoR_gfxOs6)_zt|puYc%mERP$+>~WHoQzHOtsbv57 z?X`_M>c0^r&$dU29)!?nrCEVzGg2df2tdtL8jymUh^RD6@N83R1Yl~702l>$P>)Yr zNI1LWZeN3OCKRHl#u|93`k^GGv)Q44?|Jp>p59!pR2JP&`FDC7FfThjj9T;E5Wu$Ps?n_wJFf99+D;hTo{Na+1&r~EG5q0qa z)0Jj_zc$peP#8+U&CTP-h+P$BEIH0PFDy99bOFL>sS z7OU?HuFSteV}UzyV(?u$ zT>x3F|F?L7ekh#ccgPZW619v}cgb1^UT zJAe3Mv%-z=nqC4CMFi6l+A|wG!(u?OZ+|cAh`_gZdb8jiBZnOWpesg0zrfxAat2E( ztj{d#!U!ky{z4fw^xgInBqQBl% zHRmlHmR6+npXim?Z+3by!l;~mAwU2CwSRQ8a(*r_bIR?}uc-Hh+`=(=)=&CkWj-L9FtJhI7SWvmO(&!4AoGTz!K&^A#u~>G!az)bR2QS@kJYUVqr0o03MkGmMh#6NoO5~6nQ-&$6X$Aq<@gq7=Fa& zu`qOr$LGZ3;X=j3^x}`&Li%qYzedb?(-rxaS5ME~&wg?Kf6l<1fjI-88Tb#5m^Z*f Sc>b9H0000yB>Ggt&Dwtxw)+F=1Rf(?{snAJSX0Z4HcctjR6Fz_7#VaBQ2e9{aIEb5*vjv*C{ zZ=+)UqzwhOEtYF=(*A15&$_Zczku1oNq@o;^%WM357`Qs%+y~9KH&H=HDDsM$d>bg zLgi^M)#BD)|5kNOT1AL+ZT)fM`!(79>4Hh$Z!2zaeqgJt5G?)Q!a_o8<+_Bqw&%7w ze4P2>8;=vuEv-r}y{O<%gfQZZb&NIE!Ccs$Sor z%r9X5j9EMkU-nH&atXa)D*t5ii~ddaJH!@zS@^y6PJsL#)96!IZ*JF_fAqv$zHj;t z_jb&QJ|Vn%&6?wOlMN0$tNjwT=Hs1DB^xFg9C%gRw0+0Zmkb+>8*WDf#U5`wbB-Y| zzwop%V?rv!cA(tMW1AszISd;N8*bMFRplJpYy?(5iyVZun>|LtAO1w-X9wr;9@w_0U(- zyitb7;rc!OYr&_ZgA-jn*3RCvflsmI#`$k@ZD(s_ud0Q)KbAiC>+_7w_m-v`FefE{ zDJs0Nr75Yj{p0jI#}?-uT+Se|AzVuMH;d%Xd_6WRgJtoO?i?jrMLJUx*y;n4z7*Y^ zCsLkz^P7+0iyPN2-fsHNP#cu-vv9}%mMii7)Aw#Z{O0}LUF$@pzRjrq@uzkXZ?Zm{ z@q)LfE?-<8e78d5{4I(8$KpJVeg5xL7(AA?{d(m4#b5Tt3#%KaPBJtkd<}^Y=)C8$ zK6z)i!||BQYt$JPTK>hdS}i-6X3NQ7SO05zx~)dAZPZc=`%|B)gHKNRs=~12MZDDd z{0Xg%6D4J}EZ#8ucyWI2#mZu!`2JppRu3x(qv>^EM;fw^v19$%RntIG% zm$hkzbOb}jg8GG8UoVSp-fLQ@!(j2k|6fVyzopr0P$Ea>i_@% diff --git a/packages/pluggableWidgets/signature-web/src/Signature.tile.dark.png b/packages/pluggableWidgets/signature-web/src/Signature.tile.dark.png index 38a629ddd0f66555094598fafb66322492b07398..767c36c05f6a70daa82f76c2c1314f83eadab240 100644 GIT binary patch literal 6466 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 literal 3686 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
{U28=iQr^C+h8cA6h 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 diff --git a/packages/pluggableWidgets/signature-web/src/Signature.xml b/packages/pluggableWidgets/signature-web/src/Signature.xml index edc13dad99..61fa533b1c 100644 --- a/packages/pluggableWidgets/signature-web/src/Signature.xml +++ b/packages/pluggableWidgets/signature-web/src/Signature.xml @@ -35,31 +35,71 @@ - - Width unit - - - Percentage - Pixels - - - - Width - - - - Height unit - 'Percentage of width' is the aspect ratio, 'Pixels' is absolute. Warning: When using 'Percentage of parent' the parent container must have an absolute height, else nothing is displayed. - - Percentage of width - Pixels - Percentage of parent - - - - Height - - + + + Width unit + + + Pixels + Percentage + + + + Width + + + + Height unit + + + Auto + Pixels + Percentage + Viewport + + + + Height + + + + Minimum Height unit + + + None + Pixels + Percentage + Viewport + + + + Minimum height + + + + Maximum Height unit + + + None + Pixels + Percentage + Viewport + + + + Maximum height + + + + Vertical Overflow + + + Auto + Scroll + Hidden + + + diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.png b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.png new file mode 100644 index 0000000000000000000000000000000000000000..137bba05250fd4e17e26acc66d52563d4a55de5c GIT binary patch literal 1801 zcmV+k2ln`hP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw0000^WmrjOO-%qQ0000800aRV z00jU50096106qa500jU50096107d~Q00RI3009630006L00RI3009620000000000 z0AK(B009610AK(B00DOe-{$}T21-dpK~#7F?OI!I+eQ@SP>loeW30_Nx5#!#8|^;i&3HUMZ?#$j>Q7pp z6afStz`8Nu&iD5Aj$`I{!%v2Qgy3CZqg zwgQNij=~a<1iXx8a^72VAL>6V?Lf1T1f&HoP{9lOqD~UQ&>|UC3P(Uz@B}hR)K|$U z6amwKCtwqO6=P((Fa+cTzN@0`bUK#WC$|ehKp1!!YU5mYWrKC~2z{emE?-BHuy6vR zj0f2DH~=yFZXk?WW1$4Z8Be=Skvt4Qgnr;Qn5?m`deFiM2s55CJQ(>wHdIGKls+=V z=OJsf<#nmf)Q)+yql_0B9_Dmm3%&h$g)%+Fga-2b7wGJI1Ct7oC-kXHvxW_FevJjrHAS-wYsJfHxP#W+w7i9X56fH9IAUG}f zH2T8r)t%Q7CCHsA0cngE2FWsweircbteFvz#&{XDsHf4-3Vvn;q%mFqmSr0KX~55f zfHcO-phZ26{ZXd1yph+pj0YZ^5UrXM_L&|8{UOw-h6aALwV;Kdq50_uUdBgW%ot{#9L_jv#w zej8>$9^k{)PSc+o0rcHX34r$Q?rvXaOi{p-ZMhu*d~&iBus-l~XJh;YUQtOlmARRN zn7U5dc5VdV!FBcF_~Ya`yke7%27c=_jYSUuKUAu%&n-sAdj$b-9Um&cc^#Sx zykLOy-^10|hot}K>1X*{o@VK(x)OQ7%Xh;wZtx>|d9IA^zu<{o`KbtizTKzY1z`6d zmk2P@*52g4memSTk0s#c`(X!Bswu2BS?Lh6Wm&+}E@?er=Z`y!mypLZ!=g!UA@C!o@$vQA zVA8V`LhAuexqRpY52(uso_0`60OL-R21S9}pDx?Zf5#?j6S@8VVT*C&Z?7A!|LN7U z4X?dqmB2M+$-f~;iso&jMIak0S zH&`FHMgu?J(P1V#qZlFdiy}1yu)b_ubr{?^;r8mz6Zm1d()jr6S`SBucHBoMXJ&_V z<@Mw0G@r6kdMBBM7s>I?wPpM5U7MNaiEJ2dg*F1*m%o0i_9w5!9W_xB;N>Ip->qO? z%WFZ;mr;6zlno2+V_}^i4b#LIB%=m`E$B)f$a)Xs$HwQ^YrZ9?X#@yxBl>vw)&Jn= zN9e!{4Uo_Vfj&aTSQhy(b~Zr3Ad9X}CvXI42ayRL>n7{_c#qs(-g$W*jze3G2l9A| zI>%gIHQ81Qo!F@X4-gt|M(7x4s;i4}S2F(Q(<}F^`?__FDLmmDjz$mI|6z>ZP<+v? zpS3TP09w#JpCzNt-H#ydRY&I$fsG^5^V77(P%xXURj2hQ#YPTcyO|?523Y$R{a?As rZq1R?U)FaJ0e&S{46GPfECc@nL#e%**k1?c00000NkvXXu0mjf0o^E( literal 0 HcmV?d00001 diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.png b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.png new file mode 100644 index 0000000000000000000000000000000000000000..52babd516fb707ef31328f96fa1d273a431e527b GIT binary patch literal 1879 zcmV-d2dMaoP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw0000^WmrjOO-%qQ0000800aRV z00jU50096106qa500jU50096107d~Q00RI3009630006L00RI3009620000000000 z0AK(B009610AK(B00DOe-{$}T2AD}iK~#7F?ONS#6Gs%Dvuo3$1~rIq?>s@>C%}1v z8qr9kH!%{adeJt{6U010oI4aMVJ=FzC?Pxn?i)ByfVplFD@YY+?45qc@tB#}AA9X} zyh%M$GG~6y_=n zCjrlPV^)jKS68-2!H{_ZqQDc;gXjB?s4LxNDaAd2ZR>!^m(}m@-Y@BOVREJkhy(w} z)4du4;-Gi%>`|lp#p$;wwz*EFE>T&@QF&$w7zMlz>afx9NJ{pEK?1n%289SAlLRCM zudsE#?6j2J&kI&LP|O?w;(aYLn<;wz$D-q=b8Qx#8z`=2uKIKY*_e2`R-2z zyG}1>f`BOSFx2b#PD3|1OpehPE_GkUkuY-t;*1B_#bE%3=rdo1xG`o*zzD|20*KP* zqcAIK>5PPOWl^i^i8CW0%6LBE;c4%QWoTd)qAK_3G9D}arYu31YY(D=KXS_P$ z-C4Wez^Q)SvaXGz?}|(QEdWHjnV3AK&n+QicsM>^*R{^w14aSQ20q{atr9kiyq-q^ z&to`5bJJ-5Ur3PkIY|n{261j4kQBT!JAwq&EMmb+ zGG?4)z$4CwfN{YOPzuMGNmZW+eDCpj&knBB4}z0|Poh6?dwb@s;HU`Xe5$)Z661BF zl$=C=9Pm>mAc^q`u%0K;9~b=82uNbQ4qC}c^d|v76#|kNuK??L68%ZR^Y5m=4U)7E zAE8^74qD0Q4L)@OR#!KQLJD*5jfubtIOj>gbN^G{fUuPt^nboL{hh zsHvaLt+qiiDR@@o+hBe!fY|2pIN(_?RRW}>A`hw(zpqnrR6Y)PHI^cQgxng1Xr-s; zIlVBcOoDFdW4IK4f>V7a0k6jBzYGn;9o0T8Pt^n9Plg9{PW?Ag2BZN#YV0KSshtG* z-VKkcueBc!JbSCQtbk{GQd|O^f_1WPDZreUu|v3daZC6Pyu`2QZ7h!)#O!gBmQy1D zYpG=a`0cfgI_kd>B+s@-i5`T|Xr)z>|Ru2dG?Px*IxU5MPqDY1#2 zqJ?+&N1cxgt;55*F;0li)T>7FfThjj9T;E5Wu$Ps?n_wJFf99+D;hTo{Na+1&r~EG z5q0qa)0Jj_zc$peP#8+U&CTP-h+P$BEIH0PFDy99bO zFL>sSMJ0F3o?W7xg*vXZ$TGykH$ z-c>c{EgY6sr1YQYmDq1~dNIPNoP8lc006agvvPheFmuZ7(XXiYh1|k1dFAi=wPx4p zR&6qIYy6mXEuGlnV)dkO6Q|M}oBuqXh8F>^nU;S2P{aMywoxmoMvi>>SAC(yv&cZg zW}d<8OQydoywb-4DaMJC0djjzbPBlME_8kR8iBaz2+3b~pw9Tnq1pN5u6Pfx>O)Q> z2MA!-M&y2thEUg!__f~5>)=&CkWj-L9FtJhI7SWvmO(&!4AoGTz!K&^A#u~>G!az)bR2QS@kJYUVlk2c9+?A{E8G%EXB~zVc|9V>T^@0ye~{D|e#GXn zFm#E>=fvaTLdC=M;*Z)w`fnh=M$CEB75SD|PtV=YesTVP&cK|3IRl>=_z#YlH^4)9 R{+R#(002ovPDHLkV1fk9QTG4< literal 0 HcmV?d00001 diff --git a/packages/pluggableWidgets/signature-web/src/components/Signature.tsx b/packages/pluggableWidgets/signature-web/src/components/Signature.tsx index 8ae76c77bd..f15287ca78 100644 --- a/packages/pluggableWidgets/signature-web/src/components/Signature.tsx +++ b/packages/pluggableWidgets/signature-web/src/components/Signature.tsx @@ -9,34 +9,20 @@ import { Grid } from "./Grid"; import { SizeContainer } from "./SizeContainer"; export function SignatureComponent(props: SignatureProps): ReactElement { - const { className, alertMessage, wrapperStyle, imageSource, hasSignatureAttribute, onSignEndAction } = props; + const { className, alertMessage, wrapperStyle, imageSource, onSignEndAction } = props; const handleSignEnd = (imageDataUrl?: string): void => { if (imageDataUrl) { imageSource.setValue(Utils.convertUrlToBlob(imageDataUrl)); } - if (hasSignatureAttribute) { - hasSignatureAttribute.setValue(true); - } - // Trigger microflow to update signature attribute if (onSignEndAction) { onSignEndAction(imageDataUrl); } }; - const { canvasRef, signaturePadRef } = useSignaturePad(props, handleSignEnd); - - const onResize = (): void => { - if (canvasRef.current) { - canvasRef.current.width = - canvasRef.current && canvasRef.current.parentElement ? canvasRef.current.parentElement.offsetWidth : 0; - canvasRef.current.height = - canvasRef.current && canvasRef.current.parentElement ? canvasRef.current.parentElement.offsetHeight : 0; - signaturePadRef.current?.redraw(); - } - }; + const { canvasRef, onResize } = useSignaturePad(props, handleSignEnd); return ( void; } -export const SizeContainer: FC = ({ - className, - classNameInner, - widthUnit, - width, - heightUnit, - height, - children, - style, - readOnly = false, - onResize -}) => { +export const SizeContainer: FC = (props: SizeProps) => { + const { className, children, classNameInner, readOnly = false, style, onResize } = props; const ref = useResizeObserver(() => onResize?.()); - const styleWidth = widthUnit === "percentage" ? `${width}%` : `${width}px`; + // const styleWidth = widthUnit === "percentage" ? `${width}%` : `${width}px`; + const wrapperStyle = constructWrapperStyle(props); return createElement( "div", { @@ -33,8 +25,7 @@ export const SizeContainer: FC = ({ className: classNames(className, "size-box"), style: { position: "relative", - width: styleWidth, - ...getHeight(heightUnit, height, widthUnit, width), + ...wrapperStyle, ...style } }, @@ -59,26 +50,26 @@ export const SizeContainer: FC = ({ SizeContainer.displayName = "SizeContainer"; -const getHeight = ( - heightUnit: HeightUnitType, - height: number, - widthUnit: WidthUnitType, - width: number -): CSSProperties => { - const style: CSSProperties = {}; - if (heightUnit === "percentageOfWidth") { - const ratio = (height / 100) * width; - if (widthUnit === "percentage") { - style.height = "auto"; - style.paddingBottom = `${ratio}%`; - } else { - style.height = `${ratio}px`; - } - } else if (heightUnit === "pixels") { - style.height = `${height}px`; - } else if (heightUnit === "percentageOfParent") { - style.height = `${height}%`; - } +// const getHeight = ( +// heightUnit: HeightUnitType, +// height: number, +// widthUnit: WidthUnitType, +// width: number +// ): CSSProperties => { +// const style: CSSProperties = {}; +// if (heightUnit === "percentageOfWidth") { +// const ratio = (height / 100) * width; +// if (widthUnit === "percentage") { +// style.height = "auto"; +// style.paddingBottom = `${ratio}%`; +// } else { +// style.height = `${ratio}px`; +// } +// } else if (heightUnit === "pixels") { +// style.height = `${height}px`; +// } else if (heightUnit === "percentageOfParent") { +// style.height = `${height}%`; +// } - return style; -}; +// return style; +// }; diff --git a/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts b/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts index 7b98fb953a..b29a1319a7 100644 --- a/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts +++ b/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts @@ -1,19 +1,19 @@ import { SignatureContainerProps } from "typings/SignatureProps"; -export type HeightUnitType = "percentageOfWidth" | "percentageOfParent" | "pixels"; +// export type HeightUnitType = "percentageOfWidth" | "percentageOfParent" | "pixels"; -export type WidthUnitType = "percentage" | "pixels"; +// export type WidthUnitType = "percentage" | "pixels"; -export interface Dimensions { - widthUnit: WidthUnitType; - width: number; - heightUnit: HeightUnitType; - height: number; -} +// export interface Dimensions { +// widthUnit: WidthUnitType; +// width: number; +// heightUnit: HeightUnitType; +// height: number; +// } export type penOptions = "fountain" | "ballpoint" | "marker"; -export interface SignatureProps extends Dimensions, SignatureContainerProps { +export interface SignatureProps extends SignatureContainerProps { className: string; alertMessage?: string; clearSignature: boolean; diff --git a/packages/pluggableWidgets/signature-web/src/utils/dimensions.ts b/packages/pluggableWidgets/signature-web/src/utils/dimensions.ts new file mode 100644 index 0000000000..682a6e4736 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/utils/dimensions.ts @@ -0,0 +1,53 @@ +import { CSSProperties } from "react"; + +export type WidthUnitEnum = "pixels" | "percentage"; + +export type HeightUnitEnum = "percentageOfWidth" | "pixels" | "percentageOfParent" | "percentageOfView"; + +export type MinHeightUnitEnum = "none" | "pixels" | "percentageOfParent" | "percentageOfView"; + +export type MaxHeightUnitEnum = "none" | "pixels" | "percentageOfParent" | "percentageOfView"; + +export type OverflowYEnum = "auto" | "scroll" | "hidden"; + +export type DimensionsProps = { + widthUnit: WidthUnitEnum; + width: number; + heightUnit: HeightUnitEnum; + height: number; + minHeightUnit: MinHeightUnitEnum; + minHeight: number; + maxHeightUnit: MaxHeightUnitEnum; + maxHeight: number; + OverflowY: OverflowYEnum; +}; + +function getHeightScale(height: number, heightUnit: "pixels" | "percentageOfParent" | "percentageOfView"): string { + return `${height}${heightUnit === "pixels" ? "px" : heightUnit === "percentageOfView" ? "vh" : "%"}`; +} + +export function constructWrapperStyle(props: DimensionsProps): CSSProperties { + const { widthUnit, heightUnit, minHeightUnit, maxHeightUnit, width, height, minHeight, maxHeight, OverflowY } = + props; + + const wrapperStyle: Pick = + {}; + + wrapperStyle.width = `${width}${widthUnit === "pixels" ? "px" : "%"}`; + if (heightUnit === "percentageOfWidth") { + wrapperStyle.height = "auto"; + + if (minHeightUnit !== "none") { + wrapperStyle.minHeight = getHeightScale(minHeight, minHeightUnit); + } + + if (maxHeightUnit !== "none") { + wrapperStyle.maxHeight = getHeightScale(maxHeight, maxHeightUnit); + wrapperStyle.overflowY = OverflowY; + } + } else { + wrapperStyle.height = getHeightScale(height, heightUnit); + } + + return wrapperStyle; +} diff --git a/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts b/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts index bacbf0e485..def3812a11 100644 --- a/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts +++ b/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts @@ -2,42 +2,27 @@ import { RefObject, useCallback, useEffect, useMemo, useRef } from "react"; import SignaturePad, { Options } from "signature_pad"; import { SignatureProps } from "./customTypes"; +function usePrevious(value: T): T | null { + const ref = useRef(null); + useEffect(() => { + ref.current = value; + }, [value]); + return ref.current; +} + export function useSignaturePad( props: Pick, onSignEnd?: (imageDataURL?: string) => void ): { signaturePadRef: RefObject; canvasRef: RefObject; + onResize?: () => void; } { const { readOnly, imageSource, hasSignatureAttribute, penType, penColor } = props; const signaturePadRef = useRef(null); const canvasRef = useRef(null); - const hasSignature = useRef(false); - - useEffect(() => { - if (readOnly) { - signaturePadRef.current?.off(); - } else { - signaturePadRef.current?.on(); - } - }, [readOnly]); - - useEffect(() => { - if (imageSource?.status === "available" && imageSource.value?.uri && signaturePadRef.current?.isEmpty()) { - signaturePadRef.current?.fromDataURL(imageSource.value.uri); - } - }, [imageSource]); - - useEffect(() => { - if (hasSignatureAttribute?.status === "available") { - if (hasSignatureAttribute?.value !== hasSignature.current) { - if (hasSignature.current === true) { - signaturePadRef.current?.clear(); - } - hasSignature.current = !!hasSignatureAttribute?.value; - } - } - }, [hasSignatureAttribute?.status, hasSignatureAttribute?.value]); + const isSignatureInitialized = useRef(false); + const hasSignature = usePrevious(hasSignatureAttribute?.value ?? false) ?? false; const signaturePadOptions: Options = useMemo(() => { let options: Options = {}; @@ -54,23 +39,71 @@ export function useSignaturePad( const handleSignEnd = useCallback(() => { const imageDataUrl = signaturePadRef.current?.toDataURL(); + if (hasSignatureAttribute) { + hasSignatureAttribute.setValue(!signaturePadRef.current?.isEmpty()); + } if (imageDataUrl && onSignEnd) { onSignEnd(imageDataUrl); } - }, [onSignEnd]); + }, [hasSignatureAttribute, onSignEnd]); + + useEffect(() => { + if (readOnly) { + signaturePadRef.current?.off(); + } else { + signaturePadRef.current?.on(); + } + }, [readOnly]); + + const onResize = (): void => { + if (canvasRef.current && signaturePadRef.current) { + const data = signaturePadRef.current.toData(); + canvasRef.current.width = + canvasRef.current && canvasRef.current.parentElement ? canvasRef.current.parentElement.offsetWidth : 0; + canvasRef.current.height = + canvasRef.current && canvasRef.current.parentElement ? canvasRef.current.parentElement.offsetHeight : 0; + signaturePadRef.current.clear(); + signaturePadRef.current.fromData(data); + } + }; + + useEffect(() => { + if (hasSignatureAttribute?.status === "available") { + if (hasSignatureAttribute?.value !== hasSignature) { + if (hasSignature === true) { + signaturePadRef.current?.clear(); + } + } + } + }, [hasSignature, hasSignatureAttribute?.status, hasSignatureAttribute?.value]); useEffect(() => { + console.log( + "Try Initializing signature pad", + penColor, + signaturePadOptions, + canvasRef.current, + signaturePadRef.current, + imageSource, + hasSignatureAttribute + ); if (canvasRef.current) { - signaturePadRef.current = new SignaturePad(canvasRef.current, { - penColor, - ...signaturePadOptions - }); - signaturePadRef.current.addEventListener("endStroke", handleSignEnd); - if (readOnly) { - signaturePadRef.current?.off(); + const canInstantiateSignaturePad = + signaturePadRef.current === null && + (imageSource?.status === "available" ? imageSource.value?.uri : imageSource.status === "unavailable"); + if (canInstantiateSignaturePad && !isSignatureInitialized.current) { + signaturePadRef.current = new SignaturePad(canvasRef.current, { + penColor, + ...signaturePadOptions + }); + signaturePadRef.current.addEventListener("endStroke", handleSignEnd); + if (readOnly) { + signaturePadRef.current?.off(); + } + isSignatureInitialized.current = true; } } - }, [handleSignEnd, penColor, readOnly, signaturePadOptions]); + }, [handleSignEnd, penColor, readOnly, signaturePadOptions, imageSource, hasSignatureAttribute]); - return { signaturePadRef, canvasRef }; + return { signaturePadRef, canvasRef, onResize }; } diff --git a/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts b/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts index be5646bfc3..293f723431 100644 --- a/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts +++ b/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts @@ -8,9 +8,15 @@ import { EditableValue, EditableImageValue, WebImage } from "mendix"; export type PenTypeEnum = "fountain" | "ballpoint" | "marker"; -export type WidthUnitEnum = "percentage" | "pixels"; +export type WidthUnitEnum = "pixels" | "percentage"; -export type HeightUnitEnum = "percentageOfWidth" | "pixels" | "percentageOfParent"; +export type HeightUnitEnum = "percentageOfWidth" | "pixels" | "percentageOfParent" | "percentageOfView"; + +export type MinHeightUnitEnum = "none" | "pixels" | "percentageOfParent" | "percentageOfView"; + +export type MaxHeightUnitEnum = "none" | "pixels" | "percentageOfParent" | "percentageOfView"; + +export type OverflowYEnum = "auto" | "scroll" | "hidden"; export interface SignatureContainerProps { name: string; @@ -25,6 +31,11 @@ export interface SignatureContainerProps { width: number; heightUnit: HeightUnitEnum; height: number; + minHeightUnit: MinHeightUnitEnum; + minHeight: number; + maxHeightUnit: MaxHeightUnitEnum; + maxHeight: number; + OverflowY: OverflowYEnum; showGrid: boolean; gridBorderColor: string; gridCellHeight: number; @@ -51,6 +62,11 @@ export interface SignaturePreviewProps { width: number | null; heightUnit: HeightUnitEnum; height: number | null; + minHeightUnit: MinHeightUnitEnum; + minHeight: number | null; + maxHeightUnit: MaxHeightUnitEnum; + maxHeight: number | null; + OverflowY: OverflowYEnum; showGrid: boolean; gridBorderColor: string; gridCellHeight: number | null; From fac78f13d1420385af88923165f2d4290e2ab32a Mon Sep 17 00:00:00 2001 From: gjulivan Date: Mon, 23 Mar 2026 13:50:18 +0100 Subject: [PATCH 4/7] fix: add unit test --- .../src/__tests__/AppEvents.spec.tsx | 34 --------- .../src/__tests__/Signature.spec.tsx | 70 +++++++++++++++++++ 2 files changed, 70 insertions(+), 34 deletions(-) delete mode 100644 packages/pluggableWidgets/signature-web/src/__tests__/AppEvents.spec.tsx create mode 100644 packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx diff --git a/packages/pluggableWidgets/signature-web/src/__tests__/AppEvents.spec.tsx b/packages/pluggableWidgets/signature-web/src/__tests__/AppEvents.spec.tsx deleted file mode 100644 index 02e155aa25..0000000000 --- a/packages/pluggableWidgets/signature-web/src/__tests__/AppEvents.spec.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { actionValue, dynamicValue } from "@mendix/widget-plugin-test-utils"; -import "@testing-library/jest-dom"; -import { render } from "@testing-library/react"; -import { EventsContainerProps } from "../../typings/EventsProps"; -import Events from "../Events"; - -describe("App events (load)", () => { - let defaultProps: EventsContainerProps; - beforeEach(() => { - defaultProps = { - name: "app events", - class: "app-events", - onComponentLoad: actionValue(), - componentLoadDelayParameterType: "number", - componentLoadDelay: 0, - componentLoadDelayExpression: dynamicValue(), - componentLoadRepeat: false, - componentLoadRepeatIntervalParameterType: "number", - componentLoadRepeatInterval: 0, - componentLoadRepeatIntervalExpression: dynamicValue(), - onEventChangeAttribute: undefined, - onEventChange: undefined, - onEventChangeDelayParameterType: "number", - onEventChangeDelay: 0, - onEventChangeDelayExpression: dynamicValue() - }; - }); - it("render app events", async () => { - const component = render(); - const renderedDiv = await component.container.querySelector(".widget-events"); - - expect(renderedDiv).toBeEmptyDOMElement(); - }); -}); diff --git a/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx b/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx new file mode 100644 index 0000000000..ad31f61861 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx @@ -0,0 +1,70 @@ +import "@testing-library/jest-dom"; +import { render, screen } from "@testing-library/react"; +import { ReactElement } from "react"; +import { SignatureContainerProps } from "../../typings/SignatureProps"; +import Signature from "../Signature"; + +const mockSignatureComponent = jest.fn((_props: unknown) =>
); + +jest.mock("../components/Signature", () => ({ + SignatureComponent: (props: unknown): ReactElement => mockSignatureComponent(props) +})); + +describe("Signature", () => { + const imageSource = { + setValue: jest.fn() + } as unknown as SignatureContainerProps["imageSource"]; + + const defaultProps: SignatureContainerProps = { + name: "signature", + class: "mx-signature", + tabIndex: 0, + imageSource, + hasSignatureAttribute: undefined, + penType: "ballpoint", + penColor: "#000000", + widthUnit: "pixels", + width: 300, + heightUnit: "pixels", + height: 200, + minHeightUnit: "none", + minHeight: 0, + maxHeightUnit: "none", + maxHeight: 0, + OverflowY: "auto", + showGrid: true, + gridBorderColor: "#cccccc", + gridCellHeight: 20, + gridCellWidth: 20, + gridBorderWidth: 1 + }; + + beforeEach(() => { + mockSignatureComponent.mockClear(); + }); + + it("renders SignatureComponent", () => { + render(); + + expect(screen.getByTestId("signature-component")).toBeInTheDocument(); + }); + + it("passes derived and default props to SignatureComponent", () => { + render(); + + expect(mockSignatureComponent).toHaveBeenCalledTimes(1); + expect(mockSignatureComponent).toHaveBeenCalledWith( + expect.objectContaining({ + className: defaultProps.class, + readOnly: false, + clearSignature: false, + imageSource + }) + ); + + const passedProps = mockSignatureComponent.mock.calls[0][0] as { + onSignEndAction?: () => void; + }; + expect(typeof passedProps.onSignEndAction).toBe("function"); + }); +}); From 7d72360dd827a49c288f120a7038be186fcfa2fe Mon Sep 17 00:00:00 2001 From: gjulivan Date: Mon, 23 Mar 2026 15:20:55 +0100 Subject: [PATCH 5/7] fix: update icons and code cleanup --- .../signature-web/package.json | 8 ++---- .../src/Signature.editorPreview.tsx | 1 - .../signature-web/src/Signature.tsx | 11 +++++-- .../signature-web/src/Signature.xml | 9 ++++++ .../src/assets/Signature.icon.active.svg | 3 -- .../src/assets/Signature.icon.dark.active.svg | 3 -- .../src/assets/Signature.icon.dark.png | Bin 1801 -> 0 bytes .../src/assets/Signature.icon.dark.svg | 9 ++++-- .../src/assets/Signature.icon.png | Bin 1879 -> 0 bytes .../src/assets/Signature.icon.svg | 9 ++++-- .../src/assets/Signature.tile.dark.svg | 6 ++++ .../src/assets/Signature.tile.svg | 6 ++++ .../signature-web/src/components/Alert.tsx | 12 -------- .../signature-web/src/components/Grid.tsx | 5 ++-- .../src/components/Signature.tsx | 2 +- .../src/components/SizeContainer.ts | 27 ------------------ .../signature-web/src/package.xml | 2 +- .../signature-web/src/ui/SignaturePreview.css | 22 -------------- .../signature-web/src/utils/customTypes.ts | 19 ++---------- .../signature-web/typings/SignatureProps.d.ts | 4 ++- 20 files changed, 55 insertions(+), 103 deletions(-) delete mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.icon.active.svg delete mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.active.svg delete mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.png delete mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.icon.png create mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.tile.dark.svg create mode 100644 packages/pluggableWidgets/signature-web/src/assets/Signature.tile.svg delete mode 100644 packages/pluggableWidgets/signature-web/src/components/Alert.tsx delete mode 100644 packages/pluggableWidgets/signature-web/src/ui/SignaturePreview.css diff --git a/packages/pluggableWidgets/signature-web/package.json b/packages/pluggableWidgets/signature-web/package.json index 6524437ebf..176bb67af4 100644 --- a/packages/pluggableWidgets/signature-web/package.json +++ b/packages/pluggableWidgets/signature-web/package.json @@ -1,7 +1,7 @@ { "name": "@mendix/signature-web", "widgetName": "Signature", - "version": "1.0.0", + "version": "2.0.0", "description": "Signature widget for Mendix Web", "copyright": "© Mendix Technology BV 2026. All rights reserved.", "license": "Apache-2.0", @@ -46,17 +46,15 @@ "verify": "rui-verify-package-format" }, "dependencies": { - "@uiw/react-signature": "^1.3.4", "classnames": "^2.5.1", - "react-resize-detector": "^12.3.0", "signature_pad": "^5.1.3" }, "devDependencies": { "@mendix/automation-utils": "workspace:*", "@mendix/eslint-config-web-widgets": "workspace:*", - "@mendix/pluggable-widgets-tools": "file:mendix-pluggable-widgets-tools.tgz", + "@mendix/pluggable-widgets-tools": "workspace:*", "@mendix/prettier-config-web-widgets": "workspace:*", - "@mendix/run-e2e": "workspace:^*", + "@mendix/run-e2e": "workspace:*", "@mendix/widget-plugin-component-kit": "workspace:*", "@mendix/widget-plugin-hooks": "workspace:*", "@mendix/widget-plugin-platform": "workspace:*", diff --git a/packages/pluggableWidgets/signature-web/src/Signature.editorPreview.tsx b/packages/pluggableWidgets/signature-web/src/Signature.editorPreview.tsx index 797c62a13a..04f42a5348 100644 --- a/packages/pluggableWidgets/signature-web/src/Signature.editorPreview.tsx +++ b/packages/pluggableWidgets/signature-web/src/Signature.editorPreview.tsx @@ -1,5 +1,4 @@ import { ReactElement } from "react"; -import "./ui/SignaturePreview.css"; import { SignaturePreviewProps } from "typings/SignatureProps"; import classNames from "classnames"; diff --git a/packages/pluggableWidgets/signature-web/src/Signature.tsx b/packages/pluggableWidgets/signature-web/src/Signature.tsx index 025f5335f4..1dcd9b45c6 100644 --- a/packages/pluggableWidgets/signature-web/src/Signature.tsx +++ b/packages/pluggableWidgets/signature-web/src/Signature.tsx @@ -4,8 +4,15 @@ import { SignatureComponent } from "./components/Signature"; import "./ui/Signature.scss"; export default function Signature(props: SignatureContainerProps): ReactElement { - const { class: className } = props; - const handleSignEnd = useCallback(() => {}, []); + const { class: className, onSignEndAction } = props; + const handleSignEnd = useCallback( + (imageDataUrl?: string) => { + if (onSignEndAction && !onSignEndAction.isExecuting && onSignEndAction.canExecute) { + onSignEndAction.execute({ signatureImage: imageDataUrl }); + } + }, + [onSignEndAction] + ); return ( + + + On sign end + Action that is executed when the user finishes signing. The action will receive the signature image as a parameter. + + + + + Show background grid diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.active.svg b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.active.svg deleted file mode 100644 index 549a748d04..0000000000 --- a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.active.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.active.svg b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.active.svg deleted file mode 100644 index 2cde472fd8..0000000000 --- a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.active.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.png b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.png deleted file mode 100644 index 137bba05250fd4e17e26acc66d52563d4a55de5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1801 zcmV+k2ln`hP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw0000^WmrjOO-%qQ0000800aRV z00jU50096106qa500jU50096107d~Q00RI3009630006L00RI3009620000000000 z0AK(B009610AK(B00DOe-{$}T21-dpK~#7F?OI!I+eQ@SP>loeW30_Nx5#!#8|^;i&3HUMZ?#$j>Q7pp z6afStz`8Nu&iD5Aj$`I{!%v2Qgy3CZqg zwgQNij=~a<1iXx8a^72VAL>6V?Lf1T1f&HoP{9lOqD~UQ&>|UC3P(Uz@B}hR)K|$U z6amwKCtwqO6=P((Fa+cTzN@0`bUK#WC$|ehKp1!!YU5mYWrKC~2z{emE?-BHuy6vR zj0f2DH~=yFZXk?WW1$4Z8Be=Skvt4Qgnr;Qn5?m`deFiM2s55CJQ(>wHdIGKls+=V z=OJsf<#nmf)Q)+yql_0B9_Dmm3%&h$g)%+Fga-2b7wGJI1Ct7oC-kXHvxW_FevJjrHAS-wYsJfHxP#W+w7i9X56fH9IAUG}f zH2T8r)t%Q7CCHsA0cngE2FWsweircbteFvz#&{XDsHf4-3Vvn;q%mFqmSr0KX~55f zfHcO-phZ26{ZXd1yph+pj0YZ^5UrXM_L&|8{UOw-h6aALwV;Kdq50_uUdBgW%ot{#9L_jv#w zej8>$9^k{)PSc+o0rcHX34r$Q?rvXaOi{p-ZMhu*d~&iBus-l~XJh;YUQtOlmARRN zn7U5dc5VdV!FBcF_~Ya`yke7%27c=_jYSUuKUAu%&n-sAdj$b-9Um&cc^#Sx zykLOy-^10|hot}K>1X*{o@VK(x)OQ7%Xh;wZtx>|d9IA^zu<{o`KbtizTKzY1z`6d zmk2P@*52g4memSTk0s#c`(X!Bswu2BS?Lh6Wm&+}E@?er=Z`y!mypLZ!=g!UA@C!o@$vQA zVA8V`LhAuexqRpY52(uso_0`60OL-R21S9}pDx?Zf5#?j6S@8VVT*C&Z?7A!|LN7U z4X?dqmB2M+$-f~;iso&jMIak0S zH&`FHMgu?J(P1V#qZlFdiy}1yu)b_ubr{?^;r8mz6Zm1d()jr6S`SBucHBoMXJ&_V z<@Mw0G@r6kdMBBM7s>I?wPpM5U7MNaiEJ2dg*F1*m%o0i_9w5!9W_xB;N>Ip->qO? z%WFZ;mr;6zlno2+V_}^i4b#LIB%=m`E$B)f$a)Xs$HwQ^YrZ9?X#@yxBl>vw)&Jn= zN9e!{4Uo_Vfj&aTSQhy(b~Zr3Ad9X}CvXI42ayRL>n7{_c#qs(-g$W*jze3G2l9A| zI>%gIHQ81Qo!F@X4-gt|M(7x4s;i4}S2F(Q(<}F^`?__FDLmmDjz$mI|6z>ZP<+v? zpS3TP09w#JpCzNt-H#ydRY&I$fsG^5^V77(P%xXURj2hQ#YPTcyO|?523Y$R{a?As rZq1R?U)FaJ0e&S{46GPfECc@nL#e%**k1?c00000NkvXXu0mjf0o^E( diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.svg b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.svg index e32ab55af4..f0e5b9d88d 100644 --- a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.svg +++ b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.dark.svg @@ -1,3 +1,6 @@ - - - \ No newline at end of file + + + + + + diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.png b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.png deleted file mode 100644 index 52babd516fb707ef31328f96fa1d273a431e527b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1879 zcmV-d2dMaoP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw0000^WmrjOO-%qQ0000800aRV z00jU50096106qa500jU50096107d~Q00RI3009630006L00RI3009620000000000 z0AK(B009610AK(B00DOe-{$}T2AD}iK~#7F?ONS#6Gs%Dvuo3$1~rIq?>s@>C%}1v z8qr9kH!%{adeJt{6U010oI4aMVJ=FzC?Pxn?i)ByfVplFD@YY+?45qc@tB#}AA9X} zyh%M$GG~6y_=n zCjrlPV^)jKS68-2!H{_ZqQDc;gXjB?s4LxNDaAd2ZR>!^m(}m@-Y@BOVREJkhy(w} z)4du4;-Gi%>`|lp#p$;wwz*EFE>T&@QF&$w7zMlz>afx9NJ{pEK?1n%289SAlLRCM zudsE#?6j2J&kI&LP|O?w;(aYLn<;wz$D-q=b8Qx#8z`=2uKIKY*_e2`R-2z zyG}1>f`BOSFx2b#PD3|1OpehPE_GkUkuY-t;*1B_#bE%3=rdo1xG`o*zzD|20*KP* zqcAIK>5PPOWl^i^i8CW0%6LBE;c4%QWoTd)qAK_3G9D}arYu31YY(D=KXS_P$ z-C4Wez^Q)SvaXGz?}|(QEdWHjnV3AK&n+QicsM>^*R{^w14aSQ20q{atr9kiyq-q^ z&to`5bJJ-5Ur3PkIY|n{261j4kQBT!JAwq&EMmb+ zGG?4)z$4CwfN{YOPzuMGNmZW+eDCpj&knBB4}z0|Poh6?dwb@s;HU`Xe5$)Z661BF zl$=C=9Pm>mAc^q`u%0K;9~b=82uNbQ4qC}c^d|v76#|kNuK??L68%ZR^Y5m=4U)7E zAE8^74qD0Q4L)@OR#!KQLJD*5jfubtIOj>gbN^G{fUuPt^nboL{hh zsHvaLt+qiiDR@@o+hBe!fY|2pIN(_?RRW}>A`hw(zpqnrR6Y)PHI^cQgxng1Xr-s; zIlVBcOoDFdW4IK4f>V7a0k6jBzYGn;9o0T8Pt^n9Plg9{PW?Ag2BZN#YV0KSshtG* z-VKkcueBc!JbSCQtbk{GQd|O^f_1WPDZreUu|v3daZC6Pyu`2QZ7h!)#O!gBmQy1D zYpG=a`0cfgI_kd>B+s@-i5`T|Xr)z>|Ru2dG?Px*IxU5MPqDY1#2 zqJ?+&N1cxgt;55*F;0li)T>7FfThjj9T;E5Wu$Ps?n_wJFf99+D;hTo{Na+1&r~EG z5q0qa)0Jj_zc$peP#8+U&CTP-h+P$BEIH0PFDy99bO zFL>sSMJ0F3o?W7xg*vXZ$TGykH$ z-c>c{EgY6sr1YQYmDq1~dNIPNoP8lc006agvvPheFmuZ7(XXiYh1|k1dFAi=wPx4p zR&6qIYy6mXEuGlnV)dkO6Q|M}oBuqXh8F>^nU;S2P{aMywoxmoMvi>>SAC(yv&cZg zW}d<8OQydoywb-4DaMJC0djjzbPBlME_8kR8iBaz2+3b~pw9Tnq1pN5u6Pfx>O)Q> z2MA!-M&y2thEUg!__f~5>)=&CkWj-L9FtJhI7SWvmO(&!4AoGTz!K&^A#u~>G!az)bR2QS@kJYUVlk2c9+?A{E8G%EXB~zVc|9V>T^@0ye~{D|e#GXn zFm#E>=fvaTLdC=M;*Z)w`fnh=M$CEB75SD|PtV=YesTVP&cK|3IRl>=_z#YlH^4)9 R{+R#(002ovPDHLkV1fk9QTG4< diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.svg b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.svg index 15cba120d4..70ddbb28d9 100644 --- a/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.svg +++ b/packages/pluggableWidgets/signature-web/src/assets/Signature.icon.svg @@ -1,3 +1,6 @@ - - - \ No newline at end of file + + + + + + diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.tile.dark.svg b/packages/pluggableWidgets/signature-web/src/assets/Signature.tile.dark.svg new file mode 100644 index 0000000000..6c072ae7ff --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/assets/Signature.tile.dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/pluggableWidgets/signature-web/src/assets/Signature.tile.svg b/packages/pluggableWidgets/signature-web/src/assets/Signature.tile.svg new file mode 100644 index 0000000000..b39521a425 --- /dev/null +++ b/packages/pluggableWidgets/signature-web/src/assets/Signature.tile.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/pluggableWidgets/signature-web/src/components/Alert.tsx b/packages/pluggableWidgets/signature-web/src/components/Alert.tsx deleted file mode 100644 index 189ef0aaf9..0000000000 --- a/packages/pluggableWidgets/signature-web/src/components/Alert.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { FC, PropsWithChildren } from "react"; -import classNames from "classnames"; - -export interface AlertProps extends PropsWithChildren { - bootstrapStyle?: "default" | "primary" | "success" | "info" | "warning" | "danger"; - className?: string; -} - -export const Alert: FC = ({ bootstrapStyle = "danger", className, children }) => - children ?
{children}
: null; - -Alert.displayName = "Alert"; diff --git a/packages/pluggableWidgets/signature-web/src/components/Grid.tsx b/packages/pluggableWidgets/signature-web/src/components/Grid.tsx index b4928668ca..95280f8132 100644 --- a/packages/pluggableWidgets/signature-web/src/components/Grid.tsx +++ b/packages/pluggableWidgets/signature-web/src/components/Grid.tsx @@ -1,4 +1,4 @@ -import { FC } from "react"; +import { FC, useId } from "react"; export interface GridBackgroundProps { gridCellWidth: number; @@ -14,8 +14,7 @@ export const Grid: FC = ({ gridBorderWidth, showGrid = true }) => { - // eslint-disable-next-line react-hooks/purity - const id = `grid${Math.floor(Math.random() * 1000000)}`; + const id = useId(); return showGrid ? ( diff --git a/packages/pluggableWidgets/signature-web/src/components/Signature.tsx b/packages/pluggableWidgets/signature-web/src/components/Signature.tsx index f15287ca78..11a8dd6825 100644 --- a/packages/pluggableWidgets/signature-web/src/components/Signature.tsx +++ b/packages/pluggableWidgets/signature-web/src/components/Signature.tsx @@ -4,7 +4,7 @@ import { ReactElement } from "react"; import { useSignaturePad } from "src/utils/useSignaturePad"; import Utils from "../utils/Utils"; import { SignatureProps } from "../utils/customTypes"; -import { Alert } from "./Alert"; +import { Alert } from "@mendix/widget-plugin-component-kit/Alert"; import { Grid } from "./Grid"; import { SizeContainer } from "./SizeContainer"; diff --git a/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts b/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts index 61603fbe9f..05d6e3782a 100644 --- a/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts +++ b/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts @@ -1,7 +1,6 @@ import { createElement, CSSProperties, FC, PropsWithChildren } from "react"; import classNames from "classnames"; import { useResizeObserver } from "../utils/useResizeObserver"; -// import { Dimensions, HeightUnitType, WidthUnitType } from "../utils/customTypes"; import { constructWrapperStyle, DimensionsProps } from "../utils/dimensions"; export interface SizeProps extends DimensionsProps, PropsWithChildren { @@ -15,8 +14,6 @@ export interface SizeProps extends DimensionsProps, PropsWithChildren { export const SizeContainer: FC = (props: SizeProps) => { const { className, children, classNameInner, readOnly = false, style, onResize } = props; const ref = useResizeObserver(() => onResize?.()); - - // const styleWidth = widthUnit === "percentage" ? `${width}%` : `${width}px`; const wrapperStyle = constructWrapperStyle(props); return createElement( "div", @@ -49,27 +46,3 @@ export const SizeContainer: FC = (props: SizeProps) => { }; SizeContainer.displayName = "SizeContainer"; - -// const getHeight = ( -// heightUnit: HeightUnitType, -// height: number, -// widthUnit: WidthUnitType, -// width: number -// ): CSSProperties => { -// const style: CSSProperties = {}; -// if (heightUnit === "percentageOfWidth") { -// const ratio = (height / 100) * width; -// if (widthUnit === "percentage") { -// style.height = "auto"; -// style.paddingBottom = `${ratio}%`; -// } else { -// style.height = `${ratio}px`; -// } -// } else if (heightUnit === "pixels") { -// style.height = `${height}px`; -// } else if (heightUnit === "percentageOfParent") { -// style.height = `${height}%`; -// } - -// return style; -// }; diff --git a/packages/pluggableWidgets/signature-web/src/package.xml b/packages/pluggableWidgets/signature-web/src/package.xml index 4be148fd4a..7eb2568aee 100644 --- a/packages/pluggableWidgets/signature-web/src/package.xml +++ b/packages/pluggableWidgets/signature-web/src/package.xml @@ -1,6 +1,6 @@ - + diff --git a/packages/pluggableWidgets/signature-web/src/ui/SignaturePreview.css b/packages/pluggableWidgets/signature-web/src/ui/SignaturePreview.css deleted file mode 100644 index 1ca1d4921c..0000000000 --- a/packages/pluggableWidgets/signature-web/src/ui/SignaturePreview.css +++ /dev/null @@ -1,22 +0,0 @@ -.widget-events-preview { - font-size: 12px; - color: #6b707b; - border: 1px solid #d9dbdd; - min-height: 5px; - min-width: 100%; - text-align: center; - padding: 8px; - display: flex; - justify-content: center; - background-color: #fff; -} - -.widget-events-preview.active { - background-color: var(--color-alpha-grey-2); -} - -.widget-events-icon-container { - display: flex; - justify-content: center; - align-items: center; -} diff --git a/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts b/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts index b29a1319a7..477693beb6 100644 --- a/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts +++ b/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts @@ -1,19 +1,6 @@ -import { SignatureContainerProps } from "typings/SignatureProps"; +import { PenTypeEnum, SignatureContainerProps } from "../../typings/SignatureProps"; -// export type HeightUnitType = "percentageOfWidth" | "percentageOfParent" | "pixels"; - -// export type WidthUnitType = "percentage" | "pixels"; - -// export interface Dimensions { -// widthUnit: WidthUnitType; -// width: number; -// heightUnit: HeightUnitType; -// height: number; -// } - -export type penOptions = "fountain" | "ballpoint" | "marker"; - -export interface SignatureProps extends SignatureContainerProps { +export interface SignatureProps extends Omit { className: string; alertMessage?: string; clearSignature: boolean; @@ -22,7 +9,7 @@ export interface SignatureProps extends SignatureContainerProps { gridCellHeight: number; gridBorderColor: string; gridBorderWidth: number; - penType: penOptions; + penType: PenTypeEnum; penColor: string; onSignEndAction?: (imageUrl?: string) => void; wrapperStyle?: object; diff --git a/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts b/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts index 293f723431..5efc8e9246 100644 --- a/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts +++ b/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts @@ -4,7 +4,7 @@ * @author Mendix Widgets Framework Team */ import { CSSProperties } from "react"; -import { EditableValue, EditableImageValue, WebImage } from "mendix"; +import { ActionValue, EditableValue, EditableImageValue, Option, WebImage } from "mendix"; export type PenTypeEnum = "fountain" | "ballpoint" | "marker"; @@ -36,6 +36,7 @@ export interface SignatureContainerProps { maxHeightUnit: MaxHeightUnitEnum; maxHeight: number; OverflowY: OverflowYEnum; + onSignEndAction?: ActionValue<{ signatureImage: Option }>; showGrid: boolean; gridBorderColor: string; gridCellHeight: number; @@ -67,6 +68,7 @@ export interface SignaturePreviewProps { maxHeightUnit: MaxHeightUnitEnum; maxHeight: number | null; OverflowY: OverflowYEnum; + onSignEndAction: {} | null; showGrid: boolean; gridBorderColor: string; gridCellHeight: number | null; From d50d17a0f4f56af180a0989208d58399fed6080c Mon Sep 17 00:00:00 2001 From: gjulivan Date: Tue, 24 Mar 2026 09:36:55 +0100 Subject: [PATCH 6/7] fix: snapshot and test --- .../signature-web/package.json | 2 +- pnpm-lock.yaml | 61 +++++-------------- 2 files changed, 17 insertions(+), 46 deletions(-) diff --git a/packages/pluggableWidgets/signature-web/package.json b/packages/pluggableWidgets/signature-web/package.json index 176bb67af4..4f7f7b65db 100644 --- a/packages/pluggableWidgets/signature-web/package.json +++ b/packages/pluggableWidgets/signature-web/package.json @@ -41,7 +41,7 @@ "publish-marketplace": "rui-publish-marketplace", "release": "pluggable-widgets-tools release:web", "start": "pluggable-widgets-tools start:server", - "test": "pluggable-widgets-tools test:unit:web:enzyme-free", + "test": "pluggable-widgets-tools test:unit:web", "update-changelog": "rui-update-changelog-widget", "verify": "rui-verify-package-format" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ea87af6750..f02112d5fa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2237,15 +2237,9 @@ importers: packages/pluggableWidgets/signature-web: dependencies: - '@uiw/react-signature': - specifier: ^1.3.4 - version: 1.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) classnames: specifier: ^2.5.1 version: 2.5.1 - react-resize-detector: - specifier: ^12.3.0 - version: 12.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) signature_pad: specifier: ^5.1.3 version: 5.1.3 @@ -2263,7 +2257,7 @@ importers: specifier: workspace:* version: link:../../shared/prettier-config-web-widgets '@mendix/run-e2e': - specifier: workspace:^* + specifier: workspace:* version: link:../../../automation/run-e2e '@mendix/widget-plugin-component-kit': specifier: workspace:* @@ -5188,12 +5182,6 @@ packages: react: '>=18.0.0 <19.0.0' react-dom: '>=18.0.0 <19.0.0' - '@uiw/react-signature@1.3.4': - resolution: {integrity: sha512-jmukgdpHJJMJ5aDYi7ijv85tVc5MADkof6JOoQm8a3wQ37qi3GG34YMTEKjQFXqOnjU0/gnbxrTR4DA+Lp4btg==} - peerDependencies: - react: '>=18.0.0 <19.0.0' - react-dom: '>=18.0.0 <19.0.0' - '@vis.gl/react-google-maps@0.8.3': resolution: {integrity: sha512-iubZIH9MJSkJA9NCMwKkMlHb/iNSeXzVRE7fPVhkKJPId6TBvQcpKA98tirUXi2AfEkYL+IVcE3doL6WdeQ2QA==} peerDependencies: @@ -6462,9 +6450,6 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es-toolkit@1.45.1: - resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==} - es5-ext@0.10.64: resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} engines: {node: '>=0.10'} @@ -8713,9 +8698,6 @@ packages: engines: {node: '>=10'} hasBin: true - perfect-freehand@1.2.3: - resolution: {integrity: sha512-bHZSfqDHGNlPpgH2yxXgPHlQSPpEbo+qg7li0M78J9vNAi2yjwLeA4x79BEQhX44lEWpCLSFCeRZwpw0niiXPA==} - performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} @@ -9312,12 +9294,6 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} - react-resize-detector@12.3.0: - resolution: {integrity: sha512-mIDOVrTHKGnKe6qEUWi8dFdfHM5CPyTOpqoHctdMQf89Ljm/0qqDIzkP3vTRZZJi9/raaMiRxDEOqO4you5x+A==} - peerDependencies: - react: '>=18.0.0 <19.0.0' - react-dom: '>=18.0.0 <19.0.0' - react-test-renderer@19.2.4: resolution: {integrity: sha512-Ttl5D7Rnmi6JGMUpri4UjB4BAN0FPs4yRDnu2XSsigCWOLm11o8GwRlVsh27ER+4WFqsGtrBuuv5zumUaRCmKw==} peerDependencies: @@ -12309,7 +12285,7 @@ snapshots: identity-obj-proxy: 3.0.0 jasmine: 3.99.0 jasmine-core: 3.99.1 - jest: 29.7.0(@types/node@22.14.1)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3)) + jest: 29.7.0(@types/node@22.14.1) jest-environment-jsdom: 29.7.0 jest-jasmine2: 29.7.0 jest-junit: 13.2.0 @@ -12984,7 +12960,7 @@ snapshots: react-test-renderer: 19.2.4(react@18.3.1) redent: 3.0.0 optionalDependencies: - jest: 29.7.0(@types/node@22.14.1)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3)) + jest: 29.7.0(@types/node@22.14.1) '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -13450,13 +13426,6 @@ snapshots: - '@codemirror/lint' - '@codemirror/search' - '@uiw/react-signature@1.3.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.28.6 - perfect-freehand: 1.2.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - '@vis.gl/react-google-maps@0.8.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@types/google.maps': 3.58.1 @@ -14901,8 +14870,6 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.45.1: {} - es5-ext@0.10.64: dependencies: es6-iterator: 2.0.3 @@ -16607,6 +16574,18 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 + jest@29.7.0(@types/node@22.14.1): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.14.1)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest@29.7.0(@types/node@22.14.1)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3)) @@ -17659,8 +17638,6 @@ snapshots: peggy@1.2.0: {} - perfect-freehand@1.2.3: {} - performance-now@2.1.0: {} pick-by-alias@1.2.0: {} @@ -18398,12 +18375,6 @@ snapshots: react-refresh@0.14.2: {} - react-resize-detector@12.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - es-toolkit: 1.45.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-test-renderer@19.2.4(react@18.3.1): dependencies: react: 18.3.1 @@ -19399,7 +19370,7 @@ snapshots: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.8 - jest: 29.7.0(@types/node@22.14.1)(ts-node@10.9.2(@swc/core@1.13.5)(@types/node@22.14.1)(typescript@5.9.3)) + jest: 29.7.0(@types/node@22.14.1) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 From bafb25424a32041020954e54167a427327fba0c7 Mon Sep 17 00:00:00 2001 From: gjulivan Date: Thu, 26 Mar 2026 13:45:24 +0100 Subject: [PATCH 7/7] chore: update props and code cleanup --- .../pluggableWidgets/signature-web/README.md | 2 +- .../mendix-pluggable-widgets-tools.tgz | Bin 63447 -> 0 bytes .../signature-web/package.json | 5 ++-- .../src/Signature.editorConfig.ts | 6 ++-- .../signature-web/src/Signature.tsx | 22 ++------------- .../signature-web/src/Signature.xml | 5 ++-- .../src/__tests__/Signature.spec.tsx | 12 ++------ .../signature-web/src/components/Grid.tsx | 13 ++------- .../src/components/Signature.tsx | 15 ++++++---- .../src/components/SizeContainer.ts | 2 +- .../signature-web/src/utils/Utils.ts | 16 ----------- .../signature-web/src/utils/customTypes.ts | 6 +--- .../signature-web/src/utils/dimensions.ts | 10 +++---- .../src/utils/useResizeObserver.ts | 26 ------------------ .../src/utils/useSignaturePad.ts | 18 +++++------- .../signature-web/typings/SignatureProps.d.ts | 6 ++-- pnpm-lock.yaml | 13 --------- 17 files changed, 45 insertions(+), 132 deletions(-) delete mode 100644 packages/pluggableWidgets/signature-web/mendix-pluggable-widgets-tools.tgz delete mode 100644 packages/pluggableWidgets/signature-web/src/utils/useResizeObserver.ts diff --git a/packages/pluggableWidgets/signature-web/README.md b/packages/pluggableWidgets/signature-web/README.md index 4247327a94..2dbdab3de0 100644 --- a/packages/pluggableWidgets/signature-web/README.md +++ b/packages/pluggableWidgets/signature-web/README.md @@ -1,3 +1,3 @@ -Please see [App Events](https://docs.mendix.com/appstore/widgets/) in the Mendix documentation for details. +Please see [Signature](https://docs.mendix.com/appstore/widgets/) in the Mendix documentation for details. diff --git a/packages/pluggableWidgets/signature-web/mendix-pluggable-widgets-tools.tgz b/packages/pluggableWidgets/signature-web/mendix-pluggable-widgets-tools.tgz deleted file mode 100644 index 93ea04ec327c8cd94c4c63ad547bf99bb69098ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63447 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 Q6$~IsNuoVN-F|@jA9Mu*vj6}9 diff --git a/packages/pluggableWidgets/signature-web/package.json b/packages/pluggableWidgets/signature-web/package.json index 4f7f7b65db..e475140fd3 100644 --- a/packages/pluggableWidgets/signature-web/package.json +++ b/packages/pluggableWidgets/signature-web/package.json @@ -20,7 +20,7 @@ }, "packagePath": "com.mendix.widget.web", "marketplace": { - "minimumMXVersion": "10.8.0", + "minimumMXVersion": "11.8.0", "appNumber": 107984, "appName": "Signature", "reactReady": true @@ -58,7 +58,6 @@ "@mendix/widget-plugin-component-kit": "workspace:*", "@mendix/widget-plugin-hooks": "workspace:*", "@mendix/widget-plugin-platform": "workspace:*", - "@mendix/widget-plugin-test-utils": "workspace:*", - "cross-env": "^7.0.3" + "@mendix/widget-plugin-test-utils": "workspace:*" } } diff --git a/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts b/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts index 599266b7a4..010305208d 100644 --- a/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts +++ b/packages/pluggableWidgets/signature-web/src/Signature.editorConfig.ts @@ -16,7 +16,7 @@ export function getProperties( values: SignaturePreviewProps, defaultProperties: Properties /* , target: Platform*/ ): Properties { - if (values.heightUnit === "percentageOfWidth") { + if (values.heightUnit === "auto") { hidePropertyIn(defaultProperties, values, "height"); } else { hidePropertiesIn(defaultProperties, values, [ @@ -24,7 +24,7 @@ export function getProperties( "minHeightUnit", "maxHeight", "maxHeightUnit", - "OverflowY" + "overflowY" ]); } @@ -33,7 +33,7 @@ export function getProperties( } if (values.maxHeightUnit === "none") { - hidePropertiesIn(defaultProperties, values, ["maxHeight", "OverflowY"]); + hidePropertiesIn(defaultProperties, values, ["maxHeight", "overflowY"]); } return defaultProperties; diff --git a/packages/pluggableWidgets/signature-web/src/Signature.tsx b/packages/pluggableWidgets/signature-web/src/Signature.tsx index 1dcd9b45c6..02b57c5787 100644 --- a/packages/pluggableWidgets/signature-web/src/Signature.tsx +++ b/packages/pluggableWidgets/signature-web/src/Signature.tsx @@ -1,25 +1,9 @@ -import { ReactElement, useCallback } from "react"; +import { ReactElement } from "react"; import { SignatureContainerProps } from "../typings/SignatureProps"; import { SignatureComponent } from "./components/Signature"; import "./ui/Signature.scss"; export default function Signature(props: SignatureContainerProps): ReactElement { - const { class: className, onSignEndAction } = props; - const handleSignEnd = useCallback( - (imageDataUrl?: string) => { - if (onSignEndAction && !onSignEndAction.isExecuting && onSignEndAction.canExecute) { - onSignEndAction.execute({ signatureImage: imageDataUrl }); - } - }, - [onSignEndAction] - ); - return ( - - ); + const { class: className } = props; + return ; } diff --git a/packages/pluggableWidgets/signature-web/src/Signature.xml b/packages/pluggableWidgets/signature-web/src/Signature.xml index 2c564ed164..a076b0f8ac 100644 --- a/packages/pluggableWidgets/signature-web/src/Signature.xml +++ b/packages/pluggableWidgets/signature-web/src/Signature.xml @@ -17,6 +17,7 @@ + @@ -52,7 +53,7 @@ Height unit - Auto + Auto Pixels Percentage Viewport @@ -90,7 +91,7 @@ Maximum height - + Vertical Overflow diff --git a/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx b/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx index ad31f61861..32dcfffae1 100644 --- a/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx +++ b/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx @@ -31,7 +31,7 @@ describe("Signature", () => { minHeight: 0, maxHeightUnit: "none", maxHeight: 0, - OverflowY: "auto", + overflowY: "auto", showGrid: true, gridBorderColor: "#cccccc", gridCellHeight: 20, @@ -53,18 +53,12 @@ describe("Signature", () => { render(); expect(mockSignatureComponent).toHaveBeenCalledTimes(1); - expect(mockSignatureComponent).toHaveBeenCalledWith( + expect(mockSignatureComponent.mock.calls[0][0]).toEqual( expect.objectContaining({ + ...defaultProps, className: defaultProps.class, - readOnly: false, - clearSignature: false, imageSource }) ); - - const passedProps = mockSignatureComponent.mock.calls[0][0] as { - onSignEndAction?: () => void; - }; - expect(typeof passedProps.onSignEndAction).toBe("function"); }); }); diff --git a/packages/pluggableWidgets/signature-web/src/components/Grid.tsx b/packages/pluggableWidgets/signature-web/src/components/Grid.tsx index 95280f8132..4680abd84b 100644 --- a/packages/pluggableWidgets/signature-web/src/components/Grid.tsx +++ b/packages/pluggableWidgets/signature-web/src/components/Grid.tsx @@ -5,17 +5,10 @@ export interface GridBackgroundProps { gridCellHeight: number; gridBorderColor: string; gridBorderWidth: number; - showGrid?: boolean; } -export const Grid: FC = ({ - gridCellWidth, - gridCellHeight, - gridBorderColor, - gridBorderWidth, - showGrid = true -}) => { +export const Grid: FC = ({ gridCellWidth, gridCellHeight, gridBorderColor, gridBorderWidth }) => { const id = useId(); - return showGrid ? ( + return ( @@ -39,7 +32,7 @@ export const Grid: FC = ({ - ) : null; + ); }; Grid.displayName = "Grid"; diff --git a/packages/pluggableWidgets/signature-web/src/components/Signature.tsx b/packages/pluggableWidgets/signature-web/src/components/Signature.tsx index 11a8dd6825..90bfc0d0d9 100644 --- a/packages/pluggableWidgets/signature-web/src/components/Signature.tsx +++ b/packages/pluggableWidgets/signature-web/src/components/Signature.tsx @@ -2,14 +2,17 @@ import classNames from "classnames"; import { ReactElement } from "react"; import { useSignaturePad } from "src/utils/useSignaturePad"; -import Utils from "../utils/Utils"; -import { SignatureProps } from "../utils/customTypes"; import { Alert } from "@mendix/widget-plugin-component-kit/Alert"; +import { If } from "@mendix/widget-plugin-component-kit/If"; import { Grid } from "./Grid"; import { SizeContainer } from "./SizeContainer"; +import { SignatureProps } from "../utils/customTypes"; +import Utils from "../utils/Utils"; export function SignatureComponent(props: SignatureProps): ReactElement { const { className, alertMessage, wrapperStyle, imageSource, onSignEndAction } = props; + const readOnly = imageSource.readOnly; + const showGrid = props.showGrid && !readOnly; const handleSignEnd = (imageDataUrl?: string): void => { if (imageDataUrl) { @@ -17,8 +20,8 @@ export function SignatureComponent(props: SignatureProps): ReactElement { } // Trigger microflow to update signature attribute - if (onSignEndAction) { - onSignEndAction(imageDataUrl); + if (onSignEndAction && !onSignEndAction.isExecuting && onSignEndAction.canExecute) { + onSignEndAction.execute({ signatureImage: imageDataUrl }); } }; @@ -33,7 +36,9 @@ export function SignatureComponent(props: SignatureProps): ReactElement { onResize={onResize} > {alertMessage} - + + + ); diff --git a/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts b/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts index 05d6e3782a..c8d7e48db4 100644 --- a/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts +++ b/packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts @@ -1,6 +1,6 @@ import { createElement, CSSProperties, FC, PropsWithChildren } from "react"; import classNames from "classnames"; -import { useResizeObserver } from "../utils/useResizeObserver"; +import { useResizeObserver } from "@mendix/widget-plugin-hooks/useResizeObserver"; import { constructWrapperStyle, DimensionsProps } from "../utils/dimensions"; export interface SizeProps extends DimensionsProps, PropsWithChildren { diff --git a/packages/pluggableWidgets/signature-web/src/utils/Utils.ts b/packages/pluggableWidgets/signature-web/src/utils/Utils.ts index 81b741ebf4..d3b2ed3a19 100644 --- a/packages/pluggableWidgets/signature-web/src/utils/Utils.ts +++ b/packages/pluggableWidgets/signature-web/src/utils/Utils.ts @@ -1,21 +1,5 @@ // eslint-disable-next-line @typescript-eslint/no-extraneous-class export default class Utils { - static parseStyle(style = ""): { [key: string]: string } { - try { - return style.split(";").reduce<{ [key: string]: string }>((styleObject, line) => { - const pair = line.split(":"); - if (pair.length === 2) { - const name = pair[0].trim().replace(/(-.)/g, match => match[1].toUpperCase()); - styleObject[name] = pair[1].trim(); - } - return styleObject; - }, {}); - } catch (error) { - window.console.log("Failed to parse style", style, error); - } - return {}; - } - static convertUrlToBlob(base64Uri: string): Blob { const contentType = "image/png"; const sliceSize = 512; diff --git a/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts b/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts index 477693beb6..202cf6f3f7 100644 --- a/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts +++ b/packages/pluggableWidgets/signature-web/src/utils/customTypes.ts @@ -1,17 +1,13 @@ import { PenTypeEnum, SignatureContainerProps } from "../../typings/SignatureProps"; -export interface SignatureProps extends Omit { +export interface SignatureProps extends SignatureContainerProps { className: string; alertMessage?: string; - clearSignature: boolean; - showGrid: boolean; gridCellWidth: number; gridCellHeight: number; gridBorderColor: string; gridBorderWidth: number; penType: PenTypeEnum; penColor: string; - onSignEndAction?: (imageUrl?: string) => void; wrapperStyle?: object; - readOnly: boolean; } diff --git a/packages/pluggableWidgets/signature-web/src/utils/dimensions.ts b/packages/pluggableWidgets/signature-web/src/utils/dimensions.ts index 682a6e4736..85d47afce1 100644 --- a/packages/pluggableWidgets/signature-web/src/utils/dimensions.ts +++ b/packages/pluggableWidgets/signature-web/src/utils/dimensions.ts @@ -2,7 +2,7 @@ import { CSSProperties } from "react"; export type WidthUnitEnum = "pixels" | "percentage"; -export type HeightUnitEnum = "percentageOfWidth" | "pixels" | "percentageOfParent" | "percentageOfView"; +export type HeightUnitEnum = "auto" | "pixels" | "percentageOfParent" | "percentageOfView"; export type MinHeightUnitEnum = "none" | "pixels" | "percentageOfParent" | "percentageOfView"; @@ -19,7 +19,7 @@ export type DimensionsProps = { minHeight: number; maxHeightUnit: MaxHeightUnitEnum; maxHeight: number; - OverflowY: OverflowYEnum; + overflowY: OverflowYEnum; }; function getHeightScale(height: number, heightUnit: "pixels" | "percentageOfParent" | "percentageOfView"): string { @@ -27,14 +27,14 @@ function getHeightScale(height: number, heightUnit: "pixels" | "percentageOfPare } export function constructWrapperStyle(props: DimensionsProps): CSSProperties { - const { widthUnit, heightUnit, minHeightUnit, maxHeightUnit, width, height, minHeight, maxHeight, OverflowY } = + const { widthUnit, heightUnit, minHeightUnit, maxHeightUnit, width, height, minHeight, maxHeight, overflowY } = props; const wrapperStyle: Pick = {}; wrapperStyle.width = `${width}${widthUnit === "pixels" ? "px" : "%"}`; - if (heightUnit === "percentageOfWidth") { + if (heightUnit === "auto") { wrapperStyle.height = "auto"; if (minHeightUnit !== "none") { @@ -43,7 +43,7 @@ export function constructWrapperStyle(props: DimensionsProps): CSSProperties { if (maxHeightUnit !== "none") { wrapperStyle.maxHeight = getHeightScale(maxHeight, maxHeightUnit); - wrapperStyle.overflowY = OverflowY; + wrapperStyle.overflowY = overflowY; } } else { wrapperStyle.height = getHeightScale(height, heightUnit); diff --git a/packages/pluggableWidgets/signature-web/src/utils/useResizeObserver.ts b/packages/pluggableWidgets/signature-web/src/utils/useResizeObserver.ts deleted file mode 100644 index 2e2a35423e..0000000000 --- a/packages/pluggableWidgets/signature-web/src/utils/useResizeObserver.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { RefObject, useLayoutEffect, useRef } from "react"; - -type callbackFn = (target: T, entry: ResizeObserverEntry) => void; - -export function useResizeObserver(callback: callbackFn): RefObject { - const ref = useRef(null); - - useLayoutEffect(() => { - const element = ref?.current; - - if (!element) { - return; - } - - const observer = new ResizeObserver(entries => { - callback(element, entries[0]); - }); - - observer.observe(element); - return () => { - observer.disconnect(); - }; - }, [callback, ref]); - - return ref; -} diff --git a/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts b/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts index def3812a11..1aa3ed902c 100644 --- a/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts +++ b/packages/pluggableWidgets/signature-web/src/utils/useSignaturePad.ts @@ -11,14 +11,15 @@ function usePrevious(value: T): T | null { } export function useSignaturePad( - props: Pick, + props: Pick, onSignEnd?: (imageDataURL?: string) => void ): { signaturePadRef: RefObject; canvasRef: RefObject; onResize?: () => void; } { - const { readOnly, imageSource, hasSignatureAttribute, penType, penColor } = props; + const { imageSource, hasSignatureAttribute, penType, penColor } = props; + const readOnly = imageSource.readOnly; const signaturePadRef = useRef(null); const canvasRef = useRef(null); const isSignatureInitialized = useRef(false); @@ -47,6 +48,7 @@ export function useSignaturePad( } }, [hasSignatureAttribute, onSignEnd]); + // Toggle readonly condition on signature pad when imageSource.readOnly changes useEffect(() => { if (readOnly) { signaturePadRef.current?.off(); @@ -67,6 +69,7 @@ export function useSignaturePad( } }; + // Clear signature pad when hasSignature value changes from true to false useEffect(() => { if (hasSignatureAttribute?.status === "available") { if (hasSignatureAttribute?.value !== hasSignature) { @@ -77,17 +80,10 @@ export function useSignaturePad( } }, [hasSignature, hasSignatureAttribute?.status, hasSignatureAttribute?.value]); + // Initialize signature pad useEffect(() => { - console.log( - "Try Initializing signature pad", - penColor, - signaturePadOptions, - canvasRef.current, - signaturePadRef.current, - imageSource, - hasSignatureAttribute - ); if (canvasRef.current) { + // only instantiate when all data is loaded properly to avoid unnecessary re-instantiations const canInstantiateSignaturePad = signaturePadRef.current === null && (imageSource?.status === "available" ? imageSource.value?.uri : imageSource.status === "unavailable"); diff --git a/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts b/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts index 5efc8e9246..a1add0ff87 100644 --- a/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts +++ b/packages/pluggableWidgets/signature-web/typings/SignatureProps.d.ts @@ -10,7 +10,7 @@ export type PenTypeEnum = "fountain" | "ballpoint" | "marker"; export type WidthUnitEnum = "pixels" | "percentage"; -export type HeightUnitEnum = "percentageOfWidth" | "pixels" | "percentageOfParent" | "percentageOfView"; +export type HeightUnitEnum = "auto" | "pixels" | "percentageOfParent" | "percentageOfView"; export type MinHeightUnitEnum = "none" | "pixels" | "percentageOfParent" | "percentageOfView"; @@ -35,7 +35,7 @@ export interface SignatureContainerProps { minHeight: number; maxHeightUnit: MaxHeightUnitEnum; maxHeight: number; - OverflowY: OverflowYEnum; + overflowY: OverflowYEnum; onSignEndAction?: ActionValue<{ signatureImage: Option }>; showGrid: boolean; gridBorderColor: string; @@ -67,7 +67,7 @@ export interface SignaturePreviewProps { minHeight: number | null; maxHeightUnit: MaxHeightUnitEnum; maxHeight: number | null; - OverflowY: OverflowYEnum; + overflowY: OverflowYEnum; onSignEndAction: {} | null; showGrid: boolean; gridBorderColor: string; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f02112d5fa..1445dc59d4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2271,9 +2271,6 @@ importers: '@mendix/widget-plugin-test-utils': specifier: workspace:* version: link:../../shared/widget-plugin-test-utils - cross-env: - specifier: ^7.0.3 - version: 7.0.3 packages/pluggableWidgets/skiplink-web: dependencies: @@ -6844,10 +6841,6 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} @@ -15372,8 +15365,6 @@ snapshots: flatted: 3.4.2 keyv: 4.5.4 - flat@5.0.2: {} - flatted@3.4.2: {} flatten-vertex-data@1.0.2: @@ -18435,10 +18426,6 @@ snapshots: dependencies: resolve: 1.22.10 - rechoir@0.8.0: - dependencies: - resolve: 1.22.11 - recursive-copy@2.0.14: dependencies: errno: 0.1.8