@qhealth-design-system/core 1.22.2 → 1.23.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 (78) hide show
  1. package/.storybook/assets/image-position-demo-portrait.svg +54 -0
  2. package/.storybook/assets/image-position-demo.svg +55 -0
  3. package/.storybook/globals.js +9 -0
  4. package/.storybook/preview.js +8 -1
  5. package/CHANGELOG.md +2 -0
  6. package/README.md +0 -6
  7. package/package.json +13 -33
  8. package/src/assets/img/svg-icons.svg +154 -154
  9. package/src/component-loader.js +11 -2
  10. package/src/components/_global/css/admin/component.scss +1 -0
  11. package/src/components/_global/css/btn/component.scss +9 -0
  12. package/src/components/_global/css/img/image-position-utility-classes.scss +30 -0
  13. package/src/components/_global/css/img/image-ratio-utility-classes.scss +41 -0
  14. package/src/components/_global/css/img/images.scss +74 -5
  15. package/src/components/_global/css/modal/component.scss +1 -0
  16. package/src/components/_global/js/animate/global.js +272 -294
  17. package/src/components/_global/js/collapsible.js +3 -3
  18. package/src/components/_global/js/global.js +304 -316
  19. package/src/components/_global/js/legacyGlobal.js +63 -0
  20. package/src/components/_global/js/modal/global.js +218 -223
  21. package/src/components/_global/js/popover/controller.js +4 -4
  22. package/src/components/_global/js/tabs/global.js +264 -276
  23. package/src/components/a-z_listing/js/global.js +106 -92
  24. package/src/components/accordion/css/component.scss +24 -41
  25. package/src/components/accordion/html/component.hbs +23 -5
  26. package/src/components/accordion/js/global.js +5 -10
  27. package/src/components/basic_search/js/global.js +0 -7
  28. package/src/components/code/js/global.js +6 -12
  29. package/src/components/file_upload/js/global.js +1 -5
  30. package/src/components/internal_navigation/css/component.scss +2 -2
  31. package/src/components/internal_navigation/html/component.hbs +16 -1
  32. package/src/components/main_navigation/js/global.js +341 -335
  33. package/src/components/overflow_menu/css/component.scss +1 -0
  34. package/src/components/search_box/css/component.scss +0 -1
  35. package/src/components/tab/js/global.js +5 -10
  36. package/src/components/toggle_tip/js/global.js +0 -6
  37. package/src/components/tool_tip/js/global.js +0 -6
  38. package/src/components/video_player/css/component.scss +27 -9
  39. package/src/components/video_player/html/component.hbs +32 -6
  40. package/src/components/video_player/js/global.js +8 -1
  41. package/src/index.js +4 -0
  42. package/src/stories/Accordion/accordion.stories.js +1 -0
  43. package/src/stories/Banner/bannerContained.stories.js +123 -0
  44. package/src/stories/Flexbox/Flexbox.stories.js +316 -0
  45. package/src/stories/Image/Image.stories.js +182 -0
  46. package/src/stories/Templates/ContentPage.stories.js +101 -0
  47. package/src/stories/Templates/LandingPage.stories.js +193 -0
  48. package/src/stories/Templates/templateHelpers.js +102 -0
  49. package/src/stories/VideoPlayer/VideoPlayer.stories.js +16 -0
  50. package/src/styles/imports/utilities.scss +15 -25
  51. package/src/styles/imports/variables.scss +26 -0
  52. package/src/components/_global/html/head.html +0 -22
  53. package/src/components/_global/html/scripts.html +0 -28
  54. package/src/components/_global/js/_polyfills/global.js +0 -19
  55. package/src/components/_template/html/component-page.html +0 -75
  56. package/src/components/_template/js/global.js +0 -3
  57. package/src/components/accordion/html/accordion-group.html +0 -163
  58. package/src/components/accordion/html/default.html +0 -99
  59. package/src/components/banner_basic/js/global.js +0 -3
  60. package/src/components/loading_spinner/js/global.js +0 -3
  61. package/src/components/pagination/html/default.html +0 -39
  62. package/src/components/search_box/html/component.html +0 -26
  63. package/src/data/current.json +0 -400
  64. package/src/data/current_admin.json +0 -305
  65. package/src/data/model_component.js +0 -14
  66. package/src/data/site.json +0 -977
  67. package/src/externals/tinymce_classes.css +0 -62
  68. package/src/html/component-global-elements.html +0 -2857
  69. package/src/html/component-horizontal_rule.html +0 -647
  70. package/src/html/component-internal_navigation.html +0 -583
  71. package/src/html/component-left_hand_navigation.html +0 -57
  72. package/src/html/component-main_navigation.html +0 -583
  73. package/src/html/component-multi_column.html +0 -582
  74. package/src/html/components.html +0 -354
  75. package/src/html/home.html +0 -1898
  76. package/src/html/index.html +0 -129
  77. package/src/html/inner-with-nav.html +0 -605
  78. package/src/html/inner.html +0 -618
@@ -17,6 +17,7 @@
17
17
  text-decoration: none;
18
18
  padding: 4px;
19
19
  min-width: 0;
20
+ min-height: 0;
20
21
  width: 32px;
21
22
  height: 32px;
22
23
 
@@ -95,7 +95,6 @@
95
95
  border-top-left-radius: 0;
96
96
  margin: 0;
97
97
  width: 100%;
98
- line-height: 24px;
99
98
  font-size: 1rem;
100
99
  }
101
100
  }
@@ -10,6 +10,8 @@
10
10
  * the tablist, and the focused tab is activated on click or Enter/Space.
11
11
  */
12
12
 
13
+ import utils from "../../_global/js/global.js";
14
+
13
15
  // Distance in px the tab list scrolls each time an overflow arrow is clicked.
14
16
  const SCROLL_AMOUNT = 500;
15
17
 
@@ -31,11 +33,9 @@ export default function initTab(root = document) {
31
33
  });
32
34
 
33
35
  // In the Matrix build this rewrites icon sprite paths (core vs health
34
- // sprite). QLD.utils only exists once the global bundle has loaded, so guard
35
- // it in Storybook it's absent and the icons use their authored href as-is.
36
- window.QLD?.utils?.updateSvgIconPath?.(
37
- ".qld__tab-container .qld__tabs svg.qld__icon > use",
38
- );
36
+ // sprite). It's a no-op for the core overflow-arrow icons used here, so it's
37
+ // safe to run everywhere including Storybook.
38
+ utils.updateSvgIconPath(".qld__tab-container .qld__tabs svg.qld__icon > use");
39
39
 
40
40
  return () => controller.abort();
41
41
  }
@@ -197,8 +197,3 @@ function debounce(fn, wait) {
197
197
  timeout = setTimeout(() => fn(...args), wait);
198
198
  };
199
199
  }
200
-
201
- // Expose on window.QLD for backwards compatibility (legacy callers used
202
- // `QLD.tab.init()`). New code should import `initTab` directly.
203
- window.QLD = window.QLD || {};
204
- window.QLD.tab = { init: () => initTab(document), initTab };
@@ -129,9 +129,3 @@ function wireDocument(root, closeAll, getLastOpened, signal) {
129
129
  { signal },
130
130
  );
131
131
  }
132
-
133
- // Back-compat: expose on window.QLD for any legacy callers (QLD.toggleTip.init()).
134
- // Initialisation in the app is driven by component-loader.js; new code should
135
- // import initToggleTip directly.
136
- window.QLD = window.QLD || {};
137
- window.QLD.toggleTip = { init: () => initToggleTip(document), initToggleTip };
@@ -88,9 +88,3 @@ function wireTrigger(tip, closeAll, signal) {
88
88
 
89
89
  content.addEventListener("mouseleave", () => close(), { signal });
90
90
  }
91
-
92
- // Back-compat: expose on window.QLD for any legacy callers (QLD.toolTip.init()).
93
- // Initialisation in the app is driven by component-loader.js; new code should
94
- // import initToolTip directly.
95
- window.QLD = window.QLD || {};
96
- window.QLD.toolTip = { init: () => initToolTip(document), initToolTip };
@@ -21,6 +21,12 @@
21
21
  text-decoration: underline;
22
22
  }
23
23
 
24
+ // the icon + text group is a layout wrapper; only its inner text
25
+ // should carry the underline
26
+ .qld__video__player__transcript-label {
27
+ text-decoration: none;
28
+ }
29
+
24
30
  &:hover {
25
31
  span {
26
32
  text-decoration-thickness: var(--QLD-underline__thickness-thick);
@@ -118,10 +124,6 @@
118
124
  .qld__video__player__transcript {
119
125
  .qld__accordion__title {
120
126
  color: var(--QLD-color-dark__link);
121
-
122
- &::after {
123
- background-color: var(--QLD-color-dark__action--secondary);
124
- }
125
127
  }
126
128
 
127
129
  .qld__icon {
@@ -192,25 +194,41 @@
192
194
  }
193
195
  .qld__accordion__title {
194
196
  font-size: pxToRem(16);
197
+ // label group on the left, chevron on the right
198
+ justify-content: space-between;
195
199
  transition: transform 0.25s ease-in;
196
200
  border-bottom-left-radius: $QLD-border-radius-xs;
197
201
  border-bottom-right-radius: $QLD-border-radius-xs;
202
+
203
+ @include QLD-space(padding, 1unit);
204
+
198
205
  .qld__icon {
199
206
  font-size: pxToRem(20);
200
- margin-right: pxToRem(8);
207
+ }
208
+ // chevron sits inline at the end of the row, not absolutely
209
+ // positioned like in the base accordion
210
+ .qld__accordion__icon {
211
+ margin-top: 0;
201
212
  }
202
213
  &:hover {
203
214
  background-color: transparent;
204
215
  }
205
216
  }
217
+
218
+ // groups the transcript icon and its text so space-between keeps them
219
+ // together at the start of the row
220
+ &-label {
221
+ display: flex;
222
+ align-items: center;
223
+ gap: pxToRem(8);
224
+ }
206
225
  &-link {
207
- padding: pxToRem(16) pxToRem(12);
226
+ align-items: center;
227
+ gap: pxToRem(8);
208
228
  border-bottom-left-radius: $QLD-border-radius-xs;
209
229
  border-bottom-right-radius: $QLD-border-radius-xs;
210
230
 
211
- .qld__icon {
212
- margin-right: pxToRem(8);
213
- }
231
+ @include QLD-space(padding, 1unit);
214
232
  }
215
233
  }
216
234
  }
@@ -130,16 +130,29 @@
130
130
  aria-controls="accordion-group-{{ assetid }}"
131
131
  aria-expanded="false"
132
132
  >
133
+ <span class="qld__video__player__transcript-label">
134
+ <svg
135
+ class="qld__icon qld__icon--md"
136
+ aria-hidden="true"
137
+ xmlns="http://www.w3.org/2000/svg"
138
+ >
139
+ <use
140
+ href="{{ @root.site.metadata.coreSiteIcons.value }}#transcript"
141
+ ></use>
142
+ </svg>
143
+ <span class="qld__video__player__transcript-text">
144
+ Show transcript
145
+ </span>
146
+ </span>
133
147
  <svg
134
- class="qld__icon qld__icon--md"
148
+ class="qld__icon qld__icon--md qld__accordion__icon"
135
149
  aria-hidden="true"
136
150
  xmlns="http://www.w3.org/2000/svg"
137
151
  >
138
152
  <use
139
- href="{{ @root.site.metadata.coreSiteIcons.value }}#transcript"
153
+ href="{{ @root.site.metadata.coreSiteIcons.value }}#chevron-up"
140
154
  ></use>
141
155
  </svg>
142
- <span>Show transcript</span>
143
156
  </button>
144
157
  <div
145
158
  id="accordion-group-{{ assetid }}"
@@ -241,16 +254,29 @@
241
254
  aria-controls="accordion-group-{{ assetid }}"
242
255
  aria-expanded="false"
243
256
  >
257
+ <span class="qld__video__player__transcript-label">
258
+ <svg
259
+ class="qld__icon qld__icon--sm"
260
+ aria-hidden="true"
261
+ xmlns="http://www.w3.org/2000/svg"
262
+ >
263
+ <use
264
+ href="{{ @root.site.metadata.coreSiteIcons.value }}#transcript"
265
+ ></use>
266
+ </svg>
267
+ <span class="qld__video__player__transcript-text">
268
+ Show transcript
269
+ </span>
270
+ </span>
244
271
  <svg
245
- class="qld__icon qld__icon--sm"
272
+ class="qld__icon qld__icon--md qld__accordion__icon"
246
273
  aria-hidden="true"
247
274
  xmlns="http://www.w3.org/2000/svg"
248
275
  >
249
276
  <use
250
- href="{{ @root.site.metadata.coreSiteIcons.value }}#transcript"
277
+ href="{{ @root.site.metadata.coreSiteIcons.value }}#chevron-up"
251
278
  ></use>
252
279
  </svg>
253
- <span>Show transcript</span>
254
280
  </button>
255
281
  <div
256
282
  id="accordion-group-{{ assetid }}"
@@ -30,7 +30,14 @@ export default function initVideoPlayer(root = document) {
30
30
  * `.qld__accordion__title` trigger
31
31
  */
32
32
  function syncTranscriptLabel(event) {
33
- const label = event.target.querySelector("span");
33
+ // Target the text span explicitly. The label is wrapped alongside the
34
+ // transcript icon, so writing textContent to an ancestor span would destroy
35
+ // that icon. The fallback covers legacy markup where the button's first
36
+ // span is the text itself.
37
+ const label =
38
+ event.target.querySelector(".qld__video__player__transcript-text") ??
39
+ event.target.querySelector("span");
40
+
34
41
  if (label) {
35
42
  label.textContent = event.detail.open
36
43
  ? "Hide transcript"
package/src/index.js CHANGED
@@ -1,8 +1,12 @@
1
1
  // JS
2
+ import utils from "./components/_global/js/global.js";
2
3
  import initComponents from "./component-loader.js";
3
4
  import "../src/helpers/global-helpers.js";
4
5
  import "prismjs";
5
6
 
7
+ // Swap the `no-js` html class for `js` as early as possible.
8
+ utils.browserJS();
9
+
6
10
  // Adding ES module initialisation for components
7
11
  initComponents();
8
12
 
@@ -42,6 +42,7 @@ function render(args) {
42
42
  metadata: buildMetadata(args),
43
43
  },
44
44
  },
45
+ ...args,
45
46
  });
46
47
  }
47
48
 
@@ -0,0 +1,123 @@
1
+ // The contained (curved) banner is a page-level *layout*, not a standalone
2
+ // component. It is switched on by adding the `qld__banner_contained` class to
3
+ // the page body, which then restyles the header, main navigation and banner
4
+ // together — constraining their width, adding curved edges + drop shadows and
5
+ // filling the negative space with a background colour. The effect only applies
6
+ // above 1600px, so these stories force a wide viewport.
7
+ //
8
+ // Unlike most component stories, the contained styles live in their own webpack
9
+ // entry (src/styles/banner_contained/globals.scss → dist/banner_contained.css)
10
+ // and are NOT part of the Storybook bundle, so we import them explicitly here.
11
+ import "../../styles/banner_contained/globals.scss";
12
+
13
+ import { renderHeader, headerArgs } from "../Header/Header.js";
14
+ import BannerAdvancedMeta from "./bannerAdvanced.stories";
15
+ import { storyParams } from "../../../.storybook/globals";
16
+ import { initComponents } from "../../../.storybook/decorators";
17
+ import initBannerAdvanced from "../../components/banner_advanced/js/global";
18
+ import initCtaLinks from "../../components/_global/js/cta_links/global";
19
+ import { initMegaMenu } from "../../components/mega_main_navigation/js/global";
20
+
21
+ // The curved styling activates at 1600px, so demonstrate at an extra-large width.
22
+ const containedViewport = {
23
+ name: "Contained banner (1680px)",
24
+ styles: { width: "1680px", height: "1200px" },
25
+ };
26
+
27
+ function render(args) {
28
+ // The whole page carries the `qld__banner_contained` body class — that is the
29
+ // hook every selector in banner_contained/globals.scss keys off.
30
+ const page = document.createElement("div");
31
+ page.className = "qld__banner_contained qld__body qld__grid js";
32
+
33
+ // Header + main navigation. renderHeader also emits the
34
+ // `.qld__header__contained-banner` backdrop when the contained class is set.
35
+ page.innerHTML = renderHeader({
36
+ ...args,
37
+ defaultBannerContainedBanner: "qld__banner_contained",
38
+ });
39
+
40
+ // The banner itself, reusing the Advanced banner (heading block, abstract,
41
+ // CTA buttons and hero image — matching the contained banner design).
42
+ const bannerEl = BannerAdvancedMeta.render(args);
43
+
44
+ // `main.landing` + `#content > section` is the structure the contained
45
+ // styles key off to pull the first section up behind the banner's curved
46
+ // bottom edge, so the banner overlaps into the section's white space.
47
+ const main = document.createElement("main");
48
+ main.className = "main landing";
49
+ main.appendChild(bannerEl);
50
+
51
+ // The min-height stands in for real page content: the section must extend
52
+ // past the 800px header backdrop or its background colour shows below.
53
+ const content = document.createElement("div");
54
+ content.id = "content";
55
+ content.innerHTML = `
56
+ <section class="qld__body" style="min-height: 500px">
57
+ <div class="container-fluid">
58
+ <h2>Section Heading (H2)</h2>
59
+ </div>
60
+ </section>
61
+ `;
62
+ main.appendChild(content);
63
+ page.appendChild(main);
64
+
65
+ return page;
66
+ }
67
+
68
+ const meta = {
69
+ title: "3. Components/Banner/Contained",
70
+ render,
71
+ decorators: [
72
+ initComponents([initMegaMenu, initCtaLinks, initBannerAdvanced]),
73
+ ],
74
+ // Reuse the Header and Advanced banner controls so the composed page is fully
75
+ // configurable, then narrow the notable ones below.
76
+ argTypes: {
77
+ ...BannerAdvancedMeta.argTypes,
78
+ },
79
+ args: {
80
+ ...headerArgs,
81
+ ...BannerAdvancedMeta.args,
82
+ // Match the design mock: dark banner with block headings and abstract, hero
83
+ // image aligned to the page edge, no breadcrumbs and no CTA buttons.
84
+ headingPrimary: "Heading 1 Heading 1",
85
+ headingSecondary: "Subheading heading 1",
86
+ showHeadingBackground: true,
87
+ abstract:
88
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut interdum " +
89
+ "purus at efficitur imperdiet. Maecenas placerat accumsan nulla, vel " +
90
+ "semper enim. In turpis.",
91
+ backgroundColour: "dark",
92
+ showBreadcrumbs: false,
93
+ heroImageAlignment: "page",
94
+ heroImageTreatment: "crop",
95
+ ctaPrimaryText: "",
96
+ ctaSecondaryText: "",
97
+ },
98
+ parameters: {
99
+ layout: "fullscreen",
100
+ viewport: {
101
+ defaultViewport: "containedBanner",
102
+ options: { containedBanner: containedViewport },
103
+ },
104
+ ...storyParams(
105
+ "banner",
106
+ "The **contained banner** is a page-level layout enabled by adding the " +
107
+ "`qld__banner_contained` class to the `<body>` element. It constrains " +
108
+ "the header, navigation and banner to a maximum width and applies curved " +
109
+ "edges and drop shadows. It only takes effect on viewports above 1600px.",
110
+ ),
111
+ },
112
+ };
113
+
114
+ export default meta;
115
+
116
+ export const Default = {};
117
+
118
+ // A plain colour background instead of a hero image.
119
+ export const WithoutHeroImage = {
120
+ args: {
121
+ heroImage: "",
122
+ },
123
+ };