@dmitryvim/form-builder 0.3.0 → 0.3.2
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/README.md +32 -6
- package/dist/browser/formbuilder.min.js +146 -116
- package/dist/browser/formbuilder.v0.3.2.min.js +1441 -0
- package/dist/cjs/index.cjs +398 -156
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +390 -154
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +146 -116
- package/dist/types/components/file/library.d.ts +40 -16
- package/dist/types/components/file/upload.d.ts +111 -2
- package/dist/types/utils/styles.d.ts +24 -1
- package/package.json +1 -1
- package/dist/browser/formbuilder.v0.3.0.min.js +0 -1411
package/dist/cjs/index.cjs
CHANGED
|
@@ -443,6 +443,36 @@ function ensureThemingHooks(doc) {
|
|
|
443
443
|
color: var(--fb-error-color);
|
|
444
444
|
background-color: var(--fb-background-hover-color);
|
|
445
445
|
}
|
|
446
|
+
/* Prefill-suggestion pills rendered by createPrefillHints. Outline pill at rest,
|
|
447
|
+
soft-fill on hover, solid-fill when selected. All colors flow from the active
|
|
448
|
+
theme \u2014 consumers don't need to ship their own CSS. */
|
|
449
|
+
.fb-prefill-hint {
|
|
450
|
+
padding: 0.25rem 0.625rem;
|
|
451
|
+
border: var(--fb-border-width) solid var(--fb-primary-color);
|
|
452
|
+
border-radius: 9999px;
|
|
453
|
+
background: var(--fb-background-color);
|
|
454
|
+
color: var(--fb-primary-color);
|
|
455
|
+
font-size: var(--fb-font-size-small);
|
|
456
|
+
font-weight: var(--fb-font-weight-medium);
|
|
457
|
+
font-family: var(--fb-font-family);
|
|
458
|
+
cursor: pointer;
|
|
459
|
+
transition: background-color var(--fb-transition-duration), border-color var(--fb-transition-duration), color var(--fb-transition-duration);
|
|
460
|
+
}
|
|
461
|
+
.fb-prefill-hint:hover {
|
|
462
|
+
background: var(--fb-primary-soft-color);
|
|
463
|
+
border-color: var(--fb-primary-hover-color);
|
|
464
|
+
color: var(--fb-primary-hover-color);
|
|
465
|
+
}
|
|
466
|
+
.fb-prefill-hint:focus-visible {
|
|
467
|
+
outline: var(--fb-focus-ring-width) solid var(--fb-focus-ring-color);
|
|
468
|
+
outline-offset: 2px;
|
|
469
|
+
}
|
|
470
|
+
.fb-prefill-hint[aria-pressed="true"],
|
|
471
|
+
.fb-prefill-hint.active {
|
|
472
|
+
background: var(--fb-primary-color);
|
|
473
|
+
color: #ffffff;
|
|
474
|
+
border-color: var(--fb-primary-color);
|
|
475
|
+
}
|
|
446
476
|
`;
|
|
447
477
|
doc.head.appendChild(style);
|
|
448
478
|
}
|
|
@@ -454,12 +484,29 @@ function applyAutoExpand(textarea) {
|
|
|
454
484
|
const resize = () => {
|
|
455
485
|
if (!textarea.isConnected) return;
|
|
456
486
|
textarea.style.height = "0";
|
|
457
|
-
|
|
487
|
+
const cs = getComputedStyle(textarea);
|
|
488
|
+
const borderY = parseFloat(cs.borderTopWidth || "0") + parseFloat(cs.borderBottomWidth || "0");
|
|
489
|
+
textarea.style.height = `${textarea.scrollHeight + borderY}px`;
|
|
458
490
|
};
|
|
459
491
|
textarea.addEventListener("input", resize);
|
|
460
492
|
setTimeout(() => {
|
|
461
493
|
if (textarea.isConnected) resize();
|
|
462
494
|
}, 0);
|
|
495
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
496
|
+
let lastWidth = -1;
|
|
497
|
+
const ro = new ResizeObserver((entries) => {
|
|
498
|
+
var _a, _b, _c, _d, _e;
|
|
499
|
+
if (!textarea.isConnected) {
|
|
500
|
+
ro.disconnect();
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const entry = entries[0];
|
|
504
|
+
const w = (_e = (_d = (_b = (_a = entry == null ? void 0 : entry.contentBoxSize) == null ? void 0 : _a[0]) == null ? void 0 : _b.inlineSize) != null ? _d : (_c = entry == null ? void 0 : entry.contentRect) == null ? void 0 : _c.width) != null ? _e : 0;
|
|
505
|
+
if (w === lastWidth) return;
|
|
506
|
+
lastWidth = w;
|
|
507
|
+
resize();
|
|
508
|
+
});
|
|
509
|
+
ro.observe(textarea);
|
|
463
510
|
}
|
|
464
511
|
function applySingleLineMode(textarea) {
|
|
465
512
|
textarea.addEventListener("keydown", (e) => {
|
|
@@ -4275,16 +4322,26 @@ function filterAndSlice(allFiles, currentCount, constraints, state) {
|
|
|
4275
4322
|
}
|
|
4276
4323
|
return { accepted, errorMessage: errorParts.join(" \u2022 ") };
|
|
4277
4324
|
}
|
|
4278
|
-
async function uploadBatch(
|
|
4325
|
+
async function uploadBatch(opts) {
|
|
4279
4326
|
var _a;
|
|
4280
|
-
|
|
4327
|
+
const {
|
|
4328
|
+
accepted,
|
|
4329
|
+
listEl,
|
|
4330
|
+
state,
|
|
4331
|
+
shouldHideAddTile,
|
|
4332
|
+
buildSuccessTile,
|
|
4333
|
+
prepareForUpload
|
|
4334
|
+
} = opts;
|
|
4335
|
+
if (listEl && shouldHideAddTile) {
|
|
4281
4336
|
const tilesWrap = ensureTilesWrap(listEl);
|
|
4282
4337
|
const addTile = (_a = tilesWrap.querySelector(".fb-multi-add-tile-js")) != null ? _a : tilesWrap.querySelector(".fb-tile-add");
|
|
4283
4338
|
if (addTile) addTile.style.display = "none";
|
|
4284
4339
|
}
|
|
4340
|
+
prepareForUpload == null ? void 0 : prepareForUpload();
|
|
4341
|
+
const orderedIds = new Array(accepted.length).fill(null);
|
|
4285
4342
|
const failures = [];
|
|
4286
4343
|
await Promise.allSettled(
|
|
4287
|
-
accepted.map(async (file) => {
|
|
4344
|
+
accepted.map(async (file, index) => {
|
|
4288
4345
|
const placeholder = createUploadingTile(file.name, state);
|
|
4289
4346
|
if (listEl) {
|
|
4290
4347
|
const tilesWrap = ensureTilesWrap(listEl);
|
|
@@ -4297,20 +4354,24 @@ async function uploadBatch(accepted, resourceIds, listEl, state) {
|
|
|
4297
4354
|
type: file.type,
|
|
4298
4355
|
size: file.size,
|
|
4299
4356
|
uploadedAt: /* @__PURE__ */ new Date(),
|
|
4300
|
-
file
|
|
4357
|
+
file
|
|
4301
4358
|
});
|
|
4302
|
-
|
|
4359
|
+
orderedIds[index] = rid;
|
|
4360
|
+
if (buildSuccessTile && placeholder.parentNode) {
|
|
4361
|
+
placeholder.replaceWith(buildSuccessTile(rid));
|
|
4362
|
+
} else {
|
|
4363
|
+
placeholder.remove();
|
|
4364
|
+
}
|
|
4303
4365
|
} catch (err) {
|
|
4304
4366
|
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
4305
4367
|
const cause = wrapped.cause;
|
|
4306
4368
|
const root = cause instanceof Error ? cause : cause !== void 0 ? new Error(String(cause)) : wrapped;
|
|
4307
4369
|
failures.push({ file, error: root });
|
|
4308
|
-
} finally {
|
|
4309
4370
|
placeholder.remove();
|
|
4310
4371
|
}
|
|
4311
4372
|
})
|
|
4312
4373
|
);
|
|
4313
|
-
return { failures };
|
|
4374
|
+
return { failures, orderedIds };
|
|
4314
4375
|
}
|
|
4315
4376
|
function buildBatchErrorMessage(filterError, failures, state) {
|
|
4316
4377
|
if (failures.length === 0) return filterError;
|
|
@@ -4322,69 +4383,72 @@ function buildBatchErrorMessage(filterError, failures, state) {
|
|
|
4322
4383
|
).join(" \u2022 ");
|
|
4323
4384
|
return filterError ? `${filterError} \u2022 ${uploadMsg}` : uploadMsg;
|
|
4324
4385
|
}
|
|
4325
|
-
function
|
|
4386
|
+
async function runMultiFileBatch(opts, files, listEl, errorTarget) {
|
|
4387
|
+
const {
|
|
4388
|
+
resourceIds,
|
|
4389
|
+
state,
|
|
4390
|
+
updateCallback,
|
|
4391
|
+
constraints,
|
|
4392
|
+
pathKey,
|
|
4393
|
+
instance,
|
|
4394
|
+
buildSuccessTile,
|
|
4395
|
+
prepareForUpload,
|
|
4396
|
+
coordinator
|
|
4397
|
+
} = opts;
|
|
4398
|
+
const { accepted, errorMessage } = filterAndSlice(
|
|
4399
|
+
files,
|
|
4400
|
+
coordinator.getOccupiedCount(),
|
|
4401
|
+
constraints,
|
|
4402
|
+
state
|
|
4403
|
+
);
|
|
4404
|
+
if (errorTarget) {
|
|
4405
|
+
if (errorMessage) showFileError(errorTarget, errorMessage);
|
|
4406
|
+
else clearFileError(errorTarget);
|
|
4407
|
+
}
|
|
4408
|
+
const handle = coordinator.beginBatch(accepted.length);
|
|
4409
|
+
const shouldHideAddTile = coordinator.getOccupiedCount() >= constraints.maxCount;
|
|
4410
|
+
const { failures, orderedIds } = await uploadBatch({
|
|
4411
|
+
accepted,
|
|
4412
|
+
listEl,
|
|
4413
|
+
state,
|
|
4414
|
+
shouldHideAddTile,
|
|
4415
|
+
buildSuccessTile,
|
|
4416
|
+
prepareForUpload
|
|
4417
|
+
});
|
|
4418
|
+
handle.setResults(orderedIds);
|
|
4419
|
+
if (instance && pathKey && !state.config.readonly) {
|
|
4420
|
+
instance.triggerOnChange(pathKey, resourceIds);
|
|
4421
|
+
}
|
|
4422
|
+
const { wasLast } = handle.end();
|
|
4423
|
+
if (wasLast) updateCallback();
|
|
4424
|
+
if (errorTarget) {
|
|
4425
|
+
const combined = buildBatchErrorMessage(errorMessage, failures, state);
|
|
4426
|
+
if (combined) showFileError(errorTarget, combined);
|
|
4427
|
+
else clearFileError(errorTarget);
|
|
4428
|
+
}
|
|
4429
|
+
}
|
|
4430
|
+
function setupFilesDropHandler(opts) {
|
|
4431
|
+
const { filesContainer } = opts;
|
|
4326
4432
|
setupDragAndDrop(filesContainer, async (files) => {
|
|
4327
4433
|
var _a;
|
|
4328
|
-
const { accepted, errorMessage } = filterAndSlice(
|
|
4329
|
-
Array.from(files),
|
|
4330
|
-
resourceIds.length,
|
|
4331
|
-
constraints,
|
|
4332
|
-
state
|
|
4333
|
-
);
|
|
4334
|
-
if (errorMessage) {
|
|
4335
|
-
showFileError(filesContainer, errorMessage);
|
|
4336
|
-
} else {
|
|
4337
|
-
clearFileError(filesContainer);
|
|
4338
|
-
}
|
|
4339
4434
|
const list = (_a = filesContainer.querySelector(".files-list")) != null ? _a : filesContainer;
|
|
4340
|
-
|
|
4341
|
-
const combined = buildBatchErrorMessage(errorMessage, failures, state);
|
|
4342
|
-
if (combined) {
|
|
4343
|
-
showFileError(filesContainer, combined);
|
|
4344
|
-
} else {
|
|
4345
|
-
clearFileError(filesContainer);
|
|
4346
|
-
}
|
|
4347
|
-
updateCallback();
|
|
4348
|
-
if (instance && pathKey && !state.config.readonly) {
|
|
4349
|
-
instance.triggerOnChange(pathKey, resourceIds);
|
|
4350
|
-
}
|
|
4435
|
+
await runMultiFileBatch(opts, Array.from(files), list, filesContainer);
|
|
4351
4436
|
});
|
|
4352
4437
|
}
|
|
4353
|
-
function setupFilesPickerHandler(
|
|
4438
|
+
function setupFilesPickerHandler(opts) {
|
|
4439
|
+
const { filesPicker } = opts;
|
|
4354
4440
|
filesPicker.onchange = async () => {
|
|
4441
|
+
var _a, _b;
|
|
4355
4442
|
if (!filesPicker.files) return;
|
|
4356
|
-
const wrapperEl = filesPicker.closest("[data-files-wrapper]")
|
|
4357
|
-
const
|
|
4443
|
+
const wrapperEl = (_a = filesPicker.closest("[data-files-wrapper]")) != null ? _a : filesPicker.parentElement;
|
|
4444
|
+
const listEl = (_b = wrapperEl == null ? void 0 : wrapperEl.querySelector(".files-list")) != null ? _b : null;
|
|
4445
|
+
await runMultiFileBatch(
|
|
4446
|
+
opts,
|
|
4358
4447
|
Array.from(filesPicker.files),
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
state
|
|
4448
|
+
listEl,
|
|
4449
|
+
wrapperEl
|
|
4362
4450
|
);
|
|
4363
|
-
if (errorMessage && wrapperEl) {
|
|
4364
|
-
showFileError(wrapperEl, errorMessage);
|
|
4365
|
-
} else if (wrapperEl) {
|
|
4366
|
-
clearFileError(wrapperEl);
|
|
4367
|
-
}
|
|
4368
|
-
const listEl = wrapperEl == null ? void 0 : wrapperEl.querySelector(".files-list");
|
|
4369
|
-
const { failures } = await uploadBatch(
|
|
4370
|
-
accepted,
|
|
4371
|
-
resourceIds,
|
|
4372
|
-
listEl != null ? listEl : null,
|
|
4373
|
-
state
|
|
4374
|
-
);
|
|
4375
|
-
if (wrapperEl) {
|
|
4376
|
-
const combined = buildBatchErrorMessage(errorMessage, failures, state);
|
|
4377
|
-
if (combined) {
|
|
4378
|
-
showFileError(wrapperEl, combined);
|
|
4379
|
-
} else {
|
|
4380
|
-
clearFileError(wrapperEl);
|
|
4381
|
-
}
|
|
4382
|
-
}
|
|
4383
|
-
updateCallback();
|
|
4384
4451
|
filesPicker.value = "";
|
|
4385
|
-
if (instance && pathKey && !state.config.readonly) {
|
|
4386
|
-
instance.triggerOnChange(pathKey, resourceIds);
|
|
4387
|
-
}
|
|
4388
4452
|
};
|
|
4389
4453
|
}
|
|
4390
4454
|
|
|
@@ -4426,16 +4490,6 @@ function validatePickedResource(resource, allowedExtensions, allowedMimes, maxSi
|
|
|
4426
4490
|
}
|
|
4427
4491
|
return null;
|
|
4428
4492
|
}
|
|
4429
|
-
function readCurrentResourceIds(wrapper) {
|
|
4430
|
-
const raw = wrapper.dataset.resourceIds;
|
|
4431
|
-
if (!raw) return [];
|
|
4432
|
-
try {
|
|
4433
|
-
const parsed = JSON.parse(raw);
|
|
4434
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
4435
|
-
} catch {
|
|
4436
|
-
return [];
|
|
4437
|
-
}
|
|
4438
|
-
}
|
|
4439
4493
|
function registerPickedResource(resource, state) {
|
|
4440
4494
|
var _a;
|
|
4441
4495
|
const existing = state.resourceIndex.get(resource.resourceId);
|
|
@@ -4451,14 +4505,28 @@ function extractPickerError(error, state) {
|
|
|
4451
4505
|
if (error instanceof Error && error.message) return error.message;
|
|
4452
4506
|
return t("pickerError", state);
|
|
4453
4507
|
}
|
|
4454
|
-
async function handleLibraryPickMulti(
|
|
4508
|
+
async function handleLibraryPickMulti(opts) {
|
|
4455
4509
|
var _a;
|
|
4510
|
+
const {
|
|
4511
|
+
state,
|
|
4512
|
+
element,
|
|
4513
|
+
wrapper,
|
|
4514
|
+
fieldPath,
|
|
4515
|
+
resourceIds,
|
|
4516
|
+
maxCount,
|
|
4517
|
+
updateCallback,
|
|
4518
|
+
instance,
|
|
4519
|
+
coordinator,
|
|
4520
|
+
list,
|
|
4521
|
+
buildSuccessTile
|
|
4522
|
+
} = opts;
|
|
4456
4523
|
if (!state.config.pickExistingFiles) return;
|
|
4457
4524
|
const allowedExtensions = getAllowedExtensions(element.accept);
|
|
4458
4525
|
const allowedMimes = getAllowedMimes(element.accept);
|
|
4459
4526
|
const maxSizeMB = (_a = element.maxSize) != null ? _a : Infinity;
|
|
4460
|
-
const
|
|
4461
|
-
const
|
|
4527
|
+
const knownRids = coordinator.getAllKnownRids();
|
|
4528
|
+
const existingSet = new Set(knownRids);
|
|
4529
|
+
const remaining = maxCount === Infinity ? Infinity : Math.max(0, maxCount - coordinator.getOccupiedCount());
|
|
4462
4530
|
let picked;
|
|
4463
4531
|
try {
|
|
4464
4532
|
picked = await state.config.pickExistingFiles({
|
|
@@ -4467,14 +4535,15 @@ async function handleLibraryPickMulti(state, element, wrapper, fieldPath, resour
|
|
|
4467
4535
|
accept: buildAcceptContext(element),
|
|
4468
4536
|
maxSizeMB: maxSizeMB === Infinity ? void 0 : maxSizeMB,
|
|
4469
4537
|
remainingSlots: remaining === Infinity ? void 0 : remaining,
|
|
4470
|
-
|
|
4538
|
+
// Hand the host every rid that's already selected (committed or
|
|
4539
|
+
// staged) so it can grey them out or filter them.
|
|
4540
|
+
selectedResourceIds: knownRids
|
|
4471
4541
|
});
|
|
4472
4542
|
} catch (error) {
|
|
4473
4543
|
showFileError(wrapper, extractPickerError(error, state));
|
|
4474
4544
|
return;
|
|
4475
4545
|
}
|
|
4476
4546
|
if (picked.length === 0) return;
|
|
4477
|
-
const existingSet = new Set(currentIds);
|
|
4478
4547
|
const seen = /* @__PURE__ */ new Set();
|
|
4479
4548
|
const deduped = picked.filter((r) => {
|
|
4480
4549
|
if (existingSet.has(r.resourceId)) return false;
|
|
@@ -4492,10 +4561,18 @@ async function handleLibraryPickMulti(state, element, wrapper, fieldPath, resour
|
|
|
4492
4561
|
);
|
|
4493
4562
|
return err === null;
|
|
4494
4563
|
});
|
|
4495
|
-
const freshRemaining = maxCount === Infinity ? validItems.length : Math.max(0, maxCount -
|
|
4564
|
+
const freshRemaining = maxCount === Infinity ? validItems.length : Math.max(0, maxCount - coordinator.getOccupiedCount());
|
|
4496
4565
|
const accepted = validItems.slice(0, freshRemaining);
|
|
4497
4566
|
const skipped = validItems.length - accepted.length;
|
|
4498
|
-
if (accepted.length === 0)
|
|
4567
|
+
if (accepted.length === 0) {
|
|
4568
|
+
if (skipped > 0) {
|
|
4569
|
+
showFileError(
|
|
4570
|
+
wrapper,
|
|
4571
|
+
t("filesLimitExceeded", state, { skipped, max: maxCount })
|
|
4572
|
+
);
|
|
4573
|
+
}
|
|
4574
|
+
return;
|
|
4575
|
+
}
|
|
4499
4576
|
clearFileError(wrapper);
|
|
4500
4577
|
if (skipped > 0) {
|
|
4501
4578
|
showFileError(
|
|
@@ -4505,13 +4582,22 @@ async function handleLibraryPickMulti(state, element, wrapper, fieldPath, resour
|
|
|
4505
4582
|
}
|
|
4506
4583
|
for (const resource of accepted) {
|
|
4507
4584
|
registerPickedResource(resource, state);
|
|
4508
|
-
resourceIds.push(resource.resourceId);
|
|
4509
4585
|
}
|
|
4510
|
-
|
|
4511
|
-
|
|
4586
|
+
const acceptedIds = accepted.map((r) => r.resourceId);
|
|
4587
|
+
const handle = coordinator.beginBatch(accepted.length);
|
|
4588
|
+
handle.setResults(acceptedIds);
|
|
4512
4589
|
if (!state.config.readonly) {
|
|
4513
4590
|
instance.triggerOnChange(fieldPath, resourceIds);
|
|
4514
4591
|
}
|
|
4592
|
+
const { wasLast } = handle.end();
|
|
4593
|
+
if (wasLast) {
|
|
4594
|
+
updateCallback();
|
|
4595
|
+
} else {
|
|
4596
|
+
const tilesWrap = ensureTilesWrap(list);
|
|
4597
|
+
for (const rid of acceptedIds) {
|
|
4598
|
+
tilesWrap.appendChild(buildSuccessTile(rid));
|
|
4599
|
+
}
|
|
4600
|
+
}
|
|
4515
4601
|
}
|
|
4516
4602
|
async function handleLibraryPickSingle(state, element, container, fileWrapper, pathKey, fieldPath, renderCallback, instance) {
|
|
4517
4603
|
var _a, _b;
|
|
@@ -4839,6 +4925,14 @@ function buildMetaDot() {
|
|
|
4839
4925
|
return dot;
|
|
4840
4926
|
}
|
|
4841
4927
|
var gridResizeObservers = /* @__PURE__ */ new WeakMap();
|
|
4928
|
+
function disposePlaceholdersForUpload(container) {
|
|
4929
|
+
const observer = gridResizeObservers.get(container);
|
|
4930
|
+
if (observer) {
|
|
4931
|
+
observer.disconnect();
|
|
4932
|
+
gridResizeObservers.delete(container);
|
|
4933
|
+
}
|
|
4934
|
+
container.querySelectorAll(".fb-multi-placeholder").forEach((p) => p.remove());
|
|
4935
|
+
}
|
|
4842
4936
|
function renderResourcePills(opts) {
|
|
4843
4937
|
var _a;
|
|
4844
4938
|
const {
|
|
@@ -5193,16 +5287,19 @@ function setupMultiFileEditMode(element, ctx, wrapper, pathKey, maxFiles) {
|
|
|
5193
5287
|
filesPicker.click();
|
|
5194
5288
|
};
|
|
5195
5289
|
const onLibraryPick = state.config.pickExistingFiles && !element.disableLibrary ? () => {
|
|
5196
|
-
handleLibraryPickMulti(
|
|
5290
|
+
handleLibraryPickMulti({
|
|
5197
5291
|
state,
|
|
5198
5292
|
element,
|
|
5199
|
-
filesWrapper,
|
|
5200
|
-
pathKey,
|
|
5201
|
-
initialFiles,
|
|
5202
|
-
maxFiles,
|
|
5203
|
-
updateFilesDisplay,
|
|
5204
|
-
ctx.instance
|
|
5205
|
-
|
|
5293
|
+
wrapper: filesWrapper,
|
|
5294
|
+
fieldPath: pathKey,
|
|
5295
|
+
resourceIds: initialFiles,
|
|
5296
|
+
maxCount: maxFiles,
|
|
5297
|
+
updateCallback: updateFilesDisplay,
|
|
5298
|
+
instance: ctx.instance,
|
|
5299
|
+
coordinator,
|
|
5300
|
+
list,
|
|
5301
|
+
buildSuccessTile
|
|
5302
|
+
}).catch((err) => {
|
|
5206
5303
|
console.error("Library pick failed:", err);
|
|
5207
5304
|
});
|
|
5208
5305
|
} : null;
|
|
@@ -5213,41 +5310,160 @@ function setupMultiFileEditMode(element, ctx, wrapper, pathKey, maxFiles) {
|
|
|
5213
5310
|
rids: initialFiles,
|
|
5214
5311
|
state,
|
|
5215
5312
|
onRemove: currentlyReadonly ? null : (ridToRemove) => {
|
|
5216
|
-
var _a2;
|
|
5313
|
+
var _a2, _b2;
|
|
5217
5314
|
releaseLocalFileUrl((_a2 = state.resourceIndex.get(ridToRemove)) == null ? void 0 : _a2.file);
|
|
5218
5315
|
const index = initialFiles.indexOf(ridToRemove);
|
|
5219
5316
|
if (index > -1) initialFiles.splice(index, 1);
|
|
5220
|
-
|
|
5317
|
+
if (coordinator.hasInFlightBatches()) {
|
|
5318
|
+
pendingRemovals.add(ridToRemove);
|
|
5319
|
+
(_b2 = list.querySelector(`[data-resource-id="${ridToRemove}"]`)) == null ? void 0 : _b2.remove();
|
|
5320
|
+
filesWrapper.dataset.resourceIds = JSON.stringify(initialFiles);
|
|
5321
|
+
} else {
|
|
5322
|
+
updateFilesDisplay();
|
|
5323
|
+
}
|
|
5324
|
+
if (ctx.instance && pathKey && !state.config.readonly) {
|
|
5325
|
+
ctx.instance.triggerOnChange(pathKey, initialFiles);
|
|
5326
|
+
}
|
|
5221
5327
|
},
|
|
5222
5328
|
maxCount: maxFiles < Infinity ? maxFiles : void 0,
|
|
5223
5329
|
isReadonly: currentlyReadonly,
|
|
5224
5330
|
onLibraryPick: currentlyReadonly ? null : onLibraryPick,
|
|
5225
5331
|
element,
|
|
5226
5332
|
onClearAll: currentlyReadonly ? void 0 : () => {
|
|
5333
|
+
var _a2, _b2;
|
|
5334
|
+
for (const rid of initialFiles) {
|
|
5335
|
+
releaseLocalFileUrl((_a2 = state.resourceIndex.get(rid)) == null ? void 0 : _a2.file);
|
|
5336
|
+
}
|
|
5227
5337
|
initialFiles.splice(0);
|
|
5228
|
-
|
|
5338
|
+
if (coordinator.hasInFlightBatches()) {
|
|
5339
|
+
const visibleTiles = list.querySelectorAll("[data-resource-id]");
|
|
5340
|
+
for (const tile of visibleTiles) {
|
|
5341
|
+
const rid = tile.dataset.resourceId;
|
|
5342
|
+
if (rid) {
|
|
5343
|
+
releaseLocalFileUrl((_b2 = state.resourceIndex.get(rid)) == null ? void 0 : _b2.file);
|
|
5344
|
+
pendingRemovals.add(rid);
|
|
5345
|
+
}
|
|
5346
|
+
tile.remove();
|
|
5347
|
+
}
|
|
5348
|
+
filesWrapper.dataset.resourceIds = JSON.stringify(initialFiles);
|
|
5349
|
+
} else {
|
|
5350
|
+
updateFilesDisplay();
|
|
5351
|
+
}
|
|
5352
|
+
if (ctx.instance && pathKey && !state.config.readonly) {
|
|
5353
|
+
ctx.instance.triggerOnChange(pathKey, initialFiles);
|
|
5354
|
+
}
|
|
5229
5355
|
},
|
|
5230
5356
|
openPicker
|
|
5231
5357
|
});
|
|
5232
5358
|
}
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5359
|
+
let inFlightFiles = 0;
|
|
5360
|
+
let activeBatches = 0;
|
|
5361
|
+
let nextBatchOrdinal = 0;
|
|
5362
|
+
let nextCommitOrdinal = 0;
|
|
5363
|
+
const stagedResults = /* @__PURE__ */ new Map();
|
|
5364
|
+
const batchReservations = /* @__PURE__ */ new Map();
|
|
5365
|
+
const pendingRemovals = /* @__PURE__ */ new Set();
|
|
5366
|
+
const drainContiguousStagedResults = () => {
|
|
5367
|
+
var _a2;
|
|
5368
|
+
while (stagedResults.has(nextCommitOrdinal)) {
|
|
5369
|
+
const ordinal = nextCommitOrdinal;
|
|
5370
|
+
const ids = stagedResults.get(ordinal);
|
|
5371
|
+
stagedResults.delete(ordinal);
|
|
5372
|
+
nextCommitOrdinal += 1;
|
|
5373
|
+
const reservation = (_a2 = batchReservations.get(ordinal)) != null ? _a2 : 0;
|
|
5374
|
+
batchReservations.delete(ordinal);
|
|
5375
|
+
inFlightFiles -= reservation;
|
|
5376
|
+
for (const rid of ids) {
|
|
5377
|
+
if (rid === null) continue;
|
|
5378
|
+
if (pendingRemovals.has(rid)) {
|
|
5379
|
+
pendingRemovals.delete(rid);
|
|
5380
|
+
continue;
|
|
5381
|
+
}
|
|
5382
|
+
initialFiles.push(rid);
|
|
5383
|
+
}
|
|
5384
|
+
}
|
|
5385
|
+
filesWrapper.dataset.resourceIds = JSON.stringify(initialFiles);
|
|
5386
|
+
};
|
|
5387
|
+
const coordinator = {
|
|
5388
|
+
getOccupiedCount: () => initialFiles.length + inFlightFiles,
|
|
5389
|
+
getAllKnownRids: () => {
|
|
5390
|
+
const out = [...initialFiles];
|
|
5391
|
+
for (const ids of stagedResults.values()) {
|
|
5392
|
+
for (const rid of ids) {
|
|
5393
|
+
if (rid !== null) out.push(rid);
|
|
5394
|
+
}
|
|
5395
|
+
}
|
|
5396
|
+
return out;
|
|
5397
|
+
},
|
|
5398
|
+
hasInFlightBatches: () => activeBatches > 0 || batchReservations.size > 0,
|
|
5399
|
+
wasRemovedDuringBatch: (rid) => pendingRemovals.has(rid),
|
|
5400
|
+
beginBatch: (count) => {
|
|
5401
|
+
inFlightFiles += count;
|
|
5402
|
+
activeBatches += 1;
|
|
5403
|
+
const ordinal = nextBatchOrdinal++;
|
|
5404
|
+
batchReservations.set(ordinal, count);
|
|
5405
|
+
return {
|
|
5406
|
+
setResults: (orderedIds) => {
|
|
5407
|
+
stagedResults.set(ordinal, orderedIds);
|
|
5408
|
+
drainContiguousStagedResults();
|
|
5409
|
+
},
|
|
5410
|
+
end: () => {
|
|
5411
|
+
activeBatches -= 1;
|
|
5412
|
+
const wasLast = activeBatches === 0 && batchReservations.size === 0;
|
|
5413
|
+
if (wasLast) {
|
|
5414
|
+
pendingRemovals.clear();
|
|
5415
|
+
}
|
|
5416
|
+
return { wasLast };
|
|
5417
|
+
}
|
|
5418
|
+
};
|
|
5419
|
+
}
|
|
5420
|
+
};
|
|
5421
|
+
const buildSuccessTile = (rid) => {
|
|
5422
|
+
const currentlyReadonly = isElementReadonly(element, state);
|
|
5423
|
+
return buildPreviewTile(
|
|
5424
|
+
rid,
|
|
5425
|
+
state,
|
|
5426
|
+
!currentlyReadonly,
|
|
5427
|
+
currentlyReadonly ? null : () => {
|
|
5428
|
+
var _a2, _b2, _c;
|
|
5429
|
+
releaseLocalFileUrl((_a2 = state.resourceIndex.get(rid)) == null ? void 0 : _a2.file);
|
|
5430
|
+
const idx = initialFiles.indexOf(rid);
|
|
5431
|
+
if (idx > -1) {
|
|
5432
|
+
initialFiles.splice(idx, 1);
|
|
5433
|
+
if (coordinator.hasInFlightBatches()) {
|
|
5434
|
+
pendingRemovals.add(rid);
|
|
5435
|
+
(_b2 = list.querySelector(`[data-resource-id="${rid}"]`)) == null ? void 0 : _b2.remove();
|
|
5436
|
+
filesWrapper.dataset.resourceIds = JSON.stringify(initialFiles);
|
|
5437
|
+
} else {
|
|
5438
|
+
updateFilesDisplay();
|
|
5439
|
+
}
|
|
5440
|
+
if (ctx.instance && pathKey && !state.config.readonly) {
|
|
5441
|
+
ctx.instance.triggerOnChange(pathKey, initialFiles);
|
|
5442
|
+
}
|
|
5443
|
+
return;
|
|
5444
|
+
}
|
|
5445
|
+
pendingRemovals.add(rid);
|
|
5446
|
+
(_c = list.querySelector(`[data-resource-id="${rid}"]`)) == null ? void 0 : _c.remove();
|
|
5447
|
+
if (ctx.instance && pathKey && !state.config.readonly) {
|
|
5448
|
+
ctx.instance.triggerOnChange(pathKey, initialFiles);
|
|
5449
|
+
}
|
|
5450
|
+
}
|
|
5451
|
+
);
|
|
5452
|
+
};
|
|
5453
|
+
const prepareForUpload = () => disposePlaceholdersForUpload(list);
|
|
5454
|
+
const sharedHandlerOpts = {
|
|
5455
|
+
resourceIds: initialFiles,
|
|
5245
5456
|
state,
|
|
5246
|
-
updateFilesDisplay,
|
|
5457
|
+
updateCallback: updateFilesDisplay,
|
|
5247
5458
|
constraints,
|
|
5248
5459
|
pathKey,
|
|
5249
|
-
ctx.instance
|
|
5250
|
-
|
|
5460
|
+
instance: ctx.instance,
|
|
5461
|
+
buildSuccessTile,
|
|
5462
|
+
prepareForUpload,
|
|
5463
|
+
coordinator
|
|
5464
|
+
};
|
|
5465
|
+
setupFilesDropHandler({ ...sharedHandlerOpts, filesContainer });
|
|
5466
|
+
setupFilesPickerHandler({ ...sharedHandlerOpts, filesPicker });
|
|
5251
5467
|
updateFilesDisplay();
|
|
5252
5468
|
wrapper.appendChild(filesWrapper);
|
|
5253
5469
|
}
|
|
@@ -6610,6 +6826,7 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
6610
6826
|
formData: (_b = ctx.formData) != null ? _b : ctx.prefill,
|
|
6611
6827
|
// Complete root data for enableIf evaluation
|
|
6612
6828
|
state: ctx.state,
|
|
6829
|
+
instance: ctx.instance,
|
|
6613
6830
|
inheritedReadonly: containerIsReadonly || ctx.inheritedReadonly
|
|
6614
6831
|
};
|
|
6615
6832
|
element.elements.forEach((child) => {
|
|
@@ -6698,6 +6915,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6698
6915
|
const currentFormData = state.formRoot ? extractRootFormData(state.formRoot) : {};
|
|
6699
6916
|
const subCtx = {
|
|
6700
6917
|
state: ctx.state,
|
|
6918
|
+
instance: ctx.instance,
|
|
6701
6919
|
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
6702
6920
|
prefill: childDefaults,
|
|
6703
6921
|
// Defaults for enableIf evaluation
|
|
@@ -6765,6 +6983,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6765
6983
|
const mergedPrefill = mergeWithDefaults(prefillObj || {}, childDefaults);
|
|
6766
6984
|
const subCtx = {
|
|
6767
6985
|
state: ctx.state,
|
|
6986
|
+
instance: ctx.instance,
|
|
6768
6987
|
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
6769
6988
|
prefill: mergedPrefill,
|
|
6770
6989
|
// Merged prefill with defaults for enableIf
|
|
@@ -6812,6 +7031,7 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
6812
7031
|
const idx = countItems();
|
|
6813
7032
|
const subCtx = {
|
|
6814
7033
|
state: ctx.state,
|
|
7034
|
+
instance: ctx.instance,
|
|
6815
7035
|
path: pathJoin(ctx.path, `${element.key}[${idx}]`),
|
|
6816
7036
|
prefill: childDefaults,
|
|
6817
7037
|
// Defaults for enableIf evaluation
|
|
@@ -8487,6 +8707,21 @@ function applyAutoExpand2(textarea, backdrop) {
|
|
|
8487
8707
|
setTimeout(() => {
|
|
8488
8708
|
if (textarea.isConnected) resize();
|
|
8489
8709
|
}, 0);
|
|
8710
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
8711
|
+
let lastWidth = -1;
|
|
8712
|
+
const ro = new ResizeObserver((entries) => {
|
|
8713
|
+
var _a, _b, _c, _d, _e;
|
|
8714
|
+
if (!textarea.isConnected) {
|
|
8715
|
+
ro.disconnect();
|
|
8716
|
+
return;
|
|
8717
|
+
}
|
|
8718
|
+
const entry = entries[0];
|
|
8719
|
+
const w = (_e = (_d = (_b = (_a = entry == null ? void 0 : entry.contentBoxSize) == null ? void 0 : _a[0]) == null ? void 0 : _b.inlineSize) != null ? _d : (_c = entry == null ? void 0 : entry.contentRect) == null ? void 0 : _c.width) != null ? _e : 0;
|
|
8720
|
+
if (w === lastWidth) return;
|
|
8721
|
+
lastWidth = w;
|
|
8722
|
+
resize();
|
|
8723
|
+
});
|
|
8724
|
+
ro.observe(textarea);
|
|
8490
8725
|
}
|
|
8491
8726
|
function buildFileLabels(files, state) {
|
|
8492
8727
|
var _a, _b, _c, _d;
|
|
@@ -10297,8 +10532,35 @@ function extractDOMValue(fieldPath, formRoot) {
|
|
|
10297
10532
|
}
|
|
10298
10533
|
return void 0;
|
|
10299
10534
|
}
|
|
10535
|
+
function buildScopedDataAtPath(path, value) {
|
|
10536
|
+
const segments = path.match(/[^.[\]]+|\[\d+\]/g);
|
|
10537
|
+
if (!segments || segments.length === 0) {
|
|
10538
|
+
return {};
|
|
10539
|
+
}
|
|
10540
|
+
const root = {};
|
|
10541
|
+
let current = root;
|
|
10542
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
10543
|
+
const seg = segments[i];
|
|
10544
|
+
const next = segments[i + 1];
|
|
10545
|
+
const placeholder = next.startsWith("[") && next.endsWith("]") ? [] : {};
|
|
10546
|
+
if (seg.startsWith("[") && seg.endsWith("]")) {
|
|
10547
|
+
const idx = parseInt(seg.slice(1, -1), 10);
|
|
10548
|
+
current[idx] = placeholder;
|
|
10549
|
+
} else {
|
|
10550
|
+
current[seg] = placeholder;
|
|
10551
|
+
}
|
|
10552
|
+
current = placeholder;
|
|
10553
|
+
}
|
|
10554
|
+
const last = segments[segments.length - 1];
|
|
10555
|
+
if (last.startsWith("[") && last.endsWith("]")) {
|
|
10556
|
+
current[parseInt(last.slice(1, -1), 10)] = value;
|
|
10557
|
+
} else {
|
|
10558
|
+
current[last] = value;
|
|
10559
|
+
}
|
|
10560
|
+
return root;
|
|
10561
|
+
}
|
|
10300
10562
|
function reevaluateEnableIf(wrapper, element, ctx) {
|
|
10301
|
-
var _a
|
|
10563
|
+
var _a;
|
|
10302
10564
|
if (!element.enableIf) {
|
|
10303
10565
|
return;
|
|
10304
10566
|
}
|
|
@@ -10309,54 +10571,13 @@ function reevaluateEnableIf(wrapper, element, ctx) {
|
|
|
10309
10571
|
}
|
|
10310
10572
|
const condition = element.enableIf;
|
|
10311
10573
|
const scope = (_a = condition.scope) != null ? _a : "relative";
|
|
10312
|
-
let rootFormData = {};
|
|
10313
|
-
const containerData = {};
|
|
10314
10574
|
const effectiveScope = !ctx.path || ctx.path === "" ? "absolute" : scope;
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
`[data-container-item="${containerKey}[${containerIndex}]"]`
|
|
10322
|
-
);
|
|
10323
|
-
if (containerItemElement) {
|
|
10324
|
-
const inputs = containerItemElement.querySelectorAll("input, select, textarea");
|
|
10325
|
-
inputs.forEach((input) => {
|
|
10326
|
-
const fieldName = input.getAttribute("name");
|
|
10327
|
-
if (fieldName) {
|
|
10328
|
-
const fieldKeyMatch = fieldName.match(/\.([^.[\]]+)$/);
|
|
10329
|
-
if (fieldKeyMatch) {
|
|
10330
|
-
const fieldKey = fieldKeyMatch[1];
|
|
10331
|
-
if (input instanceof HTMLSelectElement) {
|
|
10332
|
-
containerData[fieldKey] = input.value;
|
|
10333
|
-
} else if (input instanceof HTMLInputElement) {
|
|
10334
|
-
if (input.type === "checkbox") {
|
|
10335
|
-
containerData[fieldKey] = input.checked;
|
|
10336
|
-
} else if (input.type === "radio") {
|
|
10337
|
-
if (input.checked) {
|
|
10338
|
-
containerData[fieldKey] = input.value;
|
|
10339
|
-
}
|
|
10340
|
-
} else {
|
|
10341
|
-
containerData[fieldKey] = input.value;
|
|
10342
|
-
}
|
|
10343
|
-
} else if (input instanceof HTMLTextAreaElement) {
|
|
10344
|
-
containerData[fieldKey] = input.value;
|
|
10345
|
-
}
|
|
10346
|
-
}
|
|
10347
|
-
}
|
|
10348
|
-
});
|
|
10349
|
-
}
|
|
10350
|
-
}
|
|
10351
|
-
} else {
|
|
10352
|
-
const dependencyKey = condition.key;
|
|
10353
|
-
const dependencyValue = extractDOMValue(dependencyKey, formRoot);
|
|
10354
|
-
if (dependencyValue !== void 0) {
|
|
10355
|
-
rootFormData[dependencyKey] = dependencyValue;
|
|
10356
|
-
} else {
|
|
10357
|
-
rootFormData = (_b = ctx.formData) != null ? _b : ctx.prefill;
|
|
10358
|
-
}
|
|
10359
|
-
}
|
|
10575
|
+
const dependencyKey = condition.key;
|
|
10576
|
+
const dependencyFieldPath = effectiveScope === "relative" && ctx.path ? `${ctx.path}.${dependencyKey}` : dependencyKey;
|
|
10577
|
+
const dependencyValue = extractDOMValue(dependencyFieldPath, formRoot);
|
|
10578
|
+
const scopedData = buildScopedDataAtPath(dependencyKey, dependencyValue);
|
|
10579
|
+
const rootFormData = effectiveScope === "relative" ? {} : scopedData;
|
|
10580
|
+
const containerData = effectiveScope === "relative" ? scopedData : void 0;
|
|
10360
10581
|
try {
|
|
10361
10582
|
const shouldEnable = evaluateEnableCondition(
|
|
10362
10583
|
condition,
|
|
@@ -11032,6 +11253,7 @@ var exampleThemes = {
|
|
|
11032
11253
|
},
|
|
11033
11254
|
// Picaz wizard design tokens — derived from the Picaz Wizard mockups.
|
|
11034
11255
|
// Pairs with the host-side .card / .section-num / .lede chrome that wraps the form.
|
|
11256
|
+
// Assumes Inter is loaded by the host (e.g. via Google Fonts in index.html).
|
|
11035
11257
|
picaz: {
|
|
11036
11258
|
...defaultTheme,
|
|
11037
11259
|
primaryColor: "#2f5bea",
|
|
@@ -11063,6 +11285,9 @@ var exampleThemes = {
|
|
|
11063
11285
|
fileUploadBgColor: "#fafcff",
|
|
11064
11286
|
fileUploadBorderColor: "#cdd6e3",
|
|
11065
11287
|
fileUploadHoverBorderColor: "#2f5bea",
|
|
11288
|
+
// Picaz uses roomier inputs (11/14px) than the defaultTheme compact density.
|
|
11289
|
+
inputPaddingX: "14px",
|
|
11290
|
+
inputPaddingY: "11px",
|
|
11066
11291
|
borderRadius: "12px",
|
|
11067
11292
|
borderRadiusSmall: "8px",
|
|
11068
11293
|
borderRadiusLarge: "16px",
|
|
@@ -11070,7 +11295,17 @@ var exampleThemes = {
|
|
|
11070
11295
|
fontFamily: '"Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',
|
|
11071
11296
|
shadowCard: "0 1px 2px rgba(15,23,42,.04), 0 1px 0 rgba(15,23,42,.02)",
|
|
11072
11297
|
shadowPopover: "0 12px 32px -12px rgba(15,23,42,.18), 0 4px 12px -6px rgba(15,23,42,.08)",
|
|
11073
|
-
focusRingColor: "#2f5bea"
|
|
11298
|
+
focusRingColor: "#2f5bea",
|
|
11299
|
+
// Slide cards: subtle gradient lift, no rest-state shadow (mockup adds it
|
|
11300
|
+
// only on hover, which form-builder doesn't yet differentiate).
|
|
11301
|
+
slideCardBg: "linear-gradient(180deg, #f7f9fc 0%, #dde3ee 100%)",
|
|
11302
|
+
slideCardShadow: "none",
|
|
11303
|
+
slideCardRadius: "16px",
|
|
11304
|
+
// Tiny uppercase captions above grouped lists ("ПРЕИМУЩЕСТВА" in the mockup).
|
|
11305
|
+
labelSectionFontSize: "0.625rem",
|
|
11306
|
+
// 10px
|
|
11307
|
+
labelSectionLetterSpacing: "0.07em",
|
|
11308
|
+
labelSectionTextTransform: "uppercase"
|
|
11074
11309
|
}
|
|
11075
11310
|
};
|
|
11076
11311
|
|
|
@@ -11436,6 +11671,13 @@ var FormBuilderInstance = class {
|
|
|
11436
11671
|
const value = hintValues[fieldKey];
|
|
11437
11672
|
this.updateField(fullPath, value);
|
|
11438
11673
|
}
|
|
11674
|
+
const group = target.closest(".fb-prefill-hints");
|
|
11675
|
+
if (group) {
|
|
11676
|
+
group.querySelectorAll(
|
|
11677
|
+
'.fb-prefill-hint[aria-pressed="true"]'
|
|
11678
|
+
).forEach((el) => el.removeAttribute("aria-pressed"));
|
|
11679
|
+
}
|
|
11680
|
+
target.setAttribute("aria-pressed", "true");
|
|
11439
11681
|
} catch (error) {
|
|
11440
11682
|
console.error("Error parsing prefill hint values:", error);
|
|
11441
11683
|
}
|