Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@vaadin/form-layout

Package Overview
Dependencies
Maintainers
19
Versions
409
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vaadin/form-layout - npm Package Compare versions

Comparing version 23.0.0-alpha1 to 23.0.0-alpha2

15

package.json
{
"name": "@vaadin/form-layout",
"version": "23.0.0-alpha1",
"version": "23.0.0-alpha2",
"publishConfig": {

@@ -37,14 +37,15 @@ "access": "public"

"@polymer/polymer": "^3.0.0",
"@vaadin/component-base": "23.0.0-alpha1",
"@vaadin/vaadin-lumo-styles": "23.0.0-alpha1",
"@vaadin/vaadin-material-styles": "23.0.0-alpha1",
"@vaadin/vaadin-themable-mixin": "23.0.0-alpha1"
"@vaadin/component-base": "23.0.0-alpha2",
"@vaadin/vaadin-lumo-styles": "23.0.0-alpha2",
"@vaadin/vaadin-material-styles": "23.0.0-alpha2",
"@vaadin/vaadin-themable-mixin": "23.0.0-alpha2"
},
"devDependencies": {
"@esm-bundle/chai": "^4.3.4",
"@vaadin/custom-field": "23.0.0-alpha2",
"@vaadin/testing-helpers": "^0.3.2",
"@vaadin/text-field": "23.0.0-alpha1",
"@vaadin/text-field": "23.0.0-alpha2",
"sinon": "^9.2.1"
},
"gitHead": "fbcb07328fdf88260e3b461088d207426b21c710"
"gitHead": "070f586dead02ca41b66717820c647f48bf1665f"
}

@@ -100,3 +100,12 @@ /**

*/
declare class FormItem extends ThemableMixin(HTMLElement) {}
declare class FormItem extends ThemableMixin(HTMLElement) {
/**
* Returns a target element to add ARIA attributes to for a field.
*
* - For Vaadin field components, the method returns an element
* obtained through the `ariaTarget` property defined in `FieldMixin`.
* - In other cases, the method returns the field element itself.
*/
protected _getFieldAriaTarget(field: HTMLElement): HTMLElement;
}

@@ -103,0 +112,0 @@ declare global {

@@ -7,2 +7,3 @@ /**

import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
import { addValueToAttribute, removeValueFromAttribute } from '@vaadin/field-base/src/utils.js';
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';

@@ -149,4 +150,4 @@

</style>
<div id="label" part="label" on-click="_onLabelClick">
<slot name="label" id="labelSlot"></slot>
<div id="label" part="label" on-click="__onLabelClick">
<slot name="label" id="labelSlot" on-slotchange="__onLabelSlotChange"></slot>
<span part="required-indicator" aria-hidden="true"></span>

@@ -168,11 +169,76 @@ </div>

this.__updateInvalidState = this.__updateInvalidState.bind(this);
this.__contentFieldObserver = new MutationObserver(() => this.__updateRequiredState(this.__contentField.required));
/**
* An observer for a field node to reflect its `required` and `invalid` attributes to the component.
*
* @type {MutationObserver}
* @private
*/
this.__fieldNodeObserver = new MutationObserver(() => this.__updateRequiredState(this.__fieldNode.required));
/**
* The first label node in the label slot.
*
* @type {HTMLElement | null}
* @private
*/
this.__labelNode = null;
/**
* The first field node in the content slot.
*
* An element is considered a field when it has the `checkValidity` or `validate` method.
*
* @type {HTMLElement | null}
* @private
*/
this.__fieldNode = null;
// Ensure every instance has unique ID
const uniqueId = (FormItem._uniqueLabelId = 1 + FormItem._uniqueLabelId || 0);
this.__labelId = `label-${this.localName}-${uniqueId}`;
}
/**
* Returns a target element to add ARIA attributes to for a field.
*
* - For Vaadin field components, the method returns an element
* obtained through the `ariaTarget` property defined in `FieldMixin`.
* - In other cases, the method returns the field element itself.
*
* @param {HTMLElement} field
* @protected
*/
_getFieldAriaTarget(field) {
return field.ariaTarget || field;
}
/**
* Links the label to a field by adding the label id to
* the `aria-labelledby` attribute of the field's ARIA target element.
*
* @param {HTMLElement} field
* @private
*/
__linkLabelToField(field) {
addValueToAttribute(this._getFieldAriaTarget(field), 'aria-labelledby', this.__labelId);
}
/**
* Unlinks the label from a field by removing the label id from
* the `aria-labelledby` attribute of the field's ARIA target element.
*
* @param {HTMLElement} field
* @private
*/
__unlinkLabelFromField(field) {
removeValueFromAttribute(this._getFieldAriaTarget(field), 'aria-labelledby', this.__labelId);
}
/** @private */
_onLabelClick() {
const firstContentElementChild = this.$.contentSlot.assignedElements()[0];
if (firstContentElementChild) {
firstContentElementChild.focus();
firstContentElementChild.click();
__onLabelClick() {
const fieldNode = this.__fieldNode;
if (fieldNode) {
fieldNode.focus();
fieldNode.click();
}

@@ -186,17 +252,62 @@ }

/** @private */
/**
* A `slotchange` event handler for the label slot.
*
* - Ensures the label id is only assigned to the first label node.
* - Ensures the label node is linked to the first field node via the `aria-labelledby` attribute
* if both nodes are provided, and unlinked otherwise.
*
* @private
*/
__onLabelSlotChange() {
if (this.__labelNode) {
this.__labelNode.id = '';
this.__labelNode = null;
if (this.__fieldNode) {
this.__unlinkLabelFromField(this.__fieldNode);
}
}
const newLabelNode = this.$.labelSlot.assignedElements()[0];
if (newLabelNode) {
this.__labelNode = newLabelNode;
this.__labelNode.id = this.__labelId;
if (this.__fieldNode) {
this.__linkLabelToField(this.__fieldNode);
}
}
}
/**
* A `slotchange` event handler for the content slot.
*
* - Ensures the label node is only linked to the first field node via the `aria-labelledby` attribute.
* - Sets up an observer for the `required` attribute changes on the first field
* to reflect the attribute on the component. Ensures the observer is disconnected from the field
* as soon as it is removed or replaced by another one.
*
* @private
*/
__onContentSlotChange() {
if (this.__contentField) {
if (this.__fieldNode) {
// Discard the old field
this.__unlinkLabelFromField(this.__fieldNode);
this.__updateRequiredState(false);
this.__contentFieldObserver.disconnect();
delete this.__contentField;
this.__fieldNodeObserver.disconnect();
this.__fieldNode = null;
}
const contentFields = this.$.contentSlot.assignedElements().filter((node) => !!this.__getValidateFunction(node));
if (contentFields.length === 1) {
// There's only one child field
this.__contentField = contentFields[0];
this.__updateRequiredState(this.__contentField.required);
this.__contentFieldObserver.observe(this.__contentField, { attributes: true, attributeFilter: ['required'] });
const newFieldNode = this.$.contentSlot.assignedElements().find((field) => {
return !!this.__getValidateFunction(field);
});
if (newFieldNode) {
this.__fieldNode = newFieldNode;
this.__updateRequiredState(this.__fieldNode.required);
this.__fieldNodeObserver.observe(this.__fieldNode, { attributes: true, attributeFilter: ['required'] });
if (this.__labelNode) {
this.__linkLabelToField(this.__fieldNode);
}
}

@@ -209,9 +320,9 @@ }

this.setAttribute('required', '');
this.__contentField.addEventListener('blur', this.__updateInvalidState);
this.__contentField.addEventListener('change', this.__updateInvalidState);
this.__fieldNode.addEventListener('blur', this.__updateInvalidState);
this.__fieldNode.addEventListener('change', this.__updateInvalidState);
} else {
this.removeAttribute('invalid');
this.removeAttribute('required');
this.__contentField.removeEventListener('blur', this.__updateInvalidState);
this.__contentField.removeEventListener('change', this.__updateInvalidState);
this.__fieldNode.removeEventListener('blur', this.__updateInvalidState);
this.__fieldNode.removeEventListener('change', this.__updateInvalidState);
}

@@ -222,6 +333,4 @@ }

__updateInvalidState() {
this.toggleAttribute(
'invalid',
this.__getValidateFunction(this.__contentField).call(this.__contentField) === false
);
const isValid = this.__getValidateFunction(this.__fieldNode).call(this.__fieldNode);
this.toggleAttribute('invalid', isValid === false);
}

@@ -228,0 +337,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc