@dmitryvim/form-builder 0.3.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/formbuilder.min.js +181 -123
- package/dist/browser/formbuilder.v0.5.0.min.js +1499 -0
- package/dist/cjs/index.cjs +150 -91
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +144 -89
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +181 -123
- package/dist/types/components/file/library.d.ts +1 -1
- package/dist/types/components/textarea.d.ts +4 -2
- package/dist/types/styles/theme.d.ts +3 -0
- package/dist/types/types/index.d.ts +1 -1
- package/dist/types/types/schema.d.ts +32 -2
- package/dist/types/utils/styles.d.ts +3 -1
- package/package.json +19 -19
- package/dist/browser/formbuilder.v0.3.4.min.js +0 -1441
package/dist/cjs/index.cjs
CHANGED
|
@@ -427,6 +427,20 @@ function ensureThemingHooks(doc) {
|
|
|
427
427
|
min-height: var(--fb-slide-card-min-height);
|
|
428
428
|
padding: var(--fb-slide-card-padding);
|
|
429
429
|
}
|
|
430
|
+
/* Slides-mode outer grid. Responsive by design \u2014 column count derives from
|
|
431
|
+
container width and --fb-slide-min-width, not from a schema "columns" prop.
|
|
432
|
+
min(100%, ...) prevents the card from overflowing a narrow container.
|
|
433
|
+
Override per-form: set --fb-slide-min-width / --fb-slides-gap on any
|
|
434
|
+
ancestor (theme, host CSS, or the form root). */
|
|
435
|
+
.fb-container-slides {
|
|
436
|
+
display: grid;
|
|
437
|
+
gap: var(--fb-slides-gap, 14px);
|
|
438
|
+
align-items: stretch;
|
|
439
|
+
grid-template-columns: repeat(
|
|
440
|
+
auto-fit,
|
|
441
|
+
minmax(min(100%, var(--fb-slide-min-width, 280px)), 1fr)
|
|
442
|
+
);
|
|
443
|
+
}
|
|
430
444
|
[data-fb-label-row] > label {
|
|
431
445
|
font-size: var(--fb-label-section-font-size);
|
|
432
446
|
letter-spacing: var(--fb-label-section-letter-spacing);
|
|
@@ -473,20 +487,61 @@ function ensureThemingHooks(doc) {
|
|
|
473
487
|
color: #ffffff;
|
|
474
488
|
border-color: var(--fb-primary-color);
|
|
475
489
|
}
|
|
490
|
+
/* \u2500\u2500\u2500 Row layout: flex-wrap container with per-child width tokens \u2500\u2500\u2500
|
|
491
|
+
Replaces the older Tailwind \`space-y-2\` class. Children without
|
|
492
|
+
data-fb-width (or width="full") take 100% basis \u2192 forced wrap \u2192 behaves
|
|
493
|
+
like a vertical stack. Mixed widths sit side-by-side in the same row. */
|
|
494
|
+
.fb-row {
|
|
495
|
+
display: flex;
|
|
496
|
+
flex-wrap: wrap;
|
|
497
|
+
gap: var(--fb-row-gap, 0.25rem);
|
|
498
|
+
align-items: flex-start;
|
|
499
|
+
}
|
|
500
|
+
.fb-row > [data-fb-width="full"],
|
|
501
|
+
.fb-row > :not([data-fb-width]) { flex: 0 0 100%; min-width: 0; }
|
|
502
|
+
.fb-row > [data-fb-width="1/2"] { flex: 0 0 calc(50% - var(--fb-row-gap, 0.25rem) / 2); min-width: 0; }
|
|
503
|
+
.fb-row > [data-fb-width="1/3"] { flex: 0 0 calc(33.333% - var(--fb-row-gap, 0.25rem) * 2 / 3); min-width: 0; }
|
|
504
|
+
.fb-row > [data-fb-width="2/3"] { flex: 0 0 calc(66.666% - var(--fb-row-gap, 0.25rem) / 3); min-width: 0; }
|
|
505
|
+
/* \u2500\u2500\u2500 Density tokens: re-bind --fb-input-padding-* and --fb-font-size at
|
|
506
|
+
the wrapper level so every component that reads those vars (text, textarea,
|
|
507
|
+
select, number, colour, switcher, file) picks the size up via cascade. md
|
|
508
|
+
uses the defaults set in theme.ts (2px / 8px / 14px). The scale primarily
|
|
509
|
+
varies font-size; vertical padding stays close to md so an "lg" heading
|
|
510
|
+
field does not visually break the form's row rhythm \u2014 only the typography
|
|
511
|
+
announces "this is bigger". Picaz theme overrides padding directly for
|
|
512
|
+
its own density, independent of this scale. */
|
|
513
|
+
/* size-token side-effects on file tiles: --fb-file-wide-min controls the
|
|
514
|
+
single-file empty dropzone height, --fb-file-zone-min controls the inner
|
|
515
|
+
upload/library zones. Both read in src/components/file/styles.ts. */
|
|
516
|
+
.fb-size-xs { --fb-input-padding-y: 1px; --fb-input-padding-x: 6px; --fb-font-size: 12px; --fb-font-size-small: 10px; --fb-line-height: 1.25; --fb-file-wide-min: 64px; --fb-file-zone-min: 48px; --fb-file-zone-padding: 6px; }
|
|
517
|
+
.fb-size-sm { --fb-input-padding-y: 2px; --fb-input-padding-x: 6px; --fb-font-size: 13px; --fb-font-size-small: 11px; --fb-line-height: 1.35; --fb-file-wide-min: 80px; --fb-file-zone-min: 60px; --fb-file-zone-padding: 7px; }
|
|
518
|
+
/* .fb-size-md uses defaults \u2014 no override needed */
|
|
519
|
+
.fb-size-lg { --fb-input-padding-y: 2px; --fb-input-padding-x: 8px; --fb-font-size: 16px; --fb-font-size-small: 13px; --fb-file-wide-min: 128px; --fb-file-zone-min: 96px; --fb-file-zone-padding: 12px; }
|
|
520
|
+
.fb-size-xl { --fb-input-padding-y: 3px; --fb-input-padding-x: 8px; --fb-font-size: 18px; --fb-font-size-small: 14px; --fb-file-wide-min: 160px; --fb-file-zone-min: 120px; --fb-file-zone-padding: 14px; }
|
|
476
521
|
`;
|
|
477
522
|
doc.head.appendChild(style);
|
|
478
523
|
}
|
|
479
|
-
function applyAutoExpand(textarea) {
|
|
524
|
+
function applyAutoExpand(textarea, options = {}) {
|
|
525
|
+
var _a;
|
|
480
526
|
textarea.style.overflow = "hidden";
|
|
481
527
|
textarea.style.resize = "none";
|
|
528
|
+
const minRows = Math.max(1, (_a = options.minRows) != null ? _a : 1);
|
|
482
529
|
const lineCount = (textarea.value.match(/\n/g) || []).length + 1;
|
|
483
|
-
textarea.rows = Math.max(
|
|
530
|
+
textarea.rows = Math.max(minRows, lineCount);
|
|
484
531
|
const resize = () => {
|
|
485
532
|
if (!textarea.isConnected) return;
|
|
486
|
-
textarea.style.height = "
|
|
533
|
+
textarea.style.height = "";
|
|
487
534
|
const cs = getComputedStyle(textarea);
|
|
488
535
|
const borderY = parseFloat(cs.borderTopWidth || "0") + parseFloat(cs.borderBottomWidth || "0");
|
|
489
|
-
|
|
536
|
+
const lineHeight = parseFloat(cs.lineHeight || "0") || parseFloat(cs.fontSize || "0") * 1.5 || 20;
|
|
537
|
+
const padY = parseFloat(cs.paddingTop || "0") + parseFloat(cs.paddingBottom || "0");
|
|
538
|
+
const minHeight = lineHeight * minRows + padY + borderY;
|
|
539
|
+
if (textarea.value === "") {
|
|
540
|
+
textarea.style.height = `${minHeight}px`;
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const contentHeight = textarea.scrollHeight + borderY;
|
|
544
|
+
textarea.style.height = `${Math.max(contentHeight, minHeight)}px`;
|
|
490
545
|
};
|
|
491
546
|
textarea.addEventListener("input", resize);
|
|
492
547
|
setTimeout(() => {
|
|
@@ -495,13 +550,13 @@ function applyAutoExpand(textarea) {
|
|
|
495
550
|
if (typeof ResizeObserver === "undefined") return;
|
|
496
551
|
let lastWidth = -1;
|
|
497
552
|
const ro = new ResizeObserver((entries) => {
|
|
498
|
-
var
|
|
553
|
+
var _a2, _b, _c, _d, _e;
|
|
499
554
|
if (!textarea.isConnected) {
|
|
500
555
|
ro.disconnect();
|
|
501
556
|
return;
|
|
502
557
|
}
|
|
503
558
|
const entry = entries[0];
|
|
504
|
-
const w = (_e = (_d = (_b = (
|
|
559
|
+
const w = (_e = (_d = (_b = (_a2 = entry == null ? void 0 : entry.contentBoxSize) == null ? void 0 : _a2[0]) == null ? void 0 : _b.inlineSize) != null ? _d : (_c = entry == null ? void 0 : entry.contentRect) == null ? void 0 : _c.width) != null ? _e : 0;
|
|
505
560
|
if (w === lastWidth) return;
|
|
506
561
|
lastWidth = w;
|
|
507
562
|
resize();
|
|
@@ -541,8 +596,8 @@ function createAddItemRow(classNameSuffix, onClick, options = {}) {
|
|
|
541
596
|
const label = (_a = options.label) != null ? _a : "";
|
|
542
597
|
const showCounter = options.showCounter !== false;
|
|
543
598
|
const row = document.createElement("div");
|
|
544
|
-
row.className = "fb-add-row
|
|
545
|
-
row.style.cssText = "display:flex;align-items:stretch;width:100%;";
|
|
599
|
+
row.className = "fb-add-row";
|
|
600
|
+
row.style.cssText = "display:flex;align-items:stretch;width:100%;margin-top:4px;";
|
|
546
601
|
const button = document.createElement("button");
|
|
547
602
|
button.type = "button";
|
|
548
603
|
button.className = `add-${classNameSuffix}-btn`;
|
|
@@ -551,8 +606,8 @@ function createAddItemRow(classNameSuffix, onClick, options = {}) {
|
|
|
551
606
|
display: inline-flex;
|
|
552
607
|
align-items: center;
|
|
553
608
|
justify-content: center;
|
|
554
|
-
gap:
|
|
555
|
-
padding:
|
|
609
|
+
gap: 4px;
|
|
610
|
+
padding: 3px 10px;
|
|
556
611
|
border: 1px dashed var(--fb-primary-color);
|
|
557
612
|
border-radius: var(--fb-border-radius);
|
|
558
613
|
background: transparent;
|
|
@@ -698,12 +753,12 @@ function ensureChipStyles(doc) {
|
|
|
698
753
|
const style = doc.createElement("style");
|
|
699
754
|
style.setAttribute("data-fb-chip-styles", "");
|
|
700
755
|
style.textContent = `
|
|
701
|
-
.fb-chip-list { display: flex; flex-direction: column; gap:
|
|
756
|
+
.fb-chip-list { display: flex; flex-direction: column; gap: 2px; }
|
|
702
757
|
.fb-chip {
|
|
703
758
|
display: flex;
|
|
704
759
|
align-items: center;
|
|
705
|
-
gap:
|
|
706
|
-
padding:
|
|
760
|
+
gap: 6px;
|
|
761
|
+
padding: 3px 6px 3px 8px;
|
|
707
762
|
background: var(--fb-chip-bg, var(--fb-background-color, #fff));
|
|
708
763
|
border: 1px solid var(--fb-chip-border, var(--fb-border-color, #e2e8f0));
|
|
709
764
|
border-radius: 6px;
|
|
@@ -729,7 +784,13 @@ function ensureChipStyles(doc) {
|
|
|
729
784
|
color: var(--fb-chip-text, var(--fb-text-color, inherit));
|
|
730
785
|
font-size: var(--fb-font-size, 14px);
|
|
731
786
|
font-family: var(--fb-font-family, inherit);
|
|
732
|
-
line-height: 1.4;
|
|
787
|
+
line-height: var(--fb-line-height, 1.4);
|
|
788
|
+
/* Soft-wrap support (v0.4.0): chip-input is now a <textarea rows=1> that
|
|
789
|
+
grows vertically when content overflows the chip width. */
|
|
790
|
+
resize: none;
|
|
791
|
+
overflow: hidden;
|
|
792
|
+
word-break: break-word;
|
|
793
|
+
overflow-wrap: anywhere;
|
|
733
794
|
}
|
|
734
795
|
.fb-chip-input::placeholder { color: var(--fb-text-placeholder-color, #94a3b8); }
|
|
735
796
|
.fb-chip-input:read-only { color: var(--fb-text-secondary-color, #475569); }
|
|
@@ -788,6 +849,7 @@ function createCharCounter(element, input) {
|
|
|
788
849
|
return counter;
|
|
789
850
|
}
|
|
790
851
|
function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
852
|
+
var _a;
|
|
791
853
|
const state = ctx.state;
|
|
792
854
|
const readonly = isElementReadonly(element, state, ctx);
|
|
793
855
|
const inputWrapper = document.createElement("div");
|
|
@@ -814,7 +876,7 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
814
876
|
overflow-wrap: anywhere;
|
|
815
877
|
`;
|
|
816
878
|
textInput.name = pathKey;
|
|
817
|
-
textInput.placeholder = element.placeholder
|
|
879
|
+
textInput.placeholder = (_a = element.placeholder) != null ? _a : "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442";
|
|
818
880
|
textInput.value = ctx.prefill[element.key] || element.default || "";
|
|
819
881
|
textInput.readOnly = readonly;
|
|
820
882
|
applySingleLineMode(textInput);
|
|
@@ -888,8 +950,8 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
888
950
|
dot.className = "fb-chip-dot";
|
|
889
951
|
dot.setAttribute("aria-hidden", "true");
|
|
890
952
|
chip.appendChild(dot);
|
|
891
|
-
const input = document.createElement("
|
|
892
|
-
input.
|
|
953
|
+
const input = document.createElement("textarea");
|
|
954
|
+
input.rows = 1;
|
|
893
955
|
input.className = "fb-chip-input";
|
|
894
956
|
input.value = value;
|
|
895
957
|
input.placeholder = element.placeholder || t("placeholderText", state);
|
|
@@ -905,6 +967,8 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
905
967
|
input.addEventListener("blur", handleChange);
|
|
906
968
|
input.addEventListener("input", handleChange);
|
|
907
969
|
}
|
|
970
|
+
applySingleLineMode(input);
|
|
971
|
+
applyAutoExpand(input);
|
|
908
972
|
if (!readonly) {
|
|
909
973
|
const rem = document.createElement("button");
|
|
910
974
|
rem.type = "button";
|
|
@@ -1119,6 +1183,7 @@ function updateTextField(element, fieldPath, value, context) {
|
|
|
1119
1183
|
|
|
1120
1184
|
// src/components/textarea.ts
|
|
1121
1185
|
function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
1186
|
+
var _a, _b;
|
|
1122
1187
|
const state = ctx.state;
|
|
1123
1188
|
const readonly = isElementReadonly(element, state, ctx);
|
|
1124
1189
|
const textareaWrapper = document.createElement("div");
|
|
@@ -1126,13 +1191,13 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1126
1191
|
const textareaInput = document.createElement("textarea");
|
|
1127
1192
|
textareaInput.className = "w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none";
|
|
1128
1193
|
textareaInput.style.cssText = `
|
|
1129
|
-
padding: var(--fb-input-padding-y) var(--fb-input-padding-x)
|
|
1194
|
+
padding: var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
1130
1195
|
font-size: var(--fb-font-size);
|
|
1131
1196
|
font-family: var(--fb-font-family);
|
|
1197
|
+
line-height: var(--fb-line-height, 1.5);
|
|
1132
1198
|
`;
|
|
1133
1199
|
textareaInput.name = pathKey;
|
|
1134
|
-
textareaInput.placeholder = element.placeholder
|
|
1135
|
-
textareaInput.rows = element.rows || 4;
|
|
1200
|
+
textareaInput.placeholder = (_a = element.placeholder) != null ? _a : "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442";
|
|
1136
1201
|
textareaInput.value = ctx.prefill[element.key] || element.default || "";
|
|
1137
1202
|
textareaInput.readOnly = readonly;
|
|
1138
1203
|
if (!readonly && ctx.instance) {
|
|
@@ -1143,9 +1208,7 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1143
1208
|
textareaInput.addEventListener("blur", handleChange);
|
|
1144
1209
|
textareaInput.addEventListener("input", handleChange);
|
|
1145
1210
|
}
|
|
1146
|
-
|
|
1147
|
-
applyAutoExpand(textareaInput);
|
|
1148
|
-
}
|
|
1211
|
+
applyAutoExpand(textareaInput, { minRows: (_b = element.rows) != null ? _b : 1 });
|
|
1149
1212
|
textareaWrapper.appendChild(textareaInput);
|
|
1150
1213
|
if (!readonly && (element.minLength != null || element.maxLength != null)) {
|
|
1151
1214
|
const counter = createCharCounter(element, textareaInput);
|
|
@@ -1165,7 +1228,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1165
1228
|
values.push(element.default || "");
|
|
1166
1229
|
}
|
|
1167
1230
|
const container = document.createElement("div");
|
|
1168
|
-
container.className = "
|
|
1231
|
+
container.className = "fb-row";
|
|
1169
1232
|
wrapper.appendChild(container);
|
|
1170
1233
|
function updateIndices() {
|
|
1171
1234
|
const items = container.querySelectorAll(".multiple-textarea-item");
|
|
@@ -1177,6 +1240,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1177
1240
|
});
|
|
1178
1241
|
}
|
|
1179
1242
|
function addTextareaItem(value = "", index = -1) {
|
|
1243
|
+
var _a2;
|
|
1180
1244
|
const itemWrapper = document.createElement("div");
|
|
1181
1245
|
itemWrapper.className = "multiple-textarea-item";
|
|
1182
1246
|
const textareaContainer = document.createElement("div");
|
|
@@ -1184,12 +1248,12 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1184
1248
|
const textareaInput = document.createElement("textarea");
|
|
1185
1249
|
textareaInput.className = "w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none";
|
|
1186
1250
|
textareaInput.style.cssText = `
|
|
1187
|
-
padding: var(--fb-input-padding-y) var(--fb-input-padding-x)
|
|
1251
|
+
padding: var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
1188
1252
|
font-size: var(--fb-font-size);
|
|
1189
1253
|
font-family: var(--fb-font-family);
|
|
1254
|
+
line-height: var(--fb-line-height, 1.5);
|
|
1190
1255
|
`;
|
|
1191
1256
|
textareaInput.placeholder = element.placeholder || t("placeholderText", state);
|
|
1192
|
-
textareaInput.rows = element.rows || 4;
|
|
1193
1257
|
textareaInput.value = value;
|
|
1194
1258
|
textareaInput.readOnly = readonly;
|
|
1195
1259
|
if (!readonly && ctx.instance) {
|
|
@@ -1200,9 +1264,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1200
1264
|
textareaInput.addEventListener("blur", handleChange);
|
|
1201
1265
|
textareaInput.addEventListener("input", handleChange);
|
|
1202
1266
|
}
|
|
1203
|
-
|
|
1204
|
-
applyAutoExpand(textareaInput);
|
|
1205
|
-
}
|
|
1267
|
+
applyAutoExpand(textareaInput, { minRows: (_a2 = element.rows) != null ? _a2 : 1 });
|
|
1206
1268
|
textareaContainer.appendChild(textareaInput);
|
|
1207
1269
|
if (!readonly && (element.minLength != null || element.maxLength != null)) {
|
|
1208
1270
|
const counter = createCharCounter(element, textareaInput);
|
|
@@ -1278,9 +1340,7 @@ function validateTextareaElement(element, key, context) {
|
|
|
1278
1340
|
}
|
|
1279
1341
|
function updateTextareaField(element, fieldPath, value, context) {
|
|
1280
1342
|
updateTextField(element, fieldPath, value, context);
|
|
1281
|
-
const { scopeRoot
|
|
1282
|
-
const shouldAutoExpand = element.autoExpand || isElementReadonly(element, state);
|
|
1283
|
-
if (!shouldAutoExpand) return;
|
|
1343
|
+
const { scopeRoot } = context;
|
|
1284
1344
|
if (element.multiple) {
|
|
1285
1345
|
const textareas = scopeRoot.querySelectorAll(
|
|
1286
1346
|
`textarea[name^="${fieldPath}["]`
|
|
@@ -1478,7 +1538,7 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1478
1538
|
values.push(element.default || "");
|
|
1479
1539
|
}
|
|
1480
1540
|
const container = document.createElement("div");
|
|
1481
|
-
container.className = "
|
|
1541
|
+
container.className = "fb-row";
|
|
1482
1542
|
wrapper.appendChild(container);
|
|
1483
1543
|
function updateIndices() {
|
|
1484
1544
|
const items = container.querySelectorAll(".multiple-number-item");
|
|
@@ -1796,7 +1856,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1796
1856
|
values.push(element.default || ((_d = (_c = element.options) == null ? void 0 : _c[0]) == null ? void 0 : _d.value) || "");
|
|
1797
1857
|
}
|
|
1798
1858
|
const container = document.createElement("div");
|
|
1799
|
-
container.className = "
|
|
1859
|
+
container.className = "fb-row";
|
|
1800
1860
|
wrapper.appendChild(container);
|
|
1801
1861
|
function updateIndices() {
|
|
1802
1862
|
const items = container.querySelectorAll(".multiple-select-item");
|
|
@@ -2233,7 +2293,7 @@ function renderMultipleSwitcherElement(element, ctx, wrapper, pathKey) {
|
|
|
2233
2293
|
}
|
|
2234
2294
|
const readonly = isElementReadonly(element, state, ctx);
|
|
2235
2295
|
const container = document.createElement("div");
|
|
2236
|
-
container.className = "
|
|
2296
|
+
container.className = "fb-row";
|
|
2237
2297
|
wrapper.appendChild(container);
|
|
2238
2298
|
function updateIndices() {
|
|
2239
2299
|
const items = container.querySelectorAll(".multiple-switcher-item");
|
|
@@ -2818,7 +2878,9 @@ function ensureFileStyles() {
|
|
|
2818
2878
|
align-items: stretch;
|
|
2819
2879
|
gap: 0;
|
|
2820
2880
|
overflow: hidden;
|
|
2821
|
-
min-height
|
|
2881
|
+
/* min-height driven by --fb-file-wide-min so size-tokens (.fb-size-{xs|sm|lg|xl})
|
|
2882
|
+
can override per-field. Default 96px matches v0.4.0 compact density. */
|
|
2883
|
+
min-height: var(--fb-file-wide-min, 96px);
|
|
2822
2884
|
transition: border-color 150ms, background 150ms, box-shadow 150ms;
|
|
2823
2885
|
cursor: pointer;
|
|
2824
2886
|
}
|
|
@@ -2837,14 +2899,15 @@ function ensureFileStyles() {
|
|
|
2837
2899
|
upload + library on one row (~220 + 176), library wraps below. */
|
|
2838
2900
|
.fb-wide-tile-upload {
|
|
2839
2901
|
flex: 1 1 220px;
|
|
2840
|
-
min-height
|
|
2902
|
+
/* min-height theme-driven; default 72px matches v0.4.0 compact density. */
|
|
2903
|
+
min-height: var(--fb-file-zone-min, 72px);
|
|
2841
2904
|
display: flex;
|
|
2842
2905
|
flex-direction: column;
|
|
2843
2906
|
align-items: center;
|
|
2844
2907
|
justify-content: center;
|
|
2845
|
-
gap:
|
|
2908
|
+
gap: 4px;
|
|
2846
2909
|
color: #2563eb;
|
|
2847
|
-
padding:
|
|
2910
|
+
padding: var(--fb-file-zone-padding, 8px);
|
|
2848
2911
|
transition: background 150ms;
|
|
2849
2912
|
cursor: pointer;
|
|
2850
2913
|
background: transparent;
|
|
@@ -2864,14 +2927,16 @@ function ensureFileStyles() {
|
|
|
2864
2927
|
visual hierarchy "upload > library" in both layouts. */
|
|
2865
2928
|
.fb-wide-tile-library {
|
|
2866
2929
|
flex: 0 0 176px;
|
|
2867
|
-
min-
|
|
2930
|
+
/* Shares --fb-file-zone-min with the upload zone so size-tokens scale both
|
|
2931
|
+
uniformly. Default 72px matches v0.4.0 compact density. */
|
|
2932
|
+
min-height: var(--fb-file-zone-min, 72px);
|
|
2868
2933
|
display: flex;
|
|
2869
2934
|
flex-direction: column;
|
|
2870
2935
|
align-items: center;
|
|
2871
2936
|
justify-content: center;
|
|
2872
|
-
gap:
|
|
2937
|
+
gap: 4px;
|
|
2873
2938
|
color: #2563eb;
|
|
2874
|
-
padding:
|
|
2939
|
+
padding: var(--fb-file-zone-padding, 8px);
|
|
2875
2940
|
transition: background 150ms;
|
|
2876
2941
|
cursor: pointer;
|
|
2877
2942
|
background: transparent;
|
|
@@ -4148,7 +4213,9 @@ function downloadBlob(blob, fileName) {
|
|
|
4148
4213
|
URL.revokeObjectURL(blobUrl);
|
|
4149
4214
|
}, 100);
|
|
4150
4215
|
} catch (error) {
|
|
4151
|
-
throw new Error(`Blob download failed: ${error.message}
|
|
4216
|
+
throw new Error(`Blob download failed: ${error.message}`, {
|
|
4217
|
+
cause: error
|
|
4218
|
+
});
|
|
4152
4219
|
}
|
|
4153
4220
|
}
|
|
4154
4221
|
|
|
@@ -5106,7 +5173,7 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
5106
5173
|
var _a, _b;
|
|
5107
5174
|
const state = ctx.state;
|
|
5108
5175
|
const fileWrapper = document.createElement("div");
|
|
5109
|
-
fileWrapper.className = "
|
|
5176
|
+
fileWrapper.className = "fb-row";
|
|
5110
5177
|
fileWrapper.dataset.filesWrapper = pathKey;
|
|
5111
5178
|
const picker = document.createElement("input");
|
|
5112
5179
|
picker.type = "file";
|
|
@@ -5257,7 +5324,7 @@ function setupMultiFileEditMode(element, ctx, wrapper, pathKey, maxFiles) {
|
|
|
5257
5324
|
var _a, _b;
|
|
5258
5325
|
const state = ctx.state;
|
|
5259
5326
|
const filesWrapper = document.createElement("div");
|
|
5260
|
-
filesWrapper.className = "
|
|
5327
|
+
filesWrapper.className = "fb-row";
|
|
5261
5328
|
filesWrapper.dataset.filesWrapper = pathKey;
|
|
5262
5329
|
const filesPicker = document.createElement("input");
|
|
5263
5330
|
filesPicker.type = "file";
|
|
@@ -5939,7 +6006,7 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
5939
6006
|
values.push(element.default || "#000000");
|
|
5940
6007
|
}
|
|
5941
6008
|
const container = document.createElement("div");
|
|
5942
|
-
container.className = "
|
|
6009
|
+
container.className = "fb-row";
|
|
5943
6010
|
wrapper.appendChild(container);
|
|
5944
6011
|
function updateIndices() {
|
|
5945
6012
|
const items = container.querySelectorAll(".multiple-colour-item");
|
|
@@ -6805,7 +6872,7 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
6805
6872
|
const itemsWrap = document.createElement("div");
|
|
6806
6873
|
const columns = element.columns || 1;
|
|
6807
6874
|
if (columns === 1) {
|
|
6808
|
-
itemsWrap.className = "
|
|
6875
|
+
itemsWrap.className = "fb-row";
|
|
6809
6876
|
} else {
|
|
6810
6877
|
itemsWrap.className = `grid grid-cols-${columns} gap-2`;
|
|
6811
6878
|
}
|
|
@@ -6843,12 +6910,9 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
6843
6910
|
containerWrap.appendChild(itemsWrap);
|
|
6844
6911
|
wrapper.appendChild(containerWrap);
|
|
6845
6912
|
}
|
|
6846
|
-
function getChildWrapperClass(
|
|
6847
|
-
if (isSlides) {
|
|
6848
|
-
return "space-y-2";
|
|
6849
|
-
}
|
|
6913
|
+
function getChildWrapperClass(columns) {
|
|
6850
6914
|
const cols = columns || 1;
|
|
6851
|
-
return cols === 1 ? "
|
|
6915
|
+
return cols === 1 ? "fb-row" : `grid grid-cols-${cols} gap-2`;
|
|
6852
6916
|
}
|
|
6853
6917
|
function mountRemoveButton(item, onRemove, state) {
|
|
6854
6918
|
const rem = document.createElement("button");
|
|
@@ -6892,11 +6956,8 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6892
6956
|
const isSlides = element.displayMode === "slides";
|
|
6893
6957
|
if (isSlides) {
|
|
6894
6958
|
itemsWrap.className = "fb-container-slides";
|
|
6895
|
-
const slideCols = element.columns;
|
|
6896
|
-
const gridTemplateColumns = typeof slideCols === "number" && slideCols > 0 ? `repeat(${slideCols}, 1fr)` : "repeat(auto-fit, minmax(280px, 1fr))";
|
|
6897
|
-
itemsWrap.style.cssText = `display:grid;grid-template-columns:${gridTemplateColumns};gap:var(--fb-slides-gap, 14px);align-items:start;`;
|
|
6898
6959
|
} else {
|
|
6899
|
-
itemsWrap.className = "
|
|
6960
|
+
itemsWrap.className = "fb-row";
|
|
6900
6961
|
}
|
|
6901
6962
|
if (!containerIsReadonly) {
|
|
6902
6963
|
const hintsElement = createPrefillHints(element, element.key);
|
|
@@ -6930,7 +6991,9 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6930
6991
|
item.setAttribute("data-fb-slide-card", "");
|
|
6931
6992
|
}
|
|
6932
6993
|
const childWrapper = document.createElement("div");
|
|
6933
|
-
childWrapper.className = getChildWrapperClass(
|
|
6994
|
+
childWrapper.className = getChildWrapperClass(
|
|
6995
|
+
isSlides ? void 0 : element.columns
|
|
6996
|
+
);
|
|
6934
6997
|
element.elements.forEach((child) => {
|
|
6935
6998
|
var _a2;
|
|
6936
6999
|
if (child.type !== "markdown" && (child.hidden || child.type === "hidden")) {
|
|
@@ -6998,16 +7061,9 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6998
7061
|
item.setAttribute("data-fb-slide-card", "");
|
|
6999
7062
|
}
|
|
7000
7063
|
const childWrapper = document.createElement("div");
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
const columns = element.columns || 1;
|
|
7005
|
-
if (columns === 1) {
|
|
7006
|
-
childWrapper.className = "space-y-2";
|
|
7007
|
-
} else {
|
|
7008
|
-
childWrapper.className = `grid grid-cols-${columns} gap-2`;
|
|
7009
|
-
}
|
|
7010
|
-
}
|
|
7064
|
+
childWrapper.className = getChildWrapperClass(
|
|
7065
|
+
isSlides ? void 0 : element.columns
|
|
7066
|
+
);
|
|
7011
7067
|
element.elements.forEach((child) => {
|
|
7012
7068
|
var _a3, _b2;
|
|
7013
7069
|
if (child.type !== "markdown" && (child.hidden || child.type === "hidden")) {
|
|
@@ -7046,16 +7102,9 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
7046
7102
|
item.setAttribute("data-fb-slide-card", "");
|
|
7047
7103
|
}
|
|
7048
7104
|
const childWrapper = document.createElement("div");
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
const columns = element.columns || 1;
|
|
7053
|
-
if (columns === 1) {
|
|
7054
|
-
childWrapper.className = "space-y-2";
|
|
7055
|
-
} else {
|
|
7056
|
-
childWrapper.className = `grid grid-cols-${columns} gap-2`;
|
|
7057
|
-
}
|
|
7058
|
-
}
|
|
7105
|
+
childWrapper.className = getChildWrapperClass(
|
|
7106
|
+
isSlides ? void 0 : element.columns
|
|
7107
|
+
);
|
|
7059
7108
|
element.elements.forEach((child) => {
|
|
7060
7109
|
var _a2;
|
|
7061
7110
|
if (child.type !== "markdown" && (child.hidden || child.type === "hidden")) {
|
|
@@ -7085,7 +7134,6 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
7085
7134
|
containerWrap.appendChild(itemsWrap);
|
|
7086
7135
|
if (!containerIsReadonly) {
|
|
7087
7136
|
if (isSlides) {
|
|
7088
|
-
itemsWrap.style.alignItems = "stretch";
|
|
7089
7137
|
const handle = createSlideAddTile(handleAddItem, {
|
|
7090
7138
|
label: element.addLabel
|
|
7091
7139
|
});
|
|
@@ -8637,7 +8685,7 @@ function validateTableElement(element, key, context) {
|
|
|
8637
8685
|
if (!hiddenInput) {
|
|
8638
8686
|
return { value: null, errors };
|
|
8639
8687
|
}
|
|
8640
|
-
let value
|
|
8688
|
+
let value;
|
|
8641
8689
|
try {
|
|
8642
8690
|
value = JSON.parse(hiddenInput.value);
|
|
8643
8691
|
} catch {
|
|
@@ -10004,7 +10052,7 @@ function validateRichInputElement(element, key, context) {
|
|
|
10004
10052
|
if (!hiddenInput) {
|
|
10005
10053
|
return { value: null, errors };
|
|
10006
10054
|
}
|
|
10007
|
-
let rawValue
|
|
10055
|
+
let rawValue;
|
|
10008
10056
|
try {
|
|
10009
10057
|
const parsed = JSON.parse(hiddenInput.value);
|
|
10010
10058
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
@@ -10651,7 +10699,8 @@ function setupEnableIfListeners(wrapper, element, ctx) {
|
|
|
10651
10699
|
function createFieldLabel(element) {
|
|
10652
10700
|
var _a, _b;
|
|
10653
10701
|
const title = document.createElement("label");
|
|
10654
|
-
title.className = "
|
|
10702
|
+
title.className = "font-medium text-gray-900";
|
|
10703
|
+
title.style.cssText = "font-size: var(--fb-label-font-size, 0.75rem); line-height: var(--fb-label-line-height, 1.2);";
|
|
10655
10704
|
title.textContent = (_b = (_a = element.label) != null ? _a : element.key) != null ? _b : "";
|
|
10656
10705
|
if (element.required) {
|
|
10657
10706
|
const req = document.createElement("span");
|
|
@@ -10682,7 +10731,8 @@ function createInfoButton(element) {
|
|
|
10682
10731
|
}
|
|
10683
10732
|
function createLabelContainer(element) {
|
|
10684
10733
|
const label = document.createElement("div");
|
|
10685
|
-
label.className = "flex items-center
|
|
10734
|
+
label.className = "flex items-center";
|
|
10735
|
+
label.style.marginBottom = "var(--fb-label-margin-bottom, 2px)";
|
|
10686
10736
|
label.dataset.fbLabelRow = "";
|
|
10687
10737
|
const title = createFieldLabel(element);
|
|
10688
10738
|
label.appendChild(title);
|
|
@@ -10793,11 +10843,12 @@ function renderElement2(element, ctx) {
|
|
|
10793
10843
|
}
|
|
10794
10844
|
const initiallyDisabled2 = shouldDisableElement(element, ctx);
|
|
10795
10845
|
const outerWrapper = document.createElement("div");
|
|
10796
|
-
outerWrapper.className =
|
|
10846
|
+
outerWrapper.className = `fb-field-wrapper fb-markdown-wrapper fb-size-${element.size || "md"}`;
|
|
10797
10847
|
outerWrapper.setAttribute(
|
|
10798
10848
|
"data-field-key",
|
|
10799
10849
|
getElementLookupKey(element, ctx.state)
|
|
10800
10850
|
);
|
|
10851
|
+
outerWrapper.setAttribute("data-fb-width", element.width || "full");
|
|
10801
10852
|
renderMarkdown(element, ctx, outerWrapper);
|
|
10802
10853
|
if (initiallyDisabled2) {
|
|
10803
10854
|
outerWrapper.style.display = "none";
|
|
@@ -10809,8 +10860,9 @@ function renderElement2(element, ctx) {
|
|
|
10809
10860
|
}
|
|
10810
10861
|
const initiallyDisabled = shouldDisableElement(element, ctx);
|
|
10811
10862
|
const wrapper = document.createElement("div");
|
|
10812
|
-
wrapper.className =
|
|
10863
|
+
wrapper.className = `fb-field-wrapper fb-size-${element.size || "md"}`;
|
|
10813
10864
|
wrapper.setAttribute("data-field-key", element.key);
|
|
10865
|
+
wrapper.setAttribute("data-fb-width", element.width || "full");
|
|
10814
10866
|
const ops = getComponentOperations(element.type);
|
|
10815
10867
|
if (!(ops == null ? void 0 : ops.ownsLabel)) {
|
|
10816
10868
|
const label = createLabelContainer(element);
|
|
@@ -11132,9 +11184,9 @@ var defaultTheme = {
|
|
|
11132
11184
|
// blue-500
|
|
11133
11185
|
// Spacing
|
|
11134
11186
|
inputPaddingX: "0.5rem",
|
|
11135
|
-
// 8px (compact density
|
|
11136
|
-
inputPaddingY: "0.
|
|
11137
|
-
//
|
|
11187
|
+
// 8px (compact density v3 — v0.4.0)
|
|
11188
|
+
inputPaddingY: "0.125rem",
|
|
11189
|
+
// 2px (compact density v3 — v0.4.0)
|
|
11138
11190
|
borderRadius: "0.5rem",
|
|
11139
11191
|
// rounded-lg (8px)
|
|
11140
11192
|
borderRadiusSmall: "0.375rem",
|
|
@@ -11172,13 +11224,20 @@ var defaultTheme = {
|
|
|
11172
11224
|
slideCardRadius: "0.5rem",
|
|
11173
11225
|
// matches borderRadius
|
|
11174
11226
|
slideCardMinHeight: "0",
|
|
11175
|
-
slideCardPadding: "
|
|
11227
|
+
slideCardPadding: "8px",
|
|
11176
11228
|
// Section-label defaults — same look as the regular field label. Themes
|
|
11177
11229
|
// that want the "ПРЕИМУЩЕСТВА" caps style override these three vars.
|
|
11178
11230
|
labelSectionFontSize: "0.875rem",
|
|
11179
11231
|
// matches fontSize
|
|
11180
11232
|
labelSectionLetterSpacing: "normal",
|
|
11181
|
-
labelSectionTextTransform: "none"
|
|
11233
|
+
labelSectionTextTransform: "none",
|
|
11234
|
+
// Per-field label defaults — compact density: 12px @ 1.2 line-height with
|
|
11235
|
+
// a 2px gap to the input. Themes that prefer roomier labels (Picaz, klein)
|
|
11236
|
+
// can bump these via their override block.
|
|
11237
|
+
labelFontSize: "0.75rem",
|
|
11238
|
+
// 12px
|
|
11239
|
+
labelLineHeight: "1.2",
|
|
11240
|
+
labelMarginBottom: "2px"
|
|
11182
11241
|
};
|
|
11183
11242
|
function generateCSSVariables(theme) {
|
|
11184
11243
|
const mergedTheme = { ...defaultTheme, ...theme };
|
|
@@ -11724,7 +11783,7 @@ var FormBuilderInstance = class {
|
|
|
11724
11783
|
root.setAttribute("data-fb-root", "true");
|
|
11725
11784
|
injectThemeVariables(root, this.state.config.theme);
|
|
11726
11785
|
const rootContainer = document.createElement("div");
|
|
11727
|
-
rootContainer.className = "
|
|
11786
|
+
rootContainer.className = "fb-row";
|
|
11728
11787
|
if (schema.prefillHints && !this.state.config.readonly) {
|
|
11729
11788
|
const hintsContainer = this.createRootPrefillHints(schema.prefillHints);
|
|
11730
11789
|
rootContainer.appendChild(hintsContainer);
|
|
@@ -11732,7 +11791,7 @@ var FormBuilderInstance = class {
|
|
|
11732
11791
|
const fieldsWrapper = document.createElement("div");
|
|
11733
11792
|
const columns = schema.columns || 1;
|
|
11734
11793
|
if (columns === 1) {
|
|
11735
|
-
fieldsWrapper.className = "
|
|
11794
|
+
fieldsWrapper.className = "fb-row";
|
|
11736
11795
|
} else {
|
|
11737
11796
|
fieldsWrapper.className = `grid grid-cols-${columns} gap-2`;
|
|
11738
11797
|
}
|