@jseeio/jsee 0.4.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/LICENSE +21 -0
  3. package/README.md +583 -55
  4. package/dist/2b3e1faf89f94a483539.png +0 -0
  5. package/dist/416d91365b44e4b4f477.png +0 -0
  6. package/dist/8f2c4d11474275fbc161.png +0 -0
  7. package/dist/jsee.core.js +1 -0
  8. package/dist/jsee.full.js +1 -0
  9. package/dist/jsee.runtime.js +2 -1
  10. package/package.json +84 -18
  11. package/src/app.js +130 -33
  12. package/src/cli.js +474 -64
  13. package/src/extended-imports.js +11 -0
  14. package/src/main.js +264 -45
  15. package/src/overlay.js +26 -1
  16. package/src/utils.js +390 -12
  17. package/templates/common-inputs.js +88 -0
  18. package/templates/common-outputs.js +340 -4
  19. package/templates/minimal-app.vue +367 -0
  20. package/templates/minimal-input.vue +573 -0
  21. package/templates/minimal-output.vue +426 -0
  22. package/templates/virtual-table.vue +194 -0
  23. package/.claude/settings.local.json +0 -13
  24. package/.eslintrc.js +0 -38
  25. package/AGENTS.md +0 -65
  26. package/CLAUDE.md +0 -5
  27. package/CNAME +0 -1
  28. package/_config.yml +0 -26
  29. package/dist/jsee.js +0 -1
  30. package/jest-puppeteer.config.js +0 -14
  31. package/jest.config.js +0 -8
  32. package/jest.unit.config.js +0 -8
  33. package/load/index.html +0 -52
  34. package/templates/bulma-app.vue +0 -242
  35. package/templates/bulma-input.vue +0 -125
  36. package/templates/bulma-output.vue +0 -101
  37. package/test/class.html +0 -22
  38. package/test/code.html +0 -25
  39. package/test/codew.html +0 -25
  40. package/test/example-class.js +0 -8
  41. package/test/example-sum.js +0 -3
  42. package/test/fixtures/lodash-like.js +0 -15
  43. package/test/fixtures/upload-sample.csv +0 -3
  44. package/test/importw.html +0 -28
  45. package/test/minimal.html +0 -14
  46. package/test/minimal1.html +0 -13
  47. package/test/minimal2.html +0 -15
  48. package/test/minimal3.html +0 -10
  49. package/test/minimal4.html +0 -22
  50. package/test/pipeline.html +0 -52
  51. package/test/python.html +0 -41
  52. package/test/string.html +0 -26
  53. package/test/stringw.html +0 -29
  54. package/test/sum.schema.json +0 -17
  55. package/test/sumw.schema.json +0 -15
  56. package/test/test-basic.test.js +0 -603
  57. package/test/test-python.test.js +0 -23
  58. package/test/unit/cli-fetch.test.js +0 -229
  59. package/test/unit/utils.test.js +0 -888
  60. package/webpack.config.js +0 -101
@@ -0,0 +1,573 @@
1
+ <style lang="scss" scoped>
2
+ .jsee-field {
3
+ margin-bottom: 6px;
4
+ min-width: 0;
5
+ box-sizing: border-box;
6
+ *, *::before, *::after {
7
+ box-sizing: border-box;
8
+ }
9
+ }
10
+ .jsee-label {
11
+ display: inline-block;
12
+ font-size: 12px;
13
+ color: var(--jsee-text-secondary, #555);
14
+ background: var(--jsee-label-bg, #f2f2f2);
15
+ padding: 1px 6px;
16
+ border-radius: 3px 3px 0 0;
17
+ margin-bottom: -1px;
18
+ }
19
+ .jsee-input, .jsee-textarea, .jsee-select {
20
+ display: block;
21
+ width: 100%;
22
+ max-width: 100%;
23
+ min-width: 0;
24
+ padding: 6px 8px;
25
+ font-size: 13px;
26
+ border: 1px solid var(--jsee-input-border, #ddd);
27
+ border-radius: 0 3px 3px 3px;
28
+ background: var(--jsee-input-bg, #fff);
29
+ color: var(--jsee-text, #333);
30
+ font-family: inherit;
31
+ &:focus {
32
+ outline: none;
33
+ border-color: var(--jsee-focus-border, #7ab8e6);
34
+ box-shadow: 0 0 0 2px var(--jsee-focus-ring, rgba(72, 139, 199, 0.2));
35
+ }
36
+ }
37
+ .jsee-textarea {
38
+ min-height: 60px;
39
+ max-height: 400px;
40
+ resize: vertical;
41
+ overflow-y: auto;
42
+ }
43
+ .jsee-checkbox-label, .jsee-radio-label {
44
+ display: block;
45
+ font-size: 12px;
46
+ cursor: pointer;
47
+ padding: 1px 0;
48
+ }
49
+ .jsee-toggle {
50
+ position: relative;
51
+ display: inline-block;
52
+ width: 36px;
53
+ height: 20px;
54
+ input { opacity: 0; width: 0; height: 0; position: absolute; }
55
+ }
56
+ .jsee-toggle-track {
57
+ position: absolute;
58
+ inset: 0;
59
+ border-radius: 10px;
60
+ background: var(--jsee-input-border, #ccc);
61
+ transition: background 0.2s;
62
+ cursor: pointer;
63
+ &.active { background: var(--jsee-toggle-active, #00d1b2); }
64
+ }
65
+ .jsee-toggle-thumb {
66
+ position: absolute;
67
+ top: 2px;
68
+ left: 2px;
69
+ width: 16px;
70
+ height: 16px;
71
+ border-radius: 50%;
72
+ background: #fff;
73
+ transition: left 0.2s;
74
+ box-shadow: 0 1px 3px rgba(0,0,0,0.3);
75
+ &.active { left: 18px; }
76
+ }
77
+ .jsee-range {
78
+ display: flex;
79
+ align-items: center;
80
+ gap: 8px;
81
+ .jsee-range-value { font-size: 12px; min-width: 30px; text-align: center; }
82
+ }
83
+ .jsee-range-track {
84
+ flex: 1;
85
+ position: relative;
86
+ height: 20px;
87
+ &::before {
88
+ content: '';
89
+ position: absolute;
90
+ top: 50%;
91
+ left: 0;
92
+ right: 0;
93
+ transform: translateY(-50%);
94
+ height: 4px;
95
+ background: var(--jsee-border, #ddd);
96
+ border-radius: 2px;
97
+ }
98
+ .jsee-range-fill {
99
+ position: absolute;
100
+ top: 50%;
101
+ transform: translateY(-50%);
102
+ height: 4px;
103
+ background: var(--jsee-primary, #00d1b2);
104
+ border-radius: 2px;
105
+ pointer-events: none;
106
+ }
107
+ input[type="range"] {
108
+ position: absolute;
109
+ top: 0;
110
+ left: 0;
111
+ width: 100%;
112
+ height: 100%;
113
+ margin: 0;
114
+ -webkit-appearance: none;
115
+ appearance: none;
116
+ background: transparent;
117
+ pointer-events: none;
118
+ z-index: 1;
119
+ &::-webkit-slider-runnable-track {
120
+ height: 4px;
121
+ background: transparent;
122
+ }
123
+ &::-moz-range-track {
124
+ height: 4px;
125
+ background: transparent;
126
+ }
127
+ &::-webkit-slider-thumb {
128
+ -webkit-appearance: none;
129
+ appearance: none;
130
+ width: 16px;
131
+ height: 16px;
132
+ border-radius: 50%;
133
+ background: var(--jsee-primary, #00d1b2);
134
+ border: 2px solid #fff;
135
+ box-shadow: 0 1px 3px rgba(0,0,0,0.3);
136
+ cursor: pointer;
137
+ pointer-events: all;
138
+ margin-top: -6px;
139
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
140
+ }
141
+ &::-moz-range-thumb {
142
+ width: 16px;
143
+ height: 16px;
144
+ border-radius: 50%;
145
+ background: var(--jsee-primary, #00d1b2);
146
+ border: 2px solid #fff;
147
+ box-shadow: 0 1px 3px rgba(0,0,0,0.3);
148
+ cursor: pointer;
149
+ pointer-events: all;
150
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
151
+ }
152
+ &:active::-webkit-slider-thumb {
153
+ transform: scale(1.25);
154
+ box-shadow: 0 2px 6px rgba(0,0,0,0.35);
155
+ }
156
+ &:active::-moz-range-thumb {
157
+ transform: scale(1.25);
158
+ box-shadow: 0 2px 6px rgba(0,0,0,0.35);
159
+ }
160
+ }
161
+ }
162
+ .jsee-slider-track {
163
+ margin-top: 6px;
164
+ position: relative;
165
+ height: 20px;
166
+ &::before {
167
+ content: '';
168
+ position: absolute;
169
+ top: 50%;
170
+ left: 0;
171
+ right: 0;
172
+ transform: translateY(-50%);
173
+ height: 4px;
174
+ background: var(--jsee-border, #ddd);
175
+ border-radius: 2px;
176
+ }
177
+ input[type="range"] {
178
+ position: absolute;
179
+ top: 0;
180
+ left: 0;
181
+ width: 100%;
182
+ height: 100%;
183
+ margin: 0;
184
+ -webkit-appearance: none;
185
+ appearance: none;
186
+ background: transparent;
187
+ &::-webkit-slider-runnable-track {
188
+ height: 4px;
189
+ background: transparent;
190
+ }
191
+ &::-moz-range-track {
192
+ height: 4px;
193
+ background: transparent;
194
+ }
195
+ &::-webkit-slider-thumb {
196
+ -webkit-appearance: none;
197
+ appearance: none;
198
+ width: 16px;
199
+ height: 16px;
200
+ border-radius: 50%;
201
+ background: var(--jsee-primary, #00d1b2);
202
+ border: 2px solid #fff;
203
+ box-shadow: 0 1px 3px rgba(0,0,0,0.3);
204
+ cursor: pointer;
205
+ margin-top: -6px;
206
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
207
+ }
208
+ &::-moz-range-thumb {
209
+ width: 16px;
210
+ height: 16px;
211
+ border-radius: 50%;
212
+ background: var(--jsee-primary, #00d1b2);
213
+ border: 2px solid #fff;
214
+ box-shadow: 0 1px 3px rgba(0,0,0,0.3);
215
+ cursor: pointer;
216
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
217
+ }
218
+ &:active::-webkit-slider-thumb {
219
+ transform: scale(1.25);
220
+ box-shadow: 0 2px 6px rgba(0,0,0,0.35);
221
+ }
222
+ &:active::-moz-range-thumb {
223
+ transform: scale(1.25);
224
+ box-shadow: 0 2px 6px rgba(0,0,0,0.35);
225
+ }
226
+ }
227
+ }
228
+ .jsee-accordion-header {
229
+ display: flex;
230
+ align-items: center;
231
+ cursor: pointer;
232
+ user-select: none;
233
+ padding: 4px 0;
234
+ font-size: 12px;
235
+ &:hover { color: var(--jsee-primary, #00d1b2); }
236
+ }
237
+ .jsee-accordion-arrow {
238
+ display: inline-block;
239
+ width: 0; height: 0;
240
+ border-left: 5px solid transparent;
241
+ border-right: 5px solid transparent;
242
+ border-top: 6px solid currentColor;
243
+ margin-right: 6px;
244
+ transition: transform 0.2s;
245
+ &.collapsed { transform: rotate(-90deg); }
246
+ }
247
+ .jsee-accordion-body {
248
+ overflow: hidden;
249
+ transition: max-height 0.25s ease;
250
+ &.collapsed { max-height: 0 !important; }
251
+ }
252
+ .jsee-input-error {
253
+ display: block;
254
+ font-size: 11px;
255
+ color: var(--jsee-error, #e74c3c);
256
+ margin-top: 2px;
257
+ }
258
+ .jsee-input-invalid {
259
+ border-color: var(--jsee-error, #e74c3c) !important;
260
+ }
261
+ .jsee-btn {
262
+ display: block;
263
+ width: 100%;
264
+ padding: 6px 10px;
265
+ margin-top: 8px;
266
+ border: 1px solid var(--jsee-input-border, #ddd);
267
+ border-radius: 3px;
268
+ background: var(--jsee-bg-secondary, #fafafa);
269
+ color: var(--jsee-text, #333);
270
+ cursor: pointer;
271
+ font-size: 13px;
272
+ text-align: left;
273
+ &:hover { background: var(--jsee-border, #f0f0f0); }
274
+ }
275
+ .jsee-group {
276
+ display: flex;
277
+ gap: 8px;
278
+ }
279
+ .jsee-tabs-header {
280
+ display: flex;
281
+ border-bottom: 2px solid var(--jsee-border, #e0e0e0);
282
+ margin-bottom: 8px;
283
+ }
284
+ .jsee-tab-btn {
285
+ padding: 6px 14px;
286
+ border: none;
287
+ background: none;
288
+ cursor: pointer;
289
+ font-size: 12px;
290
+ color: var(--jsee-text-secondary, #666);
291
+ border-bottom: 2px solid transparent;
292
+ margin-bottom: -2px;
293
+ }
294
+ .jsee-tab-btn.active {
295
+ color: var(--jsee-primary, #00d1b2);
296
+ border-bottom-color: var(--jsee-primary, #00d1b2);
297
+ }
298
+ .jsee-tab-btn:hover { color: var(--jsee-text, #333); }
299
+ </style>
300
+
301
+ <template>
302
+ <div class="jsee-field" v-if="input.type == 'int' || input.type == 'float' || input.type == 'number'">
303
+ <label v-bind:for="input.name" class="jsee-label">{{ input.name }}</label>
304
+ <input
305
+ v-model="input.value"
306
+ v-bind:id="input.name"
307
+ v-bind:step="input.type == 'int' ? 1 : 0.001"
308
+ v-bind:placeholder="input.placeholder ? input.placeholder : input.name"
309
+ v-bind:min="input.min"
310
+ v-bind:max="input.max"
311
+ v-bind:disabled="input.disabled"
312
+ v-on:change="changeHandler"
313
+ class="jsee-input"
314
+ v-bind:class="{ 'jsee-input-invalid': input._error }"
315
+ type="number"
316
+ >
317
+ <span class="jsee-input-error" v-if="input._error">{{ input._error }}</span>
318
+ </div>
319
+
320
+ <div class="jsee-field" v-if="input.type == 'string' || input.type == 'color'">
321
+ <label v-bind:for="input.name" class="jsee-label">{{ input.name }}</label>
322
+ <input
323
+ v-model="input.value"
324
+ v-bind:id="input.name"
325
+ v-bind:type="input.type == 'color' ? 'color' : 'text'"
326
+ v-bind:placeholder="input.placeholder ? input.placeholder : input.name"
327
+ v-on:change="changeHandler"
328
+ v-on:keydown.enter="input.enter ? $emit('inchange') : null"
329
+ class="jsee-input"
330
+ v-bind:class="{ 'jsee-input-invalid': input._error }"
331
+ >
332
+ <span class="jsee-input-error" v-if="input._error">{{ input._error }}</span>
333
+ </div>
334
+
335
+ <div class="jsee-field" v-if="input.type == 'text'">
336
+ <label v-bind:for="input.name" class="jsee-label">{{ input.name }}</label>
337
+ <textarea
338
+ v-model="input.value"
339
+ v-bind:id="input.name"
340
+ v-bind:placeholder="input.placeholder ? input.placeholder : input.name"
341
+ v-on:change="changeHandler"
342
+ v-on:input="autosize"
343
+ class="jsee-textarea"
344
+ v-bind:class="{ 'jsee-input-invalid': input._error }"
345
+ ></textarea>
346
+ <span class="jsee-input-error" v-if="input._error">{{ input._error }}</span>
347
+ </div>
348
+
349
+ <div class="jsee-field" v-if="input.type == 'slider'">
350
+ <label v-bind:for="input.name" class="jsee-label">
351
+ {{ input.name }}: <strong>{{ input.value }}</strong>
352
+ </label>
353
+ <div class="jsee-slider-track">
354
+ <input
355
+ v-model.number="input.value"
356
+ v-bind:id="input.name"
357
+ v-bind:min="input.min || 0"
358
+ v-bind:max="input.max || 100"
359
+ v-bind:step="input.step || 1"
360
+ v-bind:disabled="input.disabled"
361
+ v-on:input="changeHandler"
362
+ type="range"
363
+ >
364
+ </div>
365
+ </div>
366
+
367
+ <div class="jsee-field" v-if="input.type == 'range'">
368
+ <label class="jsee-label">
369
+ {{ input.name }}: <strong>{{ (input.value || [])[0] }} - {{ (input.value || [])[1] }}</strong>
370
+ </label>
371
+ <div class="jsee-range">
372
+ <span class="jsee-range-value">{{ (input.value || [])[0] }}</span>
373
+ <div class="jsee-range-track">
374
+ <div class="jsee-range-fill" :style="{
375
+ left: (((input.value || [])[0] - (input.min || 0)) / ((input.max || 100) - (input.min || 0)) * 100) + '%',
376
+ right: (100 - ((input.value || [])[1] - (input.min || 0)) / ((input.max || 100) - (input.min || 0)) * 100) + '%'
377
+ }"></div>
378
+ <input
379
+ v-bind:value="(input.value || [])[0]"
380
+ v-on:input="rangeInput($event, 'min')"
381
+ v-bind:min="input.min || 0"
382
+ v-bind:max="input.max || 100"
383
+ v-bind:step="input.step || 1"
384
+ v-bind:disabled="input.disabled"
385
+ type="range"
386
+ style="z-index: 2"
387
+ >
388
+ <input
389
+ v-bind:value="(input.value || [])[1]"
390
+ v-on:input="rangeInput($event, 'max')"
391
+ v-bind:min="input.min || 0"
392
+ v-bind:max="input.max || 100"
393
+ v-bind:step="input.step || 1"
394
+ v-bind:disabled="input.disabled"
395
+ type="range"
396
+ >
397
+ </div>
398
+ <span class="jsee-range-value">{{ (input.value || [])[1] }}</span>
399
+ </div>
400
+ </div>
401
+
402
+ <div class="jsee-field" v-if="input.type == 'date'">
403
+ <label v-bind:for="input.name" class="jsee-label">{{ input.name }}</label>
404
+ <input
405
+ v-model="input.value"
406
+ v-bind:id="input.name"
407
+ v-bind:disabled="input.disabled"
408
+ v-on:change="changeHandler"
409
+ class="jsee-input"
410
+ v-bind:class="{ 'jsee-input-invalid': input._error }"
411
+ type="date"
412
+ >
413
+ <span class="jsee-input-error" v-if="input._error">{{ input._error }}</span>
414
+ </div>
415
+
416
+ <div class="jsee-field" v-if="input.type == 'checkbox' || input.type == 'bool'">
417
+ <label class="jsee-checkbox-label">
418
+ <input
419
+ v-model="input.value"
420
+ v-bind:id="input.name"
421
+ v-on:change="changeHandler"
422
+ type="checkbox"
423
+ >
424
+ {{ input.name }}
425
+ </label>
426
+ </div>
427
+
428
+ <div class="jsee-field" v-if="input.type == 'toggle'">
429
+ <label style="display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 12px;">
430
+ <span class="jsee-toggle">
431
+ <input type="checkbox" v-model="input.value" v-bind:id="input.name" v-on:change="changeHandler">
432
+ <span class="jsee-toggle-track" v-bind:class="{ active: input.value }"></span>
433
+ <span class="jsee-toggle-thumb" v-bind:class="{ active: input.value }"></span>
434
+ </span>
435
+ {{ input.name }}
436
+ </label>
437
+ </div>
438
+
439
+ <div class="jsee-field" v-if="input.type == 'categorical' || input.type == 'select'">
440
+ <label v-bind:for="input.name" class="jsee-label">{{ input.name }}</label>
441
+ <select
442
+ v-model="input.value"
443
+ v-bind:id="input.name"
444
+ v-on:change="changeHandler"
445
+ class="jsee-select"
446
+ v-bind:class="{ 'jsee-input-invalid': input._error }"
447
+ >
448
+ <option v-for="(option, oi) in input.options">{{ option }}</option>
449
+ </select>
450
+ <span class="jsee-input-error" v-if="input._error">{{ input._error }}</span>
451
+ </div>
452
+
453
+ <div class="jsee-field" v-if="input.type == 'radio'">
454
+ <label class="jsee-label">{{ input.name }}</label>
455
+ <label v-for="option in input.options" :key="option" class="jsee-radio-label">
456
+ <input type="radio" v-model="input.value" :value="option" :name="input.name" v-on:change="changeHandler">
457
+ {{ option }}
458
+ </label>
459
+ </div>
460
+
461
+ <div class="jsee-field" v-if="input.type == 'multi-select'">
462
+ <label class="jsee-label">{{ input.name }}</label>
463
+ <label v-for="option in input.options" :key="option" class="jsee-checkbox-label">
464
+ <input type="checkbox" :value="option" v-model="input.value" v-on:change="changeHandler">
465
+ {{ option }}
466
+ </label>
467
+ </div>
468
+
469
+ <div class="jsee-field" v-if="input.type == 'file'">
470
+ <label v-bind:for="input.name" class="jsee-label">{{ input.name }}</label>
471
+ <div v-if="!input.disabled">
472
+ <file-picker
473
+ v-model="input.value"
474
+ v-model:url="input.url"
475
+ v-bind:raw="input.raw === true || input.stream === true"
476
+ v-bind:autoload="input.urlAutoLoad === true"
477
+ v-on:change="changeHandler"
478
+ ></file-picker>
479
+ </div>
480
+ <div v-else>
481
+ <input
482
+ class="jsee-input"
483
+ v-bind:id="input.name"
484
+ v-bind:value="input.default"
485
+ disabled
486
+ >
487
+ </div>
488
+ </div>
489
+
490
+ <div class="jsee-field" v-if="input.type == 'folder'">
491
+ <label v-bind:for="input.name" class="jsee-label">{{ input.name }}</label>
492
+ <div v-if="!input.disabled && (!input.value || input.value.length === 0)">
493
+ <div class="vfp-bgArea" style="min-height: 80px; padding: 15px 10px;"
494
+ @dragover.prevent @dragleave.prevent @drop.prevent="folderDropped">
495
+ <input type="file" webkitdirectory style="display:none" ref="folderPicker"
496
+ @change="folderSelected">
497
+ <div style="text-align: center">
498
+ <button class="jsee-btn" style="display:inline-block; width:auto"
499
+ @click="$refs.folderPicker.click()">Choose Folder</button>
500
+ <span style="font-size:12px; color:#888; margin-left:8px">or drop a folder here</span>
501
+ </div>
502
+ </div>
503
+ </div>
504
+ <div v-if="input.value && input.value.length > 0">
505
+ <div style="font-size:11px; color:var(--jsee-text-secondary, #888); margin-bottom:4px">
506
+ {{ input.value.length }} files
507
+ </div>
508
+ <div style="max-height: 200px; overflow-y: auto; border: 1px solid var(--jsee-border, #ddd); border-radius: 3px">
509
+ <div v-for="(file, fi) in input.value" :key="fi"
510
+ :style="{
511
+ padding: '3px 8px', fontSize: '12px', borderBottom: '1px solid var(--jsee-border, #f0f0f0)',
512
+ display: 'flex', alignItems: 'center', gap: '6px',
513
+ cursor: input.select === 'one' ? 'pointer' : undefined,
514
+ background: input.select === 'one' && file.selected ? 'var(--jsee-focus-ring, rgba(72,139,199,0.2))' : undefined
515
+ }"
516
+ @click="input.select === 'one' && folderSelectOne(file)">
517
+ <input v-if="input.select === true || input.select === 'many'" type="checkbox"
518
+ v-model="file.selected" @change="folderSelectionChanged">
519
+ <span style="flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap">{{ file.name }}</span>
520
+ <span style="color:var(--jsee-text-secondary, #aaa); font-size:10px">{{ formatSize(file.size) }}</span>
521
+ </div>
522
+ </div>
523
+ </div>
524
+ </div>
525
+
526
+ <div class="jsee-field" v-if="input.type == 'action' || input.type == 'button'">
527
+ <button
528
+ v-on:click="$parent.$parent.run(input.name.toLowerCase().replace(/ /g, '_'))"
529
+ class="jsee-btn"
530
+ >
531
+ {{ input.title ? input.title : input.name }}
532
+ </button>
533
+ </div>
534
+
535
+ <div class="jsee-field" v-if="input.type == 'group'">
536
+ <!-- Accordion -->
537
+ <div v-if="effectiveStyle === 'accordion'">
538
+ <div class="jsee-accordion-header" v-on:click="toggleCollapsed">
539
+ <span class="jsee-accordion-arrow" v-bind:class="{ collapsed: collapsed }"></span>
540
+ <strong>{{ input.label || input.name }}</strong>
541
+ </div>
542
+ <div class="jsee-group jsee-accordion-body" v-bind:class="{ collapsed: collapsed }" style="max-height: 2000px;">
543
+ <vue-input v-for="(el, index) in input.elements" v-bind:input="el"></vue-input>
544
+ </div>
545
+ </div>
546
+ <!-- Tabs -->
547
+ <div v-else-if="effectiveStyle === 'tabs'">
548
+ <div class="jsee-tabs-header">
549
+ <button v-for="(el, ti) in input.elements" :key="ti"
550
+ class="jsee-tab-btn" :class="{ active: activeTab === ti }"
551
+ v-on:click="activeTab = ti">
552
+ {{ el.label || el.name || 'Tab ' + (ti + 1) }}
553
+ </button>
554
+ </div>
555
+ <div class="jsee-tabs-body">
556
+ <div v-for="(el, ti) in input.elements" :key="ti" v-show="activeTab === ti">
557
+ <template v-if="el.type === 'group'">
558
+ <vue-input v-for="(child, ci) in el.elements" :key="ci" :input="child"></vue-input>
559
+ </template>
560
+ <vue-input v-else :input="el"></vue-input>
561
+ </div>
562
+ </div>
563
+ </div>
564
+ <!-- Blocks (default) -->
565
+ <div v-else class="jsee-group">
566
+ <vue-input v-for="(el, index) in input.elements" v-bind:input="el"></vue-input>
567
+ </div>
568
+ </div>
569
+ </template>
570
+
571
+ <script>
572
+ export { component as default } from "./common-inputs.js"
573
+ </script>