@vaadin/vaadin-select 2.4.3 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "repository": "vaadin/vaadin-select",
11
11
  "homepage": "https://vaadin.com/components",
12
12
  "name": "@vaadin/vaadin-select",
13
- "version": "2.4.3",
13
+ "version": "2.5.0",
14
14
  "main": "vaadin-select.js",
15
15
  "author": "Vaadin Ltd",
16
16
  "license": "Apache-2.0",
@@ -36,7 +36,7 @@
36
36
  "@polymer/iron-resizable-behavior": "^3.0.0",
37
37
  "@vaadin/vaadin-control-state-mixin": "^2.2.1",
38
38
  "@vaadin/vaadin-themable-mixin": "^1.6.1",
39
- "@vaadin/vaadin-text-field": "^2.8.0",
39
+ "@vaadin/vaadin-text-field": "^2.10.0",
40
40
  "@vaadin/vaadin-list-box": "^1.4.0",
41
41
  "@vaadin/vaadin-list-mixin": "^2.5.0",
42
42
  "@vaadin/vaadin-item": "^2.3.0",
@@ -15,6 +15,22 @@ $_documentContainer.innerHTML = `<dom-module id="vaadin-select-overlay-styles" t
15
15
  align-items: flex-start;
16
16
  justify-content: flex-start;
17
17
  }
18
+
19
+ :host([bottom-aligned]) {
20
+ justify-content: flex-end;
21
+ }
22
+
23
+ :host([right-aligned]) {
24
+ align-items: flex-end;
25
+ }
26
+
27
+ :host([dir="rtl"]) {
28
+ align-items: flex-end;
29
+ }
30
+
31
+ :host([dir="rtl"][right-aligned]) {
32
+ align-items: flex-start;
33
+ }
18
34
  </style>
19
35
  </template>
20
36
  </dom-module>`;
@@ -214,9 +214,17 @@ declare class SelectElement extends
214
214
  notifyResize(): void;
215
215
  _onKeyDown(e: KeyboardEvent): void;
216
216
  _onKeyDownInside(e: KeyboardEvent): void;
217
+ _setInvalid(invalid: boolean): void;
217
218
 
218
219
  /**
219
- * Returns true if `value` is valid, and sets the `invalid` flag appropriately.
220
+ * Override this method to define whether the given `invalid` state should be set.
221
+ */
222
+ _shouldSetInvalid(_invalid: boolean): boolean;
223
+
224
+ /**
225
+ * Validates the field and sets the `invalid` property based on the result.
226
+ *
227
+ * The method fires a `validated` event with the result of the validation.
220
228
  *
221
229
  * @returns True if the value is valid and sets the `invalid` flag appropriately
222
230
  */
@@ -178,7 +178,7 @@ class SelectElement extends
178
178
  }
179
179
 
180
180
  static get version() {
181
- return '2.4.3';
181
+ return '2.5.0';
182
182
  }
183
183
 
184
184
  static get properties() {
@@ -680,17 +680,22 @@ class SelectElement extends
680
680
  /** @private */
681
681
  _setPosition() {
682
682
  const inputRect = this._inputElement.shadowRoot.querySelector('[part~="input-field"]').getBoundingClientRect();
683
+ const viewportWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
683
684
  const viewportHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);
684
- const bottomAlign = inputRect.top > (viewportHeight - inputRect.height) / 2;
685
+ const shouldAlignRight = this.__shouldAlignRight(inputRect, viewportWidth);
686
+ const shouldAlignBottom = this.__shouldAlignBottom(inputRect, viewportHeight);
685
687
 
686
- const isRtl = this.getAttribute('dir') === 'rtl';
687
- if (isRtl) {
688
- this._overlayElement.style.right = document.documentElement.clientWidth - inputRect.right + 'px';
688
+ if (shouldAlignRight) {
689
+ this._overlayElement.setAttribute('right-aligned', '');
690
+ this._overlayElement.style.right = (viewportWidth - inputRect.right) + 'px';
691
+ this._overlayElement.style.removeProperty('left');
689
692
  } else {
693
+ this._overlayElement.removeAttribute('right-aligned');
690
694
  this._overlayElement.style.left = inputRect.left + 'px';
695
+ this._overlayElement.style.removeProperty('right');
691
696
  }
692
697
 
693
- if (bottomAlign) {
698
+ if (shouldAlignBottom) {
694
699
  this._overlayElement.setAttribute('bottom-aligned', '');
695
700
  this._overlayElement.style.removeProperty('top');
696
701
  this._overlayElement.style.bottom = (viewportHeight - inputRect.bottom) + 'px';
@@ -703,13 +708,75 @@ class SelectElement extends
703
708
  this._overlayElement.updateStyles({'--vaadin-select-text-field-width': inputRect.width + 'px'});
704
709
  }
705
710
 
711
+ /** @private */
712
+ __shouldAlignRight(targetRect, viewportWidth) {
713
+ const isRTL = this.getAttribute('dir') === 'rtl';
714
+ const spaceLeft = targetRect.left / viewportWidth;
715
+ const spaceRight = (viewportWidth - targetRect.right) / viewportWidth;
716
+
717
+ if (isRTL) {
718
+ // When RTL mode, should align the dropdown right
719
+ // as long as there is enough space on the left side.
720
+ //
721
+ // Default alignment for RTL:
722
+ //
723
+ // _____Select_____
724
+ // ––––––––––––––––––––––––––
725
+ // | Dropdown |
726
+ // ––––––––––––––––––––––––––
727
+ return spaceLeft > 0.3;
728
+ }
729
+
730
+ // When LTL mode, should align the dropdown right
731
+ // only when there is not enough space on the right side.
732
+ //
733
+ // Default alignment for LTL:
734
+ //
735
+ // _____Select_____
736
+ // ––––––––––––––––––––––––––
737
+ // | Dropdown |
738
+ // ––––––––––––––––––––––––––
739
+ return spaceRight < 0.3;
740
+ }
741
+
742
+ /** @private */
743
+ __shouldAlignBottom(targetRect, viewportHeight) {
744
+ return targetRect.top > (viewportHeight - targetRect.height) / 2;
745
+ }
746
+
706
747
  /**
707
- * Returns true if `value` is valid, and sets the `invalid` flag appropriately.
748
+ * @param {boolean} invalid
749
+ * @protected
750
+ */
751
+ _setInvalid(invalid) {
752
+ if (this._shouldSetInvalid(invalid)) {
753
+ this.invalid = invalid;
754
+ }
755
+ }
756
+
757
+ /**
758
+ * Override this method to define whether the given `invalid` state should be set.
759
+ *
760
+ * @param {boolean} _invalid
761
+ * @return {boolean}
762
+ * @protected
763
+ */
764
+ _shouldSetInvalid(_invalid) {
765
+ return true;
766
+ }
767
+
768
+ /**
769
+ * Validates the field and sets the `invalid` property based on the result.
770
+ *
771
+ * The method fires a `validated` event with the result of the validation.
708
772
  *
709
773
  * @return {boolean} True if the value is valid and sets the `invalid` flag appropriately
710
774
  */
711
775
  validate() {
712
- return !(this.invalid = !(this.disabled || !this.required || this.value));
776
+ const isValid = !!(this.disabled || !this.required || this.value);
777
+ this._setInvalid(!isValid);
778
+ this.dispatchEvent(new CustomEvent('validated', {detail: {valid: isValid}}));
779
+ return isValid;
713
780
  }
714
781
 
715
782
  /**
@@ -717,6 +784,14 @@ class SelectElement extends
717
784
  *
718
785
  * @event change
719
786
  */
787
+
788
+ /**
789
+ * Fired whenever the field is validated.
790
+ *
791
+ * @event validated
792
+ * @param {Object} detail
793
+ * @param {boolean} detail.valid the result of the validation.
794
+ */
720
795
  }
721
796
 
722
797
  customElements.define(SelectElement.is, SelectElement);
@@ -105,10 +105,6 @@ const $_documentContainer = html`<dom-module id="lumo-select" theme-for="vaadin-
105
105
  --_lumo-item-selected-icon-display: block;
106
106
  }
107
107
 
108
- :host([bottom-aligned]) {
109
- justify-content: flex-end;
110
- }
111
-
112
108
  [part~="overlay"] {
113
109
  min-width: var(--vaadin-select-text-field-width);
114
110
  }
@@ -55,10 +55,6 @@ const $_documentContainer = html`<dom-module id="material-select" theme-for="vaa
55
55
  </dom-module><dom-module id="material-select-overlay" theme-for="vaadin-select-overlay">
56
56
  <template>
57
57
  <style include="material-menu-overlay">
58
- :host([bottom-aligned]) {
59
- justify-content: flex-end;
60
- }
61
-
62
58
  [part="overlay"] {
63
59
  min-width: var(--vaadin-select-text-field-width);
64
60
  }