json-renderers-build 1.3.6 → 1.5.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.
@@ -0,0 +1,832 @@
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-build | Headless UI Specification Compiler</title>
8
+ <meta name="description" content="Headless component specification compiler for json-renderers, converting structured data and UI skeletons into declarative JSON-to-DOM specs using json-to-spec.">
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-indigo-500 via-purple-600 to-pink-500 flex items-center justify-center font-bold text-white shadow-lg text-lg shadow-indigo-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-build</h1>
81
+ <span id="version-badge" class="px-2 py-0.5 text-xs bg-indigo-500/20 text-indigo-300 rounded-full border border-indigo-500/30 font-mono">v3.0.0</span>
82
+ </div>
83
+ <p class="text-xs text-slate-400">Headless UI Specification Compiler</p>
84
+ </div>
85
+ </div>
86
+
87
+ <div class="flex items-center gap-2.5">
88
+ <a href="#playground" 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">
89
+ <span>⚡</span> Live Playground
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-build" 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-indigo-500/10 border border-indigo-500/20 text-xs text-indigo-300 font-mono">
107
+ <span class="w-2 h-2 rounded-full bg-emerald-400 animate-pulse"></span>
108
+ Ecosystem Story: Spec Compiler Layer
109
+ </div>
110
+ <h2 class="text-3xl sm:text-5xl font-extrabold text-white tracking-tight leading-tight">
111
+ Build Declarative UI Specifications <br class="hidden sm:inline" />
112
+ <span class="text-transparent bg-clip-text bg-gradient-to-r from-indigo-400 via-purple-300 to-pink-400">Headless, Pure, and Config-Driven</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-build</strong> transforms raw data arrays and column definitions into comprehensive DOM specification ASTs (<code class="text-indigo-300 font-mono">specAsJsonToDom</code>). It decouples UI structure generation from DOM rendering, letting downstream runtimes like <code class="text-indigo-300 font-mono">json-renderers</code> handle the DOM mounting.
116
+ </p>
117
+
118
+ <div class="flex flex-wrap items-center justify-center gap-3 pt-2">
119
+ <a href="#playground" class="px-5 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-500 text-white font-semibold text-xs sm:text-sm transition flex items-center gap-2 shadow-lg shadow-indigo-600/25">
120
+ <span>⚡</span> Try Live Spec Compiler
121
+ </a>
122
+ <a href="#architecture" 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> Architecture & The Story
124
+ </a>
125
+ </div>
126
+ </section>
127
+
128
+ <!-- Architecture & The Story Pipeline Section -->
129
+ <section id="architecture" 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-indigo-400">Architecture Overview</span>
133
+ <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">The 3-Tier Declarative Pipeline</h3>
134
+ </div>
135
+ <p class="text-xs text-slate-400 max-w-md">
136
+ Understanding the division of labor between <span class="text-indigo-300">json-to-spec</span>, <strong class="text-white">json-renderers-build (this repo)</strong>, and <span class="text-emerald-300">json-renderers</span>.
137
+ </p>
138
+ </div>
139
+
140
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
141
+ <!-- Tier 1 -->
142
+ <div class="glass-panel p-5 rounded-2xl relative overflow-hidden group hover:border-indigo-500/40 transition">
143
+ <div class="absolute -right-6 -bottom-6 w-24 h-24 bg-indigo-500/5 rounded-full blur-xl pointer-events-none"></div>
144
+ <div class="flex items-center justify-between mb-3">
145
+ <span class="px-2 py-0.5 text-[11px] font-mono rounded bg-slate-800 text-slate-300 border border-slate-700">Tier 1 • Compiler Core</span>
146
+ <span class="text-lg">⚙️</span>
147
+ </div>
148
+ <h4 class="text-base font-bold text-white mb-2">json-to-spec</h4>
149
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
150
+ The low-level template compiler engine. Evaluates operations like <code class="text-indigo-300 font-mono">loopCollection</code>, <code class="text-indigo-300 font-mono">loopObject</code>, and <code class="text-indigo-300 font-mono">loopArray</code> on raw skeleton files.
151
+ </p>
152
+ <div class="p-2.5 rounded-lg bg-slate-950/80 border border-slate-800 text-[11px] font-mono text-slate-400">
153
+ <code>jsonToSpec(skeleton, context)</code>
154
+ </div>
155
+ </div>
156
+
157
+ <!-- Tier 2 (THIS REPO) -->
158
+ <div class="glass-panel p-5 rounded-2xl border-indigo-500/50 shadow-xl shadow-indigo-500/10 relative overflow-hidden bg-slate-900/90">
159
+ <div class="absolute top-0 right-0 bg-indigo-600 text-white text-[10px] uppercase font-bold tracking-wider px-2.5 py-0.5 rounded-bl-lg">
160
+ This Repo
161
+ </div>
162
+ <div class="flex items-center justify-between mb-3">
163
+ <span class="px-2 py-0.5 text-[11px] font-mono rounded bg-indigo-500/20 text-indigo-300 border border-indigo-500/30">Tier 2 • Spec Builder</span>
164
+ <span class="text-lg">📦</span>
165
+ </div>
166
+ <h4 class="text-base font-bold text-indigo-300 mb-2">json-renderers-build</h4>
167
+ <p class="text-xs text-slate-300 leading-relaxed mb-4">
168
+ <strong>Headless UI Spec Builder</strong>. Encapsulates predefined component blueprints (<code class="text-indigo-300 font-mono">table</code>, <code class="text-indigo-300 font-mono">select</code>, <code class="text-indigo-300 font-mono">selectOptionsOnly</code>) and returns pure JSON-to-DOM AST specifications. Zero DOM coupling.
169
+ </p>
170
+ <div class="p-2.5 rounded-lg bg-slate-950/80 border border-indigo-500/30 text-[11px] font-mono text-indigo-200">
171
+ <code>render({ type, data, columns })</code>
172
+ </div>
173
+ </div>
174
+
175
+ <!-- Tier 3 -->
176
+ <div class="glass-panel p-5 rounded-2xl relative overflow-hidden group hover:border-emerald-500/40 transition">
177
+ <div class="flex items-center justify-between mb-3">
178
+ <span class="px-2 py-0.5 text-[11px] font-mono rounded bg-slate-800 text-slate-300 border border-slate-700">Tier 3 • DOM Runtime</span>
179
+ <span class="text-lg">🖥️</span>
180
+ </div>
181
+ <h4 class="text-base font-bold text-white mb-2">json-renderers & json-to-tag</h4>
182
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
183
+ The browser DOM consumer. Ingests the specification AST generated by <code class="text-indigo-300 font-mono">json-renderers-build</code>, instantiates concrete DOM nodes, and mounts into container elements.
184
+ </p>
185
+ <div class="p-2.5 rounded-lg bg-slate-950/80 border border-slate-800 text-[11px] font-mono text-slate-400">
186
+ <code>container.append(jsonToTag(spec))</code>
187
+ </div>
188
+ </div>
189
+ </div>
190
+ </section>
191
+
192
+ <!-- Interactive Live Playground Section -->
193
+ <section id="playground" class="space-y-6">
194
+ <div class="flex flex-col md:flex-row md:items-end justify-between gap-4 border-b border-slate-800/80 pb-4">
195
+ <div>
196
+ <span class="text-xs uppercase font-mono tracking-wider text-indigo-400">Live Workbench</span>
197
+ <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">Interactive Specification Compiler</h3>
198
+ </div>
199
+ <div class="flex items-center gap-3">
200
+ <label for="component-type" class="text-xs text-slate-400 font-medium">Component Type:</label>
201
+ <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-indigo-500 focus:outline-none">
202
+ <option value="table" selected>table</option>
203
+ <option value="select">select</option>
204
+ <option value="selectOptionsOnly">selectOptionsOnly</option>
205
+ </select>
206
+ <button id="btn-compile" class="px-3 py-1.5 bg-indigo-600 hover:bg-indigo-500 text-white rounded-lg text-xs font-semibold shadow-sm transition flex items-center gap-1">
207
+ <span>▶</span> Compile
208
+ </button>
209
+ </div>
210
+ </div>
211
+
212
+ <div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
213
+
214
+ <!-- Left Column: Inputs (5 Cols) -->
215
+ <div class="lg:col-span-5 space-y-4">
216
+ <div class="glass-panel p-4 rounded-2xl space-y-3">
217
+ <div class="flex items-center justify-between">
218
+ <span class="text-xs font-bold text-white uppercase tracking-wider font-mono flex items-center gap-1.5">
219
+ <span>📝</span> Input Data (JSON)
220
+ </span>
221
+ <div class="flex items-center gap-2">
222
+ <select id="preset-selector" class="bg-slate-800 border border-slate-700 text-[11px] rounded px-2 py-1 text-slate-300 font-mono">
223
+ <option value="batches">Preset: Batches</option>
224
+ <option value="employees">Preset: Employees</option>
225
+ <option value="ledgers">Preset: Ledgers (Strings)</option>
226
+ </select>
227
+ <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>
228
+ </div>
229
+ </div>
230
+ <textarea id="input-data" rows="8" class="w-full bg-slate-950 text-indigo-200 border border-slate-800 rounded-xl p-3 font-mono text-xs focus:ring-2 focus:ring-indigo-500 focus:outline-none custom-scrollbar" spellcheck="false"></textarea>
231
+ </div>
232
+
233
+ <div id="columns-panel" class="glass-panel p-4 rounded-2xl space-y-3">
234
+ <div class="flex items-center justify-between">
235
+ <span class="text-xs font-bold text-white uppercase tracking-wider font-mono flex items-center gap-1.5">
236
+ <span>📊</span> Columns (for table)
237
+ </span>
238
+ <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>
239
+ </div>
240
+ <textarea id="input-columns" rows="5" class="w-full bg-slate-950 text-indigo-200 border border-slate-800 rounded-xl p-3 font-mono text-xs focus:ring-2 focus:ring-indigo-500 focus:outline-none custom-scrollbar" spellcheck="false"></textarea>
241
+ </div>
242
+
243
+ <div class="p-3.5 rounded-xl bg-slate-900/60 border border-slate-800/80 text-xs text-slate-400 space-y-1">
244
+ <div class="flex items-center gap-1.5 text-indigo-400 font-semibold font-mono">
245
+ <span>💡</span> Headless Execution
246
+ </div>
247
+ <p>
248
+ The compiler runs purely in memory via <code class="text-indigo-300 font-mono">render({ type, data, columns })</code>. No DOM nodes are created during this stage.
249
+ </p>
250
+ </div>
251
+ </div>
252
+
253
+ <!-- Right Column: Outputs (7 Cols) -->
254
+ <div class="lg:col-span-7 flex flex-col space-y-3">
255
+ <!-- Output Tabs Header -->
256
+ <div class="flex items-center justify-between bg-slate-900/80 p-1.5 rounded-xl border border-slate-800">
257
+ <div class="flex items-center gap-1">
258
+ <button id="tab-spec" class="px-3 py-1.5 text-xs font-semibold rounded-lg bg-indigo-600 text-white transition flex items-center gap-1.5">
259
+ <span>📄</span> Compiled Spec AST
260
+ </button>
261
+ <button id="tab-skeleton" 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">
262
+ <span>📐</span> Skeleton Blueprint
263
+ </button>
264
+ <button id="tab-preview" 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">
265
+ <span>👁️</span> Visual DOM Preview
266
+ </button>
267
+ </div>
268
+
269
+ <div class="flex items-center gap-2 pr-1">
270
+ <button id="btn-copy-spec" class="px-2.5 py-1 text-[11px] bg-slate-800 hover:bg-slate-700 text-slate-300 rounded font-mono transition flex items-center gap-1">
271
+ <span>📋</span> Copy
272
+ </button>
273
+ <button id="btn-download-spec" class="px-2.5 py-1 text-[11px] bg-slate-800 hover:bg-slate-700 text-slate-300 rounded font-mono transition flex items-center gap-1">
274
+ <span>💾</span> Download
275
+ </button>
276
+ </div>
277
+ </div>
278
+
279
+ <!-- View 1: Compiled Spec AST -->
280
+ <div id="view-spec" class="glass-panel p-4 rounded-2xl flex-1 flex flex-col min-h-[460px]">
281
+ <div class="flex items-center justify-between pb-2 border-b border-slate-800/80 mb-3 text-xs text-slate-400">
282
+ <span class="font-mono text-emerald-400 flex items-center gap-1.5">
283
+ <span class="w-2 h-2 rounded-full bg-emerald-400"></span> specAsJsonToDom output
284
+ </span>
285
+ <span id="output-meta-stats" class="font-mono text-[11px]">0 nodes generated</span>
286
+ </div>
287
+ <pre class="flex-1 m-0 p-3 bg-slate-950 rounded-xl text-emerald-300 font-mono text-xs overflow-auto custom-scrollbar leading-relaxed max-h-[500px]"><code id="code-output-spec">// Click Compile to generate spec</code></pre>
288
+ </div>
289
+
290
+ <!-- View 2: Skeleton Blueprint -->
291
+ <div id="view-skeleton" class="glass-panel p-4 rounded-2xl flex-1 flex flex-col min-h-[460px] hidden">
292
+ <div class="flex items-center justify-between pb-2 border-b border-slate-800/80 mb-3 text-xs text-slate-400">
293
+ <span class="font-mono text-indigo-400 flex items-center gap-1.5">
294
+ <span>📐</span> Predefined skeleton.json
295
+ </span>
296
+ <span class="font-mono text-[11px]">Template directive source</span>
297
+ </div>
298
+ <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-skeleton">// Loading skeleton...</code></pre>
299
+ </div>
300
+
301
+ <!-- View 3: Visual DOM Preview -->
302
+ <div id="view-preview" class="glass-panel p-4 rounded-2xl flex-1 flex flex-col min-h-[460px] hidden">
303
+ <div class="flex items-center justify-between pb-2 border-b border-slate-800/80 mb-3 text-xs text-slate-400">
304
+ <span class="font-mono text-pink-400 flex items-center gap-1.5">
305
+ <span>👁️</span> Rendered Preview (Downstream Result)
306
+ </span>
307
+ <span class="font-mono text-[11px]">How it mounts in the browser</span>
308
+ </div>
309
+ <div id="dom-preview-container" class="flex-1 p-4 bg-slate-900/60 rounded-xl border border-slate-800 overflow-auto custom-scrollbar">
310
+ <!-- DOM elements rendered dynamically here -->
311
+ </div>
312
+ </div>
313
+
314
+ </div>
315
+
316
+ </div>
317
+ </section>
318
+
319
+ <!-- Component Skeletons Reference Section -->
320
+ <section class="space-y-6">
321
+ <div class="border-b border-slate-800/80 pb-4">
322
+ <span class="text-xs uppercase font-mono tracking-wider text-indigo-400">Component Blueprints</span>
323
+ <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">Available Skeletons in v3</h3>
324
+ </div>
325
+
326
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
327
+
328
+ <!-- Table Card -->
329
+ <div class="glass-card p-5 rounded-2xl space-y-3">
330
+ <div class="flex items-center justify-between">
331
+ <span class="text-xs font-mono font-bold text-white uppercase tracking-wider">type: "table"</span>
332
+ <span class="px-2 py-0.5 rounded bg-indigo-500/20 text-indigo-300 text-[11px] font-mono">Full Grid</span>
333
+ </div>
334
+ <p class="text-xs text-slate-400 leading-relaxed">
335
+ Constructs complete Bootstrap-ready data tables with <code class="text-indigo-300">&lt;table class="table table-hover table-striped mb-0"&gt;</code>, repeating headers from <code class="text-indigo-300 font-mono">columns</code>, and row values from <code class="text-indigo-300 font-mono">data</code>.
336
+ </p>
337
+ <div class="text-[11px] font-mono text-slate-400 bg-slate-950 p-2.5 rounded-lg border border-slate-800">
338
+ <div class="text-slate-500">// Calling signature</div>
339
+ render({ type: "table", data, columns })
340
+ </div>
341
+ </div>
342
+
343
+ <!-- Select Card -->
344
+ <div class="glass-card p-5 rounded-2xl space-y-3">
345
+ <div class="flex items-center justify-between">
346
+ <span class="text-xs font-mono font-bold text-white uppercase tracking-wider">type: "select"</span>
347
+ <span class="px-2 py-0.5 rounded bg-purple-500/20 text-purple-300 text-[11px] font-mono">Dropdown</span>
348
+ </div>
349
+ <p class="text-xs text-slate-400 leading-relaxed">
350
+ Constructs a complete <code class="text-purple-300">&lt;select id="LedgerName"&gt;</code> containing an array of <code class="text-purple-300">&lt;option value="..."&gt;</code> elements from a primitive array of strings.
351
+ </p>
352
+ <div class="text-[11px] font-mono text-slate-400 bg-slate-950 p-2.5 rounded-lg border border-slate-800">
353
+ <div class="text-slate-500">// Calling signature</div>
354
+ render({ type: "select", data: ["A", "B"] })
355
+ </div>
356
+ </div>
357
+
358
+ <!-- Select Options Only Card -->
359
+ <div class="glass-card p-5 rounded-2xl space-y-3">
360
+ <div class="flex items-center justify-between">
361
+ <span class="text-xs font-mono font-bold text-white uppercase tracking-wider">type: "selectOptionsOnly"</span>
362
+ <span class="px-2 py-0.5 rounded bg-emerald-500/20 text-emerald-300 text-[11px] font-mono">Fragment</span>
363
+ </div>
364
+ <p class="text-xs text-slate-400 leading-relaxed">
365
+ Generates an un-wrapped fragment spec containing only the array of <code class="text-emerald-300">&lt;option&gt;</code> nodes, tailored for appending into existing select inputs.
366
+ </p>
367
+ <div class="text-[11px] font-mono text-slate-400 bg-slate-950 p-2.5 rounded-lg border border-slate-800">
368
+ <div class="text-slate-500">// Calling signature</div>
369
+ render({ type: "selectOptionsOnly", data: ["A", "B"] })
370
+ </div>
371
+ </div>
372
+
373
+ </div>
374
+ </section>
375
+
376
+ <!-- Runnable Samples Section -->
377
+ <section id="samples" class="space-y-6">
378
+ <div class="border-b border-slate-800/80 pb-4">
379
+ <span class="text-xs uppercase font-mono tracking-wider text-indigo-400">Browser Demos</span>
380
+ <h3 class="text-xl sm:text-2xl font-bold text-white tracking-tight">Included Verification Samples</h3>
381
+ </div>
382
+
383
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
384
+
385
+ <a href="../samples/table/index.html" class="glass-panel p-5 rounded-2xl group hover:border-indigo-500/50 transition flex flex-col justify-between">
386
+ <div>
387
+ <div class="flex items-center justify-between mb-3">
388
+ <span class="text-xl">📊</span>
389
+ <span class="text-xs text-indigo-400 font-mono group-hover:translate-x-1 transition">Open Demo &rarr;</span>
390
+ </div>
391
+ <h4 class="text-base font-bold text-white mb-1 group-hover:text-indigo-300 transition">Table Spec Demo</h4>
392
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
393
+ Demonstrates table specification generation using real multi-column batch data.
394
+ </p>
395
+ </div>
396
+ <div class="text-[11px] font-mono text-slate-500">samples/table/index.html</div>
397
+ </a>
398
+
399
+ <a href="../samples/select/index.html" class="glass-panel p-5 rounded-2xl group hover:border-purple-500/50 transition flex flex-col justify-between">
400
+ <div>
401
+ <div class="flex items-center justify-between mb-3">
402
+ <span class="text-xl">🔽</span>
403
+ <span class="text-xs text-purple-400 font-mono group-hover:translate-x-1 transition">Open Demo &rarr;</span>
404
+ </div>
405
+ <h4 class="text-base font-bold text-white mb-1 group-hover:text-purple-300 transition">Select Spec Demo</h4>
406
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
407
+ Demonstrates complete select dropdown specification generation from string arrays.
408
+ </p>
409
+ </div>
410
+ <div class="text-[11px] font-mono text-slate-500">samples/select/index.html</div>
411
+ </a>
412
+
413
+ <a href="../samples/selectOptionsOnly/index.html" class="glass-panel p-5 rounded-2xl group hover:border-emerald-500/50 transition flex flex-col justify-between">
414
+ <div>
415
+ <div class="flex items-center justify-between mb-3">
416
+ <span class="text-xl">📑</span>
417
+ <span class="text-xs text-emerald-400 font-mono group-hover:translate-x-1 transition">Open Demo &rarr;</span>
418
+ </div>
419
+ <h4 class="text-base font-bold text-white mb-1 group-hover:text-emerald-300 transition">Options Fragment Demo</h4>
420
+ <p class="text-xs text-slate-400 leading-relaxed mb-4">
421
+ Demonstrates option fragment generation for populating existing dropdown elements.
422
+ </p>
423
+ </div>
424
+ <div class="text-[11px] font-mono text-slate-500">samples/selectOptionsOnly/index.html</div>
425
+ </a>
426
+
427
+ </div>
428
+ </section>
429
+
430
+ <!-- Quick CDN & Installation Code -->
431
+ <section class="glass-panel p-6 rounded-2xl space-y-4">
432
+ <h3 class="text-sm font-bold text-white uppercase tracking-wider font-mono flex items-center gap-2">
433
+ <span>📦</span> Installation & Distribution
434
+ </h3>
435
+
436
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
437
+ <div>
438
+ <label class="text-xs text-slate-400 mb-1 block font-mono">NPM Package:</label>
439
+ <pre class="p-3 bg-slate-950 rounded-xl text-xs text-indigo-300 font-mono border border-slate-800 overflow-x-auto"><code>npm install json-renderers-build</code></pre>
440
+ </div>
441
+
442
+ <div>
443
+ <label class="text-xs text-slate-400 mb-1 block font-mono">ES Module CDN:</label>
444
+ <pre class="p-3 bg-slate-950 rounded-xl text-xs text-indigo-300 font-mono border border-slate-800 overflow-x-auto"><code>import render from "https://cdn.jsdelivr.net/gh/keshavsoft/json-renderers-build@main/docs/dist/v3/min.js";</code></pre>
445
+ </div>
446
+ </div>
447
+ </section>
448
+
449
+ </main>
450
+
451
+ <!-- Footer -->
452
+ <footer class="border-t border-slate-900 bg-slate-950 py-6 text-center text-xs text-slate-500">
453
+ <div class="max-w-7xl mx-auto px-4 flex flex-col sm:flex-row items-center justify-between gap-3">
454
+ <div>
455
+ <strong class="text-slate-400">json-renderers-build</strong> &bull; KeshavSoft &bull; MIT License
456
+ </div>
457
+ <div class="flex items-center gap-4 text-slate-400">
458
+ <a href="https://github.com/keshavsoft/json-renderers-build" class="hover:text-white transition">GitHub Repository</a>
459
+ <a href="https://github.com/keshavsoft/json-to-spec" class="hover:text-white transition">json-to-spec</a>
460
+ <a href="https://github.com/keshavsoft/json-renderers" class="hover:text-white transition">json-renderers</a>
461
+ </div>
462
+ </div>
463
+ </footer>
464
+
465
+ <!-- Playground Script importing docs/dist/v3/min.js -->
466
+ <script type="module">
467
+ import render from "./dist/v3/min.js";
468
+
469
+ // Presets catalog
470
+ const PRESETS = {
471
+ table: {
472
+ batches: {
473
+ data: [
474
+ { id: "B-101", name: "Aluminium Rods 25mm", qty: 450, status: "Verified" },
475
+ { id: "B-102", name: "Copper Sheets 1.2mm", qty: 280, status: "In Transit" },
476
+ { id: "B-103", name: "Steel Fasteners M8", qty: 1200, status: "Verified" }
477
+ ],
478
+ columns: [{ title: "Batch ID" }, { title: "Item Name" }, { title: "Quantity" }, { title: "Status" }]
479
+ },
480
+ employees: {
481
+ data: [
482
+ { empId: "EMP-01", name: "Sarah Connor", role: "Security Architect", city: "London" },
483
+ { empId: "EMP-02", name: "John Miller", role: "DevOps Engineer", city: "Berlin" },
484
+ { empId: "EMP-03", name: "Anita Rao", role: "Lead Developer", city: "Bengaluru" }
485
+ ],
486
+ columns: ["Emp ID", "Employee Name", "Designation", "Base Location"]
487
+ },
488
+ ledgers: {
489
+ data: [
490
+ { code: "A-001", account: "State Bank of India", balance: 540000 },
491
+ { code: "A-002", account: "HDFC Operating", balance: 1250000 }
492
+ ],
493
+ columns: [{ title: "Code" }, { title: "Account Name" }, { title: "Balance (INR)" }]
494
+ }
495
+ },
496
+ select: {
497
+ ledgers: {
498
+ data: ["Cash In Hand", "State Bank of India", "Accounts Receivable", "General Reserves", "Sales Account"]
499
+ },
500
+ batches: {
501
+ data: ["Batch 2026-A1", "Batch 2026-A2", "Batch 2026-B1"]
502
+ },
503
+ employees: {
504
+ data: ["Bangalore HQ", "Hyderabad Campus", "Singapore Branch"]
505
+ }
506
+ },
507
+ selectOptionsOnly: {
508
+ ledgers: {
509
+ data: ["Deluxe Suite", "Executive Premier", "Presidential Villa"]
510
+ },
511
+ batches: {
512
+ data: ["High Priority", "Medium Priority", "Low Priority"]
513
+ },
514
+ employees: {
515
+ data: ["Finance", "Human Resources", "Engineering", "Marketing"]
516
+ }
517
+ }
518
+ };
519
+
520
+ // Skeletons catalog for blueprint display
521
+ const SKELETONS = {
522
+ table: {
523
+ default: {
524
+ tagName: "table",
525
+ attributes: { class: "table table-hover table-striped mb-0" },
526
+ children: [
527
+ {
528
+ tagName: "thead",
529
+ children: [
530
+ {
531
+ tagName: "tr",
532
+ jsonToSpec: {
533
+ operation: "loopCollection",
534
+ source: "columns",
535
+ template: { tagName: "th", textContent: "${title}" }
536
+ },
537
+ children: []
538
+ }
539
+ ]
540
+ },
541
+ {
542
+ tagName: "tbody",
543
+ jsonToSpec: {
544
+ operation: "loopCollection",
545
+ source: "data",
546
+ template: {
547
+ tagName: "tr",
548
+ jsonToSpec: {
549
+ operation: "loopObject",
550
+ source: "data",
551
+ template: { tagName: "td", textContent: "${value}" }
552
+ },
553
+ children: []
554
+ }
555
+ },
556
+ children: []
557
+ }
558
+ ]
559
+ }
560
+ },
561
+ select: {
562
+ tagName: "select",
563
+ attributes: { id: "LedgerName" },
564
+ jsonToSpec: {
565
+ operation: "loopArray",
566
+ source: "arrayOfStrings",
567
+ template: {
568
+ tagName: "option",
569
+ attributes: { value: "${}" },
570
+ textContent: "${}"
571
+ }
572
+ },
573
+ children: []
574
+ },
575
+ selectOptionsOnly: {
576
+ jsonToSpec: {
577
+ operation: "loopArray",
578
+ source: "arrayOfStrings",
579
+ template: {
580
+ tagName: "option",
581
+ attributes: { value: "${}" },
582
+ textContent: "${}"
583
+ }
584
+ },
585
+ children: []
586
+ }
587
+ };
588
+
589
+ // DOM references
590
+ const typeSelect = document.getElementById("component-type");
591
+ const presetSelect = document.getElementById("preset-selector");
592
+ const inputDataEl = document.getElementById("input-data");
593
+ const inputColumnsEl = document.getElementById("input-columns");
594
+ const columnsPanel = document.getElementById("columns-panel");
595
+ const btnCompile = document.getElementById("btn-compile");
596
+ const btnFormatData = document.getElementById("btn-format-data");
597
+ const btnFormatColumns = document.getElementById("btn-format-columns");
598
+ const codeOutputSpec = document.getElementById("code-output-spec");
599
+ const codeOutputSkeleton = document.getElementById("code-output-skeleton");
600
+ const domPreviewContainer = document.getElementById("dom-preview-container");
601
+ const statsEl = document.getElementById("output-meta-stats");
602
+ const btnCopySpec = document.getElementById("btn-copy-spec");
603
+ const btnDownloadSpec = document.getElementById("btn-download-spec");
604
+
605
+ // Tabs
606
+ const tabSpec = document.getElementById("tab-spec");
607
+ const tabSkeleton = document.getElementById("tab-skeleton");
608
+ const tabPreview = document.getElementById("tab-preview");
609
+ const viewSpec = document.getElementById("view-spec");
610
+ const viewSkeleton = document.getElementById("view-skeleton");
611
+ const viewPreview = document.getElementById("view-preview");
612
+
613
+ let currentSpecOutput = null;
614
+
615
+ function switchTab(activeTab) {
616
+ const tabs = [tabSpec, tabSkeleton, tabPreview];
617
+ const views = [viewSpec, viewSkeleton, viewPreview];
618
+
619
+ tabs.forEach(t => {
620
+ t.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";
621
+ });
622
+ views.forEach(v => v.classList.add("hidden"));
623
+
624
+ if (activeTab === "spec") {
625
+ tabSpec.className = "px-3 py-1.5 text-xs font-semibold rounded-lg bg-indigo-600 text-white transition flex items-center gap-1.5";
626
+ viewSpec.classList.remove("hidden");
627
+ } else if (activeTab === "skeleton") {
628
+ tabSkeleton.className = "px-3 py-1.5 text-xs font-semibold rounded-lg bg-indigo-600 text-white transition flex items-center gap-1.5";
629
+ viewSkeleton.classList.remove("hidden");
630
+ } else if (activeTab === "preview") {
631
+ tabPreview.className = "px-3 py-1.5 text-xs font-semibold rounded-lg bg-indigo-600 text-white transition flex items-center gap-1.5";
632
+ viewPreview.classList.remove("hidden");
633
+ }
634
+ }
635
+
636
+ tabSpec.addEventListener("click", () => switchTab("spec"));
637
+ tabSkeleton.addEventListener("click", () => switchTab("skeleton"));
638
+ tabPreview.addEventListener("click", () => switchTab("preview"));
639
+
640
+ // Sync input panel UI based on selected component type
641
+ function syncTypeUI() {
642
+ const type = typeSelect.value;
643
+ if (type === "table") {
644
+ columnsPanel.classList.remove("hidden");
645
+ } else {
646
+ columnsPanel.classList.add("hidden");
647
+ }
648
+
649
+ loadPreset();
650
+ updateSkeletonView();
651
+ }
652
+
653
+ function loadPreset() {
654
+ const type = typeSelect.value;
655
+ const presetKey = presetSelect.value;
656
+ const typePresets = PRESETS[type] || {};
657
+ const preset = typePresets[presetKey] || typePresets[Object.keys(typePresets)[0]];
658
+
659
+ if (preset) {
660
+ inputDataEl.value = JSON.stringify(preset.data, null, 2);
661
+ if (preset.columns) {
662
+ inputColumnsEl.value = JSON.stringify(preset.columns, null, 2);
663
+ } else {
664
+ inputColumnsEl.value = "[]";
665
+ }
666
+ }
667
+
668
+ compileSpec();
669
+ }
670
+
671
+ function updateSkeletonView() {
672
+ const type = typeSelect.value;
673
+ const skel = SKELETONS[type] || {};
674
+ codeOutputSkeleton.textContent = JSON.stringify(skel, null, 2);
675
+ }
676
+
677
+ // Spec compilation function
678
+ function compileSpec() {
679
+ try {
680
+ const type = typeSelect.value;
681
+ const rawData = JSON.parse(inputDataEl.value || "[]");
682
+ let rawColumns = undefined;
683
+
684
+ if (type === "table") {
685
+ try {
686
+ rawColumns = JSON.parse(inputColumnsEl.value || "[]");
687
+ } catch (e) {
688
+ rawColumns = [];
689
+ }
690
+ }
691
+
692
+ const spec = render({
693
+ type,
694
+ data: rawData,
695
+ columns: rawColumns
696
+ });
697
+
698
+ currentSpecOutput = spec;
699
+ codeOutputSpec.textContent = JSON.stringify(spec, null, 2);
700
+
701
+ // Stats
702
+ const nodeCount = JSON.stringify(spec).split('"tagName"').length - 1;
703
+ statsEl.textContent = `${nodeCount || '1+'} tag nodes compiled`;
704
+
705
+ // Update DOM preview
706
+ renderDomPreview(spec, type);
707
+
708
+ } catch (err) {
709
+ console.error("Compilation error:", err);
710
+ codeOutputSpec.textContent = `// Compilation Error:\n${err.message}`;
711
+ statsEl.textContent = "Error";
712
+ }
713
+ }
714
+
715
+ // Simple visual DOM renderer for preview tab
716
+ function renderDomPreview(spec, type) {
717
+ domPreviewContainer.innerHTML = "";
718
+
719
+ if (!spec) {
720
+ domPreviewContainer.innerHTML = `<span class="text-xs text-slate-500 font-mono">No spec available</span>`;
721
+ return;
722
+ }
723
+
724
+ function buildDomNode(nodeSpec) {
725
+ if (!nodeSpec || typeof nodeSpec !== "object") return null;
726
+
727
+ if (nodeSpec.tagName) {
728
+ const el = document.createElement(nodeSpec.tagName);
729
+ if (nodeSpec.attributes) {
730
+ for (const [k, v] of Object.entries(nodeSpec.attributes)) {
731
+ el.setAttribute(k, v);
732
+ }
733
+ }
734
+ if (nodeSpec.textContent != null) {
735
+ el.textContent = nodeSpec.textContent;
736
+ }
737
+ if (Array.isArray(nodeSpec.children)) {
738
+ nodeSpec.children.forEach(child => {
739
+ const childEl = buildDomNode(child);
740
+ if (childEl) el.appendChild(childEl);
741
+ });
742
+ }
743
+ return el;
744
+ }
745
+
746
+ if (Array.isArray(nodeSpec.children)) {
747
+ const frag = document.createDocumentFragment();
748
+ nodeSpec.children.forEach(child => {
749
+ const childEl = buildDomNode(child);
750
+ if (childEl) frag.appendChild(childEl);
751
+ });
752
+ return frag;
753
+ }
754
+
755
+ return null;
756
+ }
757
+
758
+ if (type === "selectOptionsOnly") {
759
+ const selectWrapper = document.createElement("select");
760
+ selectWrapper.className = "form-select bg-slate-950 text-white border-slate-700 w-auto max-w-sm";
761
+ const frag = buildDomNode(spec);
762
+ if (frag) selectWrapper.appendChild(frag);
763
+ domPreviewContainer.appendChild(selectWrapper);
764
+ } else {
765
+ const domTree = buildDomNode(spec);
766
+ if (domTree) {
767
+ if (type === "table") {
768
+ const tableWrap = document.createElement("div");
769
+ tableWrap.className = "table-responsive bg-white rounded-lg p-2 text-dark";
770
+ tableWrap.appendChild(domTree);
771
+ domPreviewContainer.appendChild(tableWrap);
772
+ } else if (type === "select") {
773
+ domTree.className = "form-select bg-slate-950 text-white border-slate-700 w-auto max-w-sm";
774
+ domPreviewContainer.appendChild(domTree);
775
+ } else {
776
+ domPreviewContainer.appendChild(domTree);
777
+ }
778
+ }
779
+ }
780
+ }
781
+
782
+ // Event listeners
783
+ typeSelect.addEventListener("change", syncTypeUI);
784
+ presetSelect.addEventListener("change", loadPreset);
785
+ btnCompile.addEventListener("click", compileSpec);
786
+
787
+ btnFormatData.addEventListener("click", () => {
788
+ try {
789
+ inputDataEl.value = JSON.stringify(JSON.parse(inputDataEl.value), null, 2);
790
+ } catch (e) {}
791
+ });
792
+
793
+ btnFormatColumns.addEventListener("click", () => {
794
+ try {
795
+ inputColumnsEl.value = JSON.stringify(JSON.parse(inputColumnsEl.value), null, 2);
796
+ } catch (e) {}
797
+ });
798
+
799
+ btnCopySpec.addEventListener("click", () => {
800
+ if (currentSpecOutput) {
801
+ navigator.clipboard.writeText(JSON.stringify(currentSpecOutput, null, 2));
802
+ btnCopySpec.textContent = "✓ Copied!";
803
+ setTimeout(() => { btnCopySpec.textContent = "📋 Copy"; }, 1500);
804
+ }
805
+ });
806
+
807
+ btnDownloadSpec.addEventListener("click", () => {
808
+ if (currentSpecOutput) {
809
+ const blob = new Blob([JSON.stringify(currentSpecOutput, null, 2)], { type: "application/json" });
810
+ const url = URL.createObjectURL(blob);
811
+ const a = document.createElement("a");
812
+ a.href = url;
813
+ a.download = `${typeSelect.value}-spec.json`;
814
+ a.click();
815
+ URL.revokeObjectURL(url);
816
+ }
817
+ });
818
+
819
+ // Auto-compile on typing with debounce
820
+ let debounceTimer;
821
+ [inputDataEl, inputColumnsEl].forEach(el => {
822
+ el.addEventListener("input", () => {
823
+ clearTimeout(debounceTimer);
824
+ debounceTimer = setTimeout(compileSpec, 350);
825
+ });
826
+ });
827
+
828
+ // Initial setup
829
+ syncTypeUI();
830
+ </script>
831
+ </body>
832
+ </html>