@dmitryvim/form-builder 0.2.32 → 0.2.34
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 +189 -175
- package/dist/browser/formbuilder.v0.2.34.min.js +1162 -0
- package/dist/cjs/index.cjs +584 -496
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +579 -493
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +189 -175
- package/dist/types/components/colour.d.ts +1 -0
- package/dist/types/components/file/upload.d.ts +4 -0
- package/dist/types/components/file.d.ts +2 -2
- package/dist/types/types/config.d.ts +1 -0
- package/dist/types/types/schema.d.ts +8 -0
- package/dist/types/utils/styles.d.ts +42 -0
- package/package.json +1 -1
- package/dist/browser/formbuilder.v0.2.32.min.js +0 -1148
package/dist/cjs/index.cjs
CHANGED
|
@@ -406,6 +406,169 @@ function deepEqual(a, b) {
|
|
|
406
406
|
return a === b;
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
+
// src/utils/styles.ts
|
|
410
|
+
function mountCounterInLabel(wrapper, counter) {
|
|
411
|
+
const labelRow = wrapper.querySelector(
|
|
412
|
+
":scope > [data-fb-label-row]"
|
|
413
|
+
);
|
|
414
|
+
if (labelRow) labelRow.appendChild(counter);
|
|
415
|
+
}
|
|
416
|
+
function createAddItemRow(classNameSuffix, onClick, options = {}) {
|
|
417
|
+
var _a;
|
|
418
|
+
const label = (_a = options.label) != null ? _a : "";
|
|
419
|
+
const showCounter = options.showCounter !== false;
|
|
420
|
+
const row = document.createElement("div");
|
|
421
|
+
row.className = "fb-add-row mt-2";
|
|
422
|
+
row.style.cssText = "display:flex;align-items:stretch;width:100%;";
|
|
423
|
+
const button = document.createElement("button");
|
|
424
|
+
button.type = "button";
|
|
425
|
+
button.className = `add-${classNameSuffix}-btn`;
|
|
426
|
+
button.style.cssText = `
|
|
427
|
+
flex: 1 1 auto;
|
|
428
|
+
display: inline-flex;
|
|
429
|
+
align-items: center;
|
|
430
|
+
justify-content: center;
|
|
431
|
+
gap: 6px;
|
|
432
|
+
padding: 6px 10px;
|
|
433
|
+
border: 1px dashed var(--fb-primary-color);
|
|
434
|
+
border-radius: var(--fb-border-radius);
|
|
435
|
+
background: transparent;
|
|
436
|
+
color: var(--fb-primary-color);
|
|
437
|
+
font-size: var(--fb-font-size-small, var(--fb-font-size));
|
|
438
|
+
font-weight: 500;
|
|
439
|
+
font-family: var(--fb-font-family);
|
|
440
|
+
cursor: pointer;
|
|
441
|
+
transition: border-color var(--fb-transition-duration), color var(--fb-transition-duration), background-color var(--fb-transition-duration);
|
|
442
|
+
`;
|
|
443
|
+
button.textContent = label ? `+ ${label}` : "+";
|
|
444
|
+
button.addEventListener("mouseenter", () => {
|
|
445
|
+
if (button.disabled) return;
|
|
446
|
+
button.style.borderStyle = "solid";
|
|
447
|
+
button.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
448
|
+
});
|
|
449
|
+
button.addEventListener("mouseleave", () => {
|
|
450
|
+
button.style.borderStyle = "dashed";
|
|
451
|
+
button.style.backgroundColor = "transparent";
|
|
452
|
+
});
|
|
453
|
+
button.onclick = onClick;
|
|
454
|
+
const counter = document.createElement("span");
|
|
455
|
+
counter.className = "fb-add-counter";
|
|
456
|
+
counter.style.cssText = `
|
|
457
|
+
margin-left: auto;
|
|
458
|
+
font-size: var(--fb-font-size-small, 0.875rem);
|
|
459
|
+
color: var(--fb-text-secondary-color);
|
|
460
|
+
font-weight: 400;
|
|
461
|
+
`;
|
|
462
|
+
if (!showCounter) counter.style.display = "none";
|
|
463
|
+
row.appendChild(button);
|
|
464
|
+
const update = (current, max) => {
|
|
465
|
+
const reached = current >= max;
|
|
466
|
+
row.style.display = reached ? "none" : "flex";
|
|
467
|
+
button.style.display = reached ? "none" : "inline-flex";
|
|
468
|
+
button.disabled = reached;
|
|
469
|
+
if (showCounter) {
|
|
470
|
+
counter.textContent = `${current}/${max === Infinity ? "\u221E" : max}`;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
return { row, button, counter, update };
|
|
474
|
+
}
|
|
475
|
+
function createSlideAddTile(onClick, options = {}) {
|
|
476
|
+
var _a;
|
|
477
|
+
const label = (_a = options.label) != null ? _a : "";
|
|
478
|
+
const tile = document.createElement("button");
|
|
479
|
+
tile.type = "button";
|
|
480
|
+
tile.className = "add-container-btn fb-slide-add";
|
|
481
|
+
tile.style.cssText = `
|
|
482
|
+
display: flex;
|
|
483
|
+
flex-direction: column;
|
|
484
|
+
align-items: center;
|
|
485
|
+
justify-content: center;
|
|
486
|
+
gap: 12px;
|
|
487
|
+
width: 100%;
|
|
488
|
+
min-height: 180px;
|
|
489
|
+
align-self: stretch;
|
|
490
|
+
padding: 24px 16px;
|
|
491
|
+
border: 1.5px dashed var(--fb-primary-color);
|
|
492
|
+
border-radius: var(--fb-border-radius);
|
|
493
|
+
background: transparent;
|
|
494
|
+
color: var(--fb-primary-color);
|
|
495
|
+
font-size: var(--fb-font-size-small, var(--fb-font-size));
|
|
496
|
+
font-weight: 500;
|
|
497
|
+
font-family: var(--fb-font-family);
|
|
498
|
+
cursor: pointer;
|
|
499
|
+
transition: border-color var(--fb-transition-duration), color var(--fb-transition-duration), background-color var(--fb-transition-duration);
|
|
500
|
+
`;
|
|
501
|
+
const circle = document.createElement("span");
|
|
502
|
+
circle.className = "fb-slide-add-circle";
|
|
503
|
+
circle.style.cssText = `
|
|
504
|
+
display: inline-flex;
|
|
505
|
+
align-items: center;
|
|
506
|
+
justify-content: center;
|
|
507
|
+
width: 36px;
|
|
508
|
+
height: 36px;
|
|
509
|
+
border: 1px solid var(--fb-primary-color);
|
|
510
|
+
border-radius: 50%;
|
|
511
|
+
background: var(--fb-background-color);
|
|
512
|
+
font-size: 20px;
|
|
513
|
+
line-height: 1;
|
|
514
|
+
color: inherit;
|
|
515
|
+
transition: inherit;
|
|
516
|
+
`;
|
|
517
|
+
circle.textContent = "+";
|
|
518
|
+
tile.appendChild(circle);
|
|
519
|
+
if (label) {
|
|
520
|
+
const text = document.createElement("span");
|
|
521
|
+
text.textContent = label;
|
|
522
|
+
tile.appendChild(text);
|
|
523
|
+
}
|
|
524
|
+
tile.addEventListener("mouseenter", () => {
|
|
525
|
+
if (tile.disabled) return;
|
|
526
|
+
tile.style.borderStyle = "solid";
|
|
527
|
+
tile.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
528
|
+
});
|
|
529
|
+
tile.addEventListener("mouseleave", () => {
|
|
530
|
+
tile.style.borderStyle = "dashed";
|
|
531
|
+
tile.style.backgroundColor = "transparent";
|
|
532
|
+
});
|
|
533
|
+
tile.onclick = onClick;
|
|
534
|
+
const counter = document.createElement("span");
|
|
535
|
+
counter.className = "fb-add-counter";
|
|
536
|
+
counter.style.cssText = `
|
|
537
|
+
margin-left: auto;
|
|
538
|
+
font-size: var(--fb-font-size-small, 0.875rem);
|
|
539
|
+
color: var(--fb-text-secondary-color);
|
|
540
|
+
font-weight: 400;
|
|
541
|
+
`;
|
|
542
|
+
const update = (current, max) => {
|
|
543
|
+
const reached = current >= max;
|
|
544
|
+
tile.style.display = reached ? "none" : "flex";
|
|
545
|
+
tile.disabled = reached;
|
|
546
|
+
counter.textContent = `${current}/${max === Infinity ? "\u221E" : max}`;
|
|
547
|
+
};
|
|
548
|
+
return { tile, counter, update };
|
|
549
|
+
}
|
|
550
|
+
function applyActionButtonStyles(button, isFormLevel = false) {
|
|
551
|
+
button.style.cssText = `
|
|
552
|
+
background-color: var(--fb-action-bg-color);
|
|
553
|
+
color: var(--fb-action-text-color);
|
|
554
|
+
border: var(--fb-border-width) solid var(--fb-action-border-color);
|
|
555
|
+
padding: ${isFormLevel ? "0.5rem 1rem" : "0.5rem 0.75rem"};
|
|
556
|
+
font-size: var(--fb-font-size);
|
|
557
|
+
font-weight: var(--fb-font-weight-medium);
|
|
558
|
+
border-radius: var(--fb-border-radius);
|
|
559
|
+
transition: all var(--fb-transition-duration);
|
|
560
|
+
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
561
|
+
`;
|
|
562
|
+
button.addEventListener("mouseenter", () => {
|
|
563
|
+
button.style.backgroundColor = "var(--fb-action-hover-bg-color)";
|
|
564
|
+
button.style.borderColor = "var(--fb-action-hover-border-color)";
|
|
565
|
+
});
|
|
566
|
+
button.addEventListener("mouseleave", () => {
|
|
567
|
+
button.style.backgroundColor = "var(--fb-action-bg-color)";
|
|
568
|
+
button.style.borderColor = "var(--fb-action-border-color)";
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
409
572
|
// src/components/text.ts
|
|
410
573
|
function createCharCounter(element, input, isTextarea = false) {
|
|
411
574
|
const counter = document.createElement("span");
|
|
@@ -458,12 +621,13 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
458
621
|
const readonly = isElementReadonly(element, state, ctx);
|
|
459
622
|
const inputWrapper = document.createElement("div");
|
|
460
623
|
inputWrapper.style.cssText = "position: relative;";
|
|
624
|
+
const hasCharCounter = !readonly && (element.minLength != null || element.maxLength != null);
|
|
461
625
|
const textInput = document.createElement("input");
|
|
462
626
|
textInput.type = "text";
|
|
463
627
|
textInput.className = "w-full rounded-lg";
|
|
464
628
|
textInput.style.cssText = `
|
|
465
629
|
padding: var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
466
|
-
padding-right: 60px;
|
|
630
|
+
${hasCharCounter ? "padding-right: 60px;" : ""}
|
|
467
631
|
border: var(--fb-border-width) solid var(--fb-border-color);
|
|
468
632
|
border-radius: var(--fb-border-radius);
|
|
469
633
|
background-color: ${readonly ? "var(--fb-background-readonly-color)" : "var(--fb-background-color)"};
|
|
@@ -508,7 +672,7 @@ function renderTextElement(element, ctx, wrapper, pathKey) {
|
|
|
508
672
|
textInput.addEventListener("input", handleChange);
|
|
509
673
|
}
|
|
510
674
|
inputWrapper.appendChild(textInput);
|
|
511
|
-
if (
|
|
675
|
+
if (hasCharCounter) {
|
|
512
676
|
const counter = createCharCounter(element, textInput, false);
|
|
513
677
|
inputWrapper.appendChild(counter);
|
|
514
678
|
}
|
|
@@ -520,6 +684,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
520
684
|
const readonly = isElementReadonly(element, state, ctx);
|
|
521
685
|
const prefillValues = ctx.prefill[element.key] || [];
|
|
522
686
|
const values = Array.isArray(prefillValues) ? [...prefillValues] : [];
|
|
687
|
+
const hasCharCounter = !readonly && (element.minLength != null || element.maxLength != null);
|
|
523
688
|
const minCount = (_a = element.minCount) != null ? _a : 1;
|
|
524
689
|
const maxCount = (_b = element.maxCount) != null ? _b : Infinity;
|
|
525
690
|
while (values.length < minCount) {
|
|
@@ -546,7 +711,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
546
711
|
textInput.type = "text";
|
|
547
712
|
textInput.style.cssText = `
|
|
548
713
|
padding: var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
549
|
-
padding-right: 60px;
|
|
714
|
+
${hasCharCounter ? "padding-right: 60px;" : ""}
|
|
550
715
|
border: var(--fb-border-width) solid var(--fb-border-color);
|
|
551
716
|
border-radius: var(--fb-border-radius);
|
|
552
717
|
background-color: ${readonly ? "var(--fb-background-readonly-color)" : "var(--fb-background-color)"};
|
|
@@ -590,7 +755,7 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
590
755
|
textInput.addEventListener("input", handleChange);
|
|
591
756
|
}
|
|
592
757
|
inputContainer.appendChild(textInput);
|
|
593
|
-
if (
|
|
758
|
+
if (hasCharCounter) {
|
|
594
759
|
const counter = createCharCounter(element, textInput, false);
|
|
595
760
|
inputContainer.appendChild(counter);
|
|
596
761
|
}
|
|
@@ -647,50 +812,24 @@ function renderMultipleTextElement(element, ctx, wrapper, pathKey) {
|
|
|
647
812
|
removeBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
648
813
|
});
|
|
649
814
|
}
|
|
650
|
-
let
|
|
651
|
-
let countDisplay = null;
|
|
815
|
+
let addUpdate = null;
|
|
652
816
|
if (!readonly) {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
addBtn.addEventListener("mouseenter", () => {
|
|
667
|
-
addBtn.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
668
|
-
});
|
|
669
|
-
addBtn.addEventListener("mouseleave", () => {
|
|
670
|
-
addBtn.style.backgroundColor = "transparent";
|
|
671
|
-
});
|
|
672
|
-
addBtn.onclick = () => {
|
|
673
|
-
values.push(element.default || "");
|
|
674
|
-
addTextItem(element.default || "");
|
|
675
|
-
updateAddButton();
|
|
676
|
-
updateRemoveButtons();
|
|
677
|
-
};
|
|
678
|
-
countDisplay = document.createElement("span");
|
|
679
|
-
countDisplay.className = "text-sm text-gray-500";
|
|
680
|
-
addRow.appendChild(addBtn);
|
|
681
|
-
addRow.appendChild(countDisplay);
|
|
682
|
-
wrapper.appendChild(addRow);
|
|
817
|
+
const handle = createAddItemRow(
|
|
818
|
+
"text",
|
|
819
|
+
() => {
|
|
820
|
+
values.push(element.default || "");
|
|
821
|
+
addTextItem(element.default || "");
|
|
822
|
+
updateAddButton();
|
|
823
|
+
updateRemoveButtons();
|
|
824
|
+
},
|
|
825
|
+
{ label: element.addLabel }
|
|
826
|
+
);
|
|
827
|
+
addUpdate = handle.update;
|
|
828
|
+
mountCounterInLabel(wrapper, handle.counter);
|
|
829
|
+
wrapper.appendChild(handle.row);
|
|
683
830
|
}
|
|
684
831
|
function updateAddButton() {
|
|
685
|
-
if (
|
|
686
|
-
const addBtn = addRow.querySelector(".add-text-btn");
|
|
687
|
-
if (addBtn) {
|
|
688
|
-
const disabled = values.length >= maxCount;
|
|
689
|
-
addBtn.disabled = disabled;
|
|
690
|
-
addBtn.style.opacity = disabled ? "0.5" : "1";
|
|
691
|
-
addBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
692
|
-
}
|
|
693
|
-
countDisplay.textContent = `${values.length}/${maxCount === Infinity ? "\u221E" : maxCount}`;
|
|
832
|
+
if (addUpdate) addUpdate(values.length, maxCount);
|
|
694
833
|
}
|
|
695
834
|
values.forEach((value) => addTextItem(value));
|
|
696
835
|
updateAddButton();
|
|
@@ -990,52 +1129,24 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
990
1129
|
removeBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
991
1130
|
});
|
|
992
1131
|
}
|
|
993
|
-
let
|
|
994
|
-
let countDisplay = null;
|
|
1132
|
+
let addUpdate = null;
|
|
995
1133
|
if (!readonly) {
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
addBtn.addEventListener("mouseenter", () => {
|
|
1010
|
-
addBtn.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
1011
|
-
});
|
|
1012
|
-
addBtn.addEventListener("mouseleave", () => {
|
|
1013
|
-
addBtn.style.backgroundColor = "transparent";
|
|
1014
|
-
});
|
|
1015
|
-
addBtn.onclick = () => {
|
|
1016
|
-
values.push(element.default || "");
|
|
1017
|
-
addTextareaItem(element.default || "");
|
|
1018
|
-
updateAddButton();
|
|
1019
|
-
updateRemoveButtons();
|
|
1020
|
-
};
|
|
1021
|
-
countDisplay = document.createElement("span");
|
|
1022
|
-
countDisplay.className = "text-sm text-gray-500";
|
|
1023
|
-
addRow.appendChild(addBtn);
|
|
1024
|
-
addRow.appendChild(countDisplay);
|
|
1025
|
-
wrapper.appendChild(addRow);
|
|
1134
|
+
const handle = createAddItemRow(
|
|
1135
|
+
"textarea",
|
|
1136
|
+
() => {
|
|
1137
|
+
values.push(element.default || "");
|
|
1138
|
+
addTextareaItem(element.default || "");
|
|
1139
|
+
updateAddButton();
|
|
1140
|
+
updateRemoveButtons();
|
|
1141
|
+
},
|
|
1142
|
+
{ label: element.addLabel }
|
|
1143
|
+
);
|
|
1144
|
+
addUpdate = handle.update;
|
|
1145
|
+
mountCounterInLabel(wrapper, handle.counter);
|
|
1146
|
+
wrapper.appendChild(handle.row);
|
|
1026
1147
|
}
|
|
1027
1148
|
function updateAddButton() {
|
|
1028
|
-
if (
|
|
1029
|
-
const addBtn = addRow.querySelector(
|
|
1030
|
-
".add-textarea-btn"
|
|
1031
|
-
);
|
|
1032
|
-
if (addBtn) {
|
|
1033
|
-
const disabled = values.length >= maxCount;
|
|
1034
|
-
addBtn.disabled = disabled;
|
|
1035
|
-
addBtn.style.opacity = disabled ? "0.5" : "1";
|
|
1036
|
-
addBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
1037
|
-
}
|
|
1038
|
-
countDisplay.textContent = `${values.length}/${maxCount === Infinity ? "\u221E" : maxCount}`;
|
|
1149
|
+
if (addUpdate) addUpdate(values.length, maxCount);
|
|
1039
1150
|
}
|
|
1040
1151
|
values.forEach((value) => addTextareaItem(value));
|
|
1041
1152
|
updateAddButton();
|
|
@@ -1242,50 +1353,24 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1242
1353
|
removeBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
1243
1354
|
});
|
|
1244
1355
|
}
|
|
1245
|
-
let
|
|
1246
|
-
let countDisplay = null;
|
|
1356
|
+
let addUpdate = null;
|
|
1247
1357
|
if (!readonly) {
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
addBtn.addEventListener("mouseenter", () => {
|
|
1262
|
-
addBtn.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
1263
|
-
});
|
|
1264
|
-
addBtn.addEventListener("mouseleave", () => {
|
|
1265
|
-
addBtn.style.backgroundColor = "transparent";
|
|
1266
|
-
});
|
|
1267
|
-
addBtn.onclick = () => {
|
|
1268
|
-
values.push(element.default || "");
|
|
1269
|
-
addNumberItem(element.default || "");
|
|
1270
|
-
updateAddButton();
|
|
1271
|
-
updateRemoveButtons();
|
|
1272
|
-
};
|
|
1273
|
-
countDisplay = document.createElement("span");
|
|
1274
|
-
countDisplay.className = "text-sm text-gray-500";
|
|
1275
|
-
addRow.appendChild(addBtn);
|
|
1276
|
-
addRow.appendChild(countDisplay);
|
|
1277
|
-
wrapper.appendChild(addRow);
|
|
1358
|
+
const handle = createAddItemRow(
|
|
1359
|
+
"number",
|
|
1360
|
+
() => {
|
|
1361
|
+
values.push(element.default || "");
|
|
1362
|
+
addNumberItem(element.default || "");
|
|
1363
|
+
updateAddButton();
|
|
1364
|
+
updateRemoveButtons();
|
|
1365
|
+
},
|
|
1366
|
+
{ label: element.addLabel }
|
|
1367
|
+
);
|
|
1368
|
+
addUpdate = handle.update;
|
|
1369
|
+
mountCounterInLabel(wrapper, handle.counter);
|
|
1370
|
+
wrapper.appendChild(handle.row);
|
|
1278
1371
|
}
|
|
1279
1372
|
function updateAddButton() {
|
|
1280
|
-
if (
|
|
1281
|
-
const addBtn = addRow.querySelector(".add-number-btn");
|
|
1282
|
-
if (addBtn) {
|
|
1283
|
-
const disabled = values.length >= maxCount;
|
|
1284
|
-
addBtn.disabled = disabled;
|
|
1285
|
-
addBtn.style.opacity = disabled ? "0.5" : "1";
|
|
1286
|
-
addBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
1287
|
-
}
|
|
1288
|
-
countDisplay.textContent = `${values.length}/${maxCount === Infinity ? "\u221E" : maxCount}`;
|
|
1373
|
+
if (addUpdate) addUpdate(values.length, maxCount);
|
|
1289
1374
|
}
|
|
1290
1375
|
values.forEach((value) => addNumberItem(value));
|
|
1291
1376
|
updateAddButton();
|
|
@@ -1574,52 +1659,26 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1574
1659
|
removeBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
1575
1660
|
});
|
|
1576
1661
|
}
|
|
1577
|
-
let
|
|
1578
|
-
let countDisplay = null;
|
|
1662
|
+
let addUpdate = null;
|
|
1579
1663
|
if (!readonly) {
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
});
|
|
1596
|
-
addBtn.addEventListener("mouseleave", () => {
|
|
1597
|
-
addBtn.style.backgroundColor = "transparent";
|
|
1598
|
-
});
|
|
1599
|
-
addBtn.onclick = () => {
|
|
1600
|
-
var _a2, _b2;
|
|
1601
|
-
const defaultValue = element.default || ((_b2 = (_a2 = element.options) == null ? void 0 : _a2[0]) == null ? void 0 : _b2.value) || "";
|
|
1602
|
-
values.push(defaultValue);
|
|
1603
|
-
addSelectItem(defaultValue);
|
|
1604
|
-
updateAddButton();
|
|
1605
|
-
updateRemoveButtons();
|
|
1606
|
-
};
|
|
1607
|
-
countDisplay = document.createElement("span");
|
|
1608
|
-
countDisplay.className = "text-sm text-gray-500";
|
|
1609
|
-
addRow.appendChild(addBtn);
|
|
1610
|
-
addRow.appendChild(countDisplay);
|
|
1611
|
-
wrapper.appendChild(addRow);
|
|
1664
|
+
const handle = createAddItemRow(
|
|
1665
|
+
"select",
|
|
1666
|
+
() => {
|
|
1667
|
+
var _a2, _b2;
|
|
1668
|
+
const defaultValue = element.default || ((_b2 = (_a2 = element.options) == null ? void 0 : _a2[0]) == null ? void 0 : _b2.value) || "";
|
|
1669
|
+
values.push(defaultValue);
|
|
1670
|
+
addSelectItem(defaultValue);
|
|
1671
|
+
updateAddButton();
|
|
1672
|
+
updateRemoveButtons();
|
|
1673
|
+
},
|
|
1674
|
+
{ label: element.addLabel }
|
|
1675
|
+
);
|
|
1676
|
+
addUpdate = handle.update;
|
|
1677
|
+
mountCounterInLabel(wrapper, handle.counter);
|
|
1678
|
+
wrapper.appendChild(handle.row);
|
|
1612
1679
|
}
|
|
1613
1680
|
function updateAddButton() {
|
|
1614
|
-
if (
|
|
1615
|
-
const addBtn = addRow.querySelector(".add-select-btn");
|
|
1616
|
-
if (addBtn) {
|
|
1617
|
-
const disabled = values.length >= maxCount;
|
|
1618
|
-
addBtn.disabled = disabled;
|
|
1619
|
-
addBtn.style.opacity = disabled ? "0.5" : "1";
|
|
1620
|
-
addBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
1621
|
-
}
|
|
1622
|
-
countDisplay.textContent = `${values.length}/${maxCount === Infinity ? "\u221E" : maxCount}`;
|
|
1681
|
+
if (addUpdate) addUpdate(values.length, maxCount);
|
|
1623
1682
|
}
|
|
1624
1683
|
values.forEach((value) => addSelectItem(value));
|
|
1625
1684
|
updateAddButton();
|
|
@@ -1968,54 +2027,26 @@ function renderMultipleSwitcherElement(element, ctx, wrapper, pathKey) {
|
|
|
1968
2027
|
removeBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
1969
2028
|
});
|
|
1970
2029
|
}
|
|
1971
|
-
let
|
|
1972
|
-
let countDisplay = null;
|
|
2030
|
+
let addUpdate = null;
|
|
1973
2031
|
if (!readonly) {
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
});
|
|
1990
|
-
addBtn.addEventListener("mouseleave", () => {
|
|
1991
|
-
addBtn.style.backgroundColor = "transparent";
|
|
1992
|
-
});
|
|
1993
|
-
addBtn.onclick = () => {
|
|
1994
|
-
var _a2, _b2;
|
|
1995
|
-
const defaultValue = element.default || ((_b2 = (_a2 = element.options) == null ? void 0 : _a2[0]) == null ? void 0 : _b2.value) || "";
|
|
1996
|
-
values.push(defaultValue);
|
|
1997
|
-
addSwitcherItem(defaultValue);
|
|
1998
|
-
updateAddButton();
|
|
1999
|
-
updateRemoveButtons();
|
|
2000
|
-
};
|
|
2001
|
-
countDisplay = document.createElement("span");
|
|
2002
|
-
countDisplay.className = "text-sm text-gray-500";
|
|
2003
|
-
addRow.appendChild(addBtn);
|
|
2004
|
-
addRow.appendChild(countDisplay);
|
|
2005
|
-
wrapper.appendChild(addRow);
|
|
2032
|
+
const handle = createAddItemRow(
|
|
2033
|
+
"switcher",
|
|
2034
|
+
() => {
|
|
2035
|
+
var _a2, _b2;
|
|
2036
|
+
const defaultValue = element.default || ((_b2 = (_a2 = element.options) == null ? void 0 : _a2[0]) == null ? void 0 : _b2.value) || "";
|
|
2037
|
+
values.push(defaultValue);
|
|
2038
|
+
addSwitcherItem(defaultValue);
|
|
2039
|
+
updateAddButton();
|
|
2040
|
+
updateRemoveButtons();
|
|
2041
|
+
},
|
|
2042
|
+
{ label: element.addLabel }
|
|
2043
|
+
);
|
|
2044
|
+
addUpdate = handle.update;
|
|
2045
|
+
mountCounterInLabel(wrapper, handle.counter);
|
|
2046
|
+
wrapper.appendChild(handle.row);
|
|
2006
2047
|
}
|
|
2007
2048
|
function updateAddButton() {
|
|
2008
|
-
if (
|
|
2009
|
-
const addBtn = addRow.querySelector(
|
|
2010
|
-
".add-switcher-btn"
|
|
2011
|
-
);
|
|
2012
|
-
if (addBtn) {
|
|
2013
|
-
const disabled = values.length >= maxCount;
|
|
2014
|
-
addBtn.disabled = disabled;
|
|
2015
|
-
addBtn.style.opacity = disabled ? "0.5" : "1";
|
|
2016
|
-
addBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
2017
|
-
}
|
|
2018
|
-
countDisplay.textContent = `${values.length}/${maxCount === Infinity ? "\u221E" : maxCount}`;
|
|
2049
|
+
if (addUpdate) addUpdate(values.length, maxCount);
|
|
2019
2050
|
}
|
|
2020
2051
|
values.forEach((value) => addSwitcherItem(value));
|
|
2021
2052
|
updateAddButton();
|
|
@@ -2895,24 +2926,40 @@ function createTileActions(options) {
|
|
|
2895
2926
|
return btn;
|
|
2896
2927
|
};
|
|
2897
2928
|
if (replaceHandler) {
|
|
2898
|
-
const replaceBtn = makeBtn(
|
|
2929
|
+
const replaceBtn = makeBtn(
|
|
2930
|
+
ICON_REPLACE,
|
|
2931
|
+
t("replaceFile", state),
|
|
2932
|
+
"fb-tile-action-replace"
|
|
2933
|
+
);
|
|
2899
2934
|
replaceBtn.addEventListener("click", () => replaceHandler());
|
|
2900
2935
|
group.appendChild(replaceBtn);
|
|
2901
2936
|
}
|
|
2902
2937
|
if (libraryHandler) {
|
|
2903
|
-
const libBtn = makeBtn(
|
|
2938
|
+
const libBtn = makeBtn(
|
|
2939
|
+
ICON_LIBRARY,
|
|
2940
|
+
t("fromLibrary", state),
|
|
2941
|
+
"fb-tile-action-library"
|
|
2942
|
+
);
|
|
2904
2943
|
libBtn.addEventListener("click", () => libraryHandler());
|
|
2905
2944
|
group.appendChild(libBtn);
|
|
2906
2945
|
}
|
|
2907
2946
|
if (canDownload(state, meta)) {
|
|
2908
|
-
const dlBtn = makeBtn(
|
|
2947
|
+
const dlBtn = makeBtn(
|
|
2948
|
+
ICON_DOWNLOAD,
|
|
2949
|
+
t("downloadFile", state),
|
|
2950
|
+
"fb-tile-action-download"
|
|
2951
|
+
);
|
|
2909
2952
|
dlBtn.addEventListener("click", () => {
|
|
2910
2953
|
triggerTileDownload(resourceId, fileName, state, meta);
|
|
2911
2954
|
});
|
|
2912
2955
|
group.appendChild(dlBtn);
|
|
2913
2956
|
}
|
|
2914
2957
|
if (canOpenInTab(state, meta)) {
|
|
2915
|
-
const openBtn = makeBtn(
|
|
2958
|
+
const openBtn = makeBtn(
|
|
2959
|
+
ICON_OPEN,
|
|
2960
|
+
t("openInNewTab", state),
|
|
2961
|
+
"fb-tile-action-open"
|
|
2962
|
+
);
|
|
2916
2963
|
openBtn.addEventListener("click", () => {
|
|
2917
2964
|
triggerTileOpen(resourceId, state, meta).catch((err) => {
|
|
2918
2965
|
console.error("Open failed:", err);
|
|
@@ -2921,7 +2968,11 @@ function createTileActions(options) {
|
|
|
2921
2968
|
group.appendChild(openBtn);
|
|
2922
2969
|
}
|
|
2923
2970
|
if (canRemove && removeHandler) {
|
|
2924
|
-
const rmBtn = makeBtn(
|
|
2971
|
+
const rmBtn = makeBtn(
|
|
2972
|
+
ICON_REMOVE,
|
|
2973
|
+
t("removeElement", state),
|
|
2974
|
+
"fb-tile-action-remove"
|
|
2975
|
+
);
|
|
2925
2976
|
rmBtn.addEventListener("click", () => {
|
|
2926
2977
|
removeHandler();
|
|
2927
2978
|
});
|
|
@@ -2999,11 +3050,17 @@ function positionZoomPopup(popup, tile) {
|
|
|
2999
3050
|
} else if (tileRect.bottom + margin + popupSize + padding <= window.innerHeight) {
|
|
3000
3051
|
top = tileRect.bottom + margin;
|
|
3001
3052
|
} else {
|
|
3002
|
-
top = Math.max(
|
|
3053
|
+
top = Math.max(
|
|
3054
|
+
padding,
|
|
3055
|
+
Math.min(window.innerHeight - popupSize - padding, tileRect.top)
|
|
3056
|
+
);
|
|
3003
3057
|
}
|
|
3004
3058
|
const tileCenterX = tileRect.left + tileRect.width / 2;
|
|
3005
3059
|
let left = tileCenterX - popupSize / 2;
|
|
3006
|
-
left = Math.max(
|
|
3060
|
+
left = Math.max(
|
|
3061
|
+
padding,
|
|
3062
|
+
Math.min(window.innerWidth - popupSize - padding, left)
|
|
3063
|
+
);
|
|
3007
3064
|
popup.style.top = `${top}px`;
|
|
3008
3065
|
popup.style.left = `${left}px`;
|
|
3009
3066
|
}
|
|
@@ -3047,7 +3104,9 @@ function attachZoomHover(tile, src, alt, actionsEl) {
|
|
|
3047
3104
|
const popup = getOrCreateZoomPopup();
|
|
3048
3105
|
const existingActions = popup.querySelector(".fb-tile-actions");
|
|
3049
3106
|
if (existingActions) existingActions.remove();
|
|
3050
|
-
const img = popup.querySelector(
|
|
3107
|
+
const img = popup.querySelector(
|
|
3108
|
+
".fb-tile-zoom-preview-img"
|
|
3109
|
+
);
|
|
3051
3110
|
img.src = src;
|
|
3052
3111
|
img.alt = alt;
|
|
3053
3112
|
if (actionsEl) {
|
|
@@ -3075,7 +3134,9 @@ function attachZoomHover(tile, src, alt, actionsEl) {
|
|
|
3075
3134
|
});
|
|
3076
3135
|
}
|
|
3077
3136
|
function attachClonedActionListeners(cloned, original) {
|
|
3078
|
-
const originalBtns = Array.from(
|
|
3137
|
+
const originalBtns = Array.from(
|
|
3138
|
+
original.querySelectorAll(".fb-tile-action-btn")
|
|
3139
|
+
);
|
|
3079
3140
|
const clonedBtns = Array.from(cloned.querySelectorAll(".fb-tile-action-btn"));
|
|
3080
3141
|
clonedBtns.forEach((clonedBtn, i) => {
|
|
3081
3142
|
const origBtn = originalBtns[i];
|
|
@@ -3129,7 +3190,9 @@ function renderLocalVideoPreview(container, file, videoType, resourceId, state,
|
|
|
3129
3190
|
return newContainer;
|
|
3130
3191
|
}
|
|
3131
3192
|
function attachVideoButtonHandlers(container, resourceId, state, deps) {
|
|
3132
|
-
const changeBtn = container.querySelector(
|
|
3193
|
+
const changeBtn = container.querySelector(
|
|
3194
|
+
".change-file-btn"
|
|
3195
|
+
);
|
|
3133
3196
|
if (changeBtn) {
|
|
3134
3197
|
changeBtn.onclick = (e) => {
|
|
3135
3198
|
var _a;
|
|
@@ -3137,7 +3200,9 @@ function attachVideoButtonHandlers(container, resourceId, state, deps) {
|
|
|
3137
3200
|
(_a = deps == null ? void 0 : deps.picker) == null ? void 0 : _a.click();
|
|
3138
3201
|
};
|
|
3139
3202
|
}
|
|
3140
|
-
const deleteBtn = container.querySelector(
|
|
3203
|
+
const deleteBtn = container.querySelector(
|
|
3204
|
+
".delete-file-btn"
|
|
3205
|
+
);
|
|
3141
3206
|
if (deleteBtn) {
|
|
3142
3207
|
deleteBtn.onclick = (e) => {
|
|
3143
3208
|
e.stopPropagation();
|
|
@@ -3275,7 +3340,13 @@ async function renderFilePreview(container, resourceId, state, options = {}) {
|
|
|
3275
3340
|
deps
|
|
3276
3341
|
);
|
|
3277
3342
|
} else {
|
|
3278
|
-
await renderUploadedFilePreview(
|
|
3343
|
+
await renderUploadedFilePreview(
|
|
3344
|
+
container,
|
|
3345
|
+
resourceId,
|
|
3346
|
+
fileName,
|
|
3347
|
+
meta,
|
|
3348
|
+
state
|
|
3349
|
+
);
|
|
3279
3350
|
const isVideo = (_a = meta == null ? void 0 : meta.type) == null ? void 0 : _a.startsWith("video/");
|
|
3280
3351
|
if (!isReadonly && !isVideo) {
|
|
3281
3352
|
renderDeleteButton(container, resourceId, state);
|
|
@@ -3304,7 +3375,8 @@ async function renderFilePreviewReadonly(resourceId, state, fileName, options =
|
|
|
3304
3375
|
}
|
|
3305
3376
|
const localFileUrl = (meta == null ? void 0 : meta.file) instanceof File ? getLocalFileUrl(meta.file) : null;
|
|
3306
3377
|
const resolveOpenUrl = async () => {
|
|
3307
|
-
if (state.config.getDownloadUrl)
|
|
3378
|
+
if (state.config.getDownloadUrl)
|
|
3379
|
+
return state.config.getDownloadUrl(resourceId);
|
|
3308
3380
|
if (state.config.getThumbnail) return state.config.getThumbnail(resourceId);
|
|
3309
3381
|
return localFileUrl;
|
|
3310
3382
|
};
|
|
@@ -3446,7 +3518,8 @@ async function fillTileContent(tile, rid, meta, state, actionsEl) {
|
|
|
3446
3518
|
}
|
|
3447
3519
|
} catch (error) {
|
|
3448
3520
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
3449
|
-
if (state.config.onThumbnailError)
|
|
3521
|
+
if (state.config.onThumbnailError)
|
|
3522
|
+
state.config.onThumbnailError(err, rid);
|
|
3450
3523
|
tile.innerHTML = `<div style="display:flex;align-items:center;justify-content:center;height:100%;font-size:16px;color:var(--fb-error-color,#ef4444);">\u2715</div>`;
|
|
3451
3524
|
}
|
|
3452
3525
|
} else {
|
|
@@ -3479,7 +3552,8 @@ async function fillTileContent(tile, rid, meta, state, actionsEl) {
|
|
|
3479
3552
|
}
|
|
3480
3553
|
} catch (error) {
|
|
3481
3554
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
3482
|
-
if (state.config.onThumbnailError)
|
|
3555
|
+
if (state.config.onThumbnailError)
|
|
3556
|
+
state.config.onThumbnailError(err, rid);
|
|
3483
3557
|
tile.innerHTML = `<div style="display:flex;align-items:center;justify-content:center;height:100%;font-size:16px;color:var(--fb-error-color,#ef4444);">\u2715</div>`;
|
|
3484
3558
|
}
|
|
3485
3559
|
} else {
|
|
@@ -3513,7 +3587,8 @@ async function forceDownload(resourceId, fileName, state) {
|
|
|
3513
3587
|
if (fileUrl) {
|
|
3514
3588
|
const finalUrl = fileUrl.startsWith("http") ? fileUrl : new URL(fileUrl, window.location.href).href;
|
|
3515
3589
|
const response = await fetch(finalUrl);
|
|
3516
|
-
if (!response.ok)
|
|
3590
|
+
if (!response.ok)
|
|
3591
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
3517
3592
|
const blob = await response.blob();
|
|
3518
3593
|
downloadBlob(blob, fileName);
|
|
3519
3594
|
} else {
|
|
@@ -3562,7 +3637,9 @@ async function uploadSingleFile(file, state) {
|
|
|
3562
3637
|
} catch (error) {
|
|
3563
3638
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
3564
3639
|
if (state.config.onUploadError) state.config.onUploadError(err, file);
|
|
3565
|
-
|
|
3640
|
+
const wrapped = new Error(`File upload failed: ${err.message}`);
|
|
3641
|
+
wrapped.cause = err;
|
|
3642
|
+
throw wrapped;
|
|
3566
3643
|
}
|
|
3567
3644
|
}
|
|
3568
3645
|
async function handleFileSelect(opts) {
|
|
@@ -3675,7 +3752,9 @@ function filterAndSlice(allFiles, currentCount, constraints, state) {
|
|
|
3675
3752
|
const rejectedBySize = afterMime.filter(
|
|
3676
3753
|
(f) => !isFileSizeAllowed(f, constraints.maxSize)
|
|
3677
3754
|
);
|
|
3678
|
-
const valid = afterMime.filter(
|
|
3755
|
+
const valid = afterMime.filter(
|
|
3756
|
+
(f) => isFileSizeAllowed(f, constraints.maxSize)
|
|
3757
|
+
);
|
|
3679
3758
|
const remaining = constraints.maxCount === Infinity ? valid.length : Math.max(0, constraints.maxCount - currentCount);
|
|
3680
3759
|
const accepted = valid.slice(0, remaining);
|
|
3681
3760
|
const skippedByCount = valid.length - accepted.length;
|
|
@@ -3688,7 +3767,13 @@ function filterAndSlice(allFiles, currentCount, constraints, state) {
|
|
|
3688
3767
|
if (rejectedByMime.length > 0) {
|
|
3689
3768
|
const mimes = constraints.allowedMimes.join(", ");
|
|
3690
3769
|
const names = rejectedByMime.map((f) => f.name).join(", ");
|
|
3691
|
-
errorParts.push(
|
|
3770
|
+
errorParts.push(
|
|
3771
|
+
t("invalidFileMime", state, {
|
|
3772
|
+
name: names,
|
|
3773
|
+
type: rejectedByMime.map((f) => f.type).join(", "),
|
|
3774
|
+
mimes
|
|
3775
|
+
})
|
|
3776
|
+
);
|
|
3692
3777
|
}
|
|
3693
3778
|
if (rejectedBySize.length > 0) {
|
|
3694
3779
|
const names = rejectedBySize.map((f) => f.name).join(", ");
|
|
@@ -3713,7 +3798,8 @@ async function uploadBatch(accepted, resourceIds, listEl, state) {
|
|
|
3713
3798
|
const addTile = (_a = tilesWrap.querySelector(".fb-multi-add-tile-js")) != null ? _a : tilesWrap.querySelector(".fb-tile-add");
|
|
3714
3799
|
if (addTile) addTile.style.display = "none";
|
|
3715
3800
|
}
|
|
3716
|
-
|
|
3801
|
+
const failures = [];
|
|
3802
|
+
await Promise.allSettled(
|
|
3717
3803
|
accepted.map(async (file) => {
|
|
3718
3804
|
const placeholder = createUploadingTile(file.name, state);
|
|
3719
3805
|
if (listEl) {
|
|
@@ -3730,11 +3816,27 @@ async function uploadBatch(accepted, resourceIds, listEl, state) {
|
|
|
3730
3816
|
file: void 0
|
|
3731
3817
|
});
|
|
3732
3818
|
resourceIds.push(rid);
|
|
3819
|
+
} catch (err) {
|
|
3820
|
+
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
3821
|
+
const cause = wrapped.cause;
|
|
3822
|
+
const root = cause instanceof Error ? cause : cause !== void 0 ? new Error(String(cause)) : wrapped;
|
|
3823
|
+
failures.push({ file, error: root });
|
|
3733
3824
|
} finally {
|
|
3734
3825
|
placeholder.remove();
|
|
3735
3826
|
}
|
|
3736
3827
|
})
|
|
3737
3828
|
);
|
|
3829
|
+
return { failures };
|
|
3830
|
+
}
|
|
3831
|
+
function buildBatchErrorMessage(filterError, failures, state) {
|
|
3832
|
+
if (failures.length === 0) return filterError;
|
|
3833
|
+
const uploadMsg = failures.map(
|
|
3834
|
+
(f) => t("uploadFailed", state, {
|
|
3835
|
+
name: f.file.name,
|
|
3836
|
+
error: f.error.message
|
|
3837
|
+
})
|
|
3838
|
+
).join(" \u2022 ");
|
|
3839
|
+
return filterError ? `${filterError} \u2022 ${uploadMsg}` : uploadMsg;
|
|
3738
3840
|
}
|
|
3739
3841
|
function setupFilesDropHandler(filesContainer, resourceIds, state, updateCallback, constraints, pathKey, instance) {
|
|
3740
3842
|
setupDragAndDrop(filesContainer, async (files) => {
|
|
@@ -3751,7 +3853,13 @@ function setupFilesDropHandler(filesContainer, resourceIds, state, updateCallbac
|
|
|
3751
3853
|
clearFileError(filesContainer);
|
|
3752
3854
|
}
|
|
3753
3855
|
const list = (_a = filesContainer.querySelector(".files-list")) != null ? _a : filesContainer;
|
|
3754
|
-
await uploadBatch(accepted, resourceIds, list, state);
|
|
3856
|
+
const { failures } = await uploadBatch(accepted, resourceIds, list, state);
|
|
3857
|
+
const combined = buildBatchErrorMessage(errorMessage, failures, state);
|
|
3858
|
+
if (combined) {
|
|
3859
|
+
showFileError(filesContainer, combined);
|
|
3860
|
+
} else {
|
|
3861
|
+
clearFileError(filesContainer);
|
|
3862
|
+
}
|
|
3755
3863
|
updateCallback();
|
|
3756
3864
|
if (instance && pathKey && !state.config.readonly) {
|
|
3757
3865
|
instance.triggerOnChange(pathKey, resourceIds);
|
|
@@ -3774,7 +3882,20 @@ function setupFilesPickerHandler(filesPicker, resourceIds, state, updateCallback
|
|
|
3774
3882
|
clearFileError(wrapperEl);
|
|
3775
3883
|
}
|
|
3776
3884
|
const listEl = wrapperEl == null ? void 0 : wrapperEl.querySelector(".files-list");
|
|
3777
|
-
|
|
3885
|
+
const { failures } = await uploadBatch(
|
|
3886
|
+
accepted,
|
|
3887
|
+
resourceIds,
|
|
3888
|
+
listEl != null ? listEl : null,
|
|
3889
|
+
state
|
|
3890
|
+
);
|
|
3891
|
+
if (wrapperEl) {
|
|
3892
|
+
const combined = buildBatchErrorMessage(errorMessage, failures, state);
|
|
3893
|
+
if (combined) {
|
|
3894
|
+
showFileError(wrapperEl, combined);
|
|
3895
|
+
} else {
|
|
3896
|
+
clearFileError(wrapperEl);
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3778
3899
|
updateCallback();
|
|
3779
3900
|
filesPicker.value = "";
|
|
3780
3901
|
if (instance && pathKey && !state.config.readonly) {
|
|
@@ -3807,10 +3928,17 @@ function validatePickedResource(resource, allowedExtensions, allowedMimes, maxSi
|
|
|
3807
3928
|
}
|
|
3808
3929
|
if (!isMimeAllowed(resource.type, allowedMimes)) {
|
|
3809
3930
|
const mimes = allowedMimes.join(", ");
|
|
3810
|
-
return t("invalidFileMime", state, {
|
|
3931
|
+
return t("invalidFileMime", state, {
|
|
3932
|
+
name: resource.name,
|
|
3933
|
+
type: resource.type,
|
|
3934
|
+
mimes
|
|
3935
|
+
});
|
|
3811
3936
|
}
|
|
3812
3937
|
if (!isSizeWithinLimit(resource.size, maxSizeMB)) {
|
|
3813
|
-
return t("fileTooLarge", state, {
|
|
3938
|
+
return t("fileTooLarge", state, {
|
|
3939
|
+
name: resource.name,
|
|
3940
|
+
maxSize: maxSizeMB
|
|
3941
|
+
});
|
|
3814
3942
|
}
|
|
3815
3943
|
return null;
|
|
3816
3944
|
}
|
|
@@ -3871,7 +3999,13 @@ async function handleLibraryPickMulti(state, element, wrapper, fieldPath, resour
|
|
|
3871
3999
|
return true;
|
|
3872
4000
|
});
|
|
3873
4001
|
const validItems = deduped.filter((r) => {
|
|
3874
|
-
const err = validatePickedResource(
|
|
4002
|
+
const err = validatePickedResource(
|
|
4003
|
+
r,
|
|
4004
|
+
allowedExtensions,
|
|
4005
|
+
allowedMimes,
|
|
4006
|
+
maxSizeMB,
|
|
4007
|
+
state
|
|
4008
|
+
);
|
|
3875
4009
|
return err === null;
|
|
3876
4010
|
});
|
|
3877
4011
|
const freshRemaining = maxCount === Infinity ? validItems.length : Math.max(0, maxCount - resourceIds.length);
|
|
@@ -3916,14 +4050,22 @@ async function handleLibraryPickSingle(state, element, container, fileWrapper, p
|
|
|
3916
4050
|
}
|
|
3917
4051
|
if (picked.length === 0) return;
|
|
3918
4052
|
const first = picked[0];
|
|
3919
|
-
const validationError = validatePickedResource(
|
|
4053
|
+
const validationError = validatePickedResource(
|
|
4054
|
+
first,
|
|
4055
|
+
allowedExtensions,
|
|
4056
|
+
allowedMimes,
|
|
4057
|
+
maxSizeMB,
|
|
4058
|
+
state
|
|
4059
|
+
);
|
|
3920
4060
|
if (validationError !== null) {
|
|
3921
4061
|
showFileError(container, validationError);
|
|
3922
4062
|
return;
|
|
3923
4063
|
}
|
|
3924
4064
|
clearFileError(container);
|
|
3925
4065
|
registerPickedResource(first, state);
|
|
3926
|
-
let hiddenInput = fileWrapper.querySelector(
|
|
4066
|
+
let hiddenInput = fileWrapper.querySelector(
|
|
4067
|
+
'input[type="hidden"]'
|
|
4068
|
+
);
|
|
3927
4069
|
if (!hiddenInput) {
|
|
3928
4070
|
hiddenInput = document.createElement("input");
|
|
3929
4071
|
hiddenInput.type = "hidden";
|
|
@@ -4087,7 +4229,8 @@ function renderSingleFileFilled(fileContainer, resourceId, state, deps, extras)
|
|
|
4087
4229
|
grid.appendChild(tile);
|
|
4088
4230
|
fileContainer.className = "file-preview-container";
|
|
4089
4231
|
fileContainer.removeAttribute("style");
|
|
4090
|
-
while (fileContainer.firstChild)
|
|
4232
|
+
while (fileContainer.firstChild)
|
|
4233
|
+
fileContainer.removeChild(fileContainer.firstChild);
|
|
4091
4234
|
fileContainer.appendChild(outer);
|
|
4092
4235
|
}
|
|
4093
4236
|
function buildMultiAddTile(state, hasLibrary, onUploadClick, onLibraryClick, isDragOver = false) {
|
|
@@ -4169,7 +4312,9 @@ function buildMetaLine(state, element, ridCount, maxCount, canClearAll, onClearA
|
|
|
4169
4312
|
metaText.appendChild(sizeSpan);
|
|
4170
4313
|
metaText.appendChild(buildMetaDot());
|
|
4171
4314
|
}
|
|
4172
|
-
const exts = getAllowedExtensions(
|
|
4315
|
+
const exts = getAllowedExtensions(
|
|
4316
|
+
element.accept
|
|
4317
|
+
);
|
|
4173
4318
|
if (exts.length > 0) {
|
|
4174
4319
|
const fmtSpan = document.createElement("span");
|
|
4175
4320
|
fmtSpan.className = "fb-meta-mono";
|
|
@@ -4420,7 +4565,9 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4420
4565
|
},
|
|
4421
4566
|
onRemove() {
|
|
4422
4567
|
var _a2;
|
|
4423
|
-
const hiddenInput = fileWrapper.querySelector(
|
|
4568
|
+
const hiddenInput = fileWrapper.querySelector(
|
|
4569
|
+
'input[type="hidden"]'
|
|
4570
|
+
);
|
|
4424
4571
|
const currentRid = hiddenInput == null ? void 0 : hiddenInput.value;
|
|
4425
4572
|
if (currentRid) {
|
|
4426
4573
|
releaseLocalFileUrl((_a2 = state.resourceIndex.get(currentRid)) == null ? void 0 : _a2.file);
|
|
@@ -4430,7 +4577,9 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4430
4577
|
}
|
|
4431
4578
|
};
|
|
4432
4579
|
const buildSingleExtras = () => {
|
|
4433
|
-
const hasLibrary = Boolean(
|
|
4580
|
+
const hasLibrary = Boolean(
|
|
4581
|
+
state.config.pickExistingFiles && !element.disableLibrary
|
|
4582
|
+
);
|
|
4434
4583
|
return {
|
|
4435
4584
|
replaceHandler: state.config.uploadFile ? () => picker.click() : null,
|
|
4436
4585
|
libraryHandler: hasLibrary ? () => {
|
|
@@ -4442,7 +4591,13 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4442
4591
|
pathKey,
|
|
4443
4592
|
pathKey,
|
|
4444
4593
|
async (rid) => {
|
|
4445
|
-
renderSingleFileFilled(
|
|
4594
|
+
renderSingleFileFilled(
|
|
4595
|
+
fileContainer,
|
|
4596
|
+
rid,
|
|
4597
|
+
state,
|
|
4598
|
+
buildDeps(),
|
|
4599
|
+
buildSingleExtras()
|
|
4600
|
+
);
|
|
4446
4601
|
},
|
|
4447
4602
|
ctx.instance
|
|
4448
4603
|
).catch((err) => {
|
|
@@ -4458,14 +4613,21 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4458
4613
|
setupDrop: handlers.setupDrop,
|
|
4459
4614
|
onRemove: handlers.onRemove,
|
|
4460
4615
|
onAfterUpload: (container, rid) => {
|
|
4461
|
-
renderSingleFileFilled(
|
|
4616
|
+
renderSingleFileFilled(
|
|
4617
|
+
container,
|
|
4618
|
+
rid,
|
|
4619
|
+
state,
|
|
4620
|
+
buildDeps(),
|
|
4621
|
+
buildSingleExtras()
|
|
4622
|
+
);
|
|
4462
4623
|
}
|
|
4463
4624
|
});
|
|
4464
4625
|
const renderEmptySingleState = () => {
|
|
4465
4626
|
ensureFileStyles();
|
|
4466
4627
|
fileContainer.className = "file-preview-container";
|
|
4467
4628
|
fileContainer.removeAttribute("style");
|
|
4468
|
-
while (fileContainer.firstChild)
|
|
4629
|
+
while (fileContainer.firstChild)
|
|
4630
|
+
fileContainer.removeChild(fileContainer.firstChild);
|
|
4469
4631
|
const onLibraryClick = buildSingleExtras().libraryHandler;
|
|
4470
4632
|
const wideTile = buildWideTile(
|
|
4471
4633
|
state,
|
|
@@ -4610,7 +4772,13 @@ function renderFilesElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4610
4772
|
}
|
|
4611
4773
|
function renderMultipleFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
4612
4774
|
var _a;
|
|
4613
|
-
setupMultiFileEditMode(
|
|
4775
|
+
setupMultiFileEditMode(
|
|
4776
|
+
element,
|
|
4777
|
+
ctx,
|
|
4778
|
+
wrapper,
|
|
4779
|
+
pathKey,
|
|
4780
|
+
(_a = element.maxCount) != null ? _a : Infinity
|
|
4781
|
+
);
|
|
4614
4782
|
}
|
|
4615
4783
|
|
|
4616
4784
|
// src/components/file/validate.ts
|
|
@@ -4793,7 +4961,11 @@ function renderMultiFileReadonly(rids, state, wrapper, pathKey, _marginTop) {
|
|
|
4793
4961
|
const placeholder = placeholders[i];
|
|
4794
4962
|
const meta = state.resourceIndex.get(resourceId);
|
|
4795
4963
|
renderFilePreviewReadonly(resourceId, state, meta == null ? void 0 : meta.name).then((tile) => {
|
|
4796
|
-
tile.classList.add(
|
|
4964
|
+
tile.classList.add(
|
|
4965
|
+
"fb-readonly-tile",
|
|
4966
|
+
"fb-checker",
|
|
4967
|
+
"fb-tile-resource"
|
|
4968
|
+
);
|
|
4797
4969
|
tile.dataset.resourceId = resourceId;
|
|
4798
4970
|
placeholder.replaceWith(tile);
|
|
4799
4971
|
}).catch(() => {
|
|
@@ -5144,51 +5316,25 @@ function renderMultipleColourElement(element, ctx, wrapper, pathKey) {
|
|
|
5144
5316
|
removeBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
5145
5317
|
});
|
|
5146
5318
|
}
|
|
5147
|
-
let
|
|
5148
|
-
let countDisplay = null;
|
|
5319
|
+
let addUpdate = null;
|
|
5149
5320
|
if (!readonly) {
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
addBtn.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
5165
|
-
});
|
|
5166
|
-
addBtn.addEventListener("mouseleave", () => {
|
|
5167
|
-
addBtn.style.backgroundColor = "transparent";
|
|
5168
|
-
});
|
|
5169
|
-
addBtn.onclick = () => {
|
|
5170
|
-
const defaultColour = element.default || "#000000";
|
|
5171
|
-
values.push(defaultColour);
|
|
5172
|
-
addColourItem(defaultColour);
|
|
5173
|
-
updateAddButton();
|
|
5174
|
-
updateRemoveButtons();
|
|
5175
|
-
};
|
|
5176
|
-
countDisplay = document.createElement("span");
|
|
5177
|
-
countDisplay.className = "text-sm text-gray-500";
|
|
5178
|
-
addRow.appendChild(addBtn);
|
|
5179
|
-
addRow.appendChild(countDisplay);
|
|
5180
|
-
wrapper.appendChild(addRow);
|
|
5321
|
+
const handle = createAddItemRow(
|
|
5322
|
+
"colour",
|
|
5323
|
+
() => {
|
|
5324
|
+
const defaultColour = element.default || "#000000";
|
|
5325
|
+
values.push(defaultColour);
|
|
5326
|
+
addColourItem(defaultColour);
|
|
5327
|
+
updateAddButton();
|
|
5328
|
+
updateRemoveButtons();
|
|
5329
|
+
},
|
|
5330
|
+
{ label: element.addLabel }
|
|
5331
|
+
);
|
|
5332
|
+
addUpdate = handle.update;
|
|
5333
|
+
mountCounterInLabel(wrapper, handle.counter);
|
|
5334
|
+
wrapper.appendChild(handle.row);
|
|
5181
5335
|
}
|
|
5182
5336
|
function updateAddButton() {
|
|
5183
|
-
if (
|
|
5184
|
-
const addBtn = addRow.querySelector(".add-colour-btn");
|
|
5185
|
-
if (addBtn) {
|
|
5186
|
-
const disabled = values.length >= maxCount;
|
|
5187
|
-
addBtn.disabled = disabled;
|
|
5188
|
-
addBtn.style.opacity = disabled ? "0.5" : "1";
|
|
5189
|
-
addBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
5190
|
-
}
|
|
5191
|
-
countDisplay.textContent = `${values.length}/${maxCount === Infinity ? "\u221E" : maxCount}`;
|
|
5337
|
+
if (addUpdate) addUpdate(values.length, maxCount);
|
|
5192
5338
|
}
|
|
5193
5339
|
values.forEach((value) => addColourItem(value));
|
|
5194
5340
|
updateAddButton();
|
|
@@ -5630,50 +5776,24 @@ function renderMultipleSliderElement(element, ctx, wrapper, pathKey) {
|
|
|
5630
5776
|
removeBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
5631
5777
|
});
|
|
5632
5778
|
}
|
|
5633
|
-
let
|
|
5634
|
-
let countDisplay = null;
|
|
5779
|
+
let addUpdate = null;
|
|
5635
5780
|
if (!readonly) {
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
addBtn.addEventListener("mouseenter", () => {
|
|
5650
|
-
addBtn.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
5651
|
-
});
|
|
5652
|
-
addBtn.addEventListener("mouseleave", () => {
|
|
5653
|
-
addBtn.style.backgroundColor = "transparent";
|
|
5654
|
-
});
|
|
5655
|
-
addBtn.onclick = () => {
|
|
5656
|
-
values.push(defaultValue);
|
|
5657
|
-
addSliderItem(defaultValue);
|
|
5658
|
-
updateAddButton();
|
|
5659
|
-
updateRemoveButtons();
|
|
5660
|
-
};
|
|
5661
|
-
countDisplay = document.createElement("span");
|
|
5662
|
-
countDisplay.className = "text-sm text-gray-500";
|
|
5663
|
-
addRow.appendChild(addBtn);
|
|
5664
|
-
addRow.appendChild(countDisplay);
|
|
5665
|
-
wrapper.appendChild(addRow);
|
|
5781
|
+
const handle = createAddItemRow(
|
|
5782
|
+
"slider",
|
|
5783
|
+
() => {
|
|
5784
|
+
values.push(defaultValue);
|
|
5785
|
+
addSliderItem(defaultValue);
|
|
5786
|
+
updateAddButton();
|
|
5787
|
+
updateRemoveButtons();
|
|
5788
|
+
},
|
|
5789
|
+
{ label: element.addLabel }
|
|
5790
|
+
);
|
|
5791
|
+
addUpdate = handle.update;
|
|
5792
|
+
mountCounterInLabel(wrapper, handle.counter);
|
|
5793
|
+
wrapper.appendChild(handle.row);
|
|
5666
5794
|
}
|
|
5667
5795
|
function updateAddButton() {
|
|
5668
|
-
if (
|
|
5669
|
-
const addBtn = addRow.querySelector(".add-slider-btn");
|
|
5670
|
-
if (addBtn) {
|
|
5671
|
-
const disabled = values.length >= maxCount;
|
|
5672
|
-
addBtn.disabled = disabled;
|
|
5673
|
-
addBtn.style.opacity = disabled ? "0.5" : "1";
|
|
5674
|
-
addBtn.style.pointerEvents = disabled ? "none" : "auto";
|
|
5675
|
-
}
|
|
5676
|
-
countDisplay.textContent = `${values.length}/${maxCount === Infinity ? "\u221E" : maxCount}`;
|
|
5796
|
+
if (addUpdate) addUpdate(values.length, maxCount);
|
|
5677
5797
|
}
|
|
5678
5798
|
values.forEach((value) => addSliderItem(value));
|
|
5679
5799
|
updateAddButton();
|
|
@@ -6025,6 +6145,47 @@ function getChildWrapperClass(isSlides, columns) {
|
|
|
6025
6145
|
const cols = columns || 1;
|
|
6026
6146
|
return cols === 1 ? "space-y-2" : `grid grid-cols-${cols} gap-2`;
|
|
6027
6147
|
}
|
|
6148
|
+
function mountRemoveButton(item, onRemove) {
|
|
6149
|
+
const rem = document.createElement("button");
|
|
6150
|
+
rem.type = "button";
|
|
6151
|
+
rem.className = "fb-item-remove";
|
|
6152
|
+
rem.style.cssText = `
|
|
6153
|
+
width: 22px;
|
|
6154
|
+
height: 22px;
|
|
6155
|
+
display: inline-flex;
|
|
6156
|
+
align-items: center;
|
|
6157
|
+
justify-content: center;
|
|
6158
|
+
padding: 0;
|
|
6159
|
+
line-height: 1;
|
|
6160
|
+
font-size: 14px;
|
|
6161
|
+
color: var(--fb-error-color);
|
|
6162
|
+
background-color: transparent;
|
|
6163
|
+
border: 0;
|
|
6164
|
+
border-radius: 4px;
|
|
6165
|
+
cursor: pointer;
|
|
6166
|
+
flex-shrink: 0;
|
|
6167
|
+
transition: background-color var(--fb-transition-duration);
|
|
6168
|
+
`;
|
|
6169
|
+
rem.textContent = "\u2715";
|
|
6170
|
+
rem.addEventListener("mouseenter", () => {
|
|
6171
|
+
rem.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
6172
|
+
});
|
|
6173
|
+
rem.addEventListener("mouseleave", () => {
|
|
6174
|
+
rem.style.backgroundColor = "transparent";
|
|
6175
|
+
});
|
|
6176
|
+
rem.onclick = onRemove;
|
|
6177
|
+
const labelRow = item.querySelector("[data-fb-label-row]");
|
|
6178
|
+
if (labelRow) {
|
|
6179
|
+
rem.style.marginLeft = "auto";
|
|
6180
|
+
labelRow.appendChild(rem);
|
|
6181
|
+
return;
|
|
6182
|
+
}
|
|
6183
|
+
rem.style.position = "absolute";
|
|
6184
|
+
rem.style.top = "8px";
|
|
6185
|
+
rem.style.right = "8px";
|
|
6186
|
+
item.style.position = "relative";
|
|
6187
|
+
item.appendChild(rem);
|
|
6188
|
+
}
|
|
6028
6189
|
function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
6029
6190
|
var _a, _b, _c, _d;
|
|
6030
6191
|
const state = ctx.state;
|
|
@@ -6032,8 +6193,6 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6032
6193
|
const childInheritedReadonly = containerIsReadonly || ctx.inheritedReadonly;
|
|
6033
6194
|
const containerWrap = document.createElement("div");
|
|
6034
6195
|
containerWrap.className = "border border-gray-200 rounded-lg p-2 bg-gray-50";
|
|
6035
|
-
const countDisplay = document.createElement("span");
|
|
6036
|
-
countDisplay.className = "text-sm text-gray-500";
|
|
6037
6196
|
const itemsWrap = document.createElement("div");
|
|
6038
6197
|
const isSlides = element.displayMode === "slides";
|
|
6039
6198
|
if (isSlides) {
|
|
@@ -6055,93 +6214,65 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6055
6214
|
const pre = Array.isArray((_c = ctx.prefill) == null ? void 0 : _c[element.key]) ? ctx.prefill[element.key] : null;
|
|
6056
6215
|
const childDefaults = extractChildDefaults(element.elements);
|
|
6057
6216
|
const countItems = () => itemsWrap.querySelectorAll(":scope > .containerItem").length;
|
|
6058
|
-
const
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
add.addEventListener("mouseenter", () => {
|
|
6071
|
-
add.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
6072
|
-
});
|
|
6073
|
-
add.addEventListener("mouseleave", () => {
|
|
6074
|
-
add.style.backgroundColor = "transparent";
|
|
6075
|
-
});
|
|
6076
|
-
add.onclick = () => {
|
|
6077
|
-
if (countItems() < max) {
|
|
6078
|
-
const idx = countItems();
|
|
6079
|
-
const currentFormData = state.formRoot ? extractRootFormData(state.formRoot) : {};
|
|
6080
|
-
const subCtx = {
|
|
6081
|
-
state: ctx.state,
|
|
6082
|
-
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
6083
|
-
prefill: childDefaults,
|
|
6084
|
-
// Defaults for enableIf evaluation
|
|
6085
|
-
formData: currentFormData,
|
|
6086
|
-
// Current root data from DOM for enableIf
|
|
6087
|
-
inheritedReadonly: childInheritedReadonly
|
|
6088
|
-
};
|
|
6089
|
-
const item = document.createElement("div");
|
|
6090
|
-
item.className = "containerItem border border-gray-300 rounded-lg p-2 bg-white";
|
|
6091
|
-
item.setAttribute("data-container-item", `${element.key}[${idx}]`);
|
|
6092
|
-
const childWrapper = document.createElement("div");
|
|
6093
|
-
childWrapper.className = getChildWrapperClass(isSlides, element.columns);
|
|
6094
|
-
element.elements.forEach((child) => {
|
|
6095
|
-
var _a2;
|
|
6096
|
-
if (child.type !== "markdown" && (child.hidden || child.type === "hidden")) {
|
|
6097
|
-
childWrapper.appendChild(
|
|
6098
|
-
createHiddenInput(
|
|
6099
|
-
pathJoin(subCtx.path, child.key),
|
|
6100
|
-
(_a2 = "default" in child ? child.default : null) != null ? _a2 : null
|
|
6101
|
-
)
|
|
6102
|
-
);
|
|
6103
|
-
} else {
|
|
6104
|
-
childWrapper.appendChild(renderElement(child, subCtx));
|
|
6105
|
-
}
|
|
6106
|
-
});
|
|
6107
|
-
item.appendChild(childWrapper);
|
|
6108
|
-
if (!containerIsReadonly) {
|
|
6109
|
-
const rem = document.createElement("button");
|
|
6110
|
-
rem.type = "button";
|
|
6111
|
-
rem.className = "absolute top-2 right-2 px-2 py-1 rounded";
|
|
6112
|
-
rem.style.cssText = `
|
|
6113
|
-
color: var(--fb-error-color);
|
|
6114
|
-
background-color: transparent;
|
|
6115
|
-
transition: background-color var(--fb-transition-duration);
|
|
6116
|
-
`;
|
|
6117
|
-
rem.textContent = "\u2715";
|
|
6118
|
-
rem.addEventListener("mouseenter", () => {
|
|
6119
|
-
rem.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
6120
|
-
});
|
|
6121
|
-
rem.addEventListener("mouseleave", () => {
|
|
6122
|
-
rem.style.backgroundColor = "transparent";
|
|
6123
|
-
});
|
|
6124
|
-
rem.onclick = () => handleRemoveItem(item);
|
|
6125
|
-
item.style.position = "relative";
|
|
6126
|
-
item.appendChild(rem);
|
|
6127
|
-
}
|
|
6128
|
-
itemsWrap.appendChild(item);
|
|
6129
|
-
updateAddButton();
|
|
6130
|
-
}
|
|
6217
|
+
const handleAddItem = () => {
|
|
6218
|
+
if (countItems() >= max) return;
|
|
6219
|
+
const idx = countItems();
|
|
6220
|
+
const currentFormData = state.formRoot ? extractRootFormData(state.formRoot) : {};
|
|
6221
|
+
const subCtx = {
|
|
6222
|
+
state: ctx.state,
|
|
6223
|
+
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
6224
|
+
prefill: childDefaults,
|
|
6225
|
+
// Defaults for enableIf evaluation
|
|
6226
|
+
formData: currentFormData,
|
|
6227
|
+
// Current root data from DOM for enableIf
|
|
6228
|
+
inheritedReadonly: childInheritedReadonly
|
|
6131
6229
|
};
|
|
6132
|
-
|
|
6230
|
+
const item = document.createElement("div");
|
|
6231
|
+
item.className = "containerItem border border-gray-300 rounded-lg p-2 bg-white";
|
|
6232
|
+
item.setAttribute("data-container-item", `${element.key}[${idx}]`);
|
|
6233
|
+
const childWrapper = document.createElement("div");
|
|
6234
|
+
childWrapper.className = getChildWrapperClass(isSlides, element.columns);
|
|
6235
|
+
element.elements.forEach((child) => {
|
|
6236
|
+
var _a2;
|
|
6237
|
+
if (child.type !== "markdown" && (child.hidden || child.type === "hidden")) {
|
|
6238
|
+
childWrapper.appendChild(
|
|
6239
|
+
createHiddenInput(
|
|
6240
|
+
pathJoin(subCtx.path, child.key),
|
|
6241
|
+
(_a2 = "default" in child ? child.default : null) != null ? _a2 : null
|
|
6242
|
+
)
|
|
6243
|
+
);
|
|
6244
|
+
} else {
|
|
6245
|
+
childWrapper.appendChild(renderElement(child, subCtx));
|
|
6246
|
+
}
|
|
6247
|
+
});
|
|
6248
|
+
item.appendChild(childWrapper);
|
|
6249
|
+
if (!containerIsReadonly) {
|
|
6250
|
+
mountRemoveButton(item, () => handleRemoveItem(item));
|
|
6251
|
+
}
|
|
6252
|
+
if (slideAddTile && slideAddTile.parentElement === itemsWrap) {
|
|
6253
|
+
itemsWrap.insertBefore(item, slideAddTile);
|
|
6254
|
+
} else {
|
|
6255
|
+
itemsWrap.appendChild(item);
|
|
6256
|
+
}
|
|
6257
|
+
updateAddButton();
|
|
6133
6258
|
};
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6259
|
+
let slideAddTile = null;
|
|
6260
|
+
let slideAddUpdate = null;
|
|
6261
|
+
let pillAddUpdate = null;
|
|
6262
|
+
const syncSlideTileSize = () => {
|
|
6263
|
+
if (!slideAddTile) return;
|
|
6264
|
+
const firstSlide = itemsWrap.querySelector(
|
|
6265
|
+
":scope > .containerItem"
|
|
6138
6266
|
);
|
|
6139
|
-
if (
|
|
6140
|
-
|
|
6141
|
-
existingAddBtn.style.opacity = currentCount >= max ? "0.5" : "1";
|
|
6142
|
-
existingAddBtn.style.pointerEvents = currentCount >= max ? "none" : "auto";
|
|
6267
|
+
if (firstSlide && firstSlide.offsetHeight > 0) {
|
|
6268
|
+
slideAddTile.style.minHeight = `${firstSlide.offsetHeight}px`;
|
|
6143
6269
|
}
|
|
6144
|
-
|
|
6270
|
+
};
|
|
6271
|
+
const updateAddButton = () => {
|
|
6272
|
+
const currentCount = countItems();
|
|
6273
|
+
if (slideAddUpdate) slideAddUpdate(currentCount, max);
|
|
6274
|
+
if (pillAddUpdate) pillAddUpdate(currentCount, max);
|
|
6275
|
+
if (slideAddTile) syncSlideTileSize();
|
|
6145
6276
|
};
|
|
6146
6277
|
const handleRemoveItem = (item) => {
|
|
6147
6278
|
item.remove();
|
|
@@ -6187,24 +6318,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6187
6318
|
});
|
|
6188
6319
|
item.appendChild(childWrapper);
|
|
6189
6320
|
if (!containerIsReadonly) {
|
|
6190
|
-
|
|
6191
|
-
rem.type = "button";
|
|
6192
|
-
rem.className = "absolute top-2 right-2 px-2 py-1 rounded";
|
|
6193
|
-
rem.style.cssText = `
|
|
6194
|
-
color: var(--fb-error-color);
|
|
6195
|
-
background-color: transparent;
|
|
6196
|
-
transition: background-color var(--fb-transition-duration);
|
|
6197
|
-
`;
|
|
6198
|
-
rem.textContent = "\u2715";
|
|
6199
|
-
rem.addEventListener("mouseenter", () => {
|
|
6200
|
-
rem.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
6201
|
-
});
|
|
6202
|
-
rem.addEventListener("mouseleave", () => {
|
|
6203
|
-
rem.style.backgroundColor = "transparent";
|
|
6204
|
-
});
|
|
6205
|
-
rem.onclick = () => handleRemoveItem(item);
|
|
6206
|
-
item.style.position = "relative";
|
|
6207
|
-
item.appendChild(rem);
|
|
6321
|
+
mountRemoveButton(item, () => handleRemoveItem(item));
|
|
6208
6322
|
}
|
|
6209
6323
|
itemsWrap.appendChild(item);
|
|
6210
6324
|
});
|
|
@@ -6249,41 +6363,43 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6249
6363
|
}
|
|
6250
6364
|
});
|
|
6251
6365
|
item.appendChild(childWrapper);
|
|
6252
|
-
|
|
6253
|
-
rem.type = "button";
|
|
6254
|
-
rem.className = "absolute top-2 right-2 px-2 py-1 rounded";
|
|
6255
|
-
rem.style.cssText = `
|
|
6256
|
-
color: var(--fb-error-color);
|
|
6257
|
-
background-color: transparent;
|
|
6258
|
-
transition: background-color var(--fb-transition-duration);
|
|
6259
|
-
`;
|
|
6260
|
-
rem.textContent = "\u2715";
|
|
6261
|
-
rem.addEventListener("mouseenter", () => {
|
|
6262
|
-
rem.style.backgroundColor = "var(--fb-background-hover-color)";
|
|
6263
|
-
});
|
|
6264
|
-
rem.addEventListener("mouseleave", () => {
|
|
6265
|
-
rem.style.backgroundColor = "transparent";
|
|
6266
|
-
});
|
|
6267
|
-
rem.onclick = () => {
|
|
6366
|
+
mountRemoveButton(item, () => {
|
|
6268
6367
|
if (countItems() > min) {
|
|
6269
6368
|
handleRemoveItem(item);
|
|
6270
6369
|
}
|
|
6271
|
-
};
|
|
6272
|
-
item.style.position = "relative";
|
|
6273
|
-
item.appendChild(rem);
|
|
6370
|
+
});
|
|
6274
6371
|
itemsWrap.appendChild(item);
|
|
6275
6372
|
}
|
|
6276
6373
|
}
|
|
6277
6374
|
containerWrap.appendChild(itemsWrap);
|
|
6278
6375
|
if (!containerIsReadonly) {
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6376
|
+
if (isSlides) {
|
|
6377
|
+
itemsWrap.style.alignItems = "stretch";
|
|
6378
|
+
const handle = createSlideAddTile(handleAddItem, {
|
|
6379
|
+
label: element.addLabel
|
|
6380
|
+
});
|
|
6381
|
+
slideAddTile = handle.tile;
|
|
6382
|
+
slideAddUpdate = handle.update;
|
|
6383
|
+
mountCounterInLabel(wrapper, handle.counter);
|
|
6384
|
+
itemsWrap.appendChild(handle.tile);
|
|
6385
|
+
} else {
|
|
6386
|
+
const handle = createAddItemRow("container", handleAddItem, {
|
|
6387
|
+
label: element.addLabel
|
|
6388
|
+
});
|
|
6389
|
+
pillAddUpdate = handle.update;
|
|
6390
|
+
mountCounterInLabel(wrapper, handle.counter);
|
|
6391
|
+
containerWrap.appendChild(handle.row);
|
|
6392
|
+
}
|
|
6284
6393
|
}
|
|
6285
6394
|
updateAddButton();
|
|
6286
6395
|
wrapper.appendChild(containerWrap);
|
|
6396
|
+
if (slideAddTile) {
|
|
6397
|
+
if (typeof requestAnimationFrame === "function") {
|
|
6398
|
+
requestAnimationFrame(syncSlideTileSize);
|
|
6399
|
+
} else {
|
|
6400
|
+
syncSlideTileSize();
|
|
6401
|
+
}
|
|
6402
|
+
}
|
|
6287
6403
|
}
|
|
6288
6404
|
var validateElementFunc = null;
|
|
6289
6405
|
function setValidateElement(fn) {
|
|
@@ -9251,10 +9367,7 @@ var TAGS = {
|
|
|
9251
9367
|
"-": ["<hr />"]
|
|
9252
9368
|
};
|
|
9253
9369
|
function outdent(str) {
|
|
9254
|
-
return str.replace(
|
|
9255
|
-
RegExp("^" + (str.match(/^(\t| )+/) || "")[0], "gm"),
|
|
9256
|
-
""
|
|
9257
|
-
);
|
|
9370
|
+
return str.replace(RegExp("^" + (str.match(/^(\t| )+/) || "")[0], "gm"), "");
|
|
9258
9371
|
}
|
|
9259
9372
|
function encodeAttr(str) {
|
|
9260
9373
|
return (str + "").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -9417,12 +9530,7 @@ function ensureMarkdownStyles() {
|
|
|
9417
9530
|
`;
|
|
9418
9531
|
document.head.appendChild(style);
|
|
9419
9532
|
}
|
|
9420
|
-
var ANCHOR_DANGEROUS_SCHEMES = [
|
|
9421
|
-
"javascript:",
|
|
9422
|
-
"data:",
|
|
9423
|
-
"vbscript:",
|
|
9424
|
-
"blob:"
|
|
9425
|
-
];
|
|
9533
|
+
var ANCHOR_DANGEROUS_SCHEMES = ["javascript:", "data:", "vbscript:", "blob:"];
|
|
9426
9534
|
var IMG_DANGEROUS_SCHEMES = ["javascript:", "vbscript:", "blob:"];
|
|
9427
9535
|
function isImgSrcDangerous(normalized) {
|
|
9428
9536
|
if (IMG_DANGEROUS_SCHEMES.some((scheme) => normalized.startsWith(scheme))) {
|
|
@@ -9749,6 +9857,7 @@ function createInfoButton(element) {
|
|
|
9749
9857
|
function createLabelContainer(element) {
|
|
9750
9858
|
const label = document.createElement("div");
|
|
9751
9859
|
label.className = "flex items-center mb-1";
|
|
9860
|
+
label.dataset.fbLabelRow = "";
|
|
9752
9861
|
const title = createFieldLabel(element);
|
|
9753
9862
|
label.appendChild(title);
|
|
9754
9863
|
if (element.description || element.hint) {
|
|
@@ -9966,6 +10075,7 @@ var defaultConfig = {
|
|
|
9966
10075
|
invalidFileExtension: 'File "{name}" has unsupported format. Allowed: {formats}',
|
|
9967
10076
|
invalidFileMime: 'File "{name}": file type {type} not allowed (allowed: {mimes})',
|
|
9968
10077
|
fileTooLarge: 'File "{name}" exceeds maximum size of {maxSize}MB',
|
|
10078
|
+
uploadFailed: 'Failed to upload "{name}": {error}',
|
|
9969
10079
|
filesLimitExceeded: "{skipped} file(s) skipped: maximum {max} files allowed",
|
|
9970
10080
|
unsupportedFieldType: "Unsupported field type: {type}",
|
|
9971
10081
|
invalidOption: "Invalid option",
|
|
@@ -10041,6 +10151,7 @@ var defaultConfig = {
|
|
|
10041
10151
|
invalidFileExtension: '\u0424\u0430\u0439\u043B "{name}" \u0438\u043C\u0435\u0435\u0442 \u043D\u0435\u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043C\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442. \u0414\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u0435: {formats}',
|
|
10042
10152
|
invalidFileMime: '\u0424\u0430\u0439\u043B "{name}": \u0442\u0438\u043F \u0444\u0430\u0439\u043B\u0430 {type} \u043D\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043D (\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u044B: {mimes})',
|
|
10043
10153
|
fileTooLarge: '\u0424\u0430\u0439\u043B "{name}" \u043F\u0440\u0435\u0432\u044B\u0448\u0430\u0435\u0442 \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0440\u0430\u0437\u043C\u0435\u0440 {maxSize}\u041C\u0411',
|
|
10154
|
+
uploadFailed: '\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C "{name}": {error}',
|
|
10044
10155
|
filesLimitExceeded: "{skipped} \u0444\u0430\u0439\u043B(\u043E\u0432) \u043F\u0440\u043E\u043F\u0443\u0449\u0435\u043D\u043E: \u043C\u0430\u043A\u0441\u0438\u043C\u0443\u043C {max} \u0444\u0430\u0439\u043B\u043E\u0432",
|
|
10045
10156
|
unsupportedFieldType: "\u041D\u0435\u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043C\u044B\u0439 \u0442\u0438\u043F \u043F\u043E\u043B\u044F: {type}",
|
|
10046
10157
|
invalidOption: "\u041D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435",
|
|
@@ -10263,29 +10374,6 @@ var exampleThemes = {
|
|
|
10263
10374
|
}
|
|
10264
10375
|
};
|
|
10265
10376
|
|
|
10266
|
-
// src/utils/styles.ts
|
|
10267
|
-
function applyActionButtonStyles(button, isFormLevel = false) {
|
|
10268
|
-
button.style.cssText = `
|
|
10269
|
-
background-color: var(--fb-action-bg-color);
|
|
10270
|
-
color: var(--fb-action-text-color);
|
|
10271
|
-
border: var(--fb-border-width) solid var(--fb-action-border-color);
|
|
10272
|
-
padding: ${isFormLevel ? "0.5rem 1rem" : "0.5rem 0.75rem"};
|
|
10273
|
-
font-size: var(--fb-font-size);
|
|
10274
|
-
font-weight: var(--fb-font-weight-medium);
|
|
10275
|
-
border-radius: var(--fb-border-radius);
|
|
10276
|
-
transition: all var(--fb-transition-duration);
|
|
10277
|
-
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
10278
|
-
`;
|
|
10279
|
-
button.addEventListener("mouseenter", () => {
|
|
10280
|
-
button.style.backgroundColor = "var(--fb-action-hover-bg-color)";
|
|
10281
|
-
button.style.borderColor = "var(--fb-action-hover-border-color)";
|
|
10282
|
-
});
|
|
10283
|
-
button.addEventListener("mouseleave", () => {
|
|
10284
|
-
button.style.backgroundColor = "var(--fb-action-bg-color)";
|
|
10285
|
-
button.style.borderColor = "var(--fb-action-border-color)";
|
|
10286
|
-
});
|
|
10287
|
-
}
|
|
10288
|
-
|
|
10289
10377
|
// src/components/registry.ts
|
|
10290
10378
|
function validateHiddenElement(element, key, context) {
|
|
10291
10379
|
var _a;
|