agent-canvas 0.1.16 → 0.1.18

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 (41) hide show
  1. package/bin/agent-canvas.ts +3 -0
  2. package/bin/lib/commands/install.ts +7 -7
  3. package/bin/lib/commands/instructions.ts +66 -0
  4. package/bin/lib/instructions/component-callout.md +27 -0
  5. package/bin/lib/instructions/component-checklist.md +17 -0
  6. package/bin/lib/instructions/component-choice.md +27 -0
  7. package/bin/lib/instructions/component-codeblock.md +24 -0
  8. package/bin/lib/instructions/component-custom.md +34 -0
  9. package/bin/lib/instructions/component-diff.md +18 -0
  10. package/bin/lib/instructions/component-filepreview.md +15 -0
  11. package/bin/lib/instructions/component-image.md +17 -0
  12. package/bin/lib/instructions/component-item.md +43 -0
  13. package/bin/lib/instructions/component-markdown.md +33 -0
  14. package/bin/lib/instructions/component-mermaid.md +40 -0
  15. package/bin/lib/instructions/component-multichoice.md +19 -0
  16. package/bin/lib/instructions/component-note.md +11 -0
  17. package/bin/lib/instructions/component-priority.md +15 -0
  18. package/bin/lib/instructions/component-rangeinput.md +20 -0
  19. package/bin/lib/instructions/component-section.md +22 -0
  20. package/bin/lib/instructions/component-svg.md +31 -0
  21. package/bin/lib/instructions/component-table.md +21 -0
  22. package/bin/lib/instructions/component-usefeedback.md +33 -0
  23. package/bin/lib/instructions/component-userinput.md +17 -0
  24. package/bin/lib/instructions/flow-decision.md +53 -0
  25. package/bin/lib/instructions/flow-explain.md +47 -0
  26. package/bin/lib/instructions/flow-feature.md +188 -0
  27. package/bin/lib/instructions/flow-plan.md +106 -0
  28. package/bin/lib/instructions/flow-review.md +60 -0
  29. package/bin/lib/instructions/overview.md +173 -0
  30. package/bin/lib/instructions/theming.md +50 -0
  31. package/daemon/client/AnnotationSidebar.tsx +40 -20
  32. package/daemon/client/App.tsx +8 -1
  33. package/daemon/dist/client.js +35 -35
  34. package/daemon/src/compiler.ts +1 -0
  35. package/daemon/src/handlers/api.ts +3 -1
  36. package/daemon/src/server.ts +1 -1
  37. package/daemon/src/websocket.ts +62 -1
  38. package/package.json +1 -1
  39. package/skills/canvas/SKILL.md +9 -194
  40. package/skills/canvas/components.md +0 -403
  41. package/skills/canvas/flows.md +0 -406
@@ -5,12 +5,14 @@ import { handleFetch } from "./lib/commands/fetch.ts";
5
5
  import { handleWatch } from "./lib/commands/watch.ts";
6
6
  import { handleDaemon } from "./lib/commands/daemon.ts";
7
7
  import { handleInstall } from "./lib/commands/install.ts";
8
+ import { handleInstructions } from "./lib/commands/instructions.ts";
8
9
 
9
10
  function printUsage() {
10
11
  console.error(`agent-canvas — Interactive visual canvas for Claude Code
11
12
 
12
13
  Commands:
13
14
  agent-canvas install [local|global] Install skill for Claude Code
15
+ agent-canvas instructions [topic] Show usage instructions (for AI agents)
14
16
  agent-canvas push <file.jsx> Push a canvas, open browser
15
17
  agent-canvas fetch [--session <id>] Check for feedback (returns immediately)
16
18
  agent-canvas watch [--session <id>] Wait for user feedback (blocks until submitted)
@@ -38,6 +40,7 @@ async function main() {
38
40
  case "push": return handlePush(rest);
39
41
  case "fetch": return handleFetch(rest);
40
42
  case "watch": return handleWatch(rest);
43
+ case "instructions": return handleInstructions(rest);
41
44
  case "install": return handleInstall(rest);
42
45
  case "daemon": return handleDaemon(rest);
43
46
  default:
@@ -1,5 +1,5 @@
1
1
  import { parseArgs } from "util";
2
- import { existsSync, mkdirSync, cpSync } from "fs";
2
+ import { existsSync, mkdirSync, cpSync, unlinkSync } from "fs";
3
3
  import { join } from "path";
4
4
  import { homedir } from "os";
5
5
  import { PACKAGE_ROOT } from "../config.ts";
@@ -35,12 +35,12 @@ export async function handleInstall(args: string[]) {
35
35
  const skillTarget = join(targetBase, "skills", "canvas");
36
36
  mkdirSync(skillTarget, { recursive: true });
37
37
 
38
- const skillSrc = join(PACKAGE_ROOT, "skills", "canvas");
39
- for (const file of ["SKILL.md", "components.md", "flows.md"]) {
40
- const src = join(skillSrc, file);
41
- if (existsSync(src)) {
42
- cpSync(src, join(skillTarget, file));
43
- }
38
+ cpSync(join(PACKAGE_ROOT, "skills", "canvas", "SKILL.md"), join(skillTarget, "SKILL.md"));
39
+
40
+ // Clean up files from older versions
41
+ for (const old of ["components.md", "flows.md"]) {
42
+ const p = join(skillTarget, old);
43
+ if (existsSync(p)) unlinkSync(p);
44
44
  }
45
45
 
46
46
  console.log(` Skill installed to ${skillTarget}`);
@@ -0,0 +1,66 @@
1
+ import { existsSync, readFileSync, readdirSync } from "fs";
2
+ import { join } from "path";
3
+ import { PACKAGE_ROOT } from "../config.ts";
4
+
5
+ const INSTRUCTIONS_DIR = join(PACKAGE_ROOT, "bin", "lib", "instructions");
6
+
7
+ export async function handleInstructions(args: string[]) {
8
+ const topic = args[0];
9
+
10
+ if (!topic) {
11
+ // Base instructions — overview
12
+ const overview = readFileSync(join(INSTRUCTIONS_DIR, "overview.md"), "utf-8");
13
+ process.stdout.write(overview);
14
+ return;
15
+ }
16
+
17
+ if (topic === "--list") {
18
+ printAvailableTopics(process.stdout);
19
+ return;
20
+ }
21
+
22
+ // Try exact match: topic.md
23
+ const file = join(INSTRUCTIONS_DIR, `${topic}.md`);
24
+ if (existsSync(file)) {
25
+ const content = readFileSync(file, "utf-8");
26
+ process.stdout.write(content);
27
+ return;
28
+ }
29
+
30
+ // Not found
31
+ console.error(`Unknown topic: ${topic}\n`);
32
+ printAvailableTopics(process.stderr);
33
+ process.exit(1);
34
+ }
35
+
36
+ function printAvailableTopics(out: NodeJS.WriteStream) {
37
+ const files = readdirSync(INSTRUCTIONS_DIR)
38
+ .filter(f => f.endsWith(".md") && f !== "overview.md")
39
+ .map(f => f.replace(".md", ""))
40
+ .sort();
41
+
42
+ const components = files.filter(f => f.startsWith("component-"));
43
+ const flows = files.filter(f => f.startsWith("flow-"));
44
+ const other = files.filter(f => !f.startsWith("component-") && !f.startsWith("flow-"));
45
+
46
+ const lines: string[] = ["## Available Detail Topics", ""];
47
+
48
+ if (components.length) {
49
+ lines.push("### Components");
50
+ for (const c of components) lines.push(`- \`${c}\``);
51
+ lines.push("");
52
+ }
53
+ if (flows.length) {
54
+ lines.push("### Flows");
55
+ for (const f of flows) lines.push(`- \`${f}\``);
56
+ lines.push("");
57
+ }
58
+ if (other.length) {
59
+ lines.push("### Other");
60
+ for (const o of other) lines.push(`- \`${o}\``);
61
+ lines.push("");
62
+ }
63
+
64
+ lines.push("Usage: `bunx agent-canvas instructions <topic>`");
65
+ out.write(lines.join("\n") + "\n");
66
+ }
@@ -0,0 +1,27 @@
1
+ # Component: Callout
2
+
3
+ Highlighted information block. Background-tinted, no border.
4
+
5
+ ## Props
6
+
7
+ - `type` ("info" | "warning" | "danger" | "tip") — determines color and icon
8
+
9
+ ## Usage
10
+
11
+ ```jsx
12
+ <Callout type="warning">
13
+ This will invalidate all existing sessions. Plan a maintenance window.
14
+ </Callout>
15
+
16
+ <Callout type="tip">
17
+ Consider using connection pooling for better performance.
18
+ </Callout>
19
+
20
+ <Callout type="danger">
21
+ This action is irreversible.
22
+ </Callout>
23
+
24
+ <Callout type="info">
25
+ Review each requirement. Annotate anything that's wrong or missing.
26
+ </Callout>
27
+ ```
@@ -0,0 +1,17 @@
1
+ # Component: Checklist
2
+
3
+ Visual checklist. Read-only display (feedback via annotations).
4
+
5
+ ## Props
6
+
7
+ - `items` (array of `{ label: string, checked: boolean }`)
8
+
9
+ ## Usage
10
+
11
+ ```jsx
12
+ <Checklist items={[
13
+ { label: "Run migration on staging", checked: true },
14
+ { label: "Verify data integrity", checked: false },
15
+ { label: "Update API docs", checked: false },
16
+ ]} />
17
+ ```
@@ -0,0 +1,27 @@
1
+ # Component: Choice
2
+
3
+ Single-select radio group.
4
+
5
+ ## Props
6
+
7
+ - `id` (string, required) — unique, used as key in feedback
8
+ - `label` (string, required) — question text
9
+ - `options` (string[], required) — radio options
10
+ - `required` (boolean) — prevents submit until answered
11
+
12
+ ## Usage
13
+
14
+ ```jsx
15
+ <Choice id="db-choice" label="Which database?" required
16
+ options={["PostgreSQL", "SQLite", "MongoDB"]} />
17
+
18
+ <Choice id="review-action" label="How should I proceed?" required
19
+ options={[
20
+ "Fix all critical + warnings",
21
+ "Fix critical only, I'll handle warnings",
22
+ "Don't fix anything, this was informational",
23
+ "Let me annotate which ones to fix"
24
+ ]} />
25
+ ```
26
+
27
+ Appears in feedback as: `[db-choice]: PostgreSQL`
@@ -0,0 +1,24 @@
1
+ # Component: CodeBlock
2
+
3
+ Inline code block with syntax highlighting. For code that's part of the narrative, not from a file on disk.
4
+
5
+ ## Props
6
+
7
+ - `language` (string) — syntax highlighting language (typescript, javascript, bash, python, sql, etc.)
8
+
9
+ ## Usage
10
+
11
+ ```jsx
12
+ <CodeBlock language="typescript">
13
+ interface User {
14
+ id: string;
15
+ email: string;
16
+ }
17
+ </CodeBlock>
18
+
19
+ <CodeBlock language="bash">
20
+ npm run migrate:staging
21
+ </CodeBlock>
22
+ ```
23
+
24
+ **Tip**: For showing code from an actual project file, use `<FilePreview>` instead — it shows the real file with line numbers and the user can browse it.
@@ -0,0 +1,34 @@
1
+ # Custom Components
2
+
3
+ When you use the full module format (`export default function Canvas()`), you can define custom helper components. Standard components remain available without import.
4
+
5
+ ## Usage
6
+
7
+ ```jsx
8
+ function Metric({ label, value, trend }) {
9
+ const color = trend === 'up' ? 'var(--color-accent-green)' : trend === 'down' ? 'var(--color-accent-red)' : 'var(--color-text-secondary)';
10
+ return (
11
+ <div style={{ display: 'flex', gap: 12, alignItems: 'baseline' }}>
12
+ <span style={{ color: 'var(--color-text-tertiary)', fontSize: '0.75rem' }}>{label}</span>
13
+ <span style={{ color, fontSize: '1.25rem', fontWeight: 600 }}>{value}</span>
14
+ </div>
15
+ );
16
+ }
17
+
18
+ export default function Canvas() {
19
+ return (
20
+ <Section title="Performance Summary">
21
+ <Metric label="P95 Latency" value="42ms" trend="down" />
22
+ <Metric label="Error Rate" value="0.3%" trend="up" />
23
+ <Metric label="Throughput" value="1.2k rps" trend="up" />
24
+ </Section>
25
+ );
26
+ }
27
+ ```
28
+
29
+ ## Tips
30
+
31
+ - Use `style={{ }}` with CSS variables for theming (see `bunx agent-canvas instructions theming`)
32
+ - Standard components (Section, Item, etc.) are available without import even in module format
33
+ - You can use `React.useState`, `React.useEffect`, etc. — React is available globally
34
+ - Use `useFeedback` hook to contribute custom data to the feedback response
@@ -0,0 +1,18 @@
1
+ # Component: Diff
2
+
3
+ Shows a diff view between two code snippets.
4
+
5
+ ## Props
6
+
7
+ - `before` (string, required) — original code
8
+ - `after` (string, required) — modified code
9
+ - `language` (string) — syntax highlighting language
10
+
11
+ ## Usage
12
+
13
+ ```jsx
14
+ <Diff language="typescript"
15
+ before={`function auth(req) {\n return true;\n}`}
16
+ after={`function auth(req) {\n const token = req.headers.authorization;\n if (!token) throw new Error('Unauthorized');\n return verify(token);\n}`}
17
+ />
18
+ ```
@@ -0,0 +1,15 @@
1
+ # Component: FilePreview
2
+
3
+ Shows a syntax-highlighted preview of a project file. The daemon serves the file content from the project root.
4
+
5
+ ## Props
6
+
7
+ - `path` (string, required) — relative to project root
8
+ - `lines` ([number, number]) — line range to show. Omit for full file.
9
+
10
+ ## Usage
11
+
12
+ ```jsx
13
+ <FilePreview path="src/auth/middleware.ts" />
14
+ <FilePreview path="src/auth/middleware.ts" lines={[42, 87]} />
15
+ ```
@@ -0,0 +1,17 @@
1
+ # Component: ImageView
2
+
3
+ Displays an image from the project directory.
4
+
5
+ ## Props
6
+
7
+ - `src` (string, required) — path relative to project root
8
+ - `alt` (string) — alt text
9
+ - `caption` (string) — caption displayed below image
10
+ - `width` (number) — max width in pixels
11
+
12
+ ## Usage
13
+
14
+ ```jsx
15
+ <ImageView src="docs/architecture.png" />
16
+ <ImageView src="screenshots/before.png" alt="Before refactor" caption="Current state" width={600} />
17
+ ```
@@ -0,0 +1,43 @@
1
+ # Component: Item
2
+
3
+ The primary content block. A flexible card-like row used for tasks, findings, requirements, observations, options — anything that has a title and details.
4
+
5
+ Previously called "Task" — Item is the generalized version.
6
+
7
+ ## Props
8
+
9
+ - `id` (string) — unique ID. Required if the item should be individually addressable in feedback. Optional for informational items.
10
+ - `label` (string, required) — item title, rendered in Inter 600
11
+ - `badge` (string) — short label shown as a small tag. Freeform text.
12
+ - `badgeVariant` ("default" | "success" | "warning" | "danger" | "info") — badge color. Default is neutral gray.
13
+ - `status` ("todo" | "done" | "blocked" | "in-progress") — shows a colored dot. Alternative to badge for plan-style items.
14
+
15
+ **Badge vs Status**: Use `status` for things with a workflow state (tasks in a plan). Use `badge` for categorical labels (requirement priority, review severity, component type). You can use both on the same Item if needed.
16
+
17
+ **Children**: Any content — text, components, code blocks, file previews, nested items.
18
+
19
+ ## Usage
20
+
21
+ ```jsx
22
+ {/* As a plan task */}
23
+ <Item id="migrate-db" label="Run database migration" badge="todo">
24
+ Execute the migration script against staging first.
25
+ <CodeBlock language="bash">npm run migrate:staging</CodeBlock>
26
+ </Item>
27
+
28
+ {/* As a review finding */}
29
+ <Item id="finding-1" label="Missing null check in auth handler" badge="critical" badgeVariant="danger">
30
+ The handler doesn't check for missing tokens.
31
+ <FilePreview path="src/auth.ts" lines={[42, 48]} />
32
+ </Item>
33
+
34
+ {/* As a requirement */}
35
+ <Item id="req-auth" label="JWT authentication" badge="must-have" badgeVariant="danger">
36
+ All API endpoints must require a valid JWT token.
37
+ </Item>
38
+
39
+ {/* As an architecture component */}
40
+ <Item label="API Gateway" badge="core" badgeVariant="info">
41
+ Routes requests to downstream services. Handles rate limiting.
42
+ </Item>
43
+ ```
@@ -0,0 +1,33 @@
1
+ # Component: Markdown
2
+
3
+ Renders markdown content with full GFM support (headings, lists, tables, code blocks, links, etc.). Two modes:
4
+
5
+ ## Inline source — markdown as children
6
+
7
+ ```jsx
8
+ <Markdown>{`
9
+ # Summary
10
+
11
+ This is **bold** and *italic*. Here's a list:
12
+
13
+ - First item
14
+ - Second item
15
+ - Nested item
16
+
17
+ \`\`\`typescript
18
+ const x = 42;
19
+ \`\`\`
20
+ `}</Markdown>
21
+ ```
22
+
23
+ ## File reference — loads file content at compile time
24
+
25
+ ```jsx
26
+ <Markdown file="docs/architecture.md" />
27
+ <Markdown file="CHANGELOG.md" />
28
+ ```
29
+
30
+ ## Props
31
+
32
+ - `file` (string) — path relative to project root. Content resolved at compile time.
33
+ - Children (string) — inline markdown source. Used when `file` is not specified.
@@ -0,0 +1,40 @@
1
+ # Component: Mermaid
2
+
3
+ Renders a Mermaid diagram. Supports flowchart, sequence, ER, gantt, pie, and more. The daemon bundles mermaid.js with a custom dark theme matching Canvas colors.
4
+
5
+ ## Usage
6
+
7
+ ```jsx
8
+ <Mermaid>{`
9
+ graph TD
10
+ A[Client] -->|HTTP| B(API Gateway)
11
+ B --> C{Auth?}
12
+ C -->|Valid| D[Service]
13
+ C -->|Invalid| E[401 Response]
14
+ `}</Mermaid>
15
+ ```
16
+
17
+ ### Sequence diagram
18
+
19
+ ```jsx
20
+ <Mermaid>{`
21
+ sequenceDiagram
22
+ Client->>+API: POST /login
23
+ API->>+DB: Find user
24
+ DB-->>-API: User record
25
+ API-->>-Client: JWT token
26
+ `}</Mermaid>
27
+ ```
28
+
29
+ ### ER diagram
30
+
31
+ ```jsx
32
+ <Mermaid>{`
33
+ erDiagram
34
+ USER ||--o{ ORDER : places
35
+ ORDER ||--|{ LINE-ITEM : contains
36
+ PRODUCT ||--o{ LINE-ITEM : "ordered in"
37
+ `}</Mermaid>
38
+ ```
39
+
40
+ For complex diagrams, prefer Mermaid over raw SVG. Use raw `<svg>` only when Mermaid can't express what you need.
@@ -0,0 +1,19 @@
1
+ # Component: MultiChoice
2
+
3
+ Multi-select checkboxes.
4
+
5
+ ## Props
6
+
7
+ - `id` (string, required) — unique, used as key in feedback
8
+ - `label` (string, required) — question text
9
+ - `options` (string[], required) — checkbox options
10
+ - `required` (boolean) — prevents submit until at least one selected
11
+
12
+ ## Usage
13
+
14
+ ```jsx
15
+ <MultiChoice id="affected-areas" label="Which areas need changes?" required
16
+ options={["Models", "API", "Frontend", "Tests"]} />
17
+ ```
18
+
19
+ Appears in feedback as: `[affected-areas]: Models, API, Tests`
@@ -0,0 +1,11 @@
1
+ # Component: Note
2
+
3
+ Softer than Callout. For asides, context, non-critical info.
4
+
5
+ ## Usage
6
+
7
+ ```jsx
8
+ <Note>
9
+ This pattern is also used in the payment service — see src/payments/auth.ts.
10
+ </Note>
11
+ ```
@@ -0,0 +1,15 @@
1
+ # Component: Priority
2
+
3
+ Inline badge. Use inside Item labels or body text.
4
+
5
+ ## Props
6
+
7
+ - `level` ("high" | "medium" | "low")
8
+
9
+ ## Usage
10
+
11
+ ```jsx
12
+ <Item label="Fix the race condition">
13
+ <Priority level="high" /> This causes data corruption under load.
14
+ </Item>
15
+ ```
@@ -0,0 +1,20 @@
1
+ # Component: RangeInput
2
+
3
+ Slider for numeric ranges or scales.
4
+
5
+ ## Props
6
+
7
+ - `id` (string, required) — unique, used as key in feedback
8
+ - `label` (string, required) — question text
9
+ - `min` (number) — minimum value
10
+ - `max` (number) — maximum value
11
+ - `minLabel` (string) — label for minimum end
12
+ - `maxLabel` (string) — label for maximum end
13
+ - `required` (boolean) — prevents submit until set
14
+
15
+ ## Usage
16
+
17
+ ```jsx
18
+ <RangeInput id="effort-tolerance" label="How much refactoring is acceptable?"
19
+ min={1} max={5} minLabel="Minimal changes" maxLabel="Full rewrite OK" required />
20
+ ```
@@ -0,0 +1,22 @@
1
+ # Component: Section
2
+
3
+ Top-level grouping. Rendered as a serif heading with generous spacing. Collapsible (chevron appears on hover).
4
+
5
+ ## Props
6
+
7
+ - `title` (string, required) — section heading, rendered in Instrument Serif
8
+ - `collapsed` (boolean, default false) — start collapsed
9
+
10
+ ## Usage
11
+
12
+ ```jsx
13
+ <Section title="Phase 1: Data Migration">
14
+ A brief description of this section.
15
+
16
+ {/* Items, callouts, code blocks, diagrams, etc. */}
17
+ </Section>
18
+
19
+ <Section title="Advanced Details" collapsed>
20
+ This section starts collapsed — user clicks to expand.
21
+ </Section>
22
+ ```
@@ -0,0 +1,31 @@
1
+ # Diagrams with Raw SVG
2
+
3
+ For custom visuals that Mermaid can't express, write `<svg>` directly. Use CSS variables for colors to match the theme.
4
+
5
+ ## Usage
6
+
7
+ ```jsx
8
+ <svg viewBox="0 0 400 200" style={{ width: '100%', maxWidth: 400 }}>
9
+ <rect x="10" y="10" width="120" height="50" rx="8"
10
+ fill="var(--color-accent-blue-muted)" stroke="var(--color-accent-blue)" strokeOpacity="0.3" />
11
+ <text x="70" y="40" textAnchor="middle" fill="var(--color-text-primary)" fontSize="13"
12
+ fontFamily="var(--font-body)">API Gateway</text>
13
+
14
+ <line x1="130" y1="35" x2="180" y2="35" stroke="var(--color-text-tertiary)" strokeWidth="1.5"
15
+ markerEnd="url(#arrow)" />
16
+
17
+ <rect x="180" y="10" width="120" height="50" rx="8"
18
+ fill="var(--color-accent-green-muted)" stroke="var(--color-accent-green)" strokeOpacity="0.3" />
19
+ <text x="240" y="40" textAnchor="middle" fill="var(--color-text-primary)" fontSize="13"
20
+ fontFamily="var(--font-body)">Auth Service</text>
21
+
22
+ <defs>
23
+ <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6"
24
+ orient="auto-start-reverse">
25
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="var(--color-text-tertiary)" />
26
+ </marker>
27
+ </defs>
28
+ </svg>
29
+ ```
30
+
31
+ Keep SVG diagrams simple. For anything with more than ~5 nodes, prefer Mermaid.
@@ -0,0 +1,21 @@
1
+ # Component: Table
2
+
3
+ Simple data table.
4
+
5
+ ## Props
6
+
7
+ - `headers` (string[]) — column headers
8
+ - `rows` (string[][]) — row data
9
+
10
+ ## Usage
11
+
12
+ ```jsx
13
+ <Table
14
+ headers={["Endpoint", "Method", "Auth"]}
15
+ rows={[
16
+ ["/users", "GET", "Required"],
17
+ ["/users/:id", "PUT", "Owner only"],
18
+ ["/health", "GET", "None"],
19
+ ]}
20
+ />
21
+ ```
@@ -0,0 +1,33 @@
1
+ # Hook: useFeedback
2
+
3
+ Hook for custom components to contribute computed/derived data to the feedback response. Use when built-in interactive components don't cover your needs.
4
+
5
+ ## Signature
6
+
7
+ ```typescript
8
+ useFeedback(id: string, markdown: string, options?: { label?: string; required?: boolean })
9
+ ```
10
+
11
+ - `id` (string, required) — unique feedback entry identifier
12
+ - `markdown` (string, required) — markdown included in feedback, re-evaluated each render
13
+ - `options.label` — display label in feedback preview
14
+ - `options.required` — blocks submit while markdown is empty
15
+
16
+ Registers on mount, updates on change, unregisters on unmount.
17
+
18
+ ## Usage
19
+
20
+ ```jsx
21
+ function ProConList() {
22
+ const [pros, setPros] = React.useState(["Fast builds"]);
23
+ const [cons, setCons] = React.useState(["New runtime"]);
24
+
25
+ useFeedback(
26
+ "pro-con",
27
+ `**Pros:** ${pros.join(", ")}\n**Cons:** ${cons.join(", ")}`,
28
+ { label: "Pro/Con Analysis" },
29
+ );
30
+
31
+ return <div>{/* UI for managing pros/cons */}</div>;
32
+ }
33
+ ```
@@ -0,0 +1,17 @@
1
+ # Component: UserInput
2
+
3
+ Free text input.
4
+
5
+ ## Props
6
+
7
+ - `id` (string, required) — unique, used as key in feedback
8
+ - `label` (string, required) — question text
9
+ - `placeholder` (string) — hint text
10
+ - `required` (boolean) — prevents submit until filled
11
+
12
+ ## Usage
13
+
14
+ ```jsx
15
+ <UserInput id="constraints" label="Any constraints I should know about?"
16
+ placeholder="e.g. must work with existing Redis setup" required />
17
+ ```