@zywave/zui-base
Advanced tools
Comparing version
@@ -52,2 +52,12 @@ { | ||
"kind": "field", | ||
"name": "_focusControlSelector", | ||
"type": { | ||
"text": "string" | ||
}, | ||
"privacy": "protected", | ||
"description": "Necessary workaround to https://issues.chromium.org/issues/389587444 and purely needed for validation", | ||
"readonly": true | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "formAssociated", | ||
@@ -142,2 +152,11 @@ "privacy": "protected", | ||
"kind": "field", | ||
"name": "#focusControl", | ||
"privacy": "private", | ||
"type": { | ||
"text": "HTMLElement | HTMLInputElement | null | undefined" | ||
}, | ||
"default": "null" | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "#internals", | ||
@@ -151,2 +170,21 @@ "privacy": "private", | ||
"kind": "field", | ||
"name": "_deferFocus", | ||
"type": { | ||
"text": "boolean" | ||
}, | ||
"privacy": "protected", | ||
"default": "false", | ||
"description": "TODO(pat): Temporary hack for zui-select-dropdown; focus should be refactored in that component" | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "_deferClick", | ||
"type": { | ||
"text": "boolean" | ||
}, | ||
"privacy": "protected", | ||
"default": "false" | ||
}, | ||
{ | ||
"kind": "field", | ||
"name": "_formSubmitButton", | ||
@@ -153,0 +191,0 @@ "type": { |
@@ -18,2 +18,6 @@ import { ZuiBaseElement } from './zui-base.js'; | ||
/** | ||
* Necessary workaround to https://issues.chromium.org/issues/389587444 and purely needed for validation | ||
*/ | ||
protected get _focusControlSelector(): string; | ||
/** | ||
* Tells the browser that this is a form-associated custom element: https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example | ||
@@ -52,2 +56,7 @@ */ | ||
get validationMessage(): string; | ||
/** | ||
* TODO(pat): Temporary hack for zui-select-dropdown; focus should be refactored in that component | ||
*/ | ||
protected _deferFocus: boolean; | ||
protected _deferClick: boolean; | ||
protected get _formSubmitButton(): HTMLButtonElement | HTMLInputElement | null; | ||
@@ -54,0 +63,0 @@ constructor(); |
@@ -44,2 +44,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
/** | ||
* Necessary workaround to https://issues.chromium.org/issues/389587444 and purely needed for validation | ||
*/ | ||
get _focusControlSelector() { | ||
throw new Error('You must implement a getter for "form control" query in the `_focusControlSelector` property.'); | ||
} | ||
/** | ||
* Tells the browser that this is a form-associated custom element: https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example | ||
@@ -99,2 +105,3 @@ */ | ||
#priorValidationMessage; | ||
#focusControl; | ||
#internals; | ||
@@ -127,2 +134,8 @@ get _formSubmitButton() { | ||
this.#priorValidationMessage = ''; | ||
this.#focusControl = null; | ||
/** | ||
* TODO(pat): Temporary hack for zui-select-dropdown; focus should be refactored in that component | ||
*/ | ||
this._deferFocus = false; | ||
this._deferClick = false; | ||
this.#internals = this.attachInternals?.(); | ||
@@ -132,2 +145,8 @@ } | ||
super.firstUpdated(changedProps); | ||
this.#focusControl = this.shadowRoot?.querySelector(this._focusControlSelector); | ||
this.addEventListener('click', () => { | ||
if (!this.disabled && !this._deferClick) { | ||
this.focus(); | ||
} | ||
}); | ||
// once the form control has received and lost focus, we can consider the user to have interacted with the control | ||
@@ -167,6 +186,6 @@ // this is necessary to workaround the lack of :user-invalid support in ElementInternals | ||
} | ||
this.#internals?.setValidity({ ...cloneValidityState(this.validity), customError: true }, message); | ||
this.#internals?.setValidity({ ...cloneValidityState(this.validity), customError: true }, message, this.#focusControl); | ||
} | ||
else if (this.#priorValidationMessage) { | ||
this.#internals?.setValidity({ ...cloneValidityState(this.validity), customError: false }, this.#priorValidationMessage); | ||
this.#internals?.setValidity({ ...cloneValidityState(this.validity), customError: false }, this.#priorValidationMessage, this.#focusControl); | ||
} | ||
@@ -193,3 +212,5 @@ else { | ||
_setValidity(validity, message) { | ||
message ? this.#internals?.setValidity?.(validity, message) : this.#internals?.setValidity?.({}); | ||
message | ||
? this.#internals?.setValidity?.(validity, message, this.#focusControl) | ||
: this.#internals?.setValidity?.({}); | ||
} | ||
@@ -196,0 +217,0 @@ _mapValidationMessage(message, validityState, validationMessageMap) { |
{ | ||
"name": "@zywave/zui-base", | ||
"version": "4.4.0-pre.0", | ||
"version": "4.4.0-pre.1", | ||
"main": "dist/index.js", | ||
@@ -23,3 +23,3 @@ "module": "dist/index.js", | ||
}, | ||
"gitHead": "af5c5593589b0d976d1c0d851116d8c3e95ae467" | ||
"gitHead": "be9f692297fbee1cf28bf0e38333d392052dd5f7" | ||
} |
@@ -45,2 +45,9 @@ import { ZuiBaseElement } from './zui-base.js'; | ||
/** | ||
* Necessary workaround to https://issues.chromium.org/issues/389587444 and purely needed for validation | ||
*/ | ||
protected get _focusControlSelector(): string { | ||
throw new Error('You must implement a getter for "form control" query in the `_focusControlSelector` property.'); | ||
} | ||
/** | ||
* Tells the browser that this is a form-associated custom element: https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-face-example | ||
@@ -127,4 +134,12 @@ */ | ||
#focusControl?: HTMLElement | HTMLInputElement | null = null; | ||
#internals?: ElementInternals; | ||
/** | ||
* TODO(pat): Temporary hack for zui-select-dropdown; focus should be refactored in that component | ||
*/ | ||
protected _deferFocus = false; | ||
protected _deferClick = false; | ||
protected get _formSubmitButton(): HTMLButtonElement | HTMLInputElement | null { | ||
@@ -147,2 +162,10 @@ if (this.form) { | ||
this.#focusControl = this.shadowRoot?.querySelector(this._focusControlSelector); | ||
this.addEventListener('click', () => { | ||
if (!this.disabled && !this._deferClick) { | ||
this.focus(); | ||
} | ||
}); | ||
// once the form control has received and lost focus, we can consider the user to have interacted with the control | ||
@@ -188,7 +211,12 @@ // this is necessary to workaround the lack of :user-invalid support in ElementInternals | ||
} | ||
this.#internals?.setValidity({ ...cloneValidityState(this.validity), customError: true }, message); | ||
this.#internals?.setValidity( | ||
{ ...cloneValidityState(this.validity), customError: true }, | ||
message, | ||
this.#focusControl | ||
); | ||
} else if (this.#priorValidationMessage) { | ||
this.#internals?.setValidity( | ||
{ ...cloneValidityState(this.validity), customError: false }, | ||
this.#priorValidationMessage | ||
this.#priorValidationMessage, | ||
this.#focusControl | ||
); | ||
@@ -216,3 +244,5 @@ } else { | ||
protected _setValidity(validity: ValidityStateFlags, message: string) { | ||
message ? this.#internals?.setValidity?.(validity, message) : this.#internals?.setValidity?.({}); | ||
message | ||
? this.#internals?.setValidity?.(validity, message, this.#focusControl) | ||
: this.#internals?.setValidity?.({}); | ||
} | ||
@@ -219,0 +249,0 @@ |
@@ -59,2 +59,24 @@ // eslint-disable-next-line @typescript-eslint/triple-slash-reference | ||
test('Not configuring _focusControlSelector throws error', async () => { | ||
const elementTagName = 'test-form-selector-error'; | ||
customElements.define( | ||
elementTagName, | ||
class extends FACETestBase { | ||
render() { | ||
return html`<input />`; | ||
} | ||
} | ||
); | ||
const element = createFACEElement(elementTagName); | ||
form.append(element); | ||
try { | ||
await element.updateComplete; | ||
assert.isFalse(true, 'Expected an error'); | ||
} catch { | ||
// left empty on purpose | ||
} | ||
}); | ||
test('Not configuring formResetCallback throws error', async () => { | ||
@@ -88,2 +110,6 @@ const elementTagName = 'test-form-reset-callback-error'; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -108,2 +134,6 @@ return html`<input />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -127,2 +157,6 @@ return html`<input />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -153,2 +187,6 @@ return html`<input />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -185,2 +223,6 @@ return html`<input />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -219,2 +261,6 @@ return html`<input />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -249,2 +295,6 @@ return html`<input />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -276,2 +326,6 @@ return html`<input />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -306,2 +360,6 @@ return html`<input />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -330,2 +388,6 @@ return html`<input />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -360,2 +422,6 @@ return html`<input type="checkbox" />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
render() { | ||
@@ -399,2 +465,6 @@ return html`<input />`; | ||
class extends FACETestBase { | ||
get _focusControlSelector() { | ||
return 'input'; | ||
} | ||
firstUpdated(changedProps: PropertyValues<this>) { | ||
@@ -401,0 +471,0 @@ super.firstUpdated(changedProps); |
Sorry, the diff of this file is not supported yet
119631
5.49%1910
8.4%