@pine-ds/icons 9.6.0 → 9.6.2

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.
@@ -39,10 +39,26 @@ export class PdsIcon {
39
39
  if (!this.didLoadIcon) {
40
40
  this.loadIcon();
41
41
  }
42
+ // Fallback: Ensure icon loads even if IntersectionObserver doesn't fire
43
+ setTimeout(() => {
44
+ if (!this.svgContent && !this.isVisible) {
45
+ this.isVisible = true;
46
+ this.loadIcon();
47
+ }
48
+ }, 100);
49
+ // Additional fallback for client-side navigation (React Router, etc.)
50
+ // React's useLayoutEffect and rendering cycles can delay visibility detection
51
+ setTimeout(() => {
52
+ if (!this.svgContent && !this.isVisible) {
53
+ this.isVisible = true;
54
+ this.loadIcon();
55
+ }
56
+ }, 500);
42
57
  }
43
58
  componentWillLoad() {
44
59
  this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
45
60
  this.setCSSVariables();
61
+ this.setupInitialAriaLabel();
46
62
  }
47
63
  setCSSVariables() {
48
64
  this.el.style.setProperty(`--dimension-icon-height`, this.iconSize());
@@ -50,10 +66,18 @@ export class PdsIcon {
50
66
  this.el.style.setProperty(`--color-icon-fill`, typeof this.color !== 'undefined' ? this.color : 'currentColor');
51
67
  }
52
68
  connectedCallback() {
53
- this.waitUntilVisible(this.el, '50px', () => {
69
+ // Handle re-connection during client-side navigation
70
+ if (!this.isVisible && !this.svgContent) {
71
+ this.waitUntilVisible(this.el, '50px', () => {
72
+ this.isVisible = true;
73
+ this.loadIcon();
74
+ });
75
+ }
76
+ // Immediate load attempt if already visible (e.g., during React navigation)
77
+ if (this.isElementInViewport(this.el)) {
54
78
  this.isVisible = true;
55
79
  this.loadIcon();
56
- });
80
+ }
57
81
  }
58
82
  disconnectedCallback() {
59
83
  if (this.io) {
@@ -64,7 +88,16 @@ export class PdsIcon {
64
88
  updateStyles() {
65
89
  this.setCSSVariables();
66
90
  }
91
+ onIconPropertyChange() {
92
+ this.loadIcon();
93
+ // Update aria-label when icon properties change
94
+ this.setupInitialAriaLabel();
95
+ }
67
96
  loadIcon() {
97
+ // Reset load state when URL changes
98
+ this.didLoadIcon = false;
99
+ // Clear existing content to prevent stale content when switching icons
100
+ this.svgContent = undefined;
68
101
  if (Build.isBrowser && this.isVisible) {
69
102
  const url = getUrl(this);
70
103
  if (url) {
@@ -72,15 +105,23 @@ export class PdsIcon {
72
105
  this.svgContent = pdsIconContent.get(url);
73
106
  }
74
107
  else {
75
- getSvgContent(url).then(() => (this.svgContent = pdsIconContent.get(url)));
108
+ // Fix: Ensure promise callback triggers re-render and handle errors
109
+ getSvgContent(url)
110
+ .then(() => {
111
+ // Force re-render by setting state in next tick
112
+ setTimeout(() => {
113
+ this.svgContent = pdsIconContent.get(url);
114
+ }, 0);
115
+ })
116
+ .catch(() => {
117
+ // Handle fetch errors gracefully
118
+ this.svgContent = '';
119
+ });
76
120
  }
77
121
  this.didLoadIcon = true;
78
122
  }
79
123
  }
80
124
  this.iconName = getName(this.name, this.icon);
81
- if (this.iconName) {
82
- this.ariaLabel = this.iconName.replace(/\-/g, ' ');
83
- }
84
125
  }
85
126
  render() {
86
127
  const { ariaLabel, flipRtl, iconName, inheritedAttributes } = this;
@@ -88,11 +129,22 @@ export class PdsIcon {
88
129
  ? shouldRtlFlipIcon(iconName, this.el) && flipRtl !== false
89
130
  : false;
90
131
  const shouldFlip = flipRtl || shouldIconAutoFlip;
91
- return (h(Host, Object.assign({ key: 'bc8e46daa75df27a8039e0e767bdb43164ad7d4c', "aria-label": ariaLabel !== undefined && !this.hasAriaHidden() ? ariaLabel : null, alt: "", role: "img", class: Object.assign(Object.assign({}, createColorClasses(this.color)), { 'flip-rtl': shouldFlip, 'icon-rtl': shouldFlip && isRTL(this.el) }) }, inheritedAttributes), Build.isBrowser && this.svgContent ? (h("div", { class: "icon-inner", innerHTML: this.svgContent })) : (h("div", { class: "icon-inner" }))));
132
+ // Use inherited aria-label if provided, otherwise fall back to auto-generated one
133
+ const finalAriaLabel = inheritedAttributes['aria-label'] || ariaLabel;
134
+ return (h(Host, Object.assign({ key: '43aa73531314e6529a887468e69362430d006229', "aria-label": finalAriaLabel !== undefined && !this.hasAriaHidden() ? finalAriaLabel : null, alt: "", role: "img", class: Object.assign(Object.assign({}, createColorClasses(this.color)), { 'flip-rtl': shouldFlip, 'icon-rtl': shouldFlip && isRTL(this.el) }) }, inheritedAttributes), Build.isBrowser && this.svgContent ? (h("div", { class: "icon-inner", innerHTML: this.svgContent })) : (h("div", { class: "icon-inner" }))));
92
135
  }
93
136
  /*****
94
137
  * Private Methods
95
138
  ****/
139
+ setupInitialAriaLabel() {
140
+ // Only set aria-label during initial load if one isn't already provided
141
+ if (!this.inheritedAttributes['aria-label']) {
142
+ const iconName = getName(this.name, this.icon);
143
+ if (iconName) {
144
+ this.ariaLabel = iconName.replace(/\-/g, ' ');
145
+ }
146
+ }
147
+ }
96
148
  waitUntilVisible(el, rootMargin, cb) {
97
149
  if (Build.isBrowser && typeof window !== 'undefined' && (window).IntersectionObserver) {
98
150
  const io = (this.io = new (window).IntersectionObserver((data) => {
@@ -103,6 +155,18 @@ export class PdsIcon {
103
155
  }
104
156
  }, { rootMargin }));
105
157
  io.observe(el);
158
+ // Safety timeout for client-side navigation scenarios
159
+ // Sometimes IntersectionObserver doesn't fire during React navigation
160
+ setTimeout(() => {
161
+ if (this.io && !this.isVisible) {
162
+ // Check if element is actually visible in viewport
163
+ if (this.isElementInViewport(el)) {
164
+ this.io.disconnect();
165
+ this.io = undefined;
166
+ cb();
167
+ }
168
+ }
169
+ }, 1000);
106
170
  }
107
171
  else {
108
172
  // browser doesn't support IntersectionObserver
@@ -110,6 +174,54 @@ export class PdsIcon {
110
174
  cb();
111
175
  }
112
176
  }
177
+ isElementInViewport(el) {
178
+ if (!el || !el.isConnected)
179
+ return false;
180
+ const rect = el.getBoundingClientRect();
181
+ const windowHeight = window.innerHeight || document.documentElement.clientHeight;
182
+ const windowWidth = window.innerWidth || document.documentElement.clientWidth;
183
+ return (rect.top >= 0 &&
184
+ rect.left >= 0 &&
185
+ rect.bottom <= windowHeight &&
186
+ rect.right <= windowWidth) || (
187
+ // Also consider partially visible elements
188
+ rect.top < windowHeight &&
189
+ rect.bottom > 0 &&
190
+ rect.left < windowWidth &&
191
+ rect.right > 0);
192
+ }
193
+ /**
194
+ * Debug method to help diagnose loading issues
195
+ * Call from browser console: document.querySelector('pds-icon').debugIconState()
196
+ */
197
+ debugIconState() {
198
+ var _a;
199
+ const url = getUrl(this);
200
+ const rect = this.el.getBoundingClientRect();
201
+ console.log('PdsIcon Debug State:', {
202
+ name: this.name,
203
+ src: this.src,
204
+ icon: this.icon,
205
+ iconName: this.iconName,
206
+ url,
207
+ isVisible: this.isVisible,
208
+ didLoadIcon: this.didLoadIcon,
209
+ hasSvgContent: !!this.svgContent,
210
+ svgContentLength: ((_a = this.svgContent) === null || _a === void 0 ? void 0 : _a.length) || 0,
211
+ isInCache: url ? pdsIconContent.has(url) : false,
212
+ cachedContent: url ? pdsIconContent.get(url) : null,
213
+ element: this.el,
214
+ // Client-side navigation specific debug info
215
+ isConnected: this.el.isConnected,
216
+ isInViewport: this.isElementInViewport(this.el),
217
+ hasIntersectionObserver: !!this.io,
218
+ boundingClientRect: rect,
219
+ windowDimensions: {
220
+ width: window.innerWidth || document.documentElement.clientWidth,
221
+ height: window.innerHeight || document.documentElement.clientHeight
222
+ }
223
+ });
224
+ }
113
225
  static get is() { return "pds-icon"; }
114
226
  static get encapsulation() { return "shadow"; }
115
227
  static get originalStyleUrls() {
@@ -259,13 +371,13 @@ export class PdsIcon {
259
371
  "methodName": "updateStyles"
260
372
  }, {
261
373
  "propName": "name",
262
- "methodName": "loadIcon"
374
+ "methodName": "onIconPropertyChange"
263
375
  }, {
264
376
  "propName": "src",
265
- "methodName": "loadIcon"
377
+ "methodName": "onIconPropertyChange"
266
378
  }, {
267
379
  "propName": "icon",
268
- "methodName": "loadIcon"
380
+ "methodName": "onIconPropertyChange"
269
381
  }];
270
382
  }
271
383
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pds-icon.js","sourceRoot":"","sources":["../../../../src/components/pds-icon/pds-icon.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Build, Component, Element, Host, Prop, State, Watch, h } from '@stencil/core';\nimport { getSvgContent, pdsIconContent } from './request';\nimport { getName, getUrl, inheritAttributes, isRTL, shouldRtlFlipIcon } from './utils';\n\n@Component({\n tag: 'pds-icon',\n assetsDirs: ['svg'],\n styleUrl: 'pds-icon.scss',\n shadow: true,\n})\nexport class PdsIcon {\n private didLoadIcon = false;\n private iconName: string | null = null;\n private io?: IntersectionObserver;\n private inheritedAttributes: { [k: string]: any } = {}; // eslint-disable-line @typescript-eslint/no-explicit-any\n\n @Element() el!: HTMLPdsIconElement;\n\n @State() private ariaLabel?: string;\n @State() private isVisible = false;\n @State() private svgContent?: string;\n\n /**\n *\n * The color of the icon\n *\n */\n @Prop() color?: string;\n\n /**\n * Determines if the icon should be flipped when the `dir` is right-to-left (`\"rtl\"`).\n * This is automatically enabled for icons that are in the `ICONS_TO_FLIP` list and\n * when the `dir` is `\"rtl\"`. If `flipRtl` is set to `false`, the icon will not be flipped\n * even if the `dir` is `\"rtl\"`.\n */\n @Prop() flipRtl?: boolean;\n\n /**\n * This is a combination of both `name` and `src`. If a `src` URL is detected,\n * it will set the `src` property. Otherwise it assumes it's a built-in named\n * SVG and sets the `name` property.\n */\n @Prop() icon?: any;\n\n /**\n * The name of the icon to use from\n * the built-in set.\n */\n @Prop({ reflect: true }) name?: string;\n\n /**\n * The size of the icon. This can be\n * 'small', 'regular', 'medium', 'large', or a\n * custom value (40px, 1rem, etc)\n *\n */\n @Prop({ reflect: true }) size?:\n | 'small' // 12px\n | 'regular' // 16px\n | 'medium' // 20px\n | 'large' // 24px\n | 'auto'\n | string = 'regular'\n\n /**\n *\n * Specifies the exact `src` of an SVG file to use.\n */\n @Prop() src?: string;\n\n private iconSize() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sizes: { [key: string]: any } = {\n small: '12px',\n regular: '16px',\n medium: '20px',\n large: '24px',\n }\n\n if (sizes[this.size]) {\n return sizes[this.size];\n } else {\n return this.size;\n }\n }\n\n componentDidLoad() {\n this.setCSSVariables();\n\n if (!this.didLoadIcon) {\n this.loadIcon();\n }\n }\n\n componentWillLoad() {\n this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);\n this.setCSSVariables();\n }\n\n setCSSVariables() {\n this.el.style.setProperty(`--dimension-icon-height`, this.iconSize());\n this.el.style.setProperty(`--dimension-icon-width`, this.iconSize());\n this.el.style.setProperty(`--color-icon-fill`, typeof this.color !== 'undefined' ? this.color : 'currentColor');\n }\n\n connectedCallback() {\n this.waitUntilVisible(this.el, '50px', () => {\n this.isVisible = true;\n this.loadIcon();\n })\n }\n\n disconnectedCallback() {\n if (this.io) {\n this.io.disconnect();\n this.io = undefined;\n }\n }\n\n @Watch('size')\n @Watch('color')\n updateStyles() {\n this.setCSSVariables();\n }\n\n @Watch('name')\n @Watch('src')\n @Watch('icon')\n loadIcon() {\n if (Build.isBrowser && this.isVisible) {\n const url = getUrl(this);\n if (url) {\n if (pdsIconContent.has(url)) {\n this.svgContent = pdsIconContent.get(url);\n } else {\n getSvgContent(url).then(() => (this.svgContent = pdsIconContent.get(url)));\n }\n this.didLoadIcon = true;\n }\n }\n\n this.iconName = getName(this.name, this.icon);\n\n if (this.iconName) {\n this.ariaLabel = this.iconName.replace(/\\-/g, ' ');\n }\n }\n\n render() {\n const { ariaLabel, flipRtl, iconName,inheritedAttributes } = this;\n const shouldIconAutoFlip = iconName\n ? shouldRtlFlipIcon(iconName, this.el) && flipRtl !== false\n : false;\n const shouldFlip = flipRtl || shouldIconAutoFlip;\n\n return (\n\n <Host\n aria-label={ariaLabel !== undefined && !this.hasAriaHidden() ? ariaLabel : null }\n alt=\"\"\n role=\"img\"\n class={{\n ...createColorClasses(this.color),\n 'flip-rtl': shouldFlip,\n 'icon-rtl': shouldFlip && isRTL(this.el)\n }}\n {...inheritedAttributes}\n >\n {Build.isBrowser && this.svgContent ? (\n <div class=\"icon-inner\" innerHTML={this.svgContent}></div>\n ) : (\n <div class=\"icon-inner\"></div>\n )}\n </Host>\n )\n }\n\n /*****\n * Private Methods\n ****/\n\n private waitUntilVisible(el: HTMLElement, rootMargin: string, cb: () => void) {\n if (Build.isBrowser && typeof window !== 'undefined' && (window).IntersectionObserver) {\n const io = (this.io = new (window).IntersectionObserver(\n (data: IntersectionObserverEntry[]) => {\n if (data[0].isIntersecting) {\n io.disconnect();\n this.io = undefined;\n cb();\n }\n },\n { rootMargin },\n ));\n\n io.observe(el);\n } else {\n // browser doesn't support IntersectionObserver\n // so just fallback to always show it\n cb();\n }\n }\n\n private hasAriaHidden = () => {\n const { el } = this;\n\n return el.hasAttribute('aria-hidden') && el.getAttribute('aria-hidden') === 'true';\n }\n}\n\nconst createColorClasses = (color: string | undefined) => {\n return color\n ? {\n 'pds-color': true,\n [`pds-color-${color}`]: true,\n }\n : null;\n };\n"]}
1
+ {"version":3,"file":"pds-icon.js","sourceRoot":"","sources":["../../../../src/components/pds-icon/pds-icon.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Build, Component, Element, Host, Prop, State, Watch, h } from '@stencil/core';\nimport { getSvgContent, pdsIconContent } from './request';\nimport { getName, getUrl, inheritAttributes, isRTL, shouldRtlFlipIcon } from './utils';\n\n@Component({\n tag: 'pds-icon',\n assetsDirs: ['svg'],\n styleUrl: 'pds-icon.scss',\n shadow: true,\n})\nexport class PdsIcon {\n private didLoadIcon = false;\n private iconName: string | null = null;\n private io?: IntersectionObserver;\n private inheritedAttributes: { [k: string]: any } = {}; // eslint-disable-line @typescript-eslint/no-explicit-any\n\n @Element() el!: HTMLPdsIconElement;\n\n @State() private ariaLabel?: string;\n @State() private isVisible = false;\n @State() private svgContent?: string;\n\n /**\n *\n * The color of the icon\n *\n */\n @Prop() color?: string;\n\n /**\n * Determines if the icon should be flipped when the `dir` is right-to-left (`\"rtl\"`).\n * This is automatically enabled for icons that are in the `ICONS_TO_FLIP` list and\n * when the `dir` is `\"rtl\"`. If `flipRtl` is set to `false`, the icon will not be flipped\n * even if the `dir` is `\"rtl\"`.\n */\n @Prop() flipRtl?: boolean;\n\n /**\n * This is a combination of both `name` and `src`. If a `src` URL is detected,\n * it will set the `src` property. Otherwise it assumes it's a built-in named\n * SVG and sets the `name` property.\n */\n @Prop() icon?: any;\n\n /**\n * The name of the icon to use from\n * the built-in set.\n */\n @Prop({ reflect: true }) name?: string;\n\n /**\n * The size of the icon. This can be\n * 'small', 'regular', 'medium', 'large', or a\n * custom value (40px, 1rem, etc)\n *\n */\n @Prop({ reflect: true }) size?:\n | 'small' // 12px\n | 'regular' // 16px\n | 'medium' // 20px\n | 'large' // 24px\n | 'auto'\n | string = 'regular'\n\n /**\n *\n * Specifies the exact `src` of an SVG file to use.\n */\n @Prop() src?: string;\n\n private iconSize() {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sizes: { [key: string]: any } = {\n small: '12px',\n regular: '16px',\n medium: '20px',\n large: '24px',\n }\n\n if (sizes[this.size]) {\n return sizes[this.size];\n } else {\n return this.size;\n }\n }\n\n componentDidLoad() {\n this.setCSSVariables();\n\n if (!this.didLoadIcon) {\n this.loadIcon();\n }\n\n // Fallback: Ensure icon loads even if IntersectionObserver doesn't fire\n setTimeout(() => {\n if (!this.svgContent && !this.isVisible) {\n this.isVisible = true;\n this.loadIcon();\n }\n }, 100);\n\n // Additional fallback for client-side navigation (React Router, etc.)\n // React's useLayoutEffect and rendering cycles can delay visibility detection\n setTimeout(() => {\n if (!this.svgContent && !this.isVisible) {\n this.isVisible = true;\n this.loadIcon();\n }\n }, 500);\n }\n\n componentWillLoad() {\n this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);\n this.setCSSVariables();\n this.setupInitialAriaLabel();\n }\n\n setCSSVariables() {\n this.el.style.setProperty(`--dimension-icon-height`, this.iconSize());\n this.el.style.setProperty(`--dimension-icon-width`, this.iconSize());\n this.el.style.setProperty(`--color-icon-fill`, typeof this.color !== 'undefined' ? this.color : 'currentColor');\n }\n\n connectedCallback() {\n // Handle re-connection during client-side navigation\n if (!this.isVisible && !this.svgContent) {\n this.waitUntilVisible(this.el, '50px', () => {\n this.isVisible = true;\n this.loadIcon();\n });\n }\n\n // Immediate load attempt if already visible (e.g., during React navigation)\n if (this.isElementInViewport(this.el)) {\n this.isVisible = true;\n this.loadIcon();\n }\n }\n\n disconnectedCallback() {\n if (this.io) {\n this.io.disconnect();\n this.io = undefined;\n }\n }\n\n @Watch('size')\n @Watch('color')\n updateStyles() {\n this.setCSSVariables();\n }\n\n @Watch('name')\n @Watch('src')\n @Watch('icon')\n onIconPropertyChange() {\n this.loadIcon();\n // Update aria-label when icon properties change\n this.setupInitialAriaLabel();\n }\n\n loadIcon() {\n // Reset load state when URL changes\n this.didLoadIcon = false;\n\n // Clear existing content to prevent stale content when switching icons\n this.svgContent = undefined;\n\n if (Build.isBrowser && this.isVisible) {\n const url = getUrl(this);\n if (url) {\n if (pdsIconContent.has(url)) {\n this.svgContent = pdsIconContent.get(url);\n } else {\n // Fix: Ensure promise callback triggers re-render and handle errors\n getSvgContent(url)\n .then(() => {\n // Force re-render by setting state in next tick\n setTimeout(() => {\n this.svgContent = pdsIconContent.get(url);\n }, 0);\n })\n .catch(() => {\n // Handle fetch errors gracefully\n this.svgContent = '';\n });\n }\n this.didLoadIcon = true;\n }\n }\n\n this.iconName = getName(this.name, this.icon);\n }\n\n render() {\n const { ariaLabel, flipRtl, iconName,inheritedAttributes } = this;\n const shouldIconAutoFlip = iconName\n ? shouldRtlFlipIcon(iconName, this.el) && flipRtl !== false\n : false;\n const shouldFlip = flipRtl || shouldIconAutoFlip;\n\n // Use inherited aria-label if provided, otherwise fall back to auto-generated one\n const finalAriaLabel = inheritedAttributes['aria-label'] || ariaLabel;\n\n return (\n\n <Host\n aria-label={finalAriaLabel !== undefined && !this.hasAriaHidden() ? finalAriaLabel : null }\n alt=\"\"\n role=\"img\"\n class={{\n ...createColorClasses(this.color),\n 'flip-rtl': shouldFlip,\n 'icon-rtl': shouldFlip && isRTL(this.el)\n }}\n {...inheritedAttributes}\n >\n {Build.isBrowser && this.svgContent ? (\n <div class=\"icon-inner\" innerHTML={this.svgContent}></div>\n ) : (\n <div class=\"icon-inner\"></div>\n )}\n </Host>\n )\n }\n\n /*****\n * Private Methods\n ****/\n\n private setupInitialAriaLabel() {\n // Only set aria-label during initial load if one isn't already provided\n if (!this.inheritedAttributes['aria-label']) {\n const iconName = getName(this.name, this.icon);\n if (iconName) {\n this.ariaLabel = iconName.replace(/\\-/g, ' ');\n }\n }\n }\n\n private waitUntilVisible(el: HTMLElement, rootMargin: string, cb: () => void) {\n if (Build.isBrowser && typeof window !== 'undefined' && (window).IntersectionObserver) {\n const io = (this.io = new (window).IntersectionObserver(\n (data: IntersectionObserverEntry[]) => {\n if (data[0].isIntersecting) {\n io.disconnect();\n this.io = undefined;\n cb();\n }\n },\n { rootMargin },\n ));\n\n io.observe(el);\n\n // Safety timeout for client-side navigation scenarios\n // Sometimes IntersectionObserver doesn't fire during React navigation\n setTimeout(() => {\n if (this.io && !this.isVisible) {\n // Check if element is actually visible in viewport\n if (this.isElementInViewport(el)) {\n this.io.disconnect();\n this.io = undefined;\n cb();\n }\n }\n }, 1000);\n } else {\n // browser doesn't support IntersectionObserver\n // so just fallback to always show it\n cb();\n }\n }\n\n private isElementInViewport(el: HTMLElement): boolean {\n if (!el || !el.isConnected) return false;\n\n const rect = el.getBoundingClientRect();\n const windowHeight = window.innerHeight || document.documentElement.clientHeight;\n const windowWidth = window.innerWidth || document.documentElement.clientWidth;\n\n return (\n rect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= windowHeight &&\n rect.right <= windowWidth\n ) || (\n // Also consider partially visible elements\n rect.top < windowHeight &&\n rect.bottom > 0 &&\n rect.left < windowWidth &&\n rect.right > 0\n );\n }\n\n private hasAriaHidden = () => {\n const { el } = this;\n\n return el.hasAttribute('aria-hidden') && el.getAttribute('aria-hidden') === 'true';\n }\n\n /**\n * Debug method to help diagnose loading issues\n * Call from browser console: document.querySelector('pds-icon').debugIconState()\n */\n debugIconState() {\n const url = getUrl(this);\n const rect = this.el.getBoundingClientRect();\n\n console.log('PdsIcon Debug State:', {\n name: this.name,\n src: this.src,\n icon: this.icon,\n iconName: this.iconName,\n url,\n isVisible: this.isVisible,\n didLoadIcon: this.didLoadIcon,\n hasSvgContent: !!this.svgContent,\n svgContentLength: this.svgContent?.length || 0,\n isInCache: url ? pdsIconContent.has(url) : false,\n cachedContent: url ? pdsIconContent.get(url) : null,\n element: this.el,\n // Client-side navigation specific debug info\n isConnected: this.el.isConnected,\n isInViewport: this.isElementInViewport(this.el),\n hasIntersectionObserver: !!this.io,\n boundingClientRect: rect,\n windowDimensions: {\n width: window.innerWidth || document.documentElement.clientWidth,\n height: window.innerHeight || document.documentElement.clientHeight\n }\n });\n }\n}\n\nconst createColorClasses = (color: string | undefined) => {\n return color\n ? {\n 'pds-color': true,\n [`pds-color-${color}`]: true,\n }\n : null;\n };\n"]}
@@ -10,10 +10,18 @@ export const getSvgContent = (url, sanitize = false) => {
10
10
  if (!parser) {
11
11
  parser = new DOMParser();
12
12
  }
13
- const doc = parser.parseFromString(url, 'text/html');
14
- const svg = doc.querySelector('svg');
15
- if (svg) {
16
- pdsIconContent.set(url, svg.outerHTML);
13
+ try {
14
+ const doc = parser.parseFromString(url, 'text/html');
15
+ const svg = doc.querySelector('svg');
16
+ if (svg) {
17
+ pdsIconContent.set(url, svg.outerHTML);
18
+ }
19
+ else {
20
+ pdsIconContent.set(url, '');
21
+ }
22
+ }
23
+ catch (error) {
24
+ pdsIconContent.set(url, '');
17
25
  }
18
26
  return Promise.resolve();
19
27
  }
@@ -23,12 +31,25 @@ export const getSvgContent = (url, sanitize = false) => {
23
31
  if (rsp.ok) {
24
32
  return rsp.text().then((svgContent) => {
25
33
  if (svgContent && sanitize !== false) {
26
- svgContent = validateContent(svgContent);
34
+ try {
35
+ svgContent = validateContent(svgContent);
36
+ }
37
+ catch (validationError) {
38
+ svgContent = '';
39
+ }
27
40
  }
28
41
  pdsIconContent.set(url, svgContent || '');
29
42
  });
30
43
  }
44
+ else {
45
+ // Handle HTTP errors
46
+ throw new Error(`Failed to load SVG: ${rsp.status} ${rsp.statusText}`);
47
+ }
48
+ }).catch((error) => {
49
+ // Handle all fetch errors gracefully
50
+ console.warn('Failed to load SVG:', url, error);
31
51
  pdsIconContent.set(url, '');
52
+ // Don't re-throw to prevent unhandled promise rejections
32
53
  });
33
54
  requests.set(url, req);
34
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../../src/components/pds-icon/request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7E,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;AACxD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAC,CAAC,yDAAyD;AAE3G,IAAI,MAAiB,CAAC;AAEtB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAW,EAAE,QAAQ,GAAG,KAAK,EAAE,EAAE;IAC7D,IAAI,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAE5B,IAAG,CAAC,GAAG,EAAE,CAAC;QACR,IAAI,OAAO,KAAK,IAAI,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACnE,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC3B,CAAC;gBAED,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;gBACrD,MAAM,GAAG,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;gBAErC,IAAI,GAAG,EAAE,CAAC;oBACR,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;gBACzC,CAAC;gBAED,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,0BAA0B;gBAC1B,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC5B,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;wBACX,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE;4BACpC,IAAI,UAAU,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gCACrC,UAAU,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;4BAC3C,CAAC;4BACD,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;wBAC5C,CAAC,CAAC,CAAC;oBACL,CAAC;oBACD,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC9B,CAAC,CAAC,CAAC;gBAEH,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC5B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC,CAAA","sourcesContent":["import { isEncodedDataUrl, isSvgDataUrl, validateContent } from './validate';\n\nexport const pdsIconContent = new Map<string, string>();\nconst requests = new Map<string, Promise<any>>(); // eslint-disable-line @typescript-eslint/no-explicit-any\n\nlet parser: DOMParser;\n\nexport const getSvgContent = (url: string, sanitize = false) => {\n let req = requests.get(url);\n\n if(!req) {\n if (typeof fetch != 'undefined' && typeof document !== 'undefined') {\n if (isSvgDataUrl(url) && isEncodedDataUrl(url)) {\n if (!parser) {\n parser = new DOMParser();\n }\n\n const doc = parser.parseFromString(url, 'text/html');\n const svg = doc.querySelector('svg');\n\n if (svg) {\n pdsIconContent.set(url, svg.outerHTML);\n }\n\n return Promise.resolve();\n } else {\n // we don't have a request\n req = fetch(url).then((rsp) => {\n if (rsp.ok) {\n return rsp.text().then((svgContent) => {\n if (svgContent && sanitize !== false) {\n svgContent = validateContent(svgContent);\n }\n pdsIconContent.set(url, svgContent || '');\n });\n }\n pdsIconContent.set(url, '');\n });\n\n requests.set(url, req);\n }\n } else {\n pdsIconContent.set(url, '');\n return Promise.resolve();\n }\n }\n\n return req;\n}\n"]}
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../../src/components/pds-icon/request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7E,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;AACxD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAC,CAAC,yDAAyD;AAE3G,IAAI,MAAiB,CAAC;AAEtB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAW,EAAE,QAAQ,GAAG,KAAK,EAAE,EAAE;IAC7D,IAAI,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAE5B,IAAG,CAAC,GAAG,EAAE,CAAC;QACR,IAAI,OAAO,KAAK,IAAI,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACnE,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC3B,CAAC;gBAED,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;oBACrD,MAAM,GAAG,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;oBAErC,IAAI,GAAG,EAAE,CAAC;wBACR,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;oBACzC,CAAC;yBAAM,CAAC;wBACN,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBAC9B,CAAC;gBACH,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;gBAC9B,CAAC;gBAED,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,0BAA0B;gBAC1B,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC5B,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;wBACX,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE;4BACpC,IAAI,UAAU,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gCACrC,IAAI,CAAC;oCACH,UAAU,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;gCAC3C,CAAC;gCAAC,OAAO,eAAe,EAAE,CAAC;oCACzB,UAAU,GAAG,EAAE,CAAC;gCAClB,CAAC;4BACH,CAAC;4BACD,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;wBAC5C,CAAC,CAAC,CAAC;oBACL,CAAC;yBAAM,CAAC;wBACN,qBAAqB;wBACrB,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;oBACzE,CAAC;gBACH,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;oBACjB,qCAAqC;oBACrC,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;oBAChD,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBAC5B,yDAAyD;gBAC3D,CAAC,CAAC,CAAC;gBAEH,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC5B,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC,CAAA","sourcesContent":["import { isEncodedDataUrl, isSvgDataUrl, validateContent } from './validate';\n\nexport const pdsIconContent = new Map<string, string>();\nconst requests = new Map<string, Promise<any>>(); // eslint-disable-line @typescript-eslint/no-explicit-any\n\nlet parser: DOMParser;\n\nexport const getSvgContent = (url: string, sanitize = false) => {\n let req = requests.get(url);\n\n if(!req) {\n if (typeof fetch != 'undefined' && typeof document !== 'undefined') {\n if (isSvgDataUrl(url) && isEncodedDataUrl(url)) {\n if (!parser) {\n parser = new DOMParser();\n }\n\n try {\n const doc = parser.parseFromString(url, 'text/html');\n const svg = doc.querySelector('svg');\n\n if (svg) {\n pdsIconContent.set(url, svg.outerHTML);\n } else {\n pdsIconContent.set(url, '');\n }\n } catch (error) {\n pdsIconContent.set(url, '');\n }\n\n return Promise.resolve();\n } else {\n // we don't have a request\n req = fetch(url).then((rsp) => {\n if (rsp.ok) {\n return rsp.text().then((svgContent) => {\n if (svgContent && sanitize !== false) {\n try {\n svgContent = validateContent(svgContent);\n } catch (validationError) {\n svgContent = '';\n }\n }\n pdsIconContent.set(url, svgContent || '');\n });\n } else {\n // Handle HTTP errors\n throw new Error(`Failed to load SVG: ${rsp.status} ${rsp.statusText}`);\n }\n }).catch((error) => {\n // Handle all fetch errors gracefully\n console.warn('Failed to load SVG:', url, error);\n pdsIconContent.set(url, '');\n // Don't re-throw to prevent unhandled promise rejections\n });\n\n requests.set(url, req);\n }\n } else {\n pdsIconContent.set(url, '');\n return Promise.resolve();\n }\n }\n\n return req;\n}\n"]}
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2025-07-03T11:05:25",
2
+ "timestamp": "2025-07-15T11:05:33",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.28.2",
@@ -5,7 +5,7 @@ import { g as globalScripts } from './app-globals-DQuL1Twl.js';
5
5
  const defineCustomElements = async (win, options) => {
6
6
  if (typeof window === 'undefined') return undefined;
7
7
  await globalScripts();
8
- return bootstrapLazy([["pds-icon",[[1,"pds-icon",{"color":[1],"flipRtl":[4,"flip-rtl"],"icon":[8],"name":[513],"size":[513],"src":[1],"ariaLabel":[32],"isVisible":[32],"svgContent":[32]},null,{"size":["updateStyles"],"color":["updateStyles"],"name":["loadIcon"],"src":["loadIcon"],"icon":["loadIcon"]}]]]], options);
8
+ return bootstrapLazy([["pds-icon",[[1,"pds-icon",{"color":[1],"flipRtl":[4,"flip-rtl"],"icon":[8],"name":[513],"size":[513],"src":[1],"ariaLabel":[32],"isVisible":[32],"svgContent":[32]},null,{"size":["updateStyles"],"color":["updateStyles"],"name":["onIconPropertyChange"],"src":["onIconPropertyChange"],"icon":["onIconPropertyChange"]}]]]], options);
9
9
  };
10
10
 
11
11
  export { defineCustomElements };
@@ -57,10 +57,18 @@ const getSvgContent = (url, sanitize = false) => {
57
57
  if (!parser) {
58
58
  parser = new DOMParser();
59
59
  }
60
- const doc = parser.parseFromString(url, 'text/html');
61
- const svg = doc.querySelector('svg');
62
- if (svg) {
63
- pdsIconContent.set(url, svg.outerHTML);
60
+ try {
61
+ const doc = parser.parseFromString(url, 'text/html');
62
+ const svg = doc.querySelector('svg');
63
+ if (svg) {
64
+ pdsIconContent.set(url, svg.outerHTML);
65
+ }
66
+ else {
67
+ pdsIconContent.set(url, '');
68
+ }
69
+ }
70
+ catch (error) {
71
+ pdsIconContent.set(url, '');
64
72
  }
65
73
  return Promise.resolve();
66
74
  }
@@ -70,12 +78,25 @@ const getSvgContent = (url, sanitize = false) => {
70
78
  if (rsp.ok) {
71
79
  return rsp.text().then((svgContent) => {
72
80
  if (svgContent && sanitize !== false) {
73
- svgContent = validateContent(svgContent);
81
+ try {
82
+ svgContent = validateContent(svgContent);
83
+ }
84
+ catch (validationError) {
85
+ svgContent = '';
86
+ }
74
87
  }
75
88
  pdsIconContent.set(url, svgContent || '');
76
89
  });
77
90
  }
91
+ else {
92
+ // Handle HTTP errors
93
+ throw new Error(`Failed to load SVG: ${rsp.status} ${rsp.statusText}`);
94
+ }
95
+ }).catch((error) => {
96
+ // Handle all fetch errors gracefully
97
+ console.warn('Failed to load SVG:', url, error);
78
98
  pdsIconContent.set(url, '');
99
+ // Don't re-throw to prevent unhandled promise rejections
79
100
  });
80
101
  requests.set(url, req);
81
102
  }
@@ -129,10 +150,26 @@ const PdsIcon = class {
129
150
  if (!this.didLoadIcon) {
130
151
  this.loadIcon();
131
152
  }
153
+ // Fallback: Ensure icon loads even if IntersectionObserver doesn't fire
154
+ setTimeout(() => {
155
+ if (!this.svgContent && !this.isVisible) {
156
+ this.isVisible = true;
157
+ this.loadIcon();
158
+ }
159
+ }, 100);
160
+ // Additional fallback for client-side navigation (React Router, etc.)
161
+ // React's useLayoutEffect and rendering cycles can delay visibility detection
162
+ setTimeout(() => {
163
+ if (!this.svgContent && !this.isVisible) {
164
+ this.isVisible = true;
165
+ this.loadIcon();
166
+ }
167
+ }, 500);
132
168
  }
133
169
  componentWillLoad() {
134
170
  this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
135
171
  this.setCSSVariables();
172
+ this.setupInitialAriaLabel();
136
173
  }
137
174
  setCSSVariables() {
138
175
  this.el.style.setProperty(`--dimension-icon-height`, this.iconSize());
@@ -140,10 +177,18 @@ const PdsIcon = class {
140
177
  this.el.style.setProperty(`--color-icon-fill`, typeof this.color !== 'undefined' ? this.color : 'currentColor');
141
178
  }
142
179
  connectedCallback() {
143
- this.waitUntilVisible(this.el, '50px', () => {
180
+ // Handle re-connection during client-side navigation
181
+ if (!this.isVisible && !this.svgContent) {
182
+ this.waitUntilVisible(this.el, '50px', () => {
183
+ this.isVisible = true;
184
+ this.loadIcon();
185
+ });
186
+ }
187
+ // Immediate load attempt if already visible (e.g., during React navigation)
188
+ if (this.isElementInViewport(this.el)) {
144
189
  this.isVisible = true;
145
190
  this.loadIcon();
146
- });
191
+ }
147
192
  }
148
193
  disconnectedCallback() {
149
194
  if (this.io) {
@@ -154,7 +199,16 @@ const PdsIcon = class {
154
199
  updateStyles() {
155
200
  this.setCSSVariables();
156
201
  }
202
+ onIconPropertyChange() {
203
+ this.loadIcon();
204
+ // Update aria-label when icon properties change
205
+ this.setupInitialAriaLabel();
206
+ }
157
207
  loadIcon() {
208
+ // Reset load state when URL changes
209
+ this.didLoadIcon = false;
210
+ // Clear existing content to prevent stale content when switching icons
211
+ this.svgContent = undefined;
158
212
  if (this.isVisible) {
159
213
  const url = getUrl(this);
160
214
  if (url) {
@@ -162,15 +216,23 @@ const PdsIcon = class {
162
216
  this.svgContent = pdsIconContent.get(url);
163
217
  }
164
218
  else {
165
- getSvgContent(url).then(() => (this.svgContent = pdsIconContent.get(url)));
219
+ // Fix: Ensure promise callback triggers re-render and handle errors
220
+ getSvgContent(url)
221
+ .then(() => {
222
+ // Force re-render by setting state in next tick
223
+ setTimeout(() => {
224
+ this.svgContent = pdsIconContent.get(url);
225
+ }, 0);
226
+ })
227
+ .catch(() => {
228
+ // Handle fetch errors gracefully
229
+ this.svgContent = '';
230
+ });
166
231
  }
167
232
  this.didLoadIcon = true;
168
233
  }
169
234
  }
170
235
  this.iconName = getName(this.name, this.icon);
171
- if (this.iconName) {
172
- this.ariaLabel = this.iconName.replace(/\-/g, ' ');
173
- }
174
236
  }
175
237
  render() {
176
238
  const { ariaLabel, flipRtl, iconName, inheritedAttributes } = this;
@@ -178,11 +240,22 @@ const PdsIcon = class {
178
240
  ? shouldRtlFlipIcon(iconName, this.el) && flipRtl !== false
179
241
  : false;
180
242
  const shouldFlip = flipRtl || shouldIconAutoFlip;
181
- return (h(Host, Object.assign({ key: 'bc8e46daa75df27a8039e0e767bdb43164ad7d4c', "aria-label": ariaLabel !== undefined && !this.hasAriaHidden() ? ariaLabel : null, alt: "", role: "img", class: Object.assign(Object.assign({}, createColorClasses(this.color)), { 'flip-rtl': shouldFlip, 'icon-rtl': shouldFlip && isRTL(this.el) }) }, inheritedAttributes), this.svgContent ? (h("div", { class: "icon-inner", innerHTML: this.svgContent })) : (h("div", { class: "icon-inner" }))));
243
+ // Use inherited aria-label if provided, otherwise fall back to auto-generated one
244
+ const finalAriaLabel = inheritedAttributes['aria-label'] || ariaLabel;
245
+ return (h(Host, Object.assign({ key: '43aa73531314e6529a887468e69362430d006229', "aria-label": finalAriaLabel !== undefined && !this.hasAriaHidden() ? finalAriaLabel : null, alt: "", role: "img", class: Object.assign(Object.assign({}, createColorClasses(this.color)), { 'flip-rtl': shouldFlip, 'icon-rtl': shouldFlip && isRTL(this.el) }) }, inheritedAttributes), this.svgContent ? (h("div", { class: "icon-inner", innerHTML: this.svgContent })) : (h("div", { class: "icon-inner" }))));
182
246
  }
183
247
  /*****
184
248
  * Private Methods
185
249
  ****/
250
+ setupInitialAriaLabel() {
251
+ // Only set aria-label during initial load if one isn't already provided
252
+ if (!this.inheritedAttributes['aria-label']) {
253
+ const iconName = getName(this.name, this.icon);
254
+ if (iconName) {
255
+ this.ariaLabel = iconName.replace(/\-/g, ' ');
256
+ }
257
+ }
258
+ }
186
259
  waitUntilVisible(el, rootMargin, cb) {
187
260
  if (typeof window !== 'undefined' && (window).IntersectionObserver) {
188
261
  const io = (this.io = new (window).IntersectionObserver((data) => {
@@ -193,6 +266,18 @@ const PdsIcon = class {
193
266
  }
194
267
  }, { rootMargin }));
195
268
  io.observe(el);
269
+ // Safety timeout for client-side navigation scenarios
270
+ // Sometimes IntersectionObserver doesn't fire during React navigation
271
+ setTimeout(() => {
272
+ if (this.io && !this.isVisible) {
273
+ // Check if element is actually visible in viewport
274
+ if (this.isElementInViewport(el)) {
275
+ this.io.disconnect();
276
+ this.io = undefined;
277
+ cb();
278
+ }
279
+ }
280
+ }, 1000);
196
281
  }
197
282
  else {
198
283
  // browser doesn't support IntersectionObserver
@@ -200,14 +285,62 @@ const PdsIcon = class {
200
285
  cb();
201
286
  }
202
287
  }
288
+ isElementInViewport(el) {
289
+ if (!el || !el.isConnected)
290
+ return false;
291
+ const rect = el.getBoundingClientRect();
292
+ const windowHeight = window.innerHeight || document.documentElement.clientHeight;
293
+ const windowWidth = window.innerWidth || document.documentElement.clientWidth;
294
+ return (rect.top >= 0 &&
295
+ rect.left >= 0 &&
296
+ rect.bottom <= windowHeight &&
297
+ rect.right <= windowWidth) || (
298
+ // Also consider partially visible elements
299
+ rect.top < windowHeight &&
300
+ rect.bottom > 0 &&
301
+ rect.left < windowWidth &&
302
+ rect.right > 0);
303
+ }
304
+ /**
305
+ * Debug method to help diagnose loading issues
306
+ * Call from browser console: document.querySelector('pds-icon').debugIconState()
307
+ */
308
+ debugIconState() {
309
+ var _a;
310
+ const url = getUrl(this);
311
+ const rect = this.el.getBoundingClientRect();
312
+ console.log('PdsIcon Debug State:', {
313
+ name: this.name,
314
+ src: this.src,
315
+ icon: this.icon,
316
+ iconName: this.iconName,
317
+ url,
318
+ isVisible: this.isVisible,
319
+ didLoadIcon: this.didLoadIcon,
320
+ hasSvgContent: !!this.svgContent,
321
+ svgContentLength: ((_a = this.svgContent) === null || _a === void 0 ? void 0 : _a.length) || 0,
322
+ isInCache: url ? pdsIconContent.has(url) : false,
323
+ cachedContent: url ? pdsIconContent.get(url) : null,
324
+ element: this.el,
325
+ // Client-side navigation specific debug info
326
+ isConnected: this.el.isConnected,
327
+ isInViewport: this.isElementInViewport(this.el),
328
+ hasIntersectionObserver: !!this.io,
329
+ boundingClientRect: rect,
330
+ windowDimensions: {
331
+ width: window.innerWidth || document.documentElement.clientWidth,
332
+ height: window.innerHeight || document.documentElement.clientHeight
333
+ }
334
+ });
335
+ }
203
336
  static get assetsDirs() { return ["svg"]; }
204
337
  get el() { return getElement(this); }
205
338
  static get watchers() { return {
206
339
  "size": ["updateStyles"],
207
340
  "color": ["updateStyles"],
208
- "name": ["loadIcon"],
209
- "src": ["loadIcon"],
210
- "icon": ["loadIcon"]
341
+ "name": ["onIconPropertyChange"],
342
+ "src": ["onIconPropertyChange"],
343
+ "icon": ["onIconPropertyChange"]
211
344
  }; }
212
345
  };
213
346
  const createColorClasses = (color) => {