@dmitryvim/form-builder 0.3.0 → 0.3.1
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 +150 -120
- package/dist/browser/formbuilder.v0.3.1.min.js +1441 -0
- package/dist/cjs/index.cjs +330 -108
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +325 -107
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +150 -120
- 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 +9 -1
- package/package.json +1 -1
- package/dist/browser/formbuilder.v0.3.0.min.js +0 -1411
package/dist/esm/index.js
CHANGED
|
@@ -435,6 +435,36 @@ function ensureThemingHooks(doc) {
|
|
|
435
435
|
color: var(--fb-error-color);
|
|
436
436
|
background-color: var(--fb-background-hover-color);
|
|
437
437
|
}
|
|
438
|
+
/* Prefill-suggestion pills rendered by createPrefillHints. Outline pill at rest,
|
|
439
|
+
soft-fill on hover, solid-fill when selected. All colors flow from the active
|
|
440
|
+
theme \u2014 consumers don't need to ship their own CSS. */
|
|
441
|
+
.fb-prefill-hint {
|
|
442
|
+
padding: 0.25rem 0.625rem;
|
|
443
|
+
border: var(--fb-border-width) solid var(--fb-primary-color);
|
|
444
|
+
border-radius: 9999px;
|
|
445
|
+
background: var(--fb-background-color);
|
|
446
|
+
color: var(--fb-primary-color);
|
|
447
|
+
font-size: var(--fb-font-size-small);
|
|
448
|
+
font-weight: var(--fb-font-weight-medium);
|
|
449
|
+
font-family: var(--fb-font-family);
|
|
450
|
+
cursor: pointer;
|
|
451
|
+
transition: background-color var(--fb-transition-duration), border-color var(--fb-transition-duration), color var(--fb-transition-duration);
|
|
452
|
+
}
|
|
453
|
+
.fb-prefill-hint:hover {
|
|
454
|
+
background: var(--fb-primary-soft-color);
|
|
455
|
+
border-color: var(--fb-primary-hover-color);
|
|
456
|
+
color: var(--fb-primary-hover-color);
|
|
457
|
+
}
|
|
458
|
+
.fb-prefill-hint:focus-visible {
|
|
459
|
+
outline: var(--fb-focus-ring-width) solid var(--fb-focus-ring-color);
|
|
460
|
+
outline-offset: 2px;
|
|
461
|
+
}
|
|
462
|
+
.fb-prefill-hint[aria-pressed="true"],
|
|
463
|
+
.fb-prefill-hint.active {
|
|
464
|
+
background: var(--fb-primary-color);
|
|
465
|
+
color: #ffffff;
|
|
466
|
+
border-color: var(--fb-primary-color);
|
|
467
|
+
}
|
|
438
468
|
`;
|
|
439
469
|
doc.head.appendChild(style);
|
|
440
470
|
}
|
|
@@ -446,7 +476,9 @@ function applyAutoExpand(textarea) {
|
|
|
446
476
|
const resize = () => {
|
|
447
477
|
if (!textarea.isConnected) return;
|
|
448
478
|
textarea.style.height = "0";
|
|
449
|
-
|
|
479
|
+
const cs = getComputedStyle(textarea);
|
|
480
|
+
const borderY = parseFloat(cs.borderTopWidth || "0") + parseFloat(cs.borderBottomWidth || "0");
|
|
481
|
+
textarea.style.height = `${textarea.scrollHeight + borderY}px`;
|
|
450
482
|
};
|
|
451
483
|
textarea.addEventListener("input", resize);
|
|
452
484
|
setTimeout(() => {
|
|
@@ -4215,15 +4247,25 @@ function filterAndSlice(allFiles, currentCount, constraints, state) {
|
|
|
4215
4247
|
}
|
|
4216
4248
|
return { accepted, errorMessage: errorParts.join(" \u2022 ") };
|
|
4217
4249
|
}
|
|
4218
|
-
async function uploadBatch(
|
|
4219
|
-
|
|
4250
|
+
async function uploadBatch(opts) {
|
|
4251
|
+
const {
|
|
4252
|
+
accepted,
|
|
4253
|
+
listEl,
|
|
4254
|
+
state,
|
|
4255
|
+
shouldHideAddTile,
|
|
4256
|
+
buildSuccessTile,
|
|
4257
|
+
prepareForUpload
|
|
4258
|
+
} = opts;
|
|
4259
|
+
if (listEl && shouldHideAddTile) {
|
|
4220
4260
|
const tilesWrap = ensureTilesWrap(listEl);
|
|
4221
4261
|
const addTile = tilesWrap.querySelector(".fb-multi-add-tile-js") ?? tilesWrap.querySelector(".fb-tile-add");
|
|
4222
4262
|
if (addTile) addTile.style.display = "none";
|
|
4223
4263
|
}
|
|
4264
|
+
prepareForUpload?.();
|
|
4265
|
+
const orderedIds = new Array(accepted.length).fill(null);
|
|
4224
4266
|
const failures = [];
|
|
4225
4267
|
await Promise.allSettled(
|
|
4226
|
-
accepted.map(async (file) => {
|
|
4268
|
+
accepted.map(async (file, index) => {
|
|
4227
4269
|
const placeholder = createUploadingTile(file.name, state);
|
|
4228
4270
|
if (listEl) {
|
|
4229
4271
|
const tilesWrap = ensureTilesWrap(listEl);
|
|
@@ -4236,20 +4278,24 @@ async function uploadBatch(accepted, resourceIds, listEl, state) {
|
|
|
4236
4278
|
type: file.type,
|
|
4237
4279
|
size: file.size,
|
|
4238
4280
|
uploadedAt: /* @__PURE__ */ new Date(),
|
|
4239
|
-
file
|
|
4281
|
+
file
|
|
4240
4282
|
});
|
|
4241
|
-
|
|
4283
|
+
orderedIds[index] = rid;
|
|
4284
|
+
if (buildSuccessTile && placeholder.parentNode) {
|
|
4285
|
+
placeholder.replaceWith(buildSuccessTile(rid));
|
|
4286
|
+
} else {
|
|
4287
|
+
placeholder.remove();
|
|
4288
|
+
}
|
|
4242
4289
|
} catch (err) {
|
|
4243
4290
|
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
4244
4291
|
const cause = wrapped.cause;
|
|
4245
4292
|
const root = cause instanceof Error ? cause : cause !== void 0 ? new Error(String(cause)) : wrapped;
|
|
4246
4293
|
failures.push({ file, error: root });
|
|
4247
|
-
} finally {
|
|
4248
4294
|
placeholder.remove();
|
|
4249
4295
|
}
|
|
4250
4296
|
})
|
|
4251
4297
|
);
|
|
4252
|
-
return { failures };
|
|
4298
|
+
return { failures, orderedIds };
|
|
4253
4299
|
}
|
|
4254
4300
|
function buildBatchErrorMessage(filterError, failures, state) {
|
|
4255
4301
|
if (failures.length === 0) return filterError;
|
|
@@ -4261,68 +4307,70 @@ function buildBatchErrorMessage(filterError, failures, state) {
|
|
|
4261
4307
|
).join(" \u2022 ");
|
|
4262
4308
|
return filterError ? `${filterError} \u2022 ${uploadMsg}` : uploadMsg;
|
|
4263
4309
|
}
|
|
4264
|
-
function
|
|
4310
|
+
async function runMultiFileBatch(opts, files, listEl, errorTarget) {
|
|
4311
|
+
const {
|
|
4312
|
+
resourceIds,
|
|
4313
|
+
state,
|
|
4314
|
+
updateCallback,
|
|
4315
|
+
constraints,
|
|
4316
|
+
pathKey,
|
|
4317
|
+
instance,
|
|
4318
|
+
buildSuccessTile,
|
|
4319
|
+
prepareForUpload,
|
|
4320
|
+
coordinator
|
|
4321
|
+
} = opts;
|
|
4322
|
+
const { accepted, errorMessage } = filterAndSlice(
|
|
4323
|
+
files,
|
|
4324
|
+
coordinator.getOccupiedCount(),
|
|
4325
|
+
constraints,
|
|
4326
|
+
state
|
|
4327
|
+
);
|
|
4328
|
+
if (errorTarget) {
|
|
4329
|
+
if (errorMessage) showFileError(errorTarget, errorMessage);
|
|
4330
|
+
else clearFileError(errorTarget);
|
|
4331
|
+
}
|
|
4332
|
+
const handle = coordinator.beginBatch(accepted.length);
|
|
4333
|
+
const shouldHideAddTile = coordinator.getOccupiedCount() >= constraints.maxCount;
|
|
4334
|
+
const { failures, orderedIds } = await uploadBatch({
|
|
4335
|
+
accepted,
|
|
4336
|
+
listEl,
|
|
4337
|
+
state,
|
|
4338
|
+
shouldHideAddTile,
|
|
4339
|
+
buildSuccessTile,
|
|
4340
|
+
prepareForUpload
|
|
4341
|
+
});
|
|
4342
|
+
handle.setResults(orderedIds);
|
|
4343
|
+
if (instance && pathKey && !state.config.readonly) {
|
|
4344
|
+
instance.triggerOnChange(pathKey, resourceIds);
|
|
4345
|
+
}
|
|
4346
|
+
const { wasLast } = handle.end();
|
|
4347
|
+
if (wasLast) updateCallback();
|
|
4348
|
+
if (errorTarget) {
|
|
4349
|
+
const combined = buildBatchErrorMessage(errorMessage, failures, state);
|
|
4350
|
+
if (combined) showFileError(errorTarget, combined);
|
|
4351
|
+
else clearFileError(errorTarget);
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4354
|
+
function setupFilesDropHandler(opts) {
|
|
4355
|
+
const { filesContainer } = opts;
|
|
4265
4356
|
setupDragAndDrop(filesContainer, async (files) => {
|
|
4266
|
-
const { accepted, errorMessage } = filterAndSlice(
|
|
4267
|
-
Array.from(files),
|
|
4268
|
-
resourceIds.length,
|
|
4269
|
-
constraints,
|
|
4270
|
-
state
|
|
4271
|
-
);
|
|
4272
|
-
if (errorMessage) {
|
|
4273
|
-
showFileError(filesContainer, errorMessage);
|
|
4274
|
-
} else {
|
|
4275
|
-
clearFileError(filesContainer);
|
|
4276
|
-
}
|
|
4277
4357
|
const list = filesContainer.querySelector(".files-list") ?? filesContainer;
|
|
4278
|
-
|
|
4279
|
-
const combined = buildBatchErrorMessage(errorMessage, failures, state);
|
|
4280
|
-
if (combined) {
|
|
4281
|
-
showFileError(filesContainer, combined);
|
|
4282
|
-
} else {
|
|
4283
|
-
clearFileError(filesContainer);
|
|
4284
|
-
}
|
|
4285
|
-
updateCallback();
|
|
4286
|
-
if (instance && pathKey && !state.config.readonly) {
|
|
4287
|
-
instance.triggerOnChange(pathKey, resourceIds);
|
|
4288
|
-
}
|
|
4358
|
+
await runMultiFileBatch(opts, Array.from(files), list, filesContainer);
|
|
4289
4359
|
});
|
|
4290
4360
|
}
|
|
4291
|
-
function setupFilesPickerHandler(
|
|
4361
|
+
function setupFilesPickerHandler(opts) {
|
|
4362
|
+
const { filesPicker } = opts;
|
|
4292
4363
|
filesPicker.onchange = async () => {
|
|
4293
4364
|
if (!filesPicker.files) return;
|
|
4294
|
-
const wrapperEl = filesPicker.closest("[data-files-wrapper]")
|
|
4295
|
-
const
|
|
4365
|
+
const wrapperEl = filesPicker.closest("[data-files-wrapper]") ?? filesPicker.parentElement;
|
|
4366
|
+
const listEl = wrapperEl?.querySelector(".files-list") ?? null;
|
|
4367
|
+
await runMultiFileBatch(
|
|
4368
|
+
opts,
|
|
4296
4369
|
Array.from(filesPicker.files),
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
state
|
|
4300
|
-
);
|
|
4301
|
-
if (errorMessage && wrapperEl) {
|
|
4302
|
-
showFileError(wrapperEl, errorMessage);
|
|
4303
|
-
} else if (wrapperEl) {
|
|
4304
|
-
clearFileError(wrapperEl);
|
|
4305
|
-
}
|
|
4306
|
-
const listEl = wrapperEl?.querySelector(".files-list");
|
|
4307
|
-
const { failures } = await uploadBatch(
|
|
4308
|
-
accepted,
|
|
4309
|
-
resourceIds,
|
|
4310
|
-
listEl ?? null,
|
|
4311
|
-
state
|
|
4370
|
+
listEl,
|
|
4371
|
+
wrapperEl
|
|
4312
4372
|
);
|
|
4313
|
-
if (wrapperEl) {
|
|
4314
|
-
const combined = buildBatchErrorMessage(errorMessage, failures, state);
|
|
4315
|
-
if (combined) {
|
|
4316
|
-
showFileError(wrapperEl, combined);
|
|
4317
|
-
} else {
|
|
4318
|
-
clearFileError(wrapperEl);
|
|
4319
|
-
}
|
|
4320
|
-
}
|
|
4321
|
-
updateCallback();
|
|
4322
4373
|
filesPicker.value = "";
|
|
4323
|
-
if (instance && pathKey && !state.config.readonly) {
|
|
4324
|
-
instance.triggerOnChange(pathKey, resourceIds);
|
|
4325
|
-
}
|
|
4326
4374
|
};
|
|
4327
4375
|
}
|
|
4328
4376
|
|
|
@@ -4363,16 +4411,6 @@ function validatePickedResource(resource, allowedExtensions, allowedMimes, maxSi
|
|
|
4363
4411
|
}
|
|
4364
4412
|
return null;
|
|
4365
4413
|
}
|
|
4366
|
-
function readCurrentResourceIds(wrapper) {
|
|
4367
|
-
const raw = wrapper.dataset.resourceIds;
|
|
4368
|
-
if (!raw) return [];
|
|
4369
|
-
try {
|
|
4370
|
-
const parsed = JSON.parse(raw);
|
|
4371
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
4372
|
-
} catch {
|
|
4373
|
-
return [];
|
|
4374
|
-
}
|
|
4375
|
-
}
|
|
4376
4414
|
function registerPickedResource(resource, state) {
|
|
4377
4415
|
const existing = state.resourceIndex.get(resource.resourceId);
|
|
4378
4416
|
state.resourceIndex.set(resource.resourceId, {
|
|
@@ -4387,13 +4425,27 @@ function extractPickerError(error, state) {
|
|
|
4387
4425
|
if (error instanceof Error && error.message) return error.message;
|
|
4388
4426
|
return t("pickerError", state);
|
|
4389
4427
|
}
|
|
4390
|
-
async function handleLibraryPickMulti(
|
|
4428
|
+
async function handleLibraryPickMulti(opts) {
|
|
4429
|
+
const {
|
|
4430
|
+
state,
|
|
4431
|
+
element,
|
|
4432
|
+
wrapper,
|
|
4433
|
+
fieldPath,
|
|
4434
|
+
resourceIds,
|
|
4435
|
+
maxCount,
|
|
4436
|
+
updateCallback,
|
|
4437
|
+
instance,
|
|
4438
|
+
coordinator,
|
|
4439
|
+
list,
|
|
4440
|
+
buildSuccessTile
|
|
4441
|
+
} = opts;
|
|
4391
4442
|
if (!state.config.pickExistingFiles) return;
|
|
4392
4443
|
const allowedExtensions = getAllowedExtensions(element.accept);
|
|
4393
4444
|
const allowedMimes = getAllowedMimes(element.accept);
|
|
4394
4445
|
const maxSizeMB = element.maxSize ?? Infinity;
|
|
4395
|
-
const
|
|
4396
|
-
const
|
|
4446
|
+
const knownRids = coordinator.getAllKnownRids();
|
|
4447
|
+
const existingSet = new Set(knownRids);
|
|
4448
|
+
const remaining = maxCount === Infinity ? Infinity : Math.max(0, maxCount - coordinator.getOccupiedCount());
|
|
4397
4449
|
let picked;
|
|
4398
4450
|
try {
|
|
4399
4451
|
picked = await state.config.pickExistingFiles({
|
|
@@ -4402,14 +4454,15 @@ async function handleLibraryPickMulti(state, element, wrapper, fieldPath, resour
|
|
|
4402
4454
|
accept: buildAcceptContext(element),
|
|
4403
4455
|
maxSizeMB: maxSizeMB === Infinity ? void 0 : maxSizeMB,
|
|
4404
4456
|
remainingSlots: remaining === Infinity ? void 0 : remaining,
|
|
4405
|
-
|
|
4457
|
+
// Hand the host every rid that's already selected (committed or
|
|
4458
|
+
// staged) so it can grey them out or filter them.
|
|
4459
|
+
selectedResourceIds: knownRids
|
|
4406
4460
|
});
|
|
4407
4461
|
} catch (error) {
|
|
4408
4462
|
showFileError(wrapper, extractPickerError(error, state));
|
|
4409
4463
|
return;
|
|
4410
4464
|
}
|
|
4411
4465
|
if (picked.length === 0) return;
|
|
4412
|
-
const existingSet = new Set(currentIds);
|
|
4413
4466
|
const seen = /* @__PURE__ */ new Set();
|
|
4414
4467
|
const deduped = picked.filter((r) => {
|
|
4415
4468
|
if (existingSet.has(r.resourceId)) return false;
|
|
@@ -4427,10 +4480,18 @@ async function handleLibraryPickMulti(state, element, wrapper, fieldPath, resour
|
|
|
4427
4480
|
);
|
|
4428
4481
|
return err === null;
|
|
4429
4482
|
});
|
|
4430
|
-
const freshRemaining = maxCount === Infinity ? validItems.length : Math.max(0, maxCount -
|
|
4483
|
+
const freshRemaining = maxCount === Infinity ? validItems.length : Math.max(0, maxCount - coordinator.getOccupiedCount());
|
|
4431
4484
|
const accepted = validItems.slice(0, freshRemaining);
|
|
4432
4485
|
const skipped = validItems.length - accepted.length;
|
|
4433
|
-
if (accepted.length === 0)
|
|
4486
|
+
if (accepted.length === 0) {
|
|
4487
|
+
if (skipped > 0) {
|
|
4488
|
+
showFileError(
|
|
4489
|
+
wrapper,
|
|
4490
|
+
t("filesLimitExceeded", state, { skipped, max: maxCount })
|
|
4491
|
+
);
|
|
4492
|
+
}
|
|
4493
|
+
return;
|
|
4494
|
+
}
|
|
4434
4495
|
clearFileError(wrapper);
|
|
4435
4496
|
if (skipped > 0) {
|
|
4436
4497
|
showFileError(
|
|
@@ -4440,13 +4501,22 @@ async function handleLibraryPickMulti(state, element, wrapper, fieldPath, resour
|
|
|
4440
4501
|
}
|
|
4441
4502
|
for (const resource of accepted) {
|
|
4442
4503
|
registerPickedResource(resource, state);
|
|
4443
|
-
resourceIds.push(resource.resourceId);
|
|
4444
4504
|
}
|
|
4445
|
-
|
|
4446
|
-
|
|
4505
|
+
const acceptedIds = accepted.map((r) => r.resourceId);
|
|
4506
|
+
const handle = coordinator.beginBatch(accepted.length);
|
|
4507
|
+
handle.setResults(acceptedIds);
|
|
4447
4508
|
if (!state.config.readonly) {
|
|
4448
4509
|
instance.triggerOnChange(fieldPath, resourceIds);
|
|
4449
4510
|
}
|
|
4511
|
+
const { wasLast } = handle.end();
|
|
4512
|
+
if (wasLast) {
|
|
4513
|
+
updateCallback();
|
|
4514
|
+
} else {
|
|
4515
|
+
const tilesWrap = ensureTilesWrap(list);
|
|
4516
|
+
for (const rid of acceptedIds) {
|
|
4517
|
+
tilesWrap.appendChild(buildSuccessTile(rid));
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4450
4520
|
}
|
|
4451
4521
|
async function handleLibraryPickSingle(state, element, container, fileWrapper, pathKey, fieldPath, renderCallback, instance) {
|
|
4452
4522
|
if (!state.config.pickExistingFiles) return;
|
|
@@ -4767,6 +4837,14 @@ function buildMetaDot() {
|
|
|
4767
4837
|
return dot;
|
|
4768
4838
|
}
|
|
4769
4839
|
var gridResizeObservers = /* @__PURE__ */ new WeakMap();
|
|
4840
|
+
function disposePlaceholdersForUpload(container) {
|
|
4841
|
+
const observer = gridResizeObservers.get(container);
|
|
4842
|
+
if (observer) {
|
|
4843
|
+
observer.disconnect();
|
|
4844
|
+
gridResizeObservers.delete(container);
|
|
4845
|
+
}
|
|
4846
|
+
container.querySelectorAll(".fb-multi-placeholder").forEach((p) => p.remove());
|
|
4847
|
+
}
|
|
4770
4848
|
function renderResourcePills(opts) {
|
|
4771
4849
|
const {
|
|
4772
4850
|
container,
|
|
@@ -5114,16 +5192,19 @@ function setupMultiFileEditMode(element, ctx, wrapper, pathKey, maxFiles) {
|
|
|
5114
5192
|
filesPicker.click();
|
|
5115
5193
|
};
|
|
5116
5194
|
const onLibraryPick = state.config.pickExistingFiles && !element.disableLibrary ? () => {
|
|
5117
|
-
handleLibraryPickMulti(
|
|
5195
|
+
handleLibraryPickMulti({
|
|
5118
5196
|
state,
|
|
5119
5197
|
element,
|
|
5120
|
-
filesWrapper,
|
|
5121
|
-
pathKey,
|
|
5122
|
-
initialFiles,
|
|
5123
|
-
maxFiles,
|
|
5124
|
-
updateFilesDisplay,
|
|
5125
|
-
ctx.instance
|
|
5126
|
-
|
|
5198
|
+
wrapper: filesWrapper,
|
|
5199
|
+
fieldPath: pathKey,
|
|
5200
|
+
resourceIds: initialFiles,
|
|
5201
|
+
maxCount: maxFiles,
|
|
5202
|
+
updateCallback: updateFilesDisplay,
|
|
5203
|
+
instance: ctx.instance,
|
|
5204
|
+
coordinator,
|
|
5205
|
+
list,
|
|
5206
|
+
buildSuccessTile
|
|
5207
|
+
}).catch((err) => {
|
|
5127
5208
|
console.error("Library pick failed:", err);
|
|
5128
5209
|
});
|
|
5129
5210
|
} : null;
|
|
@@ -5137,37 +5218,153 @@ function setupMultiFileEditMode(element, ctx, wrapper, pathKey, maxFiles) {
|
|
|
5137
5218
|
releaseLocalFileUrl(state.resourceIndex.get(ridToRemove)?.file);
|
|
5138
5219
|
const index = initialFiles.indexOf(ridToRemove);
|
|
5139
5220
|
if (index > -1) initialFiles.splice(index, 1);
|
|
5140
|
-
|
|
5221
|
+
if (coordinator.hasInFlightBatches()) {
|
|
5222
|
+
pendingRemovals.add(ridToRemove);
|
|
5223
|
+
list.querySelector(`[data-resource-id="${ridToRemove}"]`)?.remove();
|
|
5224
|
+
filesWrapper.dataset.resourceIds = JSON.stringify(initialFiles);
|
|
5225
|
+
} else {
|
|
5226
|
+
updateFilesDisplay();
|
|
5227
|
+
}
|
|
5228
|
+
if (ctx.instance && pathKey && !state.config.readonly) {
|
|
5229
|
+
ctx.instance.triggerOnChange(pathKey, initialFiles);
|
|
5230
|
+
}
|
|
5141
5231
|
},
|
|
5142
5232
|
maxCount: maxFiles < Infinity ? maxFiles : void 0,
|
|
5143
5233
|
isReadonly: currentlyReadonly,
|
|
5144
5234
|
onLibraryPick: currentlyReadonly ? null : onLibraryPick,
|
|
5145
5235
|
element,
|
|
5146
5236
|
onClearAll: currentlyReadonly ? void 0 : () => {
|
|
5237
|
+
for (const rid of initialFiles) {
|
|
5238
|
+
releaseLocalFileUrl(state.resourceIndex.get(rid)?.file);
|
|
5239
|
+
}
|
|
5147
5240
|
initialFiles.splice(0);
|
|
5148
|
-
|
|
5241
|
+
if (coordinator.hasInFlightBatches()) {
|
|
5242
|
+
const visibleTiles = list.querySelectorAll("[data-resource-id]");
|
|
5243
|
+
for (const tile of visibleTiles) {
|
|
5244
|
+
const rid = tile.dataset.resourceId;
|
|
5245
|
+
if (rid) {
|
|
5246
|
+
releaseLocalFileUrl(state.resourceIndex.get(rid)?.file);
|
|
5247
|
+
pendingRemovals.add(rid);
|
|
5248
|
+
}
|
|
5249
|
+
tile.remove();
|
|
5250
|
+
}
|
|
5251
|
+
filesWrapper.dataset.resourceIds = JSON.stringify(initialFiles);
|
|
5252
|
+
} else {
|
|
5253
|
+
updateFilesDisplay();
|
|
5254
|
+
}
|
|
5255
|
+
if (ctx.instance && pathKey && !state.config.readonly) {
|
|
5256
|
+
ctx.instance.triggerOnChange(pathKey, initialFiles);
|
|
5257
|
+
}
|
|
5149
5258
|
},
|
|
5150
5259
|
openPicker
|
|
5151
5260
|
});
|
|
5152
5261
|
}
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5262
|
+
let inFlightFiles = 0;
|
|
5263
|
+
let activeBatches = 0;
|
|
5264
|
+
let nextBatchOrdinal = 0;
|
|
5265
|
+
let nextCommitOrdinal = 0;
|
|
5266
|
+
const stagedResults = /* @__PURE__ */ new Map();
|
|
5267
|
+
const batchReservations = /* @__PURE__ */ new Map();
|
|
5268
|
+
const pendingRemovals = /* @__PURE__ */ new Set();
|
|
5269
|
+
const drainContiguousStagedResults = () => {
|
|
5270
|
+
while (stagedResults.has(nextCommitOrdinal)) {
|
|
5271
|
+
const ordinal = nextCommitOrdinal;
|
|
5272
|
+
const ids = stagedResults.get(ordinal);
|
|
5273
|
+
stagedResults.delete(ordinal);
|
|
5274
|
+
nextCommitOrdinal += 1;
|
|
5275
|
+
const reservation = batchReservations.get(ordinal) ?? 0;
|
|
5276
|
+
batchReservations.delete(ordinal);
|
|
5277
|
+
inFlightFiles -= reservation;
|
|
5278
|
+
for (const rid of ids) {
|
|
5279
|
+
if (rid === null) continue;
|
|
5280
|
+
if (pendingRemovals.has(rid)) {
|
|
5281
|
+
pendingRemovals.delete(rid);
|
|
5282
|
+
continue;
|
|
5283
|
+
}
|
|
5284
|
+
initialFiles.push(rid);
|
|
5285
|
+
}
|
|
5286
|
+
}
|
|
5287
|
+
filesWrapper.dataset.resourceIds = JSON.stringify(initialFiles);
|
|
5288
|
+
};
|
|
5289
|
+
const coordinator = {
|
|
5290
|
+
getOccupiedCount: () => initialFiles.length + inFlightFiles,
|
|
5291
|
+
getAllKnownRids: () => {
|
|
5292
|
+
const out = [...initialFiles];
|
|
5293
|
+
for (const ids of stagedResults.values()) {
|
|
5294
|
+
for (const rid of ids) {
|
|
5295
|
+
if (rid !== null) out.push(rid);
|
|
5296
|
+
}
|
|
5297
|
+
}
|
|
5298
|
+
return out;
|
|
5299
|
+
},
|
|
5300
|
+
hasInFlightBatches: () => activeBatches > 0 || batchReservations.size > 0,
|
|
5301
|
+
wasRemovedDuringBatch: (rid) => pendingRemovals.has(rid),
|
|
5302
|
+
beginBatch: (count) => {
|
|
5303
|
+
inFlightFiles += count;
|
|
5304
|
+
activeBatches += 1;
|
|
5305
|
+
const ordinal = nextBatchOrdinal++;
|
|
5306
|
+
batchReservations.set(ordinal, count);
|
|
5307
|
+
return {
|
|
5308
|
+
setResults: (orderedIds) => {
|
|
5309
|
+
stagedResults.set(ordinal, orderedIds);
|
|
5310
|
+
drainContiguousStagedResults();
|
|
5311
|
+
},
|
|
5312
|
+
end: () => {
|
|
5313
|
+
activeBatches -= 1;
|
|
5314
|
+
const wasLast = activeBatches === 0 && batchReservations.size === 0;
|
|
5315
|
+
if (wasLast) {
|
|
5316
|
+
pendingRemovals.clear();
|
|
5317
|
+
}
|
|
5318
|
+
return { wasLast };
|
|
5319
|
+
}
|
|
5320
|
+
};
|
|
5321
|
+
}
|
|
5322
|
+
};
|
|
5323
|
+
const buildSuccessTile = (rid) => {
|
|
5324
|
+
const currentlyReadonly = isElementReadonly(element, state);
|
|
5325
|
+
return buildPreviewTile(
|
|
5326
|
+
rid,
|
|
5327
|
+
state,
|
|
5328
|
+
!currentlyReadonly,
|
|
5329
|
+
currentlyReadonly ? null : () => {
|
|
5330
|
+
releaseLocalFileUrl(state.resourceIndex.get(rid)?.file);
|
|
5331
|
+
const idx = initialFiles.indexOf(rid);
|
|
5332
|
+
if (idx > -1) {
|
|
5333
|
+
initialFiles.splice(idx, 1);
|
|
5334
|
+
if (coordinator.hasInFlightBatches()) {
|
|
5335
|
+
pendingRemovals.add(rid);
|
|
5336
|
+
list.querySelector(`[data-resource-id="${rid}"]`)?.remove();
|
|
5337
|
+
filesWrapper.dataset.resourceIds = JSON.stringify(initialFiles);
|
|
5338
|
+
} else {
|
|
5339
|
+
updateFilesDisplay();
|
|
5340
|
+
}
|
|
5341
|
+
if (ctx.instance && pathKey && !state.config.readonly) {
|
|
5342
|
+
ctx.instance.triggerOnChange(pathKey, initialFiles);
|
|
5343
|
+
}
|
|
5344
|
+
return;
|
|
5345
|
+
}
|
|
5346
|
+
pendingRemovals.add(rid);
|
|
5347
|
+
list.querySelector(`[data-resource-id="${rid}"]`)?.remove();
|
|
5348
|
+
if (ctx.instance && pathKey && !state.config.readonly) {
|
|
5349
|
+
ctx.instance.triggerOnChange(pathKey, initialFiles);
|
|
5350
|
+
}
|
|
5351
|
+
}
|
|
5352
|
+
);
|
|
5353
|
+
};
|
|
5354
|
+
const prepareForUpload = () => disposePlaceholdersForUpload(list);
|
|
5355
|
+
const sharedHandlerOpts = {
|
|
5356
|
+
resourceIds: initialFiles,
|
|
5165
5357
|
state,
|
|
5166
|
-
updateFilesDisplay,
|
|
5358
|
+
updateCallback: updateFilesDisplay,
|
|
5167
5359
|
constraints,
|
|
5168
5360
|
pathKey,
|
|
5169
|
-
ctx.instance
|
|
5170
|
-
|
|
5361
|
+
instance: ctx.instance,
|
|
5362
|
+
buildSuccessTile,
|
|
5363
|
+
prepareForUpload,
|
|
5364
|
+
coordinator
|
|
5365
|
+
};
|
|
5366
|
+
setupFilesDropHandler({ ...sharedHandlerOpts, filesContainer });
|
|
5367
|
+
setupFilesPickerHandler({ ...sharedHandlerOpts, filesPicker });
|
|
5171
5368
|
updateFilesDisplay();
|
|
5172
5369
|
wrapper.appendChild(filesWrapper);
|
|
5173
5370
|
}
|
|
@@ -10850,6 +11047,7 @@ var exampleThemes = {
|
|
|
10850
11047
|
},
|
|
10851
11048
|
// Picaz wizard design tokens — derived from the Picaz Wizard mockups.
|
|
10852
11049
|
// Pairs with the host-side .card / .section-num / .lede chrome that wraps the form.
|
|
11050
|
+
// Assumes Inter is loaded by the host (e.g. via Google Fonts in index.html).
|
|
10853
11051
|
picaz: {
|
|
10854
11052
|
...defaultTheme,
|
|
10855
11053
|
primaryColor: "#2f5bea",
|
|
@@ -10881,6 +11079,9 @@ var exampleThemes = {
|
|
|
10881
11079
|
fileUploadBgColor: "#fafcff",
|
|
10882
11080
|
fileUploadBorderColor: "#cdd6e3",
|
|
10883
11081
|
fileUploadHoverBorderColor: "#2f5bea",
|
|
11082
|
+
// Picaz uses roomier inputs (11/14px) than the defaultTheme compact density.
|
|
11083
|
+
inputPaddingX: "14px",
|
|
11084
|
+
inputPaddingY: "11px",
|
|
10884
11085
|
borderRadius: "12px",
|
|
10885
11086
|
borderRadiusSmall: "8px",
|
|
10886
11087
|
borderRadiusLarge: "16px",
|
|
@@ -10888,7 +11089,17 @@ var exampleThemes = {
|
|
|
10888
11089
|
fontFamily: '"Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',
|
|
10889
11090
|
shadowCard: "0 1px 2px rgba(15,23,42,.04), 0 1px 0 rgba(15,23,42,.02)",
|
|
10890
11091
|
shadowPopover: "0 12px 32px -12px rgba(15,23,42,.18), 0 4px 12px -6px rgba(15,23,42,.08)",
|
|
10891
|
-
focusRingColor: "#2f5bea"
|
|
11092
|
+
focusRingColor: "#2f5bea",
|
|
11093
|
+
// Slide cards: subtle gradient lift, no rest-state shadow (mockup adds it
|
|
11094
|
+
// only on hover, which form-builder doesn't yet differentiate).
|
|
11095
|
+
slideCardBg: "linear-gradient(180deg, #f7f9fc 0%, #dde3ee 100%)",
|
|
11096
|
+
slideCardShadow: "none",
|
|
11097
|
+
slideCardRadius: "16px",
|
|
11098
|
+
// Tiny uppercase captions above grouped lists ("ПРЕИМУЩЕСТВА" in the mockup).
|
|
11099
|
+
labelSectionFontSize: "0.625rem",
|
|
11100
|
+
// 10px
|
|
11101
|
+
labelSectionLetterSpacing: "0.07em",
|
|
11102
|
+
labelSectionTextTransform: "uppercase"
|
|
10892
11103
|
}
|
|
10893
11104
|
};
|
|
10894
11105
|
|
|
@@ -11254,6 +11465,13 @@ var FormBuilderInstance = class {
|
|
|
11254
11465
|
const value = hintValues[fieldKey];
|
|
11255
11466
|
this.updateField(fullPath, value);
|
|
11256
11467
|
}
|
|
11468
|
+
const group = target.closest(".fb-prefill-hints");
|
|
11469
|
+
if (group) {
|
|
11470
|
+
group.querySelectorAll(
|
|
11471
|
+
'.fb-prefill-hint[aria-pressed="true"]'
|
|
11472
|
+
).forEach((el) => el.removeAttribute("aria-pressed"));
|
|
11473
|
+
}
|
|
11474
|
+
target.setAttribute("aria-pressed", "true");
|
|
11257
11475
|
} catch (error) {
|
|
11258
11476
|
console.error("Error parsing prefill hint values:", error);
|
|
11259
11477
|
}
|