diff --git a/.changeset/mighty-fans-retire.md b/.changeset/mighty-fans-retire.md deleted file mode 100644 index a71832f0f..000000000 --- a/.changeset/mighty-fans-retire.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@lion/button': patch -'@lion/overlays': patch -'@lion/tooltip': patch ---- - -Types for overlays, tooltip, button diff --git a/.changeset/witty-paws-care.md b/.changeset/witty-paws-care.md deleted file mode 100644 index e00b1c7ed..000000000 --- a/.changeset/witty-paws-care.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@lion/core': minor ---- - -EventTargetShim - -#### Features - -EventTargetShim is a base class that works like EventTarget, on all browsers. diff --git a/packages/form-core/src/FormControlMixin.js b/packages/form-core/src/FormControlMixin.js index fde787992..0ef37f189 100644 --- a/packages/form-core/src/FormControlMixin.js +++ b/packages/form-core/src/FormControlMixin.js @@ -40,11 +40,26 @@ const FormControlMixinImplementation = superclass => reflect: true, }, /** - * When no light dom defined and prop set + * A Boolean attribute which, if present, indicates that the user should not be able to edit + * the value of the input. The difference between disabled and readonly is that read-only + * controls can still function, whereas disabled controls generally do not function as + * controls until they are enabled. + * + * (From: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-readonly) + */ + readOnly: { + type: Boolean, + attribute: 'readonly', + reflect: true, + }, + /** + * The label text for the input node. + * When no light dom defined via [slot=label], this value will be used */ label: String, // FIXME: { attribute: false } breaks a bunch of tests, but shouldn't... /** - * When no light dom defined and prop set + * The helpt text for the input node. + * When no light dom defined via [slot=help-text], this value will be used */ helpText: { type: String, diff --git a/packages/form-core/src/choice-group/ChoiceGroupMixin.js b/packages/form-core/src/choice-group/ChoiceGroupMixin.js index 4d1e6fb7d..597aba16f 100644 --- a/packages/form-core/src/choice-group/ChoiceGroupMixin.js +++ b/packages/form-core/src/choice-group/ChoiceGroupMixin.js @@ -7,6 +7,7 @@ import { InteractionStateMixin } from '../InteractionStateMixin.js'; * @typedef {import('../../types/FormControlMixinTypes').FormControlHost} FormControlHost * @typedef {import('../../types/registration/FormRegistrarMixinTypes').ElementWithParentFormGroup} ElementWithParentFormGroup * @typedef {FormControlHost & HTMLElement & {__parentFormGroup?:HTMLElement, checked?:boolean}} FormControl + * @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputHost} ChoiceInputHost */ /** @@ -14,6 +15,7 @@ import { InteractionStateMixin } from '../InteractionStateMixin.js'; * @param {import('@open-wc/dedupe-mixin').Constructor} superclass */ const ChoiceGroupMixinImplementation = superclass => + // @ts-expect-error class ChoiceGroupMixin extends FormRegistrarMixin(InteractionStateMixin(superclass)) { static get properties() { return { @@ -32,25 +34,27 @@ const ChoiceGroupMixinImplementation = superclass => get modelValue() { const elems = this._getCheckedElements(); if (this.multipleChoice) { - return elems.map(el => el.modelValue.value); + return elems.map(el => el.choiceValue); } - return elems[0] ? elems[0].modelValue.value : ''; + return elems[0] ? elems[0].choiceValue : ''; } set modelValue(value) { /** - * @param {{ modelValue: { value: any; }; }} el + * @param {ChoiceInputHost} el * @param {any} val */ - const checkCondition = (el, val) => el.modelValue.value === val; + const checkCondition = (el, val) => el.choiceValue === val; if (this.__isInitialModelValue) { this.__isInitialModelValue = false; this.registrationComplete.then(() => { this._setCheckedElements(value, checkCondition); }); + this.requestUpdate('modelValue'); } else { this._setCheckedElements(value, checkCondition); + this.requestUpdate('modelValue'); } } @@ -72,7 +76,7 @@ const ChoiceGroupMixinImplementation = superclass => set serializedValue(value) { /** - * @param {{ serializedValue: { value: any; }; }} el + * @param {ChoiceInputHost} el * @param {string} val */ const checkCondition = (el, val) => el.serializedValue.value === val; @@ -81,9 +85,11 @@ const ChoiceGroupMixinImplementation = superclass => this.__isInitialSerializedValue = false; this.registrationComplete.then(() => { this._setCheckedElements(value, checkCondition); + this.requestUpdate('serializedValue'); }); } else { this._setCheckedElements(value, checkCondition); + this.requestUpdate('serializedValue'); } } diff --git a/packages/form-core/src/choice-group/ChoiceInputMixin.js b/packages/form-core/src/choice-group/ChoiceInputMixin.js index 6bdc79f99..a527eb00e 100644 --- a/packages/form-core/src/choice-group/ChoiceInputMixin.js +++ b/packages/form-core/src/choice-group/ChoiceInputMixin.js @@ -6,9 +6,6 @@ import { FormatMixin } from '../FormatMixin.js'; /** * @typedef {import('../../types/FormControlMixinTypes').FormControlHost} FormControlHost * @typedef {FormControlHost & HTMLElement & {__parentFormGroup?:HTMLElement, checked?:boolean}} FormControl - */ - -/** * @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputMixin} ChoiceInputMixin * @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputModelValue} ChoiceInputModelValue */ diff --git a/packages/form-core/src/validate/ValidateMixin.js b/packages/form-core/src/validate/ValidateMixin.js index ca7516b3a..4f1dee4d7 100644 --- a/packages/form-core/src/validate/ValidateMixin.js +++ b/packages/form-core/src/validate/ValidateMixin.js @@ -32,7 +32,6 @@ function arrayDiff(array1 = [], array2 = []) { * @param {import('@open-wc/dedupe-mixin').Constructor} superclass */ export const ValidateMixinImplementation = superclass => - // eslint-disable-next-line no-unused-vars, no-shadow class extends FormControlMixin( SyncUpdatableMixin(DisabledMixin(SlotMixin(ScopedElementsMixin(superclass)))), ) { diff --git a/packages/form-core/test/choice-group/ChoiceInputMixin.test.js b/packages/form-core/test/choice-group/ChoiceInputMixin.test.js index 54464ac96..6ec5aae29 100644 --- a/packages/form-core/test/choice-group/ChoiceInputMixin.test.js +++ b/packages/form-core/test/choice-group/ChoiceInputMixin.test.js @@ -10,15 +10,6 @@ import { ChoiceInputMixin } from '../../src/choice-group/ChoiceInputMixin.js'; * @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputHost} ChoiceInputHost */ -// class InputField extends LionField { -// get slots() { -// return { -// ...super.slots, -// input: () => document.createElement('input'), -// }; -// } -// } - describe('ChoiceInputMixin', () => { /** @typedef {Element & ChoiceClass} ChoiceInput */ class ChoiceClass extends ChoiceInputMixin(LionInput) { diff --git a/packages/form-core/types/FormControlMixinTypes.d.ts b/packages/form-core/types/FormControlMixinTypes.d.ts index d11ebf644..0c2bd205f 100644 --- a/packages/form-core/types/FormControlMixinTypes.d.ts +++ b/packages/form-core/types/FormControlMixinTypes.d.ts @@ -8,14 +8,45 @@ import { FormRegisteringHost } from './registration/FormRegisteringMixinTypes'; export class FormControlHost { static get styles(): CSSResult | CSSResult[]; - + /** + * A Boolean attribute which, if present, indicates that the user should not be able to edit + * the value of the input. The difference between disabled and readonly is that read-only + * controls can still function, whereas disabled controls generally do not function as + * controls until they are enabled. + * (From: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-readonly) + */ + readOnly: boolean; + /** + * The name the element will be registered on to the .formElements collection + * of the parent. + */ name: string; + /** + * The model value is the result of the parser function(when available). + * It should be considered as the internal value used for validation and reasoning/logic. + * The model value is 'ready for consumption' by the outside world (think of a Date + * object or a float). The modelValue can(and is recommended to) be used as both input + * value and output value of the `LionField`. + * + * Examples: + * - For a date input: a String '20/01/1999' will be converted to new Date('1999/01/20') + * - For a number input: a formatted String '1.234,56' will be converted to a Number: + * 1234.56 + */ modelValue: unknown; - set label(arg: string); + /** + * The label text for the input node. + * When no light dom defined via [slot=label], this value will be used + */ get label(): string; + set label(arg: string); __label: string | undefined; - set helpText(arg: string); + /** + * The helpt text for the input node. + * When no light dom defined via [slot=help-text], this value will be used + */ get helpText(): string; + set helpText(arg: string); __helpText: string | undefined; set fieldName(arg: string); get fieldName(): string; @@ -28,7 +59,20 @@ export class FormControlHost { _inputId: string; _ariaLabelledNodes: HTMLElement[]; _ariaDescribedNodes: HTMLElement[]; - _repropagationRole: string; // 'child' | 'choice-group' | 'fieldset'; + /** + * Based on the role, details of handling model-value-changed repropagation differ. + */ + _repropagationRole: 'child' | 'choice-group' | 'fieldset'; + /** + * By default, a field with _repropagationRole 'choice-group' will act as an + * 'endpoint'. This means it will be considered as an individual field: for + * a select, individual options will not be part of the formPath. They + * will. + * Similarly, components that (a11y wise) need to be fieldsets, but 'interaction wise' + * (from Application Developer perspective) need to be more like fields + * (think of an amount-input with a currency select box next to it), can set this + * to true to hide private internals in the formPath. + */ _isRepropagationEndpoint: boolean; connectedCallback(): void; diff --git a/packages/form-core/types/choice-group/ChoiceInputMixinTypes.d.ts b/packages/form-core/types/choice-group/ChoiceInputMixinTypes.d.ts index bd9850476..d895cb95a 100644 --- a/packages/form-core/types/choice-group/ChoiceInputMixinTypes.d.ts +++ b/packages/form-core/types/choice-group/ChoiceInputMixinTypes.d.ts @@ -7,8 +7,15 @@ export interface ChoiceInputModelValue { value: any; } +/** TODO: legacy code: serialization should happen on choice-group level */ +export interface ChoiceInputSerializedValue { + checked: boolean; + value: string; +} + export declare class ChoiceInputHost { modelValue: ChoiceInputModelValue; + serializedValue: ChoiceInputSerializedValue; get choiceValue(): any; diff --git a/packages/form-core/types/registration/FormRegistrarPortalMixinTypes.d.ts b/packages/form-core/types/registration/FormRegistrarPortalMixinTypes.d.ts index 1b690df7d..a53d49986 100644 --- a/packages/form-core/types/registration/FormRegistrarPortalMixinTypes.d.ts +++ b/packages/form-core/types/registration/FormRegistrarPortalMixinTypes.d.ts @@ -2,6 +2,7 @@ import { Constructor } from '@open-wc/dedupe-mixin'; import { LitElement } from '@lion/core'; export declare class FormRegistrarPortalHost { + registrationTarget: HTMLElement; __redispatchEventForFormRegistrarPortalMixin(ev: CustomEvent): void; }