api_binding_ui 1.1.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -394
- package/SKILL.md +50 -350
- package/dist/framework/contract.d.ts +268 -0
- package/dist/framework/engine.d.ts +88 -0
- package/dist/framework/expr.d.ts +34 -0
- package/dist/framework/loadCatalog.d.ts +6 -0
- package/dist/framework/names.d.ts +7 -0
- package/dist/framework/openapi.d.ts +7 -0
- package/dist/framework/runner.d.ts +36 -0
- package/dist/framework/schema.d.ts +22 -0
- package/dist/framework/store.d.ts +17 -0
- package/dist/framework/validate.d.ts +7 -0
- package/dist/index-3q1vx729.js +759 -0
- package/dist/index-3q1vx729.js.map +16 -0
- package/dist/index.d.ts +11 -29
- package/dist/index.js +348 -11932
- package/dist/index.js.map +14 -0
- package/dist/runtime/BindingProvider.d.ts +42 -0
- package/dist/runtime/BindingScreen.d.ts +23 -0
- package/dist/runtime/hooks.d.ts +22 -0
- package/dist/runtime/screenStore.d.ts +7 -0
- package/dist/studio/ApiPicker.d.ts +15 -0
- package/dist/studio/BindingStudio.d.ts +21 -0
- package/dist/studio/BindingWidget.d.ts +9 -0
- package/dist/studio/Collapse.d.ts +6 -0
- package/dist/studio/ComponentList.d.ts +10 -0
- package/dist/studio/FindAnything.d.ts +7 -0
- package/dist/studio/Inspector.d.ts +12 -0
- package/dist/studio/Navigator.d.ts +17 -0
- package/dist/studio/SettingsPanel.d.ts +15 -0
- package/dist/studio/Tip.d.ts +23 -0
- package/dist/studio/editors/ConsumeEditor.d.ts +4 -0
- package/dist/studio/editors/RequestInputs.d.ts +11 -0
- package/dist/studio/editors/ScopedEditor.d.ts +3 -0
- package/dist/studio/editors/SlotSection.d.ts +3 -0
- package/dist/studio/editors/SourceSelect.d.ts +10 -0
- package/dist/studio/editors/StepCard.d.ts +12 -0
- package/dist/studio/editors/TriggerEditor.d.ts +4 -0
- package/dist/studio/editors/types.d.ts +14 -0
- package/dist/studio/icons.d.ts +65 -0
- package/dist/studio/index.css +2021 -0
- package/dist/studio/index.d.ts +3 -0
- package/dist/studio/index.js +2806 -0
- package/dist/studio/index.js.map +33 -0
- package/dist/studio/useBindings.d.ts +20 -0
- package/dist/studio/useCatalog.d.ts +15 -0
- package/dist/studio/useGlide.d.ts +11 -0
- package/dist/studio/useSettings.d.ts +8 -0
- package/package.json +20 -14
- package/spec/FRAMEWORK.md +271 -0
- package/dist/api-binding-ui.css +0 -248
- package/dist/components/ApiBindingWorkspace.d.ts +0 -10
- package/dist/components/ApiMappings.d.ts +0 -21
- package/dist/components/BindApiButton.d.ts +0 -41
- package/dist/components/RequestPreview.d.ts +0 -7
- package/dist/components/SimulationDialog.d.ts +0 -8
- package/dist/components/ValidationDialog.d.ts +0 -8
- package/dist/components/WorkspaceContext.d.ts +0 -7
- package/dist/components/ui/AppGrid.d.ts +0 -27
- package/dist/components/ui/Badge.d.ts +0 -9
- package/dist/components/ui/Banner.d.ts +0 -8
- package/dist/components/ui/Button.d.ts +0 -31
- package/dist/components/ui/Card.d.ts +0 -14
- package/dist/components/ui/Dialog.d.ts +0 -61
- package/dist/components/ui/Icons.d.ts +0 -21
- package/dist/components/ui/Input.d.ts +0 -31
- package/dist/core/bindingContext.d.ts +0 -67
- package/dist/core/catalog.d.ts +0 -18
- package/dist/core/componentId.d.ts +0 -12
- package/dist/core/model.d.ts +0 -63
- package/dist/core/openapi.d.ts +0 -2
- package/dist/core/transport.d.ts +0 -33
- package/dist/core/validation.d.ts +0 -2
- package/dist/core/valueCoercion.d.ts +0 -17
- package/dist/hooks/useAppliedBinding.d.ts +0 -6
- package/dist/index.css +0 -248
- package/dist/style.css +0 -244
- package/dist/types.d.ts +0 -245
package/README.md
CHANGED
|
@@ -1,394 +1,74 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
#### TanStack Router (`src/routes/api-binding.$key.tsx`)
|
|
77
|
-
```tsx
|
|
78
|
-
import { createFileRoute } from "@tanstack/react-router";
|
|
79
|
-
import { ApiBindingWorkspace } from "api_binding_ui";
|
|
80
|
-
import "api_binding_ui/style.css";
|
|
81
|
-
|
|
82
|
-
export const Route = createFileRoute("/api-binding/$key")({
|
|
83
|
-
head: () => ({
|
|
84
|
-
meta: [
|
|
85
|
-
{ title: "API Binding Studio" },
|
|
86
|
-
{ name: "description", content: "Visual API mapping and simulation studio." },
|
|
87
|
-
],
|
|
88
|
-
}),
|
|
89
|
-
component: ApiBindingRouteView,
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
function ApiBindingRouteView() {
|
|
93
|
-
const { key } = Route.useParams();
|
|
94
|
-
return <ApiBindingWorkspace key={key} pageKey={key} />;
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
#### React Router (`src/App.tsx`)
|
|
99
|
-
```tsx
|
|
100
|
-
import { BrowserRouter, Routes, Route, useParams } from "react-router-dom";
|
|
101
|
-
import { ApiBindingWorkspace } from "api_binding_ui";
|
|
102
|
-
import "api_binding_ui/style.css";
|
|
103
|
-
|
|
104
|
-
function ApiBindingPage() {
|
|
105
|
-
const { key = "default" } = useParams();
|
|
106
|
-
return <ApiBindingWorkspace key={key} pageKey={key} />;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function App() {
|
|
110
|
-
return (
|
|
111
|
-
<BrowserRouter>
|
|
112
|
-
<Routes>
|
|
113
|
-
<Route path="/api-binding/:key" element={<ApiBindingPage />} />
|
|
114
|
-
{/* Application routes */}
|
|
115
|
-
</Routes>
|
|
116
|
-
</BrowserRouter>
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
---
|
|
122
|
-
|
|
123
|
-
### Step 2: Mount `<BindApiButton />` on Host Screens
|
|
124
|
-
|
|
125
|
-
Place `<BindApiButton />` inside your modal dialogs, slide-out drawers, form panels, or screen toolbars.
|
|
126
|
-
|
|
127
|
-
Supply a complete `ApiDefinition[]` catalog and a per-window `MappingFile` seed. For an OpenAPI file attached to an AI coding task, generate the static catalog from the attachment; the app does not need to store or parse YAML at runtime. If the host already has a parsed OpenAPI 3.0/3.1 object, it may use `buildCatalogFromOpenApi(parsedOpenApi)`. Neither catalog discovery nor semantic mapping inference happens automatically at runtime. Have the host AI generate high-confidence seeds using OpenAPI names, descriptions, tags and actual components; leave ambiguities editable. A `hook` string identifies a catalog operation; it does not create an executable hook.
|
|
128
|
-
|
|
129
|
-
#### Example A: Dialog with Data Grid Context
|
|
130
|
-
```tsx
|
|
131
|
-
import * as React from "react";
|
|
132
|
-
import { BindApiButton, type ApiDefinition, type MappingFile } from "api_binding_ui";
|
|
133
|
-
|
|
134
|
-
interface CustomerRecord {
|
|
135
|
-
customerId: number;
|
|
136
|
-
customerName: string;
|
|
137
|
-
accountNumber: string;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export function AddNotesModal({
|
|
141
|
-
open,
|
|
142
|
-
onClose,
|
|
143
|
-
selectedCustomers,
|
|
144
|
-
definitions,
|
|
145
|
-
mappingFile,
|
|
146
|
-
}: {
|
|
147
|
-
open: boolean;
|
|
148
|
-
onClose: () => void;
|
|
149
|
-
selectedCustomers: CustomerRecord[];
|
|
150
|
-
definitions: ApiDefinition[];
|
|
151
|
-
mappingFile: MappingFile;
|
|
152
|
-
}) {
|
|
153
|
-
if (!open) return null;
|
|
154
|
-
|
|
155
|
-
const noteTypeOptions = [
|
|
156
|
-
{ value: "1", label: "General Follow-up" },
|
|
157
|
-
{ value: "2", label: "Promise to Pay" },
|
|
158
|
-
];
|
|
159
|
-
|
|
160
|
-
const templateOptions = [
|
|
161
|
-
{
|
|
162
|
-
value: "tmpl-payment",
|
|
163
|
-
label: "Payment Reminder",
|
|
164
|
-
subject: "Pending statement follow-up",
|
|
165
|
-
description: "Contacted accounts payable regarding past-due invoices.",
|
|
166
|
-
},
|
|
167
|
-
];
|
|
168
|
-
|
|
169
|
-
return (
|
|
170
|
-
<div role="dialog" aria-labelledby="modal-heading" className="modal-container">
|
|
171
|
-
<h2 id="modal-heading">Add Customer Note</h2>
|
|
172
|
-
|
|
173
|
-
<div className="form-group">
|
|
174
|
-
<label htmlFor="notesType">Note Type</label>
|
|
175
|
-
<select id="notesType" name="notesType" required>
|
|
176
|
-
{noteTypeOptions.map((opt) => (
|
|
177
|
-
<option key={opt.value} value={opt.value}>
|
|
178
|
-
{opt.label}
|
|
179
|
-
</option>
|
|
180
|
-
))}
|
|
181
|
-
</select>
|
|
182
|
-
</div>
|
|
183
|
-
|
|
184
|
-
<div className="form-group">
|
|
185
|
-
<label htmlFor="subject">Subject</label>
|
|
186
|
-
<input id="subject" name="subject" required />
|
|
187
|
-
</div>
|
|
188
|
-
|
|
189
|
-
<div className="form-group">
|
|
190
|
-
<label htmlFor="notes">Description</label>
|
|
191
|
-
<textarea id="notes" name="notes" required />
|
|
192
|
-
</div>
|
|
193
|
-
|
|
194
|
-
<div className="modal-actions">
|
|
195
|
-
<button type="button" onClick={onClose}>
|
|
196
|
-
Cancel
|
|
197
|
-
</button>
|
|
198
|
-
<button type="submit">
|
|
199
|
-
Save Note
|
|
200
|
-
</button>
|
|
201
|
-
|
|
202
|
-
<BindApiButton
|
|
203
|
-
definitions={definitions}
|
|
204
|
-
mappingFile={mappingFile}
|
|
205
|
-
appId="collections"
|
|
206
|
-
windowId="worklist-add-notes"
|
|
207
|
-
source="Add Notes Dialog"
|
|
208
|
-
parent="Worklist Grid"
|
|
209
|
-
grid={{
|
|
210
|
-
gridId: "worklistUIGrid",
|
|
211
|
-
rows: selectedCustomers,
|
|
212
|
-
}}
|
|
213
|
-
options={{
|
|
214
|
-
notesType: noteTypeOptions,
|
|
215
|
-
template: templateOptions,
|
|
216
|
-
}}
|
|
217
|
-
/>
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
#### Example B: Standalone Screen or Drawer without a Grid
|
|
225
|
-
```tsx
|
|
226
|
-
import * as React from "react";
|
|
227
|
-
import { BindApiButton, type ApiDefinition, type MappingFile } from "api_binding_ui";
|
|
228
|
-
|
|
229
|
-
export function CreateDisputeDrawer({ isOpen, onClose, definitions, mappingFile }: { isOpen: boolean; onClose: () => void; definitions: ApiDefinition[]; mappingFile: MappingFile }) {
|
|
230
|
-
if (!isOpen) return null;
|
|
231
|
-
|
|
232
|
-
const reasonCodes = [
|
|
233
|
-
{ value: "PRICING_ERROR", label: "Pricing Discrepancy" },
|
|
234
|
-
{ value: "DAMAGED_GOODS", label: "Damaged Goods" },
|
|
235
|
-
];
|
|
236
|
-
|
|
237
|
-
return (
|
|
238
|
-
<aside className="drawer-panel" aria-label="Create Dispute">
|
|
239
|
-
<h2>Create Dispute</h2>
|
|
240
|
-
|
|
241
|
-
<form id="dispute-form">
|
|
242
|
-
<label htmlFor="reasonCode">Reason Code</label>
|
|
243
|
-
<select id="reasonCode" name="reasonCode" required>
|
|
244
|
-
{reasonCodes.map((r) => (
|
|
245
|
-
<option key={r.value} value={r.value}>{r.label}</option>
|
|
246
|
-
))}
|
|
247
|
-
</select>
|
|
248
|
-
|
|
249
|
-
<label htmlFor="amount">Disputed Amount</label>
|
|
250
|
-
<input id="amount" name="amount" type="number" required />
|
|
251
|
-
|
|
252
|
-
<label htmlFor="comments">Comments</label>
|
|
253
|
-
<textarea id="comments" name="comments" />
|
|
254
|
-
|
|
255
|
-
<div className="drawer-footer">
|
|
256
|
-
<button type="button" onClick={onClose}>Cancel</button>
|
|
257
|
-
<button type="submit">Submit Dispute</button>
|
|
258
|
-
|
|
259
|
-
<BindApiButton
|
|
260
|
-
definitions={definitions}
|
|
261
|
-
mappingFile={mappingFile}
|
|
262
|
-
appId="receivables"
|
|
263
|
-
windowId="dispute-create"
|
|
264
|
-
source="Create Dispute"
|
|
265
|
-
parent="Disputes Management"
|
|
266
|
-
options={{
|
|
267
|
-
reasonCode: reasonCodes,
|
|
268
|
-
}}
|
|
269
|
-
/>
|
|
270
|
-
</div>
|
|
271
|
-
</form>
|
|
272
|
-
</aside>
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
## Component API Specification
|
|
280
|
-
|
|
281
|
-
### `<BindApiButton />` Props
|
|
282
|
-
|
|
283
|
-
| Prop | Type | Default | Description |
|
|
284
|
-
| :--- | :--- | :--- | :--- |
|
|
285
|
-
| `appId` | `string` | `"app"` | Identifier of the parent application module. |
|
|
286
|
-
| `windowId` | `string` | *(Required)* | Stable identifier of the screen, dialog, or form. |
|
|
287
|
-
| `source` | `string` | *(Required)* | Human-readable title of the current screen or action. |
|
|
288
|
-
| `parent` | `string` | *(Required)* | Human-readable title of the parent view or grid. |
|
|
289
|
-
| `grid` | `BindingGrid` | `undefined` | Grid context including `gridId`, `columns`, and `rows` when actions target selected records. |
|
|
290
|
-
| `parents` | `SnapshotContext[]` | `undefined` | Array of parent context hierarchies for multi-level navigation. |
|
|
291
|
-
| `kind` | `WindowKind` | Automatic | `"dialog" \| "drawer" \| "screen" \| "action-form"`. Detected automatically if omitted. |
|
|
292
|
-
| `trigger` | `WindowTrigger` | `undefined` | Invocation metadata: `button`, `needsSelection`, `gridId`. |
|
|
293
|
-
| `options` | `Record<string, BindingOption[]>` | `{}` | Lookup options for select and combobox fields. Supports `{ value, label, subject, description }`. |
|
|
294
|
-
| `definitions` | `ApiDefinition[]` | `[]` | Registered API endpoints catalog available for mapping. |
|
|
295
|
-
| `mappingFile` | `MappingFile \| null` | `null` | Pre-existing mapping file to preload. |
|
|
296
|
-
| `routeBase` | `string` | `"/api-binding"` | Studio route base path configured in the application router. |
|
|
297
|
-
| `containerRef` | `React.RefObject<HTMLElement>` | `undefined` | Explicit DOM reference to the container element. |
|
|
298
|
-
| `containerSelector` | `string` | `undefined` | CSS selector used to locate the enclosing container element. |
|
|
299
|
-
| `rootElement` | `HTMLElement \| null` | `undefined` | Direct DOM element override. |
|
|
300
|
-
| `formId` | `string` | `undefined` | Target HTML `<form id="...">` identifier. |
|
|
301
|
-
| `components` | `SnapshotComponent[]` | `undefined` | Explicit components list overriding automatic DOM discovery. |
|
|
302
|
-
| `buttons` | `string[]` | `undefined` | Explicit action buttons list overriding automatic DOM discovery. |
|
|
303
|
-
| `className` | `string` | `""` | Additional CSS class for the button. |
|
|
304
|
-
| `children` | `React.ReactNode` | `"Bind API"` | Button label or children nodes. |
|
|
305
|
-
|
|
306
|
-
---
|
|
307
|
-
|
|
308
|
-
## DOM Discovery Protocol
|
|
309
|
-
|
|
310
|
-
When `<BindApiButton />` is clicked, the context extraction pipeline executes the following sequence:
|
|
311
|
-
|
|
312
|
-
1. **Container Resolution**:
|
|
313
|
-
- Checks `rootElement`, `containerRef`, `containerSelector`, and `formId`.
|
|
314
|
-
- Searches upward for `role="dialog"`, `<dialog>`, or `.ds-dialog`.
|
|
315
|
-
- Searches upward for `<form>`.
|
|
316
|
-
- Searches upward for `role="region"`, `[data-drawer]`, `<aside>`, `<main>`, `<section>`, `.drawer`, or `.panel`.
|
|
317
|
-
- Traverses parent elements to locate any ancestor containing at least two input elements.
|
|
318
|
-
- Falls back to `document.body`.
|
|
319
|
-
|
|
320
|
-
2. **Form Control Discovery**:
|
|
321
|
-
- Evaluates all standard controls (`input`, `select`, `textarea`) and custom ARIA controls (`role="combobox"`, `role="textbox"`, `role="checkbox"`, `role="switch"`).
|
|
322
|
-
- Resolves control names from `name`, `id`, `data-testid`, `data-field`, or `aria-label`.
|
|
323
|
-
- Extracts labels from `<label for="...">`, parent `<label>`, `aria-labelledby`, `aria-label`, or field placeholders.
|
|
324
|
-
- Captures current input values and state (`checked`, `value`, `data-value`).
|
|
325
|
-
|
|
326
|
-
3. **Action Button Discovery**:
|
|
327
|
-
- Evaluates buttons and submit inputs within the container.
|
|
328
|
-
- Excludes modal close controls, minimize/maximize adornments, dismiss triggers, and API binding triggers.
|
|
329
|
-
- Captures active primary and secondary action labels (e.g., `"Save"`, `"Submit"`, `"Cancel"`, `"Reset"`).
|
|
330
|
-
|
|
331
|
-
---
|
|
332
|
-
|
|
333
|
-
## Consuming Applied Bindings
|
|
334
|
-
|
|
335
|
-
When an engineer or analyst clicks **Apply Binding** inside the Studio, the verified configuration is stored in `localStorage` under `api-binding:applied:<key>` and broadcast across active windows.
|
|
336
|
-
|
|
337
|
-
Host components can listen to applied bindings using the `useAppliedBinding` hook:
|
|
338
|
-
|
|
339
|
-
```tsx
|
|
340
|
-
import * as React from "react";
|
|
341
|
-
import { useAppliedBinding } from "api_binding_ui";
|
|
342
|
-
|
|
343
|
-
export function AddNotesModal() {
|
|
344
|
-
const { isApplied, appliedConfig, appliedAt } = useAppliedBinding(
|
|
345
|
-
"collections.worklistUIGrid.worklist-add-notes"
|
|
346
|
-
);
|
|
347
|
-
|
|
348
|
-
React.useEffect(() => {
|
|
349
|
-
if (isApplied && appliedConfig) {
|
|
350
|
-
console.log("Applied API Binding Configuration:", appliedConfig);
|
|
351
|
-
// Access appliedConfig.calls, appliedConfig.fields, appliedConfig.customerRule
|
|
352
|
-
}
|
|
353
|
-
}, [isApplied, appliedConfig]);
|
|
354
|
-
|
|
355
|
-
// Render modal
|
|
356
|
-
}
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
---
|
|
360
|
-
|
|
361
|
-
## Testing and Verification
|
|
362
|
-
|
|
363
|
-
`useAppliedBinding` observes stored configuration only; the host retains responsibility for any live execution, response-to-field population and durable persistence. Draft edits take precedence over new seeds. Captured context lives in same-origin browser storage; exclude sensitive fields and keep credentials out of snapshots and fixed values. External schema references must be bundled before import. Cookie parameters, non-JSON bodies, non-object root bodies and unsupported wire serialization produce contract limitations rather than network fallbacks.
|
|
364
|
-
|
|
365
|
-
Run test suites using the bundled test runner:
|
|
366
|
-
|
|
367
|
-
```bash
|
|
368
|
-
bun test
|
|
369
|
-
# or
|
|
370
|
-
yarn test
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
Build the distribution package:
|
|
374
|
-
|
|
375
|
-
```bash
|
|
376
|
-
bun run build
|
|
377
|
-
# or
|
|
378
|
-
yarn build
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
The build produces:
|
|
382
|
-
- `dist/index.js`: Browser ES module bundle.
|
|
383
|
-
- `dist/api-binding-ui.css`: Compiled style bundle with `--ds-*` design token bridges.
|
|
384
|
-
- `dist/**/*.d.ts`: TypeScript declaration definitions.
|
|
385
|
-
|
|
386
|
-
## Manual Release
|
|
387
|
-
|
|
388
|
-
The original Bun/PowerShell build scripts are unchanged. Run `bun test`, `bun run build`, then `npm pack --dry-run` and inspect the archive/exports. Publish version 1.1.0 yourself using `npm publish` after reviewing the diff. This project has not been published automatically. The Lovable handoff prompt is a separate local document, not part of the npm package's files list.
|
|
389
|
-
|
|
390
|
-
---
|
|
391
|
-
|
|
392
|
-
## License
|
|
393
|
-
|
|
394
|
-
Internal enterprise package. All rights reserved.
|
|
1
|
+
# api_binding_ui
|
|
2
|
+
|
|
3
|
+
Bind any UI component to documented APIs while a product is being designed, then run those bindings in production.
|
|
4
|
+
|
|
5
|
+
- **Generic.** The code knows three slot roles (`consume`, `produce`, `trigger`) and nothing else. Component kinds, screens, products and APIs are data.
|
|
6
|
+
- **Docs only.** APIs come from the OpenAPI documents. If the docs do not have it, it cannot be bound.
|
|
7
|
+
- **API only.** Bindings say which API is called with what data and where results go. Opening, closing and navigation stay in the app.
|
|
8
|
+
|
|
9
|
+
The full contract is in [`spec/FRAMEWORK.md`](spec/FRAMEWORK.md); the types are in [`src/framework/contract.ts`](src/framework/contract.ts).
|
|
10
|
+
|
|
11
|
+
## Entries
|
|
12
|
+
|
|
13
|
+
| Import | Use | In production |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `api_binding_ui` | Contract types, `catalogFromOpenApi`, the runtime (`BindingProvider`, `BindingScreen`, `useSlot`, `useCell`, `useProduce`, `useTrigger`), validation | Yes |
|
|
16
|
+
| `api_binding_ui/studio` + `api_binding_ui/studio.css` | `BindingWidget`, `BindingStudio` | No; import only from design-time code |
|
|
17
|
+
|
|
18
|
+
## Runtime
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { BindingProvider, BindingScreen, useSlot, useProduce, useTrigger } from "api_binding_ui";
|
|
22
|
+
|
|
23
|
+
<BindingProvider catalog={catalog} manifests={manifests} fetcher={fetcher}>
|
|
24
|
+
<BindingScreen id="collections.worklist.add-notes" context={{ selection }}>
|
|
25
|
+
<AddNotesForm />
|
|
26
|
+
</BindingScreen>
|
|
27
|
+
</BindingProvider>;
|
|
28
|
+
|
|
29
|
+
function AddNotesForm() {
|
|
30
|
+
const notesType = useSlot<{ value: string; label: string }[]>("notesType", "options");
|
|
31
|
+
const [subject, setSubject] = useState("");
|
|
32
|
+
useProduce("subject", "value", subject);
|
|
33
|
+
const submit = useTrigger("submit", "click");
|
|
34
|
+
// render notesType.data, call submit.run(), then close the dialog in your own code
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`fetcher` receives `{ method, path, query, headers, body }` and the catalog operation; base URL, auth and errors stay in the app.
|
|
39
|
+
|
|
40
|
+
## Studio
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { BindingWidget } from "api_binding_ui/studio";
|
|
44
|
+
import "api_binding_ui/studio.css";
|
|
45
|
+
|
|
46
|
+
// once, inside <BindingProvider persistence={…}>, design mode only
|
|
47
|
+
<BindingWidget framework={{ descriptors, registry }} />
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
A floating button opens the studio over the app on the screen being shown. Edits apply when it closes.
|
|
51
|
+
|
|
52
|
+
The studio reads every product's APIs from the published docs (default `https://apidocs.highradius.com/documentation-ui/index.yaml`, JSON or YAML). Each user can change the URL in **Settings** (top right), which also downloads and imports bindings as JSON for committing with the app. Pass `docsUrl` to change the default, or `framework.catalog` to skip loading.
|
|
53
|
+
|
|
54
|
+
## Layout
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
src/
|
|
58
|
+
framework/ pure TypeScript: contract, OpenAPI → catalog, schema, names, engine, validation,
|
|
59
|
+
expressions, request runner, persistence
|
|
60
|
+
runtime/ React runtime: provider, screen scope, hooks
|
|
61
|
+
studio/ design-time UI: shell, navigator, search, component list, inspector, slot editors
|
|
62
|
+
dev/ sample data and the local harness (not published)
|
|
63
|
+
spec/ FRAMEWORK.md (the contract) and contract.ts (re-export)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Develop
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
bun install
|
|
70
|
+
bun run dev # studio with sample data on http://localhost:5174
|
|
71
|
+
bun test
|
|
72
|
+
bun run typecheck
|
|
73
|
+
bun run build
|
|
74
|
+
```
|