@agent-native/core 0.192.0 → 0.192.1-nightly-20260926144920
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/corpus/README.md +1 -1
- package/corpus/templates/calendar/actions/cancel-booking.ts +12 -4
- package/corpus/templates/calendar/actions/list-bookings.ts +23 -2
- package/corpus/templates/calendar/actions/list-events.ts +42 -29
- package/corpus/templates/calendar/actions/update-booking-link.ts +27 -1
- package/corpus/templates/calendar/app/hooks/use-bookings.ts +9 -2
- package/corpus/templates/calendar/app/i18n/en-US.ts +8 -0
- package/corpus/templates/calendar/app/lib/booking-sorting.ts +7 -0
- package/corpus/templates/calendar/app/lib/event-colors.ts +29 -4
- package/corpus/templates/calendar/app/pages/BookingsList.tsx +99 -19
- package/corpus/templates/calendar/app/pages/CalendarView.tsx +5 -11
- package/corpus/templates/calendar/app/pages/ManageBookingPage.tsx +5 -0
- package/corpus/templates/calendar/changelog/2026-09-25-ambiguous-zoom-bookings-need-review.md +6 -0
- package/corpus/templates/calendar/changelog/2026-09-25-bookings-list-shows-newest-bookings-first.md +6 -0
- package/corpus/templates/calendar/changelog/2026-09-25-canceling-a-booking-now-resolves-its-zoom-meeting-first.md +6 -0
- package/corpus/templates/calendar/changelog/2026-09-25-colleague-events-use-sidebar-colors.md +6 -0
- package/corpus/templates/calendar/changelog/2026-09-25-public-booking-pages-reject-malformed-meeting-settings-befor.md +6 -0
- package/corpus/templates/calendar/changelog/2026-09-25-shared-booking-cancellations-require-editor-access-and-unres.md +6 -0
- package/corpus/templates/calendar/server/db/schema.ts +5 -0
- package/corpus/templates/calendar/server/handlers/availability.ts +32 -29
- package/corpus/templates/calendar/server/handlers/bookings.ts +189 -62
- package/corpus/templates/calendar/server/lib/booking-link-utils.ts +46 -1
- package/corpus/templates/calendar/server/lib/zoom.ts +66 -1
- package/corpus/templates/calendar/server/plugins/db.ts +13 -0
- package/corpus/templates/calendar/shared/api.ts +4 -0
- package/corpus/templates/clips/app/components/capture-install-options.tsx +9 -6
- package/corpus/templates/clips/app/components/clips-command-menu.tsx +4 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +5 -4
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +4 -0
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +7 -33
- package/corpus/templates/clips/changelog/2026-09-26-desktop-platform-icon.md +6 -0
- package/corpus/templates/clips/changelog/2026-09-26-the-empty-comments-state-now-explains-how-screen-recordings-.md +6 -0
- package/corpus/templates/clips/changelog/2026-09-26-the-empty-comments-view-has-a-clearer-headline-and-a-focused.md +6 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +26 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +74 -40
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +64 -42
- package/corpus/templates/design/app/components/design/design-canvas/creation.ts +1 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +5 -2
- package/corpus/templates/design/app/pages/design-editor/commands/duplicate-screen.ts +56 -25
- package/corpus/templates/design/app/routes/design-systems.tsx +2 -4
- package/corpus/templates/design/app/routes/design.$id.tsx +2 -1
- package/corpus/templates/design/app/routes/public-design-meta.ts +0 -39
- package/corpus/templates/design/app/routes/templates.tsx +2 -4
- package/corpus/templates/design/app/routes/visual-edit_.$id.tsx +2 -1
- package/corpus/templates/design/changelog/2026-09-25-escape-finishes-open-pen-paths.md +7 -0
- package/corpus/templates/design/changelog/2026-09-25-pen-paths-remain-available-after-save-failures-and-retries-k.md +6 -0
- package/corpus/templates/design/changelog/2026-09-25-pen-retries-keep-extending-the-selected-vector-after-a-save-.md +6 -0
- package/corpus/templates/design/changelog/2026-09-25-pressing-enter-finishes-a-new-pen-path-and-selects-its-vector-on-move.md +6 -0
- package/corpus/templates/design/changelog/2026-09-26-cmd-d-places-screen-duplicates-in-the-next-open-slot.md +6 -0
- package/corpus/templates/design/changelog/2026-09-26-dropping-a-layer-beside-a-sibling-keeps-that-insertion-point.md +6 -0
- package/corpus/templates/design/changelog/2026-09-26-layers-dragged-out-of-frames-now-land-at-the-board-level-and.md +6 -0
- package/corpus/templates/design/changelog/2026-09-26-opening-shared-designs-no-longer-fails-during-client-startup.md +6 -0
- package/corpus/templates/design/package.json +1 -1
- package/corpus/templates/design/scripts/check-client-server-boundary.ts +55 -0
- package/corpus/templates/design/server/lib/public-design-meta.server.ts +40 -0
- package/corpus/templates/mail/app/components/email/EmailListItem.tsx +11 -9
- package/corpus/templates/mail/app/components/email/EmailThread.tsx +9 -1
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
- package/corpus/templates/mail/app/components/settings/AiFilterSection.tsx +25 -2
- package/corpus/templates/mail/app/hooks/use-emails.ts +159 -27
- package/corpus/templates/mail/app/i18n/en-US.ts +2 -1
- package/corpus/templates/mail/app/lib/label-display.ts +6 -0
- package/corpus/templates/mail/app/pages/InboxPage.tsx +5 -0
- package/corpus/templates/mail/changelog/2026-09-26-fixed-importance-actions-label-display-and-triage-loading-fe.md +6 -0
- package/corpus/templates/mail/changelog/2026-09-26-mail-cancels-stale-thread-read-cooldown-retries-after-a-newe.md +6 -0
- package/corpus/templates/mail/server/lib/google-api.ts +12 -7
- package/corpus/templates/slides/app/i18n/en-US.ts +0 -1
- package/corpus/templates/slides/app/pages/Index.tsx +1 -29
- package/corpus/templates/slides/changelog/2026-09-26-create-decks-from-the-prompt-without-a-separate-new-deck-button.md +6 -0
- package/corpus/templates/tasks/.agents/skills/agent-watchdog/SKILL.md +7 -2
- package/dist/client/settings/UsageSection.js +18 -5
- package/dist/client/settings/recent-prompt-groups.d.ts +12 -0
- package/dist/client/settings/recent-prompt-groups.js +20 -0
- package/dist/client/use-action.js +7 -0
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/action-routes.js +25 -2
- package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
- package/package.json +3 -3
|
@@ -222,6 +222,19 @@ CREATE INDEX IF NOT EXISTS idx_bookings_slug_start ON bookings (slug, "start");`
|
|
|
222
222
|
name: "bookings-meeting-link-pending",
|
|
223
223
|
sql: `ALTER TABLE bookings ADD COLUMN IF NOT EXISTS meeting_link_pending BOOLEAN NOT NULL DEFAULT false`,
|
|
224
224
|
},
|
|
225
|
+
{
|
|
226
|
+
version: 25,
|
|
227
|
+
name: "bookings-zoom-needs-review",
|
|
228
|
+
sql: `ALTER TABLE bookings ADD COLUMN IF NOT EXISTS zoom_needs_review BOOLEAN NOT NULL DEFAULT false`,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
version: 26,
|
|
232
|
+
name: "bookings-zoom-provider-identifiers",
|
|
233
|
+
sql: `
|
|
234
|
+
ALTER TABLE bookings ADD COLUMN IF NOT EXISTS zoom_meeting_id TEXT;
|
|
235
|
+
ALTER TABLE bookings ADD COLUMN IF NOT EXISTS zoom_account_id TEXT;
|
|
236
|
+
`,
|
|
237
|
+
},
|
|
225
238
|
],
|
|
226
239
|
{ table: "calendar_migrations" },
|
|
227
240
|
);
|
|
@@ -407,6 +407,10 @@ export interface Booking {
|
|
|
407
407
|
googleEventId?: string;
|
|
408
408
|
/** Token for cancel/reschedule link (only returned to the booker) */
|
|
409
409
|
cancelToken?: string;
|
|
410
|
+
/** Zoom may have created the meeting even though its booking request failed. */
|
|
411
|
+
zoomNeedsReview?: boolean;
|
|
412
|
+
/** Cancellation requires a manual Zoom check because no provider ID was saved. */
|
|
413
|
+
zoomCancellationNeedsReview?: boolean;
|
|
410
414
|
status: "confirmed" | "cancelled";
|
|
411
415
|
createdAt: string;
|
|
412
416
|
}
|
|
@@ -80,10 +80,16 @@ function desktopOsIcon(): typeof IconDeviceDesktop {
|
|
|
80
80
|
return IconDeviceDesktop;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
const subscribeToDesktopPlatform = () => () => undefined;
|
|
84
|
+
|
|
83
85
|
export function DesktopPlatformIcon(
|
|
84
86
|
props: ComponentProps<typeof IconDeviceDesktop>,
|
|
85
87
|
) {
|
|
86
|
-
const DesktopIcon =
|
|
88
|
+
const DesktopIcon = useSyncExternalStore(
|
|
89
|
+
subscribeToDesktopPlatform,
|
|
90
|
+
desktopOsIcon,
|
|
91
|
+
() => IconDeviceDesktop,
|
|
92
|
+
);
|
|
87
93
|
return <DesktopIcon {...props} />;
|
|
88
94
|
}
|
|
89
95
|
|
|
@@ -198,11 +204,6 @@ export function CaptureInstallButton({
|
|
|
198
204
|
);
|
|
199
205
|
}
|
|
200
206
|
|
|
201
|
-
/**
|
|
202
|
-
* Compact recorder CTA for the web capture surface. Keep the trigger as plain
|
|
203
|
-
* text so the action reads like a source choice; install destinations belong
|
|
204
|
-
* in the menu rather than in a platform-specific icon treatment.
|
|
205
|
-
*/
|
|
206
207
|
export function CaptureInstallMenu({
|
|
207
208
|
children,
|
|
208
209
|
className,
|
|
@@ -229,6 +230,7 @@ export function CaptureInstallMenu({
|
|
|
229
230
|
attemptOpenDesktopApp(desktopHref);
|
|
230
231
|
}}
|
|
231
232
|
>
|
|
233
|
+
<DesktopPlatformIcon aria-hidden="true" className="size-4" />
|
|
232
234
|
{children}
|
|
233
235
|
</Button>
|
|
234
236
|
);
|
|
@@ -243,6 +245,7 @@ export function CaptureInstallMenu({
|
|
|
243
245
|
variant={variant}
|
|
244
246
|
{...buttonProps}
|
|
245
247
|
>
|
|
248
|
+
<DesktopPlatformIcon aria-hidden="true" className="size-4" />
|
|
246
249
|
{children}
|
|
247
250
|
<IconChevronDown className="size-3.5" />
|
|
248
251
|
</Button>
|
|
@@ -451,6 +451,10 @@ export function ClipsCommandMenu({
|
|
|
451
451
|
"The no-comments sidebar gives viewers a concise reason to try Clips and a clear path to sign up.",
|
|
452
452
|
)
|
|
453
453
|
.join(t("settings.changelogCommentSignup"))
|
|
454
|
+
.split(
|
|
455
|
+
"The empty comments state now explains how screen recordings help AI agents.",
|
|
456
|
+
)
|
|
457
|
+
.join(t("settings.changelogCommentsEmptyState"))
|
|
454
458
|
.split(
|
|
455
459
|
'Signed-in viewers who hit an unavailable, expired, or private share link now land in their library instead of the public marketing page when they choose "Go home."',
|
|
456
460
|
)
|
|
@@ -359,10 +359,9 @@ const messages = {
|
|
|
359
359
|
downloadForWindows: "Download for Windows",
|
|
360
360
|
downloadForLinux: "Download for Linux",
|
|
361
361
|
downloadDesktopApp: "Download desktop app",
|
|
362
|
-
commentSignupTitle: "
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
commentSignupDebug: "Capture console errors and failed requests",
|
|
362
|
+
commentSignupTitle: "Screen recordings your AI agent can see and hear",
|
|
363
|
+
commentSignupDescription:
|
|
364
|
+
"Clips is a free and open-source screen recorder for sharing bugs, feedback, and walkthroughs with AI agents.",
|
|
366
365
|
agentEmptyTitle: "Join the conversation",
|
|
367
366
|
agentEmptyDescription:
|
|
368
367
|
"Create a free Clips account to comment, react, and ask about this clip.",
|
|
@@ -755,6 +754,8 @@ const messages = {
|
|
|
755
754
|
changelogEmpty: "No updates yet.",
|
|
756
755
|
changelogCommentSignup:
|
|
757
756
|
"The no-comments sidebar gives viewers a concise reason to try Clips and a clear path to sign up.",
|
|
757
|
+
changelogCommentsEmptyState:
|
|
758
|
+
"The empty comments state now explains how screen recordings help AI agents.",
|
|
758
759
|
changelogShareLink:
|
|
759
760
|
'Signed-in viewers who hit an unavailable, expired, or private share link now land in their library instead of the public marketing page when they choose "Go home."',
|
|
760
761
|
viewAllUpdates: "View all updates",
|
|
@@ -459,6 +459,10 @@ export default function SettingsIndexRoute() {
|
|
|
459
459
|
"The no-comments sidebar gives viewers a concise reason to try Clips and a clear path to sign up.",
|
|
460
460
|
)
|
|
461
461
|
.join(t("settings.changelogCommentSignup"))
|
|
462
|
+
.split(
|
|
463
|
+
"The empty comments state now explains how screen recordings help AI agents.",
|
|
464
|
+
)
|
|
465
|
+
.join(t("settings.changelogCommentsEmptyState"))
|
|
462
466
|
.split(
|
|
463
467
|
'Signed-in viewers who hit an unavailable, expired, or private share link now land in their library instead of the public marketing page when they choose "Go home."',
|
|
464
468
|
)
|
|
@@ -1869,12 +1869,10 @@ export default function ShareRoute() {
|
|
|
1869
1869
|
sessionStatus !== "signing-out" &&
|
|
1870
1870
|
comments.length === 0 ? (
|
|
1871
1871
|
<PublicCommentsEmptyState
|
|
1872
|
-
signInHref={signInHref}
|
|
1873
1872
|
onSignUp={() => {
|
|
1874
1873
|
fireShareCtaClick("signup");
|
|
1875
1874
|
openCreateAccount("comment");
|
|
1876
1875
|
}}
|
|
1877
|
-
onSignIn={() => fireShareCtaClick("signin")}
|
|
1878
1876
|
/>
|
|
1879
1877
|
) : (
|
|
1880
1878
|
<CommentsPanel
|
|
@@ -2054,45 +2052,21 @@ function formatRecordedOn(
|
|
|
2054
2052
|
}).format(date);
|
|
2055
2053
|
}
|
|
2056
2054
|
|
|
2057
|
-
function PublicCommentsEmptyState({
|
|
2058
|
-
signInHref,
|
|
2059
|
-
onSignUp,
|
|
2060
|
-
onSignIn,
|
|
2061
|
-
}: {
|
|
2062
|
-
signInHref: string;
|
|
2063
|
-
onSignUp: () => void;
|
|
2064
|
-
onSignIn: () => void;
|
|
2065
|
-
}) {
|
|
2055
|
+
function PublicCommentsEmptyState({ onSignUp }: { onSignUp: () => void }) {
|
|
2066
2056
|
const t = useT();
|
|
2067
2057
|
|
|
2068
2058
|
return (
|
|
2069
2059
|
<div className="mx-auto flex min-h-0 w-full max-w-sm flex-1 flex-col items-center justify-center gap-4 overflow-y-auto px-5 py-5 text-center">
|
|
2070
|
-
<
|
|
2071
|
-
|
|
2072
|
-
</div>
|
|
2073
|
-
<h2 className="text-base font-semibold tracking-tight">
|
|
2060
|
+
<AgentNativeIcon aria-hidden="true" className="h-5 w-8 text-primary" />
|
|
2061
|
+
<h2 className="text-xl leading-6 font-semibold tracking-tight">
|
|
2074
2062
|
{t("sharePage.commentSignupTitle")}
|
|
2075
2063
|
</h2>
|
|
2076
2064
|
<p className="max-w-xs text-sm leading-5 text-muted-foreground">
|
|
2077
|
-
{t("sharePage.
|
|
2078
|
-
{t("sharePage.commentSignupFeedback")} ·{" "}
|
|
2079
|
-
{t("sharePage.commentSignupDebug")}
|
|
2065
|
+
{t("sharePage.commentSignupDescription")}
|
|
2080
2066
|
</p>
|
|
2081
|
-
<
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
</Button>
|
|
2085
|
-
<p className="text-center text-xs text-muted-foreground">
|
|
2086
|
-
{t("sharePage.agentEmptySignInPrompt")}{" "}
|
|
2087
|
-
<a
|
|
2088
|
-
href={signInHref}
|
|
2089
|
-
onClick={onSignIn}
|
|
2090
|
-
className="font-medium text-foreground underline underline-offset-4 hover:no-underline"
|
|
2091
|
-
>
|
|
2092
|
-
{t("signInPrompt.signIn")}
|
|
2093
|
-
</a>
|
|
2094
|
-
</p>
|
|
2095
|
-
</div>
|
|
2067
|
+
<Button type="button" onClick={onSignUp}>
|
|
2068
|
+
{t("signInPrompt.createAccount")}
|
|
2069
|
+
</Button>
|
|
2096
2070
|
</div>
|
|
2097
2071
|
);
|
|
2098
2072
|
}
|
|
@@ -12641,9 +12641,12 @@ export const editorChromeBridgeScript: string = `"use strict";
|
|
|
12641
12641
|
};
|
|
12642
12642
|
}
|
|
12643
12643
|
}
|
|
12644
|
+
if (pointerOutsideCurrentParent && (!pointHit || pointHit === document.body || pointHit === document.documentElement) && dropContainerForTarget(target) === currentParent) {
|
|
12645
|
+
target = unnestAbsoluteToScreenRoot(el, clientX, clientY) || target;
|
|
12646
|
+
}
|
|
12644
12647
|
var container = dropContainerForTarget(target);
|
|
12645
12648
|
if (ignoreTargetAutoLayout && container && container !== document.body && isAutoLayoutElement(container)) {
|
|
12646
|
-
|
|
12649
|
+
target = {
|
|
12647
12650
|
anchor: container,
|
|
12648
12651
|
placement: "inside",
|
|
12649
12652
|
axis: parentFlowAxis(container),
|
|
@@ -12651,13 +12654,34 @@ export const editorChromeBridgeScript: string = `"use strict";
|
|
|
12651
12654
|
};
|
|
12652
12655
|
}
|
|
12653
12656
|
if (currentParent !== document.body && (container === document.body || container === document.documentElement || target?.anchor === document.body)) {
|
|
12654
|
-
|
|
12657
|
+
target = {
|
|
12655
12658
|
anchor: currentParent,
|
|
12656
12659
|
placement: "after",
|
|
12657
12660
|
axis: "y",
|
|
12658
12661
|
dropMode: "absolute-container"
|
|
12659
12662
|
};
|
|
12660
12663
|
}
|
|
12664
|
+
var exitedContainer = el.parentElement;
|
|
12665
|
+
var receivingContainer = exitedContainer && exitedContainer.parentElement;
|
|
12666
|
+
var targetContainer = dropContainerForTarget(target);
|
|
12667
|
+
if (!ignoreTargetAutoLayout && target && exitedContainer && receivingContainer && isContainerDropTarget(exitedContainer) && targetContainer === receivingContainer && (pointHit === receivingContainer || !pointHit || pointHit === document.body || pointHit === document.documentElement)) {
|
|
12668
|
+
target = {
|
|
12669
|
+
...target,
|
|
12670
|
+
anchor: exitedContainer,
|
|
12671
|
+
placement: "after",
|
|
12672
|
+
axis: parentFlowAxis(receivingContainer),
|
|
12673
|
+
persistenceAnchor: exitedContainer,
|
|
12674
|
+
persistencePlacement: "after",
|
|
12675
|
+
gridCell: void 0,
|
|
12676
|
+
gridPlacement: void 0,
|
|
12677
|
+
gridDisplacement: void 0,
|
|
12678
|
+
gridDisplacementPlacements: void 0,
|
|
12679
|
+
gridDisplacementPrevStyles: void 0,
|
|
12680
|
+
guideRect: void 0,
|
|
12681
|
+
guideMode: void 0,
|
|
12682
|
+
guidePlacement: void 0
|
|
12683
|
+
};
|
|
12684
|
+
}
|
|
12661
12685
|
if (target && target.dropMode === "flow-insert" && container && container !== document.body && isContainerDropTarget(container) && !isAutoLayoutElement(container) && isEmptyDropContainer(container, dragged)) {
|
|
12662
12686
|
target.needsAutoLayoutConversion = true;
|
|
12663
12687
|
target.conversionTarget = container;
|
|
@@ -1129,8 +1129,8 @@ interface DesignCanvasProps {
|
|
|
1129
1129
|
* screen. When set to a non-null tool, DesignCanvas mounts a transparent
|
|
1130
1130
|
* capture overlay above the iframe so pointer gestures draw a new
|
|
1131
1131
|
* primitive instead of reaching the iframe's own content/editor-chrome
|
|
1132
|
-
* bridge. `null`/`undefined`
|
|
1133
|
-
*
|
|
1132
|
+
* bridge. `null`/`undefined` disables pointer capture while keeping a
|
|
1133
|
+
* rejected Pen draft mounted for retry.
|
|
1134
1134
|
*/
|
|
1135
1135
|
activeCreationTool?: CreationTool | null;
|
|
1136
1136
|
selectedPenPathNodeId?: string | null;
|
|
@@ -1143,7 +1143,7 @@ interface DesignCanvasProps {
|
|
|
1143
1143
|
* persisted primitive (see `appendCanvasPrimitiveToHtml` /
|
|
1144
1144
|
* `draftPrimitiveToInsert` on the overview side).
|
|
1145
1145
|
*/
|
|
1146
|
-
onCreatePrimitive?: (spec: CreatePrimitiveSpec) => string | void;
|
|
1146
|
+
onCreatePrimitive?: (spec: CreatePrimitiveSpec) => string | false | void;
|
|
1147
1147
|
onUpdatePenPath?: (
|
|
1148
1148
|
nodeId: string,
|
|
1149
1149
|
path: PenPath,
|
|
@@ -8120,23 +8120,19 @@ export function DesignCanvas({
|
|
|
8120
8120
|
title=""
|
|
8121
8121
|
/>
|
|
8122
8122
|
) : null}
|
|
8123
|
-
{/*
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
onUpdatePenPath={onUpdatePenPath}
|
|
8135
|
-
/>
|
|
8136
|
-
) : null}
|
|
8123
|
+
{/* Keep the overlay mounted while Move is active so a rejected Pen
|
|
8124
|
+
commit remains available to retry; without a creation tool it is
|
|
8125
|
+
transparent to pointer events. */}
|
|
8126
|
+
<SingleScreenCreationOverlay
|
|
8127
|
+
key={screenId}
|
|
8128
|
+
tool={interactMode ? null : (activeCreationTool ?? null)}
|
|
8129
|
+
iframeRef={iframeRef}
|
|
8130
|
+
selectedPenPathNodeId={selectedPenPathNodeId}
|
|
8131
|
+
onCreatePrimitive={onCreatePrimitive}
|
|
8132
|
+
onUpdatePenPath={onUpdatePenPath}
|
|
8133
|
+
/>
|
|
8137
8134
|
{/* OS file drag-over capture overlay — sits over the iframe, NOT
|
|
8138
|
-
inside it
|
|
8139
|
-
just above. Only mounts while a native OS file drag is actually in
|
|
8135
|
+
inside it. Only mounts while a native OS file drag is actually in
|
|
8140
8136
|
progress over this wrapper (see handleWrapperDragEnter/Leave), so it
|
|
8141
8137
|
never changes existing pointer/click behavior otherwise. Skipped
|
|
8142
8138
|
while a creation tool is active — the two capture surfaces would
|
|
@@ -8692,10 +8688,10 @@ interface SingleScreenPenGestureState {
|
|
|
8692
8688
|
const SINGLE_SCREEN_PEN_HIT_RADIUS_PX = 10;
|
|
8693
8689
|
|
|
8694
8690
|
interface SingleScreenCreationOverlayProps {
|
|
8695
|
-
tool: CreationTool;
|
|
8691
|
+
tool: CreationTool | null;
|
|
8696
8692
|
iframeRef: React.RefObject<HTMLIFrameElement | null>;
|
|
8697
8693
|
selectedPenPathNodeId?: string | null;
|
|
8698
|
-
onCreatePrimitive?: (spec: CreatePrimitiveSpec) => string | void;
|
|
8694
|
+
onCreatePrimitive?: (spec: CreatePrimitiveSpec) => string | false | void;
|
|
8699
8695
|
onUpdatePenPath?: (
|
|
8700
8696
|
nodeId: string,
|
|
8701
8697
|
path: PenPath,
|
|
@@ -8843,6 +8839,7 @@ function SingleScreenCreationOverlay({
|
|
|
8843
8839
|
options?: {
|
|
8844
8840
|
preserveActiveTool?: boolean;
|
|
8845
8841
|
continueAfterCommit?: boolean;
|
|
8842
|
+
nextTool?: "move" | "pen";
|
|
8846
8843
|
},
|
|
8847
8844
|
) => {
|
|
8848
8845
|
const committed = path ? clonePenPath(path) : null;
|
|
@@ -8859,7 +8856,6 @@ function SingleScreenCreationOverlay({
|
|
|
8859
8856
|
options?.preserveActiveTool === false ? "move" : undefined,
|
|
8860
8857
|
);
|
|
8861
8858
|
if (!updated) {
|
|
8862
|
-
continuationPenPathRef.current = null;
|
|
8863
8859
|
updatePenPath(committed);
|
|
8864
8860
|
setPenGesturePreview(null);
|
|
8865
8861
|
return;
|
|
@@ -8874,13 +8870,30 @@ function SingleScreenCreationOverlay({
|
|
|
8874
8870
|
return;
|
|
8875
8871
|
}
|
|
8876
8872
|
clearPenPath();
|
|
8877
|
-
const
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
8882
|
-
|
|
8883
|
-
|
|
8873
|
+
const restoreDraft = () => {
|
|
8874
|
+
updatePenPath(committed);
|
|
8875
|
+
setPenGesturePreview(null);
|
|
8876
|
+
setPenPointer(null);
|
|
8877
|
+
setPenCloseHover(false);
|
|
8878
|
+
};
|
|
8879
|
+
let nodeId: string | false | void;
|
|
8880
|
+
try {
|
|
8881
|
+
nodeId = onCreatePrimitive({
|
|
8882
|
+
tool: "pen",
|
|
8883
|
+
points: committed.nodes.map((node) => node.point),
|
|
8884
|
+
penPath: committed,
|
|
8885
|
+
fromClick: false,
|
|
8886
|
+
preserveActiveTool: options?.preserveActiveTool,
|
|
8887
|
+
nextTool: options?.nextTool,
|
|
8888
|
+
});
|
|
8889
|
+
} catch (error) {
|
|
8890
|
+
restoreDraft();
|
|
8891
|
+
throw error;
|
|
8892
|
+
}
|
|
8893
|
+
if (nodeId === false) {
|
|
8894
|
+
restoreDraft();
|
|
8895
|
+
return;
|
|
8896
|
+
}
|
|
8884
8897
|
continuationPenPathRef.current =
|
|
8885
8898
|
typeof nodeId === "string" &&
|
|
8886
8899
|
!committed.closed &&
|
|
@@ -8934,6 +8947,12 @@ function SingleScreenCreationOverlay({
|
|
|
8934
8947
|
finishPenPath(penPathRef.current, { preserveActiveTool: true });
|
|
8935
8948
|
if (!penPathRef.current) continuationPenPathRef.current = null;
|
|
8936
8949
|
}
|
|
8950
|
+
if (!tool) {
|
|
8951
|
+
dragRef.current = null;
|
|
8952
|
+
setDrag(null);
|
|
8953
|
+
setPenPointer(null);
|
|
8954
|
+
setPenCloseHover(false);
|
|
8955
|
+
}
|
|
8937
8956
|
}, [finishPenPath, tool]);
|
|
8938
8957
|
|
|
8939
8958
|
const emit = useCallback(
|
|
@@ -8995,14 +9014,13 @@ function SingleScreenCreationOverlay({
|
|
|
8995
9014
|
|
|
8996
9015
|
const handlePointerDown = useCallback(
|
|
8997
9016
|
(e: React.PointerEvent<HTMLDivElement>) => {
|
|
8998
|
-
if (e.button !== 0) return;
|
|
9017
|
+
if (e.button !== 0 || !tool) return;
|
|
8999
9018
|
if (tool === "pen") {
|
|
9000
9019
|
e.preventDefault();
|
|
9001
9020
|
e.stopPropagation();
|
|
9002
9021
|
seedSelectedPenContinuation();
|
|
9003
|
-
const currentPath = penPathRef.current
|
|
9004
|
-
|
|
9005
|
-
: penPathRef.current;
|
|
9022
|
+
const currentPath = penPathRef.current;
|
|
9023
|
+
if (currentPath?.closed) return;
|
|
9006
9024
|
const pathBefore = currentPath ? clonePenPath(currentPath) : null;
|
|
9007
9025
|
const rawPoint = toContentPoint(e.clientX, e.clientY);
|
|
9008
9026
|
if (!pathBefore && continuationPenPathRef.current) {
|
|
@@ -9244,13 +9262,23 @@ function SingleScreenCreationOverlay({
|
|
|
9244
9262
|
event.preventDefault();
|
|
9245
9263
|
event.stopPropagation();
|
|
9246
9264
|
event.stopImmediatePropagation();
|
|
9247
|
-
if (event.key === "Escape") {
|
|
9265
|
+
if (event.key === "Escape" && penGestureRef.current) {
|
|
9266
|
+
const pathBefore = penGestureRef.current.pathBefore;
|
|
9248
9267
|
clearPenPath();
|
|
9268
|
+
updatePenPath(pathBefore);
|
|
9249
9269
|
return;
|
|
9250
9270
|
}
|
|
9271
|
+
const continuesExistingPath =
|
|
9272
|
+
event.key === "Enter" && continuationPenPathRef.current !== null;
|
|
9251
9273
|
finishPenPath(path, {
|
|
9252
|
-
preserveActiveTool:
|
|
9253
|
-
continueAfterCommit:
|
|
9274
|
+
preserveActiveTool: event.key === "Escape" || continuesExistingPath,
|
|
9275
|
+
continueAfterCommit: continuesExistingPath,
|
|
9276
|
+
nextTool:
|
|
9277
|
+
event.key === "Enter"
|
|
9278
|
+
? continuesExistingPath
|
|
9279
|
+
? "pen"
|
|
9280
|
+
: "move"
|
|
9281
|
+
: undefined,
|
|
9254
9282
|
});
|
|
9255
9283
|
};
|
|
9256
9284
|
|
|
@@ -9258,7 +9286,13 @@ function SingleScreenCreationOverlay({
|
|
|
9258
9286
|
return () => window.removeEventListener("keydown", handleKeyDown, true);
|
|
9259
9287
|
}, [clearPenPath, finishPenPath, tool, updatePenPath]);
|
|
9260
9288
|
|
|
9261
|
-
const cursorClass =
|
|
9289
|
+
const cursorClass =
|
|
9290
|
+
tool === null
|
|
9291
|
+
? "pointer-events-none"
|
|
9292
|
+
: cn(
|
|
9293
|
+
"pointer-events-auto",
|
|
9294
|
+
tool === "text" ? "cursor-text" : "cursor-crosshair",
|
|
9295
|
+
);
|
|
9262
9296
|
const isLineTool = tool === "line" || tool === "arrow";
|
|
9263
9297
|
const displayedPenPath =
|
|
9264
9298
|
penGesturePreview ??
|
|
@@ -9287,7 +9321,7 @@ function SingleScreenCreationOverlay({
|
|
|
9287
9321
|
y: point.y - previewScrollOffset.top,
|
|
9288
9322
|
});
|
|
9289
9323
|
const previewRect =
|
|
9290
|
-
drag && drag.moved && !isLineTool && tool !== "pen"
|
|
9324
|
+
tool && drag && drag.moved && !isLineTool && tool !== "pen"
|
|
9291
9325
|
? getDraftGeometryFromPoints(
|
|
9292
9326
|
toOverlayLocal(drag.startContent),
|
|
9293
9327
|
toOverlayLocal(drag.currentContent),
|
|
@@ -9321,7 +9355,7 @@ function SingleScreenCreationOverlay({
|
|
|
9321
9355
|
ref={penOverlayRef}
|
|
9322
9356
|
data-design-canvas-creation-overlay
|
|
9323
9357
|
data-creation-tool={tool}
|
|
9324
|
-
className={cn("absolute inset-0 z-20
|
|
9358
|
+
className={cn("absolute inset-0 z-20", cursorClass)}
|
|
9325
9359
|
onPointerDown={handlePointerDown}
|
|
9326
9360
|
onPointerMove={handlePointerMove}
|
|
9327
9361
|
onPointerUp={handlePointerUp}
|
|
@@ -9339,7 +9373,7 @@ function SingleScreenCreationOverlay({
|
|
|
9339
9373
|
}
|
|
9340
9374
|
}}
|
|
9341
9375
|
>
|
|
9342
|
-
{
|
|
9376
|
+
{displayedPenPathOverlay ? (
|
|
9343
9377
|
<SingleScreenPenPathOverlay
|
|
9344
9378
|
path={displayedPenPathOverlay}
|
|
9345
9379
|
closeHover={penCloseHover}
|