@qld-gov-au/qgds-bootstrap5 2.1.0 → 2.1.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 (94) hide show
  1. package/.storybook/preview.js +15 -6
  2. package/dist/assets/components/bs5/button/button.hbs +2 -1
  3. package/dist/assets/components/bs5/callToAction/callToAction.hbs +3 -3
  4. package/dist/assets/components/bs5/dateinput/dateinput.hbs +21 -27
  5. package/dist/assets/components/bs5/formcheck/formcheck.hbs +1 -1
  6. package/dist/assets/components/bs5/globalAlert/globalAlert.hbs +8 -1
  7. package/dist/assets/components/bs5/head/head.hbs +1 -1
  8. package/dist/assets/components/bs5/pagination/pagination.hbs +7 -2
  9. package/dist/assets/components/bs5/promotionalPanel/promotionalPanel.hbs +1 -1
  10. package/dist/assets/components/bs5/searchInput/searchInput.hbs +2 -2
  11. package/dist/assets/components/bs5/select/select.hbs +1 -1
  12. package/dist/assets/components/bs5/textarea/textarea.hbs +1 -1
  13. package/dist/assets/components/bs5/textbox/textbox.hbs +1 -1
  14. package/dist/assets/css/qld.bootstrap.css +2 -2
  15. package/dist/assets/css/qld.bootstrap.css.map +3 -3
  16. package/dist/assets/css/qld.bootstrap.legacy.css +2 -2
  17. package/dist/assets/css/qld.bootstrap.legacy.css.map +3 -3
  18. package/dist/assets/js/handlebars.helpers.bundle.js +1 -1
  19. package/dist/assets/js/handlebars.init.min.js +56 -49
  20. package/dist/assets/js/handlebars.init.min.js.map +2 -2
  21. package/dist/assets/js/handlebars.partials.js +56 -49
  22. package/dist/assets/js/handlebars.partials.js.map +2 -2
  23. package/dist/assets/js/qld.bootstrap.min.js +6 -6
  24. package/dist/assets/js/qld.bootstrap.min.js.map +4 -4
  25. package/dist/assets/node/handlebars.init.min.js +21 -13
  26. package/dist/assets/node/handlebars.init.min.js.map +2 -2
  27. package/dist/components/bs5/button/button.hbs +2 -1
  28. package/dist/components/bs5/callToAction/callToAction.hbs +3 -3
  29. package/dist/components/bs5/dateinput/dateinput.hbs +21 -27
  30. package/dist/components/bs5/formcheck/formcheck.hbs +1 -1
  31. package/dist/components/bs5/globalAlert/globalAlert.hbs +8 -1
  32. package/dist/components/bs5/head/head.hbs +1 -1
  33. package/dist/components/bs5/pagination/pagination.hbs +7 -2
  34. package/dist/components/bs5/promotionalPanel/promotionalPanel.hbs +1 -1
  35. package/dist/components/bs5/searchInput/searchInput.hbs +2 -2
  36. package/dist/components/bs5/select/select.hbs +1 -1
  37. package/dist/components/bs5/textarea/textarea.hbs +1 -1
  38. package/dist/components/bs5/textbox/textbox.hbs +1 -1
  39. package/dist/package.json +33 -32
  40. package/dist/sample-data/callToAction/callToAction.data.json +2 -1
  41. package/dist/sample-data/dateinput/dateinput.data.json +3 -1
  42. package/dist/sample-data/pagination/pagination.data.json +4 -4
  43. package/dist/sample-data/promotionalPanel/promotionalPanel.data.json +45 -47
  44. package/package.json +33 -32
  45. package/src/components/bs5/breadcrumbs/breadcrumbs.scss +1 -0
  46. package/src/components/bs5/button/button.hbs +2 -1
  47. package/src/components/bs5/button/button.scss +1 -0
  48. package/src/components/bs5/button/button.stories.js +16 -4
  49. package/src/components/bs5/callToAction/callToAction.data.json +2 -1
  50. package/src/components/bs5/callToAction/callToAction.hbs +3 -3
  51. package/src/components/bs5/callToAction/callToAction.stories.js +2 -2
  52. package/src/components/bs5/card/card.scss +2 -2
  53. package/src/components/bs5/dateinput/Dateinput.js +1 -38
  54. package/src/components/bs5/dateinput/Dateinput.mdx +27 -0
  55. package/src/components/bs5/dateinput/Dateinput.stories.js +48 -4
  56. package/src/components/bs5/dateinput/dateinput.data.json +3 -1
  57. package/src/components/bs5/dateinput/dateinput.functions.js +91 -0
  58. package/src/components/bs5/dateinput/dateinput.hbs +21 -27
  59. package/src/components/bs5/formcheck/formcheck.hbs +1 -1
  60. package/src/components/bs5/formcheck/formcheck.scss +5 -0
  61. package/src/components/bs5/globalAlert/globalAlert.hbs +8 -1
  62. package/src/components/bs5/globalAlert/globalAlert.scss +14 -19
  63. package/src/components/bs5/globalAlert/globalAlert.stories.js +1 -0
  64. package/src/components/bs5/globalAlert/globalAlert.test.js +10 -5
  65. package/src/components/bs5/inpageAlert/inpageAlert.scss +3 -4
  66. package/src/components/bs5/inpagenav/inpagenav.scss +9 -1
  67. package/src/components/bs5/modal/modal.scss +1 -1
  68. package/src/components/bs5/navbar/navbar.functions.js +39 -28
  69. package/src/components/bs5/navbar/navbar.scss +43 -28
  70. package/src/components/bs5/navbar/navbar.stories.js +4 -3
  71. package/src/components/bs5/pageLayout/pageLayout.stories.js +2 -0
  72. package/src/components/bs5/pagination/pagination.data.json +4 -4
  73. package/src/components/bs5/pagination/pagination.hbs +7 -2
  74. package/src/components/bs5/pagination/pagination.scss +1 -1
  75. package/src/components/bs5/promotionalPanel/promotionalPanel.data.json +45 -47
  76. package/src/components/bs5/promotionalPanel/promotionalPanel.hbs +1 -1
  77. package/src/components/bs5/quickexit/quickexit.scss +1 -1
  78. package/src/components/bs5/searchInput/__snapshots__/searchInput.test.js.snap +2 -2
  79. package/src/components/bs5/searchInput/search.functions.js +9 -5
  80. package/src/components/bs5/searchInput/searchInput.hbs +2 -2
  81. package/src/components/bs5/searchInput/searchInput.scss +1 -0
  82. package/src/components/bs5/select/select.hbs +1 -1
  83. package/src/components/bs5/sidenav/sidenav.scss +17 -19
  84. package/src/components/bs5/table/table.scss +93 -83
  85. package/src/components/bs5/textarea/textarea.hbs +1 -1
  86. package/src/components/bs5/textbox/textbox.hbs +1 -1
  87. package/src/css/main.scss +3 -0
  88. package/src/css/mixins/focusable.scss +1 -1
  89. package/src/css/qld-reduced-motion.scss +51 -0
  90. package/src/css/qld-tokens.scss +3 -3
  91. package/src/css/qld-type.scss +7 -13
  92. package/src/js/constants.js +10 -0
  93. package/src/js/qld.bootstrap.js +99 -99
  94. package/src/js/utils.js +3 -1
@@ -48,7 +48,10 @@ function buttonVariantsMarkup() {
48
48
  return `<div class="d-grid p-32">
49
49
  <div class="fw-bold">${variantLabel}</div>
50
50
  <div class="d-flex gap-3">
51
+
52
+ <!-- Example buttons -->
51
53
  ${variantButtons}
54
+
52
55
  </div>
53
56
  </div>`;
54
57
  })
@@ -61,11 +64,20 @@ export default {
61
64
  args: defaultdata,
62
65
  render: (args) => {
63
66
  return `
67
+ <!-- Wrapper div for storybook only -->
64
68
  <div class="d-flex gap-3 p-32">
65
- ${new Button(args).html}
66
- ${new Button({ ...args, isdisabled: true }).html}
67
- ${new Button({ ...args, isprogress: true, iconClass: "", label: "Loading button", progressLabel: "Loading...", islink: false, dataatts: 'data-loading-btn="true"' }).html}
68
- </div>
69
+
70
+ <!-- Example link presented as QGDS button -->
71
+ ${new Button(args).html.trim()}
72
+
73
+ <!-- Example link presented as QGDS button -->
74
+ ${new Button({ ...args, isdisabled: true }).html.trim()}
75
+
76
+ <!-- Example button presented as QGDS button -->
77
+ ${new Button({ ...args, isprogress: true, iconClass: "", label: "Loading button", progressLabel: "Loading...", islink: false, dataatts: 'data-loading-btn="true"' }).html.trim()}
78
+
79
+
80
+ </div>
69
81
  `; //expand arguments, specifically turn isdisabled into true
70
82
  },
71
83
 
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "id": "",
3
3
  "label": "View all",
4
+ "arialabel": "View all services",
4
5
  "href": "#123",
5
6
  "target": "_blank",
6
7
  "class": [
7
- {"small": false},
8
+ {"small": false},
8
9
  {"view-all": true}
9
10
  ]
10
11
  }
@@ -1,8 +1,8 @@
1
1
  <a class="qld-cta-link {{getClassNames "small, view-all" class}}"
2
2
  {{#if id}}id="{{id}}"{{/if}}
3
- href="{{href}}"
4
- target="{{target}}"
5
- {{#if arialabel}}aria-label="{{arialabel}}"{{/if}}
3
+ href="{{href}}"
4
+ target="{{target}}"
5
+ {{#if arialabel}}aria-label="{{arialabel}}"{{/if}}
6
6
  >
7
7
  {{label}}
8
8
  <span class="icon" aria-hidden="true"></span>
@@ -19,7 +19,7 @@ export default {
19
19
  ${new CallToAction({ ...args }).html}
20
20
  </div>
21
21
  <div class="col">
22
- ${new CallToAction({ ...args, label: "Label", class: [{ small: false }, { "view-all": false }] }).html}
22
+ ${new CallToAction({ ...args, label: "Label", arialabel: "View more information", class: [{ small: false }, { "view-all": false }] }).html}
23
23
  </div>
24
24
  </div>
25
25
  </div>
@@ -134,7 +134,7 @@ export const Small = {
134
134
  ${new CallToAction({ ...args }).html}
135
135
  </div>
136
136
  <div class="col">
137
- ${new CallToAction({ ...args, label: "Label", class: [{ small: true }, { "view-all": false }] }).html}
137
+ ${new CallToAction({ ...args, label: "Label", arialabel: "View more information", class: [{ small: true }, { "view-all": false }] }).html}
138
138
  </div>
139
139
  </div>
140
140
  </div>
@@ -29,7 +29,7 @@
29
29
  --#{$prefix}card-group-margin: #{$card-group-margin};
30
30
  --#{$prefix}card-link-color: var(--#{$prefix}light-link);
31
31
  --#{$prefix}card-date-color: var(--#{$prefix}dark-grey-muted);
32
- --#{$prefix}card-footer-border: var(--#{$prefix}light-border);
32
+ --#{$prefix}card-footer-border: var(--#{$prefix}neutral-lighter);
33
33
  --#{$prefix}card-img-border-radius: 0px 0px 6.0882800609%/10.8108108108% 0px; // from QHDS website
34
34
  --#{$prefix}card-img-overlay-color: var(--#{$prefix}dark-background);
35
35
  --#{$prefix}link-hover-colour: var(--#{$prefix}light-action-primary-hover);
@@ -113,7 +113,7 @@
113
113
  }
114
114
  &-alt {
115
115
  --#{$prefix}card-bg: var(--#{$prefix}light-alt-background);
116
- --#{$prefix}card-footer-border: var(--#{$prefix}soft-grey);
116
+ --#{$prefix}card-footer-border: var(--#{$prefix}light-border-alt);
117
117
  --#{$prefix}card-icon-background-color: var(
118
118
  --#{$prefix}light-alt-background-shade
119
119
  );
@@ -6,44 +6,7 @@ export class Dateinput {
6
6
  // A data object, containing the Handlebars placeholder replacement strings, should be provided as an argument.
7
7
 
8
8
  constructor(data = {}) {
9
- var component = new Component(template, data);
10
- this.dateInputs();
11
- return component;
12
- }
13
-
14
- dateInputs() {
15
- let elements = document.querySelectorAll(
16
- ".dayinput, .monthinput, .yearinput",
17
- );
18
-
19
- Array.from(elements).forEach(function (element) {
20
- element.addEventListener("keyup", function () {
21
- const input = event.currentTarget;
22
- let max = 0;
23
- if (input.value) {
24
- if (input.classList.contains("dayinput")) {
25
- max = 31;
26
- } else if (input.classList.contains("monthinput")) {
27
- max = 12;
28
- }
29
- if (input.classList.contains("yearinput")) {
30
- max = 2030;
31
- }
32
- if (!parseInt(input.value)) {
33
- input.classList.add("qld-input-error");
34
- input.blur();
35
- } else {
36
- if (
37
- parseInt(input.value) > max &&
38
- !input.classList.contains("qld-input-error")
39
- ) {
40
- input.classList.add("qld-input-error");
41
- input.blur();
42
- }
43
- }
44
- }
45
- });
46
- });
9
+ return new Component(template, data);
47
10
  }
48
11
  }
49
12
 
@@ -0,0 +1,27 @@
1
+ import {
2
+ Canvas,
3
+ Controls,
4
+ Meta,
5
+ Story,
6
+ Stories,
7
+ Source,
8
+ } from "@storybook/addon-docs/blocks";
9
+ import * as dateinputStories from "./Dateinput.stories";
10
+
11
+ <Meta of={dateinputStories} />
12
+
13
+ # Date input
14
+
15
+ The Date input consists of 3 separate text inputs.
16
+
17
+ ## Behaviour
18
+
19
+ - Only numeric values may be typed into each these, and any out-of-range value will be converted into an in-range value.
20
+ - Additionally, on blur the value will be padded with leading zeroes if needed.
21
+ - If a min and/or max value is passed via `yearMin` and `yearMax`, these are also used to constrain the input value.
22
+
23
+ <Canvas of={dateinputStories.Default} />
24
+
25
+ <Controls />
26
+
27
+ <Stories />
@@ -1,6 +1,6 @@
1
- // ComponentExample.stories.js
2
1
  import { Dateinput } from "./Dateinput.js";
3
2
  import defaultdata from "./dateinput.data.json";
3
+ import { expect } from "storybook/test";
4
4
 
5
5
  export default {
6
6
  tags: ["autodocs"],
@@ -17,17 +17,18 @@ export default {
17
17
 
18
18
  return new Dateinput(args).html;
19
19
  },
20
-
21
- //https://storybook.js.org/docs/api/arg-types
22
20
  argTypes: {},
23
21
  globals: { backgrounds: { value: "default" } },
24
- parameters: { backgrounds: { disable: false } },
22
+ parameters: {
23
+ backgrounds: { disable: false },
24
+ },
25
25
  };
26
26
 
27
27
  /**
28
28
  * Default Date inputs
29
29
  */
30
30
  export const Default = {
31
+ tags: ["!autodocs"],
31
32
  args: defaultdata,
32
33
  globals: { backgrounds: { value: "default" } },
33
34
  };
@@ -91,3 +92,46 @@ export const Invalid = {
91
92
  ...{ customClass: "qld-input-error" },
92
93
  },
93
94
  };
95
+
96
+ export const InputValuesArePaddedWithLeadingZeroesOnBlur = {
97
+ tags: ["!autodocs"],
98
+ args: defaultdata,
99
+ play: async ({ canvas, userEvent }) => {
100
+ const dayInput = document.getElementById(`${defaultdata.id}-dayinput`);
101
+ const monthInput = document.getElementById(`${defaultdata.id}-monthinput`);
102
+ const yearInput = document.getElementById(`${defaultdata.id}-yearinput`);
103
+
104
+ await userEvent.type(dayInput, "4");
105
+ await userEvent.tab();
106
+ await userEvent.type(monthInput, "4");
107
+ await userEvent.tab();
108
+ await userEvent.type(yearInput, "42");
109
+ await userEvent.tab();
110
+
111
+ await expect(dayInput.value).toBe("04");
112
+ await expect(monthInput.value).toBe("04");
113
+ await expect(yearInput.value).toBe("0042");
114
+ },
115
+ };
116
+
117
+ export const OutOfRangeValuesAreCorrected = {
118
+ tags: ["!autodocs"],
119
+ args: {
120
+ ...defaultdata,
121
+ ...{ yearMin: "1000", yearMax: "2000" },
122
+ },
123
+ play: async ({ canvas, userEvent }) => {
124
+ const dayInput = document.getElementById(`${defaultdata.id}-dayinput`);
125
+ const monthInput = document.getElementById(`${defaultdata.id}-monthinput`);
126
+ const yearInput = document.getElementById(`${defaultdata.id}-yearinput`);
127
+
128
+ await userEvent.type(dayInput, "42");
129
+ await userEvent.type(monthInput, "42");
130
+ await userEvent.type(yearInput, "42");
131
+ await userEvent.tab();
132
+
133
+ await expect(dayInput.value).toBe("31");
134
+ await expect(monthInput.value).toBe("12");
135
+ await expect(yearInput.value).toBe("1000");
136
+ },
137
+ };
@@ -12,5 +12,7 @@
12
12
  "optional-text": "optional",
13
13
  "hint-text": "(dd/mm/yyyy)",
14
14
  "successMessageText": "Success message",
15
- "errorMessageText": "Error message"
15
+ "errorMessageText": "Error message",
16
+ "yearMin": "",
17
+ "yearMax": ""
16
18
  }
@@ -0,0 +1,91 @@
1
+ export function initDateInput() {
2
+ const dateContainers = document.querySelectorAll(".date-container");
3
+
4
+ /**
5
+ * @param {InputEvent} e
6
+ * @returns void
7
+ */
8
+ const inputHandler = (e) => {
9
+ // verify the event target is what we expect.
10
+ if (!(e.target.tagName === "INPUT" && e.target.type === "text")) {
11
+ return;
12
+ }
13
+
14
+ /**
15
+ * @type HTMLInputElement
16
+ */
17
+ const input = e.target;
18
+ const { value, min, max, pattern } = input;
19
+ const previousValue = input.dataset.previousValue || "";
20
+ // enforce the validation attributes
21
+ if (max && parseInt(value) > parseInt(max)) {
22
+ input.dataset.previousValue = input.value = max;
23
+ return;
24
+ }
25
+
26
+ if (
27
+ min &&
28
+ parseInt(value) !== 0 && // Must allow typing leading zeroes
29
+ value.length >= min.length &&
30
+ parseInt(value) < parseInt(min)
31
+ ) {
32
+ input.dataset.previousValue = input.value = min;
33
+ return;
34
+ }
35
+
36
+ if (
37
+ value &&
38
+ value !== "" &&
39
+ parseInt(value) !== 0 &&
40
+ !RegExp(pattern).test(value)
41
+ ) {
42
+ input.value = previousValue;
43
+ return;
44
+ }
45
+
46
+ // all good - update previousValue with current value
47
+ input.dataset.previousValue = input.value = input.value.trim();
48
+ };
49
+
50
+ /**
51
+ * @param {FocusEvent} e
52
+ * @returns void
53
+ */
54
+ const focusOutHandler = (e) => {
55
+ // Because format is dd/mm/yyyy we want to add leading zeroes to single digits
56
+ // verify the event target is what we expect
57
+ if (!(e.target.tagName === "INPUT" && e.target.type === "text")) {
58
+ return;
59
+ }
60
+
61
+ /** @type {HTMLInputElement} */
62
+ const input = e.target;
63
+ const { min, max } = input;
64
+ const minLength = input.minLength || 0;
65
+ const value = (input.value || "").trim();
66
+
67
+ if (!value || parseInt(value) === 0) {
68
+ input.dataset.previousValue = input.value = "";
69
+ return;
70
+ }
71
+
72
+ // If value is less than the min, bump up to min and add padding.
73
+ if (min && parseInt(value) < min) {
74
+ input.dataset.previousValue = input.value = min.padStart(minLength, "0");
75
+ return;
76
+ }
77
+
78
+ // If value exceeds max, bring it down to max and add padding
79
+ if (max && parseInt(value) > max) {
80
+ input.dataset.previousValue = input.value = max.padStart(minLength, "0");
81
+ return;
82
+ }
83
+
84
+ input.dataset.previousValue = input.value = value.padStart(minLength, "0");
85
+ };
86
+
87
+ dateContainers.forEach((dateContainer) => {
88
+ dateContainer.addEventListener("input", inputHandler);
89
+ dateContainer.addEventListener("focusout", focusOutHandler);
90
+ });
91
+ }
@@ -1,8 +1,6 @@
1
1
  <!-- QGDS Component: Date input -->
2
2
 
3
- <label id="{{id}}-label"
4
- class="qld-text-input-label {{#if isRequired}}field-required{{/if}} {{#if isDisabled}}field-disabled{{/if}}"
5
- for="{{id}}">
3
+ <label id="{{id}}-label" class="qld-text-input-label {{#if isRequired}}field-required{{/if}} {{#if isDisabled}}field-disabled{{/if}}" for="{{id}}">
6
4
  {{label-text}}
7
5
  {{#if optional-text}}
8
6
  <span class="label-text-optional">({{optional-text}})</span>
@@ -12,53 +10,49 @@
12
10
  {{#if hint-text}}
13
11
  <span class="qld-hint-text" id="{{id}}-hint">{{hint-text}}</span>
14
12
  {{/if}}
15
-
16
13
  {{#contains "qld-input-success" customClass}}{{! legacy support for feedback classes `qld-input-success`}}
17
14
  <span class="qld-input-success">{{successMessageText}}</span>
18
- {{else}}
19
- {{#if successMessageText}}{{! updated bootstrap style classes - `valid-feedback`}}
15
+ {{else if successMessageText}}{{! updated bootstrap style classes - `valid-feedback`}}
20
16
  <div class="valid-feedback">{{successMessageText}}</div>
21
- {{/if}}{{/contains}}
22
-
17
+ {{/contains}}
23
18
  {{#contains "qld-input-error" customClass}}{{! legacy support for feedback classes `qld-input-error`}}
24
19
  <span class="qld-input-error">{{errorMessageText}}</span>
25
- {{else}}
26
- {{#if errorMessageText}}{{! updated bootstrap style classes - `invalid-feedback`}}
20
+ {{else if errorMessageText}}{{! updated bootstrap style classes - `invalid-feedback`}}
27
21
  <div class="invalid-feedback">{{errorMessageText}}</div>
28
- {{/if}}{{/contains}}
22
+ {{/contains}}
29
23
 
30
24
  <div aria-labelledby="{{id}}-label" role="group" class="row date-container {{customClass}}">
31
25
  <!-- day group -->
32
26
  <div class="day-group">
33
27
  <label id="{{id}}-dayinput-label" for="{{id}}-dayinput" class="date-label qld-text-input-label">Day</label>
34
28
  <div>
35
- <input id="{{id}}-dayinput" aria-required="true" aria-labelledby="{{id}}-label {{id}}-dayinput-label" placeholder="{{day-placeholder}}" type="text"
36
- inputmode="numeric" maxlength="2"
37
- class="qld-text-input form-control dayinput {{customClass}} {{#if isFilled}}form-style-filled{{/if}} {{#if isValid}}is-valid{{else}}{{#ifCond isValid "===" false}}is-invalid{{/ifCond}}{{/if}}" ref="day"
38
- aria-invalid="false" {{#if isDisabled}}disabled{{/if}} {{#if isRequired}}required aria-required="true"
39
- {{/if}}>
29
+ <input id="{{id}}-dayinput" aria-labelledby="{{id}}-label {{id}}-dayinput-label" placeholder="{{day-placeholder}}" type="text"
30
+ inputmode="numeric" maxlength="2" minlength="2" min="1" max="31" pattern="^(0?[1-9]|[12][0-9]|3[01])$"
31
+ class="form-control dayinput {{customClass}} {{#if isFilled}}form-style-filled{{/if}}
32
+ {{#if isValid}}is-valid{{else}}{{#ifCond isValid "===" false}}is-invalid{{/ifCond}}{{/if}}" ref="day"
33
+ aria-invalid="false" {{#if isDisabled}}disabled{{/if}} {{#if isRequired}}required{{/if}} tabindex="0" >
40
34
  </div>
41
35
  </div>
42
36
  <!-- month group -->
43
37
  <div class="date-group">
44
38
  <label id="{{id}}-monthinput-label" for="{{id}}-monthinput" class="date-label qld-text-input-label">Month</label>
45
39
  <div>
46
- <input id="{{id}}-monthinput" aria-required="true" aria-labelledby="{{id}}-label {{id}}-monthinput-label" placeholder="{{month-placeholder}}"
47
- type="text" inputmode="numeric" maxlength="2"
48
- class="qld-text-input form-control monthinput {{customClass}} {{#if isFilled}}form-style-filled{{/if}} {{#if isValid}}is-valid{{else}}{{#ifCond isValid "===" false}}is-invalid{{/ifCond}}{{/if}}" ref="month"
49
- aria-invalid="false" {{#if isDisabled}}disabled{{/if}} {{#if isRequired}}required aria-required="true"
50
- {{/if}}>
40
+ <input id="{{id}}-monthinput" aria-labelledby="{{id}}-label {{id}}-monthinput-label" placeholder="{{month-placeholder}}"
41
+ type="text" inputmode="numeric" maxlength="2" minlength="2" min="1" max="12" pattern="^(0?[1-9]|[1][0-2])$"
42
+ class="form-control monthinput {{customClass}} {{#if isFilled}}form-style-filled{{/if}}
43
+ {{#if isValid}}is-valid{{else}}{{#ifCond isValid "===" false}}is-invalid{{/ifCond}}{{/if}}" ref="month"
44
+ aria-invalid="false" {{#if isDisabled}}disabled{{/if}} {{#if isRequired}}required{{/if}} tabindex="0">
51
45
  </div>
52
46
  </div>
53
47
  <!-- year group -->
54
48
  <div class="date-group">
55
- <label id="{{id}}-yearinput-label" for="{{id}}-yearinput" class="date-label">Year</label>
49
+ <label id="{{id}}-yearinput-label" for="{{id}}-yearinput" class="date-label qld-text-input-label">Year</label>
56
50
  <div class="year-label">
57
- <input id="{{id}}-yearinput" aria-required="true" aria-labelledby="{{id}}-label {{id}}-yearinput-label"
58
- placeholder="{{year-placeholder}}" type="text" inputmode="numeric" maxlength="4"
59
- class="qld-text-input form-control yearinput {{customClass}} {{#if isFilled}}form-style-filled{{/if}} {{#if isValid}}is-valid{{else}}{{#ifCond isValid "===" false}}is-invalid{{/ifCond}}{{/if}}"
60
- ref="year" aria-invalid="false" {{#if isDisabled}}disabled{{/if}} {{#if
61
- isRequired}}required{{/if}}>
51
+ <input id="{{id}}-yearinput" aria-labelledby="{{id}}-label {{id}}-yearinput-label"
52
+ placeholder="{{year-placeholder}}" type="text" inputmode="numeric" maxlength="4" minlength="4" pattern="[0-9]*"
53
+ {{#if yearMin}}min="{{yearMin}}"{{/if}} {{#if yearMax}}max="{{yearMax}}"{{/if}}
54
+ class="form-control yearinput {{customClass}} {{#if isFilled}}form-style-filled{{/if}} {{#if isValid}}is-valid{{else}}{{#ifCond isValid "===" false}}is-invalid{{/ifCond}}{{/if}}"
55
+ ref="year" aria-invalid="false" {{#if isDisabled}}disabled{{/if}} {{#if isRequired}}required{{/if}} tabindex="0">
62
56
  </div>
63
57
  </div>
64
58
  </div>
@@ -22,7 +22,7 @@
22
22
 
23
23
  {{#each listitems}}
24
24
  <div class="form-check {{#if ../isValid}}is-valid{{else}}{{#ifCond ../isValid "===" false}}is-invalid{{/ifCond}}{{/if}}">
25
- <input class="form-check-input" type="{{#if ../type}}{{../type}}{{else}}{{#if type}}{{type}}{{else}}checkbox{{/if}}{{/if}}" name="{{name}}" id="{{id}}" value="{{value}}" {{#if isDisabled}}disabled{{/if}} {{#if isChecked}}checked{{/if}} {{#if isRequired}}required{{/if}} >
25
+ <input class="form-check-input" type="{{#if ../type}}{{../type}}{{else}}{{#if type}}{{type}}{{else}}checkbox{{/if}}{{/if}}" name="{{name}}" id="{{id}}" value="{{value}}" tabindex="{{isdefined ../tabindex 0}}" {{#if isDisabled}}disabled{{/if}} {{#if isChecked}}checked{{/if}} {{#if isRequired}}required{{/if}} >
26
26
  <label class="form-check-label" for="{{id}}">
27
27
  {{label}}
28
28
  </label>
@@ -150,6 +150,11 @@ $form-check-inline-margin-end: 1rem;
150
150
  &::placeholder {
151
151
  color: var(--#{$prefix}placeholder-color-focus);
152
152
  }
153
+
154
+ .dark &,
155
+ .dark-alt & {
156
+ @extend %qld-palette-default;
157
+ }
153
158
  }
154
159
 
155
160
  &:disabled,
@@ -3,7 +3,13 @@
3
3
  <div class="global-alert-include">
4
4
  {{#each alertItems}}
5
5
  <section role="region" class="global-alert alert container-full d-none {{variant}}" data-variant="{{variant}}"
6
- aria-label="{{ariaLabel}}" {{#if id}} data-id="{{id}}" {{/if}}{{#if dismissedExpiryDays}}
6
+ {{#if ariaLabel}} aria-label="{{ ariaLabel }}"
7
+ {{~else ifCond variant "==" "global-alert-critical"}} aria-label="Critical alert"
8
+ {{~else ifCond variant "==" "global-alert-info"}} aria-label="Informational alert"
9
+ {{~else ifCond variant "==" "global-alert-warning"}} aria-label="Warning alert"
10
+ {{~else}} aria-label="Informational alert"
11
+ {{~/if}}
12
+ {{#if id}} data-id="{{id}}" {{/if}}{{#if dismissedExpiryDays}}
7
13
  data-expiry-days="{{dismissedExpiryDays}}" {{/if}}>
8
14
  <div class="qld-global-alert-main">
9
15
  <div class="global-alert-icon">
@@ -13,6 +19,7 @@
13
19
  <span class="qld-icon qld-icon-sm qld-icon-alert-information" aria-hidden="true"></span>
14
20
  {{else ifCond variant '==' 'global-alert-warning'}}
15
21
  <span class="qld-icon qld-icon-sm qld-icon-alert-warning" aria-hidden="true"></span>
22
+ {{else}}<span class="qld-icon qld-icon-sm qld-icon-alert-information" aria-hidden="true"></span>
16
23
  {{/ifCond}}
17
24
  </div>
18
25
 
@@ -1,3 +1,5 @@
1
+ @use "../../../css/mixins" as m;
2
+
1
3
  .global-alert {
2
4
  line-height: 1.25rem;
3
5
  border-radius: 0;
@@ -35,6 +37,7 @@
35
37
  }
36
38
 
37
39
  .global-alert-content {
40
+ --qld-focus-color: #000;
38
41
  display: flex;
39
42
  flex-direction: column;
40
43
  gap: 0.5rem;
@@ -49,8 +52,8 @@
49
52
  text-underline-offset: 0.3rem;
50
53
  }
51
54
 
52
- a:focus {
53
- outline-color: #000;
55
+ a {
56
+ @include m.focusable($outlineWidth: 2px);
54
57
  }
55
58
 
56
59
  .global-alert-action {
@@ -103,11 +106,8 @@
103
106
  mask-size: contain;
104
107
  }
105
108
 
106
- &:focus {
107
- outline: 3px solid;
108
- outline-offset: 0;
109
- box-shadow: none;
110
- }
109
+ @include m.focusable($outlineWidth: 2px);
110
+ box-shadow: none;
111
111
 
112
112
  @include media-breakpoint-down(lg) {
113
113
  &:hover {
@@ -119,7 +119,7 @@
119
119
 
120
120
  &.global-alert-critical {
121
121
  --#{$prefix}icon-color: #{$core-default-color-neutral-white};
122
- //
122
+
123
123
  background-color: $qld-notify-warning;
124
124
  color: var(--#{$prefix}white);
125
125
  font-size: 0.875em;
@@ -129,12 +129,6 @@
129
129
  background-color: var(--#{$prefix}white);
130
130
  }
131
131
 
132
- a {
133
- &:focus {
134
- outline-color: #fff;
135
- }
136
- }
137
-
138
132
  .global-alert-action a {
139
133
  color: var(--#{$prefix}white);
140
134
  text-decoration-color: var(--#{$prefix}white);
@@ -145,18 +139,19 @@
145
139
  }
146
140
 
147
141
  .global-alert-close .btn-close {
148
- &:focus {
149
- outline-color: #ffffff;
150
- }
151
142
  &::before {
152
143
  background-color: #ffffff;
153
144
  }
154
145
  }
146
+
147
+ a {
148
+ --qld-focus-color: #ffffff;
149
+ }
155
150
  }
156
151
 
157
152
  &.global-alert-warning {
158
153
  --#{$prefix}icon-color: #{$core-default-color-neutral-black};
159
- //
154
+
160
155
  background-color: $qld-notify-alert;
161
156
  color: var(--#{$prefix}body-color);
162
157
  font-size: 0.875em;
@@ -170,7 +165,7 @@
170
165
 
171
166
  &.global-alert-info {
172
167
  --#{$prefix}icon-color: #{$core-default-color-neutral-black};
173
- //
168
+
174
169
  background-color: $qld-general-info-alert;
175
170
  color: var(--#{$prefix}body-color);
176
171
  font-size: 0.875em;
@@ -34,6 +34,7 @@ export default {
34
34
 
35
35
  if (args.variant && storyName === "Default") {
36
36
  args.alertItems[0].variant = args.variant || "global-alert-critical";
37
+ args.alertItems[0].ariaLabel = "";
37
38
  }
38
39
 
39
40
  // Render the story with the updated args.
@@ -124,8 +124,13 @@ describe("initGlobalAlerts", () => {
124
124
  beforeParse(window) {
125
125
  // Ensure console methods exist
126
126
  window.console = console;
127
- // Mock localStorage before any scripts run
128
- window.localStorage = localStorageMock;
127
+ // Mock localStorage by redefining localStorage property entirely
128
+ Object.defineProperty(window, "localStorage", {
129
+ value: localStorageMock,
130
+ configurable: true,
131
+ enumerable: true,
132
+ writable: true,
133
+ });
129
134
  Object.defineProperty(window, "localStorage", {
130
135
  value: localStorageMock,
131
136
  writable: true,
@@ -139,11 +144,11 @@ describe("initGlobalAlerts", () => {
139
144
  localStorage = localStorageMock;
140
145
 
141
146
  // Set global references for initGlobalAlerts
142
-
147
+
143
148
  global.document = d;
144
-
149
+
145
150
  global.window = window;
146
-
151
+
147
152
  global.localStorage = localStorageMock;
148
153
 
149
154
  // Clear localStorage before each test
@@ -30,12 +30,11 @@
30
30
  ul,
31
31
  ol {
32
32
  line-height: 1.5;
33
-
34
- &:last-of-type {
35
- margin-bottom: 0;
36
- }
37
33
  }
38
34
 
35
+ &> :last-child {
36
+ margin-bottom: 0;
37
+ }
39
38
  // Close button for dismissible alerts
40
39
  .btn-close {
41
40
  position: absolute;
@@ -14,7 +14,7 @@
14
14
  --#{$prefix}inpage-nav-border-color: var(--#{$prefix}dark-action-primary);
15
15
 
16
16
  .nav {
17
- --#{$prefix}nav-link-color: var(--#{$prefix}white);
17
+ --#{$prefix}nav-link-color: var(--#{$prefix}neutral-white);
18
18
  --#{$prefix}nav-link-hover-color: var(--#{$prefix}brand-accent);
19
19
  }
20
20
  }
@@ -40,12 +40,20 @@
40
40
 
41
41
  .nav-item {
42
42
  margin-top: 0;
43
+ display: inline-flex;
44
+
43
45
  .nav-link {
44
46
  padding-top: var(--#{$prefix}inpage-nav-link-padding-y);
45
47
  padding-bottom: var(--#{$prefix}inpage-nav-link-padding-y);
46
48
  padding-left: var(--#{$prefix}inpage-nav-title-padding-left);
49
+ padding-right: 0;
47
50
  color: var(--#{$prefix}nav-link-color);
48
51
  text-decoration-line: underline;
52
+
53
+ &:hover,
54
+ &:visited {
55
+ text-decoration-color: var(--qld-link-underline);
56
+ }
49
57
  }
50
58
 
51
59
  &:first-child .nav-link {