@pine-ds/core 3.15.3 → 3.16.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 (51) hide show
  1. package/components/pds-dropdown-menu.js +70 -27
  2. package/components/pds-dropdown-menu.js.map +1 -1
  3. package/components/pds-table.js +5 -2
  4. package/components/pds-table.js.map +1 -1
  5. package/dist/cjs/pds-dropdown-menu.cjs.entry.js +70 -27
  6. package/dist/cjs/pds-dropdown-menu.entry.cjs.js.map +1 -1
  7. package/dist/cjs/pds-table.cjs.entry.js +5 -2
  8. package/dist/cjs/pds-table.entry.cjs.js.map +1 -1
  9. package/dist/collection/components/pds-dropdown-menu/pds-dropdown-menu.css +32 -0
  10. package/dist/collection/components/pds-dropdown-menu/pds-dropdown-menu.js +69 -26
  11. package/dist/collection/components/pds-dropdown-menu/pds-dropdown-menu.js.map +1 -1
  12. package/dist/collection/components/pds-table/pds-table.js +5 -2
  13. package/dist/collection/components/pds-table/pds-table.js.map +1 -1
  14. package/dist/docs.json +1 -1
  15. package/dist/esm/pds-dropdown-menu.entry.js +70 -27
  16. package/dist/esm/pds-dropdown-menu.entry.js.map +1 -1
  17. package/dist/esm/pds-table.entry.js +5 -2
  18. package/dist/esm/pds-table.entry.js.map +1 -1
  19. package/dist/esm-es5/pds-dropdown-menu.entry.js +1 -1
  20. package/dist/esm-es5/pds-dropdown-menu.entry.js.map +1 -1
  21. package/dist/esm-es5/pds-table.entry.js +1 -1
  22. package/dist/esm-es5/pds-table.entry.js.map +1 -1
  23. package/dist/pine-core/p-23aba538.entry.js +2 -0
  24. package/dist/pine-core/p-23aba538.entry.js.map +1 -0
  25. package/dist/pine-core/p-3c026ec7.system.entry.js +2 -0
  26. package/dist/pine-core/p-3c026ec7.system.entry.js.map +1 -0
  27. package/dist/pine-core/p-8b4f76e4.system.entry.js +2 -0
  28. package/dist/pine-core/p-8b4f76e4.system.entry.js.map +1 -0
  29. package/dist/pine-core/p-C7XKS9nY.system.js.map +1 -0
  30. package/dist/pine-core/p-DZEhYV6y.system.js.map +1 -0
  31. package/dist/pine-core/p-JAVnELnm.system.js +1 -1
  32. package/dist/pine-core/p-d456c898.entry.js +2 -0
  33. package/dist/pine-core/p-d456c898.entry.js.map +1 -0
  34. package/dist/pine-core/pds-dropdown-menu.entry.esm.js.map +1 -1
  35. package/dist/pine-core/pds-table.entry.esm.js.map +1 -1
  36. package/dist/pine-core/pine-core.esm.js +1 -1
  37. package/dist/types/components/pds-dropdown-menu/pds-dropdown-menu.d.ts +1 -0
  38. package/dist/vscode.html-data.json +1 -1
  39. package/hydrate/index.js +76 -30
  40. package/hydrate/index.mjs +76 -30
  41. package/package.json +2 -2
  42. package/dist/pine-core/p-9660a2c2.entry.js +0 -2
  43. package/dist/pine-core/p-9660a2c2.entry.js.map +0 -1
  44. package/dist/pine-core/p-9c0ec80a.entry.js +0 -2
  45. package/dist/pine-core/p-9c0ec80a.entry.js.map +0 -1
  46. package/dist/pine-core/p-CCgKUhC7.system.js.map +0 -1
  47. package/dist/pine-core/p-d98310b9.system.entry.js +0 -2
  48. package/dist/pine-core/p-d98310b9.system.entry.js.map +0 -1
  49. package/dist/pine-core/p-f00f70bf.system.entry.js +0 -2
  50. package/dist/pine-core/p-f00f70bf.system.entry.js.map +0 -1
  51. package/dist/pine-core/p-g2zH2UyI.system.js.map +0 -1
@@ -2,7 +2,7 @@ import { proxyCustomElement, HTMLElement, h, Host } from '@stencil/core/internal
2
2
  import { a as autoUpdate, c as computePosition, o as offset, f as flip, s as shift } from './floating-ui.dom.js';
3
3
  import { d as defineCustomElement$2 } from './pds-box2.js';
4
4
 
5
- const pdsDropdownMenuCss = ":host{display:block}.is-hidden{display:none}.pds-dropdown-menu--panel{background-color:var(--pine-color-background-container);border-radius:var(--pine-dimension-xs);left:var(--pine-dimension-none);min-width:170px;padding:var(--pine-dimension-xs);position:fixed;z-index:var(--pine-z-index-overlay)}:host-context([data-theme=dark]) .pds-dropdown-menu--panel{border:var(--pine-border)}";
5
+ const pdsDropdownMenuCss = ":host{display:block}.is-hidden{display:none}.pds-dropdown-menu--panel{background-color:var(--pine-color-background-container);border-radius:var(--pine-dimension-xs);left:var(--pine-dimension-none);min-width:170px;padding:var(--pine-dimension-xs);position:fixed;z-index:var(--pine-z-index-overlay)}:host-context([data-theme=dark]) .pds-dropdown-menu--panel{border:var(--pine-border)}::slotted(a),::slotted(button){-ms-flex-align:center;align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;border-radius:var(--pine-dimension-xs);-webkit-box-sizing:border-box;box-sizing:border-box;color:var(--pine-color-text) !important;cursor:pointer;display:-ms-flexbox;display:flex;-ms-flex-positive:1;flex-grow:1;font:var(--pine-typography-body-medium);gap:var(--pine-dimension-xs);margin:calc(var(--pine-border-width) + 2px);padding:var(--pine-dimension-xs);text-align:start;text-decoration:none !important;width:calc(100% - (var(--pine-border-width) + 2px) * 2)}::slotted(.destructive){color:var(--pine-color-danger) !important}::slotted([aria-disabled=true]),::slotted([disabled]){cursor:not-allowed;opacity:0.5;pointer-events:none}";
6
6
 
7
7
  const PdsDropdownMenu$1 = /*@__PURE__*/ proxyCustomElement(class PdsDropdownMenu extends HTMLElement {
8
8
  constructor(registerHost) {
@@ -33,14 +33,22 @@ const PdsDropdownMenu$1 = /*@__PURE__*/ proxyCustomElement(class PdsDropdownMenu
33
33
  this.slotEl = event.target;
34
34
  // Get all elements assigned to this slot
35
35
  const assignedElements = this.slotEl.assignedElements();
36
- // ensure assignedElements only contains pds-dropdown-menu-item or pds-dropdown-menu-separator
37
- // if there are other elements, throw an error
38
- const invalidElements = assignedElements.filter(el => el.tagName.toLowerCase() !== 'pds-dropdown-menu-item' && el.tagName.toLowerCase() !== 'pds-dropdown-menu-separator');
36
+ // Allowed elements: pds-dropdown-menu-item, pds-dropdown-menu-separator, <a>, <button>
37
+ // Raw <a> and <button> elements are allowed for edge cases requiring native browser/framework
38
+ // behavior (e.g., Rails UJS, Turbo) that cannot work through Shadow DOM.
39
+ const allowedTags = ['pds-dropdown-menu-item', 'pds-dropdown-menu-separator', 'a', 'button'];
40
+ const invalidElements = assignedElements.filter(el => !allowedTags.includes(el.tagName.toLowerCase()));
39
41
  if (invalidElements.length > 0) {
40
- throw new Error(`pds-dropdown-menu only accepts pds-dropdown-menu-item and pds-dropdown-menu-separator elements`);
42
+ const invalidTags = invalidElements.map(el => el.tagName.toLowerCase()).join(', ');
43
+ console.warn(`pds-dropdown-menu: Unexpected element(s) found: ${invalidTags}. ` +
44
+ `Expected: ${allowedTags.join(', ')}`);
41
45
  }
42
- // Store all menu items for keyboard navigation
43
- this.menuItems = assignedElements.filter(el => el.tagName.toLowerCase() === 'pds-dropdown-menu-item');
46
+ // Store all focusable items for keyboard navigation
47
+ // This includes pds-dropdown-menu-item components and raw <a>/<button> elements
48
+ this.menuItems = assignedElements.filter(el => {
49
+ const tag = el.tagName.toLowerCase();
50
+ return tag === 'pds-dropdown-menu-item' || tag === 'a' || tag === 'button';
51
+ });
44
52
  };
45
53
  // Toggle dropdown open/closed
46
54
  this.toggleDropdown = () => {
@@ -109,31 +117,66 @@ const PdsDropdownMenu$1 = /*@__PURE__*/ proxyCustomElement(class PdsDropdownMenu
109
117
  this.cleanupAutoUpdate = null;
110
118
  }
111
119
  }
120
+ // Check if a menu item is disabled (handles both component and raw elements)
121
+ isItemDisabled(item) {
122
+ const tagName = item.tagName.toLowerCase();
123
+ if (tagName === 'pds-dropdown-menu-item') {
124
+ return item.disabled;
125
+ }
126
+ else if (tagName === 'button') {
127
+ return item.disabled;
128
+ }
129
+ else if (tagName === 'a') {
130
+ return item.getAttribute('aria-disabled') === 'true';
131
+ }
132
+ return false;
133
+ }
112
134
  // Get the index of the currently focused menu item
113
135
  getFocusedItemIndex() {
114
136
  const activeElement = document.activeElement;
115
137
  if (!activeElement)
116
138
  return -1;
117
- return this.menuItems.findIndex(item => item === activeElement);
139
+ // For raw elements, check direct match
140
+ // For pds-dropdown-menu-item, also check if the active element is inside the shadow root
141
+ return this.menuItems.findIndex(item => {
142
+ if (item === activeElement)
143
+ return true;
144
+ // Check if activeElement is inside the item's shadow root (for pds-dropdown-menu-item)
145
+ if (item.tagName.toLowerCase() === 'pds-dropdown-menu-item') {
146
+ const shadowRoot = item.shadowRoot;
147
+ if (shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.contains(activeElement))
148
+ return true;
149
+ }
150
+ return false;
151
+ });
118
152
  }
119
153
  // Focus a specific menu item by index
120
154
  focusItemByIndex(index) {
121
- var _a, _b, _c, _d;
155
+ var _a, _b, _c, _d, _e;
122
156
  if (index >= 0 && index < this.menuItems.length) {
123
157
  this.currentFocusIndex = index;
124
- // Focus the inner button/link instead of the host element
125
- const menuItem = this.menuItems[index];
126
- const innerButton = (_a = menuItem.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('button');
127
- const innerLink = (_d = (_c = (_b = menuItem.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('pds-link')) === null || _c === void 0 ? void 0 : _c.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector('a');
128
- if (innerButton) {
129
- return innerButton.focus();
130
- }
131
- else if (innerLink) {
132
- return innerLink.focus();
158
+ const item = this.menuItems[index];
159
+ const tagName = item.tagName.toLowerCase();
160
+ if (tagName === 'pds-dropdown-menu-item') {
161
+ // For pds-dropdown-menu-item, focus the inner element
162
+ const menuItem = item;
163
+ const innerButton = (_a = menuItem.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('button');
164
+ const innerLink = ((_d = (_c = (_b = menuItem.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('pds-link')) === null || _c === void 0 ? void 0 : _c.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector('a'))
165
+ || ((_e = menuItem.shadowRoot) === null || _e === void 0 ? void 0 : _e.querySelector('a'));
166
+ if (innerButton) {
167
+ innerButton.focus();
168
+ }
169
+ else if (innerLink) {
170
+ innerLink.focus();
171
+ }
172
+ else {
173
+ // Fallback to focusing the host
174
+ menuItem.focus();
175
+ }
133
176
  }
134
177
  else {
135
- // Fallback to focusing the host if we can't find the inner element
136
- menuItem.focus();
178
+ // For raw <a> or <button> elements, focus directly
179
+ item.focus();
137
180
  }
138
181
  }
139
182
  }
@@ -143,7 +186,7 @@ const PdsDropdownMenu$1 = /*@__PURE__*/ proxyCustomElement(class PdsDropdownMenu
143
186
  // Skip disabled items
144
187
  let attempts = 0;
145
188
  const maxAttempts = this.menuItems.length;
146
- while (attempts < maxAttempts && this.menuItems[nextIndex].disabled) {
189
+ while (attempts < maxAttempts && this.isItemDisabled(this.menuItems[nextIndex])) {
147
190
  nextIndex = (nextIndex + 1) % this.menuItems.length;
148
191
  attempts++;
149
192
  }
@@ -160,7 +203,7 @@ const PdsDropdownMenu$1 = /*@__PURE__*/ proxyCustomElement(class PdsDropdownMenu
160
203
  // Skip disabled items
161
204
  let attempts = 0;
162
205
  const maxAttempts = this.menuItems.length;
163
- while (attempts < maxAttempts && this.menuItems[prevIndex].disabled) {
206
+ while (attempts < maxAttempts && this.isItemDisabled(this.menuItems[prevIndex])) {
164
207
  prevIndex = prevIndex <= 0 ? this.menuItems.length - 1 : prevIndex - 1;
165
208
  attempts++;
166
209
  }
@@ -191,7 +234,7 @@ const PdsDropdownMenu$1 = /*@__PURE__*/ proxyCustomElement(class PdsDropdownMenu
191
234
  if (this.menuItems.length > 0) {
192
235
  // Find first non-disabled item
193
236
  let firstIndex = 0;
194
- while (firstIndex < this.menuItems.length && this.menuItems[firstIndex].disabled) {
237
+ while (firstIndex < this.menuItems.length && this.isItemDisabled(this.menuItems[firstIndex])) {
195
238
  firstIndex++;
196
239
  }
197
240
  if (firstIndex < this.menuItems.length) {
@@ -204,7 +247,7 @@ const PdsDropdownMenu$1 = /*@__PURE__*/ proxyCustomElement(class PdsDropdownMenu
204
247
  if (this.menuItems.length > 0) {
205
248
  // Find last non-disabled item
206
249
  let lastIndex = this.menuItems.length - 1;
207
- while (lastIndex >= 0 && this.menuItems[lastIndex].disabled) {
250
+ while (lastIndex >= 0 && this.isItemDisabled(this.menuItems[lastIndex])) {
208
251
  lastIndex--;
209
252
  }
210
253
  if (lastIndex >= 0) {
@@ -234,7 +277,7 @@ const PdsDropdownMenu$1 = /*@__PURE__*/ proxyCustomElement(class PdsDropdownMenu
234
277
  event.preventDefault();
235
278
  // Find the first non-disabled item
236
279
  let firstFocusableIndex = 0;
237
- while (firstFocusableIndex < this.menuItems.length && this.menuItems[firstFocusableIndex].disabled) {
280
+ while (firstFocusableIndex < this.menuItems.length && this.isItemDisabled(this.menuItems[firstFocusableIndex])) {
238
281
  firstFocusableIndex++;
239
282
  }
240
283
  if (firstFocusableIndex < this.menuItems.length) {
@@ -246,7 +289,7 @@ const PdsDropdownMenu$1 = /*@__PURE__*/ proxyCustomElement(class PdsDropdownMenu
246
289
  event.preventDefault();
247
290
  // Find the first non-disabled item
248
291
  let firstFocusableIndex = 0;
249
- while (firstFocusableIndex < this.menuItems.length && this.menuItems[firstFocusableIndex].disabled) {
292
+ while (firstFocusableIndex < this.menuItems.length && this.isItemDisabled(this.menuItems[firstFocusableIndex])) {
250
293
  firstFocusableIndex++;
251
294
  }
252
295
  if (firstFocusableIndex < this.menuItems.length) {
@@ -269,7 +312,7 @@ const PdsDropdownMenu$1 = /*@__PURE__*/ proxyCustomElement(class PdsDropdownMenu
269
312
  }
270
313
  }
271
314
  render() {
272
- return (h(Host, { key: 'bedd78a69e84f10abb3c714c02227fa76e255a35', id: this.componentId }, h("slot", { key: 'd2bf56037a85679a677470d04865823966ca19d6', name: "trigger", onSlotchange: this.handleTriggerSlotChange }), h("pds-box", { key: '64f56896103bb6cca6c71020d3d37c375d300c40', "border-radius": "sm", display: "flex", direction: "column", class: "pds-dropdown-menu--panel is-hidden", shadow: "100", role: "menu", "aria-orientation": "vertical", part: "menu-panel" }, h("slot", { key: '0303160562f74fe9d32cc020c4539a7c8fc288a9', onSlotchange: this.handleSlotChange }))));
315
+ return (h(Host, { key: '3144bc264072eccf89cdca45a0b28eb004b5d06e', id: this.componentId }, h("slot", { key: '500288f266dc7ab7e1ac5070e628c31a6ed50861', name: "trigger", onSlotchange: this.handleTriggerSlotChange }), h("pds-box", { key: '4085130e381b8be28e2e36de073c0755a455e30c', "border-radius": "sm", display: "flex", direction: "column", class: "pds-dropdown-menu--panel is-hidden", shadow: "100", role: "menu", "aria-orientation": "vertical", part: "menu-panel" }, h("slot", { key: '2c4d53799576d1c6913df9bb854bfbaf50e5032c', onSlotchange: this.handleSlotChange }))));
273
316
  }
274
317
  get host() { return this; }
275
318
  static get style() { return pdsDropdownMenuCss; }
@@ -1 +1 @@
1
- {"file":"pds-dropdown-menu.js","mappings":"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","names":["PdsDropdownMenu","__stencil_proxyCustomElement"],"sources":["src/components/pds-dropdown-menu/pds-dropdown-menu.scss?tag=pds-dropdown-menu&encapsulation=shadow","src/components/pds-dropdown-menu/pds-dropdown-menu.tsx"],"sourcesContent":[":host {\n display: block;\n}\n\n.is-hidden {\n display: none;\n}\n\n.pds-dropdown-menu--panel {\n background-color: var(--pine-color-background-container);\n border-radius: var(--pine-dimension-xs);\n left: var(--pine-dimension-none);\n min-width: 170px;\n padding: var(--pine-dimension-xs);\n position: fixed;\n z-index: var(--pine-z-index-overlay);\n\n :host-context([data-theme=\"dark\"]) & {\n border: var(--pine-border);\n }\n}\n","import { Component, Element, Host, h, Prop, Listen, State } from '@stencil/core';\nimport type { BasePdsProps } from '@utils/interfaces';\nimport { PlacementType } from '@utils/types';\nimport { computePosition,\n flip,\n offset,\n shift,\n autoUpdate,\n} from '@floating-ui/dom';\n\n/**\n * @part menu-panel - Exposes the dropdown menu container for styling.\n */\n@Component({\n tag: 'pds-dropdown-menu',\n styleUrl: 'pds-dropdown-menu.scss',\n shadow: true,\n})\nexport class PdsDropdownMenu implements BasePdsProps {\n private slotEl: HTMLSlotElement;\n private triggerEl: HTMLElement;\n private panelEl: HTMLPdsBoxElement;\n private isOpen: boolean = false;\n private menuItems: HTMLPdsDropdownMenuItemElement[] = [];\n private cleanupAutoUpdate: (() => void) | null = null;\n\n @Element() host: HTMLPdsDropdownMenuElement;\n\n @State() currentFocusIndex: number = -1;\n\n /**\n * A unique identifier used for the underlying component `id` attribute.\n */\n @Prop() componentId: string;\n\n /**\n * The placement of the dropdown panel relative to the trigger.\n */\n @Prop() placement: PlacementType = 'bottom-start';\n\n componentDidRender() {\n this.panelEl = this.host.shadowRoot?.querySelector('pds-box') as HTMLPdsBoxElement;\n }\n\n disconnectedCallback() {\n // Clean up auto-update when component is removed from DOM\n if (this.cleanupAutoUpdate) {\n this.cleanupAutoUpdate();\n this.cleanupAutoUpdate = null;\n }\n }\n\n private handleTriggerSlotChange = (event: Event) => {\n this.slotEl = event.target as HTMLSlotElement;\n\n // Get all elements assigned to this slot\n const assignedElements = this.slotEl.assignedElements();\n\n this.triggerEl = assignedElements[0] as HTMLElement;\n this.triggerEl.onclick = this.handleClick;\n\n // Add accessibility attributes to trigger\n this.triggerEl.setAttribute('aria-haspopup', 'menu');\n this.triggerEl.setAttribute('aria-expanded', 'false');\n }\n\n private handleSlotChange = (event: Event) => {\n this.slotEl = event.target as HTMLSlotElement;\n\n // Get all elements assigned to this slot\n const assignedElements = this.slotEl.assignedElements();\n\n // ensure assignedElements only contains pds-dropdown-menu-item or pds-dropdown-menu-separator\n // if there are other elements, throw an error\n const invalidElements = assignedElements.filter(el => el.tagName.toLowerCase() !== 'pds-dropdown-menu-item' && el.tagName.toLowerCase() !== 'pds-dropdown-menu-separator');\n if (invalidElements.length > 0) {\n throw new Error(`pds-dropdown-menu only accepts pds-dropdown-menu-item and pds-dropdown-menu-separator elements`);\n }\n\n // Store all menu items for keyboard navigation\n this.menuItems = assignedElements.filter(\n el => el.tagName.toLowerCase() === 'pds-dropdown-menu-item'\n ) as HTMLPdsDropdownMenuItemElement[];\n }\n\n // Toggle dropdown open/closed\n private toggleDropdown = () => {\n this.isOpen = !this.isOpen;\n\n if (this.isOpen) {\n this.openDropdown();\n } else {\n this.closeDropdown();\n }\n }\n\n // Open the dropdown and position it\n private openDropdown = () => {\n const updatePosition = () => {\n computePosition(this.triggerEl, this.panelEl as HTMLElement, {\n placement: this.placement,\n strategy: 'fixed',\n middleware: [offset(6), flip(), shift({padding: 5})],\n }).then(({ x, y }) => {\n Object.assign(this.panelEl.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n });\n };\n\n // Initial position\n updatePosition();\n\n // Set up auto-update for window resize and scroll\n this.cleanupAutoUpdate = autoUpdate(\n this.triggerEl,\n this.panelEl as HTMLElement,\n updatePosition\n );\n\n this.host.shadowRoot?.querySelector('pds-box').classList.remove('is-hidden');\n this.isOpen = true;\n\n // Update ARIA attributes\n this.triggerEl.setAttribute('aria-expanded', 'true');\n }\n\n // Close the dropdown\n private closeDropdown = () => {\n this.host.shadowRoot?.querySelector('pds-box').classList.add('is-hidden');\n this.isOpen = false;\n\n // Clean up auto-update\n if (this.cleanupAutoUpdate) {\n this.cleanupAutoUpdate();\n this.cleanupAutoUpdate = null;\n }\n\n // Update ARIA attributes\n this.triggerEl.setAttribute('aria-expanded', 'false');\n\n // Reset focus index\n this.currentFocusIndex = -1;\n\n // Return focus to trigger\n this.triggerEl.focus();\n }\n\n // Handle click on the trigger element\n private handleClick = () => {\n this.toggleDropdown();\n }\n\n // Get the index of the currently focused menu item\n private getFocusedItemIndex(): number {\n const activeElement = document.activeElement as HTMLPdsDropdownMenuItemElement | null;\n if (!activeElement) return -1;\n return this.menuItems.findIndex(item => item === activeElement);\n }\n\n // Focus a specific menu item by index\n private focusItemByIndex(index: number): void {\n if (index >= 0 && index < this.menuItems.length) {\n this.currentFocusIndex = index;\n\n // Focus the inner button/link instead of the host element\n const menuItem = this.menuItems[index];\n const innerButton = menuItem.shadowRoot?.querySelector('button');\n const innerLink = menuItem.shadowRoot?.querySelector('pds-link')?.shadowRoot?.querySelector('a');\n\n if (innerButton) {\n return innerButton.focus();\n } else if (innerLink) {\n return innerLink.focus();\n } else {\n // Fallback to focusing the host if we can't find the inner element\n menuItem.focus();\n }\n }\n }\n\n // Focus the next menu item\n private focusNextItem(): void {\n let nextIndex = (this.currentFocusIndex + 1) % this.menuItems.length;\n\n // Skip disabled items\n let attempts = 0;\n const maxAttempts = this.menuItems.length;\n\n while (attempts < maxAttempts && this.menuItems[nextIndex].disabled) {\n nextIndex = (nextIndex + 1) % this.menuItems.length;\n attempts++;\n }\n\n // Only focus if we found a non-disabled item\n if (attempts < maxAttempts) {\n this.focusItemByIndex(nextIndex);\n }\n }\n\n // Focus the previous menu item\n private focusPreviousItem(): void {\n let prevIndex = this.currentFocusIndex <= 0\n ? this.menuItems.length - 1\n : this.currentFocusIndex - 1;\n\n // Skip disabled items\n let attempts = 0;\n const maxAttempts = this.menuItems.length;\n\n while (attempts < maxAttempts && this.menuItems[prevIndex].disabled) {\n prevIndex = prevIndex <= 0 ? this.menuItems.length - 1 : prevIndex - 1;\n attempts++;\n }\n\n // Only focus if we found a non-disabled item\n if (attempts < maxAttempts) {\n this.focusItemByIndex(prevIndex);\n }\n }\n\n // Handle keyboard events for the dropdown\n @Listen('keydown', { target: 'window' })\n handleKeyDown(event: KeyboardEvent) {\n if (!this.isOpen) return;\n\n switch (event.key) {\n case 'Escape':\n event.preventDefault();\n this.closeDropdown();\n break;\n\n case 'ArrowDown':\n event.preventDefault();\n this.focusNextItem();\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n this.focusPreviousItem();\n break;\n\n case 'Home':\n event.preventDefault();\n if (this.menuItems.length > 0) {\n // Find first non-disabled item\n let firstIndex = 0;\n while (firstIndex < this.menuItems.length && this.menuItems[firstIndex].disabled) {\n firstIndex++;\n }\n if (firstIndex < this.menuItems.length) {\n this.focusItemByIndex(firstIndex);\n }\n }\n break;\n\n case 'End':\n event.preventDefault();\n if (this.menuItems.length > 0) {\n // Find last non-disabled item\n let lastIndex = this.menuItems.length - 1;\n while (lastIndex >= 0 && this.menuItems[lastIndex].disabled) {\n lastIndex--;\n }\n if (lastIndex >= 0) {\n this.focusItemByIndex(lastIndex);\n }\n }\n break;\n\n case 'Tab':\n if (event.shiftKey) {\n // Let Shift+Tab navigate naturally from first item to trigger\n // For all other items, move to previous item\n const currentIndex = this.getFocusedItemIndex();\n\n if (currentIndex > 0) {\n // If not on first item, prevent default and go to previous item\n event.preventDefault();\n this.focusPreviousItem(); // Use our method that skips disabled items\n }\n // If on first item or no item, let natural tab order move back to trigger\n } else {\n // Forward Tab navigation\n const activeElement = document.activeElement;\n const isTriggerFocused = activeElement === this.triggerEl;\n const currentIndex = this.getFocusedItemIndex();\n\n if (isTriggerFocused && this.menuItems.length > 0) {\n // If trigger is focused, move to first non-disabled menu item\n event.preventDefault();\n\n // Find the first non-disabled item\n let firstFocusableIndex = 0;\n while (firstFocusableIndex < this.menuItems.length && this.menuItems[firstFocusableIndex].disabled) {\n firstFocusableIndex++;\n }\n\n if (firstFocusableIndex < this.menuItems.length) {\n this.focusItemByIndex(firstFocusableIndex);\n }\n } else if (currentIndex === -1 && this.menuItems.length > 0) {\n // If no menu item is focused, focus the first non-disabled one\n event.preventDefault();\n\n // Find the first non-disabled item\n let firstFocusableIndex = 0;\n while (firstFocusableIndex < this.menuItems.length && this.menuItems[firstFocusableIndex].disabled) {\n firstFocusableIndex++;\n }\n\n if (firstFocusableIndex < this.menuItems.length) {\n this.focusItemByIndex(firstFocusableIndex);\n }\n } else if (currentIndex !== -1) {\n // Use our method that skips disabled items\n event.preventDefault();\n this.focusNextItem();\n }\n }\n break;\n }\n }\n\n // Handle clicks outside the dropdown to close it\n @Listen('click', { target: 'window' })\n handleWindowClick(event: MouseEvent) {\n if (this.isOpen && !this.host.contains(event.target as Node) && event.target !== this.triggerEl) {\n this.closeDropdown();\n }\n }\n\n\n render() {\n return (\n <Host id={this.componentId}>\n <slot\n name=\"trigger\"\n onSlotchange={this.handleTriggerSlotChange}\n ></slot>\n <pds-box\n border-radius=\"sm\"\n display=\"flex\"\n direction=\"column\"\n class=\"pds-dropdown-menu--panel is-hidden\"\n shadow=\"100\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n part=\"menu-panel\"\n >\n <slot onSlotchange={this.handleSlotChange}></slot>\n </pds-box>\n </Host>\n );\n }\n}\n"],"version":3}
1
+ {"file":"pds-dropdown-menu.js","mappings":"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","names":["PdsDropdownMenu","__stencil_proxyCustomElement"],"sources":["src/components/pds-dropdown-menu/pds-dropdown-menu.scss?tag=pds-dropdown-menu&encapsulation=shadow","src/components/pds-dropdown-menu/pds-dropdown-menu.tsx"],"sourcesContent":[":host {\n display: block;\n}\n\n.is-hidden {\n display: none;\n}\n\n.pds-dropdown-menu--panel {\n background-color: var(--pine-color-background-container);\n border-radius: var(--pine-dimension-xs);\n left: var(--pine-dimension-none);\n min-width: 170px;\n padding: var(--pine-dimension-xs);\n position: fixed;\n z-index: var(--pine-z-index-overlay);\n\n :host-context([data-theme=\"dark\"]) & {\n border: var(--pine-border);\n }\n}\n\n// Styles for raw <a> and <button> elements slotted into the menu\n// These are allowed for edge cases requiring native browser/framework behavior\n// (e.g., Rails UJS, Turbo) that cannot work through Shadow DOM.\n//\n// Note: ::slotted() cannot be combined with pseudo-classes like :hover or :focus.\n// Raw elements will receive base styling here; hover/focus states must be handled\n// by the consuming application's CSS if needed.\n::slotted(a),\n::slotted(button) {\n align-items: center;\n appearance: none;\n background: transparent;\n border: 0;\n border-radius: var(--pine-dimension-xs);\n box-sizing: border-box;\n color: var(--pine-color-text) !important;\n cursor: pointer;\n display: flex;\n flex-grow: 1;\n font: var(--pine-typography-body-medium);\n gap: var(--pine-dimension-xs);\n margin: calc(var(--pine-border-width) + 2px);\n padding: var(--pine-dimension-xs);\n text-align: start;\n text-decoration: none !important;\n width: calc(100% - calc(var(--pine-border-width) + 2px) * 2);\n}\n\n// Destructive variant for raw elements\n::slotted(.destructive) {\n color: var(--pine-color-danger) !important;\n}\n\n// Disabled state for raw elements (using attribute selectors, not pseudo-classes)\n::slotted([aria-disabled=\"true\"]),\n::slotted([disabled]) {\n cursor: not-allowed;\n opacity: 0.5;\n pointer-events: none;\n}\n","import { Component, Element, Host, h, Prop, Listen, State } from '@stencil/core';\nimport type { BasePdsProps } from '@utils/interfaces';\nimport { PlacementType } from '@utils/types';\nimport { computePosition,\n flip,\n offset,\n shift,\n autoUpdate,\n} from '@floating-ui/dom';\n\n/**\n * Union type for focusable menu items (component or raw elements)\n */\ntype MenuItemElement = HTMLPdsDropdownMenuItemElement | HTMLAnchorElement | HTMLButtonElement;\n\n/**\n * @part menu-panel - Exposes the dropdown menu container for styling.\n */\n@Component({\n tag: 'pds-dropdown-menu',\n styleUrl: 'pds-dropdown-menu.scss',\n shadow: true,\n})\nexport class PdsDropdownMenu implements BasePdsProps {\n private slotEl: HTMLSlotElement;\n private triggerEl: HTMLElement;\n private panelEl: HTMLPdsBoxElement;\n private isOpen: boolean = false;\n private menuItems: MenuItemElement[] = [];\n private cleanupAutoUpdate: (() => void) | null = null;\n\n @Element() host: HTMLPdsDropdownMenuElement;\n\n @State() currentFocusIndex: number = -1;\n\n /**\n * A unique identifier used for the underlying component `id` attribute.\n */\n @Prop() componentId: string;\n\n /**\n * The placement of the dropdown panel relative to the trigger.\n */\n @Prop() placement: PlacementType = 'bottom-start';\n\n componentDidRender() {\n this.panelEl = this.host.shadowRoot?.querySelector('pds-box') as HTMLPdsBoxElement;\n }\n\n disconnectedCallback() {\n // Clean up auto-update when component is removed from DOM\n if (this.cleanupAutoUpdate) {\n this.cleanupAutoUpdate();\n this.cleanupAutoUpdate = null;\n }\n }\n\n private handleTriggerSlotChange = (event: Event) => {\n this.slotEl = event.target as HTMLSlotElement;\n\n // Get all elements assigned to this slot\n const assignedElements = this.slotEl.assignedElements();\n\n this.triggerEl = assignedElements[0] as HTMLElement;\n this.triggerEl.onclick = this.handleClick;\n\n // Add accessibility attributes to trigger\n this.triggerEl.setAttribute('aria-haspopup', 'menu');\n this.triggerEl.setAttribute('aria-expanded', 'false');\n }\n\n private handleSlotChange = (event: Event) => {\n this.slotEl = event.target as HTMLSlotElement;\n\n // Get all elements assigned to this slot\n const assignedElements = this.slotEl.assignedElements();\n\n // Allowed elements: pds-dropdown-menu-item, pds-dropdown-menu-separator, <a>, <button>\n // Raw <a> and <button> elements are allowed for edge cases requiring native browser/framework\n // behavior (e.g., Rails UJS, Turbo) that cannot work through Shadow DOM.\n const allowedTags = ['pds-dropdown-menu-item', 'pds-dropdown-menu-separator', 'a', 'button'];\n const invalidElements = assignedElements.filter(\n el => !allowedTags.includes(el.tagName.toLowerCase())\n );\n\n if (invalidElements.length > 0) {\n const invalidTags = invalidElements.map(el => el.tagName.toLowerCase()).join(', ');\n console.warn(\n `pds-dropdown-menu: Unexpected element(s) found: ${invalidTags}. ` +\n `Expected: ${allowedTags.join(', ')}`\n );\n }\n\n // Store all focusable items for keyboard navigation\n // This includes pds-dropdown-menu-item components and raw <a>/<button> elements\n this.menuItems = assignedElements.filter(el => {\n const tag = el.tagName.toLowerCase();\n return tag === 'pds-dropdown-menu-item' || tag === 'a' || tag === 'button';\n }) as MenuItemElement[];\n }\n\n // Toggle dropdown open/closed\n private toggleDropdown = () => {\n this.isOpen = !this.isOpen;\n\n if (this.isOpen) {\n this.openDropdown();\n } else {\n this.closeDropdown();\n }\n }\n\n // Open the dropdown and position it\n private openDropdown = () => {\n const updatePosition = () => {\n computePosition(this.triggerEl, this.panelEl as HTMLElement, {\n placement: this.placement,\n strategy: 'fixed',\n middleware: [offset(6), flip(), shift({padding: 5})],\n }).then(({ x, y }) => {\n Object.assign(this.panelEl.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n });\n };\n\n // Initial position\n updatePosition();\n\n // Set up auto-update for window resize and scroll\n this.cleanupAutoUpdate = autoUpdate(\n this.triggerEl,\n this.panelEl as HTMLElement,\n updatePosition\n );\n\n this.host.shadowRoot?.querySelector('pds-box').classList.remove('is-hidden');\n this.isOpen = true;\n\n // Update ARIA attributes\n this.triggerEl.setAttribute('aria-expanded', 'true');\n }\n\n // Close the dropdown\n private closeDropdown = () => {\n this.host.shadowRoot?.querySelector('pds-box').classList.add('is-hidden');\n this.isOpen = false;\n\n // Clean up auto-update\n if (this.cleanupAutoUpdate) {\n this.cleanupAutoUpdate();\n this.cleanupAutoUpdate = null;\n }\n\n // Update ARIA attributes\n this.triggerEl.setAttribute('aria-expanded', 'false');\n\n // Reset focus index\n this.currentFocusIndex = -1;\n\n // Return focus to trigger\n this.triggerEl.focus();\n }\n\n // Handle click on the trigger element\n private handleClick = () => {\n this.toggleDropdown();\n }\n\n // Check if a menu item is disabled (handles both component and raw elements)\n private isItemDisabled(item: MenuItemElement): boolean {\n const tagName = item.tagName.toLowerCase();\n\n if (tagName === 'pds-dropdown-menu-item') {\n return (item as HTMLPdsDropdownMenuItemElement).disabled;\n } else if (tagName === 'button') {\n return (item as HTMLButtonElement).disabled;\n } else if (tagName === 'a') {\n return item.getAttribute('aria-disabled') === 'true';\n }\n return false;\n }\n\n // Get the index of the currently focused menu item\n private getFocusedItemIndex(): number {\n const activeElement = document.activeElement as MenuItemElement | null;\n if (!activeElement) return -1;\n\n // For raw elements, check direct match\n // For pds-dropdown-menu-item, also check if the active element is inside the shadow root\n return this.menuItems.findIndex(item => {\n if (item === activeElement) return true;\n\n // Check if activeElement is inside the item's shadow root (for pds-dropdown-menu-item)\n if (item.tagName.toLowerCase() === 'pds-dropdown-menu-item') {\n const shadowRoot = (item as HTMLPdsDropdownMenuItemElement).shadowRoot;\n if (shadowRoot?.contains(activeElement)) return true;\n }\n\n return false;\n });\n }\n\n // Focus a specific menu item by index\n private focusItemByIndex(index: number): void {\n if (index >= 0 && index < this.menuItems.length) {\n this.currentFocusIndex = index;\n const item = this.menuItems[index];\n const tagName = item.tagName.toLowerCase();\n\n if (tagName === 'pds-dropdown-menu-item') {\n // For pds-dropdown-menu-item, focus the inner element\n const menuItem = item as HTMLPdsDropdownMenuItemElement;\n const innerButton = menuItem.shadowRoot?.querySelector('button');\n const innerLink = menuItem.shadowRoot?.querySelector('pds-link')?.shadowRoot?.querySelector('a')\n || menuItem.shadowRoot?.querySelector('a');\n\n if (innerButton) {\n innerButton.focus();\n } else if (innerLink) {\n innerLink.focus();\n } else {\n // Fallback to focusing the host\n menuItem.focus();\n }\n } else {\n // For raw <a> or <button> elements, focus directly\n (item as HTMLElement).focus();\n }\n }\n }\n\n // Focus the next menu item\n private focusNextItem(): void {\n let nextIndex = (this.currentFocusIndex + 1) % this.menuItems.length;\n\n // Skip disabled items\n let attempts = 0;\n const maxAttempts = this.menuItems.length;\n\n while (attempts < maxAttempts && this.isItemDisabled(this.menuItems[nextIndex])) {\n nextIndex = (nextIndex + 1) % this.menuItems.length;\n attempts++;\n }\n\n // Only focus if we found a non-disabled item\n if (attempts < maxAttempts) {\n this.focusItemByIndex(nextIndex);\n }\n }\n\n // Focus the previous menu item\n private focusPreviousItem(): void {\n let prevIndex = this.currentFocusIndex <= 0\n ? this.menuItems.length - 1\n : this.currentFocusIndex - 1;\n\n // Skip disabled items\n let attempts = 0;\n const maxAttempts = this.menuItems.length;\n\n while (attempts < maxAttempts && this.isItemDisabled(this.menuItems[prevIndex])) {\n prevIndex = prevIndex <= 0 ? this.menuItems.length - 1 : prevIndex - 1;\n attempts++;\n }\n\n // Only focus if we found a non-disabled item\n if (attempts < maxAttempts) {\n this.focusItemByIndex(prevIndex);\n }\n }\n\n // Handle keyboard events for the dropdown\n @Listen('keydown', { target: 'window' })\n handleKeyDown(event: KeyboardEvent) {\n if (!this.isOpen) return;\n\n switch (event.key) {\n case 'Escape':\n event.preventDefault();\n this.closeDropdown();\n break;\n\n case 'ArrowDown':\n event.preventDefault();\n this.focusNextItem();\n break;\n\n case 'ArrowUp':\n event.preventDefault();\n this.focusPreviousItem();\n break;\n\n case 'Home':\n event.preventDefault();\n if (this.menuItems.length > 0) {\n // Find first non-disabled item\n let firstIndex = 0;\n while (firstIndex < this.menuItems.length && this.isItemDisabled(this.menuItems[firstIndex])) {\n firstIndex++;\n }\n if (firstIndex < this.menuItems.length) {\n this.focusItemByIndex(firstIndex);\n }\n }\n break;\n\n case 'End':\n event.preventDefault();\n if (this.menuItems.length > 0) {\n // Find last non-disabled item\n let lastIndex = this.menuItems.length - 1;\n while (lastIndex >= 0 && this.isItemDisabled(this.menuItems[lastIndex])) {\n lastIndex--;\n }\n if (lastIndex >= 0) {\n this.focusItemByIndex(lastIndex);\n }\n }\n break;\n\n case 'Tab':\n if (event.shiftKey) {\n // Let Shift+Tab navigate naturally from first item to trigger\n // For all other items, move to previous item\n const currentIndex = this.getFocusedItemIndex();\n\n if (currentIndex > 0) {\n // If not on first item, prevent default and go to previous item\n event.preventDefault();\n this.focusPreviousItem(); // Use our method that skips disabled items\n }\n // If on first item or no item, let natural tab order move back to trigger\n } else {\n // Forward Tab navigation\n const activeElement = document.activeElement;\n const isTriggerFocused = activeElement === this.triggerEl;\n const currentIndex = this.getFocusedItemIndex();\n\n if (isTriggerFocused && this.menuItems.length > 0) {\n // If trigger is focused, move to first non-disabled menu item\n event.preventDefault();\n\n // Find the first non-disabled item\n let firstFocusableIndex = 0;\n while (firstFocusableIndex < this.menuItems.length && this.isItemDisabled(this.menuItems[firstFocusableIndex])) {\n firstFocusableIndex++;\n }\n\n if (firstFocusableIndex < this.menuItems.length) {\n this.focusItemByIndex(firstFocusableIndex);\n }\n } else if (currentIndex === -1 && this.menuItems.length > 0) {\n // If no menu item is focused, focus the first non-disabled one\n event.preventDefault();\n\n // Find the first non-disabled item\n let firstFocusableIndex = 0;\n while (firstFocusableIndex < this.menuItems.length && this.isItemDisabled(this.menuItems[firstFocusableIndex])) {\n firstFocusableIndex++;\n }\n\n if (firstFocusableIndex < this.menuItems.length) {\n this.focusItemByIndex(firstFocusableIndex);\n }\n } else if (currentIndex !== -1) {\n // Use our method that skips disabled items\n event.preventDefault();\n this.focusNextItem();\n }\n }\n break;\n }\n }\n\n // Handle clicks outside the dropdown to close it\n @Listen('click', { target: 'window' })\n handleWindowClick(event: MouseEvent) {\n if (this.isOpen && !this.host.contains(event.target as Node) && event.target !== this.triggerEl) {\n this.closeDropdown();\n }\n }\n\n\n render() {\n return (\n <Host id={this.componentId}>\n <slot\n name=\"trigger\"\n onSlotchange={this.handleTriggerSlotChange}\n ></slot>\n <pds-box\n border-radius=\"sm\"\n display=\"flex\"\n direction=\"column\"\n class=\"pds-dropdown-menu--panel is-hidden\"\n shadow=\"100\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n part=\"menu-panel\"\n >\n <slot onSlotchange={this.handleSlotChange}></slot>\n </pds-box>\n </Host>\n );\n }\n}\n"],"version":3}
@@ -43,9 +43,12 @@ const PdsTable$1 = /*@__PURE__*/ proxyCustomElement(class PdsTable extends HTMLE
43
43
  this.setupResponsiveScrolling();
44
44
  }
45
45
  // Apply default sort if specified
46
+ // Use requestAnimationFrame to defer until child components are fully initialized
46
47
  if (this.defaultSortColumn) {
47
- void this.applyDefaultSort().catch((err) => {
48
- console.warn('Failed to apply default sort.', err);
48
+ requestAnimationFrame(() => {
49
+ void this.applyDefaultSort().catch((err) => {
50
+ console.warn('Failed to apply default sort.', err);
51
+ });
49
52
  });
50
53
  }
51
54
  }
@@ -1 +1 @@
1
- {"file":"pds-table.js","mappings":"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","names":["PdsTable","__stencil_proxyCustomElement"],"sources":["src/components/pds-table/pds-table.scss?tag=pds-table&encapsulation=shadow","src/components/pds-table/pds-table.tsx"],"sourcesContent":[":host {\n --color-background-default: var(--pine-color-background-container);\n\n background: var(--color-background-default);\n border-collapse: separate;\n border-radius: inherit;\n box-sizing: border-box;\n display: table;\n width: 100%;\n}\n\n:host(:focus-visible) {\n outline: var(--pine-outline-focus);\n}\n\n/*\n * Responsive Table Architecture\n *\n * When responsive=true, the table uses a nested structure to provide horizontal scrolling\n * while maintaining proper width behavior and scroll shadows:\n *\n * Host (.pds-table-responsive-host)\n * ├── Shadow Left (positioned fixed to left edge)\n * ├── Shadow Right (positioned fixed to right edge)\n * └── Container (.pds-table-responsive-container)\n * └── Wrapper (.pds-table-responsive-wrapper)\n * └── Table (.pds-table)\n *\n * - Host: Constrains everything to parent width, clips shadows to border-radius\n * - Shadows: Stay fixed during scroll, provide visual scroll indicators\n * - Container: Handles horizontal scrolling (overflow-x: auto)\n * - Table: Expands to full width or scrolls based on content\n */\n:host(.pds-table-responsive-host) {\n border-radius: inherit;\n box-sizing: border-box !important;\n display: block !important;\n max-width: 100% !important;\n overflow: hidden !important;\n position: relative !important;\n width: 100% !important;\n}\n\n.pds-table-responsive-container {\n border-radius: inherit;\n box-sizing: border-box !important;\n overflow-x: auto !important;\n overflow-y: visible !important;\n position: relative !important;\n width: 100% !important;\n}\n\n.pds-table-responsive-wrapper {\n border-radius: inherit;\n box-sizing: border-box !important;\n display: block !important;\n position: relative !important;\n width: 100% !important;\n}\n\n.pds-table-responsive-wrapper .pds-table {\n display: table !important;\n min-width: max-content !important;\n table-layout: auto !important;\n white-space: nowrap !important;\n width: 100% !important;\n}\n\n/* Shadows positioned relative to host (non-scrolling), covering container edges */\n.scroll-shadow-left,\n.scroll-shadow-right {\n height: 100%;\n opacity: 0;\n pointer-events: none;\n position: absolute;\n top: 0;\n transition: opacity 0.1s ease;\n width: 4px;\n z-index: var(--pine-z-index);\n}\n\n.scroll-shadow-left {\n /* stylelint-disable-next-line pine-design-system/no-hardcoded-colors */\n background: linear-gradient(to right, rgba(0, 0, 0, 0.1), transparent);\n border-bottom-left-radius: inherit;\n border-top-left-radius: inherit;\n left: 0;\n}\n\n.scroll-shadow-right {\n /* stylelint-disable-next-line pine-design-system/no-hardcoded-colors */\n background: linear-gradient(to left, rgba(0, 0, 0, 0.1), transparent);\n border-bottom-right-radius: inherit;\n border-top-right-radius: inherit;\n right: 0;\n}\n","import { Component, Element, Event, EventEmitter, Host, h, Prop, State, Listen } from '@stencil/core';\n\n@Component({\n tag: 'pds-table',\n styleUrls: ['pds-table.scss'],\n shadow: true,\n})\nexport class PdsTable {\n @Element() el: HTMLPdsTableElement;\n private scrollContainer: HTMLElement | null = null;\n private _responsiveHandleScroll: (() => void) | null = null;\n private _responsiveHandleResize: (() => void) | null = null;\n private _responsiveResizeObserver: ResizeObserver | null = null;\n private _teardownResponsive: (() => void) | null = null;\n\n /**\n * Determines if the table displays with reduced table cell padding.\n */\n @Prop() compact: boolean;\n\n /**\n * A unique identifier used for the table `id` attribute.\n */\n @Prop() componentId!: string;\n\n /**\n * Enables the table to be responsive by horizontally scrolling on smaller screens.\n */\n @Prop() responsive: boolean;\n\n /**\n * Determines if the should display a fixed first column.\n */\n @Prop() fixedColumn: boolean;\n\n /**\n * Determines if the table displays checkboxes for selectable rows.\n */\n @Prop() selectable: boolean;\n\n /**\n * Adds divider borders between table rows. The last row will not have a bottom border.\n * @defaultValue false\n */\n @Prop({ reflect: true }) rowDividers: boolean = false;\n\n /**\n * The name of the column to sort by on initial load.\n * Must match the text content of a sortable column header.\n */\n @Prop() defaultSortColumn?: string;\n\n /**\n * The direction to sort the default column on initial load.\n * Only applies if `defaultSortColumn` is set.\n * @defaultValue 'asc'\n */\n @Prop() defaultSortDirection?: 'asc' | 'desc' = 'asc';\n\n /**\n * The name of the column being sorted.\n * @defaultValue null\n */\n @State() sortingColumn: string | null = null;\n\n /**\n * The direction of sorting.\n * @defaultValue 'asc'\n */\n @State() sortingDirection: 'asc' | 'desc' = 'asc';\n\n\n /**\n * Event that is emitted when the checkbox is clicked, carrying the rowIndex and selected value.\n */\n @Event() pdsTableSelect: EventEmitter<{ rowIndex: number; isSelected: boolean }>;\n\n /**\n * Event that is emitted when the select all checkbox is clicked, carrying the selected value.\n */\n @Event() pdsTableSelectAll: EventEmitter<{ isSelected: boolean }>;\n\n componentDidLoad() {\n if (this.responsive) {\n this.setupResponsiveScrolling();\n }\n\n // Apply default sort if specified\n if (this.defaultSortColumn) {\n void this.applyDefaultSort().catch((err) => {\n console.warn('Failed to apply default sort.', err);\n });\n }\n }\n\n /**\n * Applies the default sort configuration on initial load.\n * Finds the matching column header and activates its sort state.\n * @private\n */\n private async applyDefaultSort() {\n // Normalize direction to handle invalid HTML attribute values\n const direction: 'asc' | 'desc' = this.defaultSortDirection === 'desc' ? 'desc' : 'asc';\n\n // Find the matching sortable header cell\n const columnHeaderCells = Array.from(\n this.el.querySelectorAll('pds-table-head-cell[sortable]')\n ) as HTMLPdsTableHeadCellElement[];\n\n const matchingCell = columnHeaderCells.find(\n (cell) => (cell.textContent ?? '').trim() === this.defaultSortColumn\n );\n\n if (matchingCell) {\n const columnName = (matchingCell.textContent ?? '').trim();\n // Sort the table data\n this.sortTable(columnName, direction);\n this.sortingColumn = columnName;\n this.sortingDirection = direction;\n\n // Activate the visual state on the header cell\n await matchingCell.setActiveSort(direction);\n } else {\n console.warn(`Default sort column \"${this.defaultSortColumn}\" not found.`);\n }\n }\n\n disconnectedCallback() {\n if (this._teardownResponsive) {\n this._teardownResponsive();\n this._teardownResponsive = null;\n }\n }\n\n /**\n * Sets up responsive scrolling behavior for the table.\n *\n * This method creates a horizontal scrolling system where:\n * - The table content can scroll horizontally when it exceeds the container width\n * - Scroll shadows appear at the left/right edges to indicate scrollable content\n * - Fixed columns remain sticky during horizontal scrolling\n * - Shadows respect border-radius and don't appear when there's nothing to scroll\n *\n * Architecture:\n * - Host element: Contains everything, respects parent constraints\n * - Container element: Handles horizontal scrolling (overflow-x: auto)\n * - Shadow elements: Positioned fixed relative to host, show scroll indicators\n *\n * @private\n */\n private setupResponsiveScrolling() {\n const container = this.el.shadowRoot?.querySelector('.pds-table-responsive-container') as HTMLElement;\n const leftShadow = this.el.shadowRoot?.querySelector('.scroll-shadow-left') as HTMLElement;\n const rightShadow = this.el.shadowRoot?.querySelector('.scroll-shadow-right') as HTMLElement;\n\n if (!container || !leftShadow || !rightShadow) return;\n\n // Store container reference for cleanup\n this.scrollContainer = container;\n\n /**\n * Updates the visibility of scroll shadows based on current scroll position.\n * Left shadow: Shows when scrolled away from start (hidden if fixedColumn is enabled)\n * Right shadow: Shows when there's content to scroll and not at the end\n */\n this._responsiveHandleScroll = () => {\n if (!this.scrollContainer) return;\n\n const scrollLeft = this.scrollContainer.scrollLeft;\n const maxScrollLeft = this.scrollContainer.scrollWidth - this.scrollContainer.clientWidth;\n\n // Show left shadow when scrolled away from start, but not if there's a fixed column\n leftShadow.style.opacity = (scrollLeft > 0 && !this.fixedColumn) ? '1' : '0';\n\n // Show right shadow only if there's content to scroll AND not at end\n rightShadow.style.opacity = (maxScrollLeft > 0 && scrollLeft < maxScrollLeft - 1) ? '1' : '0';\n };\n\n // Add scroll event listener to container element\n this.scrollContainer.addEventListener('scroll', this._responsiveHandleScroll, { passive: true });\n\n // Add resize observer to update shadows when container size changes\n if (typeof window !== 'undefined' && window.ResizeObserver) {\n try {\n this._responsiveResizeObserver = new ResizeObserver(() => {\n this._responsiveHandleScroll?.();\n });\n this._responsiveResizeObserver.observe(this.scrollContainer);\n } catch (error) {\n // ResizeObserver not available in some environments (e.g., tests)\n // Fall back to window resize listener only\n }\n }\n\n // Listen for window resize as fallback\n if (typeof window !== 'undefined') {\n this._responsiveHandleResize = () => {\n this._responsiveHandleScroll?.();\n };\n window.addEventListener('resize', this._responsiveHandleResize);\n }\n\n // Create teardown function for cleanup\n this._teardownResponsive = () => {\n if (this.scrollContainer && this._responsiveHandleScroll) {\n this.scrollContainer.removeEventListener('scroll', this._responsiveHandleScroll);\n this.scrollContainer = null;\n }\n\n if (this._responsiveResizeObserver) {\n this._responsiveResizeObserver.disconnect();\n this._responsiveResizeObserver = null;\n }\n\n if (typeof window !== 'undefined' && this._responsiveHandleResize) {\n window.removeEventListener('resize', this._responsiveHandleResize);\n this._responsiveHandleResize = null;\n }\n\n this._responsiveHandleScroll = null;\n };\n\n // Initial check after setup\n this._responsiveHandleScroll();\n }\n\n\n private classNames() {\n const classNames = ['pds-table'];\n\n if (this.compact) {\n classNames.push('is-compact');\n }\n\n if (this.responsive) {\n classNames.push('is-responsive');\n }\n\n return classNames.join(' ');\n }\n\n private sortTable(column: string, direction: 'asc' | 'desc') {\n const tableBody = this.el.querySelector('pds-table-body');\n\n // Return early if no table body exists\n if (!tableBody) return;\n\n // Get the rows in the table body\n const tableRows = Array.from(tableBody.querySelectorAll('pds-table-row'));\n\n // Find the column index based on the column name\n const columnHeaderCells: HTMLElement[] = Array.from(\n this.el.querySelectorAll('pds-table-head-cell[sortable]')\n );\n\n const columnHeaderCell = columnHeaderCells.find(\n (cell) => cell.innerText.trim() === column\n );\n\n if (!columnHeaderCell) {\n console.warn(`Column \"${column}\" not found.`);\n return;\n }\n\n const columnIndex = columnHeaderCells.indexOf(columnHeaderCell);\n\n // Sort the rows based on the content of the specified column\n tableRows.sort((a, b) => {\n const valueA = a.querySelector(`pds-table-cell:nth-child(${columnIndex + 1})`).textContent.trim();\n const valueB = b.querySelector(`pds-table-cell:nth-child(${columnIndex + 1})`).textContent.trim();\n\n if (direction === 'asc') {\n return valueA.localeCompare(valueB, undefined, { sensitivity: 'base' });\n } else {\n return valueB.localeCompare(valueA, undefined, { sensitivity: 'base' });\n }\n });\n\n // Clear and append the sorted rows back to the table body\n tableBody.innerHTML = '';\n tableRows.forEach((row) => {\n tableBody.appendChild(row);\n });\n }\n\n @Listen('pdsTableSort')\n handleTableSort(event: CustomEvent<{ column: string; direction: 'asc' | 'desc' }>) {\n if (event.defaultPrevented) return;\n\n const { direction } = event.detail;\n this.sortTable(event.detail.column, direction);\n this.sortingColumn = event.detail.column;\n this.sortingDirection = direction;\n }\n\n @Listen('pdsTableSelectAll')\n handleTableSelectAll(event: CustomEvent<{ isSelected: boolean }>) {\n if (event.defaultPrevented) return;\n\n const pdsTableBody = this.el.querySelector('pds-table-body');\n const tableRows = Array.from(pdsTableBody.querySelectorAll('pds-table-row'));\n\n tableRows.forEach((row) => {\n row.isSelected = event.detail.isSelected;\n });\n }\n\n @Listen('pdsTableRowSelected')\n async handleTableSelect(event: CustomEvent<{ rowIndex: number; isSelected: boolean }>) {\n if (event.defaultPrevented) return;\n\n const allTableRows = this.el.querySelectorAll('pds-table-row');\n const allSelectedRows = Array.from(allTableRows).every((row) => row.isSelected);\n const noneSelectedRows = Array.from(allTableRows).every((row) => !row.isSelected);\n const pdsTableHead = this.el.querySelector('pds-table-head');\n if (!pdsTableHead) return;\n\n const headerCheckbox = pdsTableHead.shadowRoot.querySelector('pds-checkbox');\n headerCheckbox.checked = allSelectedRows;\n headerCheckbox.indeterminate = !allSelectedRows && !noneSelectedRows;\n }\n\n render() {\n if (this.responsive) {\n return (\n <Host\n class=\"pds-table is-responsive pds-table-responsive-host\"\n id={this.componentId}\n role=\"grid\"\n selectable={this.selectable}\n tabindex=\"0\"\n part=\"table responsive-table\"\n >\n <div class=\"scroll-shadow-left\" part=\"scroll-shadow-left\"></div>\n <div class=\"scroll-shadow-right\" part=\"scroll-shadow-right\"></div>\n <div class=\"pds-table-responsive-container\" part=\"responsive-container\">\n <div class=\"pds-table-responsive-wrapper\" part=\"responsive-wrapper\">\n <div class={this.classNames()} part=\"table-inner\">\n <slot></slot>\n </div>\n </div>\n </div>\n </Host>\n );\n }\n\n return (\n <Host\n class={this.classNames()}\n id={this.componentId}\n role=\"grid\"\n selectable={this.selectable}\n tabindex=\"0\"\n part=\"table\"\n >\n <slot></slot>\n </Host>\n );\n }\n}\n"],"version":3}
1
+ {"file":"pds-table.js","mappings":";;AAAA,MAAM,WAAW,GAAG,09DAA09D;;MCOj+DA,UAAQ,iBAAAC,kBAAA,CAAA,MAAA,QAAA,SAAA,WAAA,CAAA;AALrB,IAAA,WAAA,CAAA,YAAA,EAAA;;;;;;;;AAOU,QAAA,IAAe,CAAA,eAAA,GAAuB,IAAI;AAC1C,QAAA,IAAuB,CAAA,uBAAA,GAAwB,IAAI;AACnD,QAAA,IAAuB,CAAA,uBAAA,GAAwB,IAAI;AACnD,QAAA,IAAyB,CAAA,yBAAA,GAA0B,IAAI;AACvD,QAAA,IAAmB,CAAA,mBAAA,GAAwB,IAAI;AA2BvD;;;AAGG;AACsB,QAAA,IAAW,CAAA,WAAA,GAAY,KAAK;AAQrD;;;;AAIG;AACK,QAAA,IAAoB,CAAA,oBAAA,GAAoB,KAAK;AAErD;;;AAGG;AACM,QAAA,IAAa,CAAA,aAAA,GAAkB,IAAI;AAE5C;;;AAGG;AACM,QAAA,IAAgB,CAAA,gBAAA,GAAmB,KAAK;AAqSlD;IAxRC,gBAAgB,GAAA;AACd,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE;YACnB,IAAI,CAAC,wBAAwB,EAAE;;;;AAKjC,QAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE;YAC1B,qBAAqB,CAAC,MAAK;gBACzB,KAAK,IAAI,CAAC,gBAAgB,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,KAAI;AACzC,oBAAA,OAAO,CAAC,IAAI,CAAC,+BAA+B,EAAE,GAAG,CAAC;AACpD,iBAAC,CAAC;AACJ,aAAC,CAAC;;;AAIN;;;;AAIG;AACK,IAAA,MAAM,gBAAgB,GAAA;;;AAE5B,QAAA,MAAM,SAAS,GAAmB,IAAI,CAAC,oBAAoB,KAAK,MAAM,GAAG,MAAM,GAAG,KAAK;;AAGvF,QAAA,MAAM,iBAAiB,GAAG,KAAK,CAAC,IAAI,CAClC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,+BAA+B,CAAC,CACzB;QAElC,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,CACzC,CAAC,IAAI,KAAI,EAAC,IAAA,EAAA,CAAA,CAAA,OAAA,CAAC,CAAA,EAAA,GAAA,IAAI,CAAC,WAAW,MAAI,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAA,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC,iBAAiB,CAAA,EAAA,CACrE;QAED,IAAI,YAAY,EAAE;AAChB,YAAA,MAAM,UAAU,GAAG,CAAC,CAAA,EAAA,GAAA,YAAY,CAAC,WAAW,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,EAAA,GAAI,EAAE,EAAE,IAAI,EAAE;;AAE1D,YAAA,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC;AACrC,YAAA,IAAI,CAAC,aAAa,GAAG,UAAU;AAC/B,YAAA,IAAI,CAAC,gBAAgB,GAAG,SAAS;;AAGjC,YAAA,MAAM,YAAY,CAAC,aAAa,CAAC,SAAS,CAAC;;aACtC;YACL,OAAO,CAAC,IAAI,CAAC,CAAA,qBAAA,EAAwB,IAAI,CAAC,iBAAiB,CAAc,YAAA,CAAA,CAAC;;;IAI9E,oBAAoB,GAAA;AAClB,QAAA,IAAI,IAAI,CAAC,mBAAmB,EAAE;YAC5B,IAAI,CAAC,mBAAmB,EAAE;AAC1B,YAAA,IAAI,CAAC,mBAAmB,GAAG,IAAI;;;AAInC;;;;;;;;;;;;;;;AAeG;IACK,wBAAwB,GAAA;;AAC9B,QAAA,MAAM,SAAS,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,EAAE,CAAC,UAAU,MAAE,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,aAAa,CAAC,iCAAiC,CAAgB;AACrG,QAAA,MAAM,UAAU,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,EAAE,CAAC,UAAU,MAAE,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,aAAa,CAAC,qBAAqB,CAAgB;AAC1F,QAAA,MAAM,WAAW,GAAG,CAAA,EAAA,GAAA,IAAI,CAAC,EAAE,CAAC,UAAU,MAAE,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,aAAa,CAAC,sBAAsB,CAAgB;AAE5F,QAAA,IAAI,CAAC,SAAS,IAAI,CAAC,UAAU,IAAI,CAAC,WAAW;YAAE;;AAG/C,QAAA,IAAI,CAAC,eAAe,GAAG,SAAS;AAEhC;;;;AAIG;AACH,QAAA,IAAI,CAAC,uBAAuB,GAAG,MAAK;YAClC,IAAI,CAAC,IAAI,CAAC,eAAe;gBAAE;AAE3B,YAAA,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU;AAClD,YAAA,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW;;YAGzF,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,GAAG,GAAG,GAAG;;YAG5E,WAAW,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,aAAa,GAAG,CAAC,IAAI,UAAU,GAAG,aAAa,GAAG,CAAC,IAAI,GAAG,GAAG,GAAG;AAC/F,SAAC;;AAGD,QAAA,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,uBAAuB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;;QAGhG,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,cAAc,EAAE;AAC1D,YAAA,IAAI;AACF,gBAAA,IAAI,CAAC,yBAAyB,GAAG,IAAI,cAAc,CAAC,MAAK;;oBACvD,CAAA,EAAA,GAAA,IAAI,CAAC,uBAAuB,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,IAAA,CAAI;AAClC,iBAAC,CAAC;gBACF,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC;;YAC5D,OAAO,KAAK,EAAE;;;;;;AAOlB,QAAA,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;AACjC,YAAA,IAAI,CAAC,uBAAuB,GAAG,MAAK;;gBAClC,CAAA,EAAA,GAAA,IAAI,CAAC,uBAAuB,MAAA,IAAA,IAAA,EAAA,KAAA,MAAA,GAAA,MAAA,GAAA,EAAA,CAAA,IAAA,CAAA,IAAA,CAAI;AAClC,aAAC;YACD,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,uBAAuB,CAAC;;;AAIjE,QAAA,IAAI,CAAC,mBAAmB,GAAG,MAAK;YAC9B,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,uBAAuB,EAAE;gBACxD,IAAI,CAAC,eAAe,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,uBAAuB,CAAC;AAChF,gBAAA,IAAI,CAAC,eAAe,GAAG,IAAI;;AAG7B,YAAA,IAAI,IAAI,CAAC,yBAAyB,EAAE;AAClC,gBAAA,IAAI,CAAC,yBAAyB,CAAC,UAAU,EAAE;AAC3C,gBAAA,IAAI,CAAC,yBAAyB,GAAG,IAAI;;YAGvC,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,IAAI,CAAC,uBAAuB,EAAE;gBACjE,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,uBAAuB,CAAC;AAClE,gBAAA,IAAI,CAAC,uBAAuB,GAAG,IAAI;;AAGrC,YAAA,IAAI,CAAC,uBAAuB,GAAG,IAAI;AACrC,SAAC;;QAGD,IAAI,CAAC,uBAAuB,EAAE;;IAIxB,UAAU,GAAA;AAChB,QAAA,MAAM,UAAU,GAAG,CAAC,WAAW,CAAC;AAEhC,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE;AAChB,YAAA,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;;AAG/B,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE;AACnB,YAAA,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC;;AAGlC,QAAA,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;;IAGtB,SAAS,CAAC,MAAc,EAAE,SAAyB,EAAA;QACzD,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,gBAAgB,CAAC;;AAGzD,QAAA,IAAI,CAAC,SAAS;YAAE;;AAGhB,QAAA,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC;;AAGzE,QAAA,MAAM,iBAAiB,GAAkB,KAAK,CAAC,IAAI,CACjD,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,+BAA+B,CAAC,CAC1D;QAED,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,IAAI,CAC7C,CAAC,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,MAAM,CAC3C;QAED,IAAI,CAAC,gBAAgB,EAAE;AACrB,YAAA,OAAO,CAAC,IAAI,CAAC,WAAW,MAAM,CAAA,YAAA,CAAc,CAAC;YAC7C;;QAGF,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,gBAAgB,CAAC;;QAG/D,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAI;AACtB,YAAA,MAAM,MAAM,GAAG,CAAC,CAAC,aAAa,CAAC,CAA4B,yBAAA,EAAA,WAAW,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE;AACjG,YAAA,MAAM,MAAM,GAAG,CAAC,CAAC,aAAa,CAAC,CAA4B,yBAAA,EAAA,WAAW,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE;AAEjG,YAAA,IAAI,SAAS,KAAK,KAAK,EAAE;AACvB,gBAAA,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;;iBAClE;AACL,gBAAA,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;;AAE3E,SAAC,CAAC;;AAGF,QAAA,SAAS,CAAC,SAAS,GAAG,EAAE;AACxB,QAAA,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,KAAI;AACxB,YAAA,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC;AAC5B,SAAC,CAAC;;AAIJ,IAAA,eAAe,CAAC,KAAiE,EAAA;QAC/E,IAAI,KAAK,CAAC,gBAAgB;YAAE;AAE5B,QAAA,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,MAAM;QAClC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC;QAC9C,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM;AACxC,QAAA,IAAI,CAAC,gBAAgB,GAAG,SAAS;;AAInC,IAAA,oBAAoB,CAAC,KAA2C,EAAA;QAC9D,IAAI,KAAK,CAAC,gBAAgB;YAAE;QAE5B,MAAM,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,gBAAgB,CAAC;AAC5D,QAAA,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC;AAE5E,QAAA,SAAS,CAAC,OAAO,CAAC,CAAC,GAAG,KAAI;YACxB,GAAG,CAAC,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU;AAC1C,SAAC,CAAC;;IAIJ,MAAM,iBAAiB,CAAC,KAA6D,EAAA;QACnF,IAAI,KAAK,CAAC,gBAAgB;YAAE;QAE5B,MAAM,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,eAAe,CAAC;QAC9D,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,UAAU,CAAC;QAC/E,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;QACjF,MAAM,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,gBAAgB,CAAC;AAC5D,QAAA,IAAI,CAAC,YAAY;YAAE;QAEnB,MAAM,cAAc,GAAG,YAAY,CAAC,UAAU,CAAC,aAAa,CAAC,cAAc,CAAC;AAC5E,QAAA,cAAc,CAAC,OAAO,GAAG,eAAe;QACxC,cAAc,CAAC,aAAa,GAAG,CAAC,eAAe,IAAI,CAAC,gBAAgB;;IAGtE,MAAM,GAAA;AACJ,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE;YACnB,QACE,CAAA,CAAC,IAAI,EAAA,EACH,KAAK,EAAC,mDAAmD,EACzD,EAAE,EAAE,IAAI,CAAC,WAAW,EACpB,IAAI,EAAC,MAAM,EACX,UAAU,EAAE,IAAI,CAAC,UAAU,EAC3B,QAAQ,EAAC,GAAG,EACZ,IAAI,EAAC,wBAAwB,EAAA,EAE7B,CAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAC,oBAAoB,EAAC,IAAI,EAAC,oBAAoB,EAAO,CAAA,EAChE,CAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAC,qBAAqB,EAAC,IAAI,EAAC,qBAAqB,EAAO,CAAA,EAClE,CAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAC,gCAAgC,EAAC,IAAI,EAAC,sBAAsB,EAAA,EACrE,CAAA,CAAA,KAAA,EAAA,EAAK,KAAK,EAAC,8BAA8B,EAAC,IAAI,EAAC,oBAAoB,EAAA,EACjE,CAAK,CAAA,KAAA,EAAA,EAAA,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,EAAC,aAAa,EAAA,EAC/C,CAAA,CAAA,MAAA,EAAA,IAAA,CAAa,CACT,CACF,CACF,CACD;;QAIX,QACE,CAAA,CAAC,IAAI,EAAA,EACH,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,EACxB,EAAE,EAAE,IAAI,CAAC,WAAW,EACpB,IAAI,EAAC,MAAM,EACX,UAAU,EAAE,IAAI,CAAC,UAAU,EAC3B,QAAQ,EAAC,GAAG,EACZ,IAAI,EAAC,OAAO,EAAA,EAEZ,CAAa,CAAA,MAAA,EAAA,IAAA,CAAA,CACR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","names":["PdsTable","__stencil_proxyCustomElement"],"sources":["src/components/pds-table/pds-table.scss?tag=pds-table&encapsulation=shadow","src/components/pds-table/pds-table.tsx"],"sourcesContent":[":host {\n --color-background-default: var(--pine-color-background-container);\n\n background: var(--color-background-default);\n border-collapse: separate;\n border-radius: inherit;\n box-sizing: border-box;\n display: table;\n width: 100%;\n}\n\n:host(:focus-visible) {\n outline: var(--pine-outline-focus);\n}\n\n/*\n * Responsive Table Architecture\n *\n * When responsive=true, the table uses a nested structure to provide horizontal scrolling\n * while maintaining proper width behavior and scroll shadows:\n *\n * Host (.pds-table-responsive-host)\n * ├── Shadow Left (positioned fixed to left edge)\n * ├── Shadow Right (positioned fixed to right edge)\n * └── Container (.pds-table-responsive-container)\n * └── Wrapper (.pds-table-responsive-wrapper)\n * └── Table (.pds-table)\n *\n * - Host: Constrains everything to parent width, clips shadows to border-radius\n * - Shadows: Stay fixed during scroll, provide visual scroll indicators\n * - Container: Handles horizontal scrolling (overflow-x: auto)\n * - Table: Expands to full width or scrolls based on content\n */\n:host(.pds-table-responsive-host) {\n border-radius: inherit;\n box-sizing: border-box !important;\n display: block !important;\n max-width: 100% !important;\n overflow: hidden !important;\n position: relative !important;\n width: 100% !important;\n}\n\n.pds-table-responsive-container {\n border-radius: inherit;\n box-sizing: border-box !important;\n overflow-x: auto !important;\n overflow-y: visible !important;\n position: relative !important;\n width: 100% !important;\n}\n\n.pds-table-responsive-wrapper {\n border-radius: inherit;\n box-sizing: border-box !important;\n display: block !important;\n position: relative !important;\n width: 100% !important;\n}\n\n.pds-table-responsive-wrapper .pds-table {\n display: table !important;\n min-width: max-content !important;\n table-layout: auto !important;\n white-space: nowrap !important;\n width: 100% !important;\n}\n\n/* Shadows positioned relative to host (non-scrolling), covering container edges */\n.scroll-shadow-left,\n.scroll-shadow-right {\n height: 100%;\n opacity: 0;\n pointer-events: none;\n position: absolute;\n top: 0;\n transition: opacity 0.1s ease;\n width: 4px;\n z-index: var(--pine-z-index);\n}\n\n.scroll-shadow-left {\n /* stylelint-disable-next-line pine-design-system/no-hardcoded-colors */\n background: linear-gradient(to right, rgba(0, 0, 0, 0.1), transparent);\n border-bottom-left-radius: inherit;\n border-top-left-radius: inherit;\n left: 0;\n}\n\n.scroll-shadow-right {\n /* stylelint-disable-next-line pine-design-system/no-hardcoded-colors */\n background: linear-gradient(to left, rgba(0, 0, 0, 0.1), transparent);\n border-bottom-right-radius: inherit;\n border-top-right-radius: inherit;\n right: 0;\n}\n","import { Component, Element, Event, EventEmitter, Host, h, Prop, State, Listen } from '@stencil/core';\n\n@Component({\n tag: 'pds-table',\n styleUrls: ['pds-table.scss'],\n shadow: true,\n})\nexport class PdsTable {\n @Element() el: HTMLPdsTableElement;\n private scrollContainer: HTMLElement | null = null;\n private _responsiveHandleScroll: (() => void) | null = null;\n private _responsiveHandleResize: (() => void) | null = null;\n private _responsiveResizeObserver: ResizeObserver | null = null;\n private _teardownResponsive: (() => void) | null = null;\n\n /**\n * Determines if the table displays with reduced table cell padding.\n */\n @Prop() compact: boolean;\n\n /**\n * A unique identifier used for the table `id` attribute.\n */\n @Prop() componentId!: string;\n\n /**\n * Enables the table to be responsive by horizontally scrolling on smaller screens.\n */\n @Prop() responsive: boolean;\n\n /**\n * Determines if the should display a fixed first column.\n */\n @Prop() fixedColumn: boolean;\n\n /**\n * Determines if the table displays checkboxes for selectable rows.\n */\n @Prop() selectable: boolean;\n\n /**\n * Adds divider borders between table rows. The last row will not have a bottom border.\n * @defaultValue false\n */\n @Prop({ reflect: true }) rowDividers: boolean = false;\n\n /**\n * The name of the column to sort by on initial load.\n * Must match the text content of a sortable column header.\n */\n @Prop() defaultSortColumn?: string;\n\n /**\n * The direction to sort the default column on initial load.\n * Only applies if `defaultSortColumn` is set.\n * @defaultValue 'asc'\n */\n @Prop() defaultSortDirection?: 'asc' | 'desc' = 'asc';\n\n /**\n * The name of the column being sorted.\n * @defaultValue null\n */\n @State() sortingColumn: string | null = null;\n\n /**\n * The direction of sorting.\n * @defaultValue 'asc'\n */\n @State() sortingDirection: 'asc' | 'desc' = 'asc';\n\n\n /**\n * Event that is emitted when the checkbox is clicked, carrying the rowIndex and selected value.\n */\n @Event() pdsTableSelect: EventEmitter<{ rowIndex: number; isSelected: boolean }>;\n\n /**\n * Event that is emitted when the select all checkbox is clicked, carrying the selected value.\n */\n @Event() pdsTableSelectAll: EventEmitter<{ isSelected: boolean }>;\n\n componentDidLoad() {\n if (this.responsive) {\n this.setupResponsiveScrolling();\n }\n\n // Apply default sort if specified\n // Use requestAnimationFrame to defer until child components are fully initialized\n if (this.defaultSortColumn) {\n requestAnimationFrame(() => {\n void this.applyDefaultSort().catch((err) => {\n console.warn('Failed to apply default sort.', err);\n });\n });\n }\n }\n\n /**\n * Applies the default sort configuration on initial load.\n * Finds the matching column header and activates its sort state.\n * @private\n */\n private async applyDefaultSort() {\n // Normalize direction to handle invalid HTML attribute values\n const direction: 'asc' | 'desc' = this.defaultSortDirection === 'desc' ? 'desc' : 'asc';\n\n // Find the matching sortable header cell\n const columnHeaderCells = Array.from(\n this.el.querySelectorAll('pds-table-head-cell[sortable]')\n ) as HTMLPdsTableHeadCellElement[];\n\n const matchingCell = columnHeaderCells.find(\n (cell) => (cell.textContent ?? '').trim() === this.defaultSortColumn\n );\n\n if (matchingCell) {\n const columnName = (matchingCell.textContent ?? '').trim();\n // Sort the table data\n this.sortTable(columnName, direction);\n this.sortingColumn = columnName;\n this.sortingDirection = direction;\n\n // Activate the visual state on the header cell\n await matchingCell.setActiveSort(direction);\n } else {\n console.warn(`Default sort column \"${this.defaultSortColumn}\" not found.`);\n }\n }\n\n disconnectedCallback() {\n if (this._teardownResponsive) {\n this._teardownResponsive();\n this._teardownResponsive = null;\n }\n }\n\n /**\n * Sets up responsive scrolling behavior for the table.\n *\n * This method creates a horizontal scrolling system where:\n * - The table content can scroll horizontally when it exceeds the container width\n * - Scroll shadows appear at the left/right edges to indicate scrollable content\n * - Fixed columns remain sticky during horizontal scrolling\n * - Shadows respect border-radius and don't appear when there's nothing to scroll\n *\n * Architecture:\n * - Host element: Contains everything, respects parent constraints\n * - Container element: Handles horizontal scrolling (overflow-x: auto)\n * - Shadow elements: Positioned fixed relative to host, show scroll indicators\n *\n * @private\n */\n private setupResponsiveScrolling() {\n const container = this.el.shadowRoot?.querySelector('.pds-table-responsive-container') as HTMLElement;\n const leftShadow = this.el.shadowRoot?.querySelector('.scroll-shadow-left') as HTMLElement;\n const rightShadow = this.el.shadowRoot?.querySelector('.scroll-shadow-right') as HTMLElement;\n\n if (!container || !leftShadow || !rightShadow) return;\n\n // Store container reference for cleanup\n this.scrollContainer = container;\n\n /**\n * Updates the visibility of scroll shadows based on current scroll position.\n * Left shadow: Shows when scrolled away from start (hidden if fixedColumn is enabled)\n * Right shadow: Shows when there's content to scroll and not at the end\n */\n this._responsiveHandleScroll = () => {\n if (!this.scrollContainer) return;\n\n const scrollLeft = this.scrollContainer.scrollLeft;\n const maxScrollLeft = this.scrollContainer.scrollWidth - this.scrollContainer.clientWidth;\n\n // Show left shadow when scrolled away from start, but not if there's a fixed column\n leftShadow.style.opacity = (scrollLeft > 0 && !this.fixedColumn) ? '1' : '0';\n\n // Show right shadow only if there's content to scroll AND not at end\n rightShadow.style.opacity = (maxScrollLeft > 0 && scrollLeft < maxScrollLeft - 1) ? '1' : '0';\n };\n\n // Add scroll event listener to container element\n this.scrollContainer.addEventListener('scroll', this._responsiveHandleScroll, { passive: true });\n\n // Add resize observer to update shadows when container size changes\n if (typeof window !== 'undefined' && window.ResizeObserver) {\n try {\n this._responsiveResizeObserver = new ResizeObserver(() => {\n this._responsiveHandleScroll?.();\n });\n this._responsiveResizeObserver.observe(this.scrollContainer);\n } catch (error) {\n // ResizeObserver not available in some environments (e.g., tests)\n // Fall back to window resize listener only\n }\n }\n\n // Listen for window resize as fallback\n if (typeof window !== 'undefined') {\n this._responsiveHandleResize = () => {\n this._responsiveHandleScroll?.();\n };\n window.addEventListener('resize', this._responsiveHandleResize);\n }\n\n // Create teardown function for cleanup\n this._teardownResponsive = () => {\n if (this.scrollContainer && this._responsiveHandleScroll) {\n this.scrollContainer.removeEventListener('scroll', this._responsiveHandleScroll);\n this.scrollContainer = null;\n }\n\n if (this._responsiveResizeObserver) {\n this._responsiveResizeObserver.disconnect();\n this._responsiveResizeObserver = null;\n }\n\n if (typeof window !== 'undefined' && this._responsiveHandleResize) {\n window.removeEventListener('resize', this._responsiveHandleResize);\n this._responsiveHandleResize = null;\n }\n\n this._responsiveHandleScroll = null;\n };\n\n // Initial check after setup\n this._responsiveHandleScroll();\n }\n\n\n private classNames() {\n const classNames = ['pds-table'];\n\n if (this.compact) {\n classNames.push('is-compact');\n }\n\n if (this.responsive) {\n classNames.push('is-responsive');\n }\n\n return classNames.join(' ');\n }\n\n private sortTable(column: string, direction: 'asc' | 'desc') {\n const tableBody = this.el.querySelector('pds-table-body');\n\n // Return early if no table body exists\n if (!tableBody) return;\n\n // Get the rows in the table body\n const tableRows = Array.from(tableBody.querySelectorAll('pds-table-row'));\n\n // Find the column index based on the column name\n const columnHeaderCells: HTMLElement[] = Array.from(\n this.el.querySelectorAll('pds-table-head-cell[sortable]')\n );\n\n const columnHeaderCell = columnHeaderCells.find(\n (cell) => cell.innerText.trim() === column\n );\n\n if (!columnHeaderCell) {\n console.warn(`Column \"${column}\" not found.`);\n return;\n }\n\n const columnIndex = columnHeaderCells.indexOf(columnHeaderCell);\n\n // Sort the rows based on the content of the specified column\n tableRows.sort((a, b) => {\n const valueA = a.querySelector(`pds-table-cell:nth-child(${columnIndex + 1})`).textContent.trim();\n const valueB = b.querySelector(`pds-table-cell:nth-child(${columnIndex + 1})`).textContent.trim();\n\n if (direction === 'asc') {\n return valueA.localeCompare(valueB, undefined, { sensitivity: 'base' });\n } else {\n return valueB.localeCompare(valueA, undefined, { sensitivity: 'base' });\n }\n });\n\n // Clear and append the sorted rows back to the table body\n tableBody.innerHTML = '';\n tableRows.forEach((row) => {\n tableBody.appendChild(row);\n });\n }\n\n @Listen('pdsTableSort')\n handleTableSort(event: CustomEvent<{ column: string; direction: 'asc' | 'desc' }>) {\n if (event.defaultPrevented) return;\n\n const { direction } = event.detail;\n this.sortTable(event.detail.column, direction);\n this.sortingColumn = event.detail.column;\n this.sortingDirection = direction;\n }\n\n @Listen('pdsTableSelectAll')\n handleTableSelectAll(event: CustomEvent<{ isSelected: boolean }>) {\n if (event.defaultPrevented) return;\n\n const pdsTableBody = this.el.querySelector('pds-table-body');\n const tableRows = Array.from(pdsTableBody.querySelectorAll('pds-table-row'));\n\n tableRows.forEach((row) => {\n row.isSelected = event.detail.isSelected;\n });\n }\n\n @Listen('pdsTableRowSelected')\n async handleTableSelect(event: CustomEvent<{ rowIndex: number; isSelected: boolean }>) {\n if (event.defaultPrevented) return;\n\n const allTableRows = this.el.querySelectorAll('pds-table-row');\n const allSelectedRows = Array.from(allTableRows).every((row) => row.isSelected);\n const noneSelectedRows = Array.from(allTableRows).every((row) => !row.isSelected);\n const pdsTableHead = this.el.querySelector('pds-table-head');\n if (!pdsTableHead) return;\n\n const headerCheckbox = pdsTableHead.shadowRoot.querySelector('pds-checkbox');\n headerCheckbox.checked = allSelectedRows;\n headerCheckbox.indeterminate = !allSelectedRows && !noneSelectedRows;\n }\n\n render() {\n if (this.responsive) {\n return (\n <Host\n class=\"pds-table is-responsive pds-table-responsive-host\"\n id={this.componentId}\n role=\"grid\"\n selectable={this.selectable}\n tabindex=\"0\"\n part=\"table responsive-table\"\n >\n <div class=\"scroll-shadow-left\" part=\"scroll-shadow-left\"></div>\n <div class=\"scroll-shadow-right\" part=\"scroll-shadow-right\"></div>\n <div class=\"pds-table-responsive-container\" part=\"responsive-container\">\n <div class=\"pds-table-responsive-wrapper\" part=\"responsive-wrapper\">\n <div class={this.classNames()} part=\"table-inner\">\n <slot></slot>\n </div>\n </div>\n </div>\n </Host>\n );\n }\n\n return (\n <Host\n class={this.classNames()}\n id={this.componentId}\n role=\"grid\"\n selectable={this.selectable}\n tabindex=\"0\"\n part=\"table\"\n >\n <slot></slot>\n </Host>\n );\n }\n}\n"],"version":3}
@@ -3,7 +3,7 @@
3
3
  var index = require('./index-CI0W8NCh.js');
4
4
  var floatingUi_dom = require('./floating-ui.dom-Ca6tS7ef.js');
5
5
 
6
- const pdsDropdownMenuCss = ":host{display:block}.is-hidden{display:none}.pds-dropdown-menu--panel{background-color:var(--pine-color-background-container);border-radius:var(--pine-dimension-xs);left:var(--pine-dimension-none);min-width:170px;padding:var(--pine-dimension-xs);position:fixed;z-index:var(--pine-z-index-overlay)}:host-context([data-theme=dark]) .pds-dropdown-menu--panel{border:var(--pine-border)}";
6
+ const pdsDropdownMenuCss = ":host{display:block}.is-hidden{display:none}.pds-dropdown-menu--panel{background-color:var(--pine-color-background-container);border-radius:var(--pine-dimension-xs);left:var(--pine-dimension-none);min-width:170px;padding:var(--pine-dimension-xs);position:fixed;z-index:var(--pine-z-index-overlay)}:host-context([data-theme=dark]) .pds-dropdown-menu--panel{border:var(--pine-border)}::slotted(a),::slotted(button){-ms-flex-align:center;align-items:center;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;border-radius:var(--pine-dimension-xs);-webkit-box-sizing:border-box;box-sizing:border-box;color:var(--pine-color-text) !important;cursor:pointer;display:-ms-flexbox;display:flex;-ms-flex-positive:1;flex-grow:1;font:var(--pine-typography-body-medium);gap:var(--pine-dimension-xs);margin:calc(var(--pine-border-width) + 2px);padding:var(--pine-dimension-xs);text-align:start;text-decoration:none !important;width:calc(100% - (var(--pine-border-width) + 2px) * 2)}::slotted(.destructive){color:var(--pine-color-danger) !important}::slotted([aria-disabled=true]),::slotted([disabled]){cursor:not-allowed;opacity:0.5;pointer-events:none}";
7
7
 
8
8
  const PdsDropdownMenu = class {
9
9
  constructor(hostRef) {
@@ -30,14 +30,22 @@ const PdsDropdownMenu = class {
30
30
  this.slotEl = event.target;
31
31
  // Get all elements assigned to this slot
32
32
  const assignedElements = this.slotEl.assignedElements();
33
- // ensure assignedElements only contains pds-dropdown-menu-item or pds-dropdown-menu-separator
34
- // if there are other elements, throw an error
35
- const invalidElements = assignedElements.filter(el => el.tagName.toLowerCase() !== 'pds-dropdown-menu-item' && el.tagName.toLowerCase() !== 'pds-dropdown-menu-separator');
33
+ // Allowed elements: pds-dropdown-menu-item, pds-dropdown-menu-separator, <a>, <button>
34
+ // Raw <a> and <button> elements are allowed for edge cases requiring native browser/framework
35
+ // behavior (e.g., Rails UJS, Turbo) that cannot work through Shadow DOM.
36
+ const allowedTags = ['pds-dropdown-menu-item', 'pds-dropdown-menu-separator', 'a', 'button'];
37
+ const invalidElements = assignedElements.filter(el => !allowedTags.includes(el.tagName.toLowerCase()));
36
38
  if (invalidElements.length > 0) {
37
- throw new Error(`pds-dropdown-menu only accepts pds-dropdown-menu-item and pds-dropdown-menu-separator elements`);
39
+ const invalidTags = invalidElements.map(el => el.tagName.toLowerCase()).join(', ');
40
+ console.warn(`pds-dropdown-menu: Unexpected element(s) found: ${invalidTags}. ` +
41
+ `Expected: ${allowedTags.join(', ')}`);
38
42
  }
39
- // Store all menu items for keyboard navigation
40
- this.menuItems = assignedElements.filter(el => el.tagName.toLowerCase() === 'pds-dropdown-menu-item');
43
+ // Store all focusable items for keyboard navigation
44
+ // This includes pds-dropdown-menu-item components and raw <a>/<button> elements
45
+ this.menuItems = assignedElements.filter(el => {
46
+ const tag = el.tagName.toLowerCase();
47
+ return tag === 'pds-dropdown-menu-item' || tag === 'a' || tag === 'button';
48
+ });
41
49
  };
42
50
  // Toggle dropdown open/closed
43
51
  this.toggleDropdown = () => {
@@ -106,31 +114,66 @@ const PdsDropdownMenu = class {
106
114
  this.cleanupAutoUpdate = null;
107
115
  }
108
116
  }
117
+ // Check if a menu item is disabled (handles both component and raw elements)
118
+ isItemDisabled(item) {
119
+ const tagName = item.tagName.toLowerCase();
120
+ if (tagName === 'pds-dropdown-menu-item') {
121
+ return item.disabled;
122
+ }
123
+ else if (tagName === 'button') {
124
+ return item.disabled;
125
+ }
126
+ else if (tagName === 'a') {
127
+ return item.getAttribute('aria-disabled') === 'true';
128
+ }
129
+ return false;
130
+ }
109
131
  // Get the index of the currently focused menu item
110
132
  getFocusedItemIndex() {
111
133
  const activeElement = document.activeElement;
112
134
  if (!activeElement)
113
135
  return -1;
114
- return this.menuItems.findIndex(item => item === activeElement);
136
+ // For raw elements, check direct match
137
+ // For pds-dropdown-menu-item, also check if the active element is inside the shadow root
138
+ return this.menuItems.findIndex(item => {
139
+ if (item === activeElement)
140
+ return true;
141
+ // Check if activeElement is inside the item's shadow root (for pds-dropdown-menu-item)
142
+ if (item.tagName.toLowerCase() === 'pds-dropdown-menu-item') {
143
+ const shadowRoot = item.shadowRoot;
144
+ if (shadowRoot === null || shadowRoot === void 0 ? void 0 : shadowRoot.contains(activeElement))
145
+ return true;
146
+ }
147
+ return false;
148
+ });
115
149
  }
116
150
  // Focus a specific menu item by index
117
151
  focusItemByIndex(index) {
118
- var _a, _b, _c, _d;
152
+ var _a, _b, _c, _d, _e;
119
153
  if (index >= 0 && index < this.menuItems.length) {
120
154
  this.currentFocusIndex = index;
121
- // Focus the inner button/link instead of the host element
122
- const menuItem = this.menuItems[index];
123
- const innerButton = (_a = menuItem.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('button');
124
- const innerLink = (_d = (_c = (_b = menuItem.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('pds-link')) === null || _c === void 0 ? void 0 : _c.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector('a');
125
- if (innerButton) {
126
- return innerButton.focus();
127
- }
128
- else if (innerLink) {
129
- return innerLink.focus();
155
+ const item = this.menuItems[index];
156
+ const tagName = item.tagName.toLowerCase();
157
+ if (tagName === 'pds-dropdown-menu-item') {
158
+ // For pds-dropdown-menu-item, focus the inner element
159
+ const menuItem = item;
160
+ const innerButton = (_a = menuItem.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('button');
161
+ const innerLink = ((_d = (_c = (_b = menuItem.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('pds-link')) === null || _c === void 0 ? void 0 : _c.shadowRoot) === null || _d === void 0 ? void 0 : _d.querySelector('a'))
162
+ || ((_e = menuItem.shadowRoot) === null || _e === void 0 ? void 0 : _e.querySelector('a'));
163
+ if (innerButton) {
164
+ innerButton.focus();
165
+ }
166
+ else if (innerLink) {
167
+ innerLink.focus();
168
+ }
169
+ else {
170
+ // Fallback to focusing the host
171
+ menuItem.focus();
172
+ }
130
173
  }
131
174
  else {
132
- // Fallback to focusing the host if we can't find the inner element
133
- menuItem.focus();
175
+ // For raw <a> or <button> elements, focus directly
176
+ item.focus();
134
177
  }
135
178
  }
136
179
  }
@@ -140,7 +183,7 @@ const PdsDropdownMenu = class {
140
183
  // Skip disabled items
141
184
  let attempts = 0;
142
185
  const maxAttempts = this.menuItems.length;
143
- while (attempts < maxAttempts && this.menuItems[nextIndex].disabled) {
186
+ while (attempts < maxAttempts && this.isItemDisabled(this.menuItems[nextIndex])) {
144
187
  nextIndex = (nextIndex + 1) % this.menuItems.length;
145
188
  attempts++;
146
189
  }
@@ -157,7 +200,7 @@ const PdsDropdownMenu = class {
157
200
  // Skip disabled items
158
201
  let attempts = 0;
159
202
  const maxAttempts = this.menuItems.length;
160
- while (attempts < maxAttempts && this.menuItems[prevIndex].disabled) {
203
+ while (attempts < maxAttempts && this.isItemDisabled(this.menuItems[prevIndex])) {
161
204
  prevIndex = prevIndex <= 0 ? this.menuItems.length - 1 : prevIndex - 1;
162
205
  attempts++;
163
206
  }
@@ -188,7 +231,7 @@ const PdsDropdownMenu = class {
188
231
  if (this.menuItems.length > 0) {
189
232
  // Find first non-disabled item
190
233
  let firstIndex = 0;
191
- while (firstIndex < this.menuItems.length && this.menuItems[firstIndex].disabled) {
234
+ while (firstIndex < this.menuItems.length && this.isItemDisabled(this.menuItems[firstIndex])) {
192
235
  firstIndex++;
193
236
  }
194
237
  if (firstIndex < this.menuItems.length) {
@@ -201,7 +244,7 @@ const PdsDropdownMenu = class {
201
244
  if (this.menuItems.length > 0) {
202
245
  // Find last non-disabled item
203
246
  let lastIndex = this.menuItems.length - 1;
204
- while (lastIndex >= 0 && this.menuItems[lastIndex].disabled) {
247
+ while (lastIndex >= 0 && this.isItemDisabled(this.menuItems[lastIndex])) {
205
248
  lastIndex--;
206
249
  }
207
250
  if (lastIndex >= 0) {
@@ -231,7 +274,7 @@ const PdsDropdownMenu = class {
231
274
  event.preventDefault();
232
275
  // Find the first non-disabled item
233
276
  let firstFocusableIndex = 0;
234
- while (firstFocusableIndex < this.menuItems.length && this.menuItems[firstFocusableIndex].disabled) {
277
+ while (firstFocusableIndex < this.menuItems.length && this.isItemDisabled(this.menuItems[firstFocusableIndex])) {
235
278
  firstFocusableIndex++;
236
279
  }
237
280
  if (firstFocusableIndex < this.menuItems.length) {
@@ -243,7 +286,7 @@ const PdsDropdownMenu = class {
243
286
  event.preventDefault();
244
287
  // Find the first non-disabled item
245
288
  let firstFocusableIndex = 0;
246
- while (firstFocusableIndex < this.menuItems.length && this.menuItems[firstFocusableIndex].disabled) {
289
+ while (firstFocusableIndex < this.menuItems.length && this.isItemDisabled(this.menuItems[firstFocusableIndex])) {
247
290
  firstFocusableIndex++;
248
291
  }
249
292
  if (firstFocusableIndex < this.menuItems.length) {
@@ -266,7 +309,7 @@ const PdsDropdownMenu = class {
266
309
  }
267
310
  }
268
311
  render() {
269
- return (index.h(index.Host, { key: 'bedd78a69e84f10abb3c714c02227fa76e255a35', id: this.componentId }, index.h("slot", { key: 'd2bf56037a85679a677470d04865823966ca19d6', name: "trigger", onSlotchange: this.handleTriggerSlotChange }), index.h("pds-box", { key: '64f56896103bb6cca6c71020d3d37c375d300c40', "border-radius": "sm", display: "flex", direction: "column", class: "pds-dropdown-menu--panel is-hidden", shadow: "100", role: "menu", "aria-orientation": "vertical", part: "menu-panel" }, index.h("slot", { key: '0303160562f74fe9d32cc020c4539a7c8fc288a9', onSlotchange: this.handleSlotChange }))));
312
+ return (index.h(index.Host, { key: '3144bc264072eccf89cdca45a0b28eb004b5d06e', id: this.componentId }, index.h("slot", { key: '500288f266dc7ab7e1ac5070e628c31a6ed50861', name: "trigger", onSlotchange: this.handleTriggerSlotChange }), index.h("pds-box", { key: '4085130e381b8be28e2e36de073c0755a455e30c', "border-radius": "sm", display: "flex", direction: "column", class: "pds-dropdown-menu--panel is-hidden", shadow: "100", role: "menu", "aria-orientation": "vertical", part: "menu-panel" }, index.h("slot", { key: '2c4d53799576d1c6913df9bb854bfbaf50e5032c', onSlotchange: this.handleSlotChange }))));
270
313
  }
271
314
  get host() { return index.getElement(this); }
272
315
  };