@ons/design-system 72.9.2 → 72.10.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 (48) hide show
  1. package/components/char-check-limit/_macro.njk +2 -2
  2. package/components/char-check-limit/character-check.js +30 -9
  3. package/components/char-check-limit/character-check.spec.js +1 -1
  4. package/components/chart/_chart.scss +73 -1
  5. package/components/chart/_macro.njk +90 -20
  6. package/components/chart/_macro.spec.js +424 -0
  7. package/components/chart/bar-chart.js +46 -20
  8. package/components/chart/boxplot.js +37 -0
  9. package/components/chart/chart-constants.js +14 -0
  10. package/components/chart/chart.js +102 -46
  11. package/components/chart/columnrange-chart.js +94 -0
  12. package/components/chart/common-chart-options.js +65 -23
  13. package/components/chart/example-bar-chart-with-annotations.njk +1 -1
  14. package/components/chart/example-bar-chart-with-point-range-and-reference-line-annotations.njk +95 -0
  15. package/components/chart/example-bar-with-confidence-levels.njk +71 -0
  16. package/components/chart/example-clustered-column-chart.njk +1 -3
  17. package/components/chart/example-column-chart-with-annotations.njk +1 -1
  18. package/components/chart/example-column-chart-with-custom-reference-line-value.njk +56 -0
  19. package/components/chart/example-column-chart-with-range-annotations.njk +64 -0
  20. package/components/chart/example-column-chart-with-reference-line-annotations.njk +64 -0
  21. package/components/chart/example-column-with-confidence-levels.njk +61 -0
  22. package/components/chart/example-line-chart-with-annotations.njk +3 -3
  23. package/components/chart/example-line-chart-with-custom-reference-line-value.njk +224 -0
  24. package/components/chart/example-line-chart-with-markers.njk +21 -21
  25. package/components/chart/example-line-chart-with-range-annotations-inside.njk +238 -0
  26. package/components/chart/example-line-chart-with-range-annotations-outside-left-right.njk +240 -0
  27. package/components/chart/example-line-chart-with-range-annotations-outside-top-bottom.njk +239 -0
  28. package/components/chart/example-line-chart-with-reference-line-annotations.njk +236 -0
  29. package/components/chart/example-scatter-chart.njk +5 -5
  30. package/components/chart/line-chart.js +29 -11
  31. package/components/chart/range-annotations-options.js +221 -0
  32. package/components/chart/reference-line-annotations-options.js +93 -0
  33. package/components/chart/scatter-chart.js +15 -6
  34. package/components/chart/specific-chart-options.js +22 -1
  35. package/components/chart/utilities.js +97 -0
  36. package/components/checkboxes/_macro.spec.js +1 -1
  37. package/components/mutually-exclusive/mutually-exclusive.textarea.spec.js +1 -1
  38. package/components/textarea/_macro.njk +8 -6
  39. package/components/textarea/_macro.spec.js +12 -8
  40. package/components/textarea/{example-textarea-with-character-limit.njk → example-textarea-with-character-check.njk} +3 -1
  41. package/css/main.css +1 -1
  42. package/js/main.js +0 -1
  43. package/package.json +14 -14
  44. package/scripts/main.es5.js +1 -1
  45. package/scripts/main.js +1 -1
  46. package/components/char-check-limit/character-limit.js +0 -55
  47. package/components/textarea/textarea.dom.js +0 -12
  48. package/components/textarea/textarea.spec.js +0 -98
@@ -0,0 +1,221 @@
1
+ import ChartConstants from './chart-constants';
2
+
3
+ class RangeAnnotationsOptions {
4
+ constructor(rangeAnnotations) {
5
+ this.constants = ChartConstants.constants();
6
+ this.rangeAnnotations = rangeAnnotations;
7
+ }
8
+
9
+ getRangeAnnotationsOptionsDesktop = (chartType) => {
10
+ let xAxisPlotBands = [];
11
+ let yAxisPlotBands = [];
12
+ this.rangeAnnotations.forEach((rangeAnnotation) => {
13
+ let adjustedRangeValues = this.adjustRangeForCategoryAxis(rangeAnnotation, chartType);
14
+ let rangeAnnotationLabelWidth = undefined;
15
+ if (!rangeAnnotation.labelInside) {
16
+ rangeAnnotationLabelWidth = rangeAnnotation.labelWidth ? rangeAnnotation.labelWidth : 150;
17
+ }
18
+ let rangeConfig = {
19
+ from: adjustedRangeValues.axisValue1,
20
+ to: adjustedRangeValues.axisValue2,
21
+ label: {
22
+ text: rangeAnnotation.text,
23
+ useHTML: true,
24
+ className: rangeAnnotation.labelInside
25
+ ? `ons-chart__range-annotation-label ons-chart__range-annotation-label--${rangeAnnotation.axis}`
26
+ : 'ons-chart__range-annotation-label--outside',
27
+ allowOverlap: true,
28
+ style: {
29
+ color: this.constants.labelColor,
30
+ fontSize: this.constants.defaultFontSize,
31
+ // This property is not set as an inline style if rangeAnnotation.labelInside is undefined
32
+ width: rangeAnnotationLabelWidth,
33
+ },
34
+ },
35
+ color: this.constants.shadingColor,
36
+ };
37
+ if (!rangeAnnotation.labelInside && rangeAnnotation.labelOffsetX) {
38
+ rangeConfig.label.x = rangeAnnotation.labelOffsetX;
39
+ }
40
+ if (!rangeAnnotation.labelInside && rangeAnnotation.labelOffsetY) {
41
+ rangeConfig.label.y = rangeAnnotation.labelOffsetY;
42
+ }
43
+ if (rangeAnnotation.axis === 'x') {
44
+ xAxisPlotBands.push(rangeConfig);
45
+ } else if (rangeAnnotation.axis === 'y') {
46
+ yAxisPlotBands.push(rangeConfig);
47
+ }
48
+ });
49
+ return {
50
+ xAxis: xAxisPlotBands.length > 0 ? { plotBands: xAxisPlotBands } : undefined,
51
+ yAxis: yAxisPlotBands.length > 0 ? { plotBands: yAxisPlotBands } : undefined,
52
+ };
53
+ };
54
+
55
+ getRangeAnnotationsOptionsMobile = (annotationsLength, chartType) => {
56
+ let xAxisPlotBands = [];
57
+ let yAxisPlotBands = [];
58
+ this.rangeAnnotations.forEach((rangeAnnotation, index) => {
59
+ let adjustedRangeValues = this.adjustRangeForCategoryAxis(rangeAnnotation, chartType);
60
+ let rangeConfig = {
61
+ from: adjustedRangeValues.axisValue1,
62
+ to: adjustedRangeValues.axisValue2,
63
+ label: {
64
+ // Add the number of point annotations to the current range annotation loop
65
+ // So that if we have both types of annotations, the numbers will be sequential
66
+ text: `${annotationsLength + index + 1}`,
67
+ useHTML: true,
68
+ className: 'ons-chart__footnote-number',
69
+ allowOverlap: true,
70
+ style: {
71
+ color: this.constants.labelColor,
72
+ fontSize: this.constants.defaultFontSize,
73
+ },
74
+ },
75
+ color: this.constants.shadingColor,
76
+ };
77
+ if (rangeAnnotation.axis === 'x') {
78
+ xAxisPlotBands.push(rangeConfig);
79
+ } else if (rangeAnnotation.axis === 'y') {
80
+ yAxisPlotBands.push(rangeConfig);
81
+ }
82
+ });
83
+ return {
84
+ xAxis: xAxisPlotBands.length > 0 ? { plotBands: xAxisPlotBands } : undefined,
85
+ yAxis: yAxisPlotBands.length > 0 ? { plotBands: yAxisPlotBands } : undefined,
86
+ };
87
+ };
88
+
89
+ // Returns the position of the label relative to the plotBand
90
+ getLabelPosition = (chartType, labelRect, plotBandRect, isXaxis) => {
91
+ let isToLeft = false;
92
+ let isToRight = false;
93
+ let isToTop = false;
94
+ let isToBottom = false;
95
+ let isVertical = chartType === 'bar' ? !isXaxis : isXaxis;
96
+ if (isVertical) {
97
+ // vertical plotBand
98
+ if (labelRect.right < plotBandRect.left) {
99
+ isToLeft = true;
100
+ }
101
+ if (labelRect.left > plotBandRect.right) {
102
+ isToRight = true;
103
+ }
104
+ } else {
105
+ // horizontal plotBand
106
+ if (labelRect.bottom < plotBandRect.top) {
107
+ isToTop = true;
108
+ }
109
+ if (labelRect.top > plotBandRect.bottom) {
110
+ isToBottom = true;
111
+ }
112
+ }
113
+ return { isToLeft, isToRight, isToTop, isToBottom };
114
+ };
115
+
116
+ // Draws the line connecting the label to the plotBand
117
+ // Also adds a custom class to the label based on its position
118
+ addLine = (currentChart) => {
119
+ // If there is already a line in the chart, remove it before redrawing it
120
+ const lines = currentChart.container.querySelectorAll('[data-range-annotation-line]');
121
+ if (lines.length > 0) {
122
+ lines.forEach((line) => {
123
+ line.remove();
124
+ });
125
+ }
126
+
127
+ // Get all plotBands from both axes
128
+ // The filter ensures that plotLines are not included as they will have a `value` property rather than `from` and `to` properties
129
+ const xAxisPlotBands = currentChart.xAxis[0].plotLinesAndBands.filter((band) => band.options.from !== undefined);
130
+ const yAxisPlotBands = currentChart.yAxis[0].plotLinesAndBands.filter((band) => band.options.from !== undefined);
131
+
132
+ // Combine all plotBands
133
+ const allPlotBands = [...xAxisPlotBands, ...yAxisPlotBands];
134
+
135
+ allPlotBands.forEach((plotBand) => {
136
+ // If the label is set to be inside the plotBand, exit early and don't draw a line
137
+ if (plotBand.options.label.x === undefined && plotBand.options.label.y === undefined) {
138
+ return;
139
+ }
140
+
141
+ // Get the plotBand element
142
+ const plotBandElement = plotBand.svgElem.element;
143
+ const plotBandRect = plotBandElement.getBoundingClientRect();
144
+
145
+ // Get the label element
146
+ const labelElement = plotBand.label.element;
147
+ const labelRect = labelElement.getBoundingClientRect();
148
+
149
+ // Get the label position relative to the plotBand (left, right, top or bottom)
150
+ const labelPosition = this.getLabelPosition(
151
+ currentChart.userOptions.chart.type,
152
+ labelRect,
153
+ plotBandRect,
154
+ plotBand.axis.isXAxis,
155
+ );
156
+
157
+ // Only draw a line in the label doesn't overlap the plot band
158
+ if (!(labelPosition.isToLeft || labelPosition.isToRight || labelPosition.isToTop || labelPosition.isToBottom)) {
159
+ return;
160
+ }
161
+
162
+ // Create and add the connecting line
163
+ const line = document.createElement('div');
164
+ line.classList.add('ons-chart__connector-line');
165
+ line.setAttribute('data-range-annotation-line', true);
166
+ labelElement.appendChild(line);
167
+
168
+ // Draw the line based on the label position
169
+ if (labelPosition.isToRight) {
170
+ let divWidth = labelRect.left - plotBandRect.right;
171
+ line.style.width = `${divWidth}px`;
172
+ line.style.height = '1px';
173
+ line.style.top = `${labelRect.height / 2}px`;
174
+ line.style.left = `-${divWidth}px`;
175
+ labelElement.classList.add('ons-chart__range-annotation-label--right');
176
+ }
177
+
178
+ if (labelPosition.isToLeft) {
179
+ let divWidth = plotBandRect.left - labelRect.right;
180
+ line.style.width = `${divWidth}px`;
181
+ line.style.height = '1px';
182
+ line.style.top = `${labelRect.height / 2}px`;
183
+ line.style.right = `-${divWidth}px`;
184
+ labelElement.classList.add('ons-chart__range-annotation-label--left');
185
+ }
186
+
187
+ if (labelPosition.isToTop) {
188
+ let divHeight = plotBandRect.top - labelRect.bottom;
189
+ line.style.height = `${divHeight}px`;
190
+ line.style.width = '1px';
191
+ line.style.top = `${labelRect.height}px`;
192
+ line.style.left = `${labelRect.width / 2}px`;
193
+ labelElement.classList.add('ons-chart__range-annotation-label--top');
194
+ }
195
+
196
+ if (labelPosition.isToBottom) {
197
+ let divHeight = labelRect.top - plotBandRect.bottom;
198
+ line.style.height = `${divHeight}px`;
199
+ line.style.width = '1px';
200
+ line.style.top = `-${divHeight}px`;
201
+ line.style.left = `${labelRect.width / 2}px`;
202
+ labelElement.classList.add('ons-chart__range-annotation-label--bottom');
203
+ }
204
+ });
205
+ };
206
+
207
+ // For bar and column charts, we want the range to
208
+ // start and end flush with the edges of the columns / bars,
209
+ // not halfway through as is the Highcharts default.
210
+ adjustRangeForCategoryAxis = (rangeAnnotation, chartType) => {
211
+ let axisValue1 = rangeAnnotation.range.axisValue1;
212
+ let axisValue2 = rangeAnnotation.range.axisValue2;
213
+ if ((chartType === 'bar' && rangeAnnotation.axis === 'x') || (chartType === 'column' && rangeAnnotation.axis === 'x')) {
214
+ axisValue1 = rangeAnnotation.range.axisValue1 - 0.5;
215
+ axisValue2 = rangeAnnotation.range.axisValue2 - 0.5;
216
+ }
217
+ return { axisValue1, axisValue2 };
218
+ };
219
+ }
220
+
221
+ export default RangeAnnotationsOptions;
@@ -0,0 +1,93 @@
1
+ import ChartConstants from './chart-constants';
2
+
3
+ class ReferenceLineAnnotationsOptions {
4
+ constructor(referenceLineAnnotations) {
5
+ this.constants = ChartConstants.constants();
6
+ this.referenceLineAnnotations = referenceLineAnnotations;
7
+ }
8
+
9
+ getReferenceLineAnnotationsOptionsDesktop = () => {
10
+ let xAxisPlotLines = [];
11
+ let yAxisPlotLines = [];
12
+ this.referenceLineAnnotations.forEach((referenceLineAnnotation) => {
13
+ let referenceLineConfig = {
14
+ label: {
15
+ text: referenceLineAnnotation.text,
16
+ style: {
17
+ color: this.constants.labelColor,
18
+ fontSize: this.constants.defaultFontSize,
19
+ width: referenceLineAnnotation.labelWidth ? referenceLineAnnotation.labelWidth : 150,
20
+ },
21
+ x: referenceLineAnnotation.labelOffsetX ? referenceLineAnnotation.labelOffsetX : 10,
22
+ y: referenceLineAnnotation.labelOffsetY ? referenceLineAnnotation.labelOffsetY : 20,
23
+ rotation: 0,
24
+ align: 'left',
25
+ textAlign: 'left',
26
+ },
27
+ color: this.constants.zeroLineColor,
28
+ // note this works to give a dashed line with 4px and a 4px gap, but
29
+ // this way of styling it is undocumented
30
+ dashStyle: '2 2',
31
+ width: 2,
32
+ value: referenceLineAnnotation.value,
33
+ zIndex: 3,
34
+ };
35
+ if (referenceLineAnnotation.axis === 'x') {
36
+ xAxisPlotLines.push(referenceLineConfig);
37
+ } else if (referenceLineAnnotation.axis === 'y') {
38
+ yAxisPlotLines.push(referenceLineConfig);
39
+ }
40
+ });
41
+ return {
42
+ xAxis: xAxisPlotLines.length > 0 ? { plotLines: xAxisPlotLines } : undefined,
43
+ yAxis: yAxisPlotLines.length > 0 ? { plotLines: yAxisPlotLines } : undefined,
44
+ };
45
+ };
46
+
47
+ getReferenceLineAnnotationsOptionsMobile = (annotationsLength, chartType) => {
48
+ let xAxisPlotLines = [];
49
+ let yAxisPlotLines = [];
50
+ this.referenceLineAnnotations.forEach((referenceLineAnnotation, index) => {
51
+ let isVertical = referenceLineAnnotation.axis === 'x' ? true : false;
52
+ if (chartType === 'bar') {
53
+ isVertical = !isVertical;
54
+ }
55
+ let referenceLineConfig = {
56
+ label: {
57
+ // Add the number of point and range annotations to the current reference line annotation loop
58
+ // So that if we have more than one type of annotations, the numbers will be sequential
59
+ text: `${annotationsLength + index + 1}`,
60
+ useHTML: true,
61
+ className: 'ons-chart__footnote-number',
62
+ allowOverlap: true,
63
+ style: {
64
+ color: this.constants.labelColor,
65
+ fontSize: this.constants.defaultFontSize,
66
+ },
67
+ x: isVertical ? 7 : 0,
68
+ y: isVertical ? 13 : -10, // 13 works with the height of the styled number
69
+ rotation: 0,
70
+ zIndex: 3,
71
+ },
72
+ color: this.constants.zeroLineColor,
73
+ // note this works to give a dashed line with 4px and a 4px gap, but
74
+ // this way of styling it is undocumented
75
+ dashStyle: '2 2',
76
+ width: 2,
77
+ value: referenceLineAnnotation.value,
78
+ zIndex: 3,
79
+ };
80
+ if (referenceLineAnnotation.axis === 'x') {
81
+ xAxisPlotLines.push(referenceLineConfig);
82
+ } else if (referenceLineAnnotation.axis === 'y') {
83
+ yAxisPlotLines.push(referenceLineConfig);
84
+ }
85
+ });
86
+ return {
87
+ xAxis: xAxisPlotLines.length > 0 ? { plotLines: xAxisPlotLines } : undefined,
88
+ yAxis: yAxisPlotLines.length > 0 ? { plotLines: yAxisPlotLines } : undefined,
89
+ };
90
+ };
91
+ }
92
+
93
+ export default ReferenceLineAnnotationsOptions;
@@ -4,16 +4,11 @@ class ScatterChart {
4
4
  constructor() {
5
5
  this.chartConstants = ChartConstants.constants();
6
6
  this.markerStyles = this.chartConstants.scatterMarkerStyles;
7
+ this.confidenceLevelMarkerStyles = this.chartConstants.confidenceLevelMarkerStyles;
7
8
  }
8
9
 
9
10
  getScatterChartOptions = () => {
10
11
  return {
11
- plotOptions: {
12
- scatter: {
13
- // enable tooltips for scatter charts
14
- enableMouseTracking: true,
15
- },
16
- },
17
12
  xAxis: {
18
13
  gridLineWidth: 1,
19
14
  },
@@ -29,6 +24,20 @@ class ScatterChart {
29
24
  series.update({ marker: this.markerStyles[i] != undefined ? this.markerStyles[i] : this.markerStyles[0] }, false);
30
25
  });
31
26
  };
27
+
28
+ updateMarkersForConfidenceLevels = (series) => {
29
+ series.forEach((series, i) => {
30
+ series.update(
31
+ {
32
+ marker:
33
+ this.confidenceLevelMarkerStyles[i] != undefined
34
+ ? this.confidenceLevelMarkerStyles[i]
35
+ : this.confidenceLevelMarkerStyles[0],
36
+ },
37
+ false,
38
+ );
39
+ });
40
+ };
32
41
  }
33
42
 
34
43
  export default ScatterChart;
@@ -11,12 +11,33 @@ class SpecificChartOptions {
11
11
  colors: this.theme === 'alternate' ? this.constants.alternateTheme : this.constants.primaryTheme,
12
12
  chart: {
13
13
  type: type,
14
- marginTop: this.config.legend.enabled ? undefined : 50,
14
+ marginTop: this.config.legend.enabled ? (type === 'boxplot' ? 50 : undefined) : 50,
15
15
  },
16
16
  };
17
17
  }
18
18
 
19
19
  getOptions = () => this.options;
20
+
21
+ // Add zero line or custom reference line (but only for column or line charts)
22
+ getReferenceLine = (customReferenceLineValue, chartType) => {
23
+ let lineValue = 0;
24
+ if (customReferenceLineValue && (chartType === 'line' || chartType === 'column')) {
25
+ lineValue = customReferenceLineValue;
26
+ }
27
+
28
+ return {
29
+ yAxis: {
30
+ plotLines: [
31
+ {
32
+ color: this.constants.zeroLineColor,
33
+ width: 1.5,
34
+ value: lineValue,
35
+ zIndex: 2,
36
+ },
37
+ ],
38
+ },
39
+ };
40
+ };
20
41
  }
21
42
 
22
43
  export default SpecificChartOptions;
@@ -0,0 +1,97 @@
1
+ // Utility function to merge two configs together
2
+ export const mergeConfigs = (baseConfig, newConfig) => {
3
+ // If newConfig is null/undefined, return baseConfig
4
+ if (!newConfig) return baseConfig;
5
+
6
+ // Create a new object to store the merged result
7
+ const merged = { ...baseConfig };
8
+
9
+ // Iterate through all keys in newConfig
10
+ Object.keys(newConfig).forEach((key) => {
11
+ // Get values from both configs for this key
12
+ const baseValue = merged[key];
13
+ const newValue = newConfig[key];
14
+
15
+ // If both values are objects (and not null), recursively merge them
16
+ if (
17
+ baseValue &&
18
+ newValue &&
19
+ typeof baseValue === 'object' &&
20
+ typeof newValue === 'object' &&
21
+ !Array.isArray(baseValue) &&
22
+ !Array.isArray(newValue)
23
+ ) {
24
+ merged[key] = mergeConfigs(baseValue, newValue);
25
+ } else {
26
+ // For non-objects and arrays use the new value
27
+ // If the new value is null/undefined, use the base value
28
+ merged[key] = newValue ?? baseValue;
29
+ }
30
+ });
31
+
32
+ return merged;
33
+ };
34
+
35
+ // Helper function to process the range and reference line annotations plus any plot lines config
36
+ // ready to pass to the responsive rules
37
+ export const preparePlotLinesAndBands = (
38
+ annotations = undefined,
39
+ rangeAnnotations = undefined,
40
+ rangeAnnotationsOptions = undefined,
41
+ referenceLineAnnotationsOptions = undefined,
42
+ specificChartOptions,
43
+ chartType,
44
+ customReferenceLineValue,
45
+ ) => {
46
+ const totalPointAndRangeAnnotations = (annotations ? annotations.length : 0) + (rangeAnnotations ? rangeAnnotations.length : 0);
47
+
48
+ // Both range and reference line annotations are added to the axis objects, so we need to correctly combine them before we can pass them to the config.
49
+ let desktopRangeAnnotations = {};
50
+ let mobileRangeAnnotations = {};
51
+ let desktopReferenceLineAnnotations = {};
52
+ let mobileReferenceLineAnnotations = {};
53
+ let desktopAllPlotLines = {};
54
+ let mobileAllPlotLines = {};
55
+ let desktopAllPlotLinesAndBands = {};
56
+ let mobileAllPlotLinesAndBands = {};
57
+
58
+ // get the desktop and mobile range annotations
59
+ if (rangeAnnotationsOptions) {
60
+ desktopRangeAnnotations = rangeAnnotationsOptions.getRangeAnnotationsOptionsDesktop(chartType);
61
+ mobileRangeAnnotations = rangeAnnotationsOptions.getRangeAnnotationsOptionsMobile(annotations ? annotations.length : 0, chartType);
62
+ }
63
+
64
+ // get the desktop and mobile reference line annotations
65
+ if (referenceLineAnnotationsOptions) {
66
+ desktopReferenceLineAnnotations = referenceLineAnnotationsOptions.getReferenceLineAnnotationsOptionsDesktop();
67
+ mobileReferenceLineAnnotations = referenceLineAnnotationsOptions.getReferenceLineAnnotationsOptionsMobile(
68
+ totalPointAndRangeAnnotations,
69
+ chartType,
70
+ );
71
+ }
72
+
73
+ // We also need to combine the zero line / custom reference line with the reference line annotations here, as otherwise
74
+ // it gets overridden by the reference line annotations config
75
+ let plotLineOptions = specificChartOptions.getReferenceLine(customReferenceLineValue, chartType);
76
+ desktopAllPlotLines = { ...desktopReferenceLineAnnotations };
77
+ mobileAllPlotLines = { ...mobileReferenceLineAnnotations };
78
+
79
+ if (desktopReferenceLineAnnotations.yAxis !== undefined) {
80
+ let desktopMergedPlotLines = desktopReferenceLineAnnotations.yAxis.plotLines.concat(plotLineOptions.yAxis.plotLines);
81
+ let mobileMergedPlotLines = mobileReferenceLineAnnotations.yAxis.plotLines.concat(plotLineOptions.yAxis.plotLines);
82
+ desktopAllPlotLines.yAxis.plotLines = desktopMergedPlotLines;
83
+ mobileAllPlotLines.yAxis.plotLines = mobileMergedPlotLines;
84
+ } else {
85
+ desktopAllPlotLines.yAxis = { ...plotLineOptions.yAxis };
86
+ mobileAllPlotLines.yAxis = { ...plotLineOptions.yAxis };
87
+ }
88
+
89
+ // combine the desktop and mobile range and reference line annotations, along with other plot lines, ready to pass to the config
90
+ desktopAllPlotLinesAndBands = mergeConfigs(desktopRangeAnnotations, desktopAllPlotLines);
91
+ mobileAllPlotLinesAndBands = mergeConfigs(mobileRangeAnnotations, mobileAllPlotLines);
92
+
93
+ return {
94
+ desktopAllPlotLinesAndBands,
95
+ mobileAllPlotLinesAndBands,
96
+ };
97
+ };
@@ -164,7 +164,7 @@ describe('macro: checkboxes', () => {
164
164
  it('renders the text area with expected parameters', () => {
165
165
  const $ = cheerio.load(renderComponent('checkboxes', EXAMPLE_CHECKBOX_ITEM_CHECKBOXES_WITH_TEXTAREA));
166
166
  expect($('.ons-input--textarea').attr('name')).toBe('other answer');
167
- expect($('.ons-input--textarea').attr('maxlength')).toBe('300');
167
+ expect($('.ons-input--textarea').attr('data-char-check-num')).toBe('300');
168
168
  expect($('.ons-input__limit').attr('data-charcount-singular')).toBe('You have {x} character remaining');
169
169
  expect($('.ons-input__limit').attr('data-charcount-plural')).toBe('You have {x} characters remaining');
170
170
  });
@@ -65,7 +65,7 @@ describe('script: mutually-exclusive', () => {
65
65
  });
66
66
 
67
67
  it('then the characters remaining readout should be reset', async () => {
68
- const limitText = await page.$eval('#feedback-lim', (node) => node.textContent);
68
+ const limitText = await page.$eval('#feedback-check', (node) => node.textContent);
69
69
  expect(limitText).toBe('You have 200 characters remaining');
70
70
  });
71
71
 
@@ -19,14 +19,14 @@
19
19
 
20
20
  <textarea
21
21
  id="{{ params.id }}"
22
- class="ons-input ons-input--textarea{{ ' ons-input--error' if params.error }}{{ ' ons-js-char-limit-input' if params.charCheckLimit and params.charCheckLimit.limit }}{{ textareaExclusiveClass }}{{ ' ' + params.classes if params.classes else '' }}{% if params.width %}{{ ' ' }}ons-input--w-{{ params.width }}{% endif %}"
22
+ class="ons-input ons-input--textarea{{ ' ons-input--error' if params.error }}{{ ' ons-js-char-check-input' if params.charCheckLimit and params.charCheckLimit.limit }}{{ textareaExclusiveClass }}{{ ' ' + params.classes if params.classes else '' }}{% if params.width %}{{ ' ' }}ons-input--w-{{ params.width }}{% endif %}"
23
23
  {% if params.name %}
24
24
  name="{{ params.name }}"
25
25
  {% endif %}
26
26
  rows="{{ params.rows | default(8) }}"
27
- {% if params.charCheckLimit and params.charCheckLimit.limit %}
28
- maxlength="{{ params.charCheckLimit.limit }}" data-char-limit-ref="{{ params.id }}-lim"
29
- aria-describedby="{{ params.id }}-lim"
27
+ {% if params.charCheckLimit %}
28
+ data-char-check-ref="{{ params.id }}-check" data-char-check-num="{{ params.charCheckLimit.limit }}"
29
+ aria-describedby="{{ params.id }}-check" data-char-check-countdown=true
30
30
  {% endif %}
31
31
  {% if params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{ ' ' }}{{ attribute }}{% if value %}="{{ value }}"{% endif %}{% endfor %}{% endif %}
32
32
  >
@@ -36,10 +36,12 @@
36
36
  {% if params.charCheckLimit and params.charCheckLimit.limit %}
37
37
  {%
38
38
  call onsCharLimit({
39
- "id": params.id ~ "-lim",
39
+ "id": params.id ~ "-check",
40
40
  "limit": params.charCheckLimit.limit,
41
41
  "charCountSingular": params.charCheckLimit.charCountSingular,
42
- "charCountPlural": params.charCheckLimit.charCountPlural
42
+ "charCountPlural": params.charCheckLimit.charCountPlural,
43
+ "charCountOverLimitSingular": params.charCheckLimit.charCountOverLimitSingular,
44
+ "charCountOverLimitPlural": params.charCheckLimit.charCountOverLimitPlural
43
45
  })
44
46
  %}
45
47
  {% endcall %}
@@ -22,6 +22,8 @@ const EXAMPLE_TEXTAREA_WITH_CHARACTER_LIMIT = {
22
22
  limit: 200,
23
23
  charCountSingular: 'You have {x} character remaining',
24
24
  charCountPlural: 'You have {x} characters remaining',
25
+ charCountOverLimitSingular: '{x} character too many',
26
+ charCountOverLimitPlural: '{x} characters too many',
25
27
  },
26
28
  };
27
29
 
@@ -200,29 +202,29 @@ describe('macro: textarea', () => {
200
202
  });
201
203
  });
202
204
 
203
- describe('with character limit', () => {
204
- it('has the `ons-js-char-limit-input` class', () => {
205
+ describe('with character check', () => {
206
+ it('has the `ons-js-char-check-input` class', () => {
205
207
  const $ = cheerio.load(renderComponent('textarea', EXAMPLE_TEXTAREA_WITH_CHARACTER_LIMIT));
206
208
 
207
- expect($('.ons-input--textarea').hasClass('ons-js-char-limit-input')).toBe(true);
209
+ expect($('.ons-input--textarea').hasClass('ons-js-char-check-input')).toBe(true);
208
210
  });
209
211
 
210
212
  it('has the provided maximum length', () => {
211
213
  const $ = cheerio.load(renderComponent('textarea', EXAMPLE_TEXTAREA_WITH_CHARACTER_LIMIT));
212
214
 
213
- expect($('.ons-input--textarea').attr('maxlength')).toBe('200');
215
+ expect($('.ons-input--textarea').attr('data-char-check-num')).toBe('200');
214
216
  });
215
217
 
216
- it('has data attribute which references the character limit component', () => {
218
+ it('has data attribute which references the character check component', () => {
217
219
  const $ = cheerio.load(renderComponent('textarea', EXAMPLE_TEXTAREA_WITH_CHARACTER_LIMIT));
218
220
 
219
- expect($('.ons-input--textarea').attr('data-char-limit-ref')).toBe('example-id-lim');
221
+ expect($('.ons-input--textarea').attr('data-char-check-ref')).toBe('example-id-check');
220
222
  });
221
223
 
222
224
  it('has `aria-describedby` attribute which references the character limit component', () => {
223
225
  const $ = cheerio.load(renderComponent('textarea', EXAMPLE_TEXTAREA_WITH_CHARACTER_LIMIT));
224
226
 
225
- expect($('.ons-input--textarea').attr('aria-describedby')).toBe('example-id-lim');
227
+ expect($('.ons-input--textarea').attr('aria-describedby')).toBe('example-id-check');
226
228
  });
227
229
 
228
230
  it('renders character limit component', () => {
@@ -232,10 +234,12 @@ describe('macro: textarea', () => {
232
234
  faker.renderComponent('textarea', EXAMPLE_TEXTAREA_WITH_CHARACTER_LIMIT);
233
235
 
234
236
  expect(charCheckLimitSpy.occurrences).toContainEqual({
235
- id: 'example-id-lim',
237
+ id: 'example-id-check',
236
238
  limit: 200,
237
239
  charCountSingular: 'You have {x} character remaining',
238
240
  charCountPlural: 'You have {x} characters remaining',
241
+ charCountOverLimitSingular: '{x} character too many',
242
+ charCountOverLimitPlural: '{x} characters too many',
239
243
  });
240
244
  });
241
245
  });
@@ -12,7 +12,9 @@
12
12
  "charCheckLimit": {
13
13
  "limit": 200,
14
14
  "charCountSingular": "You have {x} character remaining",
15
- "charCountPlural": "You have {x} characters remaining"
15
+ "charCountPlural": "You have {x} characters remaining",
16
+ "charCountOverLimitSingular": "{x} character too many",
17
+ "charCountOverLimitPlural": "{x} characters too many"
16
18
  }
17
19
  })
18
20
  }}