@dmitryvim/form-builder 0.3.4 → 0.4.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 +164 -120
- package/dist/browser/formbuilder.v0.4.0.min.js +1485 -0
- package/dist/cjs/index.cjs +131 -67
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +125 -65
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +164 -120
- 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 +23 -0
- 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
|
@@ -473,20 +473,61 @@ function ensureThemingHooks(doc) {
|
|
|
473
473
|
color: #ffffff;
|
|
474
474
|
border-color: var(--fb-primary-color);
|
|
475
475
|
}
|
|
476
|
+
/* \u2500\u2500\u2500 Row layout: flex-wrap container with per-child width tokens \u2500\u2500\u2500
|
|
477
|
+
Replaces the older Tailwind \`space-y-2\` class. Children without
|
|
478
|
+
data-fb-width (or width="full") take 100% basis \u2192 forced wrap \u2192 behaves
|
|
479
|
+
like a vertical stack. Mixed widths sit side-by-side in the same row. */
|
|
480
|
+
.fb-row {
|
|
481
|
+
display: flex;
|
|
482
|
+
flex-wrap: wrap;
|
|
483
|
+
gap: var(--fb-row-gap, 0.25rem);
|
|
484
|
+
align-items: flex-start;
|
|
485
|
+
}
|
|
486
|
+
.fb-row > [data-fb-width="full"],
|
|
487
|
+
.fb-row > :not([data-fb-width]) { flex: 0 0 100%; min-width: 0; }
|
|
488
|
+
.fb-row > [data-fb-width="1/2"] { flex: 0 0 calc(50% - var(--fb-row-gap, 0.25rem) / 2); min-width: 0; }
|
|
489
|
+
.fb-row > [data-fb-width="1/3"] { flex: 0 0 calc(33.333% - var(--fb-row-gap, 0.25rem) * 2 / 3); min-width: 0; }
|
|
490
|
+
.fb-row > [data-fb-width="2/3"] { flex: 0 0 calc(66.666% - var(--fb-row-gap, 0.25rem) / 3); min-width: 0; }
|
|
491
|
+
/* \u2500\u2500\u2500 Density tokens: re-bind --fb-input-padding-* and --fb-font-size at
|
|
492
|
+
the wrapper level so every component that reads those vars (text, textarea,
|
|
493
|
+
select, number, colour, switcher, file) picks the size up via cascade. md
|
|
494
|
+
uses the defaults set in theme.ts (2px / 8px / 14px). The scale primarily
|
|
495
|
+
varies font-size; vertical padding stays close to md so an "lg" heading
|
|
496
|
+
field does not visually break the form's row rhythm \u2014 only the typography
|
|
497
|
+
announces "this is bigger". Picaz theme overrides padding directly for
|
|
498
|
+
its own density, independent of this scale. */
|
|
499
|
+
/* size-token side-effects on file tiles: --fb-file-wide-min controls the
|
|
500
|
+
single-file empty dropzone height, --fb-file-zone-min controls the inner
|
|
501
|
+
upload/library zones. Both read in src/components/file/styles.ts. */
|
|
502
|
+
.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; }
|
|
503
|
+
.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; }
|
|
504
|
+
/* .fb-size-md uses defaults \u2014 no override needed */
|
|
505
|
+
.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; }
|
|
506
|
+
.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
507
|
`;
|
|
477
508
|
doc.head.appendChild(style);
|
|
478
509
|
}
|
|
479
|
-
function applyAutoExpand(textarea) {
|
|
510
|
+
function applyAutoExpand(textarea, options = {}) {
|
|
511
|
+
var _a;
|
|
480
512
|
textarea.style.overflow = "hidden";
|
|
481
513
|
textarea.style.resize = "none";
|
|
514
|
+
const minRows = Math.max(1, (_a = options.minRows) != null ? _a : 1);
|
|
482
515
|
const lineCount = (textarea.value.match(/\n/g) || []).length + 1;
|
|
483
|
-
textarea.rows = Math.max(
|
|
516
|
+
textarea.rows = Math.max(minRows, lineCount);
|
|
484
517
|
const resize = () => {
|
|
485
518
|
if (!textarea.isConnected) return;
|
|
486
|
-
textarea.style.height = "
|
|
519
|
+
textarea.style.height = "";
|
|
487
520
|
const cs = getComputedStyle(textarea);
|
|
488
521
|
const borderY = parseFloat(cs.borderTopWidth || "0") + parseFloat(cs.borderBottomWidth || "0");
|
|
489
|
-
|
|
522
|
+
const lineHeight = parseFloat(cs.lineHeight || "0") || parseFloat(cs.fontSize || "0") * 1.5 || 20;
|
|
523
|
+
const padY = parseFloat(cs.paddingTop || "0") + parseFloat(cs.paddingBottom || "0");
|
|
524
|
+
const minHeight = lineHeight * minRows + padY + borderY;
|
|
525
|
+
if (textarea.value === "") {
|
|
526
|
+
textarea.style.height = `${minHeight}px`;
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
const contentHeight = textarea.scrollHeight + borderY;
|
|
530
|
+
textarea.style.height = `${Math.max(contentHeight, minHeight)}px`;
|
|
490
531
|
};
|
|
491
532
|
textarea.addEventListener("input", resize);
|
|
492
533
|
setTimeout(() => {
|
|
@@ -495,13 +536,13 @@ function applyAutoExpand(textarea) {
|
|
|
495
536
|
if (typeof ResizeObserver === "undefined") return;
|
|
496
537
|
let lastWidth = -1;
|
|
497
538
|
const ro = new ResizeObserver((entries) => {
|
|
498
|
-
var
|
|
539
|
+
var _a2, _b, _c, _d, _e;
|
|
499
540
|
if (!textarea.isConnected) {
|
|
500
541
|
ro.disconnect();
|
|
501
542
|
return;
|
|
502
543
|
}
|
|
503
544
|
const entry = entries[0];
|
|
504
|
-
const w = (_e = (_d = (_b = (
|
|
545
|
+
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
546
|
if (w === lastWidth) return;
|
|
506
547
|
lastWidth = w;
|
|
507
548
|
resize();
|
|
@@ -541,8 +582,8 @@ function createAddItemRow(classNameSuffix, onClick, options = {}) {
|
|
|
541
582
|
const label = (_a = options.label) != null ? _a : "";
|
|
542
583
|
const showCounter = options.showCounter !== false;
|
|
543
584
|
const row = document.createElement("div");
|
|
544
|
-
row.className = "fb-add-row
|
|
545
|
-
row.style.cssText = "display:flex;align-items:stretch;width:100%;";
|
|
585
|
+
row.className = "fb-add-row";
|
|
586
|
+
row.style.cssText = "display:flex;align-items:stretch;width:100%;margin-top:4px;";
|
|
546
587
|
const button = document.createElement("button");
|
|
547
588
|
button.type = "button";
|
|
548
589
|
button.className = `add-${classNameSuffix}-btn`;
|
|
@@ -551,8 +592,8 @@ function createAddItemRow(classNameSuffix, onClick, options = {}) {
|
|
|
551
592
|
display: inline-flex;
|
|
552
593
|
align-items: center;
|
|
553
594
|
justify-content: center;
|
|
554
|
-
gap:
|
|
555
|
-
padding:
|
|
595
|
+
gap: 4px;
|
|
596
|
+
padding: 3px 10px;
|
|
556
597
|
border: 1px dashed var(--fb-primary-color);
|
|
557
598
|
border-radius: var(--fb-border-radius);
|
|
558
599
|
background: transparent;
|
|
@@ -698,12 +739,12 @@ function ensureChipStyles(doc) {
|
|
|
698
739
|
const style = doc.createElement("style");
|
|
699
740
|
style.setAttribute("data-fb-chip-styles", "");
|
|
700
741
|
style.textContent = `
|
|
701
|
-
.fb-chip-list { display: flex; flex-direction: column; gap:
|
|
742
|
+
.fb-chip-list { display: flex; flex-direction: column; gap: 2px; }
|
|
702
743
|
.fb-chip {
|
|
703
744
|
display: flex;
|
|
704
745
|
align-items: center;
|
|
705
|
-
gap:
|
|
706
|
-
padding:
|
|
746
|
+
gap: 6px;
|
|
747
|
+
padding: 3px 6px 3px 8px;
|
|
707
748
|
background: var(--fb-chip-bg, var(--fb-background-color, #fff));
|
|
708
749
|
border: 1px solid var(--fb-chip-border, var(--fb-border-color, #e2e8f0));
|
|
709
750
|
border-radius: 6px;
|
|
@@ -729,7 +770,13 @@ function ensureChipStyles(doc) {
|
|
|
729
770
|
color: var(--fb-chip-text, var(--fb-text-color, inherit));
|
|
730
771
|
font-size: var(--fb-font-size, 14px);
|
|
731
772
|
font-family: var(--fb-font-family, inherit);
|
|
732
|
-
line-height: 1.4;
|
|
773
|
+
line-height: var(--fb-line-height, 1.4);
|
|
774
|
+
/* Soft-wrap support (v0.4.0): chip-input is now a <textarea rows=1> that
|
|
775
|
+
grows vertically when content overflows the chip width. */
|
|
776
|
+
resize: none;
|
|
777
|
+
overflow: hidden;
|
|
778
|
+
word-break: break-word;
|
|
779
|
+
overflow-wrap: anywhere;
|
|
733
780
|
}
|
|
734
781
|
.fb-chip-input::placeholder { color: var(--fb-text-placeholder-color, #94a3b8); }
|
|
735
782
|
.fb-chip-input:read-only { color: var(--fb-text-secondary-color, #475569); }
|
|
@@ -788,6 +835,7 @@ function createCharCounter(element, input) {
|
|
|
788
835
|
return counter;
|
|
789
836
|
}
|
|
790
837
|
function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
838
|
+
var _a;
|
|
791
839
|
const state = ctx.state;
|
|
792
840
|
const readonly = isElementReadonly(element, state, ctx);
|
|
793
841
|
const inputWrapper = document.createElement("div");
|
|
@@ -814,7 +862,7 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
814
862
|
overflow-wrap: anywhere;
|
|
815
863
|
`;
|
|
816
864
|
textInput.name = pathKey;
|
|
817
|
-
textInput.placeholder = element.placeholder
|
|
865
|
+
textInput.placeholder = (_a = element.placeholder) != null ? _a : "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442";
|
|
818
866
|
textInput.value = ctx.prefill[element.key] || element.default || "";
|
|
819
867
|
textInput.readOnly = readonly;
|
|
820
868
|
applySingleLineMode(textInput);
|
|
@@ -888,8 +936,8 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
888
936
|
dot.className = "fb-chip-dot";
|
|
889
937
|
dot.setAttribute("aria-hidden", "true");
|
|
890
938
|
chip.appendChild(dot);
|
|
891
|
-
const input = document.createElement("
|
|
892
|
-
input.
|
|
939
|
+
const input = document.createElement("textarea");
|
|
940
|
+
input.rows = 1;
|
|
893
941
|
input.className = "fb-chip-input";
|
|
894
942
|
input.value = value;
|
|
895
943
|
input.placeholder = element.placeholder || t("placeholderText", state);
|
|
@@ -905,6 +953,8 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
905
953
|
input.addEventListener("blur", handleChange);
|
|
906
954
|
input.addEventListener("input", handleChange);
|
|
907
955
|
}
|
|
956
|
+
applySingleLineMode(input);
|
|
957
|
+
applyAutoExpand(input);
|
|
908
958
|
if (!readonly) {
|
|
909
959
|
const rem = document.createElement("button");
|
|
910
960
|
rem.type = "button";
|
|
@@ -1119,6 +1169,7 @@ function updateTextField(element, fieldPath, value, context) {
|
|
|
1119
1169
|
|
|
1120
1170
|
// src/components/textarea.ts
|
|
1121
1171
|
function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
1172
|
+
var _a, _b;
|
|
1122
1173
|
const state = ctx.state;
|
|
1123
1174
|
const readonly = isElementReadonly(element, state, ctx);
|
|
1124
1175
|
const textareaWrapper = document.createElement("div");
|
|
@@ -1126,13 +1177,13 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1126
1177
|
const textareaInput = document.createElement("textarea");
|
|
1127
1178
|
textareaInput.className = "w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none";
|
|
1128
1179
|
textareaInput.style.cssText = `
|
|
1129
|
-
padding: var(--fb-input-padding-y) var(--fb-input-padding-x)
|
|
1180
|
+
padding: var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
1130
1181
|
font-size: var(--fb-font-size);
|
|
1131
1182
|
font-family: var(--fb-font-family);
|
|
1183
|
+
line-height: var(--fb-line-height, 1.5);
|
|
1132
1184
|
`;
|
|
1133
1185
|
textareaInput.name = pathKey;
|
|
1134
|
-
textareaInput.placeholder = element.placeholder
|
|
1135
|
-
textareaInput.rows = element.rows || 4;
|
|
1186
|
+
textareaInput.placeholder = (_a = element.placeholder) != null ? _a : "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442";
|
|
1136
1187
|
textareaInput.value = ctx.prefill[element.key] || element.default || "";
|
|
1137
1188
|
textareaInput.readOnly = readonly;
|
|
1138
1189
|
if (!readonly && ctx.instance) {
|
|
@@ -1143,9 +1194,7 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1143
1194
|
textareaInput.addEventListener("blur", handleChange);
|
|
1144
1195
|
textareaInput.addEventListener("input", handleChange);
|
|
1145
1196
|
}
|
|
1146
|
-
|
|
1147
|
-
applyAutoExpand(textareaInput);
|
|
1148
|
-
}
|
|
1197
|
+
applyAutoExpand(textareaInput, { minRows: (_b = element.rows) != null ? _b : 1 });
|
|
1149
1198
|
textareaWrapper.appendChild(textareaInput);
|
|
1150
1199
|
if (!readonly && (element.minLength != null || element.maxLength != null)) {
|
|
1151
1200
|
const counter = createCharCounter(element, textareaInput);
|
|
@@ -1165,7 +1214,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1165
1214
|
values.push(element.default || "");
|
|
1166
1215
|
}
|
|
1167
1216
|
const container = document.createElement("div");
|
|
1168
|
-
container.className = "
|
|
1217
|
+
container.className = "fb-row";
|
|
1169
1218
|
wrapper.appendChild(container);
|
|
1170
1219
|
function updateIndices() {
|
|
1171
1220
|
const items = container.querySelectorAll(".multiple-textarea-item");
|
|
@@ -1177,6 +1226,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1177
1226
|
});
|
|
1178
1227
|
}
|
|
1179
1228
|
function addTextareaItem(value = "", index = -1) {
|
|
1229
|
+
var _a2;
|
|
1180
1230
|
const itemWrapper = document.createElement("div");
|
|
1181
1231
|
itemWrapper.className = "multiple-textarea-item";
|
|
1182
1232
|
const textareaContainer = document.createElement("div");
|
|
@@ -1184,12 +1234,12 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1184
1234
|
const textareaInput = document.createElement("textarea");
|
|
1185
1235
|
textareaInput.className = "w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none";
|
|
1186
1236
|
textareaInput.style.cssText = `
|
|
1187
|
-
padding: var(--fb-input-padding-y) var(--fb-input-padding-x)
|
|
1237
|
+
padding: var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
1188
1238
|
font-size: var(--fb-font-size);
|
|
1189
1239
|
font-family: var(--fb-font-family);
|
|
1240
|
+
line-height: var(--fb-line-height, 1.5);
|
|
1190
1241
|
`;
|
|
1191
1242
|
textareaInput.placeholder = element.placeholder || t("placeholderText", state);
|
|
1192
|
-
textareaInput.rows = element.rows || 4;
|
|
1193
1243
|
textareaInput.value = value;
|
|
1194
1244
|
textareaInput.readOnly = readonly;
|
|
1195
1245
|
if (!readonly && ctx.instance) {
|
|
@@ -1200,9 +1250,7 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
1200
1250
|
textareaInput.addEventListener("blur", handleChange);
|
|
1201
1251
|
textareaInput.addEventListener("input", handleChange);
|
|
1202
1252
|
}
|
|
1203
|
-
|
|
1204
|
-
applyAutoExpand(textareaInput);
|
|
1205
|
-
}
|
|
1253
|
+
applyAutoExpand(textareaInput, { minRows: (_a2 = element.rows) != null ? _a2 : 1 });
|
|
1206
1254
|
textareaContainer.appendChild(textareaInput);
|
|
1207
1255
|
if (!readonly && (element.minLength != null || element.maxLength != null)) {
|
|
1208
1256
|
const counter = createCharCounter(element, textareaInput);
|
|
@@ -1278,9 +1326,7 @@ function validateTextareaElement(element, key, context) {
|
|
|
1278
1326
|
}
|
|
1279
1327
|
function updateTextareaField(element, fieldPath, value, context) {
|
|
1280
1328
|
updateTextField(element, fieldPath, value, context);
|
|
1281
|
-
const { scopeRoot
|
|
1282
|
-
const shouldAutoExpand = element.autoExpand || isElementReadonly(element, state);
|
|
1283
|
-
if (!shouldAutoExpand) return;
|
|
1329
|
+
const { scopeRoot } = context;
|
|
1284
1330
|
if (element.multiple) {
|
|
1285
1331
|
const textareas = scopeRoot.querySelectorAll(
|
|
1286
1332
|
`textarea[name^="${fieldPath}["]`
|
|
@@ -1478,7 +1524,7 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1478
1524
|
values.push(element.default || "");
|
|
1479
1525
|
}
|
|
1480
1526
|
const container = document.createElement("div");
|
|
1481
|
-
container.className = "
|
|
1527
|
+
container.className = "fb-row";
|
|
1482
1528
|
wrapper.appendChild(container);
|
|
1483
1529
|
function updateIndices() {
|
|
1484
1530
|
const items = container.querySelectorAll(".multiple-number-item");
|
|
@@ -1796,7 +1842,7 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1796
1842
|
values.push(element.default || ((_d = (_c = element.options) == null ? void 0 : _c[0]) == null ? void 0 : _d.value) || "");
|
|
1797
1843
|
}
|
|
1798
1844
|
const container = document.createElement("div");
|
|
1799
|
-
container.className = "
|
|
1845
|
+
container.className = "fb-row";
|
|
1800
1846
|
wrapper.appendChild(container);
|
|
1801
1847
|
function updateIndices() {
|
|
1802
1848
|
const items = container.querySelectorAll(".multiple-select-item");
|
|
@@ -2233,7 +2279,7 @@ function renderMultipleSwitcherElement(element, ctx, wrapper, pathKey) {
|
|
|
2233
2279
|
}
|
|
2234
2280
|
const readonly = isElementReadonly(element, state, ctx);
|
|
2235
2281
|
const container = document.createElement("div");
|
|
2236
|
-
container.className = "
|
|
2282
|
+
container.className = "fb-row";
|
|
2237
2283
|
wrapper.appendChild(container);
|
|
2238
2284
|
function updateIndices() {
|
|
2239
2285
|
const items = container.querySelectorAll(".multiple-switcher-item");
|
|
@@ -2818,7 +2864,9 @@ function ensureFileStyles() {
|
|
|
2818
2864
|
align-items: stretch;
|
|
2819
2865
|
gap: 0;
|
|
2820
2866
|
overflow: hidden;
|
|
2821
|
-
min-height
|
|
2867
|
+
/* min-height driven by --fb-file-wide-min so size-tokens (.fb-size-{xs|sm|lg|xl})
|
|
2868
|
+
can override per-field. Default 96px matches v0.4.0 compact density. */
|
|
2869
|
+
min-height: var(--fb-file-wide-min, 96px);
|
|
2822
2870
|
transition: border-color 150ms, background 150ms, box-shadow 150ms;
|
|
2823
2871
|
cursor: pointer;
|
|
2824
2872
|
}
|
|
@@ -2837,14 +2885,15 @@ function ensureFileStyles() {
|
|
|
2837
2885
|
upload + library on one row (~220 + 176), library wraps below. */
|
|
2838
2886
|
.fb-wide-tile-upload {
|
|
2839
2887
|
flex: 1 1 220px;
|
|
2840
|
-
min-height
|
|
2888
|
+
/* min-height theme-driven; default 72px matches v0.4.0 compact density. */
|
|
2889
|
+
min-height: var(--fb-file-zone-min, 72px);
|
|
2841
2890
|
display: flex;
|
|
2842
2891
|
flex-direction: column;
|
|
2843
2892
|
align-items: center;
|
|
2844
2893
|
justify-content: center;
|
|
2845
|
-
gap:
|
|
2894
|
+
gap: 4px;
|
|
2846
2895
|
color: #2563eb;
|
|
2847
|
-
padding:
|
|
2896
|
+
padding: var(--fb-file-zone-padding, 8px);
|
|
2848
2897
|
transition: background 150ms;
|
|
2849
2898
|
cursor: pointer;
|
|
2850
2899
|
background: transparent;
|
|
@@ -2864,14 +2913,16 @@ function ensureFileStyles() {
|
|
|
2864
2913
|
visual hierarchy "upload > library" in both layouts. */
|
|
2865
2914
|
.fb-wide-tile-library {
|
|
2866
2915
|
flex: 0 0 176px;
|
|
2867
|
-
min-
|
|
2916
|
+
/* Shares --fb-file-zone-min with the upload zone so size-tokens scale both
|
|
2917
|
+
uniformly. Default 72px matches v0.4.0 compact density. */
|
|
2918
|
+
min-height: var(--fb-file-zone-min, 72px);
|
|
2868
2919
|
display: flex;
|
|
2869
2920
|
flex-direction: column;
|
|
2870
2921
|
align-items: center;
|
|
2871
2922
|
justify-content: center;
|
|
2872
|
-
gap:
|
|
2923
|
+
gap: 4px;
|
|
2873
2924
|
color: #2563eb;
|
|
2874
|
-
padding:
|
|
2925
|
+
padding: var(--fb-file-zone-padding, 8px);
|
|
2875
2926
|
transition: background 150ms;
|
|
2876
2927
|
cursor: pointer;
|
|
2877
2928
|
background: transparent;
|
|
@@ -4148,7 +4199,9 @@ function downloadBlob(blob, fileName) {
|
|
|
4148
4199
|
URL.revokeObjectURL(blobUrl);
|
|
4149
4200
|
}, 100);
|
|
4150
4201
|
} catch (error) {
|
|
4151
|
-
throw new Error(`Blob download failed: ${error.message}
|
|
4202
|
+
throw new Error(`Blob download failed: ${error.message}`, {
|
|
4203
|
+
cause: error
|
|
4204
|
+
});
|
|
4152
4205
|
}
|
|
4153
4206
|
}
|
|
4154
4207
|
|
|
@@ -5106,7 +5159,7 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
5106
5159
|
var _a, _b;
|
|
5107
5160
|
const state = ctx.state;
|
|
5108
5161
|
const fileWrapper = document.createElement("div");
|
|
5109
|
-
fileWrapper.className = "
|
|
5162
|
+
fileWrapper.className = "fb-row";
|
|
5110
5163
|
fileWrapper.dataset.filesWrapper = pathKey;
|
|
5111
5164
|
const picker = document.createElement("input");
|
|
5112
5165
|
picker.type = "file";
|
|
@@ -5257,7 +5310,7 @@ function setupMultiFileEditMode(element, ctx, wrapper, pathKey, maxFiles) {
|
|
|
5257
5310
|
var _a, _b;
|
|
5258
5311
|
const state = ctx.state;
|
|
5259
5312
|
const filesWrapper = document.createElement("div");
|
|
5260
|
-
filesWrapper.className = "
|
|
5313
|
+
filesWrapper.className = "fb-row";
|
|
5261
5314
|
filesWrapper.dataset.filesWrapper = pathKey;
|
|
5262
5315
|
const filesPicker = document.createElement("input");
|
|
5263
5316
|
filesPicker.type = "file";
|
|
@@ -5939,7 +5992,7 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
5939
5992
|
values.push(element.default || "#000000");
|
|
5940
5993
|
}
|
|
5941
5994
|
const container = document.createElement("div");
|
|
5942
|
-
container.className = "
|
|
5995
|
+
container.className = "fb-row";
|
|
5943
5996
|
wrapper.appendChild(container);
|
|
5944
5997
|
function updateIndices() {
|
|
5945
5998
|
const items = container.querySelectorAll(".multiple-colour-item");
|
|
@@ -6805,7 +6858,7 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
6805
6858
|
const itemsWrap = document.createElement("div");
|
|
6806
6859
|
const columns = element.columns || 1;
|
|
6807
6860
|
if (columns === 1) {
|
|
6808
|
-
itemsWrap.className = "
|
|
6861
|
+
itemsWrap.className = "fb-row";
|
|
6809
6862
|
} else {
|
|
6810
6863
|
itemsWrap.className = `grid grid-cols-${columns} gap-2`;
|
|
6811
6864
|
}
|
|
@@ -6845,10 +6898,10 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
6845
6898
|
}
|
|
6846
6899
|
function getChildWrapperClass(isSlides, columns) {
|
|
6847
6900
|
if (isSlides) {
|
|
6848
|
-
return "
|
|
6901
|
+
return "fb-row";
|
|
6849
6902
|
}
|
|
6850
6903
|
const cols = columns || 1;
|
|
6851
|
-
return cols === 1 ? "
|
|
6904
|
+
return cols === 1 ? "fb-row" : `grid grid-cols-${cols} gap-2`;
|
|
6852
6905
|
}
|
|
6853
6906
|
function mountRemoveButton(item, onRemove, state) {
|
|
6854
6907
|
const rem = document.createElement("button");
|
|
@@ -6896,7 +6949,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6896
6949
|
const gridTemplateColumns = typeof slideCols === "number" && slideCols > 0 ? `repeat(${slideCols}, 1fr)` : "repeat(auto-fit, minmax(280px, 1fr))";
|
|
6897
6950
|
itemsWrap.style.cssText = `display:grid;grid-template-columns:${gridTemplateColumns};gap:var(--fb-slides-gap, 14px);align-items:start;`;
|
|
6898
6951
|
} else {
|
|
6899
|
-
itemsWrap.className = "
|
|
6952
|
+
itemsWrap.className = "fb-row";
|
|
6900
6953
|
}
|
|
6901
6954
|
if (!containerIsReadonly) {
|
|
6902
6955
|
const hintsElement = createPrefillHints(element, element.key);
|
|
@@ -6999,11 +7052,11 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6999
7052
|
}
|
|
7000
7053
|
const childWrapper = document.createElement("div");
|
|
7001
7054
|
if (isSlides) {
|
|
7002
|
-
childWrapper.className = "
|
|
7055
|
+
childWrapper.className = "fb-row";
|
|
7003
7056
|
} else {
|
|
7004
7057
|
const columns = element.columns || 1;
|
|
7005
7058
|
if (columns === 1) {
|
|
7006
|
-
childWrapper.className = "
|
|
7059
|
+
childWrapper.className = "fb-row";
|
|
7007
7060
|
} else {
|
|
7008
7061
|
childWrapper.className = `grid grid-cols-${columns} gap-2`;
|
|
7009
7062
|
}
|
|
@@ -7047,11 +7100,11 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
7047
7100
|
}
|
|
7048
7101
|
const childWrapper = document.createElement("div");
|
|
7049
7102
|
if (isSlides) {
|
|
7050
|
-
childWrapper.className = "
|
|
7103
|
+
childWrapper.className = "fb-row";
|
|
7051
7104
|
} else {
|
|
7052
7105
|
const columns = element.columns || 1;
|
|
7053
7106
|
if (columns === 1) {
|
|
7054
|
-
childWrapper.className = "
|
|
7107
|
+
childWrapper.className = "fb-row";
|
|
7055
7108
|
} else {
|
|
7056
7109
|
childWrapper.className = `grid grid-cols-${columns} gap-2`;
|
|
7057
7110
|
}
|
|
@@ -8637,7 +8690,7 @@ function validateTableElement(element, key, context) {
|
|
|
8637
8690
|
if (!hiddenInput) {
|
|
8638
8691
|
return { value: null, errors };
|
|
8639
8692
|
}
|
|
8640
|
-
let value
|
|
8693
|
+
let value;
|
|
8641
8694
|
try {
|
|
8642
8695
|
value = JSON.parse(hiddenInput.value);
|
|
8643
8696
|
} catch {
|
|
@@ -10004,7 +10057,7 @@ function validateRichInputElement(element, key, context) {
|
|
|
10004
10057
|
if (!hiddenInput) {
|
|
10005
10058
|
return { value: null, errors };
|
|
10006
10059
|
}
|
|
10007
|
-
let rawValue
|
|
10060
|
+
let rawValue;
|
|
10008
10061
|
try {
|
|
10009
10062
|
const parsed = JSON.parse(hiddenInput.value);
|
|
10010
10063
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
@@ -10651,7 +10704,8 @@ function setupEnableIfListeners(wrapper, element, ctx) {
|
|
|
10651
10704
|
function createFieldLabel(element) {
|
|
10652
10705
|
var _a, _b;
|
|
10653
10706
|
const title = document.createElement("label");
|
|
10654
|
-
title.className = "
|
|
10707
|
+
title.className = "font-medium text-gray-900";
|
|
10708
|
+
title.style.cssText = "font-size: var(--fb-label-font-size, 0.75rem); line-height: var(--fb-label-line-height, 1.2);";
|
|
10655
10709
|
title.textContent = (_b = (_a = element.label) != null ? _a : element.key) != null ? _b : "";
|
|
10656
10710
|
if (element.required) {
|
|
10657
10711
|
const req = document.createElement("span");
|
|
@@ -10682,7 +10736,8 @@ function createInfoButton(element) {
|
|
|
10682
10736
|
}
|
|
10683
10737
|
function createLabelContainer(element) {
|
|
10684
10738
|
const label = document.createElement("div");
|
|
10685
|
-
label.className = "flex items-center
|
|
10739
|
+
label.className = "flex items-center";
|
|
10740
|
+
label.style.marginBottom = "var(--fb-label-margin-bottom, 2px)";
|
|
10686
10741
|
label.dataset.fbLabelRow = "";
|
|
10687
10742
|
const title = createFieldLabel(element);
|
|
10688
10743
|
label.appendChild(title);
|
|
@@ -10793,11 +10848,12 @@ function renderElement2(element, ctx) {
|
|
|
10793
10848
|
}
|
|
10794
10849
|
const initiallyDisabled2 = shouldDisableElement(element, ctx);
|
|
10795
10850
|
const outerWrapper = document.createElement("div");
|
|
10796
|
-
outerWrapper.className =
|
|
10851
|
+
outerWrapper.className = `fb-field-wrapper fb-markdown-wrapper fb-size-${element.size || "md"}`;
|
|
10797
10852
|
outerWrapper.setAttribute(
|
|
10798
10853
|
"data-field-key",
|
|
10799
10854
|
getElementLookupKey(element, ctx.state)
|
|
10800
10855
|
);
|
|
10856
|
+
outerWrapper.setAttribute("data-fb-width", element.width || "full");
|
|
10801
10857
|
renderMarkdown(element, ctx, outerWrapper);
|
|
10802
10858
|
if (initiallyDisabled2) {
|
|
10803
10859
|
outerWrapper.style.display = "none";
|
|
@@ -10809,8 +10865,9 @@ function renderElement2(element, ctx) {
|
|
|
10809
10865
|
}
|
|
10810
10866
|
const initiallyDisabled = shouldDisableElement(element, ctx);
|
|
10811
10867
|
const wrapper = document.createElement("div");
|
|
10812
|
-
wrapper.className =
|
|
10868
|
+
wrapper.className = `fb-field-wrapper fb-size-${element.size || "md"}`;
|
|
10813
10869
|
wrapper.setAttribute("data-field-key", element.key);
|
|
10870
|
+
wrapper.setAttribute("data-fb-width", element.width || "full");
|
|
10814
10871
|
const ops = getComponentOperations(element.type);
|
|
10815
10872
|
if (!(ops == null ? void 0 : ops.ownsLabel)) {
|
|
10816
10873
|
const label = createLabelContainer(element);
|
|
@@ -11132,9 +11189,9 @@ var defaultTheme = {
|
|
|
11132
11189
|
// blue-500
|
|
11133
11190
|
// Spacing
|
|
11134
11191
|
inputPaddingX: "0.5rem",
|
|
11135
|
-
// 8px (compact density
|
|
11136
|
-
inputPaddingY: "0.
|
|
11137
|
-
//
|
|
11192
|
+
// 8px (compact density v3 — v0.4.0)
|
|
11193
|
+
inputPaddingY: "0.125rem",
|
|
11194
|
+
// 2px (compact density v3 — v0.4.0)
|
|
11138
11195
|
borderRadius: "0.5rem",
|
|
11139
11196
|
// rounded-lg (8px)
|
|
11140
11197
|
borderRadiusSmall: "0.375rem",
|
|
@@ -11172,13 +11229,20 @@ var defaultTheme = {
|
|
|
11172
11229
|
slideCardRadius: "0.5rem",
|
|
11173
11230
|
// matches borderRadius
|
|
11174
11231
|
slideCardMinHeight: "0",
|
|
11175
|
-
slideCardPadding: "
|
|
11232
|
+
slideCardPadding: "8px",
|
|
11176
11233
|
// Section-label defaults — same look as the regular field label. Themes
|
|
11177
11234
|
// that want the "ПРЕИМУЩЕСТВА" caps style override these three vars.
|
|
11178
11235
|
labelSectionFontSize: "0.875rem",
|
|
11179
11236
|
// matches fontSize
|
|
11180
11237
|
labelSectionLetterSpacing: "normal",
|
|
11181
|
-
labelSectionTextTransform: "none"
|
|
11238
|
+
labelSectionTextTransform: "none",
|
|
11239
|
+
// Per-field label defaults — compact density: 12px @ 1.2 line-height with
|
|
11240
|
+
// a 2px gap to the input. Themes that prefer roomier labels (Picaz, klein)
|
|
11241
|
+
// can bump these via their override block.
|
|
11242
|
+
labelFontSize: "0.75rem",
|
|
11243
|
+
// 12px
|
|
11244
|
+
labelLineHeight: "1.2",
|
|
11245
|
+
labelMarginBottom: "2px"
|
|
11182
11246
|
};
|
|
11183
11247
|
function generateCSSVariables(theme) {
|
|
11184
11248
|
const mergedTheme = { ...defaultTheme, ...theme };
|
|
@@ -11724,7 +11788,7 @@ var FormBuilderInstance = class {
|
|
|
11724
11788
|
root.setAttribute("data-fb-root", "true");
|
|
11725
11789
|
injectThemeVariables(root, this.state.config.theme);
|
|
11726
11790
|
const rootContainer = document.createElement("div");
|
|
11727
|
-
rootContainer.className = "
|
|
11791
|
+
rootContainer.className = "fb-row";
|
|
11728
11792
|
if (schema.prefillHints && !this.state.config.readonly) {
|
|
11729
11793
|
const hintsContainer = this.createRootPrefillHints(schema.prefillHints);
|
|
11730
11794
|
rootContainer.appendChild(hintsContainer);
|
|
@@ -11732,7 +11796,7 @@ var FormBuilderInstance = class {
|
|
|
11732
11796
|
const fieldsWrapper = document.createElement("div");
|
|
11733
11797
|
const columns = schema.columns || 1;
|
|
11734
11798
|
if (columns === 1) {
|
|
11735
|
-
fieldsWrapper.className = "
|
|
11799
|
+
fieldsWrapper.className = "fb-row";
|
|
11736
11800
|
} else {
|
|
11737
11801
|
fieldsWrapper.className = `grid grid-cols-${columns} gap-2`;
|
|
11738
11802
|
}
|