@ydtb/tk-scope-capture 0.23.1 → 0.23.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"CaptureBuilderPage.d.ts","sourceRoot":"","sources":["../../../../src/client/pages/CaptureBuilderPage.tsx"],"names":[],"mappings":"AAmNA,wBAAgB,kBAAkB,4CAyjDjC"}
1
+ {"version":3,"file":"CaptureBuilderPage.d.ts","sourceRoot":"","sources":["../../../../src/client/pages/CaptureBuilderPage.tsx"],"names":[],"mappings":"AAmNA,wBAAgB,kBAAkB,4CA0jDjC"}
@@ -908,6 +908,7 @@ export function CaptureBuilderPage() {
908
908
  const rows = (submissionsQuery.data ?? []);
909
909
  return id ? rows.filter((submission) => submission.definitionId === id) : rows;
910
910
  }, [id, submissionsQuery.data]);
911
+ const publicationId = definitionQuery.data?.publicationId ?? undefined;
911
912
  const publicationSlug = definitionQuery.data?.publicationSlug ?? undefined;
912
913
  const formStatus = definitionQuery.data?.status ?? definitionsQuery.data?.find((definition) => definition.id === id)?.status ?? "draft";
913
914
  const publicPath = publicationSlug ? `/forms/${publicationSlug}` : null;
@@ -1173,7 +1174,7 @@ export function CaptureBuilderPage() {
1173
1174
  setActiveLandingDetailTab("overview");
1174
1175
  }, onCloseDetails: () => setSelectedLandingDefinition(null), onDetailTabChange: setActiveLandingDetailTab, onCreate: () => createMutation.mutate({ name: newFormName }), isCreating: isCreating, onOpen: openDefinition, onTagsChange: (definitionId, tags) => updateTagsMutation.mutate({ id: definitionId, tags }), workflows: workflowsQuery.data ?? [], workflowsLoading: workflowsQuery.isLoading, workflowsError: workflowsQuery.isError, onRetryWorkflows: () => void workflowsQuery.refetch(), contactCustomFields: (contactCustomFieldsQuery.data ?? []), contactCustomFieldsLoading: contactCustomFieldsQuery.isLoading, contactCustomFieldsError: contactCustomFieldsQuery.isError, onRetryContactCustomFields: () => void contactCustomFieldsQuery.refetch(), onActionConfigChange: (definitionId, actionConfig) => updateActionConfigMutation.mutate({ id: definitionId, actionConfig }), isActionConfigSaving: updateActionConfigMutation.isPending })) : definitionQuery.isLoading ? (_jsx(BuilderWorkspaceSkeleton, {})) : definitionQuery.isError || !definitionQuery.data ? (_jsx(QueryErrorState, { title: "Could not load this form", description: "The form may have moved, been deleted, or failed to load. Try again or return to Capture Items.", onRetry: () => void definitionQuery.refetch() })) : (_jsx(_Fragment, { children: builderSubView === "build" ? (_jsxs("div", { className: "flex min-h-0 flex-1 gap-4", children: [_jsx("section", { className: "min-h-0 min-w-0 flex-1 overflow-auto p-4", children: _jsxs("div", { className: "flex min-h-[560px] items-center justify-center gap-3", children: [_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-9 w-9 shrink-0 rounded-full bg-background/90 shadow-sm", onClick: goToPreviousPage, disabled: currentPageIndex === 0, "aria-label": "Previous page", title: "Previous page", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) }), _jsx("div", { className: cn("flex min-h-[560px] flex-1 flex-col rounded-[2rem] border border-border bg-card p-4 shadow-sm transition", previewDevice === "mobile" ? "max-w-sm" : "max-w-3xl"), onDragEnter: currentPageItems.length === 0 ? handleDragOver : undefined, onDragOver: currentPageItems.length === 0 ? handleDragOver : undefined, onDrop: currentPageItems.length === 0 ? handleDrop : undefined, "data-testid": "capture-builder-canvas", children: _jsx(CaptureFormSurface, { title: formName || "Untitled form", pages: sortedPages, items: formDocument.items, currentPageId: currentPage?.id ?? currentPageId, fieldTypes: fieldTypes, mode: "builder", selectedItemId: selectedId, selectedItemIds: selectedItemIds, className: "flex min-h-full flex-1 flex-col gap-4 space-y-0", onSelectItem: handleCanvasItemSelect, onReorderItem: reorderItems, paletteDragTypes: [CAPTURE_BUILDER_DRAG_TYPE, CAPTURE_BUILDER_CONTENT_DRAG_TYPE], onPaletteDrop: insertPaletteItemAt, emptyContent: (_jsxs("div", { className: "flex flex-1 flex-col items-center justify-center rounded-xl border border-dashed border-border bg-muted/25 p-8 text-center", children: [_jsx(Plus, { className: "mb-3 h-8 w-8 text-muted-foreground" }), _jsx("h4", { className: "text-sm font-semibold text-foreground", children: "Add the first item to this page" }), _jsxs("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: ["Use the sidebar palette to add fields or explainer text to ", currentPage?.title ?? "the selected page", "."] })] })), footer: sortedPages.length > 1 ? (_jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs(Button, { type: "button", variant: "outline", className: "h-11 rounded-xl sm:w-auto", disabled: currentPageIndex === 0, onClick: goToPreviousPage, children: [_jsx(ArrowLeft, { className: "h-4 w-4" }), "Back"] }), _jsxs(Button, { type: "button", className: "h-11 rounded-xl sm:w-auto", disabled: currentPageIndex >= sortedPages.length - 1, onClick: goToNextPage, children: ["Next", _jsx(ArrowRight, { className: "h-4 w-4" })] })] })) : null }) }), _jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-9 w-9 shrink-0 rounded-full bg-background/90 shadow-sm", onClick: currentPageIndex >= sortedPages.length - 1 ? addPage : goToNextPage, "aria-label": currentPageIndex >= sortedPages.length - 1 ? "Add page" : "Next page", title: currentPageIndex >= sortedPages.length - 1 ? "Add page" : "Next page", children: currentPageIndex >= sortedPages.length - 1 ? _jsx(Plus, { className: "h-4 w-4" }) : _jsx(ChevronRight, { className: "h-4 w-4" }) })] }) }), _jsx(TabbedPanel, { open: detailsOpen, onClose: () => setDetailsOpen(false), tabs: formPanelTabs, activeTab: activePanel, onTabChange: setActivePanel, width: "380px", inline: true, flush: true, className: "self-stretch rounded-2xl border shadow-sm", header: _jsxs("div", { className: "border-b border-border px-4 py-3", children: [_jsx("h2", { className: "text-sm font-semibold text-foreground", children: detailsPanelTitle }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: activePanel === "validation"
1175
1176
  ? "When the validation expression matches, respondents are blocked and see the failure message."
1176
- : "Builder context and selected-field controls." })] }), footer: selectedItemDeleteLabel ? (_jsx("div", { className: "border-t border-border p-3", children: _jsx(DeleteSelectedItemButton, { onDelete: deleteSelectedItem, label: selectedItemDeleteLabel }) })) : null, children: _jsx(FormDetailsPanel, { activePanel: activePanel, pages: sortedPages, items: formDocument.items, currentPage: currentPage, selectedPage: selectedPage, fieldTypes: fieldTypes, selectedField: selectedField, selectedTextBlock: selectedTextBlock, selectedIconBlock: selectedIconBlock, selectedImageBlock: selectedImageBlock, selectedDivider: selectedDivider, selectedPageHeader: selectedPageHeader, selectedPageProgress: selectedPageProgress, selectedId: selectedId, selectedItemIds: selectedItemIds, savedFieldIds: savedFieldIds, selectedFieldKeyDuplicate: selectedFieldKeyDuplicate, onSelectItem: handleCanvasItemSelect, onOpenInspector: (itemId) => { setSingleSelectedItem(itemId); setActivePanel("inspector"); setDetailsOpen(true); }, onSelectPage: selectPageForInspection, updateSelectedField: updateSelectedField, updateSelectedTextBlock: updateSelectedTextBlock, updateSelectedIconBlock: updateSelectedIconBlock, updateSelectedImageBlock: updateSelectedImageBlock, updateSelectedDivider: updateSelectedDivider, updateSelectedPageHeader: updateSelectedPageHeader, updateSelectedPageProgress: updateSelectedPageProgress, updateCurrentPage: updateCurrentPage, deleteCurrentPage: deleteCurrentPage }) })] })) : builderSubView === "submissions" ? (_jsx(BuilderSubmissionsView, { submissions: definitionSubmissions, fields: submissionFields, columns: submissionColumns, filters: submissionFilters, sort: submissionSort, onFiltersChange: setSubmissionFilters, onSortChange: setSubmissionSort, onOpenColumns: () => setActiveSubmissionPanel("columns"), isLoading: submissionsQuery.isLoading, isError: submissionsQuery.isError, onRetry: () => void submissionsQuery.refetch() })) : (_jsx(BuilderShareView, { publicationSlug: publicationSlug, onCopy: copyToClipboard })) })) }), _jsx(TabbedPanel, { open: builderSubView === "submissions" && activeSubmissionPanel != null, onClose: () => setActiveSubmissionPanel(null), tabs: [
1177
+ : "Builder context and selected-field controls." })] }), footer: selectedItemDeleteLabel ? (_jsx("div", { className: "border-t border-border p-3", children: _jsx(DeleteSelectedItemButton, { onDelete: deleteSelectedItem, label: selectedItemDeleteLabel }) })) : null, children: _jsx(FormDetailsPanel, { activePanel: activePanel, pages: sortedPages, items: formDocument.items, currentPage: currentPage, selectedPage: selectedPage, fieldTypes: fieldTypes, selectedField: selectedField, selectedTextBlock: selectedTextBlock, selectedIconBlock: selectedIconBlock, selectedImageBlock: selectedImageBlock, selectedDivider: selectedDivider, selectedPageHeader: selectedPageHeader, selectedPageProgress: selectedPageProgress, selectedId: selectedId, selectedItemIds: selectedItemIds, savedFieldIds: savedFieldIds, selectedFieldKeyDuplicate: selectedFieldKeyDuplicate, onSelectItem: handleCanvasItemSelect, onOpenInspector: (itemId) => { setSingleSelectedItem(itemId); setActivePanel("inspector"); setDetailsOpen(true); }, onSelectPage: selectPageForInspection, updateSelectedField: updateSelectedField, updateSelectedTextBlock: updateSelectedTextBlock, updateSelectedIconBlock: updateSelectedIconBlock, updateSelectedImageBlock: updateSelectedImageBlock, updateSelectedDivider: updateSelectedDivider, updateSelectedPageHeader: updateSelectedPageHeader, updateSelectedPageProgress: updateSelectedPageProgress, updateCurrentPage: updateCurrentPage, deleteCurrentPage: deleteCurrentPage }) })] })) : builderSubView === "submissions" ? (_jsx(BuilderSubmissionsView, { submissions: definitionSubmissions, fields: submissionFields, columns: submissionColumns, filters: submissionFilters, sort: submissionSort, onFiltersChange: setSubmissionFilters, onSortChange: setSubmissionSort, onOpenColumns: () => setActiveSubmissionPanel("columns"), isLoading: submissionsQuery.isLoading, isError: submissionsQuery.isError, onRetry: () => void submissionsQuery.refetch() })) : (_jsx(BuilderShareView, { publicationId: publicationId, publicationSlug: publicationSlug, onCopy: copyToClipboard })) })) }), _jsx(TabbedPanel, { open: builderSubView === "submissions" && activeSubmissionPanel != null, onClose: () => setActiveSubmissionPanel(null), tabs: [
1177
1178
  { id: "details", icon: Settings2, label: "View details" },
1178
1179
  { id: "filters", icon: Filter, label: "Filters" },
1179
1180
  { id: "columns", icon: Columns3, label: "Columns" },
@@ -1406,16 +1407,50 @@ function BuilderSubmissionsSkeleton() {
1406
1407
  function BuilderSubmissionsEmptyState() {
1407
1408
  return (_jsxs("div", { className: "flex min-h-[320px] flex-col items-center justify-center rounded-2xl border border-dashed border-border bg-muted/25 p-8 text-center", children: [_jsx(Inbox, { className: "mb-3 h-10 w-10 text-muted-foreground/60" }), _jsx("h3", { className: "text-sm font-semibold text-foreground", children: "No submissions yet" }), _jsx("p", { className: "mt-1 max-w-md text-sm text-muted-foreground", children: "Once this form is published and respondents submit answers, they will appear here for review." })] }));
1408
1409
  }
1409
- function BuilderShareView({ publicationSlug, onCopy, }) {
1410
+ function BuilderShareView({ publicationId, publicationSlug, onCopy, }) {
1410
1411
  const publicPath = publicationSlug ? `/forms/${publicationSlug}` : null;
1411
- const embedPath = publicationSlug ? `/forms/embed/${publicationSlug}` : null;
1412
+ const embedPath = publicationId ? `/forms/embed/${publicationId}` : null;
1412
1413
  const publicUrl = publicPath ? buildPublicUrl(publicPath) : null;
1413
1414
  const embedUrl = embedPath ? buildPublicUrl(embedPath) : null;
1415
+ const productionBaseUrl = "https://ydtb.app";
1416
+ const sdkInstallSnippet = "npm install @ydtb/public-sdk @ydtb/public-capture react";
1417
+ const sdkComponentSnippet = publicationId ? `import { CaptureForm } from "@ydtb/public-capture/react"
1418
+
1419
+ export function YdtbCaptureForm() {
1420
+ return (
1421
+ <CaptureForm
1422
+ apiBaseUrl="${productionBaseUrl}"
1423
+ lookup={{ publishId: "${publicationId}" }}
1424
+ source="external"
1425
+ />
1426
+ )
1427
+ }` : null;
1428
+ const sdkCompactSnippet = publicationId ? `import { CaptureForm } from "@ydtb/public-capture/react"
1429
+
1430
+ export function NewsletterSignup() {
1431
+ return (
1432
+ <CaptureForm
1433
+ apiBaseUrl="${productionBaseUrl}"
1434
+ lookup={{ publishId: "${publicationId}" }}
1435
+ source="external"
1436
+ variant="inline"
1437
+ submitLabel="Join"
1438
+ placeholder="you@example.com"
1439
+ classNames={{
1440
+ form: "flex gap-2",
1441
+ input: "min-w-0 flex-1 rounded-xl border px-4 py-3",
1442
+ button: "rounded-xl px-6 py-3 font-semibold",
1443
+ error: "basis-full text-sm"
1444
+ }}
1445
+ />
1446
+ )
1447
+ }` : null;
1448
+ const sdkCompactInstallSnippet = "npm install @ydtb/public-sdk @ydtb/public-capture react";
1414
1449
  const iframeSnippet = embedUrl ? `<iframe src="${embedUrl}" title="Capture form" style="width:100%;min-height:640px;border:0;"></iframe>` : null;
1415
- if (!publicationSlug) {
1450
+ if (!publicationSlug || !publicationId) {
1416
1451
  return (_jsx("section", { className: "min-h-0 flex-1 overflow-auto", children: _jsxs("div", { className: "flex min-h-[360px] flex-col items-center justify-center rounded-2xl border border-dashed border-border bg-muted/25 p-8 text-center", children: [_jsx(AlertCircle, { className: "mb-3 h-10 w-10 text-muted-foreground/60" }), _jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Publish to enable sharing" }), _jsx("p", { className: "mt-1 max-w-md text-sm text-muted-foreground", children: "Public links and embed snippets are created after this form is published. Use Publish in the page header when the form is ready." })] }) }));
1417
1452
  }
1418
- return (_jsx("section", { className: "min-h-0 flex-1 overflow-auto", children: _jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [_jsxs("div", { className: "rounded-xl border border-border bg-card p-4 shadow-sm", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Direct public link" }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Share this respondent-safe public form route." })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [publicUrl && (_jsxs(Button, { variant: "outline", size: "sm", type: "button", onClick: () => void onCopy(publicUrl, "Public link"), children: [_jsx(Copy, { className: "h-4 w-4" }), "Copy"] })), publicPath && (_jsx(Button, { variant: "outline", size: "icon", type: "button", asChild: true, "aria-label": "Open public form", children: _jsx("a", { href: publicPath, target: "_blank", rel: "noreferrer", children: _jsx(ExternalLink, { className: "h-4 w-4" }) }) }))] })] }), publicUrl && (_jsx("p", { className: "mt-3 break-all rounded-lg bg-muted/50 px-3 py-2 font-mono text-xs text-muted-foreground", children: publicUrl }))] }), _jsxs("div", { className: "rounded-xl border border-border bg-card p-4 shadow-sm", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Iframe embed" }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Embed the public form in an external page with the current public embed route." })] }), iframeSnippet && (_jsxs(Button, { variant: "outline", size: "sm", type: "button", onClick: () => void onCopy(iframeSnippet, "Embed snippet"), children: [_jsx(Copy, { className: "h-4 w-4" }), "Copy"] }))] }), iframeSnippet && (_jsx("pre", { className: "mt-3 overflow-auto rounded-lg bg-muted/50 p-3 text-xs text-muted-foreground", children: _jsx("code", { children: iframeSnippet }) }))] }), _jsxs("div", { className: "rounded-xl border border-dashed border-border bg-muted/25 p-4", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Tag / script snippet" }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Not available yet. Capture currently exposes direct public and iframe routes only; tag-based embeds need a separate product protocol." })] }), _jsxs("div", { className: "rounded-xl border border-dashed border-border bg-muted/25 p-4", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Embed constraints" }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Allowed-origin controls and advanced completion behavior are not configured in this slice. Treat the iframe snippet as the current public embed mode." })] })] }) }));
1453
+ return (_jsx("section", { className: "min-h-0 flex-1 overflow-auto", children: _jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [_jsxs("div", { className: "rounded-xl border border-border bg-card p-4 shadow-sm", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Direct public link" }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Share this respondent-safe public form route." })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [publicUrl && (_jsxs(Button, { variant: "outline", size: "sm", type: "button", onClick: () => void onCopy(publicUrl, "Public link"), children: [_jsx(Copy, { className: "h-4 w-4" }), "Copy"] })), publicPath && (_jsx(Button, { variant: "outline", size: "icon", type: "button", asChild: true, "aria-label": "Open public form", children: _jsx("a", { href: publicPath, target: "_blank", rel: "noreferrer", children: _jsx(ExternalLink, { className: "h-4 w-4" }) }) }))] })] }), publicUrl && (_jsx("p", { className: "mt-3 break-all rounded-lg bg-muted/50 px-3 py-2 font-mono text-xs text-muted-foreground", children: publicUrl }))] }), _jsxs("div", { className: "rounded-xl border border-border bg-card p-4 shadow-sm", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Iframe embed" }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Embed the public form in an external page with the current public embed route." })] }), iframeSnippet && (_jsxs(Button, { variant: "outline", size: "sm", type: "button", onClick: () => void onCopy(iframeSnippet, "Embed snippet"), children: [_jsx(Copy, { className: "h-4 w-4" }), "Copy"] }))] }), iframeSnippet && (_jsx("pre", { className: "mt-3 overflow-auto rounded-lg bg-muted/50 p-3 text-xs text-muted-foreground", children: _jsx("code", { children: iframeSnippet }) }))] }), _jsxs("div", { className: "rounded-xl border border-border bg-card p-4 shadow-sm lg:col-span-2", children: [_jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "React SDK / external app" }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Use this in Replit, Lovable, or a custom React site. No scope id is needed \u2014 the publish id resolves the form and owning scope on YDTB." })] }), _jsxs("div", { className: "flex shrink-0 flex-wrap gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", type: "button", onClick: () => void onCopy(sdkInstallSnippet, "SDK install command"), children: [_jsx(Copy, { className: "h-4 w-4" }), "Copy install"] }), sdkComponentSnippet && (_jsxs(Button, { variant: "outline", size: "sm", type: "button", onClick: () => void onCopy(sdkComponentSnippet, "SDK component snippet"), children: [_jsx(Copy, { className: "h-4 w-4" }), "Copy component"] })), sdkCompactSnippet && (_jsxs(Button, { variant: "outline", size: "sm", type: "button", onClick: () => void onCopy(sdkCompactSnippet, "Compact opt-in snippet"), children: [_jsx(Copy, { className: "h-4 w-4" }), "Copy opt-in"] }))] })] }), _jsxs("div", { className: "mt-3 grid gap-3 lg:grid-cols-[minmax(0,0.7fr)_minmax(0,1.3fr)]", children: [_jsxs("div", { className: "space-y-2 rounded-lg bg-muted/50 p-3 text-xs text-muted-foreground", children: [_jsxs("p", { children: [_jsx("span", { className: "font-semibold text-foreground", children: "Production API:" }), " ", _jsx("span", { className: "font-mono", children: productionBaseUrl })] }), _jsxs("p", { children: [_jsx("span", { className: "font-semibold text-foreground", children: "Publish ID:" }), " ", _jsx("span", { className: "font-mono", children: publicationId })] }), _jsx("p", { className: "leading-5", children: "Backend routing resolves the owning scope from this public publication. Do not expose or send internal scope ids from the external page." })] }), sdkComponentSnippet && (_jsx("pre", { className: "overflow-auto rounded-lg bg-muted/50 p-3 text-xs text-muted-foreground", children: _jsxs("code", { children: [sdkInstallSnippet, "\n\n", sdkComponentSnippet, sdkCompactSnippet ? "\n\n// Compact one-line opt-in\n" : "", sdkCompactSnippet ? sdkCompactInstallSnippet + "\n\n" + sdkCompactSnippet : ""] }) }))] })] }), _jsxs("div", { className: "rounded-xl border border-dashed border-border bg-muted/25 p-4", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Embed constraints" }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Allowed-origin controls and advanced completion behavior are not configured in this slice. Treat the iframe snippet as the current public embed mode." })] })] }) }));
1419
1454
  }
1420
1455
  function buildPublicUrl(path) {
1421
1456
  if (typeof window === "undefined")