diff --git a/packages/checkbox/src/vaadin-checkbox.js b/packages/checkbox/src/vaadin-checkbox.js
index a31a534f64..65567067ff 100644
--- a/packages/checkbox/src/vaadin-checkbox.js
+++ b/packages/checkbox/src/vaadin-checkbox.js
@@ -4,9 +4,12 @@
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { PolymerElement, html } from '@polymer/polymer/polymer-element.js';
-import { GestureEventListeners } from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
-import { ControlStateMixin } from '@vaadin/vaadin-control-state-mixin/vaadin-control-state-mixin.js';
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
+import { ActiveMixin } from '@vaadin/field-base/src/active-mixin.js';
+import { AriaLabelMixin } from '@vaadin/field-base/src/aria-label-mixin.js';
+import { CheckedMixin } from '@vaadin/field-base/src/checked-mixin.js';
+import { InputSlotMixin } from '@vaadin/field-base/src/input-slot-mixin.js';
+import { SlotLabelMixin } from '@vaadin/field-base/src/slot-label-mixin.js';
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
/**
@@ -46,12 +49,21 @@ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mix
* @fires {CustomEvent} indeterminate-changed - Fired when the `indeterminate` property changes.
*
* @extends HTMLElement
- * @mixes ElementMixin
- * @mixes ControlStateMixin
* @mixes ThemableMixin
- * @mixes GestureEventListeners
+ * @mixes ElementMixin
+ * @mixes ActiveMixin
+ * @mixes AriaLabelMixin
+ * @mixes InputSlotMixin
+ * @mixes CheckedMixin
+ * @mixes SlotLabelMixin
*/
-class CheckboxElement extends ElementMixin(ControlStateMixin(ThemableMixin(GestureEventListeners(PolymerElement)))) {
+class Checkbox extends SlotLabelMixin(
+ CheckedMixin(InputSlotMixin(AriaLabelMixin(ActiveMixin(ElementMixin(ThemableMixin(PolymerElement))))))
+) {
+ static get is() {
+ return 'vaadin-checkbox';
+ }
+
static get template() {
return html`
-
-
+
`;
}
- static get is() {
- return 'vaadin-checkbox';
- }
-
static get properties() {
return {
/**
- * True if the checkbox is checked.
- * @type {boolean}
- */
- checked: {
- type: Boolean,
- value: false,
- notify: true,
- observer: '_checkedChanged',
- reflectToAttribute: true
- },
-
- /**
- * Indeterminate state of the checkbox when it's neither checked nor unchecked, but undetermined.
+ * True if the checkbox is in the indeterminate state which means
+ * it is not possible to say whether the checkbox is checked or unchecked.
+ * The state resets once the checkbox gets checked or unchecked.
+ *
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox#Indeterminate_state_checkboxes
+ *
* @type {boolean}
*/
indeterminate: {
type: Boolean,
notify: true,
- observer: '_indeterminateChanged',
- reflectToAttribute: true,
- value: false
+ value: false,
+ reflectToAttribute: true
},
/**
- * The value given to the data submitted with the checkbox's name to the server when the control is inside a form.
+ * The value of the checkbox.
*/
value: {
type: String,
- value: 'on'
- },
-
- /** @private */
- _nativeCheckbox: {
- type: Object
+ value: 'on',
+ observer: '_valueChanged',
+ reflectToAttribute: true
}
};
}
- constructor() {
- super();
- /**
- * @type {string}
- * Name of the element.
- */
- this.name;
- }
-
- get name() {
- return this.checked ? this._storedName : '';
- }
-
- set name(name) {
- this._storedName = name;
- }
-
- ready() {
- super.ready();
-
- this.setAttribute('role', 'checkbox');
-
- this._nativeCheckbox = this.shadowRoot.querySelector('input[type="checkbox"]');
-
- this.addEventListener('click', this._handleClick.bind(this));
-
- this._addActiveListeners();
-
- const attrName = this.getAttribute('name');
- if (attrName) {
- this.name = attrName;
- }
-
- this.shadowRoot
- .querySelector('[part~="label"]')
- .querySelector('slot')
- .addEventListener('slotchange', this._updateLabelAttribute.bind(this));
-
- this._updateLabelAttribute();
- }
-
- /** @private */
- _updateLabelAttribute() {
- const label = this.shadowRoot.querySelector('[part~="label"]');
- const assignedNodes = label.firstElementChild.assignedNodes();
- if (this._isAssignedNodesEmpty(assignedNodes)) {
- label.setAttribute('empty', '');
- } else {
- label.removeAttribute('empty');
- }
- }
-
- /** @private */
- _isAssignedNodesEmpty(nodes) {
- // The assigned nodes considered to be empty if there is no slotted content or only one empty text node
- return (
- nodes.length === 0 ||
- (nodes.length == 1 && nodes[0].nodeType == Node.TEXT_NODE && nodes[0].textContent.trim() === '')
- );
- }
-
- /** @private */
- _checkedChanged(checked) {
- if (this.indeterminate) {
- this.setAttribute('aria-checked', 'mixed');
- } else {
- this.setAttribute('aria-checked', Boolean(checked));
- }
- }
-
- /** @private */
- _indeterminateChanged(indeterminate) {
- if (indeterminate) {
- this.setAttribute('aria-checked', 'mixed');
- } else {
- this.setAttribute('aria-checked', this.checked);
- }
+ static get delegateProps() {
+ return [...super.delegateProps, 'indeterminate'];
}
- /** @private */
- _addActiveListeners() {
- // DOWN
- this._addEventListenerToNode(this, 'down', (e) => {
- if (this.__interactionsAllowed(e)) {
- this.setAttribute('active', '');
- }
- });
-
- // UP
- this._addEventListenerToNode(this, 'up', () => this.removeAttribute('active'));
-
- // KEYDOWN
- this.addEventListener('keydown', (e) => {
- if (this.__interactionsAllowed(e) && e.keyCode === 32) {
- e.preventDefault();
- this.setAttribute('active', '');
- }
- });
-
- // KEYUP
- this.addEventListener('keyup', (e) => {
- if (this.__interactionsAllowed(e) && e.keyCode === 32) {
- e.preventDefault();
- this._toggleChecked();
- this.removeAttribute('active');
+ constructor() {
+ super();
- if (this.indeterminate) {
- this.indeterminate = false;
- }
- }
- });
+ this._setType('checkbox');
}
/**
- * @return {!HTMLInputElement}
+ * @override
* @protected
*/
- get focusElement() {
- return this.shadowRoot.querySelector('input');
+ get _sourceSlot() {
+ return this.$.noop;
}
/**
- * True if users' interactions (mouse or keyboard)
- * should toggle the checkbox
+ * @protected
+ * @override
*/
- __interactionsAllowed(e) {
- if (this.disabled) {
- return false;
- }
+ _toggleChecked() {
+ this.indeterminate = false;
- // https://github.com/vaadin/vaadin-checkbox/issues/63
- if (e.target.localName === 'a') {
- return false;
- }
+ super._toggleChecked();
- return true;
- }
-
- /** @private */
- _handleClick(e) {
- if (this.__interactionsAllowed(e)) {
- if (!this.indeterminate) {
- if (e.composedPath()[0] !== this._nativeCheckbox) {
- e.preventDefault();
- this._toggleChecked();
- }
- } else {
- /*
- * Required for IE 11 and Edge.
- * See issue here: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7344418/
- */
- this.indeterminate = false;
- e.preventDefault();
- this._toggleChecked();
- }
- }
- }
-
- /** @protected */
- _toggleChecked() {
- this.checked = !this.checked;
this.dispatchEvent(new CustomEvent('change', { composed: false, bubbles: true }));
}
@@ -328,6 +175,6 @@ class CheckboxElement extends ElementMixin(ControlStateMixin(ThemableMixin(Gestu
*/
}
-customElements.define(CheckboxElement.is, CheckboxElement);
+customElements.define(Checkbox.is, Checkbox);
-export { CheckboxElement };
+export { Checkbox };
diff --git a/packages/checkbox/theme/lumo/vaadin-checkbox-styles.js b/packages/checkbox/theme/lumo/vaadin-checkbox-styles.js
index 86e0ccdfe4..fc91fab023 100644
--- a/packages/checkbox/theme/lumo/vaadin-checkbox-styles.js
+++ b/packages/checkbox/theme/lumo/vaadin-checkbox-styles.js
@@ -26,7 +26,6 @@ registerStyles(
border-radius: var(--lumo-border-radius-s);
background-color: var(--lumo-contrast-20pct);
transition: transform 0.2s cubic-bezier(0.12, 0.32, 0.54, 2), background-color 0.15s;
- pointer-events: none;
line-height: 1.2;
cursor: var(--lumo-clickable-cursor);
}
diff --git a/packages/checkbox/theme/material/vaadin-checkbox-styles.js b/packages/checkbox/theme/material/vaadin-checkbox-styles.js
index 26acb948cb..bf8d814342 100644
--- a/packages/checkbox/theme/material/vaadin-checkbox-styles.js
+++ b/packages/checkbox/theme/material/vaadin-checkbox-styles.js
@@ -32,7 +32,6 @@ registerStyles(
position: relative;
border-radius: 2px;
box-shadow: inset 0 0 0 2px var(--material-secondary-text-color);
- pointer-events: none;
line-height: 1.275;
background-color: transparent;
}
diff --git a/packages/field-base/src/aria-label-mixin.js b/packages/field-base/src/aria-label-mixin.js
index 4db921dea7..0394a18d3c 100644
--- a/packages/field-base/src/aria-label-mixin.js
+++ b/packages/field-base/src/aria-label-mixin.js
@@ -9,27 +9,14 @@ import { InputMixin } from './input-mixin.js';
const AriaLabelMixinImplementation = (superclass) =>
class AriaLabelMixinClass extends InputMixin(LabelMixin(superclass)) {
- constructor() {
- super();
-
- this.__preventDuplicateLabelClick = this.__preventDuplicateLabelClick.bind(this);
- }
-
- /** @protected */
- connectedCallback() {
- super.connectedCallback();
-
- if (this._labelNode) {
- this._labelNode.addEventListener('click', this.__preventDuplicateLabelClick);
- }
- }
-
/** @protected */
- disconnectedCallback() {
- super.disconnectedCallback();
+ ready() {
+ super.ready();
if (this._labelNode) {
- this._labelNode.removeEventListener('click', this.__preventDuplicateLabelClick);
+ this._labelNode.addEventListener('click', (event) => {
+ this.__preventDuplicateLabelClick(event);
+ });
}
}
diff --git a/packages/field-base/src/helper-text-mixin.js b/packages/field-base/src/helper-text-mixin.js
index 212e6bf22b..241c21d6ce 100644
--- a/packages/field-base/src/helper-text-mixin.js
+++ b/packages/field-base/src/helper-text-mixin.js
@@ -52,8 +52,8 @@ const HelperTextMixinImplementation = (superclass) =>
}
/** @protected */
- connectedCallback() {
- super.connectedCallback();
+ ready() {
+ super.ready();
if (this._helperNode) {
this._currentHelper = this._helperNode;
@@ -61,11 +61,6 @@ const HelperTextMixinImplementation = (superclass) =>
this._applyCustomHelper();
}
- }
-
- /** @protected */
- ready() {
- super.ready();
this.__helperSlot = this.shadowRoot.querySelector('[name="helper"]');
this.__helperSlot.addEventListener('slotchange', this.__onHelperSlotChange.bind(this));