Skip to content

Commit

Permalink
feat(form-core): member descriptions for editors and api tables
Browse files Browse the repository at this point in the history
  • Loading branch information
tlouisse committed May 1, 2021
1 parent 099ed2a commit 0ca4440
Show file tree
Hide file tree
Showing 34 changed files with 904 additions and 197 deletions.
9 changes: 9 additions & 0 deletions .changeset/selfish-ears-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@lion/form-core': minor
'@lion/input-range': minor
'@lion/listbox': minor
'@lion/radio-group': minor
'@lion/select': minor
---

member descriptions for editors and api tables
4 changes: 3 additions & 1 deletion packages/form-core/src/FocusMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,18 @@ const FocusMixinImplementation = superclass =>

constructor() {
super();

/**
* Whether the focusable element within (`._focusableNode`) is focused.
* Reflects to attribute '[focused]' as a styling hook
* @type {boolean}
*/
this.focused = false;

/**
* Whether the focusable element within (`._focusableNode`) matches ':focus-visible'
* Reflects to attribute '[focused-visible]' as a styling hook
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible
* See: https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible
* @type {boolean}
*/
this.focusedVisible = false;
Expand Down
37 changes: 28 additions & 9 deletions packages/form-core/src/FormControlMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ const FormControlMixinImplementation = superclass =>
}

/**
* @return {string}
* The label text for the input node.
* When no light dom defined via [slot=label], this value will be used.
* @type {string}
*/
get label() {
return this.__label || (this._labelNode && this._labelNode.textContent) || '';
Expand All @@ -70,7 +72,9 @@ const FormControlMixinImplementation = superclass =>
}

/**
* @return {string}
* The helpt text for the input node.
* When no light dom defined via [slot=help-text], this value will be used
* @type {string}
*/
get helpText() {
return this.__helpText || (this._helpTextNode && this._helpTextNode.textContent) || '';
Expand All @@ -88,7 +92,7 @@ const FormControlMixinImplementation = superclass =>

/**
* Will be used in validation messages to refer to the current field
* @return {string}
* @type {string}
*/
get fieldName() {
return this.__fieldName || this.label || this.name || '';
Expand Down Expand Up @@ -156,12 +160,15 @@ const FormControlMixinImplementation = superclass =>

constructor() {
super();

/**
* The name the element will be registered on to the .formElements collection
* of the parent.
* The name the element will be registered with to the .formElements collection
* of the parent. Also, it serves as the key of key/value pairs in
* modelValue/serializedValue objects
* @type {string}
*/
this.name = '';

/**
* 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
Expand All @@ -171,18 +178,21 @@ const FormControlMixinImplementation = superclass =>
* @type {boolean}
*/
this.readOnly = false;

/**
* The label text for the input node.
* When no value is defined, textContent of [slot=label] will be used
* @type {string}
*/
this.label = '';

/**
* The helpt text for the input node.
* When no value is defined, textContent of [slot=help-text] will be used
* @type {string}
*/
this.helpText = '';

/**
* 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.
Expand All @@ -203,21 +213,25 @@ const FormControlMixinImplementation = superclass =>
* @protected
*/
this._inputId = uuid(this.localName);

/**
* Contains all elements that should end up in aria-labelledby of `._inputNode`
* @type {HTMLElement[]}
*/
this._ariaLabelledNodes = [];

/**
* Contains all elements that should end up in aria-describedby of `._inputNode`
* @type {HTMLElement[]}
*/
this._ariaDescribedNodes = [];

/**
* Based on the role, details of handling model-value-changed repropagation differ.
* @type {'child'|'choice-group'|'fieldset'}
*/
this._repropagationRole = 'child';

/**
* By default, a field with _repropagationRole 'choice-group' will act as an
* 'endpoint'. This means it will be considered as an individual field: for
Expand All @@ -230,6 +244,7 @@ const FormControlMixinImplementation = superclass =>
* @type {boolean}
*/
this._isRepropagationEndpoint = false;

this.addEventListener(
'model-value-changed',
/** @type {EventListenerOrEventListenerObject} */ (this.__repropagateChildrenValues),
Expand Down Expand Up @@ -286,6 +301,7 @@ const FormControlMixinImplementation = superclass =>

if (changedProperties.has('name')) {
this.dispatchEvent(
/** @privateEvent */
new CustomEvent('form-element-name-changed', {
detail: { oldName: changedProperties.get('name'), newName: this.name },
bubbles: true,
Expand Down Expand Up @@ -563,6 +579,7 @@ const FormControlMixinImplementation = superclass =>
}

/**
* Used for Required validation and computation of interaction states
* @param {any} modelValue
* @return {boolean}
* @protected
Expand Down Expand Up @@ -725,7 +742,7 @@ const FormControlMixinImplementation = superclass =>
}

/**
* Meant for Application Developers wanting to add to aria-labelledby attribute.
* Allows to add extra element references to aria-labelledby attribute.
* @param {HTMLElement} element
* @param {{idPrefix?:string; reorder?: boolean}} customConfig
*/
Expand All @@ -741,7 +758,7 @@ const FormControlMixinImplementation = superclass =>
}

/**
* Meant for Application Developers wanting to delete from aria-labelledby attribute.
* Allows to remove element references from aria-labelledby attribute.
* @param {HTMLElement} element
*/
removeFromAriaLabelledBy(element) {
Expand All @@ -756,7 +773,7 @@ const FormControlMixinImplementation = superclass =>
}

/**
* Meant for Application Developers wanting to add to aria-describedby attribute.
* Allows to add element references to aria-describedby attribute.
* @param {HTMLElement} element
* @param {{idPrefix?:string; reorder?: boolean}} customConfig
*/
Expand All @@ -772,7 +789,7 @@ const FormControlMixinImplementation = superclass =>
}

/**
* Meant for Application Developers wanting to delete from aria-describedby attribute.
* Allows to remove element references from aria-describedby attribute.
* @param {HTMLElement} element
*/
removeFromAriaDescribedBy(element) {
Expand Down Expand Up @@ -822,6 +839,8 @@ const FormControlMixinImplementation = superclass =>
}

/**
* Hook for Subclassers to add logic before repropagation
* @configurable
* @param {CustomEvent} ev
* @protected
*/
Expand Down
55 changes: 36 additions & 19 deletions packages/form-core/src/FormatMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const FormatMixinImplementation = superclass =>
* @example
* ```js
* preprocessor(viewValue) {
* // only use
* // only use digits
* return viewValue.replace(/\D/g, '');
* }
* ```
Expand All @@ -123,9 +123,9 @@ const FormatMixinImplementation = superclass =>
}

/**
* Converts formattedValue to modelValue
* Converts viewValue to modelValue
* For instance, a localized date to a Date Object
* @param {string} v - formattedValue: the formatted value inside <input>
* @param {string} v - viewValue: the formatted value inside <input>
* @param {FormatOptions} opts
* @returns {*} modelValue
*/
Expand Down Expand Up @@ -160,7 +160,7 @@ const FormatMixinImplementation = superclass =>
}

/**
* Converts `LionField.value` to `.modelValue`
* Converts `.serializedValue` to `.modelValue`
* For instance, an iso formatted date string to a Date object
* @param {?} v - modelValue: can be an Object, Number, String depending on the
* input type(date, number, email etc)
Expand Down Expand Up @@ -281,7 +281,6 @@ const FormatMixinImplementation = superclass =>
}

/**
* Observer Handlers
* @param {{ modelValue: unknown; }[]} args
* @protected
*/
Expand All @@ -291,9 +290,9 @@ const FormatMixinImplementation = superclass =>
}

/**
* @param {{ modelValue: unknown; }[]} args
* This is wrapped in a distinct method, so that parents can control when the changed event
* is fired. For objects, a deep comparison might be needed.
* @param {{ modelValue: unknown; }[]} args
* @protected
*/
// eslint-disable-next-line no-unused-vars
Expand Down Expand Up @@ -370,12 +369,7 @@ const FormatMixinImplementation = superclass =>
_proxyInputEvent() {
// TODO: [v1] remove composed (and bubbles as well if possible)
/** @protectedEvent user-input-changed meant for usage by Subclassers only */
this.dispatchEvent(
new Event('user-input-changed', {
bubbles: true,
composed: true,
}),
);
this.dispatchEvent(new Event('user-input-changed', { bubbles: true }));
}

/** @protected */
Expand All @@ -402,6 +396,7 @@ const FormatMixinImplementation = superclass =>

constructor() {
super();

// TODO: [v1] delete; use 'change' event directly within this file
/**
* Event that will trigger formatting (more precise, visual update of the view, so the
Expand All @@ -411,10 +406,12 @@ const FormatMixinImplementation = superclass =>
* @protected
*/
this.formatOn = 'change';

/**
* Configuration object that will be available inside the formatter function
*/
this.formatOptions = /** @type {FormatOptions} */ ({});

/**
* The view value is the result of the formatter function (when available).
* The result will be stored in the native _inputNode (usually an input[type=text]).
Expand All @@ -424,8 +421,10 @@ const FormatMixinImplementation = superclass =>
* - For a number input, this could be '1,234.56' (a String representation of modelValue
* 1234.56)
* @type {string|undefined}
* @readOnly
*/
this.formattedValue = undefined;

/**
* The serialized version of the model value.
* This value exists for maximal compatibility with the platform API.
Expand All @@ -442,6 +441,7 @@ const FormatMixinImplementation = superclass =>
* @type {string|undefined}
*/
this.serializedValue = undefined;

/**
* Whether the user is pasting content. Allows Subclassers to do this in their subclass:
* @example
Expand All @@ -451,8 +451,18 @@ const FormatMixinImplementation = superclass =>
* }
* ```
* @protected
* @type {boolean}
*/
this._isPasting = false;

/**
* Flag that will be set when user interaction takes place (for instance after an 'input'
* event). Will be added as meta info to the `model-value-changed` event. Depending on
* whether a user is interacting, formatting logic will be handled differently.
* @protected
* @type {boolean}
*/
this._isHandlingUserInput = false;
/**
* @private
* @type {string}
Expand All @@ -463,6 +473,20 @@ const FormatMixinImplementation = superclass =>
this.addEventListener('user-input-changed', this._onUserInputChanged);
// This sets the formatted viewValue after paste
this.addEventListener('paste', this.__onPaste);

/**
* @protected
*/
this._reflectBackFormattedValueToUser = this._reflectBackFormattedValueToUser.bind(this);

/**
* @private
*/
this._reflectBackFormattedValueDebounced = () => {
// Make sure this is fired after the change event of _inputNode, so that formattedValue
// is guaranteed to be calculated
setTimeout(this._reflectBackFormattedValueToUser);
};
}

__onPaste() {
Expand All @@ -476,13 +500,6 @@ const FormatMixinImplementation = superclass =>

connectedCallback() {
super.connectedCallback();
this._reflectBackFormattedValueToUser = this._reflectBackFormattedValueToUser.bind(this);

this._reflectBackFormattedValueDebounced = () => {
// Make sure this is fired after the change event of _inputNode, so that formattedValue
// is guaranteed to be calculated
setTimeout(this._reflectBackFormattedValueToUser);
};

// Connect the value found in <input> to the formatting/parsing/serializing loop as a
// fallback mechanism. Assume the user uses the value property of the
Expand Down
Loading

0 comments on commit 0ca4440

Please sign in to comment.