@dowel-ui/react 0.2.0 → 0.4.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 (141) hide show
  1. package/README.md +14 -7
  2. package/dist/components/ai-agent-plan/ai-agent-plan.d.ts +50 -0
  3. package/dist/components/ai-agent-plan/ai-agent-plan.d.ts.map +1 -0
  4. package/dist/components/ai-agent-plan/ai-agent-plan.js +156 -0
  5. package/dist/components/ai-agent-plan/ai-agent-plan.js.map +1 -0
  6. package/dist/components/ai-agent-plan/index.d.ts +2 -0
  7. package/dist/components/ai-agent-plan/index.js +2 -0
  8. package/dist/components/ai-agent-plan/meta.js +17 -0
  9. package/dist/components/ai-agent-plan/meta.js.map +1 -0
  10. package/dist/components/ai-agent-status/ai-agent-status.d.ts +1 -1
  11. package/dist/components/ai-approval-request/ai-approval-request.d.ts +67 -0
  12. package/dist/components/ai-approval-request/ai-approval-request.d.ts.map +1 -0
  13. package/dist/components/ai-approval-request/ai-approval-request.js +218 -0
  14. package/dist/components/ai-approval-request/ai-approval-request.js.map +1 -0
  15. package/dist/components/ai-approval-request/index.d.ts +2 -0
  16. package/dist/components/ai-approval-request/index.js +2 -0
  17. package/dist/components/ai-approval-request/meta.js +17 -0
  18. package/dist/components/ai-approval-request/meta.js.map +1 -0
  19. package/dist/components/ai-disclosure/ai-disclosure.d.ts +92 -0
  20. package/dist/components/ai-disclosure/ai-disclosure.d.ts.map +1 -0
  21. package/dist/components/ai-disclosure/ai-disclosure.js +122 -0
  22. package/dist/components/ai-disclosure/ai-disclosure.js.map +1 -0
  23. package/dist/components/ai-disclosure/index.d.ts +2 -0
  24. package/dist/components/ai-disclosure/index.js +2 -0
  25. package/dist/components/ai-disclosure/meta.js +17 -0
  26. package/dist/components/ai-disclosure/meta.js.map +1 -0
  27. package/dist/components/ai-response/ai-response.d.ts.map +1 -1
  28. package/dist/components/ai-response/ai-response.js +1 -0
  29. package/dist/components/ai-response/ai-response.js.map +1 -1
  30. package/dist/components/ai-structured-output/ai-structured-output.d.ts.map +1 -1
  31. package/dist/components/ai-structured-output/ai-structured-output.js +13 -2
  32. package/dist/components/ai-structured-output/ai-structured-output.js.map +1 -1
  33. package/dist/components/ai-tool/ai-tool.d.ts +1 -1
  34. package/dist/components/alert/alert.d.ts +1 -1
  35. package/dist/components/avatar/avatar.d.ts +1 -1
  36. package/dist/components/badge/badge.d.ts +1 -1
  37. package/dist/components/button/button.d.ts +1 -1
  38. package/dist/components/date-picker/date-picker.js +1 -1
  39. package/dist/components/diff-viewer/diff-model.d.ts +69 -0
  40. package/dist/components/diff-viewer/diff-model.d.ts.map +1 -0
  41. package/dist/components/diff-viewer/diff-model.js +180 -0
  42. package/dist/components/diff-viewer/diff-model.js.map +1 -0
  43. package/dist/components/diff-viewer/diff-viewer.d.ts +42 -0
  44. package/dist/components/diff-viewer/diff-viewer.d.ts.map +1 -0
  45. package/dist/components/diff-viewer/diff-viewer.js +212 -0
  46. package/dist/components/diff-viewer/diff-viewer.js.map +1 -0
  47. package/dist/components/diff-viewer/index.d.ts +3 -0
  48. package/dist/components/diff-viewer/index.js +3 -0
  49. package/dist/components/diff-viewer/meta.js +17 -0
  50. package/dist/components/diff-viewer/meta.js.map +1 -0
  51. package/dist/components/file-upload/file-upload.d.ts +46 -0
  52. package/dist/components/file-upload/file-upload.d.ts.map +1 -0
  53. package/dist/components/file-upload/file-upload.js +204 -0
  54. package/dist/components/file-upload/file-upload.js.map +1 -0
  55. package/dist/components/file-upload/index.d.ts +3 -0
  56. package/dist/components/file-upload/index.js +3 -0
  57. package/dist/components/file-upload/meta.js +17 -0
  58. package/dist/components/file-upload/meta.js.map +1 -0
  59. package/dist/components/file-upload/upload-queue.d.ts +87 -0
  60. package/dist/components/file-upload/upload-queue.d.ts.map +1 -0
  61. package/dist/components/file-upload/upload-queue.js +249 -0
  62. package/dist/components/file-upload/upload-queue.js.map +1 -0
  63. package/dist/components/log-viewer/index.d.ts +3 -0
  64. package/dist/components/log-viewer/index.js +3 -0
  65. package/dist/components/log-viewer/log-stream.d.ts +68 -0
  66. package/dist/components/log-viewer/log-stream.d.ts.map +1 -0
  67. package/dist/components/log-viewer/log-stream.js +120 -0
  68. package/dist/components/log-viewer/log-stream.js.map +1 -0
  69. package/dist/components/log-viewer/log-viewer.d.ts +51 -0
  70. package/dist/components/log-viewer/log-viewer.d.ts.map +1 -0
  71. package/dist/components/log-viewer/log-viewer.js +284 -0
  72. package/dist/components/log-viewer/log-viewer.js.map +1 -0
  73. package/dist/components/log-viewer/meta.js +17 -0
  74. package/dist/components/log-viewer/meta.js.map +1 -0
  75. package/dist/components/progress/progress.d.ts +1 -1
  76. package/dist/components/progress/progress.js +1 -0
  77. package/dist/components/progress/progress.js.map +1 -1
  78. package/dist/components/spinner/spinner.d.ts +1 -1
  79. package/dist/components/spinner/spinner.js +1 -0
  80. package/dist/components/spinner/spinner.js.map +1 -1
  81. package/dist/components/tags-input/index.d.ts +2 -0
  82. package/dist/components/tags-input/index.js +2 -0
  83. package/dist/components/tags-input/meta.js +17 -0
  84. package/dist/components/tags-input/meta.js.map +1 -0
  85. package/dist/components/tags-input/tags-input.d.ts +47 -0
  86. package/dist/components/tags-input/tags-input.d.ts.map +1 -0
  87. package/dist/components/tags-input/tags-input.js +182 -0
  88. package/dist/components/tags-input/tags-input.js.map +1 -0
  89. package/dist/components/time-range-picker/index.d.ts +3 -0
  90. package/dist/components/time-range-picker/index.js +3 -0
  91. package/dist/components/time-range-picker/meta.js +22 -0
  92. package/dist/components/time-range-picker/meta.js.map +1 -0
  93. package/dist/components/time-range-picker/time-expression.d.ts +88 -0
  94. package/dist/components/time-range-picker/time-expression.d.ts.map +1 -0
  95. package/dist/components/time-range-picker/time-expression.js +335 -0
  96. package/dist/components/time-range-picker/time-expression.js.map +1 -0
  97. package/dist/components/time-range-picker/time-range-picker.d.ts +65 -0
  98. package/dist/components/time-range-picker/time-range-picker.d.ts.map +1 -0
  99. package/dist/components/time-range-picker/time-range-picker.js +377 -0
  100. package/dist/components/time-range-picker/time-range-picker.js.map +1 -0
  101. package/dist/components/toast/toast.d.ts +1 -1
  102. package/dist/index.d.ts +21 -1
  103. package/dist/index.js +14 -2
  104. package/dist/registry/components.d.ts.map +1 -1
  105. package/dist/registry/components.js +66 -50
  106. package/dist/registry/components.js.map +1 -1
  107. package/package.json +6 -4
  108. package/src/components/ai-agent-plan/ai-agent-plan.tsx +0 -0
  109. package/src/components/ai-agent-plan/index.ts +10 -0
  110. package/src/components/ai-agent-plan/meta.ts +19 -0
  111. package/src/components/ai-approval-request/ai-approval-request.tsx +368 -0
  112. package/src/components/ai-approval-request/index.ts +7 -0
  113. package/src/components/ai-approval-request/meta.ts +21 -0
  114. package/src/components/ai-disclosure/ai-disclosure.tsx +244 -0
  115. package/src/components/ai-disclosure/index.ts +9 -0
  116. package/src/components/ai-disclosure/meta.ts +23 -0
  117. package/src/components/ai-response/ai-response.tsx +1 -0
  118. package/src/components/ai-structured-output/ai-structured-output.tsx +25 -1
  119. package/src/components/diff-viewer/diff-model.ts +256 -0
  120. package/src/components/diff-viewer/diff-viewer.tsx +339 -0
  121. package/src/components/diff-viewer/index.ts +17 -0
  122. package/src/components/diff-viewer/meta.ts +20 -0
  123. package/src/components/file-upload/file-upload.tsx +322 -0
  124. package/src/components/file-upload/index.ts +20 -0
  125. package/src/components/file-upload/meta.ts +21 -0
  126. package/src/components/file-upload/upload-queue.ts +337 -0
  127. package/src/components/log-viewer/index.ts +21 -0
  128. package/src/components/log-viewer/log-stream.ts +176 -0
  129. package/src/components/log-viewer/log-viewer.tsx +424 -0
  130. package/src/components/log-viewer/meta.ts +21 -0
  131. package/src/components/progress/progress.tsx +3 -0
  132. package/src/components/spinner/spinner.tsx +5 -0
  133. package/src/components/tags-input/index.ts +1 -0
  134. package/src/components/tags-input/meta.ts +23 -0
  135. package/src/components/tags-input/tags-input.tsx +300 -0
  136. package/src/components/time-range-picker/index.ts +25 -0
  137. package/src/components/time-range-picker/meta.ts +22 -0
  138. package/src/components/time-range-picker/time-expression.ts +491 -0
  139. package/src/components/time-range-picker/time-range-picker.tsx +522 -0
  140. package/src/index.ts +8 -0
  141. package/src/registry/components.ts +16 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-approval-request.js","names":[],"sources":["../../../src/components/ai-approval-request/ai-approval-request.tsx"],"sourcesContent":["\"use client\";\n\nimport { useId, useMemo, useState, type ComponentPropsWithRef, type ReactNode } from \"react\";\n\nimport { disabledStyles, focusRing } from \"@/lib/styles\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * The gate between an agent deciding to act and it acting.\n *\n * Two things separate this from the confirmations that already exist.\n *\n * The first is that the proposed arguments are editable. Every implementation\n * surveyed returns a boolean over a read-only payload, which forces a false\n * choice: approve a call whose recipient is wrong, or deny it and make the\n * model try again. \"Approve this, but fix the address first\" is the answer\n * people actually want, and it is only possible if the arguments are fields.\n * Edited values come back in the decision, and are marked as changed so an\n * audit trail can tell the model's proposal from the human's correction.\n *\n * The second is that it renders while the arguments are still arriving. The\n * common implementation returns null until the tool input is complete, which\n * means nothing is on screen at the moment approval becomes relevant and the\n * request appears abruptly, fully formed. Here the request is visible as it\n * forms, with the decision held until there is something whole to decide on.\n */\n\nexport type ApprovalScope = \"once\" | \"always\";\n\nexport type ApprovalDecision =\n | {\n approved: true;\n scope: ApprovalScope;\n arguments: Record<string, string>;\n edited: string[];\n }\n | { approved: false; reason?: string };\n\nexport interface ApprovalField {\n name: string;\n label: string;\n /** A textarea instead of a single line. For message bodies and prompts. */\n multiline?: boolean;\n /** Locked arguments are shown but not editable — an id, a resolved amount. */\n readOnly?: boolean;\n}\n\nexport interface ApprovalRequestProps extends Omit<\n ComponentPropsWithRef<\"section\">,\n \"onSubmit\" | \"children\"\n> {\n /** The tool the model wants to call, as it named it. */\n tool: string;\n /** What the call will do, in the reader's language rather than the API's. */\n summary: string;\n /** Proposed arguments. Missing keys are treated as still arriving. */\n arguments: Record<string, string>;\n /** Which arguments to show, in order, and which may be changed. */\n fields: ApprovalField[];\n onDecision: (decision: ApprovalDecision) => void;\n /**\n * True while the model is still producing the arguments. The request renders\n * anyway; only the decision waits.\n */\n streaming?: boolean;\n /**\n * Said plainly above the controls when the call cannot be taken back. Not a\n * severity colour — the sentence is the warning.\n */\n irreversible?: string;\n /** Set once decided, to render the outcome instead of the controls. */\n decision?: ApprovalDecision;\n children?: ReactNode;\n}\n\nexport function ApprovalRequest({\n className,\n tool,\n summary,\n arguments: proposed,\n fields,\n onDecision,\n streaming = false,\n irreversible,\n decision,\n children,\n ...props\n}: ApprovalRequestProps) {\n const headingId = useId();\n const [edits, setEdits] = useState<Record<string, string>>({});\n const [denying, setDenying] = useState(false);\n const [reason, setReason] = useState(\"\");\n\n // The model's proposal with the human's corrections applied on top. Keeping\n // them apart is what lets the component say which is which.\n const values = useMemo(() => ({ ...proposed, ...edits }), [proposed, edits]);\n\n const edited = useMemo(\n () => Object.keys(edits).filter((name) => edits[name] !== proposed[name]),\n [edits, proposed],\n );\n\n const missing = fields.filter((field) => proposed[field.name] === undefined);\n const settled = !streaming && missing.length === 0;\n\n if (decision) {\n return (\n <section\n data-slot=\"approval-request\"\n data-state={decision.approved ? \"approved\" : \"denied\"}\n aria-labelledby={headingId}\n className={cn(\n \"rounded-lg border p-4 text-sm\",\n decision.approved ? \"border-border bg-muted/40\" : \"border-border bg-muted/40\",\n className,\n )}\n {...props}\n >\n <h3 id={headingId} className=\"text-sm font-medium\">\n {summary}\n </h3>\n <p data-slot=\"approval-outcome\" className=\"mt-1 text-xs text-muted-foreground\">\n {decision.approved\n ? `Approved ${decision.scope === \"always\" ? \"for every call to this tool\" : \"once\"}` +\n (decision.edited.length > 0\n ? `, with ${String(decision.edited.length)} argument${decision.edited.length === 1 ? \"\" : \"s\"} corrected`\n : \"\")\n : `Denied${decision.reason ? `: ${decision.reason}` : \"\"}`}\n </p>\n </section>\n );\n }\n\n return (\n <section\n data-slot=\"approval-request\"\n data-state={settled ? \"pending\" : \"forming\"}\n aria-labelledby={headingId}\n // Busy while the arguments are still arriving, so a reader is told the\n // request is not yet whole rather than acting on half of it.\n aria-busy={!settled}\n className={cn(\"rounded-lg border border-border bg-card p-4\", className)}\n {...props}\n >\n <div className=\"flex flex-wrap items-baseline justify-between gap-2\">\n <h3 id={headingId} className=\"text-sm font-medium\">\n {summary}\n </h3>\n <code className=\"rounded bg-muted px-1.5 py-0.5 font-mono text-2xs text-muted-foreground\">\n {tool}\n </code>\n </div>\n\n <dl className=\"mt-3 flex flex-col gap-2.5\">\n {fields.map((field) => {\n const arrived = proposed[field.name] !== undefined;\n const changed = edited.includes(field.name);\n\n return (\n <ApprovalArgument\n key={field.name}\n field={field}\n value={values[field.name] ?? \"\"}\n arrived={arrived}\n changed={changed}\n onChange={(next) => {\n setEdits((current) => ({ ...current, [field.name]: next }));\n }}\n />\n );\n })}\n </dl>\n\n {children}\n\n {irreversible ? (\n <p data-slot=\"approval-warning\" className=\"mt-3 text-xs text-destructive\">\n {irreversible}\n </p>\n ) : null}\n\n {denying ? (\n <div className=\"mt-3 flex flex-col gap-2\">\n <label htmlFor={`${headingId}-reason`} className=\"text-xs text-muted-foreground\">\n Why not? The model sees this.\n </label>\n <textarea\n id={`${headingId}-reason`}\n rows={2}\n value={reason}\n onChange={(event) => {\n setReason(event.target.value);\n }}\n className={cn(\n \"w-full resize-none rounded-md border border-input bg-background px-2 py-1.5 text-sm\",\n focusRing,\n )}\n />\n <div className=\"flex flex-wrap gap-2\">\n <Action\n variant=\"destructive\"\n onClick={() => {\n onDecision({ approved: false, reason: reason.trim() || undefined });\n }}\n >\n Deny\n </Action>\n <Action\n onClick={() => {\n setDenying(false);\n }}\n >\n Back\n </Action>\n </div>\n </div>\n ) : (\n <div className=\"mt-4 flex flex-wrap items-center gap-2\">\n <Action\n variant=\"primary\"\n disabled={!settled}\n onClick={() => {\n onDecision({ approved: true, scope: \"once\", arguments: values, edited });\n }}\n >\n {edited.length > 0 ? \"Approve with changes\" : \"Approve once\"}\n </Action>\n\n {/* Scope is a separate decision from approval, and blanket consent\n should never be the easiest button to reach. */}\n <Action\n disabled={!settled}\n onClick={() => {\n onDecision({ approved: true, scope: \"always\", arguments: values, edited });\n }}\n >\n Always allow {tool}\n </Action>\n\n <Action\n onClick={() => {\n setDenying(true);\n }}\n >\n Deny…\n </Action>\n\n {!settled ? (\n <span aria-live=\"polite\" className=\"text-xs text-muted-foreground\">\n Waiting for the model to finish the request\n </span>\n ) : null}\n </div>\n )}\n </section>\n );\n}\n\nfunction ApprovalArgument({\n field,\n value,\n arrived,\n changed,\n onChange,\n}: {\n field: ApprovalField;\n value: string;\n arrived: boolean;\n changed: boolean;\n onChange: (value: string) => void;\n}) {\n const id = useId();\n const changedId = useId();\n const editable = !field.readOnly && arrived;\n\n return (\n <div\n data-slot=\"approval-argument\"\n data-changed={changed || undefined}\n className=\"flex flex-col gap-1\"\n >\n <dt className=\"flex items-baseline gap-1\">\n <label htmlFor={editable ? id : undefined} className=\"text-xs text-muted-foreground\">\n {field.label}\n </label>\n {/* Outside the label, and attached as a description instead. Inside it,\n editing a field would rename the field — a screen reader user would\n hear its accessible name change under them mid-edit. Marked in text\n rather than by border colour alone, because an audit trail has to\n tell the model's proposal from the human's correction. */}\n {changed ? (\n <span id={changedId} className=\"text-xs text-warning\">\n · changed from the model&rsquo;s proposal\n </span>\n ) : null}\n </dt>\n <dd className=\"m-0\">\n {!arrived ? (\n <span\n aria-hidden=\"true\"\n className=\"block h-8 w-full animate-pulse-soft rounded-md bg-muted\"\n />\n ) : editable ? (\n field.multiline ? (\n <textarea\n id={id}\n aria-describedby={changed ? changedId : undefined}\n rows={3}\n value={value}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n className={cn(\n \"w-full resize-none rounded-md border border-input bg-background px-2 py-1.5 font-mono text-xs\",\n changed && \"border-warning\",\n focusRing,\n )}\n />\n ) : (\n <input\n id={id}\n type=\"text\"\n aria-describedby={changed ? changedId : undefined}\n value={value}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n className={cn(\n \"w-full rounded-md border border-input bg-background px-2 py-1.5 font-mono text-xs\",\n changed && \"border-warning\",\n focusRing,\n )}\n />\n )\n ) : (\n <p className=\"rounded-md bg-muted px-2 py-1.5 font-mono text-xs break-words\">\n {value}\n </p>\n )}\n </dd>\n </div>\n );\n}\n\nfunction Action({\n className,\n variant = \"default\",\n ...props\n}: ComponentPropsWithRef<\"button\"> & { variant?: \"default\" | \"primary\" | \"destructive\" }) {\n return (\n <button\n type=\"button\"\n className={cn(\n \"rounded-md border px-2.5 py-1 text-xs font-medium transition-colors\",\n variant === \"primary\" &&\n \"border-primary bg-primary text-primary-foreground hover:bg-primary-hover\",\n variant === \"destructive\" &&\n \"border-destructive bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n variant === \"default\" &&\n \"border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n focusRing,\n disabledStyles,\n className,\n )}\n {...props}\n />\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { ApprovalDecision, ApprovalField, ApprovalRequest, ApprovalRequestProps, ApprovalScope } from "./ai-approval-request.js";
2
+ export { type ApprovalDecision, type ApprovalField, ApprovalRequest, type ApprovalRequestProps, type ApprovalScope };
@@ -0,0 +1,2 @@
1
+ import { ApprovalRequest } from "./ai-approval-request.js";
2
+ export { ApprovalRequest };
@@ -0,0 +1,17 @@
1
+ import { defineMeta } from "../../registry/schema.js";
2
+ //#region src/components/ai-approval-request/meta.ts
3
+ const meta = defineMeta({
4
+ name: "ai-approval-request",
5
+ title: "AI Approval Request",
6
+ description: "Approve a tool call — after correcting the arguments the model got wrong.",
7
+ category: "ai",
8
+ status: "stable",
9
+ dependencies: [],
10
+ registryDependencies: [],
11
+ files: ["ai-approval-request.tsx"],
12
+ a11y: "The proposed arguments are a description list of real labelled form controls, so each value is associated with its name and editable ones are reachable by keyboard. A corrected argument is marked in text rather than by border colour alone, because an audit trail has to distinguish the model's proposal from the human's edit. The request is aria-busy while arguments are still arriving and the decision controls stay disabled until it is whole — rendering nothing until then, as the common implementation does, means nothing is on screen at the moment approval becomes relevant. Irreversibility is stated as a sentence, never as a severity colour."
13
+ });
14
+ //#endregion
15
+ export { meta };
16
+
17
+ //# sourceMappingURL=meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.js","names":[],"sources":["../../../src/components/ai-approval-request/meta.ts"],"sourcesContent":["import { defineMeta } from \"@/registry/schema\";\n\nexport const meta = defineMeta({\n name: \"ai-approval-request\",\n title: \"AI Approval Request\",\n description: \"Approve a tool call — after correcting the arguments the model got wrong.\",\n category: \"ai\",\n status: \"stable\",\n dependencies: [],\n registryDependencies: [],\n files: [\"ai-approval-request.tsx\"],\n a11y:\n \"The proposed arguments are a description list of real labelled form controls, so each value \" +\n \"is associated with its name and editable ones are reachable by keyboard. A corrected \" +\n \"argument is marked in text rather than by border colour alone, because an audit trail has \" +\n \"to distinguish the model's proposal from the human's edit. The request is aria-busy while \" +\n \"arguments are still arriving and the decision controls stay disabled until it is whole — \" +\n \"rendering nothing until then, as the common implementation does, means nothing is on screen \" +\n \"at the moment approval becomes relevant. Irreversibility is stated as a sentence, never as a \" +\n \"severity colour.\",\n});\n"],"mappings":";;AAEA,MAAa,OAAO,WAAW;CAC7B,MAAM;CACN,OAAO;CACP,aAAa;CACb,UAAU;CACV,QAAQ;CACR,cAAc,CAAC;CACf,sBAAsB,CAAC;CACvB,OAAO,CAAC,yBAAyB;CACjC,MACE;AAQJ,CAAC"}
@@ -0,0 +1,92 @@
1
+ import { VariantProps } from "class-variance-authority";
2
+ import { ComponentPropsWithRef, ReactNode } from "react";
3
+ //#region src/components/ai-disclosure/ai-disclosure.d.ts
4
+ /**
5
+ * Telling someone they are looking at AI.
6
+ *
7
+ * Not one registry ships this — not AI Elements, assistant-ui, prompt-kit,
8
+ * CopilotKit or shadcn — while every one of them ships the chat surface that
9
+ * needs it. The gap is the reason this exists.
10
+ *
11
+ * The four `kind`s are not invented. They are the four human-visible situations
12
+ * the EU AI Act's Article 50 actually creates, which has applied since 2 August
13
+ * 2026: you are talking to a machine (50(1)); this media was generated or
14
+ * manipulated and resembles something real (50(4), "deep fakes"); this text was
15
+ * published to inform the public (50(4)); and the assisted case, which the same
16
+ * paragraph exempts where there is human review or editorial control — worth
17
+ * saying out loud rather than leaving to inference.
18
+ *
19
+ * What this cannot do, and what no React component can: Article 50(2) requires
20
+ * synthetic output to be marked *in a machine-readable format*, in the artifact
21
+ * itself, by whoever generated it. Rendering a badge does not do that, and a
22
+ * component that let you believe otherwise would be worse than none. Read the
23
+ * accessibility note and the docs page: this is a disclosure control, not a
24
+ * compliance product, and nothing here is legal advice.
25
+ */
26
+ type DisclosureKind = "interaction" | "generated" | "manipulated" | "assisted";
27
+ declare const disclosureVariants: (props?: ({
28
+ variant?: "banner" | "inline" | "overlay" | null | undefined;
29
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
30
+ interface AIDisclosureProps extends Omit<ComponentPropsWithRef<"div">, "children">, VariantProps<typeof disclosureVariants> {
31
+ kind: DisclosureKind;
32
+ /** Replaces the default wording. The default is a starting point, not a rule. */
33
+ label?: ReactNode;
34
+ /**
35
+ * Replaces the mark. The Commission publishes three icons for this and lets
36
+ * anyone use them without attribution — they are deliberately not bundled
37
+ * here, because an official mark shipped inside a component library ends up
38
+ * on content nobody checked. Bring your own, and the Commission's own words
39
+ * apply: using them "does not establish legal compliance by itself".
40
+ */
41
+ icon?: ReactNode;
42
+ /** A provenance panel, or anything else that belongs after the label. */
43
+ children?: ReactNode;
44
+ }
45
+ /**
46
+ * A disclosure, in words.
47
+ *
48
+ * The icon is decorative and the text is the disclosure. A sparkle alone is not
49
+ * a notice — it is a decoration that a sighted reader may or may not decode and
50
+ * that a screen reader passes over in silence, which is the failure mode the
51
+ * whole component exists to avoid.
52
+ */
53
+ declare function AIDisclosure({ className, kind, variant, label, icon, children, ...props }: AIDisclosureProps): import("react").JSX.Element;
54
+ interface ProvenanceClaim {
55
+ label: string;
56
+ value: ReactNode;
57
+ }
58
+ interface AIDisclosureProvenanceProps extends Omit<ComponentPropsWithRef<"button">, "children"> {
59
+ /**
60
+ * What is being claimed about this content, and by whom.
61
+ *
62
+ * Claims, not findings. They arrive as data — from a C2PA manifest your
63
+ * server read, from your own pipeline, from a vendor — and this renders them.
64
+ */
65
+ claims: ProvenanceClaim[];
66
+ /** Who asserts the claims. Named, because an unattributed claim is a rumour. */
67
+ source?: string;
68
+ /**
69
+ * Whether something you trust checked the claims, and said so.
70
+ *
71
+ * Supplied, never computed. Verifying a C2PA manifest means parsing signed
72
+ * COSE and walking a certificate chain; doing that in the browser would mean
73
+ * a wasm blob you cannot read, and "you own the source" would stop being
74
+ * true. It also cannot be trusted client-side even when it succeeds, because
75
+ * the page doing the checking is the page making the claim. Verify on a
76
+ * server and pass the answer down. Left undefined, this says so.
77
+ */
78
+ verified?: boolean;
79
+ triggerLabel?: string;
80
+ }
81
+ /**
82
+ * The metadata behind a disclosure, presented as claims rather than proof.
83
+ *
84
+ * The distinction is the entire point. "Made with Model X on 3 September" looks
85
+ * like a fact and is a string somebody put in a file. Rendering it beside a
86
+ * checkmark would launder an assertion into evidence, so the panel names who is
87
+ * asserting and states plainly whether anyone checked.
88
+ */
89
+ declare function AIDisclosureProvenance({ className, claims, source, verified, triggerLabel, ...props }: AIDisclosureProvenanceProps): import("react").JSX.Element;
90
+ //#endregion
91
+ export { AIDisclosure, AIDisclosureProps, AIDisclosureProvenance, AIDisclosureProvenanceProps, DisclosureKind, ProvenanceClaim, disclosureVariants };
92
+ //# sourceMappingURL=ai-disclosure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-disclosure.d.ts","names":[],"sources":["../../../src/components/ai-disclosure/ai-disclosure.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;KAgCY;cAgBN,qBAAkB;;6CAyBvB;UAegB,0BAEb,KAAK,2CACL,oBAAoB;EACtB,MAAM;;EAEN,QAAQ;;;;;;;;EAQR,OAAO;;EAEP,WAAW;;;;;;;;;;iBAWG,eACd,WACA,MACA,SACA,OACA,MACA,aACG,SACF,oCAAiB,IAAA;UAmBH;EACf;EACA,OAAO;;UAGQ,oCAAoC,KACnD;;;;;;;EASA,QAAQ;;EAER;;;;;;;;;;;EAWA;EACA;;;;;;;;;;iBAoBc,yBACd,WACA,QACA,QACA,UACA,iBACG,SACF,8CAA2B,IAAA"}
@@ -0,0 +1,122 @@
1
+ "use client";
2
+ import { focusRing, iconSlot } from "../../lib/styles.js";
3
+ import { cn } from "../../lib/utils.js";
4
+ import { Popover, PopoverContent, PopoverTrigger } from "../popover/popover.js";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { cva } from "class-variance-authority";
7
+ //#region src/components/ai-disclosure/ai-disclosure.tsx
8
+ /**
9
+ * What each kind says by default.
10
+ *
11
+ * Phrased for a reader rather than for a lawyer, and every one of them is
12
+ * overridable — the Act says the disclosure must be clear, not that it must use
13
+ * these words, and the right words depend on the product.
14
+ */
15
+ const DEFAULT_LABEL = {
16
+ interaction: "You are chatting with an AI assistant",
17
+ generated: "Generated by AI",
18
+ manipulated: "This media was altered by AI",
19
+ assisted: "AI-assisted, reviewed by a person"
20
+ };
21
+ const disclosureVariants = cva(cn("inline-flex w-fit items-center gap-1.5 font-medium", "[&_svg:not([class*='size-'])]:size-3.5", iconSlot), {
22
+ variants: { variant: {
23
+ /** Sits beside the thing it describes. */
24
+ inline: "rounded-full border border-border-strong px-2 py-0.5 text-xs",
25
+ /** Above a conversation, where Article 50(1) usually belongs. */
26
+ banner: "w-full rounded-lg border border-border bg-muted/40 px-3 py-2 text-xs text-muted-foreground",
27
+ /**
28
+ * Over the corner of an image or video. `--overlay` is a dark scrim in
29
+ * every shipped theme, so the text is white on purpose rather than
30
+ * following the theme — a label that inverts over a photograph is
31
+ * unreadable on half of them.
32
+ */
33
+ overlay: "rounded-md bg-overlay px-2 py-1 text-2xs text-white backdrop-blur-sm"
34
+ } },
35
+ defaultVariants: { variant: "inline" }
36
+ });
37
+ function SparkIcon() {
38
+ return /* @__PURE__ */ jsx("svg", {
39
+ viewBox: "0 0 24 24",
40
+ fill: "none",
41
+ "aria-hidden": "true",
42
+ children: /* @__PURE__ */ jsx("path", {
43
+ d: "M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9L12 3Z",
44
+ stroke: "currentColor",
45
+ strokeWidth: "2",
46
+ strokeLinejoin: "round"
47
+ })
48
+ });
49
+ }
50
+ /**
51
+ * A disclosure, in words.
52
+ *
53
+ * The icon is decorative and the text is the disclosure. A sparkle alone is not
54
+ * a notice — it is a decoration that a sighted reader may or may not decode and
55
+ * that a screen reader passes over in silence, which is the failure mode the
56
+ * whole component exists to avoid.
57
+ */
58
+ function AIDisclosure({ className, kind, variant, label, icon, children, ...props }) {
59
+ return /* @__PURE__ */ jsxs("div", {
60
+ "data-slot": "ai-disclosure",
61
+ "data-kind": kind,
62
+ className: cn(disclosureVariants({ variant }), className),
63
+ ...props,
64
+ children: [
65
+ icon ?? /* @__PURE__ */ jsx(SparkIcon, {}),
66
+ /* @__PURE__ */ jsx("span", { children: label ?? DEFAULT_LABEL[kind] }),
67
+ children
68
+ ]
69
+ });
70
+ }
71
+ function statusText(status, source) {
72
+ const by = source ? ` by ${source}` : "";
73
+ if (status === "verified") return `Checked${by} and the claims matched.`;
74
+ if (status === "failed") return `Checked${by} and the claims did not match.`;
75
+ return "Not checked. These are claims made about the content, not findings.";
76
+ }
77
+ /**
78
+ * The metadata behind a disclosure, presented as claims rather than proof.
79
+ *
80
+ * The distinction is the entire point. "Made with Model X on 3 September" looks
81
+ * like a fact and is a string somebody put in a file. Rendering it beside a
82
+ * checkmark would launder an assertion into evidence, so the panel names who is
83
+ * asserting and states plainly whether anyone checked.
84
+ */
85
+ function AIDisclosureProvenance({ className, claims, source, verified, triggerLabel = "Content details", ...props }) {
86
+ const status = verified === void 0 ? "unchecked" : verified ? "verified" : "failed";
87
+ return /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PopoverTrigger, {
88
+ asChild: true,
89
+ children: /* @__PURE__ */ jsx("button", {
90
+ type: "button",
91
+ "data-slot": "ai-disclosure-provenance-trigger",
92
+ className: cn("rounded-sm underline decoration-dotted underline-offset-2 hover:decoration-solid", focusRing, className),
93
+ ...props,
94
+ children: triggerLabel
95
+ })
96
+ }), /* @__PURE__ */ jsxs(PopoverContent, {
97
+ "aria-label": triggerLabel,
98
+ className: "w-80 text-xs",
99
+ children: [/* @__PURE__ */ jsx("dl", {
100
+ className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1.5",
101
+ children: claims.map((claim) => /* @__PURE__ */ jsxs("div", {
102
+ className: "contents",
103
+ children: [/* @__PURE__ */ jsx("dt", {
104
+ className: "text-muted-foreground",
105
+ children: claim.label
106
+ }), /* @__PURE__ */ jsx("dd", {
107
+ className: "break-words",
108
+ children: claim.value
109
+ })]
110
+ }, claim.label))
111
+ }), /* @__PURE__ */ jsx("p", {
112
+ "data-slot": "ai-disclosure-provenance-status",
113
+ "data-status": status,
114
+ className: cn("mt-3 border-t border-border pt-2", status === "failed" ? "text-destructive" : "text-muted-foreground"),
115
+ children: statusText(status, source)
116
+ })]
117
+ })] });
118
+ }
119
+ //#endregion
120
+ export { AIDisclosure, AIDisclosureProvenance, disclosureVariants };
121
+
122
+ //# sourceMappingURL=ai-disclosure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-disclosure.js","names":[],"sources":["../../../src/components/ai-disclosure/ai-disclosure.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentPropsWithRef, ReactNode } from \"react\";\n\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/components/popover\";\nimport { focusRing, iconSlot } from \"@/lib/styles\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Telling someone they are looking at AI.\n *\n * Not one registry ships this — not AI Elements, assistant-ui, prompt-kit,\n * CopilotKit or shadcn — while every one of them ships the chat surface that\n * needs it. The gap is the reason this exists.\n *\n * The four `kind`s are not invented. They are the four human-visible situations\n * the EU AI Act's Article 50 actually creates, which has applied since 2 August\n * 2026: you are talking to a machine (50(1)); this media was generated or\n * manipulated and resembles something real (50(4), \"deep fakes\"); this text was\n * published to inform the public (50(4)); and the assisted case, which the same\n * paragraph exempts where there is human review or editorial control — worth\n * saying out loud rather than leaving to inference.\n *\n * What this cannot do, and what no React component can: Article 50(2) requires\n * synthetic output to be marked *in a machine-readable format*, in the artifact\n * itself, by whoever generated it. Rendering a badge does not do that, and a\n * component that let you believe otherwise would be worse than none. Read the\n * accessibility note and the docs page: this is a disclosure control, not a\n * compliance product, and nothing here is legal advice.\n */\n\nexport type DisclosureKind = \"interaction\" | \"generated\" | \"manipulated\" | \"assisted\";\n\n/**\n * What each kind says by default.\n *\n * Phrased for a reader rather than for a lawyer, and every one of them is\n * overridable — the Act says the disclosure must be clear, not that it must use\n * these words, and the right words depend on the product.\n */\nconst DEFAULT_LABEL: Record<DisclosureKind, string> = {\n interaction: \"You are chatting with an AI assistant\",\n generated: \"Generated by AI\",\n manipulated: \"This media was altered by AI\",\n assisted: \"AI-assisted, reviewed by a person\",\n};\n\nconst disclosureVariants = cva(\n cn(\n \"inline-flex w-fit items-center gap-1.5 font-medium\",\n \"[&_svg:not([class*='size-'])]:size-3.5\",\n iconSlot,\n ),\n {\n variants: {\n variant: {\n /** Sits beside the thing it describes. */\n inline: \"rounded-full border border-border-strong px-2 py-0.5 text-xs\",\n /** Above a conversation, where Article 50(1) usually belongs. */\n banner:\n \"w-full rounded-lg border border-border bg-muted/40 px-3 py-2 text-xs text-muted-foreground\",\n /**\n * Over the corner of an image or video. `--overlay` is a dark scrim in\n * every shipped theme, so the text is white on purpose rather than\n * following the theme — a label that inverts over a photograph is\n * unreadable on half of them.\n */\n overlay: \"rounded-md bg-overlay px-2 py-1 text-2xs text-white backdrop-blur-sm\",\n },\n },\n defaultVariants: { variant: \"inline\" },\n },\n);\n\nfunction SparkIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9L12 3Z\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\nexport interface AIDisclosureProps\n extends\n Omit<ComponentPropsWithRef<\"div\">, \"children\">,\n VariantProps<typeof disclosureVariants> {\n kind: DisclosureKind;\n /** Replaces the default wording. The default is a starting point, not a rule. */\n label?: ReactNode;\n /**\n * Replaces the mark. The Commission publishes three icons for this and lets\n * anyone use them without attribution — they are deliberately not bundled\n * here, because an official mark shipped inside a component library ends up\n * on content nobody checked. Bring your own, and the Commission's own words\n * apply: using them \"does not establish legal compliance by itself\".\n */\n icon?: ReactNode;\n /** A provenance panel, or anything else that belongs after the label. */\n children?: ReactNode;\n}\n\n/**\n * A disclosure, in words.\n *\n * The icon is decorative and the text is the disclosure. A sparkle alone is not\n * a notice — it is a decoration that a sighted reader may or may not decode and\n * that a screen reader passes over in silence, which is the failure mode the\n * whole component exists to avoid.\n */\nexport function AIDisclosure({\n className,\n kind,\n variant,\n label,\n icon,\n children,\n ...props\n}: AIDisclosureProps) {\n return (\n <div\n data-slot=\"ai-disclosure\"\n data-kind={kind}\n className={cn(disclosureVariants({ variant }), className)}\n {...props}\n >\n {icon ?? <SparkIcon />}\n <span>{label ?? DEFAULT_LABEL[kind]}</span>\n {children}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Provenance */\n/* ------------------------------------------------------------------ */\n\nexport interface ProvenanceClaim {\n label: string;\n value: ReactNode;\n}\n\nexport interface AIDisclosureProvenanceProps extends Omit<\n ComponentPropsWithRef<\"button\">,\n \"children\"\n> {\n /**\n * What is being claimed about this content, and by whom.\n *\n * Claims, not findings. They arrive as data — from a C2PA manifest your\n * server read, from your own pipeline, from a vendor — and this renders them.\n */\n claims: ProvenanceClaim[];\n /** Who asserts the claims. Named, because an unattributed claim is a rumour. */\n source?: string;\n /**\n * Whether something you trust checked the claims, and said so.\n *\n * Supplied, never computed. Verifying a C2PA manifest means parsing signed\n * COSE and walking a certificate chain; doing that in the browser would mean\n * a wasm blob you cannot read, and \"you own the source\" would stop being\n * true. It also cannot be trusted client-side even when it succeeds, because\n * the page doing the checking is the page making the claim. Verify on a\n * server and pass the answer down. Left undefined, this says so.\n */\n verified?: boolean;\n triggerLabel?: string;\n}\n\ntype CheckStatus = \"verified\" | \"failed\" | \"unchecked\";\n\nfunction statusText(status: CheckStatus, source?: string): string {\n const by = source ? ` by ${source}` : \"\";\n if (status === \"verified\") return `Checked${by} and the claims matched.`;\n if (status === \"failed\") return `Checked${by} and the claims did not match.`;\n return \"Not checked. These are claims made about the content, not findings.\";\n}\n\n/**\n * The metadata behind a disclosure, presented as claims rather than proof.\n *\n * The distinction is the entire point. \"Made with Model X on 3 September\" looks\n * like a fact and is a string somebody put in a file. Rendering it beside a\n * checkmark would launder an assertion into evidence, so the panel names who is\n * asserting and states plainly whether anyone checked.\n */\nexport function AIDisclosureProvenance({\n className,\n claims,\n source,\n verified,\n triggerLabel = \"Content details\",\n ...props\n}: AIDisclosureProvenanceProps) {\n const status = verified === undefined ? \"unchecked\" : verified ? \"verified\" : \"failed\";\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-slot=\"ai-disclosure-provenance-trigger\"\n className={cn(\n \"rounded-sm underline decoration-dotted underline-offset-2 hover:decoration-solid\",\n focusRing,\n className,\n )}\n {...props}\n >\n {triggerLabel}\n </button>\n </PopoverTrigger>\n <PopoverContent aria-label={triggerLabel} className=\"w-80 text-xs\">\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-3 gap-y-1.5\">\n {claims.map((claim) => (\n <div key={claim.label} className=\"contents\">\n <dt className=\"text-muted-foreground\">{claim.label}</dt>\n <dd className=\"break-words\">{claim.value}</dd>\n </div>\n ))}\n </dl>\n {/* Said in text, and last, so it qualifies everything above it rather\n than being a tick a reader has to interpret. */}\n <p\n data-slot=\"ai-disclosure-provenance-status\"\n data-status={status}\n className={cn(\n \"mt-3 border-t border-border pt-2\",\n status === \"failed\" ? \"text-destructive\" : \"text-muted-foreground\",\n )}\n >\n {statusText(status, source)}\n </p>\n </PopoverContent>\n </Popover>\n );\n}\n\nexport { disclosureVariants };\n"],"mappings":";;;;;;;;;;;;;;AAyCA,MAAM,gBAAgD;CACpD,aAAa;CACb,WAAW;CACX,aAAa;CACb,UAAU;AACZ;AAEA,MAAM,qBAAqB,IACzB,GACE,sDACA,0CACA,QACF,GACA;CACE,UAAU,EACR,SAAS;;EAEP,QAAQ;;EAER,QACE;;;;;;;EAOF,SAAS;CACX,EACF;CACA,iBAAiB,EAAE,SAAS,SAAS;AACvC,CACF;AAEA,SAAS,YAAY;CACnB,OACE,oBAAC,OAAD;EAAK,SAAQ;EAAY,MAAK;EAAO,eAAY;EAC/C,UAAA,oBAAC,QAAD;GACE,GAAE;GACF,QAAO;GACP,aAAY;GACZ,gBAAe;EAChB,CAAA;CACE,CAAA;AAET;;;;;;;;;AA6BA,SAAgB,aAAa,EAC3B,WACA,MACA,SACA,OACA,MACA,UACA,GAAG,SACiB;CACpB,OACE,qBAAC,OAAD;EACE,aAAU;EACV,aAAW;EACX,WAAW,GAAG,mBAAmB,EAAE,QAAQ,CAAC,GAAG,SAAS;EACxD,GAAI;EAJN,UAAA;GAMG,QAAQ,oBAAC,WAAD,CAAY,CAAA;GACrB,oBAAC,QAAD,EAAA,UAAO,SAAS,cAAc,MAAY,CAAA;GACzC;EACE;;AAET;AAwCA,SAAS,WAAW,QAAqB,QAAyB;CAChE,MAAM,KAAK,SAAS,OAAO,WAAW;CACtC,IAAI,WAAW,YAAY,OAAO,UAAU,GAAG;CAC/C,IAAI,WAAW,UAAU,OAAO,UAAU,GAAG;CAC7C,OAAO;AACT;;;;;;;;;AAUA,SAAgB,uBAAuB,EACrC,WACA,QACA,QACA,UACA,eAAe,mBACf,GAAG,SAC2B;CAC9B,MAAM,SAAS,aAAa,KAAA,IAAY,cAAc,WAAW,aAAa;CAE9E,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD;EAAgB,SAAA;EACd,UAAA,oBAAC,UAAD;GACE,MAAK;GACL,aAAU;GACV,WAAW,GACT,oFACA,WACA,SACF;GACA,GAAI;GAEH,UAAA;EACK,CAAA;CACM,CAAA,GAChB,qBAAC,gBAAD;EAAgB,cAAY;EAAc,WAAU;EAApD,UAAA,CACE,oBAAC,MAAD;GAAI,WAAU;GACX,UAAA,OAAO,KAAK,UACX,qBAAC,OAAD;IAAuB,WAAU;IAAjC,UAAA,CACE,oBAAC,MAAD;KAAI,WAAU;KAAyB,UAAA,MAAM;IAAU,CAAA,GACvD,oBAAC,MAAD;KAAI,WAAU;KAAe,UAAA,MAAM;IAAU,CAAA,CAC1C;GAHK,GAAA,MAAM,KAGX,CACN;EACC,CAAA,GAGJ,oBAAC,KAAD;GACE,aAAU;GACV,eAAa;GACb,WAAW,GACT,oCACA,WAAW,WAAW,qBAAqB,uBAC7C;GAEC,UAAA,WAAW,QAAQ,MAAM;EACzB,CAAA,CACW;CACT,CAAA,CAAA,EAAA,CAAA;AAEb"}
@@ -0,0 +1,2 @@
1
+ import { AIDisclosure, AIDisclosureProps, AIDisclosureProvenance, AIDisclosureProvenanceProps, DisclosureKind, ProvenanceClaim, disclosureVariants } from "./ai-disclosure.js";
2
+ export { AIDisclosure, type AIDisclosureProps, AIDisclosureProvenance, type AIDisclosureProvenanceProps, type DisclosureKind, type ProvenanceClaim, disclosureVariants };
@@ -0,0 +1,2 @@
1
+ import { AIDisclosure, AIDisclosureProvenance, disclosureVariants } from "./ai-disclosure.js";
2
+ export { AIDisclosure, AIDisclosureProvenance, disclosureVariants };
@@ -0,0 +1,17 @@
1
+ import { defineMeta } from "../../registry/schema.js";
2
+ //#region src/components/ai-disclosure/meta.ts
3
+ const meta = defineMeta({
4
+ name: "ai-disclosure",
5
+ title: "AI Disclosure",
6
+ description: "Tells a reader they are looking at AI, and what is actually known about it.",
7
+ category: "ai",
8
+ status: "stable",
9
+ dependencies: ["class-variance-authority"],
10
+ registryDependencies: ["popover"],
11
+ files: ["ai-disclosure.tsx"],
12
+ a11y: "The text is the disclosure and the icon is decoration, marked aria-hidden — a sparkle alone is a mark a sighted reader may not decode and a screen reader passes over in silence, which is the exact failure this component exists to prevent. Each of the four kinds carries wording of its own, so the distinction between generated, manipulated and human-reviewed survives for anyone who cannot see the styling. The provenance panel states in words whether anyone checked the claims and who, rather than implying it with a tick, and its three states are told apart by their sentences rather than by colour. Scope: this renders the human-visible disclosures of EU AI Act Article 50(1) and 50(4). It cannot satisfy 50(2), which requires machine-readable marking inside the artifact by whoever generated it, and no React component can. Not legal advice."
13
+ });
14
+ //#endregion
15
+ export { meta };
16
+
17
+ //# sourceMappingURL=meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.js","names":[],"sources":["../../../src/components/ai-disclosure/meta.ts"],"sourcesContent":["import { defineMeta } from \"@/registry/schema\";\n\nexport const meta = defineMeta({\n name: \"ai-disclosure\",\n title: \"AI Disclosure\",\n description: \"Tells a reader they are looking at AI, and what is actually known about it.\",\n category: \"ai\",\n status: \"stable\",\n dependencies: [\"class-variance-authority\"],\n registryDependencies: [\"popover\"],\n files: [\"ai-disclosure.tsx\"],\n a11y:\n \"The text is the disclosure and the icon is decoration, marked aria-hidden — a sparkle alone \" +\n \"is a mark a sighted reader may not decode and a screen reader passes over in silence, which \" +\n \"is the exact failure this component exists to prevent. Each of the four kinds carries \" +\n \"wording of its own, so the distinction between generated, manipulated and human-reviewed \" +\n \"survives for anyone who cannot see the styling. The provenance panel states in words \" +\n \"whether anyone checked the claims and who, rather than implying it with a tick, and its \" +\n \"three states are told apart by their sentences rather than by colour. \" +\n \"Scope: this renders the human-visible disclosures of EU AI Act Article 50(1) and 50(4). \" +\n \"It cannot satisfy 50(2), which requires machine-readable marking inside the artifact by \" +\n \"whoever generated it, and no React component can. Not legal advice.\",\n});\n"],"mappings":";;AAEA,MAAa,OAAO,WAAW;CAC7B,MAAM;CACN,OAAO;CACP,aAAa;CACb,UAAU;CACV,QAAQ;CACR,cAAc,CAAC,0BAA0B;CACzC,sBAAsB,CAAC,SAAS;CAChC,OAAO,CAAC,mBAAmB;CAC3B,MACE;AAUJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ai-response.d.ts","names":[],"sources":["../../../src/components/ai-response/ai-response.tsx"],"mappings":";;;;;;;;;;;;;;UAkBiB,sBAAsB;;EAErC;;iBAGc,WAAW,WAAW,WAAW,aAAa,SAAS,gCAAa,IAAA;;;iBAwBpE,gBAAgB,cAAc,SAAS,gDAA6B,IAAA;;;;;;;;UAqBnE,+BAA+B;EAC9C;;iBAGc,oBACd,WACA,UACG,SACF,yCAAsB,IAAA"}
1
+ {"version":3,"file":"ai-response.d.ts","names":[],"sources":["../../../src/components/ai-response/ai-response.tsx"],"mappings":";;;;;;;;;;;;;;UAkBiB,sBAAsB;;EAErC;;iBAGc,WAAW,WAAW,WAAW,aAAa,SAAS,gCAAa,IAAA;;;iBAwBpE,gBAAgB,cAAc,SAAS,gDAA6B,IAAA;;;;;;;;UAsBnE,+BAA+B;EAC9C;;iBAGc,oBACd,WACA,UACG,SACF,yCAAsB,IAAA"}
@@ -17,6 +17,7 @@ function ResponseCaret({ className, ...props }) {
17
17
  return /* @__PURE__ */ jsx("span", {
18
18
  "data-slot": "response-caret",
19
19
  "aria-hidden": "true",
20
+ "data-motion": "indicator",
20
21
  className: cn("ml-0.5 inline-block h-[1em] w-[2px] translate-y-[0.15em] animate-caret bg-current align-baseline", className),
21
22
  ...props
22
23
  });
@@ -1 +1 @@
1
- {"version":3,"file":"ai-response.js","names":[],"sources":["../../../src/components/ai-response/ai-response.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * The text of an assistant response.\n *\n * Renders plain text with paragraph whitespace preserved. Markdown is\n * deliberately not parsed here: a Markdown renderer is a dependency, a security\n * decision about raw HTML, and a styling surface all at once, and every product\n * makes those differently. Pass already-rendered content as children when you\n * need it — the prose styling below applies either way.\n *\n * Not a live region, and not by omission. See the note on `Conversation`:\n * announcing streamed text token by token is unusable with a screen reader.\n */\nexport interface ResponseProps extends ComponentPropsWithRef<\"div\"> {\n /** Shows the caret. Purely visual — it carries no announcement. */\n streaming?: boolean;\n}\n\nexport function Response({ className, streaming, children, ...props }: ResponseProps) {\n return (\n <div\n data-slot=\"response\"\n data-streaming={streaming || undefined}\n className={cn(\n \"text-sm leading-relaxed whitespace-pre-wrap text-foreground\",\n // Minimal prose styling for consumers who pass rendered Markdown.\n \"[&_a]:text-primary [&_a]:underline [&_a]:underline-offset-4\",\n \"[&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.9em]\",\n \"[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5 [&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5\",\n \"[&_p+p]:mt-3\",\n className,\n )}\n {...props}\n >\n {children}\n {streaming ? <ResponseCaret /> : null}\n </div>\n );\n}\n\n/** The trailing cursor. Decorative — the streaming state is announced, if at\n * all, through ConversationStatus. */\nexport function ResponseCaret({ className, ...props }: ComponentPropsWithRef<\"span\">) {\n return (\n <span\n data-slot=\"response-caret\"\n aria-hidden=\"true\"\n className={cn(\n \"ml-0.5 inline-block h-[1em] w-[2px] translate-y-[0.15em] animate-caret bg-current align-baseline\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Shown while waiting for the first token.\n *\n * A distinct state from streaming: nothing has arrived yet, so there is no text\n * to show a caret after. Labelled for assistive technology because, unlike the\n * caret, this is the only thing on screen.\n */\nexport interface ThinkingIndicatorProps extends ComponentPropsWithRef<\"div\"> {\n label?: string;\n}\n\nexport function ThinkingIndicator({\n className,\n label = \"Thinking\",\n ...props\n}: ThinkingIndicatorProps) {\n return (\n <div\n data-slot=\"thinking-indicator\"\n className={cn(\"flex items-center gap-1.5 text-sm text-muted-foreground\", className)}\n {...props}\n >\n <span className=\"sr-only\">{label}</span>\n {[0, 1, 2].map((index) => (\n <span\n key={index}\n aria-hidden=\"true\"\n className=\"size-1.5 animate-pulse-soft rounded-full bg-current\"\n style={{ animationDelay: `${String(index * 160)}ms` }}\n />\n ))}\n </div>\n );\n}\n"],"mappings":";;;;AAuBA,SAAgB,SAAS,EAAE,WAAW,WAAW,UAAU,GAAG,SAAwB;CACpF,OACE,qBAAC,OAAD;EACE,aAAU;EACV,kBAAgB,aAAa,KAAA;EAC7B,WAAW,GACT,+DAEA,+DACA,6GACA,wFACA,gBACA,SACF;EACA,GAAI;EAZN,UAAA,CAcG,UACA,YAAY,oBAAC,eAAD,CAAgB,CAAA,IAAI,IAC9B;;AAET;;;AAIA,SAAgB,cAAc,EAAE,WAAW,GAAG,SAAwC;CACpF,OACE,oBAAC,QAAD;EACE,aAAU;EACV,eAAY;EACZ,WAAW,GACT,oGACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAaA,SAAgB,kBAAkB,EAChC,WACA,QAAQ,YACR,GAAG,SACsB;CACzB,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,2DAA2D,SAAS;EAClF,GAAI;EAHN,UAAA,CAKE,oBAAC,QAAD;GAAM,WAAU;GAAW,UAAA;EAAY,CAAA,GACtC;GAAC;GAAG;GAAG;EAAC,CAAC,CAAC,KAAK,UACd,oBAAC,QAAD;GAEE,eAAY;GACZ,WAAU;GACV,OAAO,EAAE,gBAAgB,GAAG,OAAO,QAAQ,GAAG,EAAE,IAAI;EACrD,GAJM,KAIN,CACF,CACE;;AAET"}
1
+ {"version":3,"file":"ai-response.js","names":[],"sources":["../../../src/components/ai-response/ai-response.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * The text of an assistant response.\n *\n * Renders plain text with paragraph whitespace preserved. Markdown is\n * deliberately not parsed here: a Markdown renderer is a dependency, a security\n * decision about raw HTML, and a styling surface all at once, and every product\n * makes those differently. Pass already-rendered content as children when you\n * need it — the prose styling below applies either way.\n *\n * Not a live region, and not by omission. See the note on `Conversation`:\n * announcing streamed text token by token is unusable with a screen reader.\n */\nexport interface ResponseProps extends ComponentPropsWithRef<\"div\"> {\n /** Shows the caret. Purely visual — it carries no announcement. */\n streaming?: boolean;\n}\n\nexport function Response({ className, streaming, children, ...props }: ResponseProps) {\n return (\n <div\n data-slot=\"response\"\n data-streaming={streaming || undefined}\n className={cn(\n \"text-sm leading-relaxed whitespace-pre-wrap text-foreground\",\n // Minimal prose styling for consumers who pass rendered Markdown.\n \"[&_a]:text-primary [&_a]:underline [&_a]:underline-offset-4\",\n \"[&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.9em]\",\n \"[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5 [&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5\",\n \"[&_p+p]:mt-3\",\n className,\n )}\n {...props}\n >\n {children}\n {streaming ? <ResponseCaret /> : null}\n </div>\n );\n}\n\n/** The trailing cursor. Decorative — the streaming state is announced, if at\n * all, through ConversationStatus. */\nexport function ResponseCaret({ className, ...props }: ComponentPropsWithRef<\"span\">) {\n return (\n <span\n data-slot=\"response-caret\"\n aria-hidden=\"true\"\n data-motion=\"indicator\"\n className={cn(\n \"ml-0.5 inline-block h-[1em] w-[2px] translate-y-[0.15em] animate-caret bg-current align-baseline\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/**\n * Shown while waiting for the first token.\n *\n * A distinct state from streaming: nothing has arrived yet, so there is no text\n * to show a caret after. Labelled for assistive technology because, unlike the\n * caret, this is the only thing on screen.\n */\nexport interface ThinkingIndicatorProps extends ComponentPropsWithRef<\"div\"> {\n label?: string;\n}\n\nexport function ThinkingIndicator({\n className,\n label = \"Thinking\",\n ...props\n}: ThinkingIndicatorProps) {\n return (\n <div\n data-slot=\"thinking-indicator\"\n className={cn(\"flex items-center gap-1.5 text-sm text-muted-foreground\", className)}\n {...props}\n >\n <span className=\"sr-only\">{label}</span>\n {[0, 1, 2].map((index) => (\n <span\n key={index}\n aria-hidden=\"true\"\n className=\"size-1.5 animate-pulse-soft rounded-full bg-current\"\n style={{ animationDelay: `${String(index * 160)}ms` }}\n />\n ))}\n </div>\n );\n}\n"],"mappings":";;;;AAuBA,SAAgB,SAAS,EAAE,WAAW,WAAW,UAAU,GAAG,SAAwB;CACpF,OACE,qBAAC,OAAD;EACE,aAAU;EACV,kBAAgB,aAAa,KAAA;EAC7B,WAAW,GACT,+DAEA,+DACA,6GACA,wFACA,gBACA,SACF;EACA,GAAI;EAZN,UAAA,CAcG,UACA,YAAY,oBAAC,eAAD,CAAgB,CAAA,IAAI,IAC9B;;AAET;;;AAIA,SAAgB,cAAc,EAAE,WAAW,GAAG,SAAwC;CACpF,OACE,oBAAC,QAAD;EACE,aAAU;EACV,eAAY;EACZ,eAAY;EACZ,WAAW,GACT,oGACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAaA,SAAgB,kBAAkB,EAChC,WACA,QAAQ,YACR,GAAG,SACsB;CACzB,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,2DAA2D,SAAS;EAClF,GAAI;EAHN,UAAA,CAKE,oBAAC,QAAD;GAAM,WAAU;GAAW,UAAA;EAAY,CAAA,GACtC;GAAC;GAAG;GAAG;EAAC,CAAC,CAAC,KAAK,UACd,oBAAC,QAAD;GAEE,eAAY;GACZ,WAAU;GACV,OAAO,EAAE,gBAAgB,GAAG,OAAO,QAAQ,GAAG,EAAE,IAAI;EACrD,GAJM,KAIN,CACF,CACE;;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"ai-structured-output.d.ts","names":[],"sources":["../../../src/components/ai-structured-output/ai-structured-output.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;KA+BY;UAEK;;EAEf;EACA;;EAEA;;UA6Be,8BAA8B,KAAK;;EAElD,QAAQ;;EAER,OAAO;;;;;EAKP;;;;;EAKA;;EAEA,SAAS;EACT,eAAe,gBAAgB;EAC/B,WAAW;;iBAGG,mBACd,WACA,QACA,OACA,WACA,SACA,QACA,aACA,aACG,SACF,wCAAqB,IAAA;UAiDP,6BAA6B,KAAK;EACjD;EACA,WAAW;;;;;;;;iBASG,kBAAkB,WAAW,MAAM,aAAa,SAAS,uCAAoB,IAAA;;;;;;;iBAoD7E,uBACd,WACA,OAAO,YACP,aACG,SACF;EAA+B;EAAe;oBAAmB,IAAA;;iBAoBpD,uBAAuB,cAAc,SAAS,6CAA0B,IAAA"}
1
+ {"version":3,"file":"ai-structured-output.d.ts","names":[],"sources":["../../../src/components/ai-structured-output/ai-structured-output.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;KAgCY;UAEK;;EAEf;EACA;;EAEA;;UA6Be,8BAA8B,KAAK;;EAElD,QAAQ;;EAER,OAAO;;;;;EAKP;;;;;EAKA;;EAEA,SAAS;EACT,eAAe,gBAAgB;EAC/B,WAAW;;iBAGG,mBACd,WACA,QACA,OACA,WACA,SACA,QACA,aACA,aACG,SACF,wCAAqB,IAAA;UAiDP,6BAA6B,KAAK;EACjD;EACA,WAAW;;;;;;;;iBASG,kBAAkB,WAAW,MAAM,aAAa,SAAS,uCAAoB,IAAA;;;;;;;iBA2E7E,uBACd,WACA,OAAO,YACP,aACG,SACF;EAA+B;EAAe;oBAAmB,IAAA;;iBAoBpD,uBAAuB,cAAc,SAAS,6CAA0B,IAAA"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "../../lib/utils.js";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
- import { createContext, useContext, useMemo } from "react";
4
+ import { createContext, useContext, useMemo, useState } from "react";
5
5
  //#region src/components/ai-structured-output/ai-structured-output.tsx
6
6
  const StructuredOutputContext = createContext(null);
7
7
  function useStructuredOutputContext(component) {
@@ -72,9 +72,16 @@ function StructuredField({ className, name, children, ...props }) {
72
72
  if (!field) throw new Error(`StructuredField "${name}" is not declared in the fields prop.`);
73
73
  const state = stateOf(name);
74
74
  const raw = value[name];
75
+ const [seenState, setSeenState] = useState(state);
76
+ const [hasSettled, setHasSettled] = useState(false);
77
+ if (seenState !== state) {
78
+ setSeenState(state);
79
+ if (state === "settled" && seenState !== "settled") setHasSettled(true);
80
+ }
75
81
  return /* @__PURE__ */ jsxs("div", {
76
82
  "data-slot": "structured-field",
77
83
  "data-state": state,
84
+ "data-settled": hasSettled || void 0,
78
85
  "data-field": name,
79
86
  className: cn("flex flex-col gap-1", className),
80
87
  ...props,
@@ -88,7 +95,11 @@ function StructuredField({ className, name, children, ...props }) {
88
95
  "data-slot": "structured-field-placeholder",
89
96
  "aria-hidden": "true",
90
97
  className: "block h-4 w-24 animate-pulse-soft rounded bg-muted"
91
- }) : children ?? formatValue(raw, name)
98
+ }) : /* @__PURE__ */ jsx("span", {
99
+ "data-slot": "structured-field-value",
100
+ className: cn(hasSettled && "inline-block animate-settle"),
101
+ children: children ?? formatValue(raw, name)
102
+ })
92
103
  })]
93
104
  });
94
105
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ai-structured-output.js","names":[],"sources":["../../../src/components/ai-structured-output/ai-structured-output.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useContext,\n useMemo,\n type ComponentPropsWithRef,\n type ReactNode,\n} from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * An object arriving field by field from the model.\n *\n * Most AI features inside real software are not chatbots. They are invoice\n * extraction, CRM enrichment, resume parsing, form autofill — a schema goes in\n * and a filled object comes back. Every one of them streams a partial object\n * into a layout, and almost every one reflows on each token because the fields\n * appear as they arrive.\n *\n * The honest limitation, stated here rather than discovered later: there is no\n * per-field completion signal anywhere in the stack. A streaming API hands you\n * successive partial snapshots, and a string that has stopped growing is\n * indistinguishable from one still arriving. So this component does not pretend\n * to know. It takes the field list up front, reserves the layout from it, and\n * lets the caller say which fields are settled — defaulting to the rule that a\n * field is settled once a later field has appeared, which is true of\n * depth-first JSON streaming and is documented rather than assumed silently.\n */\n\nexport type FieldState = \"pending\" | \"streaming\" | \"settled\" | \"error\";\n\nexport interface OutputField {\n /** Key in the streamed object. */\n name: string;\n label: string;\n /** Rough height reserved before the value arrives, in lines. */\n lines?: number;\n}\n\ninterface StructuredOutputContextValue {\n fields: OutputField[];\n value: Record<string, unknown>;\n stateOf: (name: string) => FieldState;\n formatValue: (value: unknown, name: string) => string;\n}\n\nconst StructuredOutputContext = createContext<StructuredOutputContextValue | null>(null);\n\nfunction useStructuredOutputContext(component: string): StructuredOutputContextValue {\n const context = useContext(StructuredOutputContext);\n if (!context) {\n throw new Error(`${component} must be rendered inside <StructuredOutput>.`);\n }\n return context;\n}\n\nfunction defaultFormat(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"bigint\") return String(value);\n if (typeof value === \"boolean\") return value ? \"Yes\" : \"No\";\n if (Array.isArray(value)) return value.map(defaultFormat).join(\", \");\n return JSON.stringify(value);\n}\n\nexport interface StructuredOutputProps extends Omit<ComponentPropsWithRef<\"dl\">, \"children\"> {\n /** Declared up front, so layout is reserved before anything arrives. */\n fields: OutputField[];\n /** The latest partial snapshot. */\n value: Record<string, unknown>;\n /**\n * True while more of the object is still expected. When false every present\n * field is settled, which is the only completion signal that is ever certain.\n */\n streaming?: boolean;\n /**\n * Fields the caller knows are finished. Supply this when the API gives a\n * real signal; otherwise the default rule applies.\n */\n settled?: string[];\n /** Fields that failed to extract, with the reason shown in place. */\n errors?: Record<string, string>;\n formatValue?: (value: unknown, name: string) => string;\n children?: ReactNode;\n}\n\nexport function StructuredOutput({\n className,\n fields,\n value,\n streaming = false,\n settled,\n errors,\n formatValue = defaultFormat,\n children,\n ...props\n}: StructuredOutputProps) {\n const stateOf = useMemo(() => {\n const explicit = settled ? new Set(settled) : null;\n const lastPresentIndex = fields.reduce(\n (last, field, index) => (value[field.name] !== undefined ? index : last),\n -1,\n );\n\n return (name: string): FieldState => {\n if (errors?.[name]) return \"error\";\n\n const index = fields.findIndex((field) => field.name === name);\n const present = value[name] !== undefined;\n\n if (!present) return \"pending\";\n if (explicit) return explicit.has(name) ? \"settled\" : \"streaming\";\n // No explicit signal. Once a later field has appeared this one cannot\n // still be growing, which holds for depth-first JSON streaming. The last\n // present field stays \"streaming\" until the caller says streaming ended.\n if (!streaming) return \"settled\";\n return index < lastPresentIndex ? \"settled\" : \"streaming\";\n };\n }, [fields, value, streaming, settled, errors]);\n\n const context = useMemo<StructuredOutputContextValue>(\n () => ({ fields, value, stateOf, formatValue }),\n [fields, value, stateOf, formatValue],\n );\n\n return (\n <StructuredOutputContext.Provider value={context}>\n <dl\n data-slot=\"structured-output\"\n data-streaming={streaming || undefined}\n // Fields arrive one at a time and each is a small, self-contained fact,\n // so the region is polite and additive rather than re-reading the whole\n // object on every token.\n aria-live=\"polite\"\n aria-busy={streaming}\n className={cn(\"flex flex-col gap-3\", className)}\n {...props}\n >\n {children ??\n fields.map((field) => <StructuredField key={field.name} name={field.name} />)}\n </dl>\n </StructuredOutputContext.Provider>\n );\n}\n\nexport interface StructuredFieldProps extends Omit<ComponentPropsWithRef<\"div\">, \"children\"> {\n name: string;\n children?: ReactNode;\n}\n\n/**\n * One field: its label, its value, and the space it will occupy before it has\n * one.\n *\n * The reserved height is what stops the layout jumping as the object fills in.\n */\nexport function StructuredField({ className, name, children, ...props }: StructuredFieldProps) {\n const { fields, value, stateOf, formatValue } = useStructuredOutputContext(\"StructuredField\");\n\n const field = fields.find((candidate) => candidate.name === name);\n if (!field) {\n throw new Error(`StructuredField \"${name}\" is not declared in the fields prop.`);\n }\n\n const state = stateOf(name);\n const raw = value[name];\n\n return (\n <div\n data-slot=\"structured-field\"\n data-state={state}\n data-field={name}\n className={cn(\"flex flex-col gap-1\", className)}\n {...props}\n >\n <dt className=\"text-xs text-muted-foreground\">{field.label}</dt>\n <dd\n className={cn(\n \"m-0 text-sm\",\n state === \"pending\" && \"text-muted-foreground\",\n state === \"error\" && \"text-destructive\",\n )}\n // Height is reserved from the declared line count so the value lands in\n // space already set aside for it rather than pushing the page down.\n // Computed rather than left to calc() so the reserved height is a plain\n // value that can be asserted and reasoned about.\n style={{ minHeight: `${String((field.lines ?? 1) * 1.25)}rem` }}\n >\n {state === \"pending\" ? (\n <span\n data-slot=\"structured-field-placeholder\"\n aria-hidden=\"true\"\n className=\"block h-4 w-24 animate-pulse-soft rounded bg-muted\"\n />\n ) : (\n (children ?? formatValue(raw, name))\n )}\n </dd>\n </div>\n );\n}\n\n/**\n * A confidence score for one field.\n *\n * Rendered as text with the number, never as a bare colour, because \"how much\n * should I trust this\" is exactly the thing a colour cannot answer.\n */\nexport function StructuredConfidence({\n className,\n value: confidence,\n lowBelow = 0.7,\n ...props\n}: ComponentPropsWithRef<\"p\"> & { value: number; lowBelow?: number }) {\n const low = confidence < lowBelow;\n const percent = new Intl.NumberFormat(undefined, {\n style: \"percent\",\n maximumFractionDigits: 0,\n }).format(confidence);\n\n return (\n <p\n data-slot=\"structured-confidence\"\n data-low={low || undefined}\n className={cn(\"text-xs\", low ? \"text-warning\" : \"text-muted-foreground\", className)}\n {...props}\n >\n {low ? `Low confidence, ${percent} — worth checking` : `${percent} confidence`}\n </p>\n );\n}\n\n/** The reason a field could not be extracted, shown where the value would be. */\nexport function StructuredFieldError({ className, ...props }: ComponentPropsWithRef<\"p\">) {\n return (\n <p\n data-slot=\"structured-field-error\"\n className={cn(\"text-xs text-destructive\", className)}\n {...props}\n />\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ai-structured-output.js","names":[],"sources":["../../../src/components/ai-structured-output/ai-structured-output.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n useContext,\n useMemo,\n useState,\n type ComponentPropsWithRef,\n type ReactNode,\n} from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * An object arriving field by field from the model.\n *\n * Most AI features inside real software are not chatbots. They are invoice\n * extraction, CRM enrichment, resume parsing, form autofill — a schema goes in\n * and a filled object comes back. Every one of them streams a partial object\n * into a layout, and almost every one reflows on each token because the fields\n * appear as they arrive.\n *\n * The honest limitation, stated here rather than discovered later: there is no\n * per-field completion signal anywhere in the stack. A streaming API hands you\n * successive partial snapshots, and a string that has stopped growing is\n * indistinguishable from one still arriving. So this component does not pretend\n * to know. It takes the field list up front, reserves the layout from it, and\n * lets the caller say which fields are settled — defaulting to the rule that a\n * field is settled once a later field has appeared, which is true of\n * depth-first JSON streaming and is documented rather than assumed silently.\n */\n\nexport type FieldState = \"pending\" | \"streaming\" | \"settled\" | \"error\";\n\nexport interface OutputField {\n /** Key in the streamed object. */\n name: string;\n label: string;\n /** Rough height reserved before the value arrives, in lines. */\n lines?: number;\n}\n\ninterface StructuredOutputContextValue {\n fields: OutputField[];\n value: Record<string, unknown>;\n stateOf: (name: string) => FieldState;\n formatValue: (value: unknown, name: string) => string;\n}\n\nconst StructuredOutputContext = createContext<StructuredOutputContextValue | null>(null);\n\nfunction useStructuredOutputContext(component: string): StructuredOutputContextValue {\n const context = useContext(StructuredOutputContext);\n if (!context) {\n throw new Error(`${component} must be rendered inside <StructuredOutput>.`);\n }\n return context;\n}\n\nfunction defaultFormat(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"bigint\") return String(value);\n if (typeof value === \"boolean\") return value ? \"Yes\" : \"No\";\n if (Array.isArray(value)) return value.map(defaultFormat).join(\", \");\n return JSON.stringify(value);\n}\n\nexport interface StructuredOutputProps extends Omit<ComponentPropsWithRef<\"dl\">, \"children\"> {\n /** Declared up front, so layout is reserved before anything arrives. */\n fields: OutputField[];\n /** The latest partial snapshot. */\n value: Record<string, unknown>;\n /**\n * True while more of the object is still expected. When false every present\n * field is settled, which is the only completion signal that is ever certain.\n */\n streaming?: boolean;\n /**\n * Fields the caller knows are finished. Supply this when the API gives a\n * real signal; otherwise the default rule applies.\n */\n settled?: string[];\n /** Fields that failed to extract, with the reason shown in place. */\n errors?: Record<string, string>;\n formatValue?: (value: unknown, name: string) => string;\n children?: ReactNode;\n}\n\nexport function StructuredOutput({\n className,\n fields,\n value,\n streaming = false,\n settled,\n errors,\n formatValue = defaultFormat,\n children,\n ...props\n}: StructuredOutputProps) {\n const stateOf = useMemo(() => {\n const explicit = settled ? new Set(settled) : null;\n const lastPresentIndex = fields.reduce(\n (last, field, index) => (value[field.name] !== undefined ? index : last),\n -1,\n );\n\n return (name: string): FieldState => {\n if (errors?.[name]) return \"error\";\n\n const index = fields.findIndex((field) => field.name === name);\n const present = value[name] !== undefined;\n\n if (!present) return \"pending\";\n if (explicit) return explicit.has(name) ? \"settled\" : \"streaming\";\n // No explicit signal. Once a later field has appeared this one cannot\n // still be growing, which holds for depth-first JSON streaming. The last\n // present field stays \"streaming\" until the caller says streaming ended.\n if (!streaming) return \"settled\";\n return index < lastPresentIndex ? \"settled\" : \"streaming\";\n };\n }, [fields, value, streaming, settled, errors]);\n\n const context = useMemo<StructuredOutputContextValue>(\n () => ({ fields, value, stateOf, formatValue }),\n [fields, value, stateOf, formatValue],\n );\n\n return (\n <StructuredOutputContext.Provider value={context}>\n <dl\n data-slot=\"structured-output\"\n data-streaming={streaming || undefined}\n // Fields arrive one at a time and each is a small, self-contained fact,\n // so the region is polite and additive rather than re-reading the whole\n // object on every token.\n aria-live=\"polite\"\n aria-busy={streaming}\n className={cn(\"flex flex-col gap-3\", className)}\n {...props}\n >\n {children ??\n fields.map((field) => <StructuredField key={field.name} name={field.name} />)}\n </dl>\n </StructuredOutputContext.Provider>\n );\n}\n\nexport interface StructuredFieldProps extends Omit<ComponentPropsWithRef<\"div\">, \"children\"> {\n name: string;\n children?: ReactNode;\n}\n\n/**\n * One field: its label, its value, and the space it will occupy before it has\n * one.\n *\n * The reserved height is what stops the layout jumping as the object fills in.\n */\nexport function StructuredField({ className, name, children, ...props }: StructuredFieldProps) {\n const { fields, value, stateOf, formatValue } = useStructuredOutputContext(\"StructuredField\");\n\n const field = fields.find((candidate) => candidate.name === name);\n if (!field) {\n throw new Error(`StructuredField \"${name}\" is not declared in the fields prop.`);\n }\n\n const state = stateOf(name);\n const raw = value[name];\n\n // \"A token arrived\" and \"this field is final\" are different facts, and in a\n // streamed object they look identical. The settle makes that distinction\n // visible — so it plays on the transition into settled, and never on a field\n // that was already final when the component mounted.\n //\n // State adjusted during render rather than tracked in a ref: reading a ref\n // while rendering is unsafe under concurrent rendering, and an effect would\n // paint the plain value first and animate a frame later. React re-renders\n // immediately here and discards the intermediate pass.\n const [seenState, setSeenState] = useState<FieldState>(state);\n const [hasSettled, setHasSettled] = useState(false);\n\n if (seenState !== state) {\n setSeenState(state);\n if (state === \"settled\" && seenState !== \"settled\") setHasSettled(true);\n }\n\n return (\n <div\n data-slot=\"structured-field\"\n data-state={state}\n data-settled={hasSettled || undefined}\n data-field={name}\n className={cn(\"flex flex-col gap-1\", className)}\n {...props}\n >\n <dt className=\"text-xs text-muted-foreground\">{field.label}</dt>\n <dd\n className={cn(\n \"m-0 text-sm\",\n state === \"pending\" && \"text-muted-foreground\",\n state === \"error\" && \"text-destructive\",\n )}\n // Height is reserved from the declared line count so the value lands in\n // space already set aside for it rather than pushing the page down.\n // Computed rather than left to calc() so the reserved height is a plain\n // value that can be asserted and reasoned about.\n style={{ minHeight: `${String((field.lines ?? 1) * 1.25)}rem` }}\n >\n {state === \"pending\" ? (\n <span\n data-slot=\"structured-field-placeholder\"\n aria-hidden=\"true\"\n className=\"block h-4 w-24 animate-pulse-soft rounded bg-muted\"\n />\n ) : (\n <span\n data-slot=\"structured-field-value\"\n className={cn(hasSettled && \"inline-block animate-settle\")}\n >\n {children ?? formatValue(raw, name)}\n </span>\n )}\n </dd>\n </div>\n );\n}\n\n/**\n * A confidence score for one field.\n *\n * Rendered as text with the number, never as a bare colour, because \"how much\n * should I trust this\" is exactly the thing a colour cannot answer.\n */\nexport function StructuredConfidence({\n className,\n value: confidence,\n lowBelow = 0.7,\n ...props\n}: ComponentPropsWithRef<\"p\"> & { value: number; lowBelow?: number }) {\n const low = confidence < lowBelow;\n const percent = new Intl.NumberFormat(undefined, {\n style: \"percent\",\n maximumFractionDigits: 0,\n }).format(confidence);\n\n return (\n <p\n data-slot=\"structured-confidence\"\n data-low={low || undefined}\n className={cn(\"text-xs\", low ? \"text-warning\" : \"text-muted-foreground\", className)}\n {...props}\n >\n {low ? `Low confidence, ${percent} — worth checking` : `${percent} confidence`}\n </p>\n );\n}\n\n/** The reason a field could not be extracted, shown where the value would be. */\nexport function StructuredFieldError({ className, ...props }: ComponentPropsWithRef<\"p\">) {\n return (\n <p\n data-slot=\"structured-field-error\"\n className={cn(\"text-xs text-destructive\", className)}\n {...props}\n />\n );\n}\n"],"mappings":"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"}
@@ -14,7 +14,7 @@ import { ComponentPropsWithRef, ReactNode } from "react";
14
14
  */
15
15
  type ToolStatus = "pending" | "running" | "success" | "error";
16
16
  declare const toolVariants: (props?: ({
17
- status?: "success" | "error" | "pending" | "running" | null | undefined;
17
+ status?: "success" | "pending" | "running" | "error" | null | undefined;
18
18
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
19
19
  interface ToolProps extends ComponentPropsWithRef<typeof Collapsible.Root>, VariantProps<typeof toolVariants> {
20
20
  status?: ToolStatus;
@@ -2,7 +2,7 @@ import { VariantProps } from "class-variance-authority";
2
2
  import { ComponentPropsWithRef } from "react";
3
3
  //#region src/components/alert/alert.d.ts
4
4
  declare const alertVariants: (props?: ({
5
- variant?: "destructive" | "default" | "success" | "warning" | "info" | null | undefined;
5
+ variant?: "default" | "destructive" | "success" | "warning" | "info" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  /**
8
8
  * How urgently the alert should interrupt a screen reader.
@@ -3,7 +3,7 @@ import { VariantProps } from "class-variance-authority";
3
3
  import { ComponentPropsWithRef } from "react";
4
4
  //#region src/components/avatar/avatar.d.ts
5
5
  declare const avatarVariants: (props?: ({
6
- size?: "sm" | "md" | "lg" | "xs" | "xl" | null | undefined;
6
+ size?: "sm" | "md" | "xs" | "lg" | "xl" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
8
  interface AvatarProps extends ComponentPropsWithRef<typeof Avatar.Root>, VariantProps<typeof avatarVariants> {}
9
9
  /** Image representation of a user or entity, with a text fallback. */
@@ -2,7 +2,7 @@ import { VariantProps } from "class-variance-authority";
2
2
  import { ComponentPropsWithRef } from "react";
3
3
  //#region src/components/badge/badge.d.ts
4
4
  declare const badgeVariants: (props?: ({
5
- variant?: "secondary" | "outline" | "destructive" | "default" | "success" | "warning" | "info" | null | undefined;
5
+ variant?: "default" | "secondary" | "outline" | "destructive" | "success" | "warning" | "info" | null | undefined;
6
6
  size?: "sm" | "md" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
8
  interface BadgeProps extends ComponentPropsWithRef<"span">, VariantProps<typeof badgeVariants> {
@@ -2,7 +2,7 @@ import { VariantProps } from "class-variance-authority";
2
2
  import { ComponentPropsWithRef } from "react";
3
3
  //#region src/components/button/button.d.ts
4
4
  declare const buttonVariants: (props?: ({
5
- variant?: "link" | "primary" | "secondary" | "outline" | "ghost" | "destructive" | null | undefined;
5
+ variant?: "link" | "secondary" | "outline" | "destructive" | "primary" | "ghost" | null | undefined;
6
6
  size?: "sm" | "md" | "lg" | "icon" | "icon-sm" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
8
  interface ButtonProps extends ComponentPropsWithRef<"button">, VariantProps<typeof buttonVariants> {
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { cn } from "../../lib/utils.js";
3
+ import { Popover, PopoverContent, PopoverTrigger } from "../popover/popover.js";
3
4
  import { Button } from "../button/button.js";
4
5
  import { Calendar } from "../calendar/calendar.js";
5
- import { Popover, PopoverContent, PopoverTrigger } from "../popover/popover.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { useState } from "react";
8
8
  //#region src/components/date-picker/date-picker.tsx