@carbon/ibm-products-web-components 0.41.1 → 0.42.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 (160) hide show
  1. package/custom-elements.json +64 -0
  2. package/es/components/coachmark/coachmark-body.d.ts +1 -1
  3. package/es/components/coachmark/coachmark-header.d.ts +1 -1
  4. package/es/components/coachmark/coachmark.d.ts +1 -1
  5. package/es/components/interstitial-screen/interstitial-screen-body-item.js +1 -1
  6. package/es/components/interstitial-screen/interstitial-screen-body.d.ts +1 -1
  7. package/es/components/interstitial-screen/interstitial-screen-footer.d.ts +1 -1
  8. package/es/components/interstitial-screen/interstitial-screen-footer.js +1 -1
  9. package/es/components/interstitial-screen/interstitial-screen-header.d.ts +1 -1
  10. package/es/components/interstitial-screen/interstitial-screen-header.js +1 -1
  11. package/es/components/interstitial-screen/interstitial-screen.d.ts +1 -1
  12. package/es/components/interstitial-screen/interstitial-screen.d.ts.map +1 -1
  13. package/es/components/interstitial-screen/interstitial-screen.js +2 -1
  14. package/es/components/interstitial-screen/interstitial-screen.js.map +1 -1
  15. package/es/components/page-header/context.d.ts +1 -0
  16. package/es/components/page-header/context.d.ts.map +1 -1
  17. package/es/components/page-header/context.js +2 -1
  18. package/es/components/page-header/context.js.map +1 -1
  19. package/es/components/page-header/page-header-breadcrumb.d.ts +3 -0
  20. package/es/components/page-header/page-header-breadcrumb.d.ts.map +1 -1
  21. package/es/components/page-header/page-header-breadcrumb.js +18 -3
  22. package/es/components/page-header/page-header-breadcrumb.js.map +1 -1
  23. package/es/components/page-header/page-header-tabs.d.ts +7 -0
  24. package/es/components/page-header/page-header-tabs.d.ts.map +1 -1
  25. package/es/components/page-header/page-header-tabs.js +27 -0
  26. package/es/components/page-header/page-header-tabs.js.map +1 -1
  27. package/es/components/page-header/page-header.d.ts +2 -0
  28. package/es/components/page-header/page-header.d.ts.map +1 -1
  29. package/es/components/page-header/page-header.js +5 -0
  30. package/es/components/page-header/page-header.js.map +1 -1
  31. package/es/components/page-header/page-header.scss.js +1 -1
  32. package/es/components/page-header/page-header.scss.js.map +1 -1
  33. package/es/components/side-panel/side-panel.d.ts +31 -0
  34. package/es/components/side-panel/side-panel.d.ts.map +1 -1
  35. package/es/components/side-panel/side-panel.js +89 -0
  36. package/es/components/side-panel/side-panel.js.map +1 -1
  37. package/es/components/side-panel/side-panel.scss.js +1 -1
  38. package/es/components/side-panel/side-panel.scss.js.map +1 -1
  39. package/es/components/tearsheet/tearsheet.scss.js +1 -1
  40. package/es/components/tearsheet-preview/tearsheet-body.d.ts +1 -1
  41. package/es/components/tearsheet-preview/tearsheet-footer.d.ts +6 -2
  42. package/es/components/tearsheet-preview/tearsheet-footer.d.ts.map +1 -1
  43. package/es/components/tearsheet-preview/tearsheet-footer.js +15 -1
  44. package/es/components/tearsheet-preview/tearsheet-footer.js.map +1 -1
  45. package/es/components/tearsheet-preview/tearsheet-header-content.d.ts +8 -0
  46. package/es/components/tearsheet-preview/tearsheet-header-content.d.ts.map +1 -1
  47. package/es/components/tearsheet-preview/tearsheet-header-content.js +12 -1
  48. package/es/components/tearsheet-preview/tearsheet-header-content.js.map +1 -1
  49. package/es/components/tearsheet-preview/tearsheet-header-content.scss.js +1 -1
  50. package/es/components/tearsheet-preview/tearsheet-header.d.ts +1 -1
  51. package/es/components/tearsheet-preview/tearsheet-header.d.ts.map +1 -1
  52. package/es/components/tearsheet-preview/tearsheet-header.js +12 -4
  53. package/es/components/tearsheet-preview/tearsheet-header.js.map +1 -1
  54. package/es/components/tearsheet-preview/tearsheet-header.scss.js +1 -1
  55. package/es/components/tearsheet-preview/tearsheet-influencer.d.ts +5 -1
  56. package/es/components/tearsheet-preview/tearsheet-influencer.d.ts.map +1 -1
  57. package/es/components/tearsheet-preview/tearsheet-influencer.js +4 -0
  58. package/es/components/tearsheet-preview/tearsheet-influencer.js.map +1 -1
  59. package/es/components/tearsheet-preview/tearsheet-navigation-bar.scss.js +1 -1
  60. package/es/components/tearsheet-preview/tearsheet-signal.d.ts +1 -0
  61. package/es/components/tearsheet-preview/tearsheet-signal.d.ts.map +1 -1
  62. package/es/components/tearsheet-preview/tearsheet-signal.js +2 -1
  63. package/es/components/tearsheet-preview/tearsheet-signal.js.map +1 -1
  64. package/es/components/tearsheet-preview/tearsheet-summary-content.d.ts +5 -1
  65. package/es/components/tearsheet-preview/tearsheet-summary-content.d.ts.map +1 -1
  66. package/es/components/tearsheet-preview/tearsheet-summary-content.js +4 -0
  67. package/es/components/tearsheet-preview/tearsheet-summary-content.js.map +1 -1
  68. package/es/components/tearsheet-preview/tearsheet.d.ts +11 -1
  69. package/es/components/tearsheet-preview/tearsheet.d.ts.map +1 -1
  70. package/es/components/tearsheet-preview/tearsheet.js +30 -1
  71. package/es/components/tearsheet-preview/tearsheet.js.map +1 -1
  72. package/es/components/tearsheet-preview/tearsheet.scss.js +1 -1
  73. package/es/components/tearsheet-preview/tearsheet.scss.js.map +1 -1
  74. package/es/ibm-products-web-components/package.js +1 -1
  75. package/es/utilities/manageFocusTrap/manageFocusTrap.d.ts +121 -3
  76. package/es/utilities/manageFocusTrap/manageFocusTrap.d.ts.map +1 -1
  77. package/es/utilities/manageFocusTrap/manageFocusTrap.js +188 -33
  78. package/es/utilities/manageFocusTrap/manageFocusTrap.js.map +1 -1
  79. package/es-custom/components/interstitial-screen/interstitial-screen-body-item.js +1 -1
  80. package/es-custom/components/interstitial-screen/interstitial-screen-footer.js +1 -1
  81. package/es-custom/components/interstitial-screen/interstitial-screen-header.js +1 -1
  82. package/es-custom/components/interstitial-screen/interstitial-screen.js +2 -1
  83. package/es-custom/components/interstitial-screen/interstitial-screen.js.map +1 -1
  84. package/es-custom/components/page-header/context.js +2 -1
  85. package/es-custom/components/page-header/context.js.map +1 -1
  86. package/es-custom/components/page-header/page-header-breadcrumb.js +18 -3
  87. package/es-custom/components/page-header/page-header-breadcrumb.js.map +1 -1
  88. package/es-custom/components/page-header/page-header-tabs.js +27 -0
  89. package/es-custom/components/page-header/page-header-tabs.js.map +1 -1
  90. package/es-custom/components/page-header/page-header.js +5 -0
  91. package/es-custom/components/page-header/page-header.js.map +1 -1
  92. package/es-custom/components/page-header/page-header.scss.js +1 -1
  93. package/es-custom/components/page-header/page-header.scss.js.map +1 -1
  94. package/es-custom/components/side-panel/side-panel.js +89 -0
  95. package/es-custom/components/side-panel/side-panel.js.map +1 -1
  96. package/es-custom/components/side-panel/side-panel.scss.js +1 -1
  97. package/es-custom/components/side-panel/side-panel.scss.js.map +1 -1
  98. package/es-custom/components/tearsheet/tearsheet.scss.js +1 -1
  99. package/es-custom/components/tearsheet-preview/tearsheet-footer.js +15 -1
  100. package/es-custom/components/tearsheet-preview/tearsheet-footer.js.map +1 -1
  101. package/es-custom/components/tearsheet-preview/tearsheet-header-content.js +12 -1
  102. package/es-custom/components/tearsheet-preview/tearsheet-header-content.js.map +1 -1
  103. package/es-custom/components/tearsheet-preview/tearsheet-header-content.scss.js +1 -1
  104. package/es-custom/components/tearsheet-preview/tearsheet-header.js +12 -4
  105. package/es-custom/components/tearsheet-preview/tearsheet-header.js.map +1 -1
  106. package/es-custom/components/tearsheet-preview/tearsheet-header.scss.js +1 -1
  107. package/es-custom/components/tearsheet-preview/tearsheet-influencer.js +4 -0
  108. package/es-custom/components/tearsheet-preview/tearsheet-influencer.js.map +1 -1
  109. package/es-custom/components/tearsheet-preview/tearsheet-navigation-bar.scss.js +1 -1
  110. package/es-custom/components/tearsheet-preview/tearsheet-signal.js +2 -1
  111. package/es-custom/components/tearsheet-preview/tearsheet-signal.js.map +1 -1
  112. package/es-custom/components/tearsheet-preview/tearsheet-summary-content.js +4 -0
  113. package/es-custom/components/tearsheet-preview/tearsheet-summary-content.js.map +1 -1
  114. package/es-custom/components/tearsheet-preview/tearsheet.js +30 -1
  115. package/es-custom/components/tearsheet-preview/tearsheet.js.map +1 -1
  116. package/es-custom/components/tearsheet-preview/tearsheet.scss.js +1 -1
  117. package/es-custom/components/tearsheet-preview/tearsheet.scss.js.map +1 -1
  118. package/es-custom/ibm-products-web-components/package.js +1 -1
  119. package/es-custom/utilities/manageFocusTrap/manageFocusTrap.js +188 -33
  120. package/es-custom/utilities/manageFocusTrap/manageFocusTrap.js.map +1 -1
  121. package/lib/components/coachmark/coachmark-body.d.ts +1 -1
  122. package/lib/components/coachmark/coachmark-header.d.ts +1 -1
  123. package/lib/components/coachmark/coachmark.d.ts +1 -1
  124. package/lib/components/interstitial-screen/interstitial-screen-body.d.ts +1 -1
  125. package/lib/components/interstitial-screen/interstitial-screen-footer.d.ts +1 -1
  126. package/lib/components/interstitial-screen/interstitial-screen-header.d.ts +1 -1
  127. package/lib/components/interstitial-screen/interstitial-screen.d.ts +1 -1
  128. package/lib/components/interstitial-screen/interstitial-screen.d.ts.map +1 -1
  129. package/lib/components/page-header/context.d.ts +1 -0
  130. package/lib/components/page-header/context.d.ts.map +1 -1
  131. package/lib/components/page-header/page-header-breadcrumb.d.ts +3 -0
  132. package/lib/components/page-header/page-header-breadcrumb.d.ts.map +1 -1
  133. package/lib/components/page-header/page-header-tabs.d.ts +7 -0
  134. package/lib/components/page-header/page-header-tabs.d.ts.map +1 -1
  135. package/lib/components/page-header/page-header.d.ts +2 -0
  136. package/lib/components/page-header/page-header.d.ts.map +1 -1
  137. package/lib/components/side-panel/side-panel.d.ts +31 -0
  138. package/lib/components/side-panel/side-panel.d.ts.map +1 -1
  139. package/lib/components/tearsheet-preview/tearsheet-body.d.ts +1 -1
  140. package/lib/components/tearsheet-preview/tearsheet-footer.d.ts +6 -2
  141. package/lib/components/tearsheet-preview/tearsheet-footer.d.ts.map +1 -1
  142. package/lib/components/tearsheet-preview/tearsheet-header-content.d.ts +8 -0
  143. package/lib/components/tearsheet-preview/tearsheet-header-content.d.ts.map +1 -1
  144. package/lib/components/tearsheet-preview/tearsheet-header.d.ts +1 -1
  145. package/lib/components/tearsheet-preview/tearsheet-header.d.ts.map +1 -1
  146. package/lib/components/tearsheet-preview/tearsheet-influencer.d.ts +5 -1
  147. package/lib/components/tearsheet-preview/tearsheet-influencer.d.ts.map +1 -1
  148. package/lib/components/tearsheet-preview/tearsheet-signal.d.ts +1 -0
  149. package/lib/components/tearsheet-preview/tearsheet-signal.d.ts.map +1 -1
  150. package/lib/components/tearsheet-preview/tearsheet-summary-content.d.ts +5 -1
  151. package/lib/components/tearsheet-preview/tearsheet-summary-content.d.ts.map +1 -1
  152. package/lib/components/tearsheet-preview/tearsheet.d.ts +11 -1
  153. package/lib/components/tearsheet-preview/tearsheet.d.ts.map +1 -1
  154. package/lib/utilities/manageFocusTrap/manageFocusTrap.d.ts +121 -3
  155. package/lib/utilities/manageFocusTrap/manageFocusTrap.d.ts.map +1 -1
  156. package/package.json +7 -6
  157. package/scss/components/page-header/page-header.scss +49 -10
  158. package/scss/components/side-panel/side-panel.scss +19 -0
  159. package/scss/components/tearsheet-preview/tearsheet.scss +5 -0
  160. package/telemetry.yml +5 -0
@@ -16,25 +16,161 @@ import { prefix, selectorTabbable } from "@carbon/web-components/es/globals/sett
16
16
  * LICENSE file in the root directory of this source tree.
17
17
  */
18
18
  /**
19
- * Traps focus within a set of containers, ensuring it stays within focusable elements.
20
- * @param {NodeListOf<Element>} containers - The containers to trap focus within.
21
- * @returns {object} An object with a `cleanup` method to remove event listeners.
19
+ * Simple object to store containers by uniqueId
20
+ * { id: [container1, container2, ...] }
22
21
  */
23
- let _containers = [];
24
- const registerFocusableContainers = (container) => {
25
- if (container) _containers.push(container);
22
+ const containers = {};
23
+ /**
24
+ * Default key for backward compatibility when no uniqueId is provided
25
+ */
26
+ const DEFAULT_KEY = "__default__";
27
+ /**
28
+ * Registers a focusable container to be included in the focus trap.
29
+ *
30
+ * This function allows child components to register their shadow roots or DOM elements
31
+ * so that the focus trap utility can query focusable elements within them. This is necessary
32
+ * because shadow DOM boundaries prevent direct querying from parent components.
33
+ *
34
+ * @param container - The HTMLElement or ShadowRoot to register as a focusable container.
35
+ * If null, the function returns early without registering.
36
+ * @param uniqueId - Optional unique identifier to scope containers to a specific component instance.
37
+ * If not provided, uses a default key for backward compatibility.
38
+ *
39
+ * @example
40
+ * // In a child component's firstUpdated lifecycle
41
+ * protected firstUpdated() {
42
+ * const uniqueId = tearsheetSignal.get().uniqueId;
43
+ * registerFocusableContainers(this.shadowRoot, uniqueId);
44
+ * }
45
+ *
46
+ * @example
47
+ * // Without uniqueId (uses default key)
48
+ * registerFocusableContainers(this.shadowRoot);
49
+ */
50
+ const registerFocusableContainers = (container, uniqueId) => {
51
+ if (!container) return;
52
+ const id = uniqueId || DEFAULT_KEY;
53
+ if (!containers[id]) containers[id] = [];
54
+ if (!containers[id].includes(container)) containers[id].push(container);
26
55
  };
27
- const clearFocusableContainers = () => {
28
- _containers.length = 0;
56
+ /**
57
+ * UnRegisters a previously registered focusable container.
58
+ *
59
+ * This function should be called in the component's disconnectedCallback lifecycle method
60
+ * to clean up and prevent memory leaks when the component is removed from the DOM.
61
+ *
62
+ * @param container - The HTMLElement or ShadowRoot to unregister.
63
+ * If null, the function returns early without doing anything.
64
+ * @param uniqueId - Optional unique identifier that was used when registering the container.
65
+ * If not provided, uses the default key.
66
+ *
67
+ * @example
68
+ * // In a child component's disconnectedCallback
69
+ * disconnectedCallback() {
70
+ * super.disconnectedCallback();
71
+ * const uniqueId = tearsheetSignal.get().uniqueId;
72
+ * unregisterFocusableContainers(this.shadowRoot, uniqueId);
73
+ * }
74
+ *
75
+ * @example
76
+ * // Without uniqueId (uses default key)
77
+ * disconnectedCallback() {
78
+ * super.disconnectedCallback();
79
+ * unregisterFocusableContainers(this.shadowRoot);
80
+ * }
81
+ */
82
+ const unregisterFocusableContainers = (container, uniqueId) => {
83
+ if (!container) return;
84
+ const id = uniqueId || DEFAULT_KEY;
85
+ if (containers[id]) {
86
+ containers[id] = containers[id].filter((c) => c !== container);
87
+ if (containers[id].length === 0) delete containers[id];
88
+ }
29
89
  };
30
- const trapFocus = (containers) => {
90
+ /**
91
+ * Clears all registered focusable containers, either globally or for a specific uniqueId.
92
+ *
93
+ * This function is typically called when a parent component (like a tearsheet or modal) is closing
94
+ * or being removed from the DOM. It ensures all registered containers are cleaned up to prevent
95
+ * memory leaks.
96
+ *
97
+ * @param uniqueId - Optional unique identifier to clear containers for a specific component instance.
98
+ * If provided, only containers registered with this uniqueId are cleared.
99
+ * If not provided, ALL containers across all uniqueIds are cleared.
100
+ *
101
+ * @example
102
+ * // Clear containers for a specific tearsheet instance
103
+ * clearFocusableContainers(this.uniqueId);
104
+ *
105
+ * @example
106
+ * // Clear all containers (typically in disconnectedCallback)
107
+ * disconnectedCallback() {
108
+ * super.disconnectedCallback();
109
+ * this._trapFocusAPI?.cleanup();
110
+ * clearFocusableContainers();
111
+ * }
112
+ */
113
+ const clearFocusableContainers = (uniqueId) => {
114
+ if (uniqueId) delete containers[uniqueId];
115
+ else Object.keys(containers).forEach((key) => delete containers[key]);
116
+ };
117
+ /**
118
+ * Traps keyboard focus within registered focusable containers.
119
+ *
120
+ * This function creates a focus trap that prevents Tab/Shift+Tab navigation from leaving
121
+ * the registered containers. When the user reaches the last focusable element and presses Tab,
122
+ * focus wraps to the first element, and vice versa with Shift+Tab.
123
+ *
124
+ * The function works with Shadow DOM by querying focusable elements from all registered
125
+ * containers, which can include shadow roots from child components.
126
+ *
127
+ * @param wrapper - Optional wrapper element to attach the keydown listener to.
128
+ * If not provided, defaults to document for backward compatibility.
129
+ * Using a specific wrapper can improve performance and scope the listener.
130
+ * @param uniqueId - Optional unique identifier to scope the focus trap to specific containers.
131
+ * If provided, only containers registered with this uniqueId are included.
132
+ * If not provided, uses the default key for backward compatibility.
133
+ *
134
+ * @returns An object with a `cleanup` method that removes event listeners.
135
+ * Call this method when the component is closing or unmounting.
136
+ *
137
+ * @example
138
+ * // In a parent component when opening
139
+ * protected updated(changedProps) {
140
+ * if (changedProps.has('open') && this.open) {
141
+ * // Update signal so children can register
142
+ * updateTearsheetSignals({ uniqueId: this.uniqueId });
143
+ *
144
+ * // Wait for children to register, then trap focus
145
+ * requestAnimationFrame(() => {
146
+ * this._trapFocusAPI = trapFocus(this as HTMLElement, this.uniqueId);
147
+ * });
148
+ * }
149
+ * }
150
+ *
151
+ * @example
152
+ * // Without uniqueId (uses default key)
153
+ * this._trapFocusAPI = trapFocus();
154
+ *
155
+ * @example
156
+ * // Cleanup when closing
157
+ * disconnectedCallback() {
158
+ * this._trapFocusAPI?.cleanup();
159
+ * clearFocusableContainers(this.uniqueId);
160
+ * }
161
+ */
162
+ const trapFocus = (wrapper, uniqueId) => {
31
163
  const selectorTabbable$1 = selectorTabbable.replace(`${prefix}-button`, `${prefix}-button:not([disabled]), ${prefix}-selectable-tag`);
32
- if (containers && containers.length > 0) _containers = containers;
33
- if (!_containers.length) return { cleanup: () => {} };
164
+ const containerArray = containers[uniqueId || DEFAULT_KEY];
165
+ if (!containerArray || containerArray.length === 0) return { cleanup: () => {} };
166
+ const eventTarget = wrapper || document;
34
167
  /**
35
- * Given a container element, return the best candidate to focus.
36
- * - If element itself is tabbable, return it.
37
- * - Otherwise, find the first tabbable descendant.
168
+ * Determines the best focusable element within a given container.
169
+ *
170
+ * @param el - The element to check for ability to focus
171
+ * @returns The focusable element, or null if none found
172
+ *
173
+ * @internal
38
174
  */
39
175
  const getFocusTarget = (el) => {
40
176
  if (!el) return null;
@@ -42,21 +178,29 @@ const trapFocus = (containers) => {
42
178
  return el.querySelector("button, [tabindex]:not([tabindex=\"-1\"])") || el;
43
179
  };
44
180
  /**
45
-
46
- * Returns the "real" active element in the document, resolving through
47
- * Shadow DOM and slot boundaries when necessary.
181
+ * Returns the actual focused element, resolving through Shadow DOM and slot boundaries.
48
182
  *
49
- * In some cases `document.activeElement` may not reflect the actual
50
- * tabbable node that has focus:
51
- * - If focus is inside a shadow root, `document.activeElement` is the host,
52
- * not the element inside. This utility dives into the shadowRoot to find
53
- * the inner active element.
54
- * - If focus is on a `<slot>` element, this function resolves to the first
55
- * tabbable assigned element within the slot.
183
+ * In standard DOM, `document.activeElement` returns the focused element. However, with
184
+ * Shadow DOM and slots, this can be misleading:
185
+ * - If focus is inside a shadow root, `document.activeElement` returns the host element,
186
+ * not the actual focused element inside the shadow root.
187
+ * - If focus is on a `<slot>` element, we need to resolve to the assigned element.
188
+ *
189
+ * This function traverses shadow roots to find the true focused element, stopping at
190
+ * tabbable elements like buttons to avoid going too deep into component internals.
191
+ *
192
+ * @returns The actual focused element in the document
193
+ *
194
+ * @internal
56
195
  */
57
196
  const getRealActiveElement = () => {
58
197
  let activeElement = document.activeElement;
59
- if (activeElement && selectorTabbable$1.indexOf(activeElement.tagName.toLocaleLowerCase()) == -1 && activeElement?.shadowRoot?.activeElement) activeElement = activeElement.shadowRoot.activeElement;
198
+ while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement) {
199
+ const nextElement = activeElement.shadowRoot.activeElement;
200
+ const tagName = activeElement.tagName.toLowerCase();
201
+ if (selectorTabbable$1.indexOf(tagName) !== -1 || tagName.includes("-button") || activeElement.hasAttribute("tabindex")) break;
202
+ activeElement = nextElement;
203
+ }
60
204
  if (activeElement?.tagName === "SLOT") {
61
205
  let assigned;
62
206
  if (activeElement instanceof HTMLSlotElement) assigned = activeElement.assignedElements({ flatten: true });
@@ -66,11 +210,18 @@ const trapFocus = (containers) => {
66
210
  return activeElement;
67
211
  };
68
212
  requestAnimationFrame(() => {
69
- getFocusTarget(getAllFocusableElements(_containers)[0])?.focus({ preventScroll: true });
213
+ getFocusTarget(getAllFocusableElements(containerArray)[0])?.focus({ preventScroll: true });
70
214
  });
215
+ /**
216
+ * Handles Tab and Shift+Tab key presses to trap focus within containers.
217
+ *
218
+ * @param e - The keyboard event
219
+ *
220
+ * @internal
221
+ */
71
222
  function onKeyDown(e) {
72
223
  if (e.key !== "Tab") return;
73
- const elements = getAllFocusableElements(_containers);
224
+ const elements = getAllFocusableElements(containerArray);
74
225
  const first = elements[0];
75
226
  const last = elements[elements.length - 1];
76
227
  const active = getRealActiveElement();
@@ -85,16 +236,20 @@ const trapFocus = (containers) => {
85
236
  }
86
237
  }
87
238
  /**
88
- * Retrieves all focusable elements within the provided containers.
89
- **/
239
+ * Retrieves all focusable elements from all registered containers.
240
+ *
241
+ * @param containers - Array of containers to query for focusable elements
242
+ * @returns Array of all focusable elements found
243
+ *
244
+ * @internal
245
+ */
90
246
  const getAllFocusableElements = (containers) => containers.flatMap((container) => [...container.querySelectorAll(selectorTabbable$1)]).filter(Boolean);
91
- document.addEventListener("keydown", onKeyDown, true);
247
+ eventTarget.addEventListener("keydown", onKeyDown, true);
92
248
  return { cleanup: () => {
93
- document.removeEventListener("keydown", onKeyDown, true);
94
- _containers.length = 0;
249
+ eventTarget.removeEventListener("keydown", onKeyDown, true);
95
250
  } };
96
251
  };
97
252
  //#endregion
98
- export { clearFocusableContainers, registerFocusableContainers, trapFocus };
253
+ export { clearFocusableContainers, registerFocusableContainers, trapFocus, unregisterFocusableContainers };
99
254
 
100
255
  //# sourceMappingURL=manageFocusTrap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manageFocusTrap.js","names":["selectorTabbable","selectorTabbableCarbon","carbonPrefix"],"sources":["../../../src/utilities/manageFocusTrap/manageFocusTrap.ts"],"sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2025\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport {\n selectorTabbable as selectorTabbableCarbon,\n prefix as carbonPrefix,\n} from '@carbon/web-components/es/globals/settings';\n/**\n * Traps focus within a set of containers, ensuring it stays within focusable elements.\n * @param {NodeListOf<Element>} containers - The containers to trap focus within.\n * @returns {object} An object with a `cleanup` method to remove event listeners.\n */\nlet _containers: HTMLElement[] = [];\n\nexport const registerFocusableContainers = (container) => {\n if (container) {\n _containers.push(container);\n }\n};\nexport const clearFocusableContainers = () => {\n _containers.length = 0;\n};\nexport const trapFocus = (containers?: HTMLElement[]) => {\n const selectorTabbable = selectorTabbableCarbon.replace(\n `${carbonPrefix}-button`,\n `${carbonPrefix}-button:not([disabled]), ${carbonPrefix}-selectable-tag`\n );\n\n if (containers && containers.length > 0) {\n _containers = containers;\n }\n if (!_containers.length) {\n return { cleanup: () => {} };\n }\n\n /**\n * Given a container element, return the best candidate to focus.\n * - If element itself is tabbable, return it.\n * - Otherwise, find the first tabbable descendant.\n */\n const getFocusTarget = (el) => {\n if (!el) {\n return null;\n }\n if (el.tagName === 'BUTTON' || el.tabIndex >= 0) {\n return el;\n }\n const inner = el.querySelector('button, [tabindex]:not([tabindex=\"-1\"])');\n return inner || el;\n };\n\n /**\n\n * Returns the \"real\" active element in the document, resolving through\n * Shadow DOM and slot boundaries when necessary.\n *\n * In some cases `document.activeElement` may not reflect the actual\n * tabbable node that has focus:\n * - If focus is inside a shadow root, `document.activeElement` is the host,\n * not the element inside. This utility dives into the shadowRoot to find\n * the inner active element.\n * - If focus is on a `<slot>` element, this function resolves to the first\n * tabbable assigned element within the slot.\n */\n const getRealActiveElement = () => {\n let activeElement = document.activeElement;\n\n // If inside shadow DOM\n if (\n activeElement &&\n selectorTabbable.indexOf(activeElement.tagName.toLocaleLowerCase()) ==\n -1 &&\n activeElement?.shadowRoot?.activeElement\n ) {\n activeElement = activeElement.shadowRoot.activeElement;\n }\n\n // If active element is a slot\n if (activeElement?.tagName === 'SLOT') {\n let assigned: Element[] | undefined;\n\n if (activeElement instanceof HTMLSlotElement) {\n assigned = activeElement.assignedElements({ flatten: true });\n }\n const candidate = assigned?.find((node) =>\n node.matches('button, [tabindex]:not([tabindex=\"-1\"])')\n );\n if (candidate) {\n activeElement = candidate;\n }\n }\n\n return activeElement;\n };\n\n //Optionally focus first element immediately\n requestAnimationFrame(() => {\n const elements = getAllFocusableElements(_containers);\n getFocusTarget(elements[0])?.focus({ preventScroll: true });\n });\n\n function onKeyDown(e) {\n if (e.key !== 'Tab') {\n return;\n }\n\n // Flatten all focusable elements from all containers\n const elements = getAllFocusableElements(_containers);\n\n const first = elements[0];\n const last = elements[elements.length - 1];\n const active = getRealActiveElement();\n\n if (e.shiftKey) {\n // Shift+Tab wrap\n if (active === first || first.contains(active)) {\n e.preventDefault();\n getFocusTarget(last)?.focus();\n }\n } else {\n // Tab wrap\n if (active === last || last.contains(active)) {\n e.preventDefault();\n getFocusTarget(first)?.focus();\n }\n }\n }\n\n /**\n * Retrieves all focusable elements within the provided containers.\n **/\n const getAllFocusableElements = (containers) =>\n containers\n .flatMap((container) => [...container.querySelectorAll(selectorTabbable)])\n .filter(Boolean);\n\n document.addEventListener('keydown', onKeyDown, true);\n\n return {\n cleanup: () => {\n document.removeEventListener('keydown', onKeyDown, true);\n _containers.length = 0;\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAkBA,IAAI,cAA6B,EAAE;AAEnC,MAAa,+BAA+B,cAAc;AACxD,KAAI,UACF,aAAY,KAAK,UAAU;;AAG/B,MAAa,iCAAiC;AAC5C,aAAY,SAAS;;AAEvB,MAAa,aAAa,eAA+B;CACvD,MAAMA,qBAAmBC,iBAAuB,QAC9C,GAAGC,OAAa,UAChB,GAAGA,OAAa,2BAA2BA,OAAa,iBACzD;AAED,KAAI,cAAc,WAAW,SAAS,EACpC,eAAc;AAEhB,KAAI,CAAC,YAAY,OACf,QAAO,EAAE,eAAe,IAAI;;;;;;CAQ9B,MAAM,kBAAkB,OAAO;AAC7B,MAAI,CAAC,GACH,QAAO;AAET,MAAI,GAAG,YAAY,YAAY,GAAG,YAAY,EAC5C,QAAO;AAGT,SADc,GAAG,cAAc,4CACnB,IAAI;;;;;;;;;;;;;;;CAgBlB,MAAM,6BAA6B;EACjC,IAAI,gBAAgB,SAAS;AAG7B,MACE,iBACAF,mBAAiB,QAAQ,cAAc,QAAQ,mBAAmB,CAAC,IACjE,MACF,eAAe,YAAY,cAE3B,iBAAgB,cAAc,WAAW;AAI3C,MAAI,eAAe,YAAY,QAAQ;GACrC,IAAI;AAEJ,OAAI,yBAAyB,gBAC3B,YAAW,cAAc,iBAAiB,EAAE,SAAS,MAAM,CAAC;GAE9D,MAAM,YAAY,UAAU,MAAM,SAChC,KAAK,QAAQ,4CAA0C,CACxD;AACD,OAAI,UACF,iBAAgB;;AAIpB,SAAO;;AAIT,6BAA4B;AAE1B,iBADiB,wBAAwB,YAClB,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,MAAM,CAAC;GAC3D;CAEF,SAAS,UAAU,GAAG;AACpB,MAAI,EAAE,QAAQ,MACZ;EAIF,MAAM,WAAW,wBAAwB,YAAY;EAErD,MAAM,QAAQ,SAAS;EACvB,MAAM,OAAO,SAAS,SAAS,SAAS;EACxC,MAAM,SAAS,sBAAsB;AAErC,MAAI,EAAE;OAEA,WAAW,SAAS,MAAM,SAAS,OAAO,EAAE;AAC9C,MAAE,gBAAgB;AAClB,mBAAe,KAAK,EAAE,OAAO;;aAI3B,WAAW,QAAQ,KAAK,SAAS,OAAO,EAAE;AAC5C,KAAE,gBAAgB;AAClB,kBAAe,MAAM,EAAE,OAAO;;;;;;CAQpC,MAAM,2BAA2B,eAC/B,WACG,SAAS,cAAc,CAAC,GAAG,UAAU,iBAAiBA,mBAAiB,CAAC,CAAC,CACzE,OAAO,QAAQ;AAEpB,UAAS,iBAAiB,WAAW,WAAW,KAAK;AAErD,QAAO,EACL,eAAe;AACb,WAAS,oBAAoB,WAAW,WAAW,KAAK;AACxD,cAAY,SAAS;IAExB"}
1
+ {"version":3,"file":"manageFocusTrap.js","names":["selectorTabbable","selectorTabbableCarbon","carbonPrefix"],"sources":["../../../src/utilities/manageFocusTrap/manageFocusTrap.ts"],"sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2025\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport {\n selectorTabbable as selectorTabbableCarbon,\n prefix as carbonPrefix,\n} from '@carbon/web-components/es/globals/settings';\n\n/**\n * Simple object to store containers by uniqueId\n * { id: [container1, container2, ...] }\n */\nconst containers: Record<string, Array<HTMLElement | ShadowRoot>> = {};\n\n/**\n * Default key for backward compatibility when no uniqueId is provided\n */\nconst DEFAULT_KEY = '__default__';\n\n/**\n * Registers a focusable container to be included in the focus trap.\n *\n * This function allows child components to register their shadow roots or DOM elements\n * so that the focus trap utility can query focusable elements within them. This is necessary\n * because shadow DOM boundaries prevent direct querying from parent components.\n *\n * @param container - The HTMLElement or ShadowRoot to register as a focusable container.\n * If null, the function returns early without registering.\n * @param uniqueId - Optional unique identifier to scope containers to a specific component instance.\n * If not provided, uses a default key for backward compatibility.\n *\n * @example\n * // In a child component's firstUpdated lifecycle\n * protected firstUpdated() {\n * const uniqueId = tearsheetSignal.get().uniqueId;\n * registerFocusableContainers(this.shadowRoot, uniqueId);\n * }\n *\n * @example\n * // Without uniqueId (uses default key)\n * registerFocusableContainers(this.shadowRoot);\n */\nexport const registerFocusableContainers = (\n container: HTMLElement | ShadowRoot | null,\n uniqueId?: string\n) => {\n if (!container) {\n return;\n }\n\n const id = uniqueId || DEFAULT_KEY;\n\n // Initialize array if it doesn't exist\n if (!containers[id]) {\n containers[id] = [];\n }\n\n // Add container if not already present\n if (!containers[id].includes(container)) {\n containers[id].push(container);\n }\n};\n\n/**\n * UnRegisters a previously registered focusable container.\n *\n * This function should be called in the component's disconnectedCallback lifecycle method\n * to clean up and prevent memory leaks when the component is removed from the DOM.\n *\n * @param container - The HTMLElement or ShadowRoot to unregister.\n * If null, the function returns early without doing anything.\n * @param uniqueId - Optional unique identifier that was used when registering the container.\n * If not provided, uses the default key.\n *\n * @example\n * // In a child component's disconnectedCallback\n * disconnectedCallback() {\n * super.disconnectedCallback();\n * const uniqueId = tearsheetSignal.get().uniqueId;\n * unregisterFocusableContainers(this.shadowRoot, uniqueId);\n * }\n *\n * @example\n * // Without uniqueId (uses default key)\n * disconnectedCallback() {\n * super.disconnectedCallback();\n * unregisterFocusableContainers(this.shadowRoot);\n * }\n */\nexport const unregisterFocusableContainers = (\n container: HTMLElement | ShadowRoot | null,\n uniqueId?: string\n) => {\n if (!container) {\n return;\n }\n\n const id = uniqueId || DEFAULT_KEY;\n if (containers[id]) {\n containers[id] = containers[id].filter((c) => c !== container);\n if (containers[id].length === 0) {\n delete containers[id];\n }\n }\n};\n\n/**\n * Clears all registered focusable containers, either globally or for a specific uniqueId.\n *\n * This function is typically called when a parent component (like a tearsheet or modal) is closing\n * or being removed from the DOM. It ensures all registered containers are cleaned up to prevent\n * memory leaks.\n *\n * @param uniqueId - Optional unique identifier to clear containers for a specific component instance.\n * If provided, only containers registered with this uniqueId are cleared.\n * If not provided, ALL containers across all uniqueIds are cleared.\n *\n * @example\n * // Clear containers for a specific tearsheet instance\n * clearFocusableContainers(this.uniqueId);\n *\n * @example\n * // Clear all containers (typically in disconnectedCallback)\n * disconnectedCallback() {\n * super.disconnectedCallback();\n * this._trapFocusAPI?.cleanup();\n * clearFocusableContainers();\n * }\n */\nexport const clearFocusableContainers = (uniqueId?: string) => {\n if (uniqueId) {\n delete containers[uniqueId];\n } else {\n Object.keys(containers).forEach((key) => delete containers[key]);\n }\n};\n\n/**\n * Traps keyboard focus within registered focusable containers.\n *\n * This function creates a focus trap that prevents Tab/Shift+Tab navigation from leaving\n * the registered containers. When the user reaches the last focusable element and presses Tab,\n * focus wraps to the first element, and vice versa with Shift+Tab.\n *\n * The function works with Shadow DOM by querying focusable elements from all registered\n * containers, which can include shadow roots from child components.\n *\n * @param wrapper - Optional wrapper element to attach the keydown listener to.\n * If not provided, defaults to document for backward compatibility.\n * Using a specific wrapper can improve performance and scope the listener.\n * @param uniqueId - Optional unique identifier to scope the focus trap to specific containers.\n * If provided, only containers registered with this uniqueId are included.\n * If not provided, uses the default key for backward compatibility.\n *\n * @returns An object with a `cleanup` method that removes event listeners.\n * Call this method when the component is closing or unmounting.\n *\n * @example\n * // In a parent component when opening\n * protected updated(changedProps) {\n * if (changedProps.has('open') && this.open) {\n * // Update signal so children can register\n * updateTearsheetSignals({ uniqueId: this.uniqueId });\n *\n * // Wait for children to register, then trap focus\n * requestAnimationFrame(() => {\n * this._trapFocusAPI = trapFocus(this as HTMLElement, this.uniqueId);\n * });\n * }\n * }\n *\n * @example\n * // Without uniqueId (uses default key)\n * this._trapFocusAPI = trapFocus();\n *\n * @example\n * // Cleanup when closing\n * disconnectedCallback() {\n * this._trapFocusAPI?.cleanup();\n * clearFocusableContainers(this.uniqueId);\n * }\n */\nexport const trapFocus = (wrapper?: HTMLElement, uniqueId?: string) => {\n const selectorTabbable = selectorTabbableCarbon.replace(\n `${carbonPrefix}-button`,\n `${carbonPrefix}-button:not([disabled]), ${carbonPrefix}-selectable-tag`\n );\n\n // Get containers for this uniqueId (or default key for backward compatibility)\n const id = uniqueId || DEFAULT_KEY;\n\n const containerArray = containers[id];\n\n if (!containerArray || containerArray.length === 0) {\n return { cleanup: () => {} };\n }\n\n // Use wrapper if provided, otherwise default to document for backward compatibility\n const eventTarget = wrapper || document;\n\n /**\n * Determines the best focusable element within a given container.\n *\n * @param el - The element to check for ability to focus\n * @returns The focusable element, or null if none found\n *\n * @internal\n */\n const getFocusTarget = (el) => {\n if (!el) {\n return null;\n }\n if (el.tagName === 'BUTTON' || el.tabIndex >= 0) {\n return el;\n }\n const inner = el.querySelector('button, [tabindex]:not([tabindex=\"-1\"])');\n return inner || el;\n };\n\n /**\n * Returns the actual focused element, resolving through Shadow DOM and slot boundaries.\n *\n * In standard DOM, `document.activeElement` returns the focused element. However, with\n * Shadow DOM and slots, this can be misleading:\n * - If focus is inside a shadow root, `document.activeElement` returns the host element,\n * not the actual focused element inside the shadow root.\n * - If focus is on a `<slot>` element, we need to resolve to the assigned element.\n *\n * This function traverses shadow roots to find the true focused element, stopping at\n * tabbable elements like buttons to avoid going too deep into component internals.\n *\n * @returns The actual focused element in the document\n *\n * @internal\n */\n const getRealActiveElement = () => {\n let activeElement = document.activeElement;\n\n // Traverse through nested shadow DOMs, but stop at tabbable elements\n // This ensures we stop at cds-button level, not go deeper into its shadow root\n while (\n activeElement &&\n activeElement.shadowRoot &&\n activeElement.shadowRoot.activeElement\n ) {\n const nextElement = activeElement.shadowRoot.activeElement;\n\n // Check if current element is a tabbable element (like cds-button)\n // If so, stop here instead of going deeper\n const tagName = activeElement.tagName.toLowerCase();\n if (\n selectorTabbable.indexOf(tagName) !== -1 ||\n tagName.includes('-button') ||\n activeElement.hasAttribute('tabindex')\n ) {\n break;\n }\n\n activeElement = nextElement;\n }\n\n // If active element is a slot, resolve to the assigned element\n if (activeElement?.tagName === 'SLOT') {\n let assigned: Element[] | undefined;\n\n if (activeElement instanceof HTMLSlotElement) {\n assigned = activeElement.assignedElements({ flatten: true });\n }\n const candidate = assigned?.find((node) =>\n node.matches('button, [tabindex]:not([tabindex=\"-1\"])')\n );\n if (candidate) {\n activeElement = candidate;\n }\n }\n\n return activeElement;\n };\n\n //Optionally focus first element immediately\n requestAnimationFrame(() => {\n const elements = getAllFocusableElements(containerArray);\n getFocusTarget(elements[0])?.focus({ preventScroll: true });\n });\n\n /**\n * Handles Tab and Shift+Tab key presses to trap focus within containers.\n *\n * @param e - The keyboard event\n *\n * @internal\n */\n function onKeyDown(e) {\n if (e.key !== 'Tab') {\n return;\n }\n\n // Flatten all focusable elements from all containers\n const elements = getAllFocusableElements(containerArray);\n\n const first = elements[0];\n const last = elements[elements.length - 1];\n const active = getRealActiveElement();\n\n if (e.shiftKey) {\n // Shift+Tab wrap\n if (active === first || first.contains(active)) {\n e.preventDefault();\n getFocusTarget(last)?.focus();\n }\n } else {\n // Tab wrap\n if (active === last || last.contains(active)) {\n e.preventDefault();\n getFocusTarget(first)?.focus();\n }\n }\n }\n\n /**\n * Retrieves all focusable elements from all registered containers.\n *\n * @param containers - Array of containers to query for focusable elements\n * @returns Array of all focusable elements found\n *\n * @internal\n */\n const getAllFocusableElements = (containers) =>\n containers\n .flatMap((container) => [...container.querySelectorAll(selectorTabbable)])\n .filter(Boolean);\n\n eventTarget.addEventListener('keydown', onKeyDown, true);\n\n return {\n cleanup: () => {\n eventTarget.removeEventListener('keydown', onKeyDown, true);\n // Don't clear containers here - let components unregister themselves\n },\n };\n};\n"],"mappings":"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"}
@@ -7,8 +7,8 @@
7
7
 
8
8
  import "../../globals/settings.js";
9
9
  import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
10
- import { interstitialDetailsSignal, updateInterstitialDetailsSignal } from "./interstitial-screen-context.js";
11
10
  import { registerFocusableContainers } from "../../utilities/manageFocusTrap/manageFocusTrap.js";
11
+ import { interstitialDetailsSignal, updateInterstitialDetailsSignal } from "./interstitial-screen-context.js";
12
12
  import interstitial_screen_body_item_default$1 from "./interstitial-screen-body-item.scss.js";
13
13
  import { LitElement, html } from "lit";
14
14
  import { property } from "lit/decorators.js";
@@ -8,8 +8,8 @@
8
8
  import "../../globals/settings.js";
9
9
  import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
10
10
  import "../action-set/index.js";
11
- import { interstitialDetailsSignal } from "./interstitial-screen-context.js";
12
11
  import { registerFocusableContainers } from "../../utilities/manageFocusTrap/manageFocusTrap.js";
12
+ import { interstitialDetailsSignal } from "./interstitial-screen-context.js";
13
13
  import interstitial_screen_footer_default$1 from "./interstitial-screen-footer.scss.js";
14
14
  import { html, nothing } from "lit";
15
15
  import { property, state } from "lit/decorators.js";
@@ -7,8 +7,8 @@
7
7
 
8
8
  import "../../globals/settings.js";
9
9
  import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
10
- import { interstitialDetailsSignal } from "./interstitial-screen-context.js";
11
10
  import { registerFocusableContainers } from "../../utilities/manageFocusTrap/manageFocusTrap.js";
11
+ import { interstitialDetailsSignal } from "./interstitial-screen-context.js";
12
12
  import interstitial_screen_header_default$1 from "./interstitial-screen-header.scss.js";
13
13
  import { LitElement, html, nothing } from "lit";
14
14
  import { property } from "lit/decorators.js";
@@ -7,9 +7,9 @@
7
7
 
8
8
  import "../../globals/settings.js";
9
9
  import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
10
+ import { clearFocusableContainers, trapFocus } from "../../utilities/manageFocusTrap/manageFocusTrap.js";
10
11
  import interstitial_screen_default$1 from "./interstitial-screen.scss.js";
11
12
  import { interstitialDetailsSignal, resetInterstitialDetailsSignal, updateInterstitialDetailsSignal } from "./interstitial-screen-context.js";
12
- import { trapFocus } from "../../utilities/manageFocusTrap/manageFocusTrap.js";
13
13
  import { LitElement, html, nothing } from "lit";
14
14
  import { property, query, state } from "lit/decorators.js";
15
15
  import HostListenerMixin from "@carbon/web-components/es/globals/mixins/host-listener.js";
@@ -84,6 +84,7 @@ let CDSInterstitialScreen = class CDSInterstitialScreen extends SignalWatcher(Ho
84
84
  const { carouselAPI } = interstitialDetailsSignal.get();
85
85
  carouselAPI?.destroyEvents?.();
86
86
  this._trapFocusAPI?.cleanup();
87
+ clearFocusableContainers();
87
88
  }
88
89
  firstUpdated() {
89
90
  this.requestUpdate();
@@ -1 +1 @@
1
- {"version":3,"file":"interstitial-screen.js","names":["styles","customElement"],"sources":["../../../src/components/interstitial-screen/interstitial-screen.ts"],"sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2025\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { LitElement, html, nothing } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { carbonPrefix, prefix } from '../../globals/settings';\nimport '@carbon/web-components/es-custom/components/modal/index.js';\nimport HostListenerMixin from '@carbon/web-components/es/globals/mixins/host-listener.js';\nimport { carbonElement as customElement } from '@carbon/web-components/es/globals/decorators/carbon-element.js';\n\nimport styles from './interstitial-screen.scss?lit';\nimport { SignalWatcher } from '@lit-labs/signals';\nimport {\n interstitialDetailsSignal,\n resetInterstitialDetailsSignal,\n updateInterstitialDetailsSignal,\n} from './interstitial-screen-context';\nimport HostListener from '@carbon/web-components/es/globals/decorators/host-listener';\nimport { trapFocus } from '../../utilities/manageFocusTrap/manageFocusTrap';\n\nexport const blockClass = `${prefix}--interstitial-screen`;\n\nexport type disableButtonConfigType = {\n skip?: boolean;\n back?: boolean;\n next?: boolean;\n start?: boolean;\n};\n/**\n * interstitial-screen main component\n * @element c4p-interstitial-screen\n * @fires c4p-interstitial-opened - The custom event triggered after loading the component.\n * Its event.detail will provide you with carousal api methods for step navigation and method to disable any action button\n * * @fires c4p-interstitial-beingclosed - The name of the custom event fired before interstitial is being closed upon a user gesture.\n * Cancellation of this event stops the user-initiated action of closing the interstitial.\n * @fires c4p-interstitial-closed - The name of the custom event fired after this tearsheet is closed upon a user gesture.\n\n */\n\n@customElement(`${prefix}-interstitial-screen`)\nclass CDSInterstitialScreen extends SignalWatcher(\n HostListenerMixin(LitElement)\n) {\n /**\n * Specifies whether the component is shown as a full-screen\n * experience, else it is shown as a modal by default.\n */\n\n @property({ type: Boolean, reflect: true, attribute: 'fullscreen' })\n isFullScreen: boolean = false;\n /**\n * Specifies whether the component is currently open.\n */\n @property({ type: Boolean, reflect: true })\n open: boolean = false;\n\n @state()\n stepDetails: Array<{ stepTitle: string; name?: string }> = [];\n /**\n * @ignore\n */\n @query('cds-custom-modal-body') modalBody!: HTMLElement;\n\n private _wasOpen = false;\n private _trapFocusAPI: { cleanup: () => void } | null = null;\n\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener(`${prefix}-request-close`, this._handleClose);\n }\n disconnectedCallback(): void {\n const { carouselAPI } = interstitialDetailsSignal.get();\n carouselAPI?.destroyEvents?.();\n this._trapFocusAPI?.cleanup();\n }\n firstUpdated() {\n this.requestUpdate(); // Ensure re-render\n resetInterstitialDetailsSignal();\n\n updateInterstitialDetailsSignal({\n name: 'isFullScreen',\n detail: this.isFullScreen,\n });\n }\n\n updated(changedProps: Map<string | number | symbol, unknown>) {\n if (changedProps.has('open')) {\n const wasOpen = this._wasOpen;\n const isOpen = this.open;\n\n // Update the signal with the open state\n updateInterstitialDetailsSignal({\n name: 'open',\n detail: isOpen,\n });\n\n if (!wasOpen && isOpen) {\n this.dispatchInItializeEvent();\n // `focusableContainers` holds the containers where we can query DOM elements.\n // Our strategy here is to let child/slotted components register their containers,\n // which are then passed to `trapFocus`. This allows the utility to query elements\n // directly without being blocked by shadow DOM boundaries.\n\n this._trapFocusAPI = trapFocus();\n }\n\n this._wasOpen = isOpen;\n }\n }\n\n private dispatchInItializeEvent = () => {\n setTimeout(() => {\n const { carouselAPI } = interstitialDetailsSignal.get();\n this.dispatchEvent(\n new CustomEvent(\n (\n this.constructor as typeof CDSInterstitialScreen\n ).eventOnInterstitialOpened,\n {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail: {\n carouselAPI: carouselAPI\n ? {\n next: carouselAPI.next,\n prev: carouselAPI.prev,\n reset: carouselAPI.reset,\n gotToStep: carouselAPI.goToIndex,\n }\n : undefined,\n setDisableActionButtons: this.setDisableActionButtons,\n },\n }\n )\n );\n });\n };\n\n /**\n * Handles `click` event on this element.\n *\n * @param event The event.\n */\n @HostListener('click')\n // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to\n private _handleOutsideClick = (event: MouseEvent) => {\n const modal = this.shadowRoot?.querySelector(`${carbonPrefix}-modal`);\n const modalContent = modal?.shadowRoot?.querySelector(\n `.${carbonPrefix}--modal-container`\n );\n const path = event.composedPath();\n if (modalContent && !path.includes(modalContent)) {\n this._handleClose(event);\n }\n };\n\n private setDisableActionButtons = (config: disableButtonConfigType) => {\n updateInterstitialDetailsSignal({ name: 'disableActions', detail: config });\n };\n\n _handleClose(e) {\n this.open = false;\n e.stopPropagation();\n\n const init = {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail: {\n triggeredBy: e.detail.triggeredBy,\n },\n };\n if (\n this.dispatchEvent(\n new CustomEvent(\n (this.constructor as typeof CDSInterstitialScreen).eventBeforeClose,\n init\n )\n )\n ) {\n this.dispatchEvent(\n new CustomEvent(\n (this.constructor as typeof CDSInterstitialScreen).eventClose,\n init\n )\n );\n\n // Reset carousel and step after close event is dispatched\n const { carouselAPI } = interstitialDetailsSignal.get();\n if (carouselAPI) {\n carouselAPI.reset();\n }\n\n // Reset the current step to 0\n updateInterstitialDetailsSignal({\n name: 'currentStep',\n detail: 0,\n });\n }\n }\n\n //template methods\n\n renderFullScreen() {\n return html`\n <div class=\"${blockClass}--container\">\n <slot name=\"header\"></slot>\n <slot name=\"body\"></slot>\n <slot name=\"footer\"></slot>\n </div>\n `;\n }\n\n renderModal() {\n return html`<cds-custom-modal\n key=${this.open}\n ?prevent-close-on-click-outside=\"true\"\n class=${blockClass}\n size=\"lg\"\n ?open=\"${this.open}\"\n >\n <slot name=\"header\"></slot>\n <cds-custom-modal-body class=\"${blockClass}__body-container\">\n <slot name=\"body\"></slot>\n </cds-custom-modal-body>\n <cds-custom-modal-footer>\n <slot name=\"footer\"></slot>\n </cds-custom-modal-footer>\n </cds-custom-modal>`;\n }\n\n render() {\n return this.open\n ? this.isFullScreen\n ? html`${this.renderFullScreen()}`\n : html`${this.renderModal()}`\n : nothing;\n }\n\n static styles = styles;\n\n static get eventOnInterstitialOpened() {\n return `${prefix}-interstitial-opened`;\n }\n /**\n \n * The name of the custom event fired before interstitial is being closed upon a user gesture.\n * Cancellation of this event stops the user-initiated action of closing the interstitial.\n */\n static get eventBeforeClose() {\n return `${prefix}-interstitial-beingclosed`;\n }\n\n /**\n * The name of the custom event fired after this tearsheet is closed upon a user gesture.\n */\n static get eventClose() {\n return `${prefix}-interstitial-closed`;\n }\n}\n\nexport default CDSInterstitialScreen;\n"],"mappings":"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"}
1
+ {"version":3,"file":"interstitial-screen.js","names":["styles","customElement"],"sources":["../../../src/components/interstitial-screen/interstitial-screen.ts"],"sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2025\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { LitElement, html, nothing } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { carbonPrefix, prefix } from '../../globals/settings';\nimport '@carbon/web-components/es-custom/components/modal/index.js';\nimport HostListenerMixin from '@carbon/web-components/es/globals/mixins/host-listener.js';\nimport { carbonElement as customElement } from '@carbon/web-components/es/globals/decorators/carbon-element.js';\n\nimport styles from './interstitial-screen.scss?lit';\nimport { SignalWatcher } from '@lit-labs/signals';\nimport {\n interstitialDetailsSignal,\n resetInterstitialDetailsSignal,\n updateInterstitialDetailsSignal,\n} from './interstitial-screen-context';\nimport HostListener from '@carbon/web-components/es/globals/decorators/host-listener';\nimport {\n trapFocus,\n clearFocusableContainers,\n} from '../../utilities/manageFocusTrap/manageFocusTrap';\n\nexport const blockClass = `${prefix}--interstitial-screen`;\n\nexport type disableButtonConfigType = {\n skip?: boolean;\n back?: boolean;\n next?: boolean;\n start?: boolean;\n};\n/**\n * interstitial-screen main component\n * @element c4p-interstitial-screen\n * @fires c4p-interstitial-opened - The custom event triggered after loading the component.\n * Its event.detail will provide you with carousal api methods for step navigation and method to disable any action button\n * * @fires c4p-interstitial-beingclosed - The name of the custom event fired before interstitial is being closed upon a user gesture.\n * Cancellation of this event stops the user-initiated action of closing the interstitial.\n * @fires c4p-interstitial-closed - The name of the custom event fired after this tearsheet is closed upon a user gesture.\n\n */\n\n@customElement(`${prefix}-interstitial-screen`)\nclass CDSInterstitialScreen extends SignalWatcher(\n HostListenerMixin(LitElement)\n) {\n /**\n * Specifies whether the component is shown as a full-screen\n * experience, else it is shown as a modal by default.\n */\n\n @property({ type: Boolean, reflect: true, attribute: 'fullscreen' })\n isFullScreen: boolean = false;\n /**\n * Specifies whether the component is currently open.\n */\n @property({ type: Boolean, reflect: true })\n open: boolean = false;\n\n @state()\n stepDetails: Array<{ stepTitle: string; name?: string }> = [];\n /**\n * @ignore\n */\n @query('cds-custom-modal-body') modalBody!: HTMLElement;\n\n private _wasOpen = false;\n private _trapFocusAPI: { cleanup: () => void } | null = null;\n\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener(`${prefix}-request-close`, this._handleClose);\n }\n disconnectedCallback(): void {\n const { carouselAPI } = interstitialDetailsSignal.get();\n carouselAPI?.destroyEvents?.();\n this._trapFocusAPI?.cleanup();\n clearFocusableContainers();\n }\n firstUpdated() {\n this.requestUpdate(); // Ensure re-render\n resetInterstitialDetailsSignal();\n\n updateInterstitialDetailsSignal({\n name: 'isFullScreen',\n detail: this.isFullScreen,\n });\n }\n\n updated(changedProps: Map<string | number | symbol, unknown>) {\n if (changedProps.has('open')) {\n const wasOpen = this._wasOpen;\n const isOpen = this.open;\n\n // Update the signal with the open state\n updateInterstitialDetailsSignal({\n name: 'open',\n detail: isOpen,\n });\n\n if (!wasOpen && isOpen) {\n this.dispatchInItializeEvent();\n // `focusableContainers` holds the containers where we can query DOM elements.\n // Our strategy here is to let child/slotted components register their containers,\n // which are then passed to `trapFocus`. This allows the utility to query elements\n // directly without being blocked by shadow DOM boundaries.\n\n this._trapFocusAPI = trapFocus();\n }\n\n this._wasOpen = isOpen;\n }\n }\n\n private dispatchInItializeEvent = () => {\n setTimeout(() => {\n const { carouselAPI } = interstitialDetailsSignal.get();\n this.dispatchEvent(\n new CustomEvent(\n (\n this.constructor as typeof CDSInterstitialScreen\n ).eventOnInterstitialOpened,\n {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail: {\n carouselAPI: carouselAPI\n ? {\n next: carouselAPI.next,\n prev: carouselAPI.prev,\n reset: carouselAPI.reset,\n gotToStep: carouselAPI.goToIndex,\n }\n : undefined,\n setDisableActionButtons: this.setDisableActionButtons,\n },\n }\n )\n );\n });\n };\n\n /**\n * Handles `click` event on this element.\n *\n * @param event The event.\n */\n @HostListener('click')\n // @ts-ignore: The decorator refers to this method but TS thinks this method is not referred to\n private _handleOutsideClick = (event: MouseEvent) => {\n const modal = this.shadowRoot?.querySelector(`${carbonPrefix}-modal`);\n const modalContent = modal?.shadowRoot?.querySelector(\n `.${carbonPrefix}--modal-container`\n );\n const path = event.composedPath();\n if (modalContent && !path.includes(modalContent)) {\n this._handleClose(event);\n }\n };\n\n private setDisableActionButtons = (config: disableButtonConfigType) => {\n updateInterstitialDetailsSignal({ name: 'disableActions', detail: config });\n };\n\n _handleClose(e) {\n this.open = false;\n e.stopPropagation();\n\n const init = {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail: {\n triggeredBy: e.detail.triggeredBy,\n },\n };\n if (\n this.dispatchEvent(\n new CustomEvent(\n (this.constructor as typeof CDSInterstitialScreen).eventBeforeClose,\n init\n )\n )\n ) {\n this.dispatchEvent(\n new CustomEvent(\n (this.constructor as typeof CDSInterstitialScreen).eventClose,\n init\n )\n );\n\n // Reset carousel and step after close event is dispatched\n const { carouselAPI } = interstitialDetailsSignal.get();\n if (carouselAPI) {\n carouselAPI.reset();\n }\n\n // Reset the current step to 0\n updateInterstitialDetailsSignal({\n name: 'currentStep',\n detail: 0,\n });\n }\n }\n\n //template methods\n\n renderFullScreen() {\n return html`\n <div class=\"${blockClass}--container\">\n <slot name=\"header\"></slot>\n <slot name=\"body\"></slot>\n <slot name=\"footer\"></slot>\n </div>\n `;\n }\n\n renderModal() {\n return html`<cds-custom-modal\n key=${this.open}\n ?prevent-close-on-click-outside=\"true\"\n class=${blockClass}\n size=\"lg\"\n ?open=\"${this.open}\"\n >\n <slot name=\"header\"></slot>\n <cds-custom-modal-body class=\"${blockClass}__body-container\">\n <slot name=\"body\"></slot>\n </cds-custom-modal-body>\n <cds-custom-modal-footer>\n <slot name=\"footer\"></slot>\n </cds-custom-modal-footer>\n </cds-custom-modal>`;\n }\n\n render() {\n return this.open\n ? this.isFullScreen\n ? html`${this.renderFullScreen()}`\n : html`${this.renderModal()}`\n : nothing;\n }\n\n static styles = styles;\n\n static get eventOnInterstitialOpened() {\n return `${prefix}-interstitial-opened`;\n }\n /**\n \n * The name of the custom event fired before interstitial is being closed upon a user gesture.\n * Cancellation of this event stops the user-initiated action of closing the interstitial.\n */\n static get eventBeforeClose() {\n return `${prefix}-interstitial-beingclosed`;\n }\n\n /**\n * The name of the custom event fired after this tearsheet is closed upon a user gesture.\n */\n static get eventClose() {\n return `${prefix}-interstitial-closed`;\n }\n}\n\nexport default CDSInterstitialScreen;\n"],"mappings":"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"}
@@ -20,7 +20,8 @@ const pageHeaderContext = createContext({
20
20
  breadcrumbOffset: 0,
21
21
  fullyCollapsed: false,
22
22
  root: null,
23
- titleClipped: false
23
+ titleClipped: false,
24
+ disableStickyTabBar: false
24
25
  });
25
26
  //#endregion
26
27
  export { pageHeaderContext };
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../../../src/components/page-header/context.ts"],"sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2025, 2025\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { createContext } from '@lit/context';\n\nexport const pageHeaderContext = createContext({\n headerOffset: 0,\n breadcrumbOffset: 0,\n fullyCollapsed: false,\n root: null,\n titleClipped: false,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;AAWA,MAAa,oBAAoB,cAAc;CAC7C,cAAc;CACd,kBAAkB;CAClB,gBAAgB;CAChB,MAAM;CACN,cAAc;CACf,CAAC"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../../../src/components/page-header/context.ts"],"sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2025, 2025\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { createContext } from '@lit/context';\n\nexport const pageHeaderContext = createContext({\n headerOffset: 0,\n breadcrumbOffset: 0,\n fullyCollapsed: false,\n root: null,\n titleClipped: false,\n disableStickyTabBar: false,\n});\n"],"mappings":";;;;;;;;;;;;;;;;;AAWA,MAAa,oBAAoB,cAAc;CAC7C,cAAc;CACd,kBAAkB;CAClB,gBAAgB;CAChB,MAAM;CACN,cAAc;CACd,qBAAqB;CACtB,CAAC"}
@@ -11,7 +11,7 @@ import page_header_default from "./page-header.scss.js";
11
11
  import { pageHeaderContext } from "./context.js";
12
12
  import { classMap } from "lit/directives/class-map.js";
13
13
  import { LitElement, html } from "lit";
14
- import { property } from "lit/decorators.js";
14
+ import { property, state } from "lit/decorators.js";
15
15
  import { carbonElement } from "@carbon/web-components/es/globals/decorators/carbon-element.js";
16
16
  import { consume } from "@lit/context";
17
17
  //#region src/components/page-header/page-header-breadcrumb.ts
@@ -35,6 +35,18 @@ let CDSPageHeaderBreadcrumb = class CDSPageHeaderBreadcrumb extends LitElement {
35
35
  this.pageActionsFlush = false;
36
36
  this.contentActionsFlush = false;
37
37
  }
38
+ connectedCallback() {
39
+ super.connectedCallback();
40
+ this.updateFixedClass();
41
+ }
42
+ updated(changedProperties) {
43
+ super.updated(changedProperties);
44
+ if (changedProperties.has("context")) this.updateFixedClass();
45
+ }
46
+ updateFixedClass() {
47
+ if (this.context?.disableStickyTabBar) this.classList.add(`c4p--page-header-breadcrumb--fixed`);
48
+ else this.classList.remove(`c4p--page-header-breadcrumb--fixed`);
49
+ }
38
50
  render() {
39
51
  const { withinGrid, context } = this;
40
52
  const { contentActionsClipped } = context ?? {};
@@ -69,7 +81,10 @@ let CDSPageHeaderBreadcrumb = class CDSPageHeaderBreadcrumb extends LitElement {
69
81
  this.styles = page_header_default;
70
82
  }
71
83
  };
72
- __decorate([property({ reflect: true })], CDSPageHeaderBreadcrumb.prototype, "border", void 0);
84
+ __decorate([property({
85
+ reflect: true,
86
+ type: Boolean
87
+ })], CDSPageHeaderBreadcrumb.prototype, "border", void 0);
73
88
  __decorate([property({
74
89
  attribute: "within-grid",
75
90
  type: Boolean
@@ -85,7 +100,7 @@ __decorate([property({
85
100
  __decorate([consume({
86
101
  context: pageHeaderContext,
87
102
  subscribe: true
88
- })], CDSPageHeaderBreadcrumb.prototype, "context", void 0);
103
+ }), state()], CDSPageHeaderBreadcrumb.prototype, "context", void 0);
89
104
  CDSPageHeaderBreadcrumb = __decorate([carbonElement(`c4p-page-header-breadcrumb`)], CDSPageHeaderBreadcrumb);
90
105
  var page_header_breadcrumb_default = CDSPageHeaderBreadcrumb;
91
106
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"page-header-breadcrumb.js","names":["styles","customElement"],"sources":["../../../src/components/page-header/page-header-breadcrumb.ts"],"sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2025, 2025\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { LitElement, html } from 'lit';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { prefix, carbonPrefix } from '../../globals/settings';\nimport { property } from 'lit/decorators.js';\nimport styles from './page-header.scss?lit';\nimport { consume } from '@lit/context';\nimport { pageHeaderContext } from './context';\nimport { carbonElement as customElement } from '@carbon/web-components/es/globals/decorators/carbon-element.js';\n\n/**\n * Page header Breadcrumb Bar.\n * @element c4p-page-header-breadcrumb\n */\n@customElement(`${prefix}-page-header-breadcrumb`)\nclass CDSPageHeaderBreadcrumb extends LitElement {\n /**\n * Specify if breadcrumb bar has bottom border.\n */\n @property({ reflect: true })\n border = true;\n\n /**\n * Set to `true` if the breadcrumb bar is sitting within a grid\n * (ie. when used in tandem with page-header-hero-image)\n */\n @property({ attribute: 'within-grid', type: Boolean })\n withinGrid = false;\n\n /**\n * Set to `true` if page actions should be flush (no padding)\n */\n @property({ attribute: 'page-actions-flush', type: Boolean })\n pageActionsFlush = false;\n\n /**\n * Set to `true` if content actions should be flush (no padding)\n */\n @property({ attribute: 'content-actions-flush', type: Boolean })\n contentActionsFlush = false;\n\n @consume({ context: pageHeaderContext, subscribe: true })\n context;\n\n render() {\n const { withinGrid, context } = this;\n const { contentActionsClipped } = context ?? {};\n const gridClasses = classMap({\n [`${carbonPrefix}--css-grid`]: !withinGrid,\n [`${carbonPrefix}--subgrid ${carbonPrefix}--subgrid--wide`]: withinGrid,\n });\n\n const contentActionClasses = classMap({\n [`${prefix}--page-header__breadcrumb__content-actions-with-global-actions`]:\n true,\n [`${prefix}--page-header__breadcrumb__content-actions-with-global-actions--show`]:\n contentActionsClipped,\n });\n\n return html`\n <div class=\"${gridClasses}\">\n <div\n class=\"${carbonPrefix}--sm:col-span-4 ${carbonPrefix}--md:col-span-8 ${carbonPrefix}--lg:col-span-16 ${carbonPrefix}--css-grid-column\"\n >\n <div class=\"${prefix}--page-header__breadcrumb-container\">\n <div class=\"${prefix}--page-header__breadcrumb-wrapper\">\n <slot name=\"icon\"></slot>\n <slot></slot>\n </div>\n <div class=\"${prefix}--page-header__breadcrumb__actions\">\n <div class=\"${contentActionClasses}\">\n <slot name=\"content-actions\"></slot>\n </div>\n <slot name=\"page-actions\"></slot>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n\n static styles = styles;\n}\n\nexport default CDSPageHeaderBreadcrumb;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAA,0BAAA,MACM,gCAAgC,WAAW;;;gBAKtC;oBAOI;0BAMM;6BAMG;;CAKtB,SAAS;EACP,MAAM,EAAE,YAAY,YAAY;EAChC,MAAM,EAAE,0BAA0B,WAAW,EAAE;AAa/C,SAAO,IAAI;oBAZS,SAAS;IAC1B,kBAA8B,CAAC;IAC/B,oCAA4D;GAC9D,CAU0B,CAAC;;yBAEA,kBAAA,MAA+B,kBAAA,MAA+B,mBAAA,MAAgC;;8BAE/F;gCACE;;;;gCAIA;4BAjBA,SAAS;IACnC,sEACC;IACD,4EACC;GACH,CAa2C,CAAC;;;;;;;;;;;gBAW/BA;;;YA9Df,SAAS,EAAE,SAAS,MAAM,CAAC,CAAA,EAAA,wBAAA,WAAA,UAAA,KAAA,EAAA;YAO3B,SAAS;CAAE,WAAW;CAAe,MAAM;CAAS,CAAC,CAAA,EAAA,wBAAA,WAAA,cAAA,KAAA,EAAA;YAMrD,SAAS;CAAE,WAAW;CAAsB,MAAM;CAAS,CAAC,CAAA,EAAA,wBAAA,WAAA,oBAAA,KAAA,EAAA;YAM5D,SAAS;CAAE,WAAW;CAAyB,MAAM;CAAS,CAAC,CAAA,EAAA,wBAAA,WAAA,uBAAA,KAAA,EAAA;YAG/D,QAAQ;CAAE,SAAS;CAAmB,WAAW;CAAM,CAAC,CAAA,EAAA,wBAAA,WAAA,WAAA,KAAA,EAAA;sCA3B1DC,cAAc,6BAAmC,CAAA,EAAA,wBAAA;AAsElD,IAAA,iCAAe"}
1
+ {"version":3,"file":"page-header-breadcrumb.js","names":["styles","customElement"],"sources":["../../../src/components/page-header/page-header-breadcrumb.ts"],"sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2025, 2025\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { LitElement, html } from 'lit';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { prefix, carbonPrefix } from '../../globals/settings';\nimport { property, state } from 'lit/decorators.js';\nimport styles from './page-header.scss?lit';\nimport { consume } from '@lit/context';\nimport { pageHeaderContext } from './context';\nimport { carbonElement as customElement } from '@carbon/web-components/es/globals/decorators/carbon-element.js';\n\n/**\n * Page header Breadcrumb Bar.\n * @element c4p-page-header-breadcrumb\n */\n@customElement(`${prefix}-page-header-breadcrumb`)\nclass CDSPageHeaderBreadcrumb extends LitElement {\n /**\n * Specify if breadcrumb bar has bottom border.\n */\n @property({ reflect: true, type: Boolean })\n border = true;\n\n /**\n * Set to `true` if the breadcrumb bar is sitting within a grid\n * (ie. when used in tandem with page-header-hero-image)\n */\n @property({ attribute: 'within-grid', type: Boolean })\n withinGrid = false;\n\n /**\n * Set to `true` if page actions should be flush (no padding)\n */\n @property({ attribute: 'page-actions-flush', type: Boolean })\n pageActionsFlush = false;\n\n /**\n * Set to `true` if content actions should be flush (no padding)\n */\n @property({ attribute: 'content-actions-flush', type: Boolean })\n contentActionsFlush = false;\n\n @consume({ context: pageHeaderContext, subscribe: true })\n @state()\n context;\n\n connectedCallback() {\n super.connectedCallback();\n // Apply class on initial connection\n this.updateFixedClass();\n }\n\n updated(changedProperties: Map<string, any>) {\n super.updated(changedProperties);\n if (changedProperties.has('context')) {\n this.updateFixedClass();\n }\n }\n\n private updateFixedClass() {\n if (this.context?.disableStickyTabBar) {\n this.classList.add(`${prefix}--page-header-breadcrumb--fixed`);\n } else {\n this.classList.remove(`${prefix}--page-header-breadcrumb--fixed`);\n }\n }\n\n render() {\n const { withinGrid, context } = this;\n const { contentActionsClipped } = context ?? {};\n const gridClasses = classMap({\n [`${carbonPrefix}--css-grid`]: !withinGrid,\n [`${carbonPrefix}--subgrid ${carbonPrefix}--subgrid--wide`]: withinGrid,\n });\n\n const contentActionClasses = classMap({\n [`${prefix}--page-header__breadcrumb__content-actions-with-global-actions`]:\n true,\n [`${prefix}--page-header__breadcrumb__content-actions-with-global-actions--show`]:\n contentActionsClipped,\n });\n\n return html`\n <div class=\"${gridClasses}\">\n <div\n class=\"${carbonPrefix}--sm:col-span-4 ${carbonPrefix}--md:col-span-8 ${carbonPrefix}--lg:col-span-16 ${carbonPrefix}--css-grid-column\"\n >\n <div class=\"${prefix}--page-header__breadcrumb-container\">\n <div class=\"${prefix}--page-header__breadcrumb-wrapper\">\n <slot name=\"icon\"></slot>\n <slot></slot>\n </div>\n <div class=\"${prefix}--page-header__breadcrumb__actions\">\n <div class=\"${contentActionClasses}\">\n <slot name=\"content-actions\"></slot>\n </div>\n <slot name=\"page-actions\"></slot>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n\n static styles = styles;\n}\n\nexport default CDSPageHeaderBreadcrumb;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAA,0BAAA,MACM,gCAAgC,WAAW;;;gBAKtC;oBAOI;0BAMM;6BAMG;;CAMtB,oBAAoB;AAClB,QAAM,mBAAmB;AAEzB,OAAK,kBAAkB;;CAGzB,QAAQ,mBAAqC;AAC3C,QAAM,QAAQ,kBAAkB;AAChC,MAAI,kBAAkB,IAAI,UAAU,CAClC,MAAK,kBAAkB;;CAI3B,mBAA2B;AACzB,MAAI,KAAK,SAAS,oBAChB,MAAK,UAAU,IAAI,qCAA2C;MAE9D,MAAK,UAAU,OAAO,qCAA2C;;CAIrE,SAAS;EACP,MAAM,EAAE,YAAY,YAAY;EAChC,MAAM,EAAE,0BAA0B,WAAW,EAAE;AAa/C,SAAO,IAAI;oBAZS,SAAS;IAC1B,kBAA8B,CAAC;IAC/B,oCAA4D;GAC9D,CAU0B,CAAC;;yBAEA,kBAAA,MAA+B,kBAAA,MAA+B,mBAAA,MAAgC;;8BAE/F;gCACE;;;;gCAIA;4BAjBA,SAAS;IACnC,sEACC;IACD,4EACC;GACH,CAa2C,CAAC;;;;;;;;;;;gBAW/BA;;;YApFf,SAAS;CAAE,SAAS;CAAM,MAAM;CAAS,CAAC,CAAA,EAAA,wBAAA,WAAA,UAAA,KAAA,EAAA;YAO1C,SAAS;CAAE,WAAW;CAAe,MAAM;CAAS,CAAC,CAAA,EAAA,wBAAA,WAAA,cAAA,KAAA,EAAA;YAMrD,SAAS;CAAE,WAAW;CAAsB,MAAM;CAAS,CAAC,CAAA,EAAA,wBAAA,WAAA,oBAAA,KAAA,EAAA;YAM5D,SAAS;CAAE,WAAW;CAAyB,MAAM;CAAS,CAAC,CAAA,EAAA,wBAAA,WAAA,uBAAA,KAAA,EAAA;YAG/D,QAAQ;CAAE,SAAS;CAAmB,WAAW;CAAM,CAAC,EACxD,OAAO,CAAA,EAAA,wBAAA,WAAA,WAAA,KAAA,EAAA;sCA5BTC,cAAc,6BAAmC,CAAA,EAAA,wBAAA;AA4FlD,IAAA,iCAAe"}
@@ -9,6 +9,7 @@ import "../../globals/settings.js";
9
9
  import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
10
10
  import page_header_default from "./page-header.scss.js";
11
11
  import { LitElement, html } from "lit";
12
+ import { property } from "lit/decorators.js";
12
13
  import { carbonElement } from "@carbon/web-components/es/globals/decorators/carbon-element.js";
13
14
  //#region src/components/page-header/page-header-tabs.ts
14
15
  /**
@@ -24,6 +25,28 @@ import { carbonElement } from "@carbon/web-components/es/globals/decorators/carb
24
25
  * @element c4p-page-header-tabs
25
26
  */
26
27
  let CDSPageHeaderTabs = class CDSPageHeaderTabs extends LitElement {
28
+ constructor(..._args) {
29
+ super(..._args);
30
+ this.disableStickyTabBar = false;
31
+ }
32
+ connectedCallback() {
33
+ super.connectedCallback();
34
+ this.updateContext();
35
+ }
36
+ updated(changedProperties) {
37
+ super.updated(changedProperties);
38
+ if (changedProperties.has("disableStickyTabBar")) this.updateContext();
39
+ }
40
+ updateContext() {
41
+ const pageHeader = this.closest(`c4p-page-header`);
42
+ if (pageHeader) {
43
+ pageHeader.context = {
44
+ ...pageHeader.context,
45
+ disableStickyTabBar: this.disableStickyTabBar
46
+ };
47
+ pageHeader.requestUpdate("context");
48
+ }
49
+ }
27
50
  render() {
28
51
  return html` <div class="${"cds-custom"}--css-grid" condensed="">
29
52
  <div
@@ -41,6 +64,10 @@ let CDSPageHeaderTabs = class CDSPageHeaderTabs extends LitElement {
41
64
  this.styles = page_header_default;
42
65
  }
43
66
  };
67
+ __decorate([property({
68
+ type: Boolean,
69
+ attribute: "disable-sticky-tab-bar"
70
+ })], CDSPageHeaderTabs.prototype, "disableStickyTabBar", void 0);
44
71
  CDSPageHeaderTabs = __decorate([carbonElement(`c4p-page-header-tabs`)], CDSPageHeaderTabs);
45
72
  var page_header_tabs_default = CDSPageHeaderTabs;
46
73
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"page-header-tabs.js","names":["styles","customElement"],"sources":["../../../src/components/page-header/page-header-tabs.ts"],"sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2025, 2025\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { LitElement, html } from 'lit';\nimport { prefix, carbonPrefix } from '../../globals/settings';\nimport styles from './page-header.scss?lit';\nimport { carbonElement as customElement } from '@carbon/web-components/es/globals/decorators/carbon-element.js';\n\n/**\n * Page header Tabs Bar.\n * @element c4p-page-header-tabs\n */\n@customElement(`${prefix}-page-header-tabs`)\nclass CDSPageHeaderTabs extends LitElement {\n render() {\n return html` <div class=\"${carbonPrefix}--css-grid\" condensed=\"\">\n <div\n class=\"${carbonPrefix}--sm:col-span-4 ${carbonPrefix}--md:col-span-8 ${carbonPrefix}--lg:col-span-16 ${carbonPrefix}--css-grid-column\"\n >\n <div class=\"${prefix}--page-header__tab-bar--tablist\">\n <slot></slot>\n <slot name=\"tags\"></slot>\n </div>\n </div>\n <slot name=\"scroller\"></slot>\n </div>`;\n }\n\n static styles = styles;\n}\n\nexport default CDSPageHeaderTabs;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAkBA,IAAA,oBAAA,MACM,0BAA0B,WAAW;CACzC,SAAS;AACP,SAAO,IAAI,gBAAA,MAA6B;;uBAEd,kBAAA,MAA+B,kBAAA,MAA+B,mBAAA,MAAgC;;4BAE/F;;;;;;;;;gBASXA;;;gCAhBjBC,cAAc,uBAA6B,CAAA,EAAA,kBAAA;AAmB5C,IAAA,2BAAe"}
1
+ {"version":3,"file":"page-header-tabs.js","names":["styles","customElement"],"sources":["../../../src/components/page-header/page-header-tabs.ts"],"sourcesContent":["/**\n * @license\n *\n * Copyright IBM Corp. 2025, 2025\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport { LitElement, html } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { prefix, carbonPrefix } from '../../globals/settings';\nimport styles from './page-header.scss?lit';\nimport { carbonElement as customElement } from '@carbon/web-components/es/globals/decorators/carbon-element.js';\nimport CDSPageHeader from './page-header';\n\n/**\n * Page header Tabs Bar.\n * @element c4p-page-header-tabs\n */\n@customElement(`${prefix}-page-header-tabs`)\nclass CDSPageHeaderTabs extends LitElement {\n /**\n * Disable sticky positioning for the tab bar\n */\n @property({ type: Boolean, attribute: 'disable-sticky-tab-bar' })\n disableStickyTabBar = false;\n\n connectedCallback() {\n super.connectedCallback();\n this.updateContext();\n }\n\n updated(changedProperties: Map<string, any>) {\n super.updated(changedProperties);\n if (changedProperties.has('disableStickyTabBar')) {\n this.updateContext();\n }\n }\n\n private updateContext() {\n const pageHeader = this.closest(`${prefix}-page-header`) as CDSPageHeader;\n if (pageHeader) {\n // Create a new object to trigger reactivity\n pageHeader.context = {\n ...pageHeader.context,\n disableStickyTabBar: this.disableStickyTabBar,\n };\n // Force update\n pageHeader.requestUpdate('context');\n }\n }\n\n render() {\n return html` <div class=\"${carbonPrefix}--css-grid\" condensed=\"\">\n <div\n class=\"${carbonPrefix}--sm:col-span-4 ${carbonPrefix}--md:col-span-8 ${carbonPrefix}--lg:col-span-16 ${carbonPrefix}--css-grid-column\"\n >\n <div class=\"${prefix}--page-header__tab-bar--tablist\">\n <slot></slot>\n <slot name=\"tags\"></slot>\n </div>\n </div>\n <slot name=\"scroller\"></slot>\n </div>`;\n }\n\n static styles = styles;\n}\n\nexport default CDSPageHeaderTabs;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAoBA,IAAA,oBAAA,MACM,0BAA0B,WAAW;;;6BAKnB;;CAEtB,oBAAoB;AAClB,QAAM,mBAAmB;AACzB,OAAK,eAAe;;CAGtB,QAAQ,mBAAqC;AAC3C,QAAM,QAAQ,kBAAkB;AAChC,MAAI,kBAAkB,IAAI,sBAAsB,CAC9C,MAAK,eAAe;;CAIxB,gBAAwB;EACtB,MAAM,aAAa,KAAK,QAAQ,kBAAwB;AACxD,MAAI,YAAY;AAEd,cAAW,UAAU;IACnB,GAAG,WAAW;IACd,qBAAqB,KAAK;IAC3B;AAED,cAAW,cAAc,UAAU;;;CAIvC,SAAS;AACP,SAAO,IAAI,gBAAA,MAA6B;;uBAEd,kBAAA,MAA+B,kBAAA,MAA+B,mBAAA,MAAgC;;4BAE/F;;;;;;;;;gBASXA;;;YA1Cf,SAAS;CAAE,MAAM;CAAS,WAAW;CAA0B,CAAC,CAAA,EAAA,kBAAA,WAAA,uBAAA,KAAA,EAAA;gCALlEC,cAAc,uBAA6B,CAAA,EAAA,kBAAA;AAkD5C,IAAA,2BAAe"}
@@ -33,6 +33,11 @@ let CDSPageHeader = class CDSPageHeader extends LitElement {
33
33
  super(..._args);
34
34
  this.context = {};
35
35
  }
36
+ updated(changedProperties) {
37
+ super.updated(changedProperties);
38
+ if (changedProperties.has("context")) if (this.context.disableStickyTabBar) this.classList.add(`c4p--page-header--disable-sticky-tab-bar`);
39
+ else this.classList.remove(`c4p--page-header--disable-sticky-tab-bar`);
40
+ }
36
41
  connectedCallback() {
37
42
  super.connectedCallback();
38
43
  const contentElement = this.querySelector(`c4p-page-header-content`);