From a0248c32413deb776bcbee6436f94be41f1b306a Mon Sep 17 00:00:00 2001 From: Hedwig Doets Date: Fri, 11 Jul 2025 10:25:29 +0200 Subject: [PATCH 1/3] feat: initial setup of skiplink widget --- .../pluggableWidgets/skiplink-web/README.md | 27 ++++++++ .../skiplink-web/e2e/SkipLink.spec.ts | 23 +++++++ .../skiplink-web/package.json | 50 ++++++++++++++ .../skiplink-web/src/SkipLink.css | 20 ++++++ .../skiplink-web/src/SkipLink.tsx | 66 +++++++++++++++++++ .../skiplink-web/src/SkipLink.xml | 20 ++++++ .../skiplink-web/src/package.xml | 11 ++++ .../skiplink-web/tsconfig.json | 25 +++++++ .../skiplink-web/typings/SkipLinkProps.d.ts | 30 +++++++++ pnpm-lock.yaml | 24 +++++++ 10 files changed, 296 insertions(+) create mode 100644 packages/pluggableWidgets/skiplink-web/README.md create mode 100644 packages/pluggableWidgets/skiplink-web/e2e/SkipLink.spec.ts create mode 100644 packages/pluggableWidgets/skiplink-web/package.json create mode 100644 packages/pluggableWidgets/skiplink-web/src/SkipLink.css create mode 100644 packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx create mode 100644 packages/pluggableWidgets/skiplink-web/src/SkipLink.xml create mode 100644 packages/pluggableWidgets/skiplink-web/src/package.xml create mode 100644 packages/pluggableWidgets/skiplink-web/tsconfig.json create mode 100644 packages/pluggableWidgets/skiplink-web/typings/SkipLinkProps.d.ts diff --git a/packages/pluggableWidgets/skiplink-web/README.md b/packages/pluggableWidgets/skiplink-web/README.md new file mode 100644 index 0000000000..02b3c70903 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/README.md @@ -0,0 +1,27 @@ +# SkipLink Web Widget + +A simple accessibility widget that adds a skip link to the top of the page. The link is only visible when focused and allows users to jump directly to the main content. + +## Usage + +1. Place the `` component at the very top of your page or layout. +2. Ensure your main content container has `id="main-content"`. + + ```jsx + +
Main content here
+ ``` + +## Accessibility + +- The skip link is visually hidden except when focused, making it accessible for keyboard and screen reader users. + +## End-to-End Testing + +E2E tests are located in the `e2e/` folder and use Playwright. Run them with: + +``` +npm install +npx playwright install +npm test +``` diff --git a/packages/pluggableWidgets/skiplink-web/e2e/SkipLink.spec.ts b/packages/pluggableWidgets/skiplink-web/e2e/SkipLink.spec.ts new file mode 100644 index 0000000000..80c13e8155 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/e2e/SkipLink.spec.ts @@ -0,0 +1,23 @@ +import { expect, test } from "@playwright/test"; + +// Assumes the test project renders and a
element + +test.describe("SkipLink", () => { + test("should be hidden by default and visible on focus, and should skip to main content", async ({ page }) => { + await page.goto("/"); + const skipLink = page.locator(".skip-link"); + // Should be hidden by default + await expect(skipLink).toHaveCSS("transform", "matrix(1, 0, 0, 1, 0, -120)"); + // Tab to focus the skip link + await page.keyboard.press("Tab"); + await expect(skipLink).toBeVisible(); + // Check if skipLink is the active element + const isFocused = await skipLink.evaluate(node => node === document.activeElement); + expect(isFocused).toBe(true); + // Press Enter to activate the link + await page.keyboard.press("Enter"); + // The main content should be focused or scrolled into view + const main = page.locator("#main-content"); + await expect(main).toBeVisible(); + }); +}); diff --git a/packages/pluggableWidgets/skiplink-web/package.json b/packages/pluggableWidgets/skiplink-web/package.json new file mode 100644 index 0000000000..5bc7730fc4 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/package.json @@ -0,0 +1,50 @@ +{ + "name": "@mendix/pluggable-widget-skiplink-web", + "widgetName": "SkipLink", + "version": "1.0.0", + "description": "Adds a skip link to the top of the page for accessibility.", + "copyright": "© Mendix Technology BV 2025. All rights reserved.", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/mendix/web-widgets.git" + }, + "config": {}, + "mxpackage": { + "name": "SkipLink", + "type": "widget", + "mpkName": "com.mendix.widget.web.SkipLink.mpk" + }, + "packagePath": "com.mendix.widget.web", + "marketplace": { + "minimumMXVersion": "9.6.0", + "appNumber": 119999, + "appName": "SkipLink", + "reactReady": true + }, + "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": "run-e2e ci", + "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": "jest --projects jest.config.js", + "update-changelog": "rui-update-changelog-widget", + "verify": "rui-verify-package-format" + }, + "devDependencies": { + "@mendix/automation-utils": "workspace:*", + "@mendix/eslint-config-web-widgets": "workspace:*", + "@mendix/pluggable-widgets-tools": "*", + "@mendix/prettier-config-web-widgets": "workspace:*", + "@mendix/run-e2e": "workspace:*", + "@mendix/widget-plugin-hooks": "workspace:*", + "@mendix/widget-plugin-platform": "workspace:*" + } +} diff --git a/packages/pluggableWidgets/skiplink-web/src/SkipLink.css b/packages/pluggableWidgets/skiplink-web/src/SkipLink.css new file mode 100644 index 0000000000..5a613ceb39 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/src/SkipLink.css @@ -0,0 +1,20 @@ +.skip-link { + position: absolute; + top: 0; + left: 0; + background: #fff; + color: #0078d4; + padding: 8px 16px; + z-index: 1000; + transform: translateY(-120%); + transition: transform 0.2s; + text-decoration: none; + border: 2px solid #0078d4; + border-radius: 4px; + font-weight: bold; +} + +.skip-link:focus { + transform: translateY(0); + outline: none; +} diff --git a/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx b/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx new file mode 100644 index 0000000000..ff5569ad64 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx @@ -0,0 +1,66 @@ +import "./SkipLink.css"; +import { useEffect } from "react"; + +export interface SkipLinkProps { + /** + * The text displayed for the skip link. + */ + linkText: string; + /** + * The id of the main content element to jump to. + */ + mainContentId: string; +} + +/** + * Inserts a skip link as the first child of the element with ID 'root'. + * When activated, focus is programmatically set to the main content. + */ +export function SkipLink({ linkText, mainContentId }: SkipLinkProps): null { + useEffect(() => { + // Create the skip link element + const link = document.createElement("a"); + link.href = `#${mainContentId}`; + link.className = "skip-link"; + link.textContent = linkText; + link.tabIndex = 0; + + // Handler to move focus to the main content + function handleClick(event: MouseEvent) { + event.preventDefault(); + const main = document.getElementById(mainContentId); + if (main) { + // Store previous tabindex + const prevTabIndex = main.getAttribute("tabindex"); + // Ensure main is focusable + if (!main.hasAttribute("tabindex")) { + main.setAttribute("tabindex", "-1"); + } + main.focus(); + // Clean up tabindex if it was not present before + if (prevTabIndex === null) { + main.addEventListener("blur", () => main.removeAttribute("tabindex"), { once: true }); + } + } + } + + link.addEventListener("click", handleClick); + + // Insert as the first child of the element with ID 'root' + const root = document.getElementById("root"); + if (root) { + root.insertBefore(link, root.firstChild); + } + + // Cleanup on unmount + return () => { + link.removeEventListener("click", handleClick); + if (link.parentNode) { + link.parentNode.removeChild(link); + } + }; + }, [linkText, mainContentId]); + + // This component does not render anything in the React tree + return null; +} diff --git a/packages/pluggableWidgets/skiplink-web/src/SkipLink.xml b/packages/pluggableWidgets/skiplink-web/src/SkipLink.xml new file mode 100644 index 0000000000..9769fe7d01 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/src/SkipLink.xml @@ -0,0 +1,20 @@ + + + SkipLink + A skip link for accessibility, allowing users to jump directly to the main content. + Accessibility + Accessibility + https://docs.mendix.com/appstore/widgets/skiplink + + + + Link text + The text displayed for the skip link. + + + Main content ID + The id of the main content element to jump to. + + + + diff --git a/packages/pluggableWidgets/skiplink-web/src/package.xml b/packages/pluggableWidgets/skiplink-web/src/package.xml new file mode 100644 index 0000000000..811a87e4ab --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/src/package.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/pluggableWidgets/skiplink-web/tsconfig.json b/packages/pluggableWidgets/skiplink-web/tsconfig.json new file mode 100644 index 0000000000..743a60a240 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/tsconfig.json @@ -0,0 +1,25 @@ +{ + "include": ["./src", "./typings"], + "compilerOptions": { + "baseUrl": "./", + "noEmitOnError": true, + "sourceMap": true, + "module": "esnext", + "target": "es6", + "lib": ["esnext", "dom"], + "types": ["jest", "node"], + "moduleResolution": "node", + "declaration": false, + "noLib": false, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "strict": true, + "strictFunctionTypes": false, + "skipLibCheck": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "jsx": "react-jsx", + "outDir": "dist", + "rootDir": "src" + } +} diff --git a/packages/pluggableWidgets/skiplink-web/typings/SkipLinkProps.d.ts b/packages/pluggableWidgets/skiplink-web/typings/SkipLinkProps.d.ts new file mode 100644 index 0000000000..dd4d4c8a82 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/typings/SkipLinkProps.d.ts @@ -0,0 +1,30 @@ +/** + * This file was generated from SkipLink.xml + * WARNING: All changes made to this file will be overwritten + * @author Mendix Widgets Framework Team + */ +import { CSSProperties } from "react"; + +export interface SkipLinkContainerProps { + name: string; + class: string; + style?: CSSProperties; + tabIndex?: number; + linkText: string; + mainContentId: string; +} + +export interface SkipLinkPreviewProps { + /** + * @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; + linkText: string; + mainContentId: string; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 40d480cc17..7849c62107 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2138,6 +2138,30 @@ importers: specifier: ^7.0.3 version: 7.0.3 + packages/pluggableWidgets/skiplink-web: + 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: 10.21.0 + version: 10.21.0(@jest/transform@29.7.0)(@jest/types@29.6.3)(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/babel__core@7.20.3)(@types/node@22.14.0)(picomatch@4.0.2)(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(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-hooks': + specifier: workspace:* + version: link:../../shared/widget-plugin-hooks + '@mendix/widget-plugin-platform': + specifier: workspace:* + version: link:../../shared/widget-plugin-platform + packages/pluggableWidgets/slider-web: dependencies: '@mendix/widget-plugin-component-kit': From 6bec63da8dad2f8eedad1c35277820dfe0a0fff5 Mon Sep 17 00:00:00 2001 From: Hedwig Doets Date: Fri, 11 Jul 2025 13:43:01 +0200 Subject: [PATCH 2/3] feat(skiplink-web): adding configuration --- .../pluggableWidgets/skiplink-web/.gitignore | 14 ++++ .../skiplink-web/.prettierrc.js | 1 + .../skiplink-web/e2e/package.json | 0 .../skiplink-web/eslint.config.mjs | 3 + .../skiplink-web/jest.config.js | 3 + .../skiplink-web/package.json | 4 +- .../skiplink-web/playwright.config.cjs | 1 + .../skiplink-web/src/SkipLink.editorConfig.ts | 80 +++++++++++++++++++ .../src/SkipLink.editorPreview.tsx | 35 ++++++++ .../skiplink-web/src/SkipLink.tsx | 2 +- .../skiplink-web/src/{ => ui}/SkipLink.css | 0 .../skiplink-web/tsconfig.json | 12 ++- 12 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 packages/pluggableWidgets/skiplink-web/.gitignore create mode 100644 packages/pluggableWidgets/skiplink-web/.prettierrc.js create mode 100644 packages/pluggableWidgets/skiplink-web/e2e/package.json create mode 100644 packages/pluggableWidgets/skiplink-web/eslint.config.mjs create mode 100644 packages/pluggableWidgets/skiplink-web/jest.config.js create mode 100644 packages/pluggableWidgets/skiplink-web/playwright.config.cjs create mode 100644 packages/pluggableWidgets/skiplink-web/src/SkipLink.editorConfig.ts create mode 100644 packages/pluggableWidgets/skiplink-web/src/SkipLink.editorPreview.tsx rename packages/pluggableWidgets/skiplink-web/src/{ => ui}/SkipLink.css (100%) diff --git a/packages/pluggableWidgets/skiplink-web/.gitignore b/packages/pluggableWidgets/skiplink-web/.gitignore new file mode 100644 index 0000000000..a1bd0102fd --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/.gitignore @@ -0,0 +1,14 @@ +/tests/TestProjects/**/.classpath +/tests/TestProjects/**/.project +/tests/TestProjects/**/javascriptsource +/tests/TestProjects/**/javasource +/tests/TestProjects/**/resources +/tests/TestProjects/**/userlib + +/tests/TestProjects/Mendix8/theme/styles/native +/tests/TestProjects/Mendix8/theme/styles/web/sass +/tests/TestProjects/Mendix8/theme/*.* +!/tests/TestProjects/Mendix8/theme/components.json +!/tests/TestProjects/Mendix8/theme/favicon.ico +!/tests/TestProjects/Mendix8/theme/LICENSE +!/tests/TestProjects/Mendix8/theme/settings.json diff --git a/packages/pluggableWidgets/skiplink-web/.prettierrc.js b/packages/pluggableWidgets/skiplink-web/.prettierrc.js new file mode 100644 index 0000000000..0892704ab0 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/.prettierrc.js @@ -0,0 +1 @@ +module.exports = require("@mendix/prettier-config-web-widgets"); diff --git a/packages/pluggableWidgets/skiplink-web/e2e/package.json b/packages/pluggableWidgets/skiplink-web/e2e/package.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/pluggableWidgets/skiplink-web/eslint.config.mjs b/packages/pluggableWidgets/skiplink-web/eslint.config.mjs new file mode 100644 index 0000000000..ed68ae9e78 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/eslint.config.mjs @@ -0,0 +1,3 @@ +import config from "@mendix/eslint-config-web-widgets/widget-ts.mjs"; + +export default config; diff --git a/packages/pluggableWidgets/skiplink-web/jest.config.js b/packages/pluggableWidgets/skiplink-web/jest.config.js new file mode 100644 index 0000000000..88999d5568 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + ...require("@mendix/pluggable-widgets-tools/test-config/jest.enzyme-free.config.js") +}; diff --git a/packages/pluggableWidgets/skiplink-web/package.json b/packages/pluggableWidgets/skiplink-web/package.json index 5bc7730fc4..1215278b7a 100644 --- a/packages/pluggableWidgets/skiplink-web/package.json +++ b/packages/pluggableWidgets/skiplink-web/package.json @@ -17,7 +17,7 @@ }, "packagePath": "com.mendix.widget.web", "marketplace": { - "minimumMXVersion": "9.6.0", + "minimumMXVersion": "11.1.0", "appNumber": 119999, "appName": "SkipLink", "reactReady": true @@ -30,7 +30,7 @@ "e2e": "run-e2e ci", "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", + "lint": "eslint src package.json", "publish-marketplace": "rui-publish-marketplace", "release": "pluggable-widgets-tools release:web", "start": "pluggable-widgets-tools start:server", diff --git a/packages/pluggableWidgets/skiplink-web/playwright.config.cjs b/packages/pluggableWidgets/skiplink-web/playwright.config.cjs new file mode 100644 index 0000000000..29045fc372 --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/playwright.config.cjs @@ -0,0 +1 @@ +module.exports = require("@mendix/run-e2e/playwright.config.cjs"); diff --git a/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorConfig.ts b/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorConfig.ts new file mode 100644 index 0000000000..b4e9f6536a --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorConfig.ts @@ -0,0 +1,80 @@ +import { hidePropertiesIn, Problem, Properties } from "@mendix/pluggable-widgets-tools"; +import { + StructurePreviewProps, + RowLayoutProps, + ContainerProps, + TextProps, + structurePreviewPalette +} from "@mendix/widget-plugin-platform/preview/structure-preview-api"; + +export function getProperties(values: any, defaultValues: Properties): Properties { + // No conditional properties for skiplink, but function provided for consistency + return defaultValues; +} + +export function check(values: any): Problem[] { + const errors: Problem[] = []; + if (!values.linkText) { + errors.push({ + property: "linkText", + message: "Link text is required" + }); + } + if (!values.mainContentId) { + errors.push({ + property: "mainContentId", + message: "Main content ID is required" + }); + } + return errors; +} + +export function getPreview(values: any, isDarkMode: boolean): StructurePreviewProps | null { + const palette = structurePreviewPalette[isDarkMode ? "dark" : "light"]; + const titleHeader: RowLayoutProps = { + type: "RowLayout", + columnSize: "grow", + backgroundColor: palette.background.topbarStandard, + borders: true, + borderWidth: 1, + children: [ + { + type: "Container", + padding: 4, + children: [ + { + type: "Text", + content: "SkipLink", + fontColor: palette.text.secondary + } as TextProps + ] + } + ] + }; + const linkContent: RowLayoutProps = { + type: "RowLayout", + columnSize: "grow", + borders: true, + padding: 0, + children: [ + { + type: "Container", + padding: 6, + children: [ + { + type: "Text", + content: values.linkText || "Skip to main content", + fontSize: 14, + fontColor: palette.text.primary, + bold: true + } as TextProps + ] + } + ] + }; + return { + type: "Container", + borders: true, + children: [titleHeader, linkContent] + } as ContainerProps; +} diff --git a/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorPreview.tsx b/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorPreview.tsx new file mode 100644 index 0000000000..c0278a11fe --- /dev/null +++ b/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorPreview.tsx @@ -0,0 +1,35 @@ +import { createElement, ReactElement } from "react"; + +export interface SkipLinkPreviewProps { + linkText: string; + mainContentId: string; +} + +export const preview = (props: SkipLinkPreviewProps): ReactElement => { + return ( + + ); +}; + +export function getPreviewCss(): string { + return require("./SkipLink.css"); +} diff --git a/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx b/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx index ff5569ad64..acee6f0363 100644 --- a/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx +++ b/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx @@ -1,4 +1,4 @@ -import "./SkipLink.css"; +import "./ui/SkipLink.css"; import { useEffect } from "react"; export interface SkipLinkProps { diff --git a/packages/pluggableWidgets/skiplink-web/src/SkipLink.css b/packages/pluggableWidgets/skiplink-web/src/ui/SkipLink.css similarity index 100% rename from packages/pluggableWidgets/skiplink-web/src/SkipLink.css rename to packages/pluggableWidgets/skiplink-web/src/ui/SkipLink.css diff --git a/packages/pluggableWidgets/skiplink-web/tsconfig.json b/packages/pluggableWidgets/skiplink-web/tsconfig.json index 743a60a240..a2a5b87e60 100644 --- a/packages/pluggableWidgets/skiplink-web/tsconfig.json +++ b/packages/pluggableWidgets/skiplink-web/tsconfig.json @@ -18,8 +18,14 @@ "skipLibCheck": true, "noUnusedLocals": true, "noUnusedParameters": true, - "jsx": "react-jsx", - "outDir": "dist", - "rootDir": "src" + "jsx": "react", + "jsxFactory": "createElement", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "useUnknownInCatchVariables": false, + "exactOptionalPropertyTypes": false, + "paths": { + "react-hot-loader/root": ["./hot-typescript.ts"] + } } } From e314e29b08cd89ef02932059301e558e3acf9cce Mon Sep 17 00:00:00 2001 From: Hedwig Doets Date: Tue, 15 Jul 2025 14:09:08 +0200 Subject: [PATCH 3/3] chore: improve config files, ran linting --- .../skiplink-web/package.json | 9 ++- .../skiplink-web/src/SkipLink.editorConfig.ts | 4 +- .../src/SkipLink.editorPreview.tsx | 55 +++++++++---------- .../skiplink-web/src/SkipLink.tsx | 2 +- .../src/ui/{SkipLink.css => SkipLink.scss} | 0 pnpm-lock.yaml | 16 +++++- 6 files changed, 50 insertions(+), 36 deletions(-) rename packages/pluggableWidgets/skiplink-web/src/ui/{SkipLink.css => SkipLink.scss} (100%) diff --git a/packages/pluggableWidgets/skiplink-web/package.json b/packages/pluggableWidgets/skiplink-web/package.json index 1215278b7a..dd660ba034 100644 --- a/packages/pluggableWidgets/skiplink-web/package.json +++ b/packages/pluggableWidgets/skiplink-web/package.json @@ -1,5 +1,5 @@ { - "name": "@mendix/pluggable-widget-skiplink-web", + "name": "@mendix/skiplink-web", "widgetName": "SkipLink", "version": "1.0.0", "description": "Adds a skip link to the top of the page for accessibility.", @@ -30,7 +30,7 @@ "e2e": "run-e2e ci", "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", + "lint": "eslint src/ package.json", "publish-marketplace": "rui-publish-marketplace", "release": "pluggable-widgets-tools release:web", "start": "pluggable-widgets-tools start:server", @@ -38,6 +38,11 @@ "update-changelog": "rui-update-changelog-widget", "verify": "rui-verify-package-format" }, + "dependencies": { + "@floating-ui/react": "^0.26.27", + "@mendix/widget-plugin-component-kit": "workspace:*", + "classnames": "^2.5.1" + }, "devDependencies": { "@mendix/automation-utils": "workspace:*", "@mendix/eslint-config-web-widgets": "workspace:*", diff --git a/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorConfig.ts b/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorConfig.ts index b4e9f6536a..6fa0fe3dbb 100644 --- a/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorConfig.ts +++ b/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorConfig.ts @@ -1,4 +1,4 @@ -import { hidePropertiesIn, Problem, Properties } from "@mendix/pluggable-widgets-tools"; +import { Problem, Properties } from "@mendix/pluggable-widgets-tools"; import { StructurePreviewProps, RowLayoutProps, @@ -7,7 +7,7 @@ import { structurePreviewPalette } from "@mendix/widget-plugin-platform/preview/structure-preview-api"; -export function getProperties(values: any, defaultValues: Properties): Properties { +export function getProperties(defaultValues: Properties): Properties { // No conditional properties for skiplink, but function provided for consistency return defaultValues; } diff --git a/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorPreview.tsx b/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorPreview.tsx index c0278a11fe..543e043658 100644 --- a/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorPreview.tsx +++ b/packages/pluggableWidgets/skiplink-web/src/SkipLink.editorPreview.tsx @@ -1,35 +1,34 @@ import { createElement, ReactElement } from "react"; - -export interface SkipLinkPreviewProps { - linkText: string; - mainContentId: string; -} +import { SkipLinkPreviewProps } from "../typings/SkipLinkProps"; export const preview = (props: SkipLinkPreviewProps): ReactElement => { - return ( - - ); + if (props.renderMode === "xray") { + return ( + + ); + } + return
; }; export function getPreviewCss(): string { - return require("./SkipLink.css"); + return require("./ui/SkipLink.scss"); } diff --git a/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx b/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx index acee6f0363..2c748c0263 100644 --- a/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx +++ b/packages/pluggableWidgets/skiplink-web/src/SkipLink.tsx @@ -1,4 +1,4 @@ -import "./ui/SkipLink.css"; +import "./ui/SkipLink.scss"; import { useEffect } from "react"; export interface SkipLinkProps { diff --git a/packages/pluggableWidgets/skiplink-web/src/ui/SkipLink.css b/packages/pluggableWidgets/skiplink-web/src/ui/SkipLink.scss similarity index 100% rename from packages/pluggableWidgets/skiplink-web/src/ui/SkipLink.css rename to packages/pluggableWidgets/skiplink-web/src/ui/SkipLink.scss diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7849c62107..4f024987f7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2139,6 +2139,16 @@ importers: version: 7.0.3 packages/pluggableWidgets/skiplink-web: + dependencies: + '@floating-ui/react': + specifier: ^0.26.27 + version: 0.26.27(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@mendix/widget-plugin-component-kit': + specifier: workspace:* + version: link:../../shared/widget-plugin-component-kit + classnames: + specifier: ^2.5.1 + version: 2.5.1 devDependencies: '@mendix/automation-utils': specifier: workspace:* @@ -2147,8 +2157,8 @@ importers: specifier: workspace:* version: link:../../shared/eslint-config-web-widgets '@mendix/pluggable-widgets-tools': - specifier: 10.21.0 - version: 10.21.0(@jest/transform@29.7.0)(@jest/types@29.6.3)(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/babel__core@7.20.3)(@types/node@22.14.0)(picomatch@4.0.2)(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@18.2.36)(react@18.2.0)(typescript@5.8.2))(react@18.2.0)(tslib@2.8.1) + specifier: 10.21.2 + version: 10.21.2(@jest/transform@29.7.0)(@jest/types@29.6.3)(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/babel__core@7.20.3)(@types/node@22.14.1)(picomatch@4.0.2)(react-dom@18.2.0(react@18.2.0))(react-native@0.75.3(@babel/core@7.27.4)(@babel/preset-env@7.26.9(@babel/core@7.27.4))(@types/react@18.2.36)(react@18.2.0))(react@18.2.0)(tslib@2.8.1) '@mendix/prettier-config-web-widgets': specifier: workspace:* version: link:../../shared/prettier-config-web-widgets @@ -17626,7 +17636,7 @@ snapshots: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0