Repository navigation
Expand file tree
/
Copy pathshadowDOMExample.ts
More file actions
188 lines (156 loc) · 6.38 KB
/
Copy pathshadowDOMExample.ts
File metadata and controls
188 lines (156 loc) · 6.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/**
* Shadow DOM Usage Examples
*
* This file demonstrates how to use the shadow DOM utilities
* to solve CSS isolation challenges mentioned in sveltejs/svelte#5869
*/
import { createApp } from '../lib/utils/createApp';
import { mountInShadow } from '../lib/utils/shadowDOM';
import { injectCSS, getBundledCSSUrl, cloneDocumentStyles } from '../lib/utils/cssInjector';
import ShadowDOMDemo from '../lib/components/ShadowDOMDemo.svelte';
// =============================================================================
// Example 1: Basic Shadow DOM mounting with automatic CSS injection
// =============================================================================
export function example1_basicShadowDOM() {
const app = createApp(ShadowDOMDemo, {
target: '#app',
useShadowDOM: true,
injectStyles: true, // Automatically injects all CSS including Lucide icons
});
console.log('Shadow DOM app mounted:', app);
// Cleanup when done
// app.cleanup();
}
// =============================================================================
// Example 2: Manual shadow DOM creation with custom CSS
// =============================================================================
export function example2_manualShadowDOM() {
const container = document.getElementById('app');
if (!container) return;
const result = mountInShadow(ShadowDOMDemo, {
target: container,
mode: 'open',
injectStyles: true,
});
console.log('Manually mounted shadow DOM:', result);
// Access shadow root
console.log('Shadow root:', result.shadowRoot);
// Cleanup when done
// result.cleanup();
}
// =============================================================================
// Example 3: Shadow DOM with custom CSS URLs (for content scripts)
// =============================================================================
export function example3_contentScriptShadowDOM() {
// Useful when injecting into a web page via content script
const app = createApp(ShadowDOMDemo, {
target: '#my-extension-root',
useShadowDOM: true,
injectStyles: true,
cssUrls: [
// Extension CSS bundle
chrome.runtime.getURL('assets/main.css'),
// Additional custom styles
chrome.runtime.getURL('assets/content.css'),
],
});
console.log('Content script shadow DOM mounted:', app);
}
// =============================================================================
// Example 4: Advanced CSS injection with Constructable Stylesheets
// =============================================================================
export async function example4_advancedCSSInjection() {
const container = document.getElementById('app');
if (!container) return;
// Create shadow root
const shadowRoot = container.attachShadow({ mode: 'open' });
// Create app container
const appDiv = document.createElement('div');
appDiv.className = 'w-full h-full';
shadowRoot.appendChild(appDiv);
// Inject CSS using Constructable Stylesheets (fastest method)
await injectCSS({
shadowRoot,
cssUrls: [getBundledCSSUrl() || ''],
adoptedStyleSheets: true, // Use modern API
});
// Mount component
const { mount } = await import('svelte');
const component = mount(ShadowDOMDemo, { target: appDiv });
console.log('Component with advanced CSS injection:', component);
}
// =============================================================================
// Example 5: Clone all document styles (simplest method)
// =============================================================================
export function example5_cloneStyles() {
const container = document.getElementById('app');
if (!container) return;
// Create shadow root
const shadowRoot = container.attachShadow({ mode: 'open' });
// Clone all document styles (includes Lucide icon styles)
cloneDocumentStyles(shadowRoot);
// Create app container
const appDiv = document.createElement('div');
appDiv.className = 'w-full h-full';
shadowRoot.appendChild(appDiv);
// Mount component
import('svelte').then(({ mount }) => {
const component = mount(ShadowDOMDemo, { target: appDiv });
console.log('Component with cloned styles:', component);
});
}
// =============================================================================
// Example 6: Multiple shadow DOM instances
// =============================================================================
export function example6_multipleInstances() {
const { createApps, cleanupApps } = require('../lib/utils/createApp');
const apps = createApps(ShadowDOMDemo, [
{ target: '#app1', useShadowDOM: true, injectStyles: true },
{ target: '#app2', useShadowDOM: true, injectStyles: true },
{ target: '#app3', useShadowDOM: true, injectStyles: true },
]);
console.log('Multiple shadow DOM instances:', apps);
// Cleanup all instances
// cleanupApps(apps);
}
// =============================================================================
// Example 7: Content Script Injection Pattern (Real-world usage)
// =============================================================================
export function example7_realWorldContentScript() {
// This is how you'd inject your extension UI into any webpage
// with complete CSS isolation (solving the original issue)
// 1. Create container in the target page
const container = document.createElement('div');
container.id = 'my-extension-widget';
container.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
z-index: 999999;
width: 400px;
max-height: 600px;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
`;
document.body.appendChild(container);
// 2. Mount with shadow DOM for complete isolation
const app = createApp(ShadowDOMDemo, {
target: container,
useShadowDOM: true,
injectStyles: true,
cssUrls: [
// Load your extension's bundled CSS from the extension
chrome.runtime.getURL('assets/main.css'),
],
});
console.log('Real-world content script injection:', app);
// 3. The widget is now isolated from the host page's CSS!
// Lucide icons, Tailwind, DaisyUI all work perfectly inside shadow DOM
}
// =============================================================================
// Export default function to run the basic example
// =============================================================================
export default function runExample() {
console.log('Running Shadow DOM Example...');
example1_basicShadowDOM();
}