feat: support cross-root registration with form-element-register event
This commit is contained in:
parent
79a64674f8
commit
37deecd2a3
4 changed files with 85 additions and 3 deletions
5
.changeset/happy-jars-joke.md
Normal file
5
.changeset/happy-jars-joke.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/ui': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Added support for cross-root registration by adding a flag to composed property of form-element-register event.
|
||||||
|
|
@ -28,6 +28,19 @@ const FormRegisteringMixinImplementation = superclass =>
|
||||||
* @type {FormRegistrarHost | undefined}
|
* @type {FormRegistrarHost | undefined}
|
||||||
*/
|
*/
|
||||||
this._parentFormGroup = undefined;
|
this._parentFormGroup = undefined;
|
||||||
|
/**
|
||||||
|
* To encourage accessibility best practices, `form-element-register` events
|
||||||
|
* do not pierce through shadow roots. This forces the developer to create form groups and fieldsets that automatically allow the creation of accessible relationships in the same dom tree.
|
||||||
|
Use this option if you know what you're doing. It will then be possible to nest FormControls
|
||||||
|
inside shadow dom. See https://lion-web.netlify.app/fundamentals/rationales/accessibility/#shadow-roots-and-accessibility
|
||||||
|
*/
|
||||||
|
this.allowCrossRootRegistration = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
allowCrossRootRegistration: { type: Boolean, attribute: 'allow-cross-root-registration' },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
|
|
@ -36,6 +49,7 @@ const FormRegisteringMixinImplementation = superclass =>
|
||||||
new CustomEvent('form-element-register', {
|
new CustomEvent('form-element-register', {
|
||||||
detail: { element: this },
|
detail: { element: this },
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
|
composed: Boolean(this.allowCrossRootRegistration),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import { LitElement } from 'lit';
|
|
||||||
import { uuid } from '@lion/ui/core.js';
|
import { uuid } from '@lion/ui/core.js';
|
||||||
import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
|
|
||||||
import {
|
import {
|
||||||
FormRegisteringMixin,
|
FormRegisteringMixin,
|
||||||
FormRegistrarMixin,
|
FormRegistrarMixin,
|
||||||
FormRegistrarPortalMixin,
|
FormRegistrarPortalMixin,
|
||||||
} from '@lion/ui/form-core.js';
|
} from '@lion/ui/form-core.js';
|
||||||
|
import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
|
||||||
|
import { LitElement } from 'lit';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} customConfig
|
* @typedef {Object} customConfig
|
||||||
|
|
@ -256,6 +257,60 @@ export const runRegistrationSuite = customConfig => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('FormRegisteringMixin', () => {
|
||||||
|
it('propagates the form-element-register event through the shadowDom', async () => {
|
||||||
|
const eventSpy = sinon.spy();
|
||||||
|
const withShadowFormControlStr = defineCE(
|
||||||
|
class extends FormRegistrarMixin(LitElement) {
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<${childTag}
|
||||||
|
id="child"
|
||||||
|
@form-element-register=${eventSpy}
|
||||||
|
allow-cross-root-registration
|
||||||
|
>
|
||||||
|
</${childTag}>`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const withShadowFormControlTag = unsafeStatic(withShadowFormControlStr);
|
||||||
|
|
||||||
|
const el = /** @type {RegistrarClass} */ (
|
||||||
|
await fixture(html`
|
||||||
|
<${withShadowFormControlTag}>
|
||||||
|
</${withShadowFormControlTag}>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(eventSpy).to.have.been.calledOnce;
|
||||||
|
expect(eventSpy.getCall(0).args[0].composed).to.equal(true);
|
||||||
|
expect(el.formElements).to.deep.equal([el.shadowRoot?.querySelector('#child')]);
|
||||||
|
});
|
||||||
|
it('dispatches the form-element-register event with compose true if allowCrossRootRegistration is set', async () => {
|
||||||
|
const eventSpy = sinon.spy();
|
||||||
|
/** @type {RegisteringClass} */ (
|
||||||
|
await fixture(html`
|
||||||
|
<${childTag}
|
||||||
|
@form-element-register=${eventSpy}
|
||||||
|
allow-cross-root-registration
|
||||||
|
>
|
||||||
|
</${childTag}>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
expect(eventSpy).to.have.been.calledOnce;
|
||||||
|
expect(eventSpy.getCall(0).args[0].composed).to.equal(true);
|
||||||
|
});
|
||||||
|
it('dispatches the form-element-register event with compose false if allowCrossRootRegistration is not set', async () => {
|
||||||
|
const eventSpy = sinon.spy();
|
||||||
|
/** @type {RegisteringClass} */ (
|
||||||
|
await fixture(html`
|
||||||
|
<${childTag} @form-element-register=${eventSpy}></${childTag}>
|
||||||
|
`)
|
||||||
|
);
|
||||||
|
expect(eventSpy).to.have.been.calledOnce;
|
||||||
|
expect(eventSpy.getCall(0).args[0].composed).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
describe('FormRegistrarPortalMixin', () => {
|
describe('FormRegistrarPortalMixin', () => {
|
||||||
it('forwards registrations to the .registrationTarget', async () => {
|
it('forwards registrations to the .registrationTarget', async () => {
|
||||||
const el = /** @type {RegistrarClass} */ (
|
const el = /** @type {RegistrarClass} */ (
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { LitElement } from 'lit';
|
|
||||||
import { Constructor } from '@open-wc/dedupe-mixin';
|
import { Constructor } from '@open-wc/dedupe-mixin';
|
||||||
|
import { LitElement } from 'lit';
|
||||||
|
|
||||||
import { FormRegistrarHost } from './FormRegistrarMixinTypes.js';
|
import { FormRegistrarHost } from './FormRegistrarMixinTypes.js';
|
||||||
|
|
||||||
|
|
@ -8,6 +8,14 @@ export declare class FormRegisteringHost {
|
||||||
* The name the host is registered with to a parent
|
* The name the host is registered with to a parent
|
||||||
*/
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
/**
|
||||||
|
* To encourage accessibility best practices, `form-element-register` events
|
||||||
|
* do not pierce through shadow roots. This forces the developer to create form groups and fieldsets that
|
||||||
|
* automatically allow the creation of accessible relationships in the same dom tree.
|
||||||
|
* Use this option if you know what you're doing. It will then be possible to nest FormControls
|
||||||
|
* inside shadow dom. See https://lion-web.netlify.app/fundamentals/rationales/accessibility#shadow-roots-and-accessibility
|
||||||
|
*/
|
||||||
|
allowCrossRootRegistration: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The registrar this FormControl registers to, Usually a descendant of FormGroup or
|
* The registrar this FormControl registers to, Usually a descendant of FormGroup or
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue