@ons/design-system 72.0.1 → 72.1.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.
@@ -15,6 +15,7 @@
15
15
  data-results-title="{{ params.resultsTitle }}"
16
16
  data-no-results="{{ params.noResults }}"
17
17
  data-type-more="{{ params.typeMore }}"
18
+ {% if params.resultsThreshold %}data-result-threshold="{{ params.resultsThreshold }}"{% endif %}
18
19
  {% if params.apiDomain %}data-api-domain="{{ params.apiDomain }}"{% endif %}
19
20
  {% if params.apiDomainBearerToken %}data-authorization-token="{{ params.apiDomainBearerToken }}"{% endif %}
20
21
  {% if params.apiManualQueryParams == true %}data-query-params=""{% endif %}
@@ -32,6 +32,11 @@ const EXAMPLE_AUTOSUGGEST = {
32
32
  typeMore: 'Continue entering to get suggestions',
33
33
  };
34
34
 
35
+ const EXAMPLE_AUTOSUGGEST_WITH_RESULTS_THRESHOLD = {
36
+ ...EXAMPLE_AUTOSUGGEST,
37
+ resultsThreshold: 0.5,
38
+ };
39
+
35
40
  describe('macro: autosuggest', () => {
36
41
  it('passes jest-axe checks', async () => {
37
42
  const $ = cheerio.load(renderComponent('autosuggest', EXAMPLE_AUTOSUGGEST));
@@ -47,7 +52,7 @@ describe('macro: autosuggest', () => {
47
52
  });
48
53
 
49
54
  it('has the provided data attributes', () => {
50
- const $ = cheerio.load(renderComponent('autosuggest', EXAMPLE_AUTOSUGGEST));
55
+ const $ = cheerio.load(renderComponent('autosuggest', EXAMPLE_AUTOSUGGEST_WITH_RESULTS_THRESHOLD));
51
56
 
52
57
  const $element = $('.ons-autosuggest');
53
58
  expect($element.attr('data-allow-multiple')).toBeUndefined();
@@ -63,6 +68,7 @@ describe('macro: autosuggest', () => {
63
68
  expect($element.attr('data-no-results')).toBe('No suggestions found. You can enter your own answer');
64
69
  expect($element.attr('data-results-title')).toBe('Suggestions');
65
70
  expect($element.attr('data-type-more')).toBe('Continue entering to get suggestions');
71
+ expect($element.attr('data-result-threshold')).toBe('0.5');
66
72
  });
67
73
 
68
74
  it('has the `data-allow-multiple` attribute when `allowMultiple` is `true`', () => {
@@ -609,6 +609,8 @@ describe('script: autosuggest', () => {
609
609
  expect(resultsItemCount).toBe(1);
610
610
  const warningText = await page.$eval('.ons-autosuggest__warning', (node) => node.textContent);
611
611
  expect(warningText.trim()).toBe('!Sorry, there is a problem.');
612
+ const warningContainer = await page.$eval('.ons-autosuggest__warning', (node) => node.id);
613
+ expect(warningContainer).toBe('country-of-birth-listbox');
612
614
  });
613
615
 
614
616
  it('the list and results element should be removed from the page', async () => {
@@ -657,7 +659,7 @@ describe('script: autosuggest', () => {
657
659
  await page.type('.ons-js-autosuggest-input', 'England', { delay: 20 });
658
660
  await page.keyboard.press('ArrowUp');
659
661
  await page.keyboard.press('Enter');
660
- // Defocus the autosuggest input.
662
+ // Unfocus the autosuggest input
661
663
  await page.keyboard.press('Tab');
662
664
  await page.focus('.ons-js-autosuggest-input');
663
665
 
@@ -37,6 +37,7 @@ export default class AutosuggestUI {
37
37
  errorAPI,
38
38
  errorAPILinkText,
39
39
  typeMore,
40
+ customResultsThreshold,
40
41
  }) {
41
42
  // DOM Elements
42
43
  this.context = context;
@@ -65,6 +66,7 @@ export default class AutosuggestUI {
65
66
  this.errorAPI = errorAPI || context.getAttribute('data-error-api');
66
67
  this.errorAPILinkText = errorAPILinkText || context.getAttribute('data-error-api-link-text');
67
68
  this.typeMore = typeMore || context.getAttribute('data-type-more');
69
+ this.customResultsThreshold = customResultsThreshold || context.getAttribute('data-result-threshold');
68
70
  this.language = context.getAttribute('data-lang');
69
71
  this.allowMultiple = context.getAttribute('data-allow-multiple') || false;
70
72
  this.listboxId = this.listbox.getAttribute('id');
@@ -293,9 +295,30 @@ export default class AutosuggestUI {
293
295
 
294
296
  async fetchSuggestions(sanitisedQuery, data) {
295
297
  this.abortFetch();
296
- const results = await runFuse(sanitisedQuery, data, this.lang, this.resultLimit);
298
+
299
+ const threshold =
300
+ this.customResultsThreshold != null && this.customResultsThreshold >= 0 && this.customResultsThreshold <= 1
301
+ ? this.customResultsThreshold
302
+ : 0.2;
303
+
304
+ let distance;
305
+ if (threshold >= 0.6) {
306
+ distance = 500;
307
+ } else if (threshold >= 0.4) {
308
+ distance = 300;
309
+ } else {
310
+ distance = 100;
311
+ }
312
+
313
+ const results = await runFuse(sanitisedQuery, data, this.lang, threshold, distance);
314
+
297
315
  results.forEach((result) => {
298
- result.sanitisedText = sanitiseAutosuggestText(result[this.lang], this.sanitisedQueryReplaceChars);
316
+ const resultItem = result.item ?? result;
317
+
318
+ result.sanitisedText = sanitiseAutosuggestText(
319
+ resultItem[this.lang] ?? resultItem['formattedAddress'],
320
+ this.sanitisedQueryReplaceChars,
321
+ );
299
322
  });
300
323
  return {
301
324
  status: this.responseStatus,
@@ -345,16 +368,18 @@ export default class AutosuggestUI {
345
368
  this.listbox.innerHTML = '';
346
369
  if (this.results) {
347
370
  this.resultOptions = this.results.map((result, index) => {
348
- let innerHTML = this.emboldenMatch(result[this.lang], this.query);
371
+ const resultItem = result.item ?? result;
372
+
373
+ let innerHTML = this.emboldenMatch(resultItem[this.lang] ?? resultItem['formattedAddress'], this.query);
349
374
 
350
375
  const listElement = document.createElement('li');
351
376
  listElement.className = classAutosuggestOption;
352
377
  listElement.setAttribute('id', `${this.listboxId}__option--${index}`);
353
378
  listElement.setAttribute('role', 'option');
354
- if (result.category) {
379
+ if (resultItem.category) {
355
380
  innerHTML =
356
381
  innerHTML +
357
- `<span class="ons-autosuggest__category ons-u-lighter ons-u-fs-s ons-u-db">${result.category}</span>`;
382
+ `<span class="ons-autosuggest__category ons-u-lighter ons-u-fs-s ons-u-db">${resultItem.category}</span>`;
358
383
  }
359
384
  listElement.innerHTML = innerHTML;
360
385
  listElement.addEventListener('click', () => {
@@ -485,16 +510,19 @@ export default class AutosuggestUI {
485
510
  if (this.results.length) {
486
511
  this.settingResult = true;
487
512
  const result = this.results[index || this.highlightedResultIndex || 0];
513
+ const resultItem = result.item ?? result;
514
+ const resultValue = resultItem[this.lang] ?? resultItem['formattedAddress'];
515
+
488
516
  this.resultSelected = true;
489
517
 
490
518
  if (this.allowMultiple === 'true') {
491
- let value = this.storeExistingSelections(result[this.lang]);
519
+ let value = this.storeExistingSelections(resultValue);
492
520
  result.displayText = value;
493
- } else if (result.url) {
494
- result.displayText = result[this.lang];
495
- window.location = result.url;
521
+ } else if (resultItem.url) {
522
+ result.displayText = resultValue;
523
+ window.location = resultItem.url;
496
524
  } else {
497
- result.displayText = result[this.lang];
525
+ result.displayText = resultValue;
498
526
  }
499
527
  this.onSelect(result).then(() => (this.settingResult = false));
500
528
 
@@ -511,6 +539,7 @@ export default class AutosuggestUI {
511
539
  const warningSpanElement = document.createElement('span');
512
540
  const warningBodyElement = document.createElement('div');
513
541
 
542
+ warningContainer.id = this.listbox.getAttribute('id');
514
543
  warningContainer.className = 'ons-autosuggest__warning';
515
544
  warningElement.className = 'ons-panel ons-panel--warn ons-autosuggest__panel';
516
545
 
@@ -24,7 +24,8 @@
24
24
  "resultsTitleId": "country-of-birth-suggestions",
25
25
  "autosuggestData": "/examples/data/country-of-birth.json",
26
26
  "noResults": "No suggestions found. You can enter your own answer",
27
- "typeMore": "Continue entering to get suggestions"
27
+ "typeMore": "Continue entering to get suggestions",
28
+ "resultsThreshold": 0.2
28
29
  })
29
30
  }}
30
31
  </div>
@@ -1,14 +1,19 @@
1
1
  import Fuse from 'fuse.js';
2
2
 
3
- export default function runFuse(query, data, searchFields) {
3
+ export default function runFuse(query, data, searchFields, threshold, distance) {
4
4
  const options = {
5
5
  shouldSort: true,
6
- threshold: 0.2,
6
+ threshold: threshold,
7
+ distance: distance,
7
8
  keys: [
8
9
  {
9
10
  name: searchFields,
10
11
  weight: 0.9,
11
12
  },
13
+ {
14
+ name: 'formattedAddress',
15
+ weight: 0.9,
16
+ },
12
17
  {
13
18
  name: 'tags',
14
19
  weight: 0.1,
@@ -98,6 +98,26 @@
98
98
  "radios": params.other.radios
99
99
  })
100
100
  }}
101
+ {% elif otherType == "textarea" %}
102
+ {% from "components/textarea/_macro.njk" import onsTextarea %}
103
+ {{
104
+ onsTextarea({
105
+ "id": params.other.id,
106
+ "name": params.other.name,
107
+ "value": params.other.value,
108
+ "label": {
109
+ "id": params.other.id + "-label",
110
+ "text": params.other.label.text,
111
+ "description": params.other.label.description,
112
+ "classes": 'ons-u-fw-n'
113
+ },
114
+ "charCheckLimit": {
115
+ "limit": params.other.charCheckLimit.limit,
116
+ "charCountSingular": params.other.charCheckLimit.charCountSingular,
117
+ "charCountPlural": params.other.charCheckLimit.charCountPlural
118
+ }
119
+ })
120
+ }}
101
121
  {% endif %}
102
122
  </span>
103
123
  {% endif %}
@@ -90,6 +90,11 @@
90
90
  "label": {
91
91
  "text": checkbox.other.label.text
92
92
  },
93
+ "charCheckLimit": {
94
+ "limit": checkbox.other.charCheckLimit.limit,
95
+ "charCountSingular": checkbox.other.charCheckLimit.charCountSingular,
96
+ "charCountPlural": checkbox.other.charCheckLimit.charCountPlural
97
+ },
93
98
  "legend": checkbox.other.legend,
94
99
  "legendClasses": checkbox.other.legendClasses,
95
100
  "value": checkbox.other.value,
@@ -87,6 +87,31 @@ const EXAMPLE_CHECKBOXES_WITH_MUTUALLY_EXCLUSIVE_WITH_ERROR = {
87
87
  },
88
88
  };
89
89
 
90
+ const EXAMPLE_CHECKBOX_ITEM_CHECKBOXES_WITH_TEXTAREA = {
91
+ name: 'example-checkboxes-name',
92
+ legend: 'Legend text',
93
+ checkboxesLabel: 'Select all that apply',
94
+ checkboxesLabelClasses: 'extra-checkboxes-label-class',
95
+ checkboxes: [
96
+ EXAMPLE_CHECKBOX_ITEM,
97
+ {
98
+ other: {
99
+ otherType: 'textarea',
100
+ id: 'other-textbox-example-checkbox-with-revealed-text-area',
101
+ name: 'other answer',
102
+ label: {
103
+ text: 'Provide more details',
104
+ },
105
+ charCheckLimit: {
106
+ limit: 300,
107
+ charCountSingular: 'You have {x} character remaining',
108
+ charCountPlural: 'You have {x} characters remaining',
109
+ },
110
+ },
111
+ },
112
+ ],
113
+ };
114
+
90
115
  describe('macro: checkboxes', () => {
91
116
  it('passes jest-axe checks', async () => {
92
117
  const $ = cheerio.load(renderComponent('checkboxes', EXAMPLE_CHECKBOXES));
@@ -135,6 +160,16 @@ describe('macro: checkboxes', () => {
135
160
  });
136
161
  });
137
162
 
163
+ describe('checkbox item with text area', () => {
164
+ it('renders the text area with expected parameters', () => {
165
+ const $ = cheerio.load(renderComponent('checkboxes', EXAMPLE_CHECKBOX_ITEM_CHECKBOXES_WITH_TEXTAREA));
166
+ expect($('.ons-input--textarea').attr('name')).toBe('other answer');
167
+ expect($('.ons-input--textarea').attr('maxlength')).toBe('300');
168
+ expect($('.ons-input__limit').attr('data-charcount-singular')).toBe('You have {x} character remaining');
169
+ expect($('.ons-input__limit').attr('data-charcount-plural')).toBe('You have {x} characters remaining');
170
+ });
171
+ });
172
+
138
173
  describe('mutually exclusive', () => {
139
174
  it('has the `ons-js-exclusive-group-item` class', () => {
140
175
  const $ = cheerio.load(renderComponent('checkboxes', EXAMPLE_CHECKBOXES_WITH_MUTUALLY_EXCLUSIVE_WITH_ERROR));
@@ -0,0 +1,68 @@
1
+ {% from "components/question/_macro.njk" import onsQuestion %}
2
+ {% from "components/checkboxes/_macro.njk" import onsCheckboxes %}
3
+
4
+ {%
5
+ call onsQuestion({
6
+ "title": "Do you have any dietary requirements?",
7
+ "legendIsQuestionTitle": true,
8
+ "classes": "ons-u-mt-no"
9
+ })
10
+ %}
11
+ {{
12
+ onsCheckboxes({
13
+ "checkboxesLabel": "Select all that apply",
14
+ "dontWrap": true,
15
+ "checkboxes": [
16
+ {
17
+ "id": "gluten-free-example-checkbox-with-revealed-text-area",
18
+ "label": {
19
+ "text": "Gluten free"
20
+ },
21
+ "value": "gluten-free"
22
+ },
23
+ {
24
+ "id": "lactose-intolerant-example-checkbox-with-revealed-text-area",
25
+ "label": {
26
+ "text": "Lactose intolerant"
27
+ },
28
+ "value": "lactose-intolerant"
29
+ },
30
+ {
31
+ "id": "vegan-example-checkbox-with-revealed-text-area",
32
+ "label": {
33
+ "text": "Vegan"
34
+ },
35
+ "value": "vegan"
36
+ },
37
+ {
38
+ "id": "vegetarian-example-checkbox-with-revealed-text-area",
39
+ "label": {
40
+ "text": "Vegetarian"
41
+ },
42
+ "value": "vegetarian"
43
+ },
44
+ {
45
+ "id": "other-checkbox-with-revealed-text-area",
46
+ "label": {
47
+ "text": "Other"
48
+ },
49
+ "value": "other",
50
+ "checked": true,
51
+ "other": {
52
+ "otherType": "textarea",
53
+ "id": "other-textbox-example-checkbox-with-revealed-text-area",
54
+ "name": "other-answer",
55
+ "label": {
56
+ "text": "Provide more details"
57
+ },
58
+ "charCheckLimit": {
59
+ "limit": 200,
60
+ "charCountSingular": "You have {x} character remaining",
61
+ "charCountPlural": "You have {x} characters remaining"
62
+ }
63
+ }
64
+ }
65
+ ]
66
+ })
67
+ }}
68
+ {% endcall %}
@@ -0,0 +1,67 @@
1
+ {% from "components/question/_macro.njk" import onsQuestion %}
2
+ {% from "components/checkboxes/_macro.njk" import onsCheckboxes %}
3
+
4
+ {%
5
+ call onsQuestion({
6
+ "title": "Do you have any dietary requirements?",
7
+ "legendIsQuestionTitle": true,
8
+ "classes": "ons-u-mt-no"
9
+ })
10
+ %}
11
+ {{
12
+ onsCheckboxes({
13
+ "checkboxesLabel": "Select all that apply",
14
+ "dontWrap": true,
15
+ "checkboxes": [
16
+ {
17
+ "id": "gluten-free-example-checkbox-with-revealed-text-area",
18
+ "label": {
19
+ "text": "Gluten free"
20
+ },
21
+ "value": "gluten-free"
22
+ },
23
+ {
24
+ "id": "lactose-intolerant-example-checkbox-with-revealed-text-area",
25
+ "label": {
26
+ "text": "Lactose intolerant"
27
+ },
28
+ "value": "lactose-intolerant"
29
+ },
30
+ {
31
+ "id": "vegan-example-checkbox-with-revealed-text-area",
32
+ "label": {
33
+ "text": "Vegan"
34
+ },
35
+ "value": "vegan"
36
+ },
37
+ {
38
+ "id": "vegetarian-example-checkbox-with-revealed-text-area",
39
+ "label": {
40
+ "text": "Vegetarian"
41
+ },
42
+ "value": "vegetarian"
43
+ },
44
+ {
45
+ "id": "other-checkbox-with-revealed-text-area",
46
+ "label": {
47
+ "text": "Other"
48
+ },
49
+ "value": "other",
50
+ "other": {
51
+ "otherType": "textarea",
52
+ "id": "other-textbox-example-checkbox-with-revealed-text-area",
53
+ "name": "other-answer",
54
+ "label": {
55
+ "text": "Provide more details"
56
+ },
57
+ "charCheckLimit": {
58
+ "limit": 200,
59
+ "charCountSingular": "You have {x} character remaining",
60
+ "charCountPlural": "You have {x} characters remaining"
61
+ }
62
+ }
63
+ }
64
+ ]
65
+ })
66
+ }}
67
+ {% endcall %}
@@ -35,96 +35,91 @@
35
35
  {% if row.total %}{% set itemClass = itemClass + " ons-summary__item--total" %}{% endif %}
36
36
  <div {% if row.id %}id="{{ row.id }}"{% endif %}class="ons-summary__item{{ itemClass }}">
37
37
  {% if row.errorMessage %}
38
- <div class="ons-summary__row-title--error ons-u-fs-r">{{ row.errorMessage }}</div>
38
+ <dt class="ons-summary__row-title--error ons-u-fs-r">{{ row.errorMessage }}</dt>
39
39
  {% endif %}
40
40
  {% if row.itemsList | length > 1 and row.title %}
41
- <div class="ons-summary__row-title ons-summary__row-title--no-group-title ons-u-fs-r">
41
+ <dt class="ons-summary__row-title ons-summary__row-title--no-group-title ons-u-fs-r">
42
42
  {{- row.title -}}
43
- </div>
43
+ </dt>
44
44
  {% endif %}
45
45
 
46
46
  {% for item in row.itemsList %}
47
- <div
48
- class="ons-summary__row{{ ' ons-summary__row--has-values' if item.valueList else "" }}"
49
- {% if item.id %}id="{{ item.id }}"{% endif %}
47
+ <dt
48
+ class="ons-summary__item-title"
49
+ {% if item.titleAttributes %}{% for attribute, value in (item.titleAttributes.items() if item.titleAttributes is mapping and item.titleAttributes.items else item.titleAttributes) %}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
50
50
  >
51
- <dt
52
- class="ons-summary__item-title"
53
- {% if item.titleAttributes %}{% for attribute, value in (item.titleAttributes.items() if item.titleAttributes is mapping and item.titleAttributes.items else item.titleAttributes) %}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
54
- >
55
- {% if item.iconType %}
56
- {% from "components/icon/_macro.njk" import onsIcon %}
57
- <span
58
- class="ons-summary__item-title-icon{{ ' ons-summary__item-title-icon--check' if item.iconType == 'check' else "" }}"
59
- >
60
- {{-
61
- onsIcon({
62
- "iconType": item.iconType
63
- })
64
- -}}
65
- {% if item.iconVisuallyHiddenText %}
66
- <span class="ons-u-vh">{{ item.iconVisuallyHiddenText }}</span>
67
- {% endif %}
68
- </span>
69
- {% endif %}
70
-
71
- <div
72
- class="ons-summary__item--text{{ ' ons-summary__item-title--text' if item.iconType else "" }}"
51
+ {% if item.iconType %}
52
+ {% from "components/icon/_macro.njk" import onsIcon %}
53
+ <span
54
+ class="ons-summary__item-title-icon{{ ' ons-summary__item-title-icon--check' if item.iconType == 'check' else "" }}"
73
55
  >
74
- {{- item.title | default(row.title) | safe -}}
75
- </div>
56
+ {{-
57
+ onsIcon({
58
+ "iconType": item.iconType
59
+ })
60
+ -}}
61
+ {% if item.iconVisuallyHiddenText %}
62
+ <span class="ons-u-vh">{{ item.iconVisuallyHiddenText }}</span>
63
+ {% endif %}
64
+ </span>
65
+ {% endif %}
76
66
 
77
- {# Render section status for mobile if is hub #}
78
- {% if variantHub and item.valueList %}
79
- <span class="ons-u-d-no@m ons-u-fs-r"> — {{ item.valueList[0].text | safe }}</span>
80
- {% endif %}
81
- </dt>
82
- {% if item.valueList %}
83
- <dd
84
- class="ons-summary__values{{ ' ons-summary__values--2' if not item.actions }}"
85
- {% if item.attributes %}{% for attribute, value in (item.attributes.items() if item.attributes is mapping and item.attributes.items else item.attributes) %}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
86
- >
87
- {% if item.valueList | length == 1 %}
88
- <span class="ons-summary__text">{{ item.valueList[0].text | safe }}</span>
89
- {% if item.valueList[0].other or item.valueList[0].other == 0 %}
90
- <ul class="ons-u-mb-no">
91
- <li>{{ item.valueList[0].other | safe }}</li>
92
- </ul>
93
- {% endif %}
94
- {% else %}
67
+ <div
68
+ class="ons-summary__item--text{{ ' ons-summary__item-title--text' if item.iconType else "" }}"
69
+ >
70
+ {{- item.title | default(row.title) | safe -}}
71
+ </div>
72
+
73
+ {# Render section status for mobile if is hub #}
74
+ {% if variantHub and item.valueList %}
75
+ <span class="ons-u-d-no@m ons-u-fs-r"> {{ item.valueList[0].text | safe }}</span>
76
+ {% endif %}
77
+ </dt>
78
+ {% if item.valueList %}
79
+ <dd
80
+ class="ons-summary__values{{ ' ons-summary__values--2' if not item.actions }}"
81
+ {% if item.attributes %}{% for attribute, value in (item.attributes.items() if item.attributes is mapping and item.attributes.items else item.attributes) %}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
82
+ >
83
+ {% if item.valueList | length == 1 %}
84
+ <span class="ons-summary__text">{{ item.valueList[0].text | safe }}</span>
85
+ {% if item.valueList[0].other or item.valueList[0].other == 0 %}
95
86
  <ul class="ons-u-mb-no">
96
- {% for value in item.valueList %}
97
- <li>
98
- <span class="ons-summary__text">{{ value.text | safe }}</span>
99
- {% if value.other or value.other == 0 %}
100
- <ul class="ons-u-mb-no">
101
- <li>{{ value.other | safe }}</li>
102
- </ul>
103
- {% endif %}
104
- </li>
105
- {% endfor %}
87
+ <li>{{ item.valueList[0].other | safe }}</li>
106
88
  </ul>
107
89
  {% endif %}
108
- </dd>
109
- {% endif %}
110
- {% if item.actions %}
111
- <dd class="ons-summary__actions">
112
- {% for action in item.actions %}
113
- {% if loop.index > 1 %}<span class="ons-summary__spacer"></span>{% endif %}
114
- <a
115
- href="{{ action.url }}"
116
- class="ons-summary__button"
117
- {% if action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{ ' ' }}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
90
+ {% else %}
91
+ <ul class="ons-u-mb-no">
92
+ {% for value in item.valueList %}
93
+ <li>
94
+ <span class="ons-summary__text">{{ value.text | safe }}</span>
95
+ {% if value.other or value.other == 0 %}
96
+ <ul class="ons-u-mb-no">
97
+ <li>{{ value.other | safe }}</li>
98
+ </ul>
99
+ {% endif %}
100
+ </li>
101
+ {% endfor %}
102
+ </ul>
103
+ {% endif %}
104
+ </dd>
105
+ {% endif %}
106
+ {% if item.actions %}
107
+ <dd class="ons-summary__actions">
108
+ {% for action in item.actions %}
109
+ {% if loop.index > 1 %}<span class="ons-summary__spacer"></span>{% endif %}
110
+ <a
111
+ href="{{ action.url }}"
112
+ class="ons-summary__button"
113
+ {% if action.attributes %}{% for attribute, value in (action.attributes.items() if action.attributes is mapping and action.attributes.items else action.attributes) %}{{ ' ' }}{{ attribute }}="{{ value }}"{% endfor %}{% endif %}
114
+ >
115
+ <span class="ons-summary__button-text" aria-hidden="true">{{- action.text -}}</span>
116
+ <span class="ons-u-vh"
117
+ >{{ action.visuallyHiddenText | default (action.text) }}</span
118
118
  >
119
- <span class="ons-summary__button-text" aria-hidden="true">
120
- {{- action.text -}}
121
- </span>
122
- <span class="ons-u-vh">{{ action.visuallyHiddenText }}</span>
123
- </a>
124
- {% endfor %}
125
- </dd>
126
- {% endif %}
127
- </div>
119
+ </a>
120
+ {% endfor %}
121
+ </dd>
122
+ {% endif %}
128
123
  {% endfor %}
129
124
  </div>
130
125
  {% endfor %}
@@ -146,7 +141,7 @@
146
141
  </a>
147
142
  {% endset %}
148
143
  {% if params.variant == 'card' %}
149
- <div>{{ link | safe }}</div>
144
+ <div class="ons-summary__link-container">{{ link | safe }}</div>
150
145
  {% else %}
151
146
  {{ link | safe }}
152
147
  {% endif %}