json-renderers 1.13.7 → 1.16.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.
package/docs/index.html CHANGED
@@ -1,680 +1,935 @@
1
- <!DOCTYPE html>
2
- <html lang="en" class="dark">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>json-renderers | Browser DOM Component Renderer</title>
8
- <meta name="description" content="Browser DOM component renderer built on top of json-renderers-build and @keshavsoft/json-to-tag.">
9
- <link rel="preconnect" href="https://fonts.googleapis.com">
10
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
- <link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600&family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
12
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
13
- <script src="https://cdn.tailwindcss.com"></script>
14
- <script>
15
- tailwind.config = {
16
- darkMode: 'class',
17
- theme: {
18
- extend: {
19
- colors: {
20
- brand: {
21
- 50: '#eef2ff',
22
- 100: '#e0e7ff',
23
- 500: '#6366f1',
24
- 600: '#4f46e5',
25
- 700: '#4338ca',
26
- 800: '#3730a3',
27
- 900: '#312e81'
28
- }
29
- },
30
- fontFamily: {
31
- sans: ['Inter', 'sans-serif'],
32
- mono: ['Fira Code', 'monospace']
33
- }
34
- }
35
- }
36
- };
37
- </script>
38
- <style>
39
- pre, code {
40
- font-family: 'Fira Code', monospace;
41
- }
42
- .custom-scrollbar::-webkit-scrollbar {
43
- width: 6px;
44
- height: 6px;
45
- }
46
- .custom-scrollbar::-webkit-scrollbar-track {
47
- background: rgba(15, 23, 42, 0.6);
48
- }
49
- .custom-scrollbar::-webkit-scrollbar-thumb {
50
- background: rgba(99, 102, 241, 0.3);
51
- border-radius: 4px;
52
- }
53
- .custom-scrollbar::-webkit-scrollbar-thumb:hover {
54
- background: rgba(99, 102, 241, 0.6);
55
- }
56
- .glass-panel {
57
- background: rgba(15, 23, 42, 0.75);
58
- backdrop-filter: blur(12px);
59
- border: 1px solid rgba(255, 255, 255, 0.08);
60
- }
61
- .glass-card {
62
- background: rgba(30, 41, 59, 0.5);
63
- backdrop-filter: blur(8px);
64
- border: 1px solid rgba(255, 255, 255, 0.05);
65
- }
66
- </style>
67
- </head>
68
-
69
- <body class="bg-slate-950 text-slate-100 min-h-screen antialiased flex flex-col font-sans selection:bg-indigo-500 selection:text-white">
70
-
71
- <!-- Top Navbar -->
72
- <header class="border-b border-slate-800/80 bg-slate-900/80 backdrop-blur sticky top-0 z-50">
73
- <div class="max-w-7xl mx-auto px-4 sm:px-6 py-3.5 flex items-center justify-between gap-4">
74
- <div class="flex items-center gap-3">
75
- <div class="w-10 h-10 rounded-xl bg-gradient-to-br from-emerald-500 via-teal-600 to-indigo-600 flex items-center justify-center font-bold text-white shadow-lg text-lg shadow-emerald-500/20">
76
- 🖥️
77
- </div>
78
- <div>
79
- <div class="flex items-center gap-2">
80
- <h1 class="text-base font-bold text-white tracking-tight">json-renderers</h1>
81
- <span class="px-2 py-0.5 text-xs bg-emerald-500/20 text-emerald-300 rounded-full border border-emerald-500/30 font-mono">v13.1.0</span>
82
- </div>
83
- <p class="text-xs text-slate-400">Browser DOM Component Renderer Runtime</p>
84
- </div>
85
- </div>
86
-
87
- <div class="flex items-center gap-2.5">
88
- <a href="#workbench" class="px-3.5 py-1.5 text-xs font-semibold rounded-lg bg-emerald-600 hover:bg-emerald-500 text-white transition flex items-center gap-1.5 shadow-sm shadow-emerald-600/30">
89
- <span>⚡</span> Live DOM Workbench
90
- </a>
91
- <a href="#samples" class="px-3 py-1.5 text-xs font-semibold rounded-lg bg-slate-800 hover:bg-slate-700 text-slate-200 border border-slate-700 transition hidden sm:flex items-center gap-1">
92
- <span>📂</span> Samples
93
- </a>
94
- <a href="https://github.com/keshavsoft/json-renderers" target="_blank" rel="noopener noreferrer" class="px-3 py-1.5 text-xs font-semibold rounded-lg bg-slate-800 hover:bg-slate-700 text-slate-200 border border-slate-700 transition flex items-center gap-1.5">
95
- <svg class="w-4 h-4 fill-current" viewBox="0 0 24 24"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
96
- <span class="hidden md:inline">GitHub</span>
97
- </a>
98
- </div>
99
- </div>
100
- </header>
101
-
102
- <main class="flex-1 max-w-7xl w-full mx-auto p-4 sm:p-6 lg:p-8 space-y-12">
103
-
104
- <!-- Hero Section -->
105
- <section class="text-center py-6 sm:py-10 space-y-5">
106
- <div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-xs text-emerald-300 font-mono">
107
- <span class="w-2 h-2 rounded-full bg-emerald-400 animate-pulse"></span>
108
- Ecosystem Story: DOM Mounting Runtime
109
- </div>
110
- <h2 class="text-3xl sm:text-5xl font-extrabold text-white tracking-tight leading-tight">
111
- Render Business JSON into Live DOM <br class="hidden sm:inline" />
112
- <span class="text-transparent bg-clip-text bg-gradient-to-r from-emerald-400 via-teal-300 to-indigo-400">Powered by json-renderers-build</span>
113
- </h2>
114
- <p class="max-w-3xl mx-auto text-slate-400 text-sm sm:text-base leading-relaxed">
115
- <strong class="text-slate-200">json-renderers</strong> is the browser execution engine. It accepts your data, queries <strong class="text-indigo-300 font-mono">json-renderers-build</strong> for the compiled AST specification, instantiates real HTML elements using <strong class="text-emerald-300 font-mono">@keshavsoft/json-to-tag</strong>, and mounts them directly into your container.
116
- </p>
117
-
118
- <div class="flex flex-wrap items-center justify-center gap-3 pt-2">
119
- <a href="#workbench" class="px-5 py-2.5 rounded-xl bg-emerald-600 hover:bg-emerald-500 text-white font-semibold text-xs sm:text-sm transition flex items-center gap-2 shadow-lg shadow-emerald-600/25">
120
- <span>⚡</span> Try Live DOM Mounting
121
- </a>
122
- <a href="#in-between" class="px-5 py-2.5 rounded-xl bg-slate-900 hover:bg-slate-800 border border-slate-800 text-slate-200 font-semibold text-xs sm:text-sm transition flex items-center gap-2">
123
- <span>🔗</span> The "In-Between" Story
124
- </a>
125
- </div>
126
- </section>
127
-
128
- <!-- The In-Between & 3-Tier Pipeline Section -->
129
- <section id="in-between" class="space-y-6">
130
- <div class="flex flex-col md:flex-row md:items-end justify-between gap-4 border-b border-slate-800/80 pb-4">
131
- <div>
132
- <span class="text-xs uppercase font-mono tracking-wider text-emerald-400">Ecosystem Architecture</span>
133
- <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">The "In-Between" Handoff Story</h3>
134
- </div>
135
- <p class="text-xs text-slate-400 max-w-md">
136
- How <span class="text-indigo-300 font-mono">json-renderers-build</span> and <span class="text-emerald-300 font-mono">json-renderers</span> cooperate seamlessly.
137
- </p>
138
- </div>
139
-
140
- <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
141
- <!-- Step 1 -->
142
- <div class="glass-panel p-5 rounded-2xl relative">
143
- <div class="flex items-center justify-between mb-3">
144
- <span class="px-2 py-0.5 text-[11px] font-mono rounded bg-indigo-500/20 text-indigo-300 border border-indigo-500/30">Step 1 • Spec Request</span>
145
- <span class="text-lg">📦</span>
146
- </div>
147
- <h4 class="text-base font-bold text-white mb-2">json-renderers-build</h4>
148
- <p class="text-xs text-slate-400 leading-relaxed mb-4">
149
- <code class="text-emerald-300 font-mono">json-renderers</code> calls <code class="text-indigo-300 font-mono">jsonRenderBuild({ type, data, columns })</code>. The builder matches the skeleton blueprint (<code class="text-indigo-300 font-mono">table</code>, <code class="text-indigo-300 font-mono">select</code>) and evaluates it with <code class="text-indigo-300 font-mono">json-to-spec</code>.
150
- </p>
151
- <div class="p-2.5 rounded-lg bg-slate-950/80 border border-indigo-500/30 text-[11px] font-mono text-indigo-300">
152
- Returns: specAsJsonToDom (AST)
153
- </div>
154
- </div>
155
-
156
- <!-- Step 2 -->
157
- <div class="glass-panel p-5 rounded-2xl relative">
158
- <div class="flex items-center justify-between mb-3">
159
- <span class="px-2 py-0.5 text-[11px] font-mono rounded bg-purple-500/20 text-purple-300 border border-purple-500/30">Step 2 • Instantiation</span>
160
- <span class="text-lg">🏷️</span>
161
- </div>
162
- <h4 class="text-base font-bold text-white mb-2">@keshavsoft/json-to-tag</h4>
163
- <p class="text-xs text-slate-400 leading-relaxed mb-4">
164
- The generated specification AST is unwrapped (if fragment) and handed to <code class="text-purple-300 font-mono">jsonToTag(spec)</code>. Real browser DOM elements (<code class="text-purple-300 font-mono">HTMLTableElement</code>, <code class="text-purple-300 font-mono">DocumentFragment</code>) are constructed.
165
- </p>
166
- <div class="p-2.5 rounded-lg bg-slate-950/80 border border-purple-500/30 text-[11px] font-mono text-purple-300">
167
- Returns: content (DOM Node / List)
168
- </div>
169
- </div>
170
-
171
- <!-- Step 3 -->
172
- <div class="glass-panel p-5 rounded-2xl border-emerald-500/50 shadow-xl shadow-emerald-500/10 bg-slate-900/90 relative">
173
- <div class="absolute top-0 right-0 bg-emerald-600 text-white text-[10px] uppercase font-bold tracking-wider px-2.5 py-0.5 rounded-bl-lg">
174
- This Repo
175
- </div>
176
- <div class="flex items-center justify-between mb-3">
177
- <span class="px-2 py-0.5 text-[11px] font-mono rounded bg-emerald-500/20 text-emerald-300 border border-emerald-500/30">Step 3 • Container Mount</span>
178
- <span class="text-lg">🖥️</span>
179
- </div>
180
- <h4 class="text-base font-bold text-emerald-300 mb-2">json-renderers</h4>
181
- <p class="text-xs text-slate-300 leading-relaxed mb-4">
182
- Locates <code class="text-emerald-300 font-mono">document.getElementById(targetHtmlId)</code>. Clears or prepends content based on <code class="text-emerald-300 font-mono">appendPosition</code>, mounts the nodes, and returns the mounted container.
183
- </p>
184
- <div class="p-2.5 rounded-lg bg-slate-950/80 border border-emerald-500/30 text-[11px] font-mono text-emerald-200">
185
- container.append(content)
186
- </div>
187
- </div>
188
- </div>
189
- </section>
190
-
191
- <!-- Interactive Live DOM Workbench -->
192
- <section id="workbench" class="space-y-6">
193
- <div class="flex flex-col md:flex-row md:items-end justify-between gap-4 border-b border-slate-800/80 pb-4">
194
- <div>
195
- <span class="text-xs uppercase font-mono tracking-wider text-emerald-400">Live Demonstration</span>
196
- <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">Interactive DOM Mounting Workbench</h3>
197
- </div>
198
- <div class="flex items-center gap-3">
199
- <label for="component-type" class="text-xs text-slate-400 font-medium">Type:</label>
200
- <select id="component-type" class="bg-slate-900 border border-slate-700 text-xs rounded-lg px-3 py-1.5 text-white font-mono focus:ring-2 focus:ring-emerald-500 focus:outline-none">
201
- <option value="table" selected>table</option>
202
- <option value="select">select</option>
203
- <option value="selectOptionsOnly">selectOptionsOnly</option>
204
- </select>
205
- <button id="btn-render-dom" class="px-3.5 py-1.5 bg-emerald-600 hover:bg-emerald-500 text-white rounded-lg text-xs font-semibold shadow-sm transition flex items-center gap-1 shadow-emerald-600/30">
206
- <span>▶</span> Mount to DOM
207
- </button>
208
- </div>
209
- </div>
210
-
211
- <div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
212
-
213
- <!-- Left Column: Inputs (5 Cols) -->
214
- <div class="lg:col-span-5 space-y-4">
215
- <div class="glass-panel p-4 rounded-2xl space-y-3">
216
- <div class="flex items-center justify-between">
217
- <span class="text-xs font-bold text-white uppercase tracking-wider font-mono flex items-center gap-1.5">
218
- <span>📝</span> Input Data (JSON)
219
- </span>
220
- <div class="flex items-center gap-2">
221
- <select id="preset-selector" class="bg-slate-800 border border-slate-700 text-[11px] rounded px-2 py-1 text-slate-300 font-mono">
222
- <option value="batches">Preset: Batches</option>
223
- <option value="employees">Preset: Employees</option>
224
- <option value="ledgers">Preset: Ledgers</option>
225
- </select>
226
- <button id="btn-format-data" class="text-[11px] text-slate-400 hover:text-white px-2 py-0.5 rounded bg-slate-800">Format</button>
227
- </div>
228
- </div>
229
- <textarea id="input-data" rows="8" class="w-full bg-slate-950 text-emerald-200 border border-slate-800 rounded-xl p-3 font-mono text-xs focus:ring-2 focus:ring-emerald-500 focus:outline-none custom-scrollbar" spellcheck="false"></textarea>
230
- </div>
231
-
232
- <div id="columns-panel" class="glass-panel p-4 rounded-2xl space-y-3">
233
- <div class="flex items-center justify-between">
234
- <span class="text-xs font-bold text-white uppercase tracking-wider font-mono flex items-center gap-1.5">
235
- <span>📊</span> Columns (for table)
236
- </span>
237
- <button id="btn-format-columns" class="text-[11px] text-slate-400 hover:text-white px-2 py-0.5 rounded bg-slate-800">Format</button>
238
- </div>
239
- <textarea id="input-columns" rows="5" class="w-full bg-slate-950 text-emerald-200 border border-slate-800 rounded-xl p-3 font-mono text-xs focus:ring-2 focus:ring-emerald-500 focus:outline-none custom-scrollbar" spellcheck="false"></textarea>
240
- </div>
241
-
242
- <div class="p-3.5 rounded-xl bg-slate-900/60 border border-slate-800/80 text-xs text-slate-400 space-y-1">
243
- <div class="flex items-center gap-1.5 text-emerald-400 font-semibold font-mono">
244
- <span>🎯</span> Mounting Contract
245
- </div>
246
- <p>
247
- Calls <code class="text-emerald-300 font-mono">render({ type, targetHtmlId: "live-mount-container", data, columns })</code>. Ingests spec from <code class="text-indigo-300 font-mono">json-renderers-build</code> and instantiates into DOM.
248
- </p>
249
- </div>
250
- </div>
251
-
252
- <!-- Right Column: Outputs (7 Cols) -->
253
- <div class="lg:col-span-7 flex flex-col space-y-3">
254
- <!-- View Toggle -->
255
- <div class="flex items-center justify-between bg-slate-900/80 p-1.5 rounded-xl border border-slate-800">
256
- <div class="flex items-center gap-1">
257
- <button id="tab-dom" class="px-3 py-1.5 text-xs font-semibold rounded-lg bg-emerald-600 text-white transition flex items-center gap-1.5">
258
- <span>🖥️</span> Live Mounted DOM
259
- </button>
260
- <button id="tab-in-between" class="px-3 py-1.5 text-xs font-semibold rounded-lg text-slate-400 hover:text-white transition flex items-center gap-1.5">
261
- <span>🔗</span> "In-Between" Spec AST
262
- </button>
263
- </div>
264
-
265
- <div class="flex items-center gap-2 pr-1">
266
- <span id="mount-status-badge" class="px-2 py-0.5 text-[11px] bg-emerald-500/20 text-emerald-300 rounded font-mono border border-emerald-500/30">
267
- Mounted
268
- </span>
269
- </div>
270
- </div>
271
-
272
- <!-- View 1: Real DOM Container -->
273
- <div id="view-dom" class="glass-panel p-4 rounded-2xl flex-1 flex flex-col min-h-[460px]">
274
- <div class="flex items-center justify-between pb-2 border-b border-slate-800/80 mb-3 text-xs text-slate-400">
275
- <span class="font-mono text-emerald-400 flex items-center gap-1.5">
276
- <span class="w-2 h-2 rounded-full bg-emerald-400"></span> #live-mount-container
277
- </span>
278
- <span class="font-mono text-[11px]">Real HTML Elements</span>
279
- </div>
280
-
281
- <div id="live-mount-container" class="flex-1 p-3 bg-slate-900/60 rounded-xl border border-slate-800 overflow-auto custom-scrollbar">
282
- <!-- Elements mounted by json-renderers here -->
283
- </div>
284
- </div>
285
-
286
- <!-- View 2: "In-Between" Spec AST from json-renderers-build -->
287
- <div id="view-in-between" class="glass-panel p-4 rounded-2xl flex-1 flex flex-col min-h-[460px] hidden">
288
- <div class="flex items-center justify-between pb-2 border-b border-slate-800/80 mb-3 text-xs text-slate-400">
289
- <span class="font-mono text-indigo-400 flex items-center gap-1.5">
290
- <span>📦</span> Generated by json-renderers-build before mounting
291
- </span>
292
- <button id="btn-copy-ast" class="px-2 py-0.5 text-[11px] bg-slate-800 hover:bg-slate-700 text-slate-300 rounded font-mono">Copy AST</button>
293
- </div>
294
- <pre class="flex-1 m-0 p-3 bg-slate-950 rounded-xl text-indigo-200 font-mono text-xs overflow-auto custom-scrollbar leading-relaxed max-h-[500px]"><code id="code-output-ast">// Loading in-between spec...</code></pre>
295
- </div>
296
-
297
- </div>
298
-
299
- </div>
300
- </section>
301
-
302
- <!-- Component Renderers Catalog -->
303
- <section class="space-y-6">
304
- <div class="border-b border-slate-800/80 pb-4">
305
- <span class="text-xs uppercase font-mono tracking-wider text-emerald-400">Component Catalog</span>
306
- <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">Supported Renderers in v13</h3>
307
- </div>
308
-
309
- <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
310
-
311
- <!-- Table Card -->
312
- <div class="glass-card p-5 rounded-2xl space-y-3">
313
- <div class="flex items-center justify-between">
314
- <span class="text-xs font-mono font-bold text-white uppercase tracking-wider">type: "table"</span>
315
- <span class="px-2 py-0.5 rounded bg-emerald-500/20 text-emerald-300 text-[11px] font-mono">Data Grid</span>
316
- </div>
317
- <p class="text-xs text-slate-400 leading-relaxed">
318
- Mounts complete Bootstrap-styled table into the target element. Supports multi-column headers and automated cell value bindings.
319
- </p>
320
- <div class="text-[11px] font-mono text-slate-400 bg-slate-950 p-2.5 rounded-lg border border-slate-800">
321
- render({ type: "table", targetHtmlId, data, columns })
322
- </div>
323
- </div>
324
-
325
- <!-- Select Card -->
326
- <div class="glass-card p-5 rounded-2xl space-y-3">
327
- <div class="flex items-center justify-between">
328
- <span class="text-xs font-mono font-bold text-white uppercase tracking-wider">type: "select"</span>
329
- <span class="px-2 py-0.5 rounded bg-teal-500/20 text-teal-300 text-[11px] font-mono">Select Element</span>
330
- </div>
331
- <p class="text-xs text-slate-400 leading-relaxed">
332
- Mounts a newly created <code class="text-teal-300">&lt;select id="LedgerName"&gt;</code> populated with child option elements into the target container.
333
- </p>
334
- <div class="text-[11px] font-mono text-slate-400 bg-slate-950 p-2.5 rounded-lg border border-slate-800">
335
- render({ type: "select", targetHtmlId, data })
336
- </div>
337
- </div>
338
-
339
- <!-- Select Options Only Card -->
340
- <div class="glass-card p-5 rounded-2xl space-y-3">
341
- <div class="flex items-center justify-between">
342
- <span class="text-xs font-mono font-bold text-white uppercase tracking-wider">type: "selectOptionsOnly"</span>
343
- <span class="px-2 py-0.5 rounded bg-indigo-500/20 text-indigo-300 text-[11px] font-mono">Option Injection</span>
344
- </div>
345
- <p class="text-xs text-slate-400 leading-relaxed">
346
- Populates dynamic option items directly into a pre-existing <code class="text-indigo-300">&lt;select&gt;</code> element without modifying outer wrapper tags.
347
- </p>
348
- <div class="text-[11px] font-mono text-slate-400 bg-slate-950 p-2.5 rounded-lg border border-slate-800">
349
- render({ type: "selectOptionsOnly", targetHtmlId, data })
350
- </div>
351
- </div>
352
-
353
- </div>
354
- </section>
355
-
356
- <!-- Runnable Samples Section -->
357
- <section id="samples" class="space-y-6">
358
- <div class="border-b border-slate-800/80 pb-4">
359
- <span class="text-xs uppercase font-mono tracking-wider text-emerald-400">Browser Demos</span>
360
- <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">Included Verification Samples</h3>
361
- </div>
362
-
363
- <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
364
-
365
- <a href="../samples/table/index.html" class="glass-panel p-5 rounded-2xl group hover:border-emerald-500/50 transition flex flex-col justify-between">
366
- <div>
367
- <div class="flex items-center justify-between mb-3">
368
- <span class="text-xl">📊</span>
369
- <span class="text-xs text-emerald-400 font-mono group-hover:translate-x-1 transition">Open Demo &rarr;</span>
370
- </div>
371
- <h4 class="text-base font-bold text-white mb-1 group-hover:text-emerald-300 transition">Table DOM Sample</h4>
372
- <p class="text-xs text-slate-400 leading-relaxed mb-4">
373
- Mounts a responsive batches table into the browser DOM using <code class="text-emerald-300 font-mono">json-renderers</code>.
374
- </p>
375
- </div>
376
- <div class="text-[11px] font-mono text-slate-500">samples/table/index.html</div>
377
- </a>
378
-
379
- <a href="../samples/select/index.html" class="glass-panel p-5 rounded-2xl group hover:border-teal-500/50 transition flex flex-col justify-between">
380
- <div>
381
- <div class="flex items-center justify-between mb-3">
382
- <span class="text-xl">🔽</span>
383
- <span class="text-xs text-teal-400 font-mono group-hover:translate-x-1 transition">Open Demo &rarr;</span>
384
- </div>
385
- <h4 class="text-base font-bold text-white mb-1 group-hover:text-teal-300 transition">Select DOM Sample</h4>
386
- <p class="text-xs text-slate-400 leading-relaxed mb-4">
387
- Mounts a ledger accounts dropdown element into the DOM container.
388
- </p>
389
- </div>
390
- <div class="text-[11px] font-mono text-slate-500">samples/select/index.html</div>
391
- </a>
392
-
393
- <a href="../samples/selectOptionsOnly/index.html" class="glass-panel p-5 rounded-2xl group hover:border-indigo-500/50 transition flex flex-col justify-between">
394
- <div>
395
- <div class="flex items-center justify-between mb-3">
396
- <span class="text-xl">📑</span>
397
- <span class="text-xs text-indigo-400 font-mono group-hover:translate-x-1 transition">Open Demo &rarr;</span>
398
- </div>
399
- <h4 class="text-base font-bold text-white mb-1 group-hover:text-indigo-300 transition">Options Injection Sample</h4>
400
- <p class="text-xs text-slate-400 leading-relaxed mb-4">
401
- Populates option tags into an existing select dropdown on the page.
402
- </p>
403
- </div>
404
- <div class="text-[11px] font-mono text-slate-500">samples/selectOptionsOnly/index.html</div>
405
- </a>
406
-
407
- </div>
408
- </section>
409
-
410
- <!-- Quick CDN & Installation Code -->
411
- <section class="glass-panel p-6 rounded-2xl space-y-4">
412
- <h3 class="text-sm font-bold text-white uppercase tracking-wider font-mono flex items-center gap-2">
413
- <span>📦</span> Installation & Distribution
414
- </h3>
415
-
416
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
417
- <div>
418
- <label class="text-xs text-slate-400 mb-1 block font-mono">NPM Package:</label>
419
- <pre class="p-3 bg-slate-950 rounded-xl text-xs text-emerald-300 font-mono border border-slate-800 overflow-x-auto"><code>npm install json-renderers</code></pre>
420
- </div>
421
-
422
- <div>
423
- <label class="text-xs text-slate-400 mb-1 block font-mono">ES Module CDN:</label>
424
- <pre class="p-3 bg-slate-950 rounded-xl text-xs text-emerald-300 font-mono border border-slate-800 overflow-x-auto"><code>import render from "https://cdn.jsdelivr.net/gh/keshavsoft/json-renderers@main/docs/dist/v13/min.js";</code></pre>
425
- </div>
426
- </div>
427
- </section>
428
-
429
- </main>
430
-
431
- <!-- Footer -->
432
- <footer class="border-t border-slate-900 bg-slate-950 py-6 text-center text-xs text-slate-500">
433
- <div class="max-w-7xl mx-auto px-4 flex flex-col sm:flex-row items-center justify-between gap-3">
434
- <div>
435
- <strong class="text-slate-400">json-renderers</strong> &bull; KeshavSoft &bull; MIT License
436
- </div>
437
- <div class="flex items-center gap-4 text-slate-400">
438
- <a href="https://github.com/keshavsoft/json-renderers" class="hover:text-white transition">json-renderers</a>
439
- <a href="https://github.com/keshavsoft/json-renderers-build" class="hover:text-white transition">json-renderers-build</a>
440
- <a href="https://github.com/keshavsoft/json-to-spec" class="hover:text-white transition">json-to-spec</a>
441
- </div>
442
- </div>
443
- </footer>
444
-
445
- <!-- Workbench Script importing docs/dist/v13/min.js -->
446
- <script type="module">
447
- import render from "./dist/v13/min.js";
448
-
449
- // Presets catalog
450
- const PRESETS = {
451
- table: {
452
- batches: {
453
- data: [
454
- { id: "B-101", name: "Aluminium Rods 25mm", qty: 450, status: "Verified" },
455
- { id: "B-102", name: "Copper Sheets 1.2mm", qty: 280, status: "In Transit" },
456
- { id: "B-103", name: "Steel Fasteners M8", qty: 1200, status: "Verified" }
457
- ],
458
- columns: [{ title: "Batch ID" }, { title: "Item Name" }, { title: "Quantity" }, { title: "Status" }]
459
- },
460
- employees: {
461
- data: [
462
- { empId: "EMP-01", name: "Sarah Connor", role: "Security Architect", city: "London" },
463
- { empId: "EMP-02", name: "John Miller", role: "DevOps Engineer", city: "Berlin" },
464
- { empId: "EMP-03", name: "Anita Rao", role: "Lead Developer", city: "Bengaluru" }
465
- ],
466
- columns: ["Emp ID", "Employee Name", "Designation", "Base Location"]
467
- },
468
- ledgers: {
469
- data: [
470
- { code: "A-001", account: "State Bank of India", balance: 540000 },
471
- { code: "A-002", account: "HDFC Operating", balance: 1250000 }
472
- ],
473
- columns: [{ title: "Code" }, { title: "Account Name" }, { title: "Balance (INR)" }]
474
- }
475
- },
476
- select: {
477
- ledgers: {
478
- data: ["Cash In Hand", "State Bank of India", "Accounts Receivable", "General Reserves", "Sales Account"]
479
- },
480
- batches: {
481
- data: ["Batch 2026-A1", "Batch 2026-A2", "Batch 2026-B1"]
482
- },
483
- employees: {
484
- data: ["Bangalore HQ", "Hyderabad Campus", "Singapore Branch"]
485
- }
486
- },
487
- selectOptionsOnly: {
488
- ledgers: {
489
- data: ["Deluxe Suite", "Executive Premier", "Presidential Villa"]
490
- },
491
- batches: {
492
- data: ["High Priority", "Medium Priority", "Low Priority"]
493
- },
494
- employees: {
495
- data: ["Finance", "Human Resources", "Engineering", "Marketing"]
496
- }
497
- }
498
- };
499
-
500
- // DOM references
501
- const typeSelect = document.getElementById("component-type");
502
- const presetSelect = document.getElementById("preset-selector");
503
- const inputDataEl = document.getElementById("input-data");
504
- const inputColumnsEl = document.getElementById("input-columns");
505
- const columnsPanel = document.getElementById("columns-panel");
506
- const btnRenderDom = document.getElementById("btn-render-dom");
507
- const btnFormatData = document.getElementById("btn-format-data");
508
- const btnFormatColumns = document.getElementById("btn-format-columns");
509
- const liveMountContainer = document.getElementById("live-mount-container");
510
- const codeOutputAst = document.getElementById("code-output-ast");
511
- const mountStatusBadge = document.getElementById("mount-status-badge");
512
- const btnCopyAst = document.getElementById("btn-copy-ast");
513
-
514
- // Tabs
515
- const tabDom = document.getElementById("tab-dom");
516
- const tabInBetween = document.getElementById("tab-in-between");
517
- const viewDom = document.getElementById("view-dom");
518
- const viewInBetween = document.getElementById("view-in-between");
519
-
520
- let currentAstOutput = null;
521
-
522
- function switchTab(activeTab) {
523
- if (activeTab === "dom") {
524
- tabDom.className = "px-3 py-1.5 text-xs font-semibold rounded-lg bg-emerald-600 text-white transition flex items-center gap-1.5";
525
- tabInBetween.className = "px-3 py-1.5 text-xs font-semibold rounded-lg text-slate-400 hover:text-white transition flex items-center gap-1.5";
526
- viewDom.classList.remove("hidden");
527
- viewInBetween.classList.add("hidden");
528
- } else {
529
- tabDom.className = "px-3 py-1.5 text-xs font-semibold rounded-lg text-slate-400 hover:text-white transition flex items-center gap-1.5";
530
- tabInBetween.className = "px-3 py-1.5 text-xs font-semibold rounded-lg bg-indigo-600 text-white transition flex items-center gap-1.5";
531
- viewDom.classList.add("hidden");
532
- viewInBetween.classList.remove("hidden");
533
- }
534
- }
535
-
536
- tabDom.addEventListener("click", () => switchTab("dom"));
537
- tabInBetween.addEventListener("click", () => switchTab("in-between"));
538
-
539
- function syncTypeUI() {
540
- const type = typeSelect.value;
541
- if (type === "table") {
542
- columnsPanel.classList.remove("hidden");
543
- } else {
544
- columnsPanel.classList.add("hidden");
545
- }
546
- loadPreset();
547
- }
548
-
549
- function loadPreset() {
550
- const type = typeSelect.value;
551
- const presetKey = presetSelect.value;
552
- const typePresets = PRESETS[type] || {};
553
- const preset = typePresets[presetKey] || typePresets[Object.keys(typePresets)[0]];
554
-
555
- if (preset) {
556
- inputDataEl.value = JSON.stringify(preset.data, null, 2);
557
- if (preset.columns) {
558
- inputColumnsEl.value = JSON.stringify(preset.columns, null, 2);
559
- } else {
560
- inputColumnsEl.value = "[]";
561
- }
562
- }
563
-
564
- mountToDom();
565
- }
566
-
567
- // Mount to DOM execution
568
- function mountToDom() {
569
- try {
570
- const type = typeSelect.value;
571
- const rawData = JSON.parse(inputDataEl.value || "[]");
572
- let rawColumns = undefined;
573
-
574
- if (type === "table") {
575
- try {
576
- rawColumns = JSON.parse(inputColumnsEl.value || "[]");
577
- } catch (e) {
578
- rawColumns = [];
579
- }
580
- }
581
-
582
- let targetId = "live-mount-container";
583
-
584
- // Setup host if selectOptionsOnly needs an existing <select>
585
- if (type === "selectOptionsOnly") {
586
- liveMountContainer.innerHTML = `
587
- <div class="p-3 bg-slate-950 rounded-lg max-w-sm border border-slate-800">
588
- <label for="demo-existing-select" class="block text-xs font-mono text-slate-400 mb-1.5">Pre-existing Dropdown Target:</label>
589
- <select id="demo-existing-select" class="form-select bg-slate-900 text-white border-slate-700"></select>
590
- </div>
591
- `;
592
- targetId = "demo-existing-select";
593
- } else {
594
- liveMountContainer.innerHTML = "";
595
- }
596
-
597
- // Call the real json-renderers function!
598
- const result = render({
599
- type,
600
- targetHtmlId: targetId,
601
- data: rawData,
602
- columns: rawColumns
603
- });
604
-
605
- // If table, wrap in clean white bootstrap card for readability
606
- if (type === "table") {
607
- const table = liveMountContainer.querySelector("table");
608
- if (table) {
609
- table.classList.add("bg-white", "text-dark", "rounded");
610
- }
611
- } else if (type === "select") {
612
- const sel = liveMountContainer.querySelector("select");
613
- if (sel) {
614
- sel.className = "form-select bg-slate-950 text-white border-slate-700 max-w-sm";
615
- }
616
- }
617
-
618
- mountStatusBadge.textContent = `Mounted (${type})`;
619
- mountStatusBadge.className = "px-2 py-0.5 text-[11px] bg-emerald-500/20 text-emerald-300 rounded font-mono border border-emerald-500/30";
620
-
621
- // Also compute the "in-between" spec AST for inspection tab
622
- if (window.ks?.jsonRenderersBuild?.renderToDom) {
623
- const ast = window.ks.jsonRenderersBuild.renderToDom({
624
- type,
625
- data: rawData,
626
- columns: rawColumns
627
- });
628
- currentAstOutput = ast;
629
- codeOutputAst.textContent = JSON.stringify(ast, null, 2);
630
- } else {
631
- codeOutputAst.textContent = "// json-renderers-build AST rendered into DOM successfully";
632
- }
633
-
634
- } catch (err) {
635
- console.error("Mount error:", err);
636
- liveMountContainer.innerHTML = `<div class="alert alert-danger font-mono text-xs m-2">${err.message}</div>`;
637
- mountStatusBadge.textContent = "Error";
638
- mountStatusBadge.className = "px-2 py-0.5 text-[11px] bg-rose-500/20 text-rose-300 rounded font-mono border border-rose-500/30";
639
- }
640
- }
641
-
642
- // Event listeners
643
- typeSelect.addEventListener("change", syncTypeUI);
644
- presetSelect.addEventListener("change", loadPreset);
645
- btnRenderDom.addEventListener("click", mountToDom);
646
-
647
- btnFormatData.addEventListener("click", () => {
648
- try {
649
- inputDataEl.value = JSON.stringify(JSON.parse(inputDataEl.value), null, 2);
650
- } catch (e) {}
651
- });
652
-
653
- btnFormatColumns.addEventListener("click", () => {
654
- try {
655
- inputColumnsEl.value = JSON.stringify(JSON.parse(inputColumnsEl.value), null, 2);
656
- } catch (e) {}
657
- });
658
-
659
- btnCopyAst.addEventListener("click", () => {
660
- if (currentAstOutput) {
661
- navigator.clipboard.writeText(JSON.stringify(currentAstOutput, null, 2));
662
- btnCopyAst.textContent = "Copied!";
663
- setTimeout(() => { btnCopyAst.textContent = "Copy AST"; }, 1500);
664
- }
665
- });
666
-
667
- // Auto-update on typing with debounce
668
- let debounceTimer;
669
- [inputDataEl, inputColumnsEl].forEach(el => {
670
- el.addEventListener("input", () => {
671
- clearTimeout(debounceTimer);
672
- debounceTimer = setTimeout(mountToDom, 350);
673
- });
674
- });
675
-
676
- // Initial setup
677
- syncTypeUI();
678
- </script>
679
- </body>
1
+ <!DOCTYPE html>
2
+ <html lang="en" class="dark">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>json-renderers | Browser DOM Component Renderer</title>
8
+ <meta name="description"
9
+ content="Browser DOM component renderer built on top of json-renderers-build and @keshavsoft/json-to-tag.">
10
+ <link rel="preconnect" href="https://fonts.googleapis.com">
11
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12
+ <link
13
+ href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600&family=Inter:wght@300;400;500;600;700;800&display=swap"
14
+ rel="stylesheet">
15
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
16
+ <script src="https://cdn.tailwindcss.com"></script>
17
+ <script>
18
+ tailwind.config = {
19
+ darkMode: 'class',
20
+ theme: {
21
+ extend: {
22
+ colors: {
23
+ brand: {
24
+ 50: '#eef2ff',
25
+ 100: '#e0e7ff',
26
+ 500: '#6366f1',
27
+ 600: '#4f46e5',
28
+ 700: '#4338ca',
29
+ 800: '#3730a3',
30
+ 900: '#312e81'
31
+ }
32
+ },
33
+ fontFamily: {
34
+ sans: ['Inter', 'sans-serif'],
35
+ mono: ['Fira Code', 'monospace']
36
+ }
37
+ }
38
+ }
39
+ };
40
+ </script>
41
+ <style>
42
+ pre,
43
+ code {
44
+ font-family: 'Fira Code', monospace;
45
+ }
46
+
47
+ .custom-scrollbar::-webkit-scrollbar {
48
+ width: 6px;
49
+ height: 6px;
50
+ }
51
+
52
+ .custom-scrollbar::-webkit-scrollbar-track {
53
+ background: rgba(15, 23, 42, 0.6);
54
+ }
55
+
56
+ .custom-scrollbar::-webkit-scrollbar-thumb {
57
+ background: rgba(99, 102, 241, 0.3);
58
+ border-radius: 4px;
59
+ }
60
+
61
+ .custom-scrollbar::-webkit-scrollbar-thumb:hover {
62
+ background: rgba(99, 102, 241, 0.6);
63
+ }
64
+
65
+ .glass-panel {
66
+ background: rgba(15, 23, 42, 0.75);
67
+ backdrop-filter: blur(12px);
68
+ border: 1px solid rgba(255, 255, 255, 0.08);
69
+ }
70
+
71
+ .glass-card {
72
+ background: rgba(30, 41, 59, 0.5);
73
+ backdrop-filter: blur(8px);
74
+ border: 1px solid rgba(255, 255, 255, 0.05);
75
+ }
76
+ </style>
77
+ </head>
78
+
79
+ <body
80
+ class="bg-slate-950 text-slate-100 min-h-screen antialiased flex flex-col font-sans selection:bg-indigo-500 selection:text-white">
81
+
82
+ <!-- Top Navbar -->
83
+ <header class="border-b border-slate-800/80 bg-slate-900/80 backdrop-blur sticky top-0 z-50">
84
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 py-3.5 flex items-center justify-between gap-4">
85
+ <div class="flex items-center gap-3">
86
+ <div
87
+ class="w-10 h-10 rounded-xl bg-gradient-to-br from-emerald-500 via-teal-600 to-indigo-600 flex items-center justify-center font-bold text-white shadow-lg text-lg shadow-emerald-500/20">
88
+ 🖥️
89
+ </div>
90
+ <div>
91
+ <div class="flex items-center gap-2">
92
+ <h1 class="text-base font-bold text-white tracking-tight">json-renderers</h1>
93
+ <span
94
+ class="px-2 py-0.5 text-xs bg-emerald-500/20 text-emerald-300 rounded-full border border-emerald-500/30 font-mono">v13.1.0</span>
95
+ </div>
96
+ <p class="text-xs text-slate-400">Browser DOM Component Renderer Runtime</p>
97
+ </div>
98
+ </div>
99
+
100
+ <div class="flex items-center gap-2.5">
101
+ <a href="aboutSelect.html"
102
+ class="px-3.5 py-1.5 text-xs font-semibold rounded-lg bg-cyan-600 hover:bg-cyan-500 text-white transition flex items-center gap-1.5 shadow-sm shadow-cyan-600/30">
103
+ <span>▣</span> About Select Guide
104
+ </a>
105
+ <a href="table/index.html"
106
+ class="px-3.5 py-1.5 text-xs font-semibold rounded-lg bg-indigo-600 hover:bg-indigo-500 text-white transition flex items-center gap-1.5 shadow-sm shadow-indigo-600/30">
107
+ <span>📖</span> Table Guide
108
+ </a>
109
+ <a href="#workbench"
110
+ class="px-3.5 py-1.5 text-xs font-semibold rounded-lg bg-emerald-600 hover:bg-emerald-500 text-white transition flex items-center gap-1.5 shadow-sm shadow-emerald-600/30">
111
+ <span>⚡</span> Live DOM Workbench
112
+ </a>
113
+ <a href="#samples"
114
+ class="px-3 py-1.5 text-xs font-semibold rounded-lg bg-slate-800 hover:bg-slate-700 text-slate-200 border border-slate-700 transition hidden sm:flex items-center gap-1">
115
+ <span>📂</span> Samples
116
+ </a>
117
+ <a href="https://github.com/keshavsoft/json-renderers" target="_blank" rel="noopener noreferrer"
118
+ class="px-3 py-1.5 text-xs font-semibold rounded-lg bg-slate-800 hover:bg-slate-700 text-slate-200 border border-slate-700 transition flex items-center gap-1.5">
119
+ <svg class="w-4 h-4 fill-current" viewBox="0 0 24 24">
120
+ <path
121
+ d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
122
+ </svg>
123
+ <span class="hidden md:inline">GitHub</span>
124
+ </a>
125
+ </div>
126
+ </div>
127
+ </header>
128
+
129
+ <main class="flex-1 max-w-7xl w-full mx-auto p-4 sm:p-6 lg:p-8 space-y-12">
130
+
131
+ <!-- Hero Section -->
132
+ <section class="text-center py-6 sm:py-10 space-y-5">
133
+ <div
134
+ class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-xs text-emerald-300 font-mono">
135
+ <span class="w-2 h-2 rounded-full bg-emerald-400 animate-pulse"></span>
136
+ Ecosystem Story: DOM Mounting Runtime
137
+ </div>
138
+ <h2 class="text-3xl sm:text-5xl font-extrabold text-white tracking-tight leading-tight">
139
+ Render Business JSON into Live DOM <br class="hidden sm:inline" />
140
+ <span class="text-transparent bg-clip-text bg-gradient-to-r from-emerald-400 via-teal-300 to-indigo-400">Powered
141
+ by json-renderers-build + json-to-tag</span>
142
+ </h2>
143
+ <p class="max-w-4xl mx-auto text-slate-400 text-sm sm:text-base leading-relaxed">
144
+ The real DOM magic happens in <strong class="text-emerald-300 font-mono">@keshavsoft/json-to-tag</strong>.
145
+ Before that, data may be shaped in <strong class="text-indigo-300 font-mono">json-transformer</strong>, a
146
+ component blueprint is built in <strong class="text-indigo-300 font-mono">json-renderers-build</strong>, and
147
+ <strong class="text-slate-200">json-renderers</strong> simply orchestrates the runtime flow and mounts the final
148
+ HTML into the browser container.
149
+ </p>
150
+
151
+ <div class="flex flex-wrap items-center justify-center gap-3 pt-2">
152
+ <a href="aboutSelect.html"
153
+ class="px-5 py-2.5 rounded-xl bg-gradient-to-r from-cyan-600 to-teal-600 hover:from-cyan-500 hover:to-teal-500 text-white font-semibold text-xs sm:text-sm transition flex items-center gap-2 shadow-lg shadow-cyan-600/25">
154
+ <span>▣</span> Select Guide (CDN &amp; KS)
155
+ </a>
156
+ <a href="table/index.html"
157
+ class="px-5 py-2.5 rounded-xl bg-gradient-to-r from-emerald-600 to-indigo-600 hover:from-emerald-500 hover:to-indigo-500 text-white font-semibold text-xs sm:text-sm transition flex items-center gap-2 shadow-lg shadow-indigo-600/25">
158
+ <span>📖</span> Table Guide (CDN &amp; KS)
159
+ </a>
160
+ <a href="#workbench"
161
+ class="px-5 py-2.5 rounded-xl bg-emerald-600 hover:bg-emerald-500 text-white font-semibold text-xs sm:text-sm transition flex items-center gap-2 shadow-lg shadow-emerald-600/25">
162
+ <span>⚡</span> Try Live DOM Mounting
163
+ </a>
164
+ <a href="table.html"
165
+ class="px-5 py-2.5 rounded-xl bg-slate-900 hover:bg-slate-800 border border-slate-800 text-slate-200 font-semibold text-xs sm:text-sm transition flex items-center gap-2">
166
+ <span>📊</span> Table Story
167
+ </a>
168
+ <a href="select.html"
169
+ class="px-5 py-2.5 rounded-xl bg-slate-900 hover:bg-slate-800 border border-slate-800 text-slate-200 font-semibold text-xs sm:text-sm transition flex items-center gap-2">
170
+ <span>▣</span> Select Story
171
+ </a>
172
+ </div>
173
+ </section>
174
+
175
+ <!-- Inside the Builder: JSON Shape Section -->
176
+ <section id="inside-builder" class="space-y-6">
177
+ <div class="flex flex-col md:flex-row md:items-end justify-between gap-4 border-b border-slate-800/80 pb-4">
178
+ <div>
179
+ <span class="text-xs uppercase font-mono tracking-wider text-cyan-400">Inside the Builder</span>
180
+ <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">What the runtime actually asks for</h3>
181
+ </div>
182
+ <p class="text-xs text-slate-400 max-w-md">
183
+ The runtime does not hand-code table or select DOM. It asks for a JSON blueprint and then lets <span
184
+ class="text-emerald-300 font-mono">json-to-tag</span> create real elements.
185
+ </p>
186
+ </div>
187
+
188
+ <div class="grid grid-cols-1 xl:grid-cols-2 gap-6">
189
+ <div class="glass-panel p-5 rounded-2xl">
190
+ <div class="flex items-center justify-between mb-3">
191
+ <span
192
+ class="px-2 py-0.5 text-[11px] font-mono rounded bg-emerald-500/20 text-emerald-300 border border-emerald-500/30">Table
193
+ Spec</span>
194
+ <span class="text-lg">📊</span>
195
+ </div>
196
+ <pre class="text-xs text-slate-200 bg-slate-950/80 border border-slate-800 rounded-xl p-3 overflow-auto"><code>{
197
+ "type": "table",
198
+ "children": [
199
+ { "type": "thead", "children": [{ "type": "tr", "children": ["Name", "City", "Amount"] }] },
200
+ { "type": "tbody", "children": [
201
+ { "type": "tr", "children": ["Alpha", "Hyderabad", 1200] },
202
+ { "type": "tr", "children": ["Beta", "Bengaluru", 2200] }
203
+ ] }
204
+ ]
205
+ }</code></pre>
206
+ </div>
207
+
208
+ <div class="glass-panel p-5 rounded-2xl">
209
+ <div class="flex items-center justify-between mb-3">
210
+ <span
211
+ class="px-2 py-0.5 text-[11px] font-mono rounded bg-cyan-500/20 text-cyan-300 border border-cyan-500/30">Select
212
+ Spec</span>
213
+ <span class="text-lg">▣</span>
214
+ </div>
215
+ <pre class="text-xs text-slate-200 bg-slate-950/80 border border-slate-800 rounded-xl p-3 overflow-auto"><code>{
216
+ "type": "select",
217
+ "id": "city-select",
218
+ "children": [
219
+ { "type": "option", "value": "Hyderabad", "text": "Hyderabad" },
220
+ { "type": "option", "value": "Bengaluru", "text": "Bengaluru" },
221
+ { "type": "option", "value": "Pune", "text": "Pune" }
222
+ ]
223
+ }</code></pre>
224
+ </div>
225
+ </div>
226
+ </section>
227
+
228
+ <!-- The In-Between & 3-Tier Pipeline Section -->
229
+ <section id="in-between" class="space-y-6">
230
+ <div class="flex flex-col md:flex-row md:items-end justify-between gap-4 border-b border-slate-800/80 pb-4">
231
+ <div>
232
+ <span class="text-xs uppercase font-mono tracking-wider text-emerald-400">Ecosystem Architecture</span>
233
+ <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">The "In-Between" Handoff Story</h3>
234
+ </div>
235
+ <p class="text-xs text-slate-400 max-w-md">
236
+ How <span class="text-indigo-300 font-mono">json-transformer</span>, <span
237
+ class="text-indigo-300 font-mono">json-renderers-build</span>, <span
238
+ class="text-emerald-300 font-mono">json-to-tag</span>, and <span
239
+ class="text-emerald-300 font-mono">json-renderers</span> work together.
240
+ </p>
241
+ </div>
242
+
243
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
244
+ <!-- Step 1 -->
245
+ <div class="glass-panel p-5 rounded-2xl relative">
246
+ <div class="flex items-center justify-between mb-3">
247
+ <span
248
+ class="px-2 py-0.5 text-[11px] font-mono rounded bg-indigo-500/20 text-indigo-300 border border-indigo-500/30">Step
249
+ 1 • Spec Request</span>
250
+ <span class="text-lg">📦</span>
251
+ </div>
252
+ <h4 class="text-base font-bold text-white mb-2">json-renderers-build</h4>
253
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
254
+ <code class="text-emerald-300 font-mono">json-renderers</code> calls <code
255
+ class="text-indigo-300 font-mono">jsonRenderBuild({ type, data, columns })</code>. The builder matches the
256
+ skeleton blueprint (<code class="text-indigo-300 font-mono">table</code>, <code
257
+ class="text-indigo-300 font-mono">select</code>) and evaluates it with <code
258
+ class="text-indigo-300 font-mono">json-to-spec</code>.
259
+ </p>
260
+ <div
261
+ class="p-2.5 rounded-lg bg-slate-950/80 border border-indigo-500/30 text-[11px] font-mono text-indigo-300">
262
+ Returns: specAsJsonToDom (AST)
263
+ </div>
264
+ </div>
265
+
266
+ <!-- Step 2 -->
267
+ <div class="glass-panel p-5 rounded-2xl relative">
268
+ <div class="flex items-center justify-between mb-3">
269
+ <span
270
+ class="px-2 py-0.5 text-[11px] font-mono rounded bg-purple-500/20 text-purple-300 border border-purple-500/30">Step
271
+ 2 • Instantiation</span>
272
+ <span class="text-lg">🏷️</span>
273
+ </div>
274
+ <h4 class="text-base font-bold text-white mb-2">@keshavsoft/json-to-tag</h4>
275
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
276
+ The generated specification AST is unwrapped (if fragment) and handed to <code
277
+ class="text-purple-300 font-mono">jsonToTag(spec)</code>. Real browser DOM elements (<code
278
+ class="text-purple-300 font-mono">HTMLTableElement</code>, <code
279
+ class="text-purple-300 font-mono">DocumentFragment</code>) are constructed.
280
+ </p>
281
+ <div
282
+ class="p-2.5 rounded-lg bg-slate-950/80 border border-purple-500/30 text-[11px] font-mono text-purple-300">
283
+ Returns: content (DOM Node / List)
284
+ </div>
285
+ </div>
286
+
287
+ <!-- Step 3 -->
288
+ <div
289
+ class="glass-panel p-5 rounded-2xl border-emerald-500/50 shadow-xl shadow-emerald-500/10 bg-slate-900/90 relative">
290
+ <div
291
+ class="absolute top-0 right-0 bg-emerald-600 text-white text-[10px] uppercase font-bold tracking-wider px-2.5 py-0.5 rounded-bl-lg">
292
+ This Repo
293
+ </div>
294
+ <div class="flex items-center justify-between mb-3">
295
+ <span
296
+ class="px-2 py-0.5 text-[11px] font-mono rounded bg-emerald-500/20 text-emerald-300 border border-emerald-500/30">Step
297
+ 3 • Container Mount</span>
298
+ <span class="text-lg">🖥️</span>
299
+ </div>
300
+ <h4 class="text-base font-bold text-emerald-300 mb-2">json-renderers</h4>
301
+ <p class="text-xs text-slate-300 leading-relaxed mb-4">
302
+ Locates <code class="text-emerald-300 font-mono">document.getElementById(targetHtmlId)</code>. Clears or
303
+ prepends content based on <code class="text-emerald-300 font-mono">appendPosition</code>, mounts the nodes,
304
+ and returns the mounted container.
305
+ </p>
306
+ <div
307
+ class="p-2.5 rounded-lg bg-slate-950/80 border border-emerald-500/30 text-[11px] font-mono text-emerald-200">
308
+ container.append(content)
309
+ </div>
310
+ </div>
311
+ </div>
312
+ </section>
313
+
314
+ <!-- Interactive Live DOM Workbench -->
315
+ <section id="workbench" class="space-y-6">
316
+ <div class="flex flex-col md:flex-row md:items-end justify-between gap-4 border-b border-slate-800/80 pb-4">
317
+ <div>
318
+ <span class="text-xs uppercase font-mono tracking-wider text-emerald-400">Live Demonstration</span>
319
+ <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">Interactive DOM Mounting Workbench</h3>
320
+ </div>
321
+ <div class="flex items-center gap-3">
322
+ <label for="component-type" class="text-xs text-slate-400 font-medium">Type:</label>
323
+ <select id="component-type"
324
+ class="bg-slate-900 border border-slate-700 text-xs rounded-lg px-3 py-1.5 text-white font-mono focus:ring-2 focus:ring-emerald-500 focus:outline-none">
325
+ <option value="table" selected>table</option>
326
+ <option value="select">select</option>
327
+ <option value="selectOptionsOnly">selectOptionsOnly</option>
328
+ </select>
329
+ <button id="btn-render-dom"
330
+ class="px-3.5 py-1.5 bg-emerald-600 hover:bg-emerald-500 text-white rounded-lg text-xs font-semibold shadow-sm transition flex items-center gap-1 shadow-emerald-600/30">
331
+ <span>▶</span> Mount to DOM
332
+ </button>
333
+ </div>
334
+ </div>
335
+
336
+ <div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
337
+
338
+ <!-- Left Column: Inputs (5 Cols) -->
339
+ <div class="lg:col-span-5 space-y-4">
340
+ <div class="glass-panel p-4 rounded-2xl space-y-3">
341
+ <div class="flex items-center justify-between">
342
+ <span class="text-xs font-bold text-white uppercase tracking-wider font-mono flex items-center gap-1.5">
343
+ <span>📝</span> Input Data (JSON)
344
+ </span>
345
+ <div class="flex items-center gap-2">
346
+ <select id="preset-selector"
347
+ class="bg-slate-800 border border-slate-700 text-[11px] rounded px-2 py-1 text-slate-300 font-mono">
348
+ <option value="batches">Preset: Batches</option>
349
+ <option value="employees">Preset: Employees</option>
350
+ <option value="ledgers">Preset: Ledgers</option>
351
+ </select>
352
+ <button id="btn-format-data"
353
+ class="text-[11px] text-slate-400 hover:text-white px-2 py-0.5 rounded bg-slate-800">Format</button>
354
+ </div>
355
+ </div>
356
+ <textarea id="input-data" rows="8"
357
+ class="w-full bg-slate-950 text-emerald-200 border border-slate-800 rounded-xl p-3 font-mono text-xs focus:ring-2 focus:ring-emerald-500 focus:outline-none custom-scrollbar"
358
+ spellcheck="false"></textarea>
359
+ </div>
360
+
361
+ <div id="columns-panel" class="glass-panel p-4 rounded-2xl space-y-3">
362
+ <div class="flex items-center justify-between">
363
+ <span class="text-xs font-bold text-white uppercase tracking-wider font-mono flex items-center gap-1.5">
364
+ <span>📊</span> Columns (for table)
365
+ </span>
366
+ <button id="btn-format-columns"
367
+ class="text-[11px] text-slate-400 hover:text-white px-2 py-0.5 rounded bg-slate-800">Format</button>
368
+ </div>
369
+ <textarea id="input-columns" rows="5"
370
+ class="w-full bg-slate-950 text-emerald-200 border border-slate-800 rounded-xl p-3 font-mono text-xs focus:ring-2 focus:ring-emerald-500 focus:outline-none custom-scrollbar"
371
+ spellcheck="false"></textarea>
372
+ </div>
373
+
374
+ <div class="p-3.5 rounded-xl bg-slate-900/60 border border-slate-800/80 text-xs text-slate-400 space-y-1">
375
+ <div class="flex items-center gap-1.5 text-emerald-400 font-semibold font-mono">
376
+ <span>🎯</span> Mounting Contract
377
+ </div>
378
+ <p>
379
+ Calls <code
380
+ class="text-emerald-300 font-mono">render({ type, targetHtmlId: "live-mount-container", data, columns })</code>.
381
+ Ingests spec from <code class="text-indigo-300 font-mono">json-renderers-build</code> and instantiates
382
+ into DOM.
383
+ </p>
384
+ </div>
385
+ </div>
386
+
387
+ <!-- Right Column: Outputs (7 Cols) -->
388
+ <div class="lg:col-span-7 flex flex-col space-y-3">
389
+ <!-- View Toggle -->
390
+ <div class="flex items-center justify-between bg-slate-900/80 p-1.5 rounded-xl border border-slate-800">
391
+ <div class="flex items-center gap-1">
392
+ <button id="tab-dom"
393
+ class="px-3 py-1.5 text-xs font-semibold rounded-lg bg-emerald-600 text-white transition flex items-center gap-1.5">
394
+ <span>🖥️</span> Live Mounted DOM
395
+ </button>
396
+ <button id="tab-in-between"
397
+ class="px-3 py-1.5 text-xs font-semibold rounded-lg text-slate-400 hover:text-white transition flex items-center gap-1.5">
398
+ <span>🔗</span> "In-Between" Spec AST
399
+ </button>
400
+ </div>
401
+
402
+ <div class="flex items-center gap-2 pr-1">
403
+ <span id="mount-status-badge"
404
+ class="px-2 py-0.5 text-[11px] bg-emerald-500/20 text-emerald-300 rounded font-mono border border-emerald-500/30">
405
+ Mounted
406
+ </span>
407
+ </div>
408
+ </div>
409
+
410
+ <!-- View 1: Real DOM Container -->
411
+ <div id="view-dom" class="glass-panel p-4 rounded-2xl flex-1 flex flex-col min-h-[460px]">
412
+ <div
413
+ class="flex items-center justify-between pb-2 border-b border-slate-800/80 mb-3 text-xs text-slate-400">
414
+ <span class="font-mono text-emerald-400 flex items-center gap-1.5">
415
+ <span class="w-2 h-2 rounded-full bg-emerald-400"></span> #live-mount-container
416
+ </span>
417
+ <span class="font-mono text-[11px]">Real HTML Elements</span>
418
+ </div>
419
+
420
+ <div id="live-mount-container"
421
+ class="flex-1 p-3 bg-slate-900/60 rounded-xl border border-slate-800 overflow-auto custom-scrollbar">
422
+ <!-- Elements mounted by json-renderers here -->
423
+ </div>
424
+ </div>
425
+
426
+ <!-- View 2: "In-Between" Spec AST from json-renderers-build -->
427
+ <div id="view-in-between" class="glass-panel p-4 rounded-2xl flex-1 flex flex-col min-h-[460px] hidden">
428
+ <div
429
+ class="flex items-center justify-between pb-2 border-b border-slate-800/80 mb-3 text-xs text-slate-400">
430
+ <span class="font-mono text-indigo-400 flex items-center gap-1.5">
431
+ <span>📦</span> Generated by json-renderers-build before mounting
432
+ </span>
433
+ <button id="btn-copy-ast"
434
+ class="px-2 py-0.5 text-[11px] bg-slate-800 hover:bg-slate-700 text-slate-300 rounded font-mono">Copy
435
+ AST</button>
436
+ </div>
437
+ <pre
438
+ class="flex-1 m-0 p-3 bg-slate-950 rounded-xl text-indigo-200 font-mono text-xs overflow-auto custom-scrollbar leading-relaxed max-h-[500px]"><code id="code-output-ast">// Loading in-between spec...</code></pre>
439
+ </div>
440
+
441
+ </div>
442
+
443
+ </div>
444
+ </section>
445
+
446
+ <!-- Component Renderers Catalog -->
447
+ <section class="space-y-6">
448
+ <div class="border-b border-slate-800/80 pb-4">
449
+ <span class="text-xs uppercase font-mono tracking-wider text-emerald-400">Component Catalog</span>
450
+ <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">Supported Renderers in v13</h3>
451
+ </div>
452
+
453
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
454
+
455
+ <!-- Table Card -->
456
+ <div class="glass-card p-5 rounded-2xl space-y-3">
457
+ <div class="flex items-center justify-between">
458
+ <span class="text-xs font-mono font-bold text-white uppercase tracking-wider">type: "table"</span>
459
+ <span class="px-2 py-0.5 rounded bg-emerald-500/20 text-emerald-300 text-[11px] font-mono">Data Grid</span>
460
+ </div>
461
+ <p class="text-xs text-slate-400 leading-relaxed">
462
+ Mounts complete Bootstrap-styled table into the target element. Supports multi-column headers and automated
463
+ cell value bindings.
464
+ </p>
465
+ <div class="text-[11px] font-mono text-slate-400 bg-slate-950 p-2.5 rounded-lg border border-slate-800">
466
+ render({ type: "table", targetHtmlId, data, columns })
467
+ </div>
468
+ </div>
469
+
470
+ <!-- Select Card -->
471
+ <div class="glass-card p-5 rounded-2xl space-y-3">
472
+ <div class="flex items-center justify-between">
473
+ <span class="text-xs font-mono font-bold text-white uppercase tracking-wider">type: "select"</span>
474
+ <span class="px-2 py-0.5 rounded bg-teal-500/20 text-teal-300 text-[11px] font-mono">Select Element</span>
475
+ </div>
476
+ <p class="text-xs text-slate-400 leading-relaxed">
477
+ Mounts a newly created <code class="text-teal-300">&lt;select id="LedgerName"&gt;</code> populated with
478
+ child option elements into the target container.
479
+ </p>
480
+ <div class="text-[11px] font-mono text-slate-400 bg-slate-950 p-2.5 rounded-lg border border-slate-800">
481
+ render({ type: "select", targetHtmlId, data })
482
+ </div>
483
+ </div>
484
+
485
+ <!-- Select Options Only Card -->
486
+ <div class="glass-card p-5 rounded-2xl space-y-3">
487
+ <div class="flex items-center justify-between">
488
+ <span class="text-xs font-mono font-bold text-white uppercase tracking-wider">type:
489
+ "selectOptionsOnly"</span>
490
+ <span class="px-2 py-0.5 rounded bg-indigo-500/20 text-indigo-300 text-[11px] font-mono">Option
491
+ Injection</span>
492
+ </div>
493
+ <p class="text-xs text-slate-400 leading-relaxed">
494
+ Populates dynamic option items directly into a pre-existing <code
495
+ class="text-indigo-300">&lt;select&gt;</code> element without modifying outer wrapper tags.
496
+ </p>
497
+ <div class="text-[11px] font-mono text-slate-400 bg-slate-950 p-2.5 rounded-lg border border-slate-800">
498
+ render({ type: "selectOptionsOnly", targetHtmlId, data })
499
+ </div>
500
+ </div>
501
+
502
+ </div>
503
+ </section>
504
+
505
+ <!-- Runnable Samples Section -->
506
+ <section id="samples" class="space-y-6">
507
+ <div class="border-b border-slate-800/80 pb-4 flex flex-col sm:flex-row sm:items-end justify-between gap-3">
508
+ <div>
509
+ <span class="text-xs uppercase font-mono tracking-wider text-emerald-400">Browser Demos</span>
510
+ <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">Included Verification Samples</h3>
511
+ </div>
512
+ <a href="abouutTable.html"
513
+ class="inline-flex items-center gap-1.5 text-xs font-semibold text-emerald-400 hover:text-emerald-300 font-mono transition">
514
+ <span>📖</span> Read Complete Table Guide (CDN &amp; window.ks) &rarr;
515
+ </a>
516
+ </div>
517
+
518
+ <!-- Spotlight Banner for Table Guide -->
519
+ <div
520
+ class="glass-panel p-5 rounded-2xl border border-indigo-500/30 bg-gradient-to-r from-indigo-950/40 via-slate-900 to-emerald-950/40 flex flex-col md:flex-row items-start md:items-center justify-between gap-4">
521
+ <div class="space-y-1">
522
+ <div
523
+ class="inline-flex items-center gap-2 px-2.5 py-0.5 rounded-full bg-indigo-500/20 text-indigo-300 border border-indigo-500/30 text-xs font-mono">
524
+ Table Guide
525
+ </div>
526
+ <h4 class="text-base font-bold text-white">How to Create HTML Tables with CDN &amp; window.ks</h4>
527
+ <p class="text-xs text-slate-400 max-w-2xl leading-relaxed">
528
+ Beginner-friendly walkthrough explaining step-by-step how to render tables using CDN imports vs the global
529
+ <code class="text-indigo-300 font-mono">window.ks</code> namespace, complete with live playground and
530
+ side-by-side comparison.
531
+ </p>
532
+ </div>
533
+ <a href="table/index.html"
534
+ class="px-4 py-2 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white font-semibold text-xs transition whitespace-nowrap shadow-md shadow-indigo-600/30 flex items-center gap-1.5">
535
+ <span>📖</span> Open Table Guide &rarr;
536
+ </a>
537
+ </div>
538
+
539
+ <!-- Spotlight Banner for Select Guide -->
540
+ <div
541
+ class="glass-panel p-5 rounded-2xl border border-cyan-500/30 bg-gradient-to-r from-cyan-950/40 via-slate-900 to-teal-950/40 flex flex-col md:flex-row items-start md:items-center justify-between gap-4">
542
+ <div class="space-y-1">
543
+ <div
544
+ class="inline-flex items-center gap-2 px-2.5 py-0.5 rounded-full bg-cyan-500/20 text-cyan-300 border border-cyan-500/30 text-xs font-mono">
545
+ Select Guide (White BG Edition)
546
+ </div>
547
+ <h4 class="text-base font-bold text-white">How to Create HTML Select Dropdowns with CDN &amp; window.ks</h4>
548
+ <p class="text-xs text-slate-400 max-w-2xl leading-relaxed">
549
+ Complete guide on populating dropdown elements from JSON data using <code class="text-cyan-300 font-mono">byCdn</code> and <code class="text-cyan-300 font-mono">byKs</code> with interactive testing and live selection tracking.
550
+ </p>
551
+ </div>
552
+ <a href="aboutSelect.html"
553
+ class="px-4 py-2 rounded-xl bg-cyan-600 hover:bg-cyan-500 text-white font-semibold text-xs transition whitespace-nowrap shadow-md shadow-cyan-600/30 flex items-center gap-1.5">
554
+ <span>▣</span> Open Select Guide &rarr;
555
+ </a>
556
+ </div>
557
+
558
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
559
+
560
+ <a href="../samples/select/byCdn/index.html"
561
+ class="glass-panel p-5 rounded-2xl group hover:border-cyan-500/50 transition flex flex-col justify-between">
562
+ <div>
563
+ <div class="flex items-center justify-between mb-3">
564
+ <span class="text-xl">⚡</span>
565
+ <span class="text-xs text-cyan-400 font-mono group-hover:translate-x-1 transition">Open Demo &rarr;</span>
566
+ </div>
567
+ <h4 class="text-base font-bold text-white mb-1 group-hover:text-cyan-300 transition">Select via CDN (byCdn)</h4>
568
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
569
+ Mounts select dropdown via direct ES module import from jsDelivr CDN (<code class="text-cyan-300 font-mono">samples/select/byCdn</code>).
570
+ </p>
571
+ </div>
572
+ <div class="text-[11px] font-mono text-slate-500">samples/select/byCdn/index.html</div>
573
+ </a>
574
+
575
+ <a href="../samples/select/byKs/index.html"
576
+ class="glass-panel p-5 rounded-2xl group hover:border-indigo-500/50 transition flex flex-col justify-between">
577
+ <div>
578
+ <div class="flex items-center justify-between mb-3">
579
+ <span class="text-xl">🌐</span>
580
+ <span class="text-xs text-indigo-400 font-mono group-hover:translate-x-1 transition">Open Demo &rarr;</span>
581
+ </div>
582
+ <h4 class="text-base font-bold text-white mb-1 group-hover:text-indigo-300 transition">Select via window.ks (byKs)</h4>
583
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
584
+ Mounts select dropdown using the global namespace (<code class="text-indigo-300 font-mono">samples/select/byKs</code>).
585
+ </p>
586
+ </div>
587
+ <div class="text-[11px] font-mono text-slate-500">samples/select/byKs/index.html</div>
588
+ </a>
589
+
590
+ <a href="aboutSelect.html"
591
+ class="glass-panel p-5 rounded-2xl group hover:border-cyan-500/50 transition flex flex-col justify-between border-dashed border-cyan-500/40">
592
+ <div>
593
+ <div class="flex items-center justify-between mb-3">
594
+ <span class="text-xl">▣</span>
595
+ <span class="text-xs text-cyan-400 font-mono group-hover:translate-x-1 transition">Read Guide &rarr;</span>
596
+ </div>
597
+ <h4 class="text-base font-bold text-white mb-1 group-hover:text-cyan-300 transition">About Select Guide</h4>
598
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
599
+ Complete beginner documentation with white background and suitable font colors.
600
+ </p>
601
+ </div>
602
+ <div class="text-[11px] font-mono text-cyan-400/80">docs/aboutSelect.html</div>
603
+ </a>
604
+
605
+ <a href="../samples/table/byCdn/index.html"
606
+ class="glass-panel p-5 rounded-2xl group hover:border-emerald-500/50 transition flex flex-col justify-between">
607
+ <div>
608
+ <div class="flex items-center justify-between mb-3">
609
+ <span class="text-xl">⚡</span>
610
+ <span class="text-xs text-emerald-400 font-mono group-hover:translate-x-1 transition">Open Demo
611
+ &rarr;</span>
612
+ </div>
613
+ <h4 class="text-base font-bold text-white mb-1 group-hover:text-emerald-300 transition">Table via CDN Sample
614
+ </h4>
615
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
616
+ Mounts batches table via direct ES module import from jsDelivr CDN (<code
617
+ class="text-emerald-300 font-mono">import render from "..."</code>).
618
+ </p>
619
+ </div>
620
+ <div class="text-[11px] font-mono text-slate-500">samples/table/byCdn/index.html</div>
621
+ </a>
622
+
623
+ <a href="../samples/table/byKs/index.html"
624
+ class="glass-panel p-5 rounded-2xl group hover:border-indigo-500/50 transition flex flex-col justify-between">
625
+ <div>
626
+ <div class="flex items-center justify-between mb-3">
627
+ <span class="text-xl">🌐</span>
628
+ <span class="text-xs text-indigo-400 font-mono group-hover:translate-x-1 transition">Open Demo
629
+ &rarr;</span>
630
+ </div>
631
+ <h4 class="text-base font-bold text-white mb-1 group-hover:text-indigo-300 transition">Table via window.ks
632
+ Sample</h4>
633
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
634
+ Mounts table using the globally attached namespace (<code
635
+ class="text-indigo-300 font-mono">window.ks.jsonRenderers.renderToDom</code>).
636
+ </p>
637
+ </div>
638
+ <div class="text-[11px] font-mono text-slate-500">samples/table/byKs/index.html</div>
639
+ </a>
640
+
641
+ <a href="table/index.html"
642
+ class="glass-panel p-5 rounded-2xl group hover:border-emerald-500/50 transition flex flex-col justify-between border-dashed border-emerald-500/40">
643
+ <div>
644
+ <div class="flex items-center justify-between mb-3">
645
+ <span class="text-xl">📖</span>
646
+ <span class="text-xs text-emerald-400 font-mono group-hover:translate-x-1 transition">Read Guide
647
+ &rarr;</span>
648
+ </div>
649
+ <h4 class="text-base font-bold text-white mb-1 group-hover:text-emerald-300 transition">Table Process Guide
650
+ </h4>
651
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
652
+ Detailed step-by-step documentation explaining table creation for beginners.
653
+ </p>
654
+ </div>
655
+ <div class="text-[11px] font-mono text-emerald-400/80">docs/table/index.html</div>
656
+ </a>
657
+
658
+ </div>
659
+ </section>
660
+
661
+ <!-- Quick CDN & Installation Code -->
662
+ <section class="glass-panel p-6 rounded-2xl space-y-4">
663
+ <h3 class="text-sm font-bold text-white uppercase tracking-wider font-mono flex items-center gap-2">
664
+ <span>📦</span> Installation & Distribution
665
+ </h3>
666
+
667
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
668
+ <div>
669
+ <label class="text-xs text-slate-400 mb-1 block font-mono">NPM Package:</label>
670
+ <pre
671
+ class="p-3 bg-slate-950 rounded-xl text-xs text-emerald-300 font-mono border border-slate-800 overflow-x-auto"><code>npm install json-renderers</code></pre>
672
+ </div>
673
+
674
+ <div>
675
+ <label class="text-xs text-slate-400 mb-1 block font-mono">ES Module CDN:</label>
676
+ <pre
677
+ class="p-3 bg-slate-950 rounded-xl text-xs text-emerald-300 font-mono border border-slate-800 overflow-x-auto"><code>import render from "https://cdn.jsdelivr.net/gh/keshavsoft/json-renderers@main/docs/dist/v13/min.js";</code></pre>
678
+ </div>
679
+ </div>
680
+ </section>
681
+
682
+ </main>
683
+
684
+ <!-- Footer -->
685
+ <footer class="border-t border-slate-900 bg-slate-950 py-6 text-center text-xs text-slate-500">
686
+ <div class="max-w-7xl mx-auto px-4 flex flex-col sm:flex-row items-center justify-between gap-3">
687
+ <div>
688
+ <strong class="text-slate-400">json-renderers</strong> &bull; KeshavSoft &bull; MIT License
689
+ </div>
690
+ <div class="flex items-center gap-4 text-slate-400">
691
+ <a href="https://github.com/keshavsoft/json-renderers" class="hover:text-white transition">json-renderers</a>
692
+ <a href="https://github.com/keshavsoft/json-renderers-build"
693
+ class="hover:text-white transition">json-renderers-build</a>
694
+ <a href="https://github.com/keshavsoft/json-to-spec" class="hover:text-white transition">json-to-spec</a>
695
+ </div>
696
+ </div>
697
+ </footer>
698
+
699
+ <!-- Workbench Script importing docs/dist/v13/min.js -->
700
+ <script type="module">
701
+ import render from "./dist/v13/min.js";
702
+
703
+ // Presets catalog
704
+ const PRESETS = {
705
+ table: {
706
+ batches: {
707
+ data: [
708
+ { id: "B-101", name: "Aluminium Rods 25mm", qty: 450, status: "Verified" },
709
+ { id: "B-102", name: "Copper Sheets 1.2mm", qty: 280, status: "In Transit" },
710
+ { id: "B-103", name: "Steel Fasteners M8", qty: 1200, status: "Verified" }
711
+ ],
712
+ columns: [{ title: "Batch ID" }, { title: "Item Name" }, { title: "Quantity" }, { title: "Status" }]
713
+ },
714
+ employees: {
715
+ data: [
716
+ { empId: "EMP-01", name: "Sarah Connor", role: "Security Architect", city: "London" },
717
+ { empId: "EMP-02", name: "John Miller", role: "DevOps Engineer", city: "Berlin" },
718
+ { empId: "EMP-03", name: "Anita Rao", role: "Lead Developer", city: "Bengaluru" }
719
+ ],
720
+ columns: ["Emp ID", "Employee Name", "Designation", "Base Location"]
721
+ },
722
+ ledgers: {
723
+ data: [
724
+ { code: "A-001", account: "State Bank of India", balance: 540000 },
725
+ { code: "A-002", account: "HDFC Operating", balance: 1250000 }
726
+ ],
727
+ columns: [{ title: "Code" }, { title: "Account Name" }, { title: "Balance (INR)" }]
728
+ }
729
+ },
730
+ select: {
731
+ ledgers: {
732
+ data: ["Cash In Hand", "State Bank of India", "Accounts Receivable", "General Reserves", "Sales Account"]
733
+ },
734
+ batches: {
735
+ data: ["Batch 2026-A1", "Batch 2026-A2", "Batch 2026-B1"]
736
+ },
737
+ employees: {
738
+ data: ["Bangalore HQ", "Hyderabad Campus", "Singapore Branch"]
739
+ }
740
+ },
741
+ selectOptionsOnly: {
742
+ ledgers: {
743
+ data: ["Deluxe Suite", "Executive Premier", "Presidential Villa"]
744
+ },
745
+ batches: {
746
+ data: ["High Priority", "Medium Priority", "Low Priority"]
747
+ },
748
+ employees: {
749
+ data: ["Finance", "Human Resources", "Engineering", "Marketing"]
750
+ }
751
+ }
752
+ };
753
+
754
+ // DOM references
755
+ const typeSelect = document.getElementById("component-type");
756
+ const presetSelect = document.getElementById("preset-selector");
757
+ const inputDataEl = document.getElementById("input-data");
758
+ const inputColumnsEl = document.getElementById("input-columns");
759
+ const columnsPanel = document.getElementById("columns-panel");
760
+ const btnRenderDom = document.getElementById("btn-render-dom");
761
+ const btnFormatData = document.getElementById("btn-format-data");
762
+ const btnFormatColumns = document.getElementById("btn-format-columns");
763
+ const liveMountContainer = document.getElementById("live-mount-container");
764
+ const codeOutputAst = document.getElementById("code-output-ast");
765
+ const mountStatusBadge = document.getElementById("mount-status-badge");
766
+ const btnCopyAst = document.getElementById("btn-copy-ast");
767
+
768
+ // Tabs
769
+ const tabDom = document.getElementById("tab-dom");
770
+ const tabInBetween = document.getElementById("tab-in-between");
771
+ const viewDom = document.getElementById("view-dom");
772
+ const viewInBetween = document.getElementById("view-in-between");
773
+
774
+ let currentAstOutput = null;
775
+
776
+ function switchTab(activeTab) {
777
+ if (activeTab === "dom") {
778
+ tabDom.className = "px-3 py-1.5 text-xs font-semibold rounded-lg bg-emerald-600 text-white transition flex items-center gap-1.5";
779
+ tabInBetween.className = "px-3 py-1.5 text-xs font-semibold rounded-lg text-slate-400 hover:text-white transition flex items-center gap-1.5";
780
+ viewDom.classList.remove("hidden");
781
+ viewInBetween.classList.add("hidden");
782
+ } else {
783
+ tabDom.className = "px-3 py-1.5 text-xs font-semibold rounded-lg text-slate-400 hover:text-white transition flex items-center gap-1.5";
784
+ tabInBetween.className = "px-3 py-1.5 text-xs font-semibold rounded-lg bg-indigo-600 text-white transition flex items-center gap-1.5";
785
+ viewDom.classList.add("hidden");
786
+ viewInBetween.classList.remove("hidden");
787
+ }
788
+ }
789
+
790
+ tabDom.addEventListener("click", () => switchTab("dom"));
791
+ tabInBetween.addEventListener("click", () => switchTab("in-between"));
792
+
793
+ function syncTypeUI() {
794
+ const type = typeSelect.value;
795
+ if (type === "table") {
796
+ columnsPanel.classList.remove("hidden");
797
+ } else {
798
+ columnsPanel.classList.add("hidden");
799
+ }
800
+ loadPreset();
801
+ }
802
+
803
+ function loadPreset() {
804
+ const type = typeSelect.value;
805
+ const presetKey = presetSelect.value;
806
+ const typePresets = PRESETS[type] || {};
807
+ const preset = typePresets[presetKey] || typePresets[Object.keys(typePresets)[0]];
808
+
809
+ if (preset) {
810
+ inputDataEl.value = JSON.stringify(preset.data, null, 2);
811
+ if (preset.columns) {
812
+ inputColumnsEl.value = JSON.stringify(preset.columns, null, 2);
813
+ } else {
814
+ inputColumnsEl.value = "[]";
815
+ }
816
+ }
817
+
818
+ mountToDom();
819
+ }
820
+
821
+ // Mount to DOM execution
822
+ function mountToDom() {
823
+ try {
824
+ const type = typeSelect.value;
825
+ const rawData = JSON.parse(inputDataEl.value || "[]");
826
+ let rawColumns = undefined;
827
+
828
+ if (type === "table") {
829
+ try {
830
+ rawColumns = JSON.parse(inputColumnsEl.value || "[]");
831
+ } catch (e) {
832
+ rawColumns = [];
833
+ }
834
+ }
835
+
836
+ let targetId = "live-mount-container";
837
+
838
+ // Setup host if selectOptionsOnly needs an existing <select>
839
+ if (type === "selectOptionsOnly") {
840
+ liveMountContainer.innerHTML = `
841
+ <div class="p-3 bg-slate-950 rounded-lg max-w-sm border border-slate-800">
842
+ <label for="demo-existing-select" class="block text-xs font-mono text-slate-400 mb-1.5">Pre-existing Dropdown Target:</label>
843
+ <select id="demo-existing-select" class="form-select bg-slate-900 text-white border-slate-700"></select>
844
+ </div>
845
+ `;
846
+ targetId = "demo-existing-select";
847
+ } else {
848
+ liveMountContainer.innerHTML = "";
849
+ }
850
+
851
+ // Call the real json-renderers function!
852
+ const result = render({
853
+ type,
854
+ targetHtmlId: targetId,
855
+ data: rawData,
856
+ columns: rawColumns
857
+ });
858
+
859
+ // If table, wrap in clean white bootstrap card for readability
860
+ if (type === "table") {
861
+ const table = liveMountContainer.querySelector("table");
862
+ if (table) {
863
+ table.classList.add("bg-white", "text-dark", "rounded");
864
+ }
865
+ } else if (type === "select") {
866
+ const sel = liveMountContainer.querySelector("select");
867
+ if (sel) {
868
+ sel.className = "form-select bg-slate-950 text-white border-slate-700 max-w-sm";
869
+ }
870
+ }
871
+
872
+ mountStatusBadge.textContent = `Mounted (${type})`;
873
+ mountStatusBadge.className = "px-2 py-0.5 text-[11px] bg-emerald-500/20 text-emerald-300 rounded font-mono border border-emerald-500/30";
874
+
875
+ // Also compute the "in-between" spec AST for inspection tab
876
+ if (window.ks?.jsonRenderersBuild?.renderToDom) {
877
+ const ast = window.ks.jsonRenderersBuild.renderToDom({
878
+ type,
879
+ data: rawData,
880
+ columns: rawColumns
881
+ });
882
+ currentAstOutput = ast;
883
+ codeOutputAst.textContent = JSON.stringify(ast, null, 2);
884
+ } else {
885
+ codeOutputAst.textContent = "// json-renderers-build AST rendered into DOM successfully";
886
+ }
887
+
888
+ } catch (err) {
889
+ console.error("Mount error:", err);
890
+ liveMountContainer.innerHTML = `<div class="alert alert-danger font-mono text-xs m-2">${err.message}</div>`;
891
+ mountStatusBadge.textContent = "Error";
892
+ mountStatusBadge.className = "px-2 py-0.5 text-[11px] bg-rose-500/20 text-rose-300 rounded font-mono border border-rose-500/30";
893
+ }
894
+ }
895
+
896
+ // Event listeners
897
+ typeSelect.addEventListener("change", syncTypeUI);
898
+ presetSelect.addEventListener("change", loadPreset);
899
+ btnRenderDom.addEventListener("click", mountToDom);
900
+
901
+ btnFormatData.addEventListener("click", () => {
902
+ try {
903
+ inputDataEl.value = JSON.stringify(JSON.parse(inputDataEl.value), null, 2);
904
+ } catch (e) { }
905
+ });
906
+
907
+ btnFormatColumns.addEventListener("click", () => {
908
+ try {
909
+ inputColumnsEl.value = JSON.stringify(JSON.parse(inputColumnsEl.value), null, 2);
910
+ } catch (e) { }
911
+ });
912
+
913
+ btnCopyAst.addEventListener("click", () => {
914
+ if (currentAstOutput) {
915
+ navigator.clipboard.writeText(JSON.stringify(currentAstOutput, null, 2));
916
+ btnCopyAst.textContent = "Copied!";
917
+ setTimeout(() => { btnCopyAst.textContent = "Copy AST"; }, 1500);
918
+ }
919
+ });
920
+
921
+ // Auto-update on typing with debounce
922
+ let debounceTimer;
923
+ [inputDataEl, inputColumnsEl].forEach(el => {
924
+ el.addEventListener("input", () => {
925
+ clearTimeout(debounceTimer);
926
+ debounceTimer = setTimeout(mountToDom, 350);
927
+ });
928
+ });
929
+
930
+ // Initial setup
931
+ syncTypeUI();
932
+ </script>
933
+ </body>
934
+
680
935
  </html>