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.
- 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 +1331 -21
- 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 +612 -0
- 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 +487 -0
- 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 +134 -0
- 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 +658 -1109
- 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/components/chart/chart.html +0 -17
- package/components/chart/example.html +0 -32
- package/components/chart.html +0 -83
- package/components/components.js +0 -113
- package/components/gantt/example.html +0 -22
- package/components/gantt/gantt.html +0 -42
- package/components/gauge/example.html +0 -28
- package/components/gauge/gauge.html +0 -20
- package/components/gauge.html +0 -60
- package/components/orgchart/example.html +0 -25
- package/components/orgchart/orgchart.html +0 -41
- package/components/repl/code-editor.html +0 -64
- package/components/repl/editor.html +0 -37
- package/components/repl/editorjs-inline-tool/index.js +0 -3
- package/components/repl/editorjs-inline-tool/inline-tools.js +0 -28
- package/components/repl/editorjs-inline-tool/tool.js +0 -175
- package/components/repl/repl-with-wysiwyg.html +0 -355
- package/components/repl/repl.html +0 -345
- package/components/repl/sup.js +0 -44
- package/components/repl/wysiwyg-repl.html +0 -258
- package/components/timeline/example.html +0 -33
- package/components/timeline/timeline.html +0 -44
- package/components/timeline.html +0 -81
- package/examples/anchor.html +0 -11
- package/examples/chart.html +0 -34
- package/examples/counter.html +0 -26
- package/examples/counter.test.mjs +0 -47
- package/examples/counter2.html +0 -26
- package/examples/directives.html +0 -79
- package/examples/foreign.html +0 -50
- package/examples/forgeinform.html +0 -98
- package/examples/form.html +0 -61
- package/examples/gauge.html +0 -18
- package/examples/invalid-template-literals.html +0 -44
- package/examples/medium/remote.html +0 -60
- package/examples/message.html +0 -18
- package/examples/nested.html +0 -11
- package/examples/object-bound-form.html +0 -34
- package/examples/remote-server.js +0 -51
- package/examples/remote.html +0 -34
- package/examples/remote.json +0 -1
- package/examples/scratch.html +0 -69
- package/examples/sensors/index.html +0 -30
- package/examples/sensors/sensor-server.js +0 -30
- package/examples/shared.html +0 -41
- package/examples/template.html +0 -33
- package/examples/timeline.html +0 -21
- package/examples/todo.html +0 -38
- package/examples/top.html +0 -10
- package/examples/types.html +0 -94
- package/examples/xor.html +0 -62
- package/jest-puppeteer.config.js +0 -5
- package/jest.config.json +0 -12
- package/sites/client.html +0 -48
- package/sites/index.html +0 -247
- package/test/basic.html +0 -93
- package/test/basic.test.mjs +0 -315
- package/test/extended.html +0 -29
- package/test/extended.test.mjs +0 -448
- package/types.js +0 -534
- 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>
|