@dmitryvim/form-builder 0.2.30 → 0.2.32
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 +502 -387
- package/dist/browser/formbuilder.v0.2.32.min.js +1148 -0
- package/dist/cjs/index.cjs +1085 -703
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +1050 -677
- package/dist/esm/index.js.map +1 -1
- package/dist/form-builder.js +502 -387
- package/dist/types/components/file/dom.d.ts +4 -5
- package/dist/types/components/file/preview.d.ts +5 -0
- package/dist/types/components/file/render-edit.d.ts +8 -1
- package/dist/types/components/file/render-readonly.d.ts +4 -7
- package/dist/types/components/file/upload.d.ts +6 -0
- package/dist/types/types/config.d.ts +4 -0
- package/dist/types/types/schema.d.ts +8 -0
- package/package.json +1 -1
- package/dist/browser/formbuilder.v0.2.30.min.js +0 -1033
package/dist/cjs/index.cjs
CHANGED
|
@@ -50,8 +50,10 @@ function addRangeHint(element, parts, state) {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
function addFileSizeHint(element, parts, state) {
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
var _a;
|
|
54
|
+
const sizeMB = (_a = element.maxSize) != null ? _a : element.maxSizeMB;
|
|
55
|
+
if (sizeMB && sizeMB !== Infinity) {
|
|
56
|
+
parts.push(t("hintMaxSize", state, { size: sizeMB }));
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
function addFormatHint(element, parts, state) {
|
|
@@ -125,6 +127,25 @@ function validateSchema(schema) {
|
|
|
125
127
|
});
|
|
126
128
|
}
|
|
127
129
|
}
|
|
130
|
+
function validateContainerProps(element, elementPath, errors2) {
|
|
131
|
+
if ("columns" in element && element.columns !== void 0) {
|
|
132
|
+
const columns = element.columns;
|
|
133
|
+
const validColumns = [1, 2, 3, 4];
|
|
134
|
+
if (!Number.isInteger(columns) || !validColumns.includes(columns)) {
|
|
135
|
+
errors2.push(
|
|
136
|
+
`${elementPath}: columns must be 1, 2, 3, or 4 (got ${columns})`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if ("displayMode" in element && element.displayMode !== void 0) {
|
|
141
|
+
const displayMode = element.displayMode;
|
|
142
|
+
if (displayMode !== "stack" && displayMode !== "slides") {
|
|
143
|
+
errors2.push(
|
|
144
|
+
`${elementPath}: displayMode must be "stack" or "slides" (got ${JSON.stringify(displayMode)})`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
128
149
|
function checkFlatOutputCollisions(elements, scopePath) {
|
|
129
150
|
var _a, _b;
|
|
130
151
|
const allOutputKeys = /* @__PURE__ */ new Set();
|
|
@@ -205,15 +226,7 @@ function validateSchema(schema) {
|
|
|
205
226
|
validateElements(element.elements, `${elementPath}.elements`);
|
|
206
227
|
}
|
|
207
228
|
if (element.type === "container" && element.elements) {
|
|
208
|
-
|
|
209
|
-
const columns = element.columns;
|
|
210
|
-
const validColumns = [1, 2, 3, 4];
|
|
211
|
-
if (!Number.isInteger(columns) || !validColumns.includes(columns)) {
|
|
212
|
-
errors.push(
|
|
213
|
-
`${elementPath}: columns must be 1, 2, 3, or 4 (got ${columns})`
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
229
|
+
validateContainerProps(element, elementPath, errors);
|
|
217
230
|
if ("prefillHints" in element && element.prefillHints) {
|
|
218
231
|
const prefillHints = element.prefillHints;
|
|
219
232
|
if (Array.isArray(prefillHints)) {
|
|
@@ -851,8 +864,12 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
851
864
|
const textareaWrapper = document.createElement("div");
|
|
852
865
|
textareaWrapper.style.cssText = "position: relative;";
|
|
853
866
|
const textareaInput = document.createElement("textarea");
|
|
854
|
-
textareaInput.className = "w-full
|
|
855
|
-
textareaInput.style.cssText =
|
|
867
|
+
textareaInput.className = "w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none";
|
|
868
|
+
textareaInput.style.cssText = `
|
|
869
|
+
padding: var(--fb-input-padding-y) var(--fb-input-padding-x) 24px var(--fb-input-padding-x);
|
|
870
|
+
font-size: var(--fb-font-size);
|
|
871
|
+
font-family: var(--fb-font-family);
|
|
872
|
+
`;
|
|
856
873
|
textareaInput.name = pathKey;
|
|
857
874
|
textareaInput.placeholder = element.placeholder || "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442";
|
|
858
875
|
textareaInput.rows = element.rows || 4;
|
|
@@ -905,8 +922,12 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
|
|
|
905
922
|
const textareaContainer = document.createElement("div");
|
|
906
923
|
textareaContainer.style.cssText = "position: relative;";
|
|
907
924
|
const textareaInput = document.createElement("textarea");
|
|
908
|
-
textareaInput.className = "w-full
|
|
909
|
-
textareaInput.style.cssText =
|
|
925
|
+
textareaInput.className = "w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none";
|
|
926
|
+
textareaInput.style.cssText = `
|
|
927
|
+
padding: var(--fb-input-padding-y) var(--fb-input-padding-x) 24px var(--fb-input-padding-x);
|
|
928
|
+
font-size: var(--fb-font-size);
|
|
929
|
+
font-family: var(--fb-font-family);
|
|
930
|
+
`;
|
|
910
931
|
textareaInput.placeholder = element.placeholder || t("placeholderText", state);
|
|
911
932
|
textareaInput.rows = element.rows || 4;
|
|
912
933
|
textareaInput.value = value;
|
|
@@ -1092,8 +1113,14 @@ function renderNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1092
1113
|
inputWrapper.style.cssText = "position: relative;";
|
|
1093
1114
|
const numberInput = document.createElement("input");
|
|
1094
1115
|
numberInput.type = "number";
|
|
1095
|
-
numberInput.className = "w-full
|
|
1096
|
-
numberInput.style.cssText =
|
|
1116
|
+
numberInput.className = "w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500";
|
|
1117
|
+
numberInput.style.cssText = `
|
|
1118
|
+
padding: var(--fb-input-padding-y) 60px var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
1119
|
+
font-size: var(--fb-font-size);
|
|
1120
|
+
font-family: var(--fb-font-family);
|
|
1121
|
+
width: 100%;
|
|
1122
|
+
box-sizing: border-box;
|
|
1123
|
+
`;
|
|
1097
1124
|
numberInput.name = pathKey;
|
|
1098
1125
|
numberInput.placeholder = element.placeholder || "0";
|
|
1099
1126
|
if (element.min !== void 0) numberInput.min = element.min.toString();
|
|
@@ -1146,8 +1173,14 @@ function renderMultipleNumberElement(element, ctx, wrapper, pathKey) {
|
|
|
1146
1173
|
inputContainer.style.cssText = "position: relative; flex: 1;";
|
|
1147
1174
|
const numberInput = document.createElement("input");
|
|
1148
1175
|
numberInput.type = "number";
|
|
1149
|
-
numberInput.className = "w-full
|
|
1150
|
-
numberInput.style.cssText =
|
|
1176
|
+
numberInput.className = "w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500";
|
|
1177
|
+
numberInput.style.cssText = `
|
|
1178
|
+
padding: var(--fb-input-padding-y) 60px var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
1179
|
+
font-size: var(--fb-font-size);
|
|
1180
|
+
font-family: var(--fb-font-family);
|
|
1181
|
+
width: 100%;
|
|
1182
|
+
box-sizing: border-box;
|
|
1183
|
+
`;
|
|
1151
1184
|
numberInput.placeholder = element.placeholder || "0";
|
|
1152
1185
|
if (element.min !== void 0) numberInput.min = element.min.toString();
|
|
1153
1186
|
if (element.max !== void 0) numberInput.max = element.max.toString();
|
|
@@ -1421,7 +1454,12 @@ function renderSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1421
1454
|
const state = ctx.state;
|
|
1422
1455
|
const readonly = isElementReadonly(element, state, ctx);
|
|
1423
1456
|
const selectInput = document.createElement("select");
|
|
1424
|
-
selectInput.className = "w-full
|
|
1457
|
+
selectInput.className = "w-full border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500";
|
|
1458
|
+
selectInput.style.cssText = `
|
|
1459
|
+
padding: var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
1460
|
+
font-size: var(--fb-font-size);
|
|
1461
|
+
font-family: var(--fb-font-family);
|
|
1462
|
+
`;
|
|
1425
1463
|
selectInput.name = pathKey;
|
|
1426
1464
|
selectInput.disabled = readonly;
|
|
1427
1465
|
(element.options || []).forEach((option) => {
|
|
@@ -1474,7 +1512,12 @@ function renderMultipleSelectElement(element, ctx, wrapper, pathKey) {
|
|
|
1474
1512
|
const itemWrapper = document.createElement("div");
|
|
1475
1513
|
itemWrapper.className = "multiple-select-item flex items-center gap-2";
|
|
1476
1514
|
const selectInput = document.createElement("select");
|
|
1477
|
-
selectInput.className = "flex-1
|
|
1515
|
+
selectInput.className = "flex-1 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500";
|
|
1516
|
+
selectInput.style.cssText = `
|
|
1517
|
+
padding: var(--fb-input-padding-y) var(--fb-input-padding-x);
|
|
1518
|
+
font-size: var(--fb-font-size);
|
|
1519
|
+
font-family: var(--fb-font-family);
|
|
1520
|
+
`;
|
|
1478
1521
|
selectInput.disabled = readonly;
|
|
1479
1522
|
(element.options || []).forEach((option) => {
|
|
1480
1523
|
const optionElement = document.createElement("option");
|
|
@@ -2225,7 +2268,13 @@ function ensureFileStyles() {
|
|
|
2225
2268
|
style.textContent = `
|
|
2226
2269
|
@keyframes fb-spin { to { transform: rotate(360deg); } }
|
|
2227
2270
|
|
|
2228
|
-
/*
|
|
2271
|
+
/* \u2500\u2500\u2500 Checker background utility \u2500\u2500\u2500 */
|
|
2272
|
+
/* Neutral diagonal-stripe background for image previews (never crops) */
|
|
2273
|
+
.fb-checker {
|
|
2274
|
+
background-image: repeating-linear-gradient(45deg, #fafafa 0 6px, #f3f4f6 6px 12px);
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
/* \u2500\u2500\u2500 Spinner \u2500\u2500\u2500 */
|
|
2229
2278
|
.fb-spinner {
|
|
2230
2279
|
width: 36px;
|
|
2231
2280
|
height: 36px;
|
|
@@ -2236,207 +2285,271 @@ function ensureFileStyles() {
|
|
|
2236
2285
|
flex-shrink: 0;
|
|
2237
2286
|
}
|
|
2238
2287
|
|
|
2239
|
-
/*
|
|
2240
|
-
.fb-tile {
|
|
2241
|
-
width:
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2288
|
+
/* \u2500\u2500\u2500 Wide single-file add tile (empty state) \u2500\u2500\u2500 */
|
|
2289
|
+
.fb-wide-tile {
|
|
2290
|
+
width: 100%;
|
|
2291
|
+
border-radius: 0.75rem;
|
|
2292
|
+
border: 1px dashed #60a5fa;
|
|
2293
|
+
background: rgba(239,246,255,0.5);
|
|
2294
|
+
display: flex;
|
|
2245
2295
|
overflow: hidden;
|
|
2246
|
-
|
|
2247
|
-
|
|
2296
|
+
height: 180px;
|
|
2297
|
+
transition: border-color 150ms, background 150ms, box-shadow 150ms;
|
|
2298
|
+
cursor: pointer;
|
|
2248
2299
|
}
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
.fb-tile-resource {
|
|
2252
|
-
border: 1px solid var(--fb-file-upload-border-color, #d1d5db);
|
|
2300
|
+
.fb-wide-tile:hover {
|
|
2301
|
+
background: #eff6ff;
|
|
2253
2302
|
}
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2303
|
+
.fb-wide-tile.fb-drag-over {
|
|
2304
|
+
border-color: #3b82f6;
|
|
2305
|
+
border-width: 2px;
|
|
2306
|
+
background: #eff6ff;
|
|
2307
|
+
box-shadow: 0 0 0 4px rgba(191,219,254,0.7);
|
|
2258
2308
|
}
|
|
2259
2309
|
|
|
2260
|
-
/*
|
|
2261
|
-
.fb-tile-
|
|
2262
|
-
|
|
2310
|
+
/* Upload zone inside wide tile */
|
|
2311
|
+
.fb-wide-tile-upload {
|
|
2312
|
+
flex: 1;
|
|
2263
2313
|
display: flex;
|
|
2314
|
+
flex-direction: column;
|
|
2264
2315
|
align-items: center;
|
|
2265
2316
|
justify-content: center;
|
|
2317
|
+
gap: 8px;
|
|
2318
|
+
color: #2563eb;
|
|
2319
|
+
padding: 16px;
|
|
2320
|
+
transition: background 150ms;
|
|
2266
2321
|
cursor: pointer;
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
border-color var(--fb-transition-duration, 200ms),
|
|
2271
|
-
color var(--fb-transition-duration, 200ms);
|
|
2322
|
+
background: transparent;
|
|
2323
|
+
border: none;
|
|
2324
|
+
font-family: inherit;
|
|
2272
2325
|
}
|
|
2273
|
-
.fb-tile-
|
|
2274
|
-
|
|
2275
|
-
color: var(--fb-text-color, #1f2937);
|
|
2326
|
+
.fb-wide-tile-upload:hover {
|
|
2327
|
+
background: rgba(191,219,254,0.25);
|
|
2276
2328
|
}
|
|
2277
2329
|
|
|
2278
|
-
/*
|
|
2279
|
-
.fb-tile-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
padding: 2px 6px;
|
|
2286
|
-
align-self: flex-end;
|
|
2287
|
-
margin-bottom: 4px;
|
|
2330
|
+
/* Vertical dashed divider between upload and library zones */
|
|
2331
|
+
.fb-wide-tile-divider {
|
|
2332
|
+
width: 1px;
|
|
2333
|
+
margin: 16px 0;
|
|
2334
|
+
border-left: 1px dashed rgba(96,165,250,0.5);
|
|
2335
|
+
background: transparent;
|
|
2336
|
+
flex-shrink: 0;
|
|
2288
2337
|
}
|
|
2289
2338
|
|
|
2290
|
-
/*
|
|
2291
|
-
.fb-
|
|
2292
|
-
width:
|
|
2293
|
-
|
|
2294
|
-
border: 2px dashed var(--fb-file-upload-border-color, #d1d5db);
|
|
2295
|
-
border-radius: var(--fb-border-radius, 0.5rem);
|
|
2339
|
+
/* Library zone inside wide tile */
|
|
2340
|
+
.fb-wide-tile-library {
|
|
2341
|
+
width: 176px;
|
|
2342
|
+
flex-shrink: 0;
|
|
2296
2343
|
display: flex;
|
|
2297
2344
|
flex-direction: column;
|
|
2298
2345
|
align-items: center;
|
|
2299
2346
|
justify-content: center;
|
|
2300
|
-
gap:
|
|
2347
|
+
gap: 8px;
|
|
2348
|
+
color: #2563eb;
|
|
2349
|
+
padding: 12px;
|
|
2350
|
+
transition: background 150ms;
|
|
2301
2351
|
cursor: pointer;
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2352
|
+
background: transparent;
|
|
2353
|
+
border: none;
|
|
2354
|
+
font-family: inherit;
|
|
2305
2355
|
}
|
|
2306
|
-
.fb-
|
|
2307
|
-
|
|
2308
|
-
background: var(--fb-background-hover-color, #f9fafb);
|
|
2356
|
+
.fb-wide-tile-library:hover {
|
|
2357
|
+
background: rgba(191,219,254,0.25);
|
|
2309
2358
|
}
|
|
2310
2359
|
|
|
2311
|
-
/*
|
|
2312
|
-
.fb-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2360
|
+
/* \u2500\u2500\u2500 Multi-file outer grid container \u2500\u2500\u2500 */
|
|
2361
|
+
.fb-multi-outer {
|
|
2362
|
+
border-radius: 0.75rem;
|
|
2363
|
+
border: 1px dashed #cbd5e1;
|
|
2364
|
+
background: rgba(248,250,252,0.4);
|
|
2365
|
+
padding: 12px;
|
|
2366
|
+
transition: border-color 150ms, background 150ms, box-shadow 150ms;
|
|
2367
|
+
}
|
|
2368
|
+
.fb-multi-outer.fb-drag-over {
|
|
2369
|
+
border-width: 2px;
|
|
2370
|
+
border-color: #3b82f6;
|
|
2371
|
+
background: rgba(239,246,255,0.4);
|
|
2372
|
+
box-shadow: 0 0 0 4px rgba(191,219,254,0.7);
|
|
2319
2373
|
}
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2374
|
+
|
|
2375
|
+
/* With files present: white solid border */
|
|
2376
|
+
.fb-multi-outer.fb-multi-has-files {
|
|
2377
|
+
border-style: solid;
|
|
2378
|
+
border-color: #e2e8f0;
|
|
2379
|
+
background: #fff;
|
|
2323
2380
|
}
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2381
|
+
|
|
2382
|
+
/* The CSS grid inside */
|
|
2383
|
+
.fb-multi-grid {
|
|
2384
|
+
display: grid;
|
|
2385
|
+
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
|
2386
|
+
gap: 10px;
|
|
2328
2387
|
}
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2388
|
+
|
|
2389
|
+
/* \u2500\u2500\u2500 Multi square add-tile (combined upload + library) \u2500\u2500\u2500 */
|
|
2390
|
+
.fb-multi-add-tile {
|
|
2391
|
+
aspect-ratio: 1 / 1;
|
|
2392
|
+
border-radius: 0.5rem;
|
|
2393
|
+
border: 1px dashed #60a5fa;
|
|
2394
|
+
background: rgba(239,246,255,0.5);
|
|
2395
|
+
display: flex;
|
|
2396
|
+
flex-direction: column;
|
|
2397
|
+
overflow: hidden;
|
|
2398
|
+
transition: background 150ms;
|
|
2333
2399
|
}
|
|
2334
|
-
.fb-
|
|
2335
|
-
|
|
2336
|
-
color: var(--fb-text-secondary-color, #6b7280);
|
|
2400
|
+
.fb-multi-add-tile:hover {
|
|
2401
|
+
background: #eff6ff;
|
|
2337
2402
|
}
|
|
2338
|
-
.fb-
|
|
2339
|
-
|
|
2340
|
-
color:
|
|
2403
|
+
.fb-multi-add-tile.fb-drag-over-tile {
|
|
2404
|
+
border-width: 2px;
|
|
2405
|
+
border-color: #3b82f6;
|
|
2406
|
+
background: rgba(255,255,255,0.8);
|
|
2341
2407
|
}
|
|
2342
2408
|
|
|
2343
|
-
/*
|
|
2344
|
-
.fb-
|
|
2345
|
-
|
|
2346
|
-
inset: 0;
|
|
2347
|
-
background: transparent;
|
|
2348
|
-
transition: background var(--fb-transition-duration, 200ms);
|
|
2349
|
-
display: flex;
|
|
2350
|
-
align-items: flex-start;
|
|
2351
|
-
justify-content: flex-end;
|
|
2352
|
-
}
|
|
2353
|
-
.fb-tile-resource:hover .fb-tile-overlay {
|
|
2354
|
-
background: var(--fb-tile-hover-overlay-color, rgba(0,0,0,0.4));
|
|
2355
|
-
}
|
|
2356
|
-
.fb-tile-x-btn {
|
|
2357
|
-
margin: 3px;
|
|
2358
|
-
width: 18px;
|
|
2359
|
-
height: 18px;
|
|
2360
|
-
background: var(--fb-error-color, #ef4444);
|
|
2361
|
-
color: var(--fb-file-bg-color, #fff);
|
|
2362
|
-
border: none;
|
|
2363
|
-
border-radius: 50%;
|
|
2364
|
-
font-size: 11px;
|
|
2365
|
-
line-height: 1;
|
|
2366
|
-
cursor: pointer;
|
|
2409
|
+
/* Upload half of add-tile */
|
|
2410
|
+
.fb-multi-add-upload {
|
|
2411
|
+
flex: 1;
|
|
2367
2412
|
display: flex;
|
|
2413
|
+
flex-direction: column;
|
|
2368
2414
|
align-items: center;
|
|
2369
2415
|
justify-content: center;
|
|
2370
|
-
|
|
2371
|
-
|
|
2416
|
+
gap: 4px;
|
|
2417
|
+
color: #2563eb;
|
|
2418
|
+
cursor: pointer;
|
|
2419
|
+
background: transparent;
|
|
2420
|
+
border: none;
|
|
2421
|
+
font-family: inherit;
|
|
2422
|
+
width: 100%;
|
|
2423
|
+
transition: background 150ms;
|
|
2372
2424
|
}
|
|
2373
|
-
.fb-
|
|
2374
|
-
|
|
2425
|
+
.fb-multi-add-upload:hover {
|
|
2426
|
+
background: rgba(191,219,254,0.35);
|
|
2375
2427
|
}
|
|
2376
2428
|
|
|
2377
|
-
/*
|
|
2378
|
-
.fb-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
align-items: center;
|
|
2383
|
-
justify-content: center;
|
|
2384
|
-
background: var(--fb-tile-hover-overlay-color, rgba(0,0,0,0.25));
|
|
2429
|
+
/* Horizontal dashed divider inside add-tile */
|
|
2430
|
+
.fb-multi-add-divider {
|
|
2431
|
+
border-top: 1px dashed rgba(96,165,250,0.5);
|
|
2432
|
+
margin: 0;
|
|
2433
|
+
flex-shrink: 0;
|
|
2385
2434
|
}
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2435
|
+
|
|
2436
|
+
/* Library strip at bottom of add-tile */
|
|
2437
|
+
.fb-multi-add-library {
|
|
2438
|
+
padding: 6px 0;
|
|
2389
2439
|
display: flex;
|
|
2390
2440
|
align-items: center;
|
|
2391
2441
|
justify-content: center;
|
|
2442
|
+
gap: 4px;
|
|
2443
|
+
color: #2563eb;
|
|
2444
|
+
font-size: 11px;
|
|
2445
|
+
font-weight: 500;
|
|
2446
|
+
cursor: pointer;
|
|
2447
|
+
background: transparent;
|
|
2448
|
+
border: none;
|
|
2449
|
+
font-family: inherit;
|
|
2450
|
+
width: 100%;
|
|
2451
|
+
transition: background 150ms;
|
|
2452
|
+
flex-shrink: 0;
|
|
2453
|
+
}
|
|
2454
|
+
.fb-multi-add-library:hover {
|
|
2455
|
+
background: rgba(191,219,254,0.35);
|
|
2392
2456
|
}
|
|
2393
2457
|
|
|
2394
|
-
/*
|
|
2395
|
-
.fb-
|
|
2458
|
+
/* \u2500\u2500\u2500 Capacity placeholder squares \u2500\u2500\u2500 */
|
|
2459
|
+
.fb-multi-placeholder {
|
|
2460
|
+
aspect-ratio: 1 / 1;
|
|
2461
|
+
border-radius: 0.5rem;
|
|
2462
|
+
border: 1px solid #e2e8f0;
|
|
2463
|
+
}
|
|
2464
|
+
.fb-multi-placeholder.fb-drag-over {
|
|
2465
|
+
border-width: 2px;
|
|
2466
|
+
border-style: dashed;
|
|
2467
|
+
border-color: #93c5fd;
|
|
2468
|
+
background: rgba(219,234,254,0.6);
|
|
2469
|
+
}
|
|
2470
|
+
|
|
2471
|
+
/* \u2500\u2500\u2500 Filled preview tile \u2500\u2500\u2500 */
|
|
2472
|
+
.fb-preview-tile {
|
|
2473
|
+
aspect-ratio: 1 / 1;
|
|
2474
|
+
border-radius: 0.5rem;
|
|
2475
|
+
border: 1px solid #e2e8f0;
|
|
2476
|
+
overflow: hidden;
|
|
2396
2477
|
position: relative;
|
|
2478
|
+
cursor: pointer;
|
|
2479
|
+
}
|
|
2480
|
+
.fb-preview-tile img {
|
|
2397
2481
|
width: 100%;
|
|
2398
2482
|
height: 100%;
|
|
2483
|
+
object-fit: contain;
|
|
2484
|
+
display: block;
|
|
2399
2485
|
}
|
|
2400
2486
|
|
|
2401
|
-
/*
|
|
2402
|
-
.fb-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
z-index: 10;
|
|
2487
|
+
/* \u2500\u2500\u2500 Uploading placeholder tile \u2500\u2500\u2500 */
|
|
2488
|
+
.fb-uploading-tile {
|
|
2489
|
+
aspect-ratio: 1 / 1;
|
|
2490
|
+
border-radius: 0.5rem;
|
|
2491
|
+
border: 2px dashed #d1d5db;
|
|
2407
2492
|
display: flex;
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2493
|
+
flex-direction: column;
|
|
2494
|
+
align-items: center;
|
|
2495
|
+
justify-content: center;
|
|
2496
|
+
gap: 6px;
|
|
2497
|
+
padding: 6px;
|
|
2412
2498
|
}
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2499
|
+
|
|
2500
|
+
/* \u2500\u2500\u2500 Meta line below multi grid \u2500\u2500\u2500 */
|
|
2501
|
+
.fb-meta-line {
|
|
2502
|
+
margin-top: 10px;
|
|
2503
|
+
display: flex;
|
|
2504
|
+
align-items: center;
|
|
2505
|
+
justify-content: space-between;
|
|
2506
|
+
gap: 8px;
|
|
2507
|
+
flex-wrap: wrap;
|
|
2416
2508
|
}
|
|
2417
|
-
.fb-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
line-height: 1.2;
|
|
2509
|
+
.fb-meta-text {
|
|
2510
|
+
font-size: 12px;
|
|
2511
|
+
color: #94a3b8;
|
|
2512
|
+
display: flex;
|
|
2513
|
+
align-items: center;
|
|
2514
|
+
gap: 8px;
|
|
2515
|
+
flex-wrap: wrap;
|
|
2425
2516
|
}
|
|
2426
|
-
.fb-
|
|
2427
|
-
|
|
2517
|
+
.fb-meta-dot {
|
|
2518
|
+
width: 4px;
|
|
2519
|
+
height: 4px;
|
|
2520
|
+
border-radius: 50%;
|
|
2521
|
+
background: #cbd5e1;
|
|
2522
|
+
flex-shrink: 0;
|
|
2428
2523
|
}
|
|
2429
|
-
.fb-
|
|
2430
|
-
|
|
2524
|
+
.fb-meta-mono {
|
|
2525
|
+
font-family: ui-monospace, 'JetBrains Mono', monospace;
|
|
2526
|
+
font-size: 11px;
|
|
2527
|
+
letter-spacing: -0.02em;
|
|
2431
2528
|
}
|
|
2432
|
-
.fb-
|
|
2433
|
-
|
|
2529
|
+
.fb-clear-all-btn {
|
|
2530
|
+
font-size: 12px;
|
|
2531
|
+
color: #94a3b8;
|
|
2532
|
+
background: none;
|
|
2533
|
+
border: none;
|
|
2534
|
+
cursor: pointer;
|
|
2535
|
+
padding: 0;
|
|
2536
|
+
font-family: inherit;
|
|
2537
|
+
transition: color 150ms;
|
|
2538
|
+
white-space: nowrap;
|
|
2539
|
+
flex-shrink: 0;
|
|
2434
2540
|
}
|
|
2435
|
-
.fb-
|
|
2436
|
-
|
|
2541
|
+
.fb-clear-all-btn:hover {
|
|
2542
|
+
color: #dc2626;
|
|
2437
2543
|
}
|
|
2438
2544
|
|
|
2439
|
-
/*
|
|
2545
|
+
/* \u2500\u2500\u2500 Empty text (readonly) \u2500\u2500\u2500 */
|
|
2546
|
+
.fb-tile-empty-text {
|
|
2547
|
+
font-size: 11px;
|
|
2548
|
+
color: var(--fb-text-secondary-color, #6b7280);
|
|
2549
|
+
padding: 4px 0;
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
/* \u2500\u2500\u2500 Tile action buttons (for zoom popup, compat) \u2500\u2500\u2500 */
|
|
2440
2553
|
.fb-tile-actions {
|
|
2441
2554
|
position: absolute;
|
|
2442
2555
|
top: 3px;
|
|
@@ -2448,37 +2561,35 @@ function ensureFileStyles() {
|
|
|
2448
2561
|
transition: opacity var(--fb-transition-duration, 200ms);
|
|
2449
2562
|
z-index: 10;
|
|
2450
2563
|
}
|
|
2451
|
-
.fb-tile
|
|
2564
|
+
.fb-preview-tile:hover .fb-tile-actions {
|
|
2452
2565
|
opacity: 1;
|
|
2453
2566
|
}
|
|
2454
2567
|
.fb-tile-action-btn {
|
|
2455
|
-
width:
|
|
2456
|
-
height:
|
|
2568
|
+
width: 24px;
|
|
2569
|
+
height: 24px;
|
|
2457
2570
|
display: flex;
|
|
2458
2571
|
align-items: center;
|
|
2459
2572
|
justify-content: center;
|
|
2460
|
-
border:
|
|
2461
|
-
border-radius:
|
|
2573
|
+
border: 1px solid rgba(15,23,42,0.08);
|
|
2574
|
+
border-radius: 0.375rem;
|
|
2462
2575
|
cursor: pointer;
|
|
2463
|
-
background: rgba(
|
|
2464
|
-
color: #
|
|
2576
|
+
background: rgba(255,255,255,0.92);
|
|
2577
|
+
color: #374151;
|
|
2465
2578
|
padding: 0;
|
|
2466
2579
|
flex-shrink: 0;
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2580
|
+
box-shadow: 0 1px 2px rgba(0,0,0,0.06);
|
|
2581
|
+
transition: background var(--fb-transition-duration, 200ms),
|
|
2582
|
+
color var(--fb-transition-duration, 200ms);
|
|
2470
2583
|
}
|
|
2471
2584
|
.fb-tile-action-btn:hover {
|
|
2472
|
-
background:
|
|
2473
|
-
|
|
2474
|
-
.fb-tile-action-remove {
|
|
2475
|
-
background: rgba(220, 38, 38, 0.8);
|
|
2585
|
+
background: #ffffff;
|
|
2586
|
+
color: #0f172a;
|
|
2476
2587
|
}
|
|
2477
2588
|
.fb-tile-action-remove:hover {
|
|
2478
|
-
|
|
2589
|
+
color: #dc2626;
|
|
2479
2590
|
}
|
|
2480
2591
|
|
|
2481
|
-
/*
|
|
2592
|
+
/* Zoom popup action buttons always visible */
|
|
2482
2593
|
.fb-tile-zoom-preview .fb-tile-actions {
|
|
2483
2594
|
position: absolute;
|
|
2484
2595
|
top: 6px;
|
|
@@ -2487,116 +2598,145 @@ function ensureFileStyles() {
|
|
|
2487
2598
|
z-index: 10000;
|
|
2488
2599
|
}
|
|
2489
2600
|
|
|
2490
|
-
/*
|
|
2491
|
-
.fb-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2601
|
+
/* \u2500\u2500\u2500 Hover zoom preview popup \u2500\u2500\u2500 */
|
|
2602
|
+
.fb-tile-zoom-preview {
|
|
2603
|
+
position: fixed;
|
|
2604
|
+
z-index: 9999;
|
|
2605
|
+
background: var(--fb-background-color, #fff);
|
|
2606
|
+
border: 1px solid #e2e8f0;
|
|
2607
|
+
border-radius: 0.5rem;
|
|
2608
|
+
box-shadow: 0 4px 16px rgba(0,0,0,0.18);
|
|
2609
|
+
padding: 4px;
|
|
2610
|
+
width: 350px;
|
|
2611
|
+
height: 350px;
|
|
2612
|
+
pointer-events: none;
|
|
2613
|
+
opacity: 0;
|
|
2614
|
+
transition: opacity 150ms ease;
|
|
2495
2615
|
}
|
|
2496
|
-
.fb-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2616
|
+
.fb-tile-zoom-preview.fb-tile-zoom-preview--visible {
|
|
2617
|
+
opacity: 1;
|
|
2618
|
+
}
|
|
2619
|
+
.fb-tile-zoom-preview-img {
|
|
2620
|
+
width: 100%;
|
|
2621
|
+
height: 100%;
|
|
2622
|
+
object-fit: contain;
|
|
2623
|
+
display: block;
|
|
2624
|
+
border-radius: calc(0.5rem - 2px);
|
|
2500
2625
|
}
|
|
2501
2626
|
|
|
2502
|
-
/*
|
|
2503
|
-
.fb-
|
|
2504
|
-
height:
|
|
2505
|
-
border:
|
|
2506
|
-
border
|
|
2627
|
+
/* \u2500\u2500\u2500 Single-file uploading state \u2500\u2500\u2500 */
|
|
2628
|
+
.fb-single-uploading {
|
|
2629
|
+
height: 180px;
|
|
2630
|
+
border-radius: 0.75rem;
|
|
2631
|
+
border: 1px dashed #60a5fa;
|
|
2632
|
+
background: rgba(239,246,255,0.5);
|
|
2507
2633
|
display: flex;
|
|
2508
2634
|
flex-direction: column;
|
|
2509
2635
|
align-items: center;
|
|
2510
2636
|
justify-content: center;
|
|
2511
|
-
gap:
|
|
2512
|
-
cursor: pointer;
|
|
2513
|
-
background: none;
|
|
2514
|
-
padding: 0;
|
|
2515
|
-
transition:
|
|
2516
|
-
border-color var(--fb-transition-duration, 200ms),
|
|
2517
|
-
background var(--fb-transition-duration, 200ms);
|
|
2518
|
-
width: 100%;
|
|
2637
|
+
gap: 8px;
|
|
2519
2638
|
}
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2639
|
+
|
|
2640
|
+
/* \u2500\u2500\u2500 Video overlays \u2500\u2500\u2500 */
|
|
2641
|
+
.fb-video-overlay {
|
|
2642
|
+
position: absolute;
|
|
2643
|
+
inset: 0;
|
|
2644
|
+
display: flex;
|
|
2645
|
+
align-items: center;
|
|
2646
|
+
justify-content: center;
|
|
2647
|
+
background: rgba(0,0,0,0.25);
|
|
2525
2648
|
}
|
|
2526
|
-
.fb-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2649
|
+
.fb-play-btn {
|
|
2650
|
+
background: rgba(255,255,255,0.9);
|
|
2651
|
+
border-radius: 50%;
|
|
2652
|
+
display: flex;
|
|
2653
|
+
align-items: center;
|
|
2654
|
+
justify-content: center;
|
|
2530
2655
|
}
|
|
2531
|
-
.fb-
|
|
2532
|
-
|
|
2533
|
-
|
|
2656
|
+
.fb-video-preview-wrap {
|
|
2657
|
+
position: relative;
|
|
2658
|
+
width: 100%;
|
|
2659
|
+
height: 100%;
|
|
2534
2660
|
}
|
|
2535
|
-
.fb-
|
|
2661
|
+
.fb-video-btn-overlay {
|
|
2662
|
+
position: absolute;
|
|
2663
|
+
top: 8px;
|
|
2664
|
+
right: 8px;
|
|
2665
|
+
z-index: 10;
|
|
2666
|
+
display: flex;
|
|
2667
|
+
gap: 4px;
|
|
2668
|
+
opacity: 0;
|
|
2669
|
+
transition: opacity 150ms;
|
|
2670
|
+
pointer-events: none;
|
|
2671
|
+
}
|
|
2672
|
+
.fb-video-preview-wrap:hover .fb-video-btn-overlay {
|
|
2673
|
+
opacity: 1;
|
|
2674
|
+
pointer-events: auto;
|
|
2675
|
+
}
|
|
2676
|
+
.fb-video-btn {
|
|
2677
|
+
border: none;
|
|
2678
|
+
border-radius: 4px;
|
|
2536
2679
|
font-size: 11px;
|
|
2537
|
-
|
|
2680
|
+
padding: 4px 8px;
|
|
2681
|
+
cursor: pointer;
|
|
2682
|
+
color: #fff;
|
|
2683
|
+
line-height: 1.2;
|
|
2538
2684
|
}
|
|
2685
|
+
.fb-video-btn-delete { background: rgba(220,38,38,0.85); }
|
|
2686
|
+
.fb-video-btn-delete:hover { background: rgba(185,28,28,0.95); }
|
|
2687
|
+
.fb-video-btn-change { background: rgba(31,41,55,0.85); }
|
|
2688
|
+
.fb-video-btn-change:hover { background: rgba(17,24,39,0.95); }
|
|
2539
2689
|
|
|
2540
|
-
/*
|
|
2541
|
-
.fb-tile
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
justify-content: center;
|
|
2546
|
-
cursor: pointer;
|
|
2547
|
-
font-size: 24px;
|
|
2548
|
-
color: var(--fb-file-upload-text-color, #9ca3af);
|
|
2549
|
-
transition:
|
|
2550
|
-
border-color var(--fb-transition-duration, 200ms),
|
|
2551
|
-
color var(--fb-transition-duration, 200ms);
|
|
2552
|
-
background: none;
|
|
2553
|
-
padding: 0;
|
|
2554
|
-
width: var(--fb-tile-size, 160px);
|
|
2555
|
-
height: var(--fb-tile-size, 160px);
|
|
2556
|
-
flex-shrink: 0;
|
|
2557
|
-
position: relative;
|
|
2690
|
+
/* \u2500\u2500\u2500 Readonly readonly tile \u2500\u2500\u2500 */
|
|
2691
|
+
.fb-readonly-tile {
|
|
2692
|
+
aspect-ratio: 1 / 1;
|
|
2693
|
+
border-radius: 0.5rem;
|
|
2694
|
+
border: 1px solid #e2e8f0;
|
|
2558
2695
|
overflow: hidden;
|
|
2559
|
-
|
|
2696
|
+
position: relative;
|
|
2697
|
+
cursor: pointer;
|
|
2560
2698
|
}
|
|
2561
|
-
.fb-tile
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2699
|
+
.fb-readonly-tile img {
|
|
2700
|
+
width: 100%;
|
|
2701
|
+
height: 100%;
|
|
2702
|
+
object-fit: contain;
|
|
2703
|
+
display: block;
|
|
2566
2704
|
}
|
|
2567
|
-
|
|
2568
|
-
/* Hover zoom preview popup for image tiles \u2014 appended to document.body (fixed) */
|
|
2569
|
-
.fb-tile-zoom-preview {
|
|
2570
|
-
position: fixed;
|
|
2571
|
-
z-index: 9999;
|
|
2572
|
-
background: var(--fb-background-color, #fff);
|
|
2573
|
-
border: 1px solid var(--fb-file-upload-border-color, #d1d5db);
|
|
2574
|
-
border-radius: var(--fb-border-radius, 0.5rem);
|
|
2575
|
-
box-shadow: 0 4px 16px rgba(0,0,0,0.18);
|
|
2576
|
-
padding: 4px;
|
|
2577
|
-
width: 350px;
|
|
2578
|
-
height: 350px;
|
|
2579
|
-
pointer-events: none;
|
|
2705
|
+
.fb-readonly-tile .fb-tile-actions {
|
|
2580
2706
|
opacity: 0;
|
|
2581
|
-
transition: opacity 150ms ease;
|
|
2582
2707
|
}
|
|
2583
|
-
.fb-tile
|
|
2708
|
+
.fb-readonly-tile:hover .fb-tile-actions {
|
|
2584
2709
|
opacity: 1;
|
|
2585
2710
|
}
|
|
2586
|
-
|
|
2711
|
+
|
|
2712
|
+
/* \u2500\u2500\u2500 Readonly single-file filled \u2500\u2500\u2500 */
|
|
2713
|
+
.fb-single-readonly-filled {
|
|
2714
|
+
position: relative;
|
|
2715
|
+
border-radius: 0.75rem;
|
|
2716
|
+
border: 1px solid #e2e8f0;
|
|
2717
|
+
overflow: hidden;
|
|
2718
|
+
height: 220px;
|
|
2719
|
+
display: block;
|
|
2720
|
+
cursor: pointer;
|
|
2721
|
+
}
|
|
2722
|
+
.fb-single-readonly-filled img {
|
|
2587
2723
|
width: 100%;
|
|
2588
2724
|
height: 100%;
|
|
2589
2725
|
object-fit: contain;
|
|
2590
2726
|
display: block;
|
|
2591
|
-
|
|
2592
|
-
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
/* \u2500\u2500\u2500 Readonly multi grid \u2500\u2500\u2500 */
|
|
2730
|
+
.fb-multi-readonly-grid {
|
|
2731
|
+
display: grid;
|
|
2732
|
+
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
|
2733
|
+
gap: 10px;
|
|
2593
2734
|
}
|
|
2594
2735
|
`;
|
|
2595
2736
|
document.head.appendChild(style);
|
|
2596
2737
|
}
|
|
2597
2738
|
|
|
2598
2739
|
// src/components/file/dom.ts
|
|
2599
|
-
var TILE_SIZE = "160px";
|
|
2600
2740
|
function createFileTile() {
|
|
2601
2741
|
ensureFileStyles();
|
|
2602
2742
|
const tile = document.createElement("div");
|
|
@@ -2605,7 +2745,7 @@ function createFileTile() {
|
|
|
2605
2745
|
}
|
|
2606
2746
|
function showFileError(container, message) {
|
|
2607
2747
|
var _a, _b;
|
|
2608
|
-
const existing = (_a = container.closest("
|
|
2748
|
+
const existing = (_a = container.closest("[data-files-wrapper]")) == null ? void 0 : _a.querySelector(".file-error-message");
|
|
2609
2749
|
if (existing) existing.remove();
|
|
2610
2750
|
const errorEl = document.createElement("div");
|
|
2611
2751
|
errorEl.className = "file-error-message error-message";
|
|
@@ -2615,11 +2755,11 @@ function showFileError(container, message) {
|
|
|
2615
2755
|
margin-top: 0.25rem;
|
|
2616
2756
|
`;
|
|
2617
2757
|
errorEl.textContent = message;
|
|
2618
|
-
(_b = container.closest("
|
|
2758
|
+
(_b = container.closest("[data-files-wrapper]")) == null ? void 0 : _b.appendChild(errorEl);
|
|
2619
2759
|
}
|
|
2620
2760
|
function clearFileError(container) {
|
|
2621
2761
|
var _a;
|
|
2622
|
-
const existing = (_a = container.closest("
|
|
2762
|
+
const existing = (_a = container.closest("[data-files-wrapper]")) == null ? void 0 : _a.querySelector(".file-error-message");
|
|
2623
2763
|
if (existing) existing.remove();
|
|
2624
2764
|
}
|
|
2625
2765
|
function addDeleteButton(container, state, onDelete) {
|
|
@@ -2637,14 +2777,6 @@ function addDeleteButton(container, state, onDelete) {
|
|
|
2637
2777
|
overlay.appendChild(deleteBtn);
|
|
2638
2778
|
container.appendChild(overlay);
|
|
2639
2779
|
}
|
|
2640
|
-
function findFilePicker(container) {
|
|
2641
|
-
var _a;
|
|
2642
|
-
let el = container.parentElement;
|
|
2643
|
-
while (el && !el.dataset.filesWrapper) {
|
|
2644
|
-
el = el.parentElement;
|
|
2645
|
-
}
|
|
2646
|
-
return (_a = el == null ? void 0 : el.querySelector('input[type="file"]')) != null ? _a : null;
|
|
2647
|
-
}
|
|
2648
2780
|
function createUploadingTile(fileName, state) {
|
|
2649
2781
|
ensureFileStyles();
|
|
2650
2782
|
const tile = createFileTile();
|
|
@@ -2660,10 +2792,14 @@ function createUploadingTile(fileName, state) {
|
|
|
2660
2792
|
return tile;
|
|
2661
2793
|
}
|
|
2662
2794
|
function ensureTilesWrap(list) {
|
|
2795
|
+
var _a, _b, _c;
|
|
2796
|
+
const existingGrid = list.querySelector(".fb-multi-grid");
|
|
2797
|
+
if (existingGrid) return existingGrid;
|
|
2663
2798
|
const existing = list.querySelector(".fb-tiles-wrap");
|
|
2664
2799
|
if (existing) return existing;
|
|
2665
|
-
|
|
2666
|
-
|
|
2800
|
+
(_a = list.querySelector(".fb-file-dropzone")) == null ? void 0 : _a.remove();
|
|
2801
|
+
(_b = list.querySelector(".fb-wide-tile")) == null ? void 0 : _b.remove();
|
|
2802
|
+
(_c = list.querySelector(".fb-multi-outer")) == null ? void 0 : _c.remove();
|
|
2667
2803
|
const tilesWrap = document.createElement("div");
|
|
2668
2804
|
tilesWrap.className = "fb-tiles-wrap";
|
|
2669
2805
|
tilesWrap.style.cssText = "display:flex;flex-wrap:wrap;gap:6px;align-items:flex-start;";
|
|
@@ -2675,7 +2811,7 @@ function ensureTilesWrap(list) {
|
|
|
2675
2811
|
return tilesWrap;
|
|
2676
2812
|
}
|
|
2677
2813
|
function setEmptyFileContainer(fileContainer, state, hint) {
|
|
2678
|
-
const hintHtml =
|
|
2814
|
+
const hintHtml = "";
|
|
2679
2815
|
fileContainer.innerHTML = `
|
|
2680
2816
|
<div class="flex flex-col items-center justify-center h-full text-gray-400">
|
|
2681
2817
|
<svg class="w-6 h-6 mb-2" fill="currentColor" viewBox="0 0 24 24">
|
|
@@ -2718,9 +2854,11 @@ function setupDragAndDrop(element, dropHandler) {
|
|
|
2718
2854
|
}
|
|
2719
2855
|
|
|
2720
2856
|
// src/components/file/preview.ts
|
|
2721
|
-
var ICON_DOWNLOAD = `<svg width="
|
|
2722
|
-
var ICON_OPEN = `<svg width="
|
|
2723
|
-
var ICON_REMOVE = `<svg width="
|
|
2857
|
+
var ICON_DOWNLOAD = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>`;
|
|
2858
|
+
var ICON_OPEN = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>`;
|
|
2859
|
+
var ICON_REMOVE = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"/></svg>`;
|
|
2860
|
+
var ICON_REPLACE = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 18a4 4 0 000-8 6 6 0 00-11.5 2A4 4 0 006 20h11M12 12v7M12 12l-3 3M12 12l3 3"/></svg>`;
|
|
2861
|
+
var ICON_LIBRARY = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 4h4v16H4z"/><path d="M10 4h4v16h-4z"/><path d="M16 5l3.5 1-3 14L13 19"/></svg>`;
|
|
2724
2862
|
function canDownload(state, meta) {
|
|
2725
2863
|
return Boolean(
|
|
2726
2864
|
state.config.downloadFile || state.config.getDownloadUrl || state.config.getThumbnail || (meta == null ? void 0 : meta.file)
|
|
@@ -2732,7 +2870,16 @@ function canOpenInTab(state, meta) {
|
|
|
2732
2870
|
);
|
|
2733
2871
|
}
|
|
2734
2872
|
function createTileActions(options) {
|
|
2735
|
-
const {
|
|
2873
|
+
const {
|
|
2874
|
+
canRemove,
|
|
2875
|
+
removeHandler,
|
|
2876
|
+
state,
|
|
2877
|
+
resourceId,
|
|
2878
|
+
fileName,
|
|
2879
|
+
meta,
|
|
2880
|
+
replaceHandler,
|
|
2881
|
+
libraryHandler
|
|
2882
|
+
} = options;
|
|
2736
2883
|
const group = document.createElement("div");
|
|
2737
2884
|
group.className = "fb-tile-actions";
|
|
2738
2885
|
const makeBtn = (icon, label, cls) => {
|
|
@@ -2747,6 +2894,16 @@ function createTileActions(options) {
|
|
|
2747
2894
|
});
|
|
2748
2895
|
return btn;
|
|
2749
2896
|
};
|
|
2897
|
+
if (replaceHandler) {
|
|
2898
|
+
const replaceBtn = makeBtn(ICON_REPLACE, t("replaceFile", state), "fb-tile-action-replace");
|
|
2899
|
+
replaceBtn.addEventListener("click", () => replaceHandler());
|
|
2900
|
+
group.appendChild(replaceBtn);
|
|
2901
|
+
}
|
|
2902
|
+
if (libraryHandler) {
|
|
2903
|
+
const libBtn = makeBtn(ICON_LIBRARY, t("fromLibrary", state), "fb-tile-action-library");
|
|
2904
|
+
libBtn.addEventListener("click", () => libraryHandler());
|
|
2905
|
+
group.appendChild(libBtn);
|
|
2906
|
+
}
|
|
2750
2907
|
if (canDownload(state, meta)) {
|
|
2751
2908
|
const dlBtn = makeBtn(ICON_DOWNLOAD, t("downloadFile", state), "fb-tile-action-download");
|
|
2752
2909
|
dlBtn.addEventListener("click", () => {
|
|
@@ -2932,8 +3089,7 @@ function attachClonedActionListeners(cloned, original) {
|
|
|
2932
3089
|
}
|
|
2933
3090
|
function renderLocalImagePreview(container, file, fileName, state) {
|
|
2934
3091
|
const img = document.createElement("img");
|
|
2935
|
-
img.
|
|
2936
|
-
img.style.background = "var(--fb-file-upload-bg-color,#f3f4f6)";
|
|
3092
|
+
img.style.cssText = "width:100%;height:100%;object-fit:contain;background:var(--fb-file-upload-bg-color,#f3f4f6);";
|
|
2937
3093
|
img.alt = fileName || t("previewAlt", state);
|
|
2938
3094
|
const reader = new FileReader();
|
|
2939
3095
|
reader.onload = (e) => {
|
|
@@ -2956,7 +3112,7 @@ function renderLocalVideoPreview(container, file, videoType, resourceId, state,
|
|
|
2956
3112
|
const newContainer = setupDragDropless(container);
|
|
2957
3113
|
newContainer.innerHTML = `
|
|
2958
3114
|
<div class="fb-video-preview-wrap">
|
|
2959
|
-
<video
|
|
3115
|
+
<video style="width:100%;height:100%;object-fit:contain;" controls preload="auto" muted src="${videoUrl}">
|
|
2960
3116
|
${escapeHtml(t("videoNotSupported", state))}
|
|
2961
3117
|
</video>
|
|
2962
3118
|
<div class="fb-video-btn-overlay">
|
|
@@ -3002,11 +3158,11 @@ function handleVideoDelete(container, resourceId, state, deps) {
|
|
|
3002
3158
|
container.onclick = deps.fileUploadHandler;
|
|
3003
3159
|
}
|
|
3004
3160
|
container.innerHTML = `
|
|
3005
|
-
<div
|
|
3006
|
-
<svg
|
|
3161
|
+
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--fb-text-secondary-color,#9ca3af);">
|
|
3162
|
+
<svg style="width:1.5rem;height:1.5rem;margin-bottom:0.5rem;" fill="currentColor" viewBox="0 0 24 24">
|
|
3007
3163
|
<path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/>
|
|
3008
3164
|
</svg>
|
|
3009
|
-
<div
|
|
3165
|
+
<div style="font-size:0.875rem;text-align:center;">${escapeHtml(t("clickDragText", state))}</div>
|
|
3010
3166
|
</div>
|
|
3011
3167
|
`;
|
|
3012
3168
|
if (deps == null ? void 0 : deps.setupDrop) {
|
|
@@ -3024,11 +3180,11 @@ function renderDeleteButton(container, resourceId, state) {
|
|
|
3024
3180
|
hiddenInput.value = "";
|
|
3025
3181
|
}
|
|
3026
3182
|
container.innerHTML = `
|
|
3027
|
-
<div
|
|
3028
|
-
<svg
|
|
3183
|
+
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--fb-text-secondary-color,#9ca3af);">
|
|
3184
|
+
<svg style="width:1.5rem;height:1.5rem;margin-bottom:0.5rem;" fill="currentColor" viewBox="0 0 24 24">
|
|
3029
3185
|
<path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/>
|
|
3030
3186
|
</svg>
|
|
3031
|
-
<div
|
|
3187
|
+
<div style="font-size:0.875rem;text-align:center;">${escapeHtml(t("clickDragText", state))}</div>
|
|
3032
3188
|
</div>
|
|
3033
3189
|
`;
|
|
3034
3190
|
});
|
|
@@ -3048,7 +3204,7 @@ async function renderLocalFilePreview(container, meta, fileName, resourceId, isR
|
|
|
3048
3204
|
deps
|
|
3049
3205
|
);
|
|
3050
3206
|
} else {
|
|
3051
|
-
container.innerHTML = `<div
|
|
3207
|
+
container.innerHTML = `<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--fb-text-secondary-color,#9ca3af);"><div style="font-size:36px;margin-bottom:0.5rem;">\u{1F4C1}</div><div style="font-size:0.875rem;">${escapeHtml(fileName)}</div></div>`;
|
|
3052
3208
|
}
|
|
3053
3209
|
if (!isReadonly && !((_c = meta.type) == null ? void 0 : _c.startsWith("video/"))) {
|
|
3054
3210
|
renderDeleteButton(container, resourceId, state);
|
|
@@ -3056,7 +3212,7 @@ async function renderLocalFilePreview(container, meta, fileName, resourceId, isR
|
|
|
3056
3212
|
}
|
|
3057
3213
|
function renderUploadedVideoPreview(container, thumbnailUrl, state) {
|
|
3058
3214
|
const video = document.createElement("video");
|
|
3059
|
-
video.
|
|
3215
|
+
video.style.cssText = "width:100%;height:100%;object-fit:contain;";
|
|
3060
3216
|
video.controls = true;
|
|
3061
3217
|
video.preload = "metadata";
|
|
3062
3218
|
video.muted = true;
|
|
@@ -3078,8 +3234,7 @@ async function renderUploadedFilePreview(container, resourceId, fileName, meta,
|
|
|
3078
3234
|
renderUploadedVideoPreview(container, thumbnailUrl, state);
|
|
3079
3235
|
} else {
|
|
3080
3236
|
const img = document.createElement("img");
|
|
3081
|
-
img.
|
|
3082
|
-
img.style.background = "var(--fb-file-upload-bg-color,#f3f4f6)";
|
|
3237
|
+
img.style.cssText = "width:100%;height:100%;object-fit:contain;background:var(--fb-file-upload-bg-color,#f3f4f6);";
|
|
3083
3238
|
img.alt = fileName || t("previewAlt", state);
|
|
3084
3239
|
img.src = thumbnailUrl;
|
|
3085
3240
|
container.appendChild(img);
|
|
@@ -3090,11 +3245,11 @@ async function renderUploadedFilePreview(container, resourceId, fileName, meta,
|
|
|
3090
3245
|
} catch (error) {
|
|
3091
3246
|
console.error("Failed to get thumbnail:", error);
|
|
3092
3247
|
container.innerHTML = `
|
|
3093
|
-
<div
|
|
3094
|
-
<svg
|
|
3248
|
+
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--fb-text-secondary-color,#9ca3af);">
|
|
3249
|
+
<svg style="width:1.5rem;height:1.5rem;margin-bottom:0.5rem;" fill="currentColor" viewBox="0 0 24 24">
|
|
3095
3250
|
<path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/>
|
|
3096
3251
|
</svg>
|
|
3097
|
-
<div
|
|
3252
|
+
<div style="font-size:0.875rem;text-align:center;">${escapeHtml(fileName || t("previewUnavailable", state))}</div>
|
|
3098
3253
|
</div>
|
|
3099
3254
|
`;
|
|
3100
3255
|
}
|
|
@@ -3267,20 +3422,15 @@ async function renderSingleFileEditTile(fileContainer, resourceId, state, deps)
|
|
|
3267
3422
|
fileContainer.appendChild(tile);
|
|
3268
3423
|
}
|
|
3269
3424
|
async function fillTileContent(tile, rid, meta, state, actionsEl) {
|
|
3270
|
-
var _a, _b
|
|
3425
|
+
var _a, _b;
|
|
3271
3426
|
if ((_a = meta == null ? void 0 : meta.type) == null ? void 0 : _a.startsWith("image/")) {
|
|
3272
3427
|
if (meta.file && meta.file instanceof File) {
|
|
3273
3428
|
const img = document.createElement("img");
|
|
3274
3429
|
img.style.cssText = "width:100%;height:100%;object-fit:contain;background:var(--fb-file-upload-bg-color,#f3f4f6);";
|
|
3275
3430
|
img.alt = meta.name;
|
|
3276
|
-
|
|
3277
|
-
reader.onload = (e) => {
|
|
3278
|
-
var _a2;
|
|
3279
|
-
img.src = ((_a2 = e.target) == null ? void 0 : _a2.result) || "";
|
|
3280
|
-
attachZoomHover(tile, img.src, meta.name, actionsEl != null ? actionsEl : null);
|
|
3281
|
-
};
|
|
3282
|
-
reader.readAsDataURL(meta.file);
|
|
3431
|
+
img.src = getLocalFileUrl(meta.file);
|
|
3283
3432
|
tile.appendChild(img);
|
|
3433
|
+
attachZoomHover(tile, img.src, meta.name, actionsEl != null ? actionsEl : null);
|
|
3284
3434
|
} else if (state.config.getThumbnail) {
|
|
3285
3435
|
try {
|
|
3286
3436
|
const url = await state.config.getThumbnail(rid);
|
|
@@ -3337,17 +3487,21 @@ async function fillTileContent(tile, rid, meta, state, actionsEl) {
|
|
|
3337
3487
|
}
|
|
3338
3488
|
if (actionsEl) tile.appendChild(actionsEl);
|
|
3339
3489
|
} else {
|
|
3340
|
-
|
|
3341
|
-
const hasExtension = name.includes(".");
|
|
3342
|
-
const captionHtml = hasExtension ? `<div class="fb-tile-label">${escapeHtml(name.length > 10 ? name.substring(0, 8) + "\u2026" : name)}</div>` : "";
|
|
3343
|
-
tile.innerHTML = `
|
|
3344
|
-
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:6px;gap:4px;">
|
|
3345
|
-
<div style="font-size:36px;">\u{1F4C1}</div>
|
|
3346
|
-
${captionHtml}
|
|
3347
|
-
</div>`;
|
|
3348
|
-
if (actionsEl) tile.appendChild(actionsEl);
|
|
3490
|
+
fillDocumentFallback(tile, rid, meta, actionsEl);
|
|
3349
3491
|
}
|
|
3350
3492
|
}
|
|
3493
|
+
function fillDocumentFallback(tile, rid, meta, actionsEl) {
|
|
3494
|
+
var _a, _b;
|
|
3495
|
+
const fileName = (_b = (_a = meta == null ? void 0 : meta.name) != null ? _a : rid.split("/").pop()) != null ? _b : "";
|
|
3496
|
+
if (fileName) tile.title = fileName;
|
|
3497
|
+
const labelHtml = fileName ? `<div style="font-size:11px;line-height:1.2;text-align:center;color:var(--fb-text-secondary-color,#6b7280);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">${escapeHtml(fileName)}</div>` : "";
|
|
3498
|
+
tile.innerHTML = `
|
|
3499
|
+
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;padding:6px;gap:4px;">
|
|
3500
|
+
<div style="font-size:36px;">\u{1F4C1}</div>
|
|
3501
|
+
${labelHtml}
|
|
3502
|
+
</div>`;
|
|
3503
|
+
if (actionsEl) tile.appendChild(actionsEl);
|
|
3504
|
+
}
|
|
3351
3505
|
async function forceDownload(resourceId, fileName, state) {
|
|
3352
3506
|
try {
|
|
3353
3507
|
let fileUrl = null;
|
|
@@ -3412,7 +3566,7 @@ async function uploadSingleFile(file, state) {
|
|
|
3412
3566
|
}
|
|
3413
3567
|
}
|
|
3414
3568
|
async function handleFileSelect(opts) {
|
|
3415
|
-
var _a, _b;
|
|
3569
|
+
var _a, _b, _c;
|
|
3416
3570
|
const {
|
|
3417
3571
|
file,
|
|
3418
3572
|
container,
|
|
@@ -3448,6 +3602,10 @@ async function handleFileSelect(opts) {
|
|
|
3448
3602
|
return;
|
|
3449
3603
|
}
|
|
3450
3604
|
clearFileError(container);
|
|
3605
|
+
const existingHiddenInput = (_a = container.parentElement) == null ? void 0 : _a.querySelector(
|
|
3606
|
+
'input[type="hidden"]'
|
|
3607
|
+
);
|
|
3608
|
+
const previousRid = (existingHiddenInput == null ? void 0 : existingHiddenInput.value) || null;
|
|
3451
3609
|
ensureFileStyles();
|
|
3452
3610
|
container.innerHTML = `
|
|
3453
3611
|
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:6px;padding:6px;">
|
|
@@ -3458,7 +3616,13 @@ async function handleFileSelect(opts) {
|
|
|
3458
3616
|
try {
|
|
3459
3617
|
rid = await uploadSingleFile(file, state);
|
|
3460
3618
|
} catch (error) {
|
|
3461
|
-
|
|
3619
|
+
if (previousRid && (deps == null ? void 0 : deps.onAfterUpload)) {
|
|
3620
|
+
deps.onAfterUpload(container, previousRid);
|
|
3621
|
+
} else if (deps == null ? void 0 : deps.onRemove) {
|
|
3622
|
+
deps.onRemove();
|
|
3623
|
+
} else {
|
|
3624
|
+
setEmptyFileContainer(container, state);
|
|
3625
|
+
}
|
|
3462
3626
|
throw error;
|
|
3463
3627
|
}
|
|
3464
3628
|
state.resourceIndex.set(rid, {
|
|
@@ -3468,18 +3632,21 @@ async function handleFileSelect(opts) {
|
|
|
3468
3632
|
uploadedAt: /* @__PURE__ */ new Date(),
|
|
3469
3633
|
file
|
|
3470
3634
|
});
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3635
|
+
if (previousRid && previousRid !== rid) {
|
|
3636
|
+
releaseLocalFileUrl((_b = state.resourceIndex.get(previousRid)) == null ? void 0 : _b.file);
|
|
3637
|
+
}
|
|
3638
|
+
let hiddenInput = existingHiddenInput;
|
|
3474
3639
|
if (!hiddenInput) {
|
|
3475
3640
|
hiddenInput = document.createElement("input");
|
|
3476
3641
|
hiddenInput.type = "hidden";
|
|
3477
3642
|
hiddenInput.name = fieldName;
|
|
3478
|
-
(
|
|
3643
|
+
(_c = container.parentElement) == null ? void 0 : _c.appendChild(hiddenInput);
|
|
3479
3644
|
}
|
|
3480
3645
|
hiddenInput.value = rid;
|
|
3481
3646
|
const isVideo = file.type.startsWith("video/");
|
|
3482
|
-
if (!isVideo && deps) {
|
|
3647
|
+
if (!isVideo && (deps == null ? void 0 : deps.onAfterUpload)) {
|
|
3648
|
+
deps.onAfterUpload(container, rid);
|
|
3649
|
+
} else if (!isVideo && deps) {
|
|
3483
3650
|
renderSingleFileEditTile(container, rid, state, deps).catch(console.error);
|
|
3484
3651
|
} else {
|
|
3485
3652
|
renderFilePreview(container, rid, state, {
|
|
@@ -3540,17 +3707,18 @@ function filterAndSlice(allFiles, currentCount, constraints, state) {
|
|
|
3540
3707
|
return { accepted, errorMessage: errorParts.join(" \u2022 ") };
|
|
3541
3708
|
}
|
|
3542
3709
|
async function uploadBatch(accepted, resourceIds, listEl, state) {
|
|
3710
|
+
var _a;
|
|
3711
|
+
if (listEl) {
|
|
3712
|
+
const tilesWrap = ensureTilesWrap(listEl);
|
|
3713
|
+
const addTile = (_a = tilesWrap.querySelector(".fb-multi-add-tile-js")) != null ? _a : tilesWrap.querySelector(".fb-tile-add");
|
|
3714
|
+
if (addTile) addTile.style.display = "none";
|
|
3715
|
+
}
|
|
3543
3716
|
await Promise.all(
|
|
3544
3717
|
accepted.map(async (file) => {
|
|
3545
3718
|
const placeholder = createUploadingTile(file.name, state);
|
|
3546
3719
|
if (listEl) {
|
|
3547
3720
|
const tilesWrap = ensureTilesWrap(listEl);
|
|
3548
|
-
|
|
3549
|
-
if (addTile) {
|
|
3550
|
-
tilesWrap.insertBefore(placeholder, addTile);
|
|
3551
|
-
} else {
|
|
3552
|
-
tilesWrap.appendChild(placeholder);
|
|
3553
|
-
}
|
|
3721
|
+
tilesWrap.appendChild(placeholder);
|
|
3554
3722
|
}
|
|
3555
3723
|
try {
|
|
3556
3724
|
const rid = await uploadSingleFile(file, state);
|
|
@@ -3593,7 +3761,7 @@ function setupFilesDropHandler(filesContainer, resourceIds, state, updateCallbac
|
|
|
3593
3761
|
function setupFilesPickerHandler(filesPicker, resourceIds, state, updateCallback, constraints, pathKey, instance) {
|
|
3594
3762
|
filesPicker.onchange = async () => {
|
|
3595
3763
|
if (!filesPicker.files) return;
|
|
3596
|
-
const wrapperEl = filesPicker.closest("
|
|
3764
|
+
const wrapperEl = filesPicker.closest("[data-files-wrapper]") || filesPicker.parentElement;
|
|
3597
3765
|
const { accepted, errorMessage } = filterAndSlice(
|
|
3598
3766
|
Array.from(filesPicker.files),
|
|
3599
3767
|
resourceIds.length,
|
|
@@ -3728,7 +3896,7 @@ async function handleLibraryPickMulti(state, element, wrapper, fieldPath, resour
|
|
|
3728
3896
|
}
|
|
3729
3897
|
}
|
|
3730
3898
|
async function handleLibraryPickSingle(state, element, container, fileWrapper, pathKey, fieldPath, renderCallback, instance) {
|
|
3731
|
-
var _a;
|
|
3899
|
+
var _a, _b;
|
|
3732
3900
|
if (!state.config.pickExistingFiles) return;
|
|
3733
3901
|
const allowedExtensions = getAllowedExtensions(element.accept);
|
|
3734
3902
|
const allowedMimes = getAllowedMimes(element.accept);
|
|
@@ -3762,66 +3930,286 @@ async function handleLibraryPickSingle(state, element, container, fileWrapper, p
|
|
|
3762
3930
|
hiddenInput.name = pathKey;
|
|
3763
3931
|
fileWrapper.appendChild(hiddenInput);
|
|
3764
3932
|
}
|
|
3933
|
+
const previousRid = hiddenInput.value || null;
|
|
3934
|
+
if (previousRid && previousRid !== first.resourceId) {
|
|
3935
|
+
releaseLocalFileUrl((_b = state.resourceIndex.get(previousRid)) == null ? void 0 : _b.file);
|
|
3936
|
+
}
|
|
3765
3937
|
hiddenInput.value = first.resourceId;
|
|
3766
3938
|
await renderCallback(first.resourceId);
|
|
3767
3939
|
if (!state.config.readonly) {
|
|
3768
3940
|
instance.triggerOnChange(fieldPath, first.resourceId);
|
|
3769
3941
|
}
|
|
3770
3942
|
}
|
|
3771
|
-
|
|
3772
|
-
// src/components/file/render-edit.ts
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3943
|
+
|
|
3944
|
+
// src/components/file/render-edit.ts
|
|
3945
|
+
var ICON_CLOUD = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 18a4 4 0 000-8 6 6 0 00-11.5 2A4 4 0 006 20h11M12 12v7M12 12l-3 3M12 12l3 3"/></svg>`;
|
|
3946
|
+
var ICON_LIBRARY2 = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 4h4v16H4z"/><path d="M10 4h4v16h-4z"/><path d="M16 5l3.5 1-3 14L13 19"/></svg>`;
|
|
3947
|
+
function handleInitialFileData(initial, fileContainer, pathKey, fileWrapper, state, deps, extras) {
|
|
3948
|
+
var _a;
|
|
3949
|
+
seedInferredResource(initial, state.resourceIndex);
|
|
3950
|
+
const meta = state.resourceIndex.get(initial);
|
|
3951
|
+
const isVideo = (_a = meta == null ? void 0 : meta.type) == null ? void 0 : _a.startsWith("video/");
|
|
3952
|
+
if (isVideo) {
|
|
3953
|
+
renderFilePreview(fileContainer, initial, state, {
|
|
3954
|
+
fileName: initial,
|
|
3955
|
+
isReadonly: false,
|
|
3956
|
+
deps
|
|
3957
|
+
}).catch(console.error);
|
|
3958
|
+
} else {
|
|
3959
|
+
renderSingleFileFilled(fileContainer, initial, state, deps, extras);
|
|
3960
|
+
}
|
|
3961
|
+
const hiddenInput = document.createElement("input");
|
|
3962
|
+
hiddenInput.type = "hidden";
|
|
3963
|
+
hiddenInput.name = pathKey;
|
|
3964
|
+
hiddenInput.value = initial;
|
|
3965
|
+
fileWrapper.appendChild(hiddenInput);
|
|
3966
|
+
}
|
|
3967
|
+
function buildWideTile(state, hasLibrary, onUploadClick, onLibraryClick, isDragOver = false, constraintHint = "") {
|
|
3968
|
+
ensureFileStyles();
|
|
3969
|
+
const outer = document.createElement("div");
|
|
3970
|
+
outer.className = `fb-wide-tile${hasLibrary ? " fb-file-card-row" : ""}${isDragOver ? " fb-drag-over" : ""}`;
|
|
3971
|
+
const uploadBtn = document.createElement("button");
|
|
3972
|
+
uploadBtn.type = "button";
|
|
3973
|
+
uploadBtn.className = "fb-wide-tile-upload fb-file-dropzone";
|
|
3974
|
+
const cloudIcon = document.createElement("span");
|
|
3975
|
+
cloudIcon.style.cssText = "width:36px;height:36px;display:block;flex-shrink:0;";
|
|
3976
|
+
cloudIcon.innerHTML = ICON_CLOUD;
|
|
3977
|
+
uploadBtn.appendChild(cloudIcon);
|
|
3978
|
+
const primaryText = document.createElement("div");
|
|
3979
|
+
primaryText.className = "fb-wide-tile-label";
|
|
3980
|
+
primaryText.style.cssText = "font-size:14px;font-weight:600;";
|
|
3981
|
+
primaryText.textContent = isDragOver ? t("dropToUpload", state) : t("clickDragText", state);
|
|
3982
|
+
uploadBtn.appendChild(primaryText);
|
|
3983
|
+
if (constraintHint) {
|
|
3984
|
+
const hintEl = document.createElement("div");
|
|
3985
|
+
hintEl.style.cssText = "font-size:11px;opacity:0.65;margin-top:2px;";
|
|
3986
|
+
hintEl.textContent = constraintHint;
|
|
3987
|
+
uploadBtn.appendChild(hintEl);
|
|
3988
|
+
}
|
|
3989
|
+
uploadBtn.onclick = (e) => {
|
|
3990
|
+
e.stopPropagation();
|
|
3991
|
+
onUploadClick();
|
|
3992
|
+
};
|
|
3993
|
+
outer.appendChild(uploadBtn);
|
|
3994
|
+
if (hasLibrary && onLibraryClick) {
|
|
3995
|
+
const divider = document.createElement("div");
|
|
3996
|
+
divider.className = "fb-wide-tile-divider";
|
|
3997
|
+
outer.appendChild(divider);
|
|
3998
|
+
const libBtn = document.createElement("button");
|
|
3999
|
+
libBtn.type = "button";
|
|
4000
|
+
libBtn.className = "fb-wide-tile-library fb-file-library-card";
|
|
4001
|
+
const libIcon = document.createElement("span");
|
|
4002
|
+
libIcon.style.cssText = "width:28px;height:28px;display:block;flex-shrink:0;";
|
|
4003
|
+
libIcon.innerHTML = ICON_LIBRARY2;
|
|
4004
|
+
libBtn.appendChild(libIcon);
|
|
4005
|
+
const libLabel = document.createElement("div");
|
|
4006
|
+
libLabel.style.cssText = "font-size:13px;font-weight:600;text-align:center;";
|
|
4007
|
+
libLabel.textContent = t("fromLibrary", state);
|
|
4008
|
+
libBtn.appendChild(libLabel);
|
|
4009
|
+
const libHint = document.createElement("div");
|
|
4010
|
+
libHint.style.cssText = "font-size:11px;opacity:0.75;text-align:center;";
|
|
4011
|
+
libHint.textContent = t("libraryHint", state);
|
|
4012
|
+
libBtn.appendChild(libHint);
|
|
4013
|
+
libBtn.onclick = (e) => {
|
|
4014
|
+
e.stopPropagation();
|
|
4015
|
+
onLibraryClick();
|
|
4016
|
+
};
|
|
4017
|
+
outer.appendChild(libBtn);
|
|
4018
|
+
}
|
|
4019
|
+
attachDragOverFeedback(outer, {
|
|
4020
|
+
onEnter: () => {
|
|
4021
|
+
const primaryText2 = outer.querySelector(".fb-wide-tile-label");
|
|
4022
|
+
if (primaryText2) primaryText2.textContent = t("dropToUpload", state);
|
|
4023
|
+
},
|
|
4024
|
+
onLeave: () => {
|
|
4025
|
+
const primaryText2 = outer.querySelector(".fb-wide-tile-label");
|
|
4026
|
+
if (primaryText2) primaryText2.textContent = t("clickDragText", state);
|
|
4027
|
+
},
|
|
4028
|
+
activeClass: "fb-drag-over"
|
|
4029
|
+
});
|
|
4030
|
+
return outer;
|
|
4031
|
+
}
|
|
4032
|
+
function attachDragOverFeedback(el, hooks) {
|
|
4033
|
+
let depth = 0;
|
|
4034
|
+
el.addEventListener("dragover", (e) => {
|
|
4035
|
+
e.preventDefault();
|
|
4036
|
+
});
|
|
4037
|
+
el.addEventListener("dragenter", (e) => {
|
|
4038
|
+
e.preventDefault();
|
|
4039
|
+
depth++;
|
|
4040
|
+
if (depth === 1) {
|
|
4041
|
+
el.classList.add(hooks.activeClass);
|
|
4042
|
+
hooks.onEnter();
|
|
4043
|
+
}
|
|
4044
|
+
});
|
|
4045
|
+
el.addEventListener("dragleave", (e) => {
|
|
4046
|
+
e.preventDefault();
|
|
4047
|
+
depth = Math.max(0, depth - 1);
|
|
4048
|
+
if (depth === 0) {
|
|
4049
|
+
el.classList.remove(hooks.activeClass);
|
|
4050
|
+
hooks.onLeave();
|
|
4051
|
+
}
|
|
4052
|
+
});
|
|
4053
|
+
el.addEventListener("drop", () => {
|
|
4054
|
+
depth = 0;
|
|
4055
|
+
el.classList.remove(hooks.activeClass);
|
|
4056
|
+
hooks.onLeave();
|
|
4057
|
+
});
|
|
4058
|
+
}
|
|
4059
|
+
function renderSingleFileFilled(fileContainer, resourceId, state, deps, extras) {
|
|
4060
|
+
var _a, _b;
|
|
4061
|
+
const meta = state.resourceIndex.get(resourceId);
|
|
3777
4062
|
const isVideo = (_a = meta == null ? void 0 : meta.type) == null ? void 0 : _a.startsWith("video/");
|
|
3778
4063
|
if (isVideo) {
|
|
3779
|
-
renderFilePreview(fileContainer,
|
|
3780
|
-
fileName:
|
|
4064
|
+
renderFilePreview(fileContainer, resourceId, state, {
|
|
4065
|
+
fileName: (_b = meta == null ? void 0 : meta.name) != null ? _b : "",
|
|
3781
4066
|
isReadonly: false,
|
|
3782
4067
|
deps
|
|
3783
4068
|
}).catch(console.error);
|
|
3784
|
-
|
|
3785
|
-
renderSingleFileEditTile(fileContainer, initial, state, deps).catch(console.error);
|
|
4069
|
+
return;
|
|
3786
4070
|
}
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
4071
|
+
ensureFileStyles();
|
|
4072
|
+
const outer = document.createElement("div");
|
|
4073
|
+
outer.className = "fb-multi-outer fb-multi-has-files";
|
|
4074
|
+
const grid = document.createElement("div");
|
|
4075
|
+
grid.className = "fb-multi-grid fb-tiles-wrap";
|
|
4076
|
+
outer.appendChild(grid);
|
|
4077
|
+
const tile = buildPreviewTile(
|
|
4078
|
+
resourceId,
|
|
4079
|
+
state,
|
|
4080
|
+
Boolean(deps.onRemove),
|
|
4081
|
+
deps.onRemove ? () => {
|
|
4082
|
+
var _a2;
|
|
4083
|
+
return (_a2 = deps.onRemove) == null ? void 0 : _a2.call(deps);
|
|
4084
|
+
} : null,
|
|
4085
|
+
extras
|
|
4086
|
+
);
|
|
4087
|
+
grid.appendChild(tile);
|
|
4088
|
+
fileContainer.className = "file-preview-container";
|
|
4089
|
+
fileContainer.removeAttribute("style");
|
|
4090
|
+
while (fileContainer.firstChild) fileContainer.removeChild(fileContainer.firstChild);
|
|
4091
|
+
fileContainer.appendChild(outer);
|
|
3792
4092
|
}
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
4093
|
+
function buildMultiAddTile(state, hasLibrary, onUploadClick, onLibraryClick, isDragOver = false) {
|
|
4094
|
+
const tile = document.createElement("div");
|
|
4095
|
+
tile.className = `fb-multi-add-tile fb-multi-add-tile-js${isDragOver ? " fb-drag-over-tile" : ""}`;
|
|
4096
|
+
const uploadBtn = document.createElement("button");
|
|
4097
|
+
uploadBtn.type = "button";
|
|
4098
|
+
uploadBtn.className = "fb-multi-add-upload fb-tile-add fb-file-dropzone";
|
|
4099
|
+
const cloudIcon = document.createElement("span");
|
|
4100
|
+
cloudIcon.style.cssText = "width:28px;height:28px;display:block;flex-shrink:0;";
|
|
4101
|
+
cloudIcon.innerHTML = ICON_CLOUD;
|
|
4102
|
+
uploadBtn.appendChild(cloudIcon);
|
|
4103
|
+
const uploadLabel = document.createElement("span");
|
|
4104
|
+
uploadLabel.className = "fb-multi-add-label";
|
|
4105
|
+
uploadLabel.style.cssText = "font-size:11px;font-weight:600;";
|
|
4106
|
+
uploadLabel.textContent = isDragOver ? t("dropToUpload", state) : t("clickDragTextMultiple", state);
|
|
4107
|
+
uploadBtn.appendChild(uploadLabel);
|
|
4108
|
+
uploadBtn.onclick = (e) => {
|
|
4109
|
+
e.stopPropagation();
|
|
4110
|
+
onUploadClick();
|
|
4111
|
+
};
|
|
4112
|
+
tile.appendChild(uploadBtn);
|
|
4113
|
+
if (hasLibrary && onLibraryClick) {
|
|
4114
|
+
const divider = document.createElement("div");
|
|
4115
|
+
divider.className = "fb-multi-add-divider";
|
|
4116
|
+
tile.appendChild(divider);
|
|
4117
|
+
const libBtn = document.createElement("button");
|
|
4118
|
+
libBtn.type = "button";
|
|
4119
|
+
libBtn.className = "fb-multi-add-library fb-tile-add-library fb-file-library-card";
|
|
4120
|
+
libBtn.setAttribute("aria-label", t("fromLibrary", state));
|
|
4121
|
+
const libIcon = document.createElement("span");
|
|
4122
|
+
libIcon.style.cssText = "width:14px;height:14px;display:block;flex-shrink:0;";
|
|
4123
|
+
libIcon.innerHTML = ICON_LIBRARY2;
|
|
4124
|
+
libBtn.appendChild(libIcon);
|
|
4125
|
+
libBtn.appendChild(document.createTextNode(t("fromLibrary", state)));
|
|
4126
|
+
libBtn.onclick = (e) => {
|
|
4127
|
+
e.stopPropagation();
|
|
4128
|
+
onLibraryClick();
|
|
4129
|
+
};
|
|
4130
|
+
tile.appendChild(libBtn);
|
|
4131
|
+
}
|
|
4132
|
+
return tile;
|
|
3806
4133
|
}
|
|
3807
|
-
function
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
4134
|
+
function buildPreviewTile(rid, state, canRemove, onRemove, extras) {
|
|
4135
|
+
var _a, _b, _c;
|
|
4136
|
+
ensureFileStyles();
|
|
4137
|
+
const meta = state.resourceIndex.get(rid);
|
|
4138
|
+
const tile = document.createElement("div");
|
|
4139
|
+
tile.className = "fb-preview-tile fb-checker fb-tile-resource resource-pill";
|
|
4140
|
+
tile.dataset.resourceId = rid;
|
|
4141
|
+
const actionsEl = createTileActions({
|
|
4142
|
+
canRemove: canRemove && onRemove !== null,
|
|
4143
|
+
removeHandler: onRemove,
|
|
4144
|
+
state,
|
|
4145
|
+
resourceId: rid,
|
|
4146
|
+
fileName: (_a = meta == null ? void 0 : meta.name) != null ? _a : "",
|
|
4147
|
+
meta,
|
|
4148
|
+
replaceHandler: (_b = extras == null ? void 0 : extras.replaceHandler) != null ? _b : null,
|
|
4149
|
+
libraryHandler: (_c = extras == null ? void 0 : extras.libraryHandler) != null ? _c : null
|
|
4150
|
+
});
|
|
4151
|
+
fillTileContent(tile, rid, meta, state, actionsEl).catch((err) => {
|
|
4152
|
+
console.error("Failed to render tile:", err);
|
|
4153
|
+
});
|
|
4154
|
+
return tile;
|
|
4155
|
+
}
|
|
4156
|
+
function buildPlaceholderTile(isDragOver = false) {
|
|
4157
|
+
const div = document.createElement("div");
|
|
4158
|
+
div.className = `fb-multi-placeholder fb-checker${isDragOver ? " fb-drag-over" : ""}`;
|
|
4159
|
+
return div;
|
|
4160
|
+
}
|
|
4161
|
+
function buildMetaLine(state, element, ridCount, maxCount, canClearAll, onClearAll) {
|
|
4162
|
+
const line = document.createElement("div");
|
|
4163
|
+
line.className = "fb-meta-line";
|
|
4164
|
+
const metaText = document.createElement("div");
|
|
4165
|
+
metaText.className = "fb-meta-text";
|
|
4166
|
+
if (element.maxSize && element.maxSize !== Infinity) {
|
|
4167
|
+
const sizeSpan = document.createElement("span");
|
|
4168
|
+
sizeSpan.textContent = t("hintMaxSize", state, { size: element.maxSize });
|
|
4169
|
+
metaText.appendChild(sizeSpan);
|
|
4170
|
+
metaText.appendChild(buildMetaDot());
|
|
4171
|
+
}
|
|
4172
|
+
const exts = getAllowedExtensions(element.accept);
|
|
4173
|
+
if (exts.length > 0) {
|
|
4174
|
+
const fmtSpan = document.createElement("span");
|
|
4175
|
+
fmtSpan.className = "fb-meta-mono";
|
|
4176
|
+
fmtSpan.textContent = exts.map((e) => e.toUpperCase()).join(", ");
|
|
4177
|
+
metaText.appendChild(fmtSpan);
|
|
4178
|
+
metaText.appendChild(buildMetaDot());
|
|
4179
|
+
}
|
|
4180
|
+
const countSpan = document.createElement("span");
|
|
4181
|
+
if (maxCount < Infinity) {
|
|
4182
|
+
countSpan.textContent = t("fileCountWithMax", state, {
|
|
4183
|
+
count: ridCount,
|
|
4184
|
+
max: maxCount
|
|
4185
|
+
});
|
|
3817
4186
|
} else {
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
4187
|
+
const countKey = ridCount === 1 ? "fileCountSingle" : "fileCountPlural";
|
|
4188
|
+
countSpan.textContent = t(countKey, state, { count: ridCount });
|
|
4189
|
+
}
|
|
4190
|
+
metaText.appendChild(countSpan);
|
|
4191
|
+
line.appendChild(metaText);
|
|
4192
|
+
if (canClearAll && ridCount > 1) {
|
|
4193
|
+
const clearBtn = document.createElement("button");
|
|
4194
|
+
clearBtn.type = "button";
|
|
4195
|
+
clearBtn.className = "fb-clear-all-btn";
|
|
4196
|
+
clearBtn.textContent = t("clearAll", state);
|
|
4197
|
+
clearBtn.onclick = (e) => {
|
|
4198
|
+
e.stopPropagation();
|
|
4199
|
+
if (window.confirm(t("clearAll", state) + "?")) {
|
|
4200
|
+
onClearAll();
|
|
4201
|
+
}
|
|
4202
|
+
};
|
|
4203
|
+
line.appendChild(clearBtn);
|
|
3821
4204
|
}
|
|
3822
|
-
|
|
3823
|
-
return btn;
|
|
4205
|
+
return line;
|
|
3824
4206
|
}
|
|
4207
|
+
function buildMetaDot() {
|
|
4208
|
+
const dot = document.createElement("span");
|
|
4209
|
+
dot.className = "fb-meta-dot";
|
|
4210
|
+
return dot;
|
|
4211
|
+
}
|
|
4212
|
+
var gridResizeObservers = /* @__PURE__ */ new WeakMap();
|
|
3825
4213
|
function renderResourcePills(opts) {
|
|
3826
4214
|
var _a;
|
|
3827
4215
|
const {
|
|
@@ -3829,130 +4217,185 @@ function renderResourcePills(opts) {
|
|
|
3829
4217
|
rids,
|
|
3830
4218
|
state,
|
|
3831
4219
|
onRemove,
|
|
3832
|
-
hint,
|
|
3833
|
-
countInfo,
|
|
3834
4220
|
maxCount,
|
|
3835
4221
|
isReadonly = false,
|
|
3836
|
-
onLibraryPick
|
|
4222
|
+
onLibraryPick,
|
|
4223
|
+
element,
|
|
4224
|
+
onClearAll,
|
|
4225
|
+
openPicker: openPickerProp
|
|
3837
4226
|
} = opts;
|
|
3838
4227
|
ensureFileStyles();
|
|
3839
4228
|
const wrapper = container.closest("[data-files-wrapper]");
|
|
3840
4229
|
if (wrapper) {
|
|
3841
4230
|
wrapper.dataset.resourceIds = JSON.stringify(rids != null ? rids : []);
|
|
3842
4231
|
}
|
|
4232
|
+
const previousObserver = gridResizeObservers.get(container);
|
|
4233
|
+
if (previousObserver) {
|
|
4234
|
+
previousObserver.disconnect();
|
|
4235
|
+
gridResizeObservers.delete(container);
|
|
4236
|
+
}
|
|
3843
4237
|
while (container.firstChild) container.removeChild(container.firstChild);
|
|
3844
4238
|
const ridList = rids != null ? rids : [];
|
|
3845
|
-
const
|
|
4239
|
+
const effectiveMax = maxCount != null ? maxCount : Infinity;
|
|
4240
|
+
const atMax = effectiveMax !== Infinity && ridList.length >= effectiveMax;
|
|
3846
4241
|
const hasLibrary = !isReadonly && typeof onLibraryPick === "function";
|
|
3847
|
-
const
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
if (
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
const picker = findFilePicker(container);
|
|
3855
|
-
if (picker) picker.click();
|
|
3856
|
-
};
|
|
3857
|
-
if (ridList.length === 0) {
|
|
3858
|
-
if (isReadonly) {
|
|
4242
|
+
const openPicker = openPickerProp != null ? openPickerProp : (() => {
|
|
4243
|
+
var _a2;
|
|
4244
|
+
const pickerEl = (_a2 = container.closest("[data-files-wrapper]")) == null ? void 0 : _a2.querySelector('input[type="file"]');
|
|
4245
|
+
if (pickerEl) pickerEl.click();
|
|
4246
|
+
});
|
|
4247
|
+
if (isReadonly) {
|
|
4248
|
+
if (ridList.length === 0) {
|
|
3859
4249
|
const emptyEl = document.createElement("div");
|
|
3860
4250
|
emptyEl.className = "fb-tile-empty-text";
|
|
3861
4251
|
emptyEl.textContent = t("noFilesSelected", state);
|
|
3862
4252
|
container.appendChild(emptyEl);
|
|
3863
|
-
} else if (hasLibrary) {
|
|
3864
|
-
const row = document.createElement("div");
|
|
3865
|
-
row.className = "fb-file-card-row";
|
|
3866
|
-
const dropzone = buildEmptyDropzone(
|
|
3867
|
-
state,
|
|
3868
|
-
t("clickDragTextMultiple", state),
|
|
3869
|
-
buildSubHint(),
|
|
3870
|
-
openPicker
|
|
3871
|
-
);
|
|
3872
|
-
const libraryBtn = buildLibraryButton("card", state, onLibraryPick);
|
|
3873
|
-
row.appendChild(dropzone);
|
|
3874
|
-
row.appendChild(libraryBtn);
|
|
3875
|
-
container.appendChild(row);
|
|
3876
4253
|
} else {
|
|
3877
|
-
const
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
4254
|
+
const grid2 = document.createElement("div");
|
|
4255
|
+
grid2.className = "fb-multi-readonly-grid";
|
|
4256
|
+
container.appendChild(grid2);
|
|
4257
|
+
for (const rid of ridList) {
|
|
4258
|
+
const meta = state.resourceIndex.get(rid);
|
|
4259
|
+
const tile = document.createElement("div");
|
|
4260
|
+
tile.className = "fb-readonly-tile fb-checker fb-tile fb-tile-resource";
|
|
4261
|
+
tile.dataset.resourceId = rid;
|
|
4262
|
+
const actionsEl = createTileActions({
|
|
4263
|
+
canRemove: false,
|
|
4264
|
+
removeHandler: null,
|
|
4265
|
+
state,
|
|
4266
|
+
resourceId: rid,
|
|
4267
|
+
fileName: (_a = meta == null ? void 0 : meta.name) != null ? _a : "",
|
|
4268
|
+
meta
|
|
4269
|
+
});
|
|
4270
|
+
fillTileContent(tile, rid, meta, state, actionsEl).catch(console.error);
|
|
4271
|
+
tile.onclick = async () => {
|
|
4272
|
+
var _a2;
|
|
4273
|
+
let url = null;
|
|
4274
|
+
if (state.config.getDownloadUrl) {
|
|
4275
|
+
url = state.config.getDownloadUrl(rid);
|
|
4276
|
+
} else if (state.config.getThumbnail) {
|
|
4277
|
+
url = await state.config.getThumbnail(rid);
|
|
4278
|
+
} else if ((meta == null ? void 0 : meta.file) instanceof File) {
|
|
4279
|
+
url = URL.createObjectURL(meta.file);
|
|
4280
|
+
}
|
|
4281
|
+
if (url) {
|
|
4282
|
+
window.open(url, "_blank");
|
|
4283
|
+
} else if (state.config.downloadFile) {
|
|
4284
|
+
state.config.downloadFile(rid, (_a2 = meta == null ? void 0 : meta.name) != null ? _a2 : "");
|
|
4285
|
+
}
|
|
4286
|
+
};
|
|
4287
|
+
grid2.appendChild(tile);
|
|
4288
|
+
}
|
|
3884
4289
|
}
|
|
3885
4290
|
return;
|
|
3886
4291
|
}
|
|
3887
|
-
const
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
const
|
|
3896
|
-
|
|
3897
|
-
removeHandler: onRemove ? () => onRemove(rid) : null,
|
|
4292
|
+
const outerDiv = document.createElement("div");
|
|
4293
|
+
outerDiv.className = `fb-multi-outer${ridList.length > 0 ? " fb-multi-has-files" : ""}`;
|
|
4294
|
+
const grid = document.createElement("div");
|
|
4295
|
+
grid.className = "fb-multi-grid fb-tiles-wrap";
|
|
4296
|
+
outerDiv.appendChild(grid);
|
|
4297
|
+
container.appendChild(outerDiv);
|
|
4298
|
+
for (let i = 0; i < ridList.length; i++) {
|
|
4299
|
+
const rid = ridList[i];
|
|
4300
|
+
const tile = buildPreviewTile(
|
|
4301
|
+
rid,
|
|
3898
4302
|
state,
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
console.error("Failed to render tile:", err);
|
|
3904
|
-
});
|
|
3905
|
-
tilesWrap.appendChild(tile);
|
|
3906
|
-
}
|
|
3907
|
-
if (!isReadonly && !atMax) {
|
|
3908
|
-
const addTile = document.createElement("div");
|
|
3909
|
-
addTile.className = "fb-tile fb-tile-add";
|
|
3910
|
-
addTile.innerHTML = "+";
|
|
3911
|
-
addTile.onclick = openPicker;
|
|
3912
|
-
tilesWrap.appendChild(addTile);
|
|
3913
|
-
if (hasLibrary) {
|
|
3914
|
-
const libraryTile = buildLibraryButton("tile", state, onLibraryPick);
|
|
3915
|
-
tilesWrap.appendChild(libraryTile);
|
|
3916
|
-
}
|
|
3917
|
-
} else if (!isReadonly && atMax) {
|
|
3918
|
-
const chip = document.createElement("div");
|
|
3919
|
-
chip.className = "fb-tile-counter";
|
|
3920
|
-
chip.textContent = t("filesCounter", state, {
|
|
3921
|
-
count: ridList.length,
|
|
3922
|
-
max: maxCount
|
|
3923
|
-
});
|
|
3924
|
-
tilesWrap.appendChild(chip);
|
|
4303
|
+
onRemove !== null,
|
|
4304
|
+
onRemove ? () => onRemove(rid) : null
|
|
4305
|
+
);
|
|
4306
|
+
grid.appendChild(tile);
|
|
3925
4307
|
}
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
4308
|
+
if (!atMax) {
|
|
4309
|
+
const addTile = buildMultiAddTile(
|
|
4310
|
+
state,
|
|
4311
|
+
hasLibrary,
|
|
4312
|
+
openPicker,
|
|
4313
|
+
onLibraryPick != null ? onLibraryPick : null
|
|
4314
|
+
);
|
|
4315
|
+
grid.appendChild(addTile);
|
|
4316
|
+
}
|
|
4317
|
+
const occupied = ridList.length + (atMax ? 0 : 1);
|
|
4318
|
+
const adjustPlaceholders = () => {
|
|
4319
|
+
const tpl = getComputedStyle(grid).gridTemplateColumns;
|
|
4320
|
+
const cols = tpl ? tpl.split(" ").filter(Boolean).length : 0;
|
|
4321
|
+
if (!cols) return;
|
|
4322
|
+
const remainder = occupied % cols;
|
|
4323
|
+
const rowFill = remainder === 0 ? 0 : cols - remainder;
|
|
4324
|
+
const capacityRemaining = effectiveMax === Infinity ? rowFill : Math.max(0, effectiveMax - occupied);
|
|
4325
|
+
const needed = Math.min(rowFill, capacityRemaining);
|
|
4326
|
+
const existing = grid.querySelectorAll(".fb-multi-placeholder");
|
|
4327
|
+
if (existing.length > needed) {
|
|
4328
|
+
for (let i = existing.length - 1; i >= needed; i--) existing[i].remove();
|
|
4329
|
+
} else if (existing.length < needed) {
|
|
4330
|
+
for (let i = existing.length; i < needed; i++) {
|
|
4331
|
+
grid.appendChild(buildPlaceholderTile());
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4334
|
+
};
|
|
4335
|
+
if (effectiveMax === Infinity || effectiveMax > occupied) {
|
|
4336
|
+
grid.appendChild(buildPlaceholderTile());
|
|
4337
|
+
}
|
|
4338
|
+
requestAnimationFrame(adjustPlaceholders);
|
|
4339
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
4340
|
+
const ro = new ResizeObserver(() => adjustPlaceholders());
|
|
4341
|
+
ro.observe(grid);
|
|
4342
|
+
gridResizeObservers.set(container, ro);
|
|
4343
|
+
}
|
|
4344
|
+
attachDragOverFeedback(outerDiv, {
|
|
4345
|
+
activeClass: "fb-drag-over",
|
|
4346
|
+
onEnter: () => {
|
|
4347
|
+
grid.querySelectorAll(".fb-multi-placeholder").forEach((p) => {
|
|
4348
|
+
p.classList.add("fb-drag-over");
|
|
4349
|
+
});
|
|
4350
|
+
const addTile = grid.querySelector(".fb-multi-add-tile-js");
|
|
4351
|
+
if (addTile) {
|
|
4352
|
+
addTile.classList.add("fb-drag-over-tile");
|
|
4353
|
+
const label = addTile.querySelector(".fb-multi-add-label");
|
|
4354
|
+
if (label) label.textContent = t("dropToUpload", state);
|
|
4355
|
+
}
|
|
4356
|
+
},
|
|
4357
|
+
onLeave: () => {
|
|
4358
|
+
grid.querySelectorAll(".fb-multi-placeholder").forEach((p) => {
|
|
4359
|
+
p.classList.remove("fb-drag-over");
|
|
4360
|
+
});
|
|
4361
|
+
const addTile = grid.querySelector(".fb-multi-add-tile-js");
|
|
4362
|
+
if (addTile) {
|
|
4363
|
+
addTile.classList.remove("fb-drag-over-tile");
|
|
4364
|
+
const label = addTile.querySelector(".fb-multi-add-label");
|
|
4365
|
+
if (label) label.textContent = t("clickDragTextMultiple", state);
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
});
|
|
4369
|
+
if (element) {
|
|
4370
|
+
const metaLine = buildMetaLine(
|
|
4371
|
+
state,
|
|
4372
|
+
element,
|
|
4373
|
+
ridList.length,
|
|
4374
|
+
effectiveMax,
|
|
4375
|
+
Boolean(onClearAll),
|
|
4376
|
+
onClearAll != null ? onClearAll : (() => {
|
|
4377
|
+
})
|
|
4378
|
+
);
|
|
4379
|
+
container.appendChild(metaLine);
|
|
3933
4380
|
}
|
|
3934
4381
|
}
|
|
3935
4382
|
function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
3936
|
-
var _a, _b
|
|
4383
|
+
var _a, _b;
|
|
3937
4384
|
const state = ctx.state;
|
|
3938
4385
|
const fileWrapper = document.createElement("div");
|
|
3939
4386
|
fileWrapper.className = "space-y-2";
|
|
4387
|
+
fileWrapper.dataset.filesWrapper = pathKey;
|
|
3940
4388
|
const picker = document.createElement("input");
|
|
3941
4389
|
picker.type = "file";
|
|
3942
4390
|
picker.name = pathKey;
|
|
3943
4391
|
picker.style.display = "none";
|
|
3944
|
-
|
|
3945
|
-
picker.accept = typeof element.accept === "string" ? element.accept : [
|
|
3946
|
-
...(_b = (_a = element.accept.extensions) == null ? void 0 : _a.map((ext) => `.${ext}`)) != null ? _b : [],
|
|
3947
|
-
...(_c = element.accept.mime) != null ? _c : []
|
|
3948
|
-
].join(",") || "";
|
|
3949
|
-
}
|
|
4392
|
+
picker.accept = buildAcceptAttribute(element.accept);
|
|
3950
4393
|
const fileContainer = document.createElement("div");
|
|
3951
4394
|
fileContainer.className = "file-preview-container";
|
|
3952
4395
|
const initial = ctx.prefill[element.key];
|
|
3953
4396
|
const allowedExts = getAllowedExtensions(element.accept);
|
|
3954
4397
|
const allowedMimes = getAllowedMimes(element.accept);
|
|
3955
|
-
const maxSizeMB = (
|
|
4398
|
+
const maxSizeMB = (_a = element.maxSize) != null ? _a : Infinity;
|
|
3956
4399
|
const handlers = {
|
|
3957
4400
|
fileUploadHandler() {
|
|
3958
4401
|
picker.click();
|
|
@@ -3975,14 +4418,6 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
3975
4418
|
setupDrop(container) {
|
|
3976
4419
|
setupDragAndDrop(container, handlers.dragHandler);
|
|
3977
4420
|
},
|
|
3978
|
-
restoreDropzone() {
|
|
3979
|
-
const hint = makeFieldHint(element, state);
|
|
3980
|
-
fileContainer.className = "file-preview-container w-full max-w-md bg-gray-100 rounded-lg overflow-hidden relative group cursor-pointer";
|
|
3981
|
-
fileContainer.style.height = "128px";
|
|
3982
|
-
setEmptyFileContainer(fileContainer, state, hint);
|
|
3983
|
-
fileContainer.onclick = handlers.fileUploadHandler;
|
|
3984
|
-
setupDragAndDrop(fileContainer, handlers.dragHandler);
|
|
3985
|
-
},
|
|
3986
4421
|
onRemove() {
|
|
3987
4422
|
var _a2;
|
|
3988
4423
|
const hiddenInput = fileWrapper.querySelector('input[type="hidden"]');
|
|
@@ -3994,34 +4429,11 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
3994
4429
|
renderEmptySingleState();
|
|
3995
4430
|
}
|
|
3996
4431
|
};
|
|
3997
|
-
const
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
onRemove: handlers.onRemove
|
|
4003
|
-
});
|
|
4004
|
-
const renderEmptySingleState = () => {
|
|
4005
|
-
if (state.config.pickExistingFiles && !element.disableLibrary) {
|
|
4006
|
-
fileContainer.className = "file-preview-container";
|
|
4007
|
-
fileContainer.removeAttribute("style");
|
|
4008
|
-
fileContainer.onclick = null;
|
|
4009
|
-
while (fileContainer.firstChild) {
|
|
4010
|
-
fileContainer.removeChild(fileContainer.firstChild);
|
|
4011
|
-
}
|
|
4012
|
-
const row = document.createElement("div");
|
|
4013
|
-
row.className = "fb-file-card-row";
|
|
4014
|
-
row.style.cssText = "display:flex;gap:8px;align-items:stretch;";
|
|
4015
|
-
const hint = makeFieldHint(element, state);
|
|
4016
|
-
const uploadCard = buildEmptyDropzone(
|
|
4017
|
-
state,
|
|
4018
|
-
t("clickDragText", state),
|
|
4019
|
-
hint,
|
|
4020
|
-
handlers.fileUploadHandler
|
|
4021
|
-
);
|
|
4022
|
-
uploadCard.style.cssText = "flex:1;min-width:0;height:128px;";
|
|
4023
|
-
setupDragAndDrop(uploadCard, handlers.dragHandler);
|
|
4024
|
-
const libraryBtn = buildLibraryButton("card", state, () => {
|
|
4432
|
+
const buildSingleExtras = () => {
|
|
4433
|
+
const hasLibrary = Boolean(state.config.pickExistingFiles && !element.disableLibrary);
|
|
4434
|
+
return {
|
|
4435
|
+
replaceHandler: state.config.uploadFile ? () => picker.click() : null,
|
|
4436
|
+
libraryHandler: hasLibrary ? () => {
|
|
4025
4437
|
handleLibraryPickSingle(
|
|
4026
4438
|
state,
|
|
4027
4439
|
element,
|
|
@@ -4030,20 +4442,41 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4030
4442
|
pathKey,
|
|
4031
4443
|
pathKey,
|
|
4032
4444
|
async (rid) => {
|
|
4033
|
-
|
|
4445
|
+
renderSingleFileFilled(fileContainer, rid, state, buildDeps(), buildSingleExtras());
|
|
4034
4446
|
},
|
|
4035
4447
|
ctx.instance
|
|
4036
4448
|
).catch((err) => {
|
|
4037
4449
|
console.error("Library pick failed:", err);
|
|
4038
4450
|
});
|
|
4039
|
-
}
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4451
|
+
} : null
|
|
4452
|
+
};
|
|
4453
|
+
};
|
|
4454
|
+
const buildDeps = () => ({
|
|
4455
|
+
picker,
|
|
4456
|
+
fileUploadHandler: handlers.fileUploadHandler,
|
|
4457
|
+
dragHandler: handlers.dragHandler,
|
|
4458
|
+
setupDrop: handlers.setupDrop,
|
|
4459
|
+
onRemove: handlers.onRemove,
|
|
4460
|
+
onAfterUpload: (container, rid) => {
|
|
4461
|
+
renderSingleFileFilled(container, rid, state, buildDeps(), buildSingleExtras());
|
|
4046
4462
|
}
|
|
4463
|
+
});
|
|
4464
|
+
const renderEmptySingleState = () => {
|
|
4465
|
+
ensureFileStyles();
|
|
4466
|
+
fileContainer.className = "file-preview-container";
|
|
4467
|
+
fileContainer.removeAttribute("style");
|
|
4468
|
+
while (fileContainer.firstChild) fileContainer.removeChild(fileContainer.firstChild);
|
|
4469
|
+
const onLibraryClick = buildSingleExtras().libraryHandler;
|
|
4470
|
+
const wideTile = buildWideTile(
|
|
4471
|
+
state,
|
|
4472
|
+
onLibraryClick !== null,
|
|
4473
|
+
handlers.fileUploadHandler,
|
|
4474
|
+
onLibraryClick,
|
|
4475
|
+
false,
|
|
4476
|
+
makeFieldHint(element, state)
|
|
4477
|
+
);
|
|
4478
|
+
fileContainer.appendChild(wideTile);
|
|
4479
|
+
setupDragAndDrop(fileContainer, handlers.dragHandler);
|
|
4047
4480
|
};
|
|
4048
4481
|
if (initial) {
|
|
4049
4482
|
handleInitialFileData(
|
|
@@ -4052,11 +4485,11 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4052
4485
|
pathKey,
|
|
4053
4486
|
fileWrapper,
|
|
4054
4487
|
state,
|
|
4055
|
-
buildDeps()
|
|
4488
|
+
buildDeps(),
|
|
4489
|
+
buildSingleExtras()
|
|
4056
4490
|
);
|
|
4057
4491
|
const prefillMeta = state.resourceIndex.get(initial);
|
|
4058
|
-
if ((
|
|
4059
|
-
fileContainer.onclick = handlers.fileUploadHandler;
|
|
4492
|
+
if ((_b = prefillMeta == null ? void 0 : prefillMeta.type) == null ? void 0 : _b.startsWith("video/")) {
|
|
4060
4493
|
setupDragAndDrop(fileContainer, handlers.dragHandler);
|
|
4061
4494
|
}
|
|
4062
4495
|
} else {
|
|
@@ -4064,116 +4497,25 @@ function renderFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4064
4497
|
}
|
|
4065
4498
|
picker.onchange = () => {
|
|
4066
4499
|
if (picker.files && picker.files.length > 0) {
|
|
4067
|
-
|
|
4068
|
-
file: picker.files[0],
|
|
4069
|
-
container: fileContainer,
|
|
4070
|
-
fieldName: pathKey,
|
|
4071
|
-
state,
|
|
4072
|
-
deps: buildDeps(),
|
|
4073
|
-
instance: ctx.instance,
|
|
4074
|
-
allowedExtensions: allowedExts,
|
|
4075
|
-
allowedMimes,
|
|
4076
|
-
maxSizeMB
|
|
4077
|
-
});
|
|
4500
|
+
handlers.dragHandler(picker.files);
|
|
4078
4501
|
}
|
|
4079
4502
|
};
|
|
4080
4503
|
fileWrapper.appendChild(fileContainer);
|
|
4081
4504
|
fileWrapper.appendChild(picker);
|
|
4082
4505
|
wrapper.appendChild(fileWrapper);
|
|
4083
4506
|
}
|
|
4084
|
-
function
|
|
4085
|
-
var _a, _b, _c
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
if (element.accept) {
|
|
4096
|
-
filesPicker.accept = typeof element.accept === "string" ? element.accept : [
|
|
4097
|
-
...(_b = (_a = element.accept.extensions) == null ? void 0 : _a.map((ext) => `.${ext}`)) != null ? _b : [],
|
|
4098
|
-
...(_c = element.accept.mime) != null ? _c : []
|
|
4099
|
-
].join(",") || "";
|
|
4100
|
-
}
|
|
4101
|
-
const filesContainer = document.createElement("div");
|
|
4102
|
-
filesContainer.className = "files-list-wrapper";
|
|
4103
|
-
filesContainer.style.cssText = "border:2px dashed var(--fb-file-upload-border-color,#d1d5db);border-radius:var(--fb-border-radius,0.5rem);padding:8px;transition:border-color var(--fb-transition-duration,200ms),background var(--fb-transition-duration,200ms);";
|
|
4104
|
-
const list = document.createElement("div");
|
|
4105
|
-
list.className = "files-list";
|
|
4106
|
-
const initialFiles = ctx.prefill[element.key] || [];
|
|
4107
|
-
addPrefillFilesToIndex(initialFiles, state.resourceIndex);
|
|
4108
|
-
filesWrapper.dataset.resourceIds = JSON.stringify(initialFiles);
|
|
4109
|
-
const filesFieldHint = makeFieldHint(element, state);
|
|
4110
|
-
const filesConstraints = {
|
|
4111
|
-
maxCount: Infinity,
|
|
4112
|
-
allowedExtensions: getAllowedExtensions(element.accept),
|
|
4113
|
-
allowedMimes: getAllowedMimes(element.accept),
|
|
4114
|
-
maxSize: (_d = element.maxSize) != null ? _d : Infinity
|
|
4115
|
-
};
|
|
4116
|
-
filesContainer.appendChild(list);
|
|
4117
|
-
filesWrapper.appendChild(filesPicker);
|
|
4118
|
-
filesWrapper.appendChild(filesContainer);
|
|
4119
|
-
wrapper.appendChild(filesWrapper);
|
|
4120
|
-
const onLibraryPickFiles = state.config.pickExistingFiles && !element.disableLibrary ? () => {
|
|
4121
|
-
handleLibraryPickMulti(
|
|
4122
|
-
state,
|
|
4123
|
-
element,
|
|
4124
|
-
filesWrapper,
|
|
4125
|
-
pathKey,
|
|
4126
|
-
initialFiles,
|
|
4127
|
-
Infinity,
|
|
4128
|
-
updateFilesList,
|
|
4129
|
-
ctx.instance
|
|
4130
|
-
).catch((err) => {
|
|
4131
|
-
console.error("Library pick failed:", err);
|
|
4132
|
-
});
|
|
4133
|
-
} : null;
|
|
4134
|
-
function updateFilesList() {
|
|
4135
|
-
const currentlyReadonly = isElementReadonly(element, state);
|
|
4136
|
-
renderResourcePills({
|
|
4137
|
-
container: list,
|
|
4138
|
-
rids: initialFiles,
|
|
4139
|
-
state,
|
|
4140
|
-
onRemove: currentlyReadonly ? null : (ridToRemove) => {
|
|
4141
|
-
var _a2;
|
|
4142
|
-
releaseLocalFileUrl((_a2 = state.resourceIndex.get(ridToRemove)) == null ? void 0 : _a2.file);
|
|
4143
|
-
const index = initialFiles.indexOf(ridToRemove);
|
|
4144
|
-
if (index > -1) initialFiles.splice(index, 1);
|
|
4145
|
-
updateFilesList();
|
|
4146
|
-
},
|
|
4147
|
-
hint: filesFieldHint,
|
|
4148
|
-
isReadonly: currentlyReadonly,
|
|
4149
|
-
onLibraryPick: currentlyReadonly ? null : onLibraryPickFiles
|
|
4150
|
-
});
|
|
4151
|
-
}
|
|
4152
|
-
updateFilesList();
|
|
4153
|
-
setupFilesDropHandler(
|
|
4154
|
-
filesContainer,
|
|
4155
|
-
initialFiles,
|
|
4156
|
-
state,
|
|
4157
|
-
updateFilesList,
|
|
4158
|
-
filesConstraints,
|
|
4159
|
-
pathKey,
|
|
4160
|
-
ctx.instance
|
|
4161
|
-
);
|
|
4162
|
-
setupFilesPickerHandler(
|
|
4163
|
-
filesPicker,
|
|
4164
|
-
initialFiles,
|
|
4165
|
-
state,
|
|
4166
|
-
updateFilesList,
|
|
4167
|
-
filesConstraints,
|
|
4168
|
-
pathKey,
|
|
4169
|
-
ctx.instance
|
|
4170
|
-
);
|
|
4171
|
-
}
|
|
4172
|
-
function renderMultipleFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
4173
|
-
var _a, _b, _c, _d, _e, _f;
|
|
4507
|
+
function buildAcceptAttribute(accept) {
|
|
4508
|
+
var _a, _b, _c;
|
|
4509
|
+
if (!accept) return "";
|
|
4510
|
+
if (typeof accept === "string") return accept;
|
|
4511
|
+
return [
|
|
4512
|
+
...(_b = (_a = accept.extensions) == null ? void 0 : _a.map((ext) => `.${ext}`)) != null ? _b : [],
|
|
4513
|
+
...(_c = accept.mime) != null ? _c : []
|
|
4514
|
+
].join(",");
|
|
4515
|
+
}
|
|
4516
|
+
function setupMultiFileEditMode(element, ctx, wrapper, pathKey, maxFiles) {
|
|
4517
|
+
var _a, _b;
|
|
4174
4518
|
const state = ctx.state;
|
|
4175
|
-
const minFiles = (_a = element.minCount) != null ? _a : 0;
|
|
4176
|
-
const maxFiles = (_b = element.maxCount) != null ? _b : Infinity;
|
|
4177
4519
|
const filesWrapper = document.createElement("div");
|
|
4178
4520
|
filesWrapper.className = "space-y-2";
|
|
4179
4521
|
filesWrapper.dataset.filesWrapper = pathKey;
|
|
@@ -4182,15 +4524,9 @@ function renderMultipleFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4182
4524
|
filesPicker.name = pathKey;
|
|
4183
4525
|
filesPicker.multiple = true;
|
|
4184
4526
|
filesPicker.style.display = "none";
|
|
4185
|
-
|
|
4186
|
-
filesPicker.accept = typeof element.accept === "string" ? element.accept : [
|
|
4187
|
-
...(_d = (_c = element.accept.extensions) == null ? void 0 : _c.map((ext) => `.${ext}`)) != null ? _d : [],
|
|
4188
|
-
...(_e = element.accept.mime) != null ? _e : []
|
|
4189
|
-
].join(",") || "";
|
|
4190
|
-
}
|
|
4527
|
+
filesPicker.accept = buildAcceptAttribute(element.accept);
|
|
4191
4528
|
const filesContainer = document.createElement("div");
|
|
4192
4529
|
filesContainer.className = "files-list-wrapper";
|
|
4193
|
-
filesContainer.style.cssText = "border:2px dashed var(--fb-file-upload-border-color,#d1d5db);border-radius:var(--fb-border-radius,0.5rem);padding:8px;transition:border-color var(--fb-transition-duration,200ms),background var(--fb-transition-duration,200ms);";
|
|
4194
4530
|
const list = document.createElement("div");
|
|
4195
4531
|
list.className = "files-list";
|
|
4196
4532
|
filesWrapper.appendChild(filesPicker);
|
|
@@ -4199,19 +4535,18 @@ function renderMultipleFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4199
4535
|
const initialFiles = Array.isArray(ctx.prefill[element.key]) ? [...ctx.prefill[element.key]] : [];
|
|
4200
4536
|
addPrefillFilesToIndex(initialFiles, state.resourceIndex);
|
|
4201
4537
|
filesWrapper.dataset.resourceIds = JSON.stringify(initialFiles);
|
|
4202
|
-
const
|
|
4203
|
-
const multipleConstraints = {
|
|
4538
|
+
const constraints = {
|
|
4204
4539
|
maxCount: maxFiles,
|
|
4205
4540
|
allowedExtensions: getAllowedExtensions(element.accept),
|
|
4206
4541
|
allowedMimes: getAllowedMimes(element.accept),
|
|
4207
|
-
|
|
4542
|
+
// Prefer schema's `maxSize`; fall back to legacy `maxSizeMB` for
|
|
4543
|
+
// backward compatibility (matches addFileSizeHint in validation.ts).
|
|
4544
|
+
maxSize: (_b = (_a = element.maxSize) != null ? _a : element.maxSizeMB) != null ? _b : Infinity
|
|
4208
4545
|
};
|
|
4209
|
-
const
|
|
4210
|
-
|
|
4211
|
-
const minMaxText = minFiles > 0 || maxFiles < Infinity ? ` ${t("fileCountRange", state, { min: minFiles, max: maxFiles })}` : "";
|
|
4212
|
-
return countText + minMaxText;
|
|
4546
|
+
const openPicker = () => {
|
|
4547
|
+
filesPicker.click();
|
|
4213
4548
|
};
|
|
4214
|
-
const
|
|
4549
|
+
const onLibraryPick = state.config.pickExistingFiles && !element.disableLibrary ? () => {
|
|
4215
4550
|
handleLibraryPickMulti(
|
|
4216
4551
|
state,
|
|
4217
4552
|
element,
|
|
@@ -4225,31 +4560,36 @@ function renderMultipleFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4225
4560
|
console.error("Library pick failed:", err);
|
|
4226
4561
|
});
|
|
4227
4562
|
} : null;
|
|
4228
|
-
|
|
4563
|
+
function updateFilesDisplay() {
|
|
4229
4564
|
const currentlyReadonly = isElementReadonly(element, state);
|
|
4230
4565
|
renderResourcePills({
|
|
4231
4566
|
container: list,
|
|
4232
4567
|
rids: initialFiles,
|
|
4233
4568
|
state,
|
|
4234
|
-
onRemove: currentlyReadonly ? null : (
|
|
4569
|
+
onRemove: currentlyReadonly ? null : (ridToRemove) => {
|
|
4235
4570
|
var _a2;
|
|
4236
|
-
releaseLocalFileUrl((_a2 = state.resourceIndex.get(
|
|
4237
|
-
initialFiles.
|
|
4571
|
+
releaseLocalFileUrl((_a2 = state.resourceIndex.get(ridToRemove)) == null ? void 0 : _a2.file);
|
|
4572
|
+
const index = initialFiles.indexOf(ridToRemove);
|
|
4573
|
+
if (index > -1) initialFiles.splice(index, 1);
|
|
4238
4574
|
updateFilesDisplay();
|
|
4239
4575
|
},
|
|
4240
|
-
hint: multipleFilesHint,
|
|
4241
|
-
countInfo: buildCountInfo(),
|
|
4242
4576
|
maxCount: maxFiles < Infinity ? maxFiles : void 0,
|
|
4243
4577
|
isReadonly: currentlyReadonly,
|
|
4244
|
-
onLibraryPick: currentlyReadonly ? null :
|
|
4578
|
+
onLibraryPick: currentlyReadonly ? null : onLibraryPick,
|
|
4579
|
+
element,
|
|
4580
|
+
onClearAll: currentlyReadonly ? void 0 : () => {
|
|
4581
|
+
initialFiles.splice(0);
|
|
4582
|
+
updateFilesDisplay();
|
|
4583
|
+
},
|
|
4584
|
+
openPicker
|
|
4245
4585
|
});
|
|
4246
|
-
}
|
|
4586
|
+
}
|
|
4247
4587
|
setupFilesDropHandler(
|
|
4248
4588
|
filesContainer,
|
|
4249
4589
|
initialFiles,
|
|
4250
4590
|
state,
|
|
4251
4591
|
updateFilesDisplay,
|
|
4252
|
-
|
|
4592
|
+
constraints,
|
|
4253
4593
|
pathKey,
|
|
4254
4594
|
ctx.instance
|
|
4255
4595
|
);
|
|
@@ -4258,13 +4598,20 @@ function renderMultipleFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
|
4258
4598
|
initialFiles,
|
|
4259
4599
|
state,
|
|
4260
4600
|
updateFilesDisplay,
|
|
4261
|
-
|
|
4601
|
+
constraints,
|
|
4262
4602
|
pathKey,
|
|
4263
4603
|
ctx.instance
|
|
4264
4604
|
);
|
|
4265
4605
|
updateFilesDisplay();
|
|
4266
4606
|
wrapper.appendChild(filesWrapper);
|
|
4267
4607
|
}
|
|
4608
|
+
function renderFilesElementEdit(element, ctx, wrapper, pathKey) {
|
|
4609
|
+
setupMultiFileEditMode(element, ctx, wrapper, pathKey, Infinity);
|
|
4610
|
+
}
|
|
4611
|
+
function renderMultipleFileElementEdit(element, ctx, wrapper, pathKey) {
|
|
4612
|
+
var _a;
|
|
4613
|
+
setupMultiFileEditMode(element, ctx, wrapper, pathKey, (_a = element.maxCount) != null ? _a : Infinity);
|
|
4614
|
+
}
|
|
4268
4615
|
|
|
4269
4616
|
// src/components/file/validate.ts
|
|
4270
4617
|
function readMultiFileResourceIds(scopeRoot, fullKey) {
|
|
@@ -4391,33 +4738,36 @@ function renderFileElementReadonly(element, ctx, wrapper, pathKey) {
|
|
|
4391
4738
|
hiddenInput.name = pathKey;
|
|
4392
4739
|
hiddenInput.value = initial;
|
|
4393
4740
|
wrapper.appendChild(hiddenInput);
|
|
4394
|
-
renderFilePreviewReadonly(initial, state).then((
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4741
|
+
renderFilePreviewReadonly(initial, state).then((tile) => {
|
|
4742
|
+
tile.classList.add(
|
|
4743
|
+
"fb-single-readonly-filled",
|
|
4744
|
+
"fb-readonly-tile",
|
|
4745
|
+
"fb-checker"
|
|
4746
|
+
);
|
|
4747
|
+
wrapper.appendChild(tile);
|
|
4748
|
+
}).catch(console.error);
|
|
4400
4749
|
} else {
|
|
4401
4750
|
wrapper.appendChild(buildEmptyReadonlyTile(state));
|
|
4402
4751
|
}
|
|
4403
4752
|
}
|
|
4404
4753
|
function buildEmptyReadonlyTile(state) {
|
|
4754
|
+
ensureFileStyles();
|
|
4405
4755
|
const emptyState = document.createElement("div");
|
|
4406
4756
|
emptyState.style.cssText = `
|
|
4407
|
-
|
|
4408
|
-
height:${TILE_SIZE};
|
|
4757
|
+
height: 220px;
|
|
4409
4758
|
display:flex;
|
|
4410
4759
|
align-items:center;
|
|
4411
4760
|
justify-content:center;
|
|
4412
|
-
background:
|
|
4413
|
-
border-radius:
|
|
4414
|
-
border:1px solid
|
|
4761
|
+
background: repeating-linear-gradient(45deg, #fafafa 0 6px, #f3f4f6 6px 12px);
|
|
4762
|
+
border-radius:0.75rem;
|
|
4763
|
+
border:1px solid #e2e8f0;
|
|
4415
4764
|
`;
|
|
4416
4765
|
emptyState.innerHTML = `<div style="font-size:11px;text-align:center;color:var(--fb-text-secondary-color,#6b7280);">${escapeHtml(t("noFileSelected", state))}</div>`;
|
|
4417
4766
|
return emptyState;
|
|
4418
4767
|
}
|
|
4419
|
-
function renderMultiFileReadonly(rids, state, wrapper, pathKey,
|
|
4768
|
+
function renderMultiFileReadonly(rids, state, wrapper, pathKey, _marginTop) {
|
|
4420
4769
|
addPrefillFilesToIndex(rids, state.resourceIndex);
|
|
4770
|
+
ensureFileStyles();
|
|
4421
4771
|
const filesWrapper = document.createElement("div");
|
|
4422
4772
|
filesWrapper.dataset.filesWrapper = pathKey;
|
|
4423
4773
|
filesWrapper.dataset.resourceIds = JSON.stringify(rids);
|
|
@@ -4429,22 +4779,28 @@ function renderMultiFileReadonly(rids, state, wrapper, pathKey, marginTop) {
|
|
|
4429
4779
|
filesWrapper.appendChild(emptyEl);
|
|
4430
4780
|
return;
|
|
4431
4781
|
}
|
|
4432
|
-
const
|
|
4433
|
-
|
|
4434
|
-
filesWrapper.appendChild(
|
|
4782
|
+
const grid = document.createElement("div");
|
|
4783
|
+
grid.className = "fb-multi-readonly-grid";
|
|
4784
|
+
filesWrapper.appendChild(grid);
|
|
4435
4785
|
const placeholders = rids.map(() => {
|
|
4436
|
-
const
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
return
|
|
4786
|
+
const ph = document.createElement("div");
|
|
4787
|
+
ph.className = "fb-readonly-tile fb-checker fb-tile";
|
|
4788
|
+
grid.appendChild(ph);
|
|
4789
|
+
return ph;
|
|
4440
4790
|
});
|
|
4441
4791
|
for (let i = 0; i < rids.length; i++) {
|
|
4442
4792
|
const resourceId = rids[i];
|
|
4443
4793
|
const placeholder = placeholders[i];
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4794
|
+
const meta = state.resourceIndex.get(resourceId);
|
|
4795
|
+
renderFilePreviewReadonly(resourceId, state, meta == null ? void 0 : meta.name).then((tile) => {
|
|
4796
|
+
tile.classList.add("fb-readonly-tile", "fb-checker", "fb-tile-resource");
|
|
4797
|
+
tile.dataset.resourceId = resourceId;
|
|
4798
|
+
placeholder.replaceWith(tile);
|
|
4799
|
+
}).catch(() => {
|
|
4800
|
+
const tile = document.createElement("div");
|
|
4801
|
+
tile.className = "fb-readonly-tile fb-checker fb-tile fb-tile-resource";
|
|
4802
|
+
tile.dataset.resourceId = resourceId;
|
|
4803
|
+
placeholder.replaceWith(tile);
|
|
4448
4804
|
});
|
|
4449
4805
|
}
|
|
4450
4806
|
}
|
|
@@ -4456,7 +4812,7 @@ function renderFilesElementReadonly(element, ctx, wrapper, pathKey) {
|
|
|
4456
4812
|
function renderMultipleFileElementReadonly(element, ctx, wrapper, pathKey) {
|
|
4457
4813
|
const rawPrefill = ctx.prefill[element.key];
|
|
4458
4814
|
const initialFiles = Array.isArray(rawPrefill) ? rawPrefill : [];
|
|
4459
|
-
renderMultiFileReadonly(initialFiles, ctx.state, wrapper, pathKey
|
|
4815
|
+
renderMultiFileReadonly(initialFiles, ctx.state, wrapper, pathKey);
|
|
4460
4816
|
}
|
|
4461
4817
|
|
|
4462
4818
|
// src/components/file.ts
|
|
@@ -5604,7 +5960,7 @@ function createPrefillHints(element, pathKey) {
|
|
|
5604
5960
|
return null;
|
|
5605
5961
|
}
|
|
5606
5962
|
const hintsContainer = document.createElement("div");
|
|
5607
|
-
hintsContainer.className = "fb-prefill-hints flex flex-wrap gap-2 mb-
|
|
5963
|
+
hintsContainer.className = "fb-prefill-hints flex flex-wrap gap-2 mb-2";
|
|
5608
5964
|
element.prefillHints.forEach((hint, index) => {
|
|
5609
5965
|
const hintButton = document.createElement("button");
|
|
5610
5966
|
hintButton.type = "button";
|
|
@@ -5620,14 +5976,14 @@ function createPrefillHints(element, pathKey) {
|
|
|
5620
5976
|
function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
5621
5977
|
var _a, _b;
|
|
5622
5978
|
const containerWrap = document.createElement("div");
|
|
5623
|
-
containerWrap.className = "border border-gray-200 rounded-lg p-
|
|
5979
|
+
containerWrap.className = "border border-gray-200 rounded-lg p-2 bg-gray-50";
|
|
5624
5980
|
containerWrap.setAttribute("data-container", pathKey);
|
|
5625
5981
|
const itemsWrap = document.createElement("div");
|
|
5626
5982
|
const columns = element.columns || 1;
|
|
5627
5983
|
if (columns === 1) {
|
|
5628
|
-
itemsWrap.className = "space-y-
|
|
5984
|
+
itemsWrap.className = "space-y-2";
|
|
5629
5985
|
} else {
|
|
5630
|
-
itemsWrap.className = `grid grid-cols-${columns} gap-
|
|
5986
|
+
itemsWrap.className = `grid grid-cols-${columns} gap-2`;
|
|
5631
5987
|
}
|
|
5632
5988
|
const containerIsReadonly = isElementReadonly(element, ctx.state, ctx);
|
|
5633
5989
|
if (!containerIsReadonly) {
|
|
@@ -5662,17 +6018,32 @@ function renderSingleContainerElement(element, ctx, wrapper, pathKey) {
|
|
|
5662
6018
|
containerWrap.appendChild(itemsWrap);
|
|
5663
6019
|
wrapper.appendChild(containerWrap);
|
|
5664
6020
|
}
|
|
6021
|
+
function getChildWrapperClass(isSlides, columns) {
|
|
6022
|
+
if (isSlides) {
|
|
6023
|
+
return "space-y-2";
|
|
6024
|
+
}
|
|
6025
|
+
const cols = columns || 1;
|
|
6026
|
+
return cols === 1 ? "space-y-2" : `grid grid-cols-${cols} gap-2`;
|
|
6027
|
+
}
|
|
5665
6028
|
function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
5666
6029
|
var _a, _b, _c, _d;
|
|
5667
6030
|
const state = ctx.state;
|
|
5668
6031
|
const containerIsReadonly = isElementReadonly(element, state, ctx);
|
|
5669
6032
|
const childInheritedReadonly = containerIsReadonly || ctx.inheritedReadonly;
|
|
5670
6033
|
const containerWrap = document.createElement("div");
|
|
5671
|
-
containerWrap.className = "border border-gray-200 rounded-lg p-
|
|
6034
|
+
containerWrap.className = "border border-gray-200 rounded-lg p-2 bg-gray-50";
|
|
5672
6035
|
const countDisplay = document.createElement("span");
|
|
5673
6036
|
countDisplay.className = "text-sm text-gray-500";
|
|
5674
6037
|
const itemsWrap = document.createElement("div");
|
|
5675
|
-
|
|
6038
|
+
const isSlides = element.displayMode === "slides";
|
|
6039
|
+
if (isSlides) {
|
|
6040
|
+
itemsWrap.className = "fb-container-slides";
|
|
6041
|
+
const slideCols = element.columns;
|
|
6042
|
+
const gridTemplateColumns = typeof slideCols === "number" && slideCols > 0 ? `repeat(${slideCols}, 1fr)` : "repeat(auto-fit, minmax(280px, 1fr))";
|
|
6043
|
+
itemsWrap.style.cssText = `display:grid;grid-template-columns:${gridTemplateColumns};gap:8px;align-items:start;`;
|
|
6044
|
+
} else {
|
|
6045
|
+
itemsWrap.className = "space-y-2";
|
|
6046
|
+
}
|
|
5676
6047
|
if (!containerIsReadonly) {
|
|
5677
6048
|
const hintsElement = createPrefillHints(element, element.key);
|
|
5678
6049
|
if (hintsElement) {
|
|
@@ -5716,15 +6087,10 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
5716
6087
|
inheritedReadonly: childInheritedReadonly
|
|
5717
6088
|
};
|
|
5718
6089
|
const item = document.createElement("div");
|
|
5719
|
-
item.className = "containerItem border border-gray-300 rounded-lg p-
|
|
6090
|
+
item.className = "containerItem border border-gray-300 rounded-lg p-2 bg-white";
|
|
5720
6091
|
item.setAttribute("data-container-item", `${element.key}[${idx}]`);
|
|
5721
6092
|
const childWrapper = document.createElement("div");
|
|
5722
|
-
|
|
5723
|
-
if (columns === 1) {
|
|
5724
|
-
childWrapper.className = "space-y-4";
|
|
5725
|
-
} else {
|
|
5726
|
-
childWrapper.className = `grid grid-cols-${columns} gap-4`;
|
|
5727
|
-
}
|
|
6093
|
+
childWrapper.className = getChildWrapperClass(isSlides, element.columns);
|
|
5728
6094
|
element.elements.forEach((child) => {
|
|
5729
6095
|
var _a2;
|
|
5730
6096
|
if (child.type !== "markdown" && (child.hidden || child.type === "hidden")) {
|
|
@@ -5795,14 +6161,18 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
5795
6161
|
inheritedReadonly: childInheritedReadonly
|
|
5796
6162
|
};
|
|
5797
6163
|
const item = document.createElement("div");
|
|
5798
|
-
item.className = "containerItem border border-gray-300 rounded-lg p-
|
|
6164
|
+
item.className = "containerItem border border-gray-300 rounded-lg p-2 bg-white";
|
|
5799
6165
|
item.setAttribute("data-container-item", `${element.key}[${idx}]`);
|
|
5800
6166
|
const childWrapper = document.createElement("div");
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
childWrapper.className = "space-y-4";
|
|
6167
|
+
if (isSlides) {
|
|
6168
|
+
childWrapper.className = "space-y-2";
|
|
5804
6169
|
} else {
|
|
5805
|
-
|
|
6170
|
+
const columns = element.columns || 1;
|
|
6171
|
+
if (columns === 1) {
|
|
6172
|
+
childWrapper.className = "space-y-2";
|
|
6173
|
+
} else {
|
|
6174
|
+
childWrapper.className = `grid grid-cols-${columns} gap-2`;
|
|
6175
|
+
}
|
|
5806
6176
|
}
|
|
5807
6177
|
element.elements.forEach((child) => {
|
|
5808
6178
|
var _a3, _b2;
|
|
@@ -5852,14 +6222,18 @@ function renderMultipleContainerElement(element, ctx, wrapper, _pathKey) {
|
|
|
5852
6222
|
inheritedReadonly: childInheritedReadonly
|
|
5853
6223
|
};
|
|
5854
6224
|
const item = document.createElement("div");
|
|
5855
|
-
item.className = "containerItem border border-gray-300 rounded-lg p-
|
|
6225
|
+
item.className = "containerItem border border-gray-300 rounded-lg p-2 bg-white";
|
|
5856
6226
|
item.setAttribute("data-container-item", `${element.key}[${idx}]`);
|
|
5857
6227
|
const childWrapper = document.createElement("div");
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
childWrapper.className = "space-y-4";
|
|
6228
|
+
if (isSlides) {
|
|
6229
|
+
childWrapper.className = "space-y-2";
|
|
5861
6230
|
} else {
|
|
5862
|
-
|
|
6231
|
+
const columns = element.columns || 1;
|
|
6232
|
+
if (columns === 1) {
|
|
6233
|
+
childWrapper.className = "space-y-2";
|
|
6234
|
+
} else {
|
|
6235
|
+
childWrapper.className = `grid grid-cols-${columns} gap-2`;
|
|
6236
|
+
}
|
|
5863
6237
|
}
|
|
5864
6238
|
element.elements.forEach((child) => {
|
|
5865
6239
|
var _a2;
|
|
@@ -7932,7 +8306,7 @@ function filterFilesForDropdown(query, files, labels) {
|
|
|
7932
8306
|
});
|
|
7933
8307
|
}
|
|
7934
8308
|
var TEXTAREA_FONT = "font-size: var(--fb-font-size, 14px); font-family: var(--fb-font-family, inherit); line-height: 1.6;";
|
|
7935
|
-
var TEXTAREA_PADDING = "padding:
|
|
8309
|
+
var TEXTAREA_PADDING = "padding: 8px 40px 8px 10px;";
|
|
7936
8310
|
function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
7937
8311
|
var _a;
|
|
7938
8312
|
const state = ctx.state;
|
|
@@ -7981,7 +8355,7 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
7981
8355
|
});
|
|
7982
8356
|
const errorEl = document.createElement("div");
|
|
7983
8357
|
errorEl.className = "fb-richinput-error";
|
|
7984
|
-
errorEl.style.cssText = "display: none; color: var(--fb-error-color, #ef4444); font-size: var(--fb-font-size-small, 12px); padding: 4px
|
|
8358
|
+
errorEl.style.cssText = "display: none; color: var(--fb-error-color, #ef4444); font-size: var(--fb-font-size-small, 12px); padding: 4px 10px 6px;";
|
|
7985
8359
|
let errorTimer = null;
|
|
7986
8360
|
function showUploadError(message) {
|
|
7987
8361
|
errorEl.textContent = message;
|
|
@@ -8059,7 +8433,7 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
8059
8433
|
});
|
|
8060
8434
|
const filesRow = document.createElement("div");
|
|
8061
8435
|
filesRow.className = "fb-richinput-files";
|
|
8062
|
-
filesRow.style.cssText = "display: none; flex-wrap: wrap; gap:
|
|
8436
|
+
filesRow.style.cssText = "display: none; flex-wrap: wrap; gap: 4px; padding: 6px 10px 0; align-items: center;";
|
|
8063
8437
|
const fileInput = document.createElement("input");
|
|
8064
8438
|
fileInput.type = "file";
|
|
8065
8439
|
fileInput.multiple = true;
|
|
@@ -8195,13 +8569,13 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
8195
8569
|
paperclipBtn.title = t("richinputAttachFile", state);
|
|
8196
8570
|
paperclipBtn.style.cssText = `
|
|
8197
8571
|
position: absolute;
|
|
8198
|
-
right:
|
|
8199
|
-
bottom:
|
|
8572
|
+
right: 6px;
|
|
8573
|
+
bottom: 6px;
|
|
8200
8574
|
z-index: 2;
|
|
8201
|
-
width:
|
|
8202
|
-
height:
|
|
8575
|
+
width: 28px;
|
|
8576
|
+
height: 28px;
|
|
8203
8577
|
border: none;
|
|
8204
|
-
border-radius:
|
|
8578
|
+
border-radius: 6px;
|
|
8205
8579
|
background: transparent;
|
|
8206
8580
|
cursor: pointer;
|
|
8207
8581
|
display: flex;
|
|
@@ -8569,7 +8943,7 @@ function renderEditMode(element, ctx, wrapper, pathKey, initialValue) {
|
|
|
8569
8943
|
outerDiv.appendChild(errorEl);
|
|
8570
8944
|
if (element.minLength != null || element.maxLength != null) {
|
|
8571
8945
|
const counterRow = document.createElement("div");
|
|
8572
|
-
counterRow.style.cssText = "position: relative; padding: 2px
|
|
8946
|
+
counterRow.style.cssText = "position: relative; padding: 2px 10px 4px; text-align: right;";
|
|
8573
8947
|
const counter = createCharCounter(element, textarea, false);
|
|
8574
8948
|
counter.style.cssText = `
|
|
8575
8949
|
position: static;
|
|
@@ -9374,7 +9748,7 @@ function createInfoButton(element) {
|
|
|
9374
9748
|
}
|
|
9375
9749
|
function createLabelContainer(element) {
|
|
9376
9750
|
const label = document.createElement("div");
|
|
9377
|
-
label.className = "flex items-center mb-
|
|
9751
|
+
label.className = "flex items-center mb-1";
|
|
9378
9752
|
const title = createFieldLabel(element);
|
|
9379
9753
|
label.appendChild(title);
|
|
9380
9754
|
if (element.description || element.hint) {
|
|
@@ -9481,7 +9855,7 @@ function renderElement2(element, ctx) {
|
|
|
9481
9855
|
}
|
|
9482
9856
|
const initiallyDisabled2 = shouldDisableElement(element, ctx);
|
|
9483
9857
|
const outerWrapper = document.createElement("div");
|
|
9484
|
-
outerWrapper.className = "mb-
|
|
9858
|
+
outerWrapper.className = "mb-2 fb-field-wrapper fb-markdown-wrapper";
|
|
9485
9859
|
outerWrapper.setAttribute(
|
|
9486
9860
|
"data-field-key",
|
|
9487
9861
|
getElementLookupKey(element, ctx.state)
|
|
@@ -9497,7 +9871,7 @@ function renderElement2(element, ctx) {
|
|
|
9497
9871
|
}
|
|
9498
9872
|
const initiallyDisabled = shouldDisableElement(element, ctx);
|
|
9499
9873
|
const wrapper = document.createElement("div");
|
|
9500
|
-
wrapper.className = "mb-
|
|
9874
|
+
wrapper.className = "mb-2 fb-field-wrapper";
|
|
9501
9875
|
wrapper.setAttribute("data-field-key", element.key);
|
|
9502
9876
|
const label = createLabelContainer(element);
|
|
9503
9877
|
wrapper.appendChild(label);
|
|
@@ -9564,12 +9938,16 @@ var defaultConfig = {
|
|
|
9564
9938
|
hintPattern: "Format: {pattern}",
|
|
9565
9939
|
fileCountSingle: "{count} file",
|
|
9566
9940
|
fileCountPlural: "{count} files",
|
|
9941
|
+
fileCountWithMax: "{count} / {max} files",
|
|
9567
9942
|
fileCountRange: "({min}-{max})",
|
|
9568
9943
|
uploadingFile: "Uploading\u2026",
|
|
9569
9944
|
filesCounter: "{count}/{max}",
|
|
9570
9945
|
fromLibrary: "From library",
|
|
9571
9946
|
libraryEmpty: "Library is empty",
|
|
9572
9947
|
libraryHint: "Choose from previously uploaded files",
|
|
9948
|
+
dropToUpload: "Release to upload",
|
|
9949
|
+
replaceFile: "Replace",
|
|
9950
|
+
clearAll: "Clear all",
|
|
9573
9951
|
pickerError: "Failed to load files from library",
|
|
9574
9952
|
// Validation errors
|
|
9575
9953
|
required: "Required",
|
|
@@ -9635,12 +10013,16 @@ var defaultConfig = {
|
|
|
9635
10013
|
hintPattern: "\u0424\u043E\u0440\u043C\u0430\u0442: {pattern}",
|
|
9636
10014
|
fileCountSingle: "{count} \u0444\u0430\u0439\u043B",
|
|
9637
10015
|
fileCountPlural: "{count} \u0444\u0430\u0439\u043B\u043E\u0432",
|
|
10016
|
+
fileCountWithMax: "{count} / {max} \u0444\u0430\u0439\u043B\u043E\u0432",
|
|
9638
10017
|
fileCountRange: "({min}-{max})",
|
|
9639
10018
|
uploadingFile: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430\u2026",
|
|
9640
10019
|
filesCounter: "{count}/{max}",
|
|
9641
10020
|
fromLibrary: "\u0418\u0437 \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438",
|
|
9642
10021
|
libraryEmpty: "\u0411\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0430 \u043F\u0443\u0441\u0442\u0430",
|
|
9643
10022
|
libraryHint: "\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0438\u0437 \u0440\u0430\u043D\u0435\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043D\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432",
|
|
10023
|
+
dropToUpload: "\u041E\u0442\u043F\u0443\u0441\u0442\u0438\u0442\u0435, \u0447\u0442\u043E\u0431\u044B \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C",
|
|
10024
|
+
replaceFile: "\u0417\u0430\u043C\u0435\u043D\u0438\u0442\u044C",
|
|
10025
|
+
clearAll: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0432\u0441\u0435",
|
|
9644
10026
|
pickerError: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0444\u0430\u0439\u043B\u044B \u0438\u0437 \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438",
|
|
9645
10027
|
// Validation errors
|
|
9646
10028
|
required: "\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u043F\u043E\u043B\u0435",
|
|
@@ -9781,10 +10163,10 @@ var defaultTheme = {
|
|
|
9781
10163
|
fileUploadHoverBorderColor: "#3b82f6",
|
|
9782
10164
|
// blue-500
|
|
9783
10165
|
// Spacing
|
|
9784
|
-
inputPaddingX: "0.
|
|
9785
|
-
//
|
|
9786
|
-
inputPaddingY: "0.
|
|
9787
|
-
//
|
|
10166
|
+
inputPaddingX: "0.5rem",
|
|
10167
|
+
// 8px (compact density v2)
|
|
10168
|
+
inputPaddingY: "0.25rem",
|
|
10169
|
+
// 4px (compact density v2)
|
|
9788
10170
|
borderRadius: "0.5rem",
|
|
9789
10171
|
// rounded-lg (8px)
|
|
9790
10172
|
borderWidth: "1px",
|
|
@@ -10230,7 +10612,7 @@ var FormBuilderInstance = class {
|
|
|
10230
10612
|
existingContainer.remove();
|
|
10231
10613
|
}
|
|
10232
10614
|
const actionsContainer = document.createElement("div");
|
|
10233
|
-
actionsContainer.className = "form-level-actions-container mt-
|
|
10615
|
+
actionsContainer.className = "form-level-actions-container mt-3 pt-2 flex flex-wrap gap-2 justify-center";
|
|
10234
10616
|
actionsContainer.style.cssText = `
|
|
10235
10617
|
border-top: var(--fb-border-width) solid var(--fb-border-color);
|
|
10236
10618
|
`;
|
|
@@ -10371,7 +10753,7 @@ var FormBuilderInstance = class {
|
|
|
10371
10753
|
*/
|
|
10372
10754
|
createRootPrefillHints(hints) {
|
|
10373
10755
|
const hintsContainer = document.createElement("div");
|
|
10374
|
-
hintsContainer.className = "fb-prefill-hints flex flex-wrap gap-2 mb-
|
|
10756
|
+
hintsContainer.className = "fb-prefill-hints flex flex-wrap gap-2 mb-2";
|
|
10375
10757
|
hints.forEach((hint) => {
|
|
10376
10758
|
const hintButton = document.createElement("button");
|
|
10377
10759
|
hintButton.type = "button";
|
|
@@ -10404,7 +10786,7 @@ var FormBuilderInstance = class {
|
|
|
10404
10786
|
root.setAttribute("data-fb-root", "true");
|
|
10405
10787
|
injectThemeVariables(root, this.state.config.theme);
|
|
10406
10788
|
const rootContainer = document.createElement("div");
|
|
10407
|
-
rootContainer.className = "space-y-
|
|
10789
|
+
rootContainer.className = "space-y-2";
|
|
10408
10790
|
if (schema.prefillHints && !this.state.config.readonly) {
|
|
10409
10791
|
const hintsContainer = this.createRootPrefillHints(schema.prefillHints);
|
|
10410
10792
|
rootContainer.appendChild(hintsContainer);
|
|
@@ -10412,9 +10794,9 @@ var FormBuilderInstance = class {
|
|
|
10412
10794
|
const fieldsWrapper = document.createElement("div");
|
|
10413
10795
|
const columns = schema.columns || 1;
|
|
10414
10796
|
if (columns === 1) {
|
|
10415
|
-
fieldsWrapper.className = "space-y-
|
|
10797
|
+
fieldsWrapper.className = "space-y-2";
|
|
10416
10798
|
} else {
|
|
10417
|
-
fieldsWrapper.className = `grid grid-cols-${columns} gap-
|
|
10799
|
+
fieldsWrapper.className = `grid grid-cols-${columns} gap-2`;
|
|
10418
10800
|
}
|
|
10419
10801
|
schema.elements.forEach((element) => {
|
|
10420
10802
|
var _a, _b;
|