@dowel-ui/react 0.1.1 → 0.3.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 (142) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +193 -0
  3. package/dist/components/ai-action-ledger/ai-action-ledger.d.ts +77 -0
  4. package/dist/components/ai-action-ledger/ai-action-ledger.d.ts.map +1 -0
  5. package/dist/components/ai-action-ledger/ai-action-ledger.js +224 -0
  6. package/dist/components/ai-action-ledger/ai-action-ledger.js.map +1 -0
  7. package/dist/components/ai-action-ledger/index.d.ts +2 -0
  8. package/dist/components/ai-action-ledger/index.js +2 -0
  9. package/dist/components/ai-action-ledger/meta.js +17 -0
  10. package/dist/components/ai-action-ledger/meta.js.map +1 -0
  11. package/dist/components/ai-agent-plan/ai-agent-plan.d.ts +50 -0
  12. package/dist/components/ai-agent-plan/ai-agent-plan.d.ts.map +1 -0
  13. package/dist/components/ai-agent-plan/ai-agent-plan.js +156 -0
  14. package/dist/components/ai-agent-plan/ai-agent-plan.js.map +1 -0
  15. package/dist/components/ai-agent-plan/index.d.ts +2 -0
  16. package/dist/components/ai-agent-plan/index.js +2 -0
  17. package/dist/components/ai-agent-plan/meta.js +17 -0
  18. package/dist/components/ai-agent-plan/meta.js.map +1 -0
  19. package/dist/components/ai-agent-status/ai-agent-status.d.ts +1 -1
  20. package/dist/components/ai-approval-request/ai-approval-request.d.ts +67 -0
  21. package/dist/components/ai-approval-request/ai-approval-request.d.ts.map +1 -0
  22. package/dist/components/ai-approval-request/ai-approval-request.js +218 -0
  23. package/dist/components/ai-approval-request/ai-approval-request.js.map +1 -0
  24. package/dist/components/ai-approval-request/index.d.ts +2 -0
  25. package/dist/components/ai-approval-request/index.js +2 -0
  26. package/dist/components/ai-approval-request/meta.js +17 -0
  27. package/dist/components/ai-approval-request/meta.js.map +1 -0
  28. package/dist/components/ai-inline-completion/ai-inline-completion.d.ts +45 -0
  29. package/dist/components/ai-inline-completion/ai-inline-completion.d.ts.map +1 -0
  30. package/dist/components/ai-inline-completion/ai-inline-completion.js +110 -0
  31. package/dist/components/ai-inline-completion/ai-inline-completion.js.map +1 -0
  32. package/dist/components/ai-inline-completion/index.d.ts +2 -0
  33. package/dist/components/ai-inline-completion/index.js +2 -0
  34. package/dist/components/ai-inline-completion/meta.js +17 -0
  35. package/dist/components/ai-inline-completion/meta.js.map +1 -0
  36. package/dist/components/ai-response/ai-response.d.ts.map +1 -1
  37. package/dist/components/ai-response/ai-response.js +1 -0
  38. package/dist/components/ai-response/ai-response.js.map +1 -1
  39. package/dist/components/ai-structured-output/ai-structured-output.d.ts +75 -0
  40. package/dist/components/ai-structured-output/ai-structured-output.d.ts.map +1 -0
  41. package/dist/components/ai-structured-output/ai-structured-output.js +137 -0
  42. package/dist/components/ai-structured-output/ai-structured-output.js.map +1 -0
  43. package/dist/components/ai-structured-output/index.d.ts +2 -0
  44. package/dist/components/ai-structured-output/index.js +2 -0
  45. package/dist/components/ai-structured-output/meta.js +17 -0
  46. package/dist/components/ai-structured-output/meta.js.map +1 -0
  47. package/dist/components/ai-tool/ai-tool.d.ts +1 -1
  48. package/dist/components/alert/alert.d.ts +1 -1
  49. package/dist/components/badge/badge.d.ts +1 -1
  50. package/dist/components/button/button.d.ts +1 -1
  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/meter/index.d.ts +2 -0
  64. package/dist/components/meter/index.js +2 -0
  65. package/dist/components/meter/meta.js +17 -0
  66. package/dist/components/meter/meta.js.map +1 -0
  67. package/dist/components/meter/meter.d.ts +69 -0
  68. package/dist/components/meter/meter.d.ts.map +1 -0
  69. package/dist/components/meter/meter.js +144 -0
  70. package/dist/components/meter/meter.js.map +1 -0
  71. package/dist/components/metric-delta/index.d.ts +2 -0
  72. package/dist/components/metric-delta/index.js +2 -0
  73. package/dist/components/metric-delta/meta.js +17 -0
  74. package/dist/components/metric-delta/meta.js.map +1 -0
  75. package/dist/components/metric-delta/metric-delta.d.ts +59 -0
  76. package/dist/components/metric-delta/metric-delta.d.ts.map +1 -0
  77. package/dist/components/metric-delta/metric-delta.js +82 -0
  78. package/dist/components/metric-delta/metric-delta.js.map +1 -0
  79. package/dist/components/progress/progress.d.ts +1 -1
  80. package/dist/components/progress/progress.js +1 -0
  81. package/dist/components/progress/progress.js.map +1 -1
  82. package/dist/components/record-diff/index.d.ts +2 -0
  83. package/dist/components/record-diff/index.js +2 -0
  84. package/dist/components/record-diff/meta.js +17 -0
  85. package/dist/components/record-diff/meta.js.map +1 -0
  86. package/dist/components/record-diff/record-diff.d.ts +56 -0
  87. package/dist/components/record-diff/record-diff.d.ts.map +1 -0
  88. package/dist/components/record-diff/record-diff.js +199 -0
  89. package/dist/components/record-diff/record-diff.js.map +1 -0
  90. package/dist/components/spinner/spinner.js +1 -0
  91. package/dist/components/spinner/spinner.js.map +1 -1
  92. package/dist/components/tags-input/index.d.ts +2 -0
  93. package/dist/components/tags-input/index.js +2 -0
  94. package/dist/components/tags-input/meta.js +17 -0
  95. package/dist/components/tags-input/meta.js.map +1 -0
  96. package/dist/components/tags-input/tags-input.d.ts +47 -0
  97. package/dist/components/tags-input/tags-input.d.ts.map +1 -0
  98. package/dist/components/tags-input/tags-input.js +182 -0
  99. package/dist/components/tags-input/tags-input.js.map +1 -0
  100. package/dist/components/toast/toast.d.ts +1 -1
  101. package/dist/index.d.ts +22 -1
  102. package/dist/index.js +12 -1
  103. package/dist/registry/components.d.ts.map +1 -1
  104. package/dist/registry/components.js +65 -45
  105. package/dist/registry/components.js.map +1 -1
  106. package/package.json +36 -4
  107. package/src/components/ai-action-ledger/ai-action-ledger.tsx +381 -0
  108. package/src/components/ai-action-ledger/index.ts +14 -0
  109. package/src/components/ai-action-ledger/meta.ts +19 -0
  110. package/src/components/ai-agent-plan/ai-agent-plan.tsx +0 -0
  111. package/src/components/ai-agent-plan/index.ts +10 -0
  112. package/src/components/ai-agent-plan/meta.ts +19 -0
  113. package/src/components/ai-approval-request/ai-approval-request.tsx +368 -0
  114. package/src/components/ai-approval-request/index.ts +7 -0
  115. package/src/components/ai-approval-request/meta.ts +21 -0
  116. package/src/components/ai-inline-completion/ai-inline-completion.tsx +214 -0
  117. package/src/components/ai-inline-completion/index.ts +1 -0
  118. package/src/components/ai-inline-completion/meta.ts +20 -0
  119. package/src/components/ai-response/ai-response.tsx +1 -0
  120. package/src/components/ai-structured-output/ai-structured-output.tsx +268 -0
  121. package/src/components/ai-structured-output/index.ts +10 -0
  122. package/src/components/ai-structured-output/meta.ts +18 -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/meter/index.ts +8 -0
  128. package/src/components/meter/meta.ts +20 -0
  129. package/src/components/meter/meter.tsx +219 -0
  130. package/src/components/metric-delta/index.ts +6 -0
  131. package/src/components/metric-delta/meta.ts +18 -0
  132. package/src/components/metric-delta/metric-delta.tsx +180 -0
  133. package/src/components/progress/progress.tsx +3 -0
  134. package/src/components/record-diff/index.ts +10 -0
  135. package/src/components/record-diff/meta.ts +19 -0
  136. package/src/components/record-diff/record-diff.tsx +341 -0
  137. package/src/components/spinner/spinner.tsx +5 -0
  138. package/src/components/tags-input/index.ts +1 -0
  139. package/src/components/tags-input/meta.ts +23 -0
  140. package/src/components/tags-input/tags-input.tsx +300 -0
  141. package/src/index.ts +10 -0
  142. package/src/registry/components.ts +20 -0
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 LibName contributors
3
+ Copyright (c) 2026 Dowel contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md ADDED
@@ -0,0 +1,193 @@
1
+ <div align="center">
2
+
3
+ # Dowel
4
+
5
+ ### Source-first React components for SaaS and AI products
6
+
7
+ **You install the code, not a dependency.**
8
+
9
+ [![npm](https://img.shields.io/npm/v/@dowel-ui/react?color=5b5bd6&label=%40dowel-ui%2Freact)](https://www.npmjs.com/package/@dowel-ui/react)
10
+ [![license](https://img.shields.io/npm/l/@dowel-ui/react?color=5b5bd6)](https://github.com/aqkprogrammer/dowel-ui/blob/main/LICENSE)
11
+ [![types](https://img.shields.io/badge/types-included-5b5bd6)](https://www.typescriptlang.org)
12
+
13
+ [**Documentation**](https://dowel-eight.vercel.app) · [**Components**](https://dowel-eight.vercel.app/docs/components) · [**GitHub**](https://github.com/aqkprogrammer/dowel-ui)
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ A dowel is the hidden pin that joins two pieces of wood without a visible
20
+ fastener. That is the idea here: components that fit together, hold, and then
21
+ get out of your way.
22
+
23
+ ```bash
24
+ npx @dowel-ui/cli init
25
+ npx @dowel-ui/cli add button
26
+ ```
27
+
28
+ That second command writes `button.tsx` into your project. Open it. Change it.
29
+ It is your file now — there is no package standing between you and the markup.
30
+
31
+ ---
32
+
33
+ ## Why another component library
34
+
35
+ Most libraries hand you a black box and a theming API. When the design calls for
36
+ something the API did not anticipate, you fight it, wrap it, or override it with
37
+ `!important`.
38
+
39
+ Dowel gives you the source instead.
40
+
41
+ | | Dowel | Typical library |
42
+ | -------------------- | ----------------------------- | ---------------------------- |
43
+ | Where the code lives | **Your repo** | `node_modules` |
44
+ | Changing a component | **Edit the file** | Props, overrides, forks |
45
+ | Upgrades | **You choose, per component** | All at once, or not at all |
46
+ | Reading the source | **It is right there** | Sourcemaps, if you are lucky |
47
+ | Runtime you ship | **Only what you used** | The library |
48
+
49
+ You can still `npm install @dowel-ui/react` and import from it — that path
50
+ works, and is the fastest way to try things. Most people move to the CLI once
51
+ they want to change something.
52
+
53
+ ---
54
+
55
+ ## What is in it
56
+
57
+ **56 components** and **8 blocks**, every one keyboard-operable and audited for
58
+ contrast.
59
+
60
+ **AI** — the reason this library exists
61
+ Conversation · Message · Response · Prompt Input · Tool Call · Reasoning ·
62
+ Sources · Model Selector · Token Usage · Agent Status · **Agent Plan** ·
63
+ **Approval Request** · **Action Ledger** · **Structured Output** ·
64
+ **Inline Completion**
65
+
66
+ **Forms**
67
+ Input · Label · Checkbox · Radio Group · Switch · Slider · Select · Combobox ·
68
+ Form · Calendar · Date Picker · **Tags Input** · **File Upload**
69
+
70
+ **Overlays**
71
+ Dialog · Sheet · Drawer · Popover · Tooltip · Dropdown Menu
72
+
73
+ **Data**
74
+ Table · Data Table · Accordion · Activity Feed · Code Block · **Metric Delta** ·
75
+ **Record Diff**
76
+
77
+ **Feedback**
78
+ Alert · Toast · Progress · **Meter** · Skeleton · Spinner · Empty State
79
+
80
+ **Navigation & layout**
81
+ Tabs · Command · Pagination · Card · Badge · Avatar · Button · Separator
82
+
83
+ ---
84
+
85
+ ## The AI components
86
+
87
+ Most "AI component libraries" ship a chat transcript and stop. Real AI features
88
+ inside real software are extraction, enrichment, autofill and agents that
89
+ _change things_ — and those need surfaces nobody else provides.
90
+
91
+ **`ai-agent-plan` + `ai-approval-request` + `ai-action-ledger`** — the whole
92
+ sequence, which no other library covers: what the agent intends, the gate where
93
+ you approve it (after correcting the arguments it got wrong), and the record of
94
+ what it actually did.
95
+
96
+ **`ai-action-ledger`** — what the agent actually did, and what can be undone.
97
+ Everyone ships approval _before_ a tool runs. Nothing ships the part after,
98
+ where a deletion can be reverted, a refund can only be offset by another
99
+ transaction, and a sent email cannot be taken back at all. Hiding those three
100
+ behind one "Undo" button is a lie you discover after clicking.
101
+
102
+ **`ai-structured-output`** — an object arriving field by field, with the layout
103
+ reserved up front so nothing jumps as it fills in.
104
+
105
+ **`ai-inline-completion`** — ghost text in a real textarea. Tab accepts,
106
+ Alt+Right takes a word, and Escape always gives Tab back to focus management, so
107
+ a keyboard user is never trapped in the field.
108
+
109
+ ---
110
+
111
+ ## Blocks
112
+
113
+ Whole sections, assembled from components. Installing one brings everything it
114
+ is built from:
115
+
116
+ ```bash
117
+ npx @dowel-ui/cli add ai-chat
118
+ # ✓ Added ai-conversation, ai-message, select, ai-model-selector,
119
+ # ai-prompt-input, ai-reasoning, ai-response, ai-sources, ai-token-usage,
120
+ # ai-tool, spinner, button, empty-state, ai-chat
121
+ ```
122
+
123
+ Login · Signup · Forgot Password · Dashboard · Admin Users · Settings ·
124
+ Pricing · AI Chat
125
+
126
+ ---
127
+
128
+ ## Theming
129
+
130
+ Two tiers of design tokens, in plain CSS. No config file, no JavaScript theme
131
+ object.
132
+
133
+ ```css
134
+ :root {
135
+ --primary: oklch(0.55 0.2 275);
136
+ --radius-scale: 1; /* one knob re-proportions every corner in the system */
137
+ }
138
+ ```
139
+
140
+ Seven presets ship with it, and every one passes **WCAG AA contrast in both
141
+ light and dark** — verified by an audit that checks 322 colour pairs across 14
142
+ schemes on every commit, not by eye.
143
+
144
+ ---
145
+
146
+ ## Accessibility is not a checklist here
147
+
148
+ Every component is tested for behaviour, not appearance. A few things that fell
149
+ out of taking it seriously:
150
+
151
+ - `Meter` uses `role="meter"`, not `progressbar` — a level that may never move
152
+ is a different thing from a task heading for completion, and screen readers
153
+ say them differently.
154
+ - `MetricDelta` never puts meaning in colour alone. Rising churn is not good
155
+ news, and a red triangle is not information.
156
+ - Every pointer gesture has a keyboard equivalent, or the component was not
157
+ built. One candidate was dropped for failing exactly that test.
158
+
159
+ ---
160
+
161
+ ## Requirements
162
+
163
+ React 19 · TypeScript · Tailwind CSS v4
164
+
165
+ ---
166
+
167
+ ## Install
168
+
169
+ ```bash
170
+ # The CLI — writes components into your project as source
171
+ npx @dowel-ui/cli init
172
+
173
+ # Or import from the package
174
+ npm install @dowel-ui/react
175
+ ```
176
+
177
+ ```tsx
178
+ import { Button } from "@dowel-ui/react";
179
+
180
+ export function Save() {
181
+ return <Button variant="primary">Save changes</Button>;
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ <div align="center">
188
+
189
+ [**Read the docs →**](https://dowel-eight.vercel.app)
190
+
191
+ MIT licensed
192
+
193
+ </div>
@@ -0,0 +1,77 @@
1
+ import { Collapsible } from "radix-ui";
2
+ import { VariantProps } from "class-variance-authority";
3
+ import { ComponentPropsWithRef, ReactNode } from "react";
4
+ //#region src/components/ai-action-ledger/ai-action-ledger.d.ts
5
+ /**
6
+ * What an agent actually did, and what can be undone.
7
+ *
8
+ * Every AI component library stops at the conversation boundary: approve a tool
9
+ * call before it runs, then treat whatever it did to the database as the
10
+ * application's problem. But the thing that blocks agents from getting write
11
+ * access in real products is not "did I approve this", it is "it did the wrong
12
+ * thing, now what".
13
+ *
14
+ * The load-bearing idea is that undo is not uniform. Deleting a row can be
15
+ * reverted. A refund can be compensated by another transaction, which is not
16
+ * the same as never having happened. A sent email cannot be taken back at all.
17
+ * Presenting all three behind one "Undo" button is a lie the user only
18
+ * discovers after clicking, so reversibility is a required field and the
19
+ * affordance follows from it.
20
+ *
21
+ * This renders and selects. It performs nothing — `onRevert` receives the
22
+ * chosen actions and the application decides what that means.
23
+ */
24
+ type Reversibility = "revertible" | "compensable" | "irreversible";
25
+ type ActionStatus = "applied" | "reverting" | "reverted" | "failed";
26
+ interface LedgerAction {
27
+ id: string;
28
+ /** What was done, in the user's language: "Deleted 3 contacts". */
29
+ summary: string;
30
+ reversibility: Reversibility;
31
+ status: ActionStatus;
32
+ /** What the action touched, for grouping and scanning. */
33
+ target?: string;
34
+ timestamp?: string;
35
+ /** Why a revert failed. Shown only when status is "failed". */
36
+ error?: string;
37
+ }
38
+ declare const ledgerEntryVariants: (props?: ({
39
+ status?: "applied" | "reverting" | "reverted" | "failed" | null | undefined;
40
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
41
+ interface ActionLedgerProps extends Omit<ComponentPropsWithRef<"div">, "onSelect"> {
42
+ actions: LedgerAction[];
43
+ /** Receives the selected actions. The application performs the revert. */
44
+ onRevert?: (actions: LedgerAction[]) => void;
45
+ children?: ReactNode;
46
+ }
47
+ declare function ActionLedger({ className, actions, onRevert, children, ...props }: ActionLedgerProps): import("react").JSX.Element;
48
+ /**
49
+ * Selection controls and the revert action.
50
+ *
51
+ * The count is stated on the button rather than beside it, so the accessible
52
+ * name says what pressing it will do.
53
+ */
54
+ declare function ActionLedgerToolbar({ className, ...props }: ComponentPropsWithRef<"div">): import("react").JSX.Element;
55
+ interface ActionLedgerEntryProps extends Omit<ComponentPropsWithRef<"li">, "children">, VariantProps<typeof ledgerEntryVariants> {
56
+ action: LedgerAction;
57
+ /** The payload inspector. Collapsed, because it is provenance not content. */
58
+ children?: ReactNode;
59
+ }
60
+ declare function ActionLedgerEntry({ className, action, children, ...props }: ActionLedgerEntryProps): import("react").JSX.Element;
61
+ /** The list wrapper. A real list, so its length is announced. */
62
+ declare function ActionLedgerList({ className, ...props }: ComponentPropsWithRef<"ul">): import("react").JSX.Element;
63
+ /** Collapsed payload for one entry: the arguments, the result, the diff. */
64
+ declare function ActionLedgerPayload({ className, label, children, ...props }: ComponentPropsWithRef<typeof Collapsible.Root> & {
65
+ label?: string;
66
+ }): import("react").JSX.Element;
67
+ /**
68
+ * A summary of what is selected and what it will and will not undo.
69
+ *
70
+ * This exists because "Undo 4 selected" is not enough information when one of
71
+ * the four can only be compensated. Saying so before the click is the whole
72
+ * difference between an honest control and a misleading one.
73
+ */
74
+ declare function ActionLedgerSelectionSummary({ className, ...props }: ComponentPropsWithRef<"p">): import("react").JSX.Element | null;
75
+ //#endregion
76
+ export { ActionLedger, ActionLedgerEntry, ActionLedgerEntryProps, ActionLedgerList, ActionLedgerPayload, ActionLedgerProps, ActionLedgerSelectionSummary, ActionLedgerToolbar, ActionStatus, LedgerAction, Reversibility, ledgerEntryVariants };
77
+ //# sourceMappingURL=ai-action-ledger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-action-ledger.d.ts","names":[],"sources":["../../../src/components/ai-action-ledger/ai-action-ledger.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;KAqCY;KAEA;UAEK;EACf;;EAEA;EACA,eAAe;EACf,QAAQ;;EAER;EACA;;EAEA;;cAqBI,sBAAmB;;6CAUvB;UAsBe,0BAA0B,KAAK;EAC9C,SAAS;;EAET,YAAY,SAAS;EACrB,WAAW;;iBAGG,eACd,WACA,SACA,UACA,aACG,SACF,oCAAiB,IAAA;;;;;;;iBAmDJ,sBAAsB,cAAc,SAAS,+CAA4B,IAAA;UAiDxE,+BAEb,KAAK,0CACL,oBAAoB;EACtB,QAAQ;;EAER,WAAW;;iBAGG,oBACd,WACA,QACA,aACG,SACF,yCAAsB,IAAA;;iBA8ET,mBAAmB,cAAc,SAAS,8CAA2B,IAAA;;iBAWrE,sBACd,WACA,OACA,aACG,SACF,6BAA6B,YAAqB;EAAU;oBAAgB,IAAA;;;;;;;;iBA2B/D,+BACd,cACG,SACF,6CAA0B,IAAA"}
@@ -0,0 +1,224 @@
1
+ "use client";
2
+ import { focusRing } from "../../lib/styles.js";
3
+ import { cn } from "../../lib/utils.js";
4
+ import { Collapsible } from "radix-ui";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { cva } from "class-variance-authority";
7
+ import { createContext, useContext, useId, useMemo, useState } from "react";
8
+ //#region src/components/ai-action-ledger/ai-action-ledger.tsx
9
+ const REVERSIBILITY_LABEL = {
10
+ revertible: "Can be undone",
11
+ compensable: "Can be offset, not undone",
12
+ irreversible: "Cannot be undone"
13
+ };
14
+ const STATUS_LABEL = {
15
+ applied: "Applied",
16
+ reverting: "Reverting",
17
+ reverted: "Reverted",
18
+ failed: "Revert failed"
19
+ };
20
+ /** Only an applied action can be selected — the rest are already resolved. */
21
+ function isSelectable(action) {
22
+ return action.status === "applied" && action.reversibility !== "irreversible";
23
+ }
24
+ const ledgerEntryVariants = cva("rounded-lg border text-sm transition-colors", {
25
+ variants: { status: {
26
+ applied: "border-border bg-card",
27
+ reverting: "border-info/30 bg-info/5",
28
+ reverted: "border-border bg-muted/40",
29
+ failed: "border-destructive/40 bg-destructive/5"
30
+ } },
31
+ defaultVariants: { status: "applied" }
32
+ });
33
+ const LedgerContext = createContext(null);
34
+ function useLedgerContext(component) {
35
+ const context = useContext(LedgerContext);
36
+ if (!context) throw new Error(`${component} must be rendered inside <ActionLedger>.`);
37
+ return context;
38
+ }
39
+ function ActionLedger({ className, actions, onRevert, children, ...props }) {
40
+ const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
41
+ const selectableIds = useMemo(() => actions.filter(isSelectable).map((action) => action.id), [actions]);
42
+ const context = useMemo(() => ({
43
+ actions,
44
+ selected,
45
+ selectableIds,
46
+ onRevert,
47
+ toggle: (id) => {
48
+ setSelected((current) => {
49
+ const next = new Set(current);
50
+ if (next.has(id)) next.delete(id);
51
+ else next.add(id);
52
+ return next;
53
+ });
54
+ },
55
+ selectAll: () => {
56
+ setSelected(new Set(selectableIds));
57
+ },
58
+ clear: () => {
59
+ setSelected(/* @__PURE__ */ new Set());
60
+ }
61
+ }), [
62
+ actions,
63
+ selected,
64
+ selectableIds,
65
+ onRevert
66
+ ]);
67
+ return /* @__PURE__ */ jsx(LedgerContext.Provider, {
68
+ value: context,
69
+ children: /* @__PURE__ */ jsx("div", {
70
+ "data-slot": "action-ledger",
71
+ className: cn("flex flex-col gap-3", className),
72
+ ...props,
73
+ children
74
+ })
75
+ });
76
+ }
77
+ /**
78
+ * Selection controls and the revert action.
79
+ *
80
+ * The count is stated on the button rather than beside it, so the accessible
81
+ * name says what pressing it will do.
82
+ */
83
+ function ActionLedgerToolbar({ className, ...props }) {
84
+ const { selected, selectableIds, actions, selectAll, clear, onRevert } = useLedgerContext("ActionLedgerToolbar");
85
+ const count = selected.size;
86
+ const allSelected = selectableIds.length > 0 && count === selectableIds.length;
87
+ return /* @__PURE__ */ jsxs("div", {
88
+ "data-slot": "action-ledger-toolbar",
89
+ className: cn("flex flex-wrap items-center gap-2", className),
90
+ ...props,
91
+ children: [/* @__PURE__ */ jsx("button", {
92
+ type: "button",
93
+ disabled: selectableIds.length === 0,
94
+ onClick: allSelected ? clear : selectAll,
95
+ className: cn("rounded-md border border-input bg-background px-2.5 py-1 text-xs font-medium", "transition-colors hover:bg-accent hover:text-accent-foreground", "disabled:pointer-events-none disabled:opacity-50", focusRing),
96
+ children: allSelected ? "Clear selection" : `Select all ${String(selectableIds.length)} undoable`
97
+ }), /* @__PURE__ */ jsx("button", {
98
+ type: "button",
99
+ "data-slot": "action-ledger-revert",
100
+ disabled: count === 0,
101
+ onClick: () => {
102
+ onRevert?.(actions.filter((action) => selected.has(action.id)));
103
+ },
104
+ className: cn("rounded-md bg-primary px-2.5 py-1 text-xs font-medium text-primary-foreground", "transition-colors hover:bg-primary-hover", "disabled:pointer-events-none disabled:opacity-50", focusRing),
105
+ children: count === 0 ? "Undo selected" : `Undo ${String(count)} selected`
106
+ })]
107
+ });
108
+ }
109
+ function ActionLedgerEntry({ className, action, children, ...props }) {
110
+ const { selected, toggle } = useLedgerContext("ActionLedgerEntry");
111
+ const checkboxId = useId();
112
+ const selectable = isSelectable(action);
113
+ const isSelected = selected.has(action.id);
114
+ return /* @__PURE__ */ jsx("li", {
115
+ "data-slot": "action-ledger-entry",
116
+ "data-status": action.status,
117
+ "data-reversibility": action.reversibility,
118
+ className: cn(ledgerEntryVariants({ status: action.status }), className),
119
+ ...props,
120
+ children: /* @__PURE__ */ jsxs("div", {
121
+ className: "flex items-start gap-3 p-3",
122
+ children: [/* @__PURE__ */ jsx("input", {
123
+ type: "checkbox",
124
+ id: checkboxId,
125
+ disabled: !selectable,
126
+ checked: isSelected,
127
+ onChange: () => {
128
+ toggle(action.id);
129
+ },
130
+ className: cn("mt-0.5 size-4 shrink-0 rounded border-input", "disabled:cursor-not-allowed disabled:opacity-40", focusRing)
131
+ }), /* @__PURE__ */ jsxs("div", {
132
+ className: "flex min-w-0 flex-1 flex-col gap-1",
133
+ children: [
134
+ /* @__PURE__ */ jsx("label", {
135
+ htmlFor: checkboxId,
136
+ className: cn("font-medium", !selectable && "opacity-70"),
137
+ children: action.summary
138
+ }),
139
+ /* @__PURE__ */ jsxs("p", {
140
+ className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-muted-foreground",
141
+ children: [
142
+ /* @__PURE__ */ jsx("span", {
143
+ "data-slot": "action-ledger-reversibility",
144
+ children: REVERSIBILITY_LABEL[action.reversibility]
145
+ }),
146
+ /* @__PURE__ */ jsx("span", {
147
+ "aria-hidden": "true",
148
+ children: "·"
149
+ }),
150
+ /* @__PURE__ */ jsx("span", {
151
+ "data-slot": "action-ledger-status",
152
+ children: STATUS_LABEL[action.status]
153
+ }),
154
+ action.target ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
155
+ "aria-hidden": "true",
156
+ children: "·"
157
+ }), /* @__PURE__ */ jsx("span", { children: action.target })] }) : null,
158
+ action.timestamp ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
159
+ "aria-hidden": "true",
160
+ children: "·"
161
+ }), /* @__PURE__ */ jsx("time", {
162
+ dateTime: action.timestamp,
163
+ children: action.timestamp
164
+ })] }) : null
165
+ ]
166
+ }),
167
+ action.status === "failed" && action.error ? /* @__PURE__ */ jsx("p", {
168
+ "data-slot": "action-ledger-error",
169
+ className: "text-xs text-destructive",
170
+ children: action.error
171
+ }) : null,
172
+ children
173
+ ]
174
+ })]
175
+ })
176
+ });
177
+ }
178
+ /** The list wrapper. A real list, so its length is announced. */
179
+ function ActionLedgerList({ className, ...props }) {
180
+ return /* @__PURE__ */ jsx("ul", {
181
+ "data-slot": "action-ledger-list",
182
+ className: cn("flex list-none flex-col gap-2", className),
183
+ ...props
184
+ });
185
+ }
186
+ /** Collapsed payload for one entry: the arguments, the result, the diff. */
187
+ function ActionLedgerPayload({ className, label = "Details", children, ...props }) {
188
+ return /* @__PURE__ */ jsxs(Collapsible.Root, {
189
+ "data-slot": "action-ledger-payload",
190
+ className: cn("mt-1", className),
191
+ ...props,
192
+ children: [/* @__PURE__ */ jsx(Collapsible.Trigger, {
193
+ className: cn("rounded-md text-xs text-muted-foreground transition-colors hover:text-foreground", focusRing),
194
+ children: label
195
+ }), /* @__PURE__ */ jsx(Collapsible.Content, {
196
+ className: "pt-2",
197
+ children
198
+ })]
199
+ });
200
+ }
201
+ /**
202
+ * A summary of what is selected and what it will and will not undo.
203
+ *
204
+ * This exists because "Undo 4 selected" is not enough information when one of
205
+ * the four can only be compensated. Saying so before the click is the whole
206
+ * difference between an honest control and a misleading one.
207
+ */
208
+ function ActionLedgerSelectionSummary({ className, ...props }) {
209
+ const { actions, selected } = useLedgerContext("ActionLedgerSelectionSummary");
210
+ const chosen = actions.filter((action) => selected.has(action.id));
211
+ const compensable = chosen.filter((a) => a.reversibility === "compensable").length;
212
+ if (chosen.length === 0) return null;
213
+ return /* @__PURE__ */ jsxs("p", {
214
+ "data-slot": "action-ledger-selection-summary",
215
+ "aria-live": "polite",
216
+ className: cn("text-xs text-muted-foreground", className),
217
+ ...props,
218
+ children: [`${String(chosen.length)} selected`, compensable > 0 ? `, of which ${String(compensable)} can only be offset by a further action, not undone` : ""]
219
+ });
220
+ }
221
+ //#endregion
222
+ export { ActionLedger, ActionLedgerEntry, ActionLedgerList, ActionLedgerPayload, ActionLedgerSelectionSummary, ActionLedgerToolbar, ledgerEntryVariants };
223
+
224
+ //# sourceMappingURL=ai-action-ledger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-action-ledger.js","names":["CollapsiblePrimitive"],"sources":["../../../src/components/ai-action-ledger/ai-action-ledger.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Collapsible as CollapsiblePrimitive } from \"radix-ui\";\nimport {\n createContext,\n useContext,\n useId,\n useMemo,\n useState,\n type ComponentPropsWithRef,\n type ReactNode,\n} from \"react\";\n\nimport { focusRing } from \"@/lib/styles\";\nimport { cn } from \"@/lib/utils\";\n\n/**\n * What an agent actually did, and what can be undone.\n *\n * Every AI component library stops at the conversation boundary: approve a tool\n * call before it runs, then treat whatever it did to the database as the\n * application's problem. But the thing that blocks agents from getting write\n * access in real products is not \"did I approve this\", it is \"it did the wrong\n * thing, now what\".\n *\n * The load-bearing idea is that undo is not uniform. Deleting a row can be\n * reverted. A refund can be compensated by another transaction, which is not\n * the same as never having happened. A sent email cannot be taken back at all.\n * Presenting all three behind one \"Undo\" button is a lie the user only\n * discovers after clicking, so reversibility is a required field and the\n * affordance follows from it.\n *\n * This renders and selects. It performs nothing — `onRevert` receives the\n * chosen actions and the application decides what that means.\n */\n\nexport type Reversibility = \"revertible\" | \"compensable\" | \"irreversible\";\n\nexport type ActionStatus = \"applied\" | \"reverting\" | \"reverted\" | \"failed\";\n\nexport interface LedgerAction {\n id: string;\n /** What was done, in the user's language: \"Deleted 3 contacts\". */\n summary: string;\n reversibility: Reversibility;\n status: ActionStatus;\n /** What the action touched, for grouping and scanning. */\n target?: string;\n timestamp?: string;\n /** Why a revert failed. Shown only when status is \"failed\". */\n error?: string;\n}\n\nconst REVERSIBILITY_LABEL: Record<Reversibility, string> = {\n revertible: \"Can be undone\",\n compensable: \"Can be offset, not undone\",\n irreversible: \"Cannot be undone\",\n};\n\nconst STATUS_LABEL: Record<ActionStatus, string> = {\n applied: \"Applied\",\n reverting: \"Reverting\",\n reverted: \"Reverted\",\n failed: \"Revert failed\",\n};\n\n/** Only an applied action can be selected — the rest are already resolved. */\nfunction isSelectable(action: LedgerAction): boolean {\n return action.status === \"applied\" && action.reversibility !== \"irreversible\";\n}\n\nconst ledgerEntryVariants = cva(\"rounded-lg border text-sm transition-colors\", {\n variants: {\n status: {\n applied: \"border-border bg-card\",\n reverting: \"border-info/30 bg-info/5\",\n reverted: \"border-border bg-muted/40\",\n failed: \"border-destructive/40 bg-destructive/5\",\n },\n },\n defaultVariants: { status: \"applied\" },\n});\n\ninterface LedgerContextValue {\n actions: LedgerAction[];\n selected: Set<string>;\n toggle: (id: string) => void;\n selectAll: () => void;\n clear: () => void;\n selectableIds: string[];\n onRevert?: (actions: LedgerAction[]) => void;\n}\n\nconst LedgerContext = createContext<LedgerContextValue | null>(null);\n\nfunction useLedgerContext(component: string): LedgerContextValue {\n const context = useContext(LedgerContext);\n if (!context) {\n throw new Error(`${component} must be rendered inside <ActionLedger>.`);\n }\n return context;\n}\n\nexport interface ActionLedgerProps extends Omit<ComponentPropsWithRef<\"div\">, \"onSelect\"> {\n actions: LedgerAction[];\n /** Receives the selected actions. The application performs the revert. */\n onRevert?: (actions: LedgerAction[]) => void;\n children?: ReactNode;\n}\n\nexport function ActionLedger({\n className,\n actions,\n onRevert,\n children,\n ...props\n}: ActionLedgerProps) {\n const [selected, setSelected] = useState<Set<string>>(new Set());\n\n const selectableIds = useMemo(\n () => actions.filter(isSelectable).map((action) => action.id),\n [actions],\n );\n\n const context = useMemo<LedgerContextValue>(\n () => ({\n actions,\n selected,\n selectableIds,\n onRevert,\n toggle: (id: string) => {\n setSelected((current) => {\n const next = new Set(current);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n },\n selectAll: () => {\n setSelected(new Set(selectableIds));\n },\n clear: () => {\n setSelected(new Set());\n },\n }),\n [actions, selected, selectableIds, onRevert],\n );\n\n return (\n <LedgerContext.Provider value={context}>\n <div\n data-slot=\"action-ledger\"\n className={cn(\"flex flex-col gap-3\", className)}\n {...props}\n >\n {children}\n </div>\n </LedgerContext.Provider>\n );\n}\n\n/**\n * Selection controls and the revert action.\n *\n * The count is stated on the button rather than beside it, so the accessible\n * name says what pressing it will do.\n */\nexport function ActionLedgerToolbar({ className, ...props }: ComponentPropsWithRef<\"div\">) {\n const { selected, selectableIds, actions, selectAll, clear, onRevert } =\n useLedgerContext(\"ActionLedgerToolbar\");\n\n const count = selected.size;\n const allSelected = selectableIds.length > 0 && count === selectableIds.length;\n\n return (\n <div\n data-slot=\"action-ledger-toolbar\"\n className={cn(\"flex flex-wrap items-center gap-2\", className)}\n {...props}\n >\n <button\n type=\"button\"\n disabled={selectableIds.length === 0}\n onClick={allSelected ? clear : selectAll}\n className={cn(\n \"rounded-md border border-input bg-background px-2.5 py-1 text-xs font-medium\",\n \"transition-colors hover:bg-accent hover:text-accent-foreground\",\n \"disabled:pointer-events-none disabled:opacity-50\",\n focusRing,\n )}\n >\n {allSelected\n ? \"Clear selection\"\n : `Select all ${String(selectableIds.length)} undoable`}\n </button>\n\n <button\n type=\"button\"\n data-slot=\"action-ledger-revert\"\n disabled={count === 0}\n onClick={() => {\n onRevert?.(actions.filter((action) => selected.has(action.id)));\n }}\n className={cn(\n \"rounded-md bg-primary px-2.5 py-1 text-xs font-medium text-primary-foreground\",\n \"transition-colors hover:bg-primary-hover\",\n \"disabled:pointer-events-none disabled:opacity-50\",\n focusRing,\n )}\n >\n {count === 0 ? \"Undo selected\" : `Undo ${String(count)} selected`}\n </button>\n </div>\n );\n}\n\nexport interface ActionLedgerEntryProps\n extends\n Omit<ComponentPropsWithRef<\"li\">, \"children\">,\n VariantProps<typeof ledgerEntryVariants> {\n action: LedgerAction;\n /** The payload inspector. Collapsed, because it is provenance not content. */\n children?: ReactNode;\n}\n\nexport function ActionLedgerEntry({\n className,\n action,\n children,\n ...props\n}: ActionLedgerEntryProps) {\n const { selected, toggle } = useLedgerContext(\"ActionLedgerEntry\");\n const checkboxId = useId();\n const selectable = isSelectable(action);\n const isSelected = selected.has(action.id);\n\n return (\n <li\n data-slot=\"action-ledger-entry\"\n data-status={action.status}\n data-reversibility={action.reversibility}\n className={cn(ledgerEntryVariants({ status: action.status }), className)}\n {...props}\n >\n <div className=\"flex items-start gap-3 p-3\">\n {/* A native checkbox: this is a list of things to act on, and the\n selection has to survive without JavaScript-driven roles. */}\n <input\n type=\"checkbox\"\n id={checkboxId}\n disabled={!selectable}\n checked={isSelected}\n onChange={() => {\n toggle(action.id);\n }}\n className={cn(\n \"mt-0.5 size-4 shrink-0 rounded border-input\",\n \"disabled:cursor-not-allowed disabled:opacity-40\",\n focusRing,\n )}\n />\n\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">\n <label\n htmlFor={checkboxId}\n className={cn(\"font-medium\", !selectable && \"opacity-70\")}\n >\n {action.summary}\n </label>\n\n <p className=\"flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-muted-foreground\">\n {/* Reversibility in words, always. It decides whether the undo\n button means anything, so it cannot be a colour or an icon. */}\n <span data-slot=\"action-ledger-reversibility\">\n {REVERSIBILITY_LABEL[action.reversibility]}\n </span>\n <span aria-hidden=\"true\">·</span>\n <span data-slot=\"action-ledger-status\">{STATUS_LABEL[action.status]}</span>\n {action.target ? (\n <>\n <span aria-hidden=\"true\">·</span>\n <span>{action.target}</span>\n </>\n ) : null}\n {action.timestamp ? (\n <>\n <span aria-hidden=\"true\">·</span>\n <time dateTime={action.timestamp}>{action.timestamp}</time>\n </>\n ) : null}\n </p>\n\n {/* A failed revert is the state people most need to understand, so\n the reason is shown rather than hidden behind the inspector. */}\n {action.status === \"failed\" && action.error ? (\n <p data-slot=\"action-ledger-error\" className=\"text-xs text-destructive\">\n {action.error}\n </p>\n ) : null}\n\n {children}\n </div>\n </div>\n </li>\n );\n}\n\n/** The list wrapper. A real list, so its length is announced. */\nexport function ActionLedgerList({ className, ...props }: ComponentPropsWithRef<\"ul\">) {\n return (\n <ul\n data-slot=\"action-ledger-list\"\n className={cn(\"flex list-none flex-col gap-2\", className)}\n {...props}\n />\n );\n}\n\n/** Collapsed payload for one entry: the arguments, the result, the diff. */\nexport function ActionLedgerPayload({\n className,\n label = \"Details\",\n children,\n ...props\n}: ComponentPropsWithRef<typeof CollapsiblePrimitive.Root> & { label?: string }) {\n return (\n <CollapsiblePrimitive.Root\n data-slot=\"action-ledger-payload\"\n className={cn(\"mt-1\", className)}\n {...props}\n >\n <CollapsiblePrimitive.Trigger\n className={cn(\n \"rounded-md text-xs text-muted-foreground transition-colors hover:text-foreground\",\n focusRing,\n )}\n >\n {label}\n </CollapsiblePrimitive.Trigger>\n <CollapsiblePrimitive.Content className=\"pt-2\">{children}</CollapsiblePrimitive.Content>\n </CollapsiblePrimitive.Root>\n );\n}\n\n/**\n * A summary of what is selected and what it will and will not undo.\n *\n * This exists because \"Undo 4 selected\" is not enough information when one of\n * the four can only be compensated. Saying so before the click is the whole\n * difference between an honest control and a misleading one.\n */\nexport function ActionLedgerSelectionSummary({\n className,\n ...props\n}: ComponentPropsWithRef<\"p\">) {\n const { actions, selected } = useLedgerContext(\"ActionLedgerSelectionSummary\");\n\n const chosen = actions.filter((action) => selected.has(action.id));\n const compensable = chosen.filter((a) => a.reversibility === \"compensable\").length;\n\n if (chosen.length === 0) return null;\n\n return (\n <p\n data-slot=\"action-ledger-selection-summary\"\n // Selection changes are user-driven and the wording matters, so it is\n // announced politely rather than silently updating under the button.\n aria-live=\"polite\"\n className={cn(\"text-xs text-muted-foreground\", className)}\n {...props}\n >\n {`${String(chosen.length)} selected`}\n {compensable > 0\n ? `, of which ${String(compensable)} can only be offset by a further action, not undone`\n : \"\"}\n </p>\n );\n}\n\nexport { ledgerEntryVariants };\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { ActionLedger, ActionLedgerEntry, ActionLedgerEntryProps, ActionLedgerList, ActionLedgerPayload, ActionLedgerProps, ActionLedgerSelectionSummary, ActionLedgerToolbar, ActionStatus, LedgerAction, Reversibility, ledgerEntryVariants } from "./ai-action-ledger.js";
2
+ export { ActionLedger, ActionLedgerEntry, type ActionLedgerEntryProps, ActionLedgerList, ActionLedgerPayload, type ActionLedgerProps, ActionLedgerSelectionSummary, ActionLedgerToolbar, type ActionStatus, type LedgerAction, type Reversibility, ledgerEntryVariants };
@@ -0,0 +1,2 @@
1
+ import { ActionLedger, ActionLedgerEntry, ActionLedgerList, ActionLedgerPayload, ActionLedgerSelectionSummary, ActionLedgerToolbar, ledgerEntryVariants } from "./ai-action-ledger.js";
2
+ export { ActionLedger, ActionLedgerEntry, ActionLedgerList, ActionLedgerPayload, ActionLedgerSelectionSummary, ActionLedgerToolbar, ledgerEntryVariants };
@@ -0,0 +1,17 @@
1
+ import { defineMeta } from "../../registry/schema.js";
2
+ //#region src/components/ai-action-ledger/meta.ts
3
+ const meta = defineMeta({
4
+ name: "ai-action-ledger",
5
+ title: "AI Action Ledger",
6
+ description: "What an agent actually did, classified by what can be undone.",
7
+ category: "ai",
8
+ status: "stable",
9
+ dependencies: ["class-variance-authority", "radix-ui"],
10
+ registryDependencies: [],
11
+ files: ["ai-action-ledger.tsx"],
12
+ a11y: "Reversibility is stated in words on every entry, never by colour or icon alone — it decides whether the undo control means anything, so it cannot be decoration. Selection uses native checkboxes with real labels, and the revert button carries the count in its accessible name so it says what pressing it will do. The selection summary is an aria-live region because the wording changes as the choice changes, and warns before the click when something can only be offset rather than undone."
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-action-ledger/meta.ts"],"sourcesContent":["import { defineMeta } from \"@/registry/schema\";\n\nexport const meta = defineMeta({\n name: \"ai-action-ledger\",\n title: \"AI Action Ledger\",\n description: \"What an agent actually did, classified by what can be undone.\",\n category: \"ai\",\n status: \"stable\",\n dependencies: [\"class-variance-authority\", \"radix-ui\"],\n registryDependencies: [],\n files: [\"ai-action-ledger.tsx\"],\n a11y:\n \"Reversibility is stated in words on every entry, never by colour or icon alone — it decides \" +\n \"whether the undo control means anything, so it cannot be decoration. Selection uses native \" +\n \"checkboxes with real labels, and the revert button carries the count in its accessible name \" +\n \"so it says what pressing it will do. The selection summary is an aria-live region because \" +\n \"the wording changes as the choice changes, and warns before the click when something can \" +\n \"only be offset rather than undone.\",\n});\n"],"mappings":";;AAEA,MAAa,OAAO,WAAW;CAC7B,MAAM;CACN,OAAO;CACP,aAAa;CACb,UAAU;CACV,QAAQ;CACR,cAAc,CAAC,4BAA4B,UAAU;CACrD,sBAAsB,CAAC;CACvB,OAAO,CAAC,sBAAsB;CAC9B,MACE;AAMJ,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { ComponentPropsWithRef, ReactNode } from "react";
2
+ //#region src/components/ai-agent-plan/ai-agent-plan.d.ts
3
+ /**
4
+ * What an agent intends to do, and how far through it is.
5
+ *
6
+ * Not a stepper. A wizard's steps are decided up front and never change; an
7
+ * agent's plan is a hypothesis it revises as it learns — it adds a step when a
8
+ * lookup fails, drops one that turned out to be unnecessary, and reorders when
9
+ * a dependency appears. Every stepper treats its step list as fixed, so a plan
10
+ * rendered in one either silently mutates under the reader or re-renders from
11
+ * scratch and loses their place.
12
+ *
13
+ * So revision is the feature here, not an edge case. When the plan changes, the
14
+ * change is announced — "the model added a step" is information, and watching a
15
+ * list quietly grow is not the same as being told.
16
+ *
17
+ * Approval is not here. Deciding whether a plan may run is a different
18
+ * component with a different shape; this one displays and reports.
19
+ */
20
+ type StepStatus = "pending" | "running" | "done" | "failed" | "skipped";
21
+ interface PlanStep {
22
+ id: string;
23
+ title: string;
24
+ status: StepStatus;
25
+ /** What the step will do, or what it found. Shown under the title. */
26
+ detail?: string;
27
+ /** Why it failed. Shown only when the status is "failed". */
28
+ error?: string;
29
+ /** One level of sub-steps. Deeper nesting is a tree, which this is not. */
30
+ steps?: PlanStep[];
31
+ }
32
+ interface AgentPlanProps extends Omit<ComponentPropsWithRef<"div">, "children"> {
33
+ steps: PlanStep[];
34
+ /** Names the plan, so the list is not an unlabelled sequence. */
35
+ label: string;
36
+ children?: ReactNode;
37
+ }
38
+ declare function AgentPlan({ className, steps, label, children, ...props }: AgentPlanProps): import("react").JSX.Element;
39
+ /** "Step 3 of 6" plus the overall state, in words. */
40
+ declare function AgentPlanSummary({ className, ...props }: ComponentPropsWithRef<"p">): import("react").JSX.Element;
41
+ declare function AgentPlanSteps({ className, ...props }: ComponentPropsWithRef<"ol">): import("react").JSX.Element;
42
+ interface AgentPlanStepProps extends Omit<ComponentPropsWithRef<"li">, "children"> {
43
+ step: PlanStep;
44
+ /** Set on sub-steps. Not part of the public API surface. */
45
+ nested?: boolean;
46
+ }
47
+ declare function AgentPlanStep({ className, step, nested, ...props }: AgentPlanStepProps): import("react").JSX.Element;
48
+ //#endregion
49
+ export { AgentPlan, AgentPlanProps, AgentPlanStep, AgentPlanStepProps, AgentPlanSteps, AgentPlanSummary, PlanStep, StepStatus };
50
+ //# sourceMappingURL=ai-agent-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-agent-plan.d.ts","names":[],"sources":["../../../src/components/ai-agent-plan/ai-agent-plan.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;KA+BY;UAEK;EACf;EACA;EACA,QAAQ;;EAER;;EAEA;;EAEA,QAAQ;;UAyCO,uBAAuB,KAAK;EAC3C,OAAO;;EAEP;EACA,WAAW;;iBAGG,YAAY,WAAW,OAAO,OAAO,aAAa,SAAS,iCAAc,IAAA;;iBAqDzE,mBAAmB,cAAc,SAAS,6CAA0B,IAAA;iBA2BpE,iBAAiB,cAAc,SAAS,8CAA2B,IAAA;UAkBlE,2BAA2B,KAAK;EAC/C,MAAM;;EAEN;;iBAGc,gBACd,WACA,MACA,WACG,SACF,qCAAkB,IAAA"}