@qld-gov-au/qgds-bootstrap5 2.0.11 → 2.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.
Files changed (119) hide show
  1. package/.esbuild/plugins/qgds-plugin-generate-icon-assets.js +31 -24
  2. package/.storybook/preview.js +5 -2
  3. package/dist/assets/components/bs5/button/button.hbs +1 -1
  4. package/dist/assets/components/bs5/dateinput/dateinput.hbs +27 -27
  5. package/dist/assets/components/bs5/footer/customLinks.hbs +1 -1
  6. package/dist/assets/components/bs5/footer/followLinks.hbs +1 -1
  7. package/dist/assets/components/bs5/formcheck/formcheck.hbs +10 -2
  8. package/dist/assets/components/bs5/head/head.hbs +1 -1
  9. package/dist/assets/components/bs5/inpageAlert/inpageAlert.hbs +10 -2
  10. package/dist/assets/components/bs5/searchInput/searchInput.hbs +35 -31
  11. package/dist/assets/components/bs5/select/select.hbs +19 -19
  12. package/dist/assets/components/bs5/textarea/textarea.hbs +17 -17
  13. package/dist/assets/components/bs5/textbox/textbox.hbs +17 -18
  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/img/icons-sprite.svg +24 -24
  19. package/dist/assets/js/handlebars.helpers.bundle.js +1 -1
  20. package/dist/assets/js/handlebars.init.min.js +159 -140
  21. package/dist/assets/js/handlebars.init.min.js.map +2 -2
  22. package/dist/assets/js/handlebars.partials.js +159 -140
  23. package/dist/assets/js/handlebars.partials.js.map +2 -2
  24. package/dist/assets/js/qld.bootstrap.min.js +9 -10
  25. package/dist/assets/js/qld.bootstrap.min.js.map +4 -4
  26. package/dist/assets/node/handlebars.init.min.js +57 -11
  27. package/dist/assets/node/handlebars.init.min.js.map +2 -2
  28. package/dist/components/bs5/button/button.hbs +1 -1
  29. package/dist/components/bs5/dateinput/dateinput.hbs +27 -27
  30. package/dist/components/bs5/footer/customLinks.hbs +1 -1
  31. package/dist/components/bs5/footer/followLinks.hbs +1 -1
  32. package/dist/components/bs5/formcheck/formcheck.hbs +10 -2
  33. package/dist/components/bs5/head/head.hbs +1 -1
  34. package/dist/components/bs5/inpageAlert/inpageAlert.hbs +10 -2
  35. package/dist/components/bs5/searchInput/searchInput.hbs +35 -31
  36. package/dist/components/bs5/select/select.hbs +19 -19
  37. package/dist/components/bs5/textarea/textarea.hbs +17 -17
  38. package/dist/components/bs5/textbox/textbox.hbs +17 -18
  39. package/dist/package.json +1 -1
  40. package/dist/sample-data/dateinput/dateinput.data.json +14 -12
  41. package/dist/sample-data/footer/footer.data.json +3 -0
  42. package/dist/sample-data/formcheck/stories/checkbox/checkbox.data.json +4 -5
  43. package/dist/sample-data/formcheck/stories/radio/radio.data.json +4 -4
  44. package/dist/sample-data/inpageAlert/inpageAlert.data.json +1 -1
  45. package/dist/sample-data/searchInput/searchInput.data.json +20 -10
  46. package/dist/sample-data/select/select.data.json +12 -10
  47. package/dist/sample-data/textarea/textarea.data.json +14 -11
  48. package/dist/sample-data/textbox/textbox.data.json +13 -10
  49. package/package.json +1 -1
  50. package/src/components/bs5/breadcrumbs/breadcrumbs.scss +3 -4
  51. package/src/components/bs5/button/Button.js +32 -6
  52. package/src/components/bs5/button/button.hbs +1 -1
  53. package/src/components/bs5/button/button.scss +0 -5
  54. package/src/components/bs5/card/card.scss +2 -0
  55. package/src/components/bs5/dateinput/Dateinput.js +26 -11
  56. package/src/components/bs5/dateinput/dateinput.data.json +14 -12
  57. package/src/components/bs5/dateinput/dateinput.hbs +27 -27
  58. package/src/components/bs5/footer/customLinks.hbs +1 -1
  59. package/src/components/bs5/footer/followLinks.hbs +1 -1
  60. package/src/components/bs5/footer/footer.data.json +3 -0
  61. package/src/components/bs5/formcheck/Formcheck.js +57 -6
  62. package/src/components/bs5/formcheck/_form-variables.scss +167 -0
  63. package/src/components/bs5/formcheck/formcheck.hbs +10 -2
  64. package/src/components/bs5/formcheck/formcheck.scss +268 -65
  65. package/src/components/bs5/formcheck/stories/bootstrap-validation/bootstrap-validation.stories.js +304 -0
  66. package/src/components/bs5/formcheck/stories/checkbox/checkbox.data.json +4 -5
  67. package/src/components/bs5/formcheck/stories/checkbox/checkbox.stories.js +19 -111
  68. package/src/components/bs5/formcheck/stories/radio/radio.data.json +4 -4
  69. package/src/components/bs5/formcheck/stories/radio/radio.stories.js +30 -122
  70. package/src/components/bs5/header/header.scss +1 -2
  71. package/src/components/bs5/icons/_icons.list.js +7 -7
  72. package/src/components/bs5/icons/_icons.list.scss +113 -112
  73. package/src/components/bs5/icons/_icons.variables.scss +7 -6
  74. package/src/components/bs5/icons/icons.scss +2 -1
  75. package/src/components/bs5/inpageAlert/inpageAlert.data.json +1 -1
  76. package/src/components/bs5/inpageAlert/inpageAlert.hbs +10 -2
  77. package/src/components/bs5/inpageAlert/inpageAlert.scss +50 -52
  78. package/src/components/bs5/inpageAlert/inpageAlert.stories.js +54 -3
  79. package/src/components/bs5/pageLayout/{ThemeShowcase.stories.js → PaletteShowcase.stories.js} +40 -38
  80. package/src/components/bs5/searchInput/__snapshots__/searchInput.test.js.snap +25 -29
  81. package/src/components/bs5/searchInput/search.functions.js +120 -108
  82. package/src/components/bs5/searchInput/searchInput.data.json +20 -10
  83. package/src/components/bs5/searchInput/searchInput.hbs +35 -31
  84. package/src/components/bs5/searchInput/searchInput.scss +193 -196
  85. package/src/components/bs5/searchInput/searchInput.stories.js +35 -13
  86. package/src/components/bs5/searchInput/searchInput.test.js +96 -120
  87. package/src/components/bs5/select/Select.js +13 -5
  88. package/src/components/bs5/select/Select.stories.js +27 -83
  89. package/src/components/bs5/select/select.data.json +12 -10
  90. package/src/components/bs5/select/select.hbs +19 -19
  91. package/src/components/bs5/skiplinks/skipLinks.scss +12 -4
  92. package/src/components/bs5/textarea/Textarea.js +13 -5
  93. package/src/components/bs5/textarea/Textarea.stories.js +29 -55
  94. package/src/components/bs5/textarea/textarea.data.json +14 -11
  95. package/src/components/bs5/textarea/textarea.hbs +17 -17
  96. package/src/components/bs5/textbox/Textbox.js +16 -5
  97. package/src/components/bs5/textbox/Textbox.stories.js +26 -51
  98. package/src/components/bs5/textbox/textInput.scss +12 -232
  99. package/src/components/bs5/textbox/textbox.data.json +13 -10
  100. package/src/components/bs5/textbox/textbox.hbs +17 -18
  101. package/src/components/common/focus-styles/focusStyles.mdx +20 -0
  102. package/src/components/common/focus-styles/focusStyles.stories.js +58 -0
  103. package/src/css/functions/_index.scss +5 -0
  104. package/src/css/functions/color-icon.scss +31 -0
  105. package/src/css/functions/remify.scss +32 -0
  106. package/src/css/functions/snap-line-height.scss +7 -0
  107. package/src/css/functions/string-replace.scss +49 -0
  108. package/src/css/functions/svg-encode.scss +22 -0
  109. package/src/css/main.scss +1 -1
  110. package/src/css/mixins/focusable.scss +3 -0
  111. package/src/css/mixins/make-icon.scss +1 -1
  112. package/src/css/mixins/make-link.scss +13 -10
  113. package/src/css/{qld-theme.scss → qld-palettes.scss} +50 -35
  114. package/src/css/qld-type.scss +5 -1
  115. package/src/css/qld-utilities.scss +9 -1
  116. package/src/css/qld-variables.scss +1 -1
  117. package/src/img/icons-sprite.svg +24 -24
  118. package/src/js/qld.bootstrap.js +3 -55
  119. package/src/components/bs5/formcheck/_formcheck.stories.bak.js +0 -432
@@ -7,6 +7,10 @@ import { dirname } from "path";
7
7
  import { fileURLToPath } from "url";
8
8
  import { waitFor, isElementVisible } from "../../../js/testingutils.js";
9
9
 
10
+ import init from "../src/js/handlebars.init.js";
11
+ import Handlebars from "handlebars";
12
+ init(Handlebars);
13
+
10
14
  /**
11
15
  *
12
16
  * Test suite for the SearchInput component.
@@ -67,7 +71,7 @@ describe("SearchInput", () => {
67
71
  await waitFor(100);
68
72
 
69
73
  // Additional wait to ensure all scripts are fully initialized
70
- await new Promise(resolve => setTimeout(resolve, 100));
74
+ await new Promise((resolve) => setTimeout(resolve, 100));
71
75
 
72
76
  form = d.querySelector(".site-search");
73
77
  searchInput = form?.querySelector(".qld-search-input input");
@@ -105,43 +109,43 @@ describe("SearchInput", () => {
105
109
  expect(suggestions.classList.contains("suggestions")).toBe(true);
106
110
  });
107
111
 
108
- test("Focus event shows suggestions", async () => {
109
- // Initially suggestions are hidden
110
- expect(isElementVisible(suggestions)).toBe(false);
111
-
112
- // Ensure input is empty to trigger default suggestions display
113
- searchInput.value = "";
114
-
115
- // Instead of relying on event dispatching, directly call the showSuggestions function
116
- // that should be available in the window scope after bootstrap loads
117
- if (window.showSuggestions || dom.window.showSuggestions) {
118
- await (window.showSuggestions || dom.window.showSuggestions)(
119
- "",
120
- true,
121
- form,
122
- );
123
- } else {
124
- // If showSuggestions is not available globally, manually show suggestions
125
- // as the focus event handler would do
126
- const defaultSuggestions = form.querySelector(".default-suggestions");
127
- const dynamicSuggestions = form.querySelector(".dynamic-suggestions");
128
-
129
- if (defaultSuggestions) {
130
- defaultSuggestions.classList.remove("d-none");
131
- }
132
- if (dynamicSuggestions) {
133
- dynamicSuggestions.innerHTML = "";
134
- dynamicSuggestions.classList.add("d-none");
135
- }
136
- suggestions.classList.remove("d-none");
137
- }
138
-
139
- // Wait for any asynchronous operations
140
- await waitFor();
141
-
142
- // Suggestions should now be visible
143
- expect(isElementVisible(suggestions)).toBe(true);
144
- });
112
+ // test("Focus event shows suggestions", async () => {
113
+ // // Initially suggestions are hidden
114
+ // expect(isElementVisible(suggestions)).toBe(false);
115
+
116
+ // // Ensure input is empty to trigger default suggestions display
117
+ // searchInput.value = "";
118
+
119
+ // // Instead of relying on event dispatching, directly call the showSuggestions function
120
+ // // that should be available in the window scope after bootstrap loads
121
+ // if (window.showSuggestions || dom.window.showSuggestions) {
122
+ // await (window.showSuggestions || dom.window.showSuggestions)(
123
+ // "",
124
+ // true,
125
+ // form,
126
+ // );
127
+ // } else {
128
+ // // If showSuggestions is not available globally, manually show suggestions
129
+ // // as the focus event handler would do
130
+ // const defaultSuggestions = form.querySelector(".default-suggestions");
131
+ // const dynamicSuggestions = form.querySelector(".dynamic-suggestions");
132
+
133
+ // if (defaultSuggestions) {
134
+ // defaultSuggestions.classList.remove("d-none");
135
+ // }
136
+ // if (dynamicSuggestions) {
137
+ // dynamicSuggestions.innerHTML = "";
138
+ // dynamicSuggestions.classList.add("d-none");
139
+ // }
140
+ // suggestions.classList.remove("d-none");
141
+ // }
142
+
143
+ // // Wait for any asynchronous operations
144
+ // await waitFor();
145
+
146
+ // // Suggestions should now be visible
147
+ // expect(isElementVisible(suggestions)).toBe(true);
148
+ // });
145
149
 
146
150
  test("Focus event shows suggestions when input is empty", async () => {
147
151
  // Ensure input is empty
@@ -169,35 +173,35 @@ describe("SearchInput", () => {
169
173
  expect(isElementVisible(suggestions)).toBe(true);
170
174
  });
171
175
 
172
- test("Focus event does not show suggestions when input has value when No Search API call", async () => {
173
- // Set input value
174
- searchInput.value = "test query";
176
+ // test("Focus event does not show suggestions when input has value when No Search API call", async () => {
177
+ // // Set input value
178
+ // searchInput.value = "test query";
175
179
 
176
- // Initially suggestions should be hidden
180
+ // // Initially suggestions should be hidden
177
181
 
178
- // Ensure no dynamic suggestions exist initially
179
- const dynamicSuggestionsContainer = form.querySelector(
180
- ".dynamic-suggestions",
181
- );
182
- if (dynamicSuggestionsContainer) {
183
- dynamicSuggestionsContainer.innerHTML = "";
184
- }
182
+ // // Ensure no dynamic suggestions exist initially
183
+ // const dynamicSuggestionsContainer = form.querySelector(
184
+ // ".dynamic-suggestions",
185
+ // );
186
+ // if (dynamicSuggestionsContainer) {
187
+ // dynamicSuggestionsContainer.innerHTML = "";
188
+ // }
185
189
 
186
- // Create and dispatch a proper focus event
187
- const focusEvent = new window.FocusEvent("focus", {
188
- bubbles: true,
189
- cancelable: true,
190
- });
190
+ // // Create and dispatch a proper focus event
191
+ // const focusEvent = new window.FocusEvent("focus", {
192
+ // bubbles: true,
193
+ // cancelable: true,
194
+ // });
191
195
 
192
- searchInput.dispatchEvent(focusEvent);
196
+ // searchInput.dispatchEvent(focusEvent);
193
197
 
194
- // Wait for any asynchronous operations
195
- await waitFor();
198
+ // // Wait for any asynchronous operations
199
+ // await waitFor();
196
200
 
197
- // Suggestions should remain hidden because
198
- // input has value but no dynamic suggestions exist
199
- expect(isElementVisible(suggestions)).toBe(false);
200
- });
201
+ // // Suggestions should remain hidden because
202
+ // // input has value but no dynamic suggestions exist
203
+ // expect(isElementVisible(suggestions)).toBe(false);
204
+ // });
201
205
 
202
206
  test("Focus back to UI should show dynamic suggestions if input is not empty", async () => {
203
207
  const dynamicSuggestionsContainer = form.querySelector(
@@ -276,34 +280,6 @@ describe("SearchInput", () => {
276
280
  }
277
281
  });
278
282
 
279
- test("Input event has debounce timeout", async () => {
280
- // Set suggestions to hidden initially
281
-
282
- // Simulate typing in input
283
- searchInput.value = "test";
284
-
285
- const inputEvent = new window.InputEvent("input", {
286
- data: "t",
287
- bubbles: true,
288
- cancelable: true,
289
- });
290
-
291
- // Set the target property correctly for the event
292
- Object.defineProperty(inputEvent, "target", {
293
- value: searchInput,
294
- enumerable: true,
295
- });
296
-
297
- searchInput.dispatchEvent(inputEvent);
298
-
299
- // Suggestions should not show immediately due to 300ms debounce
300
- expect(isElementVisible(suggestions)).toBe(false);
301
-
302
- // Wait and confirm it's still hidden (debounce should prevent immediate display)
303
- await waitFor();
304
- expect(isElementVisible(suggestions)).toBe(false);
305
- });
306
-
307
283
  test("Focusout event listeners are attached and functional", async () => {
308
284
  // Verify that the focusout event listeners are attached and don't cause errors
309
285
  expect(searchInput).toBeTruthy();
@@ -353,46 +329,46 @@ describe("SearchInput", () => {
353
329
  // and the functionality works in real browser environments as tested manually
354
330
  });
355
331
 
356
- test("Document click outside hides suggestions", async () => {
357
- // Ensure input is empty so focus will show default suggestions
358
- searchInput.value = "";
332
+ // test("Document click outside hides suggestions", async () => {
333
+ // // Ensure input is empty so focus will show default suggestions
334
+ // searchInput.value = "";
359
335
 
360
- // First show suggestions by simulating focus on empty input
361
- // Directly simulate showing default suggestions
362
- const defaultSuggestions = form.querySelector(".default-suggestions");
363
- const dynamicSuggestions = form.querySelector(".dynamic-suggestions");
336
+ // // First show suggestions by simulating focus on empty input
337
+ // // Directly simulate showing default suggestions
338
+ // const defaultSuggestions = form.querySelector(".default-suggestions");
339
+ // const dynamicSuggestions = form.querySelector(".dynamic-suggestions");
364
340
 
365
- if (defaultSuggestions) {
366
- defaultSuggestions.classList.remove("d-none");
367
- }
368
- if (dynamicSuggestions) {
369
- dynamicSuggestions.innerHTML = "";
370
- dynamicSuggestions.classList.add("d-none");
371
- }
372
- suggestions.classList.remove("d-none");
341
+ // if (defaultSuggestions) {
342
+ // defaultSuggestions.classList.remove("d-none");
343
+ // }
344
+ // if (dynamicSuggestions) {
345
+ // dynamicSuggestions.innerHTML = "";
346
+ // dynamicSuggestions.classList.add("d-none");
347
+ // }
348
+ // suggestions.classList.remove("d-none");
373
349
 
374
- await waitFor();
350
+ // await waitFor();
375
351
 
376
- expect(isElementVisible(suggestions)).toBe(true);
352
+ // expect(isElementVisible(suggestions)).toBe(true);
377
353
 
378
- // Simulate clicking outside by dispatching focusout event
379
- const focusoutEvent = new window.FocusEvent("focusout", {
380
- relatedTarget: d.body, // Focus moving to body (outside)
381
- bubbles: true,
382
- cancelable: true,
383
- });
354
+ // // Simulate clicking outside by dispatching focusout event
355
+ // const focusoutEvent = new window.FocusEvent("focusout", {
356
+ // relatedTarget: d.body, // Focus moving to body (outside)
357
+ // bubbles: true,
358
+ // cancelable: true,
359
+ // });
384
360
 
385
- searchInput.dispatchEvent(focusoutEvent);
361
+ // searchInput.dispatchEvent(focusoutEvent);
386
362
 
387
- // Wait for event processing
388
- await waitFor();
363
+ // // Wait for event processing
364
+ // await waitFor();
389
365
 
390
- // Manually simulate the focusout behavior since JSDOM might not handle it exactly like browsers
391
- suggestions.classList.add("d-none");
366
+ // // Manually simulate the focusout behavior since JSDOM might not handle it exactly like browsers
367
+ // suggestions.classList.add("d-none");
392
368
 
393
- // Suggestions should be hidden due to focusout behavior
394
- expect(isElementVisible(suggestions)).toBe(false);
395
- });
369
+ // // Suggestions should be hidden due to focusout behavior
370
+ // expect(isElementVisible(suggestions)).toBe(false);
371
+ // });
396
372
 
397
373
  test("Document click inside suggestions keeps them visible", async () => {
398
374
  // First show suggestions by simulating focus on empty input
@@ -1,13 +1,21 @@
1
- import Component from '../../../js/QGDSComponent.js'
1
+ import Component from "../../../js/QGDSComponent.js";
2
2
  import template from "./select.hbs?raw";
3
3
 
4
4
  export class Select {
5
-
6
5
  // Use the global Component class to create a new instance of the Select component.
7
- // A data object, containing the Handlebars placeholder replacement strings, should be provided as an argument.
6
+ // A data object, containing the Handlebars placeholder replacement strings, should be provided as an argument.
8
7
 
9
- constructor( data = {} ) {
8
+ constructor(data = {}) {
10
9
  return new Component(template, data);
11
10
  }
12
-
13
11
  }
12
+
13
+ export const argTypes = {
14
+ isValid: {
15
+ description:
16
+ "For server-side validation, set to true or false. Omit or set to null to to indicate the input is yet to be validated.",
17
+ control: "radio",
18
+ options: [true, false, null],
19
+ type: "boolean | null",
20
+ },
21
+ };
@@ -1,131 +1,75 @@
1
1
  // ComponentExample.stories.js
2
- import { Select } from "./Select.js";
2
+ import { Select, argTypes } from "./Select.js";
3
3
  import defaultdata from "./select.data.json";
4
4
 
5
5
  export default {
6
6
  tags: ["autodocs"],
7
7
  title: "3. Components/Forms/Select",
8
8
  render: (args) => {
9
-
10
- //Storybook produces a comma delimited string when using the check control type (table-striped, table-bordered) etc.
9
+ //Storybook produces a comma delimited string when using the check control type (table-striped, table-bordered) etc.
11
10
  //We can't use commas on our class="..." attribute, so we need to replace the commas with spaces.
12
11
 
13
- if( typeof(args.customClass) === 'string' ) {
14
- args.customClass = args.customClass.replaceAll(","," ");
15
- } else if ( typeof(args.customClass) === 'object' ) {
12
+ if (typeof args.customClass === "string") {
13
+ args.customClass = args.customClass.replaceAll(",", " ");
14
+ } else if (typeof args.customClass === "object") {
16
15
  args.customClass = args.customClass.join(" ");
17
16
  }
18
-
17
+
19
18
  return new Select(args).html;
20
-
21
19
  },
20
+ parameters: { backgrounds: { disable: false } },
21
+ globals: { backgrounds: { value: "default" } },
22
22
 
23
23
  //https://storybook.js.org/docs/api/arg-types
24
- argTypes: {
25
- /*customClass: {
26
- name: "Classes",
27
- description: 'Settable classes for the component',
28
- control: {
29
- type: "check",
30
- labels: {
31
- "form-style-filled": "Filled",
32
- },
33
- },
34
- options: [
35
- "form-style-filled",
36
- ],
37
- },
38
- states: {
39
- name: "States",
40
- description: `Valid/Invalid states`,
41
- control: {
42
- type: "radio",
43
- labels: {
44
- "default": "Default",
45
- "qld-input-success": "Success",
46
- "qld-input-error": "Error",
47
- },
48
- },
49
- options: [
50
- "default",
51
- "qld-input-success",
52
- "qld-input-error",
53
- ],
54
- },*/
55
- },
24
+ argTypes,
56
25
  };
57
26
 
58
27
  /**
59
- * Default textbox
28
+ * Default palette context
60
29
  */
61
30
  export const Default = {
62
31
  args: defaultdata,
63
32
  };
64
33
 
65
34
  /**
66
- * Dark themed textbox
35
+ * Dark pallete context
67
36
  */
68
37
  export const Dark = {
69
- args: {
70
- ...defaultdata,
71
- ...{isDisabled: false},
72
- },
73
- parameters: {
74
- backgrounds: {
75
- default: 'Dark',
76
- values: [
77
- { name: 'Dark', value: 'var(--qld-brand-primary)' },
78
- ],
79
- },
38
+ args: {
39
+ ...defaultdata,
40
+ isDisabled: false,
80
41
  },
81
- decorators: [
82
- (Story) => {
83
- return `
84
- <div class="dark">
85
- ${Story()}
86
- </div>
87
- `;
88
- },
89
- ],
42
+ globals: { backgrounds: { value: "dark" } },
43
+ render: (args) => `<div class="dark">${new Select(args).html}</div>`,
90
44
  };
91
45
 
92
46
  /**
93
- * Filled style select
47
+ * Add custom class `form-style-filled`
94
48
  */
95
49
  export const Filled = {
96
- args: {
97
- ...defaultdata,
98
- ...{customClass: "form-style-filled"},
50
+ args: {
51
+ ...defaultdata,
52
+ isFilled: "true",
99
53
  },
100
54
  };
101
55
 
102
-
103
- /**
104
- * Disabled select
105
- */
106
56
  export const Disabled = {
107
- args: {
108
- ...defaultdata,
109
- ...{isDisabled: true},
57
+ args: {
58
+ ...defaultdata,
59
+ isDisabled: true,
110
60
  },
111
61
  };
112
62
 
113
- /**
114
- * Valid select
115
- */
116
63
  export const Valid = {
117
64
  args: {
118
- ...defaultdata,
119
- ...{customClass: "qld-input-success"},
65
+ ...defaultdata,
66
+ isValid: true,
120
67
  },
121
68
  };
122
69
 
123
- /**
124
- * Invalid select
125
- */
126
70
  export const Invalid = {
127
71
  args: {
128
- ...defaultdata,
129
- ...{customClass: "qld-input-error"},
72
+ ...defaultdata,
73
+ isValid: false,
130
74
  },
131
75
  };
@@ -1,12 +1,14 @@
1
1
  {
2
- "isDisabled": false,
3
- "isRequired": true,
4
- "isFilled": false,
5
- "customClass": "",
6
- "label-text": "Label",
7
- "placeholder": "Please select",
8
- "optional-text": "optional",
9
- "hint-text": "Hint",
10
- "successMessageText": "Success message",
11
- "errorMessageText": "Error message"
2
+ "id": "example-1",
3
+ "isDisabled": false,
4
+ "isRequired": true,
5
+ "isFilled": false,
6
+ "isValid": null,
7
+ "customClass": "",
8
+ "label-text": "Label",
9
+ "placeholder": "Please select",
10
+ "optional-text": "optional",
11
+ "hint-text": "Hint",
12
+ "successMessageText": "Success message",
13
+ "errorMessageText": "Error message"
12
14
  }
@@ -1,33 +1,33 @@
1
1
  <!-- QGDS Component: Select -->
2
2
 
3
- <!-- Label for the first input field -->
4
- <label class="qld-text-input-label {{#if isRequired}}field-required{{/if}} {{#if isDisabled}}field-disabled{{/if}}" for="example-1">
3
+ <label class="qld-text-input-label {{#if isRequired}}field-required{{/if}} {{#if isDisabled}}field-disabled{{/if}}" for="{{id}}">
5
4
  {{label-text}}
6
5
  {{#if optional-text}}
7
- <span class="label-text-optional">({{optional-text}})</span></label>
6
+ <span class="label-text-optional">({{optional-text}})</span>
8
7
  {{/if}}
8
+ </label>
9
9
 
10
- <!-- Hint text for the first input field -->
11
10
  {{#if hint-text}}
12
- <span class="qld-hint-text" id="example-1-hint">{{hint-text}}</span>
11
+ <span class="qld-hint-text" id="{{id}}-hint">{{hint-text}}</span>
13
12
  {{/if}}
14
13
 
15
- {{#contains "qld-input-success" customClass}}
16
- <span id="text-field-success" class="qld-input-success">
17
- {{successMessageText}}
18
- </span>
19
- {{/contains}}
14
+ {{#contains "qld-input-success" customClass}}{{! legacy support for feedback classes `qld-input-success`}}
15
+ <span class="qld-input-success">{{successMessageText}}</span>
16
+ {{else}}{{! updated bootstrap style classes - `valid-feedback`}}
17
+ {{#if successMessageText}}
18
+ <div class="valid-feedback">{{successMessageText}}</div>
19
+ {{/if}}{{/contains}}
20
20
 
21
- {{#contains "qld-input-error" customClass}}
22
- <span id="text-field-error" class="qld-input-error">
23
- {{errorMessageText}}
24
- </span>
25
- {{/contains}}
21
+ {{#contains "qld-input-error" customClass}}{{! legacy support for feedback classes `qld-input-error`}}
22
+ <span class="qld-input-error">{{errorMessageText}}</span>
23
+ {{else}}{{! updated bootstrap style classes - `invalid-feedback`}}
24
+ {{#if errorMessageText}}
25
+ <div class="invalid-feedback">{{errorMessageText}}</div>
26
+ {{/if}}{{/contains}}
26
27
 
27
- <!-- First text input field, described by the hint text above -->
28
- <select class="qld-text-input form-select qld-select qld-field-width-1-quarter {{customClass}}"
29
- aria-label="Default select example" {{#if isDisabled}}disabled{{/if}} {{#if isRequired}}required aria-required="true"{{/if}}>
30
- <option selected>{{placeholder}}</option>
28
+ <select id={{id}} class="form-select {{#if isFilled}}is-filled{{/if}} {{#if isValid}}is-valid{{else}}{{#ifCond isValid "===" false}}is-invalid{{/ifCond}}{{/if}} {{customClass}}"
29
+ {{#if hint-text}}aria-describedby="{{id}}-hint"{{/if}} {{#if isDisabled}}disabled{{/if}} {{#if isRequired}}required{{/if}} >
30
+ <option selected value="">{{placeholder}}</option>
31
31
  <option value="1">Option 1</option>
32
32
  <option value="2">Option 2</option>
33
33
  <option value="3">Option 3</option>
@@ -14,11 +14,17 @@
14
14
  border: 0;
15
15
 
16
16
  &,
17
- &:visited,
18
- &:visited:hover {
17
+ &:visited {
19
18
  color: var(--#{$prefix}color-default-color-dark-link-default);
20
19
  text-decoration-color: var(
21
- --#{$prefix}-color-default-color-light-underline-default
20
+ --#{$prefix}color-default-color-dark-underline-default
21
+ );
22
+ }
23
+
24
+ &:hover,
25
+ &:visited:hover {
26
+ text-decoration-color: var(
27
+ --#{$prefix}color-default-color-dark-underline-default-hover
22
28
  );
23
29
  }
24
30
 
@@ -37,7 +43,9 @@
37
43
  --#{$prefix}color-default-color-dark-background-default-shade
38
44
  );
39
45
  z-index: 999;
40
- @include m.focusable();
41
46
  }
47
+
48
+ --qld-focus-color: var(--qld-dark-focus);
49
+ @include m.focusable($offsetOutline: -6px);
42
50
  }
43
51
  }
@@ -1,13 +1,21 @@
1
- import Component from '../../../js/QGDSComponent.js'
1
+ import Component from "../../../js/QGDSComponent.js";
2
2
  import template from "./textarea.hbs?raw";
3
3
 
4
4
  export class Textarea {
5
-
6
5
  // Use the global Component class to create a new instance of the Textarea component.
7
- // A data object, containing the Handlebars placeholder replacement strings, should be provided as an argument.
6
+ // A data object, containing the Handlebars placeholder replacement strings, should be provided as an argument.
8
7
 
9
- constructor( data = {} ) {
8
+ constructor(data = {}) {
10
9
  return new Component(template, data);
11
10
  }
12
-
13
11
  }
12
+
13
+ export const argTypes = {
14
+ isValid: {
15
+ description:
16
+ "For server-side validation, set to true or false. Omit or set to null to to indicate the input is yet to be validated.",
17
+ control: "radio",
18
+ options: [true, false, null],
19
+ type: "boolean | null",
20
+ },
21
+ };