lightview 1.8.2 → 2.0.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.
- package/.agent/workflows/daisyui-component-migration.md +155 -0
- package/.codacy/cli.sh +149 -0
- package/.codacy/codacy.yaml +15 -0
- package/.github/instructions/codacy.instructions.md +72 -0
- package/.wranglerignore +21 -0
- package/README.md +1330 -19
- package/_headers +4 -0
- package/build.js +70 -0
- package/components/actions/button.js +151 -0
- package/components/actions/dropdown.js +120 -0
- package/components/actions/modal.js +146 -0
- package/components/actions/swap.js +118 -0
- package/components/daisyui.js +288 -0
- package/components/data-display/accordion.js +128 -0
- package/components/data-display/alert.js +112 -0
- package/components/data-display/avatar.js +170 -0
- package/components/data-display/badge.js +82 -0
- package/components/data-display/card.js +151 -0
- package/components/data-display/carousel.js +94 -0
- package/components/data-display/chart.js +220 -0
- package/components/data-display/chat.js +128 -0
- package/components/data-display/collapse.js +103 -0
- package/components/data-display/countdown.js +69 -0
- package/components/data-display/diff.js +111 -0
- package/components/data-display/kbd.js +65 -0
- package/components/data-display/loading.js +75 -0
- package/components/data-display/progress.js +79 -0
- package/components/data-display/radial-progress.js +88 -0
- package/components/data-display/skeleton.js +66 -0
- package/components/data-display/stats.js +159 -0
- package/components/data-display/table.js +146 -0
- package/components/data-display/timeline.js +146 -0
- package/components/data-display/toast.js +72 -0
- package/components/data-display/tooltip.js +74 -0
- package/components/data-input/checkbox.js +253 -0
- package/components/data-input/file-input.js +224 -0
- package/components/data-input/input.js +264 -0
- package/components/data-input/radio.js +338 -0
- package/components/data-input/range.js +204 -0
- package/components/data-input/rating.js +219 -0
- package/components/data-input/select.js +287 -0
- package/components/data-input/textarea.js +287 -0
- package/components/data-input/toggle.js +201 -0
- package/components/index.js +137 -0
- package/components/layout/divider.js +72 -0
- package/components/layout/drawer.js +142 -0
- package/components/layout/footer.js +100 -0
- package/components/layout/hero.js +109 -0
- package/components/layout/indicator.js +90 -0
- package/components/layout/join.js +78 -0
- package/components/layout/navbar.js +110 -0
- package/components/navigation/breadcrumbs.js +91 -0
- package/components/navigation/dock.js +103 -0
- package/components/navigation/menu.js +126 -0
- package/components/navigation/pagination.js +105 -0
- package/components/navigation/steps.js +89 -0
- package/components/navigation/tabs.css +177 -0
- package/components/navigation/tabs.js +123 -0
- package/components/theme/theme-switch.css +65 -0
- package/components/theme/theme-switch.js +177 -0
- package/docs/about.html +164 -0
- package/docs/api/computed.html +184 -0
- package/docs/api/effects.html +173 -0
- package/docs/api/elements.html +180 -0
- package/docs/api/enhance.html +225 -0
- package/docs/api/hypermedia.html +165 -0
- package/docs/api/index.html +178 -0
- package/docs/api/nav.html +18 -0
- package/docs/api/signals.html +136 -0
- package/docs/api/state.html +217 -0
- package/docs/assets/images/logo-favicon.svg +42 -0
- package/docs/assets/images/logo-static.svg +40 -0
- package/docs/assets/images/logo.svg +66 -0
- package/docs/assets/js/examplify.js +395 -0
- package/docs/assets/styles/site.css +1102 -0
- package/docs/assets/styles/themes.css +236 -0
- package/docs/components/accordion.html +439 -0
- package/docs/components/alert.html +528 -0
- package/docs/components/avatar.html +586 -0
- package/docs/components/badge.html +531 -0
- package/docs/components/breadcrumbs.html +278 -0
- package/docs/components/button.html +579 -0
- package/docs/components/card.html +561 -0
- package/docs/components/carousel.html +286 -0
- package/docs/components/chart-area.html +702 -0
- package/docs/components/chart-bar.html +782 -0
- package/docs/components/chart-column.html +735 -0
- package/docs/components/chart-line.html +794 -0
- package/docs/components/chart-pie.html +823 -0
- package/docs/components/chart.html +610 -15
- package/docs/components/chat.html +547 -0
- package/docs/components/checkbox.html +641 -0
- package/docs/components/collapse.html +536 -0
- package/docs/components/component-nav.html +53 -0
- package/docs/components/countdown.html +470 -0
- package/docs/components/diff.html +245 -0
- package/docs/components/divider.html +240 -0
- package/docs/components/dock.html +277 -0
- package/docs/components/drawer.html +515 -0
- package/docs/components/dropdown.html +479 -0
- package/docs/components/file-input.html +591 -0
- package/docs/components/footer.html +301 -0
- package/docs/components/gallery.html +504 -0
- package/docs/components/hero.html +264 -0
- package/docs/components/index.css +840 -0
- package/docs/components/index.html +735 -0
- package/docs/components/indicator.html +342 -0
- package/docs/components/input.html +644 -0
- package/docs/components/join.html +285 -0
- package/docs/components/kbd.html +322 -0
- package/docs/components/loading.html +521 -0
- package/docs/components/menu.html +461 -0
- package/docs/components/modal.html +639 -0
- package/docs/components/navbar.html +321 -0
- package/docs/components/pagination.html +279 -0
- package/docs/components/progress.html +514 -0
- package/docs/components/radial-progress.html +434 -0
- package/docs/components/radio.html +655 -0
- package/docs/components/range.html +611 -0
- package/docs/components/rating.html +642 -0
- package/docs/components/select.html +696 -0
- package/docs/components/sidebar-setup.js +93 -0
- package/docs/components/skeleton.html +447 -0
- package/docs/components/spinner.html +68 -0
- package/docs/components/stats.html +486 -0
- package/docs/components/steps.html +356 -0
- package/docs/components/swap.html +517 -0
- package/docs/components/switch.html +68 -0
- package/docs/components/table.html +668 -0
- package/docs/components/tabs.html +506 -0
- package/docs/components/text-input.html +68 -0
- package/docs/components/textarea.html +603 -0
- package/docs/components/timeline.html +485 -42
- package/docs/components/toast.html +474 -0
- package/docs/components/toggle.html +564 -0
- package/docs/components/tooltip.html +423 -0
- package/docs/examples/getting-started-example.html +40 -0
- package/docs/examples/index.html +93 -0
- package/docs/getting-started/index.html +739 -0
- package/docs/getting-started/reviews.html +23 -0
- package/docs/getting-started/reviews.odom +108 -0
- package/docs/getting-started/reviews.vdom +84 -0
- package/docs/index.html +132 -42
- package/docs/playground.html +416 -0
- package/docs/router.html +285 -0
- package/docs/styles/index.html +190 -0
- package/functions/_middleware.js +32 -0
- package/index.html +309 -0
- package/lightview-router.js +364 -0
- package/lightview-x.js +1577 -0
- package/lightview.js +659 -1200
- package/lightview.js.backup +793 -0
- package/middleware/locale.js +25 -0
- package/middleware/markdown.js +44 -0
- package/middleware/notFound.js +37 -0
- package/package.json +27 -41
- package/watch.js +92 -0
- package/wrangler.toml +12 -0
- package/.idea/lightview.iml +0 -12
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/LICENSE +0 -21
- package/codepen-no-tabs-embed.css +0 -2
- package/docs/CNAME +0 -1
- package/docs/api.html +0 -674
- package/docs/blank.html +0 -10
- package/docs/comparedto.html +0 -89
- package/docs/components/chart-repl.html +0 -69
- package/docs/components/components.js +0 -113
- package/docs/components/contents.html +0 -17
- package/docs/components/gantt-repl.html +0 -61
- package/docs/components/gantt.html +0 -42
- package/docs/components/gauge-repl.html +0 -66
- package/docs/components/gauge.html +0 -20
- package/docs/components/orgchart-repl.html +0 -64
- package/docs/components/orgchart.html +0 -41
- package/docs/components/repl-as-src.html +0 -17
- package/docs/components/repl-repl.html +0 -95
- package/docs/components/repl.html +0 -527
- package/docs/components/timeline-repl.html +0 -72
- package/docs/components.html +0 -14
- package/docs/css/highlightjs.min.css +0 -9
- package/docs/css/tutorial.css +0 -35
- package/docs/examples/anchor.html +0 -11
- package/docs/examples/chart.html +0 -34
- package/docs/examples/counter.html +0 -26
- package/docs/examples/counter.test.mjs +0 -47
- package/docs/examples/counter2.html +0 -26
- package/docs/examples/directives.html +0 -79
- package/docs/examples/foreign.html +0 -50
- package/docs/examples/forgeinform.html +0 -98
- package/docs/examples/form.html +0 -61
- package/docs/examples/gauge.html +0 -18
- package/docs/examples/invalid-template-literals.html +0 -44
- package/docs/examples/medium/remote.html +0 -60
- package/docs/examples/message.html +0 -18
- package/docs/examples/nested.html +0 -11
- package/docs/examples/object-bound-form.html +0 -34
- package/docs/examples/remote-server.js +0 -51
- package/docs/examples/remote.html +0 -34
- package/docs/examples/remote.json +0 -1
- package/docs/examples/scratch.html +0 -69
- package/docs/examples/sensors/index.html +0 -44
- package/docs/examples/sensors/sensor-server.js +0 -30
- package/docs/examples/shared.html +0 -41
- package/docs/examples/template.html +0 -33
- package/docs/examples/timeline.html +0 -21
- package/docs/examples/todo.html +0 -40
- package/docs/examples/top.html +0 -10
- package/docs/examples/types.html +0 -94
- package/docs/examples/xor.html +0 -62
- package/docs/examples.html +0 -25
- package/docs/javascript/codejar.min.js +0 -8
- package/docs/javascript/highlightjs.min.js +0 -1173
- package/docs/javascript/isomorphic-git.js +0 -9
- package/docs/javascript/json5.min.js +0 -1
- package/docs/javascript/lightning-fs.js +0 -1
- package/docs/javascript/lightview.js +0 -1285
- package/docs/javascript/marked.min.js +0 -6
- package/docs/javascript/peerjs.min.js +0 -70
- package/docs/javascript/turndown.js +0 -973
- package/docs/javascript/types.js +0 -606
- package/docs/javascript/utils.js +0 -45
- package/docs/lightview.html +0 -63
- package/docs/old_index.html +0 -965
- package/docs/old_index.md +0 -1132
- package/docs/slidein.html +0 -51
- package/docs/tutorial/0-getting-started.html +0 -67
- package/docs/tutorial/1-intro-to-variables.html +0 -103
- package/docs/tutorial/10-template-components.html +0 -80
- package/docs/tutorial/11-linked-components.html +0 -76
- package/docs/tutorial/12-imported-components.html +0 -67
- package/docs/tutorial/13-input-binding.html +0 -94
- package/docs/tutorial/14-automatic-variable-creation.html +0 -74
- package/docs/tutorial/15-form-binding.html +0 -110
- package/docs/tutorial/16-if-directive.html +0 -60
- package/docs/tutorial/17-loop-directives.html +0 -83
- package/docs/tutorial/18-sanitizing-and-escaping-input.html +0 -79
- package/docs/tutorial/2-imported-and-exported-variables.html +0 -80
- package/docs/tutorial/3-data-types.html +0 -89
- package/docs/tutorial/4-extended-data-types.html +0 -83
- package/docs/tutorial/5-extended-functional-types.html +0 -96
- package/docs/tutorial/5.1-extended-functional-types.html +0 -79
- package/docs/tutorial/5.2-extended-functional-types.html +0 -70
- package/docs/tutorial/6-conventional-javascript.html +0 -75
- package/docs/tutorial/7-monitoring-with-observers.html +0 -107
- package/docs/tutorial/8-event-listeners.html +0 -65
- package/docs/tutorial/9-intro-to-components.html +0 -91
- package/docs/tutorial/contents.html +0 -32
- package/docs/tutorial/my-component.html +0 -29
- package/docs/tutorial/remote-value.json +0 -4
- package/docs/websiterepl.html +0 -46
- package/jest-puppeteer.config.js +0 -5
- package/jest.config.json +0 -12
- package/lightview.min.js +0 -1
- package/lightview_good.js +0 -1267
- package/lightview_optimized.js +0 -1274
- package/repl_hold.html +0 -320
- package/test/basic.html +0 -104
- package/test/basic.test.mjs +0 -315
- package/test/extended.html +0 -29
- package/test/extended.test.mjs +0 -448
- package/types.js +0 -607
- package/unsplash.key +0 -1
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
// Unique ID counter for iframe identification
|
|
2
|
+
var examplifyIdCounter = window.examplifyIdCounter || 0;
|
|
3
|
+
window.examplifyIdCounter = examplifyIdCounter;
|
|
4
|
+
|
|
5
|
+
function examplify(target, options = {}) {
|
|
6
|
+
const { scripts, styles, modules, html, at, location = 'beforeBegin', type, height, minHeight = 100, maxHeight = Infinity, allowSameOrigin = false, language = 'js', autoRun = false } = options;
|
|
7
|
+
const originalContent = target.textContent;
|
|
8
|
+
const autoResize = !height; // Auto-resize if no explicit height is provided
|
|
9
|
+
const iframeId = `examplify-${++examplifyIdCounter}`;
|
|
10
|
+
|
|
11
|
+
// State
|
|
12
|
+
let isRunning = false;
|
|
13
|
+
|
|
14
|
+
// 2. Create controls above the target
|
|
15
|
+
const controls = document.createElement('div');
|
|
16
|
+
const editable = target.getAttribute('contenteditable') == 'true';
|
|
17
|
+
controls.className = 'examplify-controls';
|
|
18
|
+
|
|
19
|
+
// Controls HTML
|
|
20
|
+
controls.innerHTML = `
|
|
21
|
+
<button class="examplify-btn examplify-run" title="Run">
|
|
22
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
|
|
23
|
+
<path d="M8 5v14l11-7z"/>
|
|
24
|
+
</svg>
|
|
25
|
+
<span>Run</span>
|
|
26
|
+
</button>
|
|
27
|
+
<button class="examplify-btn examplify-copy" title="Copy">
|
|
28
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
29
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
|
|
30
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
|
31
|
+
</svg>
|
|
32
|
+
<span>Copy</span>
|
|
33
|
+
</button>
|
|
34
|
+
${editable ? `<button class="examplify-btn examplify-reset" title="Reset" style="display: none;">
|
|
35
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
36
|
+
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/>
|
|
37
|
+
<path d="M3 3v5h5"/>
|
|
38
|
+
</svg>
|
|
39
|
+
<span>Reset</span>
|
|
40
|
+
</button>` : ''}
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
// 3. Create iframe after target (initially empty)
|
|
44
|
+
let iframe = document.createElement('iframe');
|
|
45
|
+
iframe.className = 'examplify-iframe';
|
|
46
|
+
iframe.style.opacity = '1';
|
|
47
|
+
iframe.style.background = '#f9fafb'; // Light gray placeholder
|
|
48
|
+
iframe.style.border = '1px solid #e5e7eb';
|
|
49
|
+
iframe.style.transition = 'opacity 0.2s ease-in, height 0.2s ease-out';
|
|
50
|
+
iframe.sandbox = `${allowSameOrigin ? 'allow-same-origin ' : ''}allow-scripts`;
|
|
51
|
+
|
|
52
|
+
if (height) iframe.style.height = height;
|
|
53
|
+
if (minHeight) iframe.style.minHeight = typeof minHeight === 'number' ? `${minHeight}px` : minHeight;
|
|
54
|
+
if (maxHeight && maxHeight !== Infinity) iframe.style.maxHeight = typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight;
|
|
55
|
+
|
|
56
|
+
// Set initial placeholder height if not specified, to show it exists
|
|
57
|
+
if (!height && !iframe.style.minHeight) {
|
|
58
|
+
iframe.style.height = '100px';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Insert elements
|
|
62
|
+
const insertionPoint = (at || target);
|
|
63
|
+
insertionPoint.insertAdjacentElement(location, iframe);
|
|
64
|
+
|
|
65
|
+
if (target.parentElement && target.parentElement.tagName === 'PRE') {
|
|
66
|
+
target.parentElement.insertAdjacentElement('beforebegin', controls);
|
|
67
|
+
target.parentElement.classList.add('examplify-parent');
|
|
68
|
+
target.style.outline = 'none';
|
|
69
|
+
target.style.border = 'none';
|
|
70
|
+
} else {
|
|
71
|
+
target.insertAdjacentElement('beforebegin', controls);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Styles
|
|
75
|
+
// We add styles only if not present, to avoid duplication if called multiple times
|
|
76
|
+
if (!document.getElementById('examplify-styles')) {
|
|
77
|
+
const style = document.createElement('style');
|
|
78
|
+
style.id = 'examplify-styles';
|
|
79
|
+
style.textContent = `
|
|
80
|
+
.examplify-controls {
|
|
81
|
+
display: flex;
|
|
82
|
+
gap: 0.5rem;
|
|
83
|
+
margin-bottom: 0.5rem;
|
|
84
|
+
}
|
|
85
|
+
.examplify-btn {
|
|
86
|
+
display: inline-flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
gap: 0.25rem;
|
|
89
|
+
padding: 0.25rem 0.5rem;
|
|
90
|
+
font-size: 0.75rem;
|
|
91
|
+
border: 1px solid #e5e7eb;
|
|
92
|
+
border-radius: 4px;
|
|
93
|
+
background: #f9fafb;
|
|
94
|
+
cursor: pointer;
|
|
95
|
+
transition: all 0.2s;
|
|
96
|
+
color: #374151;
|
|
97
|
+
}
|
|
98
|
+
.examplify-btn:hover {
|
|
99
|
+
background: #f3f4f6;
|
|
100
|
+
border-color: #d1d5db;
|
|
101
|
+
}
|
|
102
|
+
.examplify-iframe {
|
|
103
|
+
width: 100%;
|
|
104
|
+
border: 1px solid #e5e7eb;
|
|
105
|
+
border-radius: 6px;
|
|
106
|
+
margin-top: 0.5rem;
|
|
107
|
+
background: white;
|
|
108
|
+
}
|
|
109
|
+
.examplify-parent {
|
|
110
|
+
transition: outline 0.2s;
|
|
111
|
+
border-radius: 4px;
|
|
112
|
+
}
|
|
113
|
+
.examplify-parent:hover {
|
|
114
|
+
outline: 1px solid #d1d5db;
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
117
|
+
document.head.appendChild(style);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Helper: Placeholder Content
|
|
121
|
+
function getPlaceholderContent() {
|
|
122
|
+
return `<!DOCTYPE html>
|
|
123
|
+
<html>
|
|
124
|
+
<head>
|
|
125
|
+
<style>
|
|
126
|
+
body {
|
|
127
|
+
margin:0; padding:0; height:100vh;
|
|
128
|
+
display:flex; align-items:center; justify-content:center;
|
|
129
|
+
background:#f9fafb; color:#6b7280;
|
|
130
|
+
cursor:pointer; user-select:none;
|
|
131
|
+
font-family:system-ui,-apple-system,sans-serif;
|
|
132
|
+
transition: color 0.2s;
|
|
133
|
+
}
|
|
134
|
+
body:hover { color: #374151; }
|
|
135
|
+
.content { display:flex; align-items:center; gap:0.5rem; font-size:0.875rem; font-weight: 500; }
|
|
136
|
+
</style>
|
|
137
|
+
</head>
|
|
138
|
+
<body onclick="parent.postMessage({type:'examplify-run-click', id:'${iframeId}'}, '*')">
|
|
139
|
+
<div class="content">
|
|
140
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
|
141
|
+
<path d="M8 5v14l11-7z"/>
|
|
142
|
+
</svg>
|
|
143
|
+
<span>Click to run</span>
|
|
144
|
+
</div>
|
|
145
|
+
</body>
|
|
146
|
+
</html>`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Helper: Generate Iframe Content
|
|
150
|
+
function getIframeContent(codeContent) {
|
|
151
|
+
const currentTheme = document.documentElement.getAttribute('data-theme');
|
|
152
|
+
const themeAttr = currentTheme ? ` data-theme="${currentTheme}"` : '';
|
|
153
|
+
const autoResizeScript = autoResize ? `
|
|
154
|
+
<script>
|
|
155
|
+
const frameId = '${iframeId}';
|
|
156
|
+
function sendHeight() {
|
|
157
|
+
const height = Math.max(
|
|
158
|
+
document.body.scrollHeight,
|
|
159
|
+
document.body.offsetHeight,
|
|
160
|
+
document.documentElement.scrollHeight,
|
|
161
|
+
document.documentElement.offsetHeight
|
|
162
|
+
);
|
|
163
|
+
parent.postMessage({ type: 'examplify-resize', id: frameId, height: height }, '*');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
window.addEventListener('load', () => {
|
|
167
|
+
sendHeight();
|
|
168
|
+
setTimeout(sendHeight, 300);
|
|
169
|
+
setTimeout(sendHeight, 1000);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
173
|
+
const resizeObserver = new ResizeObserver(() => sendHeight());
|
|
174
|
+
resizeObserver.observe(document.body);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const mutationObserver = new MutationObserver(() => {
|
|
178
|
+
setTimeout(sendHeight, 50);
|
|
179
|
+
});
|
|
180
|
+
mutationObserver.observe(document.body, { childList: true, subtree: true, attributes: true });
|
|
181
|
+
</script>
|
|
182
|
+
` : '';
|
|
183
|
+
|
|
184
|
+
return `<!DOCTYPE html>
|
|
185
|
+
<html${themeAttr}>
|
|
186
|
+
<head>
|
|
187
|
+
<style>
|
|
188
|
+
/* Hide body until stylesheets are loaded to prevent FOUC */
|
|
189
|
+
body {
|
|
190
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
191
|
+
padding: 1rem;
|
|
192
|
+
margin: 0;
|
|
193
|
+
opacity: 0;
|
|
194
|
+
transition: opacity 0.15s ease-in;
|
|
195
|
+
}
|
|
196
|
+
body.styles-ready { opacity: 1; }
|
|
197
|
+
</style>
|
|
198
|
+
${styles ? styles.map(href => `<link rel="stylesheet" href="${href}">`).join('\n') : ''}
|
|
199
|
+
<script>
|
|
200
|
+
// Synchronously create the stylesheet-ready promise before any modules execute
|
|
201
|
+
window.__stylesheetsReady = (function() {
|
|
202
|
+
return new Promise(resolve => {
|
|
203
|
+
// Use requestAnimationFrame to ensure DOM is ready for querying
|
|
204
|
+
requestAnimationFrame(() => {
|
|
205
|
+
const links = Array.from(document.querySelectorAll('link[rel="stylesheet"]'));
|
|
206
|
+
if (links.length === 0) {
|
|
207
|
+
resolve();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let loaded = 0;
|
|
212
|
+
const checkDone = () => {
|
|
213
|
+
loaded++;
|
|
214
|
+
if (loaded >= links.length) resolve();
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
links.forEach(link => {
|
|
218
|
+
if (link.sheet) {
|
|
219
|
+
checkDone();
|
|
220
|
+
} else {
|
|
221
|
+
link.addEventListener('load', checkDone);
|
|
222
|
+
link.addEventListener('error', checkDone);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Fallback timeout
|
|
227
|
+
setTimeout(resolve, 2000);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
})();
|
|
231
|
+
<\/script>
|
|
232
|
+
${modules ? modules.map(src => `<script type="module" src="${src}"></script>`).join('\n') : ''}
|
|
233
|
+
${scripts ? scripts.map(src => `<script src="${src}"></script>`).join('\n') : ''}
|
|
234
|
+
<script type="module">
|
|
235
|
+
// Wait for stylesheets before initializing Lightview components
|
|
236
|
+
await window.__stylesheetsReady;
|
|
237
|
+
if (window.LightviewX) {
|
|
238
|
+
await window.LightviewX.initComponents({ shadowDefault: true });
|
|
239
|
+
}
|
|
240
|
+
</script>
|
|
241
|
+
</head>
|
|
242
|
+
<body>
|
|
243
|
+
${language === 'html' ? codeContent : (html ? html : '<div id="example"></div>')}
|
|
244
|
+
${language === 'html' ? '' : `<script ${type ? `type="${type}"` : ''}>
|
|
245
|
+
const render = (content) => {
|
|
246
|
+
const target = document.querySelector('#example');
|
|
247
|
+
target.innerHTML = '';
|
|
248
|
+
if (typeof content === 'string') {
|
|
249
|
+
target.innerHTML = content;
|
|
250
|
+
} else if (content && content.domEl) {
|
|
251
|
+
target.insertAdjacentElement('afterbegin', content.domEl);
|
|
252
|
+
} else if (content instanceof Node) {
|
|
253
|
+
target.insertAdjacentElement('afterbegin', content);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
${type === 'module' ? codeContent : `
|
|
257
|
+
// Wait for stylesheets before running example code
|
|
258
|
+
window.__stylesheetsReady.then(async () => {
|
|
259
|
+
${codeContent}
|
|
260
|
+
});
|
|
261
|
+
`}
|
|
262
|
+
</script>`}
|
|
263
|
+
${autoResizeScript}
|
|
264
|
+
<script>
|
|
265
|
+
// Reveal body and signal ready only after stylesheets are loaded
|
|
266
|
+
window.__stylesheetsReady.then(() => {
|
|
267
|
+
document.body.classList.add('styles-ready');
|
|
268
|
+
setTimeout(() => {
|
|
269
|
+
parent.postMessage({ type: 'examplify-ready', id: '${iframeId}' }, '*');
|
|
270
|
+
}, 50);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Listen for theme changes from parent
|
|
274
|
+
window.addEventListener('message', (event) => {
|
|
275
|
+
if (event.data && event.data.type === 'theme-change' && event.data.theme) {
|
|
276
|
+
document.documentElement.setAttribute('data-theme', event.data.theme);
|
|
277
|
+
if (window.LightviewX && typeof window.LightviewX.setTheme === 'function') {
|
|
278
|
+
window.LightviewX.setTheme(event.data.theme);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
</script>
|
|
283
|
+
</body>
|
|
284
|
+
</html>`;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Helper: Run
|
|
288
|
+
function run() {
|
|
289
|
+
const content = getIframeContent(target.textContent);
|
|
290
|
+
iframe.style.background = '#fff';
|
|
291
|
+
iframe.srcdoc = content;
|
|
292
|
+
isRunning = true;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Initialize: auto-run or show placeholder
|
|
296
|
+
if (autoRun) {
|
|
297
|
+
run();
|
|
298
|
+
} else {
|
|
299
|
+
iframe.srcdoc = getPlaceholderContent();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Event Listeners
|
|
303
|
+
const runBtn = controls.querySelector('.examplify-run');
|
|
304
|
+
runBtn.addEventListener('click', run);
|
|
305
|
+
|
|
306
|
+
const copyBtn = controls.querySelector('.examplify-copy');
|
|
307
|
+
copyBtn.addEventListener('click', () => {
|
|
308
|
+
navigator.clipboard.writeText(target.textContent);
|
|
309
|
+
|
|
310
|
+
// Feedback
|
|
311
|
+
const originalHtml = copyBtn.innerHTML;
|
|
312
|
+
copyBtn.innerHTML = `
|
|
313
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
314
|
+
<polyline points="20 6 9 17 4 12"></polyline>
|
|
315
|
+
</svg>
|
|
316
|
+
<span>Copied!</span>
|
|
317
|
+
`;
|
|
318
|
+
setTimeout(() => copyBtn.innerHTML = originalHtml, 2000);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
if (editable) {
|
|
322
|
+
const resetBtn = controls.querySelector('.examplify-reset');
|
|
323
|
+
|
|
324
|
+
// Reset action
|
|
325
|
+
resetBtn.addEventListener('click', () => {
|
|
326
|
+
target.textContent = originalContent;
|
|
327
|
+
resetBtn.style.display = 'none';
|
|
328
|
+
// Force reset even if running to reflect text change if any,
|
|
329
|
+
// but actually we want to reset to original content AND re-run
|
|
330
|
+
// OR go back to placeholder?
|
|
331
|
+
// Usually reset means "restore code to initial state".
|
|
332
|
+
// If the user modified code, we reset text.
|
|
333
|
+
// If they want to run the original code, they should click run?
|
|
334
|
+
// Or should we auto-run? Use Case: "Reset" usually implies "Fix my broken code".
|
|
335
|
+
// So re-running the original code makes sense.
|
|
336
|
+
if (isRunning) run();
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// Watch for changes
|
|
340
|
+
target.addEventListener('input', () => {
|
|
341
|
+
if (target.textContent !== originalContent) {
|
|
342
|
+
resetBtn.style.display = 'inline-flex';
|
|
343
|
+
} else {
|
|
344
|
+
resetBtn.style.display = 'none';
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Global Message Listener (for resizing and run click)
|
|
350
|
+
window.addEventListener('message', (event) => {
|
|
351
|
+
if (!event.data || event.data.id !== iframeId) return;
|
|
352
|
+
|
|
353
|
+
if (event.data.type === 'examplify-resize' && autoResize) {
|
|
354
|
+
const h = event.data.height + 2; // buffer
|
|
355
|
+
iframe.style.height = Math.max(minHeight, Math.min(h, maxHeight)) + 'px';
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (event.data.type === 'examplify-run-click') {
|
|
359
|
+
run();
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
return { controls, iframe, target, run };
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Global Theme Observer (Host side)
|
|
367
|
+
if (typeof document !== 'undefined') {
|
|
368
|
+
let themeObserver = null;
|
|
369
|
+
const initThemeObserver = () => {
|
|
370
|
+
if (themeObserver) return;
|
|
371
|
+
|
|
372
|
+
themeObserver = new MutationObserver((mutations) => {
|
|
373
|
+
mutations.forEach((mutation) => {
|
|
374
|
+
if (mutation.attributeName === 'data-theme') {
|
|
375
|
+
const newTheme = document.documentElement.getAttribute('data-theme');
|
|
376
|
+
// Broadcast to all examplify iframes
|
|
377
|
+
document.querySelectorAll('.examplify-iframe').forEach(iframe => {
|
|
378
|
+
if (iframe.contentWindow) {
|
|
379
|
+
iframe.contentWindow.postMessage({ type: 'theme-change', theme: newTheme }, '*');
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] });
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// Initialize when DOM is ready
|
|
390
|
+
if (document.readyState === 'loading') {
|
|
391
|
+
document.addEventListener('DOMContentLoaded', initThemeObserver);
|
|
392
|
+
} else {
|
|
393
|
+
initThemeObserver();
|
|
394
|
+
}
|
|
395
|
+
}
|