fix(form-core): type enhancements
This commit is contained in:
parent
0ec72ac330
commit
b83ef4eeeb
10 changed files with 84 additions and 40 deletions
|
|
@ -1,7 +0,0 @@
|
||||||
---
|
|
||||||
'@lion/button': patch
|
|
||||||
'@lion/overlays': patch
|
|
||||||
'@lion/tooltip': patch
|
|
||||||
---
|
|
||||||
|
|
||||||
Types for overlays, tooltip, button
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
---
|
|
||||||
'@lion/core': minor
|
|
||||||
---
|
|
||||||
|
|
||||||
EventTargetShim
|
|
||||||
|
|
||||||
#### Features
|
|
||||||
|
|
||||||
EventTargetShim is a base class that works like EventTarget, on all browsers.
|
|
||||||
|
|
@ -40,11 +40,26 @@ const FormControlMixinImplementation = superclass =>
|
||||||
reflect: true,
|
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...
|
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: {
|
helpText: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { InteractionStateMixin } from '../InteractionStateMixin.js';
|
||||||
* @typedef {import('../../types/FormControlMixinTypes').FormControlHost} FormControlHost
|
* @typedef {import('../../types/FormControlMixinTypes').FormControlHost} FormControlHost
|
||||||
* @typedef {import('../../types/registration/FormRegistrarMixinTypes').ElementWithParentFormGroup} ElementWithParentFormGroup
|
* @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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -14,6 +15,7 @@ import { InteractionStateMixin } from '../InteractionStateMixin.js';
|
||||||
* @param {import('@open-wc/dedupe-mixin').Constructor<import('@lion/core').LitElement>} superclass
|
* @param {import('@open-wc/dedupe-mixin').Constructor<import('@lion/core').LitElement>} superclass
|
||||||
*/
|
*/
|
||||||
const ChoiceGroupMixinImplementation = superclass =>
|
const ChoiceGroupMixinImplementation = superclass =>
|
||||||
|
// @ts-expect-error
|
||||||
class ChoiceGroupMixin extends FormRegistrarMixin(InteractionStateMixin(superclass)) {
|
class ChoiceGroupMixin extends FormRegistrarMixin(InteractionStateMixin(superclass)) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -32,25 +34,27 @@ const ChoiceGroupMixinImplementation = superclass =>
|
||||||
get modelValue() {
|
get modelValue() {
|
||||||
const elems = this._getCheckedElements();
|
const elems = this._getCheckedElements();
|
||||||
if (this.multipleChoice) {
|
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) {
|
set modelValue(value) {
|
||||||
/**
|
/**
|
||||||
* @param {{ modelValue: { value: any; }; }} el
|
* @param {ChoiceInputHost} el
|
||||||
* @param {any} val
|
* @param {any} val
|
||||||
*/
|
*/
|
||||||
const checkCondition = (el, val) => el.modelValue.value === val;
|
const checkCondition = (el, val) => el.choiceValue === val;
|
||||||
|
|
||||||
if (this.__isInitialModelValue) {
|
if (this.__isInitialModelValue) {
|
||||||
this.__isInitialModelValue = false;
|
this.__isInitialModelValue = false;
|
||||||
this.registrationComplete.then(() => {
|
this.registrationComplete.then(() => {
|
||||||
this._setCheckedElements(value, checkCondition);
|
this._setCheckedElements(value, checkCondition);
|
||||||
});
|
});
|
||||||
|
this.requestUpdate('modelValue');
|
||||||
} else {
|
} else {
|
||||||
this._setCheckedElements(value, checkCondition);
|
this._setCheckedElements(value, checkCondition);
|
||||||
|
this.requestUpdate('modelValue');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,7 +76,7 @@ const ChoiceGroupMixinImplementation = superclass =>
|
||||||
|
|
||||||
set serializedValue(value) {
|
set serializedValue(value) {
|
||||||
/**
|
/**
|
||||||
* @param {{ serializedValue: { value: any; }; }} el
|
* @param {ChoiceInputHost} el
|
||||||
* @param {string} val
|
* @param {string} val
|
||||||
*/
|
*/
|
||||||
const checkCondition = (el, val) => el.serializedValue.value === val;
|
const checkCondition = (el, val) => el.serializedValue.value === val;
|
||||||
|
|
@ -81,9 +85,11 @@ const ChoiceGroupMixinImplementation = superclass =>
|
||||||
this.__isInitialSerializedValue = false;
|
this.__isInitialSerializedValue = false;
|
||||||
this.registrationComplete.then(() => {
|
this.registrationComplete.then(() => {
|
||||||
this._setCheckedElements(value, checkCondition);
|
this._setCheckedElements(value, checkCondition);
|
||||||
|
this.requestUpdate('serializedValue');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this._setCheckedElements(value, checkCondition);
|
this._setCheckedElements(value, checkCondition);
|
||||||
|
this.requestUpdate('serializedValue');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,6 @@ import { FormatMixin } from '../FormatMixin.js';
|
||||||
/**
|
/**
|
||||||
* @typedef {import('../../types/FormControlMixinTypes').FormControlHost} FormControlHost
|
* @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').ChoiceInputMixin} ChoiceInputMixin
|
||||||
* @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputModelValue} ChoiceInputModelValue
|
* @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputModelValue} ChoiceInputModelValue
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ function arrayDiff(array1 = [], array2 = []) {
|
||||||
* @param {import('@open-wc/dedupe-mixin').Constructor<import('@lion/core').LitElement>} superclass
|
* @param {import('@open-wc/dedupe-mixin').Constructor<import('@lion/core').LitElement>} superclass
|
||||||
*/
|
*/
|
||||||
export const ValidateMixinImplementation = superclass =>
|
export const ValidateMixinImplementation = superclass =>
|
||||||
// eslint-disable-next-line no-unused-vars, no-shadow
|
|
||||||
class extends FormControlMixin(
|
class extends FormControlMixin(
|
||||||
SyncUpdatableMixin(DisabledMixin(SlotMixin(ScopedElementsMixin(superclass)))),
|
SyncUpdatableMixin(DisabledMixin(SlotMixin(ScopedElementsMixin(superclass)))),
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,6 @@ import { ChoiceInputMixin } from '../../src/choice-group/ChoiceInputMixin.js';
|
||||||
* @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputHost} ChoiceInputHost
|
* @typedef {import('../../types/choice-group/ChoiceInputMixinTypes').ChoiceInputHost} ChoiceInputHost
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// class InputField extends LionField {
|
|
||||||
// get slots() {
|
|
||||||
// return {
|
|
||||||
// ...super.slots,
|
|
||||||
// input: () => document.createElement('input'),
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
describe('ChoiceInputMixin', () => {
|
describe('ChoiceInputMixin', () => {
|
||||||
/** @typedef {Element & ChoiceClass} ChoiceInput */
|
/** @typedef {Element & ChoiceClass} ChoiceInput */
|
||||||
class ChoiceClass extends ChoiceInputMixin(LionInput) {
|
class ChoiceClass extends ChoiceInputMixin(LionInput) {
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,45 @@ import { FormRegisteringHost } from './registration/FormRegisteringMixinTypes';
|
||||||
|
|
||||||
export class FormControlHost {
|
export class FormControlHost {
|
||||||
static get styles(): CSSResult | CSSResult[];
|
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;
|
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;
|
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;
|
get label(): string;
|
||||||
|
set label(arg: string);
|
||||||
__label: string | undefined;
|
__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;
|
get helpText(): string;
|
||||||
|
set helpText(arg: string);
|
||||||
__helpText: string | undefined;
|
__helpText: string | undefined;
|
||||||
set fieldName(arg: string);
|
set fieldName(arg: string);
|
||||||
get fieldName(): string;
|
get fieldName(): string;
|
||||||
|
|
@ -28,7 +59,20 @@ export class FormControlHost {
|
||||||
_inputId: string;
|
_inputId: string;
|
||||||
_ariaLabelledNodes: HTMLElement[];
|
_ariaLabelledNodes: HTMLElement[];
|
||||||
_ariaDescribedNodes: 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;
|
_isRepropagationEndpoint: boolean;
|
||||||
|
|
||||||
connectedCallback(): void;
|
connectedCallback(): void;
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,15 @@ export interface ChoiceInputModelValue {
|
||||||
value: any;
|
value: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** TODO: legacy code: serialization should happen on choice-group level */
|
||||||
|
export interface ChoiceInputSerializedValue {
|
||||||
|
checked: boolean;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
export declare class ChoiceInputHost {
|
export declare class ChoiceInputHost {
|
||||||
modelValue: ChoiceInputModelValue;
|
modelValue: ChoiceInputModelValue;
|
||||||
|
serializedValue: ChoiceInputSerializedValue;
|
||||||
|
|
||||||
get choiceValue(): any;
|
get choiceValue(): any;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { Constructor } from '@open-wc/dedupe-mixin';
|
||||||
import { LitElement } from '@lion/core';
|
import { LitElement } from '@lion/core';
|
||||||
|
|
||||||
export declare class FormRegistrarPortalHost {
|
export declare class FormRegistrarPortalHost {
|
||||||
|
registrationTarget: HTMLElement;
|
||||||
__redispatchEventForFormRegistrarPortalMixin(ev: CustomEvent): void;
|
__redispatchEventForFormRegistrarPortalMixin(ev: CustomEvent): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue