diff --git a/.changeset/five-onions-hope.md b/.changeset/five-onions-hope.md
new file mode 100644
index 000000000..89609021b
--- /dev/null
+++ b/.changeset/five-onions-hope.md
@@ -0,0 +1,5 @@
+---
+'@lion/checkbox-group': minor
+---
+
+Add checkbox-indeterminate component, which is a mixed state checkbox that depends on its child checkbox states.
diff --git a/.changeset/lazy-chicken-speak.md b/.changeset/lazy-chicken-speak.md
new file mode 100644
index 000000000..937297113
--- /dev/null
+++ b/.changeset/lazy-chicken-speak.md
@@ -0,0 +1,6 @@
+---
+'@lion/form-core': patch
+'@lion/listbox': patch
+---
+
+Make \_\_parentFormGroup --> \_parentFormGroup so it is protected and not private
diff --git a/.changeset/witty-mugs-vanish.md b/.changeset/witty-mugs-vanish.md
new file mode 100644
index 000000000..3f6cd4aa2
--- /dev/null
+++ b/.changeset/witty-mugs-vanish.md
@@ -0,0 +1,6 @@
+---
+'@lion/form-core': patch
+'@lion/switch': patch
+---
+
+Make \_\_toggleChecked protected property (\_toggleChecked)
diff --git a/packages/checkbox-group/README.md b/packages/checkbox-group/README.md
index 5584c8c29..781223745 100644
--- a/packages/checkbox-group/README.md
+++ b/packages/checkbox-group/README.md
@@ -11,6 +11,7 @@ Its purpose is to provide a way for users to check **multiple** options amongst
import { html } from '@lion/core';
import { Required, Validator } from '@lion/form-core';
import './lion-checkbox-group.js';
+import './lion-checkbox-indeterminate.js';
import './lion-checkbox.js';
export default {
@@ -166,3 +167,81 @@ export const event = () => html`
Selected scientists: N/A
`;
```
+
+### Indeterminate
+
+```js preview-story
+export const indeterminate = () => html`
+
+
+
+
+
+
+
+`;
+```
+
+```js preview-story
+export const indeterminateSiblings = () => html`
+
+
+
+
+
+
+
+
+
+
+
+`;
+```
+
+```js preview-story
+export const indeterminateChildren = () => html`
+
+
+
+
+
+
+
+
+
+
+
+`;
+```
diff --git a/packages/checkbox-group/index.js b/packages/checkbox-group/index.js
index 6f20e3181..c07ad86a5 100644
--- a/packages/checkbox-group/index.js
+++ b/packages/checkbox-group/index.js
@@ -1,2 +1,3 @@
export { LionCheckboxGroup } from './src/LionCheckboxGroup.js';
+export { LionCheckboxIndeterminate } from './src/LionCheckboxIndeterminate.js';
export { LionCheckbox } from './src/LionCheckbox.js';
diff --git a/packages/checkbox-group/lion-checkbox-indeterminate.js b/packages/checkbox-group/lion-checkbox-indeterminate.js
new file mode 100644
index 000000000..37b65d36b
--- /dev/null
+++ b/packages/checkbox-group/lion-checkbox-indeterminate.js
@@ -0,0 +1,3 @@
+import { LionCheckboxIndeterminate } from './src/LionCheckboxIndeterminate.js';
+
+customElements.define('lion-checkbox-indeterminate', LionCheckboxIndeterminate);
diff --git a/packages/checkbox-group/package.json b/packages/checkbox-group/package.json
index 044b29017..8e6bfa78d 100644
--- a/packages/checkbox-group/package.json
+++ b/packages/checkbox-group/package.json
@@ -31,7 +31,8 @@
},
"sideEffects": [
"lion-checkbox.js",
- "lion-checkbox-group.js"
+ "lion-checkbox-group.js",
+ "lion-checkbox-indeterminate.js"
],
"dependencies": {
"@lion/core": "0.13.8",
diff --git a/packages/checkbox-group/src/LionCheckboxIndeterminate.js b/packages/checkbox-group/src/LionCheckboxIndeterminate.js
new file mode 100644
index 000000000..e2ef1bf69
--- /dev/null
+++ b/packages/checkbox-group/src/LionCheckboxIndeterminate.js
@@ -0,0 +1,141 @@
+import { html, css } from '@lion/core';
+import { LionCheckbox } from './LionCheckbox.js';
+
+/**
+ * @typedef {import('./LionCheckboxGroup').LionCheckboxGroup} LionCheckboxGroup
+ */
+
+// @ts-expect-error false positive for incompatible static get properties. Lit-element merges super properties already for you.
+export class LionCheckboxIndeterminate extends LionCheckbox {
+ static get styles() {
+ const superCtor = /** @type {typeof LionCheckbox} */ (super.prototype.constructor);
+ return [
+ superCtor.styles ? superCtor.styles : [],
+ css`
+ :host .choice-field__nested-checkboxes {
+ display: block;
+ }
+
+ ::slotted([slot='checkbox']) {
+ padding-left: 8px;
+ }
+ `,
+ ];
+ }
+
+ static get properties() {
+ return {
+ /**
+ * Indeterminate state of the checkbox
+ */
+ indeterminate: {
+ type: Boolean,
+ reflect: true,
+ },
+ };
+ }
+
+ get _checkboxGroupNode() {
+ return /** @type LionCheckboxGroup */ (this._parentFormGroup);
+ }
+
+ get _subCheckboxes() {
+ let checkboxes = [];
+ if (
+ this._checkboxGroupNode &&
+ this._checkboxGroupNode.formElements &&
+ this._checkboxGroupNode.formElements.length > 0
+ ) {
+ checkboxes = this._checkboxGroupNode.formElements.filter(
+ checkbox => checkbox !== this && this.contains(checkbox),
+ );
+ }
+ return /** @type LionCheckbox[] */ (checkboxes);
+ }
+
+ _setOwnCheckedState() {
+ const subCheckboxes = this._subCheckboxes;
+ if (!subCheckboxes.length) {
+ return;
+ }
+
+ this.__settingOwnChecked = true;
+ const checkedElements = subCheckboxes.filter(checkbox => checkbox.checked);
+ switch (subCheckboxes.length - checkedElements.length) {
+ // all checked
+ case 0:
+ this.indeterminate = false;
+ this.checked = true;
+ break;
+ // none checked
+ case subCheckboxes.length:
+ this.indeterminate = false;
+ this.checked = false;
+ break;
+ default:
+ this.indeterminate = true;
+ this.checked = false;
+ }
+ this.updateComplete.then(() => {
+ this.__settingOwnChecked = false;
+ });
+ }
+
+ /**
+ * @param {Event} ev
+ */
+ __onModelValueChanged(ev) {
+ if (this.disabled) {
+ return;
+ }
+
+ const _ev = /** @type {CustomEvent} */ (ev);
+ if (_ev.detail.formPath[0] === this && !this.__settingOwnChecked) {
+ this._subCheckboxes.forEach(checkbox => {
+ // eslint-disable-next-line no-param-reassign
+ checkbox.checked = this._inputNode.checked;
+ });
+ }
+ this._setOwnCheckedState();
+ }
+
+ // eslint-disable-next-line class-methods-use-this
+ _afterTemplate() {
+ return html`
+
+
+
+ `;
+ }
+
+ _onRequestToAddFormElement() {
+ this._setOwnCheckedState();
+ }
+
+ constructor() {
+ super();
+ this.indeterminate = false;
+ this._onRequestToAddFormElement = this._onRequestToAddFormElement.bind(this);
+ this.__onModelValueChanged = this.__onModelValueChanged.bind(this);
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ this.addEventListener('model-value-changed', this.__onModelValueChanged);
+ this.addEventListener('form-element-register', this._onRequestToAddFormElement);
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback();
+ this.removeEventListener('model-value-changed', this.__onModelValueChanged);
+ this.removeEventListener('form-element-register', this._onRequestToAddFormElement);
+ }
+
+ /** @param {import('lit-element').PropertyValues } changedProperties */
+ updated(changedProperties) {
+ super.updated(changedProperties);
+ if (changedProperties.has('indeterminate')) {
+ this._inputNode.indeterminate = this.indeterminate;
+ }
+ }
+}
diff --git a/packages/checkbox-group/test/lion-checkbox-indeterminate-integrations.test.js b/packages/checkbox-group/test/lion-checkbox-indeterminate-integrations.test.js
new file mode 100644
index 000000000..8e3bb2f22
--- /dev/null
+++ b/packages/checkbox-group/test/lion-checkbox-indeterminate-integrations.test.js
@@ -0,0 +1,4 @@
+import '../lion-checkbox-indeterminate.js';
+import { runChoiceInputMixinSuite } from '@lion/form-core/test-suites/choice-group/ChoiceInputMixin.suite.js';
+
+runChoiceInputMixinSuite({ tagString: 'lion-checkbox-indeterminate' });
diff --git a/packages/checkbox-group/test/lion-checkbox-indeterminate.test.js b/packages/checkbox-group/test/lion-checkbox-indeterminate.test.js
new file mode 100644
index 000000000..f96123dc7
--- /dev/null
+++ b/packages/checkbox-group/test/lion-checkbox-indeterminate.test.js
@@ -0,0 +1,370 @@
+import { expect, fixture, html } from '@open-wc/testing';
+import '../lion-checkbox-indeterminate.js';
+import '../lion-checkbox-group.js';
+import '../lion-checkbox.js';
+
+/**
+ * @typedef {import('../src/LionCheckboxIndeterminate').LionCheckboxIndeterminate} LionCheckboxIndeterminate
+ * @typedef {import('../src/LionCheckboxGroup').LionCheckboxGroup} LionCheckboxGroup
+ */
+
+describe('', () => {
+ it('should have type = checkbox', async () => {
+ // Arrange
+ const el = await fixture(html`
+
+ `);
+
+ // Assert
+ expect(el.getAttribute('type')).to.equal('checkbox');
+ });
+
+ it('should not be indeterminate by default if all children are unchecked', async () => {
+ // Arrange
+ const el = await fixture(html`
+
+
+
+
+
+
+
+ `);
+ const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ 'lion-checkbox-indeterminate',
+ ));
+
+ // Assert
+ expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ });
+
+ it('should be indeterminate if one child is checked', async () => {
+ // Arrange
+ const el = /** @type {LionCheckboxGroup} */ await fixture(html`
+
+
+
+
+
+
+
+ `);
+ const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ 'lion-checkbox-indeterminate',
+ ));
+
+ // Assert
+ expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.true;
+ });
+
+ it('should be checked if all children are checked', async () => {
+ // Arrange
+ const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
+
+
+
+
+
+
+
+ `));
+ const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ 'lion-checkbox-indeterminate',
+ ));
+
+ // Assert
+ expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ expect(elIndeterminate?.checked).to.be.true;
+ });
+
+ it('should become indeterminate if one child is checked', async () => {
+ // Arrange
+ const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
+
+
+
+
+
+
+
+ `));
+ const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ 'lion-checkbox-indeterminate',
+ ));
+
+ // Act
+ elIndeterminate._subCheckboxes[0].checked = true;
+ await el.updateComplete;
+
+ // Assert
+ expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.true;
+ });
+
+ it('should become checked if all children are checked', async () => {
+ // Arrange
+ const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
+
+
+
+
+
+
+
+ `));
+ const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ 'lion-checkbox-indeterminate',
+ ));
+
+ // Act
+ elIndeterminate._subCheckboxes[0].checked = true;
+ elIndeterminate._subCheckboxes[1].checked = true;
+ elIndeterminate._subCheckboxes[2].checked = true;
+ await el.updateComplete;
+
+ // Assert
+ expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ expect(elIndeterminate?.checked).to.be.true;
+ });
+
+ it('should sync all children when parent is checked (from indeterminate to checked)', async () => {
+ // Arrange
+ const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
+
+
+
+
+
+
+
+ `));
+ const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ 'lion-checkbox-indeterminate',
+ ));
+
+ // Act
+ elIndeterminate._inputNode.click();
+ await elIndeterminate.updateComplete;
+
+ // Assert
+ expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ expect(elIndeterminate?._subCheckboxes[0].hasAttribute('checked')).to.be.true;
+ expect(elIndeterminate?._subCheckboxes[1].hasAttribute('checked')).to.be.true;
+ expect(elIndeterminate?._subCheckboxes[2].hasAttribute('checked')).to.be.true;
+ });
+
+ it('should sync all children when parent is checked (from unchecked to checked)', async () => {
+ // Arrange
+ const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
+
+
+
+
+
+
+
+ `));
+ const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ 'lion-checkbox-indeterminate',
+ ));
+
+ // Act
+ elIndeterminate._inputNode.click();
+ await elIndeterminate.updateComplete;
+
+ // Assert
+ expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ expect(elIndeterminate?._subCheckboxes[0].hasAttribute('checked')).to.be.true;
+ expect(elIndeterminate?._subCheckboxes[1].hasAttribute('checked')).to.be.true;
+ expect(elIndeterminate?._subCheckboxes[2].hasAttribute('checked')).to.be.true;
+ });
+
+ it('should sync all children when parent is checked (from checked to unchecked)', async () => {
+ // Arrange
+ const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
+
+
+
+
+
+
+
+ `));
+ const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ 'lion-checkbox-indeterminate',
+ ));
+
+ // Act
+ elIndeterminate._inputNode.click();
+ await elIndeterminate.updateComplete;
+
+ // Assert
+ expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ expect(elIndeterminate?._subCheckboxes[0].hasAttribute('checked')).to.be.false;
+ expect(elIndeterminate?._subCheckboxes[1].hasAttribute('checked')).to.be.false;
+ expect(elIndeterminate?._subCheckboxes[2].hasAttribute('checked')).to.be.false;
+ });
+
+ it('should work as expected with siblings checkbox-indeterminate', async () => {
+ // Arrange
+ const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
+
+
+
+
+
+
+
+
+
+
+
+ `));
+ const elFirstIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ '#first-checkbox-indeterminate',
+ ));
+ const elSecondIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ '#second-checkbox-indeterminate',
+ ));
+
+ // Act - check the first sibling
+ elFirstIndeterminate._inputNode.click();
+ await elFirstIndeterminate.updateComplete;
+ await elSecondIndeterminate.updateComplete;
+
+ // Assert - the second sibling should not be affected
+ expect(elFirstIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ expect(elFirstIndeterminate?._subCheckboxes[0].hasAttribute('checked')).to.be.true;
+ expect(elFirstIndeterminate?._subCheckboxes[1].hasAttribute('checked')).to.be.true;
+ expect(elFirstIndeterminate?._subCheckboxes[2].hasAttribute('checked')).to.be.true;
+ expect(elSecondIndeterminate?._subCheckboxes[0].hasAttribute('checked')).to.be.false;
+ expect(elSecondIndeterminate?._subCheckboxes[1].hasAttribute('checked')).to.be.false;
+ });
+
+ it('should work as expected with nested indeterminate checkboxes', async () => {
+ // Arrange
+ const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
+
+
+
+
+
+
+
+
+
+
+
+ `));
+ const elNestedIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ '#nested-checkbox-indeterminate',
+ ));
+ const elParentIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ '#parent-checkbox-indeterminate',
+ ));
+
+ // Act - check a nested checkbox
+ elNestedIndeterminate?._subCheckboxes[0]._inputNode.click();
+ await el.updateComplete;
+
+ // Assert
+ expect(elNestedIndeterminate?.hasAttribute('indeterminate')).to.be.true;
+ expect(elParentIndeterminate?.hasAttribute('indeterminate')).to.be.true;
+
+ // Act - check all nested checkbox
+ elNestedIndeterminate?._subCheckboxes[1]._inputNode.click();
+ elNestedIndeterminate?._subCheckboxes[2]._inputNode.click();
+ await el.updateComplete;
+
+ // Assert
+ expect(elNestedIndeterminate?.hasAttribute('checked')).to.be.true;
+ expect(elNestedIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ expect(elParentIndeterminate?.hasAttribute('checked')).to.be.false;
+ expect(elParentIndeterminate?.hasAttribute('indeterminate')).to.be.true;
+
+ // Act - finally check all remaining checkbox
+ elParentIndeterminate?._subCheckboxes[0]._inputNode.click();
+ elParentIndeterminate?._subCheckboxes[1]._inputNode.click();
+ await el.updateComplete;
+
+ // Assert
+ expect(elNestedIndeterminate?.hasAttribute('checked')).to.be.true;
+ expect(elNestedIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ expect(elParentIndeterminate?.hasAttribute('checked')).to.be.true;
+ expect(elParentIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ });
+
+ it('should work as expected if extra html', async () => {
+ // Arrange
+ const el = /** @type {LionCheckboxGroup} */ (await fixture(html`
+
+
+ Let's have some fun
+
Hello I'm a div
+
+ useless div
+
+
+ absolutely useless
+
+
+
+ Too much fun, stop it !
+
+ `));
+ const elIndeterminate = /** @type {LionCheckboxIndeterminate} */ (el.querySelector(
+ 'lion-checkbox-indeterminate',
+ ));
+
+ // Act
+ elIndeterminate._subCheckboxes[0].checked = true;
+ elIndeterminate._subCheckboxes[1].checked = true;
+ elIndeterminate._subCheckboxes[2].checked = true;
+ await el.updateComplete;
+
+ // Assert
+ expect(elIndeterminate?.hasAttribute('indeterminate')).to.be.false;
+ expect(elIndeterminate?.checked).to.be.true;
+ });
+});
diff --git a/packages/form-core/src/choice-group/ChoiceGroupMixin.js b/packages/form-core/src/choice-group/ChoiceGroupMixin.js
index b8c02ad02..98a6d1702 100644
--- a/packages/form-core/src/choice-group/ChoiceGroupMixin.js
+++ b/packages/form-core/src/choice-group/ChoiceGroupMixin.js
@@ -6,7 +6,7 @@ import { InteractionStateMixin } from '../InteractionStateMixin.js';
* @typedef {import('../../types/choice-group/ChoiceGroupMixinTypes').ChoiceGroupMixin} ChoiceGroupMixin
* @typedef {import('../../types/FormControlMixinTypes').FormControlHost} FormControlHost
* @typedef {import('../../types/registration/FormRegistrarMixinTypes').ElementWithParentFormGroup} ElementWithParentFormGroup
- * @typedef {FormControlHost & HTMLElement & {__parentFormGroup?:HTMLElement, checked?:boolean}} FormControl
+ * @typedef {FormControlHost & HTMLElement & {_parentFormGroup?:HTMLElement, checked?:boolean}} FormControl
* @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputHost} ChoiceInputHost
*/
diff --git a/packages/form-core/src/choice-group/ChoiceInputMixin.js b/packages/form-core/src/choice-group/ChoiceInputMixin.js
index e737fcddb..a3709c75e 100644
--- a/packages/form-core/src/choice-group/ChoiceInputMixin.js
+++ b/packages/form-core/src/choice-group/ChoiceInputMixin.js
@@ -5,7 +5,7 @@ import { FormatMixin } from '../FormatMixin.js';
/**
* @typedef {import('../../types/FormControlMixinTypes').FormControlHost} FormControlHost
- * @typedef {FormControlHost & HTMLElement & {__parentFormGroup?:HTMLElement, checked?:boolean}} FormControl
+ * @typedef {FormControlHost & HTMLElement & {_parentFormGroup?:HTMLElement, checked?:boolean}} FormControl
* @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputMixin} ChoiceInputMixin
* @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputModelValue} ChoiceInputModelValue
*/
@@ -115,9 +115,9 @@ const ChoiceInputMixinImplementation = superclass =>
if (
changedProperties.has('name') &&
// @ts-expect-error not all choice inputs have a parent form group, since this mixin does not have a strict contract with the registration system
- this.__parentFormGroup &&
+ this._parentFormGroup &&
// @ts-expect-error
- this.__parentFormGroup.name !== this.name
+ this._parentFormGroup.name !== this.name
) {
// @ts-expect-error not all choice inputs have a name prop, because this mixin does not have a strict contract with form control mixin
this.name = changedProperties.get('name');
@@ -129,7 +129,7 @@ const ChoiceInputMixinImplementation = superclass =>
this.modelValue = { value: '', checked: false };
this.disabled = false;
this._preventDuplicateLabelClick = this._preventDuplicateLabelClick.bind(this);
- this.__toggleChecked = this.__toggleChecked.bind(this);
+ this._toggleChecked = this._toggleChecked.bind(this);
}
/**
@@ -193,7 +193,7 @@ const ChoiceInputMixinImplementation = superclass =>
if (this._labelNode) {
this._labelNode.addEventListener('click', this._preventDuplicateLabelClick);
}
- this.addEventListener('user-input-changed', this.__toggleChecked);
+ this.addEventListener('user-input-changed', this._toggleChecked);
}
disconnectedCallback() {
@@ -201,7 +201,7 @@ const ChoiceInputMixinImplementation = superclass =>
if (this._labelNode) {
this._labelNode.removeEventListener('click', this._preventDuplicateLabelClick);
}
- this.removeEventListener('user-input-changed', this.__toggleChecked);
+ this.removeEventListener('user-input-changed', this._toggleChecked);
}
/**
@@ -221,7 +221,9 @@ const ChoiceInputMixinImplementation = superclass =>
this._inputNode.addEventListener('click', __inputClickHandler);
}
- __toggleChecked() {
+ /** @param {Event} ev */
+ // eslint-disable-next-line no-unused-vars
+ _toggleChecked(ev) {
if (this.disabled) {
return;
}
diff --git a/packages/form-core/src/form-group/FormGroupMixin.js b/packages/form-core/src/form-group/FormGroupMixin.js
index a6005b444..84b62b661 100644
--- a/packages/form-core/src/form-group/FormGroupMixin.js
+++ b/packages/form-core/src/form-group/FormGroupMixin.js
@@ -12,7 +12,7 @@ import { FormElementsHaveNoError } from './FormElementsHaveNoError.js';
* @typedef {import('../../types/FormControlMixinTypes').FormControlHost} FormControlHost
* @typedef {import('../../types/registration/FormRegisteringMixinTypes').FormRegisteringHost} FormRegisteringHost
* @typedef {import('../../types/registration/FormRegistrarMixinTypes').ElementWithParentFormGroup} ElementWithParentFormGroup
- * @typedef {FormControlHost & HTMLElement & {__parentFormGroup?: HTMLElement, checked?: boolean, disabled: boolean, hasFeedbackFor: string[], makeRequestToBeDisabled: Function }} FormControl
+ * @typedef {FormControlHost & HTMLElement & {_parentFormGroup?: HTMLElement, checked?: boolean, disabled: boolean, hasFeedbackFor: string[], makeRequestToBeDisabled: Function }} FormControl
*/
/**
@@ -449,12 +449,12 @@ const FormGroupMixinImplementation = superclass =>
__linkChildrenMessagesToParent(child) {
// aria-describedby of (nested) children
const unTypedThis = /** @type {unknown} */ (this);
- let parent = /** @type {FormControlHost & { __parentFormGroup:any }} */ (unTypedThis);
+ let parent = /** @type {FormControlHost & { _parentFormGroup:any }} */ (unTypedThis);
const ctor = /** @type {typeof FormGroupMixin} */ (this.constructor);
while (parent) {
ctor._addDescriptionElementIdsToField(child, parent._getAriaDescriptionElements());
// Also check if the newly added child needs to refer grandparents
- parent = parent.__parentFormGroup;
+ parent = parent._parentFormGroup;
}
}
diff --git a/packages/form-core/src/registration/FormRegisteringMixin.js b/packages/form-core/src/registration/FormRegisteringMixin.js
index 6060275b2..61d858034 100644
--- a/packages/form-core/src/registration/FormRegisteringMixin.js
+++ b/packages/form-core/src/registration/FormRegisteringMixin.js
@@ -19,7 +19,7 @@ const FormRegisteringMixinImplementation = superclass =>
constructor() {
super();
/** @type {FormRegistrarHost | undefined} */
- this.__parentFormGroup = undefined;
+ this._parentFormGroup = undefined;
}
connectedCallback() {
@@ -42,8 +42,8 @@ const FormRegisteringMixinImplementation = superclass =>
// @ts-expect-error check it anyway, because could be lit-element extension
super.disconnectedCallback();
}
- if (this.__parentFormGroup) {
- this.__parentFormGroup.removeFormElement(this);
+ if (this._parentFormGroup) {
+ this._parentFormGroup.removeFormElement(this);
}
}
};
diff --git a/packages/form-core/src/registration/FormRegistrarMixin.js b/packages/form-core/src/registration/FormRegistrarMixin.js
index 5bef28b20..b61cca825 100644
--- a/packages/form-core/src/registration/FormRegistrarMixin.js
+++ b/packages/form-core/src/registration/FormRegistrarMixin.js
@@ -11,7 +11,7 @@ import { FormRegisteringMixin } from './FormRegisteringMixin.js';
/**
* @typedef {import('../../types/FormControlMixinTypes').FormControlHost} FormControlHost
- * @typedef {FormControlHost & HTMLElement & {__parentFormGroup?:HTMLElement, checked?:boolean}} FormControl
+ * @typedef {FormControlHost & HTMLElement & {_parentFormGroup?:HTMLElement, checked?:boolean}} FormControl
*/
/**
@@ -77,7 +77,7 @@ const FormRegistrarMixinImplementation = superclass =>
addFormElement(child, indexToInsertAt) {
// This is a way to let the child element (a lion-fieldset or lion-field) know, about its parent
// eslint-disable-next-line no-param-reassign
- child.__parentFormGroup = this;
+ child._parentFormGroup = this;
// 1. Add children as array element
if (indexToInsertAt >= 0) {
diff --git a/packages/form-core/test/lion-field.test.js b/packages/form-core/test/lion-field.test.js
index e7bbc635a..87ec127c6 100644
--- a/packages/form-core/test/lion-field.test.js
+++ b/packages/form-core/test/lion-field.test.js
@@ -16,7 +16,7 @@ import '../lion-field.js';
/**
* @typedef {import('../src/LionField.js').LionField} LionField
* @typedef {import('../types/FormControlMixinTypes').FormControlHost} FormControlHost
- * @typedef {FormControlHost & HTMLElement & {__parentFormGroup?:HTMLElement, checked?:boolean}} FormControl
+ * @typedef {FormControlHost & HTMLElement & {_parentFormGroup?:HTMLElement, checked?:boolean}} FormControl
*/
/** @typedef {HTMLElement & {shadowRoot: HTMLElement, assignedNodes: Function}} ShadowHTMLElement */
diff --git a/packages/form-core/types/choice-group/ChoiceInputMixinTypes.d.ts b/packages/form-core/types/choice-group/ChoiceInputMixinTypes.d.ts
index 85f1e3e54..473cfd206 100644
--- a/packages/form-core/types/choice-group/ChoiceInputMixinTypes.d.ts
+++ b/packages/form-core/types/choice-group/ChoiceInputMixinTypes.d.ts
@@ -43,7 +43,7 @@ export declare class ChoiceInputHost {
_preventDuplicateLabelClick(ev: Event): void;
- __toggleChecked(): void;
+ _toggleChecked(ev: Event): void;
__syncModelCheckedToChecked(checked: boolean): void;
diff --git a/packages/form-core/types/registration/FormRegisteringMixinTypes.d.ts b/packages/form-core/types/registration/FormRegisteringMixinTypes.d.ts
index 3f418755b..8a0804d5e 100644
--- a/packages/form-core/types/registration/FormRegisteringMixinTypes.d.ts
+++ b/packages/form-core/types/registration/FormRegisteringMixinTypes.d.ts
@@ -6,7 +6,7 @@ export declare class FormRegisteringHost {
constructor(...args: any[]);
connectedCallback(): void;
disconnectedCallback(): void;
- __parentFormGroup?: FormRegistrarHost;
+ _parentFormGroup?: FormRegistrarHost;
}
export declare function FormRegisteringImplementation>(
diff --git a/packages/form-core/types/registration/FormRegistrarMixinTypes.d.ts b/packages/form-core/types/registration/FormRegistrarMixinTypes.d.ts
index f6a8a230d..823d17c4e 100644
--- a/packages/form-core/types/registration/FormRegistrarMixinTypes.d.ts
+++ b/packages/form-core/types/registration/FormRegistrarMixinTypes.d.ts
@@ -5,7 +5,7 @@ import { FormControlHost } from '../../types/FormControlMixinTypes';
import { LitElement } from '@lion/core';
export declare class ElementWithParentFormGroup {
- __parentFormGroup: FormRegistrarHost;
+ _parentFormGroup: FormRegistrarHost;
}
export declare class FormRegistrarHost {
diff --git a/packages/listbox/src/LionOption.js b/packages/listbox/src/LionOption.js
index 4ee22ffdb..873db1415 100644
--- a/packages/listbox/src/LionOption.js
+++ b/packages/listbox/src/LionOption.js
@@ -121,7 +121,7 @@ export class LionOption extends DisabledMixin(ChoiceInputMixin(FormRegisteringMi
if (this.disabled) {
return;
}
- const parentForm = /** @type {unknown} */ (this.__parentFormGroup);
+ const parentForm = /** @type {unknown} */ (this._parentFormGroup);
this.__isHandlingUserInput = true;
if (parentForm && /** @type {ChoiceGroupHost} */ (parentForm).multipleChoice) {
this.checked = !this.checked;
diff --git a/packages/listbox/types/LionOption.d.ts b/packages/listbox/types/LionOption.d.ts
index b36816f2e..22c454d67 100644
--- a/packages/listbox/types/LionOption.d.ts
+++ b/packages/listbox/types/LionOption.d.ts
@@ -2,5 +2,5 @@ import { ChoiceGroupHost } from '@lion/form-core/types/choice-group/ChoiceGroupM
export declare class LionOptionHost {
constructor(...args: any[]);
- private __parentFormGroup: ChoiceGroupHost;
+ protected _parentFormGroup: ChoiceGroupHost;
}
diff --git a/packages/switch/src/LionSwitch.js b/packages/switch/src/LionSwitch.js
index ce44ce644..89bcddfdf 100644
--- a/packages/switch/src/LionSwitch.js
+++ b/packages/switch/src/LionSwitch.js
@@ -80,7 +80,7 @@ export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField))
this._inputNode.addEventListener('checked-changed', this.__handleButtonSwitchCheckedChanged);
}
if (this._labelNode) {
- this._labelNode.addEventListener('click', this.__toggleChecked);
+ this._labelNode.addEventListener('click', this._toggleChecked);
}
this._syncButtonSwitch();
this.submitted = true;
@@ -94,7 +94,7 @@ export class LionSwitch extends ScopedElementsMixin(ChoiceInputMixin(LionField))
);
}
if (this._labelNode) {
- this._labelNode.removeEventListener('click', this.__toggleChecked);
+ this._labelNode.removeEventListener('click', this._toggleChecked);
}
}
diff --git a/packages/switch/src/LionSwitchButton.js b/packages/switch/src/LionSwitchButton.js
index ab74c1d65..d6ddacd1d 100644
--- a/packages/switch/src/LionSwitchButton.js
+++ b/packages/switch/src/LionSwitchButton.js
@@ -77,7 +77,7 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
this.role = 'switch';
this.checked = false;
- this.__toggleChecked = this.__toggleChecked.bind(this);
+ this._toggleChecked = this._toggleChecked.bind(this);
this.__handleKeydown = this.__handleKeydown.bind(this);
this.__handleKeyup = this.__handleKeyup.bind(this);
}
@@ -85,19 +85,19 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
connectedCallback() {
super.connectedCallback();
this.setAttribute('aria-checked', `${this.checked}`);
- this.addEventListener('click', this.__toggleChecked);
+ this.addEventListener('click', this._toggleChecked);
this.addEventListener('keydown', this.__handleKeydown);
this.addEventListener('keyup', this.__handleKeyup);
}
disconnectedCallback() {
super.disconnectedCallback();
- this.removeEventListener('click', this.__toggleChecked);
+ this.removeEventListener('click', this._toggleChecked);
this.removeEventListener('keydown', this.__handleKeydown);
this.removeEventListener('keyup', this.__handleKeyup);
}
- __toggleChecked() {
+ _toggleChecked() {
if (this.disabled) {
return;
}
@@ -132,7 +132,7 @@ export class LionSwitchButton extends DisabledWithTabIndexMixin(LitElement) {
*/
__handleKeyup(e) {
if ([32 /* space */, 13 /* enter */].indexOf(e.keyCode) !== -1) {
- this.__toggleChecked();
+ this._toggleChecked();
}
}