lightview 1.8.2 → 2.0.1

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 (262) hide show
  1. package/.codacy/cli.sh +149 -0
  2. package/.codacy/codacy.yaml +15 -0
  3. package/.github/instructions/codacy.instructions.md +72 -0
  4. package/.wranglerignore +21 -0
  5. package/README.md +1330 -19
  6. package/_headers +4 -0
  7. package/build.js +70 -0
  8. package/components/actions/button.js +151 -0
  9. package/components/actions/dropdown.js +120 -0
  10. package/components/actions/modal.js +146 -0
  11. package/components/actions/swap.js +118 -0
  12. package/components/daisyui.js +288 -0
  13. package/components/data-display/accordion.js +128 -0
  14. package/components/data-display/alert.js +112 -0
  15. package/components/data-display/avatar.js +170 -0
  16. package/components/data-display/badge.js +82 -0
  17. package/components/data-display/card.js +151 -0
  18. package/components/data-display/carousel.js +94 -0
  19. package/components/data-display/chart.js +220 -0
  20. package/components/data-display/chat.js +128 -0
  21. package/components/data-display/collapse.js +103 -0
  22. package/components/data-display/countdown.js +69 -0
  23. package/components/data-display/diff.js +111 -0
  24. package/components/data-display/kbd.js +65 -0
  25. package/components/data-display/loading.js +75 -0
  26. package/components/data-display/progress.js +79 -0
  27. package/components/data-display/radial-progress.js +88 -0
  28. package/components/data-display/skeleton.js +66 -0
  29. package/components/data-display/stats.js +159 -0
  30. package/components/data-display/table.js +146 -0
  31. package/components/data-display/timeline.js +146 -0
  32. package/components/data-display/toast.js +72 -0
  33. package/components/data-display/tooltip.js +74 -0
  34. package/components/data-input/checkbox.js +253 -0
  35. package/components/data-input/file-input.js +224 -0
  36. package/components/data-input/input.js +264 -0
  37. package/components/data-input/radio.js +338 -0
  38. package/components/data-input/range.js +204 -0
  39. package/components/data-input/rating.js +219 -0
  40. package/components/data-input/select.js +287 -0
  41. package/components/data-input/textarea.js +287 -0
  42. package/components/data-input/toggle.js +201 -0
  43. package/components/index.js +137 -0
  44. package/components/layout/divider.js +72 -0
  45. package/components/layout/drawer.js +142 -0
  46. package/components/layout/footer.js +100 -0
  47. package/components/layout/hero.js +109 -0
  48. package/components/layout/indicator.js +90 -0
  49. package/components/layout/join.js +78 -0
  50. package/components/layout/navbar.js +110 -0
  51. package/components/navigation/breadcrumbs.js +91 -0
  52. package/components/navigation/dock.js +103 -0
  53. package/components/navigation/menu.js +126 -0
  54. package/components/navigation/pagination.js +105 -0
  55. package/components/navigation/steps.js +89 -0
  56. package/components/navigation/tabs.css +177 -0
  57. package/components/navigation/tabs.js +123 -0
  58. package/components/theme/theme-switch.css +65 -0
  59. package/components/theme/theme-switch.js +177 -0
  60. package/docs/about.html +164 -0
  61. package/docs/api/computed.html +184 -0
  62. package/docs/api/effects.html +173 -0
  63. package/docs/api/elements.html +180 -0
  64. package/docs/api/enhance.html +225 -0
  65. package/docs/api/hypermedia.html +165 -0
  66. package/docs/api/index.html +178 -0
  67. package/docs/api/nav.html +18 -0
  68. package/docs/api/signals.html +136 -0
  69. package/docs/api/state.html +217 -0
  70. package/docs/assets/images/logo-favicon.svg +42 -0
  71. package/docs/assets/images/logo-static.svg +40 -0
  72. package/docs/assets/images/logo.svg +66 -0
  73. package/docs/assets/js/examplify.js +395 -0
  74. package/docs/assets/styles/site.css +1102 -0
  75. package/docs/assets/styles/themes.css +236 -0
  76. package/docs/components/accordion.html +439 -0
  77. package/docs/components/alert.html +528 -0
  78. package/docs/components/avatar.html +586 -0
  79. package/docs/components/badge.html +531 -0
  80. package/docs/components/breadcrumbs.html +278 -0
  81. package/docs/components/button.html +579 -0
  82. package/docs/components/card.html +561 -0
  83. package/docs/components/carousel.html +286 -0
  84. package/docs/components/chart-area.html +702 -0
  85. package/docs/components/chart-bar.html +782 -0
  86. package/docs/components/chart-column.html +735 -0
  87. package/docs/components/chart-line.html +794 -0
  88. package/docs/components/chart-pie.html +823 -0
  89. package/docs/components/chart.html +610 -15
  90. package/docs/components/chat.html +547 -0
  91. package/docs/components/checkbox.html +641 -0
  92. package/docs/components/collapse.html +536 -0
  93. package/docs/components/component-nav.html +53 -0
  94. package/docs/components/countdown.html +470 -0
  95. package/docs/components/diff.html +245 -0
  96. package/docs/components/divider.html +240 -0
  97. package/docs/components/dock.html +277 -0
  98. package/docs/components/drawer.html +515 -0
  99. package/docs/components/dropdown.html +479 -0
  100. package/docs/components/file-input.html +591 -0
  101. package/docs/components/footer.html +301 -0
  102. package/docs/components/gallery.html +504 -0
  103. package/docs/components/hero.html +264 -0
  104. package/docs/components/index.css +840 -0
  105. package/docs/components/index.html +735 -0
  106. package/docs/components/indicator.html +342 -0
  107. package/docs/components/input.html +644 -0
  108. package/docs/components/join.html +285 -0
  109. package/docs/components/kbd.html +322 -0
  110. package/docs/components/loading.html +521 -0
  111. package/docs/components/menu.html +461 -0
  112. package/docs/components/modal.html +639 -0
  113. package/docs/components/navbar.html +321 -0
  114. package/docs/components/pagination.html +279 -0
  115. package/docs/components/progress.html +514 -0
  116. package/docs/components/radial-progress.html +434 -0
  117. package/docs/components/radio.html +655 -0
  118. package/docs/components/range.html +611 -0
  119. package/docs/components/rating.html +642 -0
  120. package/docs/components/select.html +696 -0
  121. package/docs/components/sidebar-setup.js +93 -0
  122. package/docs/components/skeleton.html +447 -0
  123. package/docs/components/spinner.html +68 -0
  124. package/docs/components/stats.html +486 -0
  125. package/docs/components/steps.html +356 -0
  126. package/docs/components/swap.html +517 -0
  127. package/docs/components/switch.html +68 -0
  128. package/docs/components/table.html +668 -0
  129. package/docs/components/tabs.html +506 -0
  130. package/docs/components/text-input.html +68 -0
  131. package/docs/components/textarea.html +603 -0
  132. package/docs/components/timeline.html +485 -42
  133. package/docs/components/toast.html +474 -0
  134. package/docs/components/toggle.html +564 -0
  135. package/docs/components/tooltip.html +423 -0
  136. package/docs/examples/getting-started-example.html +40 -0
  137. package/docs/examples/index.html +93 -0
  138. package/docs/getting-started/index.html +739 -0
  139. package/docs/getting-started/reviews.html +23 -0
  140. package/docs/getting-started/reviews.odom +108 -0
  141. package/docs/getting-started/reviews.vdom +84 -0
  142. package/docs/index.html +132 -42
  143. package/docs/playground.html +416 -0
  144. package/docs/router.html +285 -0
  145. package/docs/styles/index.html +190 -0
  146. package/functions/_middleware.js +32 -0
  147. package/index.html +309 -0
  148. package/lightview-router.js +364 -0
  149. package/lightview-x.js +1577 -0
  150. package/lightview.js +659 -1200
  151. package/middleware/locale.js +25 -0
  152. package/middleware/markdown.js +44 -0
  153. package/middleware/notFound.js +37 -0
  154. package/package.json +27 -41
  155. package/watch.js +92 -0
  156. package/wrangler.toml +12 -0
  157. package/.idea/lightview.iml +0 -12
  158. package/.idea/modules.xml +0 -8
  159. package/.idea/vcs.xml +0 -6
  160. package/LICENSE +0 -21
  161. package/codepen-no-tabs-embed.css +0 -2
  162. package/docs/CNAME +0 -1
  163. package/docs/api.html +0 -674
  164. package/docs/blank.html +0 -10
  165. package/docs/comparedto.html +0 -89
  166. package/docs/components/chart-repl.html +0 -69
  167. package/docs/components/components.js +0 -113
  168. package/docs/components/contents.html +0 -17
  169. package/docs/components/gantt-repl.html +0 -61
  170. package/docs/components/gantt.html +0 -42
  171. package/docs/components/gauge-repl.html +0 -66
  172. package/docs/components/gauge.html +0 -20
  173. package/docs/components/orgchart-repl.html +0 -64
  174. package/docs/components/orgchart.html +0 -41
  175. package/docs/components/repl-as-src.html +0 -17
  176. package/docs/components/repl-repl.html +0 -95
  177. package/docs/components/repl.html +0 -527
  178. package/docs/components/timeline-repl.html +0 -72
  179. package/docs/components.html +0 -14
  180. package/docs/css/highlightjs.min.css +0 -9
  181. package/docs/css/tutorial.css +0 -35
  182. package/docs/examples/anchor.html +0 -11
  183. package/docs/examples/chart.html +0 -34
  184. package/docs/examples/counter.html +0 -26
  185. package/docs/examples/counter.test.mjs +0 -47
  186. package/docs/examples/counter2.html +0 -26
  187. package/docs/examples/directives.html +0 -79
  188. package/docs/examples/foreign.html +0 -50
  189. package/docs/examples/forgeinform.html +0 -98
  190. package/docs/examples/form.html +0 -61
  191. package/docs/examples/gauge.html +0 -18
  192. package/docs/examples/invalid-template-literals.html +0 -44
  193. package/docs/examples/medium/remote.html +0 -60
  194. package/docs/examples/message.html +0 -18
  195. package/docs/examples/nested.html +0 -11
  196. package/docs/examples/object-bound-form.html +0 -34
  197. package/docs/examples/remote-server.js +0 -51
  198. package/docs/examples/remote.html +0 -34
  199. package/docs/examples/remote.json +0 -1
  200. package/docs/examples/scratch.html +0 -69
  201. package/docs/examples/sensors/index.html +0 -44
  202. package/docs/examples/sensors/sensor-server.js +0 -30
  203. package/docs/examples/shared.html +0 -41
  204. package/docs/examples/template.html +0 -33
  205. package/docs/examples/timeline.html +0 -21
  206. package/docs/examples/todo.html +0 -40
  207. package/docs/examples/top.html +0 -10
  208. package/docs/examples/types.html +0 -94
  209. package/docs/examples/xor.html +0 -62
  210. package/docs/examples.html +0 -25
  211. package/docs/javascript/codejar.min.js +0 -8
  212. package/docs/javascript/highlightjs.min.js +0 -1173
  213. package/docs/javascript/isomorphic-git.js +0 -9
  214. package/docs/javascript/json5.min.js +0 -1
  215. package/docs/javascript/lightning-fs.js +0 -1
  216. package/docs/javascript/lightview.js +0 -1285
  217. package/docs/javascript/marked.min.js +0 -6
  218. package/docs/javascript/peerjs.min.js +0 -70
  219. package/docs/javascript/turndown.js +0 -973
  220. package/docs/javascript/types.js +0 -606
  221. package/docs/javascript/utils.js +0 -45
  222. package/docs/lightview.html +0 -63
  223. package/docs/old_index.html +0 -965
  224. package/docs/old_index.md +0 -1132
  225. package/docs/slidein.html +0 -51
  226. package/docs/tutorial/0-getting-started.html +0 -67
  227. package/docs/tutorial/1-intro-to-variables.html +0 -103
  228. package/docs/tutorial/10-template-components.html +0 -80
  229. package/docs/tutorial/11-linked-components.html +0 -76
  230. package/docs/tutorial/12-imported-components.html +0 -67
  231. package/docs/tutorial/13-input-binding.html +0 -94
  232. package/docs/tutorial/14-automatic-variable-creation.html +0 -74
  233. package/docs/tutorial/15-form-binding.html +0 -110
  234. package/docs/tutorial/16-if-directive.html +0 -60
  235. package/docs/tutorial/17-loop-directives.html +0 -83
  236. package/docs/tutorial/18-sanitizing-and-escaping-input.html +0 -79
  237. package/docs/tutorial/2-imported-and-exported-variables.html +0 -80
  238. package/docs/tutorial/3-data-types.html +0 -89
  239. package/docs/tutorial/4-extended-data-types.html +0 -83
  240. package/docs/tutorial/5-extended-functional-types.html +0 -96
  241. package/docs/tutorial/5.1-extended-functional-types.html +0 -79
  242. package/docs/tutorial/5.2-extended-functional-types.html +0 -70
  243. package/docs/tutorial/6-conventional-javascript.html +0 -75
  244. package/docs/tutorial/7-monitoring-with-observers.html +0 -107
  245. package/docs/tutorial/8-event-listeners.html +0 -65
  246. package/docs/tutorial/9-intro-to-components.html +0 -91
  247. package/docs/tutorial/contents.html +0 -32
  248. package/docs/tutorial/my-component.html +0 -29
  249. package/docs/tutorial/remote-value.json +0 -4
  250. package/docs/websiterepl.html +0 -46
  251. package/jest-puppeteer.config.js +0 -5
  252. package/jest.config.json +0 -12
  253. package/lightview.min.js +0 -1
  254. package/lightview_good.js +0 -1267
  255. package/lightview_optimized.js +0 -1274
  256. package/repl_hold.html +0 -320
  257. package/test/basic.html +0 -104
  258. package/test/basic.test.mjs +0 -315
  259. package/test/extended.html +0 -29
  260. package/test/extended.test.mjs +0 -448
  261. package/types.js +0 -607
  262. package/unsplash.key +0 -1
@@ -0,0 +1,591 @@
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: 'File Input' }
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">File Input</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
+ File Input allows users to select and upload files.
61
+ Supports labels, validation, helper text, and multiple file selection.
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 Examples</h2>
68
+ <p class="text-sm" style="opacity: 0.7; margin-bottom: 1rem;">File inputs with various
69
+ configurations
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
+ type: 'module',
106
+ minHeight: 350,
107
+ autoRun: true
108
+ });
109
+ </script><code contenteditable="true">const { default: FileInput } = await import('/components/data-input/file-input.js');
110
+ const { tags, $ } = Lightview;
111
+ const { div } = tags;
112
+
113
+ // 1. Basic file input
114
+ const basic = FileInput({});
115
+
116
+ // 2. With label and helper
117
+ const withLabel = FileInput({
118
+ label: 'Upload Document',
119
+ helper: 'PDF, DOC, or DOCX files only',
120
+ accept: '.pdf,.doc,.docx'
121
+ });
122
+
123
+ // 3. Multiple files with color
124
+ const multiple = FileInput({
125
+ label: 'Upload Images',
126
+ accept: 'image/*',
127
+ multiple: true,
128
+ color: 'primary',
129
+ helper: 'You can select multiple images'
130
+ });
131
+
132
+ // 4. Required file input
133
+ const required = FileInput({
134
+ label: 'Resume',
135
+ required: true,
136
+ accept: '.pdf'
137
+ });
138
+
139
+ // Insert all examples
140
+ $('#example').content(
141
+ div({ style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem' }, basic, withLabel, multiple, required)
142
+ );</code></pre>
143
+ </div>
144
+
145
+ <!-- vDOM Syntax -->
146
+ <div id="syntax-vdom" style="display: none;">
147
+ <pre><script>
148
+ examplify(document.currentScript.nextElementSibling, {
149
+ at: document.currentScript.parentElement,
150
+ scripts: ['/lightview.js', '/lightview-x.js'],
151
+ type: 'module',
152
+ minHeight: 350
153
+ });
154
+ </script><code contenteditable="true">const { default: FileInput } = await import('/components/data-input/file-input.js');
155
+ const { $ } = Lightview;
156
+
157
+ const demo = {
158
+ tag: 'div',
159
+ attributes: { style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem' },
160
+ children: [
161
+ { tag: FileInput },
162
+ {
163
+ tag: FileInput,
164
+ attributes: { label: 'Upload Document', helper: 'PDF, DOC, or DOCX files only', accept: '.pdf,.doc,.docx' }
165
+ },
166
+ {
167
+ tag: FileInput,
168
+ attributes: { label: 'Upload Images', accept: 'image/*', multiple: true, color: 'primary', helper: 'You can select multiple images' }
169
+ },
170
+ {
171
+ tag: FileInput,
172
+ attributes: { label: 'Resume', required: true, accept: '.pdf' }
173
+ }
174
+ ]
175
+ };
176
+
177
+ $('#example').content(demo);</code></pre>
178
+ </div>
179
+
180
+ <!-- Object DOM Syntax -->
181
+ <div id="syntax-object" style="display: none;">
182
+ <pre><script>
183
+ examplify(document.currentScript.nextElementSibling, {
184
+ at: document.currentScript.parentElement,
185
+ scripts: ['/lightview.js', '/lightview-x.js'],
186
+ type: 'module',
187
+ minHeight: 350
188
+ });
189
+ </script><code contenteditable="true">const { default: FileInput } = await import('/components/data-input/file-input.js');
190
+ const { tags, $ } = Lightview;
191
+ tags.FileInput = FileInput;
192
+
193
+ const demo = {
194
+ div: {
195
+ style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem',
196
+ children: [
197
+ { FileInput: {} },
198
+ { FileInput: { label: 'Upload Document', helper: 'PDF, DOC, or DOCX files only', accept: '.pdf,.doc,.docx' } },
199
+ { FileInput: { label: 'Upload Images', accept: 'image/*', multiple: true, color: 'primary', helper: 'You can select multiple images' } },
200
+ { FileInput: { label: 'Resume', required: true, accept: '.pdf' } }
201
+ ]
202
+ }
203
+ };
204
+
205
+ $('#example').content(demo);</code></pre>
206
+ </div>
207
+ </div>
208
+ </div>
209
+
210
+ <!-- Reactive Example with Examplify -->
211
+ <div class="card bg-base-200" style="margin-bottom: 2rem;">
212
+ <div class="card-body">
213
+ <h2 class="card-title">Reactive Example</h2>
214
+ <p class="text-sm" style="opacity: 0.7; margin-bottom: 1rem;">File validation and state
215
+ display</p>
216
+
217
+ <!-- Tabs -->
218
+ <script>
219
+ window.switchReactiveSyntaxTab = (tabId) => {
220
+ const tabs = ['tagged', 'vdom', 'object'];
221
+ tabs.forEach(t => {
222
+ const tabEl = document.getElementById(`reactive-tab-btn-${t}`);
223
+ const contentEl = document.getElementById(`reactive-syntax-${t}`);
224
+ if (t === tabId) {
225
+ tabEl.classList.add('syntax-tab-active');
226
+ contentEl.style.display = 'block';
227
+ } else {
228
+ tabEl.classList.remove('syntax-tab-active');
229
+ contentEl.style.display = 'none';
230
+ }
231
+ });
232
+ };
233
+ </script>
234
+ <div role="tablist" class="syntax-tabs" style="margin-bottom: 1rem;">
235
+ <button id="reactive-tab-btn-tagged" role="tab" class="syntax-tab syntax-tab-active"
236
+ onclick="switchReactiveSyntaxTab('tagged')">Tagged</button>
237
+ <button id="reactive-tab-btn-vdom" role="tab" class="syntax-tab"
238
+ onclick="switchReactiveSyntaxTab('vdom')">vDOM</button>
239
+ <button id="reactive-tab-btn-object" role="tab" class="syntax-tab"
240
+ onclick="switchReactiveSyntaxTab('object')">Object DOM</button>
241
+ </div>
242
+
243
+ <!-- Tagged Syntax -->
244
+ <div id="reactive-syntax-tagged">
245
+ <pre><script>
246
+ examplify(document.currentScript.nextElementSibling, {
247
+ at: document.currentScript.parentElement,
248
+ scripts: ['/lightview.js', '/lightview-x.js'],
249
+ type: 'module',
250
+ minHeight: 280
251
+ });
252
+ </script><code contenteditable="true">const { default: FileInput } = await import('/components/data-input/file-input.js');
253
+ const { signal, tags, $ } = Lightview;
254
+ const { div, p, span, ul, li } = tags;
255
+
256
+ const selectedFiles = signal([]);
257
+
258
+ const validateFile = (files) => {
259
+ if (!files || files.length === 0) return 'Please select a file';
260
+ for (const file of files) {
261
+ if (file.size > 5 * 1024 * 1024) {
262
+ return `File "${file.name}" exceeds 5MB limit`;
263
+ }
264
+ }
265
+ return null;
266
+ };
267
+
268
+ const reactiveDemo = div({ style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem' },
269
+ FileInput({
270
+ label: 'Upload Files',
271
+ helper: 'Max 5MB per file',
272
+ multiple: true,
273
+ validate: validateFile,
274
+ onChange: (files) => {
275
+ selectedFiles.value = Array.from(files);
276
+ }
277
+ }),
278
+ div({ class: 'divider' }),
279
+ () => {
280
+ const files = selectedFiles.value;
281
+ if (files.length === 0) {
282
+ return p({ class: 'text-sm opacity-50' }, 'No files selected');
283
+ }
284
+ return div({},
285
+ p({ class: 'text-sm font-semibold mb-2' },
286
+ `${files.length} file(s) selected:`
287
+ ),
288
+ ul({ class: 'text-xs font-mono', style: 'display: flex; flex-direction: column; gap: 0.25rem' },
289
+ ...files.map(f =>
290
+ li({},
291
+ span({ class: 'text-primary' }, f.name),
292
+ span({ class: 'opacity-50' }, ` (${(f.size / 1024).toFixed(1)} KB)`)
293
+ )
294
+ )
295
+ )
296
+ );
297
+ }
298
+ );
299
+
300
+ $('#example').content(reactiveDemo);</code></pre>
301
+ </div>
302
+
303
+ <!-- vDOM Syntax -->
304
+ <div id="reactive-syntax-vdom" style="display: none;">
305
+ <pre><script>
306
+ examplify(document.currentScript.nextElementSibling, {
307
+ at: document.currentScript.parentElement,
308
+ scripts: ['/lightview.js', '/lightview-x.js'],
309
+ type: 'module',
310
+ minHeight: 280
311
+ });
312
+ </script><code contenteditable="true">const { default: FileInput } = await import('/components/data-input/file-input.js');
313
+ const { signal, $ } = Lightview;
314
+
315
+ const selectedFiles = signal([]);
316
+
317
+ const validateFile = (files) => {
318
+ if (!files || files.length === 0) return 'Please select a file';
319
+ for (const file of files) {
320
+ if (file.size > 5 * 1024 * 1024) {
321
+ return `File "${file.name}" exceeds 5MB limit`;
322
+ }
323
+ }
324
+ return null;
325
+ };
326
+
327
+ const reactiveDemo = {
328
+ tag: 'div',
329
+ attributes: { style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem' },
330
+ children: [
331
+ {
332
+ tag: FileInput,
333
+ attributes: {
334
+ label: 'Upload Files',
335
+ helper: 'Max 5MB per file',
336
+ multiple: true,
337
+ validate: validateFile,
338
+ onChange: (files) => { selectedFiles.value = Array.from(files); }
339
+ }
340
+ },
341
+ { tag: 'div', attributes: { class: 'divider' } },
342
+ () => {
343
+ const files = selectedFiles.value;
344
+ if (files.length === 0) {
345
+ return { tag: 'p', attributes: { class: 'text-sm opacity-50' }, children: ['No files selected'] };
346
+ }
347
+ return {
348
+ tag: 'div',
349
+ children: [
350
+ {
351
+ tag: 'p',
352
+ attributes: { class: 'text-sm font-semibold mb-2' },
353
+ children: [`${files.length} file(s) selected:`]
354
+ },
355
+ {
356
+ tag: 'ul',
357
+ attributes: { class: 'text-xs font-mono', style: 'display: flex; flex-direction: column; gap: 0.25rem' },
358
+ children: files.map(f => ({
359
+ tag: 'li',
360
+ children: [
361
+ { tag: 'span', attributes: { class: 'text-primary' }, children: [f.name] },
362
+ { tag: 'span', attributes: { class: 'opacity-50' }, children: [` (${(f.size / 1024).toFixed(1)} KB)`] }
363
+ ]
364
+ }))
365
+ }
366
+ ]
367
+ };
368
+ }
369
+ ]
370
+ };
371
+
372
+ $('#example').content(reactiveDemo);</code></pre>
373
+ </div>
374
+
375
+ <!-- Object DOM Syntax -->
376
+ <div id="reactive-syntax-object" style="display: none;">
377
+ <pre><script>
378
+ examplify(document.currentScript.nextElementSibling, {
379
+ at: document.currentScript.parentElement,
380
+ scripts: ['/lightview.js', '/lightview-x.js'],
381
+ type: 'module',
382
+ minHeight: 280
383
+ });
384
+ </script><code contenteditable="true">const { default: FileInput } = await import('/components/data-input/file-input.js');
385
+ const { signal, tags, $ } = Lightview;
386
+ tags.FileInput = FileInput;
387
+
388
+ const selectedFiles = signal([]);
389
+
390
+ const validateFile = (files) => {
391
+ if (!files || files.length === 0) return 'Please select a file';
392
+ for (const file of files) {
393
+ if (file.size > 5 * 1024 * 1024) {
394
+ return `File "${file.name}" exceeds 5MB limit`;
395
+ }
396
+ }
397
+ return null;
398
+ };
399
+
400
+ const reactiveDemo = {
401
+ div: {
402
+ style: 'display: flex; flex-direction: column; gap: 1rem; max-width: 28rem',
403
+ children: [
404
+ {
405
+ FileInput: {
406
+ label: 'Upload Files',
407
+ helper: 'Max 5MB per file',
408
+ multiple: true,
409
+ validate: validateFile,
410
+ onChange: (files) => { selectedFiles.value = Array.from(files); }
411
+ }
412
+ },
413
+ { div: { class: 'divider' } },
414
+ () => {
415
+ const files = selectedFiles.value;
416
+ if (files.length === 0) {
417
+ return { p: { class: 'text-sm opacity-50', text: 'No files selected' } };
418
+ }
419
+ return {
420
+ div: {
421
+ children: [
422
+ { p: { class: 'text-sm font-semibold mb-2', text: `${files.length} file(s) selected:` } },
423
+ {
424
+ ul: {
425
+ class: 'text-xs font-mono', style: 'display: flex; flex-direction: column; gap: 0.25rem',
426
+ children: files.map(f => ({
427
+ li: {
428
+ children: [
429
+ { span: { class: 'text-primary', text: f.name } },
430
+ { span: { class: 'opacity-50', text: ` (${(f.size / 1024).toFixed(1)} KB)` } }
431
+ ]
432
+ }
433
+ }))
434
+ }
435
+ }
436
+ ]
437
+ }
438
+ };
439
+ }
440
+ ]
441
+ }
442
+ };
443
+
444
+ $('#example').content(reactiveDemo);</code></pre>
445
+ </div>
446
+ </div>
447
+ </div>
448
+
449
+ <!-- Props Table -->
450
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">Props</h2>
451
+ <div style="overflow-x: auto; margin-bottom: 2rem;">
452
+ <table class="table table-zebra">
453
+ <thead>
454
+ <tr>
455
+ <th>Prop</th>
456
+ <th>Type</th>
457
+ <th>Default</th>
458
+ <th>Description</th>
459
+ </tr>
460
+ </thead>
461
+ <tbody>
462
+ <tr>
463
+ <td><code>accept</code></td>
464
+ <td>string</td>
465
+ <td>-</td>
466
+ <td>Accepted file types (e.g., '.pdf,.doc', 'image/*')</td>
467
+ </tr>
468
+ <tr>
469
+ <td><code>multiple</code></td>
470
+ <td>boolean</td>
471
+ <td>false</td>
472
+ <td>Allow multiple file selection</td>
473
+ </tr>
474
+ <tr>
475
+ <td><code>label</code></td>
476
+ <td>string</td>
477
+ <td>-</td>
478
+ <td>Label text displayed above the input</td>
479
+ </tr>
480
+ <tr>
481
+ <td><code>helper</code></td>
482
+ <td>string</td>
483
+ <td>-</td>
484
+ <td>Helper text displayed below the input</td>
485
+ </tr>
486
+ <tr>
487
+ <td><code>error</code></td>
488
+ <td>string | function</td>
489
+ <td>-</td>
490
+ <td>Error message or reactive error function</td>
491
+ </tr>
492
+ <tr>
493
+ <td><code>validate</code></td>
494
+ <td>function</td>
495
+ <td>-</td>
496
+ <td>Validation function: <code>(files) => errorMessage | null</code></td>
497
+ </tr>
498
+ <tr>
499
+ <td><code>color</code></td>
500
+ <td>string</td>
501
+ <td>-</td>
502
+ <td>'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error'
503
+ </td>
504
+ </tr>
505
+ <tr>
506
+ <td><code>size</code></td>
507
+ <td>string</td>
508
+ <td>'md'</td>
509
+ <td>'xs' | 'sm' | 'md' | 'lg'</td>
510
+ </tr>
511
+ <tr>
512
+ <td><code>ghost</code></td>
513
+ <td>boolean</td>
514
+ <td>false</td>
515
+ <td>Ghost style (no background)</td>
516
+ </tr>
517
+ <tr>
518
+ <td><code>disabled</code></td>
519
+ <td>boolean</td>
520
+ <td>false</td>
521
+ <td>Disable the file input</td>
522
+ </tr>
523
+ <tr>
524
+ <td><code>required</code></td>
525
+ <td>boolean</td>
526
+ <td>false</td>
527
+ <td>Mark as required field (shows asterisk)</td>
528
+ </tr>
529
+ <tr>
530
+ <td><code>onChange</code></td>
531
+ <td>function</td>
532
+ <td>-</td>
533
+ <td>Callback when files selected: <code>(files, event) => void</code></td>
534
+ </tr>
535
+ <tr>
536
+ <td><code>useShadow</code></td>
537
+ <td>boolean</td>
538
+ <td>*</td>
539
+ <td>Render in Shadow DOM. *Follows global <code>initComponents()</code> setting</td>
540
+ </tr>
541
+ </tbody>
542
+ </table>
543
+ </div>
544
+
545
+ <!-- Colors -->
546
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">Colors</h2>
547
+ <div class="example-grid-responsive" style="margin-bottom: 2rem;">
548
+ <input type="file" class="file-input file-input-primary w-full max-w-xs" />
549
+ <input type="file" class="file-input file-input-secondary w-full max-w-xs" />
550
+ <input type="file" class="file-input file-input-accent w-full max-w-xs" />
551
+ <input type="file" class="file-input file-input-info w-full max-w-xs" />
552
+ <input type="file" class="file-input file-input-success w-full max-w-xs" />
553
+ <input type="file" class="file-input file-input-warning w-full max-w-xs" />
554
+ <input type="file" class="file-input file-input-error w-full max-w-xs" />
555
+ </div>
556
+
557
+ <!-- Sizes -->
558
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">Sizes</h2>
559
+ <div class="example-stack" style="margin-bottom: 2rem;">
560
+ <input type="file" class="file-input file-input-xs w-full max-w-xs" />
561
+ <input type="file" class="file-input file-input-sm w-full max-w-xs" />
562
+ <input type="file" class="file-input file-input-md w-full max-w-xs" />
563
+ <input type="file" class="file-input file-input-lg w-full max-w-xs" />
564
+ </div>
565
+
566
+ <!-- Variants -->
567
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">Variants</h2>
568
+ <div class="example-stack" style="margin-bottom: 2rem;">
569
+ <div>
570
+ <p class="text-sm" style="opacity: 0.7; margin-bottom: 0.25rem;">Ghost</p>
571
+ <input type="file" class="file-input file-input-ghost w-full max-w-xs" />
572
+ </div>
573
+ <div>
574
+ <p class="text-sm" style="opacity: 0.7; margin-bottom: 0.25rem;">Disabled</p>
575
+ <input type="file" class="file-input w-full max-w-xs" disabled />
576
+ </div>
577
+ </div>
578
+
579
+ <!-- With Fieldset -->
580
+ <h2 class="text-xl font-bold" style="margin-bottom: 1rem;">With Label (Fieldset Pattern)</h2>
581
+ <div style="max-width: 28rem; margin-bottom: 2rem;">
582
+ <fieldset class="fieldset">
583
+ <legend class="fieldset-legend">Upload Avatar</legend>
584
+ <input type="file" class="file-input w-full" accept="image/*" />
585
+ <p class="label">JPG, PNG, or GIF up to 2MB</p>
586
+ </fieldset>
587
+ </div>
588
+ </div>
589
+ </div>
590
+ </div>
591
+ </div>