@pure-ds/storybook 0.5.55 → 0.5.58

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 (54) hide show
  1. package/.storybook/addons/description/register.js +22 -23
  2. package/.storybook/addons/html-preview/register.js +6 -31
  3. package/.storybook/addons/pds-configurator/SearchTool.js +12 -14
  4. package/.storybook/addons/pds-configurator/Tool.js +11 -15
  5. package/.storybook/htmlPreview.js +219 -219
  6. package/.storybook/main.js +3 -3
  7. package/.storybook/preview.js +2 -15
  8. package/bin/index.js +1 -15
  9. package/dist/pds-reference.json +318 -192
  10. package/package.json +2 -2
  11. package/public/assets/js/app.js +19 -19
  12. package/public/assets/js/pds-manager.js +4 -4
  13. package/public/assets/js/pds.js +6 -6
  14. package/public/assets/pds/components/pds-omnibox.js +2 -10
  15. package/public/assets/pds/core/pds-manager.js +4 -4
  16. package/public/assets/pds/custom-elements.json +471 -0
  17. package/public/assets/pds/pds-css-complete.json +590 -179
  18. package/public/assets/pds/pds-runtime-config.json +3 -2
  19. package/public/assets/pds/pds.css-data.json +201 -165
  20. package/public/assets/pds/styles/pds-components.css +192 -96
  21. package/public/assets/pds/styles/pds-components.css.js +384 -192
  22. package/public/assets/pds/styles/pds-primitives.css +1 -1
  23. package/public/assets/pds/styles/pds-primitives.css.js +2 -2
  24. package/public/assets/pds/styles/pds-styles.css +201 -102
  25. package/public/assets/pds/styles/pds-styles.css.js +404 -198
  26. package/public/assets/pds/styles/pds-tokens.css +5 -4
  27. package/public/assets/pds/styles/pds-tokens.css.js +12 -2
  28. package/public/assets/pds/styles/pds-utilities.css +3 -1
  29. package/public/assets/pds/styles/pds-utilities.css.js +6 -2
  30. package/public/assets/pds/vscode-custom-data.json +42 -25
  31. package/src/js/common/common.js +9 -0
  32. package/src/js/pds.js +6 -15
  33. package/stories/WhatIsPDS.stories.js +34 -34
  34. package/stories/components/PdsForm.stories.js +4981 -4981
  35. package/stories/components/PdsTheme/PdsTheme.stories.js +68 -68
  36. package/stories/enhancements/Accordion.stories.js +309 -309
  37. package/stories/enhancements/ButtonWorking.stories.js +127 -127
  38. package/stories/enhancements/_enhancement-header.js +48 -48
  39. package/stories/foundations/HTMLDefaults.stories.js +470 -470
  40. package/stories/foundations/Icons.stories.js +1 -1
  41. package/stories/primitives/Callouts.stories.js +225 -225
  42. package/stories/reference/ReferenceCatalog.stories.js +28 -28
  43. package/stories/reference/reference-catalog.js +442 -442
  44. package/stories/reference/reference-docs.js +470 -470
  45. package/stories/utils/PdsAsk.stories.js +1 -1
  46. package/stories/utils/PdsParse.stories.js +4 -5
  47. package/stories/utils/PdsToast.stories.js +1 -1
  48. package/.storybook/addons/description/register.cjs +0 -61
  49. package/.storybook/addons/html-preview/constants.cjs +0 -12
  50. package/.storybook/addons/html-preview/register.cjs +0 -41
  51. package/.storybook/addons/pds-configurator/SearchTool.cjs +0 -47
  52. package/.storybook/addons/pds-configurator/Tool.cjs +0 -36
  53. package/.storybook/addons/pds-configurator/constants.cjs +0 -16
  54. package/.storybook/addons/pds-configurator/register.cjs +0 -12
@@ -1,16 +1,16 @@
1
1
  import { addons, types } from '@storybook/manager-api';
2
2
  import { AddonPanel } from '@storybook/components';
3
- import React from 'react';
3
+ import React, { useEffect, useState } from 'react';
4
4
  import { Markdown } from '@storybook/blocks';
5
5
 
6
6
  const ADDON_ID = 'pds-description';
7
7
  const PANEL_ID = `${ADDON_ID}/panel`;
8
8
 
9
9
  const DescriptionPanel = () => {
10
- const [description, setDescription] = React.useState('');
11
- const [title, setTitle] = React.useState('');
10
+ const [description, setDescription] = useState('');
11
+ const [title, setTitle] = useState('');
12
12
 
13
- React.useEffect(() => {
13
+ useEffect(() => {
14
14
  const channel = addons.getChannel();
15
15
 
16
16
  const updateDescription = (data) => {
@@ -25,23 +25,23 @@ const DescriptionPanel = () => {
25
25
  };
26
26
  }, []);
27
27
 
28
- return React.createElement(
29
- 'div',
30
- {
28
+ return React.createElement('div', {
29
+ style: {
30
+ padding: '1rem',
31
+ height: '100%',
32
+ overflow: 'auto'
33
+ }
34
+ },
35
+ React.createElement('div', {
31
36
  style: {
32
- padding: '1rem',
33
- height: '100%',
34
- overflow: 'auto'
37
+ marginBottom: '0.5rem'
35
38
  }
36
39
  },
37
- React.createElement(
38
- 'div',
39
- { style: { marginBottom: '0.5rem' } },
40
- React.createElement(
41
- 'strong',
42
- { style: { fontSize: '1rem' } },
43
- title
44
- )
40
+ React.createElement('strong', {
41
+ style: {
42
+ fontSize: '1rem'
43
+ }
44
+ }, title)
45
45
  ),
46
46
  React.createElement(Markdown, null, description)
47
47
  );
@@ -51,11 +51,10 @@ addons.register(ADDON_ID, () => {
51
51
  addons.add(PANEL_ID, {
52
52
  type: types.PANEL,
53
53
  title: 'Description',
54
- render: ({ active }) =>
55
- React.createElement(
56
- AddonPanel,
57
- { active },
54
+ render: ({ active }) => {
55
+ return React.createElement(AddonPanel, { active },
58
56
  React.createElement(DescriptionPanel)
59
- )
57
+ );
58
+ }
60
59
  });
61
60
  });
@@ -1,41 +1,16 @@
1
1
  import React from 'react';
2
2
  import { addons, types } from '@storybook/manager-api';
3
3
  import { ADDON_ID, PANEL_ID } from './constants.js';
4
-
5
- const PanelLoader = ({ active }) => {
6
- const [PanelComponent, setPanelComponent] = React.useState(null);
7
-
8
- React.useEffect(() => {
9
- let mounted = true;
10
-
11
- import('./Panel.jsx')
12
- .then((mod) => {
13
- if (!mounted) return;
14
- const Resolved = mod.Panel || mod.default || null;
15
- if (Resolved) setPanelComponent(() => Resolved);
16
- })
17
- .catch((error) => {
18
- console.error('Failed to load html-preview Panel:', error);
19
- });
20
-
21
- return () => {
22
- mounted = false;
23
- };
24
- }, []);
25
-
26
- if (!PanelComponent) return null;
27
- return React.createElement(PanelComponent, { active });
28
- };
4
+ import { Panel } from './Panel.jsx';
29
5
 
30
6
  addons.register(ADDON_ID, () => {
31
7
  addons.add(PANEL_ID, {
32
8
  type: types.PANEL,
33
9
  title: 'Code',
34
- render: ({ active, key }) =>
35
- React.createElement(
36
- 'div',
37
- { style: { display: active ? 'block' : 'none', height: '100%' } },
38
- React.createElement(PanelLoader, { key, active })
39
- )
10
+ render: ({ active, key }) => (
11
+ <div style={{ display: active ? 'block' : 'none', height: '100%' }}>
12
+ <Panel key={key} active={active} />
13
+ </div>
14
+ )
40
15
  });
41
16
  });
@@ -28,19 +28,17 @@ export const SearchTool = () => {
28
28
  setIsOpen(newState);
29
29
  }, [isOpen, channel]);
30
30
 
31
- return React.createElement(
32
- IconButton,
33
- {
34
- key: 'search-tool',
35
- active: isOpen,
36
- title: 'Quick Search PDS',
37
- onClick: toggleSearch
38
- },
39
- React.createElement(
40
- 'svg',
41
- { width: '14', height: '14', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '2' },
42
- React.createElement('circle', { cx: '11', cy: '11', r: '8' }),
43
- React.createElement('path', { d: 'm21 21-4.35-4.35' })
44
- )
31
+ return (
32
+ <IconButton
33
+ key="search-tool"
34
+ active={isOpen}
35
+ title="Quick Search PDS"
36
+ onClick={toggleSearch}
37
+ >
38
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
39
+ <circle cx="11" cy="11" r="8" />
40
+ <path d="m21 21-4.35-4.35" />
41
+ </svg>
42
+ </IconButton>
45
43
  );
46
44
  };
@@ -15,20 +15,16 @@ export const Tool = () => {
15
15
  emit(EVENTS.OPEN_CONFIGURATOR);
16
16
  }, [emit]);
17
17
 
18
- return React.createElement(
19
- IconButton,
20
- {
21
- key: 'configurator-toggle',
22
- title: 'Open PDS Configurator',
23
- onClick: openConfigurator
24
- },
25
- React.createElement(
26
- 'svg',
27
- { width: '14', height: '14', viewBox: '0 0 24 24', fill: 'currentColor' },
28
- React.createElement('path', {
29
- d: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z'
30
- }),
31
- React.createElement('circle', { cx: '12', cy: '12', r: '3' })
32
- )
18
+ return (
19
+ <IconButton
20
+ key="configurator-toggle"
21
+ title="Open PDS Configurator"
22
+ onClick={openConfigurator}
23
+ >
24
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
25
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
26
+ <circle cx="12" cy="12" r="3"/>
27
+ </svg>
28
+ </IconButton>
33
29
  );
34
30
  };
@@ -1,219 +1,219 @@
1
- /**
2
- * HTML Preview and Copy Utility for Storybook
3
- * Provides HTML source viewing and copy functionality for all stories
4
- * Uses Shiki for syntax highlighting
5
- */
6
-
7
- import { render as litRender } from 'lit';
8
- import { highlight, getCurrentTheme, escapeHtml, preloadShiki } from './shiki.js';
9
-
10
- // Pre-load Shiki in the background
11
- preloadShiki();
12
-
13
- /**
14
- * Format HTML string with proper indentation
15
- */
16
- export function formatHTML(html) {
17
- if (!html) return '';
18
-
19
- let formatted = '';
20
- let indent = 0;
21
- const tab = ' ';
22
-
23
- const tokens = html.split(/(<[^>]+>)/g).filter(Boolean);
24
-
25
- tokens.forEach((token) => {
26
- if (token.startsWith('</')) {
27
- // Closing tag
28
- indent = Math.max(0, indent - 1);
29
- formatted += '\n' + tab.repeat(indent) + token;
30
- } else if (token.startsWith('<')) {
31
- // Opening tag
32
- const isSelfClosing = token.endsWith('/>') || token.match(/<(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)/);
33
- formatted += '\n' + tab.repeat(indent) + token;
34
- if (!isSelfClosing) {
35
- indent++;
36
- }
37
- } else if (token.trim()) {
38
- // Text content
39
- formatted += token.trim();
40
- }
41
- });
42
-
43
- return formatted.trim();
44
- }
45
-
46
- /**
47
- * Extract HTML from a rendered story
48
- */
49
- export function extractHTML(element) {
50
- if (!element) return '';
51
-
52
- // Clone the element to avoid modifying the original
53
- const clone = element.cloneNode(true);
54
-
55
- // Clean up any Storybook-specific attributes or classes
56
- const cleanElement = (el) => {
57
- if (el.removeAttribute) {
58
- el.removeAttribute('data-story-id');
59
- el.removeAttribute('data-view-mode');
60
- }
61
- if (el.children) {
62
- Array.from(el.children).forEach(cleanElement);
63
- }
64
- };
65
-
66
- cleanElement(clone);
67
- return clone.innerHTML || '';
68
- }
69
-
70
- /**
71
- * Strip Lit template comments from rendered HTML
72
- * Removes markers like <!--?lit$641514976$-->, <!---->, etc.
73
- */
74
- export function stripLitComments(html) {
75
- if (!html) return '';
76
-
77
- // Remove Lit binding markers: <!--?lit$...$-->
78
- html = html.replace(/<!--\?lit\$[^$]+\$-->/g, '');
79
-
80
- // Remove empty Lit comments: <!---->
81
- html = html.replace(/<!---->/g, '');
82
-
83
- // Remove Lit template marker comments: <!--lit-part...-->
84
- html = html.replace(/<!--lit-part[^>]*-->/g, '');
85
- html = html.replace(/<!--\/lit-part-->/g, '');
86
-
87
- // Clean up any resulting multiple whitespace/newlines
88
- html = html.replace(/\n\s*\n\s*\n/g, '\n\n');
89
-
90
- return html;
91
- }
92
-
93
- /**
94
- * Transform Lit template result to HTML string
95
- */
96
- export async function litToHTML(templateResult) {
97
- if (!templateResult || !templateResult._$litType$) {
98
- return '';
99
- }
100
-
101
- const temp = document.createElement('div');
102
- litRender(templateResult, temp);
103
-
104
- // Wait for any custom elements to upgrade
105
- await new Promise(resolve => setTimeout(resolve, 50));
106
-
107
- // Strip Lit comments before formatting
108
- const cleanedHTML = stripLitComments(temp.innerHTML);
109
-
110
- return formatHTML(cleanedHTML);
111
- }
112
-
113
- /**
114
- * Global decorator that provides HTML source code display
115
- */
116
- export const withHTMLSource = (storyFn, context) => {
117
- const story = storyFn();
118
-
119
- // For docs mode, Storybook will automatically show source
120
- // We just need to ensure the parameters are set
121
- if (context.viewMode === 'docs') {
122
- return story;
123
- }
124
-
125
- // For canvas/story mode, we'll add a source viewer below the story
126
- const container = document.createElement('div');
127
- container.style.cssText = 'display: flex; flex-direction: column; gap: 1rem; width: 100%; height: 100%;';
128
-
129
- // Story container
130
- const storyContainer = document.createElement('div');
131
- storyContainer.id = 'story-preview';
132
- storyContainer.style.cssText = 'flex: 1; overflow: auto;';
133
-
134
- // Source panel with copy button
135
- const sourceSection = document.createElement('div');
136
- sourceSection.className = 'html-source-section';
137
- sourceSection.innerHTML = `
138
- <details class="html-source-details surface-subtle">
139
- <summary class="html-source-summary surface-elevated">
140
- <span class="html-source-title">
141
- <span class="html-source-icon">📝</span>
142
- <span>View HTML Source</span>
143
- </span>
144
- <button id="copy-source-btn" class="btn-outline">
145
- 📋 Copy HTML
146
- </button>
147
- </summary>
148
- <div class="html-source-content">
149
- <pre class="html-source-pre"><code class="html-source-code"></code></pre>
150
- </div>
151
- </details>
152
- `;
153
-
154
- container.appendChild(storyContainer);
155
- container.appendChild(sourceSection);
156
-
157
- // Render the story
158
- setTimeout(async () => {
159
- if (story && story._$litType$) {
160
- litRender(story, storyContainer);
161
- } else if (story instanceof HTMLElement) {
162
- storyContainer.appendChild(story);
163
- } else if (typeof story === 'string') {
164
- storyContainer.innerHTML = story;
165
- }
166
-
167
- // Extract and display HTML
168
- setTimeout(async () => {
169
- let html = '';
170
-
171
- if (story && story._$litType$) {
172
- html = await litToHTML(story);
173
- } else {
174
- html = formatHTML(extractHTML(storyContainer));
175
- }
176
-
177
- const codeEl = sourceSection.querySelector('.html-source-code');
178
- const preEl = sourceSection.querySelector('.html-source-pre');
179
- if (preEl && html) {
180
- // Use Shiki for syntax highlighting
181
- const theme = getCurrentTheme();
182
- const highlighted = await highlight(html, 'html', theme);
183
-
184
- // Shiki returns complete <pre><code>...</code></pre>, replace the whole pre element
185
- preEl.outerHTML = highlighted;
186
- }
187
-
188
- // Setup copy button
189
- const copyBtn = sourceSection.querySelector('#copy-source-btn');
190
- if (copyBtn && html) {
191
- copyBtn.addEventListener('click', async (e) => {
192
- e.preventDefault();
193
- e.stopPropagation();
194
-
195
- try {
196
- await navigator.clipboard.writeText(html);
197
- const originalClass = copyBtn.className;
198
- copyBtn.textContent = '✅ Copied!';
199
- copyBtn.className = 'btn-primary';
200
-
201
- setTimeout(() => {
202
- copyBtn.textContent = '📋 Copy HTML';
203
- copyBtn.className = originalClass;
204
- }, 2000);
205
- } catch (err) {
206
- console.error('Copy failed:', err);
207
- const originalText = copyBtn.textContent;
208
- copyBtn.textContent = '❌ Failed';
209
- setTimeout(() => {
210
- copyBtn.textContent = originalText;
211
- }, 2000);
212
- }
213
- });
214
- }
215
- }, 100);
216
- }, 0);
217
-
218
- return container;
219
- };
1
+ /**
2
+ * HTML Preview and Copy Utility for Storybook
3
+ * Provides HTML source viewing and copy functionality for all stories
4
+ * Uses Shiki for syntax highlighting
5
+ */
6
+
7
+ import { render as litRender } from 'lit';
8
+ import { highlight, getCurrentTheme, escapeHtml, preloadShiki } from './shiki.js';
9
+
10
+ // Pre-load Shiki in the background
11
+ preloadShiki();
12
+
13
+ /**
14
+ * Format HTML string with proper indentation
15
+ */
16
+ export function formatHTML(html) {
17
+ if (!html) return '';
18
+
19
+ let formatted = '';
20
+ let indent = 0;
21
+ const tab = ' ';
22
+
23
+ const tokens = html.split(/(<[^>]+>)/g).filter(Boolean);
24
+
25
+ tokens.forEach((token) => {
26
+ if (token.startsWith('</')) {
27
+ // Closing tag
28
+ indent = Math.max(0, indent - 1);
29
+ formatted += '\n' + tab.repeat(indent) + token;
30
+ } else if (token.startsWith('<')) {
31
+ // Opening tag
32
+ const isSelfClosing = token.endsWith('/>') || token.match(/<(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)/);
33
+ formatted += '\n' + tab.repeat(indent) + token;
34
+ if (!isSelfClosing) {
35
+ indent++;
36
+ }
37
+ } else if (token.trim()) {
38
+ // Text content
39
+ formatted += token.trim();
40
+ }
41
+ });
42
+
43
+ return formatted.trim();
44
+ }
45
+
46
+ /**
47
+ * Extract HTML from a rendered story
48
+ */
49
+ export function extractHTML(element) {
50
+ if (!element) return '';
51
+
52
+ // Clone the element to avoid modifying the original
53
+ const clone = element.cloneNode(true);
54
+
55
+ // Clean up any Storybook-specific attributes or classes
56
+ const cleanElement = (el) => {
57
+ if (el.removeAttribute) {
58
+ el.removeAttribute('data-story-id');
59
+ el.removeAttribute('data-view-mode');
60
+ }
61
+ if (el.children) {
62
+ Array.from(el.children).forEach(cleanElement);
63
+ }
64
+ };
65
+
66
+ cleanElement(clone);
67
+ return clone.innerHTML || '';
68
+ }
69
+
70
+ /**
71
+ * Strip Lit template comments from rendered HTML
72
+ * Removes markers like <!--?lit$641514976$-->, <!---->, etc.
73
+ */
74
+ export function stripLitComments(html) {
75
+ if (!html) return '';
76
+
77
+ // Remove Lit binding markers: <!--?lit$...$-->
78
+ html = html.replace(/<!--\?lit\$[^$]+\$-->/g, '');
79
+
80
+ // Remove empty Lit comments: <!---->
81
+ html = html.replace(/<!---->/g, '');
82
+
83
+ // Remove Lit template marker comments: <!--lit-part...-->
84
+ html = html.replace(/<!--lit-part[^>]*-->/g, '');
85
+ html = html.replace(/<!--\/lit-part-->/g, '');
86
+
87
+ // Clean up any resulting multiple whitespace/newlines
88
+ html = html.replace(/\n\s*\n\s*\n/g, '\n\n');
89
+
90
+ return html;
91
+ }
92
+
93
+ /**
94
+ * Transform Lit template result to HTML string
95
+ */
96
+ export async function litToHTML(templateResult) {
97
+ if (!templateResult || !templateResult._$litType$) {
98
+ return '';
99
+ }
100
+
101
+ const temp = document.createElement('div');
102
+ litRender(templateResult, temp);
103
+
104
+ // Wait for any custom elements to upgrade
105
+ await new Promise(resolve => setTimeout(resolve, 50));
106
+
107
+ // Strip Lit comments before formatting
108
+ const cleanedHTML = stripLitComments(temp.innerHTML);
109
+
110
+ return formatHTML(cleanedHTML);
111
+ }
112
+
113
+ /**
114
+ * Global decorator that provides HTML source code display
115
+ */
116
+ export const withHTMLSource = (storyFn, context) => {
117
+ const story = storyFn();
118
+
119
+ // For docs mode, Storybook will automatically show source
120
+ // We just need to ensure the parameters are set
121
+ if (context.viewMode === 'docs') {
122
+ return story;
123
+ }
124
+
125
+ // For canvas/story mode, we'll add a source viewer below the story
126
+ const container = document.createElement('div');
127
+ container.style.cssText = 'display: flex; flex-direction: column; gap: 1rem; width: 100%; height: 100%;';
128
+
129
+ // Story container
130
+ const storyContainer = document.createElement('div');
131
+ storyContainer.id = 'story-preview';
132
+ storyContainer.style.cssText = 'flex: 1; overflow: auto;';
133
+
134
+ // Source panel with copy button
135
+ const sourceSection = document.createElement('div');
136
+ sourceSection.className = 'html-source-section';
137
+ sourceSection.innerHTML = `
138
+ <details class="html-source-details surface-subtle">
139
+ <summary class="html-source-summary surface-elevated">
140
+ <span class="html-source-title">
141
+ <span class="html-source-icon">📝</span>
142
+ <span>View HTML Source</span>
143
+ </span>
144
+ <button id="copy-source-btn" class="btn-outline">
145
+ 📋 Copy HTML
146
+ </button>
147
+ </summary>
148
+ <div class="html-source-content">
149
+ <pre class="html-source-pre"><code class="html-source-code"></code></pre>
150
+ </div>
151
+ </details>
152
+ `;
153
+
154
+ container.appendChild(storyContainer);
155
+ container.appendChild(sourceSection);
156
+
157
+ // Render the story
158
+ setTimeout(async () => {
159
+ if (story && story._$litType$) {
160
+ litRender(story, storyContainer);
161
+ } else if (story instanceof HTMLElement) {
162
+ storyContainer.appendChild(story);
163
+ } else if (typeof story === 'string') {
164
+ storyContainer.innerHTML = story;
165
+ }
166
+
167
+ // Extract and display HTML
168
+ setTimeout(async () => {
169
+ let html = '';
170
+
171
+ if (story && story._$litType$) {
172
+ html = await litToHTML(story);
173
+ } else {
174
+ html = formatHTML(extractHTML(storyContainer));
175
+ }
176
+
177
+ const codeEl = sourceSection.querySelector('.html-source-code');
178
+ const preEl = sourceSection.querySelector('.html-source-pre');
179
+ if (preEl && html) {
180
+ // Use Shiki for syntax highlighting
181
+ const theme = getCurrentTheme();
182
+ const highlighted = await highlight(html, 'html', theme);
183
+
184
+ // Shiki returns complete <pre><code>...</code></pre>, replace the whole pre element
185
+ preEl.outerHTML = highlighted;
186
+ }
187
+
188
+ // Setup copy button
189
+ const copyBtn = sourceSection.querySelector('#copy-source-btn');
190
+ if (copyBtn && html) {
191
+ copyBtn.addEventListener('click', async (e) => {
192
+ e.preventDefault();
193
+ e.stopPropagation();
194
+
195
+ try {
196
+ await navigator.clipboard.writeText(html);
197
+ const originalClass = copyBtn.className;
198
+ copyBtn.textContent = '✅ Copied!';
199
+ copyBtn.className = 'btn-primary';
200
+
201
+ setTimeout(() => {
202
+ copyBtn.textContent = '📋 Copy HTML';
203
+ copyBtn.className = originalClass;
204
+ }, 2000);
205
+ } catch (err) {
206
+ console.error('Copy failed:', err);
207
+ const originalText = copyBtn.textContent;
208
+ copyBtn.textContent = '❌ Failed';
209
+ setTimeout(() => {
210
+ copyBtn.textContent = originalText;
211
+ }, 2000);
212
+ }
213
+ });
214
+ }
215
+ }, 100);
216
+ }, 0);
217
+
218
+ return container;
219
+ };
@@ -29,9 +29,9 @@ const config = {
29
29
  addons: [
30
30
  '@storybook/addon-links',
31
31
  '@storybook/addon-essentials',
32
- './addons/pds-configurator/register.cjs',
33
- './addons/html-preview/register.cjs',
34
- './addons/description/register.cjs'
32
+ './addons/pds-configurator/register.js',
33
+ './addons/html-preview/register.js',
34
+ './addons/description/register.js'
35
35
  ],
36
36
  framework: {
37
37
  name: '@storybook/web-components-vite',