diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 6056f16dd..a0d46bebf 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -31,7 +31,8 @@ jobs:
cache: 'npm'
- run: npm install
- run: npm run lint
- - run: sudo npx playwright install-deps
+ - name: Install Playwright dependencies
+ run: npx playwright install --with-deps
- run: npm run test
build:
diff --git a/package-lock.json b/package-lock.json
index fee808d0e..3ddfb15b4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -34,7 +34,7 @@
"@storybook/web-components": "^7.6.14",
"@storybook/web-components-vite": "^7.6.14",
"@types/chai": "4.3.12",
- "@types/eslint__js": "^8.42.3",
+ "@types/eslint__js": "8.42.3",
"@web/dev-server-esbuild": "0.4.3",
"@web/test-runner": "0.18.2",
"@web/test-runner-playwright": "0.11.0",
@@ -43,7 +43,7 @@
"chromatic": "11.5.5",
"element-internals-polyfill": "1.3.10",
"esbuild": "0.21.5",
- "eslint": "^9.7.0",
+ "eslint": "9.7.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-lit": "1.14.0",
"eslint-plugin-local-rules": "3.0.2",
@@ -25283,29 +25283,47 @@
}
},
"node_modules/playwright": {
- "version": "1.37.1",
+ "version": "1.45.3",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.45.3.tgz",
+ "integrity": "sha512-QhVaS+lpluxCaioejDZ95l4Y4jSFCsBvl2UZkpeXlzxmqS+aABr5c82YmfMHrL6x27nvrvykJAFpkzT2eWdJww==",
"dev": true,
- "hasInstallScript": true,
- "license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.37.1"
+ "playwright-core": "1.45.3"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
- "version": "1.37.1",
+ "version": "1.45.3",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.45.3.tgz",
+ "integrity": "sha512-+ym0jNbcjikaOwwSZycFbwkWgfruWvYlJfThKYAlImbxUgdWFO2oW70ojPm4OpE4t6TAo2FY/smM+hpVTtkhDA==",
"dev": true,
- "license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
+ }
+ },
+ "node_modules/playwright/node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/plop": {
diff --git a/package.json b/package.json
index 1f15ac332..c94dbe446 100644
--- a/package.json
+++ b/package.json
@@ -132,6 +132,9 @@
"vite-tsconfig-paths": "4.3.2",
"web-component-analyzer": "2.0.0"
},
+ "overrides": {
+ "playwright": "^1.45.3"
+ },
"workspaces": [
"./packages/*"
],
diff --git a/packages/uui-popover-container/lib/uui-popover-container.element.ts b/packages/uui-popover-container/lib/uui-popover-container.element.ts
index 1ed78ebb4..7d37ce1bd 100644
--- a/packages/uui-popover-container/lib/uui-popover-container.element.ts
+++ b/packages/uui-popover-container/lib/uui-popover-container.element.ts
@@ -2,7 +2,6 @@ import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
import { findAncestorByAttributeValue } from '@umbraco-ui/uui-base/lib/utils';
import { css, html, LitElement } from 'lit';
import { property, state } from 'lit/decorators.js';
-import { polyfill } from './uui-popover-polyfill.js';
export type PopoverContainerPlacement =
| 'top'
@@ -72,10 +71,6 @@ export class UUIPopoverContainerElement extends LitElement {
#scrollParents: Element[] = [];
connectedCallback(): void {
- //TODO: Remove this polyfill when firefox supports the new popover API
- !Object.prototype.hasOwnProperty.call(HTMLElement, 'popover') &&
- polyfill.bind(this)();
-
if (!this.hasAttribute('popover')) {
this.setAttribute('popover', '');
}
diff --git a/packages/uui-popover-container/lib/uui-popover-container.test.ts b/packages/uui-popover-container/lib/uui-popover-container.test.ts
index e38fe1fea..a2ad641c8 100644
--- a/packages/uui-popover-container/lib/uui-popover-container.test.ts
+++ b/packages/uui-popover-container/lib/uui-popover-container.test.ts
@@ -6,7 +6,9 @@ describe('UUIPopoverContainerElement', () => {
beforeEach(async () => {
element = await fixture(html`
-
+
+ Hello world
+
`);
});
@@ -17,4 +19,9 @@ describe('UUIPopoverContainerElement', () => {
it('passes the a11y audit', async () => {
await expect(element).shadowDom.to.be.accessible();
});
+
+ it('gets the popover attribute', async () => {
+ await element.updateComplete;
+ expect(element).to.have.attribute('popover');
+ });
});
diff --git a/packages/uui-popover-container/lib/uui-popover-polyfill.ts b/packages/uui-popover-container/lib/uui-popover-polyfill.ts
deleted file mode 100644
index f2fd7dced..000000000
--- a/packages/uui-popover-container/lib/uui-popover-polyfill.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-// @ts-nocheck
-
-export function polyfill() {
- const originalAddEventListener = this.addEventListener;
-
- // This is the only way to get access to the private functions onFocusOut and onBeforeToggle.
- this.addEventListener = function (type, listener, options) {
- if (type === 'focusout') {
- // focusout doesn't work properly in firefox, so we ignore it.
- return;
- }
- if (type === 'beforetoggle') {
- // Intercept the beforetoggle event so we can dispatch our own event.
- this.polyfill_onBeforeToggle = event => {
- this.dispatchEvent(
- new CustomEvent('polyfill-beforetoggle', {
- bubbles: false,
- composed: false,
- detail: {
- oldState: event.oldState,
- newState: event.newState,
- },
- }),
- );
-
- listener(event);
- };
- return;
- }
- originalAddEventListener.call(this, type, listener, options);
- };
-
- this.polyfill_onFocusout = event => {
- const target = event.relatedTarget;
- if (!target) return;
-
- const isInsidePopoverContainer = target?.closest('uui-popover-container');
- const isInsidePopoverTarget = target?.closest('[popovertarget]');
-
- if (!isInsidePopoverContainer && !isInsidePopoverTarget) {
- this.hidePopover();
- }
- };
-
- this.polyfill_onClick = event => {
- const path = event.composedPath();
- const isInsidePopoverContainer = path.some(element => {
- return (
- element.tagName === 'UUI-POPOVER-CONTAINER' ||
- element.attributes?.popovertarget
- );
- });
-
- if (!isInsidePopoverContainer) {
- this.hidePopover();
- }
- };
-
- this.polyfill_onParentPopoverUpdate = event => {
- if (event.detail.newState === 'closed') {
- this.hidePopover();
- }
- };
-
- const findParentPopover = element => {
- if (!element.parentElement) return null;
- if (element.parentElement?.tagName === 'UUI-POPOVER-CONTAINER') {
- return element.parentElement;
- }
- return findParentPopover(element.parentElement);
- };
-
- if (!this.polyfill_hasBeenMovedToBody) {
- this.style.display = 'none';
- this.style.position = 'fixed';
- this.style.inset = '0';
- this.style.zIndex = '9999';
- }
-
- this.showPopover = () => {
- if (!this.polyfill_hasBeenMovedToBody) {
- this.polyfill_parentPopoverContainer = findParentPopover(this);
- }
-
- this.polyfill_onBeforeToggle({
- oldState: 'closed',
- newState: 'open',
- });
- this.style.display = 'block';
- this.polyfill_parentPopoverContainer?.addEventListener(
- 'polyfill-beforetoggle',
- this.polyfill_onParentPopoverUpdate,
- );
- window.addEventListener('click', this.polyfill_onClick);
- window.addEventListener('focusout', this.polyfill_onFocusout);
-
- //Find the dom position that the popover is currently at and save it so we can restore it later.
- this.polyfill_originalParent = this.parentNode;
- this.polyfill_originalNextSibling = this.nextSibling;
-
- //TODO: Find the render root of this component and get the stylesheet from there.
- const renderRoot = this.getRootNode();
-
- if (renderRoot && renderRoot.adoptedStyleSheets) {
- // Styles from the parent are lost when moving the popover to the body, so we need to add them back.
- const adoptedStyleSheets = renderRoot.adoptedStyleSheets;
- const combinedStyles = adoptedStyleSheets.reduce((acc, styleSheet) => {
- return (
- acc +
- Object.values(styleSheet.cssRules).reduce((acc, rule) => {
- return acc + `#${this.id} ${rule.cssText}`;
- }, '')
- );
- }, '');
-
- const styleTag = document.createElement('style');
- styleTag.innerHTML = combinedStyles;
- styleTag.id = 'uui-popover-polyfill-style';
-
- //look in slot for existing style tag and remove it.
- const existingStyleTag = this.shadowRoot.host.querySelector(
- '#uui-popover-polyfill-style',
- );
-
- if (existingStyleTag) {
- existingStyleTag.parentNode.removeChild(existingStyleTag);
- }
-
- this.insertAdjacentElement('beforeend', styleTag);
- }
-
- //Move the popover to the body so it sits on top of everything else.
- if (this.parentNode !== document.body) {
- this.parentNode?.removeChild(this);
- this.polyfill_hasBeenMovedToBody = true;
- document.body.appendChild(this);
- }
- };
- this.hidePopover = () => {
- //Restore previous dom position.
- if (this.polyfill_hasBeenMovedToBody) {
- document.body.removeChild(this);
- this.polyfill_hasBeenMovedToBody = false;
- this.polyfill_originalParent?.insertBefore(
- this,
- this.polyfill_originalNextSibling,
- );
- }
-
- window.removeEventListener('click', this.polyfill_onClick);
- window.removeEventListener('focusout', this.polyfill_onFocusout);
- this.polyfill_parentPopoverContainer?.removeEventListener(
- 'polyfill-beforetoggle',
- this.polyfill_onParentPopoverUpdate,
- );
- this.polyfill_onBeforeToggle({
- oldState: 'open',
- newState: 'closed',
- });
- this.style.display = 'none';
- };
-}