diff --git a/.github/configs/labeler.yml b/.github/configs/labeler.yml index 2727e9efb7..fa92c9944e 100644 --- a/.github/configs/labeler.yml +++ b/.github/configs/labeler.yml @@ -46,8 +46,6 @@ html-element-web: - packages/*/html-element-web/**/* image-web: - packages/*/image-web/**/* -language-selector-web: - - packages/*/language-selector-web/**/* maps-web: - packages/*/maps-web/**/* popup-menu-web: diff --git a/packages/pluggableWidgets/language-selector-web/.prettierrc.js b/packages/pluggableWidgets/language-selector-web/.prettierrc.js deleted file mode 100644 index 0892704ab0..0000000000 --- a/packages/pluggableWidgets/language-selector-web/.prettierrc.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@mendix/prettier-config-web-widgets"); diff --git a/packages/pluggableWidgets/language-selector-web/CHANGELOG.md b/packages/pluggableWidgets/language-selector-web/CHANGELOG.md deleted file mode 100644 index e7b7f315a8..0000000000 --- a/packages/pluggableWidgets/language-selector-web/CHANGELOG.md +++ /dev/null @@ -1,51 +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.1.4] - 2026-02-12 - -### Added - -- We added a license file and a readme documenting all open source dependencies used in this package. - -## [1.1.3] - 2024-11-28 - -### Fixed - -- We fixed an issue where the language selector dropdown would not show properly when inside an accordion. - -## [1.1.2] - 2024-09-20 - -### Changed - -- Improved a11y with keyboard navigation - -## [1.1.1] - 2023-09-27 - -### Fixed - -- We removed redundant code to improve widget load time in the browser. - -## [1.1.0] - 2023-06-05 - -### Changed - -- We updated the light and dark icons and tiles for the widget. - -- We changed colors in the structure mode preview for dark and light modes. - -## [1.0.1] - 2022-10-28 - -### Fixed - -- We changed the way how arrow is rendered. - -## [1.0.0] - 2022-09-26 - -### Added - -- We introduced Language Selector widget! diff --git a/packages/pluggableWidgets/language-selector-web/README.md b/packages/pluggableWidgets/language-selector-web/README.md deleted file mode 100644 index a1ace6345d..0000000000 --- a/packages/pluggableWidgets/language-selector-web/README.md +++ /dev/null @@ -1 +0,0 @@ -Please see [Language selector](https://docs.mendix.com/appstore/widgets/language-selector) in the Mendix documentation for details. diff --git a/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js b/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js deleted file mode 100644 index 1cb8295bbc..0000000000 --- a/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js +++ /dev/null @@ -1,49 +0,0 @@ -import { test, expect } from "@mendix/run-e2e/fixtures"; -import { waitForMendixApp } from "@mendix/run-e2e/mendix-helpers"; -import AxeBuilder from "@axe-core/playwright"; - -test.describe("language-selector-web", () => { - test.beforeEach(async ({ page }) => { - await page.goto("/"); - await waitForMendixApp(page); - }); - - test("checks if all elements are rendered as expected", async ({ page }) => { - const languageSelectorElement = await page.locator(".mx-name-languageSelector1"); - await expect(languageSelectorElement).toBeVisible(); - await expect(page).toHaveScreenshot(`languageSelector.png`); - }); - - test("checks if Arabic language is rendered as expected", async ({ page }) => { - await page.click(".current-language-text", { force: true }); - await page.click("text=Arabic"); - await expect(page).toHaveScreenshot(`languageSelectorArabic.png`); - }); - - test("checks if Chinese language is rendered as expected", async ({ page }) => { - await page.click(".current-language-text", { force: true }); - await page.click("text=Chinese"); - await expect(page.getByText("欢迎")).toBeVisible(); - await expect(page.getByText("欢迎")).toContainText("欢迎"); - }); - - test("checks accessibility violations", async ({ page }) => { - await page.goto("/"); - await waitForMendixApp(page); - const accessibilityScanResults = await new AxeBuilder({ page }) - .withTags(["wcag21aa"]) - .disableRules([ - "aria-required-children", - "label", - "aria-roles", - "button-name", - "duplicate-id-active", - "duplicate-id", - "aria-allowed-attr" - ]) - .exclude(".mx-name-navigationTree3") - .analyze(); - - expect(accessibilityScanResults.violations).toEqual([]); - }); -}); diff --git a/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js-snapshots/languageSelector-chromium-linux.png b/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js-snapshots/languageSelector-chromium-linux.png deleted file mode 100644 index 17415f0413..0000000000 Binary files a/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js-snapshots/languageSelector-chromium-linux.png and /dev/null differ diff --git a/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js-snapshots/languageSelectorArabic-chromium-linux.png b/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js-snapshots/languageSelectorArabic-chromium-linux.png deleted file mode 100644 index 6b120b4263..0000000000 Binary files a/packages/pluggableWidgets/language-selector-web/e2e/LanguageSelector.spec.js-snapshots/languageSelectorArabic-chromium-linux.png and /dev/null differ diff --git a/packages/pluggableWidgets/language-selector-web/eslint.config.mjs b/packages/pluggableWidgets/language-selector-web/eslint.config.mjs deleted file mode 100644 index ed68ae9e78..0000000000 --- a/packages/pluggableWidgets/language-selector-web/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import config from "@mendix/eslint-config-web-widgets/widget-ts.mjs"; - -export default config; diff --git a/packages/pluggableWidgets/language-selector-web/package.json b/packages/pluggableWidgets/language-selector-web/package.json deleted file mode 100644 index eb12c06c9d..0000000000 --- a/packages/pluggableWidgets/language-selector-web/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "name": "@mendix/language-selector-web", - "widgetName": "LanguageSelector", - "version": "1.1.4", - "description": "Display a list of available languages", - "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": "LanguageSelector", - "type": "widget", - "mpkName": "com.mendix.widget.web.LanguageSelector.mpk" - }, - "packagePath": "com.mendix.widget.web", - "marketplace": { - "minimumMXVersion": "9.12.6", - "appName": "Language Selector", - "appNumber": 202738 - }, - "testProject": { - "githubUrl": "https://github.com/mendix/testProjects", - "branchName": "language-selector-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": "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": "pluggable-widgets-tools test:unit:web", - "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:*", - "@mendix/pluggable-widgets-tools": "*", - "@mendix/prettier-config-web-widgets": "workspace:*", - "@mendix/run-e2e": "workspace:*", - "@mendix/widget-plugin-platform": "workspace:*" - } -} diff --git a/packages/pluggableWidgets/language-selector-web/playwright.config.cjs b/packages/pluggableWidgets/language-selector-web/playwright.config.cjs deleted file mode 100644 index 29045fc372..0000000000 --- a/packages/pluggableWidgets/language-selector-web/playwright.config.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@mendix/run-e2e/playwright.config.cjs"); diff --git a/packages/pluggableWidgets/language-selector-web/rollup.config.mjs b/packages/pluggableWidgets/language-selector-web/rollup.config.mjs deleted file mode 100644 index 688a1a7197..0000000000 --- a/packages/pluggableWidgets/language-selector-web/rollup.config.mjs +++ /dev/null @@ -1,5 +0,0 @@ -import copyFiles from "@mendix/rollup-web-widgets/copyFiles.mjs"; - -export default args => { - return copyFiles(args); -}; diff --git a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.editorConfig.ts b/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.editorConfig.ts deleted file mode 100644 index 27dafe12c1..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.editorConfig.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - structurePreviewPalette, - StructurePreviewProps -} from "@mendix/widget-plugin-platform/preview/structure-preview-api"; -import { Properties } from "@mendix/pluggable-widgets-tools"; -import { LanguageSelectorPreviewProps } from "typings/LanguageSelectorProps"; -import ArrowDark from "./assets/arrow_dark.svg"; -import ArrowLight from "./assets/arrow_light.svg"; - -export function getProperties(__values: LanguageSelectorPreviewProps, defaultValues: Properties): Properties { - return defaultValues; -} - -export function getPreview(__values: LanguageSelectorPreviewProps, isDarkMode: boolean): StructurePreviewProps | null { - const palette = structurePreviewPalette[isDarkMode ? "dark" : "light"]; - return { - type: "RowLayout", - columnSize: "grow", // dynamic column sizes - children: [ - { - type: "Text", - content: "Selected language", - fontColor: palette.text.primary - }, - { type: "Container", grow: 0.001 }, // small space between items - { - type: "Container", - padding: 4, - children: [ - { - type: "Image", - document: decodeURIComponent( - (isDarkMode ? ArrowLight : ArrowDark).replace("data:image/svg+xml,", "") - ), - height: 14 - } - ] - }, - - { type: "Container" } // fills space on right - ] - }; -} diff --git a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.editorPreview.tsx b/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.editorPreview.tsx deleted file mode 100644 index 6eed05ff72..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.editorPreview.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { ReactElement } from "react"; -import { LanguageSelectorPreviewProps } from "typings/LanguageSelectorProps"; -import { LanguageSwitcherPreview } from "./components/LanguageSwitcherPreview"; - -export const preview = (props: LanguageSelectorPreviewProps): ReactElement => { - return ( - - ); -}; - -export function getPreviewCss(): string { - return require("./ui/LanguageSelector.scss"); -} diff --git a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.icon.dark.png b/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.icon.dark.png deleted file mode 100755 index 32c5611d2d..0000000000 Binary files a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.icon.dark.png and /dev/null differ diff --git a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.icon.png b/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.icon.png deleted file mode 100755 index bc49529c1b..0000000000 Binary files a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.icon.png and /dev/null differ diff --git a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.tile.dark.png b/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.tile.dark.png deleted file mode 100755 index a8ff4e415b..0000000000 Binary files a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.tile.dark.png and /dev/null differ diff --git a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.tile.png b/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.tile.png deleted file mode 100755 index 00d5857c66..0000000000 Binary files a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.tile.png and /dev/null differ diff --git a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.tsx b/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.tsx deleted file mode 100644 index 9e146ccb67..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { ReactNode, useCallback, useEffect, useState } from "react"; -import { LanguageSelectorContainerProps } from "typings/LanguageSelectorProps"; -import { LanguageSwitcher } from "./components/LanguageSwitcher"; -import "./ui/LanguageSelector.scss"; - -export type LanguageItem = { - _guid: string; - value: string; -}; - -export default function LanguageSelector(props: LanguageSelectorContainerProps): ReactNode { - const [selectedLanguage, setSelectedLanguage] = useState(); - const [languageList, setLanguageList] = useState([]); - const [hideWidget, setHideWidget] = useState(false); - - useEffect(() => { - if (props.languageOptions.items && props.languageCaption) { - const languages = props.languageOptions.items.map(item => ({ - _guid: item.id, - value: props.languageCaption.get(item).value as string - })); - setLanguageList(languages); - if (languages.length < 2 && props.hideForSingle) { - setHideWidget(true); - } - } - }, [props]); - - useEffect(() => { - const currentUser = window.mx.session.getUserObject(); - const currentLanguageId = currentUser.jsonData.attributes["System.User_Language"].value; - const currentLanguage = languageList.find(language => language._guid === currentLanguageId); - setSelectedLanguage(currentLanguage); - }, [languageList]); - - const selectLanguage = useCallback((item: LanguageItem) => { - const currentUser = window.mx.session.getUserObject(); - currentUser.addReference("System.User_Language", item._guid); - window.mx.data.commit({ - mxobj: currentUser, - callback() { - setSelectedLanguage(item); - window.mx.reloadWithState(); - } - }); - }, []); - - return hideWidget ? null : ( - - ); -} diff --git a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.xml b/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.xml deleted file mode 100644 index 1f631612d8..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/LanguageSelector.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - Language selector - - Display - Display - https://docs.mendix.com/appstore/widgets/languageSelector - - - - - Data source - Recommended: Database data source with System.Language as entity. - - - Language caption - Recommended: $currentObject/Description. - - - - - - Menu position - The location of the menu relative to the current selected language (click area). - - Left - Right - Top - Bottom - - - - - Open menu on - - - Click - Hover - - - - Hide for single language - - - - - - - - Label caption - Assistive technology will read this upon reaching the input element. - - - - - diff --git a/packages/pluggableWidgets/language-selector-web/src/assets/arrow_black.svg b/packages/pluggableWidgets/language-selector-web/src/assets/arrow_black.svg deleted file mode 100644 index 212f1bd72a..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/assets/arrow_black.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/pluggableWidgets/language-selector-web/src/assets/arrow_dark.svg b/packages/pluggableWidgets/language-selector-web/src/assets/arrow_dark.svg deleted file mode 100644 index 5d95758fd3..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/assets/arrow_dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/pluggableWidgets/language-selector-web/src/assets/arrow_light.svg b/packages/pluggableWidgets/language-selector-web/src/assets/arrow_light.svg deleted file mode 100644 index 3f2d73b3a3..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/assets/arrow_light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/pluggableWidgets/language-selector-web/src/components/LanguageSwitcher.tsx b/packages/pluggableWidgets/language-selector-web/src/components/LanguageSwitcher.tsx deleted file mode 100644 index 0832e81e85..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/components/LanguageSwitcher.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { FloatingFocusManager } from "@floating-ui/react"; -import classNames from "classnames"; -import { CSSProperties, ReactElement, useState } from "react"; -import { PositionEnum, TriggerEnum } from "../../typings/LanguageSelectorProps"; -import { useFloatingUI } from "../hooks/useFloatingUI"; -import { LanguageItem } from "../LanguageSelector"; - -export interface LanguageSwitcherProps { - className: string; - currentLanguage: LanguageItem | undefined; - languageList: LanguageItem[]; - onSelect?: (lang: LanguageItem) => void; - position: PositionEnum; - screenReaderLabelCaption?: string; - style?: CSSProperties; - tabIndex: number; - trigger: TriggerEnum; -} - -export const LanguageSwitcher = ({ - className, - currentLanguage, - languageList, - onSelect, - position, - screenReaderLabelCaption, - style, - tabIndex, - trigger -}: LanguageSwitcherProps): ReactElement => { - const [isOpen, setOpen] = useState(false); - - const { - activeIndex, - context, - floatingStyles, - getFloatingProps, - getItemProps, - getReferenceProps, - handleSelect, - isTypingRef, - listRef, - refs - } = useFloatingUI({ - currentLanguage, - isOpen, - languageList, - onSelect, - position, - setOpen, - triggerOn: trigger - }); - - return ( -
-
- {currentLanguage?.value || ""} -
- ); -}; diff --git a/packages/pluggableWidgets/language-selector-web/src/components/LanguageSwitcherPreview.tsx b/packages/pluggableWidgets/language-selector-web/src/components/LanguageSwitcherPreview.tsx deleted file mode 100644 index 58579d717d..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/components/LanguageSwitcherPreview.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import classNames from "classnames"; -import { CSSProperties, ReactElement } from "react"; - -import { PositionEnum, TriggerEnum } from "../../typings/LanguageSelectorProps"; -import { LanguageItem } from "../LanguageSelector"; - -export interface LanguageSwitcherProps { - preview: boolean; - currentLanguage: LanguageItem | undefined; - languageList: LanguageItem[]; - position: PositionEnum; - onSelect?: (lang: LanguageItem) => void; - trigger: TriggerEnum; - className: string; - style?: CSSProperties; - tabIndex: number; - screenReaderLabelCaption?: string; -} -export const LanguageSwitcherPreview = (props: LanguageSwitcherProps): ReactElement => { - return ( -
-
- {props.currentLanguage?.value || ""} -
- ); -}; diff --git a/packages/pluggableWidgets/language-selector-web/src/components/__tests__/LanguageSwitcher.spec.tsx b/packages/pluggableWidgets/language-selector-web/src/components/__tests__/LanguageSwitcher.spec.tsx deleted file mode 100644 index 78574bc3c1..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/components/__tests__/LanguageSwitcher.spec.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import { PositionEnum, TriggerEnum } from "typings/LanguageSelectorProps"; -import { LanguageSwitcher, LanguageSwitcherProps } from "../LanguageSwitcher"; -import "@testing-library/jest-dom"; - -jest.useFakeTimers(); - -let props: LanguageSwitcherProps = { - currentLanguage: undefined, - languageList: [], - position: "left" as PositionEnum, - onSelect: jest.fn(), - trigger: "click" as TriggerEnum, - className: "", - tabIndex: 0 -}; -const language = { _guid: "111", value: "En us" }; - -describe("Language switcher", () => { - it("renders the structure with empty language list", async () => { - const { asFragment } = render(); - const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); - const triggerElement = screen.getByRole("combobox"); - - await user.click(triggerElement); - expect(asFragment()).toMatchSnapshot(); - }); - - it("renders the structure with language list and selected default language", async () => { - props = { ...props, languageList: [language], currentLanguage: language }; - const { asFragment } = render(); - const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime }); - const triggerElement = screen.getByRole("combobox"); - - await user.click(triggerElement); - expect(asFragment()).toMatchSnapshot(); - }); -}); diff --git a/packages/pluggableWidgets/language-selector-web/src/components/__tests__/__snapshots__/LanguageSwitcher.spec.tsx.snap b/packages/pluggableWidgets/language-selector-web/src/components/__tests__/__snapshots__/LanguageSwitcher.spec.tsx.snap deleted file mode 100644 index e4c01d97c6..0000000000 --- a/packages/pluggableWidgets/language-selector-web/src/components/__tests__/__snapshots__/LanguageSwitcher.spec.tsx.snap +++ /dev/null @@ -1,97 +0,0 @@ -// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing - -exports[`Language switcher renders the structure with empty language list 1`] = ` - -
-
- -