@cerebro-labs/agentnava-sdk 0.50.0 → 0.51.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.
- package/README.md +10 -1
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/package.json +15 -2
- package/react.css +409 -0
- package/react.d.ts +40 -0
- package/react.js +196 -0
- package/react.js.map +1 -0
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.js.map +1 -1
- package/widgets.d.ts +15 -0
- package/widgets.js +29 -0
- package/widgets.js.map +1 -0
package/README.md
CHANGED
|
@@ -409,7 +409,16 @@ and "Cerebro Labs" remain trademarks of Cerebro Labs, Inc.
|
|
|
409
409
|
|
|
410
410
|
### Widgets in replies (0.50)
|
|
411
411
|
|
|
412
|
-
`agent.start({ endUserId, widgets: true })` says your screen can draw cards, tables and charts. Each turn then streams `widget` events (a whole widget each time, replace it by `surfaceId`), `done` carries the final `widgets`, and `messages()` returns them on each reply. Continue one with `agent.conversation(id, { widgets: true })`. Widgets
|
|
412
|
+
`agent.start({ endUserId, widgets: true })` says your screen can draw cards, tables and charts. Each turn then streams `widget` events (a whole widget each time, replace it by `surfaceId`), `done` carries the final `widgets`, and `messages()` returns them on each reply. Continue one with `agent.conversation(id, { widgets: true })`. Widgets use Google's open A2UI format with AgentNava's own set of parts (`Widget`, `WidgetPart`): draw each with your own components, starting from its part with id `root`, or use the ready-made React views below. `placeWidgets(text, widgets)` splits a reply into words and widgets in reading order, for any framework.
|
|
413
|
+
|
|
414
|
+
```tsx
|
|
415
|
+
import { ReplyView } from '@cerebro-labs/agentnava-sdk/react'
|
|
416
|
+
import '@cerebro-labs/agentnava-sdk/react/styles.css'
|
|
417
|
+
|
|
418
|
+
<ReplyView text={reply} widgets={widgets} onAsk={send} />
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
React is an optional peer: only `@cerebro-labs/agentnava-sdk/react` imports it. Every kind of part has a default look, themed with `--an-w-*` CSS variables; `parts={{ Stat: MyStat }}` swaps any kind for your own component, `renderText` draws the words, `currency` and `locale` format numbers, and `allowUrl` narrows which links and pictures open (https:// only by default). An agent's own `widgets: false` turns them off for it. The agent field's old meaning, a list of widget kinds nothing read, is gone, and so is the `widgets.json` file `loadAgentDir` used to load.
|
|
413
422
|
|
|
414
423
|
### Where an agent is live (0.41)
|
|
415
424
|
|
package/index.d.ts
CHANGED
|
@@ -17,3 +17,4 @@ export { loadManagerTemplate } from './templates.ts';
|
|
|
17
17
|
export type { Turn } from './turn.ts';
|
|
18
18
|
export type { ClientOptions } from './http.ts';
|
|
19
19
|
export type { AccountData, AccountNeeded, AccountStatus, AgentConnection, AgentConversationData, AgentData, AgentFields, AgentStatus, Attachment, Bindings, ConnectionStatus, Credits, DatabaseColumn, DatabaseData, DatabaseEngine, DatabaseFields, DatabaseLogin, DatabaseTable, DatabaseTestResult, DatabaseTls, DatabaseUsedBy, FileEntry, Filesystem, Grade, HttpTool, HttpToolParam, McpServer, ProjectAgent, Message, Parameter, ProjectConversationData, ProjectData, ProjectFields, Requirement, Scope, SeatPlan, SecretMeta, SecretRequirement, Step, Trigger, WebhookDelivery, WebhookVerify, TriggerTarget, TurnEvent, Widget, WidgetPart, UsedBy, WebsiteChat, WebsiteChatAccess, Workflow, WorkspaceInfo, WorkspaceMember, } from './types.ts';
|
|
20
|
+
export { placeWidgets, type ReplyPiece } from './widgets.ts';
|
package/index.js
CHANGED
|
@@ -42,4 +42,5 @@ export { loadAgentDir } from "./load-agent-dir.js";
|
|
|
42
42
|
// through the './templates' subpath; re-exported here so the package has one
|
|
43
43
|
// surface rather than two.
|
|
44
44
|
export { loadManagerTemplate } from "./templates.js";
|
|
45
|
+
export { placeWidgets } from "./widgets.js";
|
|
45
46
|
//# sourceMappingURL=index.js.map
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,EAAE;AACF,0DAA0D;AAC1D,EAAE;AACF,6DAA6D;AAC7D,EAAE;AACF,yCAAyC;AACzC,2CAA2C;AAC3C,8BAA8B;AAC9B,8EAA8E;AAC9E,QAAQ;AACR,uEAAuE;AACvE,2EAA2E;AAC3E,EAAE;AACF,yDAAyD;AAEzD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAqB,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,2EAA2E;AAC3E,iFAAiF;AACjF,OAAO,EACN,UAAU,GAGV,MAAM,iBAAiB,CAAC;AACzB,6EAA6E;AAC7E,wEAAwE;AACxE,OAAO,EAAE,GAAG,EAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAwC,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAA4B,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC9D,yEAAyE;AACzE,8EAA8E;AAC9E,6EAA6E;AAC7E,2DAA2D;AAC3D,OAAO,EACN,WAAW,EACX,WAAW,EACX,cAAc,EACd,WAAW,EACX,QAAQ,EACR,YAAY,GASZ,MAAM,mBAAmB,CAAC;AAC3B,4EAA4E;AAC5E,kEAAkE;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,+EAA+E;AAC/E,6EAA6E;AAC7E,2BAA2B;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["// @cerebro-labs/agentnava-sdk\n//\n// Configure an agent, start a conversation, work with it.\n//\n// import { AgentNava } from '@cerebro-labs/agentnava-sdk';\n//\n// const ws = AgentNava.getWorkspace();\n// const agent = await ws.agents.create({\n// name: 'Refund checker',\n// instructions: 'Decide whether a late delivery qualifies for a refund.',\n// });\n// const conversation = await agent.start({ endUserId: 'u_ananya' });\n// console.log(await conversation.ask('Order 4471 was nine days late.'));\n//\n// The reference this implements is design/sdk-design.md.\n\nexport { AgentNava, Workspace } from './workspace.ts';\nexport { Agent, type StartOptions } from './agent.ts';\nexport { Account } from './account.ts';\n// Builds one entry of an agent's setup: an app, and whose account. NOT the\n// 0.43 `Connection`, which was a handle on a signed-in account and is `Account`.\nexport {\n\tConnection,\n\ttype CreatorAccountConnection,\n\ttype EndUserAccountConnection,\n} from './connection.ts';\n// Every app the platform can connect, as constants: `App.GMAIL === 'gmail'`.\n// Generated from the connections catalog; any plain string still works.\nexport { App, type AppId } from './apps.generated.ts';\nexport { Secret } from './secret.ts';\nexport { EndUser } from './end-user.ts';\nexport { Conversation, type AskOptions, type FileUrlOptions } from './conversation.ts';\nexport { KnowledgeBase } from './knowledge-base.ts';\nexport { Database } from './database.ts';\nexport { Project, type ProjectStartOptions } from './project.ts';\nexport { AgentNavaError } from './errors.ts';\nexport { loadWorkflows, parseWorkflow } from './workflows.ts';\n// Draft an agent's tools from whatever a company already has: an OpenAPI\n// document, a Postman collection, or a working curl command. Runs entirely on\n// your machine: nothing about the source is sent to AgentNava, which matters\n// because those files routinely contain a live credential.\nexport {\n\timportTools,\n\tfromOpenApi,\n\tfromOpenApiUrl,\n\tfromPostman,\n\tfromCurl,\n\ttoolNameFrom,\n\ttype ImportSource,\n\ttype ImportOptions,\n\ttype ImportedTools,\n\ttype ImportedSecret,\n\ttype ImportWarning,\n\ttype ImportWarningKind,\n\ttype OpenApiDocument,\n\ttype PostmanCollection,\n} from './import-tools.ts';\n// Reads a whole Claude-Code-shaped agent directory (AGENT.md + workflows/ +\n// mcp-servers.json ...) into the fields ws.agents.create() takes.\nexport { loadAgentDir } from './load-agent-dir.ts';\n// The platform's built-in project-manager configuration. apps/api imports this\n// through the './templates' subpath; re-exported here so the package has one\n// surface rather than two.\nexport { loadManagerTemplate } from './templates.ts';\nexport type { Turn } from './turn.ts';\nexport type { ClientOptions } from './http.ts';\nexport type {\n\tAccountData,\n\tAccountNeeded,\n\tAccountStatus,\n\tAgentConnection,\n\tAgentConversationData,\n\tAgentData,\n\tAgentFields,\n\tAgentStatus,\n\tAttachment,\n\tBindings,\n\tConnectionStatus,\n\tCredits,\n\tDatabaseColumn,\n\tDatabaseData,\n\tDatabaseEngine,\n\tDatabaseFields,\n\tDatabaseLogin,\n\tDatabaseTable,\n\tDatabaseTestResult,\n\tDatabaseTls,\n\tDatabaseUsedBy,\n\tFileEntry,\n\tFilesystem,\n\tGrade,\n\tHttpTool,\n\tHttpToolParam,\n\tMcpServer,\n\tProjectAgent,\n\tMessage,\n\tParameter,\n\tProjectConversationData,\n\tProjectData,\n\tProjectFields,\n\tRequirement,\n\tScope,\n\tSeatPlan,\n\tSecretMeta,\n\tSecretRequirement,\n\tStep,\n\tTrigger,\n\tWebhookDelivery,\n\tWebhookVerify,\n\tTriggerTarget,\n\tTurnEvent,\n\tWidget,\n\tWidgetPart,\n\tUsedBy,\n\tWebsiteChat,\n\tWebsiteChatAccess,\n\tWorkflow,\n\tWorkspaceInfo,\n\tWorkspaceMember,\n} from './types.ts';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,EAAE;AACF,0DAA0D;AAC1D,EAAE;AACF,6DAA6D;AAC7D,EAAE;AACF,yCAAyC;AACzC,2CAA2C;AAC3C,8BAA8B;AAC9B,8EAA8E;AAC9E,QAAQ;AACR,uEAAuE;AACvE,2EAA2E;AAC3E,EAAE;AACF,yDAAyD;AAEzD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAqB,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,2EAA2E;AAC3E,iFAAiF;AACjF,OAAO,EACN,UAAU,GAGV,MAAM,iBAAiB,CAAC;AACzB,6EAA6E;AAC7E,wEAAwE;AACxE,OAAO,EAAE,GAAG,EAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAwC,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,OAAO,EAA4B,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC9D,yEAAyE;AACzE,8EAA8E;AAC9E,6EAA6E;AAC7E,2DAA2D;AAC3D,OAAO,EACN,WAAW,EACX,WAAW,EACX,cAAc,EACd,WAAW,EACX,QAAQ,EACR,YAAY,GASZ,MAAM,mBAAmB,CAAC;AAC3B,4EAA4E;AAC5E,kEAAkE;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,+EAA+E;AAC/E,6EAA6E;AAC7E,2BAA2B;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAyDrD,OAAO,EAAE,YAAY,EAAmB,MAAM,cAAc,CAAC","sourcesContent":["// @cerebro-labs/agentnava-sdk\n//\n// Configure an agent, start a conversation, work with it.\n//\n// import { AgentNava } from '@cerebro-labs/agentnava-sdk';\n//\n// const ws = AgentNava.getWorkspace();\n// const agent = await ws.agents.create({\n// name: 'Refund checker',\n// instructions: 'Decide whether a late delivery qualifies for a refund.',\n// });\n// const conversation = await agent.start({ endUserId: 'u_ananya' });\n// console.log(await conversation.ask('Order 4471 was nine days late.'));\n//\n// The reference this implements is design/sdk-design.md.\n\nexport { AgentNava, Workspace } from './workspace.ts';\nexport { Agent, type StartOptions } from './agent.ts';\nexport { Account } from './account.ts';\n// Builds one entry of an agent's setup: an app, and whose account. NOT the\n// 0.43 `Connection`, which was a handle on a signed-in account and is `Account`.\nexport {\n\tConnection,\n\ttype CreatorAccountConnection,\n\ttype EndUserAccountConnection,\n} from './connection.ts';\n// Every app the platform can connect, as constants: `App.GMAIL === 'gmail'`.\n// Generated from the connections catalog; any plain string still works.\nexport { App, type AppId } from './apps.generated.ts';\nexport { Secret } from './secret.ts';\nexport { EndUser } from './end-user.ts';\nexport { Conversation, type AskOptions, type FileUrlOptions } from './conversation.ts';\nexport { KnowledgeBase } from './knowledge-base.ts';\nexport { Database } from './database.ts';\nexport { Project, type ProjectStartOptions } from './project.ts';\nexport { AgentNavaError } from './errors.ts';\nexport { loadWorkflows, parseWorkflow } from './workflows.ts';\n// Draft an agent's tools from whatever a company already has: an OpenAPI\n// document, a Postman collection, or a working curl command. Runs entirely on\n// your machine: nothing about the source is sent to AgentNava, which matters\n// because those files routinely contain a live credential.\nexport {\n\timportTools,\n\tfromOpenApi,\n\tfromOpenApiUrl,\n\tfromPostman,\n\tfromCurl,\n\ttoolNameFrom,\n\ttype ImportSource,\n\ttype ImportOptions,\n\ttype ImportedTools,\n\ttype ImportedSecret,\n\ttype ImportWarning,\n\ttype ImportWarningKind,\n\ttype OpenApiDocument,\n\ttype PostmanCollection,\n} from './import-tools.ts';\n// Reads a whole Claude-Code-shaped agent directory (AGENT.md + workflows/ +\n// mcp-servers.json ...) into the fields ws.agents.create() takes.\nexport { loadAgentDir } from './load-agent-dir.ts';\n// The platform's built-in project-manager configuration. apps/api imports this\n// through the './templates' subpath; re-exported here so the package has one\n// surface rather than two.\nexport { loadManagerTemplate } from './templates.ts';\nexport type { Turn } from './turn.ts';\nexport type { ClientOptions } from './http.ts';\nexport type {\n\tAccountData,\n\tAccountNeeded,\n\tAccountStatus,\n\tAgentConnection,\n\tAgentConversationData,\n\tAgentData,\n\tAgentFields,\n\tAgentStatus,\n\tAttachment,\n\tBindings,\n\tConnectionStatus,\n\tCredits,\n\tDatabaseColumn,\n\tDatabaseData,\n\tDatabaseEngine,\n\tDatabaseFields,\n\tDatabaseLogin,\n\tDatabaseTable,\n\tDatabaseTestResult,\n\tDatabaseTls,\n\tDatabaseUsedBy,\n\tFileEntry,\n\tFilesystem,\n\tGrade,\n\tHttpTool,\n\tHttpToolParam,\n\tMcpServer,\n\tProjectAgent,\n\tMessage,\n\tParameter,\n\tProjectConversationData,\n\tProjectData,\n\tProjectFields,\n\tRequirement,\n\tScope,\n\tSeatPlan,\n\tSecretMeta,\n\tSecretRequirement,\n\tStep,\n\tTrigger,\n\tWebhookDelivery,\n\tWebhookVerify,\n\tTriggerTarget,\n\tTurnEvent,\n\tWidget,\n\tWidgetPart,\n\tUsedBy,\n\tWebsiteChat,\n\tWebsiteChatAccess,\n\tWorkflow,\n\tWorkspaceInfo,\n\tWorkspaceMember,\n} from './types.ts';\nexport { placeWidgets, type ReplyPiece } from './widgets.ts';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cerebro-labs/agentnava-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.0",
|
|
4
4
|
"description": "The AgentNava SDK. Configure an agent, start a conversation, and work with it.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -24,7 +24,12 @@
|
|
|
24
24
|
"./import-tools": {
|
|
25
25
|
"types": "./import-tools.d.ts",
|
|
26
26
|
"default": "./import-tools.js"
|
|
27
|
-
}
|
|
27
|
+
},
|
|
28
|
+
"./react": {
|
|
29
|
+
"types": "./react.d.ts",
|
|
30
|
+
"default": "./react.js"
|
|
31
|
+
},
|
|
32
|
+
"./react/styles.css": "./react.css"
|
|
28
33
|
},
|
|
29
34
|
"engines": {
|
|
30
35
|
"node": ">=18",
|
|
@@ -32,5 +37,13 @@
|
|
|
32
37
|
},
|
|
33
38
|
"publishConfig": {
|
|
34
39
|
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"react": ">=18.0.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependenciesMeta": {
|
|
45
|
+
"react": {
|
|
46
|
+
"optional": true
|
|
47
|
+
}
|
|
35
48
|
}
|
|
36
49
|
}
|
package/react.css
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Default look for @cerebro-labs/agentnava-sdk/react.
|
|
3
|
+
*
|
|
4
|
+
* import '@cerebro-labs/agentnava-sdk/react/styles.css'
|
|
5
|
+
*
|
|
6
|
+
* Theme it by setting these variables on any ancestor (or :root). Fonts are
|
|
7
|
+
* inherited from your page. Every class starts with an-w- so nothing here
|
|
8
|
+
* reaches the rest of your app.
|
|
9
|
+
*/
|
|
10
|
+
.an-w,
|
|
11
|
+
.an-reply {
|
|
12
|
+
--an-w-ink: #16181d;
|
|
13
|
+
--an-w-muted: #6b7280;
|
|
14
|
+
--an-w-line: #e5e7eb;
|
|
15
|
+
--an-w-surface: #f8f9fb;
|
|
16
|
+
--an-w-tint: #eef2f7;
|
|
17
|
+
--an-w-accent: #1f2937;
|
|
18
|
+
--an-w-accent-ink: #ffffff;
|
|
19
|
+
--an-w-s0: #2563eb;
|
|
20
|
+
--an-w-s1: #d97706;
|
|
21
|
+
--an-w-s2: #059669;
|
|
22
|
+
--an-w-s3: #7c3aed;
|
|
23
|
+
--an-w-high: #dc2626;
|
|
24
|
+
--an-w-medium: #d97706;
|
|
25
|
+
--an-w-good: #059669;
|
|
26
|
+
--an-w-info: #2563eb;
|
|
27
|
+
--an-w-radius: 8px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.an-reply > * + * {
|
|
31
|
+
margin-top: 8px;
|
|
32
|
+
}
|
|
33
|
+
.an-reply-text {
|
|
34
|
+
margin: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.an-w {
|
|
38
|
+
color: var(--an-w-ink);
|
|
39
|
+
font-size: 0.95em;
|
|
40
|
+
line-height: 1.45;
|
|
41
|
+
max-width: 100%;
|
|
42
|
+
}
|
|
43
|
+
.an-w p,
|
|
44
|
+
.an-w figure,
|
|
45
|
+
.an-w dl,
|
|
46
|
+
.an-w ul,
|
|
47
|
+
.an-w ol {
|
|
48
|
+
margin: 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.an-w-col {
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
gap: 10px;
|
|
55
|
+
}
|
|
56
|
+
.an-w-gap-small {
|
|
57
|
+
gap: 6px;
|
|
58
|
+
}
|
|
59
|
+
.an-w-gap-large {
|
|
60
|
+
gap: 16px;
|
|
61
|
+
}
|
|
62
|
+
.an-w-row {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-wrap: wrap;
|
|
65
|
+
gap: 8px;
|
|
66
|
+
}
|
|
67
|
+
.an-w-row > * {
|
|
68
|
+
flex: 1 1 0;
|
|
69
|
+
min-width: 96px;
|
|
70
|
+
}
|
|
71
|
+
.an-w-row.is-scroll {
|
|
72
|
+
flex-wrap: nowrap;
|
|
73
|
+
overflow-x: auto;
|
|
74
|
+
scroll-snap-type: x mandatory;
|
|
75
|
+
}
|
|
76
|
+
.an-w-row.is-scroll > * {
|
|
77
|
+
flex: 0 0 72%;
|
|
78
|
+
scroll-snap-align: start;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.an-w-card {
|
|
82
|
+
border: 1px solid var(--an-w-line);
|
|
83
|
+
border-radius: var(--an-w-radius);
|
|
84
|
+
background: var(--an-w-surface);
|
|
85
|
+
overflow: hidden;
|
|
86
|
+
}
|
|
87
|
+
.an-w-card > img {
|
|
88
|
+
display: block;
|
|
89
|
+
width: 100%;
|
|
90
|
+
aspect-ratio: 16 / 9;
|
|
91
|
+
object-fit: cover;
|
|
92
|
+
}
|
|
93
|
+
.an-w-card-body {
|
|
94
|
+
display: flex;
|
|
95
|
+
flex-direction: column;
|
|
96
|
+
gap: 6px;
|
|
97
|
+
padding: 10px 12px;
|
|
98
|
+
}
|
|
99
|
+
.an-w-card-link {
|
|
100
|
+
color: inherit;
|
|
101
|
+
text-decoration: none;
|
|
102
|
+
}
|
|
103
|
+
.an-w-card-link:hover .an-w-card {
|
|
104
|
+
border-color: var(--an-w-muted);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.an-w-text.is-title {
|
|
108
|
+
font-size: 1.15em;
|
|
109
|
+
font-weight: 600;
|
|
110
|
+
}
|
|
111
|
+
.an-w-text.is-heading {
|
|
112
|
+
font-weight: 600;
|
|
113
|
+
}
|
|
114
|
+
.an-w-text.is-caption {
|
|
115
|
+
color: var(--an-w-muted);
|
|
116
|
+
font-size: 0.9em;
|
|
117
|
+
}
|
|
118
|
+
.an-w-title {
|
|
119
|
+
color: var(--an-w-muted);
|
|
120
|
+
font-size: 0.9em;
|
|
121
|
+
font-weight: 500;
|
|
122
|
+
margin-bottom: 4px;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.an-w-stat {
|
|
126
|
+
display: flex;
|
|
127
|
+
flex-direction: column;
|
|
128
|
+
gap: 1px;
|
|
129
|
+
padding: 8px 10px;
|
|
130
|
+
border-radius: var(--an-w-radius);
|
|
131
|
+
background: var(--an-w-tint);
|
|
132
|
+
}
|
|
133
|
+
.an-w-stat strong {
|
|
134
|
+
font-size: 1.25em;
|
|
135
|
+
font-weight: 600;
|
|
136
|
+
font-variant-numeric: tabular-nums;
|
|
137
|
+
}
|
|
138
|
+
.an-w-stat span {
|
|
139
|
+
font-weight: 500;
|
|
140
|
+
}
|
|
141
|
+
.an-w-stat small {
|
|
142
|
+
color: var(--an-w-muted);
|
|
143
|
+
font-size: 0.85em;
|
|
144
|
+
line-height: 1.3;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.an-w-kv dl > div {
|
|
148
|
+
display: flex;
|
|
149
|
+
justify-content: space-between;
|
|
150
|
+
gap: 12px;
|
|
151
|
+
padding: 5px 0;
|
|
152
|
+
border-bottom: 1px solid var(--an-w-line);
|
|
153
|
+
}
|
|
154
|
+
.an-w-kv dt {
|
|
155
|
+
color: var(--an-w-muted);
|
|
156
|
+
}
|
|
157
|
+
.an-w-kv dd {
|
|
158
|
+
margin: 0;
|
|
159
|
+
text-align: right;
|
|
160
|
+
font-variant-numeric: tabular-nums;
|
|
161
|
+
}
|
|
162
|
+
.an-w-kv .is-total {
|
|
163
|
+
border-bottom: 0;
|
|
164
|
+
font-weight: 600;
|
|
165
|
+
}
|
|
166
|
+
.an-w-kv .is-total dt {
|
|
167
|
+
color: var(--an-w-ink);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.an-w-table {
|
|
171
|
+
overflow-x: auto;
|
|
172
|
+
}
|
|
173
|
+
.an-w-table table {
|
|
174
|
+
border-collapse: collapse;
|
|
175
|
+
width: 100%;
|
|
176
|
+
}
|
|
177
|
+
.an-w-table th,
|
|
178
|
+
.an-w-table td {
|
|
179
|
+
text-align: left;
|
|
180
|
+
padding: 5px 10px 5px 0;
|
|
181
|
+
border-bottom: 1px solid var(--an-w-line);
|
|
182
|
+
white-space: nowrap;
|
|
183
|
+
}
|
|
184
|
+
.an-w-table th {
|
|
185
|
+
color: var(--an-w-muted);
|
|
186
|
+
font-weight: 500;
|
|
187
|
+
}
|
|
188
|
+
.an-w-table td.is-num {
|
|
189
|
+
text-align: right;
|
|
190
|
+
font-variant-numeric: tabular-nums;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.an-w-chart figcaption {
|
|
194
|
+
color: var(--an-w-muted);
|
|
195
|
+
font-size: 0.9em;
|
|
196
|
+
font-weight: 500;
|
|
197
|
+
margin-bottom: 6px;
|
|
198
|
+
}
|
|
199
|
+
.an-w-chart svg {
|
|
200
|
+
display: block;
|
|
201
|
+
width: 100%;
|
|
202
|
+
height: auto;
|
|
203
|
+
overflow: visible;
|
|
204
|
+
}
|
|
205
|
+
.an-w-chart text {
|
|
206
|
+
font-size: 10px;
|
|
207
|
+
fill: var(--an-w-muted);
|
|
208
|
+
}
|
|
209
|
+
.an-w-chart rect.an-w-s0,
|
|
210
|
+
.an-w-chart circle.an-w-s0 {
|
|
211
|
+
fill: var(--an-w-s0);
|
|
212
|
+
}
|
|
213
|
+
.an-w-chart rect.an-w-s1,
|
|
214
|
+
.an-w-chart circle.an-w-s1 {
|
|
215
|
+
fill: var(--an-w-s1);
|
|
216
|
+
}
|
|
217
|
+
.an-w-chart rect.an-w-s2,
|
|
218
|
+
.an-w-chart circle.an-w-s2 {
|
|
219
|
+
fill: var(--an-w-s2);
|
|
220
|
+
}
|
|
221
|
+
.an-w-chart rect.an-w-s3,
|
|
222
|
+
.an-w-chart circle.an-w-s3 {
|
|
223
|
+
fill: var(--an-w-s3);
|
|
224
|
+
}
|
|
225
|
+
.an-w-line {
|
|
226
|
+
fill: none;
|
|
227
|
+
stroke-width: 2;
|
|
228
|
+
}
|
|
229
|
+
.an-w-line.an-w-s0 {
|
|
230
|
+
stroke: var(--an-w-s0);
|
|
231
|
+
}
|
|
232
|
+
.an-w-line.an-w-s1 {
|
|
233
|
+
stroke: var(--an-w-s1);
|
|
234
|
+
}
|
|
235
|
+
.an-w-line.an-w-s2 {
|
|
236
|
+
stroke: var(--an-w-s2);
|
|
237
|
+
}
|
|
238
|
+
.an-w-line.an-w-s3 {
|
|
239
|
+
stroke: var(--an-w-s3);
|
|
240
|
+
}
|
|
241
|
+
.an-w-ref line {
|
|
242
|
+
stroke: var(--an-w-muted);
|
|
243
|
+
stroke-dasharray: 4 3;
|
|
244
|
+
}
|
|
245
|
+
.an-w-legend {
|
|
246
|
+
display: flex;
|
|
247
|
+
flex-wrap: wrap;
|
|
248
|
+
gap: 12px;
|
|
249
|
+
color: var(--an-w-muted);
|
|
250
|
+
font-size: 0.9em;
|
|
251
|
+
margin-top: 4px;
|
|
252
|
+
}
|
|
253
|
+
.an-w-legend i {
|
|
254
|
+
display: inline-block;
|
|
255
|
+
width: 8px;
|
|
256
|
+
height: 8px;
|
|
257
|
+
border-radius: 50%;
|
|
258
|
+
margin-right: 5px;
|
|
259
|
+
}
|
|
260
|
+
.an-w-legend i.an-w-s0 {
|
|
261
|
+
background: var(--an-w-s0);
|
|
262
|
+
}
|
|
263
|
+
.an-w-legend i.an-w-s1 {
|
|
264
|
+
background: var(--an-w-s1);
|
|
265
|
+
}
|
|
266
|
+
.an-w-legend i.an-w-s2 {
|
|
267
|
+
background: var(--an-w-s2);
|
|
268
|
+
}
|
|
269
|
+
.an-w-legend i.an-w-s3 {
|
|
270
|
+
background: var(--an-w-s3);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.an-w-image img {
|
|
274
|
+
display: block;
|
|
275
|
+
max-width: 100%;
|
|
276
|
+
border-radius: var(--an-w-radius);
|
|
277
|
+
}
|
|
278
|
+
.an-w-image figcaption {
|
|
279
|
+
color: var(--an-w-muted);
|
|
280
|
+
font-size: 0.9em;
|
|
281
|
+
margin-top: 4px;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.an-w-list ul,
|
|
285
|
+
.an-w-list ol {
|
|
286
|
+
list-style: none;
|
|
287
|
+
padding: 0;
|
|
288
|
+
}
|
|
289
|
+
.an-w-list li {
|
|
290
|
+
display: flex;
|
|
291
|
+
align-items: baseline;
|
|
292
|
+
gap: 8px;
|
|
293
|
+
padding: 6px 0;
|
|
294
|
+
border-bottom: 1px solid var(--an-w-line);
|
|
295
|
+
}
|
|
296
|
+
.an-w-list li:last-child {
|
|
297
|
+
border-bottom: 0;
|
|
298
|
+
}
|
|
299
|
+
.an-w-list li > div {
|
|
300
|
+
flex: 1;
|
|
301
|
+
display: flex;
|
|
302
|
+
flex-direction: column;
|
|
303
|
+
}
|
|
304
|
+
.an-w-list li span,
|
|
305
|
+
.an-w-list li small {
|
|
306
|
+
color: var(--an-w-muted);
|
|
307
|
+
}
|
|
308
|
+
.an-w-dot {
|
|
309
|
+
flex: none;
|
|
310
|
+
width: 8px;
|
|
311
|
+
height: 8px;
|
|
312
|
+
border-radius: 50%;
|
|
313
|
+
background: var(--an-w-info);
|
|
314
|
+
}
|
|
315
|
+
.an-w-dot.is-high {
|
|
316
|
+
background: var(--an-w-high);
|
|
317
|
+
}
|
|
318
|
+
.an-w-dot.is-medium {
|
|
319
|
+
background: var(--an-w-medium);
|
|
320
|
+
}
|
|
321
|
+
.an-w-dot.is-good {
|
|
322
|
+
background: var(--an-w-good);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.an-w-note {
|
|
326
|
+
display: flex;
|
|
327
|
+
flex-direction: column;
|
|
328
|
+
gap: 2px;
|
|
329
|
+
padding: 8px 10px;
|
|
330
|
+
border-radius: var(--an-w-radius);
|
|
331
|
+
background: var(--an-w-tint);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.an-w-badge {
|
|
335
|
+
align-self: flex-start;
|
|
336
|
+
display: inline-block;
|
|
337
|
+
padding: 2px 8px;
|
|
338
|
+
border-radius: 999px;
|
|
339
|
+
font-size: 0.85em;
|
|
340
|
+
font-weight: 500;
|
|
341
|
+
background: var(--an-w-tint);
|
|
342
|
+
}
|
|
343
|
+
.an-w-badge.is-high {
|
|
344
|
+
color: var(--an-w-high);
|
|
345
|
+
}
|
|
346
|
+
.an-w-badge.is-medium {
|
|
347
|
+
color: var(--an-w-medium);
|
|
348
|
+
}
|
|
349
|
+
.an-w-badge.is-good {
|
|
350
|
+
color: var(--an-w-good);
|
|
351
|
+
}
|
|
352
|
+
.an-w-badge.is-info,
|
|
353
|
+
.an-w-badge.is-low {
|
|
354
|
+
color: var(--an-w-info);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.an-w-link {
|
|
358
|
+
color: var(--an-w-info);
|
|
359
|
+
font-weight: 500;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.an-w-button {
|
|
363
|
+
align-self: flex-start;
|
|
364
|
+
font: inherit;
|
|
365
|
+
padding: 6px 14px;
|
|
366
|
+
border-radius: var(--an-w-radius);
|
|
367
|
+
border: 1px solid var(--an-w-accent);
|
|
368
|
+
cursor: pointer;
|
|
369
|
+
}
|
|
370
|
+
.an-w-button.is-primary {
|
|
371
|
+
background: var(--an-w-accent);
|
|
372
|
+
color: var(--an-w-accent-ink);
|
|
373
|
+
}
|
|
374
|
+
.an-w-button.is-secondary {
|
|
375
|
+
background: transparent;
|
|
376
|
+
color: var(--an-w-ink);
|
|
377
|
+
border-color: var(--an-w-line);
|
|
378
|
+
}
|
|
379
|
+
.an-w-button:disabled,
|
|
380
|
+
.an-w-suggest button:disabled {
|
|
381
|
+
cursor: default;
|
|
382
|
+
opacity: 0.6;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.an-w-suggest {
|
|
386
|
+
display: flex;
|
|
387
|
+
flex-wrap: wrap;
|
|
388
|
+
gap: 6px;
|
|
389
|
+
}
|
|
390
|
+
.an-w-suggest button {
|
|
391
|
+
font: inherit;
|
|
392
|
+
padding: 6px 12px;
|
|
393
|
+
border-radius: 999px;
|
|
394
|
+
border: 1px solid var(--an-w-line);
|
|
395
|
+
background: transparent;
|
|
396
|
+
color: var(--an-w-ink);
|
|
397
|
+
cursor: pointer;
|
|
398
|
+
text-align: left;
|
|
399
|
+
}
|
|
400
|
+
.an-w-suggest button:hover:not(:disabled) {
|
|
401
|
+
border-color: var(--an-w-muted);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.an-w-divider {
|
|
405
|
+
border: 0;
|
|
406
|
+
border-top: 1px solid var(--an-w-line);
|
|
407
|
+
margin: 2px 0;
|
|
408
|
+
width: 100%;
|
|
409
|
+
}
|
package/react.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { Widget, WidgetPart } from './types.ts';
|
|
3
|
+
export { placeWidgets, type ReplyPiece } from './widgets.ts';
|
|
4
|
+
/** Every kind of part an agent may draw. */
|
|
5
|
+
export type WidgetKind = 'Column' | 'Row' | 'Card' | 'Text' | 'Stat' | 'KeyValue' | 'Table' | 'Chart' | 'Image' | 'List' | 'Note' | 'Badge' | 'Link' | 'Button' | 'Suggestions' | 'Divider';
|
|
6
|
+
/** What a replacement for one kind of part receives. */
|
|
7
|
+
export interface PartProps {
|
|
8
|
+
part: WidgetPart;
|
|
9
|
+
/** The part's children, already drawn (containers only). */
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
/** Send words as the reader's next message (Button, Suggestions). */
|
|
12
|
+
onAsk?: ((text: string) => void) | undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface WidgetViewProps {
|
|
15
|
+
widget: Widget;
|
|
16
|
+
/** Called with a Button's label or a tapped suggestion: send it as the next message. */
|
|
17
|
+
onAsk?: (text: string) => void;
|
|
18
|
+
/** Your own component for any kind of part, in place of the default. */
|
|
19
|
+
parts?: Partial<Record<WidgetKind, (props: PartProps) => ReactNode>>;
|
|
20
|
+
/** ISO currency code for charts and numbers marked as money. Default "USD". */
|
|
21
|
+
currency?: string;
|
|
22
|
+
/** Locale for numbers. Default: the reader's. */
|
|
23
|
+
locale?: string;
|
|
24
|
+
/** Whether a link or picture address may be opened. Default: https:// only. */
|
|
25
|
+
allowUrl?: (url: string, use: 'link' | 'image') => boolean;
|
|
26
|
+
className?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ReplyViewProps extends Omit<WidgetViewProps, 'widget' | 'className'> {
|
|
29
|
+
/** The reply's words, as `text` events or `done.reply` give them. */
|
|
30
|
+
text: string;
|
|
31
|
+
/** The reply's widgets, as `widget` events or `done.widgets` give them. */
|
|
32
|
+
widgets?: readonly Widget[] | undefined;
|
|
33
|
+
/** How to draw the words. Default: paragraphs. Pass your markdown renderer here. */
|
|
34
|
+
renderText?: (text: string) => ReactNode;
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
/** One widget, drawn from its root part. Draws nothing when there is no root yet. */
|
|
38
|
+
export declare function WidgetView(props: WidgetViewProps): import("react/jsx-runtime").JSX.Element | null;
|
|
39
|
+
/** A whole reply: its words, with each widget drawn where it sits. */
|
|
40
|
+
export declare function ReplyView({ text, widgets, renderText, className, ...widgetProps }: ReplyViewProps): import("react/jsx-runtime").JSX.Element;
|
package/react.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// Ready-made React views for the widgets an agent draws in its replies.
|
|
3
|
+
//
|
|
4
|
+
// import { ReplyView } from '@cerebro-labs/agentnava-sdk/react'
|
|
5
|
+
// import '@cerebro-labs/agentnava-sdk/react/styles.css'
|
|
6
|
+
//
|
|
7
|
+
// <ReplyView text={reply} widgets={widgets} onAsk={send} />
|
|
8
|
+
//
|
|
9
|
+
// React is optional for the SDK: only this entry needs it, and the rest of the
|
|
10
|
+
// package never imports it. Every kind of part has a default look (styles.css,
|
|
11
|
+
// themed through CSS variables), and any kind can be swapped for your own
|
|
12
|
+
// component with `parts`.
|
|
13
|
+
//
|
|
14
|
+
// A widget is written by the model, so it is drawn defensively: a kind this
|
|
15
|
+
// does not know, or a part missing a field, is skipped; each part is drawn
|
|
16
|
+
// once, even if two containers name it; links and pictures open only over
|
|
17
|
+
// https:// (narrow it further with `allowUrl`); and a widget that throws while
|
|
18
|
+
// drawing is left out rather than breaking the screen around it.
|
|
19
|
+
import { Component, Fragment } from 'react';
|
|
20
|
+
import { placeWidgets } from "./widgets.js";
|
|
21
|
+
export { placeWidgets } from "./widgets.js";
|
|
22
|
+
const str = (v) => (typeof v === 'string' || typeof v === 'number' ? String(v) : '');
|
|
23
|
+
const list = (v) => (Array.isArray(v) ? v : []);
|
|
24
|
+
const TONES = new Set(['high', 'medium', 'low', 'good', 'info']);
|
|
25
|
+
const toneOf = (v) => (typeof v === 'string' && TONES.has(v) ? v : 'info');
|
|
26
|
+
const httpsOnly = (url) => /^https:\/\//i.test(url);
|
|
27
|
+
/** A widget that throws while drawing is left out, never a crash of the screen. */
|
|
28
|
+
class Boundary extends Component {
|
|
29
|
+
state = { failed: false };
|
|
30
|
+
static getDerivedStateFromError() {
|
|
31
|
+
return { failed: true };
|
|
32
|
+
}
|
|
33
|
+
render() {
|
|
34
|
+
return this.state.failed ? null : this.props.children;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function Chart({ part, ctx }) {
|
|
38
|
+
const series = list(part.series)
|
|
39
|
+
.map((s) => ({
|
|
40
|
+
name: str(s?.name),
|
|
41
|
+
points: list(s?.points).filter((p) => typeof p?.y === 'number' && Number.isFinite(p.y)),
|
|
42
|
+
}))
|
|
43
|
+
.filter((s) => s.points.length > 0);
|
|
44
|
+
if (series.length === 0)
|
|
45
|
+
return null;
|
|
46
|
+
const xs = series[0].points.map((p) => str(p.x));
|
|
47
|
+
const ref = part.reference;
|
|
48
|
+
const refY = typeof ref?.y === 'number' && Number.isFinite(ref.y) ? ref.y : undefined;
|
|
49
|
+
const ys = [...series.flatMap((s) => s.points.map((p) => p.y)), ...(refY === undefined ? [] : [refY])];
|
|
50
|
+
const max = Math.max(...ys, 0) || 1;
|
|
51
|
+
const W = 320;
|
|
52
|
+
const H = 140;
|
|
53
|
+
const step = W / Math.max(xs.length, 1);
|
|
54
|
+
const fmt = (n) => (part.unit === 'currency' ? ctx.money(n) : part.unit === 'percent' ? `${ctx.number(n)}%` : ctx.number(n));
|
|
55
|
+
const yOf = (y) => H - (Math.max(y, 0) / max) * (H - 18);
|
|
56
|
+
const labelled = series.length === 1 && xs.length <= 6;
|
|
57
|
+
return (_jsxs("figure", { className: "an-w-chart", children: [str(part.title) && _jsx("figcaption", { children: str(part.title) }), _jsxs("svg", { viewBox: `0 0 ${W} ${H + 18}`, role: "img", "aria-label": str(part.title) || 'Chart', children: [series.map((s, si) => part.type === 'bar' ? (s.points.map((p, i) => {
|
|
58
|
+
const bw = (step * 0.7) / series.length;
|
|
59
|
+
const x = i * step + step * 0.15 + si * bw;
|
|
60
|
+
const y = yOf(p.y);
|
|
61
|
+
return (_jsxs("g", { children: [_jsx("rect", { className: `an-w-s${si % 4}`, x: x, y: y, width: bw, height: H - y, rx: 2, children: _jsx("title", { children: `${str(p.x)}: ${fmt(p.y)}` }) }), labelled && (_jsx("text", { x: x + bw / 2, y: y - 4, textAnchor: "middle", children: fmt(p.y) }))] }, `${si}-${i}`));
|
|
62
|
+
})) : (_jsxs("g", { children: [_jsx("polyline", { className: `an-w-line an-w-s${si % 4}${part.type === 'area' ? ' is-area' : ''}`, points: s.points.map((p, i) => `${i * step + step / 2},${yOf(p.y)}`).join(' ') }), s.points.map((p, i) => (_jsxs("g", { children: [_jsx("circle", { className: `an-w-s${si % 4}`, cx: i * step + step / 2, cy: yOf(p.y), r: 3, children: _jsx("title", { children: `${str(p.x)}: ${fmt(p.y)}` }) }), labelled && (_jsx("text", { x: i * step + step / 2, y: yOf(p.y) - 7, textAnchor: "middle", children: fmt(p.y) }))] }, i)))] }, si))), refY !== undefined && (_jsxs("g", { className: "an-w-ref", children: [_jsx("line", { x1: 0, x2: W, y1: yOf(refY), y2: yOf(refY) }), str(ref?.label) && (_jsx("text", { x: W, y: yOf(refY) - 4, textAnchor: "end", children: str(ref?.label) }))] })), xs.map((x, i) => (_jsx("text", { x: i * step + step / 2, y: H + 14, textAnchor: "middle", children: x }, i)))] }), series.length > 1 && (_jsx("div", { className: "an-w-legend", children: series.map((s, si) => (_jsxs("span", { children: [_jsx("i", { className: `an-w-s${si % 4}` }), s.name] }, si))) }))] }));
|
|
63
|
+
}
|
|
64
|
+
/** The default look of one part. `kids` is its children, already drawn. */
|
|
65
|
+
function defaultPart(part, kids, ctx) {
|
|
66
|
+
const onAsk = ctx.props.onAsk;
|
|
67
|
+
switch (part.component) {
|
|
68
|
+
case 'Column':
|
|
69
|
+
return _jsx("div", { className: `an-w-col an-w-gap-${['small', 'large'].includes(str(part.gap)) ? str(part.gap) : 'medium'}`, children: kids });
|
|
70
|
+
case 'Row':
|
|
71
|
+
return _jsx("div", { className: `an-w-row${part.scroll === true ? ' is-scroll' : ''}`, children: kids });
|
|
72
|
+
case 'Card': {
|
|
73
|
+
const image = ctx.url(part.image, 'image');
|
|
74
|
+
const href = ctx.url(part.href, 'link');
|
|
75
|
+
const body = (_jsxs("div", { className: "an-w-card", children: [image && _jsx("img", { src: image, alt: str(part.imageAlt), referrerPolicy: "no-referrer", loading: "lazy" }), _jsx("div", { className: "an-w-card-body", children: kids })] }));
|
|
76
|
+
return href ? (_jsx("a", { className: "an-w-card-link", href: href, target: "_blank", rel: "noreferrer noopener", children: body })) : (body);
|
|
77
|
+
}
|
|
78
|
+
case 'Text': {
|
|
79
|
+
if (!str(part.text))
|
|
80
|
+
return null;
|
|
81
|
+
const v = ['title', 'heading', 'caption'].includes(str(part.variant)) ? str(part.variant) : 'body';
|
|
82
|
+
return _jsx("p", { className: `an-w-text is-${v}`, children: str(part.text) });
|
|
83
|
+
}
|
|
84
|
+
case 'Stat':
|
|
85
|
+
if (!str(part.value))
|
|
86
|
+
return null;
|
|
87
|
+
return (_jsxs("div", { className: "an-w-stat", children: [_jsx("strong", { children: str(part.value) }), str(part.label) && _jsx("span", { children: str(part.label) }), str(part.caption) && _jsx("small", { children: str(part.caption) })] }));
|
|
88
|
+
case 'KeyValue': {
|
|
89
|
+
const rows = list(part.rows).filter((r) => str(r?.label) || str(r?.value));
|
|
90
|
+
if (rows.length === 0)
|
|
91
|
+
return null;
|
|
92
|
+
return (_jsxs("div", { className: "an-w-kv", children: [str(part.title) && _jsx("div", { className: "an-w-title", children: str(part.title) }), _jsx("dl", { children: rows.map((r, i) => (_jsxs("div", { className: r?.emphasis ? 'is-total' : undefined, children: [_jsx("dt", { children: str(r?.label) }), _jsx("dd", { children: str(r?.value) })] }, i))) })] }));
|
|
93
|
+
}
|
|
94
|
+
case 'Table': {
|
|
95
|
+
const cols = list(part.columns).map(str);
|
|
96
|
+
const rows = list(part.rows).filter(Array.isArray);
|
|
97
|
+
if (cols.length === 0 && rows.length === 0)
|
|
98
|
+
return null;
|
|
99
|
+
return (_jsxs("div", { className: "an-w-table", children: [str(part.title) && _jsx("div", { className: "an-w-title", children: str(part.title) }), _jsxs("table", { children: [cols.length > 0 && (_jsx("thead", { children: _jsx("tr", { children: cols.map((c, j) => (_jsx("th", { children: c }, j))) }) })), _jsx("tbody", { children: rows.map((r, i) => (_jsx("tr", { children: r.map((c, j) => (_jsx("td", { className: typeof c === 'number' ? 'is-num' : undefined, children: typeof c === 'number' ? ctx.number(c) : str(c) }, j))) }, i))) })] })] }));
|
|
100
|
+
}
|
|
101
|
+
case 'Chart':
|
|
102
|
+
return _jsx(Chart, { part: part, ctx: ctx });
|
|
103
|
+
case 'Image': {
|
|
104
|
+
const url = ctx.url(part.url, 'image');
|
|
105
|
+
return url ? (_jsxs("figure", { className: "an-w-image", children: [_jsx("img", { src: url, alt: str(part.alt), referrerPolicy: "no-referrer", loading: "lazy" }), str(part.caption) && _jsx("figcaption", { children: str(part.caption) })] })) : null;
|
|
106
|
+
}
|
|
107
|
+
case 'List': {
|
|
108
|
+
const items = list(part.items).filter((it) => str(it?.title));
|
|
109
|
+
if (items.length === 0)
|
|
110
|
+
return null;
|
|
111
|
+
const Tag = part.ordered === true ? 'ol' : 'ul';
|
|
112
|
+
return (_jsxs("div", { className: "an-w-list", children: [str(part.title) && _jsx("div", { className: "an-w-title", children: str(part.title) }), _jsx(Tag, { children: items.map((it, i) => (_jsxs("li", { children: [_jsx("i", { className: `an-w-dot is-${toneOf(it?.tone)}`, "aria-hidden": "true" }), _jsxs("div", { children: [_jsx("strong", { children: str(it?.title) }), str(it?.detail) && _jsx("span", { children: str(it?.detail) })] }), str(it?.meta) && _jsx("small", { children: str(it?.meta) })] }, i))) })] }));
|
|
113
|
+
}
|
|
114
|
+
case 'Note':
|
|
115
|
+
if (!str(part.text))
|
|
116
|
+
return null;
|
|
117
|
+
return (_jsxs("div", { className: "an-w-note", children: [str(part.title) && _jsx("strong", { children: str(part.title) }), _jsx("span", { children: str(part.text) })] }));
|
|
118
|
+
case 'Badge':
|
|
119
|
+
return str(part.text) ? _jsx("span", { className: `an-w-badge is-${toneOf(part.tone)}`, children: str(part.text) }) : null;
|
|
120
|
+
case 'Link': {
|
|
121
|
+
const url = ctx.url(part.url, 'link');
|
|
122
|
+
return url && str(part.label) ? (_jsx("a", { className: "an-w-link", href: url, target: "_blank", rel: "noreferrer noopener", children: str(part.label) })) : null;
|
|
123
|
+
}
|
|
124
|
+
case 'Button':
|
|
125
|
+
if (!str(part.label))
|
|
126
|
+
return null;
|
|
127
|
+
return (_jsx("button", { type: "button", className: `an-w-button is-${part.variant === 'secondary' ? 'secondary' : 'primary'}`, disabled: !onAsk, onClick: () => onAsk?.(str(part.label)), children: str(part.label) }));
|
|
128
|
+
case 'Suggestions': {
|
|
129
|
+
const options = list(part.options).map(str).filter(Boolean);
|
|
130
|
+
if (options.length === 0)
|
|
131
|
+
return null;
|
|
132
|
+
return (_jsx("div", { className: "an-w-suggest", children: options.map((o, i) => (_jsx("button", { type: "button", disabled: !onAsk, onClick: () => onAsk?.(o), children: o }, i))) }));
|
|
133
|
+
}
|
|
134
|
+
case 'Divider':
|
|
135
|
+
return _jsx("hr", { className: "an-w-divider" });
|
|
136
|
+
default:
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const CONTAINERS = new Set(['Column', 'Row', 'Card']);
|
|
141
|
+
// A plain function, not a component: the set of parts already drawn lives for
|
|
142
|
+
// one render of the widget. As a component, React's development mode would draw
|
|
143
|
+
// each part twice and find every one "already drawn" on its second pass.
|
|
144
|
+
function draw(id, ctx) {
|
|
145
|
+
const part = ctx.byId.get(id);
|
|
146
|
+
// A part listed twice, or a loop of containers, is drawn once.
|
|
147
|
+
if (!part || ctx.seen.has(id))
|
|
148
|
+
return null;
|
|
149
|
+
ctx.seen.add(id);
|
|
150
|
+
const kids = CONTAINERS.has(part.component)
|
|
151
|
+
? list(part.children)
|
|
152
|
+
.filter((k) => typeof k === 'string')
|
|
153
|
+
.map((k) => _jsx(Fragment, { children: draw(k, ctx) }, k))
|
|
154
|
+
: undefined;
|
|
155
|
+
const own = ctx.props.parts?.[part.component];
|
|
156
|
+
return own ? own({ part, children: kids, onAsk: ctx.props.onAsk }) : defaultPart(part, kids, ctx);
|
|
157
|
+
}
|
|
158
|
+
/** One widget, drawn from its root part. Draws nothing when there is no root yet. */
|
|
159
|
+
export function WidgetView(props) {
|
|
160
|
+
const { widget, currency = 'USD', locale, allowUrl } = props;
|
|
161
|
+
const byId = new Map();
|
|
162
|
+
for (const p of Array.isArray(widget?.components) ? widget.components : []) {
|
|
163
|
+
if (p && typeof p === 'object' && typeof p.id === 'string' && typeof p.component === 'string' && !byId.has(p.id))
|
|
164
|
+
byId.set(p.id, p);
|
|
165
|
+
}
|
|
166
|
+
if (!byId.has('root'))
|
|
167
|
+
return null;
|
|
168
|
+
let moneyFormat;
|
|
169
|
+
try {
|
|
170
|
+
moneyFormat = new Intl.NumberFormat(locale, { style: 'currency', currency, maximumFractionDigits: 0 });
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
moneyFormat = new Intl.NumberFormat(locale, { maximumFractionDigits: 0 });
|
|
174
|
+
}
|
|
175
|
+
const numberFormat = new Intl.NumberFormat(locale);
|
|
176
|
+
const ctx = {
|
|
177
|
+
byId,
|
|
178
|
+
seen: new Set(),
|
|
179
|
+
props,
|
|
180
|
+
money: (n) => moneyFormat.format(n),
|
|
181
|
+
number: (n) => numberFormat.format(n),
|
|
182
|
+
url: (v, use) => (typeof v === 'string' && httpsOnly(v) && (allowUrl ? allowUrl(v, use) : true) ? v : undefined),
|
|
183
|
+
};
|
|
184
|
+
return (_jsx(Boundary, { children: _jsx("div", { className: `an-w${props.className ? ` ${props.className}` : ''}`, "data-surface": widget.surfaceId, children: draw('root', ctx) }) }));
|
|
185
|
+
}
|
|
186
|
+
function Paragraphs({ text }) {
|
|
187
|
+
return (_jsx(_Fragment, { children: text
|
|
188
|
+
.trim()
|
|
189
|
+
.split(/\n{2,}/)
|
|
190
|
+
.map((p, i) => (_jsx("p", { className: "an-reply-text", children: p.split('\n').map((line, j) => (_jsxs(Fragment, { children: [j > 0 && _jsx("br", {}), line] }, j))) }, i))) }));
|
|
191
|
+
}
|
|
192
|
+
/** A whole reply: its words, with each widget drawn where it sits. */
|
|
193
|
+
export function ReplyView({ text, widgets, renderText, className, ...widgetProps }) {
|
|
194
|
+
return (_jsx("div", { className: `an-reply${className ? ` ${className}` : ''}`, children: placeWidgets(text, widgets ?? []).map((piece, i) => piece.kind === 'text' ? (_jsx(Fragment, { children: renderText ? renderText(piece.text) : _jsx(Paragraphs, { text: piece.text }) }, `t${i}`)) : (_jsx(WidgetView, { widget: piece.widget, ...widgetProps }, piece.widget.surfaceId))) }));
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=react.js.map
|
package/react.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"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","sourcesContent":["// Ready-made React views for the widgets an agent draws in its replies.\n//\n// import { ReplyView } from '@cerebro-labs/agentnava-sdk/react'\n// import '@cerebro-labs/agentnava-sdk/react/styles.css'\n//\n// <ReplyView text={reply} widgets={widgets} onAsk={send} />\n//\n// React is optional for the SDK: only this entry needs it, and the rest of the\n// package never imports it. Every kind of part has a default look (styles.css,\n// themed through CSS variables), and any kind can be swapped for your own\n// component with `parts`.\n//\n// A widget is written by the model, so it is drawn defensively: a kind this\n// does not know, or a part missing a field, is skipped; each part is drawn\n// once, even if two containers name it; links and pictures open only over\n// https:// (narrow it further with `allowUrl`); and a widget that throws while\n// drawing is left out rather than breaking the screen around it.\n\nimport { Component, Fragment, type ReactNode } from 'react';\nimport type { Widget, WidgetPart } from './types.ts';\nimport { placeWidgets } from './widgets.ts';\n\nexport { placeWidgets, type ReplyPiece } from './widgets.ts';\n\n/** Every kind of part an agent may draw. */\nexport type WidgetKind =\n\t| 'Column'\n\t| 'Row'\n\t| 'Card'\n\t| 'Text'\n\t| 'Stat'\n\t| 'KeyValue'\n\t| 'Table'\n\t| 'Chart'\n\t| 'Image'\n\t| 'List'\n\t| 'Note'\n\t| 'Badge'\n\t| 'Link'\n\t| 'Button'\n\t| 'Suggestions'\n\t| 'Divider';\n\n/** What a replacement for one kind of part receives. */\nexport interface PartProps {\n\tpart: WidgetPart;\n\t/** The part's children, already drawn (containers only). */\n\tchildren?: ReactNode;\n\t/** Send words as the reader's next message (Button, Suggestions). */\n\tonAsk?: ((text: string) => void) | undefined;\n}\n\nexport interface WidgetViewProps {\n\twidget: Widget;\n\t/** Called with a Button's label or a tapped suggestion: send it as the next message. */\n\tonAsk?: (text: string) => void;\n\t/** Your own component for any kind of part, in place of the default. */\n\tparts?: Partial<Record<WidgetKind, (props: PartProps) => ReactNode>>;\n\t/** ISO currency code for charts and numbers marked as money. Default \"USD\". */\n\tcurrency?: string;\n\t/** Locale for numbers. Default: the reader's. */\n\tlocale?: string;\n\t/** Whether a link or picture address may be opened. Default: https:// only. */\n\tallowUrl?: (url: string, use: 'link' | 'image') => boolean;\n\tclassName?: string;\n}\n\nexport interface ReplyViewProps extends Omit<WidgetViewProps, 'widget' | 'className'> {\n\t/** The reply's words, as `text` events or `done.reply` give them. */\n\ttext: string;\n\t/** The reply's widgets, as `widget` events or `done.widgets` give them. */\n\twidgets?: readonly Widget[] | undefined;\n\t/** How to draw the words. Default: paragraphs. Pass your markdown renderer here. */\n\trenderText?: (text: string) => ReactNode;\n\tclassName?: string;\n}\n\nconst str = (v: unknown): string => (typeof v === 'string' || typeof v === 'number' ? String(v) : '');\nconst list = <T = unknown,>(v: unknown): T[] => (Array.isArray(v) ? (v as T[]) : []);\nconst TONES = new Set(['high', 'medium', 'low', 'good', 'info']);\nconst toneOf = (v: unknown): string => (typeof v === 'string' && TONES.has(v) ? v : 'info');\nconst httpsOnly = (url: string) => /^https:\\/\\//i.test(url);\n\n/** A widget that throws while drawing is left out, never a crash of the screen. */\nclass Boundary extends Component<{ children: ReactNode }, { failed: boolean }> {\n\toverride state = { failed: false };\n\tstatic getDerivedStateFromError() {\n\t\treturn { failed: true };\n\t}\n\toverride render() {\n\t\treturn this.state.failed ? null : this.props.children;\n\t}\n}\n\ninterface Ctx {\n\tbyId: Map<string, WidgetPart>;\n\tseen: Set<string>;\n\tprops: WidgetViewProps;\n\tmoney: (n: number) => string;\n\tnumber: (n: number) => string;\n\turl: (v: unknown, use: 'link' | 'image') => string | undefined;\n}\n\nfunction Chart({ part, ctx }: { part: WidgetPart; ctx: Ctx }) {\n\tconst series = list<{ name?: unknown; points?: unknown }>(part.series)\n\t\t.map((s) => ({\n\t\t\tname: str(s?.name),\n\t\t\tpoints: list<{ x?: unknown; y?: unknown }>(s?.points).filter((p) => typeof p?.y === 'number' && Number.isFinite(p.y)),\n\t\t}))\n\t\t.filter((s) => s.points.length > 0);\n\tif (series.length === 0) return null;\n\tconst xs = series[0]!.points.map((p) => str(p.x));\n\tconst ref = part.reference as { y?: unknown; label?: unknown } | undefined;\n\tconst refY = typeof ref?.y === 'number' && Number.isFinite(ref.y) ? ref.y : undefined;\n\tconst ys = [...series.flatMap((s) => s.points.map((p) => p.y as number)), ...(refY === undefined ? [] : [refY])];\n\tconst max = Math.max(...ys, 0) || 1;\n\tconst W = 320;\n\tconst H = 140;\n\tconst step = W / Math.max(xs.length, 1);\n\tconst fmt = (n: number) => (part.unit === 'currency' ? ctx.money(n) : part.unit === 'percent' ? `${ctx.number(n)}%` : ctx.number(n));\n\tconst yOf = (y: number) => H - (Math.max(y, 0) / max) * (H - 18);\n\tconst labelled = series.length === 1 && xs.length <= 6;\n\treturn (\n\t\t<figure className=\"an-w-chart\">\n\t\t\t{str(part.title) && <figcaption>{str(part.title)}</figcaption>}\n\t\t\t<svg viewBox={`0 0 ${W} ${H + 18}`} role=\"img\" aria-label={str(part.title) || 'Chart'}>\n\t\t\t\t{series.map((s, si) =>\n\t\t\t\t\tpart.type === 'bar' ? (\n\t\t\t\t\t\ts.points.map((p, i) => {\n\t\t\t\t\t\t\tconst bw = (step * 0.7) / series.length;\n\t\t\t\t\t\t\tconst x = i * step + step * 0.15 + si * bw;\n\t\t\t\t\t\t\tconst y = yOf(p.y as number);\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<g key={`${si}-${i}`}>\n\t\t\t\t\t\t\t\t\t<rect className={`an-w-s${si % 4}`} x={x} y={y} width={bw} height={H - y} rx={2}>\n\t\t\t\t\t\t\t\t\t\t<title>{`${str(p.x)}: ${fmt(p.y as number)}`}</title>\n\t\t\t\t\t\t\t\t\t</rect>\n\t\t\t\t\t\t\t\t\t{labelled && (\n\t\t\t\t\t\t\t\t\t\t<text x={x + bw / 2} y={y - 4} textAnchor=\"middle\">\n\t\t\t\t\t\t\t\t\t\t\t{fmt(p.y as number)}\n\t\t\t\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</g>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<g key={si}>\n\t\t\t\t\t\t\t<polyline\n\t\t\t\t\t\t\t\tclassName={`an-w-line an-w-s${si % 4}${part.type === 'area' ? ' is-area' : ''}`}\n\t\t\t\t\t\t\t\tpoints={s.points.map((p, i) => `${i * step + step / 2},${yOf(p.y as number)}`).join(' ')}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t{s.points.map((p, i) => (\n\t\t\t\t\t\t\t\t<g key={i}>\n\t\t\t\t\t\t\t\t\t<circle className={`an-w-s${si % 4}`} cx={i * step + step / 2} cy={yOf(p.y as number)} r={3}>\n\t\t\t\t\t\t\t\t\t\t<title>{`${str(p.x)}: ${fmt(p.y as number)}`}</title>\n\t\t\t\t\t\t\t\t\t</circle>\n\t\t\t\t\t\t\t\t\t{labelled && (\n\t\t\t\t\t\t\t\t\t\t<text x={i * step + step / 2} y={yOf(p.y as number) - 7} textAnchor=\"middle\">\n\t\t\t\t\t\t\t\t\t\t\t{fmt(p.y as number)}\n\t\t\t\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</g>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t),\n\t\t\t\t)}\n\t\t\t\t{refY !== undefined && (\n\t\t\t\t\t<g className=\"an-w-ref\">\n\t\t\t\t\t\t<line x1={0} x2={W} y1={yOf(refY)} y2={yOf(refY)} />\n\t\t\t\t\t\t{str(ref?.label) && (\n\t\t\t\t\t\t\t<text x={W} y={yOf(refY) - 4} textAnchor=\"end\">\n\t\t\t\t\t\t\t\t{str(ref?.label)}\n\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</g>\n\t\t\t\t)}\n\t\t\t\t{xs.map((x, i) => (\n\t\t\t\t\t<text key={i} x={i * step + step / 2} y={H + 14} textAnchor=\"middle\">\n\t\t\t\t\t\t{x}\n\t\t\t\t\t</text>\n\t\t\t\t))}\n\t\t\t</svg>\n\t\t\t{series.length > 1 && (\n\t\t\t\t<div className=\"an-w-legend\">\n\t\t\t\t\t{series.map((s, si) => (\n\t\t\t\t\t\t<span key={si}>\n\t\t\t\t\t\t\t<i className={`an-w-s${si % 4}`} />\n\t\t\t\t\t\t\t{s.name}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</figure>\n\t);\n}\n\n/** The default look of one part. `kids` is its children, already drawn. */\nfunction defaultPart(part: WidgetPart, kids: ReactNode, ctx: Ctx): ReactNode {\n\tconst onAsk = ctx.props.onAsk;\n\tswitch (part.component) {\n\t\tcase 'Column':\n\t\t\treturn <div className={`an-w-col an-w-gap-${['small', 'large'].includes(str(part.gap)) ? str(part.gap) : 'medium'}`}>{kids}</div>;\n\t\tcase 'Row':\n\t\t\treturn <div className={`an-w-row${part.scroll === true ? ' is-scroll' : ''}`}>{kids}</div>;\n\t\tcase 'Card': {\n\t\t\tconst image = ctx.url(part.image, 'image');\n\t\t\tconst href = ctx.url(part.href, 'link');\n\t\t\tconst body = (\n\t\t\t\t<div className=\"an-w-card\">\n\t\t\t\t\t{image && <img src={image} alt={str(part.imageAlt)} referrerPolicy=\"no-referrer\" loading=\"lazy\" />}\n\t\t\t\t\t<div className=\"an-w-card-body\">{kids}</div>\n\t\t\t\t</div>\n\t\t\t);\n\t\t\treturn href ? (\n\t\t\t\t<a className=\"an-w-card-link\" href={href} target=\"_blank\" rel=\"noreferrer noopener\">\n\t\t\t\t\t{body}\n\t\t\t\t</a>\n\t\t\t) : (\n\t\t\t\tbody\n\t\t\t);\n\t\t}\n\t\tcase 'Text': {\n\t\t\tif (!str(part.text)) return null;\n\t\t\tconst v = ['title', 'heading', 'caption'].includes(str(part.variant)) ? str(part.variant) : 'body';\n\t\t\treturn <p className={`an-w-text is-${v}`}>{str(part.text)}</p>;\n\t\t}\n\t\tcase 'Stat':\n\t\t\tif (!str(part.value)) return null;\n\t\t\treturn (\n\t\t\t\t<div className=\"an-w-stat\">\n\t\t\t\t\t<strong>{str(part.value)}</strong>\n\t\t\t\t\t{str(part.label) && <span>{str(part.label)}</span>}\n\t\t\t\t\t{str(part.caption) && <small>{str(part.caption)}</small>}\n\t\t\t\t</div>\n\t\t\t);\n\t\tcase 'KeyValue': {\n\t\t\tconst rows = list<{ label?: unknown; value?: unknown; emphasis?: unknown }>(part.rows).filter((r) => str(r?.label) || str(r?.value));\n\t\t\tif (rows.length === 0) return null;\n\t\t\treturn (\n\t\t\t\t<div className=\"an-w-kv\">\n\t\t\t\t\t{str(part.title) && <div className=\"an-w-title\">{str(part.title)}</div>}\n\t\t\t\t\t<dl>\n\t\t\t\t\t\t{rows.map((r, i) => (\n\t\t\t\t\t\t\t<div key={i} className={r?.emphasis ? 'is-total' : undefined}>\n\t\t\t\t\t\t\t\t<dt>{str(r?.label)}</dt>\n\t\t\t\t\t\t\t\t<dd>{str(r?.value)}</dd>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</dl>\n\t\t\t\t</div>\n\t\t\t);\n\t\t}\n\t\tcase 'Table': {\n\t\t\tconst cols = list(part.columns).map(str);\n\t\t\tconst rows = list(part.rows).filter(Array.isArray) as unknown[][];\n\t\t\tif (cols.length === 0 && rows.length === 0) return null;\n\t\t\treturn (\n\t\t\t\t<div className=\"an-w-table\">\n\t\t\t\t\t{str(part.title) && <div className=\"an-w-title\">{str(part.title)}</div>}\n\t\t\t\t\t<table>\n\t\t\t\t\t\t{cols.length > 0 && (\n\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t{cols.map((c, j) => (\n\t\t\t\t\t\t\t\t\t\t<th key={j}>{c}</th>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t{rows.map((r, i) => (\n\t\t\t\t\t\t\t\t<tr key={i}>\n\t\t\t\t\t\t\t\t\t{r.map((c, j) => (\n\t\t\t\t\t\t\t\t\t\t<td key={j} className={typeof c === 'number' ? 'is-num' : undefined}>\n\t\t\t\t\t\t\t\t\t\t\t{typeof c === 'number' ? ctx.number(c) : str(c)}\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</tbody>\n\t\t\t\t\t</table>\n\t\t\t\t</div>\n\t\t\t);\n\t\t}\n\t\tcase 'Chart':\n\t\t\treturn <Chart part={part} ctx={ctx} />;\n\t\tcase 'Image': {\n\t\t\tconst url = ctx.url(part.url, 'image');\n\t\t\treturn url ? (\n\t\t\t\t<figure className=\"an-w-image\">\n\t\t\t\t\t<img src={url} alt={str(part.alt)} referrerPolicy=\"no-referrer\" loading=\"lazy\" />\n\t\t\t\t\t{str(part.caption) && <figcaption>{str(part.caption)}</figcaption>}\n\t\t\t\t</figure>\n\t\t\t) : null;\n\t\t}\n\t\tcase 'List': {\n\t\t\tconst items = list<{ title?: unknown; detail?: unknown; meta?: unknown; tone?: unknown }>(part.items).filter((it) => str(it?.title));\n\t\t\tif (items.length === 0) return null;\n\t\t\tconst Tag = part.ordered === true ? 'ol' : 'ul';\n\t\t\treturn (\n\t\t\t\t<div className=\"an-w-list\">\n\t\t\t\t\t{str(part.title) && <div className=\"an-w-title\">{str(part.title)}</div>}\n\t\t\t\t\t<Tag>\n\t\t\t\t\t\t{items.map((it, i) => (\n\t\t\t\t\t\t\t<li key={i}>\n\t\t\t\t\t\t\t\t<i className={`an-w-dot is-${toneOf(it?.tone)}`} aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t\t<strong>{str(it?.title)}</strong>\n\t\t\t\t\t\t\t\t\t{str(it?.detail) && <span>{str(it?.detail)}</span>}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t{str(it?.meta) && <small>{str(it?.meta)}</small>}\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Tag>\n\t\t\t\t</div>\n\t\t\t);\n\t\t}\n\t\tcase 'Note':\n\t\t\tif (!str(part.text)) return null;\n\t\t\treturn (\n\t\t\t\t<div className=\"an-w-note\">\n\t\t\t\t\t{str(part.title) && <strong>{str(part.title)}</strong>}\n\t\t\t\t\t<span>{str(part.text)}</span>\n\t\t\t\t</div>\n\t\t\t);\n\t\tcase 'Badge':\n\t\t\treturn str(part.text) ? <span className={`an-w-badge is-${toneOf(part.tone)}`}>{str(part.text)}</span> : null;\n\t\tcase 'Link': {\n\t\t\tconst url = ctx.url(part.url, 'link');\n\t\t\treturn url && str(part.label) ? (\n\t\t\t\t<a className=\"an-w-link\" href={url} target=\"_blank\" rel=\"noreferrer noopener\">\n\t\t\t\t\t{str(part.label)}\n\t\t\t\t</a>\n\t\t\t) : null;\n\t\t}\n\t\tcase 'Button':\n\t\t\tif (!str(part.label)) return null;\n\t\t\treturn (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName={`an-w-button is-${part.variant === 'secondary' ? 'secondary' : 'primary'}`}\n\t\t\t\t\tdisabled={!onAsk}\n\t\t\t\t\tonClick={() => onAsk?.(str(part.label))}\n\t\t\t\t>\n\t\t\t\t\t{str(part.label)}\n\t\t\t\t</button>\n\t\t\t);\n\t\tcase 'Suggestions': {\n\t\t\tconst options = list(part.options).map(str).filter(Boolean);\n\t\t\tif (options.length === 0) return null;\n\t\t\treturn (\n\t\t\t\t<div className=\"an-w-suggest\">\n\t\t\t\t\t{options.map((o, i) => (\n\t\t\t\t\t\t<button key={i} type=\"button\" disabled={!onAsk} onClick={() => onAsk?.(o)}>\n\t\t\t\t\t\t\t{o}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t);\n\t\t}\n\t\tcase 'Divider':\n\t\t\treturn <hr className=\"an-w-divider\" />;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nconst CONTAINERS = new Set(['Column', 'Row', 'Card']);\n\n// A plain function, not a component: the set of parts already drawn lives for\n// one render of the widget. As a component, React's development mode would draw\n// each part twice and find every one \"already drawn\" on its second pass.\nfunction draw(id: string, ctx: Ctx): ReactNode {\n\tconst part = ctx.byId.get(id);\n\t// A part listed twice, or a loop of containers, is drawn once.\n\tif (!part || ctx.seen.has(id)) return null;\n\tctx.seen.add(id);\n\tconst kids = CONTAINERS.has(part.component)\n\t\t? list(part.children)\n\t\t\t\t.filter((k): k is string => typeof k === 'string')\n\t\t\t\t.map((k) => <Fragment key={k}>{draw(k, ctx)}</Fragment>)\n\t\t: undefined;\n\tconst own = ctx.props.parts?.[part.component as WidgetKind];\n\treturn own ? own({ part, children: kids, onAsk: ctx.props.onAsk }) : defaultPart(part, kids, ctx);\n}\n\n/** One widget, drawn from its root part. Draws nothing when there is no root yet. */\nexport function WidgetView(props: WidgetViewProps) {\n\tconst { widget, currency = 'USD', locale, allowUrl } = props;\n\tconst byId = new Map<string, WidgetPart>();\n\tfor (const p of Array.isArray(widget?.components) ? widget.components : []) {\n\t\tif (p && typeof p === 'object' && typeof p.id === 'string' && typeof p.component === 'string' && !byId.has(p.id)) byId.set(p.id, p);\n\t}\n\tif (!byId.has('root')) return null;\n\tlet moneyFormat: Intl.NumberFormat;\n\ttry {\n\t\tmoneyFormat = new Intl.NumberFormat(locale, { style: 'currency', currency, maximumFractionDigits: 0 });\n\t} catch {\n\t\tmoneyFormat = new Intl.NumberFormat(locale, { maximumFractionDigits: 0 });\n\t}\n\tconst numberFormat = new Intl.NumberFormat(locale);\n\tconst ctx: Ctx = {\n\t\tbyId,\n\t\tseen: new Set(),\n\t\tprops,\n\t\tmoney: (n) => moneyFormat.format(n),\n\t\tnumber: (n) => numberFormat.format(n),\n\t\turl: (v, use) => (typeof v === 'string' && httpsOnly(v) && (allowUrl ? allowUrl(v, use) : true) ? v : undefined),\n\t};\n\treturn (\n\t\t<Boundary>\n\t\t\t<div className={`an-w${props.className ? ` ${props.className}` : ''}`} data-surface={widget.surfaceId}>\n\t\t\t\t{draw('root', ctx)}\n\t\t\t</div>\n\t\t</Boundary>\n\t);\n}\n\nfunction Paragraphs({ text }: { text: string }) {\n\treturn (\n\t\t<>\n\t\t\t{text\n\t\t\t\t.trim()\n\t\t\t\t.split(/\\n{2,}/)\n\t\t\t\t.map((p, i) => (\n\t\t\t\t\t<p key={i} className=\"an-reply-text\">\n\t\t\t\t\t\t{p.split('\\n').map((line, j) => (\n\t\t\t\t\t\t\t<Fragment key={j}>\n\t\t\t\t\t\t\t\t{j > 0 && <br />}\n\t\t\t\t\t\t\t\t{line}\n\t\t\t\t\t\t\t</Fragment>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</p>\n\t\t\t\t))}\n\t\t</>\n\t);\n}\n\n/** A whole reply: its words, with each widget drawn where it sits. */\nexport function ReplyView({ text, widgets, renderText, className, ...widgetProps }: ReplyViewProps) {\n\treturn (\n\t\t<div className={`an-reply${className ? ` ${className}` : ''}`}>\n\t\t\t{placeWidgets(text, widgets ?? []).map((piece, i) =>\n\t\t\t\tpiece.kind === 'text' ? (\n\t\t\t\t\t<Fragment key={`t${i}`}>{renderText ? renderText(piece.text) : <Paragraphs text={piece.text} />}</Fragment>\n\t\t\t\t) : (\n\t\t\t\t\t<WidgetView key={piece.widget.surfaceId} widget={piece.widget} {...widgetProps} />\n\t\t\t\t),\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"]}
|
package/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.
|
|
1
|
+
export declare const SDK_VERSION = "0.51.0";
|
package/version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// GENERATED by scripts/regen-version.mjs. Do not edit: run `bun run regen:version`
|
|
2
2
|
// after bumping the version in package.json. tests/version.test.ts fails if
|
|
3
3
|
// this drifts.
|
|
4
|
-
export const SDK_VERSION = '0.
|
|
4
|
+
export const SDK_VERSION = '0.51.0';
|
|
5
5
|
//# sourceMappingURL=version.js.map
|
package/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,4EAA4E;AAC5E,eAAe;AACf,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC","sourcesContent":["// GENERATED by scripts/regen-version.mjs. Do not edit: run `bun run regen:version`\n// after bumping the version in package.json. tests/version.test.ts fails if\n// this drifts.\nexport const SDK_VERSION = '0.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,4EAA4E;AAC5E,eAAe;AACf,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC","sourcesContent":["// GENERATED by scripts/regen-version.mjs. Do not edit: run `bun run regen:version`\n// after bumping the version in package.json. tests/version.test.ts fails if\n// this drifts.\nexport const SDK_VERSION = '0.51.0';\n"]}
|
package/widgets.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Widget } from './types.ts';
|
|
2
|
+
/** One piece of a reply in reading order: some words, or one widget. */
|
|
3
|
+
export type ReplyPiece = {
|
|
4
|
+
kind: 'text';
|
|
5
|
+
text: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: 'widget';
|
|
8
|
+
widget: Widget;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* A reply's words with each widget placed where it sits. Pieces of words that
|
|
12
|
+
* are only whitespace are left out. A widget whose `at` is past the end (a reply
|
|
13
|
+
* still arriving) goes at the end, and two widgets at one place keep their order.
|
|
14
|
+
*/
|
|
15
|
+
export declare function placeWidgets(text: string, widgets?: readonly Widget[]): ReplyPiece[];
|
package/widgets.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Placing widgets in a reply, with no UI framework.
|
|
2
|
+
//
|
|
3
|
+
// A widget arrives with `at`, a character count into the reply's words. A
|
|
4
|
+
// screen that draws widgets needs the reply as pieces in reading order: words,
|
|
5
|
+
// a widget, more words. This is that split, for any framework; the React views
|
|
6
|
+
// in ./react.tsx use it, and so can a Vue, Svelte or server-rendered screen.
|
|
7
|
+
/**
|
|
8
|
+
* A reply's words with each widget placed where it sits. Pieces of words that
|
|
9
|
+
* are only whitespace are left out. A widget whose `at` is past the end (a reply
|
|
10
|
+
* still arriving) goes at the end, and two widgets at one place keep their order.
|
|
11
|
+
*/
|
|
12
|
+
export function placeWidgets(text, widgets = []) {
|
|
13
|
+
const out = [];
|
|
14
|
+
let from = 0;
|
|
15
|
+
const sorted = widgets.map((w, i) => ({ w, i })).sort((a, b) => a.w.at - b.w.at || a.i - b.i);
|
|
16
|
+
for (const { w } of sorted) {
|
|
17
|
+
const at = Math.min(Math.max(Number.isFinite(w.at) ? w.at : text.length, from), text.length);
|
|
18
|
+
const words = text.slice(from, at);
|
|
19
|
+
if (words.trim())
|
|
20
|
+
out.push({ kind: 'text', text: words });
|
|
21
|
+
out.push({ kind: 'widget', widget: w });
|
|
22
|
+
from = at;
|
|
23
|
+
}
|
|
24
|
+
const rest = text.slice(from);
|
|
25
|
+
if (rest.trim())
|
|
26
|
+
out.push({ kind: 'text', text: rest });
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=widgets.js.map
|
package/widgets.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widgets.js","sourceRoot":"","sources":["../src/widgets.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,EAAE;AACF,0EAA0E;AAC1E,+EAA+E;AAC/E,+EAA+E;AAC/E,6EAA6E;AAO7E;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,UAA6B,EAAE;IACzE,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9F,KAAK,MAAM,EAAE,CAAC,EAAE,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7F,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACnC,IAAI,KAAK,CAAC,IAAI,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1D,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,GAAG,EAAE,CAAC;IACX,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,IAAI,CAAC,IAAI,EAAE;QAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,OAAO,GAAG,CAAC;AACZ,CAAC","sourcesContent":["// Placing widgets in a reply, with no UI framework.\n//\n// A widget arrives with `at`, a character count into the reply's words. A\n// screen that draws widgets needs the reply as pieces in reading order: words,\n// a widget, more words. This is that split, for any framework; the React views\n// in ./react.tsx use it, and so can a Vue, Svelte or server-rendered screen.\n\nimport type { Widget } from './types.ts';\n\n/** One piece of a reply in reading order: some words, or one widget. */\nexport type ReplyPiece = { kind: 'text'; text: string } | { kind: 'widget'; widget: Widget };\n\n/**\n * A reply's words with each widget placed where it sits. Pieces of words that\n * are only whitespace are left out. A widget whose `at` is past the end (a reply\n * still arriving) goes at the end, and two widgets at one place keep their order.\n */\nexport function placeWidgets(text: string, widgets: readonly Widget[] = []): ReplyPiece[] {\n\tconst out: ReplyPiece[] = [];\n\tlet from = 0;\n\tconst sorted = widgets.map((w, i) => ({ w, i })).sort((a, b) => a.w.at - b.w.at || a.i - b.i);\n\tfor (const { w } of sorted) {\n\t\tconst at = Math.min(Math.max(Number.isFinite(w.at) ? w.at : text.length, from), text.length);\n\t\tconst words = text.slice(from, at);\n\t\tif (words.trim()) out.push({ kind: 'text', text: words });\n\t\tout.push({ kind: 'widget', widget: w });\n\t\tfrom = at;\n\t}\n\tconst rest = text.slice(from);\n\tif (rest.trim()) out.push({ kind: 'text', text: rest });\n\treturn out;\n}\n"]}
|