@agent-native/core 0.84.25 → 0.84.27
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/core/CHANGELOG.md +12 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +4 -2
- package/corpus/core/src/agent/run-manager.ts +4 -3
- package/corpus/core/src/agent/types.ts +9 -2
- package/corpus/core/src/client/AssistantChat.tsx +15 -1
- package/corpus/core/src/client/FeedbackButton.tsx +2 -2
- package/corpus/core/src/client/components/PresenceBar.tsx +7 -2
- package/corpus/core/src/client/composer/ComposerPlusMenu.tsx +23 -9
- package/corpus/core/src/client/sharing/ShareButton.tsx +22 -3
- package/corpus/core/src/client/sharing/ShareDialog.tsx +13 -1
- package/corpus/core/src/client/sse-event-processor.ts +49 -20
- package/corpus/core/src/sharing/actions/set-resource-visibility.ts +3 -3
- package/corpus/templates/design/actions/insert-asset.ts +14 -2
- package/corpus/templates/design/actions/insert-design-native-asset.ts +16 -4
- package/corpus/templates/design/actions/insert-figma-library-asset.ts +14 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +14 -0
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +54 -10
- package/corpus/templates/design/app/components/design/EditPanel.tsx +23 -16
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +7 -2
- package/corpus/templates/design/app/components/design/inspector/InspectorAiActions.tsx +9 -5
- package/corpus/templates/design/app/components/layout/Header.tsx +44 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +267 -105
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +15 -1
- package/corpus/templates/design/app/pages/Index.tsx +20 -9
- package/corpus/templates/design/app/routes/settings.tsx +1 -1
- package/corpus/templates/design/changelog/2026-07-01-design-editor-polish-makes-zoom-assets-sharing-and-agent-handoffs-clearer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-01-design-qa-fixes-make-exports-permissions-and-tools-clearer.md +6 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +4 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +4 -4
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/types.d.ts +3 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +16 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/FeedbackButton.js +2 -2
- package/dist/client/FeedbackButton.js.map +1 -1
- package/dist/client/components/PresenceBar.d.ts.map +1 -1
- package/dist/client/components/PresenceBar.js +6 -2
- package/dist/client/components/PresenceBar.js.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.js +15 -7
- package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
- package/dist/client/sharing/ShareButton.js +15 -2
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/sharing/ShareDialog.js +16 -1
- package/dist/client/sharing/ShareDialog.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +42 -16
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/sharing/actions/set-resource-visibility.js +3 -3
- package/dist/sharing/actions/set-resource-visibility.js.map +1 -1
- package/package.json +1 -1
|
@@ -311,7 +311,7 @@ export function FeedbackButton({ variant = "sidebar", label, url = DEFAULT_FEEDB
|
|
|
311
311
|
trigger = (_jsx(PopoverPrimitive.Trigger, { asChild: true, children: customTrigger }));
|
|
312
312
|
}
|
|
313
313
|
else if (variant === "icon") {
|
|
314
|
-
trigger = (_jsx(TooltipPrimitive.Provider, { delayDuration: 200, children: _jsxs(TooltipPrimitive.Root, { children: [_jsx(TooltipPrimitive.Trigger, { asChild: true, children: _jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": resolvedLabel, className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", className), children: _jsx(IconMessage2, { size: 14 }) }) }) }), _jsx(TooltipPrimitive.Portal, { children: _jsx(TooltipPrimitive.Content, { sideOffset: 6, className: "z-[
|
|
314
|
+
trigger = (_jsx(TooltipPrimitive.Provider, { delayDuration: 200, children: _jsxs(TooltipPrimitive.Root, { children: [_jsx(TooltipPrimitive.Trigger, { asChild: true, children: _jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": resolvedLabel, className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", className), children: _jsx(IconMessage2, { size: 14 }) }) }) }), _jsx(TooltipPrimitive.Portal, { children: _jsx(TooltipPrimitive.Content, { sideOffset: 6, className: "z-[100040] overflow-hidden rounded-md border border-border bg-popover px-2 py-1 text-[11px] text-foreground shadow-md animate-in fade-in-0 zoom-in-95", children: resolvedLabel }) })] }) }));
|
|
315
315
|
}
|
|
316
316
|
else if (variant === "outlined") {
|
|
317
317
|
trigger = (_jsx(PopoverPrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": resolvedLabel, className: cn("flex h-8 items-center gap-2 rounded-md border border-border bg-transparent px-3 text-sm text-muted-foreground transition hover:border-foreground/40 hover:text-foreground", className), children: [_jsx(IconMessage2, { size: 14, stroke: 1.5 }), _jsx("span", { children: resolvedLabel })] }) }));
|
|
@@ -321,7 +321,7 @@ export function FeedbackButton({ variant = "sidebar", label, url = DEFAULT_FEEDB
|
|
|
321
321
|
}
|
|
322
322
|
const resolvedSide = side ?? (variant === "sidebar" ? "top" : "bottom");
|
|
323
323
|
const resolvedPlaceholder = placeholder ?? copy.placeholder;
|
|
324
|
-
return (_jsxs(PopoverPrimitive.Root, { open: open, onOpenChange: setOpen, children: [trigger, _jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { side: resolvedSide, align: align, sideOffset: 8, collisionPadding: 16, className: "z-[
|
|
324
|
+
return (_jsxs(PopoverPrimitive.Root, { open: open, onOpenChange: setOpen, children: [trigger, _jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { side: resolvedSide, align: align, sideOffset: 8, collisionPadding: 16, className: "z-[100040] overflow-hidden rounded-lg border border-border bg-popover shadow-xl outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", style: surfaceStyle, children: submitted ? (_jsxs("div", { className: "flex flex-col items-center justify-center gap-3 px-6 py-10 text-center", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-500", children: _jsx(IconCheck, { size: 20, stroke: 2.5 }) }), _jsx("div", { className: "text-sm font-medium text-foreground", children: copy.success })] })) : (_jsxs("form", { onSubmit: submit, className: "flex flex-col gap-3 p-3", children: [_jsx("textarea", { ref: textareaRef, value: value, onChange: (e) => setValue(e.target.value), onKeyDown: (e) => {
|
|
325
325
|
if ((e.metaKey || e.ctrlKey) && e.key === "Enter")
|
|
326
326
|
submit();
|
|
327
327
|
}, placeholder: resolvedPlaceholder, rows: 5, maxLength: 10000, className: "w-full resize-none rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring" }), _jsx("input", { type: "text", tabIndex: -1, autoComplete: "off", "aria-hidden": "true", value: honeypot, onChange: (e) => setHoneypot(e.target.value), style: honeypotStyle }), _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("div", { className: cn("text-[11px]", error ? "text-destructive" : "text-muted-foreground/75"), children: error ??
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FeedbackButton.js","sourceRoot":"","sources":["../../src/client/FeedbackButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { IconMessage2, IconCheck } from \"@tabler/icons-react\";\nimport {\n useState,\n useEffect,\n useRef,\n useCallback,\n type CSSProperties,\n type FormEvent,\n type ReactNode,\n} from \"react\";\n\nimport { DEFAULT_LOCALE, type LocaleCode } from \"../localization/shared.js\";\nimport { getFeedbackClientContext } from \"./feedback-context.js\";\nimport { useLocale } from \"./i18n.js\";\nimport { useSession } from \"./use-session.js\";\nimport { cn } from \"./utils.js\";\n\nconst DEFAULT_FEEDBACK_URL =\n \"https://forms.agent-native.com/f/agent-native-feedback/_16ewV\";\n\nfunction isSyntheticAgentNativeAnonymousEmail(\n value: string | null | undefined,\n): boolean {\n return /^anon-[^\\s@]+@agent-native\\.com$/i.test(value ?? \"\");\n}\n\ninterface ParsedTarget {\n endpoint: string;\n slug: string;\n}\n\ninterface FormSchema {\n formId: string;\n fieldId: string;\n}\n\nconst FEEDBACK_COPY: Record<\n LocaleCode,\n {\n label: string;\n placeholder: string;\n submit: string;\n submitting: string;\n success: string;\n loadError: string;\n invalidUrl: string;\n emptyError: string;\n sendError: string;\n keyboardHint: string;\n }\n> = {\n \"en-US\": {\n label: \"Feedback\",\n placeholder: \"What's working, what's broken, or what would you change?\",\n submit: \"Send feedback\",\n submitting: \"Sending...\",\n success: \"Thanks for the feedback!\",\n loadError: \"Couldn't load feedback form\",\n invalidUrl: \"Invalid feedback URL\",\n emptyError: \"Please write something first\",\n sendError: \"Couldn't send feedback\",\n keyboardHint: \"{{shortcut}}+Enter to send\",\n },\n \"zh-CN\": {\n label: \"反馈\",\n placeholder: \"哪些地方好用、哪里坏了,或你想改什么?\",\n submit: \"发送反馈\",\n submitting: \"正在发送...\",\n success: \"感谢你的反馈!\",\n loadError: \"无法加载反馈表单\",\n invalidUrl: \"反馈 URL 无效\",\n emptyError: \"请先写点内容\",\n sendError: \"无法发送反馈\",\n keyboardHint: \"{{shortcut}}+Enter 发送\",\n },\n \"zh-TW\": {\n label: \"意見回饋\",\n placeholder: \"哪些地方好用、哪裡壞了,或你想改什麼?\",\n submit: \"送出意見回饋\",\n submitting: \"正在送出...\",\n success: \"感謝你的意見回饋。\",\n loadError: \"無法載入意見回饋表單\",\n invalidUrl: \"意見回饋 URL 無效\",\n emptyError: \"請先輸入內容\",\n sendError: \"無法送出意見回饋\",\n keyboardHint: \"{{shortcut}}+Enter 送出\",\n },\n \"es-ES\": {\n label: \"Comentarios\",\n placeholder: \"¿Qué funciona, qué falla o qué cambiarías?\",\n submit: \"Enviar comentarios\",\n submitting: \"Enviando...\",\n success: \"Gracias por tus comentarios.\",\n loadError: \"No se pudo cargar el formulario\",\n invalidUrl: \"URL de comentarios no válida\",\n emptyError: \"Escribe algo primero\",\n sendError: \"No se pudieron enviar los comentarios\",\n keyboardHint: \"{{shortcut}}+Enter para enviar\",\n },\n \"fr-FR\": {\n label: \"Retour\",\n placeholder: \"Qu'est-ce qui marche, casse ou devrait changer ?\",\n submit: \"Envoyer\",\n submitting: \"Envoi...\",\n success: \"Merci pour votre retour.\",\n loadError: \"Impossible de charger le formulaire\",\n invalidUrl: \"URL de retour invalide\",\n emptyError: \"Écrivez quelque chose d'abord\",\n sendError: \"Impossible d'envoyer le retour\",\n keyboardHint: \"{{shortcut}}+Entrée pour envoyer\",\n },\n \"de-DE\": {\n label: \"Feedback\",\n placeholder: \"Was funktioniert, was ist kaputt, was würdest du ändern?\",\n submit: \"Feedback senden\",\n submitting: \"Wird gesendet...\",\n success: \"Danke für dein Feedback!\",\n loadError: \"Feedback-Formular konnte nicht geladen werden\",\n invalidUrl: \"Ungültige Feedback-URL\",\n emptyError: \"Bitte zuerst etwas schreiben\",\n sendError: \"Feedback konnte nicht gesendet werden\",\n keyboardHint: \"{{shortcut}}+Enter zum Senden\",\n },\n \"ja-JP\": {\n label: \"フィードバック\",\n placeholder: \"良い点、問題点、変更したい点を教えてください。\",\n submit: \"送信\",\n submitting: \"送信中...\",\n success: \"フィードバックありがとうございます。\",\n loadError: \"フォームを読み込めませんでした\",\n invalidUrl: \"フィードバック URL が無効です\",\n emptyError: \"先に内容を入力してください\",\n sendError: \"送信できませんでした\",\n keyboardHint: \"{{shortcut}}+Enter で送信\",\n },\n \"ko-KR\": {\n label: \"피드백\",\n placeholder: \"잘 되는 점, 깨진 점, 바꾸고 싶은 점을 알려주세요.\",\n submit: \"피드백 보내기\",\n submitting: \"보내는 중...\",\n success: \"피드백 감사합니다.\",\n loadError: \"피드백 양식을 불러올 수 없습니다\",\n invalidUrl: \"피드백 URL이 올바르지 않습니다\",\n emptyError: \"먼저 내용을 입력해 주세요\",\n sendError: \"피드백을 보낼 수 없습니다\",\n keyboardHint: \"{{shortcut}}+Enter로 보내기\",\n },\n \"pt-BR\": {\n label: \"Feedback\",\n placeholder: \"O que funciona, quebrou ou você mudaria?\",\n submit: \"Enviar feedback\",\n submitting: \"Enviando...\",\n success: \"Obrigado pelo feedback!\",\n loadError: \"Não foi possível carregar o formulário\",\n invalidUrl: \"URL de feedback inválida\",\n emptyError: \"Escreva algo primeiro\",\n sendError: \"Não foi possível enviar o feedback\",\n keyboardHint: \"{{shortcut}}+Enter para enviar\",\n },\n \"hi-IN\": {\n label: \"फ़ीडबैक\",\n placeholder: \"क्या काम कर रहा है, क्या टूटा है, या आप क्या बदलना चाहेंगे?\",\n submit: \"फ़ीडबैक भेजें\",\n submitting: \"भेजा जा रहा है...\",\n success: \"फ़ीडबैक के लिए धन्यवाद!\",\n loadError: \"फ़ीडबैक फ़ॉर्म लोड नहीं हुआ\",\n invalidUrl: \"फ़ीडबैक URL अमान्य है\",\n emptyError: \"पहले कुछ लिखें\",\n sendError: \"फ़ीडबैक भेजा नहीं जा सका\",\n keyboardHint: \"भेजने के लिए {{shortcut}}+Enter\",\n },\n \"ar-SA\": {\n label: \"ملاحظات\",\n placeholder: \"ما الذي يعمل، وما المعطل، وما الذي تريد تغييره؟\",\n submit: \"إرسال الملاحظات\",\n submitting: \"جار الإرسال...\",\n success: \"شكرا لملاحظاتك!\",\n loadError: \"تعذر تحميل نموذج الملاحظات\",\n invalidUrl: \"رابط الملاحظات غير صالح\",\n emptyError: \"اكتب شيئا أولا\",\n sendError: \"تعذر إرسال الملاحظات\",\n keyboardHint: \"{{shortcut}}+Enter للإرسال\",\n },\n};\n\nfunction parseTarget(url: string): ParsedTarget | null {\n try {\n const u = new URL(url);\n const idx = u.pathname.indexOf(\"/f/\");\n if (idx === -1) return null;\n const slug = u.pathname.slice(idx + 3).replace(/\\/$/, \"\");\n if (!slug) return null;\n return { endpoint: u.origin, slug };\n } catch {\n return null;\n }\n}\n\nconst schemaCache = new Map<string, Promise<FormSchema>>();\n\nasync function loadSchema(target: ParsedTarget): Promise<FormSchema> {\n const key = `${target.endpoint}|${target.slug}`;\n let pending = schemaCache.get(key);\n if (pending) return pending;\n pending = (async () => {\n const res = await fetch(\n `${target.endpoint}/api/forms/public/${encodeURIComponent(target.slug)}`,\n { headers: { Accept: \"application/json\" } },\n );\n if (!res.ok) throw new Error(`form fetch ${res.status}`);\n const body = (await res.json()) as {\n id: string;\n fields: Array<{ id: string; type: string }>;\n };\n const field =\n body.fields.find((f) => f.type === \"textarea\") ??\n body.fields.find((f) => f.type === \"text\") ??\n body.fields[0];\n if (!field) throw new Error(\"form has no fields\");\n return { formId: body.id, fieldId: field.id };\n })();\n pending.catch(() => schemaCache.delete(key));\n schemaCache.set(key, pending);\n return pending;\n}\n\nexport interface FeedbackButtonProps {\n /**\n * \"sidebar\" renders a full-width row with icon + label (for app left sidebars).\n * \"icon\" renders a small icon-only button (for dense toolbars, e.g. the agent panel header).\n * \"outlined\" renders an outlined pill button with icon + label (for top-nav bars, e.g. docs).\n */\n variant?: \"sidebar\" | \"icon\" | \"outlined\";\n label?: string;\n url?: string;\n className?: string;\n /** Which side the popover opens on. Defaults match the variant. */\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\n align?: \"start\" | \"center\" | \"end\";\n /** Placeholder text for the textarea. */\n placeholder?: string;\n /** Current chat session/thread id, when the host already knows it. */\n chatSessionId?: string | null;\n /** Chat localStorage namespace, when the host uses per-app chat storage. */\n chatStorageKey?: string | null;\n /** Controlled popover open state for hosts that trigger feedback from a menu. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Optional custom trigger element. */\n trigger?: ReactNode;\n}\n\nconst surfaceStyle: CSSProperties = {\n width: \"min(380px, calc(100vw - 32px))\",\n};\n\nconst honeypotStyle: CSSProperties = {\n position: \"absolute\",\n left: \"-10000px\",\n top: \"auto\",\n width: \"1px\",\n height: \"1px\",\n overflow: \"hidden\",\n};\n\nexport function FeedbackButton({\n variant = \"sidebar\",\n label,\n url = DEFAULT_FEEDBACK_URL,\n className,\n side,\n align = \"end\",\n placeholder,\n chatSessionId,\n chatStorageKey,\n open: controlledOpen,\n onOpenChange,\n trigger: customTrigger,\n}: FeedbackButtonProps) {\n const target = parseTarget(url);\n const { session } = useSession();\n const { locale } = useLocale();\n const copy = FEEDBACK_COPY[locale] ?? FEEDBACK_COPY[DEFAULT_LOCALE];\n const resolvedLabel = label ?? copy.label;\n\n const [uncontrolledOpen, setUncontrolledOpen] = useState(false);\n const open = controlledOpen ?? uncontrolledOpen;\n const setOpen = useCallback(\n (nextOpen: boolean) => {\n if (controlledOpen === undefined) setUncontrolledOpen(nextOpen);\n onOpenChange?.(nextOpen);\n },\n [controlledOpen, onOpenChange],\n );\n const [value, setValue] = useState(\"\");\n const [honeypot, setHoneypot] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [schema, setSchema] = useState<FormSchema | null>(null);\n const openedAtRef = useRef<number>(0);\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n\n // Reset transient state and kick off schema load on each open.\n useEffect(() => {\n if (!open) return;\n openedAtRef.current = Date.now();\n setValue(\"\");\n setHoneypot(\"\");\n setSubmitting(false);\n setSubmitted(false);\n setError(null);\n setSchema(null);\n if (target) {\n loadSchema(target)\n .then((s) => setSchema(s))\n .catch((err) => {\n console.error(\"[FeedbackButton] schema load failed\", err);\n setError(copy.loadError);\n });\n } else {\n setError(copy.invalidUrl);\n }\n const t = setTimeout(() => textareaRef.current?.focus(), 30);\n return () => {\n clearTimeout(t);\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n };\n }, [open, url]);\n\n const submit = useCallback(\n async (e?: FormEvent) => {\n e?.preventDefault();\n if (!target || submitting) return;\n const trimmed = value.trim();\n if (!trimmed) {\n setError(copy.emptyError);\n return;\n }\n setSubmitting(true);\n setError(null);\n try {\n const resolvedSchema = schema ?? (await loadSchema(target));\n if (!schema) setSchema(resolvedSchema);\n const submitterEmail = isSyntheticAgentNativeAnonymousEmail(\n session?.email,\n )\n ? null\n : session?.email;\n const feedbackContext = getFeedbackClientContext({\n chatSessionId,\n storageKey: chatStorageKey,\n });\n const res = await fetch(\n `${target.endpoint}/api/submit/${encodeURIComponent(resolvedSchema.formId)}`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n data: { [resolvedSchema.fieldId]: trimmed },\n _t: openedAtRef.current,\n _hp: honeypot,\n _meta: {\n ...(submitterEmail ? { submitterEmail } : {}),\n ...feedbackContext,\n },\n }),\n },\n );\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(body.error || `submit failed (${res.status})`);\n }\n setSubmitted(true);\n closeTimerRef.current = setTimeout(() => setOpen(false), 1400);\n } catch (err) {\n setSubmitting(false);\n setError(err instanceof Error ? err.message : copy.sendError);\n }\n },\n [\n target,\n schema,\n value,\n honeypot,\n submitting,\n session?.email,\n chatSessionId,\n chatStorageKey,\n setOpen,\n copy.emptyError,\n copy.sendError,\n ],\n );\n\n let trigger;\n if (customTrigger) {\n trigger = (\n <PopoverPrimitive.Trigger asChild>\n {customTrigger}\n </PopoverPrimitive.Trigger>\n );\n } else if (variant === \"icon\") {\n trigger = (\n <TooltipPrimitive.Provider delayDuration={200}>\n <TooltipPrimitive.Root>\n <TooltipPrimitive.Trigger asChild>\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n aria-label={resolvedLabel}\n className={cn(\n \"flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50\",\n className,\n )}\n >\n <IconMessage2 size={14} />\n </button>\n </PopoverPrimitive.Trigger>\n </TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n sideOffset={6}\n className=\"z-[300] overflow-hidden rounded-md border border-border bg-popover px-2 py-1 text-[11px] text-foreground shadow-md animate-in fade-in-0 zoom-in-95\"\n >\n {resolvedLabel}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\n } else if (variant === \"outlined\") {\n trigger = (\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n aria-label={resolvedLabel}\n className={cn(\n \"flex h-8 items-center gap-2 rounded-md border border-border bg-transparent px-3 text-sm text-muted-foreground transition hover:border-foreground/40 hover:text-foreground\",\n className,\n )}\n >\n <IconMessage2 size={14} stroke={1.5} />\n <span>{resolvedLabel}</span>\n </button>\n </PopoverPrimitive.Trigger>\n );\n } else {\n trigger = (\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground\",\n className,\n )}\n >\n <IconMessage2 className=\"h-4 w-4\" />\n <span>{resolvedLabel}</span>\n </button>\n </PopoverPrimitive.Trigger>\n );\n }\n\n const resolvedSide = side ?? (variant === \"sidebar\" ? \"top\" : \"bottom\");\n const resolvedPlaceholder = placeholder ?? copy.placeholder;\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n {trigger}\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n side={resolvedSide}\n align={align}\n sideOffset={8}\n collisionPadding={16}\n className=\"z-[300] overflow-hidden rounded-lg border border-border bg-popover shadow-xl outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\"\n style={surfaceStyle}\n >\n {submitted ? (\n <div className=\"flex flex-col items-center justify-center gap-3 px-6 py-10 text-center\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-500\">\n <IconCheck size={20} stroke={2.5} />\n </div>\n <div className=\"text-sm font-medium text-foreground\">\n {copy.success}\n </div>\n </div>\n ) : (\n <form onSubmit={submit} className=\"flex flex-col gap-3 p-3\">\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") submit();\n }}\n placeholder={resolvedPlaceholder}\n rows={5}\n maxLength={10000}\n className=\"w-full resize-none rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n <input\n type=\"text\"\n tabIndex={-1}\n autoComplete=\"off\"\n aria-hidden=\"true\"\n value={honeypot}\n onChange={(e) => setHoneypot(e.target.value)}\n style={honeypotStyle}\n />\n <div className=\"flex items-center justify-between gap-3\">\n <div\n className={cn(\n \"text-[11px]\",\n error ? \"text-destructive\" : \"text-muted-foreground/75\",\n )}\n >\n {error ??\n copy.keyboardHint.replace(\n \"{{shortcut}}\",\n /Mac|iPhone|iPad/.test(navigator.userAgent)\n ? \"⌘\"\n : \"Ctrl\",\n )}\n </div>\n <button\n type=\"submit\"\n disabled={submitting || !value.trim()}\n className=\"inline-flex h-8 items-center justify-center rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {submitting ? copy.submitting : copy.submit}\n </button>\n </div>\n </form>\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"FeedbackButton.js","sourceRoot":"","sources":["../../src/client/FeedbackButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { IconMessage2, IconCheck } from \"@tabler/icons-react\";\nimport {\n useState,\n useEffect,\n useRef,\n useCallback,\n type CSSProperties,\n type FormEvent,\n type ReactNode,\n} from \"react\";\n\nimport { DEFAULT_LOCALE, type LocaleCode } from \"../localization/shared.js\";\nimport { getFeedbackClientContext } from \"./feedback-context.js\";\nimport { useLocale } from \"./i18n.js\";\nimport { useSession } from \"./use-session.js\";\nimport { cn } from \"./utils.js\";\n\nconst DEFAULT_FEEDBACK_URL =\n \"https://forms.agent-native.com/f/agent-native-feedback/_16ewV\";\n\nfunction isSyntheticAgentNativeAnonymousEmail(\n value: string | null | undefined,\n): boolean {\n return /^anon-[^\\s@]+@agent-native\\.com$/i.test(value ?? \"\");\n}\n\ninterface ParsedTarget {\n endpoint: string;\n slug: string;\n}\n\ninterface FormSchema {\n formId: string;\n fieldId: string;\n}\n\nconst FEEDBACK_COPY: Record<\n LocaleCode,\n {\n label: string;\n placeholder: string;\n submit: string;\n submitting: string;\n success: string;\n loadError: string;\n invalidUrl: string;\n emptyError: string;\n sendError: string;\n keyboardHint: string;\n }\n> = {\n \"en-US\": {\n label: \"Feedback\",\n placeholder: \"What's working, what's broken, or what would you change?\",\n submit: \"Send feedback\",\n submitting: \"Sending...\",\n success: \"Thanks for the feedback!\",\n loadError: \"Couldn't load feedback form\",\n invalidUrl: \"Invalid feedback URL\",\n emptyError: \"Please write something first\",\n sendError: \"Couldn't send feedback\",\n keyboardHint: \"{{shortcut}}+Enter to send\",\n },\n \"zh-CN\": {\n label: \"反馈\",\n placeholder: \"哪些地方好用、哪里坏了,或你想改什么?\",\n submit: \"发送反馈\",\n submitting: \"正在发送...\",\n success: \"感谢你的反馈!\",\n loadError: \"无法加载反馈表单\",\n invalidUrl: \"反馈 URL 无效\",\n emptyError: \"请先写点内容\",\n sendError: \"无法发送反馈\",\n keyboardHint: \"{{shortcut}}+Enter 发送\",\n },\n \"zh-TW\": {\n label: \"意見回饋\",\n placeholder: \"哪些地方好用、哪裡壞了,或你想改什麼?\",\n submit: \"送出意見回饋\",\n submitting: \"正在送出...\",\n success: \"感謝你的意見回饋。\",\n loadError: \"無法載入意見回饋表單\",\n invalidUrl: \"意見回饋 URL 無效\",\n emptyError: \"請先輸入內容\",\n sendError: \"無法送出意見回饋\",\n keyboardHint: \"{{shortcut}}+Enter 送出\",\n },\n \"es-ES\": {\n label: \"Comentarios\",\n placeholder: \"¿Qué funciona, qué falla o qué cambiarías?\",\n submit: \"Enviar comentarios\",\n submitting: \"Enviando...\",\n success: \"Gracias por tus comentarios.\",\n loadError: \"No se pudo cargar el formulario\",\n invalidUrl: \"URL de comentarios no válida\",\n emptyError: \"Escribe algo primero\",\n sendError: \"No se pudieron enviar los comentarios\",\n keyboardHint: \"{{shortcut}}+Enter para enviar\",\n },\n \"fr-FR\": {\n label: \"Retour\",\n placeholder: \"Qu'est-ce qui marche, casse ou devrait changer ?\",\n submit: \"Envoyer\",\n submitting: \"Envoi...\",\n success: \"Merci pour votre retour.\",\n loadError: \"Impossible de charger le formulaire\",\n invalidUrl: \"URL de retour invalide\",\n emptyError: \"Écrivez quelque chose d'abord\",\n sendError: \"Impossible d'envoyer le retour\",\n keyboardHint: \"{{shortcut}}+Entrée pour envoyer\",\n },\n \"de-DE\": {\n label: \"Feedback\",\n placeholder: \"Was funktioniert, was ist kaputt, was würdest du ändern?\",\n submit: \"Feedback senden\",\n submitting: \"Wird gesendet...\",\n success: \"Danke für dein Feedback!\",\n loadError: \"Feedback-Formular konnte nicht geladen werden\",\n invalidUrl: \"Ungültige Feedback-URL\",\n emptyError: \"Bitte zuerst etwas schreiben\",\n sendError: \"Feedback konnte nicht gesendet werden\",\n keyboardHint: \"{{shortcut}}+Enter zum Senden\",\n },\n \"ja-JP\": {\n label: \"フィードバック\",\n placeholder: \"良い点、問題点、変更したい点を教えてください。\",\n submit: \"送信\",\n submitting: \"送信中...\",\n success: \"フィードバックありがとうございます。\",\n loadError: \"フォームを読み込めませんでした\",\n invalidUrl: \"フィードバック URL が無効です\",\n emptyError: \"先に内容を入力してください\",\n sendError: \"送信できませんでした\",\n keyboardHint: \"{{shortcut}}+Enter で送信\",\n },\n \"ko-KR\": {\n label: \"피드백\",\n placeholder: \"잘 되는 점, 깨진 점, 바꾸고 싶은 점을 알려주세요.\",\n submit: \"피드백 보내기\",\n submitting: \"보내는 중...\",\n success: \"피드백 감사합니다.\",\n loadError: \"피드백 양식을 불러올 수 없습니다\",\n invalidUrl: \"피드백 URL이 올바르지 않습니다\",\n emptyError: \"먼저 내용을 입력해 주세요\",\n sendError: \"피드백을 보낼 수 없습니다\",\n keyboardHint: \"{{shortcut}}+Enter로 보내기\",\n },\n \"pt-BR\": {\n label: \"Feedback\",\n placeholder: \"O que funciona, quebrou ou você mudaria?\",\n submit: \"Enviar feedback\",\n submitting: \"Enviando...\",\n success: \"Obrigado pelo feedback!\",\n loadError: \"Não foi possível carregar o formulário\",\n invalidUrl: \"URL de feedback inválida\",\n emptyError: \"Escreva algo primeiro\",\n sendError: \"Não foi possível enviar o feedback\",\n keyboardHint: \"{{shortcut}}+Enter para enviar\",\n },\n \"hi-IN\": {\n label: \"फ़ीडबैक\",\n placeholder: \"क्या काम कर रहा है, क्या टूटा है, या आप क्या बदलना चाहेंगे?\",\n submit: \"फ़ीडबैक भेजें\",\n submitting: \"भेजा जा रहा है...\",\n success: \"फ़ीडबैक के लिए धन्यवाद!\",\n loadError: \"फ़ीडबैक फ़ॉर्म लोड नहीं हुआ\",\n invalidUrl: \"फ़ीडबैक URL अमान्य है\",\n emptyError: \"पहले कुछ लिखें\",\n sendError: \"फ़ीडबैक भेजा नहीं जा सका\",\n keyboardHint: \"भेजने के लिए {{shortcut}}+Enter\",\n },\n \"ar-SA\": {\n label: \"ملاحظات\",\n placeholder: \"ما الذي يعمل، وما المعطل، وما الذي تريد تغييره؟\",\n submit: \"إرسال الملاحظات\",\n submitting: \"جار الإرسال...\",\n success: \"شكرا لملاحظاتك!\",\n loadError: \"تعذر تحميل نموذج الملاحظات\",\n invalidUrl: \"رابط الملاحظات غير صالح\",\n emptyError: \"اكتب شيئا أولا\",\n sendError: \"تعذر إرسال الملاحظات\",\n keyboardHint: \"{{shortcut}}+Enter للإرسال\",\n },\n};\n\nfunction parseTarget(url: string): ParsedTarget | null {\n try {\n const u = new URL(url);\n const idx = u.pathname.indexOf(\"/f/\");\n if (idx === -1) return null;\n const slug = u.pathname.slice(idx + 3).replace(/\\/$/, \"\");\n if (!slug) return null;\n return { endpoint: u.origin, slug };\n } catch {\n return null;\n }\n}\n\nconst schemaCache = new Map<string, Promise<FormSchema>>();\n\nasync function loadSchema(target: ParsedTarget): Promise<FormSchema> {\n const key = `${target.endpoint}|${target.slug}`;\n let pending = schemaCache.get(key);\n if (pending) return pending;\n pending = (async () => {\n const res = await fetch(\n `${target.endpoint}/api/forms/public/${encodeURIComponent(target.slug)}`,\n { headers: { Accept: \"application/json\" } },\n );\n if (!res.ok) throw new Error(`form fetch ${res.status}`);\n const body = (await res.json()) as {\n id: string;\n fields: Array<{ id: string; type: string }>;\n };\n const field =\n body.fields.find((f) => f.type === \"textarea\") ??\n body.fields.find((f) => f.type === \"text\") ??\n body.fields[0];\n if (!field) throw new Error(\"form has no fields\");\n return { formId: body.id, fieldId: field.id };\n })();\n pending.catch(() => schemaCache.delete(key));\n schemaCache.set(key, pending);\n return pending;\n}\n\nexport interface FeedbackButtonProps {\n /**\n * \"sidebar\" renders a full-width row with icon + label (for app left sidebars).\n * \"icon\" renders a small icon-only button (for dense toolbars, e.g. the agent panel header).\n * \"outlined\" renders an outlined pill button with icon + label (for top-nav bars, e.g. docs).\n */\n variant?: \"sidebar\" | \"icon\" | \"outlined\";\n label?: string;\n url?: string;\n className?: string;\n /** Which side the popover opens on. Defaults match the variant. */\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\n align?: \"start\" | \"center\" | \"end\";\n /** Placeholder text for the textarea. */\n placeholder?: string;\n /** Current chat session/thread id, when the host already knows it. */\n chatSessionId?: string | null;\n /** Chat localStorage namespace, when the host uses per-app chat storage. */\n chatStorageKey?: string | null;\n /** Controlled popover open state for hosts that trigger feedback from a menu. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Optional custom trigger element. */\n trigger?: ReactNode;\n}\n\nconst surfaceStyle: CSSProperties = {\n width: \"min(380px, calc(100vw - 32px))\",\n};\n\nconst honeypotStyle: CSSProperties = {\n position: \"absolute\",\n left: \"-10000px\",\n top: \"auto\",\n width: \"1px\",\n height: \"1px\",\n overflow: \"hidden\",\n};\n\nexport function FeedbackButton({\n variant = \"sidebar\",\n label,\n url = DEFAULT_FEEDBACK_URL,\n className,\n side,\n align = \"end\",\n placeholder,\n chatSessionId,\n chatStorageKey,\n open: controlledOpen,\n onOpenChange,\n trigger: customTrigger,\n}: FeedbackButtonProps) {\n const target = parseTarget(url);\n const { session } = useSession();\n const { locale } = useLocale();\n const copy = FEEDBACK_COPY[locale] ?? FEEDBACK_COPY[DEFAULT_LOCALE];\n const resolvedLabel = label ?? copy.label;\n\n const [uncontrolledOpen, setUncontrolledOpen] = useState(false);\n const open = controlledOpen ?? uncontrolledOpen;\n const setOpen = useCallback(\n (nextOpen: boolean) => {\n if (controlledOpen === undefined) setUncontrolledOpen(nextOpen);\n onOpenChange?.(nextOpen);\n },\n [controlledOpen, onOpenChange],\n );\n const [value, setValue] = useState(\"\");\n const [honeypot, setHoneypot] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [submitted, setSubmitted] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [schema, setSchema] = useState<FormSchema | null>(null);\n const openedAtRef = useRef<number>(0);\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const textareaRef = useRef<HTMLTextAreaElement | null>(null);\n\n // Reset transient state and kick off schema load on each open.\n useEffect(() => {\n if (!open) return;\n openedAtRef.current = Date.now();\n setValue(\"\");\n setHoneypot(\"\");\n setSubmitting(false);\n setSubmitted(false);\n setError(null);\n setSchema(null);\n if (target) {\n loadSchema(target)\n .then((s) => setSchema(s))\n .catch((err) => {\n console.error(\"[FeedbackButton] schema load failed\", err);\n setError(copy.loadError);\n });\n } else {\n setError(copy.invalidUrl);\n }\n const t = setTimeout(() => textareaRef.current?.focus(), 30);\n return () => {\n clearTimeout(t);\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n };\n }, [open, url]);\n\n const submit = useCallback(\n async (e?: FormEvent) => {\n e?.preventDefault();\n if (!target || submitting) return;\n const trimmed = value.trim();\n if (!trimmed) {\n setError(copy.emptyError);\n return;\n }\n setSubmitting(true);\n setError(null);\n try {\n const resolvedSchema = schema ?? (await loadSchema(target));\n if (!schema) setSchema(resolvedSchema);\n const submitterEmail = isSyntheticAgentNativeAnonymousEmail(\n session?.email,\n )\n ? null\n : session?.email;\n const feedbackContext = getFeedbackClientContext({\n chatSessionId,\n storageKey: chatStorageKey,\n });\n const res = await fetch(\n `${target.endpoint}/api/submit/${encodeURIComponent(resolvedSchema.formId)}`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n data: { [resolvedSchema.fieldId]: trimmed },\n _t: openedAtRef.current,\n _hp: honeypot,\n _meta: {\n ...(submitterEmail ? { submitterEmail } : {}),\n ...feedbackContext,\n },\n }),\n },\n );\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as {\n error?: string;\n };\n throw new Error(body.error || `submit failed (${res.status})`);\n }\n setSubmitted(true);\n closeTimerRef.current = setTimeout(() => setOpen(false), 1400);\n } catch (err) {\n setSubmitting(false);\n setError(err instanceof Error ? err.message : copy.sendError);\n }\n },\n [\n target,\n schema,\n value,\n honeypot,\n submitting,\n session?.email,\n chatSessionId,\n chatStorageKey,\n setOpen,\n copy.emptyError,\n copy.sendError,\n ],\n );\n\n let trigger;\n if (customTrigger) {\n trigger = (\n <PopoverPrimitive.Trigger asChild>\n {customTrigger}\n </PopoverPrimitive.Trigger>\n );\n } else if (variant === \"icon\") {\n trigger = (\n <TooltipPrimitive.Provider delayDuration={200}>\n <TooltipPrimitive.Root>\n <TooltipPrimitive.Trigger asChild>\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n aria-label={resolvedLabel}\n className={cn(\n \"flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50\",\n className,\n )}\n >\n <IconMessage2 size={14} />\n </button>\n </PopoverPrimitive.Trigger>\n </TooltipPrimitive.Trigger>\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n sideOffset={6}\n className=\"z-[100040] overflow-hidden rounded-md border border-border bg-popover px-2 py-1 text-[11px] text-foreground shadow-md animate-in fade-in-0 zoom-in-95\"\n >\n {resolvedLabel}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n </TooltipPrimitive.Root>\n </TooltipPrimitive.Provider>\n );\n } else if (variant === \"outlined\") {\n trigger = (\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n aria-label={resolvedLabel}\n className={cn(\n \"flex h-8 items-center gap-2 rounded-md border border-border bg-transparent px-3 text-sm text-muted-foreground transition hover:border-foreground/40 hover:text-foreground\",\n className,\n )}\n >\n <IconMessage2 size={14} stroke={1.5} />\n <span>{resolvedLabel}</span>\n </button>\n </PopoverPrimitive.Trigger>\n );\n } else {\n trigger = (\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground\",\n className,\n )}\n >\n <IconMessage2 className=\"h-4 w-4\" />\n <span>{resolvedLabel}</span>\n </button>\n </PopoverPrimitive.Trigger>\n );\n }\n\n const resolvedSide = side ?? (variant === \"sidebar\" ? \"top\" : \"bottom\");\n const resolvedPlaceholder = placeholder ?? copy.placeholder;\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n {trigger}\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n side={resolvedSide}\n align={align}\n sideOffset={8}\n collisionPadding={16}\n className=\"z-[100040] overflow-hidden rounded-lg border border-border bg-popover shadow-xl outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\"\n style={surfaceStyle}\n >\n {submitted ? (\n <div className=\"flex flex-col items-center justify-center gap-3 px-6 py-10 text-center\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-500\">\n <IconCheck size={20} stroke={2.5} />\n </div>\n <div className=\"text-sm font-medium text-foreground\">\n {copy.success}\n </div>\n </div>\n ) : (\n <form onSubmit={submit} className=\"flex flex-col gap-3 p-3\">\n <textarea\n ref={textareaRef}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") submit();\n }}\n placeholder={resolvedPlaceholder}\n rows={5}\n maxLength={10000}\n className=\"w-full resize-none rounded-md border border-input bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n <input\n type=\"text\"\n tabIndex={-1}\n autoComplete=\"off\"\n aria-hidden=\"true\"\n value={honeypot}\n onChange={(e) => setHoneypot(e.target.value)}\n style={honeypotStyle}\n />\n <div className=\"flex items-center justify-between gap-3\">\n <div\n className={cn(\n \"text-[11px]\",\n error ? \"text-destructive\" : \"text-muted-foreground/75\",\n )}\n >\n {error ??\n copy.keyboardHint.replace(\n \"{{shortcut}}\",\n /Mac|iPhone|iPad/.test(navigator.userAgent)\n ? \"⌘\"\n : \"Ctrl\",\n )}\n </div>\n <button\n type=\"submit\"\n disabled={submitting || !value.trim()}\n className=\"inline-flex h-8 items-center justify-center rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {submitting ? copy.submitting : copy.submit}\n </button>\n </div>\n </form>\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PresenceBar.d.ts","sourceRoot":"","sources":["../../../src/client/components/PresenceBar.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,UAAU,EAIhB,MAAM,wBAAwB,CAAC;AAQhC,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,sDAAsD;IACtD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;
|
|
1
|
+
{"version":3,"file":"PresenceBar.d.ts","sourceRoot":"","sources":["../../../src/client/components/PresenceBar.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,UAAU,EAIhB,MAAM,wBAAwB,CAAC;AAQhC,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,sDAAsD;IACtD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AA8ND,wBAAgB,WAAW,CAAC,EAC1B,WAAW,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,UAAc,EACd,SAAS,EACT,aAAa,EACb,cAAc,GACf,EAAE,gBAAgB,sCA+DlB"}
|
|
@@ -55,10 +55,14 @@ function UserAvatar({ user, isFirst, onClick, isFollowing, }) {
|
|
|
55
55
|
boxShadow: isFollowing
|
|
56
56
|
? `0 0 0 2px #3b82f6, 0 0 0 4px #fff`
|
|
57
57
|
: `0 0 0 2px #fff`,
|
|
58
|
-
}, "aria-label": `${name} (${user.email})${isFollowing ? " — following" : ""}`, tabIndex: 0, onClick: onClick, onKeyDown: (e) => {
|
|
58
|
+
}, "aria-label": `${name} (${user.email})${isFollowing ? " — following" : ""}`, tabIndex: onClick ? 0 : undefined, role: onClick ? "button" : undefined, onClick: onClick, onKeyDown: (e) => {
|
|
59
59
|
if (e.key === "Enter" || e.key === " ")
|
|
60
60
|
onClick?.();
|
|
61
|
-
}, children: initial }) }), _jsx(TooltipContent, { side: "bottom", children: isFollowing
|
|
61
|
+
}, children: initial }) }), _jsx(TooltipContent, { side: "bottom", children: isFollowing
|
|
62
|
+
? `Following ${name} — click to stop`
|
|
63
|
+
: onClick
|
|
64
|
+
? `${name} — click to follow`
|
|
65
|
+
: user.email })] }));
|
|
62
66
|
}
|
|
63
67
|
function AgentAvatar({ active, onClick, isFollowing, }) {
|
|
64
68
|
injectStyles();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PresenceBar.js","sourceRoot":"","sources":["../../../src/client/components/PresenceBar.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo } from \"react\";\n\nimport {\n type CollabUser,\n dedupeCollabUsersByEmail,\n emailToColor,\n emailToName,\n} from \"../../collab/client.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"./ui/tooltip.js\";\n\nexport interface PresenceBarProps {\n /** Active collaborators on this document. */\n activeUsers: CollabUser[];\n /** Whether the agent has a durable presence entry. */\n agentPresent?: boolean;\n /** Whether the agent is actively making edits right now. */\n agentActive?: boolean;\n /** Current user's email (to exclude from the list). */\n currentUserEmail?: string;\n /** Max visible avatars before \"+N\" overflow. Default: 5 */\n maxVisible?: number;\n /** Additional CSS classes. */\n className?: string;\n /**\n * Called when an avatar is clicked. Receives the user being clicked\n * (or null for the agent avatar). Use this to start/stop follow mode.\n */\n onAvatarClick?: (user: CollabUser | null) => void;\n /**\n * The email of the user currently being followed. Highlighted with a\n * blue ring to indicate active follow mode.\n */\n followingEmail?: string | null;\n}\n\nconst AVATAR_SIZE = 28;\nconst OVERLAP = -8;\nconst BORDER_WIDTH = 2;\nconst FONT_SIZE = 12;\nconst AGENT_COLOR = \"#00B5FF\";\n\nconst baseAvatarStyle: React.CSSProperties = {\n width: AVATAR_SIZE,\n height: AVATAR_SIZE,\n borderRadius: \"50%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: FONT_SIZE,\n fontWeight: 700,\n color: \"#fff\",\n border: `${BORDER_WIDTH}px solid #fff`,\n flexShrink: 0,\n position: \"relative\",\n cursor: \"default\",\n boxSizing: \"border-box\",\n};\n\nconst containerStyle: React.CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n flexDirection: \"row\",\n};\n\nconst pulseKeyframes = `\n@keyframes _anPresencePulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n}\n`;\n\nlet styleInjected = false;\n\nfunction injectStyles() {\n if (styleInjected || typeof document === \"undefined\") return;\n const style = document.createElement(\"style\");\n style.textContent = pulseKeyframes;\n document.head.appendChild(style);\n styleInjected = true;\n}\n\nfunction UserAvatar({\n user,\n isFirst,\n onClick,\n isFollowing,\n}: {\n user: CollabUser;\n isFirst: boolean;\n onClick?: () => void;\n isFollowing?: boolean;\n}) {\n const color = user.color || emailToColor(user.email);\n const name = user.name || emailToName(user.email);\n const initial = name.charAt(0).toUpperCase();\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <div\n style={{\n ...baseAvatarStyle,\n backgroundColor: color,\n marginLeft: isFirst ? 0 : OVERLAP,\n cursor: onClick ? \"pointer\" : \"default\",\n boxShadow: isFollowing\n ? `0 0 0 2px #3b82f6, 0 0 0 4px #fff`\n : `0 0 0 2px #fff`,\n }}\n aria-label={`${name} (${user.email})${isFollowing ? \" — following\" : \"\"}`}\n tabIndex={0}\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") onClick?.();\n }}\n >\n {initial}\n </div>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">\n {isFollowing ? `Following ${name} — click to stop` : user.email}\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction AgentAvatar({\n active,\n onClick,\n isFollowing,\n}: {\n active: boolean;\n onClick?: () => void;\n isFollowing?: boolean;\n}) {\n injectStyles();\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n }}\n >\n <div\n style={{\n ...baseAvatarStyle,\n backgroundColor: AGENT_COLOR,\n marginLeft: 0,\n animation: active ? \"_anPresencePulse 2s infinite\" : undefined,\n cursor: onClick ? \"pointer\" : \"default\",\n boxShadow: isFollowing\n ? `0 0 0 2px #3b82f6, 0 0 0 4px #fff`\n : undefined,\n }}\n title={\n isFollowing\n ? \"Following AI — click to stop\"\n : active\n ? \"AI is editing\"\n : \"AI agent\"\n }\n onClick={onClick}\n tabIndex={onClick ? 0 : undefined}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") onClick?.();\n }}\n role={onClick ? \"button\" : undefined}\n >\n A\n </div>\n {active && !isFollowing && <AgentEditingChip />}\n {isFollowing && (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n height: 20,\n padding: \"0 8px\",\n borderRadius: 9999,\n backgroundColor: `#3b82f620`,\n color: \"#3b82f6\",\n fontSize: 11,\n fontWeight: 600,\n whiteSpace: \"nowrap\",\n }}\n >\n Following AI\n </span>\n )}\n </div>\n );\n}\n\nfunction AgentEditingChip() {\n return (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 4,\n height: 20,\n padding: \"0 8px\",\n borderRadius: 9999,\n backgroundColor: `${AGENT_COLOR}20`,\n color: AGENT_COLOR,\n fontSize: 11,\n fontWeight: 600,\n whiteSpace: \"nowrap\",\n }}\n >\n <span\n style={{\n width: 6,\n height: 6,\n borderRadius: \"50%\",\n backgroundColor: AGENT_COLOR,\n animation: \"_anPresencePulse 2s infinite\",\n flexShrink: 0,\n }}\n />\n AI editing\n </span>\n );\n}\n\nfunction OverflowBadge({\n count,\n isFirst,\n}: {\n count: number;\n isFirst: boolean;\n}) {\n return (\n <div\n style={{\n ...baseAvatarStyle,\n backgroundColor: \"rgba(255,255,255,0.1)\",\n color: \"rgba(255,255,255,0.5)\",\n marginLeft: isFirst ? 0 : OVERLAP,\n fontSize: 10,\n }}\n title={`${count} more collaborator${count === 1 ? \"\" : \"s\"}`}\n >\n +{count}\n </div>\n );\n}\n\nexport function PresenceBar({\n activeUsers,\n agentPresent,\n agentActive,\n currentUserEmail,\n maxVisible = 5,\n className,\n onAvatarClick,\n followingEmail,\n}: PresenceBarProps) {\n const { humanUsers, showAgent } = useMemo(() => {\n const currentEmail = currentUserEmail?.trim().toLowerCase();\n const uniqueUsers = dedupeCollabUsersByEmail(activeUsers);\n const humans = uniqueUsers.filter((u) => {\n const email = u.email.trim().toLowerCase();\n return email !== currentEmail && email !== \"agent@system\";\n });\n const hasAgentUser = uniqueUsers.some(\n (u) => u.email.trim().toLowerCase() === \"agent@system\",\n );\n return {\n humanUsers: humans,\n showAgent: agentPresent || agentActive || hasAgentUser,\n };\n }, [activeUsers, currentUserEmail, agentPresent, agentActive]);\n\n const visibleUsers = humanUsers.slice(0, maxVisible);\n const overflowCount = humanUsers.length - visibleUsers.length;\n\n if (!showAgent && humanUsers.length === 0) return null;\n\n const followingLower = followingEmail?.trim().toLowerCase() ?? null;\n const isFollowingAgent = followingLower === \"agent@system\";\n\n return (\n <TooltipProvider delayDuration={150}>\n <div style={containerStyle} className={className}>\n {showAgent && (\n <AgentAvatar\n active={!!agentActive}\n onClick={onAvatarClick ? () => onAvatarClick(null) : undefined}\n isFollowing={isFollowingAgent}\n />\n )}\n {visibleUsers.length > 0 && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n marginLeft: showAgent ? 6 : 0,\n }}\n >\n {visibleUsers.map((u, i) => (\n <UserAvatar\n key={u.email}\n user={u}\n isFirst={i === 0}\n onClick={onAvatarClick ? () => onAvatarClick(u) : undefined}\n isFollowing={\n followingLower != null &&\n u.email.trim().toLowerCase() === followingLower\n }\n />\n ))}\n {overflowCount > 0 && (\n <OverflowBadge count={overflowCount} isFirst={false} />\n )}\n </div>\n )}\n </div>\n </TooltipProvider>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"PresenceBar.js","sourceRoot":"","sources":["../../../src/client/components/PresenceBar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAEL,wBAAwB,EACxB,YAAY,EACZ,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,OAAO,EACP,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,iBAAiB,CAAC;AA2BzB,MAAM,WAAW,GAAG,EAAE,CAAC;AACvB,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC;AACnB,MAAM,YAAY,GAAG,CAAC,CAAC;AACvB,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,WAAW,GAAG,SAAS,CAAC;AAE9B,MAAM,eAAe,GAAwB;IAC3C,KAAK,EAAE,WAAW;IAClB,MAAM,EAAE,WAAW;IACnB,YAAY,EAAE,KAAK;IACnB,OAAO,EAAE,MAAM;IACf,UAAU,EAAE,QAAQ;IACpB,cAAc,EAAE,QAAQ;IACxB,QAAQ,EAAE,SAAS;IACnB,UAAU,EAAE,GAAG;IACf,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,GAAG,YAAY,eAAe;IACtC,UAAU,EAAE,CAAC;IACb,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,SAAS;IACjB,SAAS,EAAE,YAAY;CACxB,CAAC;AAEF,MAAM,cAAc,GAAwB;IAC1C,OAAO,EAAE,MAAM;IACf,UAAU,EAAE,QAAQ;IACpB,aAAa,EAAE,KAAK;CACrB,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;CAKtB,CAAC;AAEF,IAAI,aAAa,GAAG,KAAK,CAAC;AAE1B,SAAS,YAAY;IACnB,IAAI,aAAa,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IAC7D,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,WAAW,GAAG,cAAc,CAAC;IACnC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACjC,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC;AAED,SAAS,UAAU,CAAC,EAClB,IAAI,EACJ,OAAO,EACP,OAAO,EACP,WAAW,GAMZ;IACC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAE7C,OAAO,CACL,MAAC,OAAO,eACN,KAAC,cAAc,IAAC,OAAO,kBACrB,cACE,KAAK,EAAE;wBACL,GAAG,eAAe;wBAClB,eAAe,EAAE,KAAK;wBACtB,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO;wBACjC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;wBACvC,SAAS,EAAE,WAAW;4BACpB,CAAC,CAAC,mCAAmC;4BACrC,CAAC,CAAC,gBAAgB;qBACrB,gBACW,GAAG,IAAI,KAAK,IAAI,CAAC,KAAK,IAAI,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,EACzE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,EACjC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EACpC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;wBACf,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG;4BAAE,OAAO,EAAE,EAAE,CAAC;oBACtD,CAAC,YAEA,OAAO,GACJ,GACS,EACjB,KAAC,cAAc,IAAC,IAAI,EAAC,QAAQ,YAC1B,WAAW;oBACV,CAAC,CAAC,aAAa,IAAI,kBAAkB;oBACrC,CAAC,CAAC,OAAO;wBACP,CAAC,CAAC,GAAG,IAAI,oBAAoB;wBAC7B,CAAC,CAAC,IAAI,CAAC,KAAK,GACD,IACT,CACX,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,EACnB,MAAM,EACN,OAAO,EACP,WAAW,GAKZ;IACC,YAAY,EAAE,CAAC;IAEf,OAAO,CACL,eACE,KAAK,EAAE;YACL,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,CAAC;SACP,aAED,cACE,KAAK,EAAE;oBACL,GAAG,eAAe;oBAClB,eAAe,EAAE,WAAW;oBAC5B,UAAU,EAAE,CAAC;oBACb,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,SAAS;oBAC9D,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;oBACvC,SAAS,EAAE,WAAW;wBACpB,CAAC,CAAC,mCAAmC;wBACrC,CAAC,CAAC,SAAS;iBACd,EACD,KAAK,EACH,WAAW;oBACT,CAAC,CAAC,8BAA8B;oBAChC,CAAC,CAAC,MAAM;wBACN,CAAC,CAAC,eAAe;wBACjB,CAAC,CAAC,UAAU,EAElB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,EACjC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;oBACf,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,CAAC,GAAG,KAAK,GAAG;wBAAE,OAAO,EAAE,EAAE,CAAC;gBACtD,CAAC,EACD,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,kBAGhC,EACL,MAAM,IAAI,CAAC,WAAW,IAAI,KAAC,gBAAgB,KAAG,EAC9C,WAAW,IAAI,CACd,eACE,KAAK,EAAE;oBACL,OAAO,EAAE,aAAa;oBACtB,UAAU,EAAE,QAAQ;oBACpB,MAAM,EAAE,EAAE;oBACV,OAAO,EAAE,OAAO;oBAChB,YAAY,EAAE,IAAI;oBAClB,eAAe,EAAE,WAAW;oBAC5B,KAAK,EAAE,SAAS;oBAChB,QAAQ,EAAE,EAAE;oBACZ,UAAU,EAAE,GAAG;oBACf,UAAU,EAAE,QAAQ;iBACrB,6BAGI,CACR,IACG,CACP,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,CACL,gBACE,KAAK,EAAE;YACL,OAAO,EAAE,aAAa;YACtB,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,CAAC;YACN,MAAM,EAAE,EAAE;YACV,OAAO,EAAE,OAAO;YAChB,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,GAAG,WAAW,IAAI;YACnC,KAAK,EAAE,WAAW;YAClB,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,QAAQ;SACrB,aAED,eACE,KAAK,EAAE;oBACL,KAAK,EAAE,CAAC;oBACR,MAAM,EAAE,CAAC;oBACT,YAAY,EAAE,KAAK;oBACnB,eAAe,EAAE,WAAW;oBAC5B,SAAS,EAAE,8BAA8B;oBACzC,UAAU,EAAE,CAAC;iBACd,GACD,kBAEG,CACR,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,EACrB,KAAK,EACL,OAAO,GAIR;IACC,OAAO,CACL,eACE,KAAK,EAAE;YACL,GAAG,eAAe;YAClB,eAAe,EAAE,uBAAuB;YACxC,KAAK,EAAE,uBAAuB;YAC9B,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO;YACjC,QAAQ,EAAE,EAAE;SACb,EACD,KAAK,EAAE,GAAG,KAAK,qBAAqB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,kBAE1D,KAAK,IACH,CACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAC1B,WAAW,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,UAAU,GAAG,CAAC,EACd,SAAS,EACT,aAAa,EACb,cAAc,GACG;IACjB,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;QAC7C,MAAM,YAAY,GAAG,gBAAgB,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC5D,MAAM,WAAW,GAAG,wBAAwB,CAAC,WAAW,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YACtC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC3C,OAAO,KAAK,KAAK,YAAY,IAAI,KAAK,KAAK,cAAc,CAAC;QAC5D,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,WAAW,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,cAAc,CACvD,CAAC;QACF,OAAO;YACL,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,YAAY,IAAI,WAAW,IAAI,YAAY;SACvD,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC;IAE/D,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC;IAE9D,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvD,MAAM,cAAc,GAAG,cAAc,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC;IACpE,MAAM,gBAAgB,GAAG,cAAc,KAAK,cAAc,CAAC;IAE3D,OAAO,CACL,KAAC,eAAe,IAAC,aAAa,EAAE,GAAG,YACjC,eAAK,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,aAC7C,SAAS,IAAI,CACZ,KAAC,WAAW,IACV,MAAM,EAAE,CAAC,CAAC,WAAW,EACrB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAC9D,WAAW,EAAE,gBAAgB,GAC7B,CACH,EACA,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,CAC1B,eACE,KAAK,EAAE;wBACL,OAAO,EAAE,MAAM;wBACf,UAAU,EAAE,QAAQ;wBACpB,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;qBAC9B,aAEA,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAC1B,KAAC,UAAU,IAET,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,CAAC,KAAK,CAAC,EAChB,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,EAC3D,WAAW,EACT,cAAc,IAAI,IAAI;gCACtB,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,cAAc,IAN5C,CAAC,CAAC,KAAK,CAQZ,CACH,CAAC,EACD,aAAa,GAAG,CAAC,IAAI,CACpB,KAAC,aAAa,IAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,GAAI,CACxD,IACG,CACP,IACG,GACU,CACnB,CAAC;AACJ,CAAC","sourcesContent":["import { useMemo } from \"react\";\n\nimport {\n type CollabUser,\n dedupeCollabUsersByEmail,\n emailToColor,\n emailToName,\n} from \"../../collab/client.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"./ui/tooltip.js\";\n\nexport interface PresenceBarProps {\n /** Active collaborators on this document. */\n activeUsers: CollabUser[];\n /** Whether the agent has a durable presence entry. */\n agentPresent?: boolean;\n /** Whether the agent is actively making edits right now. */\n agentActive?: boolean;\n /** Current user's email (to exclude from the list). */\n currentUserEmail?: string;\n /** Max visible avatars before \"+N\" overflow. Default: 5 */\n maxVisible?: number;\n /** Additional CSS classes. */\n className?: string;\n /**\n * Called when an avatar is clicked. Receives the user being clicked\n * (or null for the agent avatar). Use this to start/stop follow mode.\n */\n onAvatarClick?: (user: CollabUser | null) => void;\n /**\n * The email of the user currently being followed. Highlighted with a\n * blue ring to indicate active follow mode.\n */\n followingEmail?: string | null;\n}\n\nconst AVATAR_SIZE = 28;\nconst OVERLAP = -8;\nconst BORDER_WIDTH = 2;\nconst FONT_SIZE = 12;\nconst AGENT_COLOR = \"#00B5FF\";\n\nconst baseAvatarStyle: React.CSSProperties = {\n width: AVATAR_SIZE,\n height: AVATAR_SIZE,\n borderRadius: \"50%\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: FONT_SIZE,\n fontWeight: 700,\n color: \"#fff\",\n border: `${BORDER_WIDTH}px solid #fff`,\n flexShrink: 0,\n position: \"relative\",\n cursor: \"default\",\n boxSizing: \"border-box\",\n};\n\nconst containerStyle: React.CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n flexDirection: \"row\",\n};\n\nconst pulseKeyframes = `\n@keyframes _anPresencePulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n}\n`;\n\nlet styleInjected = false;\n\nfunction injectStyles() {\n if (styleInjected || typeof document === \"undefined\") return;\n const style = document.createElement(\"style\");\n style.textContent = pulseKeyframes;\n document.head.appendChild(style);\n styleInjected = true;\n}\n\nfunction UserAvatar({\n user,\n isFirst,\n onClick,\n isFollowing,\n}: {\n user: CollabUser;\n isFirst: boolean;\n onClick?: () => void;\n isFollowing?: boolean;\n}) {\n const color = user.color || emailToColor(user.email);\n const name = user.name || emailToName(user.email);\n const initial = name.charAt(0).toUpperCase();\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <div\n style={{\n ...baseAvatarStyle,\n backgroundColor: color,\n marginLeft: isFirst ? 0 : OVERLAP,\n cursor: onClick ? \"pointer\" : \"default\",\n boxShadow: isFollowing\n ? `0 0 0 2px #3b82f6, 0 0 0 4px #fff`\n : `0 0 0 2px #fff`,\n }}\n aria-label={`${name} (${user.email})${isFollowing ? \" — following\" : \"\"}`}\n tabIndex={onClick ? 0 : undefined}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") onClick?.();\n }}\n >\n {initial}\n </div>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">\n {isFollowing\n ? `Following ${name} — click to stop`\n : onClick\n ? `${name} — click to follow`\n : user.email}\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction AgentAvatar({\n active,\n onClick,\n isFollowing,\n}: {\n active: boolean;\n onClick?: () => void;\n isFollowing?: boolean;\n}) {\n injectStyles();\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n }}\n >\n <div\n style={{\n ...baseAvatarStyle,\n backgroundColor: AGENT_COLOR,\n marginLeft: 0,\n animation: active ? \"_anPresencePulse 2s infinite\" : undefined,\n cursor: onClick ? \"pointer\" : \"default\",\n boxShadow: isFollowing\n ? `0 0 0 2px #3b82f6, 0 0 0 4px #fff`\n : undefined,\n }}\n title={\n isFollowing\n ? \"Following AI — click to stop\"\n : active\n ? \"AI is editing\"\n : \"AI agent\"\n }\n onClick={onClick}\n tabIndex={onClick ? 0 : undefined}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") onClick?.();\n }}\n role={onClick ? \"button\" : undefined}\n >\n A\n </div>\n {active && !isFollowing && <AgentEditingChip />}\n {isFollowing && (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n height: 20,\n padding: \"0 8px\",\n borderRadius: 9999,\n backgroundColor: `#3b82f620`,\n color: \"#3b82f6\",\n fontSize: 11,\n fontWeight: 600,\n whiteSpace: \"nowrap\",\n }}\n >\n Following AI\n </span>\n )}\n </div>\n );\n}\n\nfunction AgentEditingChip() {\n return (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 4,\n height: 20,\n padding: \"0 8px\",\n borderRadius: 9999,\n backgroundColor: `${AGENT_COLOR}20`,\n color: AGENT_COLOR,\n fontSize: 11,\n fontWeight: 600,\n whiteSpace: \"nowrap\",\n }}\n >\n <span\n style={{\n width: 6,\n height: 6,\n borderRadius: \"50%\",\n backgroundColor: AGENT_COLOR,\n animation: \"_anPresencePulse 2s infinite\",\n flexShrink: 0,\n }}\n />\n AI editing\n </span>\n );\n}\n\nfunction OverflowBadge({\n count,\n isFirst,\n}: {\n count: number;\n isFirst: boolean;\n}) {\n return (\n <div\n style={{\n ...baseAvatarStyle,\n backgroundColor: \"rgba(255,255,255,0.1)\",\n color: \"rgba(255,255,255,0.5)\",\n marginLeft: isFirst ? 0 : OVERLAP,\n fontSize: 10,\n }}\n title={`${count} more collaborator${count === 1 ? \"\" : \"s\"}`}\n >\n +{count}\n </div>\n );\n}\n\nexport function PresenceBar({\n activeUsers,\n agentPresent,\n agentActive,\n currentUserEmail,\n maxVisible = 5,\n className,\n onAvatarClick,\n followingEmail,\n}: PresenceBarProps) {\n const { humanUsers, showAgent } = useMemo(() => {\n const currentEmail = currentUserEmail?.trim().toLowerCase();\n const uniqueUsers = dedupeCollabUsersByEmail(activeUsers);\n const humans = uniqueUsers.filter((u) => {\n const email = u.email.trim().toLowerCase();\n return email !== currentEmail && email !== \"agent@system\";\n });\n const hasAgentUser = uniqueUsers.some(\n (u) => u.email.trim().toLowerCase() === \"agent@system\",\n );\n return {\n humanUsers: humans,\n showAgent: agentPresent || agentActive || hasAgentUser,\n };\n }, [activeUsers, currentUserEmail, agentPresent, agentActive]);\n\n const visibleUsers = humanUsers.slice(0, maxVisible);\n const overflowCount = humanUsers.length - visibleUsers.length;\n\n if (!showAgent && humanUsers.length === 0) return null;\n\n const followingLower = followingEmail?.trim().toLowerCase() ?? null;\n const isFollowingAgent = followingLower === \"agent@system\";\n\n return (\n <TooltipProvider delayDuration={150}>\n <div style={containerStyle} className={className}>\n {showAgent && (\n <AgentAvatar\n active={!!agentActive}\n onClick={onAvatarClick ? () => onAvatarClick(null) : undefined}\n isFollowing={isFollowingAgent}\n />\n )}\n {visibleUsers.length > 0 && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n marginLeft: showAgent ? 6 : 0,\n }}\n >\n {visibleUsers.map((u, i) => (\n <UserAvatar\n key={u.email}\n user={u}\n isFirst={i === 0}\n onClick={onAvatarClick ? () => onAvatarClick(u) : undefined}\n isFollowing={\n followingLower != null &&\n u.email.trim().toLowerCase() === followingLower\n }\n />\n ))}\n {overflowCount > 0 && (\n <OverflowBadge count={overflowCount} isFirst={false} />\n )}\n </div>\n )}\n </div>\n </TooltipProvider>\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposerPlusMenu.d.ts","sourceRoot":"","sources":["../../../src/client/composer/ComposerPlusMenu.tsx"],"names":[],"mappings":"AAcA,OAAO,
|
|
1
|
+
{"version":3,"file":"ComposerPlusMenu.d.ts","sourceRoot":"","sources":["../../../src/client/composer/ComposerPlusMenu.tsx"],"names":[],"mappings":"AAcA,OAAO,KAMN,MAAM,OAAO,CAAC;AAwBf,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,UAAU,qBAAqB;IAC7B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;CAC/B;AAwLD,wBAAgB,gBAAgB,CAAC,EAC/B,YAAY,EACZ,iBAAiB,EACjB,IAAa,GACd,EAAE,qBAAqB,qBAUvB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useComposerRuntime } from "@assistant-ui/react";
|
|
3
3
|
import { IconPlus, IconUpload, IconBulb, IconClock, IconBolt, IconTool, IconPlugConnected, IconPhotoPlus, IconLoader2, IconArrowLeft, IconX, } from "@tabler/icons-react";
|
|
4
|
-
import { useState, useRef, useEffect, useMemo } from "react";
|
|
4
|
+
import { useState, useRef, useEffect, useMemo, useCallback, } from "react";
|
|
5
5
|
import { createPortal } from "react-dom";
|
|
6
6
|
import { setAgentChatContextItem } from "../agent-chat.js";
|
|
7
7
|
import { agentNativePath } from "../api-path.js";
|
|
@@ -372,6 +372,14 @@ function AssetsPickerModal({ open, onOpenChange, }) {
|
|
|
372
372
|
const sourceUrl = useMemo(() => assetPickerUrl(), []);
|
|
373
373
|
const iframeUrl = useMemo(() => withEmbeddedParams(sourceUrl), [sourceUrl]);
|
|
374
374
|
const targetOrigin = useMemo(() => assetPickerOrigin(iframeUrl), [iframeUrl]);
|
|
375
|
+
const configurePicker = useCallback(() => {
|
|
376
|
+
if (!targetOrigin)
|
|
377
|
+
return;
|
|
378
|
+
iframeRef.current?.contentWindow?.postMessage(embedEnvelope("message", {
|
|
379
|
+
name: "configure",
|
|
380
|
+
payload: { mediaType: "image", count: 3 },
|
|
381
|
+
}), targetOrigin);
|
|
382
|
+
}, [targetOrigin]);
|
|
375
383
|
useEffect(() => {
|
|
376
384
|
if (open)
|
|
377
385
|
setPickerReady(false);
|
|
@@ -388,10 +396,7 @@ function AssetsPickerModal({ open, onOpenChange, }) {
|
|
|
388
396
|
return;
|
|
389
397
|
if (event.data.type === "ready") {
|
|
390
398
|
setPickerReady(true);
|
|
391
|
-
|
|
392
|
-
name: "configure",
|
|
393
|
-
payload: { mediaType: "image", count: 3 },
|
|
394
|
-
}), targetOrigin);
|
|
399
|
+
configurePicker();
|
|
395
400
|
return;
|
|
396
401
|
}
|
|
397
402
|
if (event.data.type !== "message")
|
|
@@ -427,13 +432,16 @@ function AssetsPickerModal({ open, onOpenChange, }) {
|
|
|
427
432
|
window.removeEventListener("message", handleMessage);
|
|
428
433
|
window.removeEventListener("keydown", handleKey);
|
|
429
434
|
};
|
|
430
|
-
}, [onOpenChange, open, targetOrigin]);
|
|
435
|
+
}, [configurePicker, onOpenChange, open, targetOrigin]);
|
|
431
436
|
if (!open || typeof document === "undefined")
|
|
432
437
|
return null;
|
|
433
438
|
return createPortal(_jsx("div", { className: "fixed inset-0 z-[280] flex items-center justify-center bg-black/50 p-3", role: "dialog", "aria-modal": "true", "aria-labelledby": "composer-assets-picker-title", onMouseDown: (event) => {
|
|
434
439
|
if (event.target === event.currentTarget)
|
|
435
440
|
onOpenChange(false);
|
|
436
|
-
}, children: _jsxs("div", { className: "flex h-[min(86vh,760px)] w-[min(96vw,1040px)] flex-col overflow-hidden rounded-xl border border-border bg-background shadow-2xl", children: [_jsxs("div", { className: "flex h-12 shrink-0 items-center justify-between border-b border-border px-4", children: [_jsx("div", { id: "composer-assets-picker-title", className: "text-sm font-medium text-foreground", children: "Generate image" }), _jsx("button", { type: "button", onClick: () => onOpenChange(false), className: "flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", "aria-label": "Close image picker", children: _jsx(IconX, { className: "h-4 w-4" }) })] }), targetOrigin ? (_jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden bg-background", children: [!pickerReady && _jsx(AssetsPickerLoadingSkeleton, {}), _jsx("iframe", { ref: iframeRef, src: iframeUrl, title: "Assets image picker", className: cn("absolute inset-0 h-full w-full border-0 bg-background transition-opacity duration-150", pickerReady ? "opacity-100" : "pointer-events-none opacity-0"), sandbox: "allow-scripts allow-same-origin allow-forms allow-popups allow-downloads", allow: "clipboard-read; clipboard-write; microphone; fullscreen", referrerPolicy: "strict-origin-when-cross-origin"
|
|
441
|
+
}, children: _jsxs("div", { className: "flex h-[min(86vh,760px)] w-[min(96vw,1040px)] flex-col overflow-hidden rounded-xl border border-border bg-background shadow-2xl", children: [_jsxs("div", { className: "flex h-12 shrink-0 items-center justify-between border-b border-border px-4", children: [_jsx("div", { id: "composer-assets-picker-title", className: "text-sm font-medium text-foreground", children: "Generate image" }), _jsx("button", { type: "button", onClick: () => onOpenChange(false), className: "flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", "aria-label": "Close image picker", children: _jsx(IconX, { className: "h-4 w-4" }) })] }), targetOrigin ? (_jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden bg-background", children: [!pickerReady && _jsx(AssetsPickerLoadingSkeleton, {}), _jsx("iframe", { ref: iframeRef, src: iframeUrl, title: "Assets image picker", className: cn("absolute inset-0 h-full w-full border-0 bg-background transition-opacity duration-150", pickerReady ? "opacity-100" : "pointer-events-none opacity-0"), sandbox: "allow-scripts allow-same-origin allow-forms allow-popups allow-downloads", allow: "clipboard-read; clipboard-write; microphone; fullscreen", referrerPolicy: "strict-origin-when-cross-origin", onLoad: () => {
|
|
442
|
+
configurePicker();
|
|
443
|
+
setPickerReady(true);
|
|
444
|
+
} })] })) : (_jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center p-8 text-center text-sm text-muted-foreground", children: "The configured image picker URL is not valid." }))] }) }), document.body);
|
|
437
445
|
}
|
|
438
446
|
function AssetsPickerLoadingSkeleton() {
|
|
439
447
|
return (_jsxs("div", { className: "absolute inset-0 flex flex-col gap-5 p-5", role: "status", "aria-label": "Loading Assets picker", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "h-9 flex-1 animate-pulse rounded-md bg-muted" }), _jsx("div", { className: "h-9 w-24 animate-pulse rounded-md bg-muted" })] }), _jsx("div", { className: "grid min-h-0 flex-1 grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4", children: Array.from({ length: 8 }).map((_, index) => (_jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [_jsx("div", { className: "aspect-square w-full animate-pulse rounded-lg bg-muted" }), _jsx("div", { className: "h-3 w-3/4 animate-pulse rounded bg-muted" }), _jsx("div", { className: "h-3 w-1/2 animate-pulse rounded bg-muted" })] }, index))) })] }));
|