@wallarm-org/gen-ui 0.0.0-stage → 0.1.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 +153 -2
- package/dist/a2ui/A2uiSurfaces.d.ts +16 -0
- package/dist/a2ui/A2uiSurfaces.js +61 -0
- package/dist/a2ui/catalog.d.ts +16 -0
- package/dist/a2ui/catalog.js +66 -0
- package/dist/a2ui/check.d.ts +4 -0
- package/dist/a2ui/check.js +34 -0
- package/dist/a2ui/express.d.ts +38 -0
- package/dist/a2ui/express.js +64 -0
- package/dist/a2ui/index.d.ts +8 -0
- package/dist/a2ui/index.js +4 -0
- package/dist/a2ui/prompt.d.ts +16 -0
- package/dist/a2ui/prompt.js +17 -0
- package/dist/a2ui/toA2uiSchema.d.ts +19 -0
- package/dist/a2ui/toA2uiSchema.js +61 -0
- package/dist/components/Alert.d.ts +11 -0
- package/dist/components/Alert.js +43 -0
- package/dist/components/AreaChart.d.ts +36 -0
- package/dist/components/AreaChart.js +90 -0
- package/dist/components/Badge.d.ts +11 -0
- package/dist/components/Badge.js +30 -0
- package/dist/components/BarList.d.ts +26 -0
- package/dist/components/BarList.js +66 -0
- package/dist/components/Button.d.ts +10 -0
- package/dist/components/Button.js +40 -0
- package/dist/components/Card.d.ts +2 -0
- package/dist/components/Card.js +17 -0
- package/dist/components/ColumnChart.d.ts +32 -0
- package/dist/components/ColumnChart.js +114 -0
- package/dist/components/Grid.d.ts +29 -0
- package/dist/components/Grid.js +72 -0
- package/dist/components/Heading.d.ts +10 -0
- package/dist/components/Heading.js +29 -0
- package/dist/components/HorizontalBarStack.d.ts +39 -0
- package/dist/components/HorizontalBarStack.js +67 -0
- package/dist/components/LineChart.d.ts +36 -0
- package/dist/components/LineChart.js +101 -0
- package/dist/components/Metric.d.ts +35 -0
- package/dist/components/Metric.js +85 -0
- package/dist/components/PieChart.d.ts +25 -0
- package/dist/components/PieChart.js +83 -0
- package/dist/components/Section.d.ts +5 -0
- package/dist/components/Section.js +39 -0
- package/dist/components/Stack.d.ts +18 -0
- package/dist/components/Stack.js +41 -0
- package/dist/components/Table.d.ts +30 -0
- package/dist/components/Table.js +128 -0
- package/dist/components/Text.d.ts +9 -0
- package/dist/components/Text.js +27 -0
- package/dist/components/index.d.ts +20 -0
- package/dist/components/index.js +55 -0
- package/dist/core/check.d.ts +35 -0
- package/dist/core/check.js +63 -0
- package/dist/core/define.d.ts +64 -0
- package/dist/core/define.js +7 -0
- package/dist/core/format.d.ts +24 -0
- package/dist/core/format.js +74 -0
- package/dist/core/guards.d.ts +2 -0
- package/dist/core/guards.js +2 -0
- package/dist/fixtures/apiInventory.d.ts +36 -0
- package/dist/fixtures/apiInventory.js +287 -0
- package/dist/fixtures/attackSummary.d.ts +13 -0
- package/dist/fixtures/attackSummary.js +329 -0
- package/dist/fixtures/dashboard.d.ts +119 -0
- package/dist/fixtures/dashboard.js +428 -0
- package/dist/fixtures/incident.d.ts +44 -0
- package/dist/fixtures/incident.js +331 -0
- package/dist/fixtures/index.d.ts +13 -0
- package/dist/fixtures/index.js +9 -0
- package/dist/fixtures/liveMonitor.d.ts +9 -0
- package/dist/fixtures/liveMonitor.js +180 -0
- package/dist/fixtures/openui.d.ts +16 -0
- package/dist/fixtures/openui.js +74 -0
- package/dist/fixtures/scenarios.d.ts +13 -0
- package/dist/fixtures/scenarios.js +39 -0
- package/dist/fixtures/stream.d.ts +79 -0
- package/dist/fixtures/stream.js +147 -0
- package/dist/fixtures/weeklyReport.d.ts +46 -0
- package/dist/fixtures/weeklyReport.js +266 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +4 -0
- package/dist/json-render/JsonRenderSurface.d.ts +13 -0
- package/dist/json-render/JsonRenderSurface.js +63 -0
- package/dist/json-render/catalog.d.ts +64 -0
- package/dist/json-render/catalog.js +50 -0
- package/dist/json-render/check.d.ts +4 -0
- package/dist/json-render/check.js +13 -0
- package/dist/json-render/index.d.ts +6 -0
- package/dist/json-render/index.js +4 -0
- package/dist/json-render/spec.d.ts +23 -0
- package/dist/json-render/spec.js +77 -0
- package/dist/openui/OpenUiSurface.d.ts +24 -0
- package/dist/openui/OpenUiSurface.js +30 -0
- package/dist/openui/catalog.d.ts +23 -0
- package/dist/openui/catalog.js +65 -0
- package/dist/openui/check.d.ts +4 -0
- package/dist/openui/check.js +68 -0
- package/dist/openui/index.d.ts +5 -0
- package/dist/openui/index.js +3 -0
- package/dist/playground/GenUiChatDemo.d.ts +11 -0
- package/dist/playground/GenUiChatDemo.js +148 -0
- package/dist/playground/GenUiPlayground.d.ts +15 -0
- package/dist/playground/GenUiPlayground.js +413 -0
- package/dist/playground/index.d.ts +3 -0
- package/dist/playground/index.js +2 -0
- package/dist/playground/useEmulatedAgent.d.ts +37 -0
- package/dist/playground/useEmulatedAgent.js +221 -0
- package/dist/render/ChartSkeleton.d.ts +6 -0
- package/dist/render/ChartSkeleton.js +26 -0
- package/dist/render/GuardedView.d.ts +18 -0
- package/dist/render/GuardedView.js +24 -0
- package/dist/render/Placeholder.d.ts +16 -0
- package/dist/render/Placeholder.js +15 -0
- package/dist/render/SurfaceBoundary.d.ts +15 -0
- package/dist/render/SurfaceBoundary.js +15 -0
- package/dist/render/warn.d.ts +1 -0
- package/dist/render/warn.js +2 -0
- package/package.json +94 -4
package/README.md
CHANGED
|
@@ -1,3 +1,154 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @wallarm-org/gen-ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Generative UI catalog for the Wallarm design system: an agent answers with design-system
|
|
4
|
+
components instead of text. Each component is defined once and rendered from
|
|
5
|
+
[A2UI](https://a2ui.org) v1.0 messages, [json-render](https://json-render.dev) specs or
|
|
6
|
+
[OpenUI](https://www.openui.com) Lang programs.
|
|
7
|
+
|
|
8
|
+
Experimental: published to npm as `@wallarm-org/gen-ui`, released from `main` with its own tags
|
|
9
|
+
(`gen-ui-v*`, see `RELEASE.md`). The user docs are on the site under
|
|
10
|
+
**AI → Generative UI** (`apps/website/docs/ai/generative-ui.mdx`).
|
|
11
|
+
|
|
12
|
+
## Where things are
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
src/
|
|
16
|
+
├── index.ts @wallarm-org/gen-ui: the catalog + the API to define entries
|
|
17
|
+
├── core/ format-agnostic: no format library, React only as types
|
|
18
|
+
│ ├── check.ts checkNodes / describeIssues: the answer check every format shares
|
|
19
|
+
│ ├── define.ts GenUiComponent (an entry's contract), defineComponent,
|
|
20
|
+
│ │ subsetOf / allOf / Values (enums from DS types), seriesKey, unique
|
|
21
|
+
│ ├── format.ts named number and time formats (formatNumber, formatTime)
|
|
22
|
+
│ └── guards.ts isRecord: narrow untrusted agent output
|
|
23
|
+
├── render/ React pieces every format shares
|
|
24
|
+
│ ├── GuardedView.tsx validates props against the schema, then View or Skeleton
|
|
25
|
+
│ ├── Placeholder.tsx what stands in for a part that isn't renderable yet
|
|
26
|
+
│ ├── ChartSkeleton.tsx the chart card skeleton the chart entries use
|
|
27
|
+
│ ├── SurfaceBoundary.tsx error boundary: a View that throws blanks its own surface only
|
|
28
|
+
│ └── warn.ts the one console.warn for rejected agent output
|
|
29
|
+
├── components/ THE CATALOG: one file per entry, index.ts lists them in order
|
|
30
|
+
├── a2ui/ @wallarm-org/gen-ui/a2ui
|
|
31
|
+
│ ├── catalog.tsx createA2uiCatalog: entries → A2UI Catalog (toJson() for the agent)
|
|
32
|
+
│ ├── A2uiSurfaces.tsx feeds messages to a MessageProcessor, renders its surfaces
|
|
33
|
+
│ ├── express.tsx /a2ui/express: A2UI Express, the compact text form, compiled by @a2ui/agent
|
|
34
|
+
│ ├── prompt.ts /a2ui/prompt: a2uiPrompt, the system prompt (Express or JSON) with the actions
|
|
35
|
+
│ ├── check.ts checkA2uiAnswer: the agent's mistakes in a finished answer
|
|
36
|
+
│ └── toA2uiSchema.ts zod 4 props → the zod 3 schema A2UI's binder reads
|
|
37
|
+
├── json-render/ @wallarm-org/gen-ui/json-render
|
|
38
|
+
│ ├── catalog.tsx createJsonRenderCatalog: entries → catalog (prompt()) + registry
|
|
39
|
+
│ ├── check.ts checkJsonRenderAnswer: the same check for a spec
|
|
40
|
+
│ ├── spec.ts specFromLines (stream → spec, never throws), sanitizeSpec (allowlist)
|
|
41
|
+
│ └── JsonRenderSurface.tsx renders a spec; keeps its state in step as the app fills it
|
|
42
|
+
├── openui/ @wallarm-org/gen-ui/openui
|
|
43
|
+
│ ├── catalog.tsx createOpenUiLibrary: entries → OpenUI library (prompt()), props in order
|
|
44
|
+
│ ├── check.ts checkOpenUiAnswer: the same check for a program
|
|
45
|
+
│ └── OpenUiSurface.tsx renders a program; the app's data arrives as $variables
|
|
46
|
+
├── fixtures/ @wallarm-org/gen-ui/fixtures: recorded answers, every format
|
|
47
|
+
│ ├── stream.ts the scenario builder: layout chunks + app data → every stream (toStreams)
|
|
48
|
+
│ ├── scenarios.ts SCENARIOS: every answer a demo can replay, in picker order
|
|
49
|
+
│ ├── attackSummary.ts a chat answer written by hand in A2UI and json-render
|
|
50
|
+
│ ├── openui.ts a recorded A2UI answer as OpenUI Lang (toOpenUiLines, openUiAnswer)
|
|
51
|
+
│ ├── liveMonitor.ts the live example: the app refreshes the page every 2 s
|
|
52
|
+
│ └── dashboard.ts, … one scenario per file, built with stream.ts
|
|
53
|
+
├── playground/ @wallarm-org/gen-ui/playground: the demos the playground app and the
|
|
54
|
+
│ │ docs site embed
|
|
55
|
+
│ ├── GenUiPlayground.tsx pick a prompt, replay its answer, read the stream beside it
|
|
56
|
+
│ ├── GenUiChatDemo.tsx answers inside the Wally chat, with an approval before Block
|
|
57
|
+
│ └── useEmulatedAgent.ts the scripted agent behind the chat demo
|
|
58
|
+
└── tests/ all tests (formats.test.tsx covers the shared behaviour)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## How a render works
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
components/Metric.tsx (one definition)
|
|
65
|
+
├─ a2ui/catalog.tsx → A2UI catalog ─┐
|
|
66
|
+
└─ json-render/catalog.tsx → json-render ──┴→ agent output → GuardedView → View (DS components)
|
|
67
|
+
└ props don't pass yet → Skeleton
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
1. The app builds both catalogs once, at module scope, from `wallarmComponents`.
|
|
71
|
+
2. The agent is prompted with the catalog: `toJson()` (A2UI) or `catalog.prompt()` (json-render).
|
|
72
|
+
3. Its output streams in. `A2uiSurfaces` takes the messages so far; `JsonRenderSurface` takes
|
|
73
|
+
`specFromLines(lines)`.
|
|
74
|
+
4. For every component, `GuardedView` checks the props against the entry's zod schema. Passing
|
|
75
|
+
props reach the `View`; failing ones (data not here yet, or a mistake) show the entry's
|
|
76
|
+
`Skeleton`. A child the agent hasn't sent yet shows a plain `Placeholder`.
|
|
77
|
+
5. A pressed button fires an event; only actions in the app's allowlist reach `onAction`.
|
|
78
|
+
|
|
79
|
+
## Add a component
|
|
80
|
+
|
|
81
|
+
1. Create `src/components/<Name>.tsx` with `defineComponent({ name, description, props, View })`.
|
|
82
|
+
Copy the closest entry: `Badge.tsx` for a leaf, `Section.tsx` for a container, `BarList.tsx` for
|
|
83
|
+
a chart.
|
|
84
|
+
2. Add it to `wallarmComponents` and the `export *` list in `src/components/index.ts`.
|
|
85
|
+
3. Add a test in `src/tests/<Name>.test.tsx` that renders it through every format, with literal
|
|
86
|
+
and bound props, and with data that hasn't arrived (see `LineChart.test.tsx`).
|
|
87
|
+
|
|
88
|
+
An entry must follow these rules. Tests or typecheck enforce the ones marked ✓.
|
|
89
|
+
|
|
90
|
+
- Props are data: strings, numbers, booleans, enums, arrays, objects. No functions or ReactNode.
|
|
91
|
+
- No prop named `id`, `component`, `children` or `child` (A2UI puts props next to them).
|
|
92
|
+
- ✓ Every enum value comes from a DS type: `subsetOf<BadgeColor>()([...])` for some values,
|
|
93
|
+
`allOf<…>()([...])` for all of them, or a typed `Record<…, DSType>` map. No `as` casts in a
|
|
94
|
+
definition.
|
|
95
|
+
- Numbers and times take a named format from `core/format.ts`, never a formatter function.
|
|
96
|
+
- Events carry no arguments: `events: ['press']`, then `emit('press')`.
|
|
97
|
+
- A container sets `hasChildren: true` and renders `children`.
|
|
98
|
+
- The `View` gets props that already passed the schema, so it needn't guard against missing data;
|
|
99
|
+
declare a `Skeleton` shaped like the loaded component.
|
|
100
|
+
- The root of a widget fills its cell (`h-full`), so a Grid row lines up.
|
|
101
|
+
- The `description` is for the model: when to use it and the data shape, not how it looks.
|
|
102
|
+
|
|
103
|
+
## Add a recorded answer
|
|
104
|
+
|
|
105
|
+
1. Create `src/fixtures/<name>.ts` exporting a `Scenario` (see `dashboard.ts`): the prompt, the
|
|
106
|
+
agent's layout in the chunks it sends them (`node`, with every figure a `bind('/path')`), and
|
|
107
|
+
the app's data batches with the chunk each arrives after.
|
|
108
|
+
2. Add `{ ...scenario, ...toStreams(scenario) }` to `SCENARIOS` in `src/fixtures/scenarios.ts`:
|
|
109
|
+
the playground and the docs page list it from there.
|
|
110
|
+
3. Add a test that renders it through every format and leaves no skeleton at the end.
|
|
111
|
+
|
|
112
|
+
## Commands
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pnpm --filter @wallarm-org/gen-ui test:run # rstest, every format
|
|
116
|
+
pnpm --filter @wallarm-org/gen-ui typecheck
|
|
117
|
+
pnpm --filter @wallarm-org/gen-ui build # rslib → dist/, same layout as src/
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The playground app has two demos that replay the fixtures: `/gen-ui` (answers in the Wally chat)
|
|
121
|
+
and `/gen-ui-playground` (pick a prompt, watch the agent lay out the answer while the app fills its
|
|
122
|
+
data). The docs site embeds the same `GenUiPlayground` on its Generative UI playground page.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pnpm turbo run build --filter=@wallarm-org/design-system # the playground reads the built theme
|
|
126
|
+
pnpm --filter @wallarm-org/playground dev
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Bundle size
|
|
130
|
+
|
|
131
|
+
What each entry point adds to an app, minified (gzip), with React and the DS external. Measured
|
|
132
|
+
with esbuild from `dist` on 2026-11-12; re-measure after a dependency bump.
|
|
133
|
+
|
|
134
|
+
| Entry | Size | Most of it |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| `.` (the catalog) | 110K (33K) | zod 4 |
|
|
137
|
+
| `/a2ui` + the catalog | 498K (137K) | `@a2ui/web_core`, zod 3 and zod 4 |
|
|
138
|
+
| `/a2ui/express` | 634K (176K) | `@a2ui/web_core`, `antlr4ng`, `@a2ui/agent` |
|
|
139
|
+
| `/json-render` + the catalog | 532K (119K) | zod 4 with all its locales |
|
|
140
|
+
| `/openui` + the catalog | 564K (132K) | zod 4 with all its locales, `@openuidev/lang-core` |
|
|
141
|
+
|
|
142
|
+
- Import zod as `import * as z from 'zod'`. `import { z } from 'zod'` keeps every zod locale in the
|
|
143
|
+
bundle (443K instead of 83K). json-render and OpenUI import it that way themselves, so their entries still pay for them.
|
|
144
|
+
- Express and the prompt have their own entry points because `@a2ui/agent` and its parser are most
|
|
145
|
+
of the weight. Compile Express on the server when you can, and send the browser A2UI JSON.
|
|
146
|
+
- `@a2ui/agent` imports `fs` and `path` in modules gen-ui doesn't use. Rspack drops them; a
|
|
147
|
+
bundler that resolves them anyway needs `fs: false, path: false` as fallbacks.
|
|
148
|
+
|
|
149
|
+
## Why two versions of zod
|
|
150
|
+
|
|
151
|
+
json-render needs zod 4, and the definitions are in zod 4. `@a2ui/web_core` pins zod 3 and reads
|
|
152
|
+
zod 3 internals to decide what binds, what's an action and what holds children.
|
|
153
|
+
`a2ui/toA2uiSchema.ts` rewrites each schema with the `zod/v3` API that zod 4 ships. The two
|
|
154
|
+
packages' TS types don't match, so `a2ui/catalog.tsx` casts at that one boundary.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type FC } from 'react';
|
|
2
|
+
import { type Catalog, type ComponentApi, type RendererErrorMessage } from '@a2ui/web_core';
|
|
3
|
+
import type { GenUiAction, GenUiActionHandler } from '../core/define.js';
|
|
4
|
+
import type { A2uiMessage } from './catalog.js';
|
|
5
|
+
export interface A2uiSurfacesProps {
|
|
6
|
+
catalog: Catalog<ComponentApi>;
|
|
7
|
+
/** Every message the agent has sent so far, in order; new ones are appended while it streams. */
|
|
8
|
+
messages: readonly A2uiMessage[];
|
|
9
|
+
/** The only action names that reach `onAction`; anything else the agent names is dropped. */
|
|
10
|
+
actions: readonly GenUiAction[];
|
|
11
|
+
onAction: GenUiActionHandler;
|
|
12
|
+
/** Messages the processor rejected (bad ids, unknown surface, catalog mismatch). Default: console.warn. */
|
|
13
|
+
onError?: (errors: readonly RendererErrorMessage[]) => void;
|
|
14
|
+
}
|
|
15
|
+
/** Feeds the messages to one MessageProcessor and renders every surface it holds. */
|
|
16
|
+
export declare const A2uiSurfaces: FC<A2uiSurfacesProps>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { A2uiSurface } from "@a2ui/react";
|
|
4
|
+
import { MessageProcessor } from "@a2ui/web_core";
|
|
5
|
+
import { SurfaceBoundary } from "../render/SurfaceBoundary.js";
|
|
6
|
+
import { warn } from "../render/warn.js";
|
|
7
|
+
const A2uiSurfaces = ({ catalog, messages, actions, onAction, onError = warnErrors })=>{
|
|
8
|
+
const latest = useRef({
|
|
9
|
+
actions,
|
|
10
|
+
onAction,
|
|
11
|
+
onError
|
|
12
|
+
});
|
|
13
|
+
useEffect(()=>{
|
|
14
|
+
latest.current = {
|
|
15
|
+
actions,
|
|
16
|
+
onAction,
|
|
17
|
+
onError
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
const [processor] = useState(()=>new MessageProcessor([
|
|
21
|
+
catalog
|
|
22
|
+
], (action)=>{
|
|
23
|
+
const { actions: allowed, onAction: dispatch } = latest.current;
|
|
24
|
+
if (allowed.some((a)=>a.name === action.name)) dispatch(action.name, action.context);
|
|
25
|
+
else warn(`dropped A2UI action '${action.name}', not in the allowlist`);
|
|
26
|
+
}));
|
|
27
|
+
const [surfaces, setSurfaces] = useState(()=>[
|
|
28
|
+
...processor.model.surfacesMap.values()
|
|
29
|
+
]);
|
|
30
|
+
useEffect(()=>{
|
|
31
|
+
const sync = ()=>setSurfaces([
|
|
32
|
+
...processor.model.surfacesMap.values()
|
|
33
|
+
]);
|
|
34
|
+
const created = processor.onSurfaceCreated(sync);
|
|
35
|
+
const deleted = processor.onSurfaceDeleted(sync);
|
|
36
|
+
return ()=>{
|
|
37
|
+
created.unsubscribe();
|
|
38
|
+
deleted.unsubscribe();
|
|
39
|
+
};
|
|
40
|
+
}, [
|
|
41
|
+
processor
|
|
42
|
+
]);
|
|
43
|
+
const fed = useRef(0);
|
|
44
|
+
useEffect(()=>{
|
|
45
|
+
if (messages.length <= fed.current) return;
|
|
46
|
+
const batch = messages.slice(fed.current);
|
|
47
|
+
fed.current = messages.length;
|
|
48
|
+
const errors = processor.processMessagesWithErrors(batch);
|
|
49
|
+
if (errors.length) latest.current.onError(errors);
|
|
50
|
+
}, [
|
|
51
|
+
messages,
|
|
52
|
+
processor
|
|
53
|
+
]);
|
|
54
|
+
return surfaces.map((surface)=>/*#__PURE__*/ jsx(SurfaceBoundary, {
|
|
55
|
+
children: /*#__PURE__*/ jsx(A2uiSurface, {
|
|
56
|
+
surface: surface
|
|
57
|
+
})
|
|
58
|
+
}, surface.id));
|
|
59
|
+
};
|
|
60
|
+
const warnErrors = (errors)=>warn('A2UI errors', errors);
|
|
61
|
+
export { A2uiSurfaces };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The A2UI catalog: what the agent is prompted with (`toJson()`) and how the React renderer draws
|
|
3
|
+
* each entry. The children of a container wait in a ChildSlot until the agent has sent them.
|
|
4
|
+
*/
|
|
5
|
+
import { Catalog, type ComponentApi } from '@a2ui/web_core';
|
|
6
|
+
import type { AgentToRendererMessage } from '@a2ui/web_core/v1_0';
|
|
7
|
+
import type { GenUiComponent } from '../core/define.js';
|
|
8
|
+
/** A v1.0 agent → renderer message: createSurface, updateComponents, updateDataModel, deleteSurface. */
|
|
9
|
+
export type A2uiMessage = AgentToRendererMessage;
|
|
10
|
+
export declare const WALLARM_A2UI_CATALOG_ID = "https://wallarm.github.io/design-system/gen-ui/catalog/v1.json";
|
|
11
|
+
/**
|
|
12
|
+
* A2UI glue: each component's zod props become an A2UI API (bindable leaves, one Action prop
|
|
13
|
+
* per event, a ChildList when it has children) and its View renders the binder's resolved props.
|
|
14
|
+
* `toJson()` on the result is the catalog document the agent is prompted with.
|
|
15
|
+
*/
|
|
16
|
+
export declare const createA2uiCatalog: (components: readonly GenUiComponent[], id?: string) => Catalog<ComponentApi>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
import { createComponentImplementation, useA2uiSurface } from "@a2ui/react";
|
|
4
|
+
import { Catalog } from "@a2ui/web_core";
|
|
5
|
+
import { GuardedView } from "../render/GuardedView.js";
|
|
6
|
+
import { Placeholder } from "../render/Placeholder.js";
|
|
7
|
+
import { A2UI_ACTION, A2UI_CHILD_LIST, toA2uiProps } from "./toA2uiSchema.js";
|
|
8
|
+
const WALLARM_A2UI_CATALOG_ID = 'https://wallarm.github.io/design-system/gen-ui/catalog/v1.json';
|
|
9
|
+
const implement = createComponentImplementation;
|
|
10
|
+
const createA2uiCatalog = (components, id = WALLARM_A2UI_CATALOG_ID)=>new Catalog(id, '1.0', components.map((component)=>{
|
|
11
|
+
const { name, description, props, events = [], hasChildren } = component;
|
|
12
|
+
const schema = toA2uiProps(props).extend(Object.fromEntries(events.map((event)=>[
|
|
13
|
+
event,
|
|
14
|
+
A2UI_ACTION.optional()
|
|
15
|
+
]))).extend(hasChildren ? {
|
|
16
|
+
children: A2UI_CHILD_LIST.optional()
|
|
17
|
+
} : {}).describe(description);
|
|
18
|
+
const impl = implement({
|
|
19
|
+
name,
|
|
20
|
+
schema
|
|
21
|
+
}, ({ props: resolved, buildChild, context })=>{
|
|
22
|
+
const { children, ...rest } = resolved;
|
|
23
|
+
const values = rest;
|
|
24
|
+
const raw = context.componentModel.properties.children;
|
|
25
|
+
const rawIds = Array.isArray(raw) ? raw : void 0;
|
|
26
|
+
const emit = (event)=>{
|
|
27
|
+
const action = values[event];
|
|
28
|
+
if ('function' == typeof action) action();
|
|
29
|
+
};
|
|
30
|
+
return /*#__PURE__*/ jsx(GuardedView, {
|
|
31
|
+
component: component,
|
|
32
|
+
props: values,
|
|
33
|
+
emit: emit,
|
|
34
|
+
children: children?.map((child, index)=>{
|
|
35
|
+
const ref = 'string' == typeof child ? {
|
|
36
|
+
id: child,
|
|
37
|
+
basePath: void 0
|
|
38
|
+
} : child;
|
|
39
|
+
const agentId = rawIds?.[index];
|
|
40
|
+
return /*#__PURE__*/ jsx(ChildSlot, {
|
|
41
|
+
id: ref.id,
|
|
42
|
+
agentId: 'string' == typeof agentId ? agentId : void 0,
|
|
43
|
+
basePath: ref.basePath,
|
|
44
|
+
buildChild: buildChild
|
|
45
|
+
}, `${ref.id}@${ref.basePath ?? ''}`);
|
|
46
|
+
})
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
return impl;
|
|
50
|
+
}));
|
|
51
|
+
const ChildSlot = ({ id, agentId, basePath, buildChild })=>{
|
|
52
|
+
const components = useA2uiSurface()?.componentsModel;
|
|
53
|
+
const subscribe = (onChange)=>{
|
|
54
|
+
const created = components?.onCreated.subscribe(onChange);
|
|
55
|
+
const deleted = components?.onDeleted.subscribe(onChange);
|
|
56
|
+
return ()=>{
|
|
57
|
+
created?.unsubscribe();
|
|
58
|
+
deleted?.unsubscribe();
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
const arrived = useSyncExternalStore(subscribe, ()=>!agentId || (components?.has(agentId) ?? true));
|
|
62
|
+
return arrived || !agentId ? buildChild(id, basePath) : /*#__PURE__*/ jsx(Placeholder, {
|
|
63
|
+
id: agentId
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
export { WALLARM_A2UI_CATALOG_ID, createA2uiCatalog };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type CheckOptions, type GenUiIssue } from '../core/check.js';
|
|
2
|
+
import type { A2uiMessage } from './catalog.js';
|
|
3
|
+
/** The agent's mistakes in a finished A2UI answer (one surface), per component. */
|
|
4
|
+
export declare const checkA2uiAnswer: (messages: readonly A2uiMessage[], options: CheckOptions) => GenUiIssue[];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { checkNodes } from "../core/check.js";
|
|
2
|
+
import { isRecord } from "../core/guards.js";
|
|
3
|
+
const isBinding = (value)=>isRecord(value) && ('@path' in value || '@call' in value);
|
|
4
|
+
const checkA2uiAnswer = (messages, options)=>{
|
|
5
|
+
const byId = new Map();
|
|
6
|
+
for (const message of messages){
|
|
7
|
+
const components = 'createSurface' in message ? message.createSurface.components : 'updateComponents' in message ? message.updateComponents.components : void 0;
|
|
8
|
+
for (const raw of components ?? [])byId.set(raw.id, toNode(raw, options));
|
|
9
|
+
}
|
|
10
|
+
return checkNodes([
|
|
11
|
+
...byId.values()
|
|
12
|
+
], 'root', isBinding, options);
|
|
13
|
+
};
|
|
14
|
+
const toNode = ({ id, component, children, ...rest }, { components })=>{
|
|
15
|
+
const events = components.find((c)=>c.name === component)?.events ?? [];
|
|
16
|
+
const props = Object.fromEntries(Object.entries(rest).filter(([key])=>!events.includes(key)));
|
|
17
|
+
const actions = events.flatMap((event)=>{
|
|
18
|
+
const value = rest[event];
|
|
19
|
+
return isRecord(value) && isRecord(value.event) && 'string' == typeof value.event.name ? [
|
|
20
|
+
value.event.name
|
|
21
|
+
] : [];
|
|
22
|
+
});
|
|
23
|
+
const ids = Array.isArray(children) ? children.filter((child)=>'string' == typeof child) : isRecord(children) && 'string' == typeof children.componentId ? [
|
|
24
|
+
children.componentId
|
|
25
|
+
] : [];
|
|
26
|
+
return {
|
|
27
|
+
id,
|
|
28
|
+
type: component,
|
|
29
|
+
props,
|
|
30
|
+
children: ids,
|
|
31
|
+
actions
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
export { checkA2uiAnswer };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2UI Express: the compact text a model writes instead of A2UI JSON, one statement per
|
|
3
|
+
* component (`m = Metric("Attacks", $/kpi/attacks, "compact")`). Arguments follow the order of
|
|
4
|
+
* the entry's props, bindings are `$/path`. The official @a2ui/agent compiler turns it into the
|
|
5
|
+
* same v1.0 messages, so everything downstream is unchanged.
|
|
6
|
+
*
|
|
7
|
+
* `@wallarm-org/gen-ui/a2ui/express`: its own entry point, since the compiler is most of its weight.
|
|
8
|
+
*/
|
|
9
|
+
import { type FC } from 'react';
|
|
10
|
+
import { ExpressParser } from '@a2ui/agent';
|
|
11
|
+
import type { Catalog, ComponentApi } from '@a2ui/web_core';
|
|
12
|
+
import type { GenUiAction, GenUiActionHandler } from '../core/define.js';
|
|
13
|
+
import type { A2uiMessage } from './catalog.js';
|
|
14
|
+
type A2uiCatalog = Catalog<ComponentApi>;
|
|
15
|
+
/** A compiler (and decompiler) for one surface. */
|
|
16
|
+
export declare const createExpressParser: (catalog: A2uiCatalog, surfaceId: string) => ExpressParser;
|
|
17
|
+
/**
|
|
18
|
+
* Recorded v1.0 messages as the Express a model would have written, one statement per line, in
|
|
19
|
+
* order: feed the lines one by one to replay it streaming. The answer is decompiled as a whole,
|
|
20
|
+
* because Express creates a surface in the scope that defines its root.
|
|
21
|
+
*/
|
|
22
|
+
export declare const toExpressLines: (catalog: A2uiCatalog, surfaceId: string, messages: readonly A2uiMessage[]) => string[];
|
|
23
|
+
export interface ExpressSurfacesProps {
|
|
24
|
+
catalog: A2uiCatalog;
|
|
25
|
+
surfaceId: string;
|
|
26
|
+
/** The Express text so far, in the chunks it arrived in; new chunks are appended. */
|
|
27
|
+
chunks: readonly string[];
|
|
28
|
+
actions: readonly GenUiAction[];
|
|
29
|
+
onAction: GenUiActionHandler;
|
|
30
|
+
/** A block the compiler rejected, or a message the renderer did. Default: console.warn. */
|
|
31
|
+
onError?: (errors: readonly unknown[]) => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Renders a streaming Express answer: each new chunk goes into one streaming compiler, which
|
|
35
|
+
* emits v1.0 messages as soon as they're complete, and those render like any A2UI answer.
|
|
36
|
+
*/
|
|
37
|
+
export declare const ExpressSurfaces: FC<ExpressSurfacesProps>;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { ExpressParser } from "@a2ui/agent";
|
|
4
|
+
import { A2uiSurfaces } from "./A2uiSurfaces.js";
|
|
5
|
+
const createExpressParser = (catalog, surfaceId)=>new ExpressParser(catalog, surfaceId, '1.0');
|
|
6
|
+
const toExpressLines = (catalog, surfaceId, messages)=>createExpressParser(catalog, surfaceId).decompile(withRootInCreate(messages)).split('\n').filter((line)=>'' !== line.trim());
|
|
7
|
+
const withRootInCreate = (messages)=>{
|
|
8
|
+
const holdsRoot = (m)=>'updateComponents' in m && m.updateComponents.components.some((c)=>'root' === c.id);
|
|
9
|
+
const create = messages.find((m)=>'createSurface' in m);
|
|
10
|
+
const rootUpdate = messages.find(holdsRoot);
|
|
11
|
+
if (!create || !('createSurface' in create) || create.createSurface.components || !rootUpdate) return [
|
|
12
|
+
...messages
|
|
13
|
+
];
|
|
14
|
+
if (!('updateComponents' in rootUpdate)) return [
|
|
15
|
+
...messages
|
|
16
|
+
];
|
|
17
|
+
const merged = {
|
|
18
|
+
...create,
|
|
19
|
+
createSurface: {
|
|
20
|
+
...create.createSurface,
|
|
21
|
+
components: rootUpdate.updateComponents.components
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return messages.flatMap((m)=>m === create ? [
|
|
25
|
+
merged
|
|
26
|
+
] : m === rootUpdate ? [] : [
|
|
27
|
+
m
|
|
28
|
+
]);
|
|
29
|
+
};
|
|
30
|
+
const ExpressSurfaces = ({ catalog, surfaceId, chunks, actions, onAction, onError })=>{
|
|
31
|
+
const [stream] = useState(()=>createExpressParser(catalog, surfaceId).openStream({
|
|
32
|
+
wrapped: false,
|
|
33
|
+
afterRejectedBlock: 'continue'
|
|
34
|
+
}));
|
|
35
|
+
const [messages, setMessages] = useState([]);
|
|
36
|
+
const onErrorRef = useRef(onError);
|
|
37
|
+
useEffect(()=>{
|
|
38
|
+
onErrorRef.current = onError;
|
|
39
|
+
});
|
|
40
|
+
const fed = useRef(0);
|
|
41
|
+
useEffect(()=>{
|
|
42
|
+
if (chunks.length <= fed.current) return;
|
|
43
|
+
const parts = chunks.slice(fed.current).flatMap((chunk)=>stream.feed(`${chunk}\n`));
|
|
44
|
+
fed.current = chunks.length;
|
|
45
|
+
const compiled = parts.flatMap((part)=>'a2ui' === part.type ? part.a2ui : []);
|
|
46
|
+
const rejected = parts.filter((part)=>'error' === part.type);
|
|
47
|
+
if (compiled.length) setMessages((list)=>[
|
|
48
|
+
...list,
|
|
49
|
+
...compiled
|
|
50
|
+
]);
|
|
51
|
+
if (rejected.length) onErrorRef.current?.(rejected);
|
|
52
|
+
}, [
|
|
53
|
+
chunks,
|
|
54
|
+
stream
|
|
55
|
+
]);
|
|
56
|
+
return /*#__PURE__*/ jsx(A2uiSurfaces, {
|
|
57
|
+
catalog: catalog,
|
|
58
|
+
messages: messages,
|
|
59
|
+
actions: actions,
|
|
60
|
+
onAction: onAction,
|
|
61
|
+
onError: onError
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
export { ExpressSurfaces, createExpressParser, toExpressLines };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@wallarm-org/gen-ui/a2ui`: render the catalog from A2UI v1.0 messages. What needs the A2UI
|
|
3
|
+
* agent library (and its parser) has its own entry points: `/a2ui/express` and `/a2ui/prompt`.
|
|
4
|
+
*/
|
|
5
|
+
export { A2uiSurfaces, type A2uiSurfacesProps } from './A2uiSurfaces.js';
|
|
6
|
+
export { type A2uiMessage, createA2uiCatalog, WALLARM_A2UI_CATALOG_ID } from './catalog.js';
|
|
7
|
+
export { checkA2uiAnswer } from './check.js';
|
|
8
|
+
export { toA2uiProps, toA2uiSchema } from './toA2uiSchema.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Catalog, ComponentApi } from '@a2ui/web_core';
|
|
2
|
+
import type { GenUiAction } from '../core/define.js';
|
|
3
|
+
export interface A2uiPromptOptions {
|
|
4
|
+
/** What the model writes: A2UI Express (compact, the default) or the v1.0 JSON messages. */
|
|
5
|
+
format?: 'express' | 'json';
|
|
6
|
+
/** The actions the app accepts: the model may fire only these. */
|
|
7
|
+
actions: readonly GenUiAction[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* `@wallarm-org/gen-ui/a2ui/prompt`, meant for the server that calls the model.
|
|
11
|
+
*
|
|
12
|
+
* The system prompt for an A2UI agent: the format's rules and a signature per catalog entry (from
|
|
13
|
+
* @a2ui/agent), plus the app's actions, which an A2UI catalog doesn't carry. Append your own
|
|
14
|
+
* instructions, e.g. which data paths the app fills.
|
|
15
|
+
*/
|
|
16
|
+
export declare const a2uiPrompt: (catalog: Catalog<ComponentApi>, { format, actions }: A2uiPromptOptions) => string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DirectJsonFormat, ExpressFormat } from "@a2ui/agent";
|
|
2
|
+
const a2uiPrompt = (catalog, { format = 'express', actions })=>{
|
|
3
|
+
const generator = 'express' === format ? new ExpressFormat([
|
|
4
|
+
catalog
|
|
5
|
+
], {
|
|
6
|
+
version: '1.0'
|
|
7
|
+
}).promptGenerator : new DirectJsonFormat([
|
|
8
|
+
catalog
|
|
9
|
+
]).promptGenerator;
|
|
10
|
+
return [
|
|
11
|
+
generator.generate(),
|
|
12
|
+
'## Actions',
|
|
13
|
+
'A button fires an action by name; the app ignores any name not listed here.',
|
|
14
|
+
...actions.map((a)=>`- ${a.name}: ${a.description}`)
|
|
15
|
+
].join('\n');
|
|
16
|
+
};
|
|
17
|
+
export { a2uiPrompt };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type * as z from 'zod';
|
|
2
|
+
import { z as z3 } from 'zod/v3';
|
|
3
|
+
/**
|
|
4
|
+
* Rewrites a gen-ui zod 4 props schema into the zod 3 schema A2UI's binder walks.
|
|
5
|
+
*
|
|
6
|
+
* @a2ui/web_core pins zod 3 and recognises its schemas by `_def.typeName` and `REF:`
|
|
7
|
+
* descriptions (not `instanceof`), so `zod/v3` from our zod 4 works next to its own copy.
|
|
8
|
+
* - string / number / boolean leaves become `DynamicString` / `DynamicNumber` / `DynamicBoolean`:
|
|
9
|
+
* a literal, or `{ "@path": "/..." }` into the surface's data model.
|
|
10
|
+
* - arrays and objects take a literal, or one binding for the whole value.
|
|
11
|
+
* - enums stay literal.
|
|
12
|
+
* Field descriptions carry over, except onto a dynamic leaf or any wrapper of one: the binder
|
|
13
|
+
* finds `REF:DynamicString` and the like by the first description up the wrapper chain.
|
|
14
|
+
*/
|
|
15
|
+
export declare const toA2uiSchema: (schema: z.ZodType, dynamic?: boolean, description?: string | undefined) => z3.ZodTypeAny;
|
|
16
|
+
/** The props object itself: its fields are bound one by one, not as a whole. */
|
|
17
|
+
export declare const toA2uiProps: (props: z.ZodObject) => z3.AnyZodObject;
|
|
18
|
+
export declare const A2UI_ACTION: z3.ZodTypeAny;
|
|
19
|
+
export declare const A2UI_CHILD_LIST: z3.ZodTypeAny;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { CommonSchemas } from "@a2ui/web_core/v1_0";
|
|
2
|
+
import { z } from "zod/v3";
|
|
3
|
+
const toA2uiSchema = (schema, dynamic = true, description = schema.description)=>{
|
|
4
|
+
const def = schema._zod.def;
|
|
5
|
+
const leaf = 'string' === def.type || 'number' === def.type || 'boolean' === def.type;
|
|
6
|
+
const out = convert(schema, dynamic, description);
|
|
7
|
+
return description && !(dynamic && leaf) && 'optional' !== def.type ? out.describe(description) : out;
|
|
8
|
+
};
|
|
9
|
+
const convert = (schema, dynamic, description)=>{
|
|
10
|
+
const def = schema._zod.def;
|
|
11
|
+
switch(def.type){
|
|
12
|
+
case 'string':
|
|
13
|
+
return dynamic ? common(CommonSchemas.DynamicString) : z.string();
|
|
14
|
+
case 'number':
|
|
15
|
+
return dynamic ? common(CommonSchemas.DynamicNumber) : z.number();
|
|
16
|
+
case 'boolean':
|
|
17
|
+
return dynamic ? common(CommonSchemas.DynamicBoolean) : z.boolean();
|
|
18
|
+
case 'enum':
|
|
19
|
+
{
|
|
20
|
+
const values = Object.values(def.entries).map(String);
|
|
21
|
+
return z["enum"](values);
|
|
22
|
+
}
|
|
23
|
+
case 'optional':
|
|
24
|
+
return toA2uiSchema(def.innerType, dynamic, description ?? def.innerType.description).optional();
|
|
25
|
+
case 'array':
|
|
26
|
+
{
|
|
27
|
+
const literal = z.array(toA2uiSchema(def.element, false));
|
|
28
|
+
return dynamic ? z.union([
|
|
29
|
+
literal,
|
|
30
|
+
common(CommonSchemas.DataBinding)
|
|
31
|
+
]) : literal;
|
|
32
|
+
}
|
|
33
|
+
case 'object':
|
|
34
|
+
{
|
|
35
|
+
const { shape, catchall } = def;
|
|
36
|
+
const fixed = z.object(Object.fromEntries(Object.entries(shape).map(([key, value])=>[
|
|
37
|
+
key,
|
|
38
|
+
toA2uiSchema(value, false)
|
|
39
|
+
])));
|
|
40
|
+
const literal = catchall ? fixed.catchall(toA2uiSchema(catchall, false)) : fixed;
|
|
41
|
+
return dynamic ? z.union([
|
|
42
|
+
literal,
|
|
43
|
+
common(CommonSchemas.DataBinding)
|
|
44
|
+
]) : literal;
|
|
45
|
+
}
|
|
46
|
+
case 'nullable':
|
|
47
|
+
return toA2uiSchema(def.innerType, dynamic, description).nullable();
|
|
48
|
+
case 'unknown':
|
|
49
|
+
return z.unknown();
|
|
50
|
+
default:
|
|
51
|
+
throw new Error(`gen-ui: prop type '${def.type}' has no A2UI mapping`);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
const toA2uiProps = (props)=>z.object(Object.fromEntries(Object.entries(props.shape).map(([key, value])=>[
|
|
55
|
+
key,
|
|
56
|
+
toA2uiSchema(value)
|
|
57
|
+
])));
|
|
58
|
+
const common = (schema)=>schema;
|
|
59
|
+
const A2UI_ACTION = common(CommonSchemas.Action);
|
|
60
|
+
const A2UI_CHILD_LIST = common(CommonSchemas.ChildList);
|
|
61
|
+
export { A2UI_ACTION, A2UI_CHILD_LIST, toA2uiProps, toA2uiSchema };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
export declare const AlertComponent: import("../index.js").GenUiComponent<z.ZodObject<{
|
|
3
|
+
title: z.ZodString;
|
|
4
|
+
description: z.ZodOptional<z.ZodString>;
|
|
5
|
+
tone: z.ZodOptional<z.ZodEnum<{
|
|
6
|
+
destructive: "destructive";
|
|
7
|
+
info: "info";
|
|
8
|
+
success: "success";
|
|
9
|
+
warning: "warning";
|
|
10
|
+
}>>;
|
|
11
|
+
}, z.core.$strip>>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Alert, AlertContent, AlertDescription, AlertIcon, AlertTitle } from "@wallarm-org/design-system/Alert";
|
|
3
|
+
import { Skeleton } from "@wallarm-org/design-system/Skeleton";
|
|
4
|
+
import { defineComponent, subsetOf } from "../core/define.js";
|
|
5
|
+
import * as __rspack_external_zod from "zod";
|
|
6
|
+
const AlertComponent = defineComponent({
|
|
7
|
+
name: 'Alert',
|
|
8
|
+
description: 'A highlighted message about something the user should know or act on.',
|
|
9
|
+
props: __rspack_external_zod.object({
|
|
10
|
+
title: __rspack_external_zod.string(),
|
|
11
|
+
description: __rspack_external_zod.string().optional(),
|
|
12
|
+
tone: __rspack_external_zod["enum"](subsetOf()([
|
|
13
|
+
'info',
|
|
14
|
+
'warning',
|
|
15
|
+
'destructive',
|
|
16
|
+
'success'
|
|
17
|
+
])).optional()
|
|
18
|
+
}),
|
|
19
|
+
Skeleton: ()=>/*#__PURE__*/ jsx(Skeleton, {
|
|
20
|
+
width: "100%",
|
|
21
|
+
height: "56px",
|
|
22
|
+
rounded: 12,
|
|
23
|
+
transparent: false
|
|
24
|
+
}),
|
|
25
|
+
View: ({ props })=>/*#__PURE__*/ jsxs(Alert, {
|
|
26
|
+
color: props.tone ?? 'info',
|
|
27
|
+
minWidth: 0,
|
|
28
|
+
children: [
|
|
29
|
+
/*#__PURE__*/ jsx(AlertIcon, {}),
|
|
30
|
+
/*#__PURE__*/ jsxs(AlertContent, {
|
|
31
|
+
children: [
|
|
32
|
+
/*#__PURE__*/ jsx(AlertTitle, {
|
|
33
|
+
children: props.title
|
|
34
|
+
}),
|
|
35
|
+
props.description && /*#__PURE__*/ jsx(AlertDescription, {
|
|
36
|
+
children: props.description
|
|
37
|
+
})
|
|
38
|
+
]
|
|
39
|
+
})
|
|
40
|
+
]
|
|
41
|
+
})
|
|
42
|
+
});
|
|
43
|
+
export { AlertComponent };
|