@ons/design-system 72.9.0 → 72.9.2

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 (36) hide show
  1. package/components/button/_button.scss +10 -0
  2. package/components/card/_macro.njk +17 -4
  3. package/components/card/_macro.spec.js +109 -252
  4. package/components/card/_test_examples.js +56 -0
  5. package/components/card/example-card-set-with-headline-figures.njk +1 -4
  6. package/components/chart/_macro.njk +2 -1
  7. package/components/chart/_macro.spec.js +17 -121
  8. package/components/chart/area-chart.js +1 -0
  9. package/components/chart/bar-chart.js +2 -2
  10. package/components/chart/chart.js +13 -8
  11. package/components/chart/common-chart-options.js +0 -4
  12. package/components/details-panel/_macro.njk +5 -1
  13. package/components/details-panel/_macro.spec.js +22 -0
  14. package/components/document-list/_document-list.scss +5 -13
  15. package/components/document-list/_macro.njk +14 -17
  16. package/components/document-list/_macro.spec.js +3 -3
  17. package/components/fieldset/_macro.spec.js +200 -120
  18. package/components/fieldset/_test_examples.js +15 -0
  19. package/components/header/_header.scss +11 -0
  20. package/components/header/_macro.njk +11 -6
  21. package/components/header/_macro.spec.js +113 -3
  22. package/components/hero/_macro.spec.js +1 -1
  23. package/components/icon/_macro.njk +14 -24
  24. package/components/language-selector/_macro.njk +6 -3
  25. package/components/navigation/navigation.js +57 -58
  26. package/components/navigation/navigation.spec.js +6 -10
  27. package/components/summary/_macro.njk +4 -1
  28. package/components/table-of-contents/_macro.njk +2 -12
  29. package/components/table-of-contents/_macro.spec.js +7 -0
  30. package/components/table-of-contents/example-table-of-contents-related-links-with-button.njk +1 -2
  31. package/components/table-of-contents/table-of-contents.js +43 -26
  32. package/css/main.css +1 -1
  33. package/package.json +1 -1
  34. package/scripts/main.es5.js +1 -1
  35. package/scripts/main.js +1 -1
  36. package/components/chart/example-bar-with-line-chart.njk +0 -64
@@ -13,7 +13,6 @@ import {
13
13
  EXAMPLE_LINE_CHART_WITH_ANNOTATIONS_PARAMS,
14
14
  EXAMPLE_BAR_CHART_WITH_ANNOTATIONS_PARAMS,
15
15
  EXAMPLE_COLUMN_CHART_WITH_ANNOTATIONS_PARAMS,
16
- EXAMPLE_BAR_WITH_LINE_CHART_PARAMS,
17
16
  EXAMPLE_COLUMN_WITH_LINE_CHART_PARAMS,
18
17
  EXAMPLE_SCATTER_CHART_PARAMS,
19
18
  EXAMPLE_AREA_CHART_PARAMS,
@@ -625,126 +624,6 @@ describe('Macro: Chart', () => {
625
624
  });
626
625
  });
627
626
 
628
- describe('FOR: Bar Chart with Line', () => {
629
- describe('GIVEN: Params: required', () => {
630
- describe('WHEN: required params are provided', () => {
631
- const $ = cheerio.load(renderComponent('chart', EXAMPLE_BAR_WITH_LINE_CHART_PARAMS));
632
- const configScript = $(`script[data-highcharts-config--bar-chart-123]`).html();
633
-
634
- test('THEN: it passes jest-axe checks', async () => {
635
- const results = await axe($.html());
636
- expect(results).toHaveNoViolations();
637
- });
638
-
639
- test('THEN: it includes one series of type "bar" and another of type "line"', () => {
640
- expect(configScript).toContain('"type":"bar"');
641
- expect(configScript).toContain('"type":"line"');
642
- });
643
-
644
- test('THEN: it renders the chart container with correct data attributes', () => {
645
- expect($('[data-highcharts-base-chart]').attr('data-highcharts-type')).toBe('bar');
646
- expect($('[data-highcharts-base-chart]').attr('data-highcharts-theme')).toBe('alternate');
647
- expect($('[data-highcharts-base-chart]').attr('data-highcharts-title')).toBe('Example Bar Chart');
648
- expect($('[data-highcharts-base-chart]').attr('data-highcharts-id')).toBe('bar-chart-123');
649
- });
650
-
651
- test('THEN: it includes the Highcharts JSON config', () => {
652
- expect(configScript).toContain('"text":"X Axis Title"');
653
- expect(configScript).toContain('"text":"Y Axis Title"');
654
- });
655
- });
656
- });
657
-
658
- describe('GIVEN: Params: Legend', () => {
659
- describe('WHEN: legend is enabled', () => {
660
- const $ = cheerio.load(renderComponent('chart', { ...EXAMPLE_BAR_WITH_LINE_CHART_PARAMS, legend: false }));
661
-
662
- test('THEN: it renders the legend', () => {
663
- const configScript = $(`script[data-highcharts-config--bar-chart-123]`).html();
664
- expect(configScript).toContain('"enabled":false');
665
- });
666
- });
667
- });
668
-
669
- describe('GIVEN: Params: Caption', () => {
670
- describe('WHEN: caption is provided', () => {
671
- const $ = cheerio.load(
672
- renderComponent('chart', {
673
- ...EXAMPLE_BAR_WITH_LINE_CHART_PARAMS,
674
- caption: 'This is an example caption for the chart.',
675
- }),
676
- );
677
-
678
- test('THEN: it renders the caption when provided', () => {
679
- expect($('figcaption').text()).toBe('This is an example caption for the chart.');
680
- });
681
- });
682
- });
683
-
684
- describe('GIVEN: Params: Description', () => {
685
- describe('WHEN: description is provided', () => {
686
- const $ = cheerio.load(
687
- renderComponent('chart', {
688
- ...EXAMPLE_BAR_WITH_LINE_CHART_PARAMS,
689
- description: 'An accessible description for screen readers.',
690
- }),
691
- );
692
-
693
- test('THEN: it renders the description for accessibility', () => {
694
- expect($('.ons-u-vh').text()).toBe('An accessible description for screen readers.');
695
- });
696
- });
697
- });
698
-
699
- describe('GIVEN: Params: Series: Type', () => {
700
- describe('WHEN: a series has an invalid type', () => {
701
- const invalidTypeParams = {
702
- ...EXAMPLE_BAR_WITH_LINE_CHART_PARAMS,
703
- series: [
704
- { name: 'Invalid Series', data: [5, 15, 25], type: 'scatter' },
705
- { name: 'Valid Line Series', data: [10, 20, 30], type: 'line' },
706
- ],
707
- };
708
-
709
- const $ = cheerio.load(renderComponent('chart', invalidTypeParams));
710
- const configScript = $(`script[data-highcharts-config--bar-chart-123]`).html();
711
-
712
- test('THEN: it defaults non-line series type to the chartType', () => {
713
- expect(configScript).not.toContain('"type":"scatter"');
714
- expect(configScript).toContain('"type":"bar"');
715
- expect(configScript).toContain('"type":"line"');
716
- });
717
- });
718
- });
719
-
720
- describe('GIVEN: Params: Download', () => {
721
- describe('WHEN: download object are provided', () => {
722
- const $ = cheerio.load(
723
- renderComponent('chart', {
724
- ...EXAMPLE_BAR_WITH_LINE_CHART_PARAMS,
725
- download: {
726
- title: 'Download Chart Data',
727
- itemsList: [
728
- { text: 'Download as PNG', url: 'https://example.com/chart.png' },
729
- { text: 'Download as CSV', url: 'https://example.com/chart.csv' },
730
- ],
731
- },
732
- }),
733
- );
734
-
735
- test('THEN: it renders the download section correctly', () => {
736
- expect($('.ons-chart__download-title').text()).toBe('Download Chart Data');
737
-
738
- const downloadLinks = $('.ons-chart__download-title').next().find('li a');
739
- expect(downloadLinks.eq(0).text()).toBe('Download as PNG');
740
- expect(downloadLinks.eq(0).attr('href')).toBe('https://example.com/chart.png');
741
- expect(downloadLinks.eq(1).text()).toBe('Download as CSV');
742
- expect(downloadLinks.eq(1).attr('href')).toBe('https://example.com/chart.csv');
743
- });
744
- });
745
- });
746
- });
747
-
748
627
  describe('FOR: Column Chart with Line', () => {
749
628
  describe('GIVEN: Params: required', () => {
750
629
  describe('WHEN: required params are provided', () => {
@@ -863,6 +742,23 @@ describe('Macro: Chart', () => {
863
742
  });
864
743
  });
865
744
  });
745
+
746
+ describe('GIVEN: Params: ChartType', () => {
747
+ describe('WHEN: chartType is not compatible with line series', () => {
748
+ const params = {
749
+ ...EXAMPLE_COLUMN_WITH_LINE_CHART_PARAMS,
750
+ chartType: 'bar',
751
+ };
752
+
753
+ const $ = cheerio.load(renderComponent('chart', params));
754
+ const configScript = $('script[data-highcharts-config--column-chart-123]').html();
755
+
756
+ test('THEN: it falls back to chartType and does not include "line" series', () => {
757
+ expect(configScript).not.toContain('"type":"line"');
758
+ expect(configScript).toContain('"type":"bar"');
759
+ });
760
+ });
761
+ });
866
762
  });
867
763
 
868
764
  describe('FOR: Scatter chart', () => {
@@ -12,6 +12,7 @@ class AreaChart {
12
12
  // 'rectangle' counterintuitively gives a circle, because the legend icon has a border radius of half it's height by default
13
13
  legendSymbol: 'rectangle',
14
14
  stacking: 'normal',
15
+ lineWidth: 0,
15
16
  },
16
17
  series: {
17
18
  marker: {
@@ -125,9 +125,9 @@ class BarChart {
125
125
 
126
126
  // This updates the height of the vertical axis and overall chart to fit the number of categories
127
127
  // Note that the vertical axis on a bar chart is the x axis
128
- updateBarChartHeight = (config, currentChart, useStackedLayout, numberOfExtraLines) => {
128
+ updateBarChartHeight = (config, currentChart, useStackedLayout) => {
129
129
  const numberOfCategories = config.xAxis.categories.length;
130
- const numberOfSeries = currentChart.series.length - numberOfExtraLines; // Get number of bar series
130
+ const numberOfSeries = currentChart.series.length; // Get number of bar series
131
131
  let barHeight = 30; // Height of each individual bar - set in bar-chart-plot-options
132
132
  let groupSpacing = 0; // Space we want between category groups, or between series groups for cluster charts
133
133
  let categoriesTotalHeight = 0;
@@ -34,10 +34,18 @@ class HighchartsBaseChart {
34
34
  }
35
35
  this.percentageHeightDesktop = this.node.dataset.highchartsPercentageHeightDesktop;
36
36
  this.percentageHeightMobile = this.node.dataset.highchartsPercentageHeightMobile;
37
- this.xAxisTickIntervalMobile = parseInt(this.node.dataset.highchartsXAxisTickIntervalMobile);
38
- this.xAxisTickIntervalDesktop = parseInt(this.node.dataset.highchartsXAxisTickIntervalDesktop);
39
- this.yAxisTickIntervalMobile = parseInt(this.node.dataset.highchartsYAxisTickIntervalMobile);
40
- this.yAxisTickIntervalDesktop = parseInt(this.node.dataset.highchartsYAxisTickIntervalDesktop);
37
+ this.xAxisTickIntervalMobile = this.node.dataset.highchartsXAxisTickIntervalMobile
38
+ ? parseInt(this.node.dataset.highchartsXAxisTickIntervalMobile)
39
+ : undefined;
40
+ this.xAxisTickIntervalDesktop = this.node.dataset.highchartsXAxisTickIntervalDesktop
41
+ ? parseInt(this.node.dataset.highchartsXAxisTickIntervalDesktop)
42
+ : undefined;
43
+ this.yAxisTickIntervalMobile = this.node.dataset.highchartsYAxisTickIntervalMobile
44
+ ? parseInt(this.node.dataset.highchartsYAxisTickIntervalMobile)
45
+ : undefined;
46
+ this.yAxisTickIntervalDesktop = this.node.dataset.highchartsYAxisTickIntervalDesktop
47
+ ? parseInt(this.node.dataset.highchartsYAxisTickIntervalDesktop)
48
+ : undefined;
41
49
  this.commonChartOptions = new CommonChartOptions(this.xAxisTickIntervalDesktop, this.yAxisTickIntervalDesktop);
42
50
  this.specificChartOptions = new SpecificChartOptions(this.theme, this.chartType, this.config);
43
51
  this.lineChart = new LineChart();
@@ -141,9 +149,6 @@ class HighchartsBaseChart {
141
149
  if (this.chartType === 'column') {
142
150
  this.config = this.mergeConfigs(this.config, columnChartOptions);
143
151
  }
144
- if (this.chartType === 'bar') {
145
- this.config = this.mergeConfigs(this.config, barChartOptions);
146
- }
147
152
  }
148
153
 
149
154
  // Disable the legend for single series charts
@@ -220,7 +225,7 @@ class HighchartsBaseChart {
220
225
  this.commonChartOptions.hideDataLabels(currentChart.series);
221
226
  }
222
227
  if (this.chartType === 'bar') {
223
- this.barChart.updateBarChartHeight(this.config, currentChart, this.useStackedLayout, this.extraLines);
228
+ this.barChart.updateBarChartHeight(this.config, currentChart, this.useStackedLayout);
224
229
  if (!this.hideDataLabels) {
225
230
  this.barChart.postLoadDataLabels(currentChart);
226
231
  } else {
@@ -183,10 +183,6 @@ class CommonChartOptions {
183
183
  const { label, symbol } = legendItem || {};
184
184
 
185
185
  if (seriesType === 'line') {
186
- symbol?.attr({
187
- x: 16, // Position the marker to the right of the line
188
- });
189
-
190
186
  label?.attr({
191
187
  x: 30, // Adjust label position to account for longer line
192
188
  });
@@ -4,7 +4,11 @@
4
4
  <div class="ons-container ons-details-panel__banner-contents">
5
5
  <span class="ons-details-panel__info-icon ons-u-mr-2xs" aria-hidden="true">i</span>
6
6
  <div class="ons-details-panel__banner-body">
7
- <h3 class="ons-details-panel__banner-title ons-u-mb-2xs">{{ params.title }}</h3>
7
+ {% set titleTag = params.headingLevel | default(2) %}
8
+ {% set openingTag = "<h" ~ titleTag %}
9
+ {% set closingTag = "</h" ~ titleTag ~ ">" %}
10
+ {{ openingTag | safe }}
11
+ class="ons-details-panel__banner-title ons-u-fs-m ons-u-mb-2xs">{{ params.title }}{{ closingTag | safe }}
8
12
  <div class="ons-details-panel__banner-detail ons-js-details-heading">
9
13
  <span class="ons-details-panel__banner-detail-title ons-js-corrections-details-title ons-u-mr-3xs"
10
14
  >Show detail</span
@@ -15,6 +15,28 @@ describe('FOR: Macro: Details Panel', () => {
15
15
  });
16
16
  });
17
17
 
18
+ describe('GIVEN: Params: headingLevel', () => {
19
+ describe('WHEN: headingLevel is provided', () => {
20
+ const customParams = {
21
+ ...EXAMPLE_DETAILS_PANEL,
22
+ headingLevel: 3,
23
+ };
24
+ const $ = cheerio.load(renderComponent('details-panel', customParams));
25
+ test('THEN: banner title uses the correct heading level', () => {
26
+ const bannerTitle = $('.ons-details-panel__banner-title');
27
+ expect(bannerTitle.prop('tagName')).toBe('H3');
28
+ });
29
+ });
30
+
31
+ describe('WHEN: headingLevel is not provided', () => {
32
+ const $ = cheerio.load(renderComponent('details-panel', EXAMPLE_DETAILS_PANEL));
33
+ test('THEN: banner title uses default heading level (h2)', () => {
34
+ const bannerTitle = $('.ons-details-panel__banner-title');
35
+ expect(bannerTitle.prop('tagName')).toBe('H2');
36
+ });
37
+ });
38
+ });
39
+
18
40
  describe('GIVEN: Params: detailsItems', () => {
19
41
  describe('WHEN: detailsItems is provided', () => {
20
42
  const $ = cheerio.load(renderComponent('details-panel', EXAMPLE_DETAILS_PANEL));
@@ -40,7 +40,7 @@
40
40
  .ons-document-list__item-image {
41
41
  width: 248px;
42
42
 
43
- & &__image-link {
43
+ & &__image {
44
44
  &--placeholder {
45
45
  height: 96px;
46
46
  }
@@ -50,7 +50,7 @@
50
50
  margin-right: 2.5rem;
51
51
  width: 379px;
52
52
 
53
- & &__image-link {
53
+ & &__image {
54
54
  &--placeholder {
55
55
  height: 248px;
56
56
  }
@@ -100,7 +100,7 @@
100
100
  }
101
101
 
102
102
  &__item-image & {
103
- &__image-link {
103
+ &__image {
104
104
  &--placeholder {
105
105
  height: 96px;
106
106
  }
@@ -112,7 +112,7 @@
112
112
  }
113
113
 
114
114
  &__item-image--file & {
115
- &__image-link {
115
+ &__image {
116
116
  border-color: var(--ons-color-borders);
117
117
 
118
118
  &--placeholder {
@@ -121,20 +121,12 @@
121
121
  }
122
122
  }
123
123
 
124
- &__image-link {
124
+ &__image {
125
125
  border: 2px solid transparent;
126
126
  box-sizing: content-box;
127
127
  display: block;
128
128
  width: 100%;
129
129
 
130
- &:focus {
131
- background-color: var(--ons-color-placeholder) !important;
132
- border: 2px solid var(--ons-color-borders-document-image-focus);
133
- box-shadow: none;
134
- outline: 4px solid var(--ons-color-focus) !important;
135
- outline-offset: 0 !important;
136
- }
137
-
138
130
  &--placeholder {
139
131
  background-clip: padding-box;
140
132
  background-color: var(--ons-color-placeholder);
@@ -1,32 +1,29 @@
1
1
  {% macro onsDocumentList(params) %}
2
+ {% set titleTag = params.headingLevel | default(2) %}
3
+ {% set openingTag = "<h" ~ titleTag %}
4
+ {% set closingTag = "</h" ~ titleTag ~ ">" %}
2
5
  <ul
3
6
  {% if params.id %}id="{{ params.id }}"{% endif %}class="ons-document-list{{ ' ' + params.classes if params.classes else '' }}"
4
7
  {% if params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{ ' ' }}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
5
8
  >
6
9
  {% for document in params.documents %}
7
- {% set titleTag = params.headingLevel | default(2) %}
8
- {% set openingTag = "<h" ~ titleTag %}
9
- {% set closingTag = "</h" ~ titleTag ~ ">" %}
10
10
  {% set documentItem %}
11
11
  {% if document.thumbnail %}
12
12
  <div
13
13
  class="ons-document-list__item-image{{ ' ons-document-list__item-image--file' if document.metadata.file }}"
14
14
  aria-hidden="true"
15
15
  >
16
- <a
17
- class="ons-document-list__image-link{{ ' ons-document-list__image-link--placeholder' if not document.thumbnail.smallSrc }}"
18
- href="{{ document.title.url }}"
19
- tabindex="-1"
20
- >
21
- {% if document.thumbnail.smallSrc and document.thumbnail.largeSrc %}
22
- <img
23
- srcset="{{ document.thumbnail.smallSrc }} 1x, {{ document.thumbnail.largeSrc }} 2x"
24
- src="{{ document.thumbnail.smallSrc }}"
25
- alt=""
26
- loading="lazy"
27
- />
28
- {% endif %}
29
- </a>
16
+ {% if document.thumbnail.smallSrc and document.thumbnail.largeSrc %}
17
+ <img
18
+ class="ons-document-list__image"
19
+ srcset="{{ document.thumbnail.smallSrc }} 1x, {{ document.thumbnail.largeSrc }} 2x"
20
+ src="{{ document.thumbnail.smallSrc }}"
21
+ alt=""
22
+ loading="lazy"
23
+ />
24
+ {% else %}
25
+ <span class="ons-document-list__image ons-document-list__image--placeholder"> </span>
26
+ {% endif %}
30
27
  </div>
31
28
  {% endif %}
32
29
 
@@ -232,12 +232,12 @@ describe('FOR: Macro: Document list', () => {
232
232
  });
233
233
 
234
234
  test('THEN: has expected srcset attribute', () => {
235
- const srcset = $('.ons-document-list__image-link img').attr('srcset');
235
+ const srcset = $('.ons-document-list__image').attr('srcset');
236
236
  expect(srcset).toBe('/example-small.png 1x, /example-large.png 2x');
237
237
  });
238
238
 
239
239
  test('THEN: has expected src attribute', () => {
240
- const src = $('.ons-document-list__image-link img').attr('src');
240
+ const src = $('.ons-document-list__image').attr('src');
241
241
  expect(src).toBe('/example-small.png');
242
242
  });
243
243
  });
@@ -249,7 +249,7 @@ describe('FOR: Macro: Document list', () => {
249
249
  documents: [{ ...EXAMPLE_DOCUMENT_LIST_BASIC, thumbnail: true }],
250
250
  }),
251
251
  );
252
- expect($('.ons-document-list__image-link').hasClass('ons-document-list__image-link--placeholder')).toBe(true);
252
+ expect($('.ons-document-list__image').hasClass('ons-document-list__image--placeholder')).toBe(true);
253
253
  });
254
254
  });
255
255
  });