@scaleflex/uploader 0.2.6 → 0.2.8

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.
Files changed (115) hide show
  1. package/.claude/skills/integrate-uploader/SKILL.md +4 -3
  2. package/CHANGELOG.md +16 -1
  3. package/README.md +3 -3
  4. package/dist/components/actions-bar.d.ts +2 -0
  5. package/dist/components/actions-bar.d.ts.map +1 -1
  6. package/dist/components/drop-zone.d.ts.map +1 -1
  7. package/dist/components/file-item.d.ts +6 -0
  8. package/dist/components/file-item.d.ts.map +1 -1
  9. package/dist/components/file-list.d.ts.map +1 -1
  10. package/dist/components/toast.d.ts +18 -0
  11. package/dist/components/toast.d.ts.map +1 -0
  12. package/dist/define.cjs +1 -1
  13. package/dist/define.js +1 -1
  14. package/dist/engine/index.d.ts +1 -0
  15. package/dist/engine/index.d.ts.map +1 -1
  16. package/dist/engine/tus-upload.d.ts +52 -0
  17. package/dist/engine/tus-upload.d.ts.map +1 -0
  18. package/dist/engine/upload-engine.d.ts +14 -0
  19. package/dist/engine/upload-engine.d.ts.map +1 -1
  20. package/dist/engine/xhr-upload.d.ts.map +1 -1
  21. package/dist/events/public-events.d.ts +2 -0
  22. package/dist/events/public-events.d.ts.map +1 -1
  23. package/dist/index-D7hE18PK.js +3541 -0
  24. package/dist/index-DuX47Oy3.cjs +1625 -0
  25. package/dist/index.cjs +1 -1
  26. package/dist/index.d.ts +3 -2
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/metadata/bulk/bulk-meta-diff-view.d.ts +17 -0
  30. package/dist/metadata/bulk/bulk-meta-diff-view.d.ts.map +1 -0
  31. package/dist/metadata/bulk/bulk-meta-op-bar.d.ts +38 -0
  32. package/dist/metadata/bulk/bulk-meta-op-bar.d.ts.map +1 -0
  33. package/dist/metadata/bulk/bulk-meta-row.d.ts +35 -0
  34. package/dist/metadata/bulk/bulk-meta-row.d.ts.map +1 -0
  35. package/dist/metadata/bulk/bulk-meta-sidebar.d.ts +20 -0
  36. package/dist/metadata/bulk/bulk-meta-sidebar.d.ts.map +1 -0
  37. package/dist/metadata/bulk/bulk-meta-table.d.ts +20 -0
  38. package/dist/metadata/bulk/bulk-meta-table.d.ts.map +1 -0
  39. package/dist/metadata/bulk/bulk-metadata-modal.d.ts +46 -0
  40. package/dist/metadata/bulk/bulk-metadata-modal.d.ts.map +1 -0
  41. package/dist/metadata/bulk/bulk-metadata.styles.d.ts +7 -0
  42. package/dist/metadata/bulk/bulk-metadata.styles.d.ts.map +1 -0
  43. package/dist/metadata/bulk/bulk-operations.d.ts +14 -0
  44. package/dist/metadata/bulk/bulk-operations.d.ts.map +1 -0
  45. package/dist/metadata/bulk/diff-utils.d.ts +19 -0
  46. package/dist/metadata/bulk/diff-utils.d.ts.map +1 -0
  47. package/dist/metadata/bulk/index.d.ts +3 -0
  48. package/dist/metadata/bulk/index.d.ts.map +1 -0
  49. package/dist/metadata/field-type-icons.d.ts +4 -0
  50. package/dist/metadata/field-type-icons.d.ts.map +1 -0
  51. package/dist/metadata/fields/boolean-field.d.ts +17 -0
  52. package/dist/metadata/fields/boolean-field.d.ts.map +1 -0
  53. package/dist/metadata/fields/date-field.d.ts +10 -0
  54. package/dist/metadata/fields/date-field.d.ts.map +1 -0
  55. package/dist/metadata/fields/field-base.d.ts +14 -0
  56. package/dist/metadata/fields/field-base.d.ts.map +1 -0
  57. package/dist/metadata/fields/geo-point-field.d.ts +10 -0
  58. package/dist/metadata/fields/geo-point-field.d.ts.map +1 -0
  59. package/dist/metadata/fields/multi-select-field.d.ts +23 -0
  60. package/dist/metadata/fields/multi-select-field.d.ts.map +1 -0
  61. package/dist/metadata/fields/number-field.d.ts +10 -0
  62. package/dist/metadata/fields/number-field.d.ts.map +1 -0
  63. package/dist/metadata/fields/select-field.d.ts +21 -0
  64. package/dist/metadata/fields/select-field.d.ts.map +1 -0
  65. package/dist/metadata/fields/tags-field.d.ts +29 -0
  66. package/dist/metadata/fields/tags-field.d.ts.map +1 -0
  67. package/dist/metadata/fields/text-field.d.ts +9 -0
  68. package/dist/metadata/fields/text-field.d.ts.map +1 -0
  69. package/dist/metadata/fields/textarea-field.d.ts +11 -0
  70. package/dist/metadata/fields/textarea-field.d.ts.map +1 -0
  71. package/dist/metadata/index.d.ts +9 -0
  72. package/dist/metadata/index.d.ts.map +1 -0
  73. package/dist/metadata/metadata-field-edit.d.ts +16 -0
  74. package/dist/metadata/metadata-field-edit.d.ts.map +1 -0
  75. package/dist/metadata/metadata-field-view.d.ts +10 -0
  76. package/dist/metadata/metadata-field-view.d.ts.map +1 -0
  77. package/dist/metadata/metadata-field.d.ts +22 -0
  78. package/dist/metadata/metadata-field.d.ts.map +1 -0
  79. package/dist/metadata/metadata-form.d.ts +15 -0
  80. package/dist/metadata/metadata-form.d.ts.map +1 -0
  81. package/dist/metadata/metadata-panel.d.ts +37 -0
  82. package/dist/metadata/metadata-panel.d.ts.map +1 -0
  83. package/dist/metadata/metadata.styles.d.ts +11 -0
  84. package/dist/metadata/metadata.styles.d.ts.map +1 -0
  85. package/dist/metadata/schema/required-fields.d.ts +24 -0
  86. package/dist/metadata/schema/required-fields.d.ts.map +1 -0
  87. package/dist/metadata/schema/schema-parser.d.ts +3 -0
  88. package/dist/metadata/schema/schema-parser.d.ts.map +1 -0
  89. package/dist/metadata/schema/schema-service.d.ts +5 -0
  90. package/dist/metadata/schema/schema-service.d.ts.map +1 -0
  91. package/dist/metadata/schema/schema.types.d.ts +112 -0
  92. package/dist/metadata/schema/schema.types.d.ts.map +1 -0
  93. package/dist/metadata/schema/validation.d.ts +4 -0
  94. package/dist/metadata/schema/validation.d.ts.map +1 -0
  95. package/dist/metadata/schema/value-transforms.d.ts +5 -0
  96. package/dist/metadata/schema/value-transforms.d.ts.map +1 -0
  97. package/dist/metadata/tags/tag-utils.d.ts +6 -0
  98. package/dist/metadata/tags/tag-utils.d.ts.map +1 -0
  99. package/dist/metadata/tags/tags-autocomplete.d.ts +7 -0
  100. package/dist/metadata/tags/tags-autocomplete.d.ts.map +1 -0
  101. package/dist/{provider-browser-B85iISh9.cjs → provider-browser-D9DOIUnq.cjs} +1 -1
  102. package/dist/{provider-browser-DcYDZQos.js → provider-browser-qRo0t4Wt.js} +1 -1
  103. package/dist/{search-provider-browser-Cn0v6Gcq.js → search-provider-browser-DarbREgH.js} +1 -1
  104. package/dist/{search-provider-browser-DqKnNu87.cjs → search-provider-browser-xP28_tO-.cjs} +1 -1
  105. package/dist/sfx-uploader-BqMTQWrE.cjs +4913 -0
  106. package/dist/{sfx-uploader-C3Z9k-Q8.js → sfx-uploader-D9z-E7SI.js} +4248 -1254
  107. package/dist/sfx-uploader.d.ts +53 -6
  108. package/dist/sfx-uploader.d.ts.map +1 -1
  109. package/dist/store/store.types.d.ts +3 -1
  110. package/dist/store/store.types.d.ts.map +1 -1
  111. package/dist/test-utils.d.ts.map +1 -1
  112. package/dist/utils/portal-target.d.ts +4 -2
  113. package/dist/utils/portal-target.d.ts.map +1 -1
  114. package/package.json +3 -2
  115. package/dist/sfx-uploader-C_E3gvgv.cjs +0 -4647
@@ -0,0 +1,3541 @@
1
+ import { LitElement as w, css as x, nothing as f, html as a, svg as g } from "lit";
2
+ import { property as c, state as h } from "lit/decorators.js";
3
+ import { w as Ve } from "./sfx-uploader-D9z-E7SI.js";
4
+ function Fe(o, e) {
5
+ const t = (e == null ? void 0 : e.language) ?? "en", s = o.model ?? [], i = o.store ?? {}, n = s.find((u) => u.applies_to === "FILES");
6
+ let r = (n == null ? void 0 : n.groups) ?? [];
7
+ if (Array.isArray(e == null ? void 0 : e.fields)) {
8
+ const u = new Set(e.fields);
9
+ r = r.map((k) => ({
10
+ ...k,
11
+ fields: k.fields.filter((_) => u.has(_.ckey))
12
+ })).filter((k) => k.fields.length > 0);
13
+ }
14
+ r = r.map((u) => ({
15
+ ...u,
16
+ fields: u.fields.filter((k) => !k.hide)
17
+ })).filter((u) => u.fields.length > 0);
18
+ const l = r.flatMap((u) => u.fields), d = new Map(l.map((u) => [u.key, u])), p = i.force_filling_metadata_on_upload === !0, b = i.regional_variants_groups ?? [];
19
+ return {
20
+ groups: r,
21
+ fields: l,
22
+ fieldsByKey: d,
23
+ forceFillingOnUpload: p,
24
+ regionalVariantsGroups: b,
25
+ language: t
26
+ };
27
+ }
28
+ const Me = "https://hub.scaleflex.com/api", H = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Map();
29
+ async function Ot(o, e, t, s) {
30
+ const i = H.get(t);
31
+ if (i) return i;
32
+ const n = R.get(t);
33
+ if (n) return n;
34
+ if (s != null && s.rawMetadata) {
35
+ const l = Fe(s.rawMetadata, s);
36
+ return H.set(t, l), l;
37
+ }
38
+ const r = Je(e, t, s);
39
+ R.set(t, r);
40
+ try {
41
+ const l = await r;
42
+ return H.set(t, l), l;
43
+ } finally {
44
+ R.delete(t);
45
+ }
46
+ }
47
+ async function Je(o, e, t) {
48
+ var p, b, u;
49
+ const i = `${(t == null ? void 0 : t.hubApiBase) ?? Me}/project/${encodeURIComponent(e)}`, n = (t == null ? void 0 : t.hubHeaders) ?? o, r = await fetch(i, { headers: n });
50
+ if (!r.ok)
51
+ throw new Error(
52
+ `Failed to fetch metadata schema (HTTP ${r.status})`
53
+ );
54
+ const l = await r.json(), d = ((b = (p = l.data) == null ? void 0 : p.project) == null ? void 0 : b.data) ?? ((u = l.project) == null ? void 0 : u.data);
55
+ if (!(d != null && d.metadata))
56
+ throw new Error("No metadata in project response");
57
+ return Fe(d.metadata, t);
58
+ }
59
+ function Dt(o) {
60
+ var e;
61
+ o ? (H.delete(o), (e = R.get(o)) == null || e.catch(() => {
62
+ }), R.delete(o)) : (H.clear(), R.clear());
63
+ }
64
+ function Te(o, e, t) {
65
+ let s = e;
66
+ switch (o.regional_variants_group_uuid && s != null && typeof s == "object" && !Array.isArray(s) && (s = s[t ?? "en"]), o.type) {
67
+ case "geopoint":
68
+ return He(s);
69
+ case "boolean":
70
+ return s === !0 ? "true" : s === !1 ? "false" : "null";
71
+ case "date":
72
+ return s ? new Date(s) : null;
73
+ case "decimal2":
74
+ return s != null ? String(s) : "";
75
+ case "tags":
76
+ return Array.isArray(s) ? s.map(
77
+ (i) => typeof i == "string" ? { value: i, label: i } : i
78
+ ) : [];
79
+ case "multi-select":
80
+ return s || [];
81
+ default:
82
+ return s ?? "";
83
+ }
84
+ }
85
+ function Q(o, e, t, s) {
86
+ var n;
87
+ let i;
88
+ switch (o.type) {
89
+ case "geopoint": {
90
+ const r = e;
91
+ !r || r.latitude === "" || r.latitude == null || r.longitude === "" || r.longitude == null ? i = null : i = `(${r.latitude},${r.longitude})`;
92
+ break;
93
+ }
94
+ case "boolean":
95
+ e === "true" ? i = !0 : e === "false" ? i = !1 : i = null;
96
+ break;
97
+ case "date": {
98
+ if (!e)
99
+ i = null;
100
+ else {
101
+ const r = e instanceof Date ? e : new Date(e), l = r.getFullYear(), d = String(r.getMonth() + 1).padStart(2, "0"), p = String(r.getDate()).padStart(2, "0");
102
+ i = `${l}-${d}-${p}`;
103
+ }
104
+ break;
105
+ }
106
+ case "tags":
107
+ i = Array.isArray(e) ? e.map((r) => (r == null ? void 0 : r.label) ?? "") : [];
108
+ break;
109
+ case "select-one":
110
+ i = e === "" ? null : e;
111
+ break;
112
+ case "numeric": {
113
+ if (e === "" || e == null) {
114
+ i = null;
115
+ break;
116
+ }
117
+ const r = Number(e);
118
+ i = Number.isFinite(r) ? Math.round(r) : null;
119
+ break;
120
+ }
121
+ case "decimal2": {
122
+ if (e === "" || e == null) {
123
+ i = null;
124
+ break;
125
+ }
126
+ const r = Number(e);
127
+ i = Number.isFinite(r) ? r : null;
128
+ break;
129
+ }
130
+ default:
131
+ i = e;
132
+ }
133
+ if (o.regional_variants_group_uuid) {
134
+ const r = s ?? "en";
135
+ return { ...((n = t == null ? void 0 : t.meta) == null ? void 0 : n[o.key]) ?? {}, [r]: i };
136
+ }
137
+ return i;
138
+ }
139
+ function He(o) {
140
+ if (typeof o == "string") {
141
+ const e = /\(([^)]+)\)/.exec(o);
142
+ if (e) {
143
+ const t = e[1].split(",");
144
+ if (t.length === 2)
145
+ return {
146
+ latitude: t[0].trim(),
147
+ longitude: t[1].trim()
148
+ };
149
+ }
150
+ }
151
+ return { latitude: "", longitude: "" };
152
+ }
153
+ function Le(o, e, t) {
154
+ var i;
155
+ if ((((i = t == null ? void 0 : t.requiredFields) == null ? void 0 : i.includes(o.ckey)) || o.required === 1) && A(e))
156
+ return `${o.title} is required`;
157
+ if (A(e)) return null;
158
+ switch (o.type) {
159
+ case "numeric": {
160
+ const n = Number(e);
161
+ if (!Number.isFinite(n)) return "Must be a valid number";
162
+ if (!Number.isInteger(n)) return "Must be an integer";
163
+ if (n < -1999999999 || n > 1999999999)
164
+ return "Value out of range (±1,999,999,999)";
165
+ break;
166
+ }
167
+ case "decimal2": {
168
+ const n = Number(e);
169
+ if (!Number.isFinite(n)) return "Must be a valid number";
170
+ if (!/^\-?\d*\.?\d{0,2}$/.test(String(e)))
171
+ return "Maximum 2 decimal places";
172
+ if (n < -999999999999e-2 || n > 999999999999e-2)
173
+ return "Value out of range (±9,999,999,999.99)";
174
+ break;
175
+ }
176
+ case "geopoint": {
177
+ const n = e, r = n.latitude !== "" && n.latitude != null, l = n.longitude !== "" && n.longitude != null;
178
+ if (r !== l)
179
+ return "Both latitude and longitude are required";
180
+ if (r && l) {
181
+ const d = Number(n.latitude), p = Number(n.longitude);
182
+ if (!Number.isFinite(d) || d < -90 || d > 90)
183
+ return "Latitude must be between -90 and 90";
184
+ if (!Number.isFinite(p) || p < -180 || p > 180)
185
+ return "Longitude must be between -180 and 180";
186
+ }
187
+ break;
188
+ }
189
+ case "attachment-uri": {
190
+ try {
191
+ const n = new URL(e);
192
+ if (!["http:", "https:"].includes(n.protocol))
193
+ return "Only http and https URLs are allowed";
194
+ } catch {
195
+ return "Invalid URI";
196
+ }
197
+ break;
198
+ }
199
+ }
200
+ if (o.validation && typeof e == "string")
201
+ try {
202
+ if (!new RegExp(o.validation).test(e))
203
+ return "Value does not match expected format";
204
+ } catch {
205
+ }
206
+ return null;
207
+ }
208
+ function A(o) {
209
+ return o == null ? !0 : Array.isArray(o) || typeof o == "string" ? o.length === 0 : typeof o == "object" ? !Object.values(o).some(
210
+ (e) => e != null && e !== ""
211
+ ) : !o;
212
+ }
213
+ function Ue(o) {
214
+ return !A(o);
215
+ }
216
+ function zt(o, e, t) {
217
+ const s = /* @__PURE__ */ new Set(["idle", "queued", "rejected"]), i = [...o.values()].filter(
218
+ (d) => s.has(d.status)
219
+ );
220
+ if (i.length === 0) return {};
221
+ const n = new Set((t == null ? void 0 : t.requiredFields) ?? []), r = e.fields.filter(
222
+ (d) => d.required === 1 || n.has(d.ckey)
223
+ ), l = {};
224
+ for (const d of r) {
225
+ const p = i.filter(
226
+ (b) => !Ue(b.meta[d.key])
227
+ );
228
+ p.length > 0 && (l[d.key] = p);
229
+ }
230
+ return l;
231
+ }
232
+ function Pt(o, e) {
233
+ const t = { ...o };
234
+ for (const s of Object.keys(e)) {
235
+ const i = e[s];
236
+ if (i == null || i === "") continue;
237
+ const n = o[s];
238
+ if (Array.isArray(i))
239
+ if (Array.isArray(n)) {
240
+ const r = new Set(n.map((d) => JSON.stringify(d))), l = [...n];
241
+ for (const d of i) {
242
+ const p = JSON.stringify(d);
243
+ r.has(p) || (r.add(p), l.push(d));
244
+ }
245
+ t[s] = l;
246
+ } else
247
+ t[s] = i;
248
+ else
249
+ t[s] = i;
250
+ }
251
+ return t;
252
+ }
253
+ function qt(o, e) {
254
+ let t = null, s = null, i = !1;
255
+ return {
256
+ search(n, r, l) {
257
+ if (t && clearTimeout(t), s && s.abort(), i = !1, !r.trim()) {
258
+ l([]);
259
+ return;
260
+ }
261
+ t = setTimeout(async () => {
262
+ var d;
263
+ s = new AbortController();
264
+ try {
265
+ const p = `${o}/v5/metadata/autocomplete?q=${encodeURIComponent(r.trim())}&meta_key=_${encodeURIComponent(n)}&limit=20`, b = await fetch(p, { headers: e, signal: s.signal });
266
+ if (i) return;
267
+ if (!b.ok) {
268
+ l([]);
269
+ return;
270
+ }
271
+ const u = await b.json();
272
+ if (i) return;
273
+ const k = ((d = u.data) == null ? void 0 : d.tags) ?? u.tags ?? [];
274
+ l(
275
+ k.map((_) => ({
276
+ sid: _.sid || void 0,
277
+ value: _.tag || _.value || _.label || "",
278
+ label: _.tag || _.label || _.value || ""
279
+ }))
280
+ );
281
+ } catch {
282
+ i || l([]);
283
+ }
284
+ }, 200);
285
+ },
286
+ cancel() {
287
+ i = !0, t && clearTimeout(t), s && s.abort();
288
+ }
289
+ };
290
+ }
291
+ var Ye = Object.defineProperty, V = (o, e, t, s) => {
292
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
293
+ (r = o[n]) && (i = r(e, t, i) || i);
294
+ return i && Ye(e, t, i), i;
295
+ };
296
+ const pe = class pe extends w {
297
+ constructor() {
298
+ super(...arguments), this.schema = null, this.meta = {}, this.config = null, this.disabled = !1, this._collapsed = /* @__PURE__ */ new Set();
299
+ }
300
+ _toggleGroup(e) {
301
+ const t = new Set(this._collapsed);
302
+ t.has(e) ? t.delete(e) : t.add(e), this._collapsed = t;
303
+ }
304
+ _renderGroup(e) {
305
+ const t = !this._collapsed.has(e.uuid);
306
+ return a`
307
+ <div class="group">
308
+ <button class="group-header"
309
+ @click=${() => this._toggleGroup(e.uuid)}
310
+ aria-expanded=${t}>
311
+ <span>${e.name}</span>
312
+ <svg class="chevron ${t ? "open" : ""}" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
313
+ <polyline points="4 6 8 10 12 6"/>
314
+ </svg>
315
+ </button>
316
+ ${t ? a`
317
+ <div class="group-content">
318
+ ${e.fields.map(
319
+ (s) => a`
320
+ <sfx-metadata-field
321
+ .field=${s}
322
+ .value=${this.meta[s.key]}
323
+ .config=${this.config}
324
+ .autocomplete=${this.autocomplete}
325
+ ?disabled=${this.disabled}
326
+ ></sfx-metadata-field>
327
+ `
328
+ )}
329
+ </div>
330
+ ` : f}
331
+ </div>
332
+ `;
333
+ }
334
+ render() {
335
+ return !this.schema || this.schema.groups.length === 0 ? a`<div class="empty">No metadata fields configured</div>` : a`
336
+ ${this.schema.groups.map((e) => this._renderGroup(e))}
337
+ `;
338
+ }
339
+ };
340
+ pe.styles = x`
341
+ :host { display: block; }
342
+
343
+ .group {
344
+ padding-bottom: 4px;
345
+ }
346
+ .group + .group {
347
+ border-top: 1px solid var(--sfx-up-border, #e2e8f0);
348
+ }
349
+
350
+ .group-header {
351
+ display: flex;
352
+ align-items: center;
353
+ justify-content: space-between;
354
+ width: 100%;
355
+ padding: 14px 0 8px;
356
+ border: none;
357
+ background: none;
358
+ cursor: pointer;
359
+ font-family: inherit;
360
+ font-size: 15px;
361
+ font-weight: 600;
362
+ color: var(--sfx-up-text, #1e293b);
363
+ transition: color 0.12s ease;
364
+ }
365
+ .group-header:hover {
366
+ color: var(--sfx-up-primary, #2563eb);
367
+ }
368
+ .group-header:focus-visible {
369
+ outline: 2px solid var(--sfx-up-ring, oklch(0.578 0.198 268.129 / 0.7));
370
+ outline-offset: 2px;
371
+ border-radius: 4px;
372
+ }
373
+
374
+ .chevron {
375
+ width: 16px;
376
+ height: 16px;
377
+ flex-shrink: 0;
378
+ color: var(--sfx-up-text-muted, #94a3b8);
379
+ transition: transform 0.18s ease;
380
+ }
381
+ .chevron.open {
382
+ transform: rotate(180deg);
383
+ }
384
+
385
+ .group-content {
386
+ padding: 0 0 4px;
387
+ }
388
+
389
+ .empty {
390
+ padding: 24px 16px;
391
+ text-align: center;
392
+ font-size: 14px;
393
+ color: var(--sfx-up-text-muted, #94a3b8);
394
+ }
395
+ `;
396
+ let C = pe;
397
+ V([
398
+ c({ attribute: !1 })
399
+ ], C.prototype, "schema");
400
+ V([
401
+ c({ attribute: !1 })
402
+ ], C.prototype, "meta");
403
+ V([
404
+ c({ attribute: !1 })
405
+ ], C.prototype, "config");
406
+ V([
407
+ c({ attribute: !1 })
408
+ ], C.prototype, "autocomplete");
409
+ V([
410
+ c({ type: Boolean })
411
+ ], C.prototype, "disabled");
412
+ V([
413
+ h()
414
+ ], C.prototype, "_collapsed");
415
+ customElements.define("sfx-metadata-form", C);
416
+ const G = x`
417
+ input, textarea, select {
418
+ width: 100%;
419
+ height: 36px;
420
+ padding: 0 10px;
421
+ border: 1px solid var(--sfx-up-border, #e2e8f0);
422
+ border-radius: 6px;
423
+ font-size: 14px;
424
+ font-family: inherit;
425
+ color: var(--sfx-up-text, #1e293b);
426
+ background: var(--sfx-up-bg, #fff);
427
+ outline: none;
428
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
429
+ box-sizing: border-box;
430
+ }
431
+ input:focus, textarea:focus, select:focus {
432
+ border-color: var(--sfx-up-primary, #2563eb);
433
+ box-shadow: 0 0 0 3px var(--sfx-up-ring, oklch(0.578 0.198 268.129 / 0.15));
434
+ }
435
+ input:disabled, textarea:disabled, select:disabled {
436
+ opacity: 0.55;
437
+ cursor: not-allowed;
438
+ }
439
+ `, ae = x`
440
+ :host { display: block; position: relative; }
441
+
442
+ .trigger {
443
+ width: 100%;
444
+ height: 36px;
445
+ padding: 0 10px;
446
+ border: 1px solid var(--sfx-up-border, #e2e8f0);
447
+ border-radius: 6px;
448
+ font-size: 14px;
449
+ font-family: inherit;
450
+ color: var(--sfx-up-text, #1e293b);
451
+ background: var(--sfx-up-bg, #fff);
452
+ cursor: pointer;
453
+ text-align: left;
454
+ box-sizing: border-box;
455
+ display: flex;
456
+ align-items: center;
457
+ }
458
+ .trigger:focus-visible {
459
+ border-color: var(--sfx-up-primary, #2563eb);
460
+ box-shadow: 0 0 0 3px var(--sfx-up-ring, oklch(0.578 0.198 268.129 / 0.15));
461
+ outline: none;
462
+ }
463
+ .placeholder {
464
+ color: var(--sfx-up-text-muted, #94a3b8);
465
+ font-size: 14px;
466
+ }
467
+
468
+ .dropdown {
469
+ position: absolute;
470
+ top: calc(100% + 4px);
471
+ left: 0;
472
+ right: 0;
473
+ z-index: 10;
474
+ background: var(--sfx-up-bg, #fff);
475
+ border: 1px solid var(--sfx-up-border, #e2e8f0);
476
+ border-radius: 8px;
477
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
478
+ max-height: 200px;
479
+ overflow-y: auto;
480
+ }
481
+
482
+ .search {
483
+ width: 100%;
484
+ height: 34px;
485
+ padding: 0 10px;
486
+ border: none;
487
+ border-bottom: 1px solid var(--sfx-up-border, #e2e8f0);
488
+ font-size: 13px;
489
+ font-family: inherit;
490
+ color: var(--sfx-up-text, #1e293b);
491
+ background: transparent;
492
+ outline: none;
493
+ box-sizing: border-box;
494
+ }
495
+
496
+ .option {
497
+ padding: 8px 10px;
498
+ font-size: 14px;
499
+ cursor: pointer;
500
+ color: var(--sfx-up-text, #1e293b);
501
+ }
502
+ .option:hover, .option.active { background: var(--sfx-up-hover, #f1f5f9); }
503
+ .option.selected {
504
+ color: var(--sfx-up-primary, #2563eb);
505
+ font-weight: 500;
506
+ }
507
+
508
+ .empty {
509
+ padding: 8px 10px;
510
+ font-size: 13px;
511
+ color: var(--sfx-up-text-muted, #94a3b8);
512
+ }
513
+ `, Be = x`
514
+ .chip {
515
+ display: inline-flex;
516
+ align-items: center;
517
+ gap: 4px;
518
+ padding: 2px 8px;
519
+ border-radius: 12px;
520
+ background: var(--sfx-up-primary-bg, #eff6ff);
521
+ font-size: 12px;
522
+ color: var(--sfx-up-text, #1e293b);
523
+ line-height: 1.4;
524
+ }
525
+ .chip-x {
526
+ cursor: pointer;
527
+ font-size: 14px;
528
+ line-height: 1;
529
+ color: var(--sfx-up-text-muted, #94a3b8);
530
+ background: none;
531
+ border: none;
532
+ padding: 0;
533
+ font-family: inherit;
534
+ }
535
+ .chip-x:hover { color: var(--sfx-up-error, #dc2626); }
536
+ `;
537
+ x`
538
+ :host {
539
+ display: flex;
540
+ flex-direction: column;
541
+ height: 100%;
542
+ font-family: var(--sfx-up-font, inherit);
543
+ color: var(--sfx-up-text, #1e293b);
544
+ background: var(--sfx-up-bg, #fff);
545
+ }
546
+
547
+ .panel-header {
548
+ flex-shrink: 0;
549
+ display: flex;
550
+ align-items: center;
551
+ gap: 8px;
552
+ padding: 12px 16px;
553
+ border-bottom: 1px solid var(--sfx-up-border, #e2e8f0);
554
+ }
555
+
556
+ .panel-title {
557
+ flex: 1;
558
+ font-size: 15px;
559
+ font-weight: 600;
560
+ overflow: hidden;
561
+ text-overflow: ellipsis;
562
+ white-space: nowrap;
563
+ }
564
+
565
+ .panel-close {
566
+ width: 32px;
567
+ height: 32px;
568
+ border: none;
569
+ border-radius: 6px;
570
+ background: none;
571
+ cursor: pointer;
572
+ display: inline-flex;
573
+ align-items: center;
574
+ justify-content: center;
575
+ color: var(--sfx-up-text-muted, #94a3b8);
576
+ transition: background 0.15s ease, color 0.15s ease;
577
+ flex-shrink: 0;
578
+ }
579
+ .panel-close:hover {
580
+ background: var(--sfx-up-hover, #f1f5f9);
581
+ color: var(--sfx-up-text-secondary, #64748b);
582
+ }
583
+ .panel-close:focus-visible {
584
+ outline: 2px solid var(--sfx-up-ring, oklch(0.578 0.198 268.129 / 0.7));
585
+ outline-offset: 2px;
586
+ }
587
+
588
+ .progress-bar {
589
+ flex-shrink: 0;
590
+ padding: 8px 16px;
591
+ border-bottom: 1px solid var(--sfx-up-border-light, #f8faff);
592
+ }
593
+ .progress-label {
594
+ font-size: 12px;
595
+ color: var(--sfx-up-text-secondary, #64748b);
596
+ margin-bottom: 4px;
597
+ }
598
+ .progress-track {
599
+ height: 3px;
600
+ border-radius: 2px;
601
+ background: var(--sfx-up-border-light, #f8faff);
602
+ overflow: hidden;
603
+ }
604
+ .progress-fill {
605
+ height: 100%;
606
+ border-radius: 2px;
607
+ background: var(--sfx-up-primary, #2563eb);
608
+ transition: width 0.25s ease;
609
+ }
610
+
611
+ .panel-content {
612
+ flex: 1;
613
+ overflow-y: auto;
614
+ padding: 12px 16px;
615
+ }
616
+
617
+ .panel-footer {
618
+ flex-shrink: 0;
619
+ display: flex;
620
+ align-items: center;
621
+ gap: 8px;
622
+ padding: 12px 16px;
623
+ border-top: 1px solid var(--sfx-up-border, #e2e8f0);
624
+ }
625
+ .panel-footer .spacer { flex: 1; }
626
+
627
+ /* Shared button styles */
628
+ .btn,
629
+ .btn-ghost,
630
+ .btn-primary {
631
+ height: 36px;
632
+ padding: 0 16px;
633
+ border-radius: 6px;
634
+ border: none;
635
+ font-family: inherit;
636
+ font-size: 14px;
637
+ font-weight: 500;
638
+ cursor: pointer;
639
+ display: inline-flex;
640
+ align-items: center;
641
+ justify-content: center;
642
+ gap: 6px;
643
+ transition: all 0.15s ease;
644
+ white-space: nowrap;
645
+ }
646
+ .btn svg,
647
+ .btn-ghost svg,
648
+ .btn-primary svg {
649
+ width: 14px;
650
+ height: 14px;
651
+ }
652
+ .btn-ghost {
653
+ background: none;
654
+ color: var(--sfx-up-text-muted, #94a3b8);
655
+ border: 1.5px solid var(--sfx-up-border, #e2e8f0);
656
+ }
657
+ .btn-ghost:hover {
658
+ background: var(--sfx-up-border-light, #f8faff);
659
+ color: var(--sfx-up-text-secondary, #64748b);
660
+ border-color: var(--sfx-up-border, #d1dff0);
661
+ }
662
+ .btn-ghost:disabled {
663
+ opacity: 0.45;
664
+ cursor: not-allowed;
665
+ }
666
+ .btn-primary {
667
+ background: linear-gradient(135deg, var(--sfx-up-primary, #2563eb), var(--sfx-up-primary-mid, #3b82f6));
668
+ color: #fff;
669
+ box-shadow: 0 2px 10px var(--sfx-up-primary-glow, rgba(37, 99, 235, 0.28));
670
+ position: relative;
671
+ overflow: hidden;
672
+ }
673
+ .btn-primary:hover:not(:disabled) {
674
+ background: linear-gradient(135deg, var(--sfx-up-primary-hover, #1d4ed8), var(--sfx-up-primary, #2563eb));
675
+ box-shadow: 0 4px 16px var(--sfx-up-primary-glow, rgba(37, 99, 235, 0.38));
676
+ transform: translateY(-1px);
677
+ }
678
+ .btn-primary:active { transform: translateY(0); }
679
+ .btn-primary:disabled {
680
+ opacity: 0.55;
681
+ cursor: not-allowed;
682
+ }
683
+ button:focus-visible {
684
+ outline: 2px solid var(--sfx-up-ring, oklch(0.578 0.198 268.129 / 0.7));
685
+ outline-offset: 2px;
686
+ }
687
+ `;
688
+ const Ge = x`
689
+ :host { display: block; }
690
+
691
+ .field-row {
692
+ display: flex;
693
+ align-items: baseline;
694
+ gap: 8px;
695
+ padding: 10px 0;
696
+ }
697
+
698
+ .field-label {
699
+ display: flex;
700
+ align-items: center;
701
+ gap: 3px;
702
+ width: 120px;
703
+ flex-shrink: 0;
704
+ }
705
+ .field-label-text {
706
+ font-size: 14px;
707
+ font-weight: 400;
708
+ color: var(--sfx-up-text-muted, #94a3b8);
709
+ }
710
+ .field-required {
711
+ color: var(--sfx-up-error, #dc2626);
712
+ font-size: 13px;
713
+ font-weight: 500;
714
+ }
715
+ .field-hint {
716
+ width: 14px;
717
+ height: 14px;
718
+ display: inline-flex;
719
+ align-items: center;
720
+ justify-content: center;
721
+ color: var(--sfx-up-text-muted, #94a3b8);
722
+ cursor: help;
723
+ flex-shrink: 0;
724
+ }
725
+ .field-hint svg {
726
+ width: 12px;
727
+ height: 12px;
728
+ }
729
+
730
+ .field-content {
731
+ flex: 1;
732
+ min-width: 0;
733
+ }
734
+
735
+ .field-error {
736
+ font-size: 11px;
737
+ color: var(--sfx-up-error, #dc2626);
738
+ margin-top: 2px;
739
+ }
740
+ `;
741
+ var We = Object.defineProperty, M = (o, e, t, s) => {
742
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
743
+ (r = o[n]) && (i = r(e, t, i) || i);
744
+ return i && We(e, t, i), i;
745
+ };
746
+ const ue = class ue extends w {
747
+ constructor() {
748
+ super(...arguments), this.config = null, this.disabled = !1, this._error = null, this._dispatching = !1, this._handleChildBlur = (e) => {
749
+ this._dispatching || (e.stopPropagation(), this._onFieldBlur(e));
750
+ };
751
+ }
752
+ get _isRequired() {
753
+ var e, t;
754
+ return (t = (e = this.config) == null ? void 0 : e.requiredFields) != null && t.includes(this.field.ckey) ? !0 : this.field.required === 1;
755
+ }
756
+ _onFieldBlur(e) {
757
+ var r;
758
+ const { key: t, value: s } = e.detail, i = Le(this.field, s, this.config ?? void 0);
759
+ if (i) {
760
+ this._error = i;
761
+ return;
762
+ }
763
+ this._error = null;
764
+ const n = Q(this.field, s, void 0, (r = this.config) == null ? void 0 : r.language);
765
+ this._dispatching = !0, this.dispatchEvent(
766
+ new CustomEvent("field-blur", {
767
+ detail: { key: t, value: n },
768
+ bubbles: !0,
769
+ composed: !0
770
+ })
771
+ ), this._dispatching = !1;
772
+ }
773
+ connectedCallback() {
774
+ super.connectedCallback(), this.addEventListener("field-blur", this._handleChildBlur);
775
+ }
776
+ disconnectedCallback() {
777
+ super.disconnectedCallback(), this.removeEventListener("field-blur", this._handleChildBlur);
778
+ }
779
+ /** Render the correct field editor based on field.type. */
780
+ _renderField(e, t) {
781
+ const s = this.disabled;
782
+ switch (e.type) {
783
+ case "text":
784
+ case "attachment-uri":
785
+ return a`<sfx-meta-text-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-text-field>`;
786
+ case "textarea":
787
+ return a`<sfx-meta-textarea-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-textarea-field>`;
788
+ case "select-one":
789
+ return a`<sfx-meta-select-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-select-field>`;
790
+ case "multi-select":
791
+ return a`<sfx-meta-multi-select-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-multi-select-field>`;
792
+ case "tags":
793
+ return a`<sfx-meta-tags-field .field=${e} .value=${t} .autocomplete=${this.autocomplete} ?disabled=${s}></sfx-meta-tags-field>`;
794
+ case "boolean":
795
+ return a`<sfx-meta-boolean-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-boolean-field>`;
796
+ case "numeric":
797
+ case "decimal2":
798
+ return a`<sfx-meta-number-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-number-field>`;
799
+ case "date":
800
+ return a`<sfx-meta-date-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-date-field>`;
801
+ case "geopoint":
802
+ return a`<sfx-meta-geo-point-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-geo-point-field>`;
803
+ default:
804
+ return a`<sfx-meta-text-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-text-field>`;
805
+ }
806
+ }
807
+ render() {
808
+ var s;
809
+ const e = this.field;
810
+ if (!e) return f;
811
+ const t = Te(e, this.value, (s = this.config) == null ? void 0 : s.language);
812
+ return a`
813
+ <div class="field-row" aria-required=${this._isRequired ? "true" : "false"}>
814
+ <div class="field-label" id="label-${e.key}">
815
+ <span class="field-label-text">${e.title}</span>
816
+ ${this._isRequired ? a`<span class="field-required" aria-hidden="true">*</span>` : f}
817
+ </div>
818
+ <div class="field-content">
819
+ ${this._renderField(e, t)}
820
+ ${this._error ? a`<div class="field-error" id="error-${e.key}" role="alert">${this._error}</div>` : f}
821
+ </div>
822
+ </div>
823
+ `;
824
+ }
825
+ };
826
+ ue.styles = [Ge];
827
+ let S = ue;
828
+ M([
829
+ c({ attribute: !1 })
830
+ ], S.prototype, "field");
831
+ M([
832
+ c({ attribute: !1 })
833
+ ], S.prototype, "value");
834
+ M([
835
+ c({ attribute: !1 })
836
+ ], S.prototype, "config");
837
+ M([
838
+ c({ attribute: !1 })
839
+ ], S.prototype, "autocomplete");
840
+ M([
841
+ c({ type: Boolean })
842
+ ], S.prototype, "disabled");
843
+ M([
844
+ h()
845
+ ], S.prototype, "_error");
846
+ customElements.define("sfx-metadata-field", S);
847
+ var Ze = Object.defineProperty, le = (o, e, t, s) => {
848
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
849
+ (r = o[n]) && (i = r(e, t, i) || i);
850
+ return i && Ze(e, t, i), i;
851
+ };
852
+ class v extends w {
853
+ constructor() {
854
+ super(...arguments), this.value = "", this.disabled = !1;
855
+ }
856
+ /** Dispatch a metadata field event with consistent shape. */
857
+ _emit(e, t) {
858
+ this.dispatchEvent(
859
+ new CustomEvent(e, {
860
+ detail: { key: this.field.key, ...t !== void 0 ? { value: t } : {} },
861
+ bubbles: !0,
862
+ composed: !0
863
+ })
864
+ );
865
+ }
866
+ }
867
+ le([
868
+ c({ attribute: !1 })
869
+ ], v.prototype, "field");
870
+ le([
871
+ c({ attribute: !1 })
872
+ ], v.prototype, "value");
873
+ le([
874
+ c({ type: Boolean })
875
+ ], v.prototype, "disabled");
876
+ const fe = class fe extends v {
877
+ _onInput(e) {
878
+ this._emit("field-change", e.target.value);
879
+ }
880
+ _onBlur(e) {
881
+ this._emit("field-blur", e.target.value);
882
+ }
883
+ _onKeydown(e) {
884
+ e.key === "Escape" && this._emit("field-escape");
885
+ }
886
+ render() {
887
+ var e;
888
+ return a`
889
+ <input
890
+ type="text"
891
+ .value=${this.value ?? ""}
892
+ placeholder=${((e = this.field) == null ? void 0 : e.placeholder) ?? ""}
893
+ ?disabled=${this.disabled}
894
+ @input=${this._onInput}
895
+ @blur=${this._onBlur}
896
+ @keydown=${this._onKeydown}
897
+ />
898
+ `;
899
+ }
900
+ };
901
+ fe.styles = [G];
902
+ let te = fe;
903
+ customElements.define("sfx-meta-text-field", te);
904
+ const he = class he extends v {
905
+ firstUpdated() {
906
+ const e = this.renderRoot.querySelector("textarea");
907
+ e && this._autoResize(e);
908
+ }
909
+ _autoResize(e) {
910
+ e.style.height = "auto", e.style.height = `${Math.max(80, e.scrollHeight)}px`;
911
+ }
912
+ _onInput(e) {
913
+ const t = e.target;
914
+ this._autoResize(t), this._emit("field-change", t.value);
915
+ }
916
+ _onBlur(e) {
917
+ this._emit("field-blur", e.target.value);
918
+ }
919
+ _onKeydown(e) {
920
+ e.key === "Escape" && this._emit("field-escape");
921
+ }
922
+ render() {
923
+ var e;
924
+ return a`
925
+ <textarea
926
+ .value=${this.value ?? ""}
927
+ placeholder=${((e = this.field) == null ? void 0 : e.placeholder) ?? ""}
928
+ ?disabled=${this.disabled}
929
+ @input=${this._onInput}
930
+ @blur=${this._onBlur}
931
+ @keydown=${this._onKeydown}
932
+ ></textarea>
933
+ `;
934
+ }
935
+ };
936
+ he.styles = [
937
+ G,
938
+ x`
939
+ textarea {
940
+ height: auto;
941
+ min-height: 80px;
942
+ padding: 8px 10px;
943
+ resize: none;
944
+ }
945
+ `
946
+ ];
947
+ let ie = he;
948
+ customElements.define("sfx-meta-textarea-field", ie);
949
+ var Qe = Object.defineProperty, de = (o, e, t, s) => {
950
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
951
+ (r = o[n]) && (i = r(e, t, i) || i);
952
+ return i && Qe(e, t, i), i;
953
+ };
954
+ const xe = class xe extends v {
955
+ constructor() {
956
+ super(...arguments), this._open = !1, this._search = "", this._activeIndex = -1, this._boundOutsideClick = this._onOutsideClick.bind(this);
957
+ }
958
+ get _options() {
959
+ var e;
960
+ return (((e = this.field) == null ? void 0 : e.possible_values) ?? []).map((t) => ({
961
+ id: t.internal_unique_value,
962
+ label: t.label,
963
+ value: t.internal_unique_value
964
+ }));
965
+ }
966
+ get _filtered() {
967
+ const e = this._search.toLowerCase();
968
+ return this._options.filter((t) => t.label.toLowerCase().includes(e)).sort((t, s) => t.label.localeCompare(s.label));
969
+ }
970
+ get _selectedLabel() {
971
+ var e;
972
+ return ((e = this._options.find((t) => t.value === this.value)) == null ? void 0 : e.label) ?? "";
973
+ }
974
+ disconnectedCallback() {
975
+ super.disconnectedCallback(), document.removeEventListener("mousedown", this._boundOutsideClick);
976
+ }
977
+ _openDropdown() {
978
+ this._open = !0, this._search = "";
979
+ const t = this._filtered.findIndex((s) => s.value === this.value);
980
+ this._activeIndex = t >= 0 ? t : 0, document.addEventListener("mousedown", this._boundOutsideClick), this.updateComplete.then(() => {
981
+ var s;
982
+ (s = this.renderRoot.querySelector(".search")) == null || s.focus(), this._scrollActive();
983
+ });
984
+ }
985
+ _closeAndSubmit(e = !1) {
986
+ this._open = !1, this._activeIndex = -1, document.removeEventListener("mousedown", this._boundOutsideClick), this._emit("field-blur", this.value), e && this.updateComplete.then(() => {
987
+ var t;
988
+ (t = this.renderRoot.querySelector(".trigger")) == null || t.focus();
989
+ });
990
+ }
991
+ _onOutsideClick(e) {
992
+ e.composedPath().includes(this) || this._closeAndSubmit();
993
+ }
994
+ _onSelect(e, t = !1) {
995
+ this._emit("field-change", e.value), this.value = e.value, this._closeAndSubmit(t);
996
+ }
997
+ _scrollActive() {
998
+ this.updateComplete.then(() => {
999
+ var e;
1000
+ (e = this.renderRoot.querySelector(".option.active")) == null || e.scrollIntoView({ block: "nearest" });
1001
+ });
1002
+ }
1003
+ _onSearchInput(e) {
1004
+ this._search = e.target.value, this._activeIndex = 0;
1005
+ }
1006
+ _onKeydown(e) {
1007
+ var s;
1008
+ if (e.key === "Escape") {
1009
+ this._open = !1, this._activeIndex = -1, document.removeEventListener("mousedown", this._boundOutsideClick), this._emit("field-escape"), (s = this.renderRoot.querySelector(".trigger")) == null || s.focus();
1010
+ return;
1011
+ }
1012
+ if (!this._open) {
1013
+ (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && (e.preventDefault(), this._openDropdown());
1014
+ return;
1015
+ }
1016
+ const t = this._filtered;
1017
+ if (t.length)
1018
+ switch (e.key) {
1019
+ case "ArrowDown":
1020
+ e.preventDefault(), this._activeIndex = Math.min(this._activeIndex + 1, t.length - 1), this._scrollActive();
1021
+ break;
1022
+ case "ArrowUp":
1023
+ e.preventDefault(), this._activeIndex = Math.max(this._activeIndex - 1, 0), this._scrollActive();
1024
+ break;
1025
+ case "Home":
1026
+ e.preventDefault(), this._activeIndex = 0, this._scrollActive();
1027
+ break;
1028
+ case "End":
1029
+ e.preventDefault(), this._activeIndex = t.length - 1, this._scrollActive();
1030
+ break;
1031
+ case "Enter":
1032
+ this._activeIndex >= 0 && this._activeIndex < t.length && (e.preventDefault(), this._onSelect(t[this._activeIndex], !0));
1033
+ break;
1034
+ }
1035
+ }
1036
+ render() {
1037
+ var e;
1038
+ return a`
1039
+ <button class="trigger" ?disabled=${this.disabled}
1040
+ role="combobox"
1041
+ aria-expanded=${this._open}
1042
+ aria-haspopup="listbox"
1043
+ @click=${() => !this._open && this._openDropdown()}
1044
+ @keydown=${this._onKeydown}>
1045
+ ${this._selectedLabel ? a`<span>${this._selectedLabel}</span>` : a`<span class="placeholder">${((e = this.field) == null ? void 0 : e.placeholder) ?? "Select..."}</span>`}
1046
+ </button>
1047
+
1048
+ ${this._open ? a`
1049
+ <div class="dropdown" role="listbox" @keydown=${this._onKeydown}>
1050
+ <input class="search" type="text" placeholder="Search..."
1051
+ aria-label="Filter options"
1052
+ .value=${this._search}
1053
+ @input=${this._onSearchInput} />
1054
+ ${this._filtered.length ? this._filtered.map((t, s) => a`
1055
+ <div class="option ${t.value === this.value ? "selected" : ""} ${s === this._activeIndex ? "active" : ""}"
1056
+ role="option" aria-selected=${t.value === this.value}
1057
+ @mousedown=${(i) => {
1058
+ i.preventDefault(), this._onSelect(t);
1059
+ }}
1060
+ @mouseenter=${() => {
1061
+ this._activeIndex = s;
1062
+ }}>
1063
+ ${t.label}
1064
+ </div>`) : a`<div class="empty">No options</div>`}
1065
+ </div>
1066
+ ` : f}
1067
+ `;
1068
+ }
1069
+ };
1070
+ xe.styles = [ae];
1071
+ let N = xe;
1072
+ de([
1073
+ h()
1074
+ ], N.prototype, "_open");
1075
+ de([
1076
+ h()
1077
+ ], N.prototype, "_search");
1078
+ de([
1079
+ h()
1080
+ ], N.prototype, "_activeIndex");
1081
+ customElements.define("sfx-meta-select-field", N);
1082
+ var Xe = Object.defineProperty, ce = (o, e, t, s) => {
1083
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
1084
+ (r = o[n]) && (i = r(e, t, i) || i);
1085
+ return i && Xe(e, t, i), i;
1086
+ };
1087
+ const be = class be extends v {
1088
+ constructor() {
1089
+ super(...arguments), this._open = !1, this._search = "", this._activeIndex = -1, this._boundOutsideClick = this._onOutsideClick.bind(this);
1090
+ }
1091
+ get _selected() {
1092
+ return Array.isArray(this.value) ? this.value : [];
1093
+ }
1094
+ get _options() {
1095
+ var e;
1096
+ return (((e = this.field) == null ? void 0 : e.possible_values) ?? []).map((t) => ({
1097
+ id: t.internal_unique_value,
1098
+ label: t.label,
1099
+ value: t.internal_unique_value
1100
+ }));
1101
+ }
1102
+ get _filtered() {
1103
+ const e = this._search.toLowerCase();
1104
+ return this._options.filter((t) => t.label.toLowerCase().includes(e)).sort((t, s) => t.label.localeCompare(s.label));
1105
+ }
1106
+ disconnectedCallback() {
1107
+ super.disconnectedCallback(), document.removeEventListener("mousedown", this._boundOutsideClick);
1108
+ }
1109
+ _openDropdown() {
1110
+ this._open = !0, this._search = "", this._activeIndex = -1, document.addEventListener("mousedown", this._boundOutsideClick), this.updateComplete.then(() => {
1111
+ var e;
1112
+ (e = this.renderRoot.querySelector(".search")) == null || e.focus();
1113
+ });
1114
+ }
1115
+ _closeAndSubmit() {
1116
+ this._open = !1, this._activeIndex = -1, document.removeEventListener("mousedown", this._boundOutsideClick), this._emit("field-blur", this._selected);
1117
+ }
1118
+ _onOutsideClick(e) {
1119
+ e.composedPath().includes(this) || this._closeAndSubmit();
1120
+ }
1121
+ _toggle(e) {
1122
+ const t = this._selected, s = t.includes(e.value) ? t.filter((i) => i !== e.value) : [...t, e.value];
1123
+ this.value = s, this._emit("field-change", s);
1124
+ }
1125
+ _remove(e) {
1126
+ const t = this._selected.filter((s) => s !== e);
1127
+ this.value = t, this._emit("field-change", t);
1128
+ }
1129
+ _scrollActive() {
1130
+ this.updateComplete.then(() => {
1131
+ var e;
1132
+ (e = this.renderRoot.querySelector(".option.active")) == null || e.scrollIntoView({ block: "nearest" });
1133
+ });
1134
+ }
1135
+ _onSearchInput(e) {
1136
+ this._search = e.target.value, this._activeIndex = -1;
1137
+ }
1138
+ _onKeydown(e) {
1139
+ var s;
1140
+ if (e.key === "Escape") {
1141
+ this._open = !1, this._activeIndex = -1, document.removeEventListener("mousedown", this._boundOutsideClick), this._emit("field-escape"), (s = this.renderRoot.querySelector(".trigger")) == null || s.focus();
1142
+ return;
1143
+ }
1144
+ if (!this._open) {
1145
+ (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && (e.preventDefault(), this._openDropdown());
1146
+ return;
1147
+ }
1148
+ if (e.key === "Backspace" && !this._search && this._selected.length > 0) {
1149
+ this._remove(this._selected[this._selected.length - 1]);
1150
+ return;
1151
+ }
1152
+ const t = this._filtered;
1153
+ if (t.length)
1154
+ switch (e.key) {
1155
+ case "ArrowDown":
1156
+ e.preventDefault(), this._activeIndex = Math.min(this._activeIndex + 1, t.length - 1), this._scrollActive();
1157
+ break;
1158
+ case "ArrowUp":
1159
+ e.preventDefault(), this._activeIndex = Math.max(this._activeIndex - 1, 0), this._scrollActive();
1160
+ break;
1161
+ case "Home":
1162
+ e.preventDefault(), this._activeIndex = 0, this._scrollActive();
1163
+ break;
1164
+ case "End":
1165
+ e.preventDefault(), this._activeIndex = t.length - 1, this._scrollActive();
1166
+ break;
1167
+ case "Enter":
1168
+ this._activeIndex >= 0 && this._activeIndex < t.length && (e.preventDefault(), this._toggle(t[this._activeIndex]));
1169
+ break;
1170
+ case " ":
1171
+ this._activeIndex >= 0 && this._activeIndex < t.length && !this._search && (e.preventDefault(), this._toggle(t[this._activeIndex]));
1172
+ break;
1173
+ }
1174
+ }
1175
+ _labelFor(e) {
1176
+ var t;
1177
+ return ((t = this._options.find((s) => s.value === e)) == null ? void 0 : t.label) ?? e;
1178
+ }
1179
+ render() {
1180
+ var t;
1181
+ const e = this._selected;
1182
+ return a`
1183
+ <div class="trigger"
1184
+ role="combobox" aria-expanded=${this._open} aria-haspopup="listbox"
1185
+ tabindex="0"
1186
+ @click=${() => !this._open && this._openDropdown()} @keydown=${this._onKeydown}>
1187
+ ${e.length ? e.map((s) => a`
1188
+ <span class="chip">
1189
+ ${this._labelFor(s)}
1190
+ <button class="chip-x" aria-label="Remove ${this._labelFor(s)}" @click=${(i) => {
1191
+ i.stopPropagation(), this._remove(s);
1192
+ }}>&times;</button>
1193
+ </span>`) : a`<span class="placeholder">${((t = this.field) == null ? void 0 : t.placeholder) ?? "Select..."}</span>`}
1194
+ </div>
1195
+
1196
+ ${this._open ? a`
1197
+ <div class="dropdown" role="listbox" aria-multiselectable="true" @keydown=${this._onKeydown}>
1198
+ <input class="search" type="text" placeholder="Search..."
1199
+ aria-label="Filter options"
1200
+ .value=${this._search}
1201
+ @input=${this._onSearchInput} />
1202
+ ${this._filtered.length ? this._filtered.map((s, i) => a`
1203
+ <div class="option ${i === this._activeIndex ? "active" : ""}" role="option" aria-selected=${e.includes(s.value)}
1204
+ @mousedown=${(n) => {
1205
+ n.preventDefault(), this._toggle(s);
1206
+ }}
1207
+ @mouseenter=${() => {
1208
+ this._activeIndex = i;
1209
+ }}>
1210
+ <span class="check ${e.includes(s.value) ? "checked" : ""}">
1211
+ ${e.includes(s.value) ? "✓" : ""}
1212
+ </span>
1213
+ ${s.label}
1214
+ </div>`) : a`<div class="empty">No options</div>`}
1215
+ </div>
1216
+ ` : f}
1217
+ `;
1218
+ }
1219
+ };
1220
+ be.styles = [
1221
+ ae,
1222
+ Be,
1223
+ x`
1224
+ .trigger {
1225
+ min-height: 36px;
1226
+ height: auto;
1227
+ padding: 4px 8px;
1228
+ flex-wrap: wrap;
1229
+ gap: 4px;
1230
+ }
1231
+ .check {
1232
+ width: 16px;
1233
+ height: 16px;
1234
+ border: 1.5px solid var(--sfx-up-border, #e2e8f0);
1235
+ border-radius: 3px;
1236
+ display: flex;
1237
+ align-items: center;
1238
+ justify-content: center;
1239
+ flex-shrink: 0;
1240
+ font-size: 11px;
1241
+ }
1242
+ .check.checked {
1243
+ background: var(--sfx-up-primary, #2563eb);
1244
+ border-color: var(--sfx-up-primary, #2563eb);
1245
+ color: #fff;
1246
+ }
1247
+ .option { display: flex; align-items: center; gap: 8px; }
1248
+ `
1249
+ ];
1250
+ let K = be;
1251
+ ce([
1252
+ h()
1253
+ ], K.prototype, "_open");
1254
+ ce([
1255
+ h()
1256
+ ], K.prototype, "_search");
1257
+ ce([
1258
+ h()
1259
+ ], K.prototype, "_activeIndex");
1260
+ customElements.define("sfx-meta-multi-select-field", K);
1261
+ function P(o, e) {
1262
+ var t, s;
1263
+ return ((t = o.label) == null ? void 0 : t.trim().toLowerCase()) === ((s = e.label) == null ? void 0 : s.trim().toLowerCase());
1264
+ }
1265
+ function je(o) {
1266
+ return o.trim().replace(/\s+/g, " ");
1267
+ }
1268
+ function et(o) {
1269
+ return je(o).replace(/\s/g, "-");
1270
+ }
1271
+ function Z(o) {
1272
+ return { label: je(o), value: et(o) };
1273
+ }
1274
+ var tt = Object.defineProperty, J = (o, e, t, s) => {
1275
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
1276
+ (r = o[n]) && (i = r(e, t, i) || i);
1277
+ return i && tt(e, t, i), i;
1278
+ };
1279
+ const ge = class ge extends v {
1280
+ constructor() {
1281
+ super(...arguments), this._query = "", this._results = [], this._loading = !1, this._dropdownOpen = !1, this._activeIndex = -1, this._blurTimeout = null;
1282
+ }
1283
+ get _tags() {
1284
+ return Array.isArray(this.value) ? this.value : [];
1285
+ }
1286
+ disconnectedCallback() {
1287
+ var e;
1288
+ super.disconnectedCallback(), this._blurTimeout && clearTimeout(this._blurTimeout), (e = this.autocomplete) == null || e.cancel();
1289
+ }
1290
+ _onInput(e) {
1291
+ var s, i, n;
1292
+ const t = e.target.value;
1293
+ if (this._query = t, this._dropdownOpen = !0, this._activeIndex = -1, !t.trim() || !((s = this.field) != null && s.ckey)) {
1294
+ this._results = [], this._loading = !1, (i = this.autocomplete) == null || i.cancel();
1295
+ return;
1296
+ }
1297
+ this._loading = !0, (n = this.autocomplete) == null || n.search(this.field.ckey, t, (r) => {
1298
+ this._results = r, this._loading = !1;
1299
+ });
1300
+ }
1301
+ _addTag(e) {
1302
+ if (this._tags.some((s) => P(s, e))) return;
1303
+ const t = [...this._tags, e];
1304
+ this.value = t, this._query = "", this._results = [], this._dropdownOpen = !1, this._activeIndex = -1, this._emit("field-change", t), this.updateComplete.then(() => {
1305
+ var s;
1306
+ (s = this.renderRoot.querySelector(".input")) == null || s.focus();
1307
+ });
1308
+ }
1309
+ _removeTag(e) {
1310
+ const t = this._tags.filter((s) => !P(s, e));
1311
+ this.value = t, this._emit("field-change", t);
1312
+ }
1313
+ _onBlur() {
1314
+ this._blurTimeout && clearTimeout(this._blurTimeout), this._blurTimeout = setTimeout(() => {
1315
+ this._blurTimeout = null, this.renderRoot.querySelector(".dropdown:hover") || (this._dropdownOpen = !1, this._activeIndex = -1, this._emit("field-blur", this._tags));
1316
+ }, 150);
1317
+ }
1318
+ _scrollActive() {
1319
+ this.updateComplete.then(() => {
1320
+ var e;
1321
+ (e = this.renderRoot.querySelector(".option.active")) == null || e.scrollIntoView({ block: "nearest" });
1322
+ });
1323
+ }
1324
+ /** Total navigable items: suggestions + optional "Create" item. */
1325
+ get _itemCount() {
1326
+ return this._suggestions.length + (this._canCreate ? 1 : 0);
1327
+ }
1328
+ _onKeydown(e) {
1329
+ if (e.key === "Escape") {
1330
+ this._dropdownOpen = !1, this._activeIndex = -1, this._emit("field-escape");
1331
+ return;
1332
+ }
1333
+ if (e.key === "Backspace" && !this._query && this._tags.length) {
1334
+ this._removeTag(this._tags[this._tags.length - 1]);
1335
+ return;
1336
+ }
1337
+ if (!this._dropdownOpen) return;
1338
+ const t = this._itemCount;
1339
+ if (this._activeIndex >= t && (this._activeIndex = Math.max(t - 1, -1)), !(t === 0 && e.key !== "Enter"))
1340
+ switch (e.key) {
1341
+ case "ArrowDown":
1342
+ e.preventDefault(), this._activeIndex = Math.min(this._activeIndex + 1, t - 1), this._scrollActive();
1343
+ break;
1344
+ case "ArrowUp":
1345
+ e.preventDefault(), this._activeIndex = Math.max(this._activeIndex - 1, -1), this._scrollActive();
1346
+ break;
1347
+ case "Home":
1348
+ e.preventDefault(), this._activeIndex = 0, this._scrollActive();
1349
+ break;
1350
+ case "End":
1351
+ e.preventDefault(), this._activeIndex = t - 1, this._scrollActive();
1352
+ break;
1353
+ case "Enter": {
1354
+ e.preventDefault();
1355
+ const s = this._suggestions;
1356
+ this._activeIndex >= 0 && this._activeIndex < s.length ? this._addTag(s[this._activeIndex]) : this._activeIndex === s.length && this._canCreate ? this._addTag(Z(this._query)) : this._activeIndex === -1 && this._canCreate ? this._addTag(Z(this._query)) : this._activeIndex === -1 && s.length && this._addTag(s[0]);
1357
+ break;
1358
+ }
1359
+ }
1360
+ }
1361
+ get _suggestions() {
1362
+ var n;
1363
+ const e = this._query.toLowerCase().trim(), t = this._tags, s = (((n = this.field) == null ? void 0 : n.possible_values) ?? []).map((r) => ({ value: r.api_value || r.internal_unique_value, label: r.label })).filter((r) => !t.some((l) => P(l, r))).filter((r) => !e || r.label.toLowerCase().includes(e)), i = this._results.filter(
1364
+ (r) => !t.some((l) => P(l, r)) && !s.some((l) => P(l, r))
1365
+ );
1366
+ return [...s, ...i];
1367
+ }
1368
+ get _canCreate() {
1369
+ const e = this._query.trim();
1370
+ if (!e || this._loading) return !1;
1371
+ const t = Z(e);
1372
+ return !this._tags.some((s) => P(s, t)) && !this._suggestions.some((s) => P(s, t));
1373
+ }
1374
+ render() {
1375
+ var i, n;
1376
+ const e = this._tags, t = this._suggestions, s = t.length;
1377
+ return a`
1378
+ <div class="container" @click=${() => {
1379
+ var r;
1380
+ return (r = this.renderRoot.querySelector(".input")) == null ? void 0 : r.focus();
1381
+ }}>
1382
+ ${e.map((r) => a`
1383
+ <span class="chip">
1384
+ ${r.label}
1385
+ <button class="chip-x" aria-label="Remove ${r.label}" @click=${(l) => {
1386
+ l.stopPropagation(), this._removeTag(r);
1387
+ }}>&times;</button>
1388
+ </span>`)}
1389
+ <input class="input" type="text" .value=${this._query}
1390
+ role="combobox" aria-expanded=${this._dropdownOpen} aria-haspopup="listbox"
1391
+ aria-label=${((i = this.field) == null ? void 0 : i.title) ?? "Tags"}
1392
+ placeholder=${e.length ? "" : ((n = this.field) == null ? void 0 : n.placeholder) ?? "Add tags..."}
1393
+ ?disabled=${this.disabled}
1394
+ @input=${this._onInput} @blur=${this._onBlur} @keydown=${this._onKeydown} />
1395
+ </div>
1396
+
1397
+ ${this._dropdownOpen && (this._query.trim() || t.length) ? a`
1398
+ <div class="dropdown" role="listbox">
1399
+ ${this._loading ? a`<div class="loading">Loading...</div>` : f}
1400
+ ${t.map((r, l) => a`
1401
+ <div class="option ${l === this._activeIndex ? "active" : ""}" role="option"
1402
+ @mousedown=${(d) => {
1403
+ d.preventDefault(), this._addTag(r);
1404
+ }}
1405
+ @mouseenter=${() => {
1406
+ this._activeIndex = l;
1407
+ }}>
1408
+ ${r.label}
1409
+ </div>`)}
1410
+ ${this._canCreate ? a`
1411
+ <div class="option create ${s === this._activeIndex ? "active" : ""}"
1412
+ @mousedown=${(r) => {
1413
+ r.preventDefault(), this._addTag(Z(this._query));
1414
+ }}
1415
+ @mouseenter=${() => {
1416
+ this._activeIndex = s;
1417
+ }}>
1418
+ Create '${this._query.trim()}'
1419
+ </div>` : f}
1420
+ ${!this._loading && !t.length && !this._canCreate ? a`<div class="empty">No results</div>` : f}
1421
+ </div>
1422
+ ` : f}
1423
+ `;
1424
+ }
1425
+ };
1426
+ ge.styles = [
1427
+ Be,
1428
+ x`
1429
+ :host { display: block; position: relative; }
1430
+
1431
+ .container {
1432
+ display: flex;
1433
+ flex-wrap: wrap;
1434
+ align-items: center;
1435
+ gap: 4px;
1436
+ min-height: 36px;
1437
+ padding: 4px 8px;
1438
+ border: 1px solid var(--sfx-up-border, #e2e8f0);
1439
+ border-radius: 6px;
1440
+ background: var(--sfx-up-bg, #fff);
1441
+ box-sizing: border-box;
1442
+ cursor: text;
1443
+ }
1444
+ .container:focus-within {
1445
+ border-color: var(--sfx-up-primary, #2563eb);
1446
+ box-shadow: 0 0 0 3px var(--sfx-up-ring, oklch(0.578 0.198 268.129 / 0.15));
1447
+ }
1448
+
1449
+ .input {
1450
+ flex: 1;
1451
+ min-width: 80px;
1452
+ border: none;
1453
+ outline: none;
1454
+ font-size: 14px;
1455
+ font-family: inherit;
1456
+ color: var(--sfx-up-text, #1e293b);
1457
+ background: transparent;
1458
+ padding: 2px 0;
1459
+ }
1460
+
1461
+ .dropdown {
1462
+ position: absolute;
1463
+ top: calc(100% + 4px);
1464
+ left: 0;
1465
+ right: 0;
1466
+ z-index: 10;
1467
+ background: var(--sfx-up-bg, #fff);
1468
+ border: 1px solid var(--sfx-up-border, #e2e8f0);
1469
+ border-radius: 8px;
1470
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
1471
+ max-height: 200px;
1472
+ overflow-y: auto;
1473
+ }
1474
+
1475
+ .option {
1476
+ padding: 8px 10px;
1477
+ font-size: 14px;
1478
+ cursor: pointer;
1479
+ color: var(--sfx-up-text, #1e293b);
1480
+ }
1481
+ .option:hover, .option.active { background: var(--sfx-up-hover, #f1f5f9); }
1482
+ .option.create {
1483
+ color: var(--sfx-up-primary, #2563eb);
1484
+ font-weight: 500;
1485
+ }
1486
+
1487
+ .loading, .empty {
1488
+ padding: 8px 10px;
1489
+ font-size: 13px;
1490
+ color: var(--sfx-up-text-muted, #94a3b8);
1491
+ }
1492
+ `
1493
+ ];
1494
+ let I = ge;
1495
+ J([
1496
+ c({ attribute: !1 })
1497
+ ], I.prototype, "autocomplete");
1498
+ J([
1499
+ h()
1500
+ ], I.prototype, "_query");
1501
+ J([
1502
+ h()
1503
+ ], I.prototype, "_results");
1504
+ J([
1505
+ h()
1506
+ ], I.prototype, "_loading");
1507
+ J([
1508
+ h()
1509
+ ], I.prototype, "_dropdownOpen");
1510
+ J([
1511
+ h()
1512
+ ], I.prototype, "_activeIndex");
1513
+ customElements.define("sfx-meta-tags-field", I);
1514
+ var it = Object.defineProperty, Re = (o, e, t, s) => {
1515
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
1516
+ (r = o[n]) && (i = r(e, t, i) || i);
1517
+ return i && it(e, t, i), i;
1518
+ };
1519
+ const q = [
1520
+ { label: "True", value: "true" },
1521
+ { label: "False", value: "false" },
1522
+ { label: "None", value: "null" }
1523
+ ], me = class me extends v {
1524
+ constructor() {
1525
+ super(...arguments), this._open = !1, this._activeIndex = -1, this._boundOutsideClick = this._onOutsideClick.bind(this);
1526
+ }
1527
+ get _currentLabel() {
1528
+ var t;
1529
+ const e = String(this.value ?? "null");
1530
+ return ((t = q.find((s) => s.value === e)) == null ? void 0 : t.label) ?? "";
1531
+ }
1532
+ disconnectedCallback() {
1533
+ super.disconnectedCallback(), document.removeEventListener("mousedown", this._boundOutsideClick);
1534
+ }
1535
+ _openDropdown() {
1536
+ this._open = !0;
1537
+ const e = String(this.value ?? "null");
1538
+ this._activeIndex = Math.max(q.findIndex((t) => t.value === e), 0), document.addEventListener("mousedown", this._boundOutsideClick), this.updateComplete.then(() => {
1539
+ var t;
1540
+ (t = this.renderRoot.querySelector(".dropdown")) == null || t.focus();
1541
+ });
1542
+ }
1543
+ _closeAndSubmit(e = !1) {
1544
+ this._open = !1, this._activeIndex = -1, document.removeEventListener("mousedown", this._boundOutsideClick), this._emit("field-blur", this.value), e && this.updateComplete.then(() => {
1545
+ var t;
1546
+ (t = this.renderRoot.querySelector(".trigger")) == null || t.focus();
1547
+ });
1548
+ }
1549
+ _onOutsideClick(e) {
1550
+ e.composedPath().includes(this) || this._closeAndSubmit();
1551
+ }
1552
+ _onSelect(e, t = !1) {
1553
+ this.value = e.value, this._emit("field-change", e.value), this._closeAndSubmit(t);
1554
+ }
1555
+ _scrollActive() {
1556
+ this.updateComplete.then(() => {
1557
+ var e;
1558
+ (e = this.renderRoot.querySelector(".option.active")) == null || e.scrollIntoView({ block: "nearest" });
1559
+ });
1560
+ }
1561
+ _onKeydown(e) {
1562
+ var t;
1563
+ if (e.key === "Escape") {
1564
+ this._open = !1, this._activeIndex = -1, document.removeEventListener("mousedown", this._boundOutsideClick), this._emit("field-escape"), (t = this.renderRoot.querySelector(".trigger")) == null || t.focus();
1565
+ return;
1566
+ }
1567
+ if (!this._open) {
1568
+ (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") && (e.preventDefault(), this._openDropdown());
1569
+ return;
1570
+ }
1571
+ switch (e.key) {
1572
+ case "ArrowDown":
1573
+ e.preventDefault(), this._activeIndex = Math.min(this._activeIndex + 1, q.length - 1), this._scrollActive();
1574
+ break;
1575
+ case "ArrowUp":
1576
+ e.preventDefault(), this._activeIndex = Math.max(this._activeIndex - 1, 0), this._scrollActive();
1577
+ break;
1578
+ case "Home":
1579
+ e.preventDefault(), this._activeIndex = 0, this._scrollActive();
1580
+ break;
1581
+ case "End":
1582
+ e.preventDefault(), this._activeIndex = q.length - 1, this._scrollActive();
1583
+ break;
1584
+ case "Enter":
1585
+ case " ":
1586
+ this._activeIndex >= 0 && this._activeIndex < q.length && (e.preventDefault(), this._onSelect(q[this._activeIndex], !0));
1587
+ break;
1588
+ }
1589
+ }
1590
+ render() {
1591
+ const e = String(this.value ?? "null");
1592
+ return a`
1593
+ <button class="trigger" ?disabled=${this.disabled}
1594
+ role="combobox" aria-expanded=${this._open} aria-haspopup="listbox"
1595
+ @click=${() => !this._open && this._openDropdown()}
1596
+ @keydown=${this._onKeydown}>
1597
+ ${this._currentLabel ? a`<span>${this._currentLabel}</span>` : a`<span class="placeholder">Select...</span>`}
1598
+ </button>
1599
+
1600
+ ${this._open ? a`
1601
+ <div class="dropdown" role="listbox" tabindex="-1" @keydown=${this._onKeydown}>
1602
+ ${q.map((t, s) => a`
1603
+ <div class="option ${t.value === e ? "selected" : ""} ${s === this._activeIndex ? "active" : ""}"
1604
+ role="option" aria-selected=${t.value === e}
1605
+ @mousedown=${(i) => {
1606
+ i.preventDefault(), this._onSelect(t);
1607
+ }}
1608
+ @mouseenter=${() => {
1609
+ this._activeIndex = s;
1610
+ }}>
1611
+ ${t.label}
1612
+ </div>`)}
1613
+ </div>
1614
+ ` : f}
1615
+ `;
1616
+ }
1617
+ };
1618
+ me.styles = [ae];
1619
+ let U = me;
1620
+ Re([
1621
+ h()
1622
+ ], U.prototype, "_open");
1623
+ Re([
1624
+ h()
1625
+ ], U.prototype, "_activeIndex");
1626
+ customElements.define("sfx-meta-boolean-field", U);
1627
+ const ve = class ve extends v {
1628
+ get _step() {
1629
+ var e;
1630
+ return ((e = this.field) == null ? void 0 : e.type) === "decimal2" ? "0.01" : "1";
1631
+ }
1632
+ _onInput(e) {
1633
+ this._emit("field-change", e.target.value);
1634
+ }
1635
+ _onBlur(e) {
1636
+ this._emit("field-blur", e.target.value);
1637
+ }
1638
+ _onKeydown(e) {
1639
+ e.key === "Escape" && this._emit("field-escape");
1640
+ }
1641
+ render() {
1642
+ var e;
1643
+ return a`
1644
+ <input
1645
+ type="number"
1646
+ step=${this._step}
1647
+ .value=${String(this.value ?? "")}
1648
+ placeholder=${((e = this.field) == null ? void 0 : e.placeholder) ?? ""}
1649
+ ?disabled=${this.disabled}
1650
+ @input=${this._onInput}
1651
+ @blur=${this._onBlur}
1652
+ @keydown=${this._onKeydown}
1653
+ />
1654
+ `;
1655
+ }
1656
+ };
1657
+ ve.styles = [G];
1658
+ let se = ve;
1659
+ customElements.define("sfx-meta-number-field", se);
1660
+ const _e = class _e extends v {
1661
+ /** Convert value to "YYYY-MM-DD" string for the native date input. */
1662
+ get _dateStr() {
1663
+ const e = this.value;
1664
+ return e ? e instanceof Date ? e.toISOString().split("T")[0] : String(e) : "";
1665
+ }
1666
+ _onChange(e) {
1667
+ const t = e.target.value;
1668
+ this._emit("field-change", t), this._emit("field-blur", t);
1669
+ }
1670
+ _onKeydown(e) {
1671
+ e.key === "Escape" && this._emit("field-escape");
1672
+ }
1673
+ render() {
1674
+ return a`
1675
+ <input
1676
+ type="date"
1677
+ .value=${this._dateStr}
1678
+ ?disabled=${this.disabled}
1679
+ @change=${this._onChange}
1680
+ @keydown=${this._onKeydown}
1681
+ />
1682
+ `;
1683
+ }
1684
+ };
1685
+ _e.styles = [G];
1686
+ let re = _e;
1687
+ customElements.define("sfx-meta-date-field", re);
1688
+ const ye = class ye extends v {
1689
+ get _geo() {
1690
+ const e = this.value;
1691
+ return { latitude: (e == null ? void 0 : e.latitude) ?? "", longitude: (e == null ? void 0 : e.longitude) ?? "" };
1692
+ }
1693
+ _onInput(e, t) {
1694
+ const s = t.target.value, i = { ...this._geo, [e]: s };
1695
+ this.value = i, this._emit("field-change", i);
1696
+ }
1697
+ _onBlur(e) {
1698
+ const t = e.relatedTarget;
1699
+ t && this.renderRoot.contains(t) || this._emit("field-blur", this._geo);
1700
+ }
1701
+ _onKeydown(e) {
1702
+ e.key === "Escape" && this._emit("field-escape");
1703
+ }
1704
+ render() {
1705
+ const e = this._geo;
1706
+ return a`
1707
+ <div class="grid">
1708
+ <div>
1709
+ <label>Latitude</label>
1710
+ <input type="number" step="any" .value=${e.latitude}
1711
+ ?disabled=${this.disabled}
1712
+ @input=${(t) => this._onInput("latitude", t)}
1713
+ @blur=${this._onBlur} @keydown=${this._onKeydown} />
1714
+ </div>
1715
+ <div>
1716
+ <label>Longitude</label>
1717
+ <input type="number" step="any" .value=${e.longitude}
1718
+ ?disabled=${this.disabled}
1719
+ @input=${(t) => this._onInput("longitude", t)}
1720
+ @blur=${this._onBlur} @keydown=${this._onKeydown} />
1721
+ </div>
1722
+ </div>
1723
+ `;
1724
+ }
1725
+ };
1726
+ ye.styles = [
1727
+ G,
1728
+ x`
1729
+ .grid {
1730
+ display: grid;
1731
+ grid-template-columns: 1fr 1fr;
1732
+ gap: 12px;
1733
+ }
1734
+ label {
1735
+ display: block;
1736
+ font-size: 12px;
1737
+ color: var(--sfx-up-text-secondary, #64748b);
1738
+ margin-bottom: 4px;
1739
+ }
1740
+ `
1741
+ ];
1742
+ let ne = ye;
1743
+ customElements.define("sfx-meta-geo-point-field", ne);
1744
+ var st = Object.defineProperty, X = (o, e, t, s) => {
1745
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
1746
+ (r = o[n]) && (i = r(e, t, i) || i);
1747
+ return i && st(e, t, i), i;
1748
+ };
1749
+ const we = class we extends w {
1750
+ constructor() {
1751
+ super(...arguments), this.disabled = !1;
1752
+ }
1753
+ render() {
1754
+ const e = this.field, t = this.value, s = this.disabled;
1755
+ switch (e.type) {
1756
+ case "text":
1757
+ case "attachment-uri":
1758
+ return a`<sfx-meta-text-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-text-field>`;
1759
+ case "textarea":
1760
+ return a`<sfx-meta-textarea-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-textarea-field>`;
1761
+ case "select-one":
1762
+ return a`<sfx-meta-select-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-select-field>`;
1763
+ case "multi-select":
1764
+ return a`<sfx-meta-multi-select-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-multi-select-field>`;
1765
+ case "tags":
1766
+ return a`<sfx-meta-tags-field .field=${e} .value=${t} .autocomplete=${this.autocomplete} ?disabled=${s}></sfx-meta-tags-field>`;
1767
+ case "boolean":
1768
+ return a`<sfx-meta-boolean-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-boolean-field>`;
1769
+ case "numeric":
1770
+ case "decimal2":
1771
+ return a`<sfx-meta-number-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-number-field>`;
1772
+ case "date":
1773
+ return a`<sfx-meta-date-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-date-field>`;
1774
+ case "geopoint":
1775
+ return a`<sfx-meta-geo-point-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-geo-point-field>`;
1776
+ default:
1777
+ return a`<sfx-meta-text-field .field=${e} .value=${t} ?disabled=${s}></sfx-meta-text-field>`;
1778
+ }
1779
+ }
1780
+ };
1781
+ we.styles = x`
1782
+ :host { display: block; }
1783
+ `;
1784
+ let T = we;
1785
+ X([
1786
+ c({ attribute: !1 })
1787
+ ], T.prototype, "field");
1788
+ X([
1789
+ c({ attribute: !1 })
1790
+ ], T.prototype, "value");
1791
+ X([
1792
+ c({ attribute: !1 })
1793
+ ], T.prototype, "autocomplete");
1794
+ X([
1795
+ c({ type: Boolean })
1796
+ ], T.prototype, "disabled");
1797
+ customElements.define("sfx-metadata-field-edit", T);
1798
+ var rt = Object.defineProperty, Ne = (o, e, t, s) => {
1799
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
1800
+ (r = o[n]) && (i = r(e, t, i) || i);
1801
+ return i && rt(e, t, i), i;
1802
+ };
1803
+ const ke = class ke extends w {
1804
+ _formatValue() {
1805
+ var s, i;
1806
+ const e = this.value, t = (s = this.field) == null ? void 0 : s.type;
1807
+ switch (t) {
1808
+ case "boolean":
1809
+ return e === "true" ? "True" : e === "false" ? "False" : "";
1810
+ case "date":
1811
+ return e ? e instanceof Date ? e.toLocaleDateString(void 0, {
1812
+ year: "numeric",
1813
+ month: "short",
1814
+ day: "numeric"
1815
+ }) : typeof e == "string" && e.length > 0 ? e : "" : "";
1816
+ case "numeric":
1817
+ case "decimal2": {
1818
+ if (e == null || e === "") return "";
1819
+ const n = Number(e);
1820
+ return Number.isFinite(n) ? n.toLocaleString(void 0, {
1821
+ maximumFractionDigits: t === "decimal2" ? 2 : 0
1822
+ }) : String(e);
1823
+ }
1824
+ case "select-one": {
1825
+ if (e == null || e === "") return "";
1826
+ const n = (i = this.field.possible_values) == null ? void 0 : i.find(
1827
+ (r) => r.internal_unique_value === e || r.api_value === e
1828
+ );
1829
+ return (n == null ? void 0 : n.label) ?? String(e);
1830
+ }
1831
+ case "multi-select":
1832
+ return !Array.isArray(e) || e.length === 0 ? "" : e.map((n) => {
1833
+ var l;
1834
+ const r = (l = this.field.possible_values) == null ? void 0 : l.find(
1835
+ (d) => d.internal_unique_value === n || d.api_value === n
1836
+ );
1837
+ return (r == null ? void 0 : r.label) ?? String(n);
1838
+ }).join(", ");
1839
+ case "tags":
1840
+ return !Array.isArray(e) || e.length === 0 ? "" : e.map((n) => n.label || n.value).join(", ");
1841
+ case "geopoint": {
1842
+ const n = e;
1843
+ return !n || n.latitude === "" || n.latitude == null || n.longitude === "" || n.longitude == null ? "" : `(${n.latitude}, ${n.longitude})`;
1844
+ }
1845
+ case "attachment-uri":
1846
+ return !e || typeof e == "string" && e.length === 0 ? "" : String(e);
1847
+ case "text":
1848
+ case "textarea":
1849
+ default:
1850
+ return e == null || e === "" ? "" : String(e);
1851
+ }
1852
+ }
1853
+ render() {
1854
+ var s;
1855
+ const e = this._formatValue(), t = e === "";
1856
+ return ((s = this.field) == null ? void 0 : s.type) === "attachment-uri" && !t ? a`
1857
+ <div class="value">
1858
+ <a class="link" href=${e} target="_blank" rel="noopener noreferrer"
1859
+ @click=${(i) => i.stopPropagation()}
1860
+ >${e}</a>
1861
+ </div>
1862
+ ` : a`
1863
+ <div class="value ${t ? "empty" : ""}">${t ? "—" : e}</div>
1864
+ `;
1865
+ }
1866
+ };
1867
+ ke.styles = x`
1868
+ :host { display: block; }
1869
+ .value {
1870
+ min-height: 28px;
1871
+ padding: 6px 8px;
1872
+ border-radius: 4px;
1873
+ font-size: 14px;
1874
+ color: var(--sfx-up-text, #1e293b);
1875
+ word-break: break-word;
1876
+ line-height: 1.4;
1877
+ }
1878
+ .empty {
1879
+ color: var(--sfx-up-text-muted, #94a3b8);
1880
+ }
1881
+ .link {
1882
+ color: var(--sfx-up-primary, #2563eb);
1883
+ text-decoration: none;
1884
+ max-width: 100%;
1885
+ display: inline-block;
1886
+ overflow: hidden;
1887
+ text-overflow: ellipsis;
1888
+ white-space: nowrap;
1889
+ }
1890
+ .link:hover {
1891
+ text-decoration: underline;
1892
+ }
1893
+ `;
1894
+ let Y = ke;
1895
+ Ne([
1896
+ c({ attribute: !1 })
1897
+ ], Y.prototype, "field");
1898
+ Ne([
1899
+ c({ attribute: !1 })
1900
+ ], Y.prototype, "value");
1901
+ customElements.define("sfx-metadata-field-view", Y);
1902
+ const Ae = { key: "SET", label: "Set" }, nt = { key: "ADD", label: "Add" }, ot = { key: "DELETE", label: "Delete" }, at = /* @__PURE__ */ new Set([
1903
+ "multi-select",
1904
+ "tags",
1905
+ "integer-list"
1906
+ ]);
1907
+ function lt(o) {
1908
+ return at.has(o) ? [Ae, nt, ot] : [Ae];
1909
+ }
1910
+ function Ke(o, e, t, s) {
1911
+ switch (o) {
1912
+ case "SET":
1913
+ return t;
1914
+ case "ADD": {
1915
+ const i = Array.isArray(e) ? e : [], n = Array.isArray(t) ? t : [];
1916
+ if (n.length === 0) return i;
1917
+ if (s === "tags") {
1918
+ const d = new Set(i.map((b) => b)), p = [...i];
1919
+ for (const b of n) {
1920
+ const u = typeof b == "string" ? b : String(b);
1921
+ d.has(u) || (d.add(u), p.push(u));
1922
+ }
1923
+ return p;
1924
+ }
1925
+ const r = new Set(i.map((d) => JSON.stringify(d))), l = [...i];
1926
+ for (const d of n) {
1927
+ const p = JSON.stringify(d);
1928
+ r.has(p) || (r.add(p), l.push(d));
1929
+ }
1930
+ return l;
1931
+ }
1932
+ case "DELETE": {
1933
+ const i = Array.isArray(e) ? e : [], n = Array.isArray(t) ? t : [];
1934
+ if (n.length === 0) return i;
1935
+ if (s === "tags") {
1936
+ const l = new Set(
1937
+ n.map((d) => typeof d == "string" ? d : String(d))
1938
+ );
1939
+ return i.filter(
1940
+ (d) => !l.has(typeof d == "string" ? d : String(d))
1941
+ );
1942
+ }
1943
+ const r = new Set(
1944
+ n.map((l) => JSON.stringify(l))
1945
+ );
1946
+ return i.filter(
1947
+ (l) => !r.has(JSON.stringify(l))
1948
+ );
1949
+ }
1950
+ default:
1951
+ return t;
1952
+ }
1953
+ }
1954
+ const dt = x`
1955
+ :host {
1956
+ display: block;
1957
+ font-family: var(--sfx-up-font, inherit);
1958
+ color: var(--sfx-up-text, #1e293b);
1959
+ }
1960
+
1961
+ .fm-overlay {
1962
+ position: fixed;
1963
+ inset: 0;
1964
+ z-index: 1010;
1965
+ display: flex;
1966
+ align-items: center;
1967
+ justify-content: center;
1968
+ background: rgba(17, 24, 39, 0.45);
1969
+ backdrop-filter: blur(6px);
1970
+ -webkit-backdrop-filter: blur(6px);
1971
+ }
1972
+
1973
+ .fm-modal {
1974
+ width: 980px;
1975
+ max-width: calc(100vw - 40px);
1976
+ height: 82vh;
1977
+ max-height: calc(100vh - 40px);
1978
+ background: var(--sfx-up-bg, #fff);
1979
+ border-radius: 14px;
1980
+ box-shadow: 0 24px 48px rgba(0, 0, 0, 0.18);
1981
+ display: flex;
1982
+ flex-direction: column;
1983
+ overflow: hidden;
1984
+ }
1985
+
1986
+ /* ---- Top bar ---- */
1987
+ .fm-topbar {
1988
+ height: 48px;
1989
+ flex-shrink: 0;
1990
+ display: flex;
1991
+ align-items: center;
1992
+ padding: 0 24px;
1993
+ border-bottom: 1px solid var(--sfx-up-border, #e2e8f0);
1994
+ }
1995
+ .fm-topbar-title {
1996
+ flex: 1;
1997
+ font-size: 15px;
1998
+ font-weight: 600;
1999
+ white-space: nowrap;
2000
+ overflow: hidden;
2001
+ text-overflow: ellipsis;
2002
+ }
2003
+ .fm-topbar-close {
2004
+ width: 32px;
2005
+ height: 32px;
2006
+ border: none;
2007
+ border-radius: 6px;
2008
+ background: none;
2009
+ cursor: pointer;
2010
+ display: inline-flex;
2011
+ align-items: center;
2012
+ justify-content: center;
2013
+ color: var(--sfx-up-text-muted, #94a3b8);
2014
+ transition: background 0.15s ease, color 0.15s ease;
2015
+ flex-shrink: 0;
2016
+ }
2017
+ .fm-topbar-close:hover {
2018
+ background: var(--sfx-up-hover, #f1f5f9);
2019
+ color: var(--sfx-up-text-secondary, #64748b);
2020
+ }
2021
+
2022
+ /* ---- Body ---- */
2023
+ .fm-body {
2024
+ flex: 1;
2025
+ display: flex;
2026
+ overflow: hidden;
2027
+ }
2028
+
2029
+ .fm-main {
2030
+ flex: 1;
2031
+ display: flex;
2032
+ flex-direction: column;
2033
+ overflow: hidden;
2034
+ }
2035
+
2036
+ /* ---- Table header ---- */
2037
+ .fm-table-header {
2038
+ display: flex;
2039
+ align-items: center;
2040
+ gap: 12px;
2041
+ padding: 8px 24px;
2042
+ border-bottom: 1px solid var(--sfx-up-border, #e2e8f0);
2043
+ font-size: 12px;
2044
+ font-weight: 500;
2045
+ color: var(--sfx-up-text-muted, #94a3b8);
2046
+ text-transform: uppercase;
2047
+ letter-spacing: 0.03em;
2048
+ flex-shrink: 0;
2049
+ }
2050
+ .fm-th-check { width: 20px; flex-shrink: 0; }
2051
+ .fm-th-thumb { width: 52px; flex-shrink: 0; }
2052
+ .fm-th-name {
2053
+ width: 180px;
2054
+ flex-shrink: 0;
2055
+ cursor: pointer;
2056
+ user-select: none;
2057
+ display: flex;
2058
+ align-items: center;
2059
+ gap: 4px;
2060
+ }
2061
+ .fm-th-name:hover { color: var(--sfx-up-text-secondary, #64748b); }
2062
+ .fm-th-size { width: 70px; flex-shrink: 0; text-align: right; }
2063
+ .fm-th-field { flex: 1; min-width: 0; }
2064
+
2065
+ .fm-sort-arrow {
2066
+ display: inline-block;
2067
+ font-size: 11px;
2068
+ line-height: 1;
2069
+ }
2070
+
2071
+ /* ---- Table body (scrollable) ---- */
2072
+ .fm-table-body {
2073
+ flex: 1;
2074
+ overflow-y: auto;
2075
+ overflow-x: hidden;
2076
+ }
2077
+
2078
+ /* ---- Footer ---- */
2079
+ .fm-footer {
2080
+ flex-shrink: 0;
2081
+ display: flex;
2082
+ align-items: center;
2083
+ gap: 8px;
2084
+ padding: 14px 24px;
2085
+ border-top: 1px solid var(--sfx-up-border, #e2e8f0);
2086
+ }
2087
+ .fm-footer .spacer { flex: 1; }
2088
+
2089
+ /* ---- Shared buttons ---- */
2090
+ .btn-ghost,
2091
+ .btn-primary,
2092
+ .btn-back {
2093
+ height: 36px;
2094
+ padding: 0 16px;
2095
+ border-radius: 6px;
2096
+ border: none;
2097
+ font-family: inherit;
2098
+ font-size: 14px;
2099
+ font-weight: 500;
2100
+ cursor: pointer;
2101
+ display: inline-flex;
2102
+ align-items: center;
2103
+ justify-content: center;
2104
+ gap: 6px;
2105
+ transition: all 0.15s ease;
2106
+ white-space: nowrap;
2107
+ }
2108
+ .btn-ghost {
2109
+ background: none;
2110
+ color: var(--sfx-up-text-muted, #94a3b8);
2111
+ border: 1.5px solid var(--sfx-up-border, #e2e8f0);
2112
+ }
2113
+ .btn-ghost:hover {
2114
+ background: var(--sfx-up-border-light, #f8faff);
2115
+ color: var(--sfx-up-text-secondary, #64748b);
2116
+ border-color: var(--sfx-up-border, #d1dff0);
2117
+ }
2118
+ .btn-ghost:disabled {
2119
+ opacity: 0.45;
2120
+ cursor: not-allowed;
2121
+ }
2122
+ .btn-primary {
2123
+ background: linear-gradient(135deg, var(--sfx-up-primary, #2563eb), var(--sfx-up-primary-mid, #3b82f6));
2124
+ color: #fff;
2125
+ box-shadow: 0 2px 10px var(--sfx-up-primary-glow, rgba(37, 99, 235, 0.28));
2126
+ position: relative;
2127
+ overflow: hidden;
2128
+ }
2129
+ .btn-primary:hover:not(:disabled) {
2130
+ background: linear-gradient(135deg, var(--sfx-up-primary-hover, #1d4ed8), var(--sfx-up-primary, #2563eb));
2131
+ box-shadow: 0 4px 16px var(--sfx-up-primary-glow, rgba(37, 99, 235, 0.38));
2132
+ transform: translateY(-1px);
2133
+ }
2134
+ .btn-primary:active { transform: translateY(0); }
2135
+ .btn-primary:disabled {
2136
+ opacity: 0.55;
2137
+ cursor: not-allowed;
2138
+ }
2139
+ .btn-back {
2140
+ background: none;
2141
+ color: var(--sfx-up-text-muted, #94a3b8);
2142
+ padding: 0 8px;
2143
+ }
2144
+ .btn-back:hover {
2145
+ color: var(--sfx-up-text-secondary, #64748b);
2146
+ }
2147
+
2148
+ button:focus-visible {
2149
+ outline: 2px solid var(--sfx-up-ring, oklch(0.578 0.198 268.129 / 0.7));
2150
+ outline-offset: 2px;
2151
+ }
2152
+
2153
+ /* ---- Empty state ---- */
2154
+ .fm-empty {
2155
+ flex: 1;
2156
+ display: flex;
2157
+ align-items: center;
2158
+ justify-content: center;
2159
+ color: var(--sfx-up-text-muted, #94a3b8);
2160
+ font-size: 14px;
2161
+ }
2162
+
2163
+ /* ---- Checkbox ---- */
2164
+ .fm-checkbox {
2165
+ width: 16px;
2166
+ height: 16px;
2167
+ accent-color: var(--sfx-up-primary, #2563eb);
2168
+ cursor: pointer;
2169
+ margin: 0;
2170
+ }
2171
+ `, ct = x`
2172
+ :host {
2173
+ display: block;
2174
+ width: 220px;
2175
+ flex-shrink: 0;
2176
+ border-right: 1px solid var(--sfx-up-border, #e2e8f0);
2177
+ overflow-y: auto;
2178
+ padding: 12px 0;
2179
+ font-family: var(--sfx-up-font, inherit);
2180
+ }
2181
+
2182
+ .group-label {
2183
+ display: flex;
2184
+ align-items: center;
2185
+ gap: 4px;
2186
+ width: 100%;
2187
+ padding: 12px 16px 6px;
2188
+ margin-top: 8px;
2189
+ font-size: 11px;
2190
+ font-weight: 600;
2191
+ text-transform: uppercase;
2192
+ letter-spacing: 0.06em;
2193
+ color: var(--sfx-up-text-muted, #94a3b8);
2194
+ border: none;
2195
+ background: none;
2196
+ cursor: pointer;
2197
+ font-family: inherit;
2198
+ text-align: left;
2199
+ }
2200
+ .group-label:first-child {
2201
+ margin-top: 0;
2202
+ }
2203
+ .group-label:hover {
2204
+ color: var(--sfx-up-text-secondary, #64748b);
2205
+ }
2206
+ .group-label-text {
2207
+ flex: 1;
2208
+ }
2209
+ .group-chevron {
2210
+ width: 14px;
2211
+ height: 14px;
2212
+ flex-shrink: 0;
2213
+ transition: transform 0.18s ease;
2214
+ }
2215
+ .group-chevron.open {
2216
+ transform: rotate(180deg);
2217
+ }
2218
+
2219
+ .field-item {
2220
+ display: flex;
2221
+ align-items: center;
2222
+ gap: 8px;
2223
+ height: 36px;
2224
+ padding: 0 16px;
2225
+ cursor: pointer;
2226
+ font-size: 14px;
2227
+ color: var(--sfx-up-text, #1e293b);
2228
+ transition: background 0.12s ease;
2229
+ border: none;
2230
+ background: none;
2231
+ width: 100%;
2232
+ text-align: left;
2233
+ font-family: inherit;
2234
+ }
2235
+ .field-item:hover {
2236
+ background: var(--sfx-up-hover, #f1f5f9);
2237
+ }
2238
+ .field-item.active {
2239
+ background: var(--sfx-up-primary-bg, #eff6ff);
2240
+ color: var(--sfx-up-primary, #2563eb);
2241
+ font-weight: 500;
2242
+ }
2243
+
2244
+ .field-icon {
2245
+ width: 16px;
2246
+ height: 16px;
2247
+ flex-shrink: 0;
2248
+ display: inline-flex;
2249
+ align-items: center;
2250
+ justify-content: center;
2251
+ opacity: 0.55;
2252
+ }
2253
+ .field-icon svg {
2254
+ width: 16px;
2255
+ height: 16px;
2256
+ }
2257
+ .field-item.active .field-icon {
2258
+ opacity: 0.85;
2259
+ }
2260
+
2261
+ .field-name {
2262
+ flex: 1;
2263
+ min-width: 0;
2264
+ overflow: hidden;
2265
+ text-overflow: ellipsis;
2266
+ white-space: nowrap;
2267
+ }
2268
+
2269
+ .field-dot {
2270
+ width: 7px;
2271
+ height: 7px;
2272
+ border-radius: 50%;
2273
+ background: #22c55e;
2274
+ flex-shrink: 0;
2275
+ }
2276
+
2277
+ .field-required {
2278
+ color: var(--sfx-up-error, #dc2626);
2279
+ font-size: 13px;
2280
+ font-weight: 500;
2281
+ flex-shrink: 0;
2282
+ }
2283
+ `, pt = x`
2284
+ :host {
2285
+ display: block;
2286
+ font-family: var(--sfx-up-font, inherit);
2287
+ }
2288
+
2289
+ .op-bar {
2290
+ display: flex;
2291
+ align-items: center;
2292
+ gap: 12px;
2293
+ padding: 14px 24px;
2294
+ border-bottom: 1px solid var(--sfx-up-border, #e2e8f0);
2295
+ flex-shrink: 0;
2296
+ }
2297
+
2298
+ .op-label {
2299
+ font-size: 13px;
2300
+ font-weight: 500;
2301
+ color: var(--sfx-up-text-muted, #94a3b8);
2302
+ white-space: nowrap;
2303
+ flex-shrink: 0;
2304
+ }
2305
+
2306
+ /* Operation dropdown */
2307
+ .op-dropdown-wrap {
2308
+ position: relative;
2309
+ flex-shrink: 0;
2310
+ }
2311
+ .op-trigger {
2312
+ height: 34px;
2313
+ padding: 0 10px;
2314
+ border: 1px solid var(--sfx-up-border, #e2e8f0);
2315
+ border-radius: 6px;
2316
+ background: var(--sfx-up-bg, #fff);
2317
+ font-size: 14px;
2318
+ font-family: inherit;
2319
+ color: var(--sfx-up-text, #1e293b);
2320
+ cursor: pointer;
2321
+ display: flex;
2322
+ align-items: center;
2323
+ gap: 6px;
2324
+ min-width: 80px;
2325
+ }
2326
+ .op-trigger:hover {
2327
+ border-color: var(--sfx-up-primary, #2563eb);
2328
+ }
2329
+ .op-arrow {
2330
+ margin-left: auto;
2331
+ font-size: 10px;
2332
+ color: var(--sfx-up-text-muted, #94a3b8);
2333
+ }
2334
+ .op-menu {
2335
+ position: absolute;
2336
+ top: calc(100% + 4px);
2337
+ left: 0;
2338
+ right: 0;
2339
+ z-index: 20;
2340
+ background: var(--sfx-up-bg, #fff);
2341
+ border: 1px solid var(--sfx-up-border, #e2e8f0);
2342
+ border-radius: 8px;
2343
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
2344
+ overflow: hidden;
2345
+ }
2346
+ .op-option {
2347
+ padding: 8px 10px;
2348
+ font-size: 14px;
2349
+ cursor: pointer;
2350
+ color: var(--sfx-up-text, #1e293b);
2351
+ font-family: inherit;
2352
+ border: none;
2353
+ background: none;
2354
+ width: 100%;
2355
+ text-align: left;
2356
+ }
2357
+ .op-option:hover {
2358
+ background: var(--sfx-up-hover, #f1f5f9);
2359
+ }
2360
+ .op-option.active {
2361
+ color: var(--sfx-up-primary, #2563eb);
2362
+ font-weight: 500;
2363
+ }
2364
+
2365
+ /* Value input area */
2366
+ .op-value {
2367
+ flex: 1;
2368
+ min-width: 0;
2369
+ }
2370
+
2371
+ /* Clear button */
2372
+ .btn-clear {
2373
+ width: 28px;
2374
+ height: 28px;
2375
+ border: none;
2376
+ border-radius: 6px;
2377
+ background: none;
2378
+ cursor: pointer;
2379
+ display: inline-flex;
2380
+ align-items: center;
2381
+ justify-content: center;
2382
+ color: var(--sfx-up-text-muted, #94a3b8);
2383
+ flex-shrink: 0;
2384
+ transition: background 0.12s ease, color 0.12s ease;
2385
+ }
2386
+ .btn-clear:hover {
2387
+ background: var(--sfx-up-hover, #f1f5f9);
2388
+ color: var(--sfx-up-text-secondary, #64748b);
2389
+ }
2390
+
2391
+ /* Apply button */
2392
+ .btn-apply {
2393
+ height: 34px;
2394
+ padding: 0 16px;
2395
+ border-radius: 6px;
2396
+ border: none;
2397
+ font-family: inherit;
2398
+ font-size: 13px;
2399
+ font-weight: 500;
2400
+ cursor: pointer;
2401
+ white-space: nowrap;
2402
+ background: var(--sfx-up-primary, #2563eb);
2403
+ color: #fff;
2404
+ transition: all 0.15s ease;
2405
+ flex-shrink: 0;
2406
+ }
2407
+ .btn-apply:hover:not(:disabled) {
2408
+ background: var(--sfx-up-primary-hover, #1d4ed8);
2409
+ }
2410
+ .btn-apply:disabled {
2411
+ opacity: 0.45;
2412
+ cursor: not-allowed;
2413
+ }
2414
+ `, ut = x`
2415
+ :host {
2416
+ display: block;
2417
+ font-family: var(--sfx-up-font, inherit);
2418
+ }
2419
+
2420
+ .row {
2421
+ display: flex;
2422
+ align-items: center;
2423
+ gap: 12px;
2424
+ padding: 10px 24px;
2425
+ border-bottom: 1px solid var(--sfx-up-border-light, #f1f5f9);
2426
+ border-left: 3px solid transparent;
2427
+ transition: background 0.1s ease;
2428
+ }
2429
+ .row:hover {
2430
+ background: var(--sfx-up-hover, #f1f5f9);
2431
+ }
2432
+
2433
+ .row-check { width: 20px; flex-shrink: 0; }
2434
+
2435
+ .row-thumb {
2436
+ width: 52px;
2437
+ height: 38px;
2438
+ flex-shrink: 0;
2439
+ border-radius: 6px;
2440
+ object-fit: cover;
2441
+ background: var(--sfx-up-border-light, #f1f5f9);
2442
+ }
2443
+ .row-thumb-placeholder {
2444
+ width: 52px;
2445
+ height: 38px;
2446
+ flex-shrink: 0;
2447
+ border-radius: 6px;
2448
+ background: var(--sfx-up-border-light, #f1f5f9);
2449
+ display: flex;
2450
+ align-items: center;
2451
+ justify-content: center;
2452
+ color: var(--sfx-up-text-muted, #94a3b8);
2453
+ font-size: 11px;
2454
+ }
2455
+
2456
+ .row-name {
2457
+ width: 180px;
2458
+ flex-shrink: 0;
2459
+ overflow: hidden;
2460
+ text-overflow: ellipsis;
2461
+ white-space: nowrap;
2462
+ font-size: 14px;
2463
+ color: var(--sfx-up-text, #1e293b);
2464
+ }
2465
+
2466
+ .row-size {
2467
+ width: 70px;
2468
+ flex-shrink: 0;
2469
+ text-align: right;
2470
+ font-size: 13px;
2471
+ color: var(--sfx-up-text-muted, #94a3b8);
2472
+ }
2473
+
2474
+ .row-field {
2475
+ flex: 1;
2476
+ min-width: 0;
2477
+ position: relative;
2478
+ }
2479
+ .row-field-edit {
2480
+ min-width: 0;
2481
+ }
2482
+
2483
+ .row-error {
2484
+ font-size: 11px;
2485
+ color: var(--sfx-up-error, #dc2626);
2486
+ margin-top: 2px;
2487
+ }
2488
+
2489
+ .row--changed {
2490
+ border-left-color: var(--sfx-up-success, #16a34a);
2491
+ }
2492
+
2493
+ .fm-checkbox {
2494
+ width: 16px;
2495
+ height: 16px;
2496
+ accent-color: var(--sfx-up-primary, #2563eb);
2497
+ cursor: pointer;
2498
+ margin: 0;
2499
+ }
2500
+ `, ft = x`
2501
+ :host {
2502
+ display: block;
2503
+ font-family: var(--sfx-up-font, inherit);
2504
+ }
2505
+
2506
+ .diff-wrap {
2507
+ display: flex;
2508
+ flex-wrap: wrap;
2509
+ align-items: center;
2510
+ gap: 4px;
2511
+ min-height: 28px;
2512
+ padding: 4px 8px;
2513
+ border-radius: 6px;
2514
+ }
2515
+
2516
+ /* ---- Chips (array diff) ---- */
2517
+ .diff-chip {
2518
+ display: inline-flex;
2519
+ align-items: center;
2520
+ padding: 2px 8px;
2521
+ border-radius: 12px;
2522
+ font-size: 12px;
2523
+ line-height: 1.4;
2524
+ }
2525
+ .diff-chip--kept {
2526
+ background: var(--sfx-up-border-light, #f1f5f9);
2527
+ color: var(--sfx-up-text-secondary, #64748b);
2528
+ }
2529
+ .diff-chip--added {
2530
+ background: #dcfce7;
2531
+ color: #166534;
2532
+ font-weight: 500;
2533
+ }
2534
+ .diff-chip--removed {
2535
+ background: #fee2e2;
2536
+ color: #991b1b;
2537
+ }
2538
+ .diff-chip--removed s {
2539
+ text-decoration: line-through;
2540
+ }
2541
+
2542
+ /* ---- Scalar diff ---- */
2543
+ .diff-old {
2544
+ color: #991b1b;
2545
+ }
2546
+ .diff-old s {
2547
+ text-decoration: line-through;
2548
+ opacity: 0.7;
2549
+ }
2550
+ .diff-arrow {
2551
+ color: var(--sfx-up-text-muted, #94a3b8);
2552
+ font-size: 13px;
2553
+ flex-shrink: 0;
2554
+ }
2555
+ .diff-new {
2556
+ color: #166534;
2557
+ font-weight: 500;
2558
+ }
2559
+ .diff-scalar-text {
2560
+ font-size: 14px;
2561
+ }
2562
+
2563
+ /* ---- Accessibility ---- */
2564
+ .sr-only {
2565
+ position: absolute;
2566
+ width: 1px;
2567
+ height: 1px;
2568
+ padding: 0;
2569
+ margin: -1px;
2570
+ overflow: hidden;
2571
+ clip: rect(0, 0, 0, 0);
2572
+ white-space: nowrap;
2573
+ border-width: 0;
2574
+ }
2575
+ `, ht = x`
2576
+ :host {
2577
+ display: block;
2578
+ }
2579
+ `;
2580
+ var xt = Object.defineProperty, E = (o, e, t, s) => {
2581
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
2582
+ (r = o[n]) && (i = r(e, t, i) || i);
2583
+ return i && xt(e, t, i), i;
2584
+ };
2585
+ const $e = class $e extends w {
2586
+ constructor() {
2587
+ super(...arguments), this.files = [], this.config = null, this._activeFieldKey = "", this._staged = /* @__PURE__ */ new Map(), this._selected = /* @__PURE__ */ new Set(), this._sortAsc = !0, this._pendingOp = null, this._originalFiles = /* @__PURE__ */ new Map(), this._onKeyDown = (e) => {
2588
+ e.key !== "Escape" || e.composedPath().some(
2589
+ (i) => i instanceof HTMLInputElement || i instanceof HTMLTextAreaElement || i instanceof HTMLSelectElement
2590
+ ) || this._confirmDiscardPending() && this._emitClose();
2591
+ }, this._onPendingChange = (e) => {
2592
+ const { operation: t, value: s } = e.detail;
2593
+ A(s) ? this._pendingOp = null : this._pendingOp = { operation: t, value: s };
2594
+ }, this._onFieldSelect = (e) => {
2595
+ this._confirmDiscardPending() && (this._pendingOp = null, this._activeFieldKey = e.detail.fieldKey);
2596
+ }, this._onBulkApply = (e) => {
2597
+ var l;
2598
+ const t = this._activeField;
2599
+ if (!t) return;
2600
+ const { operation: s, value: i } = e.detail, n = (l = this.config) == null ? void 0 : l.language, r = [];
2601
+ for (const d of this._selected) {
2602
+ const p = this._staged.get(d), b = {
2603
+ meta: p ? Object.fromEntries(p) : {}
2604
+ }, u = Q(
2605
+ t,
2606
+ i,
2607
+ b,
2608
+ n
2609
+ ), k = p == null ? void 0 : p.get(t.key), _ = Ke(
2610
+ s,
2611
+ k,
2612
+ u,
2613
+ t.type
2614
+ );
2615
+ r.push([d, t.key, _]);
2616
+ }
2617
+ this._setStagedBulk(r);
2618
+ }, this._onRowFieldChange = (e) => {
2619
+ const t = this._activeField;
2620
+ t && this._setStagedValue(e.detail.fileId, t.key, e.detail.value);
2621
+ }, this._onRowToggle = (e) => {
2622
+ const t = new Set(this._selected);
2623
+ t.has(e.detail.fileId) ? t.delete(e.detail.fileId) : t.add(e.detail.fileId), this._selected = t;
2624
+ }, this._onSelectAll = () => {
2625
+ this._selected.size === this.files.length ? this._selected = /* @__PURE__ */ new Set() : this._selected = new Set(this.files.map((e) => e.id));
2626
+ }, this._onSortToggle = () => {
2627
+ this._sortAsc = !this._sortAsc;
2628
+ }, this._onSave = () => {
2629
+ if (!this._confirmDiscardPending()) return;
2630
+ const e = [];
2631
+ for (const [t, s] of this._staged) {
2632
+ const i = this._originalFiles.get(t);
2633
+ if (!i) continue;
2634
+ const n = {};
2635
+ for (const [r, l] of s)
2636
+ JSON.stringify(l) !== JSON.stringify(i.meta[r]) && (n[r] = l);
2637
+ Object.keys(n).length > 0 && e.push({ fileId: t, meta: n });
2638
+ }
2639
+ this.dispatchEvent(
2640
+ new CustomEvent("metadata-save-batch", {
2641
+ detail: { changes: e },
2642
+ bubbles: !0,
2643
+ composed: !0
2644
+ })
2645
+ ), this._emitClose();
2646
+ }, this._onCancel = () => {
2647
+ this._confirmDiscardPending() && this._emitClose();
2648
+ }, this._onClose = () => {
2649
+ this._confirmDiscardPending() && this._emitClose();
2650
+ };
2651
+ }
2652
+ connectedCallback() {
2653
+ super.connectedCallback(), this._initStaged(), document.addEventListener("keydown", this._onKeyDown);
2654
+ }
2655
+ disconnectedCallback() {
2656
+ super.disconnectedCallback(), document.removeEventListener("keydown", this._onKeyDown);
2657
+ }
2658
+ _initStaged() {
2659
+ var i, n;
2660
+ const e = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Map();
2661
+ for (const r of this.files) {
2662
+ const l = /* @__PURE__ */ new Map();
2663
+ if (r.meta)
2664
+ for (const [d, p] of Object.entries(r.meta))
2665
+ l.set(d, p);
2666
+ e.set(r.id, l), t.add(r.id), s.set(r.id, r);
2667
+ }
2668
+ this._staged = e, this._selected = t, this._originalFiles = s, ((n = (i = this.schema) == null ? void 0 : i.fields) == null ? void 0 : n.length) > 0 && (this._activeFieldKey = this.schema.fields[0].key);
2669
+ }
2670
+ // -----------------------------------------------------------------------
2671
+ // Immutability helpers
2672
+ // -----------------------------------------------------------------------
2673
+ _setStagedValue(e, t, s) {
2674
+ const i = new Map(this._staged), n = new Map(i.get(e) ?? /* @__PURE__ */ new Map());
2675
+ n.set(t, s), i.set(e, n), this._staged = i;
2676
+ }
2677
+ _setStagedBulk(e) {
2678
+ const t = new Map(this._staged);
2679
+ for (const [s, i, n] of e) {
2680
+ const r = new Map(t.get(s) ?? /* @__PURE__ */ new Map());
2681
+ r.set(i, n), t.set(s, r);
2682
+ }
2683
+ this._staged = t;
2684
+ }
2685
+ // -----------------------------------------------------------------------
2686
+ // Active field + filled fields
2687
+ // -----------------------------------------------------------------------
2688
+ get _activeField() {
2689
+ var e, t;
2690
+ return (t = (e = this.schema) == null ? void 0 : e.fieldsByKey) == null ? void 0 : t.get(this._activeFieldKey);
2691
+ }
2692
+ /** Fields where ANY file has a non-empty staged value that differs from original. */
2693
+ get _filledFields() {
2694
+ var t, s;
2695
+ const e = /* @__PURE__ */ new Set();
2696
+ for (const i of ((t = this.schema) == null ? void 0 : t.fields) ?? [])
2697
+ for (const [n, r] of this._staged) {
2698
+ const l = r.get(i.key), d = (s = this._originalFiles.get(n)) == null ? void 0 : s.meta[i.key];
2699
+ if (l !== void 0 && !A(l) && JSON.stringify(l) !== JSON.stringify(d)) {
2700
+ e.add(i.key);
2701
+ break;
2702
+ }
2703
+ }
2704
+ return e;
2705
+ }
2706
+ // -----------------------------------------------------------------------
2707
+ // Event handlers
2708
+ // -----------------------------------------------------------------------
2709
+ get _hasPendingValue() {
2710
+ return this._pendingOp != null && !A(this._pendingOp.value);
2711
+ }
2712
+ /** Returns true if the caller should proceed; false if the user chose to stay. */
2713
+ _confirmDiscardPending() {
2714
+ return this._hasPendingValue ? confirm("You have unapplied bulk changes. Discard them?") : !0;
2715
+ }
2716
+ _emitClose() {
2717
+ this.dispatchEvent(
2718
+ new CustomEvent("metadata-close", {
2719
+ bubbles: !0,
2720
+ composed: !0
2721
+ })
2722
+ );
2723
+ }
2724
+ // -----------------------------------------------------------------------
2725
+ // Sorted files
2726
+ // -----------------------------------------------------------------------
2727
+ get _sortedFiles() {
2728
+ const e = [...this.files];
2729
+ return e.sort((t, s) => {
2730
+ const i = t.name.localeCompare(s.name) || t.id.localeCompare(s.id);
2731
+ return this._sortAsc ? i : -i;
2732
+ }), e;
2733
+ }
2734
+ // -----------------------------------------------------------------------
2735
+ // Render
2736
+ // -----------------------------------------------------------------------
2737
+ render() {
2738
+ var n, r;
2739
+ if (!((r = (n = this.schema) == null ? void 0 : n.fields) != null && r.length))
2740
+ return a`
2741
+ <div class="fm-overlay" @click=${this._onClose}>
2742
+ <div class="fm-modal" @click=${(l) => l.stopPropagation()}>
2743
+ <div class="fm-topbar">
2744
+ <span class="fm-topbar-title">Fill multiple assets</span>
2745
+ <button class="fm-topbar-close" @click=${this._onClose} title="Close">
2746
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
2747
+ <line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />
2748
+ </svg>
2749
+ </button>
2750
+ </div>
2751
+ <div class="fm-empty">No metadata fields configured</div>
2752
+ </div>
2753
+ </div>
2754
+ `;
2755
+ const e = this._activeField, t = this._sortedFiles, s = this._selected.size === this.files.length && this.files.length > 0, i = this._selected.size > 0 && !s;
2756
+ return a`
2757
+ <div class="fm-overlay" @click=${this._onClose}>
2758
+ <div class="fm-modal" @click=${(l) => l.stopPropagation()}>
2759
+ <!-- Top bar -->
2760
+ <div class="fm-topbar">
2761
+ <span class="fm-topbar-title">Fill multiple assets</span>
2762
+ <button class="fm-topbar-close" @click=${this._onClose} title="Close">
2763
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
2764
+ <line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />
2765
+ </svg>
2766
+ </button>
2767
+ </div>
2768
+
2769
+ <!-- Body -->
2770
+ <div class="fm-body">
2771
+ <!-- Sidebar -->
2772
+ <sfx-bulk-meta-sidebar
2773
+ .schema=${this.schema}
2774
+ .activeFieldKey=${this._activeFieldKey}
2775
+ .filledFields=${this._filledFields}
2776
+ .config=${this.config}
2777
+ @field-select=${this._onFieldSelect}
2778
+ ></sfx-bulk-meta-sidebar>
2779
+
2780
+ <!-- Main area -->
2781
+ <div class="fm-main">
2782
+ <!-- Op bar -->
2783
+ ${e ? a`
2784
+ <sfx-bulk-meta-op-bar
2785
+ .field=${e}
2786
+ .autocomplete=${this.autocomplete}
2787
+ .config=${this.config}
2788
+ .selectedCount=${this._selected.size}
2789
+ @bulk-apply=${this._onBulkApply}
2790
+ @pending-change=${this._onPendingChange}
2791
+ ></sfx-bulk-meta-op-bar>
2792
+ ` : f}
2793
+
2794
+ <!-- Table header -->
2795
+ <div class="fm-table-header">
2796
+ <div class="fm-th-check">
2797
+ <input
2798
+ type="checkbox"
2799
+ class="fm-checkbox"
2800
+ .checked=${s}
2801
+ .indeterminate=${i}
2802
+ @change=${this._onSelectAll}
2803
+ />
2804
+ </div>
2805
+ <div class="fm-th-thumb">Thumb</div>
2806
+ <div class="fm-th-name" @click=${this._onSortToggle}>
2807
+ Name
2808
+ <span class="fm-sort-arrow">${this._sortAsc ? "↑" : "↓"}</span>
2809
+ </div>
2810
+ <div class="fm-th-size">Size</div>
2811
+ <div class="fm-th-field">${(e == null ? void 0 : e.title) ?? ""}</div>
2812
+ </div>
2813
+
2814
+ <!-- Table body -->
2815
+ <div class="fm-table-body">
2816
+ ${e ? a`
2817
+ <sfx-bulk-meta-table
2818
+ .files=${t}
2819
+ .field=${e}
2820
+ .staged=${this._staged}
2821
+ .selected=${this._selected}
2822
+ .config=${this.config}
2823
+ .autocomplete=${this.autocomplete}
2824
+ .pendingOp=${this._pendingOp}
2825
+ @row-field-change=${this._onRowFieldChange}
2826
+ @row-toggle=${this._onRowToggle}
2827
+ ></sfx-bulk-meta-table>
2828
+ ` : f}
2829
+ </div>
2830
+ </div>
2831
+ </div>
2832
+
2833
+ <!-- Footer -->
2834
+ <div class="fm-footer">
2835
+ <button class="btn-back" @click=${this._onCancel}>
2836
+ \u2190 Back
2837
+ </button>
2838
+ <div class="spacer"></div>
2839
+ <button class="btn-ghost" @click=${this._onCancel}>Cancel</button>
2840
+ <button class="btn-primary" @click=${this._onSave}>Save</button>
2841
+ </div>
2842
+ </div>
2843
+ </div>
2844
+ `;
2845
+ }
2846
+ };
2847
+ $e.styles = [dt];
2848
+ let m = $e;
2849
+ E([
2850
+ c({ attribute: !1 })
2851
+ ], m.prototype, "schema");
2852
+ E([
2853
+ c({ attribute: !1 })
2854
+ ], m.prototype, "files");
2855
+ E([
2856
+ c({ attribute: !1 })
2857
+ ], m.prototype, "config");
2858
+ E([
2859
+ c({ attribute: !1 })
2860
+ ], m.prototype, "autocomplete");
2861
+ E([
2862
+ h()
2863
+ ], m.prototype, "_activeFieldKey");
2864
+ E([
2865
+ h()
2866
+ ], m.prototype, "_staged");
2867
+ E([
2868
+ h()
2869
+ ], m.prototype, "_selected");
2870
+ E([
2871
+ h()
2872
+ ], m.prototype, "_sortAsc");
2873
+ E([
2874
+ h()
2875
+ ], m.prototype, "_pendingOp");
2876
+ customElements.define("sfx-bulk-metadata-modal", m);
2877
+ const Oe = {
2878
+ // T — plain text
2879
+ text: a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
2880
+ ${g`<path d="M4 3h8M8 3v10"/>`}
2881
+ </svg>`,
2882
+ // Paragraph lines
2883
+ textarea: a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
2884
+ ${g`<line x1="3" y1="4" x2="13" y2="4"/><line x1="3" y1="7" x2="13" y2="7"/><line x1="3" y1="10" x2="9" y2="10"/>`}
2885
+ </svg>`,
2886
+ // Dropdown chevron
2887
+ "select-one": a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
2888
+ ${g`<rect x="2" y="3" width="12" height="10" rx="2"/><polyline points="6 7 8 9.5 10 7"/>`}
2889
+ </svg>`,
2890
+ // Checkboxes
2891
+ "multi-select": a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
2892
+ ${g`<rect x="2" y="2" width="5" height="5" rx="1"/><polyline points="3 4.5 4.2 6 6 3"/><rect x="2" y="9" width="5" height="5" rx="1"/><line x1="9" y1="4.5" x2="14" y2="4.5"/><line x1="9" y1="11.5" x2="14" y2="11.5"/>`}
2893
+ </svg>`,
2894
+ // Toggle
2895
+ boolean: a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
2896
+ ${g`<rect x="2" y="4.5" width="12" height="7" rx="3.5"/><circle cx="10.5" cy="8" r="2" fill="currentColor" stroke="none"/>`}
2897
+ </svg>`,
2898
+ // Calendar
2899
+ date: a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
2900
+ ${g`<rect x="2" y="3" width="12" height="11" rx="2"/><line x1="2" y1="7" x2="14" y2="7"/><line x1="5.5" y1="1.5" x2="5.5" y2="4.5"/><line x1="10.5" y1="1.5" x2="10.5" y2="4.5"/>`}
2901
+ </svg>`,
2902
+ // Hash #
2903
+ numeric: a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
2904
+ ${g`<line x1="6" y1="2" x2="4.5" y2="14"/><line x1="11.5" y1="2" x2="10" y2="14"/><line x1="3" y1="6" x2="13" y2="6"/><line x1="3" y1="10" x2="13" y2="10"/>`}
2905
+ </svg>`,
2906
+ // Circle + decimal marks
2907
+ decimal2: a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
2908
+ ${g`<circle cx="5.5" cy="8" r="3"/><circle cx="12" cy="11" r="1" fill="currentColor" stroke="none"/><line x1="10" y1="5" x2="13" y2="5"/><line x1="10" y1="8" x2="13" y2="8"/>`}
2909
+ </svg>`,
2910
+ // Map pin
2911
+ geopoint: a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
2912
+ ${g`<path d="M8 1.5a4.5 4.5 0 0 1 4.5 4.5c0 3.5-4.5 8.5-4.5 8.5S3.5 9.5 3.5 6A4.5 4.5 0 0 1 8 1.5Z"/><circle cx="8" cy="6" r="1.5"/>`}
2913
+ </svg>`,
2914
+ // Numbered list
2915
+ "integer-list": a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
2916
+ ${g`<line x1="7" y1="4" x2="14" y2="4"/><line x1="7" y1="8" x2="14" y2="8"/><line x1="7" y1="12" x2="14" y2="12"/><text x="2" y="5.5" font-size="4.5" fill="currentColor" stroke="none" font-family="inherit">1</text><text x="2" y="9.5" font-size="4.5" fill="currentColor" stroke="none" font-family="inherit">2</text><text x="2" y="13.5" font-size="4.5" fill="currentColor" stroke="none" font-family="inherit">3</text>`}
2917
+ </svg>`,
2918
+ // Tag label
2919
+ tags: a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
2920
+ ${g`<path d="M1.5 2.5h5.6l7.4 5.5-5.5 5.5-7.5-5.4z"/><circle cx="5" cy="6" r="1" fill="currentColor" stroke="none"/>`}
2921
+ </svg>`,
2922
+ // Link chain
2923
+ "attachment-uri": a`<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
2924
+ ${g`<path d="M7 9l2-2"/><path d="M9.5 6.5l1.8-1.8a2.1 2.1 0 0 1 3 3L12.5 9.5"/><path d="M6.5 9.5L4.7 11.3a2.1 2.1 0 0 1-3-3L3.5 6.5"/>`}
2925
+ </svg>`
2926
+ };
2927
+ function bt(o) {
2928
+ return Oe[o] ?? Oe.text;
2929
+ }
2930
+ var gt = Object.defineProperty, W = (o, e, t, s) => {
2931
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
2932
+ (r = o[n]) && (i = r(e, t, i) || i);
2933
+ return i && gt(e, t, i), i;
2934
+ };
2935
+ const Ce = class Ce extends w {
2936
+ constructor() {
2937
+ super(...arguments), this.activeFieldKey = "", this.filledFields = /* @__PURE__ */ new Set(), this.config = null, this._collapsed = /* @__PURE__ */ new Set();
2938
+ }
2939
+ _isRequired(e) {
2940
+ var t, s;
2941
+ return (s = (t = this.config) == null ? void 0 : t.requiredFields) != null && s.includes(e.ckey) ? !0 : e.required === 1;
2942
+ }
2943
+ _toggleGroup(e) {
2944
+ const t = new Set(this._collapsed);
2945
+ t.has(e) ? t.delete(e) : t.add(e), this._collapsed = t;
2946
+ }
2947
+ _onFieldClick(e) {
2948
+ this.dispatchEvent(
2949
+ new CustomEvent("field-select", {
2950
+ detail: { fieldKey: e },
2951
+ bubbles: !0,
2952
+ composed: !0
2953
+ })
2954
+ );
2955
+ }
2956
+ render() {
2957
+ return this.schema ? a`
2958
+ ${this.schema.groups.map((e) => {
2959
+ const t = !this._collapsed.has(e.uuid);
2960
+ return a`
2961
+ <button
2962
+ class="group-label"
2963
+ @click=${() => this._toggleGroup(e.uuid)}
2964
+ aria-expanded=${t}
2965
+ >
2966
+ <span class="group-label-text">${e.name}</span>
2967
+ <svg class="group-chevron ${t ? "open" : ""}" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2968
+ <polyline points="4 6 8 10 12 6"/>
2969
+ </svg>
2970
+ </button>
2971
+ ${t ? e.fields.map(
2972
+ (s) => a`
2973
+ <button
2974
+ class="field-item ${this.activeFieldKey === s.key ? "active" : ""}"
2975
+ @click=${() => this._onFieldClick(s.key)}
2976
+ >
2977
+ <span class="field-icon" aria-hidden="true">${bt(s.type)}</span>
2978
+ <span class="field-name">${s.title}</span>
2979
+ ${this.filledFields.has(s.key) ? a`<span class="field-dot"></span>` : f}
2980
+ ${this._isRequired(s) ? a`<span class="field-required" aria-hidden="true">*</span>` : f}
2981
+ </button>
2982
+ `
2983
+ ) : f}
2984
+ `;
2985
+ })}
2986
+ ` : f;
2987
+ }
2988
+ };
2989
+ Ce.styles = [ct];
2990
+ let O = Ce;
2991
+ W([
2992
+ c({ attribute: !1 })
2993
+ ], O.prototype, "schema");
2994
+ W([
2995
+ c({ attribute: !1 })
2996
+ ], O.prototype, "activeFieldKey");
2997
+ W([
2998
+ c({ attribute: !1 })
2999
+ ], O.prototype, "filledFields");
3000
+ W([
3001
+ c({ attribute: !1 })
3002
+ ], O.prototype, "config");
3003
+ W([
3004
+ h()
3005
+ ], O.prototype, "_collapsed");
3006
+ customElements.define("sfx-bulk-meta-sidebar", O);
3007
+ var mt = Object.defineProperty, B = (o, e, t, s) => {
3008
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
3009
+ (r = o[n]) && (i = r(e, t, i) || i);
3010
+ return i && mt(e, t, i), i;
3011
+ }, F;
3012
+ const D = (F = class extends w {
3013
+ constructor() {
3014
+ super(...arguments), this.config = null, this.selectedCount = 0, this._operation = "SET", this._value = void 0, this._opDropdownOpen = !1, this._availableOps = [], this._onOpDropdownClose = (e) => {
3015
+ e.composedPath().includes(this) || (this._opDropdownOpen = !1);
3016
+ }, this._onFieldBlur = (e) => {
3017
+ e.stopPropagation(), this._value = e.detail.value, this._emitPendingChange();
3018
+ }, this._onFieldChange = (e) => {
3019
+ e.stopPropagation(), this._value = e.detail.value, this._emitPendingChange();
3020
+ }, this._onFieldEscape = (e) => {
3021
+ e.stopPropagation();
3022
+ };
3023
+ }
3024
+ static _emptyValueForType(e) {
3025
+ switch (e) {
3026
+ case "multi-select":
3027
+ case "tags":
3028
+ case "integer-list":
3029
+ return [];
3030
+ case "boolean":
3031
+ return "null";
3032
+ case "geopoint":
3033
+ return { latitude: "", longitude: "" };
3034
+ default:
3035
+ return "";
3036
+ }
3037
+ }
3038
+ get _effectiveValue() {
3039
+ var e;
3040
+ return this._value ?? F._emptyValueForType((e = this.field) == null ? void 0 : e.type);
3041
+ }
3042
+ willUpdate(e) {
3043
+ e.has("field") && this.field && (this._availableOps = lt(this.field.type), this._operation = "SET", this._value = void 0, this._emitPendingChange());
3044
+ }
3045
+ _onOpSelect(e) {
3046
+ this._operation = e, this._opDropdownOpen = !1, this._emitPendingChange();
3047
+ }
3048
+ _onOpToggle() {
3049
+ this._opDropdownOpen = !this._opDropdownOpen;
3050
+ }
3051
+ connectedCallback() {
3052
+ super.connectedCallback(), document.addEventListener("click", this._onOpDropdownClose);
3053
+ }
3054
+ disconnectedCallback() {
3055
+ super.disconnectedCallback(), document.removeEventListener("click", this._onOpDropdownClose);
3056
+ }
3057
+ _emitPendingChange() {
3058
+ this.dispatchEvent(
3059
+ new CustomEvent("pending-change", {
3060
+ detail: { operation: this._operation, value: this._value },
3061
+ bubbles: !0,
3062
+ composed: !0
3063
+ })
3064
+ );
3065
+ }
3066
+ _onApply() {
3067
+ this._isApplyDisabled || (this.dispatchEvent(
3068
+ new CustomEvent("bulk-apply", {
3069
+ detail: {
3070
+ operation: this._operation,
3071
+ value: this._value
3072
+ },
3073
+ bubbles: !0,
3074
+ composed: !0
3075
+ })
3076
+ ), this._value = void 0, this._emitPendingChange());
3077
+ }
3078
+ _onClear() {
3079
+ this._value = void 0, this._emitPendingChange();
3080
+ }
3081
+ get _isApplyDisabled() {
3082
+ return this.selectedCount === 0 ? !0 : this._operation === "DELETE" ? !1 : A(this._value);
3083
+ }
3084
+ render() {
3085
+ if (!this.field) return f;
3086
+ const e = this._availableOps.length > 1, t = this._availableOps.find((s) => s.key === this._operation);
3087
+ return a`
3088
+ <div class="op-bar">
3089
+ <span class="op-label">Operation:</span>
3090
+
3091
+ ${e ? a`
3092
+ <div class="op-dropdown-wrap">
3093
+ <button class="op-trigger" @click=${this._onOpToggle}>
3094
+ <span>${(t == null ? void 0 : t.label) ?? "Set"}</span>
3095
+ <span class="op-arrow">\u25BE</span>
3096
+ </button>
3097
+ ${this._opDropdownOpen ? a`
3098
+ <div class="op-menu">
3099
+ ${this._availableOps.map(
3100
+ (s) => a`
3101
+ <button
3102
+ class="op-option ${s.key === this._operation ? "active" : ""}"
3103
+ @click=${() => this._onOpSelect(s.key)}
3104
+ >
3105
+ ${s.label}
3106
+ </button>
3107
+ `
3108
+ )}
3109
+ </div>
3110
+ ` : f}
3111
+ </div>
3112
+ ` : a`<span class="op-label">${(t == null ? void 0 : t.label) ?? "Set"}</span>`}
3113
+
3114
+ <div
3115
+ class="op-value"
3116
+ @field-blur=${this._onFieldBlur}
3117
+ @field-change=${this._onFieldChange}
3118
+ @field-escape=${this._onFieldEscape}
3119
+ >
3120
+ <sfx-metadata-field-edit
3121
+ .field=${this.field}
3122
+ .value=${this._effectiveValue}
3123
+ .autocomplete=${this.autocomplete}
3124
+ ></sfx-metadata-field-edit>
3125
+ </div>
3126
+
3127
+ ${A(this._value) ? f : a`
3128
+ <button
3129
+ class="btn-clear"
3130
+ @click=${this._onClear}
3131
+ title="Clear"
3132
+ aria-label="Clear input"
3133
+ >
3134
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
3135
+ <line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" />
3136
+ </svg>
3137
+ </button>
3138
+ `}
3139
+
3140
+ <button
3141
+ class="btn-apply"
3142
+ ?disabled=${this._isApplyDisabled}
3143
+ @click=${this._onApply}
3144
+ >
3145
+ Apply
3146
+ </button>
3147
+ </div>
3148
+ `;
3149
+ }
3150
+ }, F.styles = [pt], F);
3151
+ B([
3152
+ c({ attribute: !1 })
3153
+ ], D.prototype, "field");
3154
+ B([
3155
+ c({ attribute: !1 })
3156
+ ], D.prototype, "autocomplete");
3157
+ B([
3158
+ c({ attribute: !1 })
3159
+ ], D.prototype, "config");
3160
+ B([
3161
+ c({ type: Number })
3162
+ ], D.prototype, "selectedCount");
3163
+ B([
3164
+ h()
3165
+ ], D.prototype, "_operation");
3166
+ B([
3167
+ h()
3168
+ ], D.prototype, "_value");
3169
+ B([
3170
+ h()
3171
+ ], D.prototype, "_opDropdownOpen");
3172
+ let vt = D;
3173
+ customElements.define("sfx-bulk-meta-op-bar", vt);
3174
+ var _t = Object.defineProperty, j = (o, e, t, s) => {
3175
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
3176
+ (r = o[n]) && (i = r(e, t, i) || i);
3177
+ return i && _t(e, t, i), i;
3178
+ };
3179
+ const Se = class Se extends w {
3180
+ constructor() {
3181
+ super(...arguments), this.files = [], this.staged = /* @__PURE__ */ new Map(), this.selected = /* @__PURE__ */ new Set(), this.config = null, this.pendingOp = null;
3182
+ }
3183
+ _getEffectiveValue(e) {
3184
+ var t;
3185
+ return ((t = this.staged.get(e.id)) == null ? void 0 : t.get(this.field.key)) ?? e.meta[this.field.key];
3186
+ }
3187
+ render() {
3188
+ return a`
3189
+ ${this.files.map(
3190
+ (e) => a`
3191
+ <sfx-bulk-meta-row
3192
+ .file=${e}
3193
+ .field=${this.field}
3194
+ .value=${this._getEffectiveValue(e)}
3195
+ .selected=${this.selected.has(e.id)}
3196
+ .config=${this.config}
3197
+ .autocomplete=${this.autocomplete}
3198
+ .pendingOp=${this.selected.has(e.id) ? this.pendingOp : null}
3199
+ ></sfx-bulk-meta-row>
3200
+ `
3201
+ )}
3202
+ `;
3203
+ }
3204
+ };
3205
+ Se.styles = [ht];
3206
+ let $ = Se;
3207
+ j([
3208
+ c({ attribute: !1 })
3209
+ ], $.prototype, "files");
3210
+ j([
3211
+ c({ attribute: !1 })
3212
+ ], $.prototype, "field");
3213
+ j([
3214
+ c({ attribute: !1 })
3215
+ ], $.prototype, "staged");
3216
+ j([
3217
+ c({ attribute: !1 })
3218
+ ], $.prototype, "selected");
3219
+ j([
3220
+ c({ attribute: !1 })
3221
+ ], $.prototype, "config");
3222
+ j([
3223
+ c({ attribute: !1 })
3224
+ ], $.prototype, "autocomplete");
3225
+ j([
3226
+ c({ attribute: !1 })
3227
+ ], $.prototype, "pendingOp");
3228
+ customElements.define("sfx-bulk-meta-table", $);
3229
+ const yt = /* @__PURE__ */ new Set(["multi-select", "tags", "integer-list"]);
3230
+ function De(o, e, t) {
3231
+ return !e.regional_variants_group_uuid || o == null || typeof o != "object" || Array.isArray(o) ? o : o[t ?? "en"];
3232
+ }
3233
+ function ze(o) {
3234
+ return Array.isArray(o) ? o : [];
3235
+ }
3236
+ function Pe(o) {
3237
+ return !!(o == null || o === "" || Array.isArray(o) && o.length === 0);
3238
+ }
3239
+ function oe(o, e) {
3240
+ var s;
3241
+ const t = (s = o.possible_values) == null ? void 0 : s.find(
3242
+ (i) => i.internal_unique_value === e || i.api_value === e
3243
+ );
3244
+ return (t == null ? void 0 : t.label) ?? String(e);
3245
+ }
3246
+ function qe(o, e) {
3247
+ if (e == null || e === "") return "";
3248
+ switch (o.type) {
3249
+ case "boolean":
3250
+ return e === !0 ? "True" : e === !1 ? "False" : "None";
3251
+ case "date": {
3252
+ if (typeof e != "string" || e.length === 0) return "";
3253
+ try {
3254
+ return (/* @__PURE__ */ new Date(e + "T00:00")).toLocaleDateString(void 0, {
3255
+ year: "numeric",
3256
+ month: "short",
3257
+ day: "numeric"
3258
+ });
3259
+ } catch {
3260
+ return e;
3261
+ }
3262
+ }
3263
+ case "numeric": {
3264
+ const t = Number(e);
3265
+ return Number.isFinite(t) ? t.toLocaleString(void 0, { maximumFractionDigits: 0 }) : String(e);
3266
+ }
3267
+ case "decimal2": {
3268
+ const t = Number(e);
3269
+ return Number.isFinite(t) ? t.toLocaleString(void 0, { maximumFractionDigits: 2 }) : String(e);
3270
+ }
3271
+ case "select-one":
3272
+ return oe(o, String(e));
3273
+ case "geopoint": {
3274
+ if (typeof e == "string") {
3275
+ const t = e.match(/^\((.+),(.+)\)$/);
3276
+ if (t) return `(${t[1].trim()}, ${t[2].trim()})`;
3277
+ }
3278
+ return String(e);
3279
+ }
3280
+ default:
3281
+ return String(e);
3282
+ }
3283
+ }
3284
+ function wt(o, e) {
3285
+ const t = o.map((l) => typeof l == "string" ? l : String(l)), s = e.map((l) => typeof l == "string" ? l : String(l)), i = new Set(t), n = new Set(s), r = [];
3286
+ for (const l of s)
3287
+ r.push({ label: l, state: i.has(l) ? "kept" : "added" });
3288
+ for (const l of t)
3289
+ n.has(l) || r.push({ label: l, state: "removed" });
3290
+ return r;
3291
+ }
3292
+ function kt(o, e, t) {
3293
+ const s = new Set(o.map((r) => JSON.stringify(r))), i = new Set(e.map((r) => JSON.stringify(r))), n = [];
3294
+ for (const r of e) {
3295
+ const l = JSON.stringify(r), d = typeof r == "string" ? oe(t, r) : String(r);
3296
+ n.push({ label: d, state: s.has(l) ? "kept" : "added" });
3297
+ }
3298
+ for (const r of o) {
3299
+ const l = JSON.stringify(r);
3300
+ if (!i.has(l)) {
3301
+ const d = typeof r == "string" ? oe(t, r) : String(r);
3302
+ n.push({ label: d, state: "removed" });
3303
+ }
3304
+ }
3305
+ return n;
3306
+ }
3307
+ function $t(o, e, t, s) {
3308
+ const i = s == null ? void 0 : s.language, n = De(e, o, i), r = De(t, o, i);
3309
+ if (yt.has(o.type)) {
3310
+ const l = ze(n), d = ze(r);
3311
+ return o.type === "tags" ? { kind: "array", items: wt(l, d) } : { kind: "array", items: kt(l, d, o) };
3312
+ }
3313
+ return {
3314
+ kind: "scalar",
3315
+ oldDisplay: qe(o, n),
3316
+ newDisplay: qe(o, r),
3317
+ oldEmpty: Pe(n),
3318
+ newEmpty: Pe(r)
3319
+ };
3320
+ }
3321
+ var Ct = Object.defineProperty, ee = (o, e, t, s) => {
3322
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
3323
+ (r = o[n]) && (i = r(e, t, i) || i);
3324
+ return i && Ct(e, t, i), i;
3325
+ };
3326
+ const Ie = class Ie extends w {
3327
+ constructor() {
3328
+ super(...arguments), this.config = null;
3329
+ }
3330
+ _renderArrayDiff(e) {
3331
+ return a`
3332
+ <div class="diff-wrap" aria-label="Bulk operation preview">
3333
+ ${e.items.length === 0 ? a`<span class="diff-chip diff-chip--kept" style="opacity:0.5">\u2014</span>` : e.items.map(
3334
+ (t) => a`
3335
+ <span
3336
+ class="diff-chip diff-chip--${t.state}"
3337
+ aria-label="${t.state === "added" ? "Added" : t.state === "removed" ? "Removed" : "Kept"}: ${t.label}"
3338
+ >
3339
+ ${t.state === "removed" ? a`<s>${t.label}</s>` : t.label}
3340
+ </span>
3341
+ `
3342
+ )}
3343
+ </div>
3344
+ `;
3345
+ }
3346
+ _renderScalarDiff(e) {
3347
+ const t = `Will change from ${e.oldEmpty ? "empty" : e.oldDisplay} to ${e.newEmpty ? "empty" : e.newDisplay}`;
3348
+ return a`
3349
+ <div class="diff-wrap diff-scalar-text" aria-label="Bulk operation preview">
3350
+ <span class="sr-only">${t}</span>
3351
+ ${e.oldEmpty ? f : a`
3352
+ <span class="diff-old" aria-hidden="true"><s>${e.oldDisplay}</s></span>
3353
+ ${e.newEmpty ? f : a`<span class="diff-arrow" aria-hidden="true">\u2192</span>`}
3354
+ `}
3355
+ ${e.newEmpty ? f : a`<span class="diff-new" aria-hidden="true">${e.newDisplay}</span>`}
3356
+ </div>
3357
+ `;
3358
+ }
3359
+ render() {
3360
+ if (!this.field) return f;
3361
+ const e = $t(
3362
+ this.field,
3363
+ this.oldValue,
3364
+ this.newValue,
3365
+ this.config
3366
+ );
3367
+ return e.kind === "array" ? this._renderArrayDiff(e) : this._renderScalarDiff(e);
3368
+ }
3369
+ };
3370
+ Ie.styles = [ft];
3371
+ let L = Ie;
3372
+ ee([
3373
+ c({ attribute: !1 })
3374
+ ], L.prototype, "field");
3375
+ ee([
3376
+ c({ attribute: !1 })
3377
+ ], L.prototype, "oldValue");
3378
+ ee([
3379
+ c({ attribute: !1 })
3380
+ ], L.prototype, "newValue");
3381
+ ee([
3382
+ c({ attribute: !1 })
3383
+ ], L.prototype, "config");
3384
+ customElements.define("sfx-bulk-meta-diff-view", L);
3385
+ var St = Object.defineProperty, z = (o, e, t, s) => {
3386
+ for (var i = void 0, n = o.length - 1, r; n >= 0; n--)
3387
+ (r = o[n]) && (i = r(e, t, i) || i);
3388
+ return i && St(e, t, i), i;
3389
+ };
3390
+ const Ee = class Ee extends w {
3391
+ constructor() {
3392
+ super(...arguments), this.selected = !1, this.config = null, this.pendingOp = null, this._error = null, this._onFieldBlur = (e) => {
3393
+ var r;
3394
+ e.stopPropagation();
3395
+ const { value: t } = e.detail, s = Le(this.field, t, this.config ?? void 0);
3396
+ if (s) {
3397
+ this._error = s;
3398
+ return;
3399
+ }
3400
+ this._error = null;
3401
+ const i = {
3402
+ meta: { ...this.file.meta, [this.field.key]: this.value }
3403
+ }, n = Q(
3404
+ this.field,
3405
+ t,
3406
+ i,
3407
+ (r = this.config) == null ? void 0 : r.language
3408
+ );
3409
+ JSON.stringify(n) !== JSON.stringify(this.value) && this.dispatchEvent(
3410
+ new CustomEvent("row-field-change", {
3411
+ detail: { fileId: this.file.id, value: n },
3412
+ bubbles: !0,
3413
+ composed: !0
3414
+ })
3415
+ );
3416
+ };
3417
+ }
3418
+ willUpdate(e) {
3419
+ e.has("field") && (this._error = null);
3420
+ }
3421
+ _onCheckboxChange() {
3422
+ this.dispatchEvent(
3423
+ new CustomEvent("row-toggle", {
3424
+ detail: { fileId: this.file.id },
3425
+ bubbles: !0,
3426
+ composed: !0
3427
+ })
3428
+ );
3429
+ }
3430
+ _getExtension(e) {
3431
+ const t = e.lastIndexOf(".");
3432
+ return t > 0 ? e.slice(t + 1).toUpperCase() : "?";
3433
+ }
3434
+ /**
3435
+ * Compute what the value would become if the pending bulk operation were applied.
3436
+ * Returns null if there's no pending op or the preview equals the current value.
3437
+ */
3438
+ _computePreview() {
3439
+ var l;
3440
+ if (!this.pendingOp) return null;
3441
+ const { operation: e, value: t } = this.pendingOp, s = (l = this.config) == null ? void 0 : l.language, i = {
3442
+ meta: { ...this.file.meta, [this.field.key]: this.value }
3443
+ }, n = Q(
3444
+ this.field,
3445
+ t,
3446
+ i,
3447
+ s
3448
+ ), r = Ke(
3449
+ e,
3450
+ this.value,
3451
+ n,
3452
+ this.field.type
3453
+ );
3454
+ return JSON.stringify(r) === JSON.stringify(this.value) ? null : r;
3455
+ }
3456
+ render() {
3457
+ var i;
3458
+ const e = this.file, t = this._computePreview(), s = t !== null;
3459
+ return a`
3460
+ <div class="row ${s ? "row--changed" : ""}">
3461
+ <div class="row-check">
3462
+ <input
3463
+ type="checkbox"
3464
+ class="fm-checkbox"
3465
+ .checked=${this.selected}
3466
+ @change=${this._onCheckboxChange}
3467
+ />
3468
+ </div>
3469
+
3470
+ ${e.previewUrl ? a`<img class="row-thumb" src=${e.previewUrl} alt="" />` : a`<div class="row-thumb-placeholder">${this._getExtension(e.name)}</div>`}
3471
+
3472
+ <div class="row-name" title=${e.name}>${e.name}</div>
3473
+ <div class="row-size">${e.size ? Ve(e.size) : "—"}</div>
3474
+
3475
+ <div
3476
+ class="row-field"
3477
+ @field-blur=${this._onFieldBlur}
3478
+ >
3479
+ ${s ? a`
3480
+ <sfx-bulk-meta-diff-view
3481
+ .field=${this.field}
3482
+ .oldValue=${this.value}
3483
+ .newValue=${t}
3484
+ .config=${this.config}
3485
+ ></sfx-bulk-meta-diff-view>
3486
+ ` : a`
3487
+ <div class="row-field-edit">
3488
+ <sfx-metadata-field-edit
3489
+ .field=${this.field}
3490
+ .value=${Te(this.field, this.value, (i = this.config) == null ? void 0 : i.language)}
3491
+ .autocomplete=${this.autocomplete}
3492
+ ></sfx-metadata-field-edit>
3493
+ </div>
3494
+ `}
3495
+ ${this._error ? a`<div class="row-error" role="alert">${this._error}</div>` : f}
3496
+ </div>
3497
+ </div>
3498
+ `;
3499
+ }
3500
+ };
3501
+ Ee.styles = [ut];
3502
+ let y = Ee;
3503
+ z([
3504
+ c({ attribute: !1 })
3505
+ ], y.prototype, "file");
3506
+ z([
3507
+ c({ attribute: !1 })
3508
+ ], y.prototype, "field");
3509
+ z([
3510
+ c({ attribute: !1 })
3511
+ ], y.prototype, "value");
3512
+ z([
3513
+ c({ type: Boolean })
3514
+ ], y.prototype, "selected");
3515
+ z([
3516
+ c({ attribute: !1 })
3517
+ ], y.prototype, "config");
3518
+ z([
3519
+ c({ attribute: !1 })
3520
+ ], y.prototype, "autocomplete");
3521
+ z([
3522
+ c({ attribute: !1 })
3523
+ ], y.prototype, "pendingOp");
3524
+ z([
3525
+ h()
3526
+ ], y.prototype, "_error");
3527
+ customElements.define("sfx-bulk-meta-row", y);
3528
+ export {
3529
+ m as SfxBulkMetadataModal,
3530
+ Dt as clearSchemaCache,
3531
+ qt as createTagsAutocomplete,
3532
+ Pt as deepMergeMeta,
3533
+ Ot as fetchMetadataSchema,
3534
+ zt as getFilesWithMissingRequired,
3535
+ Ue as isAssetHasMetadataValue,
3536
+ A as isEmpty,
3537
+ Te as mapValueFromBackend,
3538
+ Q as mapValueToBackend,
3539
+ Fe as parseMetadataSchema,
3540
+ Le as validateField
3541
+ };