@pipelex/mthds-form 0.23.2 → 0.25.0

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.
@@ -1,9 +1,9 @@
1
- import { planFileSave, planStuffSave, splitFileName, typedFileStem } from './chunk-ICUEHNEH.js';
1
+ import { planFileSave, planStuffSave, splitFileName, typedFileStem } from './chunk-QWHUUMSB.js';
2
2
  import { seedInputs, closeOptionalStructures, openOptionalStructures } from './chunk-VH5CDQDR.js';
3
- import { sourceFileValue, roomForChosenFiles, addChosenFiles, chosenFilesAdded } from './chunk-O2VIVDHO.js';
4
- import { readStuffFile } from './chunk-RRTI7AIR.js';
3
+ import { sourceFileValue, roomForChosenFiles, roomForDroppedFiles, addChosenFiles, placeDroppedFiles, chosenFilesAdded } from './chunk-NSHGLM6A.js';
4
+ import { readStuffFile } from './chunk-QINLJ5RM.js';
5
5
  import { apiInputsFromRunValues, sameRunValues, runValuesFromInputs, setValueAtPath } from './chunk-ZX52CQJ4.js';
6
- import { viewableUrl, isNativeDateNode, isNativeHtmlNode, readHtmlContent, isNativeCompositeNode, readCompositeContent, isNativeValueNode, readDateContent, formatDateContent, readImageContent, readDataUrl, readDocumentContent } from './chunk-CM4KVG53.js';
6
+ import { TYPED_SCALAR_MARKERS, viewableUrl, isNativeDateNode, isNativeHtmlNode, readHtmlContent, isNativeCompositeNode, readCompositeContent, isNativePageNode, nativeVerdictOf, isNativeValueNode, readDateContent, formatDateContent, readPageContent, readYesNoContent, readRatingContent, readChoiceContent, readImageContent, readDataUrl, readDocumentContent } from './chunk-JSPF4BQP.js';
7
7
  import { buildRunFields } from './chunk-ZB4RYUKV.js';
8
8
  import { conceptCategory } from './chunk-FABY3DEY.js';
9
9
  import { acceptLabel, acceptMap, isAcceptedFile, normalizeMimeType, formatOfFilename, DOCUMENT_FORMATS, IMAGE_FORMATS } from './chunk-XCO6GTEC.js';
@@ -31,6 +31,9 @@ import { marked } from 'marked';
31
31
  function cn(...inputs) {
32
32
  return twMerge(clsx(inputs));
33
33
  }
34
+ function isThenable(answer) {
35
+ return (typeof answer === "object" || typeof answer === "function") && answer !== null && typeof answer.then === "function";
36
+ }
34
37
  var CATEGORY_ICON = {
35
38
  text: Type,
36
39
  date: CalendarDays,
@@ -216,12 +219,16 @@ var DAY_YEAR = new Intl.DateTimeFormat("en-GB", {
216
219
  month: "short",
217
220
  year: "numeric"
218
221
  });
222
+ var PERCENT = new Intl.NumberFormat("en-GB", { style: "percent", maximumFractionDigits: 0 });
219
223
  function formatFileDate(date) {
220
224
  const days = calendarDaysBefore(date);
221
225
  if (days === 0) return `Today, ${TIME.format(date)}`;
222
226
  if (days === 1) return "Yesterday";
223
227
  return inCurrentYear(date) ? DAY.format(date) : DAY_YEAR.format(date);
224
228
  }
229
+ function someNames(names, more) {
230
+ return AND.format(more > 0 ? [...names, `${more} more`] : names);
231
+ }
225
232
  var EN_FIELD_STRINGS = {
226
233
  optionalBadge: "optional",
227
234
  selectPlaceholder: "Select\u2026",
@@ -275,7 +282,24 @@ var EN_FIELD_STRINGS = {
275
282
  resultViewGroup: "Result view",
276
283
  yes: "Yes",
277
284
  no: "No",
285
+ yesProbability: (share) => `Probability of yes: ${PERCENT.format(share)}`,
286
+ verdictConfidence: (share) => `Confidence: ${PERCENT.format(share)}`,
287
+ ratingLevel: (position) => `Level ${position}`,
288
+ pageNumber: (position) => `Page ${position}`,
289
+ extractedTable: "Table",
278
290
  unsupportedFileType: (formats) => `That file type is not supported. Accepted formats: ${formats}.`,
291
+ dropFilesOrBrowse: "Drop files or click to browse",
292
+ dropFilesToAdd: "Drop to add the files",
293
+ addFilesAria: (label) => label ? `Add files to ${label}` : "Add files",
294
+ filesAdded: (count) => count === 1 ? "1 file added" : `${count} files added`,
295
+ filesRefused: (names, more, formats) => `${names.length + more === 1 ? "Not added, because its" : "Not added, because their"} file type is not supported: ${someNames(names, more)}. Accepted formats: ${formats}.`,
296
+ filesLeftOut: (names, more, fitted) => {
297
+ const these = names.length + more === 1 ? "this file was" : "these files were";
298
+ const room = fitted === 0 ? "The list is full" : `The list had room for ${fitted === 1 ? "1 more file" : `${fitted} more files`}`;
299
+ return `${room}, so ${these} not added: ${someNames(names, more)}.`;
300
+ },
301
+ oneFileOnly: "This field takes one file.",
302
+ oneFileOnlyInList: "This field takes one file. Drop several files on the list's drop area.",
279
303
  hideOptionalFields: "Hide optional fields",
280
304
  hideOptionalInputs: "Hide optional inputs",
281
305
  optionalFieldsCount: (count) => count === 1 ? "1 optional field" : `${count} optional fields`,
@@ -363,6 +387,7 @@ var DAY_YEAR2 = new Intl.DateTimeFormat("fr-FR", {
363
387
  month: "short",
364
388
  year: "numeric"
365
389
  });
390
+ var PERCENT2 = new Intl.NumberFormat("fr-FR", { style: "percent", maximumFractionDigits: 0 });
366
391
  function formatFileDate2(date) {
367
392
  const days = calendarDaysBefore(date);
368
393
  if (days === 0) return `Aujourd\u2019hui, ${TIME2.format(date)}`;
@@ -377,6 +402,9 @@ function formatBytes2(bytes) {
377
402
  if (bytes < 1024 * 1024) return KILOBYTES.format(bytes / 1024);
378
403
  return MEGABYTES.format(bytes / (1024 * 1024));
379
404
  }
405
+ function someNames2(names, more) {
406
+ return AND2.format(more > 0 ? [...names, `${more} ${plural(more, "autre", "autres")}`] : names);
407
+ }
380
408
  var FR_FIELD_STRINGS = {
381
409
  optionalBadge: "facultatif",
382
410
  selectPlaceholder: "Choisir\u2026",
@@ -430,7 +458,24 @@ var FR_FIELD_STRINGS = {
430
458
  resultViewGroup: "Affichage du r\xE9sultat",
431
459
  yes: "Oui",
432
460
  no: "Non",
461
+ yesProbability: (share) => `Probabilit\xE9 du oui\xA0: ${PERCENT2.format(share)}`,
462
+ verdictConfidence: (share) => `Confiance\xA0: ${PERCENT2.format(share)}`,
463
+ ratingLevel: (position) => `Niveau ${position}`,
464
+ pageNumber: (position) => `Page ${position}`,
465
+ extractedTable: "Tableau",
433
466
  unsupportedFileType: (formats) => `Ce type de fichier n\u2019est pas pris en charge. Formats accept\xE9s\xA0: ${formats}.`,
467
+ dropFilesOrBrowse: "D\xE9posez des fichiers ou cliquez pour parcourir",
468
+ dropFilesToAdd: "D\xE9posez pour ajouter les fichiers",
469
+ addFilesAria: (label) => label ? `Ajouter des fichiers \xE0 ${label}` : "Ajouter des fichiers",
470
+ filesAdded: (count) => `${count} ${plural(count, "fichier ajout\xE9", "fichiers ajout\xE9s")}`,
471
+ filesRefused: (names, more, formats) => `${names.length + more === 1 ? "Non ajout\xE9, car son type n\u2019est pas pris en charge" : "Non ajout\xE9s, car leur type n\u2019est pas pris en charge"}\xA0: ${someNames2(names, more)}. Formats accept\xE9s\xA0: ${formats}.`,
472
+ filesLeftOut: (names, more, fitted) => {
473
+ const these = names.length + more === 1 ? "ce fichier n\u2019a donc pas \xE9t\xE9 ajout\xE9" : "ces fichiers n\u2019ont donc pas \xE9t\xE9 ajout\xE9s";
474
+ const room = fitted === 0 ? "La liste est pleine" : `La liste n\u2019avait de place que pour ${fitted} ${plural(fitted, "fichier", "fichiers")} de plus`;
475
+ return `${room}, ${these}\xA0: ${someNames2(names, more)}.`;
476
+ },
477
+ oneFileOnly: "Ce champ accepte un seul fichier.",
478
+ oneFileOnlyInList: "Ce champ accepte un seul fichier. D\xE9posez-en plusieurs dans la zone de d\xE9p\xF4t de la liste.",
434
479
  hideOptionalFields: "Masquer les champs facultatifs",
435
480
  hideOptionalInputs: "Masquer les entr\xE9es facultatives",
436
481
  optionalFieldsCount: (count) => `${count} ${plural(count, "champ facultatif", "champs facultatifs")}`,
@@ -1001,7 +1046,7 @@ function FilePickerBody({
1001
1046
  return next;
1002
1047
  });
1003
1048
  const choices = [...chosen.values()];
1004
- const use6 = () => {
1049
+ const use7 = () => {
1005
1050
  if (choices.length === 0) return;
1006
1051
  onUse(choices);
1007
1052
  onClose();
@@ -1106,7 +1151,7 @@ function FilePickerBody({
1106
1151
  "button",
1107
1152
  {
1108
1153
  type: "button",
1109
- onClick: use6,
1154
+ onClick: use7,
1110
1155
  disabled: choices.length === 0,
1111
1156
  className: cn(
1112
1157
  "flex h-12 w-full items-center justify-center rounded-md bg-primary px-4 text-[16px] font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50",
@@ -1267,6 +1312,10 @@ function FileRow({
1267
1312
  }
1268
1313
  );
1269
1314
  }
1315
+ var ListDropAreaContext = createContext(null);
1316
+ function useListDropArea() {
1317
+ return useContext(ListDropAreaContext);
1318
+ }
1270
1319
  var IMAGE_EXT_RE = /\.(jpg|jpeg|png|gif|webp|bmp|svg|avif)(\?|$)/i;
1271
1320
  var PDF_EXT_RE = /\.pdf(\?|$)/i;
1272
1321
  var DATA_URL_MIME_RE = /^data:([^;,]+)/i;
@@ -1278,9 +1327,6 @@ function isReadableLink(url) {
1278
1327
  function dataUrlMime(url) {
1279
1328
  return DATA_URL_MIME_RE.exec(url)?.[1]?.toLowerCase();
1280
1329
  }
1281
- function isThenable(answer) {
1282
- return (typeof answer === "object" || typeof answer === "function") && answer !== null && typeof answer.then === "function";
1283
- }
1284
1330
  function storedUrlOf(stored) {
1285
1331
  if (typeof stored === "string") return stored === "" ? void 0 : stored;
1286
1332
  if (stored === null || typeof stored !== "object") return void 0;
@@ -1336,6 +1382,7 @@ function FileField({
1336
1382
  }, []);
1337
1383
  useEffect(() => () => setLocal(null), [setLocal]);
1338
1384
  const [rejected, setRejected] = useState(null);
1385
+ const dropArea = useListDropArea();
1339
1386
  const [dismissedUploadError, setDismissedUploadError] = useState(null);
1340
1387
  useEffect(() => {
1341
1388
  if (uploadError === void 0) setDismissedUploadError(null);
@@ -1349,19 +1396,11 @@ function FileField({
1349
1396
  const hint = acceptLabel(formats);
1350
1397
  const accept = useMemo(() => acceptMap(formats), [formats]);
1351
1398
  const canUpload = onDropFile !== void 0;
1352
- const handleFile = useCallback(
1353
- (file) => {
1354
- if (!onDropFile) return;
1355
- if (!isAcceptedFile(formats, file)) {
1356
- setRejected(file.name);
1357
- return;
1358
- }
1359
- setRejected(null);
1360
- setDismissedUploadError(null);
1361
- const upload = onDropFile(file);
1399
+ const track = useCallback(
1400
+ (file, upload, heldUrl) => {
1362
1401
  const awaitingUpload = isThenable(upload);
1363
1402
  setLocal({ objectUrl: URL.createObjectURL(file), type: file.type, awaitingUpload });
1364
- urlInFlight.current = value?.url;
1403
+ urlInFlight.current = heldUrl;
1365
1404
  flightSeen.current = false;
1366
1405
  if (!awaitingUpload) return;
1367
1406
  const generation = localGeneration.current;
@@ -1378,8 +1417,28 @@ function FileField({
1378
1417
  }
1379
1418
  );
1380
1419
  },
1381
- [formats, setLocal, onDropFile, value?.url]
1420
+ [setLocal]
1382
1421
  );
1422
+ const handleFile = useCallback(
1423
+ (file) => {
1424
+ if (!onDropFile) return;
1425
+ if (!isAcceptedFile(formats, file)) {
1426
+ setRejected({ kind: "type", name: file.name, over: value?.url });
1427
+ return;
1428
+ }
1429
+ setRejected(null);
1430
+ setDismissedUploadError(null);
1431
+ track(file, onDropFile(file), value?.url);
1432
+ },
1433
+ [formats, onDropFile, track, value?.url]
1434
+ );
1435
+ useEffect(() => {
1436
+ const placed = dropArea?.takePlaced(id);
1437
+ if (!placed) return;
1438
+ setRejected(null);
1439
+ setDismissedUploadError(null);
1440
+ track(placed.file, placed.upload, void 0);
1441
+ }, [dropArea, id, track]);
1383
1442
  const busy = disabled || uploading;
1384
1443
  const {
1385
1444
  getRootProps,
@@ -1403,17 +1462,22 @@ function FileField({
1403
1462
  // handlers on a `role="presentation"` div, and the element a keyboard or
1404
1463
  // voice-control user lands on is a generic with no role and no name.
1405
1464
  noKeyboard: true,
1406
- onDrop: (files) => {
1407
- const file = files[0];
1408
- if (file) handleFile(file);
1409
- },
1410
- // react-dropzone rejects a file its own matcher refuses without ever calling
1411
- // `onDrop`, so without this a wrong drop is silently swallowed - the control
1412
- // simply does nothing, which reads as a broken dropzone rather than a
1465
+ // Every drop and pick lands here, the files react-dropzone's own matcher
1466
+ // refused included. Those must be answered: left alone, a wrong drop is
1467
+ // silently swallowed, which reads as a broken dropzone rather than a
1413
1468
  // refused file.
1414
- onDropRejected: (rejections) => {
1469
+ onDrop: (accepted, rejections) => {
1470
+ if (accepted.length + rejections.length > 1) {
1471
+ setRejected({ kind: "batch", over: value?.url });
1472
+ return;
1473
+ }
1474
+ const file = accepted[0];
1475
+ if (file) {
1476
+ handleFile(file);
1477
+ return;
1478
+ }
1415
1479
  const name = rejections[0]?.file.name;
1416
- if (name) setRejected(name);
1480
+ if (name) setRejected({ kind: "type", name, over: value?.url });
1417
1481
  }
1418
1482
  });
1419
1483
  const clear = useCallback(() => {
@@ -1439,11 +1503,13 @@ function FileField({
1439
1503
  if (!localPreview || localPreview.boundUrl !== void 0) return;
1440
1504
  if (failure !== null) setLocal(null);
1441
1505
  }, [failure, localPreview, setLocal]);
1506
+ const refusal = rejected !== null && rejected.over === value?.url ? rejected : null;
1442
1507
  const lastUrl = useRef(value?.url);
1443
1508
  useEffect(() => {
1444
1509
  if (lastUrl.current === value?.url) return;
1445
1510
  lastUrl.current = value?.url;
1446
1511
  if (uploadError !== void 0) setDismissedUploadError(uploadError);
1512
+ setRejected(null);
1447
1513
  }, [value?.url, uploadError]);
1448
1514
  useEffect(() => {
1449
1515
  if (!localPreview) return;
@@ -1600,11 +1666,15 @@ function FileField({
1600
1666
  }
1601
1667
  )
1602
1668
  ),
1603
- !busy && (rejected ? /* @__PURE__ */ jsxs("p", { role: "alert", className: "text-[12px] text-destructive", children: [
1604
- /* @__PURE__ */ jsx("span", { className: "font-mono", children: rejected }),
1669
+ !busy && (refusal ? /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[12px] text-destructive", children: refusal.kind === "type" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1670
+ /* @__PURE__ */ jsx("span", { className: "font-mono", children: refusal.name }),
1605
1671
  " \u2014 ",
1606
1672
  s.unsupportedFileType(hint)
1607
- ] }) : failure && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[12px] text-destructive", children: failure })),
1673
+ ] }) : dropArea?.open ? (
1674
+ // Pointed to only while it takes files: a full list's area is
1675
+ // shut, and would refuse the very drop this sends there.
1676
+ s.oneFileOnlyInList
1677
+ ) : s.oneFileOnly }) : failure && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[12px] text-destructive", children: failure })),
1608
1678
  linkOpen ? /* @__PURE__ */ jsx(
1609
1679
  "input",
1610
1680
  {
@@ -2192,13 +2262,83 @@ function followingFocusable(from, skip) {
2192
2262
  }
2193
2263
  return null;
2194
2264
  }
2195
- function firstFocusable(within) {
2196
- if (!within) return null;
2197
- for (const element of within.querySelectorAll(FOCUSABLE)) {
2265
+ function firstFocusable(within2) {
2266
+ if (!within2) return null;
2267
+ for (const element of within2.querySelectorAll(FOCUSABLE)) {
2198
2268
  if (takesFocus(element)) return element;
2199
2269
  }
2200
2270
  return null;
2201
2271
  }
2272
+ var NAMED = 3;
2273
+ function ListFileDrop({ label, formats, shut, onPlace }) {
2274
+ const s = useFieldStrings();
2275
+ const hint = acceptLabel(formats);
2276
+ const accept = useMemo(() => acceptMap(formats), [formats]);
2277
+ const [notice, setNotice] = useState(null);
2278
+ const [added, setAdded] = useState({ count: 0, seq: 0 });
2279
+ const { getRootProps, getInputProps, isDragActive } = useDropzone({
2280
+ multiple: true,
2281
+ disabled: shut,
2282
+ // Filters the OS picker; `isAcceptedFile` below is the enforcement, as on a
2283
+ // single field, because a drop bypasses the picker entirely.
2284
+ accept,
2285
+ noKeyboard: true,
2286
+ onDrop: (accepted, rejections) => {
2287
+ const refused = rejections.map((rejection) => rejection.file);
2288
+ const taken = [];
2289
+ for (const file of accepted) (isAcceptedFile(formats, file) ? taken : refused).push(file);
2290
+ const fitted = taken.length > 0 ? onPlace(taken) : 0;
2291
+ setNotice({
2292
+ refused: refused.map((file) => file.name),
2293
+ leftOut: taken.slice(fitted).map((file) => file.name),
2294
+ fitted
2295
+ });
2296
+ if (fitted > 0) setAdded((prev) => ({ count: fitted, seq: prev.seq + 1 }));
2297
+ }
2298
+ });
2299
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
2300
+ /* @__PURE__ */ jsxs(
2301
+ "div",
2302
+ {
2303
+ ...getRootProps(),
2304
+ "data-list-file-drop": true,
2305
+ className: cn(
2306
+ "flex flex-col items-center justify-center gap-1 rounded-md border border-dashed px-4 py-4 text-center max-sm:min-h-11",
2307
+ "cursor-pointer select-none transition-colors",
2308
+ "focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 focus-within:ring-offset-background",
2309
+ isDragActive ? "border-primary/60 bg-primary/5" : "border-border bg-input hover:border-border hover:bg-muted",
2310
+ shut && "cursor-not-allowed opacity-60"
2311
+ ),
2312
+ children: [
2313
+ /* @__PURE__ */ jsx(
2314
+ "input",
2315
+ {
2316
+ ...getInputProps({ tabIndex: 0 }),
2317
+ disabled: shut,
2318
+ "aria-label": s.addFilesAria(label)
2319
+ }
2320
+ ),
2321
+ /* @__PURE__ */ jsx(Upload, { className: "h-4 w-4 text-muted-foreground", strokeWidth: 1.75 }),
2322
+ /* @__PURE__ */ jsx("p", { className: "text-[13px] text-foreground", children: isDragActive ? s.dropFilesToAdd : s.dropFilesOrBrowse }),
2323
+ hint && /* @__PURE__ */ jsx("p", { className: "font-mono text-[10.5px] text-muted-foreground", children: hint })
2324
+ ]
2325
+ }
2326
+ ),
2327
+ notice && (notice.refused.length > 0 || notice.leftOut.length > 0) && /* @__PURE__ */ jsxs("div", { role: "alert", className: "space-y-1 text-[12px] text-destructive", children: [
2328
+ notice.refused.length > 0 && /* @__PURE__ */ jsx("p", { children: s.filesRefused(
2329
+ notice.refused.slice(0, NAMED),
2330
+ Math.max(0, notice.refused.length - NAMED),
2331
+ hint
2332
+ ) }),
2333
+ notice.leftOut.length > 0 && /* @__PURE__ */ jsx("p", { children: s.filesLeftOut(
2334
+ notice.leftOut.slice(0, NAMED),
2335
+ Math.max(0, notice.leftOut.length - NAMED),
2336
+ notice.fitted
2337
+ ) })
2338
+ ] }),
2339
+ /* @__PURE__ */ jsx("p", { role: "status", className: "sr-only", children: /* @__PURE__ */ jsx("span", { children: added.count > 0 ? s.filesAdded(added.count) : "" }, added.seq) })
2340
+ ] });
2341
+ }
2202
2342
 
2203
2343
  // src/react/row-moves.ts
2204
2344
  function destinationOf(order) {
@@ -2226,6 +2366,10 @@ function ListField({ field, value, onChange, id, error, env }) {
2226
2366
  const rowsRef = useRef(null);
2227
2367
  const landedRow = useRef(null);
2228
2368
  const [staleErrors, setStaleErrors] = useState(NO_ERRORS);
2369
+ const [pending, setPending] = useState(NO_UPLOADS);
2370
+ const nextUpload = useRef(0);
2371
+ const rowMoves = env?.rowMoves;
2372
+ const arriving = useMemo(() => arrivingRows(pending, rowMoves), [pending, rowMoves]);
2229
2373
  const setItem = (index, itemValue) => {
2230
2374
  const next = items.slice();
2231
2375
  next[index] = itemValue;
@@ -2242,7 +2386,7 @@ function ListField({ field, value, onChange, id, error, env }) {
2242
2386
  onChange(items.filter((_, i) => i !== index));
2243
2387
  };
2244
2388
  const addItem = () => onChange([...items, emptyValue(field.item)]);
2245
- const busy = listIsBusy(id, env?.uploadingIds);
2389
+ const busy = listIsBusy(id, env?.uploadingIds) || arriving.size > 0;
2246
2390
  const hostErrors = env?.uploadErrors;
2247
2391
  useEffect(() => {
2248
2392
  setStaleErrors((prev) => {
@@ -2251,16 +2395,19 @@ function ListField({ field, value, onChange, id, error, env }) {
2251
2395
  return next.size === prev.size ? prev : next;
2252
2396
  });
2253
2397
  }, [hostErrors]);
2398
+ const fileItem = field.item.kind === "document" || field.item.kind === "image" ? field.item : null;
2399
+ const tracksUploads = fileItem !== null;
2254
2400
  const rowEnv = useMemo(() => {
2255
- if (!env || staleErrors.size === 0) return env;
2401
+ if (!env || staleErrors.size === 0 && !tracksUploads) return env;
2256
2402
  const drop = env.onDropFile;
2403
+ const uploadErrors = staleErrors.size === 0 ? env.uploadErrors : new Map(
2404
+ [...env.uploadErrors ?? []].filter(
2405
+ ([key, message]) => staleErrors.get(key) !== message
2406
+ )
2407
+ );
2257
2408
  return {
2258
2409
  ...env,
2259
- uploadErrors: new Map(
2260
- [...env.uploadErrors ?? []].filter(([key, message]) => staleErrors.get(key) !== message)
2261
- ),
2262
- // A new file at a position is a new attempt there, so what the host says
2263
- // about that position from now on is about the file that is there.
2410
+ uploadErrors,
2264
2411
  onDropFile: drop ? (dropId, file) => {
2265
2412
  setStaleErrors((prev) => {
2266
2413
  if (!prev.has(dropId)) return prev;
@@ -2268,14 +2415,70 @@ function ListField({ field, value, onChange, id, error, env }) {
2268
2415
  next.delete(dropId);
2269
2416
  return next;
2270
2417
  });
2271
- return drop(dropId, file);
2418
+ const upload = drop(dropId, file);
2419
+ if (tracksUploads && isThenable(upload)) {
2420
+ const token = nextUpload.current++;
2421
+ const seq = env.rowMoves?.[env.rowMoves.length - 1]?.seq ?? 0;
2422
+ setPending((prev) => new Map(prev).set(token, { id: dropId, seq }));
2423
+ const answered = () => setPending((prev) => withoutUpload(prev, token));
2424
+ void Promise.resolve(upload).then(answered, answered);
2425
+ }
2426
+ return upload;
2272
2427
  } : void 0
2273
2428
  };
2274
- }, [env, staleErrors]);
2429
+ }, [env, staleErrors, tracksUploads]);
2275
2430
  const isFull = field.maxItemCount !== void 0 && items.length >= field.maxItemCount;
2276
2431
  const fileSource = env?.fileSource;
2277
- const fileItem = field.item.kind === "document" || field.item.kind === "image" ? field.item : null;
2278
2432
  const room = roomForChosenFiles(items, field.maxItemCount);
2433
+ const dropFile = rowEnv?.onDropFile;
2434
+ const dropOffered = fileItem !== null && dropFile !== void 0;
2435
+ const isFreeRow = (index) => {
2436
+ const rowId = `${id}.${index}`;
2437
+ return !arriving.has(rowId) && !env?.uploadingIds?.has(rowId) && !rowEnv?.uploadErrors?.has(rowId);
2438
+ };
2439
+ const dropRoom = dropOffered ? roomForDroppedFiles(items, field.maxItemCount, isFreeRow) : 0;
2440
+ const dropOpen = dropOffered && !env?.disabled && dropRoom !== 0;
2441
+ const placed = useRef(/* @__PURE__ */ new Map());
2442
+ const [placements, setPlacements] = useState(0);
2443
+ const dropArea = useMemo(() => {
2444
+ if (!dropOffered) return null;
2445
+ return {
2446
+ generation: placements,
2447
+ open: dropOpen,
2448
+ takePlaced: (rowId) => {
2449
+ const file = placed.current.get(rowId);
2450
+ placed.current.delete(rowId);
2451
+ return file;
2452
+ }
2453
+ };
2454
+ }, [dropOffered, dropOpen, placements]);
2455
+ const dropRef = useRef(null);
2456
+ const landing = useRef(null);
2457
+ useEffect(() => {
2458
+ const landed = landing.current;
2459
+ if (landed === null) return;
2460
+ landing.current = null;
2461
+ const rows = rowsRef.current?.querySelectorAll(":scope > [data-list-row]");
2462
+ const target = firstFocusable(rows?.[landed]) ?? followingFocusable(dropRef.current, dropRef.current);
2463
+ target?.focus();
2464
+ });
2465
+ const placeFiles = (files) => {
2466
+ if (!dropFile) return 0;
2467
+ const placement = placeDroppedFiles(items, files.length, field.maxItemCount, isFreeRow);
2468
+ if (placement.appended > 0) onChange(placement.items);
2469
+ placement.targets.forEach((index, order) => {
2470
+ const file = files[order];
2471
+ if (!file) return;
2472
+ const rowId = `${id}.${index}`;
2473
+ placed.current.set(rowId, { file, upload: handOver(dropFile, rowId, file) });
2474
+ });
2475
+ const count = placement.targets.length;
2476
+ if (count > 0) setPlacements((generation) => generation + 1);
2477
+ if (count > 0 && count === dropRoom && dropRef.current?.contains(document.activeElement)) {
2478
+ landing.current = placement.targets[count - 1] ?? null;
2479
+ }
2480
+ return count;
2481
+ };
2279
2482
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2280
2483
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [
2281
2484
  /* @__PURE__ */ jsx(
@@ -2294,8 +2497,8 @@ function ListField({ field, value, onChange, id, error, env }) {
2294
2497
  ] }),
2295
2498
  field.description && /* @__PURE__ */ jsx("p", { className: "text-[12px] leading-relaxed text-muted-foreground", children: field.description }),
2296
2499
  /* @__PURE__ */ jsxs("div", { ref: rowsRef, className: "space-y-2", children: [
2297
- items.length === 0 && /* @__PURE__ */ jsx("p", { className: "rounded-md border border-dashed border-border bg-input/50 px-3 py-4 text-center text-[12px] text-muted-foreground", children: s.noItemsYet }),
2298
- items.map((item, index) => /* @__PURE__ */ jsxs(
2500
+ items.length === 0 && !dropOffered && /* @__PURE__ */ jsx("p", { className: "rounded-md border border-dashed border-border bg-input/50 px-3 py-4 text-center text-[12px] text-muted-foreground", children: s.noItemsYet }),
2501
+ /* @__PURE__ */ jsx(ListDropAreaContext.Provider, { value: dropArea, children: items.map((item, index) => /* @__PURE__ */ jsxs(
2299
2502
  "div",
2300
2503
  {
2301
2504
  "data-list-row": true,
@@ -2334,7 +2537,16 @@ function ListField({ field, value, onChange, id, error, env }) {
2334
2537
  ]
2335
2538
  },
2336
2539
  rowKeys[index] ?? index
2337
- )),
2540
+ )) }),
2541
+ dropOffered && fileItem && /* @__PURE__ */ jsx("div", { ref: dropRef, children: /* @__PURE__ */ jsx(
2542
+ ListFileDrop,
2543
+ {
2544
+ label: fieldLabel(field.title, field.name, presentation),
2545
+ formats: fileItem.formats,
2546
+ shut: !dropOpen,
2547
+ onPlace: placeFiles
2548
+ }
2549
+ ) }),
2338
2550
  /* @__PURE__ */ jsxs(
2339
2551
  "button",
2340
2552
  {
@@ -2411,6 +2623,42 @@ function listIsBusy(id, uploadingIds) {
2411
2623
  return false;
2412
2624
  }
2413
2625
  var NO_ERRORS = /* @__PURE__ */ new Map();
2626
+ var NO_IDS = /* @__PURE__ */ new Set();
2627
+ var NO_UPLOADS = /* @__PURE__ */ new Map();
2628
+ function withoutUpload(uploads, token) {
2629
+ if (!uploads.has(token)) return uploads;
2630
+ const next = new Map(uploads);
2631
+ next.delete(token);
2632
+ return next;
2633
+ }
2634
+ function arrivingRows(uploads, moves) {
2635
+ if (uploads.size === 0) return NO_IDS;
2636
+ const rows = /* @__PURE__ */ new Set();
2637
+ for (const upload of uploads.values()) {
2638
+ let at = upload.id;
2639
+ for (const move of moves ?? []) {
2640
+ if (at === void 0) break;
2641
+ if (move.seq > upload.seq) at = movedId(at, move.listId, destinationOf(move.order));
2642
+ }
2643
+ if (at !== void 0) rows.add(at);
2644
+ }
2645
+ return rows;
2646
+ }
2647
+ function handOver(drop, rowId, file) {
2648
+ try {
2649
+ return drop(rowId, file);
2650
+ } catch (error) {
2651
+ reportHostError(error);
2652
+ const failed = Promise.reject(error);
2653
+ failed.catch(() => {
2654
+ });
2655
+ return failed;
2656
+ }
2657
+ }
2658
+ function reportHostError(error) {
2659
+ if (typeof globalThis.reportError === "function") globalThis.reportError(error);
2660
+ else console.error(error);
2661
+ }
2414
2662
  function withRenumberedErrors(stale, listId, removed, hostErrors) {
2415
2663
  if (!hostErrors?.size) return stale;
2416
2664
  const prefix = `${listId}.`;
@@ -3132,12 +3380,12 @@ function withoutId(ids, id) {
3132
3380
  next.delete(id);
3133
3381
  return next;
3134
3382
  }
3135
- var NO_UPLOADS = /* @__PURE__ */ new Map();
3383
+ var NO_UPLOADS2 = /* @__PURE__ */ new Map();
3136
3384
  var NO_MOVES = [];
3137
3385
  var NOTHING_HELD = {
3138
3386
  edited: null,
3139
3387
  failed: EMPTY_IDS,
3140
- uploads: NO_UPLOADS,
3388
+ uploads: NO_UPLOADS2,
3141
3389
  moves: NO_MOVES
3142
3390
  };
3143
3391
  function withoutEntry(entries, id) {
@@ -3317,7 +3565,7 @@ function useMethodForm({
3317
3565
  );
3318
3566
  const reset = useCallback(
3319
3567
  (next) => {
3320
- commit({ edited: next ?? null, failed: EMPTY_IDS, uploads: NO_UPLOADS, moves: NO_MOVES });
3568
+ commit({ edited: next ?? null, failed: EMPTY_IDS, uploads: NO_UPLOADS2, moves: NO_MOVES });
3321
3569
  setGiven(next ?? null);
3322
3570
  setAttempted(false);
3323
3571
  setResets((count) => count + 1);
@@ -3569,6 +3817,7 @@ function frameDocument(content, { styles, imgSrc, fontSrc }) {
3569
3817
  const head = [
3570
3818
  '<!doctype html><html><head><meta charset="utf-8">',
3571
3819
  `<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src ${imgSrc}; font-src ${fontSrc}; base-uri 'none'; form-action 'none'">`,
3820
+ '<meta name="referrer" content="no-referrer">',
3572
3821
  `<style>${styles}</style></head>`
3573
3822
  ].join("");
3574
3823
  if (isWholeDocument(content.innerHtml)) return head + content.innerHtml;
@@ -4287,26 +4536,26 @@ function measureFlow(doc) {
4287
4536
  fixed.push(el);
4288
4537
  return;
4289
4538
  }
4290
- const span = spanOf(el);
4539
+ const span2 = spanOf(el);
4291
4540
  const display = style.display;
4292
4541
  if (FORCED.has(style.breakBefore) || FORCED.has(style.getPropertyValue("page-break-before"))) {
4293
- forced.push(span.top);
4542
+ forced.push(span2.top);
4294
4543
  }
4295
4544
  if (FORCED.has(style.breakAfter) || FORCED.has(style.getPropertyValue("page-break-after"))) {
4296
- forced.push(span.bottom);
4545
+ forced.push(span2.bottom);
4297
4546
  }
4298
- if (AVOIDED.has(style.breakAfter) || HEADING_TAGS.has(el.tagName)) keepAfter.push(span);
4299
- if (AVOIDED.has(style.breakBefore)) keepBefore.push(span);
4547
+ if (AVOIDED.has(style.breakAfter) || HEADING_TAGS.has(el.tagName)) keepAfter.push(span2);
4548
+ if (AVOIDED.has(style.breakBefore)) keepBefore.push(span2);
4300
4549
  const atomic = ATOMIC_TAGS.has(el.tagName) || display.startsWith("inline-");
4301
4550
  if (atomic) {
4302
- if (span.bottom > span.top) hard.push(span);
4551
+ if (span2.bottom > span2.top) hard.push(span2);
4303
4552
  return;
4304
4553
  }
4305
4554
  if (AVOIDED.has(style.breakInside) || AVOIDED.has(style.getPropertyValue("page-break-inside")) || display === "table-row") {
4306
- avoid.push(span);
4555
+ avoid.push(span2);
4307
4556
  }
4308
4557
  if (display === "table" || display === "inline-table") {
4309
- tables.push(tableBox(el, span));
4558
+ tables.push(tableBox(el, span2));
4310
4559
  }
4311
4560
  for (const child of Array.from(el.childNodes)) {
4312
4561
  if (child.nodeType === 1) walk(child);
@@ -4315,8 +4564,8 @@ function measureFlow(doc) {
4315
4564
  }
4316
4565
  }
4317
4566
  };
4318
- const tableBox = (table, span) => {
4319
- const box = { ...span };
4567
+ const tableBox = (table, span2) => {
4568
+ const box = { ...span2 };
4320
4569
  for (const part of Array.from(table.children)) {
4321
4570
  const display = win.getComputedStyle(part).display;
4322
4571
  if (display === "table-header-group" && !box.head) box.head = spanOf(part);
@@ -4329,13 +4578,13 @@ function measureFlow(doc) {
4329
4578
  const lines = [...hard].sort((a, b) => a.top - b.top);
4330
4579
  const firstLineFrom = (at) => lines.find((line) => line.top >= at - 0.5);
4331
4580
  const lastLineBefore = (at) => [...lines].reverse().find((line) => line.bottom <= at + 0.5);
4332
- for (const span of keepAfter) {
4333
- const next = firstLineFrom(span.bottom);
4334
- if (next) avoid.push({ top: span.top, bottom: next.bottom });
4581
+ for (const span2 of keepAfter) {
4582
+ const next = firstLineFrom(span2.bottom);
4583
+ if (next) avoid.push({ top: span2.top, bottom: next.bottom });
4335
4584
  }
4336
- for (const span of keepBefore) {
4337
- const previous = lastLineBefore(span.top);
4338
- const first = firstLineFrom(span.top);
4585
+ for (const span2 of keepBefore) {
4586
+ const previous = lastLineBefore(span2.top);
4587
+ const first = firstLineFrom(span2.top);
4339
4588
  if (previous && first) avoid.push({ top: previous.top, bottom: first.bottom });
4340
4589
  }
4341
4590
  for (const table of tables) {
@@ -4353,17 +4602,17 @@ function measureFlow(doc) {
4353
4602
  function lineSpans(doc, text, y) {
4354
4603
  const range = doc.createRange();
4355
4604
  range.selectNodeContents(text);
4356
- const spans = [];
4605
+ const spans2 = [];
4357
4606
  for (const rect of Array.from(range.getClientRects())) {
4358
4607
  if (rect.height === 0) continue;
4359
- const span = { top: y(rect.top), bottom: y(rect.bottom) };
4360
- const same = spans.find((line) => span.top < line.bottom && span.bottom > line.top);
4608
+ const span2 = { top: y(rect.top), bottom: y(rect.bottom) };
4609
+ const same = spans2.find((line) => span2.top < line.bottom && span2.bottom > line.top);
4361
4610
  if (same) {
4362
- same.top = Math.min(same.top, span.top);
4363
- same.bottom = Math.max(same.bottom, span.bottom);
4364
- } else spans.push(span);
4611
+ same.top = Math.min(same.top, span2.top);
4612
+ same.bottom = Math.max(same.bottom, span2.bottom);
4613
+ } else spans2.push(span2);
4365
4614
  }
4366
- return spans;
4615
+ return spans2;
4367
4616
  }
4368
4617
 
4369
4618
  // src/react/paginate.ts
@@ -4371,7 +4620,7 @@ var EPSILON = 0.5;
4371
4620
  function paginate(layout, pageHeight) {
4372
4621
  const pages = [];
4373
4622
  const end = layout.height;
4374
- const inkBottom = Math.max(0, ...layout.hard.map((span) => span.bottom));
4623
+ const inkBottom = Math.max(0, ...layout.hard.map((span2) => span2.bottom));
4375
4624
  const forced = [...layout.forced].sort((a, b) => a - b);
4376
4625
  let start = 0;
4377
4626
  for (let guard = 0; start < end - EPSILON && guard < 1e4; guard++) {
@@ -4402,12 +4651,12 @@ function paginate(layout, pageHeight) {
4402
4651
  }
4403
4652
  function bestCut(layout, start, limit) {
4404
4653
  const room = limit - start;
4405
- const hard = layout.hard.filter((span) => span.bottom - span.top <= room);
4406
- const avoid = layout.avoid.filter((span) => span.bottom - span.top <= room);
4654
+ const hard = layout.hard.filter((span2) => span2.bottom - span2.top <= room);
4655
+ const avoid = layout.avoid.filter((span2) => span2.bottom - span2.top <= room);
4407
4656
  const candidates = /* @__PURE__ */ new Set([limit]);
4408
- for (const span of [...hard, ...avoid]) {
4409
- candidates.add(span.top);
4410
- candidates.add(span.bottom);
4657
+ for (const span2 of [...hard, ...avoid]) {
4658
+ candidates.add(span2.top);
4659
+ candidates.add(span2.bottom);
4411
4660
  }
4412
4661
  for (const table of layout.tables) {
4413
4662
  candidates.add(table.top);
@@ -4415,19 +4664,19 @@ function bestCut(layout, start, limit) {
4415
4664
  }
4416
4665
  const sorted = [...candidates].filter((at) => at > start + EPSILON && at <= limit + EPSILON).sort((a, b) => b - a);
4417
4666
  for (const constraints of [[...hard, ...avoid], hard]) {
4418
- const cut = sorted.find((at) => !constraints.some((span) => inside(span, at)));
4667
+ const cut = sorted.find((at) => !constraints.some((span2) => inside(span2, at)));
4419
4668
  if (cut !== void 0) return Math.min(cut, limit);
4420
4669
  }
4421
4670
  return limit;
4422
4671
  }
4423
- function inside(span, at) {
4424
- return at > span.top + EPSILON && at < span.bottom - EPSILON;
4672
+ function inside(span2, at) {
4673
+ return at > span2.top + EPSILON && at < span2.bottom - EPSILON;
4425
4674
  }
4426
4675
  function openAt(tables, at) {
4427
4676
  return tables.filter((table) => at > table.top + EPSILON && at < (table.foot?.top ?? table.bottom) - EPSILON).sort((a, b) => a.top - b.top);
4428
4677
  }
4429
- function total(spans) {
4430
- return spans.reduce((sum, span) => sum + (span.bottom - span.top), 0);
4678
+ function total(spans2) {
4679
+ return spans2.reduce((sum, span2) => sum + (span2.bottom - span2.top), 0);
4431
4680
  }
4432
4681
 
4433
4682
  // src/react/print-media.ts
@@ -4693,10 +4942,10 @@ async function paintPage(slice, page, area, scale, quality, flow, overlay) {
4693
4942
  context.fillStyle = "#fff";
4694
4943
  context.fillRect(0, 0, canvas.width, canvas.height);
4695
4944
  let y = page.margin.top;
4696
- for (const span of [...slice.heads, slice.body, ...slice.feet]) {
4697
- const height = span.bottom - span.top;
4945
+ for (const span2 of [...slice.heads, slice.body, ...slice.feet]) {
4946
+ const height = span2.bottom - span2.top;
4698
4947
  if (height <= 0) continue;
4699
- const image = await svgImage(flow, { top: span.top, width: area.width, height }, scale);
4948
+ const image = await svgImage(flow, { top: span2.top, width: area.width, height }, scale);
4700
4949
  context.drawImage(
4701
4950
  image,
4702
4951
  page.margin.left * scale,
@@ -5288,6 +5537,710 @@ var ENTITIES = {
5288
5537
  function decode(text) {
5289
5538
  return text.replace(/&(?:amp|lt|gt|quot|#39|#x27);/g, (entity) => ENTITIES[entity] ?? entity);
5290
5539
  }
5540
+ function ExtractedPageText({ segments }) {
5541
+ return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: segments.map(
5542
+ (segment, index) => segment.kind === "markdown" ? /* @__PURE__ */ jsx(Markdown, { text: segment.text }, index) : /* @__PURE__ */ jsx(ExtractedTableView, { table: segment.table }, index)
5543
+ ) });
5544
+ }
5545
+ function ExtractedTableView({ table }) {
5546
+ const s = useFieldStrings();
5547
+ const headRows = leadingHeaderRows(table);
5548
+ const head = table.rows.slice(0, headRows);
5549
+ const body = table.rows.slice(headRows);
5550
+ return /* @__PURE__ */ jsxs("figure", { className: "space-y-1.5", children: [
5551
+ table.caption && /* @__PURE__ */ jsx("figcaption", { className: "text-[12.5px] text-muted-foreground", children: table.caption }),
5552
+ table.rows.length > 0 && /* @__PURE__ */ jsx(
5553
+ "div",
5554
+ {
5555
+ role: "group",
5556
+ "aria-label": table.caption ?? s.extractedTable,
5557
+ tabIndex: 0,
5558
+ className: cn("overflow-x-auto rounded-lg border border-border", focusOutlineClass),
5559
+ children: /* @__PURE__ */ jsxs("table", { className: "min-w-full border-collapse text-[12.5px] text-foreground", children: [
5560
+ head.length > 0 && /* @__PURE__ */ jsx("thead", { children: head.map((row, rowIndex) => /* @__PURE__ */ jsx("tr", { className: "border-b border-border bg-card/40", children: row.map((cell, cellIndex) => /* @__PURE__ */ jsx(
5561
+ "th",
5562
+ {
5563
+ scope: "col",
5564
+ ...spans(cell),
5565
+ className: "whitespace-pre-line px-2.5 py-1.5 text-start align-bottom font-semibold",
5566
+ children: cell.text
5567
+ },
5568
+ cellIndex
5569
+ )) }, rowIndex)) }),
5570
+ /* @__PURE__ */ jsx("tbody", { children: body.map((row, rowIndex) => /* @__PURE__ */ jsx("tr", { className: "border-b border-border/60 last:border-b-0", children: row.map(
5571
+ (cell, cellIndex) => cell.header ? /* @__PURE__ */ jsx(
5572
+ "th",
5573
+ {
5574
+ scope: "row",
5575
+ ...spans(cell),
5576
+ className: "whitespace-pre-line px-2.5 py-1.5 text-start align-top font-semibold",
5577
+ children: cell.text
5578
+ },
5579
+ cellIndex
5580
+ ) : /* @__PURE__ */ jsx(
5581
+ "td",
5582
+ {
5583
+ ...spans(cell),
5584
+ className: "whitespace-pre-line px-2.5 py-1.5 align-top",
5585
+ children: cell.text
5586
+ },
5587
+ cellIndex
5588
+ )
5589
+ ) }, rowIndex)) })
5590
+ ] })
5591
+ }
5592
+ )
5593
+ ] });
5594
+ }
5595
+ function leadingHeaderRows(table) {
5596
+ let count = 0;
5597
+ for (const row of table.rows) {
5598
+ if (!row.every((cell) => cell.header)) break;
5599
+ count += 1;
5600
+ }
5601
+ return count === table.rows.length ? 0 : count;
5602
+ }
5603
+ function spans(cell) {
5604
+ return {
5605
+ ...cell.colSpan !== void 0 ? { colSpan: cell.colSpan } : {},
5606
+ ...cell.rowSpan !== void 0 ? { rowSpan: cell.rowSpan } : {}
5607
+ };
5608
+ }
5609
+
5610
+ // src/react/html-entities.ts
5611
+ var HTML_NAMED_ENTITIES = {
5612
+ // The XML marks, their legacy uppercase spellings, and the special marks.
5613
+ apos: 39,
5614
+ AMP: 38,
5615
+ LT: 60,
5616
+ GT: 62,
5617
+ QUOT: 34,
5618
+ COPY: 169,
5619
+ REG: 174,
5620
+ quot: 34,
5621
+ amp: 38,
5622
+ lt: 60,
5623
+ gt: 62,
5624
+ OElig: 338,
5625
+ oelig: 339,
5626
+ Scaron: 352,
5627
+ scaron: 353,
5628
+ Yuml: 376,
5629
+ circ: 710,
5630
+ tilde: 732,
5631
+ ensp: 8194,
5632
+ emsp: 8195,
5633
+ thinsp: 8201,
5634
+ zwnj: 8204,
5635
+ zwj: 8205,
5636
+ lrm: 8206,
5637
+ rlm: 8207,
5638
+ ndash: 8211,
5639
+ mdash: 8212,
5640
+ lsquo: 8216,
5641
+ rsquo: 8217,
5642
+ sbquo: 8218,
5643
+ ldquo: 8220,
5644
+ rdquo: 8221,
5645
+ bdquo: 8222,
5646
+ dagger: 8224,
5647
+ Dagger: 8225,
5648
+ permil: 8240,
5649
+ lsaquo: 8249,
5650
+ rsaquo: 8250,
5651
+ euro: 8364,
5652
+ // Latin-1.
5653
+ nbsp: 160,
5654
+ iexcl: 161,
5655
+ cent: 162,
5656
+ pound: 163,
5657
+ curren: 164,
5658
+ yen: 165,
5659
+ brvbar: 166,
5660
+ sect: 167,
5661
+ uml: 168,
5662
+ copy: 169,
5663
+ ordf: 170,
5664
+ laquo: 171,
5665
+ not: 172,
5666
+ shy: 173,
5667
+ reg: 174,
5668
+ macr: 175,
5669
+ deg: 176,
5670
+ plusmn: 177,
5671
+ sup2: 178,
5672
+ sup3: 179,
5673
+ acute: 180,
5674
+ micro: 181,
5675
+ para: 182,
5676
+ middot: 183,
5677
+ cedil: 184,
5678
+ sup1: 185,
5679
+ ordm: 186,
5680
+ raquo: 187,
5681
+ frac14: 188,
5682
+ frac12: 189,
5683
+ frac34: 190,
5684
+ iquest: 191,
5685
+ Agrave: 192,
5686
+ Aacute: 193,
5687
+ Acirc: 194,
5688
+ Atilde: 195,
5689
+ Auml: 196,
5690
+ Aring: 197,
5691
+ AElig: 198,
5692
+ Ccedil: 199,
5693
+ Egrave: 200,
5694
+ Eacute: 201,
5695
+ Ecirc: 202,
5696
+ Euml: 203,
5697
+ Igrave: 204,
5698
+ Iacute: 205,
5699
+ Icirc: 206,
5700
+ Iuml: 207,
5701
+ ETH: 208,
5702
+ Ntilde: 209,
5703
+ Ograve: 210,
5704
+ Oacute: 211,
5705
+ Ocirc: 212,
5706
+ Otilde: 213,
5707
+ Ouml: 214,
5708
+ times: 215,
5709
+ Oslash: 216,
5710
+ Ugrave: 217,
5711
+ Uacute: 218,
5712
+ Ucirc: 219,
5713
+ Uuml: 220,
5714
+ Yacute: 221,
5715
+ THORN: 222,
5716
+ szlig: 223,
5717
+ agrave: 224,
5718
+ aacute: 225,
5719
+ acirc: 226,
5720
+ atilde: 227,
5721
+ auml: 228,
5722
+ aring: 229,
5723
+ aelig: 230,
5724
+ ccedil: 231,
5725
+ egrave: 232,
5726
+ eacute: 233,
5727
+ ecirc: 234,
5728
+ euml: 235,
5729
+ igrave: 236,
5730
+ iacute: 237,
5731
+ icirc: 238,
5732
+ iuml: 239,
5733
+ eth: 240,
5734
+ ntilde: 241,
5735
+ ograve: 242,
5736
+ oacute: 243,
5737
+ ocirc: 244,
5738
+ otilde: 245,
5739
+ ouml: 246,
5740
+ divide: 247,
5741
+ oslash: 248,
5742
+ ugrave: 249,
5743
+ uacute: 250,
5744
+ ucirc: 251,
5745
+ uuml: 252,
5746
+ yacute: 253,
5747
+ thorn: 254,
5748
+ yuml: 255,
5749
+ // Symbols, mathematical marks and Greek letters.
5750
+ fnof: 402,
5751
+ Alpha: 913,
5752
+ Beta: 914,
5753
+ Gamma: 915,
5754
+ Delta: 916,
5755
+ Epsilon: 917,
5756
+ Zeta: 918,
5757
+ Eta: 919,
5758
+ Theta: 920,
5759
+ Iota: 921,
5760
+ Kappa: 922,
5761
+ Lambda: 923,
5762
+ Mu: 924,
5763
+ Nu: 925,
5764
+ Xi: 926,
5765
+ Omicron: 927,
5766
+ Pi: 928,
5767
+ Rho: 929,
5768
+ Sigma: 931,
5769
+ Tau: 932,
5770
+ Upsilon: 933,
5771
+ Phi: 934,
5772
+ Chi: 935,
5773
+ Psi: 936,
5774
+ Omega: 937,
5775
+ alpha: 945,
5776
+ beta: 946,
5777
+ gamma: 947,
5778
+ delta: 948,
5779
+ epsilon: 949,
5780
+ zeta: 950,
5781
+ eta: 951,
5782
+ theta: 952,
5783
+ iota: 953,
5784
+ kappa: 954,
5785
+ lambda: 955,
5786
+ mu: 956,
5787
+ nu: 957,
5788
+ xi: 958,
5789
+ omicron: 959,
5790
+ pi: 960,
5791
+ rho: 961,
5792
+ sigmaf: 962,
5793
+ sigma: 963,
5794
+ tau: 964,
5795
+ upsilon: 965,
5796
+ phi: 966,
5797
+ chi: 967,
5798
+ psi: 968,
5799
+ omega: 969,
5800
+ thetasym: 977,
5801
+ upsih: 978,
5802
+ piv: 982,
5803
+ bull: 8226,
5804
+ hellip: 8230,
5805
+ prime: 8242,
5806
+ Prime: 8243,
5807
+ oline: 8254,
5808
+ frasl: 8260,
5809
+ image: 8465,
5810
+ weierp: 8472,
5811
+ real: 8476,
5812
+ trade: 8482,
5813
+ alefsym: 8501,
5814
+ larr: 8592,
5815
+ uarr: 8593,
5816
+ rarr: 8594,
5817
+ darr: 8595,
5818
+ harr: 8596,
5819
+ crarr: 8629,
5820
+ lArr: 8656,
5821
+ uArr: 8657,
5822
+ rArr: 8658,
5823
+ dArr: 8659,
5824
+ hArr: 8660,
5825
+ forall: 8704,
5826
+ part: 8706,
5827
+ exist: 8707,
5828
+ empty: 8709,
5829
+ nabla: 8711,
5830
+ isin: 8712,
5831
+ notin: 8713,
5832
+ ni: 8715,
5833
+ prod: 8719,
5834
+ sum: 8721,
5835
+ minus: 8722,
5836
+ lowast: 8727,
5837
+ radic: 8730,
5838
+ prop: 8733,
5839
+ infin: 8734,
5840
+ ang: 8736,
5841
+ and: 8743,
5842
+ or: 8744,
5843
+ cap: 8745,
5844
+ cup: 8746,
5845
+ int: 8747,
5846
+ there4: 8756,
5847
+ sim: 8764,
5848
+ cong: 8773,
5849
+ asymp: 8776,
5850
+ ne: 8800,
5851
+ equiv: 8801,
5852
+ le: 8804,
5853
+ ge: 8805,
5854
+ sub: 8834,
5855
+ sup: 8835,
5856
+ nsub: 8836,
5857
+ sube: 8838,
5858
+ supe: 8839,
5859
+ oplus: 8853,
5860
+ otimes: 8855,
5861
+ perp: 8869,
5862
+ sdot: 8901,
5863
+ lceil: 8968,
5864
+ rceil: 8969,
5865
+ lfloor: 8970,
5866
+ rfloor: 8971,
5867
+ lang: 9001,
5868
+ rang: 9002,
5869
+ loz: 9674,
5870
+ spades: 9824,
5871
+ clubs: 9827,
5872
+ hearts: 9829,
5873
+ diams: 9830
5874
+ };
5875
+ var ENTITY = /&(#x[0-9a-f]+|#\d+|[a-z][a-z0-9]*);/gi;
5876
+ function decodeHtmlEntities(text) {
5877
+ return text.replace(ENTITY, (entity, body) => {
5878
+ if (body.startsWith("#")) {
5879
+ const code2 = body[1] === "x" || body[1] === "X" ? parseInt(body.slice(2), 16) : Number(body.slice(1));
5880
+ return Number.isInteger(code2) && code2 > 0 && code2 <= 1114111 ? String.fromCodePoint(code2) : entity;
5881
+ }
5882
+ const code = ownProp(HTML_NAMED_ENTITIES, body);
5883
+ return typeof code === "number" ? String.fromCodePoint(code) : entity;
5884
+ });
5885
+ }
5886
+
5887
+ // src/react/extracted-text.ts
5888
+ function splitExtractedText(text) {
5889
+ const segments = [];
5890
+ const tableRows = text.includes("|") ? pipeTableRows(text) : [];
5891
+ let markdown = "";
5892
+ let index = 0;
5893
+ while (index < text.length) {
5894
+ if (index === 0 || text[index - 1] === "\n") {
5895
+ const fenceEnd = fencedBlockEnd(text, index);
5896
+ if (fenceEnd !== void 0) {
5897
+ markdown += text.slice(index, fenceEnd);
5898
+ index = fenceEnd;
5899
+ continue;
5900
+ }
5901
+ }
5902
+ const char = text.charAt(index);
5903
+ if (char === "\\" && ESCAPABLE.test(text.charAt(index + 1))) {
5904
+ markdown += text.slice(index, index + 2);
5905
+ index += 2;
5906
+ continue;
5907
+ }
5908
+ if (char === "`") {
5909
+ const end = codeSpanEnd(text, index);
5910
+ markdown += text.slice(index, end);
5911
+ index = end;
5912
+ continue;
5913
+ }
5914
+ if (char === "<") {
5915
+ const markup = readMarkup(text, index);
5916
+ if (markup) {
5917
+ if ("table" in markup) {
5918
+ pushMarkdown(segments, markdown);
5919
+ markdown = "";
5920
+ if (markup.table) segments.push({ kind: "table", table: markup.table });
5921
+ } else if (markup.text === "\n" && within(tableRows, index)) {
5922
+ markdown += " ";
5923
+ } else {
5924
+ markdown += markup.text;
5925
+ }
5926
+ index = markup.end;
5927
+ continue;
5928
+ }
5929
+ }
5930
+ markdown += char;
5931
+ index += 1;
5932
+ }
5933
+ pushMarkdown(segments, markdown);
5934
+ return segments;
5935
+ }
5936
+ function pushMarkdown(segments, text) {
5937
+ if (text.trim() !== "") segments.push({ kind: "markdown", text });
5938
+ }
5939
+ function within(spans2, index) {
5940
+ return spans2.some(([start, end]) => index >= start && index < end);
5941
+ }
5942
+ function pipeTableRows(text) {
5943
+ const lines = [];
5944
+ for (let start = 0; ; ) {
5945
+ const newline = text.indexOf("\n", start);
5946
+ lines.push([start, newline === -1 ? text.length : newline]);
5947
+ if (newline === -1) break;
5948
+ start = newline + 1;
5949
+ }
5950
+ const lineAt = (at) => {
5951
+ const [start, end] = lines[at] ?? [0, 0];
5952
+ return text.slice(start, end);
5953
+ };
5954
+ const rows = [];
5955
+ for (let at = 1; at < lines.length; at += 1) {
5956
+ const header = lineAt(at - 1);
5957
+ const delimiter = lineAt(at);
5958
+ if (!header.includes("|") || !isDelimiterRow(delimiter)) continue;
5959
+ if (rowCells(header).length !== rowCells(delimiter).length) continue;
5960
+ let last = at;
5961
+ while (last + 1 < lines.length && lineAt(last + 1).includes("|")) last += 1;
5962
+ rows.push([lines[at - 1]?.[0] ?? 0, lines[last]?.[1] ?? text.length]);
5963
+ at = last;
5964
+ }
5965
+ return rows;
5966
+ }
5967
+ function rowCells(line) {
5968
+ let row = line.trim();
5969
+ if (row.startsWith("|")) row = row.slice(1);
5970
+ if (row.endsWith("|") && !row.endsWith("\\|")) row = row.slice(0, -1);
5971
+ const cells = [];
5972
+ let cell = "";
5973
+ for (let at = 0; at < row.length; at += 1) {
5974
+ const char = row.charAt(at);
5975
+ if (char === "\\") {
5976
+ cell += row.slice(at, at + 2);
5977
+ at += 1;
5978
+ } else if (char === "|") {
5979
+ cells.push(cell);
5980
+ cell = "";
5981
+ } else {
5982
+ cell += char;
5983
+ }
5984
+ }
5985
+ cells.push(cell);
5986
+ return cells;
5987
+ }
5988
+ function isDelimiterRow(line) {
5989
+ return line.includes("|") && rowCells(line).every((cell) => /^\s*:?-+:?\s*$/.test(cell));
5990
+ }
5991
+ var ESCAPABLE = /^[\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]$/;
5992
+ var FENCE_OPEN = /[ \t]*(`{3,}|~{3,})([^\n]*)/y;
5993
+ var FENCE_LINE = /^[ \t]*(?:`{3,}|~{3,})/gm;
5994
+ function fencedBlockEnd(text, start) {
5995
+ FENCE_OPEN.lastIndex = start;
5996
+ const open = FENCE_OPEN.exec(text);
5997
+ if (!open) return void 0;
5998
+ const marker = open[1] ?? "";
5999
+ const fenceChar = marker.charAt(0);
6000
+ if (fenceChar === "`" && (open[2] ?? "").includes("`")) return void 0;
6001
+ let lineEnd = text.indexOf("\n", start);
6002
+ while (lineEnd !== -1) {
6003
+ const next = text.indexOf("\n", lineEnd + 1);
6004
+ const end = next === -1 ? text.length : next;
6005
+ const line = text.slice(lineEnd + 1, end).trim();
6006
+ if (line.length >= marker.length && [...line].every((c) => c === fenceChar)) return end;
6007
+ lineEnd = next;
6008
+ }
6009
+ return text.length;
6010
+ }
6011
+ var BLANK_LINE = /\n[ \t]*\n/g;
6012
+ function codeSpanEnd(text, start) {
6013
+ const open = backtickRun(text, start);
6014
+ BLANK_LINE.lastIndex = start;
6015
+ const blank = BLANK_LINE.exec(text);
6016
+ const limit = blank ? blank.index : text.length;
6017
+ let cursor = start + open;
6018
+ for (; ; ) {
6019
+ const next = text.indexOf("`", cursor);
6020
+ if (next === -1 || next >= limit) return start + open;
6021
+ const length = backtickRun(text, next);
6022
+ if (length === open) return next + length;
6023
+ cursor = next + length;
6024
+ }
6025
+ }
6026
+ function backtickRun(text, start) {
6027
+ let end = start;
6028
+ while (text.charAt(end) === "`") end += 1;
6029
+ return end - start;
6030
+ }
6031
+ function nextOutsideFences(text, from, pattern) {
6032
+ let cursor = from;
6033
+ for (; ; ) {
6034
+ pattern.lastIndex = cursor;
6035
+ const match = pattern.exec(text);
6036
+ if (!match) return null;
6037
+ FENCE_LINE.lastIndex = cursor;
6038
+ const fence = FENCE_LINE.exec(text);
6039
+ if (!fence || fence.index >= match.index) return match;
6040
+ cursor = fencedBlockEnd(text, fence.index) ?? fence.index + fence[0].length;
6041
+ }
6042
+ }
6043
+ var COMMENT = /<!--[\s\S]*?-->/g;
6044
+ var COMMENT_END = /-->/g;
6045
+ var TABLE_OPEN = /<table\b[^>]*>/iy;
6046
+ var TABLE_TAG = /<(\/?)table\b[^>]*>/gi;
6047
+ var HTML_TAG = /<(\/?)([a-z][a-z0-9]*)(?=[\s/>])[^<>]*>/iy;
6048
+ var BLOCK_ELEMENTS = /* @__PURE__ */ new Set([
6049
+ "address",
6050
+ "article",
6051
+ "aside",
6052
+ "blockquote",
6053
+ "body",
6054
+ "br",
6055
+ "center",
6056
+ "dd",
6057
+ "details",
6058
+ "dialog",
6059
+ "div",
6060
+ "dl",
6061
+ "dt",
6062
+ "fieldset",
6063
+ "figcaption",
6064
+ "figure",
6065
+ "footer",
6066
+ "form",
6067
+ "h1",
6068
+ "h2",
6069
+ "h3",
6070
+ "h4",
6071
+ "h5",
6072
+ "h6",
6073
+ "head",
6074
+ "header",
6075
+ "hgroup",
6076
+ "hr",
6077
+ "html",
6078
+ "legend",
6079
+ "li",
6080
+ "main",
6081
+ "nav",
6082
+ "ol",
6083
+ "option",
6084
+ "p",
6085
+ "pre",
6086
+ "section",
6087
+ "summary",
6088
+ "title",
6089
+ "ul"
6090
+ ]);
6091
+ var INLINE_ELEMENTS = /* @__PURE__ */ new Set([
6092
+ "a",
6093
+ "abbr",
6094
+ "b",
6095
+ "bdi",
6096
+ "bdo",
6097
+ "big",
6098
+ "cite",
6099
+ "code",
6100
+ "data",
6101
+ "del",
6102
+ "dfn",
6103
+ "em",
6104
+ "font",
6105
+ "i",
6106
+ "img",
6107
+ "ins",
6108
+ "kbd",
6109
+ "label",
6110
+ "mark",
6111
+ "picture",
6112
+ "q",
6113
+ "s",
6114
+ "samp",
6115
+ "small",
6116
+ "source",
6117
+ "span",
6118
+ "strike",
6119
+ "strong",
6120
+ "sub",
6121
+ "sup",
6122
+ "time",
6123
+ "tt",
6124
+ "u",
6125
+ "var",
6126
+ "wbr"
6127
+ ]);
6128
+ var RAW_TEXT_ENDS = /* @__PURE__ */ new Map([
6129
+ ["script", /<\/script\s*>/gi],
6130
+ ["style", /<\/style\s*>/gi]
6131
+ ]);
6132
+ function readMarkup(text, start) {
6133
+ if (text.startsWith("<!--", start)) {
6134
+ const close = nextOutsideFences(text, start + 4, COMMENT_END);
6135
+ return close ? { end: close.index + close[0].length, text: "" } : void 0;
6136
+ }
6137
+ TABLE_OPEN.lastIndex = start;
6138
+ if (TABLE_OPEN.test(text)) {
6139
+ const end2 = tableEnd(text, start);
6140
+ if (end2 === void 0) return void 0;
6141
+ return { end: end2, table: readTable(text.slice(start, end2).replace(COMMENT, "")) };
6142
+ }
6143
+ HTML_TAG.lastIndex = start;
6144
+ const tag = HTML_TAG.exec(text);
6145
+ if (!tag) return void 0;
6146
+ const closing = tag[1] === "/";
6147
+ const name = (tag[2] ?? "").toLowerCase();
6148
+ const end = start + tag[0].length;
6149
+ const rawTextEnd = closing ? void 0 : RAW_TEXT_ENDS.get(name);
6150
+ if (rawTextEnd) {
6151
+ rawTextEnd.lastIndex = end;
6152
+ const close = rawTextEnd.exec(text);
6153
+ return { end: close ? close.index + close[0].length : end, text: "\n" };
6154
+ }
6155
+ if (RAW_TEXT_ENDS.has(name) || BLOCK_ELEMENTS.has(name)) return { end, text: "\n" };
6156
+ if (INLINE_ELEMENTS.has(name)) return { end, text: "" };
6157
+ return void 0;
6158
+ }
6159
+ function tableEnd(text, start) {
6160
+ let depth = 0;
6161
+ let cursor = start;
6162
+ for (; ; ) {
6163
+ const tag = nextOutsideFences(text, cursor, TABLE_TAG);
6164
+ if (!tag) return void 0;
6165
+ depth += tag[1] === "/" ? -1 : 1;
6166
+ cursor = tag.index + tag[0].length;
6167
+ if (depth === 0) return cursor;
6168
+ }
6169
+ }
6170
+ var TABLE_STRUCTURE = /<(\/?)(table|caption|tr|td|th)\b([^>]*)>/gi;
6171
+ function readTable(markup) {
6172
+ let caption = "";
6173
+ let captionStart;
6174
+ const rows = [];
6175
+ let row;
6176
+ let cell;
6177
+ let depth = 0;
6178
+ const endCell = (at) => {
6179
+ if (cell && row) {
6180
+ const colSpan = span(cell.attributes, COLSPAN);
6181
+ const rowSpan = span(cell.attributes, ROWSPAN);
6182
+ row.push({
6183
+ text: cellText(markup.slice(cell.start, at)),
6184
+ header: cell.header,
6185
+ ...colSpan !== void 0 ? { colSpan } : {},
6186
+ ...rowSpan !== void 0 ? { rowSpan } : {}
6187
+ });
6188
+ }
6189
+ cell = void 0;
6190
+ };
6191
+ const endRow = (at) => {
6192
+ endCell(at);
6193
+ if (row && row.length > 0) rows.push(row);
6194
+ row = void 0;
6195
+ };
6196
+ for (const tag of markup.matchAll(TABLE_STRUCTURE)) {
6197
+ const closing = tag[1] === "/";
6198
+ const name = (tag[2] ?? "").toLowerCase();
6199
+ if (name === "table") {
6200
+ depth += closing ? -1 : 1;
6201
+ if (depth === 0) break;
6202
+ continue;
6203
+ }
6204
+ if (depth !== 1) continue;
6205
+ if (name === "caption") {
6206
+ if (!closing && caption === "" && captionStart === void 0) {
6207
+ captionStart = tag.index + tag[0].length;
6208
+ } else if (closing && captionStart !== void 0) {
6209
+ caption = cellText(markup.slice(captionStart, tag.index));
6210
+ captionStart = void 0;
6211
+ }
6212
+ continue;
6213
+ }
6214
+ if (name === "tr") {
6215
+ endRow(tag.index);
6216
+ if (!closing) row = [];
6217
+ continue;
6218
+ }
6219
+ endCell(tag.index);
6220
+ if (!closing && row) {
6221
+ cell = {
6222
+ header: name === "th",
6223
+ attributes: tag[3] ?? "",
6224
+ start: tag.index + tag[0].length
6225
+ };
6226
+ }
6227
+ }
6228
+ endRow(markup.length);
6229
+ if (rows.length === 0 && caption === "") return void 0;
6230
+ return { ...caption !== "" ? { caption } : {}, rows };
6231
+ }
6232
+ var COLSPAN = /\bcolspan\s*=\s*["']?(\d+)/i;
6233
+ var ROWSPAN = /\browspan\s*=\s*["']?(\d+)/i;
6234
+ function span(attributes, pattern) {
6235
+ const match = pattern.exec(attributes);
6236
+ const value = match ? Number(match[1]) : void 0;
6237
+ return value !== void 0 && value > 1 && value <= 1e3 ? value : void 0;
6238
+ }
6239
+ function cellText(markup) {
6240
+ return decodeHtmlEntities(
6241
+ markup.replace(/<br\s*\/?>/gi, "\n").replace(/<\/?(?:table|caption|tr|td|th)\b[^>]*>/gi, "\n").replace(/<[^>]*>/g, "")
6242
+ ).split("\n").map((line) => line.replace(/\s+/g, " ").trim()).filter((line) => line !== "").join("\n");
6243
+ }
5291
6244
  function unwrap(field, value) {
5292
6245
  if (!field.contentKey) return value;
5293
6246
  if (typeof value !== "object" || value === null || Array.isArray(value)) return value;
@@ -5665,11 +6618,13 @@ function ImageValue({
5665
6618
  value,
5666
6619
  inGallery = false,
5667
6620
  inRow = false,
5668
- compact = false
6621
+ compact = false,
6622
+ downloadable = true
5669
6623
  }) {
5670
6624
  const s = useFieldStrings();
5671
6625
  const resolve = useResolveUrl();
5672
- const file = useStuffFile("image", value);
6626
+ const stuffFile = useStuffFile("image", value);
6627
+ const file = downloadable ? stuffFile : void 0;
5673
6628
  const content = readImageContent(value);
5674
6629
  if (!content) return /* @__PURE__ */ jsx(Absent, {});
5675
6630
  const src = paintableUrl(content, resolve);
@@ -5807,7 +6762,13 @@ function LeafValue({
5807
6762
  }
5808
6763
  function RecordSummary({ field, value }) {
5809
6764
  const s = useFieldStrings();
6765
+ const presentation = useFieldPresentation();
5810
6766
  if (isNativeDateNode(field)) return /* @__PURE__ */ jsx(DateValue, { value });
6767
+ const verdict = presentation === "app" ? nativeVerdictOf(field) : void 0;
6768
+ const reading = verdict ? readVerdict(verdict, value, s) : void 0;
6769
+ if (reading) {
6770
+ return /* @__PURE__ */ jsx("span", { className: "whitespace-nowrap text-[13px] text-foreground", children: reading.answer });
6771
+ }
5811
6772
  if (!isRecord(value) || Object.keys(value).length === 0) return /* @__PURE__ */ jsx(Absent, {});
5812
6773
  const naming = isNativeHtmlNode(field) ? void 0 : recordNameField(field.fields) ?? field.fields.find((member) => member.kind === "prose");
5813
6774
  if (naming === void 0) {
@@ -6144,42 +7105,157 @@ function ObjectTable({
6144
7105
  );
6145
7106
  }
6146
7107
  function CompositeValue({ members }) {
6147
- return /* @__PURE__ */ jsx("div", { className: "space-y-3", children: members.map((member) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
6148
- /* @__PURE__ */ jsx("span", { className: "font-mono text-[12px] font-semibold text-foreground", children: member.name }),
6149
- /* @__PURE__ */ jsx(NativeValue, { value: member.value })
6150
- ] }, member.name)) });
7108
+ const presentation = useFieldPresentation();
7109
+ const isApp = presentation === "app";
7110
+ return /* @__PURE__ */ jsx("div", { className: "space-y-3", children: members.map((member) => {
7111
+ const label = isApp ? humanizeFieldName(member.name) : member.name;
7112
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
7113
+ /* @__PURE__ */ jsx(
7114
+ "span",
7115
+ {
7116
+ className: cn(
7117
+ "font-semibold text-foreground",
7118
+ isApp ? "text-[13.5px]" : "font-mono text-[12px]"
7119
+ ),
7120
+ children: label
7121
+ }
7122
+ ),
7123
+ /* @__PURE__ */ jsx(NativeValue, { value: member.value, label })
7124
+ ] }, member.name);
7125
+ }) });
6151
7126
  }
6152
- function NativeValue({ value }) {
7127
+ function NativeValue({ value, label }) {
6153
7128
  if (value === null || value === void 0 || value === "") return /* @__PURE__ */ jsx(Absent, {});
6154
- const html = readHtmlContent(value);
6155
- if (html) return /* @__PURE__ */ jsx(HtmlPreview, { content: html, downloadPdf: false });
6156
- const date = readDateContent(value);
6157
- if (date) return /* @__PURE__ */ jsx("span", { className: "text-[13px] text-foreground", children: formatDateContent(date) });
6158
- const document2 = readDocumentContent(value);
6159
- if (document2?.url !== void 0) {
6160
- return /* @__PURE__ */ jsx(
6161
- FileRef,
6162
- {
6163
- url: document2.url,
6164
- ...document2.mimeType !== void 0 ? { mimeType: document2.mimeType } : {},
6165
- ...document2.filename !== void 0 ? { filename: document2.filename } : {}
6166
- }
6167
- );
7129
+ if (typeof value === "string") return /* @__PURE__ */ jsx(Markdown, { text: value });
7130
+ if (Array.isArray(value)) return /* @__PURE__ */ jsx(NativeList, { items: value, label });
7131
+ if (!isRecord(value)) return /* @__PURE__ */ jsx(Scalar, { value });
7132
+ const content = readMemberContent(value);
7133
+ switch (content?.model) {
7134
+ case "html":
7135
+ return /* @__PURE__ */ jsx(HtmlPreview, { content: content.html, downloadPdf: false });
7136
+ case "date":
7137
+ return /* @__PURE__ */ jsx("span", { className: "text-[13px] text-foreground", children: formatDateContent(content.date) });
7138
+ case "image":
7139
+ return /* @__PURE__ */ jsx(ImageValue, { value, downloadable: false });
7140
+ case "document":
7141
+ return /* @__PURE__ */ jsx(
7142
+ FileRef,
7143
+ {
7144
+ url: content.document.url,
7145
+ ...content.document.mimeType !== void 0 ? { mimeType: content.document.mimeType } : {},
7146
+ ...content.document.filename !== void 0 ? { filename: content.document.filename } : {}
7147
+ }
7148
+ );
7149
+ case "list":
7150
+ return /* @__PURE__ */ jsx(NativeList, { items: content.items, label });
7151
+ case "text":
7152
+ return content.text === "" ? /* @__PURE__ */ jsx(Absent, {}) : /* @__PURE__ */ jsx(Markdown, { text: content.text });
7153
+ case void 0:
7154
+ return /* @__PURE__ */ jsx(RawValue, { value, compact: false });
7155
+ }
7156
+ }
7157
+ function NativeList({ items, label }) {
7158
+ if (items.length === 0) return /* @__PURE__ */ jsx(Absent, {});
7159
+ if (items.every(isPlainRecord)) return /* @__PURE__ */ jsx(RecordsTable, { items, label });
7160
+ return /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/60 overflow-hidden rounded-lg border border-border", children: items.map((item, index) => /* @__PURE__ */ jsx("div", { className: "bg-card/40 px-3 py-1.5", children: /* @__PURE__ */ jsx(NativeValue, { value: item, label }) }, index)) });
7161
+ }
7162
+ var TEXT_MEMBERS = /* @__PURE__ */ new Set(["text"]);
7163
+ var DATE_MEMBERS = /* @__PURE__ */ new Set(["date", "time", ...TYPED_SCALAR_MARKERS]);
7164
+ var HTML_MEMBERS = /* @__PURE__ */ new Set(["inner_html", "css_class"]);
7165
+ var DOCUMENT_MEMBERS = /* @__PURE__ */ new Set([
7166
+ "url",
7167
+ "public_url",
7168
+ "mime_type",
7169
+ "filename",
7170
+ "title",
7171
+ "snippet"
7172
+ ]);
7173
+ var IMAGE_MEMBERS = /* @__PURE__ */ new Set([
7174
+ "url",
7175
+ "public_url",
7176
+ "source_prompt",
7177
+ "source_negative_prompt",
7178
+ "caption",
7179
+ "mime_type",
7180
+ "width",
7181
+ "height",
7182
+ "filename"
7183
+ ]);
7184
+ var LIST_MEMBERS = /* @__PURE__ */ new Set(["items"]);
7185
+ function holdsOnly(record, members) {
7186
+ return Object.keys(record).every((key) => members.has(key));
7187
+ }
7188
+ function readMemberContent(record) {
7189
+ if (holdsOnly(record, HTML_MEMBERS)) {
7190
+ const html = readHtmlContent(record);
7191
+ if (html) return { model: "html", html };
6168
7192
  }
6169
- if (isRecord(value) && Array.isArray(value.items)) {
6170
- const items = value.items;
6171
- if (items.length === 0) return /* @__PURE__ */ jsx(Absent, {});
6172
- return /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/60 overflow-hidden rounded-lg border border-border", children: items.map((item, index) => /* @__PURE__ */ jsx("div", { className: "bg-card/40 px-3 py-1.5", children: /* @__PURE__ */ jsx(NativeValue, { value: item }) }, index)) });
7193
+ if (holdsOnly(record, DATE_MEMBERS)) {
7194
+ const date = readDateContent(record);
7195
+ if (date) return { model: "date", date };
6173
7196
  }
6174
- if (isRecord(value)) {
6175
- const text = value.text;
6176
- if (typeof text === "string") {
6177
- return text === "" ? /* @__PURE__ */ jsx(Absent, {}) : /* @__PURE__ */ jsx(Markdown, { text });
7197
+ if (holdsOnly(record, IMAGE_MEMBERS)) {
7198
+ const image = readImageContent(record);
7199
+ if (image && (!holdsOnly(record, DOCUMENT_MEMBERS) || image.mimeType?.toLowerCase().startsWith("image/") === true)) {
7200
+ return { model: "image" };
6178
7201
  }
6179
7202
  }
6180
- if (typeof value === "string") return /* @__PURE__ */ jsx(Markdown, { text: value });
6181
- if (typeof value !== "object") return /* @__PURE__ */ jsx(Scalar, { value });
6182
- return /* @__PURE__ */ jsx(RawValue, { value, compact: false });
7203
+ if (holdsOnly(record, DOCUMENT_MEMBERS)) {
7204
+ const document2 = readDocumentContent(record);
7205
+ if (document2) return { model: "document", document: document2 };
7206
+ }
7207
+ if (holdsOnly(record, LIST_MEMBERS)) {
7208
+ const items = ownProp(record, "items");
7209
+ if (Array.isArray(items)) return { model: "list", items };
7210
+ }
7211
+ if (holdsOnly(record, TEXT_MEMBERS)) {
7212
+ const text = ownProp(record, "text");
7213
+ if (typeof text === "string") return { model: "text", text };
7214
+ }
7215
+ return void 0;
7216
+ }
7217
+ function isPlainRecord(value) {
7218
+ if (!isRecord(value) || Object.keys(value).length === 0) return false;
7219
+ return readMemberContent(value) === void 0;
7220
+ }
7221
+ function RecordsTable({
7222
+ items,
7223
+ label
7224
+ }) {
7225
+ const presentation = useFieldPresentation();
7226
+ const isApp = presentation === "app";
7227
+ const columns = [];
7228
+ for (const item of items) {
7229
+ for (const key of Object.keys(item)) if (!columns.includes(key)) columns.push(key);
7230
+ }
7231
+ const columnLabel = (column) => isApp ? humanizeFieldName(column) : column;
7232
+ return /* @__PURE__ */ jsx(
7233
+ "div",
7234
+ {
7235
+ role: "group",
7236
+ "aria-label": label,
7237
+ tabIndex: 0,
7238
+ className: cn("overflow-x-auto rounded-lg border border-border", focusOutlineClass),
7239
+ children: /* @__PURE__ */ jsxs("table", { className: "min-w-full border-collapse text-[12.5px] text-foreground", children: [
7240
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { className: "border-b border-border bg-card/40", children: columns.map((column) => /* @__PURE__ */ jsx(
7241
+ "th",
7242
+ {
7243
+ scope: "col",
7244
+ className: cn(
7245
+ "px-2.5 py-1.5 text-start align-bottom font-semibold",
7246
+ !isApp && "font-mono text-[12px]"
7247
+ ),
7248
+ children: columnLabel(column)
7249
+ },
7250
+ column
7251
+ )) }) }),
7252
+ /* @__PURE__ */ jsx("tbody", { children: items.map((item, index) => /* @__PURE__ */ jsx("tr", { className: "border-b border-border/60 last:border-b-0", children: columns.map((column) => {
7253
+ const cell = ownProp(item, column);
7254
+ return /* @__PURE__ */ jsx("td", { className: "px-2.5 py-1.5 align-top", children: typeof cell === "boolean" ? /* @__PURE__ */ jsx(Bool, { value: cell }) : typeof cell === "object" && cell !== null ? /* @__PURE__ */ jsx(NativeValue, { value: cell, label: columnLabel(column) }) : /* @__PURE__ */ jsx(Scalar, { value: cell }) }, column);
7255
+ }) }, index)) })
7256
+ ] })
7257
+ }
7258
+ );
6183
7259
  }
6184
7260
  function isRecord(value) {
6185
7261
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -6188,9 +7264,10 @@ function ScalarLines({ field, items }) {
6188
7264
  return /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/60 overflow-hidden rounded-lg border border-border", children: items.map((item, index) => /* @__PURE__ */ jsx("div", { className: "bg-card/40 px-3 py-1.5", children: /* @__PURE__ */ jsx(LeafValue, { field, value: item }) }, index)) });
6189
7265
  }
6190
7266
  function ImageGallery({ items }) {
7267
+ const resolve = useResolveUrl();
6191
7268
  const anyViewable = items.some((item) => {
6192
7269
  const content = readImageContent(item);
6193
- return content ? !!(viewableUrl(content.publicUrl) ?? viewableUrl(content.url)) : false;
7270
+ return content ? paintableUrl(content, resolve) !== void 0 : false;
6194
7271
  });
6195
7272
  if (!anyViewable) return /* @__PURE__ */ jsx(FileRows, { items, kind: "image" });
6196
7273
  return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-[repeat(auto-fill,minmax(140px,1fr))] gap-2", children: items.map((item, index) => /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-lg border border-border bg-card/40", children: /* @__PURE__ */ jsx(ResultAt, { segment: String(index), children: /* @__PURE__ */ jsx(ImageValue, { value: item, inGallery: true }) }) }, index)) });
@@ -6223,17 +7300,112 @@ function chooseColumns(fields, budget) {
6223
7300
  ...name ? { name } : {}
6224
7301
  };
6225
7302
  }
7303
+ var RAW_PAGE_SOURCES = "data:";
7304
+ function PageValue({ field, value, depth }) {
7305
+ const presentation = useFieldPresentation();
7306
+ const content = readPageContent(value);
7307
+ const text = content?.text;
7308
+ const segments = useMemo(() => text === void 0 ? [] : splitExtractedText(text), [text]);
7309
+ const hasText = segments.length > 0;
7310
+ const rawHtml = hasText ? void 0 : content?.rawHtml;
7311
+ const rawPage = useMemo(
7312
+ () => rawHtml === void 0 ? void 0 : { innerHtml: rawHtml },
7313
+ [rawHtml]
7314
+ );
7315
+ if (!content) return /* @__PURE__ */ jsx(Absent, {});
7316
+ const extracted = hasText || rawPage !== void 0 || content.images.length > 0;
7317
+ const showView = content.pageView !== void 0 && (presentation === "studio" || !extracted);
7318
+ if (!extracted && !showView) return /* @__PURE__ */ jsx(Absent, {});
7319
+ const viewField = field.kind === "object" ? field.fields.find((member) => member.name === "page_view") : void 0;
7320
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
7321
+ hasText && /* @__PURE__ */ jsx(ExtractedPageText, { segments }),
7322
+ rawPage && /* @__PURE__ */ jsx(
7323
+ HtmlPreview,
7324
+ {
7325
+ content: rawPage,
7326
+ downloadPdf: false,
7327
+ imgSrc: RAW_PAGE_SOURCES,
7328
+ fontSrc: RAW_PAGE_SOURCES
7329
+ }
7330
+ ),
7331
+ content.images.length > 0 && /* @__PURE__ */ jsx(ResultAt, { segment: "text_and_images", children: /* @__PURE__ */ jsx(ResultAt, { segment: "images", children: /* @__PURE__ */ jsx(ImageGallery, { items: content.images }) }) }),
7332
+ showView && /* @__PURE__ */ jsx(ResultAt, { segment: "page_view", children: presentation === "studio" && viewField ? /* @__PURE__ */ jsx(ResultField, { field: viewField, value: content.pageView, depth: depth + 1 }) : /* @__PURE__ */ jsx(ImageValue, { value: content.pageView }) })
7333
+ ] });
7334
+ }
7335
+ function readVerdict(verdict, value, s) {
7336
+ if (verdict === "yes_no") {
7337
+ const content2 = readYesNoContent(value);
7338
+ if (!content2) return void 0;
7339
+ return {
7340
+ answer: content2.yesNo ? s.yes : s.no,
7341
+ ...content2.probability !== void 0 ? { measure: s.yesProbability(content2.probability) } : {}
7342
+ };
7343
+ }
7344
+ if (verdict === "rating") {
7345
+ const content2 = readRatingContent(value);
7346
+ if (!content2) return void 0;
7347
+ return {
7348
+ // A scale that names its levels says which one in words; one that does
7349
+ // not is counted from one, as a reader counts.
7350
+ answer: content2.label ?? s.ratingLevel(content2.level + 1),
7351
+ ...content2.confidence !== void 0 ? { measure: s.verdictConfidence(content2.confidence) } : {}
7352
+ };
7353
+ }
7354
+ const content = readChoiceContent(value);
7355
+ if (!content) return void 0;
7356
+ return {
7357
+ answer: humanizeEnumValue(content.choice),
7358
+ ...content.confidence !== void 0 ? { measure: s.verdictConfidence(content.confidence) } : {}
7359
+ };
7360
+ }
7361
+ function VerdictValue({ reading, prominent }) {
7362
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
7363
+ /* @__PURE__ */ jsx(
7364
+ "p",
7365
+ {
7366
+ className: cn(
7367
+ "font-semibold text-foreground",
7368
+ prominent ? "text-[22px] leading-tight" : "text-[15px] leading-snug"
7369
+ ),
7370
+ children: reading.answer
7371
+ }
7372
+ ),
7373
+ reading.measure !== void 0 && /* @__PURE__ */ jsx("p", { className: "text-[12.5px] text-muted-foreground", children: reading.measure })
7374
+ ] });
7375
+ }
7376
+ function isLongText(value) {
7377
+ return typeof value === "string" && (value.includes("\n") || value.length > CELL_LENGTH_LIMIT);
7378
+ }
7379
+ var PanelResultContext = createContext(null);
7380
+ var TITLED_PANEL = { hostHeaded: false };
7381
+ var HOST_HEADED_PANEL = { hostHeaded: true };
7382
+ function PanelResult({
7383
+ hostHeaded,
7384
+ children
7385
+ }) {
7386
+ return /* @__PURE__ */ jsx(PanelResultContext, { value: hostHeaded ? HOST_HEADED_PANEL : TITLED_PANEL, children });
7387
+ }
6226
7388
  function ResultField(props) {
6227
7389
  const location = useResultLocation();
6228
- if (location) return /* @__PURE__ */ jsx(ResultNode, { ...props });
6229
- return /* @__PURE__ */ jsx(ResultRoot, { baseName: props.field.name, path: [props.field.name], children: /* @__PURE__ */ jsx(ResultNode, { ...props }) });
7390
+ const panel = use(PanelResultContext);
7391
+ const node = panel ? /* @__PURE__ */ jsx(PanelResultContext, { value: null, children: /* @__PURE__ */ jsx(ResultNode, { ...props, whole: true, hostHeaded: panel.hostHeaded }) }) : /* @__PURE__ */ jsx(ResultNode, { ...props });
7392
+ if (location) return node;
7393
+ return /* @__PURE__ */ jsx(ResultRoot, { baseName: props.field.name, path: [props.field.name], children: node });
6230
7394
  }
6231
- function ResultNode({ field, value, depth = 0, hideLabel = false }) {
7395
+ function ResultNode({
7396
+ field,
7397
+ value,
7398
+ depth = 0,
7399
+ hideLabel = false,
7400
+ whole = false,
7401
+ hostHeaded = false
7402
+ }) {
6232
7403
  const s = useFieldStrings();
6233
7404
  const unwrapped = unwrap(field, value);
6234
7405
  const pageDownloadShown = useFileDownloadShown("markup");
6235
7406
  const pdfShown = usePdfSaveShown();
6236
7407
  const location = useResultLocation();
7408
+ const isApp = useFieldPresentation() === "app";
6237
7409
  const header = hideLabel ? null : /* @__PURE__ */ jsx(Label2, { field, describe: true });
6238
7410
  const copyText = (field.kind === "text" || field.kind === "prose") && typeof unwrapped === "string" && unwrapped !== "" ? unwrapped : void 0;
6239
7411
  if (isNativeDateNode(field)) {
@@ -6271,9 +7443,24 @@ function ResultNode({ field, value, depth = 0, hideLabel = false }) {
6271
7443
  members && members.length > 0 ? /* @__PURE__ */ jsx(CompositeValue, { members }) : /* @__PURE__ */ jsx(Absent, {})
6272
7444
  ] });
6273
7445
  }
7446
+ if (isNativePageNode(field)) {
7447
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
7448
+ header,
7449
+ /* @__PURE__ */ jsx(PageValue, { field, value: unwrapped, depth })
7450
+ ] });
7451
+ }
7452
+ const verdict = isApp ? nativeVerdictOf(field) : void 0;
7453
+ const reading = verdict ? readVerdict(verdict, unwrapped, s) : void 0;
7454
+ if (reading) {
7455
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
7456
+ header,
7457
+ /* @__PURE__ */ jsx(VerdictValue, { reading, prominent: whole })
7458
+ ] });
7459
+ }
6274
7460
  switch (field.kind) {
6275
7461
  case "object": {
6276
7462
  const memberValue = (child) => typeof unwrapped === "object" && unwrapped !== null ? ownProp(unwrapped, child.name) : void 0;
7463
+ const sharesALine = (child) => isInlineColumn(child) && !(isApp && child.kind === "text" && isLongText(unwrap(child, memberValue(child))));
6277
7464
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
6278
7465
  header,
6279
7466
  /* @__PURE__ */ jsx(
@@ -6305,7 +7492,7 @@ function ResultNode({ field, value, depth = 0, hideLabel = false }) {
6305
7492
  // so does anything with chrome of its own - a table, a gallery, a
6306
7493
  // frame - which beside a label would be squeezed into whatever the
6307
7494
  // longest label left over.
6308
- isInlineColumn(child) ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
7495
+ sharesALine(child) ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
6309
7496
  /* @__PURE__ */ jsx("div", { className: "min-w-0", children: /* @__PURE__ */ jsx(Label2, { field: child, describe: true }) }),
6310
7497
  /* @__PURE__ */ jsx("div", { className: "flex min-w-0 justify-end **:data-chips:justify-end", children: /* @__PURE__ */ jsx("div", { className: "min-w-0 text-left wrap-break-word", children: /* @__PURE__ */ jsx(LeafValue, { field: child, value: memberValue(child) }) }) })
6311
7498
  ] }, child.name) : /* @__PURE__ */ jsx("div", { className: "col-span-2 min-w-0", children: /* @__PURE__ */ jsx(ResultAt, { segment: child.name, children: /* @__PURE__ */ jsx(ResultField, { field: child, value: memberValue(child), depth: depth + 1 }) }) }, child.name)
@@ -6319,7 +7506,7 @@ function ResultNode({ field, value, depth = 0, hideLabel = false }) {
6319
7506
  const items = Array.isArray(unwrapped) ? unwrapped : [];
6320
7507
  const columns = recordColumns(field.item);
6321
7508
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
6322
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2", children: [
7509
+ isApp && hostHeaded ? null : /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2", children: [
6323
7510
  header,
6324
7511
  /* @__PURE__ */ jsx("span", { className: "font-mono text-[10.5px] text-muted-foreground", children: s.itemsCount(items.length) })
6325
7512
  ] }),
@@ -6331,6 +7518,30 @@ function ResultNode({ field, value, depth = 0, hideLabel = false }) {
6331
7518
  // column named by it, and show a composite as JSON. The arm keyed by
6332
7519
  // concept is the one that knows what each entry is.
6333
7520
  /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/60 overflow-hidden rounded-lg border border-border", children: items.map((item, index) => /* @__PURE__ */ jsx("div", { className: "bg-card/40 px-3 py-1.5", children: /* @__PURE__ */ jsx(ResultAt, { segment: String(index), children: /* @__PURE__ */ jsx(ResultField, { field: field.item, value: item, depth: depth + 1, hideLabel: true }) }) }, index)) })
7521
+ ) : isNativePageNode(field.item) ? (
7522
+ // A document's pages, one after the other, each drawn by the page
7523
+ // arm and captioned with its number: a page is a document's unit,
7524
+ // and a table of pages had a row per page and the text nowhere.
7525
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: items.map((item, index) => (
7526
+ // An article, not a section: a named section is a landmark,
7527
+ // and a landmark's name must be unique on the page, which
7528
+ // "Page 1" is not once a host shows two results.
7529
+ /* @__PURE__ */ jsxs(
7530
+ "article",
7531
+ {
7532
+ "aria-label": s.pageNumber(index + 1),
7533
+ className: "space-y-2 rounded-lg border border-border bg-card/40 px-3.5 py-3",
7534
+ children: [
7535
+ /* @__PURE__ */ jsx("span", { className: "text-[12px] font-medium text-muted-foreground", children: s.pageNumber(index + 1) }),
7536
+ /* @__PURE__ */ jsx(ResultAt, { segment: String(index), children: /* @__PURE__ */ jsx(ResultField, { field: field.item, value: item, depth: depth + 1, hideLabel: true }) })
7537
+ ]
7538
+ },
7539
+ index
7540
+ )
7541
+ )) })
7542
+ ) : isApp && nativeVerdictOf(field.item) ? (
7543
+ // Verdicts in `app`, one per line, each drawn by the verdict arm.
7544
+ /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/60 overflow-hidden rounded-lg border border-border", children: items.map((item, index) => /* @__PURE__ */ jsx("div", { className: "bg-card/40 px-3 py-1.5", children: /* @__PURE__ */ jsx(ResultAt, { segment: String(index), children: /* @__PURE__ */ jsx(ResultField, { field: field.item, value: item, depth: depth + 1, hideLabel: true }) }) }, index)) })
6334
7545
  ) : columns ? (
6335
7546
  // Same shape every row: the labels are column headers, not per-row
6336
7547
  // labels. See `ObjectTable`.
@@ -6387,7 +7598,7 @@ function ResultNode({ field, value, depth = 0, hideLabel = false }) {
6387
7598
  /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: header }),
6388
7599
  /* @__PURE__ */ jsx(CopyButton, { value: copyText, label: s.copyText })
6389
7600
  ] }),
6390
- /* @__PURE__ */ jsx(LeafValue, { field, value })
7601
+ isApp && field.kind === "text" && isLongText(unwrapped) ? /* @__PURE__ */ jsx(Markdown, { text: unwrapped }) : /* @__PURE__ */ jsx(LeafValue, { field, value })
6391
7602
  ] });
6392
7603
  }
6393
7604
  return null;
@@ -6549,6 +7760,9 @@ function StuffPanel({
6549
7760
  const labels = { rendered: s.viewRendered, json: s.viewJson };
6550
7761
  const pdfName = page && pdfShown ? pdfFileName(field, value, baseName) : void 0;
6551
7762
  const pageView = page !== void 0 && view !== "json";
7763
+ const titled = presentation !== "app" || name !== void 0 && name !== "" && !page;
7764
+ const switchShown = offered.length > 1;
7765
+ const headerShown = titled || downloadShown || switchShown || page && pdfName !== void 0;
6552
7766
  return /* @__PURE__ */ jsxs(
6553
7767
  "div",
6554
7768
  {
@@ -6563,8 +7777,9 @@ function StuffPanel({
6563
7777
  className
6564
7778
  ),
6565
7779
  children: [
6566
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-wrap items-center justify-between gap-x-4 gap-y-1", children: [
6567
- page && presentation === "app" ? /* @__PURE__ */ jsx("div", {}) : /* @__PURE__ */ jsx("div", { className: "min-w-0 space-y-1", children: /* @__PURE__ */ jsx(ResultHeader, { field: named }) }),
7780
+ dialog,
7781
+ headerShown && /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-wrap items-center justify-between gap-x-4 gap-y-1", children: [
7782
+ titled ? /* @__PURE__ */ jsx("div", { className: "min-w-0 space-y-1", children: /* @__PURE__ */ jsx(ResultHeader, { field: named }) }) : /* @__PURE__ */ jsx("div", {}),
6568
7783
  /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
6569
7784
  page && pdfName !== void 0 && /* @__PURE__ */ jsx(
6570
7785
  PdfDownloadButton,
@@ -6592,8 +7807,7 @@ function StuffPanel({
6592
7807
  ]
6593
7808
  }
6594
7809
  ),
6595
- dialog,
6596
- offered.length > 1 && /* @__PURE__ */ jsx(
7810
+ switchShown && /* @__PURE__ */ jsx(
6597
7811
  "div",
6598
7812
  {
6599
7813
  role: "group",
@@ -6634,7 +7848,7 @@ function StuffPanel({
6634
7848
  // `ResultField`, whose page arm would add a second control row saving
6635
7849
  // the same file, and with no box around it.
6636
7850
  /* @__PURE__ */ jsx(HtmlPreview, { content: page, downloadPdf: false, bare: true, fill: true })
6637
- ) : /* @__PURE__ */ jsx(ResultRoot, { baseName, path: [field.name], children: /* @__PURE__ */ jsx(ResultField, { field, value, hideLabel: true }) })
7851
+ ) : /* @__PURE__ */ jsx(ResultRoot, { baseName, path: [field.name], children: /* @__PURE__ */ jsx(PanelResult, { hostHeaded: !titled, children: /* @__PURE__ */ jsx(ResultField, { field, value, hideLabel: true }) }) })
6638
7852
  ]
6639
7853
  }
6640
7854
  );
@@ -6646,5 +7860,5 @@ function pdfFileName(field, value, baseName) {
6646
7860
  }
6647
7861
 
6648
7862
  export { BooleanField, ConceptPill, DEFAULT_FIELD_STRINGS, DateField, DocumentField, EN_FIELD_STRINGS, EnumField, FIELD_STRINGS_BY_LOCALE, FR_FIELD_STRINGS, FieldDomIdProvider, FieldPresentationProvider, FieldRenderer, FieldShell, FieldStringsProvider, FilePicker, FilePickerEntry, FillWithExample, HtmlPreview, ImageField, JsonView, ListField, Markdown, MethodForm, NumberField, ObjectField, OptionalToggle, PdfDownloadButton, ProseField, ResultEnvProvider, ResultField, ResultRoot, SUPPORTED_LOCALES, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, StuffViewer, Switch, TextField, ToggleGroup, ToggleGroupItem, UnknownField, checkedAccentClass, cn, fieldControlClass, fieldStringsFor, focusOutlineClass, humanizeFieldName, linkTextClass, renderHtmlPdf, resolveHtmlStorageUrls, saveInBrowser, selectedBorderClass, selectedFillClass, selectedFillStrongClass, useFieldDomId, useFieldPresentation, useFieldStrings, useMethodForm, useProseImages, useResolveShareUrl, useResolveUrl, useResolvedUrl };
6649
- //# sourceMappingURL=chunk-W5MYXDLO.js.map
6650
- //# sourceMappingURL=chunk-W5MYXDLO.js.map
7863
+ //# sourceMappingURL=chunk-NA7SIQOH.js.map
7864
+ //# sourceMappingURL=chunk-NA7SIQOH.js.map