lightview 1.8.1-b → 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.
Files changed (224) hide show
  1. package/.agent/workflows/daisyui-component-migration.md +155 -0
  2. package/.codacy/cli.sh +149 -0
  3. package/.codacy/codacy.yaml +15 -0
  4. package/.github/instructions/codacy.instructions.md +72 -0
  5. package/.wranglerignore +21 -0
  6. package/README.md +1331 -21
  7. package/_headers +4 -0
  8. package/build.js +70 -0
  9. package/components/actions/button.js +151 -0
  10. package/components/actions/dropdown.js +120 -0
  11. package/components/actions/modal.js +146 -0
  12. package/components/actions/swap.js +118 -0
  13. package/components/daisyui.js +288 -0
  14. package/components/data-display/accordion.js +128 -0
  15. package/components/data-display/alert.js +112 -0
  16. package/components/data-display/avatar.js +170 -0
  17. package/components/data-display/badge.js +82 -0
  18. package/components/data-display/card.js +151 -0
  19. package/components/data-display/carousel.js +94 -0
  20. package/components/data-display/chart.js +220 -0
  21. package/components/data-display/chat.js +128 -0
  22. package/components/data-display/collapse.js +103 -0
  23. package/components/data-display/countdown.js +69 -0
  24. package/components/data-display/diff.js +111 -0
  25. package/components/data-display/kbd.js +65 -0
  26. package/components/data-display/loading.js +75 -0
  27. package/components/data-display/progress.js +79 -0
  28. package/components/data-display/radial-progress.js +88 -0
  29. package/components/data-display/skeleton.js +66 -0
  30. package/components/data-display/stats.js +159 -0
  31. package/components/data-display/table.js +146 -0
  32. package/components/data-display/timeline.js +146 -0
  33. package/components/data-display/toast.js +72 -0
  34. package/components/data-display/tooltip.js +74 -0
  35. package/components/data-input/checkbox.js +253 -0
  36. package/components/data-input/file-input.js +224 -0
  37. package/components/data-input/input.js +264 -0
  38. package/components/data-input/radio.js +338 -0
  39. package/components/data-input/range.js +204 -0
  40. package/components/data-input/rating.js +219 -0
  41. package/components/data-input/select.js +287 -0
  42. package/components/data-input/textarea.js +287 -0
  43. package/components/data-input/toggle.js +201 -0
  44. package/components/index.js +137 -0
  45. package/components/layout/divider.js +72 -0
  46. package/components/layout/drawer.js +142 -0
  47. package/components/layout/footer.js +100 -0
  48. package/components/layout/hero.js +109 -0
  49. package/components/layout/indicator.js +90 -0
  50. package/components/layout/join.js +78 -0
  51. package/components/layout/navbar.js +110 -0
  52. package/components/navigation/breadcrumbs.js +91 -0
  53. package/components/navigation/dock.js +103 -0
  54. package/components/navigation/menu.js +126 -0
  55. package/components/navigation/pagination.js +105 -0
  56. package/components/navigation/steps.js +89 -0
  57. package/components/navigation/tabs.css +177 -0
  58. package/components/navigation/tabs.js +123 -0
  59. package/components/theme/theme-switch.css +65 -0
  60. package/components/theme/theme-switch.js +177 -0
  61. package/docs/about.html +164 -0
  62. package/docs/api/computed.html +184 -0
  63. package/docs/api/effects.html +173 -0
  64. package/docs/api/elements.html +180 -0
  65. package/docs/api/enhance.html +225 -0
  66. package/docs/api/hypermedia.html +165 -0
  67. package/docs/api/index.html +178 -0
  68. package/docs/api/nav.html +18 -0
  69. package/docs/api/signals.html +136 -0
  70. package/docs/api/state.html +217 -0
  71. package/docs/assets/images/logo-favicon.svg +42 -0
  72. package/docs/assets/images/logo-static.svg +40 -0
  73. package/docs/assets/images/logo.svg +66 -0
  74. package/docs/assets/js/examplify.js +395 -0
  75. package/docs/assets/styles/site.css +1102 -0
  76. package/docs/assets/styles/themes.css +236 -0
  77. package/docs/components/accordion.html +439 -0
  78. package/docs/components/alert.html +528 -0
  79. package/docs/components/avatar.html +586 -0
  80. package/docs/components/badge.html +531 -0
  81. package/docs/components/breadcrumbs.html +278 -0
  82. package/docs/components/button.html +579 -0
  83. package/docs/components/card.html +561 -0
  84. package/docs/components/carousel.html +286 -0
  85. package/docs/components/chart-area.html +702 -0
  86. package/docs/components/chart-bar.html +782 -0
  87. package/docs/components/chart-column.html +735 -0
  88. package/docs/components/chart-line.html +794 -0
  89. package/docs/components/chart-pie.html +823 -0
  90. package/docs/components/chart.html +612 -0
  91. package/docs/components/chat.html +547 -0
  92. package/docs/components/checkbox.html +641 -0
  93. package/docs/components/collapse.html +536 -0
  94. package/docs/components/component-nav.html +53 -0
  95. package/docs/components/countdown.html +470 -0
  96. package/docs/components/diff.html +245 -0
  97. package/docs/components/divider.html +240 -0
  98. package/docs/components/dock.html +277 -0
  99. package/docs/components/drawer.html +515 -0
  100. package/docs/components/dropdown.html +479 -0
  101. package/docs/components/file-input.html +591 -0
  102. package/docs/components/footer.html +301 -0
  103. package/docs/components/gallery.html +504 -0
  104. package/docs/components/hero.html +264 -0
  105. package/docs/components/index.css +840 -0
  106. package/docs/components/index.html +735 -0
  107. package/docs/components/indicator.html +342 -0
  108. package/docs/components/input.html +644 -0
  109. package/docs/components/join.html +285 -0
  110. package/docs/components/kbd.html +322 -0
  111. package/docs/components/loading.html +521 -0
  112. package/docs/components/menu.html +461 -0
  113. package/docs/components/modal.html +639 -0
  114. package/docs/components/navbar.html +321 -0
  115. package/docs/components/pagination.html +279 -0
  116. package/docs/components/progress.html +514 -0
  117. package/docs/components/radial-progress.html +434 -0
  118. package/docs/components/radio.html +655 -0
  119. package/docs/components/range.html +611 -0
  120. package/docs/components/rating.html +642 -0
  121. package/docs/components/select.html +696 -0
  122. package/docs/components/sidebar-setup.js +93 -0
  123. package/docs/components/skeleton.html +447 -0
  124. package/docs/components/spinner.html +68 -0
  125. package/docs/components/stats.html +486 -0
  126. package/docs/components/steps.html +356 -0
  127. package/docs/components/swap.html +517 -0
  128. package/docs/components/switch.html +68 -0
  129. package/docs/components/table.html +668 -0
  130. package/docs/components/tabs.html +506 -0
  131. package/docs/components/text-input.html +68 -0
  132. package/docs/components/textarea.html +603 -0
  133. package/docs/components/timeline.html +487 -0
  134. package/docs/components/toast.html +474 -0
  135. package/docs/components/toggle.html +564 -0
  136. package/docs/components/tooltip.html +423 -0
  137. package/docs/examples/getting-started-example.html +40 -0
  138. package/docs/examples/index.html +93 -0
  139. package/docs/getting-started/index.html +739 -0
  140. package/docs/getting-started/reviews.html +23 -0
  141. package/docs/getting-started/reviews.odom +108 -0
  142. package/docs/getting-started/reviews.vdom +84 -0
  143. package/docs/index.html +134 -0
  144. package/docs/playground.html +416 -0
  145. package/docs/router.html +285 -0
  146. package/docs/styles/index.html +190 -0
  147. package/functions/_middleware.js +32 -0
  148. package/index.html +309 -0
  149. package/lightview-router.js +364 -0
  150. package/lightview-x.js +1577 -0
  151. package/lightview.js +658 -1109
  152. package/lightview.js.backup +793 -0
  153. package/middleware/locale.js +25 -0
  154. package/middleware/markdown.js +44 -0
  155. package/middleware/notFound.js +37 -0
  156. package/package.json +27 -41
  157. package/watch.js +92 -0
  158. package/wrangler.toml +12 -0
  159. package/.idea/lightview.iml +0 -12
  160. package/.idea/modules.xml +0 -8
  161. package/.idea/vcs.xml +0 -6
  162. package/LICENSE +0 -21
  163. package/codepen-no-tabs-embed.css +0 -2
  164. package/components/chart/chart.html +0 -17
  165. package/components/chart/example.html +0 -32
  166. package/components/chart.html +0 -83
  167. package/components/components.js +0 -113
  168. package/components/gantt/example.html +0 -22
  169. package/components/gantt/gantt.html +0 -42
  170. package/components/gauge/example.html +0 -28
  171. package/components/gauge/gauge.html +0 -20
  172. package/components/gauge.html +0 -60
  173. package/components/orgchart/example.html +0 -25
  174. package/components/orgchart/orgchart.html +0 -41
  175. package/components/repl/code-editor.html +0 -64
  176. package/components/repl/editor.html +0 -37
  177. package/components/repl/editorjs-inline-tool/index.js +0 -3
  178. package/components/repl/editorjs-inline-tool/inline-tools.js +0 -28
  179. package/components/repl/editorjs-inline-tool/tool.js +0 -175
  180. package/components/repl/repl-with-wysiwyg.html +0 -355
  181. package/components/repl/repl.html +0 -345
  182. package/components/repl/sup.js +0 -44
  183. package/components/repl/wysiwyg-repl.html +0 -258
  184. package/components/timeline/example.html +0 -33
  185. package/components/timeline/timeline.html +0 -44
  186. package/components/timeline.html +0 -81
  187. package/examples/anchor.html +0 -11
  188. package/examples/chart.html +0 -34
  189. package/examples/counter.html +0 -26
  190. package/examples/counter.test.mjs +0 -47
  191. package/examples/counter2.html +0 -26
  192. package/examples/directives.html +0 -79
  193. package/examples/foreign.html +0 -50
  194. package/examples/forgeinform.html +0 -98
  195. package/examples/form.html +0 -61
  196. package/examples/gauge.html +0 -18
  197. package/examples/invalid-template-literals.html +0 -44
  198. package/examples/medium/remote.html +0 -60
  199. package/examples/message.html +0 -18
  200. package/examples/nested.html +0 -11
  201. package/examples/object-bound-form.html +0 -34
  202. package/examples/remote-server.js +0 -51
  203. package/examples/remote.html +0 -34
  204. package/examples/remote.json +0 -1
  205. package/examples/scratch.html +0 -69
  206. package/examples/sensors/index.html +0 -30
  207. package/examples/sensors/sensor-server.js +0 -30
  208. package/examples/shared.html +0 -41
  209. package/examples/template.html +0 -33
  210. package/examples/timeline.html +0 -21
  211. package/examples/todo.html +0 -38
  212. package/examples/top.html +0 -10
  213. package/examples/types.html +0 -94
  214. package/examples/xor.html +0 -62
  215. package/jest-puppeteer.config.js +0 -5
  216. package/jest.config.json +0 -12
  217. package/sites/client.html +0 -48
  218. package/sites/index.html +0 -247
  219. package/test/basic.html +0 -93
  220. package/test/basic.test.mjs +0 -315
  221. package/test/extended.html +0 -29
  222. package/test/extended.test.mjs +0 -448
  223. package/types.js +0 -534
  224. package/unsplash.key +0 -1
@@ -0,0 +1,639 @@
1
+ <!-- SEO-friendly SPA Shim -->
2
+ <script src="/lightview-router.js"></script>
3
+ <script>
4
+ if (window.LightviewRouter) {
5
+ LightviewRouter.base('/index.html');
6
+ }
7
+ </script>
8
+
9
+ <!-- Load the page-specific stylesheet -->
10
+ <link rel="stylesheet" href="./index.css">
11
+
12
+ <!-- Gallery Structure -->
13
+ <div class="gallery-page">
14
+ <div class="gallery-layout">
15
+ <!-- Sidebar Overlay -->
16
+ <div id="sidebar-overlay" class="sidebar-overlay"></div>
17
+
18
+ <!-- Sidebar -->
19
+ <div id="gallery-sidebar" class="gallery-sidebar" style="visibility: hidden" src="./component-nav.html"></div>
20
+
21
+ <!-- Main Content -->
22
+ <div id="gallery-main" class="gallery-main">
23
+ <!-- Header Container -->
24
+ <div
25
+ style="position: sticky; top: 0; z-index: 30; background: var(--gallery-surface); border-bottom: 1px solid var(--gallery-border); backdrop-filter: blur(8px);">
26
+ <!-- Breadcrumbs Row -->
27
+ <div style="padding: 0.75rem 1.5rem 0;">
28
+ <script>
29
+ (() => {
30
+ const { Breadcrumbs } = Lightview.tags;
31
+ const breadcrumbs = Breadcrumbs({
32
+ id: 'page-breadcrumbs',
33
+ items: [
34
+ { label: 'Components', href: '/docs/components' },
35
+ { label: 'Modal' }
36
+ ]
37
+ });
38
+ document.currentScript.replaceWith(breadcrumbs.domEl);
39
+ })();
40
+ </script>
41
+ </div>
42
+ <!-- Title Row -->
43
+ <div class="gallery-header"
44
+ style="border-bottom: none; height: auto; padding-top: 0.5rem; padding-bottom: 0.75rem;">
45
+ <button id="toggle-btn" class="toggle-btn" aria-label="Toggle Sidebar">
46
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="toggle-icon"
47
+ style="stroke: currentColor; stroke-width: 2;">
48
+ <path stroke-linecap="round" stroke-linejoin="round" d="M15 19l-7-7 7-7" />
49
+ <path stroke-linecap="round" stroke-linejoin="round" d="M11 19l-7-7 7-7" />
50
+ </svg>
51
+ </button>
52
+ <h1 class="gallery-title">Modal</h1>
53
+ </div>
54
+ </div>
55
+
56
+ <!-- Content -->
57
+ <div class="gallery-content">
58
+ <div class="section-content" style="max-width: 1000px;">
59
+ <p class="text-lg" style="opacity: 0.7; margin-bottom: 1.5rem;">
60
+ Modal is used to show a dialog or a box when you click a button.
61
+ Uses the native HTML <code>&lt;dialog&gt;</code> element for accessibility.
62
+ </p>
63
+
64
+ <!-- Basic Example with Examplify -->
65
+ <div class="card bg-base-200" style="margin-bottom: 2rem;">
66
+ <div class="card-body">
67
+ <h2 class="card-title">Basic Example</h2>
68
+ <p class="text-sm" style="opacity: 0.7; margin-bottom: 1rem;">Simple modal with open/close
69
+ functionality
70
+ </p>
71
+
72
+ <!-- Tabs -->
73
+ <script>
74
+ window.switchSyntaxTab = (tabId) => {
75
+ const tabs = ['tagged', 'vdom', 'object'];
76
+ tabs.forEach(t => {
77
+ const tabEl = document.getElementById(`tab-btn-${t}`);
78
+ const contentEl = document.getElementById(`syntax-${t}`);
79
+ if (t === tabId) {
80
+ tabEl.classList.add('syntax-tab-active');
81
+ contentEl.style.display = 'block';
82
+ } else {
83
+ tabEl.classList.remove('syntax-tab-active');
84
+ contentEl.style.display = 'none';
85
+ }
86
+ });
87
+ };
88
+ </script>
89
+ <div role="tablist" class="syntax-tabs" style="margin-bottom: 1rem;">
90
+ <button id="tab-btn-tagged" role="tab" class="syntax-tab syntax-tab-active"
91
+ onclick="switchSyntaxTab('tagged')">Tagged</button>
92
+ <button id="tab-btn-vdom" role="tab" class="syntax-tab"
93
+ onclick="switchSyntaxTab('vdom')">vDOM</button>
94
+ <button id="tab-btn-object" role="tab" class="syntax-tab"
95
+ onclick="switchSyntaxTab('object')">Object
96
+ DOM</button>
97
+ </div>
98
+
99
+ <!-- Tagged Syntax -->
100
+ <div id="syntax-tagged">
101
+ <pre><script>
102
+ examplify(document.currentScript.nextElementSibling, {
103
+ at: document.currentScript.parentElement,
104
+ scripts: ['/lightview.js', '/lightview-x.js'],
105
+ styles: ['https://cdn.jsdelivr.net/npm/daisyui@3.9.4/dist/full.min.css'],
106
+ type: 'module',
107
+ minHeight: 60,
108
+ autoRun: true
109
+ });
110
+ </script><code contenteditable="true">await import('/components/actions/modal.js');
111
+ await import('/components/actions/button.js');
112
+
113
+ const { tags, $ } = Lightview;
114
+ const { h3, p, Modal, Button } = tags;
115
+
116
+ const modalId = 'my_modal';
117
+
118
+ // Create the modal
119
+ const modal = Modal({ id: modalId },
120
+ Modal.Box({},
121
+ h3({ class: 'text-lg font-bold' }, 'Hello! 👋'),
122
+ p({ class: 'py-4' }, 'This modal was created with Lightview components.'),
123
+ Modal.Action({},
124
+ Button({ onclick: () => Modal.close(modalId) }, 'Close')
125
+ )
126
+ ),
127
+ Modal.Backdrop({})
128
+ );
129
+
130
+ // Create trigger button
131
+ const trigger = Button({
132
+ color: 'primary',
133
+ onclick: () => Modal.open(modalId)
134
+ }, 'Open Modal');
135
+
136
+ $('#example').content([trigger, modal]);</code></pre>
137
+ </div>
138
+
139
+ <!-- vDOM Syntax -->
140
+ <div id="syntax-vdom" style="display: none;">
141
+ <pre><script>
142
+ examplify(document.currentScript.nextElementSibling, {
143
+ at: document.currentScript.parentElement,
144
+ scripts: ['/lightview.js', '/lightview-x.js'],
145
+ styles: ['https://cdn.jsdelivr.net/npm/daisyui@3.9.4/dist/full.min.css'],
146
+ type: 'module',
147
+ minHeight: 60
148
+ });
149
+ </script><code contenteditable="true">await import('/components/actions/modal.js');
150
+ await import('/components/actions/button.js');
151
+ const { $, tags } = Lightview;
152
+ const { Modal, Button, h3, p } = tags;
153
+
154
+ const modalId = 'my_modal';
155
+
156
+ // Create the modal
157
+ const modal = {
158
+ tag: Modal,
159
+ attributes: { id: modalId },
160
+ children: [
161
+ {
162
+ tag: Modal.Box,
163
+ children: [
164
+ { tag: h3, attributes: { class: 'text-lg font-bold' }, children: ['Hello! 👋'] },
165
+ { tag: p, attributes: { class: 'py-4' }, children: ['This modal was created with Lightview components.'] },
166
+ {
167
+ tag: Modal.Action,
168
+ children: [
169
+ { tag: Button, attributes: { onclick: () => Modal.close(modalId) }, children: ['Close'] }
170
+ ]
171
+ }
172
+ ]
173
+ },
174
+ { tag: Modal.Backdrop }
175
+ ]
176
+ };
177
+
178
+ // Create trigger button
179
+ const trigger = {
180
+ tag: Button,
181
+ attributes: {
182
+ color: 'primary',
183
+ onclick: () => Modal.open(modalId)
184
+ },
185
+ children: ['Open Modal']
186
+ };
187
+
188
+ $('#example').content([trigger, modal]);</code></pre>
189
+ </div>
190
+
191
+ <!-- Object DOM Syntax -->
192
+ <div id="syntax-object" style="display: none;">
193
+ <pre><script>
194
+ examplify(document.currentScript.nextElementSibling, {
195
+ at: document.currentScript.parentElement,
196
+ scripts: ['/lightview.js', '/lightview-x.js'],
197
+ styles: ['https://cdn.jsdelivr.net/npm/daisyui@3.9.4/dist/full.min.css'],
198
+ type: 'module',
199
+ minHeight: 60
200
+ });
201
+ </script><code contenteditable="true">await import('/components/actions/modal.js');
202
+ await import('/components/actions/button.js');
203
+ const { $ } = Lightview;
204
+ const { Modal } = Lightview.tags;
205
+
206
+ const modalId = 'my_modal';
207
+
208
+ // Create the modal
209
+ const modal = {
210
+ Modal: {
211
+ id: modalId,
212
+ children: [
213
+ {
214
+ 'Modal.Box': {
215
+ children: [
216
+ { h3: { class: 'text-lg font-bold', children: ['Hello! 👋'] } },
217
+ { p: { class: 'py-4', children: ['This modal was created with Lightview components.'] } },
218
+ {
219
+ 'Modal.Action': {
220
+ children: [{ Button: { onclick: () => Modal.close(modalId), children: ['Close'] } }]
221
+ }
222
+ }
223
+ ]
224
+ }
225
+ },
226
+ { 'Modal.Backdrop': {} }
227
+ ]
228
+ }
229
+ };
230
+
231
+ // Create trigger button
232
+ const trigger = {
233
+ Button: {
234
+ color: 'primary',
235
+ onclick: () => Modal.open(modalId),
236
+ children: ['Open Modal']
237
+ }
238
+ };
239
+
240
+ $('#example').content([trigger, modal]);</code></pre>
241
+ </div>
242
+ </div>
243
+ </div>
244
+
245
+ <!-- Reactive Example with Examplify -->
246
+ <div class="card bg-base-200" style="margin-bottom: 2rem;">
247
+ <div class="card-body">
248
+ <h2 class="card-title">Confirmation Dialog</h2>
249
+ <p class="text-sm" style="opacity: 0.7; margin-bottom: 1rem;">Modal with confirm/cancel
250
+ actions</p>
251
+
252
+ <!-- Tabs -->
253
+ <script>
254
+ window.switchReactiveSyntaxTab = (tabId) => {
255
+ const tabs = ['tagged', 'vdom', 'object'];
256
+ tabs.forEach(t => {
257
+ const tabEl = document.getElementById(`tab-btn-reactive-${t}`);
258
+ const contentEl = document.getElementById(`syntax-reactive-${t}`);
259
+ if (t === tabId) {
260
+ tabEl.classList.add('syntax-tab-active');
261
+ contentEl.style.display = 'block';
262
+ } else {
263
+ tabEl.classList.remove('syntax-tab-active');
264
+ contentEl.style.display = 'none';
265
+ }
266
+ });
267
+ };
268
+ </script>
269
+ <div role="tablist" class="syntax-tabs" style="margin-bottom: 1rem;">
270
+ <button id="tab-btn-reactive-tagged" role="tab" class="syntax-tab syntax-tab-active"
271
+ onclick="switchReactiveSyntaxTab('tagged')">Tagged</button>
272
+ <button id="tab-btn-reactive-vdom" role="tab" class="syntax-tab"
273
+ onclick="switchReactiveSyntaxTab('vdom')">vDOM</button>
274
+ <button id="tab-btn-reactive-object" role="tab" class="syntax-tab"
275
+ onclick="switchReactiveSyntaxTab('object')">Object DOM</button>
276
+ </div>
277
+
278
+ <!-- Tagged Syntax -->
279
+ <div id="syntax-reactive-tagged">
280
+ <pre><script>
281
+ examplify(document.currentScript.nextElementSibling, {
282
+ at: document.currentScript.parentElement,
283
+ scripts: ['/lightview.js', '/lightview-x.js'],
284
+ styles: ['https://cdn.jsdelivr.net/npm/daisyui@3.9.4/dist/full.min.css'],
285
+ type: 'module',
286
+ minHeight: 60
287
+ });
288
+ </script><code contenteditable="true">await import('/components/actions/modal.js');
289
+ await import('/components/actions/button.js');
290
+
291
+ const { signal, tags, $ } = Lightview;
292
+ const { div, h3, p, Modal, Button } = tags;
293
+
294
+ const status = signal('Ready');
295
+ const modalId = 'confirm_modal';
296
+
297
+ const handleConfirm = () => {
298
+ status.value = '✅ Confirmed!';
299
+ Modal.close(modalId);
300
+ };
301
+
302
+ const handleCancel = () => {
303
+ status.value = '❌ Cancelled';
304
+ Modal.close(modalId);
305
+ };
306
+
307
+ const confirmModal = Modal({ id: modalId },
308
+ Modal.Box({},
309
+ h3({ class: 'text-lg font-bold' }, 'Are you sure?'),
310
+ p({ class: 'py-4' }, 'This action cannot be undone.'),
311
+ Modal.Action({},
312
+ Button({ color: 'ghost', onclick: handleCancel }, 'Cancel'),
313
+ Button({ color: 'error', onclick: handleConfirm }, 'Delete')
314
+ )
315
+ ),
316
+ Modal.Backdrop({})
317
+ );
318
+
319
+ const demo = div({ style: 'display: flex; align-items: center; gap: 1rem' },
320
+ Button({
321
+ color: 'error',
322
+ variant: 'outline',
323
+ onclick: () => Modal.open(modalId)
324
+ }, 'Delete Item'),
325
+ p({ class: 'text-sm opacity-70' }, () => `Status: ${status.value}`),
326
+ confirmModal
327
+ );
328
+
329
+ $('#example').content(demo);</code></pre>
330
+ </div>
331
+
332
+ <!-- vDOM Syntax -->
333
+ <div id="syntax-reactive-vdom" style="display: none;">
334
+ <pre><script>
335
+ examplify(document.currentScript.nextElementSibling, {
336
+ at: document.currentScript.parentElement,
337
+ scripts: ['/lightview.js', '/lightview-x.js'],
338
+ styles: ['https://cdn.jsdelivr.net/npm/daisyui@3.9.4/dist/full.min.css'],
339
+ type: 'module',
340
+ minHeight: 60
341
+ });
342
+ </script><code contenteditable="true">await import('/components/actions/modal.js');
343
+ await import('/components/actions/button.js');
344
+ const { signal, $, tags } = Lightview;
345
+ const { Modal, Button, div, h3, p } = tags;
346
+
347
+ const status = signal('Ready');
348
+ const modalId = 'confirm_modal';
349
+
350
+ const handleConfirm = () => {
351
+ status.value = '✅ Confirmed!';
352
+ Modal.close(modalId);
353
+ };
354
+
355
+ const handleCancel = () => {
356
+ status.value = '❌ Cancelled';
357
+ Modal.close(modalId);
358
+ };
359
+
360
+ const confirmModal = {
361
+ tag: Modal,
362
+ attributes: { id: modalId },
363
+ children: [
364
+ {
365
+ tag: Modal.Box,
366
+ children: [
367
+ { tag: h3, attributes: { class: 'text-lg font-bold' }, children: ['Are you sure?'] },
368
+ { tag: p, attributes: { class: 'py-4' }, children: ['This action cannot be undone.'] },
369
+ {
370
+ tag: Modal.Action,
371
+ children: [
372
+ { tag: Button, attributes: { color: 'ghost', onclick: handleCancel }, children: ['Cancel'] },
373
+ { tag: Button, attributes: { color: 'error', onclick: handleConfirm }, children: ['Delete'] }
374
+ ]
375
+ }
376
+ ]
377
+ },
378
+ { tag: Modal.Backdrop }
379
+ ]
380
+ };
381
+
382
+ const demo = {
383
+ tag: div,
384
+ attributes: { style: 'display: flex; align-items: center; gap: 1rem' },
385
+ children: [
386
+ {
387
+ tag: Button,
388
+ attributes: {
389
+ color: 'error',
390
+ variant: 'outline',
391
+ onclick: () => Modal.open(modalId)
392
+ },
393
+ children: ['Delete Item']
394
+ },
395
+ { tag: p, attributes: { class: 'text-sm opacity-70' }, children: [() => `Status: ${status.value}`] },
396
+ confirmModal
397
+ ]
398
+ };
399
+
400
+ $('#example').content(demo);</code></pre>
401
+ </div>
402
+
403
+ <!-- Object DOM Syntax -->
404
+ <div id="syntax-reactive-object" style="display: none;">
405
+ <pre><script>
406
+ examplify(document.currentScript.nextElementSibling, {
407
+ at: document.currentScript.parentElement,
408
+ scripts: ['/lightview.js', '/lightview-x.js'],
409
+ styles: ['https://cdn.jsdelivr.net/npm/daisyui@3.9.4/dist/full.min.css'],
410
+ type: 'module',
411
+ minHeight: 60
412
+ });
413
+ </script><code contenteditable="true">await import('/components/actions/modal.js');
414
+ await import('/components/actions/button.js');
415
+ const { signal, $ } = Lightview;
416
+ const { Modal } = Lightview.tags;
417
+
418
+ const status = signal('Ready');
419
+ const modalId = 'confirm_modal';
420
+
421
+ const handleConfirm = () => {
422
+ status.value = '✅ Confirmed!';
423
+ Modal.close(modalId);
424
+ };
425
+
426
+ const handleCancel = () => {
427
+ status.value = '❌ Cancelled';
428
+ Modal.close(modalId);
429
+ };
430
+
431
+ const confirmModal = {
432
+ Modal: {
433
+ id: modalId,
434
+ children: [
435
+ {
436
+ 'Modal.Box': {
437
+ children: [
438
+ { h3: { class: 'text-lg font-bold', children: ['Are you sure?'] } },
439
+ { p: { class: 'py-4', children: ['This action cannot be undone.'] } },
440
+ {
441
+ 'Modal.Action': {
442
+ children: [
443
+ { Button: { color: 'ghost', onclick: handleCancel, children: ['Cancel'] } },
444
+ { Button: { color: 'error', onclick: handleConfirm, children: ['Delete'] } }
445
+ ]
446
+ }
447
+ }
448
+ ]
449
+ }
450
+ },
451
+ { 'Modal.Backdrop': {} }
452
+ ]
453
+ }
454
+ };
455
+
456
+ const demo = {
457
+ div: {
458
+ style: 'display: flex; align-items: center; gap: 1rem',
459
+ children: [
460
+ {
461
+ Button: {
462
+ color: 'error',
463
+ variant: 'outline',
464
+ onclick: () => Modal.open(modalId),
465
+ children: ['Delete Item']
466
+ }
467
+ },
468
+ { p: { class: 'text-sm opacity-70', children: [() => `Status: ${status.value}`] } },
469
+ confirmModal
470
+ ]
471
+ }
472
+ };
473
+
474
+ $('#example').content(demo);</code></pre>
475
+ </div>
476
+ </div>
477
+ </div>
478
+
479
+ <!-- Props Table -->
480
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">Props</h2>
481
+ <div style="overflow-x: auto; margin-bottom: 2rem;">
482
+ <table class="table table-zebra">
483
+ <thead>
484
+ <tr>
485
+ <th>Prop</th>
486
+ <th>Type</th>
487
+ <th>Default</th>
488
+ <th>Description</th>
489
+ </tr>
490
+ </thead>
491
+ <tbody>
492
+ <tr>
493
+ <td><code>id</code></td>
494
+ <td>string</td>
495
+ <td>-</td>
496
+ <td>Required unique ID for the modal</td>
497
+ </tr>
498
+ <tr>
499
+ <td><code>open</code></td>
500
+ <td>boolean | function</td>
501
+ <td>false</td>
502
+ <td>Control open state (reactive)</td>
503
+ </tr>
504
+ <tr>
505
+ <td><code>position</code></td>
506
+ <td>string</td>
507
+ <td>'middle'</td>
508
+ <td>'top' | 'middle' | 'bottom'</td>
509
+ </tr>
510
+ <tr>
511
+ <td><code>onClose</code></td>
512
+ <td>function</td>
513
+ <td>-</td>
514
+ <td>Callback when modal closes</td>
515
+ </tr>
516
+ </tbody>
517
+ </table>
518
+ </div>
519
+
520
+ <!-- Static Methods -->
521
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">Static Methods</h2>
522
+ <div style="overflow-x: auto; margin-bottom: 2rem;">
523
+ <table class="table table-zebra">
524
+ <thead>
525
+ <tr>
526
+ <th>Method</th>
527
+ <th>Description</th>
528
+ </tr>
529
+ </thead>
530
+ <tbody>
531
+ <tr>
532
+ <td><code>Modal.open(id)</code></td>
533
+ <td>Open a modal by its ID</td>
534
+ </tr>
535
+ <tr>
536
+ <td><code>Modal.close(id)</code></td>
537
+ <td>Close a modal by its ID</td>
538
+ </tr>
539
+ </tbody>
540
+ </table>
541
+ </div>
542
+
543
+ <!-- Sub-components -->
544
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">Sub-components</h2>
545
+ <div style="overflow-x: auto; margin-bottom: 2rem;">
546
+ <table class="table table-zebra">
547
+ <thead>
548
+ <tr>
549
+ <th>Component</th>
550
+ <th>Description</th>
551
+ </tr>
552
+ </thead>
553
+ <tbody>
554
+ <tr>
555
+ <td><code>Modal.Box</code></td>
556
+ <td>The content container</td>
557
+ </tr>
558
+ <tr>
559
+ <td><code>Modal.Action</code></td>
560
+ <td>Container for action buttons (typically at bottom)</td>
561
+ </tr>
562
+ <tr>
563
+ <td><code>Modal.Backdrop</code></td>
564
+ <td>Click-to-close backdrop</td>
565
+ </tr>
566
+ </tbody>
567
+ </table>
568
+ </div>
569
+
570
+ <!-- Positions -->
571
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">Positions</h2>
572
+ <div class="example-flex" style="margin-bottom: 2rem;">
573
+ <button class="btn" onclick="document.getElementById('modal_top').showModal()">Top</button>
574
+ <button class="btn" onclick="document.getElementById('modal_middle').showModal()">Middle
575
+ (default)</button>
576
+ <button class="btn"
577
+ onclick="document.getElementById('modal_bottom').showModal()">Bottom</button>
578
+ </div>
579
+
580
+ <dialog id="modal_top" class="modal modal-top">
581
+ <div class="modal-box">
582
+ <h3 class="text-lg font-bold">Top Modal</h3>
583
+ <p class="py-4">This modal appears at the top.</p>
584
+ <div class="modal-action">
585
+ <form method="dialog"><button class="btn">Close</button></form>
586
+ </div>
587
+ </div>
588
+ <form method="dialog" class="modal-backdrop"><button>close</button></form>
589
+ </dialog>
590
+
591
+ <dialog id="modal_middle" class="modal modal-middle">
592
+ <div class="modal-box">
593
+ <h3 class="text-lg font-bold">Middle Modal</h3>
594
+ <p class="py-4">This modal appears in the middle (default).</p>
595
+ <div class="modal-action">
596
+ <form method="dialog"><button class="btn">Close</button></form>
597
+ </div>
598
+ </div>
599
+ <form method="dialog" class="modal-backdrop"><button>close</button></form>
600
+ </dialog>
601
+
602
+ <dialog id="modal_bottom" class="modal modal-bottom">
603
+ <div class="modal-box">
604
+ <h3 class="text-lg font-bold">Bottom Modal</h3>
605
+ <p class="py-4">This modal appears at the bottom.</p>
606
+ <div class="modal-action">
607
+ <form method="dialog"><button class="btn">Close</button></form>
608
+ </div>
609
+ </div>
610
+ <form method="dialog" class="modal-backdrop"><button>close</button></form>
611
+ </dialog>
612
+
613
+ <!-- Responsive -->
614
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">Responsive Modal</h2>
615
+ <p style="opacity: 0.7; margin-bottom: 1rem;">Full-screen on mobile, centered on desktop.</p>
616
+ <button class="btn btn-primary" style="margin-bottom: 2rem;"
617
+ onclick="document.getElementById('modal_responsive').showModal()">
618
+ Open Responsive Modal
619
+ </button>
620
+
621
+ <dialog id="modal_responsive" class="modal modal-bottom sm:modal-middle">
622
+ <div class="modal-box">
623
+ <h3 class="text-lg font-bold">Responsive Modal</h3>
624
+ <p class="py-4">This modal is full-width at the bottom on mobile, and centered on larger
625
+ screens.</p>
626
+ <div class="modal-action">
627
+ <form method="dialog">
628
+ <button class="btn">Close</button>
629
+ </form>
630
+ </div>
631
+ </div>
632
+ <form method="dialog" class="modal-backdrop">
633
+ <button>close</button>
634
+ </form>
635
+ </dialog>
636
+
637
+
638
+ </div>
639
+ </div>