@pipelex/mthds-form 0.19.0 → 0.21.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,26 +1,30 @@
1
1
  import { planFileSave, planStuffSave, splitFileName, typedFileStem } from './chunk-ICUEHNEH.js';
2
2
  import { seedInputs, closeOptionalStructures, openOptionalStructures } from './chunk-VH5CDQDR.js';
3
+ import { sourceFileValue, roomForChosenFiles, addChosenFiles, chosenFilesAdded } from './chunk-EQJBM3NS.js';
3
4
  import { readStuffFile } from './chunk-RRTI7AIR.js';
4
- import { setValueAtPath, apiInputsFromRunValues } from './chunk-MEXWXLR7.js';
5
+ import { setValueAtPath, apiInputsFromRunValues, sameRunValues, runValuesFromInputs } from './chunk-ZX52CQJ4.js';
5
6
  import { viewableUrl, isNativeDateNode, isNativeHtmlNode, readHtmlContent, isNativeCompositeNode, readCompositeContent, isNativeValueNode, readDateContent, formatDateContent, readImageContent, readDataUrl, readDocumentContent } from './chunk-CM4KVG53.js';
6
7
  import { buildRunFields } from './chunk-ZB4RYUKV.js';
7
8
  import { conceptCategory } from './chunk-FABY3DEY.js';
8
- import { acceptLabel, acceptMap, isAcceptedFile, formatOfFilename, DOCUMENT_FORMATS, IMAGE_FORMATS } from './chunk-XCO6GTEC.js';
9
+ import { acceptLabel, acceptMap, isAcceptedFile, normalizeMimeType, formatOfFilename, DOCUMENT_FORMATS, IMAGE_FORMATS } from './chunk-XCO6GTEC.js';
9
10
  import { shownAsOptional, isFoldedOptional, anyOptionalStructureOpen, isOptionalStructure, computeReadiness, optionalStructureOpen, mustBeFilled, fieldFilled, isFilled } from './chunk-XO5OENNF.js';
10
11
  import { ownProp } from './chunk-V3OV2XQT.js';
11
12
  import { toStoredDateValue, toDateInputValue } from './chunk-GKV77RAS.js';
12
13
  import { clsx } from 'clsx';
13
14
  import { twMerge } from 'tailwind-merge';
14
- import { ChevronDown, ChevronUp, Check, List, Braces, ListChecks, ToggleLeft, Hash, Image as Image$1, FileText, CalendarDays, Type, Loader2, ImageOff, Upload, Link2, EyeOff, Eye, X, Minus, Plus, Trash2, TriangleAlert, FileDown, Copy, Download, ChevronRight } from 'lucide-react';
15
+ import { ChevronDown, ChevronUp, Check, List, Braces, ListChecks, ToggleLeft, Hash, Image as Image$1, FileText, CalendarDays, Type, Folder, Search, X, ImageIcon, Loader2, ImageOff, Upload, Link2, EyeOff, Eye, Minus, Plus, Trash2, Sparkles, MoreHorizontal, TriangleAlert, FileDown, Copy, Download, ChevronRight } from 'lucide-react';
15
16
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
16
- import * as React2 from 'react';
17
- import { createContext, use, useId, useMemo, useContext, useState, useRef, useCallback, useEffect, Fragment as Fragment$1, useLayoutEffect } from 'react';
17
+ import * as React5 from 'react';
18
+ import { createContext, use, useId, useMemo, useContext, useState, useEffect, useRef, useLayoutEffect, useCallback, Fragment as Fragment$1 } from 'react';
18
19
  import * as SwitchPrimitives from '@radix-ui/react-switch';
19
20
  import { useDropzone } from 'react-dropzone';
20
- import * as SelectPrimitive from '@radix-ui/react-select';
21
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
21
22
  import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group';
22
23
  import * as TogglePrimitive from '@radix-ui/react-toggle';
23
24
  import { cva } from 'class-variance-authority';
25
+ import * as SelectPrimitive from '@radix-ui/react-select';
26
+ import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
27
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
24
28
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
25
29
  import { marked } from 'marked';
26
30
 
@@ -107,7 +111,7 @@ function fieldLabel(title, name, presentation) {
107
111
  if (title !== void 0) return title;
108
112
  return presentation === "app" ? humanizeFieldName(name) : name;
109
113
  }
110
- var Switch = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
114
+ var Switch = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
111
115
  SwitchPrimitives.Root,
112
116
  {
113
117
  className: cn(
@@ -186,12 +190,38 @@ function BooleanField({ field, value, onChange, id, disabled }) {
186
190
  );
187
191
  }
188
192
 
193
+ // src/react/locales/calendar.ts
194
+ function dayNumber(date) {
195
+ return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) / 864e5;
196
+ }
197
+ function calendarDaysBefore(date, now = /* @__PURE__ */ new Date()) {
198
+ return dayNumber(now) - dayNumber(date);
199
+ }
200
+ function inCurrentYear(date, now = /* @__PURE__ */ new Date()) {
201
+ return date.getFullYear() === now.getFullYear();
202
+ }
203
+
189
204
  // src/react/locales/en.ts
190
205
  function formatBytes(bytes) {
191
206
  if (bytes < 1024) return bytes === 1 ? "1 byte" : `${bytes} bytes`;
192
207
  if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
193
208
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
194
209
  }
210
+ var AND = new Intl.ListFormat("en-GB", { type: "conjunction" });
211
+ var OR = new Intl.ListFormat("en-GB", { type: "disjunction" });
212
+ var TIME = new Intl.DateTimeFormat("en-GB", { hour: "2-digit", minute: "2-digit" });
213
+ var DAY = new Intl.DateTimeFormat("en-GB", { day: "numeric", month: "short" });
214
+ var DAY_YEAR = new Intl.DateTimeFormat("en-GB", {
215
+ day: "numeric",
216
+ month: "short",
217
+ year: "numeric"
218
+ });
219
+ function formatFileDate(date) {
220
+ const days = calendarDaysBefore(date);
221
+ if (days === 0) return `Today, ${TIME.format(date)}`;
222
+ if (days === 1) return "Yesterday";
223
+ return inCurrentYear(date) ? DAY.format(date) : DAY_YEAR.format(date);
224
+ }
195
225
  var EN_FIELD_STRINGS = {
196
226
  optionalBadge: "optional",
197
227
  selectPlaceholder: "Select\u2026",
@@ -252,7 +282,61 @@ var EN_FIELD_STRINGS = {
252
282
  optionalInputsCount: (count) => count === 1 ? "1 optional input" : `${count} optional inputs`,
253
283
  requiredField: "Required",
254
284
  incompleteField: "Incomplete: fill in its required fields",
255
- uploadFailed: "This file could not be uploaded. Try again."
285
+ uploadFailed: "This file could not be uploaded. Try again.",
286
+ chooseFromSource: "Choose from your team's files",
287
+ chooseFromSourceAria: (label) => label ? `Choose from your team's files for ${label}` : "Choose from your team's files",
288
+ filePickerTitle: "Your team's files",
289
+ filePickerTakes: (formats) => `Showing ${AND.format(formats)} files, which this input takes`,
290
+ filePickerSearch: "Search files",
291
+ filePickerSearchPlaceholder: "Search by name",
292
+ filePickerScope: "Whose files",
293
+ filePickerMine: "Mine",
294
+ filePickerEveryone: "Everyone",
295
+ filePickerUse: (count, name) => {
296
+ if (count === 0) return "Choose a file";
297
+ if (count === 1 && name) return `Use ${name}`;
298
+ return count === 1 ? "Use 1 file" : `Use ${count} files`;
299
+ },
300
+ filePickerLoading: "Loading your files\u2026",
301
+ filePickerFailed: "Couldn't load your files.",
302
+ filePickerNoMatch: "No files match.",
303
+ filePickerClearSearch: "Clear search",
304
+ filePickerNoneTeam: (formats) => `Your team has no ${OR.format(formats)} files yet.`,
305
+ filePickerNoneMine: (formats) => `You haven't added or made any ${OR.format(formats)} files yet.`,
306
+ filePickerShowEveryone: "Show everyone's",
307
+ filePickerUpload: "Upload a file",
308
+ filePickerShown: (count) => count === 1 ? "1 file" : `${count} files`,
309
+ testFile: "Test file",
310
+ fileSize: formatBytes,
311
+ fileDate: formatFileDate,
312
+ fillWithExample: "Fill with an example",
313
+ examplesTitle: "Examples",
314
+ examplesHint: "Choosing one fills the form. Nothing runs until you run it.",
315
+ examplesLoading: "Loading the examples\u2026",
316
+ examplesFailed: "Couldn't load the examples.",
317
+ examplesNone: "No examples yet. Run it, then save the run as an example.",
318
+ examplesShown: (count) => count === 1 ? "1 example" : `${count} examples`,
319
+ replaceEnteredTitle: "Replace what you entered?",
320
+ replaceEnteredDescription: (name) => `Filling the form with \u201C${name}\u201D replaces every value in it.`,
321
+ replaceEnteredConfirm: "Replace",
322
+ exampleActions: (name) => `Actions for ${name}`,
323
+ renameExample: "Rename",
324
+ deleteExample: "Delete",
325
+ renameExampleTitle: "Rename the example",
326
+ exampleName: "Name",
327
+ renaming: "Renaming\u2026",
328
+ renameFailed: "Couldn't rename the example.",
329
+ deleteExampleTitle: (name) => `Delete \u201C${name}\u201D?`,
330
+ deleteExampleDescription: "This cannot be undone.",
331
+ deleting: "Deleting\u2026",
332
+ deleteFailed: "Couldn't delete the example.",
333
+ close: "Close",
334
+ cancel: "Cancel",
335
+ save: "Save",
336
+ tryAgain: "Try again",
337
+ showMore: "Show more",
338
+ loadingMore: "Loading more\u2026",
339
+ loadMoreFailed: "Couldn't load more."
256
340
  };
257
341
 
258
342
  // src/react/locales/fr.ts
@@ -270,6 +354,21 @@ var MEGABYTES = new Intl.NumberFormat("fr-FR", {
270
354
  unitDisplay: "short",
271
355
  maximumFractionDigits: 1
272
356
  });
357
+ var AND2 = new Intl.ListFormat("fr", { type: "conjunction" });
358
+ var OR2 = new Intl.ListFormat("fr", { type: "disjunction" });
359
+ var TIME2 = new Intl.DateTimeFormat("fr-FR", { hour: "2-digit", minute: "2-digit" });
360
+ var DAY2 = new Intl.DateTimeFormat("fr-FR", { day: "numeric", month: "short" });
361
+ var DAY_YEAR2 = new Intl.DateTimeFormat("fr-FR", {
362
+ day: "numeric",
363
+ month: "short",
364
+ year: "numeric"
365
+ });
366
+ function formatFileDate2(date) {
367
+ const days = calendarDaysBefore(date);
368
+ if (days === 0) return `Aujourd\u2019hui, ${TIME2.format(date)}`;
369
+ if (days === 1) return "Hier";
370
+ return inCurrentYear(date) ? DAY2.format(date) : DAY_YEAR2.format(date);
371
+ }
273
372
  function plural(count, one, other) {
274
373
  return PLURALS.select(count) === "one" ? one : other;
275
374
  }
@@ -338,7 +437,61 @@ var FR_FIELD_STRINGS = {
338
437
  optionalInputsCount: (count) => `${count} ${plural(count, "entr\xE9e facultative", "entr\xE9es facultatives")}`,
339
438
  requiredField: "Obligatoire",
340
439
  incompleteField: "Incomplet\xA0: remplissez ses champs obligatoires",
341
- uploadFailed: "Ce fichier n\u2019a pas pu \xEAtre envoy\xE9. R\xE9essayez."
440
+ uploadFailed: "Ce fichier n\u2019a pas pu \xEAtre envoy\xE9. R\xE9essayez.",
441
+ chooseFromSource: "Choisir parmi les fichiers de l\u2019\xE9quipe",
442
+ chooseFromSourceAria: (label) => label ? `Choisir parmi les fichiers de l\u2019\xE9quipe pour ${label}` : "Choisir parmi les fichiers de l\u2019\xE9quipe",
443
+ filePickerTitle: "Les fichiers de l\u2019\xE9quipe",
444
+ filePickerTakes: (formats) => `Fichiers ${AND2.format(formats)} uniquement, ceux que cette entr\xE9e accepte`,
445
+ filePickerSearch: "Rechercher des fichiers",
446
+ filePickerSearchPlaceholder: "Rechercher par nom",
447
+ filePickerScope: "Quels fichiers",
448
+ filePickerMine: "Les miens",
449
+ filePickerEveryone: "Toute l\u2019\xE9quipe",
450
+ filePickerUse: (count, name) => {
451
+ if (count === 0) return "Choisissez un fichier";
452
+ if (count === 1 && name) return `Utiliser ${name}`;
453
+ return `Utiliser ${count} ${plural(count, "fichier", "fichiers")}`;
454
+ },
455
+ filePickerLoading: "Chargement de vos fichiers\u2026",
456
+ filePickerFailed: "Impossible de charger vos fichiers.",
457
+ filePickerNoMatch: "Aucun fichier ne correspond.",
458
+ filePickerClearSearch: "Effacer la recherche",
459
+ filePickerNoneTeam: (formats) => `L\u2019\xE9quipe n\u2019a encore aucun fichier ${OR2.format(formats)}.`,
460
+ filePickerNoneMine: (formats) => `Vous n\u2019avez encore ni ajout\xE9 ni cr\xE9\xE9 de fichier ${OR2.format(formats)}.`,
461
+ filePickerShowEveryone: "Voir ceux de l\u2019\xE9quipe",
462
+ filePickerUpload: "Envoyer un fichier",
463
+ filePickerShown: (count) => `${count} ${plural(count, "fichier", "fichiers")}`,
464
+ testFile: "Fichier de test",
465
+ fileSize: formatBytes2,
466
+ fileDate: formatFileDate2,
467
+ fillWithExample: "Remplir avec un exemple",
468
+ examplesTitle: "Exemples",
469
+ examplesHint: "En choisir un remplit le formulaire. Rien ne s\u2019ex\xE9cute avant que vous le lanciez.",
470
+ examplesLoading: "Chargement des exemples\u2026",
471
+ examplesFailed: "Impossible de charger les exemples.",
472
+ examplesNone: "Aucun exemple pour le moment. Lancez-le, puis enregistrez l\u2019ex\xE9cution comme exemple.",
473
+ examplesShown: (count) => `${count} ${plural(count, "exemple", "exemples")}`,
474
+ replaceEnteredTitle: "Remplacer ce que vous avez saisi\xA0?",
475
+ replaceEnteredDescription: (name) => `Remplir le formulaire avec \xAB\xA0${name}\xA0\xBB remplace toutes ses valeurs.`,
476
+ replaceEnteredConfirm: "Remplacer",
477
+ exampleActions: (name) => `Actions pour ${name}`,
478
+ renameExample: "Renommer",
479
+ deleteExample: "Supprimer",
480
+ renameExampleTitle: "Renommer l\u2019exemple",
481
+ exampleName: "Nom",
482
+ renaming: "Renommage\u2026",
483
+ renameFailed: "Impossible de renommer l\u2019exemple.",
484
+ deleteExampleTitle: (name) => `Supprimer \xAB\xA0${name}\xA0\xBB\xA0?`,
485
+ deleteExampleDescription: "Cette action est irr\xE9versible.",
486
+ deleting: "Suppression\u2026",
487
+ deleteFailed: "Impossible de supprimer l\u2019exemple.",
488
+ close: "Fermer",
489
+ cancel: "Annuler",
490
+ save: "Enregistrer",
491
+ tryAgain: "R\xE9essayer",
492
+ showMore: "Afficher plus",
493
+ loadingMore: "Chargement de la suite\u2026",
494
+ loadMoreFailed: "Impossible de charger la suite."
342
495
  };
343
496
 
344
497
  // src/react/locales/index.ts
@@ -413,11 +566,20 @@ function FieldShell({
413
566
  ] });
414
567
  }
415
568
 
569
+ // src/react/brand-ink.ts
570
+ var brandInkClass = "text-[color:var(--brand,var(--primary,hsl(240_5.9%_10%)))]";
571
+ var brandFillInkClass = "text-[color:var(--brand-muted-foreground,var(--brand,var(--primary,hsl(240_5.9%_10%))))]";
572
+ var brandFillClass = "bg-[color:var(--brand-muted,color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_10%,transparent))]";
573
+ var brandFillSelectedClass = "data-[state=on]:bg-[color:var(--brand-muted,color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_10%,transparent))]";
574
+ var brandFillStrongClass = "bg-[color:var(--brand-muted,color-mix(in_oklab,var(--primary,hsl(240_5.9%_10%))_15%,transparent))]";
575
+ var brandFocusClass = "focus-visible:border-[color:var(--brand,var(--primary,hsl(240_5.9%_10%)))] focus-visible:ring-[color:color-mix(in_oklab,var(--brand,var(--primary,hsl(240_5.9%_10%)))_40%,transparent)]";
576
+
416
577
  // src/react/field-styles.ts
417
578
  var fieldControlClass = cn(
418
579
  "w-full rounded-md border border-border bg-input text-sm text-foreground",
419
580
  "placeholder:text-muted-foreground/70 transition-colors",
420
- "focus-visible:outline-hidden focus-visible:border-primary focus-visible:ring-1 focus-visible:ring-primary/40",
581
+ "focus-visible:outline-hidden focus-visible:ring-1",
582
+ brandFocusClass,
421
583
  "disabled:cursor-not-allowed disabled:opacity-50",
422
584
  "aria-invalid:border-destructive aria-invalid:ring-destructive/30"
423
585
  );
@@ -457,6 +619,622 @@ function encodedFileSummary(url, strings) {
457
619
  const format = [...DOCUMENT_FORMATS, ...IMAGE_FORMATS].find((known) => known.mimeType === view.mediaType)?.label ?? view.mediaType;
458
620
  return strings.encodedFileSummary(format, view.bytes);
459
621
  }
622
+ function startFor(key) {
623
+ return { key, status: key === null ? "idle" : "loading", items: [], cursor: null, more: "idle" };
624
+ }
625
+ function useSourcePages(load, key) {
626
+ const [stored, setState] = useState(() => startFor(key));
627
+ if (stored.key !== key) setState(startFor(key));
628
+ const state = stored.key === key ? stored : startFor(key);
629
+ const loadRef = useRef(load);
630
+ const inFlight = useRef(null);
631
+ const followed = useRef(/* @__PURE__ */ new Set());
632
+ useEffect(() => {
633
+ loadRef.current = load;
634
+ });
635
+ const read = useCallback(
636
+ (forKey, cursor, phase) => {
637
+ inFlight.current?.abort();
638
+ const controller = new AbortController();
639
+ inFlight.current = controller;
640
+ const seen = new Set(phase === "first" ? [] : followed.current);
641
+ const follow = (from) => {
642
+ if (from !== void 0) seen.add(from);
643
+ let page;
644
+ try {
645
+ page = Promise.resolve(loadRef.current(from, controller.signal));
646
+ } catch (error) {
647
+ page = Promise.reject(error);
648
+ }
649
+ page.then(
650
+ (answer) => {
651
+ if (inFlight.current !== controller) return;
652
+ const offered = answer.nextCursor ?? null;
653
+ const next = offered !== null && seen.has(offered) ? null : offered;
654
+ const items = [...answer.items];
655
+ if (items.length === 0 && next !== null) {
656
+ follow(next);
657
+ return;
658
+ }
659
+ inFlight.current = null;
660
+ followed.current = seen;
661
+ setState(
662
+ (previous) => previous.key !== forKey ? previous : {
663
+ key: forKey,
664
+ status: "ready",
665
+ items: phase === "first" ? items : [...previous.items, ...items],
666
+ cursor: next,
667
+ more: "idle"
668
+ }
669
+ );
670
+ },
671
+ () => {
672
+ if (inFlight.current !== controller) return;
673
+ inFlight.current = null;
674
+ setState(
675
+ (previous) => previous.key !== forKey ? previous : phase === "first" ? { key: forKey, status: "failed", items: [], cursor: null, more: "idle" } : { ...previous, more: "failed" }
676
+ );
677
+ }
678
+ );
679
+ };
680
+ follow(cursor);
681
+ },
682
+ []
683
+ );
684
+ useEffect(() => {
685
+ if (key === null) {
686
+ inFlight.current?.abort();
687
+ inFlight.current = null;
688
+ return;
689
+ }
690
+ read(key, void 0, "first");
691
+ }, [key, read]);
692
+ useEffect(
693
+ () => () => {
694
+ inFlight.current?.abort();
695
+ inFlight.current = null;
696
+ },
697
+ []
698
+ );
699
+ const loadMore = useCallback(() => {
700
+ if (state.status !== "ready" || state.cursor === null || state.more === "loading") return;
701
+ setState((previous) => ({ ...previous, more: "loading" }));
702
+ read(state.key, state.cursor, "more");
703
+ }, [state.key, state.status, state.cursor, state.more, read]);
704
+ const retry = useCallback(() => {
705
+ if (state.status === "failed") {
706
+ setState((previous) => startFor(previous.key));
707
+ read(state.key, void 0, "first");
708
+ } else if (state.more === "failed") {
709
+ loadMore();
710
+ }
711
+ }, [state.key, state.status, state.more, read, loadMore]);
712
+ const updateItems = useCallback((update) => {
713
+ setState((previous) => ({ ...previous, items: update(previous.items) }));
714
+ }, []);
715
+ const drained = state.status === "ready" && state.items.length === 0 && state.cursor !== null && state.more === "idle";
716
+ useEffect(() => {
717
+ if (drained) loadMore();
718
+ }, [drained, loadMore]);
719
+ return {
720
+ status: state.status,
721
+ items: state.items,
722
+ hasMore: state.cursor !== null,
723
+ empty: state.status === "ready" && state.items.length === 0 && state.cursor === null,
724
+ more: state.more,
725
+ loadMore,
726
+ retry,
727
+ updateItems
728
+ };
729
+ }
730
+ function DimRows({ count = 4 }) {
731
+ return /* @__PURE__ */ jsx("div", { "aria-hidden": "true", "data-dim-rows": true, className: "divide-y divide-border", children: Array.from({ length: count }, (_, index) => /* @__PURE__ */ jsxs("div", { className: "flex min-h-16 items-center gap-3 px-4 py-3 opacity-60", children: [
732
+ /* @__PURE__ */ jsx("span", { className: "size-8 shrink-0 rounded-md bg-muted" }),
733
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-2", children: [
734
+ /* @__PURE__ */ jsx("span", { className: "h-3.5 w-2/5 rounded-sm bg-muted" }),
735
+ /* @__PURE__ */ jsx("span", { className: "h-3 w-3/5 rounded-sm bg-muted" })
736
+ ] })
737
+ ] }, index)) });
738
+ }
739
+ function ListAction({
740
+ onClick,
741
+ children,
742
+ className
743
+ }) {
744
+ return /* @__PURE__ */ jsx(
745
+ "button",
746
+ {
747
+ type: "button",
748
+ onClick,
749
+ className: cn(
750
+ "inline-flex min-h-11 items-center justify-center rounded-md border border-border px-4 text-[14px] text-foreground transition-colors hover:bg-muted sm:min-h-9",
751
+ className
752
+ ),
753
+ children
754
+ }
755
+ );
756
+ }
757
+ function ListMessage({ text, children }) {
758
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3 px-4 py-10 text-center", children: [
759
+ /* @__PURE__ */ jsx("p", { className: "text-[14px] text-foreground", children: text }),
760
+ children && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap justify-center gap-2", children })
761
+ ] });
762
+ }
763
+ function MoreFooter({ pages }) {
764
+ const s = useFieldStrings();
765
+ if (pages.more === "failed") {
766
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 px-4 py-4", children: [
767
+ /* @__PURE__ */ jsx("p", { className: "text-[13px] text-muted-foreground", children: s.loadMoreFailed }),
768
+ /* @__PURE__ */ jsx(ListAction, { onClick: pages.retry, children: s.tryAgain })
769
+ ] });
770
+ }
771
+ if (pages.more === "loading") {
772
+ return /* @__PURE__ */ jsxs("p", { className: "flex items-center justify-center gap-2 px-4 py-4 text-[13px] text-muted-foreground", children: [
773
+ /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": "true" }),
774
+ s.loadingMore
775
+ ] });
776
+ }
777
+ if (!pages.hasMore) return null;
778
+ return /* @__PURE__ */ jsx("div", { className: "flex justify-center px-4 py-4", children: /* @__PURE__ */ jsx(ListAction, { onClick: pages.loadMore, children: s.showMore }) });
779
+ }
780
+ var Dialog = DialogPrimitive.Root;
781
+ var DialogClose = DialogPrimitive.Close;
782
+ function closeAutoFocus(onCloseAutoFocus, returnFocus) {
783
+ return (event) => {
784
+ onCloseAutoFocus?.(event);
785
+ if (event.defaultPrevented || !returnFocus) return;
786
+ const target = returnFocus();
787
+ if (!target?.isConnected) return;
788
+ event.preventDefault();
789
+ target.focus();
790
+ };
791
+ }
792
+ var DialogOverlay = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
793
+ DialogPrimitive.Overlay,
794
+ {
795
+ ref,
796
+ className: cn("fixed inset-0 z-50 bg-black/50", className),
797
+ ...props
798
+ }
799
+ ));
800
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
801
+ var DialogContent = React5.forwardRef(({ className, layout = "dialog", returnFocus, onCloseAutoFocus, children, ...props }, ref) => /* @__PURE__ */ jsxs(Fragment, { children: [
802
+ /* @__PURE__ */ jsx(DialogOverlay, {}),
803
+ /* @__PURE__ */ jsx(
804
+ DialogPrimitive.Content,
805
+ {
806
+ ref,
807
+ className: cn(
808
+ "fixed z-50 flex flex-col border-border bg-popover text-popover-foreground shadow-lg outline-hidden",
809
+ layout === "sheet" ? [
810
+ "inset-x-0 top-6 bottom-0 rounded-t-xl border-t",
811
+ "xl:inset-0 xl:m-auto xl:h-fit xl:max-h-[min(720px,calc(100dvh-4rem))] xl:w-[calc(100%-2rem)] xl:max-w-[560px] xl:rounded-xl xl:border"
812
+ ] : "inset-0 m-auto h-fit w-[calc(100%-2rem)] max-w-sm gap-3 rounded-lg border p-4",
813
+ className
814
+ ),
815
+ onCloseAutoFocus: closeAutoFocus(onCloseAutoFocus, returnFocus),
816
+ ...props,
817
+ children
818
+ }
819
+ )
820
+ ] }));
821
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
822
+ var DialogTitle = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
823
+ DialogPrimitive.Title,
824
+ {
825
+ ref,
826
+ className: cn("text-[16px] font-semibold text-foreground", className),
827
+ ...props
828
+ }
829
+ ));
830
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
831
+ var DialogDescription = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
832
+ DialogPrimitive.Description,
833
+ {
834
+ ref,
835
+ className: cn("text-[13px] text-muted-foreground", className),
836
+ ...props
837
+ }
838
+ ));
839
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
840
+ var toggleVariants = cva(
841
+ "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 gap-2",
842
+ {
843
+ variants: {
844
+ variant: {
845
+ default: "bg-transparent",
846
+ outline: "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground"
847
+ },
848
+ size: {
849
+ default: "h-10 px-3 min-w-10",
850
+ sm: "h-9 px-2.5 min-w-9",
851
+ lg: "h-11 px-5 min-w-11"
852
+ }
853
+ },
854
+ defaultVariants: {
855
+ variant: "default",
856
+ size: "default"
857
+ }
858
+ }
859
+ );
860
+ var Toggle = React5.forwardRef(({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsx(
861
+ TogglePrimitive.Root,
862
+ {
863
+ ref,
864
+ className: cn(toggleVariants({ variant, size, className })),
865
+ ...props
866
+ }
867
+ ));
868
+ Toggle.displayName = TogglePrimitive.Root.displayName;
869
+ var ToggleGroupContext = React5.createContext({
870
+ size: "default",
871
+ variant: "default"
872
+ });
873
+ var ToggleGroup = React5.forwardRef(({ className, variant, size, children, ...props }, ref) => /* @__PURE__ */ jsx(
874
+ ToggleGroupPrimitive.Root,
875
+ {
876
+ ref,
877
+ className: cn("flex items-center justify-center gap-1", className),
878
+ ...props,
879
+ children: /* @__PURE__ */ jsx(ToggleGroupContext.Provider, { value: { variant, size }, children })
880
+ }
881
+ ));
882
+ ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
883
+ var ToggleGroupItem = React5.forwardRef(({ className, children, variant, size, ...props }, ref) => {
884
+ const context = React5.useContext(ToggleGroupContext);
885
+ return /* @__PURE__ */ jsx(
886
+ ToggleGroupPrimitive.Item,
887
+ {
888
+ ref,
889
+ className: cn(
890
+ toggleVariants({
891
+ variant: context.variant || variant,
892
+ size: context.size || size
893
+ }),
894
+ className
895
+ ),
896
+ ...props,
897
+ children
898
+ }
899
+ );
900
+ });
901
+ ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
902
+ var SEARCH_PAUSE_MS = 250;
903
+ var SWIPE_CLOSE_PX = 96;
904
+ function FilePickerEntry({ onOpen, label, disabled, ref, id }) {
905
+ const s = useFieldStrings();
906
+ return /* @__PURE__ */ jsxs(
907
+ "button",
908
+ {
909
+ ref,
910
+ id,
911
+ type: "button",
912
+ onClick: onOpen,
913
+ disabled,
914
+ "aria-haspopup": "dialog",
915
+ "aria-label": s.chooseFromSourceAria(label),
916
+ className: "flex min-h-11 w-full items-center justify-center gap-2 rounded-md border border-border px-3 text-[14px] text-foreground transition-colors hover:bg-muted disabled:cursor-not-allowed disabled:opacity-50 sm:min-h-9",
917
+ children: [
918
+ /* @__PURE__ */ jsx(Folder, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": "true" }),
919
+ s.chooseFromSource
920
+ ]
921
+ }
922
+ );
923
+ }
924
+ function FilePicker({
925
+ open,
926
+ onOpenChange,
927
+ returnFocusTo,
928
+ onCloseAutoFocus,
929
+ disabled = false,
930
+ ...props
931
+ }) {
932
+ const [drag, setDrag] = useState(0);
933
+ const shown = open && !disabled;
934
+ useEffect(() => {
935
+ if (open && disabled) onOpenChange(false);
936
+ }, [open, disabled, onOpenChange]);
937
+ const heldFocus = useRef(null);
938
+ useLayoutEffect(() => {
939
+ if (!open) return;
940
+ const active = document.activeElement;
941
+ heldFocus.current = active instanceof HTMLElement && active !== document.body ? active : null;
942
+ }, [open]);
943
+ return /* @__PURE__ */ jsx(Dialog, { open: shown, onOpenChange, children: shown && /* @__PURE__ */ jsx(
944
+ DialogContent,
945
+ {
946
+ layout: "sheet",
947
+ onCloseAutoFocus,
948
+ returnFocus: () => returnFocusTo?.current ?? heldFocus.current,
949
+ style: drag > 0 ? { transform: `translateY(${drag}px)` } : void 0,
950
+ onClick: (event) => event.stopPropagation(),
951
+ children: /* @__PURE__ */ jsx(FilePickerBody, { ...props, onDrag: setDrag, onClose: () => onOpenChange(false) })
952
+ }
953
+ ) });
954
+ }
955
+ function FilePickerBody({
956
+ source,
957
+ formats,
958
+ multiple = false,
959
+ maxChoices,
960
+ held,
961
+ onUse,
962
+ onUpload,
963
+ onDrag,
964
+ onClose
965
+ }) {
966
+ const s = useFieldStrings();
967
+ const searchId = useId();
968
+ const [search, setSearch] = useState("");
969
+ const [query, setQuery] = useState("");
970
+ const [scope, setScope] = useState(source.initialScope);
971
+ const [chosen, setChosen] = useState(/* @__PURE__ */ new Map());
972
+ useEffect(() => {
973
+ const next = search.trim();
974
+ if (next === query) return;
975
+ const timer = setTimeout(() => setQuery(next), SEARCH_PAUSE_MS);
976
+ return () => clearTimeout(timer);
977
+ }, [search, query]);
978
+ const mediaTypes = useMemo(() => formats.map((format) => format.mimeType), [formats]);
979
+ const labels = useMemo(() => formats.map((format) => format.label), [formats]);
980
+ const load = (cursor, signal) => source.list({ search: query, scope, mediaTypes, cursor, signal }).then((page) => ({ items: page.files, nextCursor: page.nextCursor }));
981
+ const pages = useSourcePages(load, JSON.stringify([query, scope, mediaTypes]));
982
+ const fits = (files) => maxChoices === void 0 || chosenFilesAdded(held, files) <= maxChoices;
983
+ const toggle = (file) => setChosen((previous) => {
984
+ if (!multiple) return previous.has(file.id) ? previous : /* @__PURE__ */ new Map([[file.id, file]]);
985
+ const next = new Map(previous);
986
+ if (next.has(file.id)) next.delete(file.id);
987
+ else if (fits([...next.values(), file])) next.set(file.id, file);
988
+ return next;
989
+ });
990
+ const choices = [...chosen.values()];
991
+ const use6 = () => {
992
+ if (choices.length === 0) return;
993
+ onUse(choices);
994
+ onClose();
995
+ };
996
+ const clearSearch = () => {
997
+ setSearch("");
998
+ setQuery("");
999
+ };
1000
+ const status = pickerStatus(s, pages, query, scope, labels);
1001
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1002
+ /* @__PURE__ */ jsxs(SheetHeader, { onDrag, onClose, children: [
1003
+ /* @__PURE__ */ jsx(DialogTitle, { className: "text-[20px]", children: s.filePickerTitle }),
1004
+ /* @__PURE__ */ jsx(DialogDescription, { children: s.filePickerTakes(labels) })
1005
+ ] }),
1006
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 px-4 pb-3", children: [
1007
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1008
+ /* @__PURE__ */ jsx("label", { htmlFor: searchId, className: "sr-only", children: s.filePickerSearch }),
1009
+ /* @__PURE__ */ jsx(
1010
+ Search,
1011
+ {
1012
+ className: "pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground",
1013
+ "aria-hidden": "true"
1014
+ }
1015
+ ),
1016
+ /* @__PURE__ */ jsx(
1017
+ "input",
1018
+ {
1019
+ id: searchId,
1020
+ type: "search",
1021
+ value: search,
1022
+ onChange: (event) => setSearch(event.target.value),
1023
+ onKeyDown: (event) => {
1024
+ if (event.key === "Enter") event.preventDefault();
1025
+ },
1026
+ placeholder: s.filePickerSearchPlaceholder,
1027
+ autoComplete: "off",
1028
+ className: "h-11 w-full rounded-md border border-border bg-input pr-3 pl-9 text-[16px] text-foreground placeholder:text-muted-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-ring"
1029
+ }
1030
+ )
1031
+ ] }),
1032
+ /* @__PURE__ */ jsxs(
1033
+ ToggleGroup,
1034
+ {
1035
+ type: "single",
1036
+ value: scope,
1037
+ onValueChange: (value) => {
1038
+ if (value === "mine" || value === "everyone") setScope(value);
1039
+ },
1040
+ "aria-label": s.filePickerScope,
1041
+ className: "grid grid-cols-2 gap-1 rounded-md border border-border p-1",
1042
+ children: [
1043
+ /* @__PURE__ */ jsx(ToggleGroupItem, { value: "mine", className: "h-11 w-full text-[15px]", children: s.filePickerMine }),
1044
+ /* @__PURE__ */ jsx(ToggleGroupItem, { value: "everyone", className: "h-11 w-full text-[15px]", children: s.filePickerEveryone })
1045
+ ]
1046
+ }
1047
+ )
1048
+ ] }),
1049
+ /* @__PURE__ */ jsx("p", { role: "status", className: "sr-only", children: status }),
1050
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto border-t border-border", children: pages.status === "idle" || pages.status === "loading" ? /* @__PURE__ */ jsx(DimRows, {}) : pages.status === "failed" ? /* @__PURE__ */ jsx(ListMessage, { text: s.filePickerFailed, children: /* @__PURE__ */ jsx(ListAction, { onClick: pages.retry, children: s.tryAgain }) }) : pages.empty ? query !== "" ? /* @__PURE__ */ jsx(ListMessage, { text: s.filePickerNoMatch, children: /* @__PURE__ */ jsx(ListAction, { onClick: clearSearch, children: s.filePickerClearSearch }) }) : /* @__PURE__ */ jsxs(ListMessage, { text: status, children: [
1051
+ scope === "mine" && /* @__PURE__ */ jsx(ListAction, { onClick: () => setScope("everyone"), children: s.filePickerShowEveryone }),
1052
+ onUpload && /* @__PURE__ */ jsx(
1053
+ ListAction,
1054
+ {
1055
+ onClick: () => {
1056
+ onClose();
1057
+ onUpload();
1058
+ },
1059
+ children: s.filePickerUpload
1060
+ }
1061
+ )
1062
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1063
+ pages.items.length > 0 && /* @__PURE__ */ jsx(
1064
+ "div",
1065
+ {
1066
+ role: multiple ? "group" : "radiogroup",
1067
+ "aria-label": s.filePickerTitle,
1068
+ className: "divide-y divide-border",
1069
+ children: pages.items.map((file) => {
1070
+ const isChosen = chosen.has(file.id);
1071
+ return /* @__PURE__ */ jsx(
1072
+ FileRow,
1073
+ {
1074
+ file,
1075
+ formats,
1076
+ role: multiple ? "checkbox" : "radio",
1077
+ chosen: isChosen,
1078
+ disabled: !isChosen && !fits([...choices, file]),
1079
+ onToggle: () => toggle(file)
1080
+ },
1081
+ file.id
1082
+ );
1083
+ })
1084
+ }
1085
+ ),
1086
+ /* @__PURE__ */ jsx(MoreFooter, { pages })
1087
+ ] }) }),
1088
+ /* @__PURE__ */ jsx("div", { className: "border-t border-border px-4 pt-3 pb-[max(0.75rem,env(safe-area-inset-bottom))]", children: /* @__PURE__ */ jsx(
1089
+ "button",
1090
+ {
1091
+ type: "button",
1092
+ onClick: use6,
1093
+ disabled: choices.length === 0,
1094
+ className: "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",
1095
+ children: /* @__PURE__ */ jsx("span", { className: "truncate", children: s.filePickerUse(choices.length, choices[0]?.name) })
1096
+ }
1097
+ ) })
1098
+ ] });
1099
+ }
1100
+ function pickerStatus(s, pages, query, scope, labels) {
1101
+ if (pages.status === "idle" || pages.status === "loading") return s.filePickerLoading;
1102
+ if (pages.status === "failed") return s.filePickerFailed;
1103
+ if (pages.more === "failed") return s.loadMoreFailed;
1104
+ if (pages.items.length > 0) return s.filePickerShown(pages.items.length);
1105
+ if (!pages.empty) return s.filePickerLoading;
1106
+ if (query !== "") return s.filePickerNoMatch;
1107
+ return scope === "mine" ? s.filePickerNoneMine(labels) : s.filePickerNoneTeam(labels);
1108
+ }
1109
+ function SheetHeader({
1110
+ onDrag,
1111
+ onClose,
1112
+ children
1113
+ }) {
1114
+ const s = useFieldStrings();
1115
+ const start = useRef(null);
1116
+ const offset = useRef(0);
1117
+ const onPointerDown = (event) => {
1118
+ if (event.pointerType === "mouse") return;
1119
+ if (window.matchMedia?.("(min-width: 80rem)").matches) return;
1120
+ start.current = event.clientY;
1121
+ offset.current = 0;
1122
+ };
1123
+ const onPointerMove = (event) => {
1124
+ if (start.current === null) return;
1125
+ offset.current = Math.max(0, event.clientY - start.current);
1126
+ onDrag(offset.current);
1127
+ };
1128
+ const onPointerEnd = () => {
1129
+ if (start.current === null) return;
1130
+ const closes = offset.current > SWIPE_CLOSE_PX;
1131
+ start.current = null;
1132
+ offset.current = 0;
1133
+ onDrag(0);
1134
+ if (closes) onClose();
1135
+ };
1136
+ return /* @__PURE__ */ jsxs(
1137
+ "div",
1138
+ {
1139
+ className: "touch-none px-4 pt-2 pb-3 select-none",
1140
+ onPointerDown,
1141
+ onPointerMove,
1142
+ onPointerUp: onPointerEnd,
1143
+ onPointerCancel: onPointerEnd,
1144
+ children: [
1145
+ /* @__PURE__ */ jsx(
1146
+ "span",
1147
+ {
1148
+ "aria-hidden": "true",
1149
+ className: "mx-auto mb-2 block h-1.5 w-12 rounded-full bg-muted-foreground/40 xl:hidden"
1150
+ }
1151
+ ),
1152
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
1153
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 space-y-1 pt-1", children }),
1154
+ /* @__PURE__ */ jsx(
1155
+ DialogClose,
1156
+ {
1157
+ "aria-label": s.close,
1158
+ className: "flex size-11 shrink-0 items-center justify-center rounded-full border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
1159
+ children: /* @__PURE__ */ jsx(X, { className: "size-5", "aria-hidden": "true" })
1160
+ }
1161
+ )
1162
+ ] })
1163
+ ]
1164
+ }
1165
+ );
1166
+ }
1167
+ function rowFormat(file, formats) {
1168
+ const type = file.mediaType ? normalizeMimeType(file.mediaType) : "";
1169
+ return formats.find((format) => format.mimeType === type) ?? formatOfFilename(formats, file.name);
1170
+ }
1171
+ function rowMeta(s, file, format) {
1172
+ const parts = [];
1173
+ if (format) parts.push(format.label);
1174
+ if (file.size !== void 0) parts.push(s.fileSize(file.size));
1175
+ if (file.origin) parts.push(file.origin);
1176
+ if (file.createdAt) {
1177
+ const date = new Date(file.createdAt);
1178
+ if (!Number.isNaN(date.getTime())) parts.push(s.fileDate(date));
1179
+ }
1180
+ return parts.join(" \xB7 ");
1181
+ }
1182
+ function FileRow({
1183
+ file,
1184
+ formats,
1185
+ role,
1186
+ chosen,
1187
+ disabled,
1188
+ onToggle
1189
+ }) {
1190
+ const s = useFieldStrings();
1191
+ const format = rowFormat(file, formats);
1192
+ const isImage = format?.mimeType.startsWith("image/") ?? false;
1193
+ const meta = rowMeta(s, file, format);
1194
+ const Glyph = isImage ? ImageIcon : FileText;
1195
+ return /* @__PURE__ */ jsxs(
1196
+ "button",
1197
+ {
1198
+ type: "button",
1199
+ role,
1200
+ "aria-checked": chosen,
1201
+ disabled,
1202
+ onClick: onToggle,
1203
+ className: cn(
1204
+ "flex min-h-16 w-full items-center gap-3 px-4 py-2.5 text-left transition-colors hover:bg-muted/60 disabled:cursor-not-allowed disabled:opacity-50",
1205
+ "focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring",
1206
+ chosen && "bg-muted"
1207
+ ),
1208
+ children: [
1209
+ /* @__PURE__ */ jsx(
1210
+ Glyph,
1211
+ {
1212
+ className: "size-6 shrink-0 text-muted-foreground",
1213
+ strokeWidth: 1.5,
1214
+ "aria-hidden": "true"
1215
+ }
1216
+ ),
1217
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
1218
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-[16px] font-medium text-foreground", children: file.name }),
1219
+ (file.kind === "test" || meta) && /* @__PURE__ */ jsxs("span", { className: "block truncate text-[13px] text-muted-foreground", children: [
1220
+ file.kind === "test" && /* @__PURE__ */ jsxs("span", { className: "text-foreground", children: [
1221
+ s.testFile,
1222
+ meta && " \xB7 "
1223
+ ] }),
1224
+ meta
1225
+ ] })
1226
+ ] }),
1227
+ /* @__PURE__ */ jsx(
1228
+ Check,
1229
+ {
1230
+ className: cn("size-5 shrink-0 text-foreground", !chosen && "invisible"),
1231
+ "aria-hidden": "true"
1232
+ }
1233
+ )
1234
+ ]
1235
+ }
1236
+ );
1237
+ }
460
1238
  var IMAGE_EXT_RE = /\.(jpg|jpeg|png|gif|webp|bmp|svg|avif)(\?|$)/i;
461
1239
  var PDF_EXT_RE = /\.pdf(\?|$)/i;
462
1240
  var DATA_URL_MIME_RE = /^data:([^;,]+)/i;
@@ -484,6 +1262,7 @@ function FileField({
484
1262
  uploading,
485
1263
  uploadError,
486
1264
  resolveUrl,
1265
+ fileSource,
487
1266
  error,
488
1267
  disabled,
489
1268
  category
@@ -497,6 +1276,9 @@ function FileField({
497
1276
  const [localPreview, setLocalPreview] = useState(null);
498
1277
  const [resolved, setResolved] = useState(null);
499
1278
  const localUrlRef = useRef(null);
1279
+ const [pickerOpen, setPickerOpen] = useState(false);
1280
+ const cardRef = useRef(null);
1281
+ const pickerEntryRef = useRef(null);
500
1282
  const setLocal = useCallback((next) => {
501
1283
  if (localUrlRef.current) URL.revokeObjectURL(localUrlRef.current);
502
1284
  localUrlRef.current = next?.objectUrl ?? null;
@@ -532,7 +1314,12 @@ function FileField({
532
1314
  [formats, setLocal, onDropFile]
533
1315
  );
534
1316
  const busy = disabled || uploading;
535
- const { getRootProps, getInputProps, isDragActive } = useDropzone({
1317
+ const {
1318
+ getRootProps,
1319
+ getInputProps,
1320
+ isDragActive,
1321
+ open: openFileDialog
1322
+ } = useDropzone({
536
1323
  maxFiles: 1,
537
1324
  multiple: false,
538
1325
  // Disabled, not merely unrendered, when there is no upload path: the hook
@@ -570,7 +1357,30 @@ function FileField({
570
1357
  dismissUploadError();
571
1358
  onChange(void 0);
572
1359
  }, [setLocal, onChange, dismissUploadError]);
1360
+ const chooseFromSource = useCallback(
1361
+ (file) => {
1362
+ setLocal(null);
1363
+ setResolved(null);
1364
+ setRejected(null);
1365
+ dismissUploadError();
1366
+ onChange(sourceFileValue(file));
1367
+ },
1368
+ [setLocal, onChange, dismissUploadError]
1369
+ );
573
1370
  const localIsCurrent = !!localPreview && (localPreview.boundUrl === void 0 || localPreview.boundUrl === value?.url);
1371
+ const wasUploading = useRef(!!uploading);
1372
+ useEffect(() => {
1373
+ const ended = wasUploading.current && !uploading;
1374
+ wasUploading.current = !!uploading;
1375
+ if (!localPreview || localPreview.boundUrl !== void 0) return;
1376
+ if (failure !== null || ended && !value?.url) setLocal(null);
1377
+ }, [uploading, failure, localPreview, value?.url, setLocal]);
1378
+ const lastUrl = useRef(value?.url);
1379
+ useEffect(() => {
1380
+ if (lastUrl.current === value?.url) return;
1381
+ lastUrl.current = value?.url;
1382
+ if (uploadError !== void 0) setDismissedUploadError(uploadError);
1383
+ }, [value?.url, uploadError]);
574
1384
  useEffect(() => {
575
1385
  if (!localPreview) return;
576
1386
  if (localPreview.boundUrl === void 0) {
@@ -611,13 +1421,15 @@ function FileField({
611
1421
  };
612
1422
  const urlValue = value?.url ?? "";
613
1423
  const urlText = presentation === "studio" || isReadableLink(urlValue) || urlValue === typedUrl ? urlValue : "";
614
- if (!canUpload && !allowUrl) {
1424
+ const canChoose = fileSource !== void 0;
1425
+ if (!canUpload && !allowUrl && !canChoose) {
615
1426
  throw new Error(
616
- `The file field at "${id}" has no way in: the form's environment supplies no onDropFile and sets allowUrl to false. Supply onDropFile so the file can be uploaded, or leave allowUrl unset so a link can be pasted.`
1427
+ `The file field at "${id}" has no way in: the form's environment supplies no onDropFile and no fileSource, and sets allowUrl to false. Supply onDropFile so the file can be uploaded, leave allowUrl unset so a link can be pasted, or supply a fileSource so a stored file can be chosen.`
617
1428
  );
618
1429
  }
619
1430
  const linkOpen = allowUrl && (!canUpload || showUrl);
620
- const noUploadLineShown = !canUpload && !hasFile && !uploading;
1431
+ const noUploadLineShown = !canUpload && allowUrl && !hasFile && !uploading;
1432
+ const choosingOnly = !canUpload && !allowUrl;
621
1433
  const noUploadLineId = `${domId}-no-upload`;
622
1434
  return /* @__PURE__ */ jsxs(
623
1435
  FieldShell,
@@ -631,7 +1443,7 @@ function FileField({
631
1443
  error,
632
1444
  htmlFor: domId,
633
1445
  children: [
634
- hasFile && !uploading ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1446
+ hasFile && !uploading ? /* @__PURE__ */ jsxs("div", { ref: cardRef, tabIndex: -1, className: "space-y-2 outline-none", children: [
635
1447
  /* @__PURE__ */ jsx(
636
1448
  FileChip,
637
1449
  {
@@ -661,7 +1473,7 @@ function FileField({
661
1473
  /* @__PURE__ */ jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }),
662
1474
  s.uploading
663
1475
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
664
- /* @__PURE__ */ jsx("p", { id: noUploadLineId, className: "text-[12px] text-muted-foreground", children: s.uploadUnavailable }),
1476
+ noUploadLineShown && /* @__PURE__ */ jsx("p", { id: noUploadLineId, className: "text-[12px] text-muted-foreground", children: s.uploadUnavailable }),
665
1477
  hint && /* @__PURE__ */ jsx("p", { className: "font-mono text-[10.5px] text-muted-foreground", children: hint })
666
1478
  ] }) })
667
1479
  ) : (
@@ -736,12 +1548,43 @@ function FileField({
736
1548
  {
737
1549
  type: "button",
738
1550
  disabled: busy,
739
- onClick: () => setShowUrl(true),
740
- className: "flex w-fit items-center gap-1 font-mono text-[11px] text-muted-foreground transition-colors hover:text-foreground disabled:opacity-50 max-sm:min-h-11",
741
- children: [
742
- /* @__PURE__ */ jsx(Link2, { className: "h-3 w-3" }),
743
- s.pasteUrlInstead
744
- ]
1551
+ onClick: () => setShowUrl(true),
1552
+ className: "flex w-fit items-center gap-1 font-mono text-[11px] text-muted-foreground transition-colors hover:text-foreground disabled:opacity-50 max-sm:min-h-11",
1553
+ children: [
1554
+ /* @__PURE__ */ jsx(Link2, { className: "h-3 w-3" }),
1555
+ s.pasteUrlInstead
1556
+ ]
1557
+ }
1558
+ ),
1559
+ fileSource && !hasFile && /* @__PURE__ */ jsx(
1560
+ FilePickerEntry,
1561
+ {
1562
+ ref: pickerEntryRef,
1563
+ id: choosingOnly ? domId : void 0,
1564
+ label: fieldLabel(field.title, field.name, presentation),
1565
+ disabled: busy,
1566
+ onOpen: () => setPickerOpen(true)
1567
+ }
1568
+ ),
1569
+ fileSource && /* @__PURE__ */ jsx(
1570
+ FilePicker,
1571
+ {
1572
+ source: fileSource,
1573
+ formats,
1574
+ open: pickerOpen,
1575
+ onOpenChange: setPickerOpen,
1576
+ onUse: (files) => {
1577
+ const file = files[0];
1578
+ if (file) chooseFromSource(file);
1579
+ },
1580
+ onUpload: canUpload ? openFileDialog : void 0,
1581
+ disabled: busy,
1582
+ returnFocusTo: pickerEntryRef,
1583
+ onCloseAutoFocus: (event) => {
1584
+ if (!cardRef.current) return;
1585
+ event.preventDefault();
1586
+ cardRef.current.focus();
1587
+ }
745
1588
  }
746
1589
  )
747
1590
  ]
@@ -843,7 +1686,7 @@ function ClearButton({ disabled, onClick }) {
843
1686
  }
844
1687
  var Select = SelectPrimitive.Root;
845
1688
  var SelectValue = SelectPrimitive.Value;
846
- var SelectTrigger = React2.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1689
+ var SelectTrigger = React5.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
847
1690
  SelectPrimitive.Trigger,
848
1691
  {
849
1692
  ref,
@@ -862,7 +1705,7 @@ var SelectTrigger = React2.forwardRef(({ className, children, ...props }, ref) =
862
1705
  }
863
1706
  ));
864
1707
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
865
- var SelectScrollUpButton = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1708
+ var SelectScrollUpButton = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
866
1709
  SelectPrimitive.ScrollUpButton,
867
1710
  {
868
1711
  ref,
@@ -872,7 +1715,7 @@ var SelectScrollUpButton = React2.forwardRef(({ className, ...props }, ref) => /
872
1715
  }
873
1716
  ));
874
1717
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
875
- var SelectScrollDownButton = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1718
+ var SelectScrollDownButton = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
876
1719
  SelectPrimitive.ScrollDownButton,
877
1720
  {
878
1721
  ref,
@@ -882,7 +1725,7 @@ var SelectScrollDownButton = React2.forwardRef(({ className, ...props }, ref) =>
882
1725
  }
883
1726
  ));
884
1727
  SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
885
- var SelectContent = React2.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
1728
+ var SelectContent = React5.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
886
1729
  SelectPrimitive.Content,
887
1730
  {
888
1731
  ref,
@@ -910,7 +1753,7 @@ var SelectContent = React2.forwardRef(({ className, children, position = "popper
910
1753
  }
911
1754
  ) }));
912
1755
  SelectContent.displayName = SelectPrimitive.Content.displayName;
913
- var SelectLabel = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1756
+ var SelectLabel = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
914
1757
  SelectPrimitive.Label,
915
1758
  {
916
1759
  ref,
@@ -919,7 +1762,7 @@ var SelectLabel = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE
919
1762
  }
920
1763
  ));
921
1764
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
922
- var SelectItem = React2.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
1765
+ var SelectItem = React5.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
923
1766
  SelectPrimitive.Item,
924
1767
  {
925
1768
  ref,
@@ -935,7 +1778,7 @@ var SelectItem = React2.forwardRef(({ className, children, ...props }, ref) => /
935
1778
  }
936
1779
  ));
937
1780
  SelectItem.displayName = SelectPrimitive.Item.displayName;
938
- var SelectSeparator = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1781
+ var SelectSeparator = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
939
1782
  SelectPrimitive.Separator,
940
1783
  {
941
1784
  ref,
@@ -944,68 +1787,6 @@ var SelectSeparator = React2.forwardRef(({ className, ...props }, ref) => /* @__
944
1787
  }
945
1788
  ));
946
1789
  SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
947
- var toggleVariants = cva(
948
- "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 gap-2",
949
- {
950
- variants: {
951
- variant: {
952
- default: "bg-transparent",
953
- outline: "border border-input bg-transparent hover:bg-accent hover:text-accent-foreground"
954
- },
955
- size: {
956
- default: "h-10 px-3 min-w-10",
957
- sm: "h-9 px-2.5 min-w-9",
958
- lg: "h-11 px-5 min-w-11"
959
- }
960
- },
961
- defaultVariants: {
962
- variant: "default",
963
- size: "default"
964
- }
965
- }
966
- );
967
- var Toggle = React2.forwardRef(({ className, variant, size, ...props }, ref) => /* @__PURE__ */ jsx(
968
- TogglePrimitive.Root,
969
- {
970
- ref,
971
- className: cn(toggleVariants({ variant, size, className })),
972
- ...props
973
- }
974
- ));
975
- Toggle.displayName = TogglePrimitive.Root.displayName;
976
- var ToggleGroupContext = React2.createContext({
977
- size: "default",
978
- variant: "default"
979
- });
980
- var ToggleGroup = React2.forwardRef(({ className, variant, size, children, ...props }, ref) => /* @__PURE__ */ jsx(
981
- ToggleGroupPrimitive.Root,
982
- {
983
- ref,
984
- className: cn("flex items-center justify-center gap-1", className),
985
- ...props,
986
- children: /* @__PURE__ */ jsx(ToggleGroupContext.Provider, { value: { variant, size }, children })
987
- }
988
- ));
989
- ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
990
- var ToggleGroupItem = React2.forwardRef(({ className, children, variant, size, ...props }, ref) => {
991
- const context = React2.useContext(ToggleGroupContext);
992
- return /* @__PURE__ */ jsx(
993
- ToggleGroupPrimitive.Item,
994
- {
995
- ref,
996
- className: cn(
997
- toggleVariants({
998
- variant: context.variant || variant,
999
- size: context.size || size
1000
- }),
1001
- className
1002
- ),
1003
- ...props,
1004
- children
1005
- }
1006
- );
1007
- });
1008
- ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
1009
1790
  var CLEAR_VALUE = "__none__";
1010
1791
  function EnumField({ field, value, onChange, id, error, disabled }) {
1011
1792
  const s = useFieldStrings();
@@ -1042,9 +1823,19 @@ function EnumField({ field, value, onChange, id, error, disabled }) {
1042
1823
  {
1043
1824
  value: option,
1044
1825
  variant: "outline",
1045
- className: "h-9 min-w-0 gap-1.5 border-border bg-input px-3 text-[13px] text-muted-foreground hover:bg-muted hover:text-foreground data-[state=on]:border-primary/40 data-[state=on]:bg-primary/10 data-[state=on]:font-medium data-[state=on]:text-foreground",
1826
+ className: cn(
1827
+ "h-9 min-w-0 gap-1.5 border-border bg-input px-3 text-[13px] text-muted-foreground hover:bg-muted hover:text-foreground data-[state=on]:border-primary/40 data-[state=on]:font-medium data-[state=on]:text-foreground",
1828
+ brandFillSelectedClass
1829
+ ),
1046
1830
  children: [
1047
- value === option && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary", strokeWidth: 2.5, "aria-hidden": "true" }),
1831
+ value === option && /* @__PURE__ */ jsx(
1832
+ Check,
1833
+ {
1834
+ className: cn("size-3.5", brandFillInkClass),
1835
+ strokeWidth: 2.5,
1836
+ "aria-hidden": "true"
1837
+ }
1838
+ ),
1048
1839
  labelOf(option)
1049
1840
  ]
1050
1841
  },
@@ -1288,12 +2079,39 @@ function ObjectField({ field, value, onChange, id, error, env }) {
1288
2079
  error && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-destructive", role: "alert", children: error })
1289
2080
  ] });
1290
2081
  }
2082
+
2083
+ // src/react/focus.ts
2084
+ var FOCUSABLE = "a[href], button, input, select, textarea, [tabindex]";
2085
+ function takesFocus(element) {
2086
+ if (element.tabIndex < 0 || element.matches(":disabled")) return false;
2087
+ return element.closest("[hidden], [inert]") === null;
2088
+ }
2089
+ function followingFocusable(from, skip) {
2090
+ if (!from) return null;
2091
+ for (const element of from.ownerDocument.querySelectorAll(FOCUSABLE)) {
2092
+ if (!(from.compareDocumentPosition(element) & Node.DOCUMENT_POSITION_FOLLOWING)) continue;
2093
+ if (skip?.contains(element)) continue;
2094
+ if (takesFocus(element)) return element;
2095
+ }
2096
+ return null;
2097
+ }
2098
+ function firstFocusable(within) {
2099
+ if (!within) return null;
2100
+ for (const element of within.querySelectorAll(FOCUSABLE)) {
2101
+ if (takesFocus(element)) return element;
2102
+ }
2103
+ return null;
2104
+ }
1291
2105
  function ListField({ field, value, onChange, id, error, env }) {
1292
2106
  const s = useFieldStrings();
1293
2107
  const presentation = useFieldPresentation();
1294
2108
  const isApp = presentation === "app";
1295
2109
  const items = value ?? [];
1296
2110
  const [rowKeys, setRowKeys] = useRowKeys(items.length);
2111
+ const [pickerOpen, setPickerOpen] = useState(false);
2112
+ const pickerEntryRef = useRef(null);
2113
+ const rowsRef = useRef(null);
2114
+ const landedRow = useRef(null);
1297
2115
  const [staleErrors, setStaleErrors] = useState(NO_ERRORS);
1298
2116
  const setItem = (index, itemValue) => {
1299
2117
  const next = items.slice();
@@ -1337,6 +2155,9 @@ function ListField({ field, value, onChange, id, error, env }) {
1337
2155
  };
1338
2156
  }, [env, staleErrors]);
1339
2157
  const isFull = field.maxItemCount !== void 0 && items.length >= field.maxItemCount;
2158
+ const fileSource = env?.fileSource;
2159
+ const fileItem = field.item.kind === "document" || field.item.kind === "image" ? field.item : null;
2160
+ const room = roomForChosenFiles(items, field.maxItemCount);
1340
2161
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1341
2162
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-1", children: [
1342
2163
  /* @__PURE__ */ jsx(
@@ -1354,11 +2175,12 @@ function ListField({ field, value, onChange, id, error, env }) {
1354
2175
  shownAsOptional(field) && /* @__PURE__ */ jsx("span", { className: "ml-auto font-mono text-[10px] uppercase tracking-wider text-muted-foreground", children: s.optionalBadge })
1355
2176
  ] }),
1356
2177
  field.description && /* @__PURE__ */ jsx("p", { className: "text-[12px] leading-relaxed text-muted-foreground", children: field.description }),
1357
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2178
+ /* @__PURE__ */ jsxs("div", { ref: rowsRef, className: "space-y-2", children: [
1358
2179
  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 }),
1359
2180
  items.map((item, index) => /* @__PURE__ */ jsxs(
1360
2181
  "div",
1361
2182
  {
2183
+ "data-list-row": true,
1362
2184
  className: "flex items-start gap-2 rounded-md border border-border bg-card/40 p-3",
1363
2185
  children: [
1364
2186
  /* @__PURE__ */ jsx("span", { className: "mt-1 w-5 shrink-0 text-center font-mono text-[11px] text-muted-foreground", children: index + 1 }),
@@ -1407,11 +2229,56 @@ function ListField({ field, value, onChange, id, error, env }) {
1407
2229
  s.addItem
1408
2230
  ]
1409
2231
  }
1410
- )
2232
+ ),
2233
+ fileSource && fileItem && /* @__PURE__ */ jsxs(Fragment, { children: [
2234
+ /* @__PURE__ */ jsx(
2235
+ FilePickerEntry,
2236
+ {
2237
+ ref: pickerEntryRef,
2238
+ label: fieldLabel(field.title, field.name, presentation),
2239
+ disabled: env?.disabled || busy || room === 0,
2240
+ onOpen: () => setPickerOpen(true)
2241
+ }
2242
+ ),
2243
+ /* @__PURE__ */ jsx(
2244
+ FilePicker,
2245
+ {
2246
+ source: fileSource,
2247
+ formats: fileItem.formats,
2248
+ multiple: true,
2249
+ maxChoices: room,
2250
+ held: items,
2251
+ open: pickerOpen,
2252
+ onOpenChange: setPickerOpen,
2253
+ disabled: env?.disabled || busy,
2254
+ returnFocusTo: pickerEntryRef,
2255
+ onCloseAutoFocus: (event) => {
2256
+ const landed = landedRow.current;
2257
+ landedRow.current = null;
2258
+ if (landed === null || !pickerEntryRef.current?.disabled) return;
2259
+ const rows = rowsRef.current?.querySelectorAll(":scope > [data-list-row]");
2260
+ const target = firstFocusable(rows?.[landed]);
2261
+ if (!target) return;
2262
+ event.preventDefault();
2263
+ target.focus();
2264
+ },
2265
+ onUse: (files) => {
2266
+ const next = addChosenFiles(items, files);
2267
+ landedRow.current = lastWrittenRow(items, next);
2268
+ onChange(next);
2269
+ }
2270
+ }
2271
+ )
2272
+ ] })
1411
2273
  ] }),
1412
2274
  error && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-destructive", role: "alert", children: error })
1413
2275
  ] });
1414
2276
  }
2277
+ function lastWrittenRow(before, after) {
2278
+ let index = after.length - 1;
2279
+ while (index >= 0 && after[index] === before[index]) index -= 1;
2280
+ return index >= 0 ? index : null;
2281
+ }
1415
2282
  function listIsBusy(id, uploadingIds) {
1416
2283
  if (!uploadingIds?.size) return false;
1417
2284
  const prefix = `${id}.`;
@@ -1581,6 +2448,7 @@ function FieldRenderer({ field, value, onChange, id, error, env }) {
1581
2448
  uploading: env?.uploadingIds?.has(id),
1582
2449
  uploadError: env?.uploadErrors?.get(id),
1583
2450
  resolveUrl: env?.resolveUrl,
2451
+ fileSource: env?.fileSource,
1584
2452
  id,
1585
2453
  error,
1586
2454
  disabled
@@ -1598,6 +2466,7 @@ function FieldRenderer({ field, value, onChange, id, error, env }) {
1598
2466
  uploading: env?.uploadingIds?.has(id),
1599
2467
  uploadError: env?.uploadErrors?.get(id),
1600
2468
  resolveUrl: env?.resolveUrl,
2469
+ fileSource: env?.fileSource,
1601
2470
  id,
1602
2471
  error,
1603
2472
  disabled
@@ -1641,6 +2510,450 @@ function FieldRenderer({ field, value, onChange, id, error, env }) {
1641
2510
  );
1642
2511
  }
1643
2512
  }
2513
+ var AlertDialog = AlertDialogPrimitive.Root;
2514
+ var AlertDialogContent = React5.forwardRef(({ className, returnFocus, onCloseAutoFocus, ...props }, ref) => /* @__PURE__ */ jsxs(Fragment, { children: [
2515
+ /* @__PURE__ */ jsx(AlertDialogPrimitive.Overlay, { className: "fixed inset-0 z-50 bg-black/50" }),
2516
+ /* @__PURE__ */ jsx(
2517
+ AlertDialogPrimitive.Content,
2518
+ {
2519
+ ref,
2520
+ className: cn(
2521
+ "fixed inset-0 z-50 m-auto grid h-fit w-[calc(100%-2rem)] max-w-sm gap-3 rounded-lg border border-border bg-popover p-4 text-popover-foreground shadow-lg outline-hidden",
2522
+ className
2523
+ ),
2524
+ onCloseAutoFocus: closeAutoFocus(onCloseAutoFocus, returnFocus),
2525
+ ...props
2526
+ }
2527
+ )
2528
+ ] }));
2529
+ AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
2530
+ var AlertDialogTitle = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2531
+ AlertDialogPrimitive.Title,
2532
+ {
2533
+ ref,
2534
+ className: cn("text-[16px] font-semibold text-foreground", className),
2535
+ ...props
2536
+ }
2537
+ ));
2538
+ AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
2539
+ var AlertDialogDescription = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2540
+ AlertDialogPrimitive.Description,
2541
+ {
2542
+ ref,
2543
+ className: cn("text-[13px] text-muted-foreground", className),
2544
+ ...props
2545
+ }
2546
+ ));
2547
+ AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
2548
+ var AlertDialogCancel = AlertDialogPrimitive.Cancel;
2549
+ var AlertDialogAction = AlertDialogPrimitive.Action;
2550
+ var DropdownMenu = DropdownMenuPrimitive.Root;
2551
+ var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
2552
+ var DropdownMenuContent = React5.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
2553
+ DropdownMenuPrimitive.Content,
2554
+ {
2555
+ ref,
2556
+ sideOffset,
2557
+ className: cn(
2558
+ "z-50 min-w-36 overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md",
2559
+ className
2560
+ ),
2561
+ ...props
2562
+ }
2563
+ ));
2564
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
2565
+ var DropdownMenuItem = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2566
+ DropdownMenuPrimitive.Item,
2567
+ {
2568
+ ref,
2569
+ className: cn(
2570
+ "flex min-h-11 cursor-default select-none items-center gap-2 rounded-sm px-3 text-[14px] outline-hidden data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 sm:min-h-9",
2571
+ className
2572
+ ),
2573
+ ...props
2574
+ }
2575
+ ));
2576
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
2577
+ var buttonClass = "inline-flex min-h-11 items-center justify-center gap-2 rounded-md px-4 text-[14px] transition-colors disabled:cursor-not-allowed disabled:opacity-50 sm:min-h-9";
2578
+ var secondaryClass = cn(buttonClass, "border border-border text-foreground hover:bg-muted");
2579
+ var primaryClass = cn(
2580
+ buttonClass,
2581
+ "bg-primary font-medium text-primary-foreground hover:bg-primary/90"
2582
+ );
2583
+ var dangerClass = cn(
2584
+ buttonClass,
2585
+ "bg-destructive font-medium text-destructive-foreground hover:bg-destructive/90"
2586
+ );
2587
+ function FillWithExample({
2588
+ source,
2589
+ fields,
2590
+ touched,
2591
+ onFill,
2592
+ disabled,
2593
+ className
2594
+ }) {
2595
+ const s = useFieldStrings();
2596
+ const [open, setOpen] = useState(false);
2597
+ const [opening, setOpening] = useState(0);
2598
+ const [closing, setClosing] = useState(0);
2599
+ const [replacing, setReplacing] = useState(null);
2600
+ const [renaming, setRenaming] = useState(null);
2601
+ const [deleting, setDeleting] = useState(null);
2602
+ const control = useRef(null);
2603
+ const closeButton = useRef(null);
2604
+ const sheet = useRef(null);
2605
+ const afterControl = useRef(null);
2606
+ const rows = useRef(/* @__PURE__ */ new Map());
2607
+ const menus = useRef(/* @__PURE__ */ new Map());
2608
+ const afterRowDialog = useRef(null);
2609
+ const register = (map, id) => (element) => {
2610
+ map.set(id, element);
2611
+ return () => {
2612
+ if (map.get(id) === element) map.delete(id);
2613
+ };
2614
+ };
2615
+ const load = (cursor, signal) => source.list({ cursor, signal }).then((page) => ({ items: page.examples, nextCursor: page.nextCursor }));
2616
+ const probe = useSourcePages(load, source.hideWhenEmpty ? `probe-${closing}` : null);
2617
+ const pages = useSourcePages(load, open ? `open-${opening}` : null);
2618
+ const answer = probe.status === "failed" || probe.more === "failed" ? true : probe.items.length > 0 ? true : probe.empty ? false : null;
2619
+ const [hasExamples, setHasExamples] = useState(null);
2620
+ if (answer !== null && answer !== hasExamples) setHasExamples(answer);
2621
+ if (disabled && (open || replacing || renaming || deleting)) {
2622
+ if (open) setClosing((count) => count + 1);
2623
+ setOpen(false);
2624
+ setReplacing(null);
2625
+ setRenaming(null);
2626
+ setDeleting(null);
2627
+ }
2628
+ if (source.hideWhenEmpty && !open && (answer ?? hasExamples) !== true) return null;
2629
+ const closeList = () => {
2630
+ if (source.hideWhenEmpty && pages.status === "ready") {
2631
+ if (pages.items.length > 0) setHasExamples(true);
2632
+ else if (pages.empty) {
2633
+ afterControl.current = followingFocusable(control.current, sheet.current);
2634
+ setHasExamples(false);
2635
+ }
2636
+ }
2637
+ setOpen(false);
2638
+ setClosing((count) => count + 1);
2639
+ };
2640
+ const fill = (example) => {
2641
+ if (disabled) return;
2642
+ onFill(runValuesFromInputs(example.inputs, fields), example);
2643
+ setReplacing(null);
2644
+ closeList();
2645
+ };
2646
+ const choose = (example) => {
2647
+ if (touched) setReplacing(example);
2648
+ else fill(example);
2649
+ };
2650
+ const manages = source.rename !== void 0 || source.delete !== void 0;
2651
+ const status = pages.status === "idle" || pages.status === "loading" ? s.examplesLoading : pages.status === "failed" ? s.examplesFailed : pages.more === "failed" ? s.loadMoreFailed : pages.items.length > 0 ? s.examplesShown(pages.items.length) : pages.empty ? s.examplesNone : s.examplesLoading;
2652
+ const returnFromRowDialog = () => {
2653
+ const next = afterRowDialog.current;
2654
+ afterRowDialog.current = null;
2655
+ if (!next) return null;
2656
+ const target = next.id === void 0 ? void 0 : (next.to === "menu" ? menus : rows).current.get(next.id);
2657
+ return target?.isConnected ? target : closeButton.current;
2658
+ };
2659
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2660
+ /* @__PURE__ */ jsxs(
2661
+ "button",
2662
+ {
2663
+ ref: control,
2664
+ type: "button",
2665
+ disabled,
2666
+ "aria-haspopup": "dialog",
2667
+ onClick: () => {
2668
+ setOpening((count) => count + 1);
2669
+ setOpen(true);
2670
+ },
2671
+ className: cn(secondaryClass, className),
2672
+ children: [
2673
+ /* @__PURE__ */ jsx(Sparkles, { className: "size-4 text-muted-foreground", "aria-hidden": "true" }),
2674
+ s.fillWithExample
2675
+ ]
2676
+ }
2677
+ ),
2678
+ /* @__PURE__ */ jsx(
2679
+ Dialog,
2680
+ {
2681
+ open,
2682
+ onOpenChange: (next) => {
2683
+ if (next) setOpen(true);
2684
+ else closeList();
2685
+ },
2686
+ children: open && /* @__PURE__ */ jsxs(
2687
+ DialogContent,
2688
+ {
2689
+ layout: "sheet",
2690
+ className: "top-auto max-h-[calc(100dvh-1.5rem)]",
2691
+ ref: sheet,
2692
+ returnFocus: () => control.current ?? afterControl.current,
2693
+ onClick: (event) => event.stopPropagation(),
2694
+ children: [
2695
+ /* @__PURE__ */ jsx("div", { className: "px-4 pt-4 pb-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
2696
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1 pt-1", children: [
2697
+ /* @__PURE__ */ jsx(DialogTitle, { className: "text-[20px]", children: s.examplesTitle }),
2698
+ /* @__PURE__ */ jsx(DialogDescription, { children: s.examplesHint })
2699
+ ] }),
2700
+ /* @__PURE__ */ jsx(
2701
+ DialogClose,
2702
+ {
2703
+ ref: closeButton,
2704
+ "aria-label": s.close,
2705
+ className: "flex size-11 shrink-0 items-center justify-center rounded-full border border-border text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2706
+ children: /* @__PURE__ */ jsx(X, { className: "size-5", "aria-hidden": "true" })
2707
+ }
2708
+ )
2709
+ ] }) }),
2710
+ /* @__PURE__ */ jsx("p", { role: "status", className: "sr-only", children: status }),
2711
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto border-t border-border pb-[env(safe-area-inset-bottom)]", children: pages.status === "idle" || pages.status === "loading" ? /* @__PURE__ */ jsx(DimRows, { count: 3 }) : pages.status === "failed" ? /* @__PURE__ */ jsx(ListMessage, { text: s.examplesFailed, children: /* @__PURE__ */ jsx(ListAction, { onClick: pages.retry, children: s.tryAgain }) }) : pages.empty ? /* @__PURE__ */ jsx(ListMessage, { text: s.examplesNone }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2712
+ pages.items.length > 0 && /* @__PURE__ */ jsx("ul", { className: "divide-y divide-border", children: pages.items.map((example) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1 pr-2", children: [
2713
+ /* @__PURE__ */ jsx(
2714
+ "button",
2715
+ {
2716
+ ref: register(rows.current, example.id),
2717
+ type: "button",
2718
+ onClick: () => choose(example),
2719
+ className: "flex min-h-16 min-w-0 flex-1 items-center px-4 py-2.5 text-left transition-colors hover:bg-muted/60 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring",
2720
+ children: /* @__PURE__ */ jsx("span", { className: "truncate text-[16px] font-medium text-foreground", children: example.name })
2721
+ }
2722
+ ),
2723
+ manages && // Not modal, so the question a menu item opens takes
2724
+ // the focus without the menu fighting it for the page.
2725
+ /* @__PURE__ */ jsxs(DropdownMenu, { modal: false, children: [
2726
+ /* @__PURE__ */ jsx(
2727
+ DropdownMenuTrigger,
2728
+ {
2729
+ ref: register(menus.current, example.id),
2730
+ "aria-label": s.exampleActions(example.name),
2731
+ className: "flex size-11 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2732
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-5", "aria-hidden": "true" })
2733
+ }
2734
+ ),
2735
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
2736
+ source.rename && /* @__PURE__ */ jsx(DropdownMenuItem, { onSelect: () => setRenaming(example), children: s.renameExample }),
2737
+ source.delete && /* @__PURE__ */ jsx(
2738
+ DropdownMenuItem,
2739
+ {
2740
+ onSelect: () => setDeleting(example),
2741
+ className: "text-destructive data-highlighted:text-destructive",
2742
+ children: s.deleteExample
2743
+ }
2744
+ )
2745
+ ] })
2746
+ ] })
2747
+ ] }, example.id)) }),
2748
+ /* @__PURE__ */ jsx(MoreFooter, { pages })
2749
+ ] }) })
2750
+ ]
2751
+ }
2752
+ )
2753
+ }
2754
+ ),
2755
+ /* @__PURE__ */ jsx(
2756
+ AlertDialog,
2757
+ {
2758
+ open: replacing !== null,
2759
+ onOpenChange: (next) => {
2760
+ if (!next) setReplacing(null);
2761
+ },
2762
+ children: replacing && /* @__PURE__ */ jsxs(
2763
+ AlertDialogContent,
2764
+ {
2765
+ returnFocus: () => {
2766
+ const row = rows.current.get(replacing.id);
2767
+ return row?.isConnected ? row : control.current;
2768
+ },
2769
+ onClick: (event) => event.stopPropagation(),
2770
+ children: [
2771
+ /* @__PURE__ */ jsx(AlertDialogTitle, { children: s.replaceEnteredTitle }),
2772
+ /* @__PURE__ */ jsx(AlertDialogDescription, { children: s.replaceEnteredDescription(replacing.name) }),
2773
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap justify-end gap-2", children: [
2774
+ /* @__PURE__ */ jsx(AlertDialogCancel, { className: secondaryClass, children: s.cancel }),
2775
+ /* @__PURE__ */ jsx(AlertDialogAction, { className: primaryClass, onClick: () => fill(replacing), children: s.replaceEnteredConfirm })
2776
+ ] })
2777
+ ]
2778
+ }
2779
+ )
2780
+ }
2781
+ ),
2782
+ source.rename && renaming && /* @__PURE__ */ jsx(
2783
+ RenameExampleDialog,
2784
+ {
2785
+ example: renaming,
2786
+ rename: source.rename,
2787
+ returnFocus: returnFromRowDialog,
2788
+ onDone: (renamed) => {
2789
+ pages.updateItems(
2790
+ (items) => items.map((item) => item.id === renaming.id ? renamed : item)
2791
+ );
2792
+ afterRowDialog.current = { id: renamed.id, to: "menu" };
2793
+ setRenaming(null);
2794
+ },
2795
+ onCancel: () => {
2796
+ afterRowDialog.current = { id: renaming.id, to: "menu" };
2797
+ setRenaming(null);
2798
+ }
2799
+ }
2800
+ ),
2801
+ source.delete && deleting && /* @__PURE__ */ jsx(
2802
+ DeleteExampleDialog,
2803
+ {
2804
+ example: deleting,
2805
+ remove: source.delete,
2806
+ returnFocus: returnFromRowDialog,
2807
+ onDone: (deleted) => {
2808
+ const index = pages.items.findIndex((item) => item.id === deleted.id);
2809
+ const neighbour = pages.items[index + 1] ?? pages.items[index - 1];
2810
+ pages.updateItems((items) => items.filter((item) => item.id !== deleted.id));
2811
+ afterRowDialog.current = { id: neighbour?.id, to: "row" };
2812
+ setDeleting(null);
2813
+ },
2814
+ onCancel: () => {
2815
+ afterRowDialog.current = { id: deleting.id, to: "menu" };
2816
+ setDeleting(null);
2817
+ }
2818
+ }
2819
+ )
2820
+ ] });
2821
+ }
2822
+ function RenameExampleDialog({
2823
+ example,
2824
+ rename,
2825
+ returnFocus,
2826
+ onDone,
2827
+ onCancel
2828
+ }) {
2829
+ const s = useFieldStrings();
2830
+ const fieldId = useId();
2831
+ const [name, setName] = useState(example.name);
2832
+ const [state, setState] = useState("idle");
2833
+ const trimmed = name.trim();
2834
+ const save = () => {
2835
+ if (trimmed === "" || state === "busy") return;
2836
+ setState("busy");
2837
+ let renamed;
2838
+ try {
2839
+ renamed = Promise.resolve(rename(example, trimmed));
2840
+ } catch (error) {
2841
+ renamed = Promise.reject(error);
2842
+ }
2843
+ renamed.then(
2844
+ (stored) => onDone(stored ?? { ...example, name: trimmed }),
2845
+ () => setState("failed")
2846
+ );
2847
+ };
2848
+ const onKeyDown = (event) => {
2849
+ if (event.key !== "Enter") return;
2850
+ event.preventDefault();
2851
+ save();
2852
+ };
2853
+ return /* @__PURE__ */ jsx(
2854
+ Dialog,
2855
+ {
2856
+ open: true,
2857
+ onOpenChange: (next) => {
2858
+ if (!next && state !== "busy") onCancel();
2859
+ },
2860
+ children: /* @__PURE__ */ jsxs(DialogContent, { returnFocus, onClick: (event) => event.stopPropagation(), children: [
2861
+ /* @__PURE__ */ jsx(DialogTitle, { children: s.renameExampleTitle }),
2862
+ /* @__PURE__ */ jsx(DialogDescription, { className: "sr-only", children: example.name }),
2863
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
2864
+ /* @__PURE__ */ jsx("label", { htmlFor: fieldId, className: "text-[13px] font-medium text-foreground", children: s.exampleName }),
2865
+ /* @__PURE__ */ jsx(
2866
+ "input",
2867
+ {
2868
+ id: fieldId,
2869
+ type: "text",
2870
+ value: name,
2871
+ onChange: (event) => setName(event.target.value),
2872
+ onKeyDown,
2873
+ disabled: state === "busy",
2874
+ autoComplete: "off",
2875
+ className: "h-11 w-full rounded-md border border-border bg-input px-3 text-[16px] text-foreground focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-ring"
2876
+ }
2877
+ )
2878
+ ] }),
2879
+ state === "failed" && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[13px] text-destructive", children: s.renameFailed }),
2880
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap justify-end gap-2", children: [
2881
+ /* @__PURE__ */ jsx(
2882
+ "button",
2883
+ {
2884
+ type: "button",
2885
+ onClick: onCancel,
2886
+ disabled: state === "busy",
2887
+ className: secondaryClass,
2888
+ children: s.cancel
2889
+ }
2890
+ ),
2891
+ /* @__PURE__ */ jsx(
2892
+ "button",
2893
+ {
2894
+ type: "button",
2895
+ onClick: save,
2896
+ disabled: trimmed === "" || state === "busy",
2897
+ className: primaryClass,
2898
+ children: state === "busy" ? s.renaming : state === "failed" ? s.tryAgain : s.save
2899
+ }
2900
+ )
2901
+ ] })
2902
+ ] })
2903
+ }
2904
+ );
2905
+ }
2906
+ function DeleteExampleDialog({
2907
+ example,
2908
+ remove,
2909
+ returnFocus,
2910
+ onDone,
2911
+ onCancel
2912
+ }) {
2913
+ const s = useFieldStrings();
2914
+ const [state, setState] = useState("idle");
2915
+ const confirm = () => {
2916
+ if (state === "busy") return;
2917
+ setState("busy");
2918
+ let removed;
2919
+ try {
2920
+ removed = Promise.resolve(remove(example));
2921
+ } catch (error) {
2922
+ removed = Promise.reject(error);
2923
+ }
2924
+ removed.then(
2925
+ () => onDone(example),
2926
+ () => setState("failed")
2927
+ );
2928
+ };
2929
+ return /* @__PURE__ */ jsx(
2930
+ AlertDialog,
2931
+ {
2932
+ open: true,
2933
+ onOpenChange: (next) => {
2934
+ if (!next && state !== "busy") onCancel();
2935
+ },
2936
+ children: /* @__PURE__ */ jsxs(AlertDialogContent, { returnFocus, onClick: (event) => event.stopPropagation(), children: [
2937
+ /* @__PURE__ */ jsx(AlertDialogTitle, { children: s.deleteExampleTitle(example.name) }),
2938
+ /* @__PURE__ */ jsx(AlertDialogDescription, { children: s.deleteExampleDescription }),
2939
+ state === "failed" && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[13px] text-destructive", children: s.deleteFailed }),
2940
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap justify-end gap-2", children: [
2941
+ /* @__PURE__ */ jsx(AlertDialogCancel, { disabled: state === "busy", className: secondaryClass, children: s.cancel }),
2942
+ /* @__PURE__ */ jsx(
2943
+ "button",
2944
+ {
2945
+ type: "button",
2946
+ onClick: confirm,
2947
+ disabled: state === "busy",
2948
+ className: dangerClass,
2949
+ children: state === "busy" ? s.deleting : state === "failed" ? s.tryAgain : s.deleteExample
2950
+ }
2951
+ )
2952
+ ] })
2953
+ ] })
2954
+ }
2955
+ );
2956
+ }
1644
2957
  var EMPTY_IDS = /* @__PURE__ */ new Set();
1645
2958
  function withId(ids, id) {
1646
2959
  if (ids.has(id)) return ids;
@@ -1668,7 +2981,9 @@ function useMethodForm({
1668
2981
  prepareFields,
1669
2982
  order,
1670
2983
  initialValues,
1671
- uploadFile
2984
+ uploadFile,
2985
+ fileSource,
2986
+ exampleSource
1672
2987
  }) {
1673
2988
  const orderKey = order ? order.join("\0") : "";
1674
2989
  const fields = useMemo(() => {
@@ -1681,22 +2996,29 @@ function useMethodForm({
1681
2996
  return initialValues ?? seedInputs(fields);
1682
2997
  }, [initialValues, fields]);
1683
2998
  const [edited, setEdited] = useState(null);
2999
+ const [given, setGiven] = useState(null);
1684
3000
  const [uploadingIds, setUploadingIds] = useState(EMPTY_IDS);
1685
3001
  const [failedUploadIds, setFailedUploadIds] = useState(EMPTY_IDS);
1686
3002
  const [attempted, setAttempted] = useState(false);
3003
+ const [resets, setResets] = useState(0);
1687
3004
  const pendingUploads = useRef(/* @__PURE__ */ new Map());
1688
3005
  const uploadCounter = useRef(0);
1689
3006
  const values = edited ?? initial;
1690
3007
  const setValues = useCallback(
1691
- (next) => setEdited((previous) => typeof next === "function" ? next(previous ?? initial) : next),
3008
+ (next) => {
3009
+ setGiven((previous) => previous ?? initial);
3010
+ setEdited((previous) => typeof next === "function" ? next(previous ?? initial) : next);
3011
+ },
1692
3012
  [initial]
1693
3013
  );
1694
3014
  const reset = useCallback((next) => {
1695
3015
  pendingUploads.current.clear();
1696
3016
  setEdited(next ?? null);
3017
+ setGiven(next ?? null);
1697
3018
  setUploadingIds(EMPTY_IDS);
1698
3019
  setFailedUploadIds(EMPTY_IDS);
1699
3020
  setAttempted(false);
3021
+ setResets((count) => count + 1);
1700
3022
  }, []);
1701
3023
  const dropFile = useMemo(() => {
1702
3024
  if (!uploadFile) return void 0;
@@ -1717,6 +3039,7 @@ function useMethodForm({
1717
3039
  (stored) => {
1718
3040
  if (!current()) return;
1719
3041
  const value = typeof stored === "string" ? { url: stored, filename: file.name } : { url: stored.url, filename: stored.filename ?? file.name };
3042
+ setGiven((previous) => previous ?? initial);
1720
3043
  setEdited((previous) => setValueAtPath(previous ?? initial, path, value));
1721
3044
  },
1722
3045
  () => {
@@ -1736,6 +3059,10 @@ function useMethodForm({
1736
3059
  );
1737
3060
  const uploading = uploadingIds.size > 0;
1738
3061
  const ready = readiness.ready === readiness.total && !uploading;
3062
+ const touched = useMemo(
3063
+ () => uploading || edited !== null && given !== null && !sameRunValues(edited, given, fields),
3064
+ [uploading, edited, given, fields]
3065
+ );
1739
3066
  const attempt = useCallback(() => {
1740
3067
  setAttempted(true);
1741
3068
  return ready;
@@ -1748,12 +3075,16 @@ function useMethodForm({
1748
3075
  uploading,
1749
3076
  ready,
1750
3077
  attempted,
3078
+ touched,
1751
3079
  setValues,
1752
3080
  reset,
1753
3081
  attempt,
3082
+ resets,
1754
3083
  uploadingIds,
1755
3084
  failedUploadIds,
1756
- dropFile
3085
+ dropFile,
3086
+ fileSource,
3087
+ exampleSource
1757
3088
  };
1758
3089
  }
1759
3090
  function MethodForm({ locale, strings, presentation, ...props }) {
@@ -1777,14 +3108,35 @@ function MethodFormFields({
1777
3108
  }) {
1778
3109
  const s = useFieldStrings();
1779
3110
  const [showOptional, setShowOptional] = useState(false);
1780
- const { fields, values, setValues, attempted, uploadingIds, failedUploadIds, dropFile } = form;
3111
+ const {
3112
+ fields,
3113
+ values,
3114
+ setValues,
3115
+ reset,
3116
+ attempted,
3117
+ touched,
3118
+ resets,
3119
+ uploadingIds,
3120
+ failedUploadIds,
3121
+ dropFile,
3122
+ fileSource,
3123
+ exampleSource
3124
+ } = form;
1781
3125
  const uploadErrors = useMemo(
1782
3126
  () => new Map([...failedUploadIds].map((id) => [id, s.uploadFailed])),
1783
3127
  [failedUploadIds, s.uploadFailed]
1784
3128
  );
1785
3129
  const env = useMemo(
1786
- () => ({ disabled, onDropFile: dropFile, uploadingIds, uploadErrors, allowUrl, resolveUrl }),
1787
- [disabled, dropFile, uploadingIds, uploadErrors, allowUrl, resolveUrl]
3130
+ () => ({
3131
+ disabled,
3132
+ onDropFile: dropFile,
3133
+ uploadingIds,
3134
+ uploadErrors,
3135
+ allowUrl,
3136
+ resolveUrl,
3137
+ fileSource
3138
+ }),
3139
+ [disabled, dropFile, uploadingIds, uploadErrors, allowUrl, resolveUrl, fileSource]
1788
3140
  );
1789
3141
  const folds = (field) => {
1790
3142
  const value = ownProp(values, field.name);
@@ -1812,6 +3164,16 @@ function MethodFormFields({
1812
3164
  return isFilled(value) && !fieldFilled(field, value) ? s.incompleteField : void 0;
1813
3165
  };
1814
3166
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-6", className), children: [
3167
+ exampleSource && /* @__PURE__ */ jsx(
3168
+ FillWithExample,
3169
+ {
3170
+ source: exampleSource,
3171
+ fields,
3172
+ touched,
3173
+ onFill: (next) => reset(next),
3174
+ disabled
3175
+ }
3176
+ ),
1815
3177
  visible.map((field) => /* @__PURE__ */ jsx(
1816
3178
  FieldRenderer,
1817
3179
  {
@@ -1822,7 +3184,7 @@ function MethodFormFields({
1822
3184
  env,
1823
3185
  onChange: (next) => setValues((previous) => ({ ...previous, [field.name]: next }))
1824
3186
  },
1825
- field.name
3187
+ `${field.name}:${resets}`
1826
3188
  )),
1827
3189
  (folded.length > 0 || structureOpen) && /* @__PURE__ */ jsx(OptionalToggle, { count: folded.length, expanded, onToggle: toggle, noun: "input" })
1828
3190
  ] });
@@ -2319,7 +3681,7 @@ function ResultAt({ segment, children }) {
2319
3681
  var TooltipProvider = TooltipPrimitive.Provider;
2320
3682
  var TooltipRoot = TooltipPrimitive.Root;
2321
3683
  var TooltipTrigger = TooltipPrimitive.Trigger;
2322
- var TooltipContent = React2.forwardRef(({ className, sideOffset = 6, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
3684
+ var TooltipContent = React5.forwardRef(({ className, sideOffset = 6, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
2323
3685
  TooltipPrimitive.Content,
2324
3686
  {
2325
3687
  ref,
@@ -3301,12 +4663,12 @@ function useResolvedMarkup(markup) {
3301
4663
  }
3302
4664
  var LEX_OPTIONS = { gfm: true, breaks: true };
3303
4665
  function Markdown({ text, className, proseImages }) {
3304
- const tokens = React2.useMemo(() => marked.lexer(text, LEX_OPTIONS), [text]);
4666
+ const tokens = React5.useMemo(() => marked.lexer(text, LEX_OPTIONS), [text]);
3305
4667
  const fromEnv = useProseImages();
3306
4668
  const mode = proseImages ?? fromEnv;
3307
4669
  return /* @__PURE__ */ jsx(ProseImagesContext, { value: mode, children: /* @__PURE__ */ jsx("div", { className: cn("space-y-2 text-[13px] leading-relaxed text-foreground", className), children: /* @__PURE__ */ jsx(Blocks, { tokens }) }) });
3308
4670
  }
3309
- var ProseImagesContext = React2.createContext("link");
4671
+ var ProseImagesContext = React5.createContext("link");
3310
4672
  var HEADING_CLASS = {
3311
4673
  1: "text-[16px] font-semibold",
3312
4674
  2: "text-[14.5px] font-semibold",
@@ -3463,8 +4825,8 @@ function InlineToken({ token }) {
3463
4825
  }
3464
4826
  }
3465
4827
  function ProseImage({ token }) {
3466
- const mode = React2.use(ProseImagesContext);
3467
- const insideLink = React2.use(InsideLinkContext);
4828
+ const mode = React5.use(ProseImagesContext);
4829
+ const insideLink = React5.use(InsideLinkContext);
3468
4830
  const src = proseImageUrl(token.href);
3469
4831
  if (!src) return /* @__PURE__ */ jsx(Fragment, { children: token.text });
3470
4832
  if (mode === "load") {
@@ -3490,7 +4852,7 @@ function ProseImage({ token }) {
3490
4852
  }
3491
4853
  );
3492
4854
  }
3493
- var InsideLinkContext = React2.createContext(false);
4855
+ var InsideLinkContext = React5.createContext(false);
3494
4856
  function proseImageUrl(href) {
3495
4857
  const url = viewableUrl(href);
3496
4858
  return url && /^https?:/.test(url) ? url : void 0;
@@ -4854,6 +6216,6 @@ function pdfFileName(field, value, baseName) {
4854
6216
  return name === void 0 ? "" : name.replace(/\.[^.]+$/, "");
4855
6217
  }
4856
6218
 
4857
- export { BooleanField, ConceptPill, DEFAULT_FIELD_STRINGS, DateField, DocumentField, EN_FIELD_STRINGS, EnumField, FIELD_STRINGS_BY_LOCALE, FR_FIELD_STRINGS, FieldDomIdProvider, FieldPresentationProvider, FieldRenderer, FieldShell, FieldStringsProvider, 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, cn, fieldControlClass, fieldStringsFor, humanizeFieldName, renderHtmlPdf, resolveHtmlStorageUrls, saveInBrowser, useFieldDomId, useFieldPresentation, useFieldStrings, useMethodForm, useProseImages, useResolveShareUrl, useResolveUrl, useResolvedUrl };
4858
- //# sourceMappingURL=chunk-QCGIH3WY.js.map
4859
- //# sourceMappingURL=chunk-QCGIH3WY.js.map
6219
+ 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, brandFillClass, brandFillInkClass, brandFillStrongClass, brandInkClass, cn, fieldControlClass, fieldStringsFor, humanizeFieldName, renderHtmlPdf, resolveHtmlStorageUrls, saveInBrowser, useFieldDomId, useFieldPresentation, useFieldStrings, useMethodForm, useProseImages, useResolveShareUrl, useResolveUrl, useResolvedUrl };
6220
+ //# sourceMappingURL=chunk-3XDR2C4I.js.map
6221
+ //# sourceMappingURL=chunk-3XDR2C4I.js.map