cx 26.4.3 → 26.5.1

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.
Files changed (74) hide show
  1. package/build/charts/axis/Axis.d.ts +8 -0
  2. package/build/charts/axis/Axis.d.ts.map +1 -1
  3. package/build/charts/axis/Axis.js +18 -1
  4. package/build/charts/axis/TimeAxis.js +1 -0
  5. package/build/data/AugmentedViewBase.d.ts.map +1 -1
  6. package/build/data/AugmentedViewBase.js +5 -4
  7. package/build/data/View.d.ts +0 -1
  8. package/build/data/View.d.ts.map +1 -1
  9. package/build/data/View.js +1 -3
  10. package/build/ui/Format.d.ts.map +1 -1
  11. package/build/ui/Format.js +26 -2
  12. package/build/util/Format.d.ts.map +1 -1
  13. package/build/util/Format.js +6 -0
  14. package/build/util/date/dateQuarter.d.ts +7 -0
  15. package/build/util/date/dateQuarter.d.ts.map +1 -0
  16. package/build/util/date/dateQuarter.js +8 -0
  17. package/build/util/date/dayBefore.d.ts +12 -0
  18. package/build/util/date/dayBefore.d.ts.map +1 -0
  19. package/build/util/date/dayBefore.js +15 -0
  20. package/build/util/date/index.d.ts +2 -0
  21. package/build/util/date/index.d.ts.map +1 -1
  22. package/build/util/date/index.js +2 -0
  23. package/build/widgets/form/DateTimePicker.d.ts.map +1 -1
  24. package/build/widgets/form/DateTimePicker.js +53 -31
  25. package/build/widgets/form/Field.d.ts.map +1 -1
  26. package/build/widgets/form/Field.js +2 -1
  27. package/build/widgets/form/LookupField.js +2 -1
  28. package/build/widgets/form/Wheel.d.ts +8 -0
  29. package/build/widgets/form/Wheel.d.ts.map +1 -1
  30. package/build/widgets/form/Wheel.js +30 -7
  31. package/build/widgets/grid/Grid.d.ts +1 -1
  32. package/build/widgets/grid/Grid.d.ts.map +1 -1
  33. package/dist/charts.css +6 -0
  34. package/dist/charts.js +18 -1
  35. package/dist/data.js +5 -4
  36. package/dist/manifest.js +772 -763
  37. package/dist/ui.js +33 -1
  38. package/dist/util.js +32 -0
  39. package/dist/widgets.css +9 -3
  40. package/dist/widgets.js +230 -174
  41. package/package.json +1 -1
  42. package/src/charts/RangeMarker.scss +3 -0
  43. package/src/charts/axis/Axis.tsx +31 -1
  44. package/src/charts/axis/TimeAxis.tsx +1 -0
  45. package/src/charts/index.scss +1 -0
  46. package/src/data/AugmentedViewBase.ts +5 -4
  47. package/src/data/View.ts +16 -61
  48. package/src/ui/DataProxy.ts +55 -55
  49. package/src/ui/Format.spec.ts +32 -0
  50. package/src/ui/Format.ts +27 -2
  51. package/src/ui/Rescope.ts +50 -50
  52. package/src/ui/adapter/ArrayAdapter.ts +229 -229
  53. package/src/ui/exprHelpers.ts +96 -96
  54. package/src/util/Format.spec.ts +11 -0
  55. package/src/util/Format.ts +7 -0
  56. package/src/util/date/dateQuarter.ts +8 -0
  57. package/src/util/date/dayBefore.ts +15 -0
  58. package/src/util/date/index.ts +2 -0
  59. package/src/widgets/Sandbox.ts +104 -104
  60. package/src/widgets/form/ColorField.scss +112 -112
  61. package/src/widgets/form/DateTimeField.scss +111 -111
  62. package/src/widgets/form/DateTimePicker.tsx +453 -392
  63. package/src/widgets/form/Field.tsx +2 -1
  64. package/src/widgets/form/LookupField.maps.scss +26 -26
  65. package/src/widgets/form/LookupField.scss +10 -3
  66. package/src/widgets/form/LookupField.tsx +4 -1
  67. package/src/widgets/form/MonthField.scss +113 -113
  68. package/src/widgets/form/NumberField.scss +72 -72
  69. package/src/widgets/form/Select.scss +104 -104
  70. package/src/widgets/form/TextField.scss +66 -66
  71. package/src/widgets/form/ValidationGroup.spec.tsx +30 -1
  72. package/src/widgets/form/Wheel.tsx +36 -7
  73. package/src/widgets/grid/Grid.tsx +1 -1
  74. package/src/widgets/nav/MenuItem.tsx +525 -525
package/dist/widgets.js CHANGED
@@ -6708,6 +6708,7 @@ class Field extends PureContainerBase {
6708
6708
  data._readOnly = data.readOnly;
6709
6709
  data._viewMode = data.mode === "view" || data.viewMode;
6710
6710
  data._tabOnEnterKey = data.tabOnEnterKey;
6711
+ data._visited = data.visited;
6711
6712
  data.validationValue = this.getValidationValue(data);
6712
6713
  instance.parentDisabled = context.parentDisabled;
6713
6714
  instance.parentReadOnly = context.parentReadOnly;
@@ -6745,7 +6746,7 @@ class Field extends PureContainerBase {
6745
6746
  data._tabOnEnterKey,
6746
6747
  context.parentTabOnEnterKey,
6747
6748
  );
6748
- data.visited = coalesce(context.parentStrict ? context.parentVisited : null, data.visited, context.parentVisited);
6749
+ data.visited = coalesce(context.parentStrict ? context.parentVisited : null, data._visited, context.parentVisited);
6749
6750
  if (!data.error && !data.disabled && !data.viewMode) this.validate(context, instance);
6750
6751
  if (data.visited && !state?.visited) {
6751
6752
  //feels hacky but it should be ok since we're in the middle of a new render cycle
@@ -9153,7 +9154,11 @@ class LookupComponent extends VDOM.Component {
9153
9154
  text = this.getPlaceholder(data.placeholder);
9154
9155
  }
9155
9156
  } else {
9156
- text = !data.empty ? data.text || this.getPlaceholder() : this.getPlaceholder(data.placeholder);
9157
+ let content = !data.empty ? data.text || this.getPlaceholder() : this.getPlaceholder(data.placeholder);
9158
+ text = jsx("span", {
9159
+ className: CSS.element(baseClass, "text"),
9160
+ children: content,
9161
+ });
9157
9162
  }
9158
9163
  let states = {
9159
9164
  visited: state.visited,
@@ -13160,6 +13165,9 @@ class Wheel extends PureContainerBase {
13160
13165
  Wheel.prototype.baseClass = "wheel";
13161
13166
  Wheel.prototype.size = 3;
13162
13167
  Wheel.prototype.styled = true;
13168
+ /** A cyclic wheel renders its option list this many times, leaving scroll
13169
+ * headroom on both sides of the centre copy. */
13170
+ const WHEEL_BUFFER_COPIES = 3;
13163
13171
  class WheelComponent extends VDOM.Component {
13164
13172
  index;
13165
13173
  wheelEl;
@@ -13181,28 +13189,34 @@ class WheelComponent extends VDOM.Component {
13181
13189
  wheelRef;
13182
13190
  scrollRef;
13183
13191
  render() {
13184
- let { size, children, CSS, baseClass, active, className, style, onMouseDown } = this.props;
13192
+ let { size, children, CSS, baseClass, active, className, style, onMouseDown, cycle } = this.props;
13185
13193
  let optionClass = CSS.element(baseClass, "option");
13186
13194
  let dummyClass = CSS.element(baseClass, "option", {
13187
13195
  dummy: true,
13188
13196
  });
13197
+ // A cyclic wheel repeats the option list so it can scroll past either end.
13198
+ let options = children;
13199
+ if (cycle) {
13200
+ options = [];
13201
+ for (let i = 0; i < WHEEL_BUFFER_COPIES; i++) options.push(...children);
13202
+ }
13189
13203
  let tpad = [],
13190
13204
  bpad = [];
13191
13205
  for (let i = 0; i < (size - 1) / 2; i++) {
13192
13206
  tpad.push({
13193
13207
  key: -1 - i,
13194
- child: children[0],
13208
+ child: options[0],
13195
13209
  cls: dummyClass,
13196
13210
  });
13197
13211
  bpad.push({
13198
13212
  key: -100 - i,
13199
- child: children[0],
13213
+ child: options[0],
13200
13214
  cls: dummyClass,
13201
13215
  });
13202
13216
  }
13203
13217
  let displayedOptions = [
13204
13218
  ...tpad,
13205
- ...children.map((c, i) => ({
13219
+ ...options.map((c, i) => ({
13206
13220
  key: i,
13207
13221
  child: c,
13208
13222
  cls: optionClass,
@@ -13310,7 +13324,19 @@ class WheelComponent extends VDOM.Component {
13310
13324
  if (this.props.onPipeKeyDown) this.props.onPipeKeyDown(this.onKeyDown);
13311
13325
  }
13312
13326
  UNSAFE_componentWillReceiveProps(props) {
13313
- this.index = props.index || 0;
13327
+ let newIndex = props.index || 0;
13328
+ // A cyclic wheel renders the option list several times, so the same value
13329
+ // appears in several copies. Snap to the copy nearest the wheel's current
13330
+ // position rather than the one `props.index` names — a wrap then scrolls
13331
+ // one item into the adjacent (identical) copy with no jump, instead of
13332
+ // animating all the way back to the centre copy.
13333
+ if (props.cycle) {
13334
+ let period = props.children.length;
13335
+ let value = ((newIndex % period) + period) % period;
13336
+ newIndex = value + period * Math.round((this.index - value) / period);
13337
+ newIndex = Math.max(0, Math.min(period * WHEEL_BUFFER_COPIES - 1, newIndex));
13338
+ }
13339
+ this.index = newIndex;
13314
13340
  this.scrollTo();
13315
13341
  }
13316
13342
  componentWillUnmount() {
@@ -13347,8 +13373,9 @@ class WheelComponent extends VDOM.Component {
13347
13373
  }
13348
13374
  }
13349
13375
  select(newIndex) {
13350
- let { children } = this.props;
13351
- newIndex = Math.max(0, Math.min(children.length - 1, newIndex));
13376
+ let { children, cycle } = this.props;
13377
+ let length = children.length * (cycle ? WHEEL_BUFFER_COPIES : 1);
13378
+ newIndex = Math.max(0, Math.min(length - 1, newIndex));
13352
13379
  if (this.index !== newIndex) {
13353
13380
  this.index = newIndex;
13354
13381
  this.props.onChange(newIndex);
@@ -13404,6 +13431,24 @@ DateTimePicker.prototype.size = 3;
13404
13431
  DateTimePicker.prototype.autoFocus = false;
13405
13432
  DateTimePicker.prototype.segment = "datetime";
13406
13433
  DateTimePicker.prototype.showSeconds = false;
13434
+ // Builds the option spans for a numeric wheel — one zero-padded span per value.
13435
+ // Pass the result to a WheelComponent with `cycle` set to make it scroll
13436
+ // endlessly; centre the current value by passing `index = value + range`.
13437
+ function buildNumberWheel(range, startAt) {
13438
+ return Array.from(
13439
+ {
13440
+ length: range,
13441
+ },
13442
+ (_, j) =>
13443
+ jsx(
13444
+ "span",
13445
+ {
13446
+ children: String(j + startAt).padStart(2, "0"),
13447
+ },
13448
+ j,
13449
+ ),
13450
+ );
13451
+ }
13407
13452
  class DateTimePickerComponent extends VDOM.Component {
13408
13453
  el;
13409
13454
  keyDownPipes;
@@ -13415,6 +13460,7 @@ class DateTimePickerComponent extends VDOM.Component {
13415
13460
  date: date,
13416
13461
  activeWheel: null,
13417
13462
  };
13463
+ this.century = (date.getFullYear() / 100) | 0;
13418
13464
  let { widget } = props.instance;
13419
13465
  let pickerWidget = widget;
13420
13466
  this.handleChange = this.handleChange.bind(this);
@@ -13477,56 +13523,37 @@ class DateTimePickerComponent extends VDOM.Component {
13477
13523
  let date = this.state.date;
13478
13524
  let culture = Culture.getDateTimeCulture();
13479
13525
  let monthNames = culture.getMonthNames("short");
13480
- let years = [];
13481
- for (let y = 1970; y <= 2050; y++)
13482
- years.push(
13483
- jsx(
13484
- "span",
13485
- {
13486
- children: y,
13487
- },
13488
- y,
13489
- ),
13490
- );
13491
- let days = [];
13492
- let start = new Date(date.getFullYear(), date.getMonth(), 1);
13493
- while (start.getMonth() === date.getMonth()) {
13494
- let day = start.getDate();
13495
- days.push(
13496
- jsx(
13497
- "span",
13498
- {
13499
- children: day < 10 ? "0" + day : day,
13500
- },
13501
- day,
13502
- ),
13503
- );
13504
- start.setDate(start.getDate() + 1);
13505
- }
13506
- let hours = [];
13507
- for (let h = 0; h < 24; h++) {
13508
- hours.push(
13509
- jsx(
13510
- "span",
13511
- {
13512
- children: h < 10 ? "0" + h : h,
13513
- },
13514
- h,
13515
- ),
13516
- );
13517
- }
13518
- let minutes = [];
13519
- for (let m = 0; m < 60; m++) {
13520
- minutes.push(
13521
- jsx(
13522
- "span",
13523
- {
13524
- children: m < 10 ? "0" + m : m,
13525
- },
13526
- m,
13527
- ),
13528
- );
13526
+ // Years: a window spanning the current century, rebuilt when it changes.
13527
+ let currentCentury = (date.getFullYear() / 100) | 0;
13528
+ if (!this.years || this.century !== currentCentury) {
13529
+ this.century = currentCentury;
13530
+ this.firstYear = currentCentury * 100 - 3;
13531
+ let lastYear = (currentCentury + 1) * 100 + 5;
13532
+ this.years = [];
13533
+ for (let y = this.firstYear; y <= lastYear; y++)
13534
+ this.years.push(
13535
+ jsx(
13536
+ "span",
13537
+ {
13538
+ children: y,
13539
+ },
13540
+ y,
13541
+ ),
13542
+ );
13529
13543
  }
13544
+ let years = this.years;
13545
+ // Day/hour/minute wheels use a 3x buffer (see buildNumberWheel). The day
13546
+ // buffer depends on the month length, so it is rebuilt when that changes.
13547
+ const numberOfDaysInMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
13548
+ if (!this.days || this.numberOfDaysInMonth !== numberOfDaysInMonth) {
13549
+ this.numberOfDaysInMonth = numberOfDaysInMonth;
13550
+ this.days = buildNumberWheel(numberOfDaysInMonth, 1);
13551
+ }
13552
+ let days = this.days;
13553
+ if (!this.hours) this.hours = buildNumberWheel(24, 0);
13554
+ let hours = this.hours;
13555
+ if (!this.minutes) this.minutes = buildNumberWheel(60, 0);
13556
+ let minutes = this.minutes;
13530
13557
  return jsxs("div", {
13531
13558
  tabIndex: 0,
13532
13559
  ref: (el) => {
@@ -13538,30 +13565,34 @@ class DateTimePickerComponent extends VDOM.Component {
13538
13565
  onKeyDown: this.onKeyDown,
13539
13566
  children: [
13540
13567
  this.wheels.year &&
13541
- jsx(WheelComponent, {
13542
- size: size,
13543
- CSS: CSS,
13544
- active: this.state.activeWheel === "year",
13545
- baseClass: baseClass + "-wheel",
13546
- index: date.getFullYear() - 1970,
13547
- onChange: (newIndex) => {
13548
- this.setState(
13549
- (state) => ({
13550
- date: this.setDateComponent(this.state.date, "year", newIndex + 1970),
13551
- }),
13552
- this.handleChange,
13553
- );
13554
- },
13555
- onPipeKeyDown: (kd) => {
13556
- this.keyDownPipes["year"] = kd;
13557
- },
13558
- onMouseDown: () => {
13559
- this.setState({
13560
- activeWheel: "year",
13561
- });
13568
+ jsx(
13569
+ WheelComponent,
13570
+ {
13571
+ size: size,
13572
+ CSS: CSS,
13573
+ active: this.state.activeWheel === "year",
13574
+ baseClass: baseClass + "-wheel",
13575
+ index: date.getFullYear() - this.firstYear,
13576
+ onChange: (newIndex) => {
13577
+ this.setState(
13578
+ (state) => ({
13579
+ date: this.setDateComponent(state.date, "year", newIndex + this.firstYear),
13580
+ }),
13581
+ this.handleChange,
13582
+ );
13583
+ },
13584
+ onPipeKeyDown: (kd) => {
13585
+ this.keyDownPipes["year"] = kd;
13586
+ },
13587
+ onMouseDown: () => {
13588
+ this.setState({
13589
+ activeWheel: "year",
13590
+ });
13591
+ },
13592
+ children: years,
13562
13593
  },
13563
- children: years,
13564
- }),
13594
+ `years-${this.century}`,
13595
+ ),
13565
13596
  this.wheels.year &&
13566
13597
  this.wheels.month &&
13567
13598
  jsx("span", {
@@ -13577,7 +13608,7 @@ class DateTimePickerComponent extends VDOM.Component {
13577
13608
  onChange: (newIndex) => {
13578
13609
  this.setState(
13579
13610
  (state) => ({
13580
- date: this.setDateComponent(this.state.date, "month", newIndex),
13611
+ date: this.setDateComponent(state.date, "month", newIndex),
13581
13612
  }),
13582
13613
  this.handleChange,
13583
13614
  );
@@ -13606,120 +13637,144 @@ class DateTimePickerComponent extends VDOM.Component {
13606
13637
  children: "-",
13607
13638
  }),
13608
13639
  this.wheels.date &&
13609
- jsx(WheelComponent, {
13610
- size: size,
13611
- CSS: CSS,
13612
- active: this.state.activeWheel === "date",
13613
- baseClass: baseClass + "-wheel",
13614
- index: date.getDate() - 1,
13615
- onChange: (newIndex) => {
13616
- this.setState(
13617
- (state) => ({
13618
- date: this.setDateComponent(this.state.date, "date", newIndex + 1),
13619
- }),
13620
- this.handleChange,
13621
- );
13622
- },
13623
- onPipeKeyDown: (kd) => {
13624
- this.keyDownPipes["date"] = kd;
13625
- },
13626
- onMouseDown: () => {
13627
- this.setState({
13628
- activeWheel: "date",
13629
- });
13640
+ jsx(
13641
+ WheelComponent,
13642
+ {
13643
+ size: size,
13644
+ CSS: CSS,
13645
+ cycle: true,
13646
+ active: this.state.activeWheel === "date",
13647
+ baseClass: baseClass + "-wheel",
13648
+ index: date.getDate() - 1 + this.numberOfDaysInMonth,
13649
+ onChange: (rawIndex) => {
13650
+ let day = rawIndex % this.numberOfDaysInMonth;
13651
+ this.setState(
13652
+ (state) => ({
13653
+ date: this.setDateComponent(state.date, "date", day + 1),
13654
+ }),
13655
+ this.handleChange,
13656
+ );
13657
+ },
13658
+ onPipeKeyDown: (kd) => {
13659
+ this.keyDownPipes["date"] = kd;
13660
+ },
13661
+ onMouseDown: () => {
13662
+ this.setState({
13663
+ activeWheel: "date",
13664
+ });
13665
+ },
13666
+ children: days,
13630
13667
  },
13631
- children: days,
13632
- }),
13668
+ "date",
13669
+ ),
13633
13670
  this.wheels.hours &&
13634
13671
  this.wheels.year &&
13635
13672
  jsx("span", {
13636
13673
  className: CSS.element(baseClass, "spacer"),
13637
13674
  }),
13638
13675
  this.wheels.hours &&
13639
- jsx(WheelComponent, {
13640
- size: size,
13641
- CSS: CSS,
13642
- active: this.state.activeWheel === "hours",
13643
- baseClass: baseClass + "-wheel",
13644
- index: date.getHours(),
13645
- onChange: (newIndex) => {
13646
- this.setState(
13647
- (state) => ({
13648
- date: this.setDateComponent(this.state.date, "hours", newIndex),
13649
- }),
13650
- this.handleChange,
13651
- );
13652
- },
13653
- onPipeKeyDown: (kd) => {
13654
- this.keyDownPipes["hours"] = kd;
13655
- },
13656
- onMouseDown: () => {
13657
- this.setState({
13658
- activeWheel: "hours",
13659
- });
13676
+ jsx(
13677
+ WheelComponent,
13678
+ {
13679
+ size: size,
13680
+ CSS: CSS,
13681
+ cycle: true,
13682
+ active: this.state.activeWheel === "hours",
13683
+ baseClass: baseClass + "-wheel",
13684
+ index: date.getHours() + 24,
13685
+ onChange: (rawIndex) => {
13686
+ let hour = rawIndex % 24;
13687
+ this.setState(
13688
+ (state) => ({
13689
+ date: this.setDateComponent(state.date, "hours", hour),
13690
+ }),
13691
+ this.handleChange,
13692
+ );
13693
+ },
13694
+ onPipeKeyDown: (kd) => {
13695
+ this.keyDownPipes["hours"] = kd;
13696
+ },
13697
+ onMouseDown: () => {
13698
+ this.setState({
13699
+ activeWheel: "hours",
13700
+ });
13701
+ },
13702
+ children: hours,
13660
13703
  },
13661
- children: hours,
13662
- }),
13704
+ "hours",
13705
+ ),
13663
13706
  this.wheels.hours &&
13664
13707
  this.wheels.minutes &&
13665
13708
  jsx("span", {
13666
13709
  children: ":",
13667
13710
  }),
13668
13711
  this.wheels.minutes &&
13669
- jsx(WheelComponent, {
13670
- size: size,
13671
- CSS: CSS,
13672
- baseClass: baseClass + "-wheel",
13673
- active: this.state.activeWheel === "minutes",
13674
- index: date.getMinutes(),
13675
- onChange: (newIndex) => {
13676
- this.setState(
13677
- (state) => ({
13678
- date: this.setDateComponent(this.state.date, "minutes", newIndex),
13679
- }),
13680
- this.handleChange,
13681
- );
13682
- },
13683
- onPipeKeyDown: (kd) => {
13684
- this.keyDownPipes["minutes"] = kd;
13685
- },
13686
- onMouseDown: () => {
13687
- this.setState({
13688
- activeWheel: "minutes",
13689
- });
13712
+ jsx(
13713
+ WheelComponent,
13714
+ {
13715
+ size: size,
13716
+ CSS: CSS,
13717
+ cycle: true,
13718
+ baseClass: baseClass + "-wheel",
13719
+ active: this.state.activeWheel === "minutes",
13720
+ index: date.getMinutes() + 60,
13721
+ onChange: (rawIndex) => {
13722
+ let minute = rawIndex % 60;
13723
+ this.setState(
13724
+ (state) => ({
13725
+ date: this.setDateComponent(state.date, "minutes", minute),
13726
+ }),
13727
+ this.handleChange,
13728
+ );
13729
+ },
13730
+ onPipeKeyDown: (kd) => {
13731
+ this.keyDownPipes["minutes"] = kd;
13732
+ },
13733
+ onMouseDown: () => {
13734
+ this.setState({
13735
+ activeWheel: "minutes",
13736
+ });
13737
+ },
13738
+ children: minutes,
13690
13739
  },
13691
- children: minutes,
13692
- }),
13740
+ "minutes",
13741
+ ),
13693
13742
  this.wheels.minutes &&
13694
13743
  this.wheels.seconds &&
13695
13744
  jsx("span", {
13696
13745
  children: ":",
13697
13746
  }),
13698
13747
  this.wheels.seconds &&
13699
- jsx(WheelComponent, {
13700
- size: size,
13701
- CSS: CSS,
13702
- baseClass: baseClass + "-wheel",
13703
- active: this.state.activeWheel === "seconds",
13704
- index: date.getSeconds(),
13705
- onChange: (newIndex) => {
13706
- this.setState(
13707
- (state) => ({
13708
- date: this.setDateComponent(this.state.date, "seconds", newIndex),
13709
- }),
13710
- this.handleChange,
13711
- );
13712
- },
13713
- onPipeKeyDown: (kd) => {
13714
- this.keyDownPipes["seconds"] = kd;
13715
- },
13716
- onMouseDown: () => {
13717
- this.setState({
13718
- activeWheel: "seconds",
13719
- });
13748
+ jsx(
13749
+ WheelComponent,
13750
+ {
13751
+ size: size,
13752
+ CSS: CSS,
13753
+ cycle: true,
13754
+ baseClass: baseClass + "-wheel",
13755
+ active: this.state.activeWheel === "seconds",
13756
+ index: date.getSeconds() + 60,
13757
+ onChange: (rawIndex) => {
13758
+ let second = rawIndex % 60;
13759
+ this.setState(
13760
+ (state) => ({
13761
+ date: this.setDateComponent(state.date, "seconds", second),
13762
+ }),
13763
+ this.handleChange,
13764
+ );
13765
+ },
13766
+ onPipeKeyDown: (kd) => {
13767
+ this.keyDownPipes["seconds"] = kd;
13768
+ },
13769
+ onMouseDown: () => {
13770
+ this.setState({
13771
+ activeWheel: "seconds",
13772
+ });
13773
+ },
13774
+ children: minutes,
13720
13775
  },
13721
- children: minutes,
13722
- }),
13776
+ "seconds",
13777
+ ),
13723
13778
  ],
13724
13779
  });
13725
13780
  }
@@ -18582,6 +18637,7 @@ export {
18582
18637
  ValidationError,
18583
18638
  ValidationGroup,
18584
18639
  Validator,
18640
+ WHEEL_BUFFER_COPIES,
18585
18641
  Wheel,
18586
18642
  WheelComponent,
18587
18643
  Window,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cx",
3
- "version": "26.4.3",
3
+ "version": "26.5.1",
4
4
  "description": "Advanced JavaScript UI framework for admin and dashboard applications with ready to use grid, form and chart components.",
5
5
  "exports": {
6
6
  "./data": {
@@ -1,4 +1,7 @@
1
1
  @use "sass:map";
2
+ @use "../util/scss/besm.scss" as *;
3
+ @use "../util/scss/include.scss" as *;
4
+ @use "./variables" as *;
2
5
 
3
6
  @mixin cx-rangemarker($name: "rangemarker", $besm: $cx-besm, $range-marker-color: $cx-default-range-marker-color) {
4
7
  $block: map.get($besm, block);
@@ -74,6 +74,14 @@ export interface AxisConfig extends BoundedObjectConfig {
74
74
  /** Set to true to hide the axis labels. */
75
75
  hideLabels?: boolean;
76
76
 
77
+ /**
78
+ * Set to `true` to drop a boundary (first/last) label, together with its tick,
79
+ * when the label would not fit within the chart and get clipped at the edge.
80
+ * Minor ticks are unaffected. Only affects horizontal axes. Defaults to `false`,
81
+ * except on `TimeAxis` where it defaults to `true`.
82
+ */
83
+ hideClippedLabels?: boolean;
84
+
77
85
  /** Set to true to hide the axis line. */
78
86
  hideLine?: boolean;
79
87
 
@@ -131,6 +139,7 @@ export class Axis extends BoundedObject<AxisConfig, AxisInstance> {
131
139
  declare inverted: boolean;
132
140
  declare hidden: boolean;
133
141
  declare hideLabels: boolean;
142
+ declare hideClippedLabels: boolean;
134
143
  declare hideTicks: boolean;
135
144
  declare hideLine: boolean;
136
145
  declare tickSize: number;
@@ -185,6 +194,7 @@ export class Axis extends BoundedObject<AxisConfig, AxisInstance> {
185
194
  {
186
195
  anchors: undefined,
187
196
  hideLabels: undefined,
197
+ hideClippedLabels: undefined,
188
198
  hideLine: undefined,
189
199
  hideTicks: undefined,
190
200
  labelRotation: undefined,
@@ -259,10 +269,27 @@ export class Axis extends BoundedObject<AxisConfig, AxisInstance> {
259
269
  var t: string[] = [];
260
270
  if (!!size && !data.hideLabels) {
261
271
  var ticks = calculator.getTicks([size]);
272
+
273
+ // A boundary label is dropped when it would be clipped at the chart edge.
274
+ // How far a label reaches toward an edge depends only on its text anchor
275
+ // and minLabelDistance, so it is resolved once here rather than per tick.
276
+ // Chart bounds (parentRect) are used rather than axis bounds, since an
277
+ // axis can be inset within its chart and one Svg may host several charts.
278
+ let chartBounds = instance.parentRect;
279
+ let clipBoundaryLabels = !this.vertical && !!data.hideClippedLabels && !!chartBounds;
280
+ let reach = minLabelDistance * 0.8;
281
+ let leftReach = data.labelAnchor == "end" ? reach : data.labelAnchor == "middle" ? reach / 2 : 0;
282
+ let rightReach = data.labelAnchor == "start" ? reach : data.labelAnchor == "middle" ? reach / 2 : 0;
283
+
262
284
  ticks.forEach((serie: any[], si: number) => {
263
285
  serie.forEach((v: any, i: number) => {
264
286
  var s = calculator.map(v);
265
287
 
288
+ // Drop this boundary label (and its major tick) if it would be
289
+ // clipped at the chart edge; minor ticks render separately and stay.
290
+ let clipped =
291
+ clipBoundaryLabels && (s + rightReach > chartBounds.r || s - leftReach < chartBounds.l);
292
+
266
293
  if (this.secondary) {
267
294
  x1 = this.vertical ? bounds.r + tickOffset : s;
268
295
  y1 = this.vertical ? s : bounds.t - tickOffset;
@@ -275,7 +302,9 @@ export class Axis extends BoundedObject<AxisConfig, AxisInstance> {
275
302
  y2 = this.vertical ? s : bounds.b + tickOffset + tickSize;
276
303
  }
277
304
 
278
- if (!this.useGridlineTicks) t.push(`M ${x1} ${y1} L ${x2} ${y2}`);
305
+ if (!this.useGridlineTicks && !clipped) t.push(`M ${x1} ${y1} L ${x2} ${y2}`);
306
+
307
+ if (clipped) return;
279
308
 
280
309
  var x, y;
281
310
  let labelOffset =
@@ -422,6 +451,7 @@ Axis.prototype.secondary = false;
422
451
  Axis.prototype.inverted = false;
423
452
  Axis.prototype.hidden = false;
424
453
  Axis.prototype.hideLabels = false;
454
+ Axis.prototype.hideClippedLabels = false;
425
455
  Axis.prototype.hideTicks = false;
426
456
  Axis.prototype.hideLine = false;
427
457
 
@@ -212,6 +212,7 @@ TimeAxis.prototype.minLabelDistance = 60;
212
212
  TimeAxis.prototype.minTickDistance = 60;
213
213
  TimeAxis.prototype.minTickUnit = "second";
214
214
  TimeAxis.prototype.useLabelDistanceFormatOverrides = false;
215
+ TimeAxis.prototype.hideClippedLabels = true;
215
216
  TimeAxis.prototype.minLabelDistanceFormatOverrideDefaults = {
216
217
  [TimeFormats.fullDateAndTime]: 150,
217
218
  [TimeFormats.shortMonthDate]: 90,
@@ -14,6 +14,7 @@
14
14
  @use "Marker";
15
15
  @use "MarkerLine";
16
16
  @use "Range";
17
+ @use "RangeMarker";
17
18
  @use "Swimlane";
18
19
  @use "Swimlanes";
19
20
 
@@ -19,11 +19,12 @@ export class AugmentedViewBase<D = any> extends View<D> {
19
19
  let parentStoreData = this.store.getData();
20
20
  let result = this.getBaseData(parentStoreData);
21
21
  this.embedAugmentData(result, parentStoreData);
22
- this.cache.result = result;
23
- this.cache.parentStoreData = parentStoreData;
24
- this.cache.version = this.meta.version;
22
+ if (this.sealed) {
23
+ this.cache.result = result;
24
+ this.cache.version = this.meta.version;
25
+ }
25
26
  this.meta = this.store.meta;
26
- return this.cache.result;
27
+ return result;
27
28
  }
28
29
 
29
30
  protected getBaseData(parentStoreData: any): any {