@madgex/design-system 10.1.2 → 11.0.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.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@madgex/design-system",
3
3
  "author": "Madgex",
4
4
  "license": "UNLICENSED",
5
- "version": "10.1.2",
5
+ "version": "11.0.0",
6
6
  "main": "dist/js/index.js",
7
7
  "exports": {
8
8
  ".": "./dist/js/index.js",
@@ -25,6 +25,7 @@
25
25
 
26
26
  {%- if params.contentFirst -%}
27
27
  <button
28
+ type="button"
28
29
  class="mds-accordion__label mds-button mds-button--plain mds-padding-x-b0 {{ params.labelClasses }}"
29
30
  aria-expanded="true"
30
31
  >
@@ -5,14 +5,9 @@ Use the [callable](https://mozilla.github.io/nunjucks/templating.html#call) synt
5
5
 
6
6
  ## Parameters
7
7
 
8
- - `value`: Value attribute on the button or input
9
- - `name`: add `name` attribute
10
- - `element`: we're using `<button>` by default but you can change to be a link or an input
11
- - `href`: if `element` is a link then add the url using `href`
8
+ - `href`: this sets the href and changes the button to an anchor element
12
9
  - `classes`: css classes to add on the button (for example `mds-width-full`)
13
- - `disabled`: disable button
14
10
  - `attributes`: you can add extra attributes by passing an object to the parameter. Example: `attributes: { attribute-name: 'attribute-value' }`
15
- - `type`: by default it will be `submit`
16
11
 
17
12
  ## Full width button
18
13
 
@@ -1,40 +1,11 @@
1
- {# Determine type of element to use, if not explicitly set -#}
1
+ {% from "../../sub-components/attributes/macro.njk" import MdsAttributes %}
2
2
 
3
- {%- if params.element -%}
4
- {% set element = params.element | lower %}
5
- {%- else -%}
6
- {% if params.href %}
7
- {% set element = 'a' %}
8
- {% else %}
9
- {% set element = 'button' %}
10
- {% endif %}
11
- {%- endif -%}
12
-
13
- {#- Define common attributes that we can use across all element types #}
14
-
15
- {%- set commonAttributes %} class="mds-button
16
- {%- if params.classes %} {{ params.classes }}{% endif -%}
17
- {%- if params.disabled %} mds-button--disabled{% endif %}"
18
- {%- for attribute, value in params.attributes %} {{attribute}}="{{value}}"{% endfor %} data-test="button{% if params.id %}-{{params.id}}{% endif %}"
19
- {%- endset -%}
20
-
21
- {#- Define common attributes we can use for both button and input types #}
22
-
23
- {%- set buttonAttributes %}
24
- {% if params.name %} name="{{ params.name }}"{% endif %} type="{{ params.type if params.type else 'submit' }}"{% if params.disabled %} disabled="disabled" aria-disabled="true"{% endif %}{% endset %}
25
-
26
- {#- Actually create a button... or a link! #}
27
-
28
- {%- if element == 'a' %}
29
- <a href="{{ params.href if params.href else '#' }}" draggable="false" {{- commonAttributes | safe }}>
30
- {{ caller() }}
3
+ {%- if params.href -%}
4
+ <a href="{{ params.href }}" class="mds-button {{ params.classes }}" {{- MdsAttributes(params.attributes) -}}>
5
+ {{- caller() -}}
31
6
  </a>
32
-
33
- {%- elseif element == 'button' %}
34
- <button {%- if params.value %} value="{{ params.value }}"{% endif %} {{- buttonAttributes | safe }} {{- commonAttributes | safe }}>
35
- {{ caller() }}
7
+ {%- else -%}
8
+ <button class="mds-button {{ params.classes }}" {{- MdsAttributes(params.attributes) -}}>
9
+ {{- caller() -}}
36
10
  </button>
37
-
38
- {%- elseif element == 'input' %}
39
- <input value="{{ params.value }}" {{- buttonAttributes | safe }} {{- commonAttributes | safe }}>
40
- {%- endif %}
11
+ {%- endif -%}
@@ -3,62 +3,43 @@ module.exports = {
3
3
  status: 'wip',
4
4
  context: {
5
5
  items: [
6
- { name: 'link-buttons', href: 'http://madgex.com', text: 'Link button 1', id: 'link-1' },
7
6
  {
8
- name: 'link-buttons',
9
7
  href: 'http://madgex.com',
10
- text: 'Link Plain button 2',
11
- id: 'link-2',
12
- classes: 'mds-button--plain',
8
+ text: 'Link button 1',
13
9
  },
14
10
  {
15
- name: 'input-buttons',
16
- element: 'input',
17
- value: 'Input button 3',
18
- id: 'link-3',
11
+ href: 'http://madgex.com',
12
+ text: 'Link Plain button 2',
13
+ classes: 'mds-button--plain',
19
14
  },
20
15
  {
21
- name: 'plain-buttons',
22
16
  text: 'Plain button',
23
17
  classes: 'mds-button--plain',
24
- id: 'plain',
25
18
  },
26
19
  {
27
- name: 'small-buttons',
28
20
  text: 'Small button',
29
21
  classes: 'mds-button--small',
30
- id: 'small',
31
22
  },
32
23
  {
33
- name: 'large-buttons',
34
24
  text: 'Large button',
35
25
  classes: 'mds-button--large',
36
- id: 'large',
37
26
  },
38
27
  {
39
- name: 'icon-buttons',
40
- useIcon: true,
41
- classes: 'mds-button--icon',
42
- id: 'icon',
43
- },
44
- {
45
- name: 'full-width-example',
46
28
  text: 'Full width example',
47
29
  classes: 'mds-width-full mds-width-md-auto',
48
- id: 'full',
49
30
  },
50
31
  {
51
- name: 'neutral',
52
32
  text: 'Neutral',
53
33
  classes: 'mds-button--neutral',
54
- id: 'neutral',
55
34
  },
56
35
  {
57
- name: 'prevent double submit',
58
36
  text: 'Prevent double submit',
59
- id: 'double-submit',
60
37
  classes: 'js-mds-button-double-submit',
61
38
  },
39
+ {
40
+ text: 'With attributes',
41
+ attributes: { attributed: 'yes', 'other-thing': 'also' },
42
+ },
62
43
  ],
63
44
  },
64
45
  };
@@ -1,41 +1,14 @@
1
1
 
2
2
  {% from "./button/_macro.njk" import MdsButton %}
3
- {% from "./icons/_macro.njk" import MdsIcon %}
4
3
 
5
4
  {% for item in items %}
6
-
7
- {% if item.useIcon %}
8
- {%- set html -%}
9
- {{ MdsIcon({
10
- iconName: 'search',
11
- classes: 'mds-icon--md',
12
- visuallyHiddenLabel: 'Search icon'
13
- }) }}
14
- {%- endset -%}
15
- {% call MdsButton({
16
- element: item.element,
17
- id: item.id,
18
- value: item.value,
19
- href: item.href,
20
- classes: item.classes,
21
- attributes: item.attributes
22
- }) -%}
23
- <!-- example - in normal use `safe` is discouraged as it is dangerous, and not needed -->
24
- {{ html | safe }}
25
- {%- endcall %}
26
- {% else %}
27
5
  {% call MdsButton({
28
- element: item.element,
29
- id: item.id,
30
- value: item.value,
31
6
  href: item.href,
32
7
  classes: item.classes,
33
8
  attributes: item.attributes
34
9
  }) -%}
35
10
  {{ item.text }}
36
11
  {%- endcall %}
37
- {% endif %}
38
-
39
12
  {% endfor %}
40
13
 
41
14
 
@@ -80,19 +80,19 @@
80
80
  <div class="mds-file-upload__selected-state">
81
81
  <div class="mds-file-upload__file-name-container">
82
82
  {{- MdsIcon({
83
- iconName: 'check',
84
- classes: 'mds-icon--md',
85
- hasContainer: true,
86
- containerClasses: 'mds-icon-container--circle mds-icon-container--success mds-icon-container--before'
87
- })
88
- -}}
83
+ iconName: 'check',
84
+ classes: 'mds-icon--md',
85
+ hasContainer: true,
86
+ containerClasses: 'mds-icon-container--circle mds-icon-container--success mds-icon-container--before'
87
+ })
88
+ -}}
89
89
  <span class="mds-visually-hidden">{{ params.i18n.selectedFileText | default('Selected file:') }} </span>
90
90
  <span class="mds-file-upload__file-name">{% if params.value %}{{ params.value }}{% endif %}</span>
91
91
  </div>
92
92
  {% call MdsButton({
93
- classes: 'mds-button--plain mds-button--small mds-file-upload__remove-button',
94
- type: 'button'
95
- }) -%}
93
+ classes: 'mds-button--plain mds-button--small mds-file-upload__remove-button',
94
+ attributes: { type: 'button' }
95
+ }) -%}
96
96
  {{- params.i18n.removeButtonText | default('Remove file') -}}
97
97
  {{-
98
98
  MdsIcon({
@@ -9,7 +9,7 @@
9
9
 
10
10
  {% call MdsButton({
11
11
  classes: 'mds-button--plain js-mds-modal-close mds-modal-default-close-button',
12
- type: 'button'
12
+ attributes: { type: 'button' }
13
13
  }) -%}
14
14
  {{ closeText }}
15
15
  {{ MdsIcon({
@@ -13,7 +13,7 @@ Donec dapibus consectetur fermentum. Proin vel lacus elit. Nunc eu massa magna.
13
13
  Nullam faucibus pulvinar felis. Sed et tortor enim. Nulla luctus maximus mi aliquam tempor. Vivamus dignissim condimentum augue sed commodo. Donec a elementum risus, id interdum sem. Morbi malesuada tempor dapibus. Nam varius augue augue, vel pellentesque felis venenatis nec. Vivamus eget vulputate risus. Curabitur mollis, neque id tempus laoreet, nibh lectus aliquam felis, euismod varius mi turpis a sapien. Etiam ut mi a nisi faucibus egestas at eget ante.</p>
14
14
  <p>{% call MdsButton({
15
15
  classes: 'mds-button--neutral js-mds-modal-close',
16
- type: 'button'
16
+ attributes: { type: 'button' }
17
17
  }) -%}
18
18
  Close
19
19
  {%- endcall %}
@@ -5,7 +5,7 @@
5
5
  <p id="modal-description">I'm a modal window with <a href="#">a link</a>.</p>
6
6
  <p>{% call MdsButton({
7
7
  classes: 'mds-button--neutral js-mds-modal-close',
8
- type: 'button'
8
+ attributes: { type: 'button' }
9
9
  }) -%}
10
10
  Close
11
11
  {%- endcall %}
@@ -5,6 +5,5 @@
5
5
  headingTag: headingTag,
6
6
  actionText: actionText,
7
7
  actionHref: actionHref,
8
- actionElement: actionElement,
9
8
  classes: classes
10
9
  }) }}
@@ -6,7 +6,6 @@
6
6
  <div class="mds-section-title__action">
7
7
  {%- if params.actionHref -%}
8
8
  {% call MdsButton({
9
- element: params.actionElement,
10
9
  href: params.actionHref,
11
10
  classes: params.classes
12
11
  }) -%}
@@ -4,7 +4,9 @@
4
4
  - `classes`: add extra CSS classes to the component
5
5
  - `allHeadersTag`: the html tag to use for the panel header (h2 as default)
6
6
  - `allHeadersDisplay`: wheter the panel header should be always visible or not (default false)
7
- - `content`: is an array of objects containing [label, selected, id, content, headerText, linkCustomAttr] for each tab, the content for the panel can also be a custom component, headerText is text used for each panel header
7
+ - `content`: is an array of objects containing [label, selected, id, content, headerText, linkCustomAttr] for each tab, the content for the panel can also be a custom component, headerText is
8
+ text used for each panel header
9
+ - `content[{linkCustomAttr}]`: you can add extra attributes by passing an object to the parameter. Example: `attributes: { attribute-name: 'attribute-value' }`
8
10
 
9
11
  ## Variations
10
12
  Tabs have different style depending on the amount of items to display, if 2 tabs then it will always display tabs (except when js is disabled), if more than 2 then it will display a list of links for small devices and tabs for desktop
@@ -1,4 +1,5 @@
1
1
  {% from "./tab-id.njk" import TabId %}
2
+ {% from "../../sub-components/attributes/macro.njk" import MdsAttributes %}
2
3
 
3
4
  {% if params.content %}
4
5
  {% set kebabName -%}
@@ -11,12 +12,12 @@
11
12
  mds-tabs--full-tabbed js-full-tabbed
12
13
  {%- endif -%}
13
14
  {%- endset %}
14
- <div class="mds-tabs {{ tabVariation }}{%- if params.name %} mds-tabs--{{ kebabName }}{%- endif -%}{% if params.classes %} {{ params.classes }}{% endif %}" data-test="tabs-{{kebabName}}">
15
+ <div class="mds-tabs {{ tabVariation }}{%- if params.name %} mds-tabs--{{ kebabName }}{%- endif -%}{% if params.classes %} {{ params.classes }}{% endif %}">
15
16
  <ul class="mds-tabs__list">
16
17
  {%- for item in params.content -%}
17
18
  {%- set tabId = TabId(item, params, loop.index) -%}
18
19
  <li class="mds-tabs__list-item">
19
- <a href="#{{ tabId }}" id="label-{{tabId}}" class="mds-tabs__tab{%- if item.selected %} mds-tabs__tab--selected{%- endif %} js-tabs-item" data-test="tabs-trigger{% if tabId %}-{{tabId}}{% endif %}" {% if item.linkCustomAttr %} {{item.linkCustomAttr | safe}}{% endif %}>
20
+ <a href="#{{ tabId }}" id="label-{{ tabId }}" class="mds-tabs__tab{%- if item.selected %} mds-tabs__tab--selected{%- endif %} js-tabs-item" {{ MdsAttributes(item.linkCustomAttr) }}>
20
21
  {{- item.label -}}
21
22
  </a>
22
23
  </li>
@@ -42,7 +43,7 @@
42
43
  {%- endif -%}
43
44
  {%- endset -%}
44
45
 
45
- <section class="mds-tabs__panel{%- if not item.selected %} mds-tabs__panel--hidden {%- endif -%}{% if item.contentClasses %} {{ item.contentClasses }}{% endif %}" id="{{ tabId }}" data-test="tab-panel{% if tabId %}-{{tabId}}{% endif %}">
46
+ <section class="mds-tabs__panel{%- if not item.selected %} mds-tabs__panel--hidden {%- endif -%}{% if item.contentClasses %} {{ item.contentClasses }}{% endif %}" id="{{ tabId }}">
46
47
  {# id is used in js to apply aria-labelledby, don't forget to update both if needed #}
47
48
  <{{allHeadersTag}} class="mds-tabs__panel-header{{allHeadersDisplay}}">{{- headerText | safe -}}</{{allHeadersTag}}>
48
49
  <div class="mds-tabs__panel__content">
@@ -117,14 +117,14 @@ module.exports = {
117
117
  label: 'Plane',
118
118
  selected: true,
119
119
  headerText: 'Flying craft',
120
- linkCustomAttr: 'data-metric="wings"',
120
+ linkCustomAttr: { 'data-metric': 'wings' },
121
121
  content:
122
122
  '<p>Inspect the anchor tags inside each tab to see the custom attributes that are added. One use case of this is allowing us to add click metrics.</p>',
123
123
  },
124
124
  {
125
125
  label: 'Helicopter',
126
126
  headerText: 'Flying craft',
127
- linkCustomAttr: 'data-metric="rotor-blades"',
127
+ linkCustomAttr: { 'data-metric': 'rotor-blades' },
128
128
  content:
129
129
  '<p>Inspect the anchor tags inside each tab to see the custom attributes that are added. One use case of this is allowing us to add click metrics.</p>',
130
130
  },
@@ -6,7 +6,6 @@
6
6
  <h3>Get job alerts</h3>
7
7
  <p>Create a job alert and receive personalised <a href="/some-link">job recommendations</a> straight to your inbox</p>
8
8
  {% call MdsButton({
9
- element: 'a',
10
9
  href: '/somewhere'
11
10
  }) -%}
12
11
  Create alert
@@ -0,0 +1,94 @@
1
+ {#
2
+ Renders component attributes as string
3
+
4
+ * By default or using `optional: false`, attributes render as ` name="value"`
5
+ * Using `optional: true`, attributes with empty (`null`, `undefined` or `false`) values are omitted
6
+ * Using `optional: true`, attributes with `true` (boolean) values render `name` only without value
7
+
8
+ {@link https://developer.mozilla.org/en-US/docs/Glossary/Boolean/HTML}
9
+
10
+ @example
11
+ Output attribute ` aria-hidden="true"` when `true` (boolean) or `"true"` (string)
12
+
13
+ ```njk
14
+ MdsAttributes({
15
+ "aria-hidden": true
16
+ })
17
+ ```
18
+
19
+ @example
20
+ Output attribute ` aria-hidden="false"` when `false` (boolean) or `"false"` (string)
21
+
22
+ ```njk
23
+ MdsAttributes({
24
+ "aria-hidden": false
25
+ })
26
+ ```
27
+
28
+ @example
29
+ Output attribute ` hidden=""` when `null`, `undefined` or empty `""` (string)
30
+
31
+ ```njk
32
+ MdsAttributes({
33
+ "hidden": undefined
34
+ })
35
+ ```
36
+
37
+ @example
38
+ Output attribute ` hidden` as boolean attribute when optional and `true`
39
+
40
+ ```njk
41
+ MdsAttributes({
42
+ hidden: {
43
+ value: true,
44
+ optional: true
45
+ },
46
+ })
47
+ ```
48
+
49
+ @example
50
+ Output empty string when optional and `null`, `undefined` or `false`
51
+
52
+ ```njk
53
+ MdsAttributes({
54
+ hidden: {
55
+ value: undefined,
56
+ optional: true
57
+ },
58
+ })
59
+ ```
60
+
61
+ @private
62
+ @param {{ [attribute: string]: string | { value: string, optional?: boolean } } | string} attributes - Component attributes param
63
+ #}
64
+ {% macro MdsAttributes(attributes) -%}
65
+ {#- Default attributes output -#}
66
+ {% set attributesHtml = attributes if attributes is string else "" %}
67
+
68
+ {#- Append attribute name/value pairs -#}
69
+ {%- if attributes is mapping %}
70
+ {% for name, value in attributes %}
71
+ {#- Detect if this is a `safe` filtered value. Just pass the value through if so. -#}
72
+ {#- https://github.com/alphagov/govuk-frontend/issues/4937 -#}
73
+ {% if value is mapping and not [undefined, null].includes(value.val) and value.length %}
74
+ {% set value = value.val %}
75
+ {% endif %}
76
+
77
+ {#- Set default attribute options -#}
78
+ {% set options = value if value is mapping else {
79
+ value: value,
80
+ optional: false
81
+ } %}
82
+
83
+ {#- Output ` name` only (no value) for boolean attributes -#}
84
+ {% if options.optional === true and options.value === true %}
85
+ {% set attributesHtml = attributesHtml + " " + name | escape %}
86
+ {#- Skip optional empty attributes or output ` name="value"` pair by default -#}
87
+ {% elif (options.optional === true and not [undefined, null, false].includes(options.value)) or options.optional !== true %}
88
+ {% set attributesHtml = attributesHtml + " " + name | escape + '="' + options.value | escape + '"' %}
89
+ {% endif %}
90
+ {% endfor %}
91
+ {% endif -%}
92
+
93
+ {{- attributesHtml | safe -}}
94
+ {%- endmacro %}