cx 26.7.6 → 26.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/build/charts/Legend.d.ts +8 -1
  2. package/build/charts/Legend.d.ts.map +1 -1
  3. package/build/charts/Legend.js +8 -4
  4. package/build/charts/LineGraph.d.ts +8 -16
  5. package/build/charts/LineGraph.d.ts.map +1 -1
  6. package/build/charts/LineGraph.js +76 -69
  7. package/build/charts/axis/NumericAxis.d.ts.map +1 -1
  8. package/build/charts/axis/NumericAxis.js +1 -254
  9. package/build/charts/axis/NumericScale.d.ts +59 -0
  10. package/build/charts/axis/NumericScale.d.ts.map +1 -0
  11. package/build/charts/axis/NumericScale.js +254 -0
  12. package/build/jsx-dev-runtime.d.ts +2 -1
  13. package/build/jsx-dev-runtime.d.ts.map +1 -1
  14. package/build/svg/Svg.d.ts +9 -0
  15. package/build/svg/Svg.d.ts.map +1 -1
  16. package/build/svg/Svg.js +9 -1
  17. package/build/ui/index.d.ts +3 -2
  18. package/build/ui/index.d.ts.map +1 -1
  19. package/build/ui/index.js +1 -1
  20. package/build/util/DOM.d.ts.map +1 -1
  21. package/build/util/DOM.js +16 -4
  22. package/build/util/getActiveElement.d.ts +1 -1
  23. package/build/util/getActiveElement.d.ts.map +1 -1
  24. package/build/util/getActiveElement.js +14 -2
  25. package/build/widgets/form/TextArea.d.ts +4 -0
  26. package/build/widgets/form/TextArea.d.ts.map +1 -1
  27. package/build/widgets/form/TextArea.js +7 -1
  28. package/build/widgets/grid/Grid.d.ts +12 -2
  29. package/build/widgets/grid/Grid.d.ts.map +1 -1
  30. package/build/widgets/grid/Grid.js +17 -4
  31. package/build/widgets/nav/MenuItem.js +2 -2
  32. package/build/widgets/overlay/Dropdown.d.ts +4 -4
  33. package/build/widgets/overlay/Dropdown.d.ts.map +1 -1
  34. package/build/widgets/overlay/Dropdown.js +82 -38
  35. package/build/widgets/overlay/Overlay.d.ts.map +1 -1
  36. package/build/widgets/overlay/Overlay.js +7 -3
  37. package/build/widgets/overlay/Window.d.ts.map +1 -1
  38. package/build/widgets/overlay/Window.js +2 -1
  39. package/dist/charts.js +166 -168
  40. package/dist/manifest.js +805 -802
  41. package/dist/svg.js +13 -0
  42. package/dist/util.js +31 -9
  43. package/dist/widgets.js +153 -50
  44. package/package.json +1 -1
  45. package/src/charts/Legend.tsx +22 -2
  46. package/src/charts/LineGraph.tsx +80 -98
  47. package/src/charts/axis/NumericAxis.spec.ts +40 -0
  48. package/src/charts/axis/NumericAxis.tsx +1 -290
  49. package/src/charts/axis/NumericScale.ts +290 -0
  50. package/src/jsx-dev-runtime.ts +2 -1
  51. package/src/svg/Svg.tsx +24 -1
  52. package/src/ui/Cx.tsx +505 -505
  53. package/src/ui/DataProxy.ts +55 -55
  54. package/src/ui/Rescope.ts +50 -50
  55. package/src/ui/exprHelpers.ts +96 -96
  56. package/src/ui/index.ts +3 -6
  57. package/src/util/DOM.ts +15 -4
  58. package/src/util/getActiveElement.ts +16 -2
  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/LookupField.maps.scss +26 -26
  63. package/src/widgets/form/MonthField.scss +113 -113
  64. package/src/widgets/form/Select.scss +104 -104
  65. package/src/widgets/form/TextArea.tsx +10 -1
  66. package/src/widgets/form/TextField.scss +66 -66
  67. package/src/widgets/grid/Grid.sorting.spec.tsx +188 -0
  68. package/src/widgets/grid/Grid.tsx +31 -7
  69. package/src/widgets/index.ts +41 -41
  70. package/src/widgets/nav/MenuItem.tsx +2 -2
  71. package/src/widgets/overlay/Dropdown.tsx +87 -27
  72. package/src/widgets/overlay/Overlay.tsx +5 -3
  73. package/src/widgets/overlay/Window.tsx +2 -1
package/dist/charts.js CHANGED
@@ -1586,6 +1586,8 @@ class Legend extends HtmlElement {
1586
1586
  declareData(...args) {
1587
1587
  super.declareData(...args, {
1588
1588
  shape: undefined,
1589
+ shapeRole: undefined,
1590
+ shapeAriaLabel: undefined,
1589
1591
  entryStyle: {
1590
1592
  structured: true,
1591
1593
  },
@@ -1618,6 +1620,8 @@ class Legend extends HtmlElement {
1618
1620
  case "shapeSize":
1619
1621
  case "svgSize":
1620
1622
  case "shape":
1623
+ case "shapeRole":
1624
+ case "shapeAriaLabel":
1621
1625
  case "entryStyle":
1622
1626
  case "entryClass":
1623
1627
  case "valueStyle":
@@ -1653,7 +1657,7 @@ class Legend extends HtmlElement {
1653
1657
  const CSS = this.CSS;
1654
1658
  let entries = instance.legends[this.name] && instance.legends[this.name].entries,
1655
1659
  list;
1656
- let { entryClass, entryStyle, shape, valueClass, valueStyle } = instance.data;
1660
+ let { entryClass, entryStyle, shape, shapeRole, shapeAriaLabel, valueClass, valueStyle } = instance.data;
1657
1661
  let valueFormatter = Format.parse(this.valueFormat);
1658
1662
  let valueClasses = this.showValues ? CSS.expand(CSS.element(this.baseClass, "value"), valueClass) : undefined;
1659
1663
  let entryTextClass = CSS.element(this.baseClass, "entry-text");
@@ -1677,7 +1681,7 @@ class Legend extends HtmlElement {
1677
1681
  onMouseMove: onMouseMove,
1678
1682
  onMouseLeave: onMouseLeave,
1679
1683
  children: [
1680
- this.renderShape(e, shape),
1684
+ this.renderShape(e, shape, shapeRole, shapeAriaLabel),
1681
1685
  jsx("div", {
1682
1686
  className: entryTextClass,
1683
1687
  children: e.displayText || e.name,
@@ -1697,7 +1701,7 @@ class Legend extends HtmlElement {
1697
1701
  }
1698
1702
  return [list, super.renderChildren(context, instance)];
1699
1703
  }
1700
- renderShape(entry, legendEntriesShape) {
1704
+ renderShape(entry, legendEntriesShape, role, ariaLabel) {
1701
1705
  const className = this.CSS.element(this.baseClass, "shape", {
1702
1706
  [`color-${entry.colorIndex}`]: entry.colorIndex != null && (isUndefined(entry.active) || entry.active),
1703
1707
  });
@@ -1710,6 +1714,9 @@ class Legend extends HtmlElement {
1710
1714
  if (hasVisibleValue(style.fill) && !style.stroke) style.stroke = style.fill;
1711
1715
  return jsx("svg", {
1712
1716
  className: this.CSS.element(this.baseClass, "svg"),
1717
+ role: role ?? (ariaLabel ? "img" : undefined),
1718
+ "aria-label": ariaLabel,
1719
+ "aria-hidden": role == null && !ariaLabel ? true : undefined,
1713
1720
  style: {
1714
1721
  width: `${this.svgSize}px`,
1715
1722
  height: `${this.svgSize}px`,
@@ -2999,16 +3006,11 @@ class LineGraph extends Widget {
2999
3006
  stack: undefined,
3000
3007
  stacked: undefined,
3001
3008
  smooth: undefined,
3002
- smoothingRatio: undefined,
3003
3009
  });
3004
3010
  }
3005
3011
  prepareData(context, instance) {
3006
3012
  let { data } = instance;
3007
3013
  if (data.name && !data.colorName) data.colorName = data.name;
3008
- if (data.smooth && data.smoothingRatio != null) {
3009
- if (data.smoothingRatio < 0) data.smoothingRatio = 0;
3010
- if (data.smoothingRatio > 0.4) data.smoothingRatio = 0.4;
3011
- }
3012
3014
  super.prepareData(context, instance);
3013
3015
  }
3014
3016
  explore(context, instance) {
@@ -3119,18 +3121,16 @@ class LineGraph extends Widget {
3119
3121
  ["color-" + data.colorIndex]: data.colorIndex != null,
3120
3122
  };
3121
3123
  let line, area;
3122
- const r = data.smoothingRatio;
3123
3124
  let linePath = "";
3124
3125
  if (data.line) {
3125
3126
  lineSpans.forEach((span) => {
3126
- span.forEach((p, i) => {
3127
- linePath +=
3128
- i == 0
3129
- ? `M ${p.x} ${p.y}`
3130
- : !data.smooth || span.length < 2
3131
- ? `L ${p.x} ${p.y}`
3132
- : this.getCurvedPathSegment(p, span, i - 1, i - 2, i - 1, i + 1, r);
3133
- });
3127
+ if (span.length == 0) return;
3128
+ linePath += `M ${span[0].x} ${span[0].y}`;
3129
+ if (data.smooth && span.length >= 2) linePath += this.getMonotoneSpanPath(span, "y");
3130
+ else
3131
+ span.forEach((p, i) => {
3132
+ if (i > 0) linePath += `L ${p.x} ${p.y}`;
3133
+ });
3134
3134
  });
3135
3135
  line = jsx("path", {
3136
3136
  className: this.CSS.element(this.baseClass, "line", stateMods),
@@ -3141,31 +3141,20 @@ class LineGraph extends Widget {
3141
3141
  if (data.area) {
3142
3142
  let areaPath = "";
3143
3143
  lineSpans.forEach((span) => {
3144
- let closePath = "";
3145
- span.forEach((p, i) => {
3146
- let segment = "";
3147
- if (i == 0) {
3148
- segment = `M ${p.x} ${p.y}`;
3149
- // closing point
3150
- closePath =
3151
- !data.smooth || span.length < 2
3152
- ? `L ${p.x} ${p.y0}`
3153
- : this.getCurvedPathSegment(p, span, i + 1, i + 2, i + 1, i - 1, r, "y0");
3154
- } else {
3155
- if (!data.smooth) {
3156
- segment = `L ${p.x} ${p.y}`;
3157
- closePath = `L ${p.x} ${p.y0}` + closePath;
3158
- } else {
3159
- segment = this.getCurvedPathSegment(p, span, i - 1, i - 2, i - 1, i + 1, r, "y");
3160
- // closing point
3161
- if (i < span.length - 1)
3162
- closePath = this.getCurvedPathSegment(p, span, i + 1, i + 2, i + 1, i - 1, r, "y0") + closePath;
3163
- }
3164
- }
3165
- areaPath += segment;
3166
- });
3167
- areaPath += `L ${span[span.length - 1].x} ${span[span.length - 1].y0}`;
3168
- areaPath += closePath;
3144
+ if (span.length == 0) return;
3145
+ let last = span[span.length - 1];
3146
+ areaPath += `M ${span[0].x} ${span[0].y}`;
3147
+ if (data.smooth && span.length >= 2) {
3148
+ areaPath += this.getMonotoneSpanPath(span, "y");
3149
+ areaPath += `L ${last.x} ${last.y0}`;
3150
+ areaPath += this.getMonotoneSpanPath(span, "y0", true);
3151
+ } else {
3152
+ span.forEach((p, i) => {
3153
+ if (i > 0) areaPath += `L ${p.x} ${p.y}`;
3154
+ });
3155
+ areaPath += `L ${last.x} ${last.y0}`;
3156
+ for (let i = span.length - 2; i >= 0; i--) areaPath += `L ${span[i].x} ${span[i].y0}`;
3157
+ }
3169
3158
  areaPath += "Z";
3170
3159
  });
3171
3160
  area = jsx("path", {
@@ -3183,45 +3172,54 @@ class LineGraph extends Widget {
3183
3172
  key,
3184
3173
  );
3185
3174
  }
3186
- getCurvedPathSegment(p, points, i1, i2, j1, j2, r, yField = "y") {
3187
- const [sx, sy] = this.getControlPoint({
3188
- cp: points[i1],
3189
- pp: points[i2],
3190
- r,
3191
- np: p,
3192
- yField,
3193
- });
3194
- const [ex, ey] = this.getControlPoint({
3195
- cp: p,
3196
- pp: points[j1],
3197
- np: points[j2],
3198
- r,
3199
- reverse: true,
3200
- yField,
3201
- });
3202
- return `C ${sx} ${sy}, ${ex} ${ey}, ${p.x} ${p[yField]}`;
3203
- }
3204
- getControlPoint({ cp, pp, np, r, reverse, yField = "y" }) {
3205
- // When 'current' is the first or last point of the array 'previous' or 'next' don't exist. Replace with 'current'.
3206
- const p = pp || cp;
3207
- const n = np || cp;
3208
- // Properties of the opposed-line
3209
- let { angle, length } = this.getLineInfo(p.x, p[yField], n.x, n[yField]);
3210
- // If it is end-control-point, add PI to the angle to go backward
3211
- angle = angle + (reverse ? Math.PI : 0);
3212
- length = length * r;
3213
- // The control point position is relative to the current point
3214
- const x = cp.x + Math.cos(angle) * length;
3215
- const y = cp[yField] + Math.sin(angle) * length;
3216
- return [x, y];
3217
- }
3218
- getLineInfo(p1x, p1y, p2x, p2y) {
3219
- const lengthX = p2x - p1x;
3220
- const lengthY = p2y - p1y;
3221
- return {
3222
- length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),
3223
- angle: Math.atan2(lengthY, lengthX),
3175
+ // Fritsch-Carlson monotone cubic interpolation. Tangents are limited so the
3176
+ // curve between two points never leaves their vertical range (no overshoot).
3177
+ getMonotoneTangents(span, yField) {
3178
+ const n = span.length;
3179
+ const m = new Array(n).fill(0);
3180
+ if (n < 2) return m;
3181
+ const secant = (i) => {
3182
+ const h = span[i + 1].x - span[i].x;
3183
+ return h != 0 ? (span[i + 1][yField] - span[i][yField]) / h : 0;
3224
3184
  };
3185
+ if (n == 2) {
3186
+ m[0] = m[1] = secant(0);
3187
+ return m;
3188
+ }
3189
+ for (let i = 1; i < n - 1; i++) {
3190
+ const h0 = span[i].x - span[i - 1].x;
3191
+ const h1 = span[i + 1].x - span[i].x;
3192
+ const s0 = secant(i - 1);
3193
+ const s1 = secant(i);
3194
+ const p = (s0 * h1 + s1 * h0) / (h0 + h1);
3195
+ m[i] = (Math.sign(s0) + Math.sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
3196
+ }
3197
+ const hFirst = span[1].x - span[0].x;
3198
+ m[0] = hFirst != 0 ? (3 * secant(0) - m[1]) / 2 : m[1];
3199
+ const hLast = span[n - 1].x - span[n - 2].x;
3200
+ m[n - 1] = hLast != 0 ? (3 * secant(n - 2) - m[n - 2]) / 2 : m[n - 2];
3201
+ return m;
3202
+ }
3203
+ // Emits cubic bezier segments for the whole span using monotone tangents.
3204
+ // Assumes the path cursor is at the first (or last, when reversed) span point.
3205
+ getMonotoneSpanPath(span, yField, reverse) {
3206
+ const m = this.getMonotoneTangents(span, yField);
3207
+ let path = "";
3208
+ if (!reverse)
3209
+ for (let i = 1; i < span.length; i++) {
3210
+ const p0 = span[i - 1];
3211
+ const p1 = span[i];
3212
+ const dx = (p1.x - p0.x) / 3;
3213
+ path += `C ${p0.x + dx} ${p0[yField] + dx * m[i - 1]}, ${p1.x - dx} ${p1[yField] - dx * m[i]}, ${p1.x} ${p1[yField]}`;
3214
+ }
3215
+ else
3216
+ for (let i = span.length - 1; i > 0; i--) {
3217
+ const p0 = span[i - 1];
3218
+ const p1 = span[i];
3219
+ const dx = (p1.x - p0.x) / 3;
3220
+ path += `C ${p1.x - dx} ${p1[yField] - dx * m[i]}, ${p0.x + dx} ${p0[yField] + dx * m[i - 1]}, ${p0.x} ${p0[yField]}`;
3221
+ }
3222
+ return path;
3225
3223
  }
3226
3224
  }
3227
3225
  LineGraph.prototype.xAxis = "x";
@@ -3240,7 +3238,6 @@ LineGraph.prototype.legendShape = "rect";
3240
3238
  LineGraph.prototype.stack = "stack";
3241
3239
  LineGraph.prototype.hiddenBase = false;
3242
3240
  LineGraph.prototype.smooth = false;
3243
- LineGraph.prototype.smoothingRatio = 0.05;
3244
3241
  LineGraph.prototype.styled = true;
3245
3242
  Widget.alias("line-graph", LineGraph);
3246
3243
 
@@ -3904,92 +3901,6 @@ class Stack {
3904
3901
  }
3905
3902
  }
3906
3903
 
3907
- class NumericAxis extends Axis {
3908
- constructor(config) {
3909
- super(config);
3910
- }
3911
- init() {
3912
- if (this.deadZone) {
3913
- this.lowerDeadZone = this.deadZone;
3914
- this.upperDeadZone = this.deadZone;
3915
- }
3916
- super.init();
3917
- }
3918
- declareData(...args) {
3919
- super.declareData(
3920
- {
3921
- min: undefined,
3922
- max: undefined,
3923
- normalized: undefined,
3924
- inverted: undefined,
3925
- labelDivisor: undefined,
3926
- format: undefined,
3927
- lowerDeadZone: undefined,
3928
- upperDeadZone: undefined,
3929
- },
3930
- ...args,
3931
- );
3932
- }
3933
- initInstance(context, instance) {
3934
- instance.calculator = new NumericScale();
3935
- }
3936
- explore(context, instance) {
3937
- super.explore(context, instance);
3938
- let { min, max, normalized, inverted, lowerDeadZone, upperDeadZone } = instance.data;
3939
- instance.calculator.reset(
3940
- min,
3941
- max,
3942
- this.snapToTicks,
3943
- this.tickDivisions,
3944
- this.minTickDistance,
3945
- this.minTickStep,
3946
- this.minLabelDistance,
3947
- this.minLabelTickSize,
3948
- normalized,
3949
- inverted,
3950
- lowerDeadZone,
3951
- upperDeadZone,
3952
- );
3953
- }
3954
- render(context, instance, key) {
3955
- let { data } = instance;
3956
- if (!data.bounds.valid()) return null;
3957
- let baseFormatter = Format.parse(data.format);
3958
- let formatter = data.labelDivisor != 1 ? (v) => baseFormatter(v / data.labelDivisor) : baseFormatter;
3959
- return jsx(
3960
- "g",
3961
- {
3962
- className: data.classNames,
3963
- style: data.style,
3964
- children: this.renderTicksAndLabels(context, instance, formatter, this.minLabelDistance),
3965
- },
3966
- key,
3967
- );
3968
- }
3969
- static XY() {
3970
- return {
3971
- x: {
3972
- type: NumericAxis,
3973
- },
3974
- y: {
3975
- type: NumericAxis,
3976
- vertical: true,
3977
- },
3978
- };
3979
- }
3980
- }
3981
- NumericAxis.prototype.baseClass = "numericaxis";
3982
- NumericAxis.prototype.tickDivisions = [
3983
- [1, 2, 10, 20, 100],
3984
- [1, 5, 10, 20, 100],
3985
- ];
3986
- NumericAxis.prototype.snapToTicks = 1;
3987
- NumericAxis.prototype.normalized = false;
3988
- NumericAxis.prototype.format = "n";
3989
- NumericAxis.prototype.labelDivisor = 1;
3990
- NumericAxis.prototype.minLabelTickSize = 0;
3991
- NumericAxis.prototype.minTickStep = 0;
3992
- Axis.alias("numeric", NumericAxis);
3993
3904
  class NumericScale {
3994
3905
  min;
3995
3906
  max;
@@ -4059,7 +3970,7 @@ class NumericScale {
4059
3970
  }
4060
3971
  trackValue(v, offset = 0, constrain = false) {
4061
3972
  let value = (v - this.origin) / this.scale.factor - offset + this.scale.min - this.scale.minPadding;
4062
- if (constrain) value = this.constrainValue(v);
3973
+ if (constrain) value = this.constrainValue(value);
4063
3974
  return value;
4064
3975
  }
4065
3976
  hash() {
@@ -4237,6 +4148,93 @@ class NumericScale {
4237
4148
  }
4238
4149
  }
4239
4150
 
4151
+ class NumericAxis extends Axis {
4152
+ constructor(config) {
4153
+ super(config);
4154
+ }
4155
+ init() {
4156
+ if (this.deadZone) {
4157
+ this.lowerDeadZone = this.deadZone;
4158
+ this.upperDeadZone = this.deadZone;
4159
+ }
4160
+ super.init();
4161
+ }
4162
+ declareData(...args) {
4163
+ super.declareData(
4164
+ {
4165
+ min: undefined,
4166
+ max: undefined,
4167
+ normalized: undefined,
4168
+ inverted: undefined,
4169
+ labelDivisor: undefined,
4170
+ format: undefined,
4171
+ lowerDeadZone: undefined,
4172
+ upperDeadZone: undefined,
4173
+ },
4174
+ ...args,
4175
+ );
4176
+ }
4177
+ initInstance(context, instance) {
4178
+ instance.calculator = new NumericScale();
4179
+ }
4180
+ explore(context, instance) {
4181
+ super.explore(context, instance);
4182
+ let { min, max, normalized, inverted, lowerDeadZone, upperDeadZone } = instance.data;
4183
+ instance.calculator.reset(
4184
+ min,
4185
+ max,
4186
+ this.snapToTicks,
4187
+ this.tickDivisions,
4188
+ this.minTickDistance,
4189
+ this.minTickStep,
4190
+ this.minLabelDistance,
4191
+ this.minLabelTickSize,
4192
+ normalized,
4193
+ inverted,
4194
+ lowerDeadZone,
4195
+ upperDeadZone,
4196
+ );
4197
+ }
4198
+ render(context, instance, key) {
4199
+ let { data } = instance;
4200
+ if (!data.bounds.valid()) return null;
4201
+ let baseFormatter = Format.parse(data.format);
4202
+ let formatter = data.labelDivisor != 1 ? (v) => baseFormatter(v / data.labelDivisor) : baseFormatter;
4203
+ return jsx(
4204
+ "g",
4205
+ {
4206
+ className: data.classNames,
4207
+ style: data.style,
4208
+ children: this.renderTicksAndLabels(context, instance, formatter, this.minLabelDistance),
4209
+ },
4210
+ key,
4211
+ );
4212
+ }
4213
+ static XY() {
4214
+ return {
4215
+ x: {
4216
+ type: NumericAxis,
4217
+ },
4218
+ y: {
4219
+ type: NumericAxis,
4220
+ vertical: true,
4221
+ },
4222
+ };
4223
+ }
4224
+ }
4225
+ NumericAxis.prototype.baseClass = "numericaxis";
4226
+ NumericAxis.prototype.tickDivisions = [
4227
+ [1, 2, 10, 20, 100],
4228
+ [1, 5, 10, 20, 100],
4229
+ ];
4230
+ NumericAxis.prototype.snapToTicks = 1;
4231
+ NumericAxis.prototype.normalized = false;
4232
+ NumericAxis.prototype.format = "n";
4233
+ NumericAxis.prototype.labelDivisor = 1;
4234
+ NumericAxis.prototype.minLabelTickSize = 0;
4235
+ NumericAxis.prototype.minTickStep = 0;
4236
+ Axis.alias("numeric", NumericAxis);
4237
+
4240
4238
  class CategoryAxis extends Axis {
4241
4239
  constructor(config) {
4242
4240
  super(config);