@qhealth-design-system/core 1.21.0 → 1.21.1

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.
@@ -38,6 +38,10 @@ export const dummyText =
38
38
 
39
39
  export const dummyLink = "https://www.google.com";
40
40
 
41
+ // Path to the icon sprite, relative to the Storybook preview iframe. Used for
42
+ // <use href> references and the coreSiteIcons metadata across stories.
43
+ export const iconSpritePath = "QLD-icons.svg";
44
+
41
45
  const dsBase = "https://www.designsystem.qld.gov.au";
42
46
  const figmaBase = "https://www.figma.com/design/qKsxl3ogIlBp7dafgxXuCA/QGDS-UI-kit";
43
47
 
@@ -15,7 +15,3 @@ export const cleanStorybookUrls = (html) => {
15
15
  export const themeWrapper = (theme, content) => {
16
16
  return `<div class="${theme}" style="padding: 2rem;">${content}</div>`;
17
17
  };
18
-
19
- export const getSvgPath = () => {
20
- return window.location.origin === "https://qld-health-online-team.github.io" ? "/design-system/QLD-icons.svg" : "/QLD-icons.svg";
21
- };
@@ -1,2 +1,2 @@
1
1
  <!-- Add external links here, such as cdn scripts -->
2
- <script src="https://kit.fontawesome.com/1402b3ed47.js" crossorigin="anonymous"></script>
2
+ <script src="https://kit.fontawesome.com/66722b4f34.js" crossorigin="anonymous"></script>
@@ -2,22 +2,7 @@ import "./assets/index.js"; // Storybook JS import
2
2
  import "./assets/index.scss"; // Storybook styles import from core
3
3
  import "./assets/storybook.scss"; // Storybook specific styles
4
4
  import { INITIAL_VIEWPORTS } from "storybook/viewport";
5
- import { viewports, themes, themeColours } from "./globals.js";
6
- import { getSvgPath } from "./helper-functions.js";
7
-
8
- const iconsIds = fetch(getSvgPath())
9
- .then((res) => res.text())
10
- .then((svgText) => {
11
- // Parse the text as XML
12
- const parser = new DOMParser();
13
- const svgDoc = parser.parseFromString(svgText, "image/svg+xml");
14
-
15
- // Select all <symbol> elements
16
- const symbols = svgDoc.querySelectorAll("symbol");
17
-
18
- // Map their IDs
19
- return Array.from(symbols).map((sym) => sym.id);
20
- });
5
+ import { viewports, themes, themeColours, iconSpritePath } from "./globals.js";
21
6
 
22
7
  /** @type { import('@storybook/html-vite').Preview } */
23
8
  const preview = {
@@ -83,13 +68,11 @@ const preview = {
83
68
  },
84
69
  args: {
85
70
  // Ensure GitHub hosted page uses correct icon path
86
- site: { metadata: { coreSiteIcons: { value: getSvgPath() } } },
87
- iconIDs: await iconsIds,
71
+ site: { metadata: { coreSiteIcons: { value: iconSpritePath } } },
88
72
  },
89
73
  argTypes: {
90
74
  // Remove the site metadata from the controls
91
75
  site: { table: { disable: true } },
92
- iconIDs: { table: { disable: true } },
93
76
  },
94
77
  decorators: [
95
78
  (storyFn, context) => {
package/CHANGELOG.md CHANGED
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## Unreleased
9
9
 
10
+ ## 1.21.1 - 2026-06-10
11
+
10
12
  ## 1.21.0 - 2026-06-09
11
13
 
12
14
  ## 1.20.2 - 2026-03-12
package/eslint.config.mjs CHANGED
@@ -52,6 +52,11 @@ export default defineConfig([
52
52
  "valid-typeof": "warn",
53
53
  },
54
54
  },
55
+ {
56
+ // Storybook config files (main.js, prepare-storybook.js, etc.) run in Node.
57
+ files: [".storybook/**/*.js"],
58
+ languageOptions: { globals: globals.node },
59
+ },
55
60
  { files: ["**/*.json"], plugins: { json }, language: "json/json", extends: ["json/recommended"] },
56
61
  { files: ["**/*.md"], plugins: { markdown }, language: "markdown/gfm", extends: ["markdown/recommended"] },
57
62
  { files: ["**/*.css"], plugins: { css }, language: "css/css", extends: ["css/recommended"] },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qhealth-design-system/core",
3
- "version": "1.21.0",
3
+ "version": "1.21.1",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,9 +1,14 @@
1
1
  module.exports = function (string) {
2
2
  if (!string) return "";
3
+ let cleaned = string;
4
+ let prev;
3
5
 
4
- return string
5
- .replace(/<[^>]*>/g, "")
6
- .replace(/&/g, "&amp;")
7
- .replace(/</g, "&lt;")
8
- .replace(/>/g, "&gt;");
6
+ while (cleaned !== prev) {
7
+ prev = cleaned;
8
+ // Remove any HTML tags
9
+ cleaned = cleaned.replace(/<[^>]*>/g, "");
10
+ }
11
+
12
+ // Convert the last remaining special characters to HTML entities
13
+ return cleaned.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
9
14
  };
@@ -1,5 +1,5 @@
1
1
  import Template from "../../components/banner_advanced/html/component.hbs";
2
- import { storyParams } from "../../../.storybook/globals";
2
+ import { storyParams, iconSpritePath } from "../../../.storybook/globals";
3
3
  import ToowoombaImage from "../Cards/Toowoomba-web.jpeg";
4
4
 
5
5
  const mockLineage = [
@@ -10,7 +10,7 @@ const mockLineage = [
10
10
 
11
11
  const mockSite = {
12
12
  metadata: {
13
- coreSiteIcons: { value: "/QLD-icons.svg" },
13
+ coreSiteIcons: { value: iconSpritePath },
14
14
  defaultBannerTexture: { value: "" },
15
15
  defaultBannerTextureDark: { value: "" },
16
16
  },
@@ -1,5 +1,5 @@
1
1
  import Template from "../../components/banner_basic/html/component.hbs";
2
- import { storyParams } from "../../../.storybook/globals";
2
+ import { storyParams, iconSpritePath } from "../../../.storybook/globals";
3
3
  import bannerTexture from "../../assets/img/banner-bg.png";
4
4
 
5
5
  const mockLineage = [
@@ -10,7 +10,7 @@ const mockLineage = [
10
10
 
11
11
  const mockSite = {
12
12
  metadata: {
13
- coreSiteIcons: { value: "/QLD-icons.svg" },
13
+ coreSiteIcons: { value: iconSpritePath },
14
14
  defaultBannerTexture: { value: "" },
15
15
  defaultBannerTextureDark: { value: "" },
16
16
  },
@@ -1,4 +1,4 @@
1
- import { storyParams } from "../../../.storybook/globals";
1
+ import { storyParams, iconSpritePath } from "../../../.storybook/globals";
2
2
 
3
3
  function rowDecorator(Story) {
4
4
  return '<div style="display: flex; gap: 5px">\n' + `${Story()}` + " </div>";
@@ -17,13 +17,13 @@ function renderButtonList({ variant }) {
17
17
  `<button type="button" class="${btnClasses}">Default</button>\n\n` +
18
18
  `<button type="button" class="${btnClasses} qld__btn--icon-lead">\n` +
19
19
  ' <svg class="qld__icon qld__icon--sm" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><use' +
20
- ' href="/QLD-icons.svg#announcement"></use></svg>\n' +
20
+ ` href="${iconSpritePath}#announcement"></use></svg>\n` +
21
21
  " Leading icon\n" +
22
22
  "</button>\n\n" +
23
23
  `<button type="button" class="${btnClasses} qld__btn--icon-trail">\n` +
24
24
  " Trailing icon\n" +
25
25
  ' <svg class="qld__icon qld__icon--sm" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><use' +
26
- ' href="/QLD-icons.svg#announcement"></use></svg>\n' +
26
+ ` href="${iconSpritePath}#announcement"></use></svg>\n` +
27
27
  "</button>\n\n" +
28
28
  `<button type="button" class="${btnClasses}" disabled="">Disabled</button>`
29
29
  );
@@ -1,9 +1,9 @@
1
1
  import Template from "../../components/card_feature/html/component.hbs";
2
- import { storyParams } from "../../../.storybook/globals";
2
+ import { storyParams, iconSpritePath } from "../../../.storybook/globals";
3
3
  import ToowoombaIMage from "./Toowoomba-web.jpeg";
4
4
 
5
5
  const mockSite = {
6
- metadata: { coreSiteIcons: { value: "/QLD-icons.svg" } },
6
+ metadata: { coreSiteIcons: { value: iconSpritePath } },
7
7
  };
8
8
 
9
9
  function buildData(args) {
@@ -1,9 +1,9 @@
1
1
  import Template from "../../components/card_multi_action/html/component.hbs";
2
- import { storyParams } from "../../../.storybook/globals";
2
+ import { storyParams, iconSpritePath } from "../../../.storybook/globals";
3
3
  import ToowoombaImage from "./Toowoomba-web.jpeg";
4
4
 
5
5
  const mockSite = {
6
- metadata: { coreSiteIcons: { value: "/QLD-icons.svg" } },
6
+ metadata: { coreSiteIcons: { value: iconSpritePath } },
7
7
  };
8
8
 
9
9
  function makeChild(id, name, description = "", icon = "fal fa-heart", ctas = []) {
@@ -1,9 +1,9 @@
1
1
  import Template from "../../components/card_no_action/html/component.hbs";
2
- import { storyParams } from "../../../.storybook/globals";
2
+ import { storyParams, iconSpritePath } from "../../../.storybook/globals";
3
3
  import ToowoombaImage from "./Toowoomba-web.jpeg";
4
4
 
5
5
  const mockSite = {
6
- metadata: { coreSiteIcons: { value: "/QLD-icons.svg" } },
6
+ metadata: { coreSiteIcons: { value: iconSpritePath } },
7
7
  };
8
8
 
9
9
  function makeChild(id, name, description = "", icon = "fal fa-heart", footerContent = "") {
@@ -1,9 +1,9 @@
1
1
  import Template from "../../components/card_single_action/html/component.hbs";
2
- import { storyParams } from "../../../.storybook/globals";
2
+ import { storyParams, iconSpritePath } from "../../../.storybook/globals";
3
3
  import ToowoombaImage from "./Toowoomba-web.jpeg";
4
4
 
5
5
  const mockSite = {
6
- metadata: { coreSiteIcons: { value: "/QLD-icons.svg" } },
6
+ metadata: { coreSiteIcons: { value: iconSpritePath } },
7
7
  };
8
8
 
9
9
  function makeChild(id, name, description = "", icon = "fal fa-heart", url = "#", footerContent = "") {
@@ -1,3 +1,5 @@
1
+ import { iconSpritePath } from "../../../../.storybook/globals";
2
+
1
3
  export const Checkboxes = ({ id, legend, hintText, isRequired, inError, errorMessage, inSuccess, successMessage, inputs, isSmall }) => {
2
4
  const getInputClasses = (input) => {
3
5
  if (input.inError) return "qld__input--error";
@@ -9,13 +11,13 @@ export const Checkboxes = ({ id, legend, hintText, isRequired, inError, errorMes
9
11
  if (inError) {
10
12
  return `
11
13
  <span id="qld__checkboxes-status-${id}" class="qld__input--error" role="status" aria-live="polite">
12
- <svg class="qld__icon qld__icon--lead qld__icon--sm" aria-hidden="true"><title>Error icon</title><desc>Indicates an error</desc><use href="QLD-icons.svg#status-error"></use></svg>${errorMessage}
14
+ <svg class="qld__icon qld__icon--lead qld__icon--sm" aria-hidden="true"><title>Error icon</title><desc>Indicates an error</desc><use href="${iconSpritePath}#status-error"></use></svg>${errorMessage}
13
15
  </span>
14
16
  `;
15
17
  } else if (inSuccess) {
16
18
  return `
17
19
  <span id="qld__checkboxes-status-${id}" class="qld__input--success" role="status" aria-live="polite">
18
- <svg class="qld__icon qld__icon--lead qld__icon--sm" aria-hidden="true"><title>Success icon</title><desc>Indicates a correct answer</desc><use href="QLD-icons.svg#status-success"></svg>${successMessage}
20
+ <svg class="qld__icon qld__icon--lead qld__icon--sm" aria-hidden="true"><title>Success icon</title><desc>Indicates a correct answer</desc><use href="${iconSpritePath}#status-success"></svg>${successMessage}
19
21
  </span>
20
22
  `;
21
23
  } else return "";
@@ -1,3 +1,5 @@
1
+ import { iconSpritePath } from "../../../../.storybook/globals";
2
+
1
3
  export const RadioButtons = ({ id, legend, hintText, isRequired, inError, errorMessage, inSuccess, successMessage, inputs, isSmall }) => {
2
4
  const getInputClasses = (input) => {
3
5
  if (input.inError) return "qld__input--error";
@@ -9,13 +11,13 @@ export const RadioButtons = ({ id, legend, hintText, isRequired, inError, errorM
9
11
  if (inError) {
10
12
  return `
11
13
  <span id="qld__radio-buttons-status-${id}" class="qld__input--error" role="status" aria-live="polite">
12
- <svg class="qld__icon qld__icon--lead qld__icon--sm" aria-hidden="true"><title>Error icon</title><desc>Indicates an error</desc><use href="QLD-icons.svg#status-error"></use></svg>${errorMessage}
14
+ <svg class="qld__icon qld__icon--lead qld__icon--sm" aria-hidden="true"><title>Error icon</title><desc>Indicates an error</desc><use href="${iconSpritePath}#status-error"></use></svg>${errorMessage}
13
15
  </span>
14
16
  `;
15
17
  } else if (inSuccess) {
16
18
  return `
17
19
  <span id="qld__radio-buttons-status-${id}" class="qld__input--success" role="status" aria-live="polite">
18
- <svg class="qld__icon qld__icon--lead qld__icon--sm" aria-hidden="true"><title>Success icon</title><desc>Indicates a correct answer</desc><use href="QLD-icons.svg#status-success"></svg>${successMessage}
20
+ <svg class="qld__icon qld__icon--lead qld__icon--sm" aria-hidden="true"><title>Success icon</title><desc>Indicates a correct answer</desc><use href="${iconSpritePath}#status-success"></svg>${successMessage}
19
21
  </span>
20
22
  `;
21
23
  } else return "";
@@ -1,3 +1,5 @@
1
+ import { iconSpritePath } from "../../../../.storybook/globals";
2
+
1
3
  export const SelectBox = ({ id, extraClass, isFilled, isRequired, isDisabled, isMultiple, label, hintText, state, succcessMessage, errorMessage, defaultOption, options }) => {
2
4
  let stateMessage = "";
3
5
  let stateClass = "";
@@ -21,7 +23,7 @@ export const SelectBox = ({ id, extraClass, isFilled, isRequired, isDisabled, is
21
23
  stateMessage = `
22
24
  <span id="${id}-state-message" class="qld__input--success">
23
25
  <svg class="qld__icon qld__icon--lead qld__icon--sm" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
24
- <use href="QLD-icons.svg#status-success"></use>
26
+ <use href="${iconSpritePath}#status-success"></use>
25
27
  </svg>
26
28
  <span>${succcessMessage}</span>
27
29
  </span>`;
@@ -31,7 +33,7 @@ export const SelectBox = ({ id, extraClass, isFilled, isRequired, isDisabled, is
31
33
  stateMessage = `
32
34
  <span id="${id}-state-message" class="qld__input--error">
33
35
  <svg class="qld__icon qld__icon--lead qld__icon--sm" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
34
- <use href="QLD-icons.svg#status-error"></use>
36
+ <use href="${iconSpritePath}#status-error"></use>
35
37
  </svg>
36
38
  <span>${errorMessage}</span>
37
39
  </span>`;
@@ -1,10 +1,10 @@
1
1
  import Template from "../../components/global_alert/html/component.hbs";
2
- import { storyParams } from "../../../.storybook/globals";
2
+ import { storyParams, iconSpritePath } from "../../../.storybook/globals";
3
3
 
4
4
  function buildSite({ alertLevel, alertTitle, alertMessage, alertLinkTitle, alertLinkURL, secondAlert, thirdAlert }) {
5
5
  return {
6
6
  metadata: {
7
- coreSiteIcons: { value: "/QLD-icons.svg" },
7
+ coreSiteIcons: { value: iconSpritePath },
8
8
  mainNavVerticalNav: { value: "" },
9
9
  alertDisplay: { value: "true" },
10
10
  alertLevel: { value: alertLevel },
@@ -1,6 +1,14 @@
1
1
  import { storyParams, themes } from "../../../.storybook/globals";
2
2
  import { Iconography } from "./Iconography";
3
3
  import { themeWrapper } from "../../../.storybook/helper-functions.js";
4
+ import iconsSvg from "../../assets/img/QLD-icons.svg?raw";
5
+
6
+ // The sprite is inlined at build time (?raw); we parse it with DOMParser to list
7
+ // every <symbol> id for the allIcons gallery. Lives here as it's the only consumer.
8
+ // Parsing (rather than regex) means symbols inside comments — e.g. the "XXX"
9
+ // template placeholder — are ignored, since comment nodes aren't queried.
10
+ const iconSprite = new DOMParser().parseFromString(iconsSvg, "image/svg+xml");
11
+ const iconIDs = [...iconSprite.querySelectorAll("symbol")].map((symbol) => symbol.id);
4
12
 
5
13
  const iconographyArgs = {
6
14
  size: "lg",
@@ -42,8 +50,8 @@ export const allIcons = (args) => {
42
50
  let iconString = `<div tabindex="0" class="iconography-container">`;
43
51
 
44
52
  // Loop through each icon ID
45
- if (args.iconIDs.length > 0) {
46
- args.iconIDs.forEach((iconID) => {
53
+ if (iconIDs.length > 0) {
54
+ iconIDs.forEach((iconID) => {
47
55
  iconString += `<div class="iconography-item">`;
48
56
  iconString += Iconography(iconographySizes[2], args.site, iconID);
49
57
  iconString += `<span class="iconography-item-name">${iconID}</span></div>`;
@@ -1,3 +1,5 @@
1
+ import { iconSpritePath } from "../../../.storybook/globals";
2
+
1
3
  export const Tags = ({ type, leadingText, text, isLargeTag, action }) => {
2
4
  const tagListWrapperStart = `<div class="qld__tag-list--wrapper"><span class="qld__tag-list--title">${leadingText}</span><ul class="qld__tag-list">`;
3
5
  const tagListWrapperEnd = `</ul></div>`;
@@ -24,7 +26,7 @@ export const Tags = ({ type, leadingText, text, isLargeTag, action }) => {
24
26
  <div class="qld__tag qld__tag--filter">
25
27
  ${text}
26
28
  <button class="qld__tag--filter-close" data-toggleUrl="{{toggleUrl}}">
27
- <svg class="qld__icon qld__icon--sm" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><use href="QLD-icons.svg#close"></use></svg>
29
+ <svg class="qld__icon qld__icon--sm" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><use href="${iconSpritePath}#close"></use></svg>
28
30
  <span class="sr-only">close</span>
29
31
  </button>
30
32
  </div>
@@ -33,7 +35,7 @@ export const Tags = ({ type, leadingText, text, isLargeTag, action }) => {
33
35
  <div class="qld__tag qld__tag--filter">
34
36
  ${text}
35
37
  <button class="qld__tag--filter-close" data-toggleUrl="{{toggleUrl}}">
36
- <svg class="qld__icon qld__icon--sm" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><use href="QLD-icons.svg#close"></use></svg>
38
+ <svg class="qld__icon qld__icon--sm" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><use href="${iconSpritePath}#close"></use></svg>
37
39
  <span class="sr-only">close</span>
38
40
  </button>
39
41
  </div>
@@ -42,7 +44,7 @@ export const Tags = ({ type, leadingText, text, isLargeTag, action }) => {
42
44
  <div class="qld__tag qld__tag--filter">
43
45
  ${text}
44
46
  <button class="qld__tag--filter-close" data-toggleUrl="{{toggleUrl}}">
45
- <svg class="qld__icon qld__icon--sm" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><use href="QLD-icons.svg#close"></use></svg>
47
+ <svg class="qld__icon qld__icon--sm" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"><use href="${iconSpritePath}#close"></use></svg>
46
48
  <span class="sr-only">close</span>
47
49
  </button>
48
50
  </div>