Skip to content

Commit

Permalink
feat: support cross-root registration with form-element-register event
Browse files Browse the repository at this point in the history
  • Loading branch information
maxevilmind authored and tlouisse committed Apr 2, 2024
1 parent 79a6467 commit 37deecd
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/happy-jars-joke.md
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ const FormRegisteringMixinImplementation = superclass =>
* @type {FormRegistrarHost | 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() {
Expand All @@ -36,6 +49,7 @@ const FormRegisteringMixinImplementation = superclass =>
new CustomEvent('form-element-register', {
detail: { element: this },
bubbles: true,
composed: Boolean(this.allowCrossRootRegistration),
}),
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { LitElement } from 'lit';
import { uuid } from '@lion/ui/core.js';
import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
import {
FormRegisteringMixin,
FormRegistrarMixin,
FormRegistrarPortalMixin,
} 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
Expand Down Expand Up @@ -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', () => {
it('forwards registrations to the .registrationTarget', async () => {
const el = /** @type {RegistrarClass} */ (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LitElement } from 'lit';
import { Constructor } from '@open-wc/dedupe-mixin';
import { LitElement } from 'lit';

import { FormRegistrarHost } from './FormRegistrarMixinTypes.js';

Expand All @@ -8,6 +8,14 @@ export declare class FormRegisteringHost {
* The name the host is registered with to a parent
*/
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
Expand Down

0 comments on commit 37deecd

Please sign in to comment.