@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.
- package/README.md +4 -1
- package/dist/brand/index.d.ts +109 -1
- package/dist/brand/index.js +113 -1
- package/dist/brand/index.js.map +1 -1
- package/dist/{chunk-QCGIH3WY.js → chunk-3XDR2C4I.js} +1473 -111
- package/dist/chunk-3XDR2C4I.js.map +1 -0
- package/dist/{chunk-2HIYTIQ6.js → chunk-4DPYGNJ3.js} +3 -3
- package/dist/{chunk-2HIYTIQ6.js.map → chunk-4DPYGNJ3.js.map} +1 -1
- package/dist/{chunk-HQMXXK5X.js → chunk-E6BIXJ6C.js} +3 -3
- package/dist/{chunk-HQMXXK5X.js.map → chunk-E6BIXJ6C.js.map} +1 -1
- package/dist/chunk-EQJBM3NS.js +41 -0
- package/dist/chunk-EQJBM3NS.js.map +1 -0
- package/dist/{chunk-MEXWXLR7.js → chunk-ZX52CQJ4.js} +16 -4
- package/dist/chunk-ZX52CQJ4.js.map +1 -0
- package/dist/core/gate.js +2 -2
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.js +5 -4
- package/dist/core/sources.d.ts +161 -0
- package/dist/core/sources.js +3 -0
- package/dist/core/sources.js.map +1 -0
- package/dist/core/values.d.ts +25 -1
- package/dist/core/values.js +2 -2
- package/dist/core/wire-format.d.ts +11 -1
- package/dist/core/wire-format.js +1 -1
- package/dist/{field-renderer-C5Onx6qB.d.ts → field-renderer-B3g16qZT.d.ts} +9 -0
- package/dist/generative/index.d.ts +2 -1
- package/dist/generative/index.js +24 -7
- package/dist/generative/index.js.map +1 -1
- package/dist/react/index.d.ts +248 -6
- package/dist/react/index.js +4 -3
- package/dist/styles.css +1 -1
- package/package.json +4 -1
- package/dist/chunk-MEXWXLR7.js.map +0 -1
- package/dist/chunk-QCGIH3WY.js.map +0 -1
|
@@ -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-
|
|
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,
|
|
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
|
|
17
|
-
import { createContext, use, useId, useMemo, useContext, useState, useRef,
|
|
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
|
|
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 =
|
|
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:
|
|
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 {
|
|
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
|
-
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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(
|
|
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) =>
|
|
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 {
|
|
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
|
-
() => ({
|
|
1787
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
3467
|
-
const insideLink =
|
|
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 =
|
|
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-
|
|
4859
|
-
//# sourceMappingURL=chunk-
|
|
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
|