cx 25.6.1 → 25.6.3

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.
@@ -68,7 +68,8 @@ export class MonthPicker extends Field {
68
68
  super.init();
69
69
  }
70
70
 
71
- prepareData(context, { data }) {
71
+ prepareData(context, instance) {
72
+ let { data } = instance;
72
73
  data.stateMods = {
73
74
  disabled: data.disabled,
74
75
  };
@@ -91,6 +92,14 @@ export class MonthPicker extends Field {
91
92
 
92
93
  if (data.minValue) data.minValue = monthStart(parseDateInvariant(data.minValue));
93
94
 
95
+ if (this.onCreateIsMonthDateSelectable) {
96
+ instance.isMonthDateSelectable = instance.invoke(
97
+ "onCreateIsMonthDateSelectable",
98
+ data.validationParams,
99
+ instance,
100
+ );
101
+ }
102
+
94
103
  super.prepareData(...arguments);
95
104
  }
96
105
 
@@ -129,12 +138,13 @@ export class MonthPicker extends Field {
129
138
  }
130
139
 
131
140
  handleSelect(e, instance, date1, date2) {
132
- let { data, widget } = instance;
141
+ let { data, widget, isMonthDateSelectable } = instance;
133
142
  let encode = widget.encoding || Culture.getDefaultDateEncoding();
134
143
 
135
144
  if (data.disabled) return;
136
145
 
137
- if (!validationCheck(date1, data)) return;
146
+ if (isMonthDateSelectable && !isMonthDateSelectable(date1)) return;
147
+ if (!dateSelectableCheck(date1, data)) return;
138
148
 
139
149
  if (this.onBeforeSelect && instance.invoke("onBeforeSelect", e, instance, date1, date2) === false) return;
140
150
 
@@ -167,7 +177,7 @@ Localization.registerPrototype("cx/widgets/MonthPicker", MonthPicker);
167
177
 
168
178
  Widget.alias("month-picker", MonthPicker);
169
179
 
170
- const validationCheck = (date, data) => {
180
+ const dateSelectableCheck = (date, data) => {
171
181
  if (data.maxValue && !upperBoundCheck(date, data.maxValue, data.maxExclusive)) return false;
172
182
 
173
183
  if (data.minValue && !lowerBoundCheck(date, data.minValue, data.minExclusive)) return false;
@@ -429,7 +439,7 @@ export class MonthPickerComponent extends VDOM.Component {
429
439
 
430
440
  render() {
431
441
  let { instance } = this.props;
432
- let { data, widget } = instance;
442
+ let { data, widget, isMonthDateSelectable } = instance;
433
443
  let { CSS, baseClass, startYear, endYear, hideQuarters } = widget;
434
444
 
435
445
  let years = [];
@@ -464,29 +474,48 @@ export class MonthPickerComponent extends VDOM.Component {
464
474
  let showCursor = this.state.hover || this.state.focused;
465
475
 
466
476
  for (let y = start; y <= end; y++) {
477
+ let selectableMonths = 0b111111111111;
478
+ // Loop through the months in a year to check if all months are unselectable
479
+ for (let i = 0; i < 12; i++) {
480
+ if (
481
+ (isMonthDateSelectable && !isMonthDateSelectable(new Date(y, i, 1))) ||
482
+ !dateSelectableCheck(new Date(y, i, 1), data)
483
+ ) {
484
+ // Set month as unselectable at specified bit
485
+ selectableMonths &= ~(1 << i);
486
+ }
487
+ }
488
+
489
+ // All bits are 0 - all months are unselectable
490
+ const unselectableYear = selectableMonths === 0;
491
+
467
492
  let rows = [];
468
493
  for (let q = 0; q < 4; q++) {
469
494
  let row = [];
470
- if (q == 0)
495
+ if (q == 0) {
471
496
  row.push(
472
497
  <th
473
498
  key="year"
474
499
  rowSpan={4}
475
500
  data-point={`Y-${y}`}
476
- className={CSS.element(baseClass, "year", {
477
- cursor: showCursor && this.state.column == "Y" && y == this.state.cursorYear,
478
- })}
479
- onMouseEnter={this.handleMouseEnter}
480
- onMouseDown={this.handleMouseDown}
481
- onMouseUp={this.handleMouseUp}
501
+ className={CSS.expand(
502
+ CSS.element(baseClass, "year", {
503
+ cursor: showCursor && this.state.column == "Y" && y == this.state.cursorYear,
504
+ }),
505
+ CSS.state({ unselectable: unselectableYear }),
506
+ )}
507
+ onMouseEnter={unselectableYear ? null : this.handleMouseEnter}
508
+ onMouseDown={unselectableYear ? null : this.handleMouseDown}
509
+ onMouseUp={unselectableYear ? null : this.handleMouseUp}
482
510
  >
483
511
  {y}
484
512
  </th>,
485
513
  );
514
+ }
486
515
 
487
516
  for (let i = 0; i < 3; i++) {
488
517
  let m = q * 3 + i + 1;
489
- let unselectable = !validationCheck(new Date(y, m - 1, 1), data);
518
+ const unselectableMonth = (selectableMonths & (1 << (m - 1))) === 0;
490
519
  let mno = y * 12 + m - 1;
491
520
  let handle = true; //isTouchDevice(); //mno === from || mno === to - 1;
492
521
  row.push(
@@ -500,14 +529,14 @@ export class MonthPickerComponent extends VDOM.Component {
500
529
  m == this.state.cursorMonth,
501
530
  handle,
502
531
  selected: mno >= from && mno < to,
503
- unselectable,
532
+ unselectable: unselectableMonth,
504
533
  })}
505
534
  data-point={`Y-${y}-M-${m}`}
506
- onMouseEnter={unselectable ? null : this.handleMouseEnter}
507
- onMouseDown={unselectable ? null : this.handleMouseDown}
508
- onMouseUp={unselectable ? null : this.handleMouseUp}
509
- onTouchStart={unselectable ? null : this.handleMouseDown}
510
- onTouchMove={unselectable ? null : this.handleTouchMove}
535
+ onMouseEnter={unselectableMonth ? null : this.handleMouseEnter}
536
+ onMouseDown={unselectableMonth ? null : this.handleMouseDown}
537
+ onMouseUp={unselectableMonth ? null : this.handleMouseUp}
538
+ onTouchStart={unselectableMonth ? null : this.handleMouseDown}
539
+ onTouchMove={unselectableMonth ? null : this.handleTouchMove}
511
540
  onTouchEnd={this.handleMouseUp}
512
541
  >
513
542
  {monthNames[m - 1].substr(0, 3)}
@@ -515,7 +544,17 @@ export class MonthPickerComponent extends VDOM.Component {
515
544
  );
516
545
  }
517
546
 
518
- if (!hideQuarters)
547
+ if (!hideQuarters) {
548
+ let unselectableQuarter = true;
549
+ const start = q * 3;
550
+ for (let i = start; i < start + 3; i++) {
551
+ if ((selectableMonths & (1 << i)) !== 0) {
552
+ // found a selectable month in a quarter
553
+ unselectableQuarter = false;
554
+ break;
555
+ }
556
+ }
557
+
519
558
  row.push(
520
559
  <th
521
560
  key={`q${q}`}
@@ -525,15 +564,18 @@ export class MonthPickerComponent extends VDOM.Component {
525
564
  this.state.column == "Q" &&
526
565
  y == this.state.cursorYear &&
527
566
  q == this.state.cursorQuarter,
567
+ unselectable: unselectableQuarter,
528
568
  })}
529
569
  data-point={`Y-${y}-Q-${q}`}
530
- onMouseEnter={this.handleMouseEnter}
531
- onMouseDown={this.handleMouseDown}
532
- onMouseUp={this.handleMouseUp}
570
+ onMouseEnter={unselectableQuarter ? null : this.handleMouseEnter}
571
+ onMouseDown={unselectableQuarter ? null : this.handleMouseDown}
572
+ onMouseUp={unselectableQuarter ? null : this.handleMouseUp}
533
573
  >
534
574
  {`Q${q + 1}`}
535
575
  </th>,
536
576
  );
577
+ }
578
+
537
579
  rows.push(row);
538
580
  }
539
581
  years.push(rows);
@@ -1,118 +1,122 @@
1
- @mixin cx-monthpicker($name: "monthpicker", $state-style-map: $cx-input-state-style-map, $besm: $cx-besm) {
2
- $block: map-get($besm, block);
3
- $element: map-get($besm, element);
4
- $state: map-get($besm, state);
5
-
6
- .#{$block}#{$name} {
7
- overflow-y: scroll;
8
- overflow-x: hidden;
9
- min-height: 10em;
10
- max-height: 30em; //100vh;
11
- height: 100%;
12
- position: relative;
13
- width: 23em;
14
- overflow-anchor: none;
15
- touch-action: pan-y;
16
-
17
- @include cxe-field-input($besm, $state-style-map, $input: false);
18
-
19
- table {
20
- border-spacing: 0;
21
- width: 100%;
22
- font-size: 0.9em;
23
- }
24
-
25
- $border-color: cx-get-state-rule($state-style-map, default, border-color);
26
-
27
- th,
28
- td {
29
- border-top: 1px solid transparentize($border-color, 0.5);
30
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
31
- }
32
-
33
- tbody:not(:first-child) {
34
- tr:first-child {
35
- th,
36
- td {
37
- border-top: 1px solid $border-color;
38
- }
39
- }
40
- }
41
-
42
- th,
43
- td {
44
- text-align: center;
45
- font-size: $cx-default-monthpicker-font-size;
46
- font-weight: $cx-default-monthpicker-font-weight;
47
- line-height: 2em;
48
- cursor: pointer;
49
- -webkit-user-select: none;
50
- -ms-user-select: none;
51
- -moz-user-select: none;
52
- user-select: none;
53
- }
54
-
55
- th {
56
- padding: 0 0.5em;
57
- color: lightgray;
58
- }
59
-
60
- .#{$element}#{$name}-year {
61
- font-size: 120%;
62
- color: gray;
63
- }
64
-
65
- td {
66
- padding: 0.5em 1em;
67
- }
68
-
69
- td.#{$state}outside {
70
- color: lightgray;
71
- }
72
-
73
- td.#{$state}unselectable {
74
- @include cx-add-state-rules($cx-list-item, disabled);
75
- }
76
-
77
- td.#{$state}selected {
78
- border-color: transparent;
79
- @include cx-add-state-rules($cx-list-item, selected);
80
-
81
- &:hover {
82
- @include cx-add-state-rules($cx-list-item, selected-hover);
83
- }
84
- }
85
-
86
- td.#{$state}cursor,
87
- th.#{$state}cursor {
88
- @include cx-add-state-rules($cx-list-item, hover);
89
- }
90
-
91
- &:focus {
92
- td.#{$state}selected {
93
- @include cx-add-state-rules($cx-list-item, selected);
94
- }
95
-
96
- td.#{$state}cursor,
97
- th.#{$state}cursor {
98
- @include cx-add-state-rules($cx-list-item, selected-cursor);
99
- }
100
- }
101
-
102
- td.#{$state}handle {
103
- //@include cx-add-state-rules($cx-list-item, selected-cursor);
104
- touch-action: none;
105
- }
106
- }
107
-
108
- .#{$block}#{$name}.#{$state}disabled {
109
- background-color: transparent;
110
- border-color: transparent;
111
- color: darken(#fff, 18);
112
- pointer-events: none;
113
- }
114
- }
115
-
116
- @if (cx-should-include("cx/widgets/MonthPicker")) {
117
- @include cx-monthpicker();
118
- }
1
+ @mixin cx-monthpicker($name: "monthpicker", $state-style-map: $cx-input-state-style-map, $besm: $cx-besm) {
2
+ $block: map-get($besm, block);
3
+ $element: map-get($besm, element);
4
+ $state: map-get($besm, state);
5
+
6
+ .#{$block}#{$name} {
7
+ overflow-y: scroll;
8
+ overflow-x: hidden;
9
+ min-height: 10em;
10
+ max-height: 30em; //100vh;
11
+ height: 100%;
12
+ position: relative;
13
+ width: 23em;
14
+ overflow-anchor: none;
15
+ touch-action: pan-y;
16
+
17
+ @include cxe-field-input($besm, $state-style-map, $input: false);
18
+
19
+ table {
20
+ border-spacing: 0;
21
+ width: 100%;
22
+ font-size: 0.9em;
23
+ }
24
+
25
+ $border-color: cx-get-state-rule($state-style-map, default, border-color);
26
+
27
+ th,
28
+ td {
29
+ border-top: 1px solid transparentize($border-color, 0.5);
30
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
31
+ }
32
+
33
+ tbody:not(:first-child) {
34
+ tr:first-child {
35
+ th,
36
+ td {
37
+ border-top: 1px solid $border-color;
38
+ }
39
+ }
40
+ }
41
+
42
+ th,
43
+ td {
44
+ text-align: center;
45
+ font-size: $cx-default-monthpicker-font-size;
46
+ font-weight: $cx-default-monthpicker-font-weight;
47
+ line-height: 2em;
48
+ cursor: pointer;
49
+ -webkit-user-select: none;
50
+ -ms-user-select: none;
51
+ -moz-user-select: none;
52
+ user-select: none;
53
+ }
54
+
55
+ th {
56
+ padding: 0 0.5em;
57
+ color: lightgray;
58
+ }
59
+
60
+ th.#{$state}unselectable {
61
+ @include cx-add-state-rules($cx-list-item, disabled);
62
+ }
63
+
64
+ .#{$element}#{$name}-year {
65
+ font-size: 120%;
66
+ color: gray;
67
+ }
68
+
69
+ td {
70
+ padding: 0.5em 1em;
71
+ }
72
+
73
+ td.#{$state}outside {
74
+ color: lightgray;
75
+ }
76
+
77
+ td.#{$state}unselectable {
78
+ @include cx-add-state-rules($cx-list-item, disabled);
79
+ }
80
+
81
+ td.#{$state}selected {
82
+ border-color: transparent;
83
+ @include cx-add-state-rules($cx-list-item, selected);
84
+
85
+ &:hover {
86
+ @include cx-add-state-rules($cx-list-item, selected-hover);
87
+ }
88
+ }
89
+
90
+ td.#{$state}cursor,
91
+ th.#{$state}cursor {
92
+ @include cx-add-state-rules($cx-list-item, hover);
93
+ }
94
+
95
+ &:focus {
96
+ td.#{$state}selected {
97
+ @include cx-add-state-rules($cx-list-item, selected);
98
+ }
99
+
100
+ td.#{$state}cursor,
101
+ th.#{$state}cursor {
102
+ @include cx-add-state-rules($cx-list-item, selected-cursor);
103
+ }
104
+ }
105
+
106
+ td.#{$state}handle {
107
+ //@include cx-add-state-rules($cx-list-item, selected-cursor);
108
+ touch-action: none;
109
+ }
110
+ }
111
+
112
+ .#{$block}#{$name}.#{$state}disabled {
113
+ background-color: transparent;
114
+ border-color: transparent;
115
+ color: darken(#fff, 18);
116
+ pointer-events: none;
117
+ }
118
+ }
119
+
120
+ @if (cx-should-include("cx/widgets/MonthPicker")) {
121
+ @include cx-monthpicker();
122
+ }