@agent-native/core 0.45.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +1 -0
  2. package/dist/action.d.ts +8 -1
  3. package/dist/action.d.ts.map +1 -1
  4. package/dist/action.js +20 -10
  5. package/dist/action.js.map +1 -1
  6. package/dist/cli/app-skill.d.ts +3 -1
  7. package/dist/cli/app-skill.d.ts.map +1 -1
  8. package/dist/cli/app-skill.js +50 -8
  9. package/dist/cli/app-skill.js.map +1 -1
  10. package/dist/cli/connect.d.ts.map +1 -1
  11. package/dist/cli/connect.js +39 -5
  12. package/dist/cli/connect.js.map +1 -1
  13. package/dist/cli/create.d.ts.map +1 -1
  14. package/dist/cli/create.js +9 -7
  15. package/dist/cli/create.js.map +1 -1
  16. package/dist/cli/index.js +42 -10
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/cli/mcp-config-writers.d.ts +10 -0
  19. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  20. package/dist/cli/mcp-config-writers.js +60 -6
  21. package/dist/cli/mcp-config-writers.js.map +1 -1
  22. package/dist/cli/mcp.d.ts.map +1 -1
  23. package/dist/cli/mcp.js +4 -6
  24. package/dist/cli/mcp.js.map +1 -1
  25. package/dist/cli/plan-local.d.ts.map +1 -1
  26. package/dist/cli/plan-local.js +15 -2
  27. package/dist/cli/plan-local.js.map +1 -1
  28. package/dist/cli/plan-publish-store.d.ts +17 -7
  29. package/dist/cli/plan-publish-store.d.ts.map +1 -1
  30. package/dist/cli/plan-publish-store.js +33 -8
  31. package/dist/cli/plan-publish-store.js.map +1 -1
  32. package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
  33. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  34. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  35. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  36. package/dist/cli/recap.d.ts +63 -5
  37. package/dist/cli/recap.d.ts.map +1 -1
  38. package/dist/cli/recap.js +641 -48
  39. package/dist/cli/recap.js.map +1 -1
  40. package/dist/cli/skills.d.ts +26 -11
  41. package/dist/cli/skills.d.ts.map +1 -1
  42. package/dist/cli/skills.js +644 -972
  43. package/dist/cli/skills.js.map +1 -1
  44. package/dist/cli/templates-meta.d.ts.map +1 -1
  45. package/dist/cli/templates-meta.js +3 -2
  46. package/dist/cli/templates-meta.js.map +1 -1
  47. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  48. package/dist/client/blocks/library/AnnotatedCodeBlock.js +37 -9
  49. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  50. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  51. package/dist/client/blocks/library/DiffBlock.js +44 -12
  52. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  53. package/dist/client/blocks/library/annotation-rail.d.ts +12 -3
  54. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
  55. package/dist/client/blocks/library/annotation-rail.js +29 -3
  56. package/dist/client/blocks/library/annotation-rail.js.map +1 -1
  57. package/dist/client/blocks/library/html.d.ts.map +1 -1
  58. package/dist/client/blocks/library/html.js +3 -1
  59. package/dist/client/blocks/library/html.js.map +1 -1
  60. package/dist/client/blocks/library/question-form.d.ts.map +1 -1
  61. package/dist/client/blocks/library/question-form.js +4 -1
  62. package/dist/client/blocks/library/question-form.js.map +1 -1
  63. package/dist/client/components/LiveCursorOverlay.d.ts +46 -0
  64. package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -0
  65. package/dist/client/components/LiveCursorOverlay.js +137 -0
  66. package/dist/client/components/LiveCursorOverlay.js.map +1 -0
  67. package/dist/client/components/PresenceBar.d.ts +11 -1
  68. package/dist/client/components/PresenceBar.d.ts.map +1 -1
  69. package/dist/client/components/PresenceBar.js +39 -7
  70. package/dist/client/components/PresenceBar.js.map +1 -1
  71. package/dist/client/components/RemoteSelectionRings.d.ts +43 -0
  72. package/dist/client/components/RemoteSelectionRings.d.ts.map +1 -0
  73. package/dist/client/components/RemoteSelectionRings.js +116 -0
  74. package/dist/client/components/RemoteSelectionRings.js.map +1 -0
  75. package/dist/client/index.d.ts +4 -0
  76. package/dist/client/index.d.ts.map +1 -1
  77. package/dist/client/index.js +5 -0
  78. package/dist/client/index.js.map +1 -1
  79. package/dist/collab/awareness.d.ts +25 -0
  80. package/dist/collab/awareness.d.ts.map +1 -1
  81. package/dist/collab/awareness.js +42 -5
  82. package/dist/collab/awareness.js.map +1 -1
  83. package/dist/collab/client.d.ts +19 -1
  84. package/dist/collab/client.d.ts.map +1 -1
  85. package/dist/collab/client.js +362 -57
  86. package/dist/collab/client.js.map +1 -1
  87. package/dist/collab/follow-mode.d.ts +56 -0
  88. package/dist/collab/follow-mode.d.ts.map +1 -0
  89. package/dist/collab/follow-mode.js +54 -0
  90. package/dist/collab/follow-mode.js.map +1 -0
  91. package/dist/collab/index.d.ts +3 -1
  92. package/dist/collab/index.d.ts.map +1 -1
  93. package/dist/collab/index.js +5 -1
  94. package/dist/collab/index.js.map +1 -1
  95. package/dist/collab/presence.d.ts +56 -0
  96. package/dist/collab/presence.d.ts.map +1 -0
  97. package/dist/collab/presence.js +98 -0
  98. package/dist/collab/presence.js.map +1 -0
  99. package/dist/collab/routes.d.ts.map +1 -1
  100. package/dist/collab/routes.js +33 -6
  101. package/dist/collab/routes.js.map +1 -1
  102. package/dist/collab/struct-routes.d.ts.map +1 -1
  103. package/dist/collab/struct-routes.js +24 -4
  104. package/dist/collab/struct-routes.js.map +1 -1
  105. package/dist/collab/ydoc-manager.d.ts +13 -0
  106. package/dist/collab/ydoc-manager.d.ts.map +1 -1
  107. package/dist/collab/ydoc-manager.js +51 -15
  108. package/dist/collab/ydoc-manager.js.map +1 -1
  109. package/dist/db/migrations.d.ts.map +1 -1
  110. package/dist/db/migrations.js +2 -1
  111. package/dist/db/migrations.js.map +1 -1
  112. package/dist/extensions/routes.d.ts +18 -0
  113. package/dist/extensions/routes.d.ts.map +1 -1
  114. package/dist/extensions/routes.js +30 -8
  115. package/dist/extensions/routes.js.map +1 -1
  116. package/dist/oauth-tokens/store.d.ts.map +1 -1
  117. package/dist/oauth-tokens/store.js +42 -5
  118. package/dist/oauth-tokens/store.js.map +1 -1
  119. package/dist/scripts/db/index.d.ts.map +1 -1
  120. package/dist/scripts/db/index.js +1 -0
  121. package/dist/scripts/db/index.js.map +1 -1
  122. package/dist/scripts/db/migrate-encrypt-oauth-tokens.d.ts +28 -0
  123. package/dist/scripts/db/migrate-encrypt-oauth-tokens.d.ts.map +1 -0
  124. package/dist/scripts/db/migrate-encrypt-oauth-tokens.js +164 -0
  125. package/dist/scripts/db/migrate-encrypt-oauth-tokens.js.map +1 -0
  126. package/dist/scripts/db/scoping.d.ts.map +1 -1
  127. package/dist/scripts/db/scoping.js +7 -5
  128. package/dist/scripts/db/scoping.js.map +1 -1
  129. package/dist/secrets/index.d.ts +1 -0
  130. package/dist/secrets/index.d.ts.map +1 -1
  131. package/dist/secrets/index.js +4 -0
  132. package/dist/secrets/index.js.map +1 -1
  133. package/dist/server/collab-plugin.d.ts +6 -0
  134. package/dist/server/collab-plugin.d.ts.map +1 -1
  135. package/dist/server/collab-plugin.js +105 -5
  136. package/dist/server/collab-plugin.js.map +1 -1
  137. package/dist/server/poll-events.d.ts +5 -0
  138. package/dist/server/poll-events.d.ts.map +1 -1
  139. package/dist/server/poll-events.js +27 -4
  140. package/dist/server/poll-events.js.map +1 -1
  141. package/dist/sharing/actions/set-resource-visibility.d.ts.map +1 -1
  142. package/dist/sharing/actions/set-resource-visibility.js +4 -1
  143. package/dist/sharing/actions/set-resource-visibility.js.map +1 -1
  144. package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +185 -37
  145. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +12 -2
  146. package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +185 -37
  147. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +12 -2
  148. package/docs/content/plan-plugin.md +21 -6
  149. package/docs/content/pr-visual-recap.md +52 -3
  150. package/docs/content/real-time-collaboration.md +481 -97
  151. package/docs/content/skills-guide.md +13 -0
  152. package/docs/content/template-plan.md +18 -7
  153. package/package.json +5 -1
  154. package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +185 -37
  155. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +12 -2
  156. package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +185 -37
  157. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +12 -2
@@ -1 +1 @@
1
- {"version":3,"file":"annotation-rail.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/annotation-rail.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockRenderContext } from \"../types.js\";\n\n/**\n * Shared line-anchored annotation UI for the `annotated-code` and `diff` blocks.\n *\n * Both blocks render a numbered code surface plus a side \"rail\" of notes, where\n * each note targets a 1-based `lines` ref (`\"3\"` or `\"3-5\"`) and hovering a code\n * line ↔ its note cross-highlights. This module owns the pure pieces that were\n * identical between them so neither block forks the behavior:\n *\n * - `parseLineRange` — the forgiving 1-based `lines` range parser.\n * - `resolveAnnotations` / `buildLineMarkerMap` — turn a raw annotation list\n * into stable, marker-numbered, range-resolved records and a line→markers map.\n * - `rangeLabel` — the human \"Line 8\" / \"Lines 3–6\" label.\n * - `AnnotationGutterMarker` — the numbered amber pip placed on an annotated row\n * (used by the diff grid; the annotated-code surface uses its own rail bar).\n * - `AnnotationNoteRail` — the responsive list of note cards with two-way hover.\n * `showMarker` opts the diff block into a leading numbered pip on each card so\n * a note can be matched to its `①`/`②` row marker; annotated-code omits it to\n * keep its original card chrome.\n *\n * `AnnotatedCodeBlock` annotates a single code surface; `DiffBlock` annotates a\n * before/after grid (each annotation also carries a `side`). The shared types\n * here are intentionally minimal — callers pass their own `side` handling and\n * decide which rows a marker lands on; this module only owns the parsing, the\n * resolved-record shape, and the rendered marker + rail chrome.\n */\n\n/* ── Line-ref parsing ──────────────────────────────────────────────────────── */\n\n/**\n * Parse a 1-based `lines` ref (`\"3\"` or `\"3-5\"`) into an inclusive `[start,end]`\n * pair, clamped to `[1, lineCount]`. Returns `null` for malformed or fully\n * out-of-range refs so callers can ignore them gracefully. A reversed range\n * (`\"5-3\"`) is normalized; a partially out-of-range range is clamped.\n */\nexport function parseLineRange(\n ref: string,\n lineCount: number,\n): { start: number; end: number } | null {\n const match = /^\\s*(\\d+)\\s*(?:-\\s*(\\d+)\\s*)?$/.exec(ref);\n if (!match) return null;\n let start = Number.parseInt(match[1], 10);\n let end = match[2] != null ? Number.parseInt(match[2], 10) : start;\n if (!Number.isFinite(start) || !Number.isFinite(end)) return null;\n if (start > end) [start, end] = [end, start];\n // Fully outside the file → ignore.\n if (end < 1 || start > lineCount) return null;\n return { start: Math.max(1, start), end: Math.min(lineCount, end) };\n}\n\n/** The minimal annotation shape the rail needs (a superset works too). */\nexport interface RailAnnotation {\n lines: string;\n label?: string;\n note: string;\n}\n\nexport interface ResolvedAnnotation<A extends RailAnnotation = RailAnnotation> {\n /** Index in the original `annotations` array (stable hover key). */\n index: number;\n /** 1-based marker number (authoring order). */\n marker: number;\n annotation: A;\n range: { start: number; end: number } | null;\n}\n\n/**\n * Resolve a raw annotation list into stable, marker-numbered records, parsing\n * each `lines` ref against `lineCount`. `lineCountFor` lets the diff block pick a\n * per-annotation line count (before-side vs after-side); annotated-code passes a\n * single constant. Markers are authoring-order, 1-based, and assigned to ALL\n * annotations (even unresolved ones) so numbering is stable regardless of which\n * refs happen to match.\n */\nexport function resolveAnnotations<A extends RailAnnotation>(\n annotations: A[] | undefined,\n lineCountFor: (annotation: A) => number,\n): ResolvedAnnotation<A>[] {\n return (annotations ?? []).map((annotation, index) => ({\n index,\n marker: index + 1,\n annotation,\n range: parseLineRange(annotation.lines, lineCountFor(annotation)),\n }));\n}\n\n/** Map a 1-based line number → the resolved annotations covering it. */\nexport function buildLineMarkerMap<A extends RailAnnotation>(\n resolved: ResolvedAnnotation<A>[],\n): Map<number, ResolvedAnnotation<A>[]> {\n const map = new Map<number, ResolvedAnnotation<A>[]>();\n for (const item of resolved) {\n if (!item.range) continue;\n for (let n = item.range.start; n <= item.range.end; n += 1) {\n const list = map.get(n) ?? [];\n list.push(item);\n map.set(n, list);\n }\n }\n return map;\n}\n\n/** Human label for a resolved annotation's line span (\"Line 8\" / \"Lines 3–6\"). */\nexport function rangeLabel(item: ResolvedAnnotation): string {\n if (!item.range) return `Lines ${item.annotation.lines}`;\n return item.range.start === item.range.end\n ? `Line ${item.range.start}`\n : `Lines ${item.range.start}–${item.range.end}`;\n}\n\n/* ── Marker ────────────────────────────────────────────────────────────────── */\n\n/**\n * The numbered amber pip rendered on an annotated code row's gutter. `active`\n * brightens it when its note (or a co-located row) is hovered.\n */\nexport function AnnotationGutterMarker({\n marker,\n active,\n className,\n}: {\n marker: number;\n active: boolean;\n className?: string;\n}) {\n return (\n <span\n aria-hidden\n className={cn(\n \"inline-flex size-[15px] shrink-0 items-center justify-center rounded-full text-[9px] font-semibold leading-none tabular-nums transition-colors\",\n active\n ? \"bg-amber-500 text-white dark:bg-amber-400 dark:text-amber-950\"\n : \"bg-amber-400/25 text-amber-700 dark:bg-amber-300/20 dark:text-amber-300\",\n className,\n )}\n >\n {marker}\n </span>\n );\n}\n\n/* ── Note card ─────────────────────────────────────────────────────────────── */\n\n/**\n * One line-anchored note card: marker pip (when `showMarker`), the resolved line\n * span (\"Line 8\"), an optional label, and the markdown `note` (via\n * `ctx.renderMarkdown`). This is the single source of card markup, rendered both\n * by the visually-hidden a11y/test stack and by the on-hover portal popover.\n */\nexport function AnnotationCard<A extends RailAnnotation>({\n item,\n ctx,\n active = false,\n showMarker = false,\n className,\n onMouseEnter,\n onMouseLeave,\n}: {\n item: ResolvedAnnotation<A>;\n ctx: BlockRenderContext;\n active?: boolean;\n showMarker?: boolean;\n className?: string;\n onMouseEnter?: () => void;\n onMouseLeave?: () => void;\n}) {\n return (\n <div\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n className={cn(\n \"rounded-lg border px-3.5 py-2.5 transition-colors\",\n active\n ? \"border-amber-400/70 bg-amber-50 dark:border-amber-300/40 dark:bg-amber-300/[0.08]\"\n : \"border-plan-line bg-plan-block/40 hover:border-amber-400/50\",\n className,\n )}\n >\n <div\n className={cn(\n \"flex flex-wrap gap-x-2 gap-y-0.5\",\n showMarker ? \"items-center\" : \"items-baseline\",\n )}\n >\n {showMarker && (\n <AnnotationGutterMarker marker={item.marker} active={active} />\n )}\n <span className=\"text-[11px] font-semibold uppercase tracking-wide text-plan-muted\">\n {rangeLabel(item)}\n </span>\n {item.annotation.label && (\n <span className=\"text-[13px] font-semibold text-plan-text\">\n {item.annotation.label}\n </span>\n )}\n </div>\n <div className=\"plan-annotation-note mt-1 text-[13px] leading-relaxed text-plan-text/85\">\n {ctx.renderMarkdown ? (\n ctx.renderMarkdown(item.annotation.note)\n ) : (\n <p>{item.annotation.note}</p>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Visually-hidden stack of every resolved note. It is NOT a visible column — it\n * sits in the flow but clipped to a 1px box (the `sr-only` pattern) so the note\n * text and the per-card marker pips stay in the accessibility tree and in the\n * DOM (assistive tech can reach them, and tests that read `textContent`/count\n * pips still see them) WITHOUT painting a persistent rail beside the code. The\n * visible card appears only on hover via {@link AnnotationHoverCard}.\n */\nexport function AnnotationHiddenStack<A extends RailAnnotation>({\n items,\n ctx,\n showMarker = false,\n}: {\n items: ResolvedAnnotation<A>[];\n ctx: BlockRenderContext;\n showMarker?: boolean;\n}) {\n const resolved = useMemo(() => items.filter((item) => item.range), [items]);\n if (resolved.length === 0) return null;\n return (\n <div\n className=\"absolute size-px overflow-hidden whitespace-nowrap border-0 p-0 [clip:rect(0,0,0,0)] [clip-path:inset(50%)]\"\n data-annotation-hidden-stack\n >\n {resolved.map((item) => (\n <AnnotationCard\n key={item.index}\n item={item}\n ctx={ctx}\n showMarker={showMarker}\n />\n ))}\n </div>\n );\n}\n\n/* ── Hover popover (portal, anchored beside the code) ──────────────────────── */\n\n/** The geometry the hover card anchors to (in viewport coordinates). */\nexport interface AnnotationAnchor {\n /** Right edge of the code block (where the card should start). */\n codeRight: number;\n /** Left edge of the code block (for the below-fallback alignment). */\n codeLeft: number;\n /** Vertical center of the hovered line. */\n lineCenter: number;\n /** Bottom of the hovered line (for the below-fallback placement). */\n lineBottom: number;\n}\n\nconst HOVER_CARD_WIDTH = 280;\nconst HOVER_CARD_GAP = 12;\nconst VIEWPORT_MARGIN = 8;\n\nexport function resolveAnnotationHoverCardPosition(\n anchor: AnnotationAnchor,\n card: { width: number; height: number },\n viewport: { width: number; height: number },\n): { top: number; left: number } {\n const rightLeft = anchor.codeRight + HOVER_CARD_GAP;\n const fitsRight = rightLeft + card.width + VIEWPORT_MARGIN <= viewport.width;\n const leftLeft = anchor.codeLeft - HOVER_CARD_GAP - card.width;\n const fitsLeft = leftLeft >= VIEWPORT_MARGIN;\n\n let left: number;\n let top: number;\n if (fitsRight) {\n // Default: to the right of the code, centered on the hovered line.\n left = rightLeft;\n top = anchor.lineCenter - card.height / 2;\n } else if (fitsLeft) {\n // Prefer the left gutter over covering the code below the hovered line.\n left = leftLeft;\n top = anchor.lineCenter - card.height / 2;\n } else {\n // No clean side gutter → drop below the line, aligned to the code's left.\n left = anchor.codeLeft;\n top = anchor.lineBottom + HOVER_CARD_GAP;\n }\n\n // Clamp within the viewport so the card is never cut off.\n left = Math.max(\n VIEWPORT_MARGIN,\n Math.min(left, viewport.width - card.width - VIEWPORT_MARGIN),\n );\n top = Math.max(\n VIEWPORT_MARGIN,\n Math.min(top, viewport.height - card.height - VIEWPORT_MARGIN),\n );\n\n return { top, left };\n}\n\n/**\n * The single on-hover note card, portaled to `document.body` and positioned\n * `fixed` so it escapes the code block's `overflow` and never reflows the code.\n *\n * Placement: by default it sits to the RIGHT of the code block's right edge,\n * vertically centered on the hovered line — so it never overlaps the code text.\n * If there isn't room to the right, it uses the LEFT of the code block when the\n * card can fit there without covering code. Only when neither side fits does it\n * fall back to BELOW the hovered line (left-aligned to the code block). The card\n * keeps itself open while hovered (`onMouseEnter`/`onMouseLeave` forwarded) so\n * it stays readable; the caller adds the small hover-intent close delay.\n */\nexport function AnnotationHoverCard<A extends RailAnnotation>({\n item,\n anchor,\n ctx,\n showMarker = false,\n onMouseEnter,\n onMouseLeave,\n}: {\n item: ResolvedAnnotation<A>;\n anchor: AnnotationAnchor;\n ctx: BlockRenderContext;\n showMarker?: boolean;\n onMouseEnter?: () => void;\n onMouseLeave?: () => void;\n}) {\n const cardRef = useRef<HTMLDivElement | null>(null);\n const [pos, setPos] = useState<{ top: number; left: number } | null>(null);\n\n // Measure the rendered card, then resolve a non-overlapping position: right of\n // the code if it fits, then left if that side has a clean gutter, otherwise\n // below the line.\n useLayoutEffect(() => {\n if (typeof window === \"undefined\") return;\n const el = cardRef.current;\n const rect = el?.getBoundingClientRect();\n const width = rect && rect.width > 0 ? rect.width : HOVER_CARD_WIDTH;\n const height = rect && rect.height > 0 ? rect.height : 0;\n const vw = window.innerWidth || 0;\n const vh = window.innerHeight || 0;\n setPos(\n resolveAnnotationHoverCardPosition(\n anchor,\n { width, height },\n { width: vw, height: vh },\n ),\n );\n }, [\n anchor.codeRight,\n anchor.codeLeft,\n anchor.lineCenter,\n anchor.lineBottom,\n item.index,\n ]);\n\n if (typeof document === \"undefined\") return null;\n\n return createPortal(\n <div\n ref={cardRef}\n role=\"tooltip\"\n data-annotation-hover-card\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n className=\"pointer-events-auto fixed z-50\"\n style={{\n top: pos?.top ?? anchor.lineCenter,\n left: pos?.left ?? anchor.codeRight + HOVER_CARD_GAP,\n width: HOVER_CARD_WIDTH,\n // Hide until measured to avoid a one-frame jump from the fallback spot.\n visibility: pos ? \"visible\" : \"hidden\",\n }}\n >\n <AnnotationCard\n item={item}\n ctx={ctx}\n active\n showMarker={showMarker}\n className=\"shadow-lg shadow-black/10 dark:shadow-black/40\"\n />\n </div>,\n document.body,\n );\n}\n\n/**\n * Hover-intent controller for the on-hover note card. Exposes `activeIndex` +\n * the captured `anchor`, plus `open`/`scheduleClose`/`cancelClose` handlers.\n *\n * - `open(index, anchor)` shows a card immediately (cancels any pending close).\n * - `scheduleClose()` hides after a short delay, so moving the pointer from the\n * code line across the gap into the card itself keeps it open.\n * - `cancelClose()` (call on card mouse-enter) keeps it open while reading.\n */\nexport function useAnnotationHover(delay = 130) {\n const [active, setActive] = useState<{\n index: number;\n anchor: AnnotationAnchor;\n } | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const cancelClose = () => {\n if (timer.current) {\n clearTimeout(timer.current);\n timer.current = null;\n }\n };\n const open = (index: number, anchor: AnnotationAnchor) => {\n cancelClose();\n setActive({ index, anchor });\n };\n const scheduleClose = () => {\n cancelClose();\n timer.current = setTimeout(() => setActive(null), delay);\n };\n\n useEffect(() => () => cancelClose(), []);\n\n return {\n activeIndex: active?.index ?? null,\n anchor: active?.anchor ?? null,\n open,\n scheduleClose,\n cancelClose,\n } as const;\n}\n\n/**\n * Build an {@link AnnotationAnchor} from the code block element and the hovered\n * row element. The card anchors to the code block's RIGHT edge and the row's\n * vertical center, both in viewport coordinates (so a `fixed` portal lines up).\n */\nexport function anchorFromElements(\n codeEl: HTMLElement | null,\n rowEl: HTMLElement | null,\n): AnnotationAnchor | null {\n if (!codeEl || !rowEl) return null;\n const code = codeEl.getBoundingClientRect();\n const row = rowEl.getBoundingClientRect();\n return {\n codeRight: code.right,\n codeLeft: code.left,\n lineCenter: row.top + row.height / 2,\n lineBottom: row.bottom,\n };\n}\n\n/**\n * The responsive list of line-anchored note cards. Each card shows its marker\n * pip, the resolved line span (\"Line 8\"), an optional label, and the markdown\n * `note` (via `ctx.renderMarkdown`). Hovering a card sets the active index;\n * `activeIndex` driven from outside lets a hovered code row light its card and\n * vice-versa. Only annotations whose `range` resolved are listed.\n *\n * @deprecated Superseded by the on-hover {@link AnnotationHoverCard}; kept for\n * back-compat with any external importer. Both block read renderers now use the\n * hover popover anchored to the right of the code instead of a persistent rail.\n */\nexport function AnnotationNoteRail<A extends RailAnnotation>({\n items,\n activeIndex,\n onActiveChange,\n ctx,\n className,\n showMarker = false,\n}: {\n items: ResolvedAnnotation<A>[];\n activeIndex: number | null;\n onActiveChange: (index: number | null) => void;\n ctx: BlockRenderContext;\n className?: string;\n /** Show a leading numbered pip on each card (diff block). */\n showMarker?: boolean;\n}) {\n const sideAnnotations = useMemo(\n () => items.filter((item) => item.range),\n [items],\n );\n return (\n <div className={cn(\"flex flex-col gap-2.5\", className)}>\n {sideAnnotations.map((item) => (\n <AnnotationCard\n key={item.index}\n item={item}\n ctx={ctx}\n active={activeIndex === item.index}\n showMarker={showMarker}\n onMouseEnter={() => onActiveChange(item.index)}\n onMouseLeave={() => onActiveChange(null)}\n />\n ))}\n </div>\n );\n}\n\n/** Whether a resolved list has at least one note worth rendering a rail for. */\nexport function hasRailAnnotations(items: ResolvedAnnotation[]): boolean {\n return items.some((item) => item.range);\n}\n\nexport type AnnotationRailChildren = ReactNode;\n"]}
1
+ {"version":3,"file":"annotation-rail.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/annotation-rail.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockRenderContext } from \"../types.js\";\n\n/**\n * Shared line-anchored annotation UI for the `annotated-code` and `diff` blocks.\n *\n * Both blocks render a numbered code surface plus a side \"rail\" of notes, where\n * each note targets a 1-based `lines` ref (`\"3\"` or `\"3-5\"`) and hovering a code\n * line ↔ its note cross-highlights. This module owns the pure pieces that were\n * identical between them so neither block forks the behavior:\n *\n * - `parseLineRange` — the forgiving 1-based `lines` range parser.\n * - `resolveAnnotations` / `buildLineMarkerMap` — turn a raw annotation list\n * into stable, marker-numbered, range-resolved records and a line→markers map.\n * - `rangeLabel` — the human \"Line 8\" / \"Lines 3–6\" label.\n * - `AnnotationGutterMarker` — the numbered amber pip placed on an annotated row\n * (used by the diff grid; the annotated-code surface uses its own rail bar).\n * - `AnnotationNoteRail` — the responsive list of note cards with two-way hover.\n * `showMarker` opts the diff block into a leading numbered pip on each card so\n * a note can be matched to its `①`/`②` row marker; annotated-code omits it to\n * keep its original card chrome.\n *\n * `AnnotatedCodeBlock` annotates a single code surface; `DiffBlock` annotates a\n * before/after grid (each annotation also carries a `side`). The shared types\n * here are intentionally minimal — callers pass their own `side` handling and\n * decide which rows a marker lands on; this module only owns the parsing, the\n * resolved-record shape, and the rendered marker + rail chrome.\n */\n\n/* ── Line-ref parsing ──────────────────────────────────────────────────────── */\n\n/**\n * Parse a 1-based `lines` ref (`\"3\"` or `\"3-5\"`) into an inclusive `[start,end]`\n * pair, clamped to `[1, lineCount]`. Returns `null` for malformed or fully\n * out-of-range refs so callers can ignore them gracefully. A reversed range\n * (`\"5-3\"`) is normalized; a partially out-of-range range is clamped.\n */\nexport function parseLineRange(\n ref: string,\n lineCount: number,\n): { start: number; end: number } | null {\n const match = /^\\s*(\\d+)\\s*(?:-\\s*(\\d+)\\s*)?$/.exec(ref);\n if (!match) return null;\n let start = Number.parseInt(match[1], 10);\n let end = match[2] != null ? Number.parseInt(match[2], 10) : start;\n if (!Number.isFinite(start) || !Number.isFinite(end)) return null;\n if (start > end) [start, end] = [end, start];\n // Fully outside the file → ignore.\n if (end < 1 || start > lineCount) return null;\n return { start: Math.max(1, start), end: Math.min(lineCount, end) };\n}\n\n/** The minimal annotation shape the rail needs (a superset works too). */\nexport interface RailAnnotation {\n lines: string;\n label?: string;\n note: string;\n}\n\nexport interface ResolvedAnnotation<A extends RailAnnotation = RailAnnotation> {\n /** Index in the original `annotations` array (stable hover key). */\n index: number;\n /** 1-based marker number (authoring order). */\n marker: number;\n annotation: A;\n range: { start: number; end: number } | null;\n}\n\n/**\n * Resolve a raw annotation list into stable, marker-numbered records, parsing\n * each `lines` ref against `lineCount`. `lineCountFor` lets the diff block pick a\n * per-annotation line count (before-side vs after-side); annotated-code passes a\n * single constant. Markers are authoring-order, 1-based, and assigned to ALL\n * annotations (even unresolved ones) so numbering is stable regardless of which\n * refs happen to match.\n */\nexport function resolveAnnotations<A extends RailAnnotation>(\n annotations: A[] | undefined,\n lineCountFor: (annotation: A) => number,\n): ResolvedAnnotation<A>[] {\n return (annotations ?? []).map((annotation, index) => ({\n index,\n marker: index + 1,\n annotation,\n range: parseLineRange(annotation.lines, lineCountFor(annotation)),\n }));\n}\n\n/** Map a 1-based line number → the resolved annotations covering it. */\nexport function buildLineMarkerMap<A extends RailAnnotation>(\n resolved: ResolvedAnnotation<A>[],\n): Map<number, ResolvedAnnotation<A>[]> {\n const map = new Map<number, ResolvedAnnotation<A>[]>();\n for (const item of resolved) {\n if (!item.range) continue;\n for (let n = item.range.start; n <= item.range.end; n += 1) {\n const list = map.get(n) ?? [];\n list.push(item);\n map.set(n, list);\n }\n }\n return map;\n}\n\n/** Human label for a resolved annotation's line span (\"Line 8\" / \"Lines 3–6\"). */\nexport function rangeLabel(item: ResolvedAnnotation): string {\n if (!item.range) return `Lines ${item.annotation.lines}`;\n return item.range.start === item.range.end\n ? `Line ${item.range.start}`\n : `Lines ${item.range.start}–${item.range.end}`;\n}\n\n/* ── Marker ────────────────────────────────────────────────────────────────── */\n\n/**\n * The numbered amber pip rendered on an annotated code row's gutter. `active`\n * brightens it when its note (or a co-located row) is hovered.\n */\nexport function AnnotationGutterMarker({\n marker,\n active,\n className,\n}: {\n marker: number;\n active: boolean;\n className?: string;\n}) {\n return (\n <span\n aria-hidden\n className={cn(\n \"inline-flex size-[15px] shrink-0 items-center justify-center rounded-full text-[9px] font-semibold leading-none tabular-nums transition-colors\",\n active\n ? \"bg-amber-500 text-white dark:bg-amber-400 dark:text-amber-950\"\n : \"bg-amber-400/25 text-amber-700 dark:bg-amber-300/20 dark:text-amber-300\",\n className,\n )}\n >\n {marker}\n </span>\n );\n}\n\n/* ── Note card ─────────────────────────────────────────────────────────────── */\n\n/**\n * One line-anchored note card: marker pip (when `showMarker`), the resolved line\n * span (\"Line 8\"), an optional label, and the markdown `note` (via\n * `ctx.renderMarkdown`). This is the single source of card markup, rendered both\n * by the visually-hidden a11y/test stack and by the on-hover portal popover.\n */\nexport function AnnotationCard<A extends RailAnnotation>({\n item,\n ctx,\n active = false,\n showMarker = false,\n className,\n onMouseEnter,\n onMouseLeave,\n}: {\n item: ResolvedAnnotation<A>;\n ctx: BlockRenderContext;\n active?: boolean;\n showMarker?: boolean;\n className?: string;\n onMouseEnter?: () => void;\n onMouseLeave?: () => void;\n}) {\n return (\n <div\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n className={cn(\n \"rounded-lg border px-3.5 py-2.5 transition-colors\",\n active\n ? \"border-amber-400/70 bg-amber-50 dark:border-amber-300/40 dark:bg-amber-300/[0.08]\"\n : \"border-plan-line bg-plan-block/40 hover:border-amber-400/50\",\n className,\n )}\n >\n <div\n className={cn(\n \"flex flex-wrap gap-x-2 gap-y-0.5\",\n showMarker ? \"items-center\" : \"items-baseline\",\n )}\n >\n {showMarker && (\n <AnnotationGutterMarker marker={item.marker} active={active} />\n )}\n <span className=\"text-[11px] font-semibold uppercase tracking-wide text-plan-muted\">\n {rangeLabel(item)}\n </span>\n {item.annotation.label && (\n <span className=\"text-[13px] font-semibold text-plan-text\">\n {item.annotation.label}\n </span>\n )}\n </div>\n <div className=\"plan-annotation-note mt-1 text-[13px] leading-relaxed text-plan-text/85\">\n {ctx.renderMarkdown ? (\n ctx.renderMarkdown(item.annotation.note)\n ) : (\n <p>{item.annotation.note}</p>\n )}\n </div>\n </div>\n );\n}\n\n/**\n * Visually-hidden stack of every resolved note. It is NOT a visible column — it\n * sits in the flow but clipped to a 1px box (the `sr-only` pattern) so the note\n * text and the per-card marker pips stay in the accessibility tree and in the\n * DOM (assistive tech can reach them, and tests that read `textContent`/count\n * pips still see them) WITHOUT painting a persistent rail beside the code. The\n * visible card appears only on hover via {@link AnnotationHoverCard}.\n */\nexport function AnnotationHiddenStack<A extends RailAnnotation>({\n items,\n ctx,\n showMarker = false,\n}: {\n items: ResolvedAnnotation<A>[];\n ctx: BlockRenderContext;\n showMarker?: boolean;\n}) {\n const resolved = useMemo(() => items.filter((item) => item.range), [items]);\n if (resolved.length === 0) return null;\n return (\n <div\n className=\"absolute size-px overflow-hidden whitespace-nowrap border-0 p-0 [clip:rect(0,0,0,0)] [clip-path:inset(50%)]\"\n data-annotation-hidden-stack\n >\n {resolved.map((item) => (\n <AnnotationCard\n key={item.index}\n item={item}\n ctx={ctx}\n showMarker={showMarker}\n />\n ))}\n </div>\n );\n}\n\n/* ── Hover popover (portal, anchored beside the code) ──────────────────────── */\n\n/** The geometry the hover card anchors to (in viewport coordinates). */\nexport interface AnnotationAnchor {\n /** Right edge of the code block (where the card should start). */\n codeRight: number;\n /** Left edge of the code block (for the below-fallback alignment). */\n codeLeft: number;\n /** Vertical center of the hovered line. */\n lineCenter: number;\n /** Bottom of the hovered line (for the below-fallback placement). */\n lineBottom: number;\n}\n\nconst HOVER_CARD_WIDTH = 280;\nconst HOVER_CARD_GAP = 12;\nconst VIEWPORT_MARGIN = 8;\n\nexport function resolveAnnotationHoverCardPosition(\n anchor: AnnotationAnchor,\n card: { width: number; height: number },\n viewport: { width: number; height: number },\n): { top: number; left: number } {\n const rightLeft = anchor.codeRight + HOVER_CARD_GAP;\n const fitsRight = rightLeft + card.width + VIEWPORT_MARGIN <= viewport.width;\n const leftLeft = anchor.codeLeft - HOVER_CARD_GAP - card.width;\n const fitsLeft = leftLeft >= VIEWPORT_MARGIN;\n\n let left: number;\n let top: number;\n if (fitsRight) {\n // Default: to the right of the code, centered on the hovered line.\n left = rightLeft;\n top = anchor.lineCenter - card.height / 2;\n } else if (fitsLeft) {\n // Prefer the left gutter over covering the code below the hovered line.\n left = leftLeft;\n top = anchor.lineCenter - card.height / 2;\n } else {\n // No clean side gutter → drop below the line, aligned to the code's left.\n left = anchor.codeLeft;\n top = anchor.lineBottom + HOVER_CARD_GAP;\n }\n\n // Clamp within the viewport so the card is never cut off.\n left = Math.max(\n VIEWPORT_MARGIN,\n Math.min(left, viewport.width - card.width - VIEWPORT_MARGIN),\n );\n top = Math.max(\n VIEWPORT_MARGIN,\n Math.min(top, viewport.height - card.height - VIEWPORT_MARGIN),\n );\n\n return { top, left };\n}\n\n/**\n * The single on-hover note card, portaled to `document.body` and positioned\n * `fixed` so it escapes the code block's `overflow` and never reflows the code.\n *\n * Placement: by default it sits to the RIGHT of the code block's right edge,\n * vertically centered on the hovered line — so it never overlaps the code text.\n * If there isn't room to the right, it uses the LEFT of the code block when the\n * card can fit there without covering code. Only when neither side fits does it\n * fall back to BELOW the hovered line (left-aligned to the code block). The card\n * keeps itself open while hovered (`onMouseEnter`/`onMouseLeave` forwarded) so\n * it stays readable; the caller adds the small hover-intent close delay.\n */\nexport function AnnotationHoverCard<A extends RailAnnotation>({\n item,\n anchor,\n ctx,\n showMarker = false,\n onMouseEnter,\n onMouseLeave,\n onClose,\n}: {\n item: ResolvedAnnotation<A>;\n anchor: AnnotationAnchor;\n ctx: BlockRenderContext;\n showMarker?: boolean;\n onMouseEnter?: () => void;\n onMouseLeave?: () => void;\n /** Called when the card should be dismissed (e.g. on scroll). */\n onClose?: () => void;\n}) {\n const cardRef = useRef<HTMLDivElement | null>(null);\n const [pos, setPos] = useState<{ top: number; left: number } | null>(null);\n\n // Measure the rendered card, then resolve a non-overlapping position: right of\n // the code if it fits, then left if that side has a clean gutter, otherwise\n // below the line.\n useLayoutEffect(() => {\n if (typeof window === \"undefined\") return;\n const el = cardRef.current;\n const rect = el?.getBoundingClientRect();\n const width = rect && rect.width > 0 ? rect.width : HOVER_CARD_WIDTH;\n const height = rect && rect.height > 0 ? rect.height : 0;\n const vw = window.innerWidth || 0;\n const vh = window.innerHeight || 0;\n setPos(\n resolveAnnotationHoverCardPosition(\n anchor,\n { width, height },\n { width: vw, height: vh },\n ),\n );\n }, [\n anchor.codeRight,\n anchor.codeLeft,\n anchor.lineCenter,\n anchor.lineBottom,\n item.index,\n ]);\n\n // Close the card when the user scrolls so it doesn't float detached.\n useEffect(() => {\n if (!onClose || typeof window === \"undefined\") return;\n const handler = () => onClose();\n window.addEventListener(\"scroll\", handler, {\n capture: true,\n passive: true,\n });\n return () =>\n window.removeEventListener(\"scroll\", handler, { capture: true });\n }, [onClose]);\n\n if (typeof document === \"undefined\") return null;\n\n return createPortal(\n <div\n ref={cardRef}\n role=\"tooltip\"\n data-annotation-hover-card\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n className=\"pointer-events-auto fixed z-50\"\n style={{\n top: pos?.top ?? anchor.lineCenter,\n left: pos?.left ?? anchor.codeRight + HOVER_CARD_GAP,\n width: HOVER_CARD_WIDTH,\n // Hide until measured to avoid a one-frame jump from the fallback spot.\n visibility: pos ? \"visible\" : \"hidden\",\n }}\n >\n <AnnotationCard\n item={item}\n ctx={ctx}\n active\n showMarker={showMarker}\n className=\"shadow-lg shadow-black/10 dark:shadow-black/40\"\n />\n </div>,\n document.body,\n );\n}\n\n/**\n * Hover-intent + tap controller for the on-hover note card. Exposes\n * `activeIndex` + the captured `anchor`, plus `open`/`toggle`/`close`/\n * `scheduleClose`/`cancelClose` handlers.\n *\n * - `open(index, anchor)` shows a card immediately (cancels any pending close).\n * - `toggle(index, anchor)` opens a card if it isn't already the active one,\n * or closes it if it is — used for click/tap on annotated rows so touch users\n * can access notes without hover.\n * - `close()` hides the card immediately (used on scroll to avoid stale cards).\n * - `scheduleClose()` hides after a short delay, so moving the pointer from the\n * code line across the gap into the card itself keeps it open.\n * - `cancelClose()` (call on card mouse-enter) keeps it open while reading.\n */\nexport function useAnnotationHover(delay = 130) {\n const [active, setActive] = useState<{\n index: number;\n anchor: AnnotationAnchor;\n } | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const cancelClose = () => {\n if (timer.current) {\n clearTimeout(timer.current);\n timer.current = null;\n }\n };\n const open = (index: number, anchor: AnnotationAnchor) => {\n cancelClose();\n setActive({ index, anchor });\n };\n const toggle = (index: number, anchor: AnnotationAnchor) => {\n cancelClose();\n setActive((prev) => (prev?.index === index ? null : { index, anchor }));\n };\n const close = () => {\n cancelClose();\n setActive(null);\n };\n const scheduleClose = () => {\n cancelClose();\n timer.current = setTimeout(() => setActive(null), delay);\n };\n\n useEffect(() => () => cancelClose(), []);\n\n return {\n activeIndex: active?.index ?? null,\n anchor: active?.anchor ?? null,\n open,\n toggle,\n close,\n scheduleClose,\n cancelClose,\n } as const;\n}\n\n/**\n * Build an {@link AnnotationAnchor} from the code block element and the hovered\n * row element. The card anchors to the code block's RIGHT edge and the row's\n * vertical center, both in viewport coordinates (so a `fixed` portal lines up).\n */\nexport function anchorFromElements(\n codeEl: HTMLElement | null,\n rowEl: HTMLElement | null,\n): AnnotationAnchor | null {\n if (!codeEl || !rowEl) return null;\n const code = codeEl.getBoundingClientRect();\n const row = rowEl.getBoundingClientRect();\n return {\n codeRight: code.right,\n codeLeft: code.left,\n lineCenter: row.top + row.height / 2,\n lineBottom: row.bottom,\n };\n}\n\n/**\n * The responsive list of line-anchored note cards. Each card shows its marker\n * pip, the resolved line span (\"Line 8\"), an optional label, and the markdown\n * `note` (via `ctx.renderMarkdown`). Hovering a card sets the active index;\n * `activeIndex` driven from outside lets a hovered code row light its card and\n * vice-versa. Only annotations whose `range` resolved are listed.\n *\n * @deprecated Superseded by the on-hover {@link AnnotationHoverCard}; kept for\n * back-compat with any external importer. Both block read renderers now use the\n * hover popover anchored to the right of the code instead of a persistent rail.\n */\nexport function AnnotationNoteRail<A extends RailAnnotation>({\n items,\n activeIndex,\n onActiveChange,\n ctx,\n className,\n showMarker = false,\n}: {\n items: ResolvedAnnotation<A>[];\n activeIndex: number | null;\n onActiveChange: (index: number | null) => void;\n ctx: BlockRenderContext;\n className?: string;\n /** Show a leading numbered pip on each card (diff block). */\n showMarker?: boolean;\n}) {\n const sideAnnotations = useMemo(\n () => items.filter((item) => item.range),\n [items],\n );\n return (\n <div className={cn(\"flex flex-col gap-2.5\", className)}>\n {sideAnnotations.map((item) => (\n <AnnotationCard\n key={item.index}\n item={item}\n ctx={ctx}\n active={activeIndex === item.index}\n showMarker={showMarker}\n onMouseEnter={() => onActiveChange(item.index)}\n onMouseLeave={() => onActiveChange(null)}\n />\n ))}\n </div>\n );\n}\n\n/** Whether a resolved list has at least one note worth rendering a rail for. */\nexport function hasRailAnnotations(items: ResolvedAnnotation[]): boolean {\n return items.some((item) => item.range);\n}\n\nexport type AnnotationRailChildren = ReactNode;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/html.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAqD3E,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,GAAG,GACJ,EAAE,cAAc,CAAC,aAAa,CAAC,2CAO/B;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,aAAa,CAAC,2CAyI/B;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,gDAepB,CAAC"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/html.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAuD3E,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,GAAG,GACJ,EAAE,cAAc,CAAC,aAAa,CAAC,2CAO/B;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,aAAa,CAAC,2CAyI/B;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,gDAepB,CAAC"}
@@ -23,7 +23,9 @@ import { htmlSchema, htmlMdx } from "./html.config.js";
23
23
  function buildSrcDoc(data, sanitize) {
24
24
  const css = data.css ?? "";
25
25
  const body = sanitize ? sanitize(data.html, data.css) : data.html;
26
- return `<!doctype html><html><head><style>body{margin:0;min-height:100%;font-family:Inter,system-ui,sans-serif;color:#1f1f1d;background:transparent;}*{box-sizing:border-box}${css}</style></head><body>${body}</body></html>`;
26
+ // Use prefers-color-scheme so the iframe ink matches the host theme even
27
+ // though the iframe document is isolated and can't inherit CSS variables.
28
+ return `<!doctype html><html><head><style>body{margin:0;min-height:100%;font-family:Inter,system-ui,sans-serif;color:#1f1f1d;background:transparent;}*{box-sizing:border-box}@media(prefers-color-scheme:dark){body{color:#e8e8e6}}${css}</style></head><body>${body}</body></html>`;
27
29
  }
28
30
  function HtmlPreview({ data, title, sanitize, }) {
29
31
  return (_jsxs(_Fragment, { children: [_jsx("iframe", { title: title || "Custom HTML block", srcDoc: buildSrcDoc(data, sanitize), sandbox: "allow-same-origin", referrerPolicy: "no-referrer", className: "mt-4 h-[360px] w-full rounded-xl border bg-muted" }), data.caption && (_jsx("p", { className: "mt-3 text-sm text-muted-foreground", children: data.caption }))] }));
@@ -1 +1 @@
1
- {"version":3,"file":"html.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/html.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useId, useState } from \"react\";\nimport { IconCode, IconEdit, IconX } from \"@tabler/icons-react\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockReadProps, BlockEditProps } from \"../types.js\";\nimport { AiEditableFieldLabel } from \"../AiEditableField.js\";\nimport { htmlSchema, htmlMdx, type HtmlBlockData } from \"./html.config.js\";\n\n/**\n * Standard library HTML / Tailwind block. The registry form of the plan\n * `custom-html` block: an author-supplied HTML (+ optional CSS) fragment\n * rendered inside a sandboxed iframe, with an inline source editor.\n *\n * Security: the fragment is rendered in a `sandbox=\"allow-same-origin\"` iframe\n * with `referrerPolicy=\"no-referrer\"` — no scripts execute — and the schema's\n * `noFullHtmlDocument` refine rejects document/script/handler markup before it\n * is ever stored. When the app injects `ctx.sanitizeHtml`, the fragment + CSS\n * are additionally sanitized before being placed in the iframe `srcDoc`.\n *\n * Styling uses app-agnostic shadcn utility classes (`border`, `bg-muted`,\n * `text-muted-foreground`) so the block renders cleanly in any template, not\n * just the plan app.\n */\n\n/** Build the iframe document for a fragment, applying app sanitization if given. */\nfunction buildSrcDoc(\n data: HtmlBlockData,\n sanitize?: (html: string, css?: string) => string,\n): string {\n const css = data.css ?? \"\";\n const body = sanitize ? sanitize(data.html, data.css) : data.html;\n return `<!doctype html><html><head><style>body{margin:0;min-height:100%;font-family:Inter,system-ui,sans-serif;color:#1f1f1d;background:transparent;}*{box-sizing:border-box}${css}</style></head><body>${body}</body></html>`;\n}\n\nfunction HtmlPreview({\n data,\n title,\n sanitize,\n}: {\n data: HtmlBlockData;\n title?: string;\n sanitize?: (html: string, css?: string) => string;\n}) {\n return (\n <>\n <iframe\n title={title || \"Custom HTML block\"}\n srcDoc={buildSrcDoc(data, sanitize)}\n sandbox=\"allow-same-origin\"\n referrerPolicy=\"no-referrer\"\n className=\"mt-4 h-[360px] w-full rounded-xl border bg-muted\"\n />\n {data.caption && (\n <p className=\"mt-3 text-sm text-muted-foreground\">{data.caption}</p>\n )}\n </>\n );\n}\n\n/** Read-only renderer: the sandboxed iframe preview plus an optional caption. */\nexport function HtmlReadBlock({\n data,\n blockId,\n title,\n ctx,\n}: BlockReadProps<HtmlBlockData>) {\n return (\n <section className=\"plan-block group\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <HtmlPreview data={data} title={title} sanitize={ctx.sanitizeHtml} />\n </section>\n );\n}\n\n/**\n * Custom editor: an \"Edit source\" toggle that flips between the live preview and\n * inline HTML + CSS textareas (ported from the plan `CustomHtmlBlock`). The\n * title is rendered by the registry's edit-mode section wrapper, so this only\n * renders the toggle + content. Edits commit the merged data via `onChange`,\n * which the app routes through its generic `update-block` patch (re-validated by\n * the app schema).\n */\nexport function HtmlEditBlock({\n data,\n onChange,\n editable,\n blockId,\n title,\n summary,\n ctx,\n}: BlockEditProps<HtmlBlockData>) {\n const htmlId = useId();\n const cssId = useId();\n const captionId = useId();\n const [editing, setEditing] = useState(false);\n const [html, setHtml] = useState(data.html);\n const [css, setCss] = useState(data.css ?? \"\");\n const [caption, setCaption] = useState(data.caption ?? \"\");\n\n useEffect(() => {\n setHtml(data.html);\n setCss(data.css ?? \"\");\n setCaption(data.caption ?? \"\");\n }, [data]);\n\n const fieldAction = (\n field: \"HTML fragment\" | \"CSS\" | \"Caption\",\n value: string,\n ) => ({\n blockId,\n blockType: \"custom-html\",\n blockTitle: title,\n blockSummary: summary,\n fieldValue: value,\n draftScope: `block:custom-html:${blockId}:${field.toLowerCase().replace(/[^a-z0-9]+/g, \"-\")}`,\n disabled: !editable,\n instructions:\n \"Update the plan with update-visual-plan using a targeted update-block content patch for this custom-html block id. Preserve unrelated HTML/CSS/caption fields unless the requested edit requires changing them.\",\n companionFields: [\n { label: \"HTML fragment\", value: html || \"(empty)\", language: \"html\" },\n { label: \"CSS\", value: css || \"(empty)\", language: \"css\" },\n { label: \"Caption\", value: caption || \"(empty)\", language: \"text\" },\n ],\n });\n\n return (\n <div className=\"plan-html-block group\" data-an-block-edit>\n <div className=\"flex items-start justify-end gap-4\">\n {editable && (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={editing ? \"Cancel editing source\" : \"Edit source\"}\n className=\"inline-flex size-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n onClick={() => setEditing((value) => !value)}\n >\n {editing ? (\n <IconX className=\"size-4\" />\n ) : (\n <IconEdit className=\"size-4\" />\n )}\n </button>\n )}\n </div>\n {editing ? (\n <div className=\"mt-2 grid gap-3\" data-plan-interactive>\n <div className=\"group/field grid gap-1.5\">\n <AiEditableFieldLabel\n htmlFor={htmlId}\n label=\"HTML fragment\"\n ctx={ctx}\n action={fieldAction(\"HTML fragment\", html)}\n />\n <textarea\n id={htmlId}\n value={html}\n disabled={!editable}\n onChange={(event) => setHtml(event.target.value)}\n className=\"flex min-h-48 w-full rounded-md border border-input bg-transparent px-3 py-2 font-mono text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n placeholder=\"HTML fragment\"\n />\n </div>\n <div className=\"group/field grid gap-1.5\">\n <AiEditableFieldLabel\n htmlFor={cssId}\n label=\"CSS\"\n ctx={ctx}\n action={fieldAction(\"CSS\", css)}\n />\n <textarea\n id={cssId}\n value={css}\n disabled={!editable}\n onChange={(event) => setCss(event.target.value)}\n className=\"flex min-h-32 w-full rounded-md border border-input bg-transparent px-3 py-2 font-mono text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n placeholder=\"Optional CSS\"\n />\n </div>\n <div className=\"group/field grid gap-1.5\">\n <AiEditableFieldLabel\n htmlFor={captionId}\n label=\"Caption\"\n ctx={ctx}\n action={fieldAction(\"Caption\", caption)}\n />\n <input\n id={captionId}\n type=\"text\"\n value={caption}\n disabled={!editable}\n onChange={(event) => setCaption(event.target.value)}\n className=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n placeholder=\"Optional caption\"\n />\n </div>\n <div className=\"flex justify-end gap-2\">\n <button\n type=\"button\"\n data-plan-interactive\n className=\"inline-flex h-9 items-center rounded-md px-4 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n onClick={() => setEditing(false)}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n className=\"inline-flex h-9 items-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90\"\n onClick={() => {\n onChange({\n ...data,\n html,\n css: css || undefined,\n caption: caption || undefined,\n });\n setEditing(false);\n }}\n >\n Save\n </button>\n </div>\n </div>\n ) : (\n <HtmlPreview data={data} title={title} sanitize={ctx.sanitizeHtml} />\n )}\n </div>\n );\n}\n\n/**\n * The standard HTML / Tailwind block spec. Both apps register this; the plan app\n * registers the matching React-free `{ schema, mdx }` server-side via\n * `html.config.ts`. `empty()` seeds a friendly starter fragment for slash\n * insertion.\n */\nexport const htmlBlock = defineBlock<HtmlBlockData>({\n type: \"custom-html\",\n schema: htmlSchema,\n mdx: htmlMdx,\n Read: HtmlReadBlock,\n Edit: HtmlEditBlock,\n placement: [\"block\"],\n // Config-driven: the render (a sandboxed card) differs from its source, so edit\n // the html/css/caption from a corner button + panel rather than always-inline.\n editSurface: \"panel\",\n label: \"HTML / Tailwind\",\n icon: IconCode,\n description:\n \"An author-supplied HTML (with optional CSS) fragment rendered in a sandboxed iframe, with inline source editing.\",\n empty: () => ({ html: '<div class=\"p-6\">Edit this HTML fragment…</div>' }),\n});\n"]}
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/html.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useId, useState } from \"react\";\nimport { IconCode, IconEdit, IconX } from \"@tabler/icons-react\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockReadProps, BlockEditProps } from \"../types.js\";\nimport { AiEditableFieldLabel } from \"../AiEditableField.js\";\nimport { htmlSchema, htmlMdx, type HtmlBlockData } from \"./html.config.js\";\n\n/**\n * Standard library HTML / Tailwind block. The registry form of the plan\n * `custom-html` block: an author-supplied HTML (+ optional CSS) fragment\n * rendered inside a sandboxed iframe, with an inline source editor.\n *\n * Security: the fragment is rendered in a `sandbox=\"allow-same-origin\"` iframe\n * with `referrerPolicy=\"no-referrer\"` — no scripts execute — and the schema's\n * `noFullHtmlDocument` refine rejects document/script/handler markup before it\n * is ever stored. When the app injects `ctx.sanitizeHtml`, the fragment + CSS\n * are additionally sanitized before being placed in the iframe `srcDoc`.\n *\n * Styling uses app-agnostic shadcn utility classes (`border`, `bg-muted`,\n * `text-muted-foreground`) so the block renders cleanly in any template, not\n * just the plan app.\n */\n\n/** Build the iframe document for a fragment, applying app sanitization if given. */\nfunction buildSrcDoc(\n data: HtmlBlockData,\n sanitize?: (html: string, css?: string) => string,\n): string {\n const css = data.css ?? \"\";\n const body = sanitize ? sanitize(data.html, data.css) : data.html;\n // Use prefers-color-scheme so the iframe ink matches the host theme even\n // though the iframe document is isolated and can't inherit CSS variables.\n return `<!doctype html><html><head><style>body{margin:0;min-height:100%;font-family:Inter,system-ui,sans-serif;color:#1f1f1d;background:transparent;}*{box-sizing:border-box}@media(prefers-color-scheme:dark){body{color:#e8e8e6}}${css}</style></head><body>${body}</body></html>`;\n}\n\nfunction HtmlPreview({\n data,\n title,\n sanitize,\n}: {\n data: HtmlBlockData;\n title?: string;\n sanitize?: (html: string, css?: string) => string;\n}) {\n return (\n <>\n <iframe\n title={title || \"Custom HTML block\"}\n srcDoc={buildSrcDoc(data, sanitize)}\n sandbox=\"allow-same-origin\"\n referrerPolicy=\"no-referrer\"\n className=\"mt-4 h-[360px] w-full rounded-xl border bg-muted\"\n />\n {data.caption && (\n <p className=\"mt-3 text-sm text-muted-foreground\">{data.caption}</p>\n )}\n </>\n );\n}\n\n/** Read-only renderer: the sandboxed iframe preview plus an optional caption. */\nexport function HtmlReadBlock({\n data,\n blockId,\n title,\n ctx,\n}: BlockReadProps<HtmlBlockData>) {\n return (\n <section className=\"plan-block group\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <HtmlPreview data={data} title={title} sanitize={ctx.sanitizeHtml} />\n </section>\n );\n}\n\n/**\n * Custom editor: an \"Edit source\" toggle that flips between the live preview and\n * inline HTML + CSS textareas (ported from the plan `CustomHtmlBlock`). The\n * title is rendered by the registry's edit-mode section wrapper, so this only\n * renders the toggle + content. Edits commit the merged data via `onChange`,\n * which the app routes through its generic `update-block` patch (re-validated by\n * the app schema).\n */\nexport function HtmlEditBlock({\n data,\n onChange,\n editable,\n blockId,\n title,\n summary,\n ctx,\n}: BlockEditProps<HtmlBlockData>) {\n const htmlId = useId();\n const cssId = useId();\n const captionId = useId();\n const [editing, setEditing] = useState(false);\n const [html, setHtml] = useState(data.html);\n const [css, setCss] = useState(data.css ?? \"\");\n const [caption, setCaption] = useState(data.caption ?? \"\");\n\n useEffect(() => {\n setHtml(data.html);\n setCss(data.css ?? \"\");\n setCaption(data.caption ?? \"\");\n }, [data]);\n\n const fieldAction = (\n field: \"HTML fragment\" | \"CSS\" | \"Caption\",\n value: string,\n ) => ({\n blockId,\n blockType: \"custom-html\",\n blockTitle: title,\n blockSummary: summary,\n fieldValue: value,\n draftScope: `block:custom-html:${blockId}:${field.toLowerCase().replace(/[^a-z0-9]+/g, \"-\")}`,\n disabled: !editable,\n instructions:\n \"Update the plan with update-visual-plan using a targeted update-block content patch for this custom-html block id. Preserve unrelated HTML/CSS/caption fields unless the requested edit requires changing them.\",\n companionFields: [\n { label: \"HTML fragment\", value: html || \"(empty)\", language: \"html\" },\n { label: \"CSS\", value: css || \"(empty)\", language: \"css\" },\n { label: \"Caption\", value: caption || \"(empty)\", language: \"text\" },\n ],\n });\n\n return (\n <div className=\"plan-html-block group\" data-an-block-edit>\n <div className=\"flex items-start justify-end gap-4\">\n {editable && (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={editing ? \"Cancel editing source\" : \"Edit source\"}\n className=\"inline-flex size-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n onClick={() => setEditing((value) => !value)}\n >\n {editing ? (\n <IconX className=\"size-4\" />\n ) : (\n <IconEdit className=\"size-4\" />\n )}\n </button>\n )}\n </div>\n {editing ? (\n <div className=\"mt-2 grid gap-3\" data-plan-interactive>\n <div className=\"group/field grid gap-1.5\">\n <AiEditableFieldLabel\n htmlFor={htmlId}\n label=\"HTML fragment\"\n ctx={ctx}\n action={fieldAction(\"HTML fragment\", html)}\n />\n <textarea\n id={htmlId}\n value={html}\n disabled={!editable}\n onChange={(event) => setHtml(event.target.value)}\n className=\"flex min-h-48 w-full rounded-md border border-input bg-transparent px-3 py-2 font-mono text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n placeholder=\"HTML fragment\"\n />\n </div>\n <div className=\"group/field grid gap-1.5\">\n <AiEditableFieldLabel\n htmlFor={cssId}\n label=\"CSS\"\n ctx={ctx}\n action={fieldAction(\"CSS\", css)}\n />\n <textarea\n id={cssId}\n value={css}\n disabled={!editable}\n onChange={(event) => setCss(event.target.value)}\n className=\"flex min-h-32 w-full rounded-md border border-input bg-transparent px-3 py-2 font-mono text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n placeholder=\"Optional CSS\"\n />\n </div>\n <div className=\"group/field grid gap-1.5\">\n <AiEditableFieldLabel\n htmlFor={captionId}\n label=\"Caption\"\n ctx={ctx}\n action={fieldAction(\"Caption\", caption)}\n />\n <input\n id={captionId}\n type=\"text\"\n value={caption}\n disabled={!editable}\n onChange={(event) => setCaption(event.target.value)}\n className=\"flex h-9 w-full rounded-md border border-input bg-transparent px-3 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\"\n placeholder=\"Optional caption\"\n />\n </div>\n <div className=\"flex justify-end gap-2\">\n <button\n type=\"button\"\n data-plan-interactive\n className=\"inline-flex h-9 items-center rounded-md px-4 text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n onClick={() => setEditing(false)}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n className=\"inline-flex h-9 items-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90\"\n onClick={() => {\n onChange({\n ...data,\n html,\n css: css || undefined,\n caption: caption || undefined,\n });\n setEditing(false);\n }}\n >\n Save\n </button>\n </div>\n </div>\n ) : (\n <HtmlPreview data={data} title={title} sanitize={ctx.sanitizeHtml} />\n )}\n </div>\n );\n}\n\n/**\n * The standard HTML / Tailwind block spec. Both apps register this; the plan app\n * registers the matching React-free `{ schema, mdx }` server-side via\n * `html.config.ts`. `empty()` seeds a friendly starter fragment for slash\n * insertion.\n */\nexport const htmlBlock = defineBlock<HtmlBlockData>({\n type: \"custom-html\",\n schema: htmlSchema,\n mdx: htmlMdx,\n Read: HtmlReadBlock,\n Edit: HtmlEditBlock,\n placement: [\"block\"],\n // Config-driven: the render (a sandboxed card) differs from its source, so edit\n // the html/css/caption from a corner button + panel rather than always-inline.\n editSurface: \"panel\",\n label: \"HTML / Tailwind\",\n icon: IconCode,\n description:\n \"An author-supplied HTML (with optional CSS) fragment rendered in a sandboxed iframe, with inline source editing.\",\n empty: () => ({ html: '<div class=\"p-6\">Edit this HTML fragment…</div>' }),\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"question-form.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/question-form.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EAKL,KAAK,gBAAgB,EAIrB,KAAK,mBAAmB,EACzB,MAAM,2BAA2B,CAAC;AAganC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,gBAAgB,CAAC,2CAEvE;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,cAAc,CAAC,mBAAmB,CAAC,2CAG3C;AAaD,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,CAAC,gBAAgB,CAAC,2CAsTlC;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,mDAsB5B,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,mDAmC/B,CAAC"}
1
+ {"version":3,"file":"question-form.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/question-form.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EAKL,KAAK,gBAAgB,EAIrB,KAAK,mBAAmB,EACzB,MAAM,2BAA2B,CAAC;AA6anC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,CAAC,gBAAgB,CAAC,2CAEvE;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,cAAc,CAAC,mBAAmB,CAAC,2CAG3C;AAaD,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,CAAC,gBAAgB,CAAC,2CAsTlC;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,mDAsB5B,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,mDAmC/B,CAAC"}
@@ -66,7 +66,10 @@ function QuestionView({ question, index, answer, blockId, ctx, onAnswer, }) {
66
66
  });
67
67
  }, children: [_jsxs("div", { className: "flex min-w-0 items-start gap-3", children: [_jsx("span", { className: cn("mt-0.5 flex size-5 shrink-0 items-center justify-center border", question.mode === "single" ? "rounded-full" : "rounded", isSelected
68
68
  ? "border-primary bg-primary text-primary-foreground"
69
- : "border-border"), children: isSelected && _jsx(IconCheck, { className: "size-3.5" }) }), _jsxs("span", { children: [_jsx("span", { className: "text-base font-semibold leading-6 text-foreground", children: option.label }), option.recommended && (_jsxs(_Fragment, { children: [" ", _jsx("span", { className: "ml-3 rounded-md border border-primary/30 px-2 py-0.5 align-middle text-[11px] font-medium uppercase tracking-[0.12em] text-primary", children: "Recommended" })] })), option.detail && (_jsx("span", { className: "mt-1 block max-w-2xl whitespace-pre-line text-sm font-normal leading-6 text-muted-foreground", children: option.detail }))] })] }), hasVisualOptions && (option.wireframe || option.diagram) && (_jsxs("div", { className: "ml-8 grid gap-4 lg:grid-cols-[minmax(0,1fr)_280px]", children: [option.wireframe != null && (_jsx(OptionVisual, { type: "wireframe", data: option.wireframe, blockId: `${blockId}-${option.id}`, ctx: ctx })), option.diagram != null && (_jsx(OptionVisual, { type: "diagram", data: option.diagram, blockId: `${blockId}-${option.id}`, ctx: ctx }))] }))] }, option.id));
69
+ : "border-border"), children: isSelected && _jsx(IconCheck, { className: "size-3.5" }) }), _jsxs("span", { children: [_jsx("span", { className: "text-base font-semibold leading-6 text-foreground", children: option.label }), option.recommended && (_jsxs(_Fragment, { children: [" ", _jsx("span", { className: "ml-3 rounded-md border border-primary/30 px-2 py-0.5 align-middle text-[11px] font-medium uppercase tracking-[0.12em] text-primary", children: "Recommended" })] })), option.detail && (_jsx("span", { className: "mt-1 block max-w-2xl whitespace-pre-line text-sm font-normal leading-6 text-muted-foreground", children: option.detail }))] })] }), hasVisualOptions && (option.wireframe || option.diagram) && (_jsxs("div", { className: "ml-8 grid gap-4 lg:grid-cols-[minmax(0,1fr)_280px]", onClick: (e) => e.stopPropagation(), onKeyDown: (e) => {
70
+ if (e.key === "Enter" || e.key === " ")
71
+ e.stopPropagation();
72
+ }, children: [option.wireframe != null && (_jsx(OptionVisual, { type: "wireframe", data: option.wireframe, blockId: `${blockId}-${option.id}`, ctx: ctx })), option.diagram != null && (_jsx(OptionVisual, { type: "diagram", data: option.diagram, blockId: `${blockId}-${option.id}`, ctx: ctx }))] }))] }, option.id));
70
73
  }), question.allowOther !== false && (_jsx("input", { value: answer?.text ?? "", onChange: (event) => onAnswer({ ...answer, text: event.target.value }), className: cn("h-10 w-full rounded-lg border border-border bg-card px-4 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring", hasVisualOptions ? "md:col-span-2" : "sm:w-80"), "data-plan-interactive": true, placeholder: question.placeholder || "Other — type your own answer…" }))] }))] })] }));
71
74
  }
72
75
  /** The "Send to agent" affordance: a popover (via the app surface) when wired. */
@@ -1 +1 @@
1
- {"version":3,"file":"question-form.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/question-form.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EACL,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACR,SAAS,GACV,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1C,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,kBAAkB,GAMnB,MAAM,2BAA2B,CAAC;AAyCnC,SAAS,UAAU,CACjB,QAA8B,EAC9B,MAAuB;IAEvB,IAAI,QAAQ,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,OAAO,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACnE,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CACvB,OAA2B,EAC3B,UAA8B,EAC9B,SAAiC,EACjC,OAAwB;IAExB,MAAM,KAAK,GAAG;QACZ,gDAAgD;QAChD,OAAO,CAAC,CAAC,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE;QAC3C,UAAU,CAAC,CAAC,CAAC,YAAY,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE;QAC1C,EAAE;KACH,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;IAChC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,cAAc,GAClB,QAAQ,CAAC,OAAO;YACd,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;aAC1D,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACnC,MAAM,KAAK,GACT,QAAQ,CAAC,IAAI,KAAK,UAAU;YAC1B,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,CAAC,GAAG,cAAc,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5E,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,KAAK,KAAK,IAAI,eAAe,EAAE,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,oFAAoF;AACpF,SAAS,YAAY,CAAC,EACpB,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,GAAG,GAMJ;IACC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,KAAK,GAAgB;QACzB,EAAE,EAAE,GAAG,OAAO,IAAI,IAAI,EAAE;QACxB,IAAI;QACJ,IAAI;KACL,CAAC;IACF,OAAO,CACL,4BAAG,GAAG,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,GAAI,CACxE,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,EACpB,QAAQ,EACR,KAAK,EACL,MAAM,EACN,OAAO,EACP,GAAG,EACH,QAAQ,GAQT;IACC,MAAM,QAAQ,GAAG,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAC;IACxC,MAAM,gBAAgB,GAAG,OAAO,CAC9B,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC,CACvE,CAAC;IACF,OAAO,CACL,mBAAS,SAAS,EAAC,8CAA8C,aAC/D,cAAK,SAAS,EAAC,+HAA+H,YAC3I,KAAK,GAAG,CAAC,GACN,EACN,0BACE,aAAI,SAAS,EAAC,iDAAiD,YAC5D,QAAQ,CAAC,KAAK,GACZ,EACJ,QAAQ,CAAC,QAAQ,IAAI,CACpB,YAAG,SAAS,EAAC,0DAA0D,YACpE,QAAQ,CAAC,QAAQ,GAChB,CACL,EACA,QAAQ,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAC9B,mBACE,KAAK,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,EACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAC3D,SAAS,EAAC,8MAA8M,iCAExN,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,gBAAgB,GACrD,CACH,CAAC,CAAC,CAAC,CACF,eACE,SAAS,EAAE,EAAE,CACX,MAAM,EACN,gBAAgB;4BACd,CAAC,CAAC,2BAA2B;4BAC7B,CAAC,CAAC,sBAAsB,CAC3B,aAEA,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;gCAChC,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gCAChD,OAAO,CACL,kBAEE,IAAI,EAAC,QAAQ,iDAEC,UAAU,EACxB,SAAS,EAAE,EAAE,CACX,gBAAgB;wCACd,CAAC,CAAC,uGAAuG;wCACzG,CAAC,CAAC,4JAA4J,EAChK,UAAU,IAAI,iCAAiC,CAChD,EACD,OAAO,EAAE,GAAG,EAAE;wCACZ,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;4CAC/B,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;4CAC/C,OAAO;wCACT,CAAC;wCACD,QAAQ,CAAC;4CACP,GAAG,MAAM;4CACT,QAAQ,EAAE,UAAU;gDAClB,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;gDAC3C,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC;yCAC7B,CAAC,CAAC;oCACL,CAAC,aAED,eAAK,SAAS,EAAC,gCAAgC,aAC7C,eACE,SAAS,EAAE,EAAE,CACX,gEAAgE,EAChE,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,EACvD,UAAU;wDACR,CAAC,CAAC,mDAAmD;wDACrD,CAAC,CAAC,eAAe,CACpB,YAEA,UAAU,IAAI,KAAC,SAAS,IAAC,SAAS,EAAC,UAAU,GAAG,GAC5C,EACP,2BACE,eAAM,SAAS,EAAC,mDAAmD,YAChE,MAAM,CAAC,KAAK,GACR,EACN,MAAM,CAAC,WAAW,IAAI,CACrB,8BACG,GAAG,EACJ,eAAM,SAAS,EAAC,oIAAoI,4BAE7I,IACN,CACJ,EACA,MAAM,CAAC,MAAM,IAAI,CAChB,eAAM,SAAS,EAAC,8FAA8F,YAC3G,MAAM,CAAC,MAAM,GACT,CACR,IACI,IACH,EACL,gBAAgB,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAC3D,eAAK,SAAS,EAAC,oDAAoD,aAChE,MAAM,CAAC,SAAS,IAAI,IAAI,IAAI,CAC3B,KAAC,YAAY,IACX,IAAI,EAAC,WAAW,EAChB,IAAI,EAAE,MAAM,CAAC,SAAS,EACtB,OAAO,EAAE,GAAG,OAAO,IAAI,MAAM,CAAC,EAAE,EAAE,EAClC,GAAG,EAAE,GAAG,GACR,CACH,EACA,MAAM,CAAC,OAAO,IAAI,IAAI,IAAI,CACzB,KAAC,YAAY,IACX,IAAI,EAAC,SAAS,EACd,IAAI,EAAE,MAAM,CAAC,OAAO,EACpB,OAAO,EAAE,GAAG,OAAO,IAAI,MAAM,CAAC,EAAE,EAAE,EAClC,GAAG,EAAE,GAAG,GACR,CACH,IACG,CACP,KAzEI,MAAM,CAAC,EAAE,CA0EP,CACV,CAAC;4BACJ,CAAC,CAAC,EAID,QAAQ,CAAC,UAAU,KAAK,KAAK,IAAI,CAChC,gBACE,KAAK,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,EACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAEnD,SAAS,EAAE,EAAE,CACX,gMAAgM,EAChM,gBAAgB,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAC/C,iCAED,WAAW,EACT,QAAQ,CAAC,WAAW,IAAI,+BAA+B,GAEzD,CACH,IACG,CACP,IACG,IACE,CACX,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,SAAS,UAAU,CAAC,EAClB,GAAG,EACH,QAAQ,EACR,YAAY,GAKb;IACC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,CACd,kBACE,IAAI,EAAC,QAAQ,iCAEb,SAAS,EAAC,4JAA4J,8BAGtK,KAAC,eAAe,IAAC,SAAS,EAAC,qBAAqB,GAAG,IAC5C,CACV,CAAC;IAEF,MAAM,IAAI,GAAG,CACX,eAAK,SAAS,EAAC,YAAY,aACzB,cAAK,SAAS,EAAC,uDAAuD,8BAEhE,EACN,kBACE,IAAI,EAAC,QAAQ,iCAEb,OAAO,EAAE,GAAG,EAAE;oBACZ,KAAK,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC;oBACnD,OAAO,CAAC,KAAK,CAAC,CAAC;gBACjB,CAAC,EACD,SAAS,EAAC,sIAAsI,aAEhJ,KAAC,iBAAiB,IAAC,SAAS,EAAC,eAAe,GAAG,EAC/C,gBAAM,SAAS,EAAC,cAAc,aAC5B,iDAAgC,EAChC,eAAM,SAAS,EAAC,qDAAqD,yDAE9D,IACF,IACA,EACT,kBACE,IAAI,EAAC,QAAQ,iCAEb,QAAQ,EAAE,CAAC,QAAQ,EACnB,OAAO,EAAE,GAAG,EAAE;oBACZ,QAAQ,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;oBAC3B,OAAO,CAAC,KAAK,CAAC,CAAC;gBACjB,CAAC,EACD,SAAS,EAAC,sLAAsL,aAEhM,KAAC,QAAQ,IAAC,SAAS,EAAC,eAAe,GAAG,EACtC,gBAAM,SAAS,EAAC,cAAc,aAC5B,kDAAiC,EACjC,eAAM,SAAS,EAAC,qDAAqD,kEAE9D,IACF,IACA,IACL,CACP,CAAC;IAEF,4EAA4E;IAC5E,+EAA+E;IAC/E,4CAA4C;IAC5C,MAAM,OAAO,GAAG,GAAG,CAAC,iBAAiB,EAAE,CAAC;QACtC,KAAK,EAAE,eAAe;QACtB,IAAI;QACJ,YAAY,EAAE,OAAO;QACrB,OAAO,EAAE,MAAM;QACf,OAAO;QACP,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IACH,IAAI,OAAO;QAAE,OAAO,4BAAG,OAAO,GAAI,CAAC;IAEnC,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,iCAEb,QAAQ,EAAE,CAAC,QAAQ,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,YAAY,EAAE,CAAC,EACzC,SAAS,EAAC,4MAA4M,8BAG/M,CACV,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,SAAS,qBAAqB,CAAC,EAC7B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,GAAG,GAC8B;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IACjC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAkB,EAAE,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,GAA4B,CAAC;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,MAAM,SAAS,GAAG,CAAC,UAAkB,EAAE,IAAoB,EAAE,EAAE;QAC7D,UAAU,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAChE,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC7C,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAC3C,CAAC,MAAM,CAAC;IACT,MAAM,YAAY,GAAG,GAAG,EAAE,CACxB,gBAAgB,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAEvD,OAAO,CACL,mBACE,SAAS,EAAC,yCAAyC,mBACpC,OAAO,aAErB,KAAK,IAAI,CACR,aAAI,SAAS,EAAC,4DAA4D,YACvE,KAAK,GACH,CACN,EACD,cAAK,SAAS,EAAC,iBAAiB,YAC7B,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,CAClC,KAAC,YAAY,IAEX,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,EAC5B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,IAN3C,QAAQ,CAAC,EAAE,CAOhB,CACH,CAAC,GACE,EACN,eAAK,SAAS,EAAC,2FAA2F,aACxG,aAAG,SAAS,EAAC,6CAA6C,aACvD,QAAQ,OAAG,SAAS,CAAC,MAAM,iBAC1B,EACJ,uDACE,KAAC,UAAU,IACT,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,SAAS,CAAC,oBAAoB,EACxC,YAAY,EAAE,YAAY,GAC1B,GACE,IACF,IACE,CACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAuC;IACtE,OAAO,KAAC,qBAAqB,OAAK,KAAK,GAAI,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,KAA0C;IAE1C,OAAO,KAAC,qBAAqB,OAAK,KAAK,GAAI,CAAC;AAC9C,CAAC;AAED,MAAM,gBAAgB,GACpB,gNAAgN,CAAC;AACnN,MAAM,mBAAmB,GACvB,mOAAmO,CAAC;AACtO,MAAM,gBAAgB,GACpB,6EAA6E,CAAC;AAEhF,SAAS,UAAU,CAAC,MAAc;IAChC,OAAO,GAAG,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AAChE,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,gBAAgB,CAAC,EAC/B,IAAI,EACJ,QAAQ,EACR,QAAQ,GACyB;IACjC,MAAM,cAAc,GAAG,CACrB,UAAkB,EAClB,KAAoC,EACpC,EAAE,CACF,QAAQ,CAAC;QACP,GAAG,IAAI;QACP,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CACzC,QAAQ,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAClE;KACF,CAAC,CAAC;IAEL,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE;YAAE,OAAO;QACxC,QAAQ,CAAC;YACP,GAAG,IAAI;YACP,SAAS,EAAE;gBACT,GAAG,IAAI,CAAC,SAAS;gBACjB;oBACE,EAAE,EAAE,UAAU,CAAC,UAAU,CAAC;oBAC1B,KAAK,EAAE,cAAc;oBACrB,IAAI,EAAE,UAAU;oBAChB,WAAW,EAAE,mBAAmB;iBACjC;aACF;SACF,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,cAAc,GAAG,CAAC,UAAkB,EAAE,EAAE;QAC5C,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO;QACvC,QAAQ,CAAC;YACP,GAAG,IAAI;YACP,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAC9B,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,UAAU,CACzC;SACF,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,eAAe,GAAG,CACtB,QAA8B,EAC9B,IAAkB,EAClB,EAAE,CACF,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;QAC1B,IAAI;QACJ,OAAO,EACL,IAAI,KAAK,UAAU;YACjB,CAAC,CAAC,QAAQ,CAAC,OAAO;YAClB,CAAC,CAAC,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBAC/C,CAAC,CAAC,QAAQ,CAAC,OAAO;gBAClB,CAAC,CAAC;oBACE,EAAE,EAAE,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE;oBAC/C,EAAE,EAAE,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE;iBAChD;KACV,CAAC,CAAC;IAEL,MAAM,YAAY,GAAG,CACnB,UAAkB,EAClB,QAAgB,EAChB,KAAkC,EAClC,EAAE,CACF,QAAQ,CAAC;QACP,GAAG,IAAI;QACP,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CACzC,QAAQ,CAAC,EAAE,KAAK,UAAU;YACxB,CAAC,CAAC;gBACE,GAAG,QAAQ;gBACX,OAAO,EAAE,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAC/C,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAC1D;aACF;YACH,CAAC,CAAC,QAAQ,CACb;KACF,CAAC,CAAC;IAEL,MAAM,SAAS,GAAG,CAAC,UAAkB,EAAE,EAAE,CACvC,QAAQ,CAAC;QACP,GAAG,IAAI;QACP,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CACzC,QAAQ,CAAC,EAAE,KAAK,UAAU,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE;YAChE,CAAC,CAAC;gBACE,GAAG,QAAQ;gBACX,OAAO,EAAE;oBACP,GAAG,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC;oBAC3B,EAAE,EAAE,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE;iBAClD;aACF;YACH,CAAC,CAAC,QAAQ,CACb;KACF,CAAC,CAAC;IAEL,MAAM,YAAY,GAAG,CAAC,UAAkB,EAAE,QAAgB,EAAE,EAAE,CAC5D,QAAQ,CAAC;QACP,GAAG,IAAI;QACP,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;YACzC,IAAI,QAAQ,CAAC,EAAE,KAAK,UAAU;gBAAE,OAAO,QAAQ,CAAC;YAChD,MAAM,WAAW,GAAG,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CACjD,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,CACnC,CAAC;YACF,OAAO,EAAE,GAAG,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QAC/C,CAAC,CAAC;KACH,CAAC,CAAC;IAEL,OAAO,CACL,eAAK,SAAS,EAAC,YAAY,4CACzB,cAAK,SAAS,EAAC,YAAY,YACxB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE;oBACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC;oBACvC,OAAO,CACL,mBAEE,SAAS,EAAC,6CAA6C,aAEvD,eAAK,SAAS,EAAC,8CAA8C,aAC3D,gBAAM,SAAS,EAAE,gBAAgB,0BAAY,KAAK,GAAG,CAAC,IAAQ,EAC7D,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CAC5B,iBACE,IAAI,EAAC,QAAQ,gBACD,mBAAmB,KAAK,GAAG,CAAC,EAAE,EAC1C,SAAS,EAAC,2IAA2I,EACrJ,QAAQ,EAAE,CAAC,QAAQ,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,YAE1C,KAAC,SAAS,IAAC,SAAS,EAAC,QAAQ,GAAG,GACzB,CACV,IACG,EACN,eAAK,SAAS,EAAC,+CAA+C,aAC5D,iBAAO,SAAS,EAAC,cAAc,aAC7B,eAAM,SAAS,EAAE,gBAAgB,sBAAc,EAC/C,gBACE,SAAS,EAAE,gBAAgB,EAC3B,KAAK,EAAE,QAAQ,CAAC,KAAK,EACrB,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;oDAC1B,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;iDAC1B,CAAC,GAEJ,IACI,EACR,iBAAO,SAAS,EAAC,cAAc,aAC7B,eAAM,SAAS,EAAE,gBAAgB,qBAAa,EAC9C,kBACE,SAAS,EAAE,gBAAgB,EAC3B,KAAK,EAAE,QAAQ,CAAC,IAAI,EACpB,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,eAAe,CACb,QAAQ,EACR,KAAK,CAAC,MAAM,CAAC,KAAqB,CACnC,aAGH,iBAAQ,KAAK,EAAC,UAAU,yBAAkB,EAC1C,iBAAQ,KAAK,EAAC,QAAQ,8BAAuB,EAC7C,iBAAQ,KAAK,EAAC,OAAO,6BAAsB,IACpC,IACH,IACJ,EACN,iBAAO,SAAS,EAAC,mBAAmB,aAClC,eAAM,SAAS,EAAE,gBAAgB,yBAAiB,EAClD,mBACE,SAAS,EAAE,mBAAmB,EAC9B,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,QAAQ,CAAC,QAAQ,IAAI,EAAE,EAC9B,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;4CAC1B,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS;yCAC1C,CAAC,GAEJ,IACI,EACR,eAAK,SAAS,EAAC,wDAAwD,aACrE,iBAAO,SAAS,EAAC,cAAc,aAC7B,eAAM,SAAS,EAAE,gBAAgB,4BAAoB,EACrD,gBACE,SAAS,EAAE,gBAAgB,EAC3B,KAAK,EAAE,QAAQ,CAAC,WAAW,IAAI,EAAE,EACjC,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;oDAC1B,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS;iDAC7C,CAAC,GAEJ,IACI,EACR,iBAAO,SAAS,EAAC,kEAAkE,aACjF,gBACE,IAAI,EAAC,UAAU,EACf,SAAS,EAAC,aAAa,EACvB,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EACnC,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;oDAC1B,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,IAAI,SAAS;iDAC5C,CAAC,GAEJ,gBAEI,EACP,QAAQ,CAAC,IAAI,KAAK,UAAU,IAAI,CAC/B,iBAAO,SAAS,EAAC,kEAAkE,aACjF,gBACE,IAAI,EAAC,UAAU,EACf,SAAS,EAAC,aAAa,EACvB,OAAO,EAAE,QAAQ,CAAC,UAAU,KAAK,KAAK,EACtC,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;oDAC1B,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;iDACrD,CAAC,GAEJ,sBAEI,CACT,IACG,EACL,QAAQ,CAAC,IAAI,KAAK,UAAU,IAAI,CAC/B,eAAK,SAAS,EAAC,iBAAiB,aAC7B,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CACvB,eAEE,SAAS,EAAC,iHAAiH,aAE3H,iBAAO,SAAS,EAAC,cAAc,aAC7B,eAAM,SAAS,EAAE,gBAAgB,uBAAe,EAChD,gBACE,SAAS,EAAE,gBAAgB,EAC3B,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,YAAY,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE;4DACnC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;yDAC1B,CAAC,GAEJ,IACI,EACR,iBAAO,SAAS,EAAC,cAAc,aAC7B,eAAM,SAAS,EAAE,gBAAgB,uBAAe,EAChD,gBACE,SAAS,EAAE,gBAAgB,EAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE,EAC1B,QAAQ,EAAE,CAAC,QAAQ,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAClB,YAAY,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE;4DACnC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS;yDACxC,CAAC,GAEJ,IACI,EACR,eAAK,SAAS,EAAC,sBAAsB,aACnC,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,EAAE,CACX,4JAA4J,EAC5J,MAAM,CAAC,WAAW,IAAI,6BAA6B,CACpD,EACD,QAAQ,EAAE,CAAC,QAAQ,EACnB,OAAO,EAAE,GAAG,EAAE,CACZ,YAAY,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE;4DACnC,WAAW,EAAE,CAAC,MAAM,CAAC,WAAW;yDACjC,CAAC,aAGH,MAAM,CAAC,WAAW,IAAI,CACrB,KAAC,SAAS,IAAC,SAAS,EAAC,QAAQ,GAAG,CACjC,mBAEM,EACR,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CACrB,iBACE,IAAI,EAAC,QAAQ,gBACD,UAAU,MAAM,CAAC,KAAK,EAAE,EACpC,SAAS,EAAC,2IAA2I,EACrJ,QAAQ,EAAE,CAAC,QAAQ,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,YAEnD,KAAC,SAAS,IAAC,SAAS,EAAC,QAAQ,GAAG,GACzB,CACV,IACG,KA3DD,MAAM,CAAC,EAAE,CA4DV,CACP,CAAC,EACF,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,kKAAkK,EAC5K,QAAQ,EAAE,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,IAAI,EAAE,EAC3C,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,aAErC,KAAC,QAAQ,IAAC,SAAS,EAAC,QAAQ,GAAG,kBAExB,IACL,CACP,KAzLI,QAAQ,CAAC,EAAE,CA0LR,CACX,CAAC;gBACJ,CAAC,CAAC,GACE,EACN,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,kKAAkK,EAC5K,QAAQ,EAAE,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,EAClD,OAAO,EAAE,WAAW,aAEpB,KAAC,QAAQ,IAAC,SAAS,EAAC,QAAQ,GAAG,oBAExB,IACL,CACP,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAmB;IAC7D,IAAI,EAAE,eAAe;IACrB,MAAM,EAAE,kBAAkB;IAC1B,GAAG,EAAE,eAAe;IACpB,IAAI,EAAE,gBAAgB;IACtB,IAAI,EAAE,gBAAgB;IACtB,SAAS,EAAE,CAAC,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO;IACpB,KAAK,EAAE,eAAe;IACtB,WAAW,EACT,2OAA2O;IAC7O,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACZ,WAAW,EAAE,eAAe;QAC5B,SAAS,EAAE;YACT;gBACE,EAAE,EAAE,eAAe;gBACnB,KAAK,EAAE,0DAA0D;gBACjE,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,gDAAgD;aAC9D;SACF;KACF,CAAC;CACH,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,WAAW,CAAsB;IACnE,IAAI,EAAE,kBAAkB;IACxB,MAAM,EAAE,qBAAqB;IAC7B,GAAG,EAAE,kBAAkB;IACvB,IAAI,EAAE,mBAAmB;IACzB,IAAI,EAAE,gBAAgB;IACtB,SAAS,EAAE,CAAC,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO;IACpB,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACT,4MAA4M;IAC9M,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACZ,WAAW,EAAE,eAAe;QAC5B,SAAS,EAAE;YACT;gBACE,EAAE,EAAE,iBAAiB;gBACrB,KAAK,EAAE,wCAAwC;gBAC/C,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE;oBACP;wBACE,EAAE,EAAE,UAAU;wBACd,KAAK,EAAE,aAAa;wBACpB,MAAM,EAAE,uCAAuC;wBAC/C,WAAW,EAAE,IAAI;qBAClB;oBACD;wBACE,EAAE,EAAE,UAAU;wBACd,KAAK,EAAE,aAAa;wBACpB,MAAM,EAAE,mCAAmC;qBAC5C;iBACF;gBACD,UAAU,EAAE,IAAI;aACjB;SACF;KACF,CAAC;CACH,CAAC,CAAC","sourcesContent":["import { useEffect, useState } from \"react\";\nimport {\n IconCheck,\n IconChevronDown,\n IconClipboardText,\n IconPlus,\n IconSend,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type {\n BlockReadProps,\n BlockEditProps,\n BlockRenderContext,\n NestedBlock,\n} from \"../types.js\";\nimport {\n questionFormSchema,\n questionFormMdx,\n visualQuestionsSchema,\n visualQuestionsMdx,\n type QuestionFormData,\n type QuestionFormOption,\n type QuestionFormQuestion,\n type QuestionMode,\n type VisualQuestionsData,\n} from \"./question-form.config.js\";\n\n/**\n * Shared `question-form` and `visual-questions` blocks. A respondent-facing\n * intake form: single/multi/freeform questions, recommended options, optional\n * write-in answers, and optional inline wireframe/diagram previews per option.\n * Lives in core so any app can register it (it originated in the plan template).\n *\n * The block stays app-agnostic:\n * - It is shadcn-free. The \"Send to agent\" affordance uses `ctx.renderEditSurface`\n * (the app-provided popover primitive); when no surface is wired it falls back\n * to a plain button that submits directly.\n * - Submission routes through `ctx.onQuestionFormSubmit` so each app wires its own\n * destination (plan posts the summary into the side agent). The readable summary\n * string is built generically here from questions + collected answers.\n * - Per-option `wireframe`/`diagram` previews render through `ctx.renderBlock`\n * (the same nested-block seam tabs/columns use), so core never imports an app's\n * wireframe or diagram renderer.\n * - Colors map to shadcn theme tokens (`text-muted-foreground`, `border-border`,\n * `bg-background`, `bg-card`, `primary`). The root section carries BOTH the\n * app-neutral `an-questions-block` class and the legacy `plan-questions-block`\n * class so plan renders byte-identically while other apps get the theme treatment.\n */\n\n/**\n * `ctx.onQuestionFormSubmit` is the documented submit hook. It is read off the\n * render context as an optional extra so a host that has not yet added it to its\n * provider degrades to a no-op (the button disables) rather than throwing.\n */\ntype QuestionFormSubmitCtx = BlockRenderContext & {\n onQuestionFormSubmit?: (summary: string) => void;\n};\n\n/**\n * Reviewer answers are transient and never persisted on block data — they live\n * in local component state keyed by question id. `freeform` → a string;\n * `single`/`multi` → selected option ids (with an optional write-in `text`).\n */\ntype QuestionAnswer = { text?: string; selected?: string[] };\ntype QuestionAnswers = Record<string, QuestionAnswer>;\n\nfunction isAnswered(\n question: QuestionFormQuestion,\n answer?: QuestionAnswer,\n): boolean {\n if (question.mode === \"freeform\") return Boolean(answer?.text?.trim());\n return Boolean(answer?.selected?.length || answer?.text?.trim());\n}\n\n/**\n * Build a readable, agent-ready summary string from the questions + collected\n * answers. Generic replacement for the plan-specific `summarizeQuestionForm`.\n */\nfunction summarizeAnswers(\n blockId: string | undefined,\n blockTitle: string | undefined,\n questions: QuestionFormQuestion[],\n answers: QuestionAnswers,\n): string {\n const lines = [\n \"Use these question answers to revise the plan:\",\n blockId ? `Question block: ${blockId}` : \"\",\n blockTitle ? `Section: ${blockTitle}` : \"\",\n \"\",\n ].filter((line) => line !== \"\");\n for (const question of questions) {\n const answer = answers[question.id];\n const selectedLabels =\n question.options\n ?.filter((option) => answer?.selected?.includes(option.id))\n .map((option) => option.label) ?? [];\n const other = answer?.text?.trim();\n const value =\n question.mode === \"freeform\"\n ? other\n : [...selectedLabels, ...(other ? [`Other: ${other}`] : [])].join(\", \");\n lines.push(`- ${question.title}: ${value || \"No answer yet\"}`);\n }\n return lines.join(\"\\n\");\n}\n\n/** Render an inline preview (wireframe or diagram) through the app's dispatcher. */\nfunction OptionVisual({\n type,\n data,\n blockId,\n ctx,\n}: {\n type: \"wireframe\" | \"diagram\";\n data: unknown;\n blockId: string;\n ctx: BlockRenderContext;\n}) {\n if (!data || !ctx.renderBlock) return null;\n const block: NestedBlock = {\n id: `${blockId}-${type}`,\n type,\n data,\n };\n return (\n <>{ctx.renderBlock({ block, editing: false, compactVisuals: true })}</>\n );\n}\n\nfunction QuestionView({\n question,\n index,\n answer,\n blockId,\n ctx,\n onAnswer,\n}: {\n question: QuestionFormQuestion;\n index: number;\n answer?: QuestionAnswer;\n blockId: string;\n ctx: BlockRenderContext;\n onAnswer: (answer: QuestionAnswer) => void;\n}) {\n const selected = answer?.selected ?? [];\n const hasVisualOptions = Boolean(\n question.options?.some((option) => option.wireframe || option.diagram),\n );\n return (\n <article className=\"grid gap-4 sm:grid-cols-[36px_minmax(0,1fr)]\">\n <div className=\"flex size-7 items-center justify-center rounded-full border border-border bg-card text-xs font-semibold text-muted-foreground\">\n {index + 1}\n </div>\n <div>\n <h3 className=\"text-lg font-semibold leading-7 text-foreground\">\n {question.title}\n </h3>\n {question.subtitle && (\n <p className=\"mt-1.5 max-w-3xl text-sm leading-6 text-muted-foreground\">\n {question.subtitle}\n </p>\n )}\n {question.mode === \"freeform\" ? (\n <textarea\n value={answer?.text ?? \"\"}\n onChange={(event) => onAnswer({ text: event.target.value })}\n className=\"mt-4 min-h-28 w-full rounded-xl border border-border bg-card px-3 py-2 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring\"\n data-plan-interactive\n placeholder={question.placeholder || \"Add details...\"}\n />\n ) : (\n <div\n className={cn(\n \"mt-4\",\n hasVisualOptions\n ? \"grid gap-4 md:grid-cols-2\"\n : \"grid max-w-4xl gap-3\",\n )}\n >\n {question.options?.map((option) => {\n const isSelected = selected.includes(option.id);\n return (\n <button\n key={option.id}\n type=\"button\"\n data-plan-interactive\n aria-pressed={isSelected}\n className={cn(\n hasVisualOptions\n ? \"grid gap-4 rounded-xl border border-border bg-card p-4 text-left transition-colors hover:bg-accent/30\"\n : \"grid w-full gap-2 rounded-xl border border-border bg-card px-4 py-3 text-left text-foreground transition-colors hover:border-primary/40 hover:bg-accent/30\",\n isSelected && \"border-primary/40 bg-primary/10\",\n )}\n onClick={() => {\n if (question.mode === \"single\") {\n onAnswer({ ...answer, selected: [option.id] });\n return;\n }\n onAnswer({\n ...answer,\n selected: isSelected\n ? selected.filter((id) => id !== option.id)\n : [...selected, option.id],\n });\n }}\n >\n <div className=\"flex min-w-0 items-start gap-3\">\n <span\n className={cn(\n \"mt-0.5 flex size-5 shrink-0 items-center justify-center border\",\n question.mode === \"single\" ? \"rounded-full\" : \"rounded\",\n isSelected\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border\",\n )}\n >\n {isSelected && <IconCheck className=\"size-3.5\" />}\n </span>\n <span>\n <span className=\"text-base font-semibold leading-6 text-foreground\">\n {option.label}\n </span>\n {option.recommended && (\n <>\n {\" \"}\n <span className=\"ml-3 rounded-md border border-primary/30 px-2 py-0.5 align-middle text-[11px] font-medium uppercase tracking-[0.12em] text-primary\">\n Recommended\n </span>\n </>\n )}\n {option.detail && (\n <span className=\"mt-1 block max-w-2xl whitespace-pre-line text-sm font-normal leading-6 text-muted-foreground\">\n {option.detail}\n </span>\n )}\n </span>\n </div>\n {hasVisualOptions && (option.wireframe || option.diagram) && (\n <div className=\"ml-8 grid gap-4 lg:grid-cols-[minmax(0,1fr)_280px]\">\n {option.wireframe != null && (\n <OptionVisual\n type=\"wireframe\"\n data={option.wireframe}\n blockId={`${blockId}-${option.id}`}\n ctx={ctx}\n />\n )}\n {option.diagram != null && (\n <OptionVisual\n type=\"diagram\"\n data={option.diagram}\n blockId={`${blockId}-${option.id}`}\n ctx={ctx}\n />\n )}\n </div>\n )}\n </button>\n );\n })}\n {/* Multiple-choice questions always offer a write-in answer so a\n reviewer can give a custom response instead of the listed\n options. Authors opt out only by setting allowOther: false. */}\n {question.allowOther !== false && (\n <input\n value={answer?.text ?? \"\"}\n onChange={(event) =>\n onAnswer({ ...answer, text: event.target.value })\n }\n className={cn(\n \"h-10 w-full rounded-lg border border-border bg-card px-4 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring\",\n hasVisualOptions ? \"md:col-span-2\" : \"sm:w-80\",\n )}\n data-plan-interactive\n placeholder={\n question.placeholder || \"Other — type your own answer…\"\n }\n />\n )}\n </div>\n )}\n </div>\n </article>\n );\n}\n\n/** The \"Send to agent\" affordance: a popover (via the app surface) when wired. */\nfunction SubmitMenu({\n ctx,\n onSubmit,\n buildSummary,\n}: {\n ctx: BlockRenderContext;\n onSubmit?: (summary: string) => void;\n buildSummary: () => string;\n}) {\n const [open, setOpen] = useState(false);\n const trigger = (\n <button\n type=\"button\"\n data-plan-interactive\n className=\"inline-flex h-9 shrink-0 items-center gap-1.5 rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90\"\n >\n Send to agent\n <IconChevronDown className=\"size-3.5 opacity-70\" />\n </button>\n );\n\n const menu = (\n <div className=\"grid gap-1\">\n <div className=\"px-1 py-1 text-xs font-semibold text-muted-foreground\">\n Send feedback\n </div>\n <button\n type=\"button\"\n data-plan-interactive\n onClick={() => {\n void navigator.clipboard.writeText(buildSummary());\n setOpen(false);\n }}\n className=\"grid grid-cols-[auto_1fr] items-start gap-2 rounded-md px-2 py-2 text-left text-sm text-foreground transition-colors hover:bg-accent\"\n >\n <IconClipboardText className=\"mt-0.5 size-4\" />\n <span className=\"grid gap-0.5\">\n <span>Copy for your agent</span>\n <span className=\"text-xs font-normal leading-4 text-muted-foreground\">\n Copies a prompt you can paste into chat.\n </span>\n </span>\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n disabled={!onSubmit}\n onClick={() => {\n onSubmit?.(buildSummary());\n setOpen(false);\n }}\n className=\"grid grid-cols-[auto_1fr] items-start gap-2 rounded-md px-2 py-2 text-left text-sm text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconSend className=\"mt-0.5 size-4\" />\n <span className=\"grid gap-0.5\">\n <span>Send to inline agent</span>\n <span className=\"text-xs font-normal leading-4 text-muted-foreground\">\n Posts answered questions into the app side agent.\n </span>\n </span>\n </button>\n </div>\n );\n\n // Prefer the app-provided popover surface (shadcn Popover in plan/content);\n // core stays shadcn-free. Without a surface, fall back to a single button that\n // submits directly so the form still works.\n const surface = ctx.renderEditSurface?.({\n title: \"Send to agent\",\n open,\n onOpenChange: setOpen,\n variant: \"menu\",\n trigger,\n children: menu,\n });\n if (surface) return <>{surface}</>;\n\n return (\n <button\n type=\"button\"\n data-plan-interactive\n disabled={!onSubmit}\n onClick={() => onSubmit?.(buildSummary())}\n className=\"inline-flex h-9 shrink-0 items-center gap-1.5 rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n Send to agent\n </button>\n );\n}\n\n/** Shared read renderer for both `question-form` and `visual-questions`. */\nfunction QuestionFormReadInner({\n data,\n blockId,\n title,\n ctx,\n}: BlockReadProps<QuestionFormData>) {\n const questions = data.questions;\n const [answers, setAnswers] = useState<QuestionAnswers>({});\n const submitCtx = ctx as QuestionFormSubmitCtx;\n\n useEffect(() => {\n setAnswers({});\n }, [blockId]);\n\n const setAnswer = (questionId: string, next: QuestionAnswer) => {\n setAnswers((current) => ({ ...current, [questionId]: next }));\n };\n\n const answered = questions.filter((question) =>\n isAnswered(question, answers[question.id]),\n ).length;\n const buildSummary = () =>\n summarizeAnswers(blockId, title, questions, answers);\n\n return (\n <section\n className=\"an-questions-block plan-questions-block\"\n data-block-id={blockId}\n >\n {title && (\n <h2 className=\"text-[1.45rem] font-semibold leading-tight text-foreground\">\n {title}\n </h2>\n )}\n <div className=\"mt-7 grid gap-8\">\n {questions.map((question, index) => (\n <QuestionView\n key={question.id}\n question={question}\n index={index}\n answer={answers[question.id]}\n blockId={blockId}\n ctx={ctx}\n onAnswer={(next) => setAnswer(question.id, next)}\n />\n ))}\n </div>\n <div className=\"sticky bottom-0 mt-10 flex items-center justify-between gap-4 border-t border-border py-4\">\n <p className=\"text-sm font-semibold text-muted-foreground\">\n {answered}/{questions.length} answered\n </p>\n <div data-plan-interactive>\n <SubmitMenu\n ctx={ctx}\n onSubmit={submitCtx.onQuestionFormSubmit}\n buildSummary={buildSummary}\n />\n </div>\n </div>\n </section>\n );\n}\n\nexport function QuestionFormRead(props: BlockReadProps<QuestionFormData>) {\n return <QuestionFormReadInner {...props} />;\n}\n\nexport function VisualQuestionsRead(\n props: BlockReadProps<VisualQuestionsData>,\n) {\n return <QuestionFormReadInner {...props} />;\n}\n\nconst inlineInputClass =\n \"w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground shadow-sm outline-none transition-colors placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring\";\nconst inlineTextareaClass =\n \"w-full resize-y rounded-md border border-border bg-background px-3 py-2 text-sm leading-6 text-foreground shadow-sm outline-none transition-colors placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring\";\nconst inlineLabelClass =\n \"text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground\";\n\nfunction newLocalId(prefix: string): string {\n return `${prefix}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Shared editor for both `question-form` and `visual-questions`. */\nexport function QuestionFormEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<QuestionFormData>) {\n const updateQuestion = (\n questionId: string,\n patch: Partial<QuestionFormQuestion>,\n ) =>\n onChange({\n ...data,\n questions: data.questions.map((question) =>\n question.id === questionId ? { ...question, ...patch } : question,\n ),\n });\n\n const addQuestion = () => {\n if (data.questions.length >= 40) return;\n onChange({\n ...data,\n questions: [\n ...data.questions,\n {\n id: newLocalId(\"question\"),\n title: \"New question\",\n mode: \"freeform\",\n placeholder: \"Type an answer...\",\n },\n ],\n });\n };\n\n const removeQuestion = (questionId: string) => {\n if (data.questions.length <= 1) return;\n onChange({\n ...data,\n questions: data.questions.filter(\n (question) => question.id !== questionId,\n ),\n });\n };\n\n const setQuestionMode = (\n question: QuestionFormQuestion,\n mode: QuestionMode,\n ) =>\n updateQuestion(question.id, {\n mode,\n options:\n mode === \"freeform\"\n ? question.options\n : question.options && question.options.length > 0\n ? question.options\n : [\n { id: newLocalId(\"option\"), label: \"Option A\" },\n { id: newLocalId(\"option\"), label: \"Option B\" },\n ],\n });\n\n const updateOption = (\n questionId: string,\n optionId: string,\n patch: Partial<QuestionFormOption>,\n ) =>\n onChange({\n ...data,\n questions: data.questions.map((question) =>\n question.id === questionId\n ? {\n ...question,\n options: (question.options ?? []).map((option) =>\n option.id === optionId ? { ...option, ...patch } : option,\n ),\n }\n : question,\n ),\n });\n\n const addOption = (questionId: string) =>\n onChange({\n ...data,\n questions: data.questions.map((question) =>\n question.id === questionId && (question.options?.length ?? 0) < 40\n ? {\n ...question,\n options: [\n ...(question.options ?? []),\n { id: newLocalId(\"option\"), label: \"New option\" },\n ],\n }\n : question,\n ),\n });\n\n const removeOption = (questionId: string, optionId: string) =>\n onChange({\n ...data,\n questions: data.questions.map((question) => {\n if (question.id !== questionId) return question;\n const nextOptions = (question.options ?? []).filter(\n (option) => option.id !== optionId,\n );\n return { ...question, options: nextOptions };\n }),\n });\n\n return (\n <div className=\"grid gap-6\" data-plan-interactive>\n <div className=\"grid gap-4\">\n {data.questions.map((question, index) => {\n const options = question.options ?? [];\n return (\n <article\n key={question.id}\n className=\"rounded-lg border border-border bg-card p-4\"\n >\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <span className={inlineLabelClass}>Question {index + 1}</span>\n {data.questions.length > 1 && (\n <button\n type=\"button\"\n aria-label={`Delete question ${index + 1}`}\n className=\"inline-flex size-8 items-center justify-center rounded-md border border-border text-muted-foreground hover:bg-muted hover:text-foreground\"\n disabled={!editable}\n onClick={() => removeQuestion(question.id)}\n >\n <IconTrash className=\"size-4\" />\n </button>\n )}\n </div>\n <div className=\"grid gap-3 md:grid-cols-[minmax(0,1fr)_12rem]\">\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Title</span>\n <input\n className={inlineInputClass}\n value={question.title}\n disabled={!editable}\n onChange={(event) =>\n updateQuestion(question.id, {\n title: event.target.value,\n })\n }\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Mode</span>\n <select\n className={inlineInputClass}\n value={question.mode}\n disabled={!editable}\n onChange={(event) =>\n setQuestionMode(\n question,\n event.target.value as QuestionMode,\n )\n }\n >\n <option value=\"freeform\">Freeform</option>\n <option value=\"single\">Single choice</option>\n <option value=\"multi\">Multi choice</option>\n </select>\n </label>\n </div>\n <label className=\"mt-3 grid gap-1.5\">\n <span className={inlineLabelClass}>Subtitle</span>\n <textarea\n className={inlineTextareaClass}\n rows={2}\n value={question.subtitle ?? \"\"}\n disabled={!editable}\n onChange={(event) =>\n updateQuestion(question.id, {\n subtitle: event.target.value || undefined,\n })\n }\n />\n </label>\n <div className=\"mt-3 grid gap-3 md:grid-cols-[minmax(0,1fr)_auto_auto]\">\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Placeholder</span>\n <input\n className={inlineInputClass}\n value={question.placeholder ?? \"\"}\n disabled={!editable}\n onChange={(event) =>\n updateQuestion(question.id, {\n placeholder: event.target.value || undefined,\n })\n }\n />\n </label>\n <label className=\"flex items-end gap-2 text-sm font-semibold text-muted-foreground\">\n <input\n type=\"checkbox\"\n className=\"mb-2 size-4\"\n checked={Boolean(question.required)}\n disabled={!editable}\n onChange={(event) =>\n updateQuestion(question.id, {\n required: event.target.checked || undefined,\n })\n }\n />\n Required\n </label>\n {question.mode !== \"freeform\" && (\n <label className=\"flex items-end gap-2 text-sm font-semibold text-muted-foreground\">\n <input\n type=\"checkbox\"\n className=\"mb-2 size-4\"\n checked={question.allowOther !== false}\n disabled={!editable}\n onChange={(event) =>\n updateQuestion(question.id, {\n allowOther: event.target.checked ? undefined : false,\n })\n }\n />\n Allow write-in\n </label>\n )}\n </div>\n {question.mode !== \"freeform\" && (\n <div className=\"mt-4 grid gap-3\">\n {options.map((option) => (\n <div\n key={option.id}\n className=\"grid gap-3 rounded-md border border-border/80 bg-background p-3 md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto]\"\n >\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Option</span>\n <input\n className={inlineInputClass}\n value={option.label}\n disabled={!editable}\n onChange={(event) =>\n updateOption(question.id, option.id, {\n label: event.target.value,\n })\n }\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Detail</span>\n <input\n className={inlineInputClass}\n value={option.detail ?? \"\"}\n disabled={!editable}\n onChange={(event) =>\n updateOption(question.id, option.id, {\n detail: event.target.value || undefined,\n })\n }\n />\n </label>\n <div className=\"flex items-end gap-2\">\n <button\n type=\"button\"\n className={cn(\n \"inline-flex h-9 items-center gap-1.5 rounded-md border border-border px-3 text-sm font-semibold text-muted-foreground hover:bg-muted hover:text-foreground\",\n option.recommended && \"border-ring text-foreground\",\n )}\n disabled={!editable}\n onClick={() =>\n updateOption(question.id, option.id, {\n recommended: !option.recommended,\n })\n }\n >\n {option.recommended && (\n <IconCheck className=\"size-4\" />\n )}\n Recommended\n </button>\n {options.length > 1 && (\n <button\n type=\"button\"\n aria-label={`Delete ${option.label}`}\n className=\"inline-flex size-9 items-center justify-center rounded-md border border-border text-muted-foreground hover:bg-muted hover:text-foreground\"\n disabled={!editable}\n onClick={() => removeOption(question.id, option.id)}\n >\n <IconTrash className=\"size-4\" />\n </button>\n )}\n </div>\n </div>\n ))}\n <button\n type=\"button\"\n className=\"inline-flex h-9 w-fit items-center gap-1.5 rounded-md border border-border px-3 text-sm font-semibold text-muted-foreground hover:bg-muted hover:text-foreground\"\n disabled={!editable || options.length >= 40}\n onClick={() => addOption(question.id)}\n >\n <IconPlus className=\"size-4\" />\n Add option\n </button>\n </div>\n )}\n </article>\n );\n })}\n </div>\n <button\n type=\"button\"\n className=\"inline-flex h-9 w-fit items-center gap-1.5 rounded-md border border-border px-3 text-sm font-semibold text-muted-foreground hover:bg-muted hover:text-foreground\"\n disabled={!editable || data.questions.length >= 40}\n onClick={addQuestion}\n >\n <IconPlus className=\"size-4\" />\n Add question\n </button>\n </div>\n );\n}\n\n/**\n * Full client spec for the shared `question-form` block. A respondent-facing\n * intake form edited from the block panel (the schema-ish question shape lives\n * behind the edit surface, not inline).\n */\nexport const questionFormBlock = defineBlock<QuestionFormData>({\n type: \"question-form\",\n schema: questionFormSchema,\n mdx: questionFormMdx,\n Read: QuestionFormRead,\n Edit: QuestionFormEdit,\n placement: [\"block\"],\n editSurface: \"panel\",\n label: \"Question form\",\n description:\n \"An interactive respondent-facing form block for open questions, single-choice or multi-choice option rows, freeform answers, recommended options, and optional wireframe/diagram previews. Edit the question schema from the block panel.\",\n empty: () => ({\n submitLabel: \"Send to agent\",\n questions: [\n {\n id: \"open-question\",\n title: \"What should the agent clarify before revising this plan?\",\n mode: \"freeform\",\n placeholder: \"Add constraints, preferences, or a decision...\",\n },\n ],\n }),\n});\n\n/**\n * Full client spec for the shared `visual-questions` block — the same form UI\n * and data shape as `question-form`, branded for explicit visual intake before a\n * plan. Shares the Read/Edit internals; only the type, MDX tag, label, and seed\n * differ.\n */\nexport const visualQuestionsBlock = defineBlock<VisualQuestionsData>({\n type: \"visual-questions\",\n schema: visualQuestionsSchema,\n mdx: visualQuestionsMdx,\n Read: VisualQuestionsRead,\n Edit: QuestionFormEdit,\n placement: [\"block\"],\n editSurface: \"panel\",\n label: \"Visual questions\",\n description:\n \"A visual-intake question block that renders the respondent-facing question UI (single/multi/freeform, recommended options, inline wireframe/diagram previews) and keeps schema editing in the block panel.\",\n empty: () => ({\n submitLabel: \"Send to agent\",\n questions: [\n {\n id: \"visual-question\",\n title: \"Which direction should this plan take?\",\n mode: \"single\",\n options: [\n {\n id: \"option-a\",\n label: \"Direction A\",\n detail: \"Keep the current shape and refine it.\",\n recommended: true,\n },\n {\n id: \"option-b\",\n label: \"Direction B\",\n detail: \"Try a larger structural revision.\",\n },\n ],\n allowOther: true,\n },\n ],\n }),\n});\n"]}
1
+ {"version":3,"file":"question-form.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/question-form.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useState } from \"react\";\nimport {\n IconCheck,\n IconChevronDown,\n IconClipboardText,\n IconPlus,\n IconSend,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type {\n BlockReadProps,\n BlockEditProps,\n BlockRenderContext,\n NestedBlock,\n} from \"../types.js\";\nimport {\n questionFormSchema,\n questionFormMdx,\n visualQuestionsSchema,\n visualQuestionsMdx,\n type QuestionFormData,\n type QuestionFormOption,\n type QuestionFormQuestion,\n type QuestionMode,\n type VisualQuestionsData,\n} from \"./question-form.config.js\";\n\n/**\n * Shared `question-form` and `visual-questions` blocks. A respondent-facing\n * intake form: single/multi/freeform questions, recommended options, optional\n * write-in answers, and optional inline wireframe/diagram previews per option.\n * Lives in core so any app can register it (it originated in the plan template).\n *\n * The block stays app-agnostic:\n * - It is shadcn-free. The \"Send to agent\" affordance uses `ctx.renderEditSurface`\n * (the app-provided popover primitive); when no surface is wired it falls back\n * to a plain button that submits directly.\n * - Submission routes through `ctx.onQuestionFormSubmit` so each app wires its own\n * destination (plan posts the summary into the side agent). The readable summary\n * string is built generically here from questions + collected answers.\n * - Per-option `wireframe`/`diagram` previews render through `ctx.renderBlock`\n * (the same nested-block seam tabs/columns use), so core never imports an app's\n * wireframe or diagram renderer.\n * - Colors map to shadcn theme tokens (`text-muted-foreground`, `border-border`,\n * `bg-background`, `bg-card`, `primary`). The root section carries BOTH the\n * app-neutral `an-questions-block` class and the legacy `plan-questions-block`\n * class so plan renders byte-identically while other apps get the theme treatment.\n */\n\n/**\n * `ctx.onQuestionFormSubmit` is the documented submit hook. It is read off the\n * render context as an optional extra so a host that has not yet added it to its\n * provider degrades to a no-op (the button disables) rather than throwing.\n */\ntype QuestionFormSubmitCtx = BlockRenderContext & {\n onQuestionFormSubmit?: (summary: string) => void;\n};\n\n/**\n * Reviewer answers are transient and never persisted on block data — they live\n * in local component state keyed by question id. `freeform` → a string;\n * `single`/`multi` → selected option ids (with an optional write-in `text`).\n */\ntype QuestionAnswer = { text?: string; selected?: string[] };\ntype QuestionAnswers = Record<string, QuestionAnswer>;\n\nfunction isAnswered(\n question: QuestionFormQuestion,\n answer?: QuestionAnswer,\n): boolean {\n if (question.mode === \"freeform\") return Boolean(answer?.text?.trim());\n return Boolean(answer?.selected?.length || answer?.text?.trim());\n}\n\n/**\n * Build a readable, agent-ready summary string from the questions + collected\n * answers. Generic replacement for the plan-specific `summarizeQuestionForm`.\n */\nfunction summarizeAnswers(\n blockId: string | undefined,\n blockTitle: string | undefined,\n questions: QuestionFormQuestion[],\n answers: QuestionAnswers,\n): string {\n const lines = [\n \"Use these question answers to revise the plan:\",\n blockId ? `Question block: ${blockId}` : \"\",\n blockTitle ? `Section: ${blockTitle}` : \"\",\n \"\",\n ].filter((line) => line !== \"\");\n for (const question of questions) {\n const answer = answers[question.id];\n const selectedLabels =\n question.options\n ?.filter((option) => answer?.selected?.includes(option.id))\n .map((option) => option.label) ?? [];\n const other = answer?.text?.trim();\n const value =\n question.mode === \"freeform\"\n ? other\n : [...selectedLabels, ...(other ? [`Other: ${other}`] : [])].join(\", \");\n lines.push(`- ${question.title}: ${value || \"No answer yet\"}`);\n }\n return lines.join(\"\\n\");\n}\n\n/** Render an inline preview (wireframe or diagram) through the app's dispatcher. */\nfunction OptionVisual({\n type,\n data,\n blockId,\n ctx,\n}: {\n type: \"wireframe\" | \"diagram\";\n data: unknown;\n blockId: string;\n ctx: BlockRenderContext;\n}) {\n if (!data || !ctx.renderBlock) return null;\n const block: NestedBlock = {\n id: `${blockId}-${type}`,\n type,\n data,\n };\n return (\n <>{ctx.renderBlock({ block, editing: false, compactVisuals: true })}</>\n );\n}\n\nfunction QuestionView({\n question,\n index,\n answer,\n blockId,\n ctx,\n onAnswer,\n}: {\n question: QuestionFormQuestion;\n index: number;\n answer?: QuestionAnswer;\n blockId: string;\n ctx: BlockRenderContext;\n onAnswer: (answer: QuestionAnswer) => void;\n}) {\n const selected = answer?.selected ?? [];\n const hasVisualOptions = Boolean(\n question.options?.some((option) => option.wireframe || option.diagram),\n );\n return (\n <article className=\"grid gap-4 sm:grid-cols-[36px_minmax(0,1fr)]\">\n <div className=\"flex size-7 items-center justify-center rounded-full border border-border bg-card text-xs font-semibold text-muted-foreground\">\n {index + 1}\n </div>\n <div>\n <h3 className=\"text-lg font-semibold leading-7 text-foreground\">\n {question.title}\n </h3>\n {question.subtitle && (\n <p className=\"mt-1.5 max-w-3xl text-sm leading-6 text-muted-foreground\">\n {question.subtitle}\n </p>\n )}\n {question.mode === \"freeform\" ? (\n <textarea\n value={answer?.text ?? \"\"}\n onChange={(event) => onAnswer({ text: event.target.value })}\n className=\"mt-4 min-h-28 w-full rounded-xl border border-border bg-card px-3 py-2 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring\"\n data-plan-interactive\n placeholder={question.placeholder || \"Add details...\"}\n />\n ) : (\n <div\n className={cn(\n \"mt-4\",\n hasVisualOptions\n ? \"grid gap-4 md:grid-cols-2\"\n : \"grid max-w-4xl gap-3\",\n )}\n >\n {question.options?.map((option) => {\n const isSelected = selected.includes(option.id);\n return (\n <button\n key={option.id}\n type=\"button\"\n data-plan-interactive\n aria-pressed={isSelected}\n className={cn(\n hasVisualOptions\n ? \"grid gap-4 rounded-xl border border-border bg-card p-4 text-left transition-colors hover:bg-accent/30\"\n : \"grid w-full gap-2 rounded-xl border border-border bg-card px-4 py-3 text-left text-foreground transition-colors hover:border-primary/40 hover:bg-accent/30\",\n isSelected && \"border-primary/40 bg-primary/10\",\n )}\n onClick={() => {\n if (question.mode === \"single\") {\n onAnswer({ ...answer, selected: [option.id] });\n return;\n }\n onAnswer({\n ...answer,\n selected: isSelected\n ? selected.filter((id) => id !== option.id)\n : [...selected, option.id],\n });\n }}\n >\n <div className=\"flex min-w-0 items-start gap-3\">\n <span\n className={cn(\n \"mt-0.5 flex size-5 shrink-0 items-center justify-center border\",\n question.mode === \"single\" ? \"rounded-full\" : \"rounded\",\n isSelected\n ? \"border-primary bg-primary text-primary-foreground\"\n : \"border-border\",\n )}\n >\n {isSelected && <IconCheck className=\"size-3.5\" />}\n </span>\n <span>\n <span className=\"text-base font-semibold leading-6 text-foreground\">\n {option.label}\n </span>\n {option.recommended && (\n <>\n {\" \"}\n <span className=\"ml-3 rounded-md border border-primary/30 px-2 py-0.5 align-middle text-[11px] font-medium uppercase tracking-[0.12em] text-primary\">\n Recommended\n </span>\n </>\n )}\n {option.detail && (\n <span className=\"mt-1 block max-w-2xl whitespace-pre-line text-sm font-normal leading-6 text-muted-foreground\">\n {option.detail}\n </span>\n )}\n </span>\n </div>\n {hasVisualOptions && (option.wireframe || option.diagram) && (\n // Stop click/keyboard propagation so interactions inside the\n // preview (expand button, lightbox close) don't toggle the\n // option. Nested interactive elements inside a <button> are\n // invalid HTML, so this also keeps the outer button's\n // keyboard behaviour clean.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n className=\"ml-8 grid gap-4 lg:grid-cols-[minmax(0,1fr)_280px]\"\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \")\n e.stopPropagation();\n }}\n >\n {option.wireframe != null && (\n <OptionVisual\n type=\"wireframe\"\n data={option.wireframe}\n blockId={`${blockId}-${option.id}`}\n ctx={ctx}\n />\n )}\n {option.diagram != null && (\n <OptionVisual\n type=\"diagram\"\n data={option.diagram}\n blockId={`${blockId}-${option.id}`}\n ctx={ctx}\n />\n )}\n </div>\n )}\n </button>\n );\n })}\n {/* Multiple-choice questions always offer a write-in answer so a\n reviewer can give a custom response instead of the listed\n options. Authors opt out only by setting allowOther: false. */}\n {question.allowOther !== false && (\n <input\n value={answer?.text ?? \"\"}\n onChange={(event) =>\n onAnswer({ ...answer, text: event.target.value })\n }\n className={cn(\n \"h-10 w-full rounded-lg border border-border bg-card px-4 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring\",\n hasVisualOptions ? \"md:col-span-2\" : \"sm:w-80\",\n )}\n data-plan-interactive\n placeholder={\n question.placeholder || \"Other — type your own answer…\"\n }\n />\n )}\n </div>\n )}\n </div>\n </article>\n );\n}\n\n/** The \"Send to agent\" affordance: a popover (via the app surface) when wired. */\nfunction SubmitMenu({\n ctx,\n onSubmit,\n buildSummary,\n}: {\n ctx: BlockRenderContext;\n onSubmit?: (summary: string) => void;\n buildSummary: () => string;\n}) {\n const [open, setOpen] = useState(false);\n const trigger = (\n <button\n type=\"button\"\n data-plan-interactive\n className=\"inline-flex h-9 shrink-0 items-center gap-1.5 rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90\"\n >\n Send to agent\n <IconChevronDown className=\"size-3.5 opacity-70\" />\n </button>\n );\n\n const menu = (\n <div className=\"grid gap-1\">\n <div className=\"px-1 py-1 text-xs font-semibold text-muted-foreground\">\n Send feedback\n </div>\n <button\n type=\"button\"\n data-plan-interactive\n onClick={() => {\n void navigator.clipboard.writeText(buildSummary());\n setOpen(false);\n }}\n className=\"grid grid-cols-[auto_1fr] items-start gap-2 rounded-md px-2 py-2 text-left text-sm text-foreground transition-colors hover:bg-accent\"\n >\n <IconClipboardText className=\"mt-0.5 size-4\" />\n <span className=\"grid gap-0.5\">\n <span>Copy for your agent</span>\n <span className=\"text-xs font-normal leading-4 text-muted-foreground\">\n Copies a prompt you can paste into chat.\n </span>\n </span>\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n disabled={!onSubmit}\n onClick={() => {\n onSubmit?.(buildSummary());\n setOpen(false);\n }}\n className=\"grid grid-cols-[auto_1fr] items-start gap-2 rounded-md px-2 py-2 text-left text-sm text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconSend className=\"mt-0.5 size-4\" />\n <span className=\"grid gap-0.5\">\n <span>Send to inline agent</span>\n <span className=\"text-xs font-normal leading-4 text-muted-foreground\">\n Posts answered questions into the app side agent.\n </span>\n </span>\n </button>\n </div>\n );\n\n // Prefer the app-provided popover surface (shadcn Popover in plan/content);\n // core stays shadcn-free. Without a surface, fall back to a single button that\n // submits directly so the form still works.\n const surface = ctx.renderEditSurface?.({\n title: \"Send to agent\",\n open,\n onOpenChange: setOpen,\n variant: \"menu\",\n trigger,\n children: menu,\n });\n if (surface) return <>{surface}</>;\n\n return (\n <button\n type=\"button\"\n data-plan-interactive\n disabled={!onSubmit}\n onClick={() => onSubmit?.(buildSummary())}\n className=\"inline-flex h-9 shrink-0 items-center gap-1.5 rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n Send to agent\n </button>\n );\n}\n\n/** Shared read renderer for both `question-form` and `visual-questions`. */\nfunction QuestionFormReadInner({\n data,\n blockId,\n title,\n ctx,\n}: BlockReadProps<QuestionFormData>) {\n const questions = data.questions;\n const [answers, setAnswers] = useState<QuestionAnswers>({});\n const submitCtx = ctx as QuestionFormSubmitCtx;\n\n useEffect(() => {\n setAnswers({});\n }, [blockId]);\n\n const setAnswer = (questionId: string, next: QuestionAnswer) => {\n setAnswers((current) => ({ ...current, [questionId]: next }));\n };\n\n const answered = questions.filter((question) =>\n isAnswered(question, answers[question.id]),\n ).length;\n const buildSummary = () =>\n summarizeAnswers(blockId, title, questions, answers);\n\n return (\n <section\n className=\"an-questions-block plan-questions-block\"\n data-block-id={blockId}\n >\n {title && (\n <h2 className=\"text-[1.45rem] font-semibold leading-tight text-foreground\">\n {title}\n </h2>\n )}\n <div className=\"mt-7 grid gap-8\">\n {questions.map((question, index) => (\n <QuestionView\n key={question.id}\n question={question}\n index={index}\n answer={answers[question.id]}\n blockId={blockId}\n ctx={ctx}\n onAnswer={(next) => setAnswer(question.id, next)}\n />\n ))}\n </div>\n <div className=\"sticky bottom-0 mt-10 flex items-center justify-between gap-4 border-t border-border py-4\">\n <p className=\"text-sm font-semibold text-muted-foreground\">\n {answered}/{questions.length} answered\n </p>\n <div data-plan-interactive>\n <SubmitMenu\n ctx={ctx}\n onSubmit={submitCtx.onQuestionFormSubmit}\n buildSummary={buildSummary}\n />\n </div>\n </div>\n </section>\n );\n}\n\nexport function QuestionFormRead(props: BlockReadProps<QuestionFormData>) {\n return <QuestionFormReadInner {...props} />;\n}\n\nexport function VisualQuestionsRead(\n props: BlockReadProps<VisualQuestionsData>,\n) {\n return <QuestionFormReadInner {...props} />;\n}\n\nconst inlineInputClass =\n \"w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground shadow-sm outline-none transition-colors placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring\";\nconst inlineTextareaClass =\n \"w-full resize-y rounded-md border border-border bg-background px-3 py-2 text-sm leading-6 text-foreground shadow-sm outline-none transition-colors placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring\";\nconst inlineLabelClass =\n \"text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground\";\n\nfunction newLocalId(prefix: string): string {\n return `${prefix}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Shared editor for both `question-form` and `visual-questions`. */\nexport function QuestionFormEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<QuestionFormData>) {\n const updateQuestion = (\n questionId: string,\n patch: Partial<QuestionFormQuestion>,\n ) =>\n onChange({\n ...data,\n questions: data.questions.map((question) =>\n question.id === questionId ? { ...question, ...patch } : question,\n ),\n });\n\n const addQuestion = () => {\n if (data.questions.length >= 40) return;\n onChange({\n ...data,\n questions: [\n ...data.questions,\n {\n id: newLocalId(\"question\"),\n title: \"New question\",\n mode: \"freeform\",\n placeholder: \"Type an answer...\",\n },\n ],\n });\n };\n\n const removeQuestion = (questionId: string) => {\n if (data.questions.length <= 1) return;\n onChange({\n ...data,\n questions: data.questions.filter(\n (question) => question.id !== questionId,\n ),\n });\n };\n\n const setQuestionMode = (\n question: QuestionFormQuestion,\n mode: QuestionMode,\n ) =>\n updateQuestion(question.id, {\n mode,\n options:\n mode === \"freeform\"\n ? question.options\n : question.options && question.options.length > 0\n ? question.options\n : [\n { id: newLocalId(\"option\"), label: \"Option A\" },\n { id: newLocalId(\"option\"), label: \"Option B\" },\n ],\n });\n\n const updateOption = (\n questionId: string,\n optionId: string,\n patch: Partial<QuestionFormOption>,\n ) =>\n onChange({\n ...data,\n questions: data.questions.map((question) =>\n question.id === questionId\n ? {\n ...question,\n options: (question.options ?? []).map((option) =>\n option.id === optionId ? { ...option, ...patch } : option,\n ),\n }\n : question,\n ),\n });\n\n const addOption = (questionId: string) =>\n onChange({\n ...data,\n questions: data.questions.map((question) =>\n question.id === questionId && (question.options?.length ?? 0) < 40\n ? {\n ...question,\n options: [\n ...(question.options ?? []),\n { id: newLocalId(\"option\"), label: \"New option\" },\n ],\n }\n : question,\n ),\n });\n\n const removeOption = (questionId: string, optionId: string) =>\n onChange({\n ...data,\n questions: data.questions.map((question) => {\n if (question.id !== questionId) return question;\n const nextOptions = (question.options ?? []).filter(\n (option) => option.id !== optionId,\n );\n return { ...question, options: nextOptions };\n }),\n });\n\n return (\n <div className=\"grid gap-6\" data-plan-interactive>\n <div className=\"grid gap-4\">\n {data.questions.map((question, index) => {\n const options = question.options ?? [];\n return (\n <article\n key={question.id}\n className=\"rounded-lg border border-border bg-card p-4\"\n >\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <span className={inlineLabelClass}>Question {index + 1}</span>\n {data.questions.length > 1 && (\n <button\n type=\"button\"\n aria-label={`Delete question ${index + 1}`}\n className=\"inline-flex size-8 items-center justify-center rounded-md border border-border text-muted-foreground hover:bg-muted hover:text-foreground\"\n disabled={!editable}\n onClick={() => removeQuestion(question.id)}\n >\n <IconTrash className=\"size-4\" />\n </button>\n )}\n </div>\n <div className=\"grid gap-3 md:grid-cols-[minmax(0,1fr)_12rem]\">\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Title</span>\n <input\n className={inlineInputClass}\n value={question.title}\n disabled={!editable}\n onChange={(event) =>\n updateQuestion(question.id, {\n title: event.target.value,\n })\n }\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Mode</span>\n <select\n className={inlineInputClass}\n value={question.mode}\n disabled={!editable}\n onChange={(event) =>\n setQuestionMode(\n question,\n event.target.value as QuestionMode,\n )\n }\n >\n <option value=\"freeform\">Freeform</option>\n <option value=\"single\">Single choice</option>\n <option value=\"multi\">Multi choice</option>\n </select>\n </label>\n </div>\n <label className=\"mt-3 grid gap-1.5\">\n <span className={inlineLabelClass}>Subtitle</span>\n <textarea\n className={inlineTextareaClass}\n rows={2}\n value={question.subtitle ?? \"\"}\n disabled={!editable}\n onChange={(event) =>\n updateQuestion(question.id, {\n subtitle: event.target.value || undefined,\n })\n }\n />\n </label>\n <div className=\"mt-3 grid gap-3 md:grid-cols-[minmax(0,1fr)_auto_auto]\">\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Placeholder</span>\n <input\n className={inlineInputClass}\n value={question.placeholder ?? \"\"}\n disabled={!editable}\n onChange={(event) =>\n updateQuestion(question.id, {\n placeholder: event.target.value || undefined,\n })\n }\n />\n </label>\n <label className=\"flex items-end gap-2 text-sm font-semibold text-muted-foreground\">\n <input\n type=\"checkbox\"\n className=\"mb-2 size-4\"\n checked={Boolean(question.required)}\n disabled={!editable}\n onChange={(event) =>\n updateQuestion(question.id, {\n required: event.target.checked || undefined,\n })\n }\n />\n Required\n </label>\n {question.mode !== \"freeform\" && (\n <label className=\"flex items-end gap-2 text-sm font-semibold text-muted-foreground\">\n <input\n type=\"checkbox\"\n className=\"mb-2 size-4\"\n checked={question.allowOther !== false}\n disabled={!editable}\n onChange={(event) =>\n updateQuestion(question.id, {\n allowOther: event.target.checked ? undefined : false,\n })\n }\n />\n Allow write-in\n </label>\n )}\n </div>\n {question.mode !== \"freeform\" && (\n <div className=\"mt-4 grid gap-3\">\n {options.map((option) => (\n <div\n key={option.id}\n className=\"grid gap-3 rounded-md border border-border/80 bg-background p-3 md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto]\"\n >\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Option</span>\n <input\n className={inlineInputClass}\n value={option.label}\n disabled={!editable}\n onChange={(event) =>\n updateOption(question.id, option.id, {\n label: event.target.value,\n })\n }\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Detail</span>\n <input\n className={inlineInputClass}\n value={option.detail ?? \"\"}\n disabled={!editable}\n onChange={(event) =>\n updateOption(question.id, option.id, {\n detail: event.target.value || undefined,\n })\n }\n />\n </label>\n <div className=\"flex items-end gap-2\">\n <button\n type=\"button\"\n className={cn(\n \"inline-flex h-9 items-center gap-1.5 rounded-md border border-border px-3 text-sm font-semibold text-muted-foreground hover:bg-muted hover:text-foreground\",\n option.recommended && \"border-ring text-foreground\",\n )}\n disabled={!editable}\n onClick={() =>\n updateOption(question.id, option.id, {\n recommended: !option.recommended,\n })\n }\n >\n {option.recommended && (\n <IconCheck className=\"size-4\" />\n )}\n Recommended\n </button>\n {options.length > 1 && (\n <button\n type=\"button\"\n aria-label={`Delete ${option.label}`}\n className=\"inline-flex size-9 items-center justify-center rounded-md border border-border text-muted-foreground hover:bg-muted hover:text-foreground\"\n disabled={!editable}\n onClick={() => removeOption(question.id, option.id)}\n >\n <IconTrash className=\"size-4\" />\n </button>\n )}\n </div>\n </div>\n ))}\n <button\n type=\"button\"\n className=\"inline-flex h-9 w-fit items-center gap-1.5 rounded-md border border-border px-3 text-sm font-semibold text-muted-foreground hover:bg-muted hover:text-foreground\"\n disabled={!editable || options.length >= 40}\n onClick={() => addOption(question.id)}\n >\n <IconPlus className=\"size-4\" />\n Add option\n </button>\n </div>\n )}\n </article>\n );\n })}\n </div>\n <button\n type=\"button\"\n className=\"inline-flex h-9 w-fit items-center gap-1.5 rounded-md border border-border px-3 text-sm font-semibold text-muted-foreground hover:bg-muted hover:text-foreground\"\n disabled={!editable || data.questions.length >= 40}\n onClick={addQuestion}\n >\n <IconPlus className=\"size-4\" />\n Add question\n </button>\n </div>\n );\n}\n\n/**\n * Full client spec for the shared `question-form` block. A respondent-facing\n * intake form edited from the block panel (the schema-ish question shape lives\n * behind the edit surface, not inline).\n */\nexport const questionFormBlock = defineBlock<QuestionFormData>({\n type: \"question-form\",\n schema: questionFormSchema,\n mdx: questionFormMdx,\n Read: QuestionFormRead,\n Edit: QuestionFormEdit,\n placement: [\"block\"],\n editSurface: \"panel\",\n label: \"Question form\",\n description:\n \"An interactive respondent-facing form block for open questions, single-choice or multi-choice option rows, freeform answers, recommended options, and optional wireframe/diagram previews. Edit the question schema from the block panel.\",\n empty: () => ({\n submitLabel: \"Send to agent\",\n questions: [\n {\n id: \"open-question\",\n title: \"What should the agent clarify before revising this plan?\",\n mode: \"freeform\",\n placeholder: \"Add constraints, preferences, or a decision...\",\n },\n ],\n }),\n});\n\n/**\n * Full client spec for the shared `visual-questions` block — the same form UI\n * and data shape as `question-form`, branded for explicit visual intake before a\n * plan. Shares the Read/Edit internals; only the type, MDX tag, label, and seed\n * differ.\n */\nexport const visualQuestionsBlock = defineBlock<VisualQuestionsData>({\n type: \"visual-questions\",\n schema: visualQuestionsSchema,\n mdx: visualQuestionsMdx,\n Read: VisualQuestionsRead,\n Edit: QuestionFormEdit,\n placement: [\"block\"],\n editSurface: \"panel\",\n label: \"Visual questions\",\n description:\n \"A visual-intake question block that renders the respondent-facing question UI (single/multi/freeform, recommended options, inline wireframe/diagram previews) and keeps schema editing in the block panel.\",\n empty: () => ({\n submitLabel: \"Send to agent\",\n questions: [\n {\n id: \"visual-question\",\n title: \"Which direction should this plan take?\",\n mode: \"single\",\n options: [\n {\n id: \"option-a\",\n label: \"Direction A\",\n detail: \"Keep the current shape and refine it.\",\n recommended: true,\n },\n {\n id: \"option-b\",\n label: \"Direction B\",\n detail: \"Try a larger structural revision.\",\n },\n ],\n allowOther: true,\n },\n ],\n }),\n});\n"]}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * LiveCursorOverlay — renders remote users' cursors over an absolutely-
3
+ * positioned container.
4
+ *
5
+ * Cursor positions are expected as normalized coordinates (0–1 relative to
6
+ * the container's content size) so different zoom/scroll positions map
7
+ * correctly. Pass a `mapCoords` prop to handle non-identity transforms
8
+ * (e.g. a zoomed canvas).
9
+ *
10
+ * The agent's cursor is styled distinctly with a sparkle variant + "AI"
11
+ * label, consistent with AgentPresenceChip.
12
+ *
13
+ * Cursors fade out after 10 seconds of no movement.
14
+ */
15
+ import type { OtherPresence, NormalizedPoint } from "../../collab/presence.js";
16
+ export interface CursorMapFn {
17
+ /** Convert normalized coords to pixel offsets within the overlay container. */
18
+ (norm: NormalizedPoint): {
19
+ x: number;
20
+ y: number;
21
+ };
22
+ }
23
+ export interface LiveCursorOverlayProps {
24
+ /** Remote participants with presence payload. */
25
+ others: OtherPresence[];
26
+ /**
27
+ * Key inside presence payload that carries the cursor position.
28
+ * Default: "cursor"
29
+ * Expected shape: { x: number; y: number } (normalized 0–1).
30
+ */
31
+ cursorKey?: string;
32
+ /**
33
+ * Override coordinate mapping. Default: scale by container clientWidth/Height.
34
+ * Pass this when the container uses transform: scale() or has virtual scroll.
35
+ */
36
+ mapCoords?: CursorMapFn;
37
+ /**
38
+ * Container element ref. Required when mapCoords is not provided —
39
+ * used to compute pixel positions from normalized coords.
40
+ */
41
+ containerRef?: React.RefObject<HTMLElement | null>;
42
+ /** Additional CSS class for the overlay div. */
43
+ className?: string;
44
+ }
45
+ export declare function LiveCursorOverlay({ others, cursorKey, mapCoords, containerRef, className, }: LiveCursorOverlayProps): import("react/jsx-runtime").JSX.Element;
46
+ //# sourceMappingURL=LiveCursorOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiveCursorOverlay.d.ts","sourceRoot":"","sources":["../../../src/client/components/LiveCursorOverlay.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAG/E,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,CAAC,IAAI,EAAE,eAAe,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnD;AAED,MAAM,WAAW,sBAAsB;IACrC,iDAAiD;IACjD,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACnD,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAsHD,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,SAAoB,EACpB,SAAS,EACT,YAAY,EACZ,SAAS,GACV,EAAE,sBAAsB,2CAuFxB"}