From 65e342d1fa9761e893324c0b02cbd0205504672d Mon Sep 17 00:00:00 2001 From: Richard Helm <86777660+RichardHelm@users.noreply.github.com> Date: Thu, 7 Mar 2024 09:07:39 +0000 Subject: [PATCH] fix(components): fix validation in Safari versions before 16.4 (VIV-1568) (#1608) --- .../patterns/form-elements/form-elements.spec.ts | 16 ++++++++++++++++ .../patterns/form-elements/form-elements.ts | 5 ++++- package-lock.json | 13 +++++++++++++ package.json | 1 + 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/libs/components/src/shared/patterns/form-elements/form-elements.spec.ts b/libs/components/src/shared/patterns/form-elements/form-elements.spec.ts index 47c4be29b0..7431df1cf0 100644 --- a/libs/components/src/shared/patterns/form-elements/form-elements.spec.ts +++ b/libs/components/src/shared/patterns/form-elements/form-elements.spec.ts @@ -1,3 +1,5 @@ +import 'element-internals-polyfill'; + import { fixture } from '@vivid-nx/shared'; import { customElement, FASTElement } from '@microsoft/fast-element'; import { FormAssociated } from '@microsoft/fast-foundation'; @@ -22,6 +24,12 @@ describe('Form Elements', function () { describe('formElements() validate method', () => { @formElements class Test extends HTMLElement { + elementInternals: ElementInternals; + constructor() { + super(); + this.elementInternals = this.attachInternals(); + } + proxy = document.createElement('input'); control = document.createElement('input'); @@ -103,6 +111,14 @@ describe('Form Elements', function () { undefined ); }); + + it('should not call setValidity when element internals are not supported', () => { + delete (test as any).elementInternals; + + test.validate(); + + expect(test.setValidity).not.toHaveBeenCalled(); + }); }); describe('formElements mixin', function () { diff --git a/libs/components/src/shared/patterns/form-elements/form-elements.ts b/libs/components/src/shared/patterns/form-elements/form-elements.ts index 775289e27f..562facf5b5 100644 --- a/libs/components/src/shared/patterns/form-elements/form-elements.ts +++ b/libs/components/src/shared/patterns/form-elements/form-elements.ts @@ -51,6 +51,9 @@ export function formElements< * field. Our proxy is never interacted with, so the constraint never applies. * Therefore, we need to use the validity from the actual control in this case. * + * Additionally, we need to avoid calling setValidity when elementInternals is not available, otherwise the proxy gets + * stuck in an invalid state. + * * This needs to be done in the original validate method from the FAST FormAssociated mixin. * We walk up the prototype chain until we find the original method and replace it. */ @@ -59,7 +62,7 @@ export function formElements< const parentPrototype = Object.getPrototypeOf(currentPrototype); if (currentPrototype.validate && !parentPrototype.validate) { currentPrototype.validate = function (anchor?: HTMLElement) { - if (this.proxy instanceof HTMLElement) { + if (this.proxy instanceof HTMLElement && this.elementInternals) { const isValid = this.proxy.validity.valid; const controlIsInvalidDueToMinOrMaxLength = (this.control && this.control.validity) diff --git a/package-lock.json b/package-lock.json index de54610c3c..ff5ecce09a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,6 +92,7 @@ "cem-plugin-jsdoc-function": "^0.0.5", "cem-plugin-readonly": "^0.0.5", "clean-css": "^5.3.0", + "element-internals-polyfill": "^1.3.10", "eslint": "8.15.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-ban": "^1.6.0", @@ -15062,6 +15063,12 @@ "integrity": "sha512-Dvo5OGjnl7AZTU632dFJtWj0uJK835eeOVQIuRcmBmsFsTNn3cL05FqOyHAfGQDIoHfLhyJ1Tya3PJ0ceMz54g==", "dev": true }, + "node_modules/element-internals-polyfill": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/element-internals-polyfill/-/element-internals-polyfill-1.3.10.tgz", + "integrity": "sha512-hflkht5sNZ2LF2sP9+OHfqGDcr8R9NIiDCuDfXep8uptqqt0OjZDaWJ/7ip+OdoIZBFJL+fFJ3+aLku1cTIEGA==", + "dev": true + }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -40225,6 +40232,12 @@ "integrity": "sha512-Dvo5OGjnl7AZTU632dFJtWj0uJK835eeOVQIuRcmBmsFsTNn3cL05FqOyHAfGQDIoHfLhyJ1Tya3PJ0ceMz54g==", "dev": true }, + "element-internals-polyfill": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/element-internals-polyfill/-/element-internals-polyfill-1.3.10.tgz", + "integrity": "sha512-hflkht5sNZ2LF2sP9+OHfqGDcr8R9NIiDCuDfXep8uptqqt0OjZDaWJ/7ip+OdoIZBFJL+fFJ3+aLku1cTIEGA==", + "dev": true + }, "emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", diff --git a/package.json b/package.json index b877071345..c0c27a8e97 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "cem-plugin-jsdoc-function": "^0.0.5", "cem-plugin-readonly": "^0.0.5", "clean-css": "^5.3.0", + "element-internals-polyfill": "^1.3.10", "eslint": "8.15.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-ban": "^1.6.0",