@everymatrix/helper-filters 0.1.2 → 0.1.4

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.
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, c as createEvent, h as h$2 } from './index-af82b143.js';
1
+ import { r as registerInstance, c as createEvent, h as h$2 } from './index-1b3528e3.js';
2
2
 
3
3
  const DEFAULT_LANGUAGE = 'en';
4
4
  const SUPPORTED_LANGUAGES = ['ro', 'en'];
@@ -13,7 +13,8 @@ const TRANSLATIONS = {
13
13
  filterDateRangePlaceholder: 'Date Range',
14
14
  filterModalButton: 'Search',
15
15
  filterFromCalendar: 'From',
16
- filterToCalendar: 'To'
16
+ filterToCalendar: 'To',
17
+ filterOrDate: 'or search by date'
17
18
  },
18
19
  ro: {
19
20
  filterOpen: 'Filtrare',
@@ -23,7 +24,8 @@ const TRANSLATIONS = {
23
24
  filterTicketPlaceholder: 'Cauta ID bilet',
24
25
  filterDrawPlaceholder: 'Cauta ID draw',
25
26
  filterDateRangePlaceholder: 'Perioada',
26
- filterModalButton: 'Cauta'
27
+ filterModalButton: 'Cauta',
28
+ filterOrDate: 'sau cauta dupa data'
27
29
  },
28
30
  };
29
31
  const translate$1 = (key, customLang) => {
@@ -38,7 +40,7 @@ const translate$1 = (key, customLang) => {
38
40
  */
39
41
  class Lumo extends HTMLElement {
40
42
  static get version() {
41
- return '23.1.5';
43
+ return '23.2.0';
42
44
  }
43
45
  }
44
46
 
@@ -94,7 +96,7 @@ const ThemePropertyMixin = (superClass) =>
94
96
  * **NOTE:** Extending the mixin only provides the property for binding,
95
97
  * and does not make the propagation alone.
96
98
  *
97
- * See [Styling Components: Sub-components](https://vaadin.com/docs/latest/ds/customization/styling-components/#sub-components).
99
+ * See [Styling Components: Sub-components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components/#sub-components).
98
100
  * page for more information.
99
101
  *
100
102
  * @deprecated The `theme` property is not supposed for public use and will be dropped in Vaadin 24.
@@ -119,7 +121,7 @@ const ThemePropertyMixin = (superClass) =>
119
121
  * **NOTE:** Extending the mixin only provides the property for binding,
120
122
  * and does not make the propagation alone.
121
123
  *
122
- * See [Styling Components: Sub-components](https://vaadin.com/docs/latest/ds/customization/styling-components/#sub-components).
124
+ * See [Styling Components: Sub-components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components/#sub-components).
123
125
  * page for more information.
124
126
  *
125
127
  * @protected
@@ -224,9 +226,9 @@ function matchesThemeFor(themeFor, tagName) {
224
226
  */
225
227
  function getIncludePriority(moduleName = '') {
226
228
  let includePriority = 0;
227
- if (moduleName.indexOf('lumo-') === 0 || moduleName.indexOf('material-') === 0) {
229
+ if (moduleName.startsWith('lumo-') || moduleName.startsWith('material-')) {
228
230
  includePriority = 1;
229
- } else if (moduleName.indexOf('vaadin-') === 0) {
231
+ } else if (moduleName.startsWith('vaadin-')) {
230
232
  includePriority = 2;
231
233
  }
232
234
  return includePriority;
@@ -10111,6 +10113,38 @@ const ControllerMixin = dedupingMixin(
10111
10113
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
10112
10114
  */
10113
10115
 
10116
+ // We consider the keyboard to be active if the window has received a keydown
10117
+ // event since the last mousedown event.
10118
+ let keyboardActive = false;
10119
+
10120
+ // Listen for top-level keydown and mousedown events.
10121
+ // Use capture phase so we detect events even if they're handled.
10122
+ window.addEventListener(
10123
+ 'keydown',
10124
+ () => {
10125
+ keyboardActive = true;
10126
+ },
10127
+ { capture: true },
10128
+ );
10129
+
10130
+ window.addEventListener(
10131
+ 'mousedown',
10132
+ () => {
10133
+ keyboardActive = false;
10134
+ },
10135
+ { capture: true },
10136
+ );
10137
+
10138
+ /**
10139
+ * Returns true if the window has received a keydown
10140
+ * event since the last mousedown event.
10141
+ *
10142
+ * @return {boolean}
10143
+ */
10144
+ function isKeyboardActive() {
10145
+ return keyboardActive;
10146
+ }
10147
+
10114
10148
  /**
10115
10149
  * Returns true if the element is hidden directly with `display: none` or `visibility: hidden`,
10116
10150
  * false otherwise.
@@ -10551,7 +10585,7 @@ class FocusTrapController {
10551
10585
  * ---|---|---
10552
10586
  * `--vaadin-overlay-viewport-bottom` | Bottom offset of the visible viewport area | `0` or detected offset
10553
10587
  *
10554
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
10588
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
10555
10589
  *
10556
10590
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
10557
10591
  * @fires {CustomEvent} vaadin-overlay-open - Fired after the overlay is opened.
@@ -12821,7 +12855,7 @@ const registered = new Set();
12821
12855
  const ElementMixin = (superClass) =>
12822
12856
  class VaadinElementMixin extends DirMixin(superClass) {
12823
12857
  static get version() {
12824
- return '23.1.5';
12858
+ return '23.2.0';
12825
12859
  }
12826
12860
 
12827
12861
  /** @protected */
@@ -13119,7 +13153,7 @@ function _handleNative(ev) {
13119
13153
  }
13120
13154
  if (!ev[HANDLED_OBJ]) {
13121
13155
  ev[HANDLED_OBJ] = {};
13122
- if (type.slice(0, 5) === 'touch') {
13156
+ if (type.startsWith('touch')) {
13123
13157
  const t = ev.changedTouches[0];
13124
13158
  if (type === 'touchstart') {
13125
13159
  // Only handle the first finger
@@ -13978,28 +14012,6 @@ const ActiveMixin = (superclass) =>
13978
14012
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
13979
14013
  */
13980
14014
 
13981
- // We consider the keyboard to be active if the window has received a keydown
13982
- // event since the last mousedown event.
13983
- let keyboardActive = false;
13984
-
13985
- // Listen for top-level keydown and mousedown events.
13986
- // Use capture phase so we detect events even if they're handled.
13987
- window.addEventListener(
13988
- 'keydown',
13989
- () => {
13990
- keyboardActive = true;
13991
- },
13992
- { capture: true },
13993
- );
13994
-
13995
- window.addEventListener(
13996
- 'mousedown',
13997
- () => {
13998
- keyboardActive = false;
13999
- },
14000
- { capture: true },
14001
- );
14002
-
14003
14015
  /**
14004
14016
  * A mixin to handle `focused` and `focus-ring` attributes based on focus.
14005
14017
  *
@@ -14013,7 +14025,7 @@ const FocusMixin = dedupingMixin(
14013
14025
  * @return {boolean}
14014
14026
  */
14015
14027
  get _keyboardActive() {
14016
- return keyboardActive;
14028
+ return isKeyboardActive();
14017
14029
  }
14018
14030
 
14019
14031
  /** @protected */
@@ -14277,7 +14289,7 @@ const ButtonMixin = (superClass) =>
14277
14289
  * `focus-ring` | Set when the button is focused using the keyboard.
14278
14290
  * `focused` | Set when the button is focused.
14279
14291
  *
14280
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
14292
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
14281
14293
  *
14282
14294
  * @extends HTMLElement
14283
14295
  * @mixes ButtonMixin
@@ -14359,7 +14371,6 @@ registerStyles(
14359
14371
  i$1`
14360
14372
  :host {
14361
14373
  position: relative;
14362
- background-color: transparent;
14363
14374
  /* Background for the year scroller, placed here as we are using a mask image on the actual years part */
14364
14375
  background-image: linear-gradient(var(--lumo-shade-5pct), var(--lumo-shade-5pct));
14365
14376
  background-size: 57px 100%;
@@ -14467,17 +14478,10 @@ registerStyles(
14467
14478
 
14468
14479
  [part='toolbar'] {
14469
14480
  padding: var(--lumo-space-s);
14470
- box-shadow: 0 -1px 0 0 var(--lumo-contrast-10pct);
14471
14481
  border-bottom-left-radius: var(--lumo-border-radius-l);
14472
14482
  margin-right: 57px;
14473
14483
  }
14474
14484
 
14475
- @supports (mask-image: linear-gradient(#000, #000)) or (-webkit-mask-image: linear-gradient(#000, #000)) {
14476
- [part='toolbar'] {
14477
- box-shadow: none;
14478
- }
14479
- }
14480
-
14481
14485
  /* Today and Cancel buttons */
14482
14486
 
14483
14487
  [part='toolbar'] [part\$='button'] {
@@ -14510,8 +14514,6 @@ registerStyles(
14510
14514
  /* Very narrow screen (year scroller initially hidden) */
14511
14515
 
14512
14516
  [part='years-toggle-button'] {
14513
- position: relative;
14514
- right: auto;
14515
14517
  display: flex;
14516
14518
  align-items: center;
14517
14519
  height: var(--lumo-size-s);
@@ -14529,10 +14531,6 @@ registerStyles(
14529
14531
  color: var(--lumo-primary-contrast-color);
14530
14532
  }
14531
14533
 
14532
- [part='years-toggle-button']::before {
14533
- content: none;
14534
- }
14535
-
14536
14534
  /* TODO magic number (same as used for iron-media-query in vaadin-date-picker-overlay-content) */
14537
14535
  @media screen and (max-width: 374px) {
14538
14536
  :host {
@@ -14708,9 +14706,9 @@ registerStyles(
14708
14706
  { moduleId: 'lumo-month-calendar' },
14709
14707
  );
14710
14708
 
14711
- const $_documentContainer$1 = document.createElement('template');
14709
+ const template$1 = document.createElement('template');
14712
14710
 
14713
- $_documentContainer$1.innerHTML = `
14711
+ template$1.innerHTML = `
14714
14712
  <style>
14715
14713
  @keyframes vaadin-date-picker-month-calendar-focus-date {
14716
14714
  50% {
@@ -14720,7 +14718,7 @@ $_documentContainer$1.innerHTML = `
14720
14718
  </style>
14721
14719
  `;
14722
14720
 
14723
- document.head.appendChild($_documentContainer$1.content);
14721
+ document.head.appendChild(template$1.content);
14724
14722
 
14725
14723
  /**
14726
14724
  * @license
@@ -14728,9 +14726,9 @@ document.head.appendChild($_documentContainer$1.content);
14728
14726
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
14729
14727
  */
14730
14728
 
14731
- const $_documentContainer = document.createElement('template');
14729
+ const template = document.createElement('template');
14732
14730
 
14733
- $_documentContainer.innerHTML = `
14731
+ template.innerHTML = `
14734
14732
  <style>
14735
14733
  @font-face {
14736
14734
  font-family: 'lumo-icons';
@@ -14786,7 +14784,7 @@ $_documentContainer.innerHTML = `
14786
14784
  </style>
14787
14785
  `;
14788
14786
 
14789
- document.head.appendChild($_documentContainer.content);
14787
+ document.head.appendChild(template.content);
14790
14788
 
14791
14789
  /**
14792
14790
  * @license
@@ -15353,6 +15351,57 @@ function getAncestorRootNodes(node) {
15353
15351
  return result;
15354
15352
  }
15355
15353
 
15354
+ /**
15355
+ * @param {string} value
15356
+ * @return {Set<string>}
15357
+ */
15358
+ function deserializeAttributeValue(value) {
15359
+ if (!value) {
15360
+ return new Set();
15361
+ }
15362
+
15363
+ return new Set(value.split(' '));
15364
+ }
15365
+
15366
+ /**
15367
+ * @param {Set<string>} values
15368
+ * @return {string}
15369
+ */
15370
+ function serializeAttributeValue(values) {
15371
+ return [...values].join(' ');
15372
+ }
15373
+
15374
+ /**
15375
+ * Adds a value to an attribute containing space-delimited values.
15376
+ *
15377
+ * @param {HTMLElement} element
15378
+ * @param {string} attr
15379
+ * @param {string} value
15380
+ */
15381
+ function addValueToAttribute(element, attr, value) {
15382
+ const values = deserializeAttributeValue(element.getAttribute(attr));
15383
+ values.add(value);
15384
+ element.setAttribute(attr, serializeAttributeValue(values));
15385
+ }
15386
+
15387
+ /**
15388
+ * Removes a value from an attribute containing space-delimited values.
15389
+ * If the value is the last one, the whole attribute is removed.
15390
+ *
15391
+ * @param {HTMLElement} element
15392
+ * @param {string} attr
15393
+ * @param {string} value
15394
+ */
15395
+ function removeValueFromAttribute(element, attr, value) {
15396
+ const values = deserializeAttributeValue(element.getAttribute(attr));
15397
+ values.delete(value);
15398
+ if (values.size === 0) {
15399
+ element.removeAttribute(attr);
15400
+ return;
15401
+ }
15402
+ element.setAttribute(attr, serializeAttributeValue(values));
15403
+ }
15404
+
15356
15405
  /**
15357
15406
  * @license
15358
15407
  * Copyright (c) 2017 - 2022 Vaadin Ltd.
@@ -17077,7 +17126,9 @@ class MonthCalendar extends FocusMixin(ThemableMixin(PolymerElement)) {
17077
17126
 
17078
17127
  _onMonthGridTouchStart() {
17079
17128
  this._notTapping = false;
17080
- setTimeout(() => (this._notTapping = true), 300);
17129
+ setTimeout(() => {
17130
+ this._notTapping = true;
17131
+ }, 300);
17081
17132
  }
17082
17133
 
17083
17134
  _dateAdd(date, delta) {
@@ -17412,7 +17463,7 @@ class InfiniteScroller extends PolymerElement {
17412
17463
  // Once the first set of items start fading in, stamp the rest
17413
17464
  this._buffers.forEach((buffer) => {
17414
17465
  [].forEach.call(buffer.children, (insertionPoint) => this._ensureStampedInstance(insertionPoint._itemWrapper));
17415
- }, this);
17466
+ });
17416
17467
 
17417
17468
  if (!this._buffers[0].translateY) {
17418
17469
  this._reset();
@@ -17575,7 +17626,7 @@ class InfiniteScroller extends PolymerElement {
17575
17626
  }
17576
17627
  }, 1); // Wait for first reset
17577
17628
  }
17578
- }, this);
17629
+ });
17579
17630
 
17580
17631
  setTimeout(() => {
17581
17632
  afterNextRender(this, this._finishInit.bind(this));
@@ -17613,7 +17664,7 @@ class InfiniteScroller extends PolymerElement {
17613
17664
  });
17614
17665
  buffer.updated = true;
17615
17666
  }
17616
- }, this);
17667
+ });
17617
17668
  }
17618
17669
 
17619
17670
  _isVisible(element, container) {
@@ -17712,7 +17763,6 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
17712
17763
  height: 100%;
17713
17764
  width: 100%;
17714
17765
  outline: none;
17715
- background: #fff;
17716
17766
  }
17717
17767
 
17718
17768
  [part='overlay-header'] {
@@ -17730,22 +17780,14 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
17730
17780
  flex-grow: 1;
17731
17781
  }
17732
17782
 
17733
- [part='clear-button']:not([showclear]) {
17734
- display: none;
17783
+ [hidden] {
17784
+ display: none !important;
17735
17785
  }
17736
17786
 
17737
17787
  [part='years-toggle-button'] {
17738
17788
  display: flex;
17739
17789
  }
17740
17790
 
17741
- [part='years-toggle-button'][desktop] {
17742
- display: none;
17743
- }
17744
-
17745
- :host(:not([years-visible])) [part='years-toggle-button']::before {
17746
- transform: rotate(180deg);
17747
- }
17748
-
17749
17791
  #scrollers {
17750
17792
  display: flex;
17751
17793
  height: 100%;
@@ -17819,27 +17861,14 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
17819
17861
  z-index: 2;
17820
17862
  flex-shrink: 0;
17821
17863
  }
17822
-
17823
- [part~='overlay-header']:not([desktop]) {
17824
- padding-bottom: 40px;
17825
- }
17826
-
17827
- [part~='years-toggle-button'] {
17828
- position: absolute;
17829
- top: auto;
17830
- right: 8px;
17831
- bottom: 0;
17832
- z-index: 1;
17833
- padding: 8px;
17834
- }
17835
17864
  </style>
17836
17865
 
17837
17866
  <div part="overlay-header" on-touchend="_preventDefault" desktop$="[[_desktopMode]]" aria-hidden="true">
17838
17867
  <div part="label">[[_formatDisplayed(selectedDate, i18n.formatDate, label)]]</div>
17839
- <div part="clear-button" showclear$="[[_showClear(selectedDate)]]"></div>
17868
+ <div part="clear-button" hidden$="[[!selectedDate]]"></div>
17840
17869
  <div part="toggle-button"></div>
17841
17870
 
17842
- <div part="years-toggle-button" desktop$="[[_desktopMode]]" aria-hidden="true">
17871
+ <div part="years-toggle-button" hidden$="[[_desktopMode]]" aria-hidden="true">
17843
17872
  [[_yearAfterXMonths(_visibleMonthIndex)]]
17844
17873
  </div>
17845
17874
  </div>
@@ -17925,6 +17954,7 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
17925
17954
  */
17926
17955
  selectedDate: {
17927
17956
  type: Date,
17957
+ value: null,
17928
17958
  },
17929
17959
 
17930
17960
  /**
@@ -18000,10 +18030,12 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
18000
18030
  return this.getAttribute('dir') === 'rtl';
18001
18031
  }
18002
18032
 
18033
+ get calendars() {
18034
+ return [...this.shadowRoot.querySelectorAll('vaadin-month-calendar')];
18035
+ }
18036
+
18003
18037
  get focusableDateElement() {
18004
- return [...this.shadowRoot.querySelectorAll('vaadin-month-calendar')]
18005
- .map((calendar) => calendar.focusableDateElement)
18006
- .find(Boolean);
18038
+ return this.calendars.map((calendar) => calendar.focusableDateElement).find(Boolean);
18007
18039
  }
18008
18040
 
18009
18041
  ready() {
@@ -18011,7 +18043,6 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
18011
18043
 
18012
18044
  this.setAttribute('role', 'dialog');
18013
18045
 
18014
- addListener(this, 'tap', this._stopPropagation);
18015
18046
  addListener(this.$.scrollers, 'track', this._track.bind(this));
18016
18047
  addListener(this.shadowRoot.querySelector('[part="clear-button"]'), 'tap', this._clear.bind(this));
18017
18048
  addListener(this.shadowRoot.querySelector('[part="today-button"]'), 'tap', this._onTodayTap.bind(this));
@@ -18133,7 +18164,9 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
18133
18164
 
18134
18165
  _onYearScrollTouchStart() {
18135
18166
  this._notTapping = false;
18136
- setTimeout(() => (this._notTapping = true), 300);
18167
+ setTimeout(() => {
18168
+ this._notTapping = true;
18169
+ }, 300);
18137
18170
 
18138
18171
  this._repositionMonthScroller();
18139
18172
  }
@@ -18144,7 +18177,9 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
18144
18177
 
18145
18178
  _doIgnoreTaps() {
18146
18179
  this._ignoreTaps = true;
18147
- this._debouncer = Debouncer$1.debounce(this._debouncer, timeOut.after(300), () => (this._ignoreTaps = false));
18180
+ this._debouncer = Debouncer$1.debounce(this._debouncer, timeOut.after(300), () => {
18181
+ this._ignoreTaps = false;
18182
+ });
18148
18183
  }
18149
18184
 
18150
18185
  _formatDisplayed(date, formatDate, label) {
@@ -18175,10 +18210,6 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
18175
18210
  this.scrollToDate(new Date(), true);
18176
18211
  }
18177
18212
 
18178
- _showClear(selectedDate) {
18179
- return !!selectedDate;
18180
- }
18181
-
18182
18213
  _onYearTap(e) {
18183
18214
  if (!this._ignoreTaps && !this._notTapping) {
18184
18215
  const scrollDelta =
@@ -18204,6 +18235,11 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
18204
18235
 
18205
18236
  this._targetPosition = targetPosition;
18206
18237
 
18238
+ let revealResolve;
18239
+ this._revealPromise = new Promise((resolve) => {
18240
+ revealResolve = resolve;
18241
+ });
18242
+
18207
18243
  // http://gizma.com/easing/
18208
18244
  const easingFunction = (t, b, c, d) => {
18209
18245
  t /= d / 2;
@@ -18244,7 +18280,9 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
18244
18280
 
18245
18281
  this.$.monthScroller.position = this._targetPosition;
18246
18282
  this._targetPosition = undefined;
18247
- this.__tryFocusDate();
18283
+
18284
+ revealResolve();
18285
+ this._revealPromise = undefined;
18248
18286
  }
18249
18287
 
18250
18288
  setTimeout(this._repositionYearScroller.bind(this), 1);
@@ -18454,51 +18492,44 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
18454
18492
  switch (section) {
18455
18493
  case 'calendar':
18456
18494
  if (event.shiftKey) {
18457
- // Return focus back to the input field.
18458
18495
  event.preventDefault();
18459
- this.__focusInput();
18496
+
18497
+ if (this.hasAttribute('fullscreen')) {
18498
+ // Trap focus in the overlay
18499
+ this.$.cancelButton.focus();
18500
+ } else {
18501
+ this.__focusInput();
18502
+ }
18460
18503
  }
18461
18504
  break;
18462
18505
  case 'today':
18463
18506
  if (event.shiftKey) {
18464
- // Browser returns focus back to the calendar.
18465
- // We need to move the scroll to focused date.
18466
- setTimeout(() => this.revealDate(this.focusedDate), 1);
18507
+ event.preventDefault();
18508
+ this.focusDateElement();
18467
18509
  }
18468
18510
  break;
18469
18511
  case 'cancel':
18470
18512
  if (!event.shiftKey) {
18471
- // Return focus back to the input field.
18472
18513
  event.preventDefault();
18473
- this.__focusInput();
18514
+
18515
+ if (this.hasAttribute('fullscreen')) {
18516
+ // Trap focus in the overlay
18517
+ this.focusDateElement();
18518
+ } else {
18519
+ this.__focusInput();
18520
+ }
18474
18521
  }
18475
18522
  break;
18476
18523
  }
18477
18524
  }
18478
18525
 
18479
18526
  __onTodayButtonKeyDown(event) {
18480
- if (this.hasAttribute('fullscreen')) {
18481
- // Do not prevent closing on Esc
18482
- if (event.key !== 'Escape') {
18483
- event.stopPropagation();
18484
- }
18485
- return;
18486
- }
18487
-
18488
18527
  if (event.key === 'Tab') {
18489
18528
  this._onTabKeyDown(event, 'today');
18490
18529
  }
18491
18530
  }
18492
18531
 
18493
18532
  __onCancelButtonKeyDown(event) {
18494
- if (this.hasAttribute('fullscreen')) {
18495
- // Do not prevent closing on Esc
18496
- if (event.key !== 'Escape') {
18497
- event.stopPropagation();
18498
- }
18499
- return;
18500
- }
18501
-
18502
18533
  if (event.key === 'Tab') {
18503
18534
  this._onTabKeyDown(event, 'cancel');
18504
18535
  }
@@ -18527,15 +18558,29 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
18527
18558
  if (!keepMonth) {
18528
18559
  this._focusedMonthDate = dateToFocus.getDate();
18529
18560
  }
18530
- await this.focusDateElement();
18561
+ await this.focusDateElement(false);
18531
18562
  }
18532
18563
 
18533
- async focusDateElement() {
18564
+ async focusDateElement(reveal = true) {
18534
18565
  this.__pendingDateFocus = this.focusedDate;
18535
18566
 
18536
- await new Promise((resolve) => {
18537
- requestAnimationFrame(resolve);
18538
- });
18567
+ // Wait for `vaadin-month-calendar` elements to be rendered
18568
+ if (!this.calendars.length) {
18569
+ await new Promise((resolve) => {
18570
+ setTimeout(resolve);
18571
+ });
18572
+ }
18573
+
18574
+ // Reveal focused date unless it has been just set,
18575
+ // which triggers `revealDate()` in the observer.
18576
+ if (reveal) {
18577
+ this.revealDate(this.focusedDate);
18578
+ }
18579
+
18580
+ if (this._revealPromise) {
18581
+ // Wait for focused date to be scrolled into view.
18582
+ await this._revealPromise;
18583
+ }
18539
18584
 
18540
18585
  this.__tryFocusDate();
18541
18586
  }
@@ -18633,10 +18678,6 @@ class DatePickerOverlayContent extends ControllerMixin(ThemableMixin(DirMixin(Po
18633
18678
  todayMidnight.setDate(today.getDate());
18634
18679
  return this._dateAllowed(todayMidnight, min, max);
18635
18680
  }
18636
-
18637
- _stopPropagation(e) {
18638
- e.stopPropagation();
18639
- }
18640
18681
  }
18641
18682
 
18642
18683
  customElements.define(DatePickerOverlayContent.is, DatePickerOverlayContent);
@@ -18867,6 +18908,24 @@ const DelegateFocusMixin = dedupingMixin(
18867
18908
  },
18868
18909
  );
18869
18910
 
18911
+ /**
18912
+ * @license
18913
+ * Copyright (c) 2021 - 2022 Vaadin Ltd.
18914
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
18915
+ */
18916
+
18917
+ let uniqueId = 0;
18918
+
18919
+ /**
18920
+ * Returns a unique integer id.
18921
+ *
18922
+ * @return {number}
18923
+ */
18924
+ function generateUniqueId() {
18925
+ // eslint-disable-next-line no-plusplus
18926
+ return uniqueId++;
18927
+ }
18928
+
18870
18929
  /**
18871
18930
  * @license
18872
18931
  * Copyright (c) 2021 - 2022 Vaadin Ltd.
@@ -18887,24 +18946,21 @@ class SlotController extends EventTarget {
18887
18946
  */
18888
18947
  static generateId(slotName, host) {
18889
18948
  const prefix = slotName || 'default';
18890
-
18891
- // Support dash-case slot names e.g. "error-message"
18892
- const field = `${dashToCamelCase(prefix)}Id`;
18893
-
18894
- // Maintain the unique ID counter for a given prefix.
18895
- this[field] = 1 + this[field] || 0;
18896
-
18897
- return `${prefix}-${host.localName}-${this[field]}`;
18949
+ return `${prefix}-${host.localName}-${generateUniqueId()}`;
18898
18950
  }
18899
18951
 
18900
- constructor(host, slotName, slotFactory, slotInitializer) {
18952
+ constructor(host, slotName, slotFactory, slotInitializer, useUniqueId) {
18901
18953
  super();
18902
18954
 
18903
18955
  this.host = host;
18904
18956
  this.slotName = slotName;
18905
18957
  this.slotFactory = slotFactory;
18906
18958
  this.slotInitializer = slotInitializer;
18907
- this.defaultId = SlotController.generateId(slotName, host);
18959
+
18960
+ // Only generate the default ID if requested by the controller.
18961
+ if (useUniqueId) {
18962
+ this.defaultId = SlotController.generateId(slotName, host);
18963
+ }
18908
18964
  }
18909
18965
 
18910
18966
  hostConnected() {
@@ -19059,6 +19115,7 @@ class ErrorController extends SlotController {
19059
19115
 
19060
19116
  this.__updateHasError();
19061
19117
  },
19118
+ true,
19062
19119
  );
19063
19120
  }
19064
19121
 
@@ -19173,63 +19230,6 @@ class ErrorController extends SlotController {
19173
19230
  }
19174
19231
  }
19175
19232
 
19176
- /**
19177
- * @license
19178
- * Copyright (c) 2021 - 2022 Vaadin Ltd.
19179
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
19180
- */
19181
-
19182
- /**
19183
- * @param {string} value
19184
- * @return {Set<string>}
19185
- */
19186
- function deserializeAttributeValue(value) {
19187
- if (!value) {
19188
- return new Set();
19189
- }
19190
-
19191
- return new Set(value.split(' '));
19192
- }
19193
-
19194
- /**
19195
- * @param {Set<string>} values
19196
- * @return {string}
19197
- */
19198
- function serializeAttributeValue(values) {
19199
- return [...values].join(' ');
19200
- }
19201
-
19202
- /**
19203
- * Adds a value to an attribute containing space-delimited values.
19204
- *
19205
- * @param {HTMLElement} element
19206
- * @param {string} attr
19207
- * @param {string} value
19208
- */
19209
- function addValueToAttribute(element, attr, value) {
19210
- const values = deserializeAttributeValue(element.getAttribute(attr));
19211
- values.add(value);
19212
- element.setAttribute(attr, serializeAttributeValue(values));
19213
- }
19214
-
19215
- /**
19216
- * Removes a value from an attribute containing space-delimited values.
19217
- * If the value is the last one, the whole attribute is removed.
19218
- *
19219
- * @param {HTMLElement} element
19220
- * @param {string} attr
19221
- * @param {string} value
19222
- */
19223
- function removeValueFromAttribute(element, attr, value) {
19224
- const values = deserializeAttributeValue(element.getAttribute(attr));
19225
- values.delete(value);
19226
- if (values.size === 0) {
19227
- element.removeAttribute(attr);
19228
- return;
19229
- }
19230
- element.setAttribute(attr, serializeAttributeValue(values));
19231
- }
19232
-
19233
19233
  /**
19234
19234
  * @license
19235
19235
  * Copyright (c) 2021 - 2022 Vaadin Ltd.
@@ -19404,7 +19404,7 @@ class FieldAriaController {
19404
19404
 
19405
19405
  /**
19406
19406
  * @license
19407
- * Copyright (c) 2021 Vaadin Ltd.
19407
+ * Copyright (c) 2021 - 2022 Vaadin Ltd.
19408
19408
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
19409
19409
  */
19410
19410
 
@@ -19414,7 +19414,7 @@ class FieldAriaController {
19414
19414
  class HelperController extends SlotController {
19415
19415
  constructor(host) {
19416
19416
  // Do not provide slot factory, as only create helper lazily.
19417
- super(host, 'helper');
19417
+ super(host, 'helper', null, null, true);
19418
19418
  }
19419
19419
 
19420
19420
  get helperId() {
@@ -19611,6 +19611,7 @@ class LabelController extends SlotController {
19611
19611
 
19612
19612
  this.__observeLabel(node);
19613
19613
  },
19614
+ true,
19614
19615
  );
19615
19616
  }
19616
19617
 
@@ -19817,6 +19818,12 @@ const LabelMixin = dedupingMixin(
19817
19818
  super();
19818
19819
 
19819
19820
  this._labelController = new LabelController(this);
19821
+ }
19822
+
19823
+ /** @protected */
19824
+ ready() {
19825
+ super.ready();
19826
+
19820
19827
  this.addController(this._labelController);
19821
19828
  }
19822
19829
 
@@ -19864,12 +19871,17 @@ const ValidateMixin = dedupingMixin(
19864
19871
  }
19865
19872
 
19866
19873
  /**
19867
- * Returns true if field is valid, and sets `invalid` based on the field validity.
19874
+ * Validates the field and sets the `invalid` property based on the result.
19875
+ *
19876
+ * The method fires a `validated` event with the result of the validation.
19868
19877
  *
19869
19878
  * @return {boolean} True if the value is valid.
19870
19879
  */
19871
19880
  validate() {
19872
- return !(this.invalid = !this.checkValidity());
19881
+ const isValid = this.checkValidity();
19882
+ this._setInvalid(!isValid);
19883
+ this.dispatchEvent(new CustomEvent('validated', { detail: { valid: isValid } }));
19884
+ return isValid;
19873
19885
  }
19874
19886
 
19875
19887
  /**
@@ -19880,6 +19892,35 @@ const ValidateMixin = dedupingMixin(
19880
19892
  checkValidity() {
19881
19893
  return !this.required || !!this.value;
19882
19894
  }
19895
+
19896
+ /**
19897
+ * @param {boolean} invalid
19898
+ * @protected
19899
+ */
19900
+ _setInvalid(invalid) {
19901
+ if (this._shouldSetInvalid(invalid)) {
19902
+ this.invalid = invalid;
19903
+ }
19904
+ }
19905
+
19906
+ /**
19907
+ * Override this method to define whether the given `invalid` state should be set.
19908
+ *
19909
+ * @param {boolean} _invalid
19910
+ * @return {boolean}
19911
+ * @protected
19912
+ */
19913
+ _shouldSetInvalid(_invalid) {
19914
+ return true;
19915
+ }
19916
+
19917
+ /**
19918
+ * Fired whenever the field is validated.
19919
+ *
19920
+ * @event validated
19921
+ * @param {Object} detail
19922
+ * @param {boolean} detail.valid the result of the validation.
19923
+ */
19883
19924
  },
19884
19925
  );
19885
19926
 
@@ -19968,10 +20009,6 @@ const FieldMixin = (superclass) =>
19968
20009
  this._helperController = new HelperController(this);
19969
20010
  this._errorController = new ErrorController(this);
19970
20011
 
19971
- this.addController(this._fieldAriaController);
19972
- this.addController(this._helperController);
19973
- this.addController(this._errorController);
19974
-
19975
20012
  this._labelController.addEventListener('label-changed', (event) => {
19976
20013
  const { hasLabel, node } = event.detail;
19977
20014
  this.__labelChanged(hasLabel, node);
@@ -19983,6 +20020,15 @@ const FieldMixin = (superclass) =>
19983
20020
  });
19984
20021
  }
19985
20022
 
20023
+ /** @protected */
20024
+ ready() {
20025
+ super.ready();
20026
+
20027
+ this.addController(this._fieldAriaController);
20028
+ this.addController(this._helperController);
20029
+ this.addController(this._errorController);
20030
+ }
20031
+
19986
20032
  /** @private */
19987
20033
  __helperChanged(hasHelper, helperNode) {
19988
20034
  if (hasHelper) {
@@ -20038,7 +20084,7 @@ const FieldMixin = (superclass) =>
20038
20084
  }
20039
20085
 
20040
20086
  /**
20041
- * @param {boolean} required
20087
+ * @param {boolean} invalid
20042
20088
  * @protected
20043
20089
  */
20044
20090
  _invalidChanged(invalid) {
@@ -20238,13 +20284,23 @@ const InputMixin = dedupingMixin(
20238
20284
  observer: '_valueChanged',
20239
20285
  notify: true,
20240
20286
  },
20287
+
20288
+ /**
20289
+ * When true, the input element has a non-empty value entered by the user.
20290
+ * @protected
20291
+ */
20292
+ _hasInputValue: {
20293
+ type: Boolean,
20294
+ value: false,
20295
+ observer: '_hasInputValueChanged',
20296
+ },
20241
20297
  };
20242
20298
  }
20243
20299
 
20244
20300
  constructor() {
20245
20301
  super();
20246
20302
 
20247
- this._boundOnInput = this._onInput.bind(this);
20303
+ this._boundOnInput = this.__onInput.bind(this);
20248
20304
  this._boundOnChange = this._onChange.bind(this);
20249
20305
  }
20250
20306
 
@@ -20259,6 +20315,7 @@ const InputMixin = dedupingMixin(
20259
20315
  * Add event listeners to the input element instance.
20260
20316
  * Override this method to add custom listeners.
20261
20317
  * @param {!HTMLElement} input
20318
+ * @protected
20262
20319
  */
20263
20320
  _addInputListeners(input) {
20264
20321
  input.addEventListener('input', this._boundOnInput);
@@ -20268,6 +20325,7 @@ const InputMixin = dedupingMixin(
20268
20325
  /**
20269
20326
  * Remove event listeners from the input element instance.
20270
20327
  * @param {!HTMLElement} input
20328
+ * @protected
20271
20329
  */
20272
20330
  _removeInputListeners(input) {
20273
20331
  input.removeEventListener('input', this._boundOnInput);
@@ -20281,7 +20339,6 @@ const InputMixin = dedupingMixin(
20281
20339
  * for example to skip this in certain conditions.
20282
20340
  * @param {string} value
20283
20341
  * @protected
20284
- * @override
20285
20342
  */
20286
20343
  _forwardInputValue(value) {
20287
20344
  // Value might be set before an input element is initialized.
@@ -20298,7 +20355,11 @@ const InputMixin = dedupingMixin(
20298
20355
  }
20299
20356
  }
20300
20357
 
20301
- /** @protected */
20358
+ /**
20359
+ * @param {HTMLElement | undefined} input
20360
+ * @param {HTMLElement | undefined} oldInput
20361
+ * @protected
20362
+ */
20302
20363
  _inputElementChanged(input, oldInput) {
20303
20364
  if (input) {
20304
20365
  this._addInputListeners(input);
@@ -20307,17 +20368,47 @@ const InputMixin = dedupingMixin(
20307
20368
  }
20308
20369
  }
20309
20370
 
20371
+ /**
20372
+ * Observer to notify about the change of private property.
20373
+ *
20374
+ * @private
20375
+ */
20376
+ _hasInputValueChanged(hasValue, oldHasValue) {
20377
+ if (hasValue || oldHasValue) {
20378
+ this.dispatchEvent(new CustomEvent('has-input-value-changed'));
20379
+ }
20380
+ }
20381
+
20382
+ /**
20383
+ * An input event listener used to update `_hasInputValue` property.
20384
+ * Do not override this method.
20385
+ *
20386
+ * @param {Event} event
20387
+ * @private
20388
+ */
20389
+ __onInput(event) {
20390
+ // In the case a custom web component is passed as `inputElement`,
20391
+ // the actual native input element, on which the event occurred,
20392
+ // can be inside shadow trees.
20393
+ const target = event.composedPath()[0];
20394
+ this._hasInputValue = target.value.length > 0;
20395
+ this._onInput(event);
20396
+ }
20397
+
20310
20398
  /**
20311
20399
  * An input event listener used to update the field value.
20312
- * Override this method with an actual implementation.
20313
- * @param {Event} _event
20400
+ *
20401
+ * @param {Event} event
20314
20402
  * @protected
20315
- * @override
20316
20403
  */
20317
20404
  _onInput(event) {
20405
+ // In the case a custom web component is passed as `inputElement`,
20406
+ // the actual native input element, on which the event occurred,
20407
+ // can be inside shadow trees.
20408
+ const target = event.composedPath()[0];
20318
20409
  // Ignore fake input events e.g. used by clear button.
20319
20410
  this.__userInput = event.isTrusted;
20320
- this.value = event.target.value;
20411
+ this.value = target.value;
20321
20412
  this.__userInput = false;
20322
20413
  }
20323
20414
 
@@ -20326,12 +20417,12 @@ const InputMixin = dedupingMixin(
20326
20417
  * Override this method with an actual implementation.
20327
20418
  * @param {Event} _event
20328
20419
  * @protected
20329
- * @override
20330
20420
  */
20331
20421
  _onChange(_event) {}
20332
20422
 
20333
20423
  /**
20334
20424
  * Toggle the has-value attribute based on the value property.
20425
+ *
20335
20426
  * @param {boolean} hasValue
20336
20427
  * @protected
20337
20428
  */
@@ -20344,10 +20435,9 @@ const InputMixin = dedupingMixin(
20344
20435
  * @param {string | undefined} newVal
20345
20436
  * @param {string | undefined} oldVal
20346
20437
  * @protected
20347
- * @override
20348
20438
  */
20349
20439
  _valueChanged(newVal, oldVal) {
20350
- this._toggleHasValue(newVal !== '' && newVal != null);
20440
+ this._toggleHasValue(this._hasValue);
20351
20441
 
20352
20442
  // Setting initial value to empty string, do nothing.
20353
20443
  if (newVal === '' && oldVal === undefined) {
@@ -20362,6 +20452,16 @@ const InputMixin = dedupingMixin(
20362
20452
  // Setting a value programmatically, sync it to input element.
20363
20453
  this._forwardInputValue(newVal);
20364
20454
  }
20455
+
20456
+ /**
20457
+ * Indicates whether the value is different from the default one.
20458
+ * Override if the `value` property has a type other than `string`.
20459
+ *
20460
+ * @protected
20461
+ */
20462
+ get _hasValue() {
20463
+ return this.value != null && this.value !== '';
20464
+ }
20365
20465
  },
20366
20466
  );
20367
20467
 
@@ -20433,26 +20533,32 @@ const InputConstraintsMixin = dedupingMixin(
20433
20533
  _createConstraintsObserver() {
20434
20534
  // This complex observer needs to be added dynamically instead of using `static get observers()`
20435
20535
  // to make it possible to tweak this behavior in classes that apply this mixin.
20436
- this._createMethodObserver(`_constraintsChanged(${this.constructor.constraints.join(', ')})`);
20536
+ this._createMethodObserver(`_constraintsChanged(stateTarget, ${this.constructor.constraints.join(', ')})`);
20437
20537
  }
20438
20538
 
20439
20539
  /**
20440
20540
  * Override this method to implement custom validation constraints.
20541
+ * @param {HTMLElement | undefined} stateTarget
20441
20542
  * @param {unknown[]} constraints
20442
20543
  * @protected
20443
20544
  */
20444
- _constraintsChanged(...constraints) {
20445
- // Prevent marking field as invalid when setting required state
20446
- // or any other constraint before a user has entered the value.
20447
- if (!this.invalid) {
20545
+ _constraintsChanged(stateTarget, ...constraints) {
20546
+ // The input element's validity cannot be determined until
20547
+ // all the necessary constraint attributes aren't set on it.
20548
+ if (!stateTarget) {
20448
20549
  return;
20449
20550
  }
20450
20551
 
20451
- if (this._hasValidConstraints(constraints)) {
20552
+ const hasConstraints = this._hasValidConstraints(constraints);
20553
+ const isLastConstraintRemoved = this.__previousHasConstraints && !hasConstraints;
20554
+
20555
+ if ((this._hasValue || this.invalid) && hasConstraints) {
20452
20556
  this.validate();
20453
- } else {
20454
- this.invalid = false;
20557
+ } else if (isLastConstraintRemoved) {
20558
+ this._setInvalid(false);
20455
20559
  }
20560
+
20561
+ this.__previousHasConstraints = hasConstraints;
20456
20562
  }
20457
20563
 
20458
20564
  /**
@@ -20508,6 +20614,22 @@ const InputControlMixin = (superclass) =>
20508
20614
  ) {
20509
20615
  static get properties() {
20510
20616
  return {
20617
+ /**
20618
+ * A pattern matched against individual characters the user inputs.
20619
+ *
20620
+ * When set, the field will prevent:
20621
+ * - `keydown` events if the entered key doesn't match `/^allowedCharPattern$/`
20622
+ * - `paste` events if the pasted text doesn't match `/^allowedCharPattern*$/`
20623
+ * - `drop` events if the dropped text doesn't match `/^allowedCharPattern*$/`
20624
+ *
20625
+ * For example, to allow entering only numbers and minus signs, use:
20626
+ * `allowedCharPattern = "[\\d-]"`
20627
+ */
20628
+ allowedCharPattern: {
20629
+ type: String,
20630
+ observer: '_allowedCharPatternChanged',
20631
+ },
20632
+
20511
20633
  /**
20512
20634
  * If true, the input text gets fully selected when the field is focused using click or touch / tap.
20513
20635
  */
@@ -20565,6 +20687,14 @@ const InputControlMixin = (superclass) =>
20565
20687
  return [...super.delegateAttrs, 'name', 'type', 'placeholder', 'readonly', 'invalid', 'title'];
20566
20688
  }
20567
20689
 
20690
+ constructor() {
20691
+ super();
20692
+
20693
+ this._boundOnPaste = this._onPaste.bind(this);
20694
+ this._boundOnDrop = this._onDrop.bind(this);
20695
+ this._boundOnBeforeInput = this._onBeforeInput.bind(this);
20696
+ }
20697
+
20568
20698
  /**
20569
20699
  * Any element extending this mixin is required to implement this getter.
20570
20700
  * It returns the reference to the clear button element.
@@ -20657,6 +20787,115 @@ const InputControlMixin = (superclass) =>
20657
20787
  this.inputElement.dispatchEvent(new Event('change', { bubbles: true }));
20658
20788
  }
20659
20789
 
20790
+ /**
20791
+ * Override a method from `InputMixin`.
20792
+ * @param {!HTMLElement} input
20793
+ * @protected
20794
+ * @override
20795
+ */
20796
+ _addInputListeners(input) {
20797
+ super._addInputListeners(input);
20798
+
20799
+ input.addEventListener('paste', this._boundOnPaste);
20800
+ input.addEventListener('drop', this._boundOnDrop);
20801
+ input.addEventListener('beforeinput', this._boundOnBeforeInput);
20802
+ }
20803
+
20804
+ /**
20805
+ * Override a method from `InputMixin`.
20806
+ * @param {!HTMLElement} input
20807
+ * @protected
20808
+ * @override
20809
+ */
20810
+ _removeInputListeners(input) {
20811
+ super._removeInputListeners(input);
20812
+
20813
+ input.removeEventListener('paste', this._boundOnPaste);
20814
+ input.removeEventListener('drop', this._boundOnDrop);
20815
+ input.removeEventListener('beforeinput', this._boundOnBeforeInput);
20816
+ }
20817
+
20818
+ /**
20819
+ * Override an event listener from `KeyboardMixin`.
20820
+ * @param {!KeyboardEvent} event
20821
+ * @protected
20822
+ * @override
20823
+ */
20824
+ _onKeyDown(event) {
20825
+ super._onKeyDown(event);
20826
+
20827
+ if (this.allowedCharPattern && !this.__shouldAcceptKey(event)) {
20828
+ event.preventDefault();
20829
+ this._markInputPrevented();
20830
+ }
20831
+ }
20832
+
20833
+ /** @protected */
20834
+ _markInputPrevented() {
20835
+ // Add input-prevented attribute for 200ms
20836
+ this.setAttribute('input-prevented', '');
20837
+ this._preventInputDebouncer = Debouncer$1.debounce(this._preventInputDebouncer, timeOut.after(200), () => {
20838
+ this.removeAttribute('input-prevented');
20839
+ });
20840
+ }
20841
+
20842
+ /** @private */
20843
+ __shouldAcceptKey(event) {
20844
+ return (
20845
+ event.metaKey ||
20846
+ event.ctrlKey ||
20847
+ !event.key || // Allow typing anything if event.key is not supported
20848
+ event.key.length !== 1 || // Allow "Backspace", "ArrowLeft" etc.
20849
+ this.__allowedCharRegExp.test(event.key)
20850
+ );
20851
+ }
20852
+
20853
+ /** @private */
20854
+ _onPaste(e) {
20855
+ if (this.allowedCharPattern) {
20856
+ const pastedText = e.clipboardData.getData('text');
20857
+ if (!this.__allowedTextRegExp.test(pastedText)) {
20858
+ e.preventDefault();
20859
+ this._markInputPrevented();
20860
+ }
20861
+ }
20862
+ }
20863
+
20864
+ /** @private */
20865
+ _onDrop(e) {
20866
+ if (this.allowedCharPattern) {
20867
+ const draggedText = e.dataTransfer.getData('text');
20868
+ if (!this.__allowedTextRegExp.test(draggedText)) {
20869
+ e.preventDefault();
20870
+ this._markInputPrevented();
20871
+ }
20872
+ }
20873
+ }
20874
+
20875
+ /** @private */
20876
+ _onBeforeInput(e) {
20877
+ // The `beforeinput` event covers all the cases for `allowedCharPattern`: keyboard, pasting and dropping,
20878
+ // but it is still experimental technology so we can't rely on it. It's used here just as an additional check,
20879
+ // because it seems to be the only way to detect and prevent specific keys on mobile devices.
20880
+ // See https://github.com/vaadin/vaadin-text-field/issues/429
20881
+ if (this.allowedCharPattern && e.data && !this.__allowedTextRegExp.test(e.data)) {
20882
+ e.preventDefault();
20883
+ this._markInputPrevented();
20884
+ }
20885
+ }
20886
+
20887
+ /** @private */
20888
+ _allowedCharPatternChanged(charPattern) {
20889
+ if (charPattern) {
20890
+ try {
20891
+ this.__allowedCharRegExp = new RegExp(`^${charPattern}$`);
20892
+ this.__allowedTextRegExp = new RegExp(`^${charPattern}*$`);
20893
+ } catch (e) {
20894
+ console.error(e);
20895
+ }
20896
+ }
20897
+ }
20898
+
20660
20899
  /**
20661
20900
  * Fired when the user commits a value change.
20662
20901
  *
@@ -20695,14 +20934,13 @@ class InputController extends SlotController {
20695
20934
  }
20696
20935
 
20697
20936
  // Ensure every instance has unique ID
20698
- const uniqueId = (InputController._uniqueInputId = 1 + InputController._uniqueInputId || 0);
20699
- host._inputId = `${host.localName}-${uniqueId}`;
20700
- node.id = host._inputId;
20937
+ node.id = this.defaultId;
20701
20938
 
20702
20939
  if (typeof callback === 'function') {
20703
20940
  callback(node);
20704
20941
  }
20705
20942
  },
20943
+ true,
20706
20944
  );
20707
20945
  }
20708
20946
  }
@@ -20884,7 +21122,9 @@ class VirtualKeyboardController {
20884
21122
  * @param {function(new:HTMLElement)} subclass
20885
21123
  */
20886
21124
  const DatePickerMixin = (subclass) =>
20887
- class VaadinDatePickerMixin extends ControllerMixin(DelegateFocusMixin(InputMixin(KeyboardMixin(subclass)))) {
21125
+ class VaadinDatePickerMixin extends ControllerMixin(
21126
+ DelegateFocusMixin(InputConstraintsMixin(KeyboardMixin(subclass))),
21127
+ ) {
20888
21128
  static get properties() {
20889
21129
  return {
20890
21130
  /**
@@ -20913,7 +21153,6 @@ const DatePickerMixin = (subclass) =>
20913
21153
  */
20914
21154
  value: {
20915
21155
  type: String,
20916
- observer: '_valueChanged',
20917
21156
  notify: true,
20918
21157
  value: '',
20919
21158
  },
@@ -20969,13 +21208,6 @@ const DatePickerMixin = (subclass) =>
20969
21208
  value: '(max-width: 420px), (max-height: 420px)',
20970
21209
  },
20971
21210
 
20972
- /**
20973
- * An array of ancestor elements whose -webkit-overflow-scrolling is forced from value
20974
- * 'touch' to value 'auto' in order to prevent them from clipping the dropdown. iOS only.
20975
- * @private
20976
- */
20977
- _touchPrevented: Array,
20978
-
20979
21211
  /**
20980
21212
  * The object used to localize this component.
20981
21213
  * To change the default localization, replace the entire
@@ -21131,7 +21363,6 @@ const DatePickerMixin = (subclass) =>
21131
21363
  */
21132
21364
  min: {
21133
21365
  type: String,
21134
- observer: '_minChanged',
21135
21366
  },
21136
21367
 
21137
21368
  /**
@@ -21145,28 +21376,26 @@ const DatePickerMixin = (subclass) =>
21145
21376
  */
21146
21377
  max: {
21147
21378
  type: String,
21148
- observer: '_maxChanged',
21149
21379
  },
21150
21380
 
21151
21381
  /**
21152
21382
  * The earliest date that can be selected. All earlier dates will be disabled.
21153
- * @type {Date | string}
21383
+ * @type {Date | undefined}
21154
21384
  * @protected
21155
21385
  */
21156
21386
  _minDate: {
21157
21387
  type: Date,
21158
- // Null does not work here because minimizer passes undefined to overlay (#351)
21159
- value: '',
21388
+ computed: '__computeMinOrMaxDate(min)',
21160
21389
  },
21161
21390
 
21162
21391
  /**
21163
21392
  * The latest date that can be selected. All later dates will be disabled.
21164
- * @type {Date | string}
21393
+ * @type {Date | undefined}
21165
21394
  * @protected
21166
21395
  */
21167
21396
  _maxDate: {
21168
21397
  type: Date,
21169
- value: '',
21398
+ computed: '__computeMinOrMaxDate(max)',
21170
21399
  },
21171
21400
 
21172
21401
  /** @private */
@@ -21181,12 +21410,6 @@ const DatePickerMixin = (subclass) =>
21181
21410
  value: isIOS,
21182
21411
  },
21183
21412
 
21184
- /** @private */
21185
- _webkitOverflowScroll: {
21186
- type: Boolean,
21187
- value: document.createElement('div').style.webkitOverflowScrolling === '',
21188
- },
21189
-
21190
21413
  /** @private */
21191
21414
  _focusOverlayOnOpen: Boolean,
21192
21415
 
@@ -21202,6 +21425,10 @@ const DatePickerMixin = (subclass) =>
21202
21425
  ];
21203
21426
  }
21204
21427
 
21428
+ static get constraints() {
21429
+ return [...super.constraints, 'min', 'max'];
21430
+ }
21431
+
21205
21432
  /**
21206
21433
  * Override a getter from `InputControlMixin` to make it optional
21207
21434
  * and to prevent warning when a clear button is missing,
@@ -21268,12 +21495,10 @@ const DatePickerMixin = (subclass) =>
21268
21495
  }
21269
21496
  }
21270
21497
 
21271
- if (this.inputElement.value === '' && this.__dispatchChange) {
21272
- this.validate();
21498
+ this.validate();
21499
+
21500
+ if (this._inputValue === '' && this.value !== '') {
21273
21501
  this.value = '';
21274
- this.__dispatchChange = false;
21275
- } else {
21276
- this.validate();
21277
21502
  }
21278
21503
  }
21279
21504
  }
@@ -21342,14 +21567,19 @@ const DatePickerMixin = (subclass) =>
21342
21567
  this.$.overlay.removeAttribute('disable-upgrade');
21343
21568
  this._overlayInitialized = true;
21344
21569
 
21345
- this.$.overlay.addEventListener('opened-changed', (e) => (this.opened = e.detail.value));
21570
+ this.$.overlay.addEventListener('opened-changed', (e) => {
21571
+ this.opened = e.detail.value;
21572
+ });
21346
21573
 
21347
21574
  this.$.overlay.addEventListener('vaadin-overlay-escape-press', () => {
21348
21575
  this._focusedDate = this._selectedDate;
21349
21576
  this._close();
21350
21577
  });
21351
21578
 
21352
- this._overlayContent.addEventListener('close', this._close.bind(this));
21579
+ this._overlayContent.addEventListener('close', () => {
21580
+ this._close();
21581
+ });
21582
+
21353
21583
  this._overlayContent.addEventListener('focus-input', this._focusAndSelect.bind(this));
21354
21584
 
21355
21585
  // User confirmed selected date by clicking the calendar.
@@ -21358,7 +21588,7 @@ const DatePickerMixin = (subclass) =>
21358
21588
 
21359
21589
  this._selectDate(e.detail.date);
21360
21590
 
21361
- this._close(e);
21591
+ this._close();
21362
21592
  });
21363
21593
 
21364
21594
  // User confirmed selected date by pressing Enter or Today.
@@ -21368,24 +21598,18 @@ const DatePickerMixin = (subclass) =>
21368
21598
  this._selectDate(e.detail.date);
21369
21599
  });
21370
21600
 
21371
- // Keep focus attribute in focusElement for styling
21601
+ // Set focus-ring attribute when moving focus to the overlay
21602
+ // by pressing Tab or arrow key, after opening it on click.
21372
21603
  this._overlayContent.addEventListener('focusin', () => {
21373
- this._setFocused(true);
21604
+ if (this._keyboardActive) {
21605
+ this._setFocused(true);
21606
+ }
21374
21607
  });
21375
21608
 
21376
21609
  this.addEventListener('mousedown', () => this.__bringToFront());
21377
21610
  this.addEventListener('touchstart', () => this.__bringToFront());
21378
21611
  }
21379
21612
 
21380
- /**
21381
- * Returns true if `value` is valid, and sets the `invalid` flag appropriately.
21382
- *
21383
- * @return {boolean} True if the value is valid and sets the `invalid` flag appropriately
21384
- */
21385
- validate() {
21386
- return !(this.invalid = !this.checkValidity());
21387
- }
21388
-
21389
21613
  /**
21390
21614
  * Returns true if the current input value satisfies all constraints (if any)
21391
21615
  *
@@ -21396,7 +21620,7 @@ const DatePickerMixin = (subclass) =>
21396
21620
  checkValidity() {
21397
21621
  const inputValid =
21398
21622
  !this._inputValue ||
21399
- (this._selectedDate && this._inputValue === this._getFormattedDate(this.i18n.formatDate, this._selectedDate));
21623
+ (!!this._selectedDate && this._inputValue === this._getFormattedDate(this.i18n.formatDate, this._selectedDate));
21400
21624
  const minMaxValid = !this._selectedDate || dateAllowed(this._selectedDate, this._minDate, this._maxDate);
21401
21625
 
21402
21626
  let inputValidity = true;
@@ -21412,6 +21636,51 @@ const DatePickerMixin = (subclass) =>
21412
21636
  return inputValid && minMaxValid && inputValidity;
21413
21637
  }
21414
21638
 
21639
+ /**
21640
+ * Override method inherited from `FocusMixin`
21641
+ * to not call `_setFocused(true)` when focus
21642
+ * is restored after closing overlay on click,
21643
+ * and to avoid removing `focus-ring` attribute.
21644
+ *
21645
+ * @param {!FocusEvent} _event
21646
+ * @return {boolean}
21647
+ * @protected
21648
+ * @override
21649
+ */
21650
+ _shouldSetFocus(_event) {
21651
+ return !this._shouldKeepFocusRing;
21652
+ }
21653
+
21654
+ /**
21655
+ * Override method inherited from `FocusMixin`
21656
+ * to prevent removing the `focused` attribute:
21657
+ * - when moving focus to the overlay content,
21658
+ * - when closing on date click / outside click.
21659
+ *
21660
+ * @param {!FocusEvent} _event
21661
+ * @return {boolean}
21662
+ * @protected
21663
+ * @override
21664
+ */
21665
+ _shouldRemoveFocus(_event) {
21666
+ return !this.opened;
21667
+ }
21668
+
21669
+ /**
21670
+ * Override method inherited from `FocusMixin`
21671
+ * to store the `focus-ring` state to restore
21672
+ * it later when closing on outside click.
21673
+ *
21674
+ * @param {boolean} focused
21675
+ * @protected
21676
+ * @override
21677
+ */
21678
+ _setFocused(focused) {
21679
+ super._setFocused(focused);
21680
+
21681
+ this._shouldKeepFocusRing = focused && this._keyboardActive;
21682
+ }
21683
+
21415
21684
  /**
21416
21685
  * Select date on user interaction and set the flag
21417
21686
  * to fire change event if necessary.
@@ -21431,10 +21700,7 @@ const DatePickerMixin = (subclass) =>
21431
21700
  }
21432
21701
 
21433
21702
  /** @private */
21434
- _close(e) {
21435
- if (e) {
21436
- e.stopPropagation();
21437
- }
21703
+ _close() {
21438
21704
  this._focus();
21439
21705
  this.close();
21440
21706
  }
@@ -21563,47 +21829,46 @@ const DatePickerMixin = (subclass) =>
21563
21829
  }
21564
21830
  }
21565
21831
 
21566
- /** @private */
21567
- _handleDateChange(property, value, oldValue) {
21568
- if (!value) {
21569
- this[property] = '';
21570
- return;
21571
- }
21832
+ /**
21833
+ * Override the value observer from `InputMixin` to implement custom
21834
+ * handling of the `value` property. The date-picker doesn't forward
21835
+ * the value directly to the input like the default implementation of `InputMixin`.
21836
+ * Instead, it parses the value into a date, puts it in `_selectedDate` which
21837
+ * is then displayed in the input with respect to the specified date format.
21838
+ *
21839
+ * @param {string | undefined} value
21840
+ * @param {string | undefined} oldValue
21841
+ * @protected
21842
+ * @override
21843
+ */
21844
+ _valueChanged(value, oldValue) {
21845
+ const newDate = this._parseDate(value);
21572
21846
 
21573
- const date = this._parseDate(value);
21574
- if (!date) {
21847
+ if (value && !newDate) {
21848
+ // The new value cannot be parsed, revert the old value.
21575
21849
  this.value = oldValue;
21576
21850
  return;
21577
21851
  }
21578
- if (!dateEquals(this[property], date)) {
21579
- this[property] = date;
21580
- if (this.value) {
21581
- this.validate();
21582
- }
21583
- }
21584
- }
21585
21852
 
21586
- /** @private */
21587
- _valueChanged(value, oldValue) {
21588
- this._handleDateChange('_selectedDate', value, oldValue);
21853
+ if (value) {
21854
+ if (!dateEquals(this._selectedDate, newDate)) {
21855
+ // Update the date instance only if the date has actually changed.
21856
+ this._selectedDate = newDate;
21589
21857
 
21590
- this._toggleHasValue(!!value);
21591
- }
21592
-
21593
- /** @private */
21594
- _minChanged(value, oldValue) {
21595
- this._handleDateChange('_minDate', value, oldValue);
21596
- }
21858
+ if (oldValue !== undefined) {
21859
+ // Validate only if `value` changes after initialization.
21860
+ this.validate();
21861
+ }
21862
+ }
21863
+ } else {
21864
+ this._selectedDate = null;
21865
+ }
21597
21866
 
21598
- /** @private */
21599
- _maxChanged(value, oldValue) {
21600
- this._handleDateChange('_maxDate', value, oldValue);
21867
+ this._toggleHasValue(this._hasValue);
21601
21868
  }
21602
21869
 
21603
21870
  /** @protected */
21604
21871
  _onOverlayOpened() {
21605
- this._openedWithFocusRing = this.hasAttribute('focus-ring');
21606
-
21607
21872
  const parsedInitialPosition = this._parseDate(this.initialPosition);
21608
21873
 
21609
21874
  const initialPosition =
@@ -21623,10 +21888,6 @@ const DatePickerMixin = (subclass) =>
21623
21888
 
21624
21889
  window.addEventListener('scroll', this._boundOnScroll, true);
21625
21890
 
21626
- if (this._webkitOverflowScroll) {
21627
- this._touchPrevented = this._preventWebkitOverflowScrollingTouch(this.parentElement);
21628
- }
21629
-
21630
21891
  if (this._focusOverlayOnOpen) {
21631
21892
  this._overlayContent.focusDateElement();
21632
21893
  this._focusOverlayOnOpen = false;
@@ -21640,25 +21901,6 @@ const DatePickerMixin = (subclass) =>
21640
21901
  }
21641
21902
  }
21642
21903
 
21643
- // A hack needed for iOS to prevent dropdown from being clipped in an
21644
- // ancestor container with -webkit-overflow-scrolling: touch;
21645
- /** @private */
21646
- _preventWebkitOverflowScrollingTouch(element) {
21647
- const result = [];
21648
- while (element) {
21649
- if (window.getComputedStyle(element).webkitOverflowScrolling === 'touch') {
21650
- const oldInlineValue = element.style.webkitOverflowScrolling;
21651
- element.style.webkitOverflowScrolling = 'auto';
21652
- result.push({
21653
- element,
21654
- oldInlineValue,
21655
- });
21656
- }
21657
- element = element.parentElement;
21658
- }
21659
- return result;
21660
- }
21661
-
21662
21904
  /** @private */
21663
21905
  _selectParsedOrFocusedDate() {
21664
21906
  // Select the parsed input or focused date
@@ -21685,13 +21927,6 @@ const DatePickerMixin = (subclass) =>
21685
21927
  _onOverlayClosed() {
21686
21928
  window.removeEventListener('scroll', this._boundOnScroll, true);
21687
21929
 
21688
- if (this._touchPrevented) {
21689
- this._touchPrevented.forEach(
21690
- (prevented) => (prevented.element.style.webkitOverflowScrolling = prevented.oldInlineValue),
21691
- );
21692
- this._touchPrevented = [];
21693
- }
21694
-
21695
21930
  // No need to select date on close if it was confirmed by the user.
21696
21931
  if (this.__userConfirmedDate) {
21697
21932
  this.__userConfirmedDate = false;
@@ -21707,11 +21942,6 @@ const DatePickerMixin = (subclass) =>
21707
21942
  if (!this.value) {
21708
21943
  this.validate();
21709
21944
  }
21710
-
21711
- // If the input isn't focused when overlay closes (fullscreen mode), clear focused state
21712
- if (this.getRootNode().activeElement !== this.inputElement) {
21713
- this._setFocused(false);
21714
- }
21715
21945
  }
21716
21946
 
21717
21947
  /** @private */
@@ -21764,10 +21994,7 @@ const DatePickerMixin = (subclass) =>
21764
21994
  _onChange(event) {
21765
21995
  // For change event on the native <input> blur, after the input is cleared,
21766
21996
  // we schedule change event to be dispatched on date-picker blur.
21767
- if (
21768
- this.inputElement.value === '' &&
21769
- !(event.detail && event.detail.sourceEvent && event.detail.sourceEvent.__fromClearButton)
21770
- ) {
21997
+ if (this._inputValue === '') {
21771
21998
  this.__dispatchChange = true;
21772
21999
  }
21773
22000
 
@@ -21854,7 +22081,7 @@ const DatePickerMixin = (subclass) =>
21854
22081
  if (e.shiftKey) {
21855
22082
  this._overlayContent.focusCancel();
21856
22083
  } else {
21857
- this._overlayContent.focusDate(this._focusedDate);
22084
+ this._overlayContent.focusDateElement();
21858
22085
  }
21859
22086
  }
21860
22087
  break;
@@ -21965,6 +22192,11 @@ const DatePickerMixin = (subclass) =>
21965
22192
  return this.$.overlay.content.querySelector('#overlay-content');
21966
22193
  }
21967
22194
 
22195
+ /** @private */
22196
+ __computeMinOrMaxDate(dateString) {
22197
+ return this._parseDate(dateString);
22198
+ }
22199
+
21968
22200
  /**
21969
22201
  * Fired when the user commits a value change.
21970
22202
  *
@@ -22076,12 +22308,13 @@ registerStyles('vaadin-date-picker', [inputFieldShared, datePickerStyles], { mod
22076
22308
  * Note: the `theme` attribute value set on `<vaadin-date-picker>` is
22077
22309
  * propagated to the internal components listed above.
22078
22310
  *
22079
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
22311
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
22080
22312
  *
22081
22313
  * @fires {Event} change - Fired when the user commits a value change.
22082
22314
  * @fires {CustomEvent} invalid-changed - Fired when the `invalid` property changes.
22083
22315
  * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
22084
22316
  * @fires {CustomEvent} value-changed - Fired when the `value` property changes.
22317
+ * @fires {CustomEvent} validated - Fired whenever the field is validated.
22085
22318
  *
22086
22319
  * @extends HTMLElement
22087
22320
  * @mixes ElementMixin
@@ -22135,7 +22368,7 @@ class DatePicker extends DatePickerMixin(InputControlMixin(ThemableMixin(Element
22135
22368
  fullscreen$="[[_fullscreen]]"
22136
22369
  theme$="[[__getOverlayTheme(_theme, _overlayInitialized)]]"
22137
22370
  on-vaadin-overlay-open="_onOverlayOpened"
22138
- on-vaadin-overlay-close="_onOverlayClosed"
22371
+ on-vaadin-overlay-closing="_onOverlayClosed"
22139
22372
  restore-focus-on-close
22140
22373
  restore-focus-node="[[inputElement]]"
22141
22374
  disable-upgrade
@@ -22195,11 +22428,6 @@ class DatePicker extends DatePickerMixin(InputControlMixin(ThemableMixin(Element
22195
22428
 
22196
22429
  /** @private */
22197
22430
  _onVaadinOverlayClose(e) {
22198
- if (this._openedWithFocusRing && this.hasAttribute('focused')) {
22199
- this.setAttribute('focus-ring', '');
22200
- } else if (!this.hasAttribute('focused')) {
22201
- this.blur();
22202
- }
22203
22431
  if (e.detail.sourceEvent && e.detail.sourceEvent.composedPath().includes(this)) {
22204
22432
  e.preventDefault();
22205
22433
  }
@@ -22223,11 +22451,12 @@ class DatePicker extends DatePickerMixin(InputControlMixin(ThemableMixin(Element
22223
22451
 
22224
22452
  customElements.define(DatePicker.is, DatePicker);
22225
22453
 
22226
- const helperFiltersCss = "@import url(\"https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap\");:host{display:block;font-family:\"Roboto\", sans-serif}.FilterButtonsWrapper{display:flex;justify-content:flex-end;gap:5px}.FilterButtonsWrapper .FilterOpen{cursor:pointer;border-radius:4px;padding:8px 15px;width:max-content;border:1px solid #00958f;background:#00958f;color:#FFF;font-size:12px;transition:all 0.2s linear;text-align:center;letter-spacing:0}.FilterButtonsWrapper .FilterOpen:hover{background:#00958f;color:#FFF}.FilterButtonsWrapper .FilterClear{cursor:pointer;border-radius:4px;padding:8px 15px;width:max-content;border:1px solid #00958f;background:#FFF;color:#000;font-size:12px;transition:all 0.2s linear;text-align:center;letter-spacing:0}.FilterButtonsWrapper .FilterClear:hover{background:#00958f;color:#FFF}.FilterModalHeader,.FilterModalBody,.FilterModalFooter{display:flex;flex-direction:column;gap:5px;align-items:center;margin:20px 0}.FilterModalHeader .FilterModalTitle,.FilterModalBody .FilterModalTitle,.FilterModalFooter .FilterModalTitle{margin:0;padding:0;font-weight:700;font-size:16px;color:#009993;text-transform:uppercase}.FilterModalHeader .FilterModalSearch,.FilterModalBody .FilterModalSearch,.FilterModalFooter .FilterModalSearch{border-radius:4px;background:#e8ebef;color:#263445;width:100%;height:26px;max-width:280px;padding:5px;font-size:15px;border:none;outline:#009993}.FilterModalHeader .FilterCalendarWrapper,.FilterModalBody .FilterCalendarWrapper,.FilterModalFooter .FilterCalendarWrapper{display:flex;gap:5px}.FilterModalHeader .FilterCalendarWrapper .VaadinDatePicker,.FilterModalBody .FilterCalendarWrapper .VaadinDatePicker,.FilterModalFooter .FilterCalendarWrapper .VaadinDatePicker{width:50%;max-width:143px}.FilterModalHeader .FilterModalButton,.FilterModalBody .FilterModalButton,.FilterModalFooter .FilterModalButton{cursor:pointer;border-radius:4px;padding:8px 60px;width:max-content;margin:5px;border:1px solid #00958f;background:#00958f;color:#FFF;font-size:12px;transition:all 0.2s linear;text-transform:uppercase;text-align:center;letter-spacing:0}.FilterModalHeader .FilterModalButton:hover,.FilterModalBody .FilterModalButton:hover,.FilterModalFooter .FilterModalButton:hover{background:#00958f;color:#FFF}";
22454
+ const helperFiltersCss = "@import url(\"https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap\");:host{display:block;font-family:\"Roboto\", sans-serif}.FilterButtonsWrapper{display:flex;justify-content:flex-end;gap:5px}.FilterButtonsWrapper .FilterOpen{cursor:pointer;border-radius:4px;padding:8px 15px;width:max-content;border:1px solid #00958f;background:#00958f;color:#FFF;font-size:12px;transition:all 0.2s linear;text-align:center;letter-spacing:0}.FilterButtonsWrapper .FilterOpen:hover{background:#00958f;color:#FFF}.FilterButtonsWrapper .FilterClear{cursor:pointer;border-radius:4px;padding:8px 15px;width:max-content;border:1px solid #00958f;background:#FFF;color:#000;font-size:12px;transition:all 0.2s linear;text-align:center;letter-spacing:0}.FilterButtonsWrapper .FilterClear:hover{background:#00958f;color:#FFF}.FilterModalHeader,.FilterModalBody,.FilterModalFooter{display:flex;flex-direction:column;gap:5px;align-items:center;margin:20px 0}.FilterModalHeader .FilterModalTitle,.FilterModalBody .FilterModalTitle,.FilterModalFooter .FilterModalTitle{margin:0;padding:0;font-weight:700;font-size:16px;color:#009993;text-transform:uppercase}.FilterModalHeader .FilterModalSearch,.FilterModalBody .FilterModalSearch,.FilterModalFooter .FilterModalSearch{border-radius:4px;background:#e8ebef;color:#263445;width:100%;height:26px;max-width:280px;padding:5px;font-size:15px;border:none;outline:#009993}.FilterModalHeader .FilterCalendarWrapper,.FilterModalBody .FilterCalendarWrapper,.FilterModalFooter .FilterCalendarWrapper{display:flex;gap:5px}.FilterModalHeader .FilterCalendarWrapper .VaadinDatePicker,.FilterModalBody .FilterCalendarWrapper .VaadinDatePicker,.FilterModalFooter .FilterCalendarWrapper .VaadinDatePicker{width:50%;max-width:143px}.FilterModalHeader .FilterModalButton,.FilterModalBody .FilterModalButton,.FilterModalFooter .FilterModalButton{cursor:pointer;border-radius:4px;padding:8px 60px;width:max-content;margin:5px;border:1px solid #00958f;background:#00958f;color:#FFF;font-size:12px;transition:all 0.2s linear;text-transform:uppercase;text-align:center;letter-spacing:0}.FilterModalHeader .FilterModalButton:hover,.FilterModalBody .FilterModalButton:hover,.FilterModalFooter .FilterModalButton:hover{background:#00958f;color:#FFF}.FilterModalHeader p,.FilterModalBody p,.FilterModalFooter p{margin:5px 0}";
22227
22455
 
22228
22456
  const HelperFilters = class {
22229
22457
  constructor(hostRef) {
22230
22458
  registerInstance(this, hostRef);
22459
+ this.filterDraw = createEvent(this, "filterDraw", 7);
22231
22460
  this.filterSelection = createEvent(this, "filterSelection", 7);
22232
22461
  this.filterSelectionReset = createEvent(this, "filterSelectionReset", 7);
22233
22462
  /**
@@ -22261,23 +22490,29 @@ const HelperFilters = class {
22261
22490
  this.showFilterModal = false;
22262
22491
  this.showClearButton = false;
22263
22492
  this.filterData = {};
22264
- this.filterDataReset = { drawTicketId: '', filterFromCalendar: '', filterToCalendar: '' };
22493
+ this.filterDataReset = { ticketDrawId: '', filterFromCalendar: '', filterToCalendar: '' };
22494
+ }
22495
+ // reset field values each time the filter modal opens
22496
+ componentDidRender() {
22497
+ this.filterData.ticketDrawId = null;
22498
+ this.filterData.filterFromCalendar = null;
22499
+ this.filterData.filterToCalendar = null;
22500
+ // @TODO: to way binding?
22501
+ if (document.getElementById('#FilterById'))
22502
+ document.getElementById('#FilterById').value = '';
22265
22503
  }
22266
22504
  filterSelectionHandler(event) {
22267
- if (this.postMessage) {
22505
+ if (this.postMessage)
22268
22506
  window.postMessage({ type: 'filterSelection', event }, window.location.href);
22269
- }
22270
- else {
22507
+ if (this.filterData.ticketDrawId)
22508
+ this.filterDraw.emit(event);
22509
+ if (this.filterData.filterFromCalendar || this.filterData.filterToCalendar)
22271
22510
  this.filterSelection.emit(event);
22272
- }
22273
22511
  }
22274
22512
  filterSelectionResetHandler(event) {
22275
- if (this.postMessage) {
22513
+ if (this.postMessage)
22276
22514
  window.postMessage({ type: 'filterSelectionReset', event }, window.location.href);
22277
- }
22278
- else {
22279
- this.filterSelectionReset.emit(event);
22280
- }
22515
+ this.filterSelectionReset.emit(event);
22281
22516
  }
22282
22517
  modalCloseEvent() {
22283
22518
  this.showFilterModal = false;
@@ -22295,9 +22530,10 @@ const HelperFilters = class {
22295
22530
  resetSearch() {
22296
22531
  this.showClearButton = false;
22297
22532
  this.filterSelectionResetHandler(this.filterDataReset);
22533
+ this.filterData = {};
22298
22534
  }
22299
- handleDrawTicketId(event) {
22300
- this.filterData.drawTicketId = event.target.value;
22535
+ handleTicketDrawId(event) {
22536
+ this.filterData.ticketDrawId = event.target.value;
22301
22537
  }
22302
22538
  handleFilterFrom(event) {
22303
22539
  this.filterData.filterFromCalendar = new Date(event.target.value).toISOString();
@@ -22306,7 +22542,7 @@ const HelperFilters = class {
22306
22542
  this.filterData.filterToCalendar = new Date(event.target.value).toISOString();
22307
22543
  }
22308
22544
  render() {
22309
- return (h$2("div", { class: "HelperFilters" }, h$2("div", { class: "FilterButtonsWrapper" }, h$2("button", { class: "FilterOpen", onClick: () => this.toggleFilterModal() }, translate$1('filterOpen', this.language)), this.showClearButton ? h$2("button", { class: "FilterClear", onClick: () => this.resetSearch() }, translate$1('filterClear', this.language)) : null), h$2("helper-modal", { "title-modal": "Filter Modal", visible: this.showFilterModal }, h$2("div", { class: "FilterModalHeader" }, h$2("h3", { class: "FilterModalTitle" }, this.activateTicketSearch ? translate$1('filterModalTicketTitle', this.language) : translate$1('filterModalDrawTitle', this.language))), h$2("div", { class: "FilterModalBody" }, h$2("input", { type: "text", value: this.filterData.drawTicketId, onInput: (event) => this.handleDrawTicketId(event), class: "FilterModalSearch", placeholder: this.activateTicketSearch ? translate$1('filterTicketPlaceholder', this.language) : translate$1('filterDrawPlaceholder', this.language) }), h$2("div", { class: "FilterCalendarWrapper" }, h$2("vaadin-date-picker", { value: this.filterData.filterFromCalendar, onChange: (event) => this.handleFilterFrom(event), placeholder: translate$1('filterFromCalendar', this.language), class: "VaadinDatePicker" }), h$2("vaadin-date-picker", { value: this.filterData.filterToCalendar, onChange: (event) => this.handleFilterTo(event), placeholder: translate$1('filterToCalendar', this.language), class: "VaadinDatePicker" }))), h$2("div", { class: "FilterModalFooter" }, h$2("button", { class: "FilterModalButton", onClick: () => this.filterSearch() }, translate$1('filterModalButton', this.language))))));
22545
+ return (h$2("div", { class: "HelperFilters" }, h$2("div", { class: "FilterButtonsWrapper" }, h$2("button", { class: "FilterOpen", onClick: () => this.toggleFilterModal() }, translate$1('filterOpen', this.language)), this.showClearButton ? h$2("button", { class: "FilterClear", onClick: () => this.resetSearch() }, translate$1('filterClear', this.language)) : null), h$2("helper-modal", { "title-modal": "Filter Modal", visible: this.showFilterModal }, h$2("div", { class: "FilterModalHeader" }, h$2("h3", { class: "FilterModalTitle" }, this.activateTicketSearch ? translate$1('filterModalTicketTitle', this.language) : translate$1('filterModalDrawTitle', this.language))), h$2("div", { class: "FilterModalBody" }, h$2("input", { id: "FilterById", type: "text", value: this.filterData.ticketDrawId, onInput: (event) => this.handleTicketDrawId(event), class: "FilterModalSearch", placeholder: this.activateTicketSearch ? translate$1('filterTicketPlaceholder', this.language) : translate$1('filterDrawPlaceholder', this.language) }), h$2("p", null, translate$1('filterOrDate', this.language)), h$2("div", { class: "FilterCalendarWrapper" }, h$2("vaadin-date-picker", { value: this.filterData.filterFromCalendar, onChange: (event) => this.handleFilterFrom(event), placeholder: translate$1('filterFromCalendar', this.language), class: "VaadinDatePicker" }), h$2("vaadin-date-picker", { value: this.filterData.filterToCalendar, onChange: (event) => this.handleFilterTo(event), placeholder: translate$1('filterToCalendar', this.language), class: "VaadinDatePicker" }))), h$2("div", { class: "FilterModalFooter" }, h$2("button", { class: "FilterModalButton", onClick: () => this.filterSearch() }, translate$1('filterModalButton', this.language))))));
22310
22546
  }
22311
22547
  };
22312
22548
  HelperFilters.style = helperFiltersCss;