@swarm.ing/pieui 2.1.5 → 2.1.7
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 +595 -124
- package/dist/components/PieCard/index.d.ts +1 -1
- package/dist/components/PieCard/index.d.ts.map +1 -1
- package/dist/components/PieCard/types/index.d.ts +11 -0
- package/dist/components/PieCard/types/index.d.ts.map +1 -1
- package/dist/components/index.esm.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/index.esm.js +2 -2
- package/dist/index.js +2 -2
- package/dist/native/index.esm.js +2 -2
- package/dist/native/index.js +2 -2
- package/dist/telegram/index.esm.js +1 -1
- package/dist/telegram/index.js +1 -1
- package/dist/tests/centrifugeRecovery.test.d.ts +2 -0
- package/dist/tests/centrifugeRecovery.test.d.ts.map +1 -0
- package/dist/tests/centrifugeSubscription.test.d.ts +2 -0
- package/dist/tests/centrifugeSubscription.test.d.ts.map +1 -0
- package/dist/tests/piecardRecovery.test.d.ts +2 -0
- package/dist/tests/piecardRecovery.test.d.ts.map +1 -0
- package/dist/util/centrifuge.d.ts +5 -0
- package/dist/util/centrifuge.d.ts.map +1 -1
- package/dist/util/centrifugeRecovery.d.ts +26 -0
- package/dist/util/centrifugeRecovery.d.ts.map +1 -0
- package/dist/util/centrifugeSubscription.d.ts +18 -0
- package/dist/util/centrifugeSubscription.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,22 +1,93 @@
|
|
|
1
1
|
# PieUI
|
|
2
2
|
|
|
3
|
-
PieUI is a React
|
|
4
|
-
|
|
5
|
-
**
|
|
3
|
+
**PieUI** (`@swarm.ing/pieui`) is a React library for rendering **server-driven UIs**. A backend returns a JSON description of a screen, and PieUI turns it into a React tree by looking up each node in a component **registry**. On top of rendering it ships real-time messaging (Socket.IO, Centrifuge, Mitt), server-driven AJAX updates, host integrations (Telegram Mini Apps, MAX, React Native), an OpenAI voice-agent bridge, a Storybook addon, and a `pieui` CLI for scaffolding apps, pages, and cards.
|
|
4
|
+
|
|
5
|
+
- **Server-driven** — screens are described by data (`UIConfigType`), not code.
|
|
6
|
+
- **Registry-based** — register components by name; the backend references them by that name.
|
|
7
|
+
- **Real-time** — cards can subscribe to Socket.IO, Centrifuge, or in-process Mitt events.
|
|
8
|
+
- **Multi-platform** — web, Telegram Mini Apps, MAX (VK), and React Native from one core.
|
|
9
|
+
- **Tooling** — a CLI that scaffolds Next.js apps, generates cards/pages, and syncs a component registry.
|
|
10
|
+
|
|
11
|
+
> React and React DOM `>=19` are peer dependencies. React Native `>=0.74` and `@openai/agents` are **optional** peers (only needed for the `/native` and `/agent` entries).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Table of contents
|
|
16
|
+
|
|
17
|
+
- [Installation](#installation)
|
|
18
|
+
- [Core concepts](#core-concepts)
|
|
19
|
+
- [Quick start](#quick-start)
|
|
20
|
+
- [Package entry points](#package-entry-points)
|
|
21
|
+
- [Root components](#root-components)
|
|
22
|
+
- [Registering components](#registering-components)
|
|
23
|
+
- [Component prop shapes](#component-prop-shapes)
|
|
24
|
+
- [Built-in cards](#built-in-cards)
|
|
25
|
+
- [Real-time messaging](#real-time-messaging)
|
|
26
|
+
- [Server-driven AJAX updates](#server-driven-ajax-updates)
|
|
27
|
+
- [`depsNames` — client-side submit sources](#depsnames--client-side-submit-sources)
|
|
28
|
+
- [Configuration & environment](#configuration--environment)
|
|
29
|
+
- [Registry API](#registry-api)
|
|
30
|
+
- [Styling helpers](#styling-helpers)
|
|
31
|
+
- [Platform integrations](#platform-integrations)
|
|
32
|
+
- [Telegram Mini Apps](#telegram-mini-apps)
|
|
33
|
+
- [MAX (VK Messenger)](#max-vk-messenger)
|
|
34
|
+
- [React Native](#react-native)
|
|
35
|
+
- [OpenAI agent integration](#openai-agent-integration)
|
|
36
|
+
- [Storybook integration](#storybook-integration)
|
|
37
|
+
- [CLI reference](#cli-reference)
|
|
38
|
+
- [API reference](#api-reference)
|
|
39
|
+
- [License](#license)
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
6
44
|
|
|
7
45
|
```sh
|
|
8
46
|
bun add @swarm.ing/pieui
|
|
47
|
+
# or
|
|
9
48
|
npm install @swarm.ing/pieui
|
|
49
|
+
# or
|
|
50
|
+
pnpm add @swarm.ing/pieui
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```jsonc
|
|
54
|
+
// peerDependencies
|
|
55
|
+
"react": ">=19",
|
|
56
|
+
"react-dom": ">=19",
|
|
57
|
+
"react-native": ">=0.74", // optional — only for @swarm.ing/pieui/native
|
|
58
|
+
"@openai/agents": "^0.4.5" // optional — only for @swarm.ing/pieui/agent
|
|
10
59
|
```
|
|
11
60
|
|
|
12
|
-
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Core concepts
|
|
64
|
+
|
|
65
|
+
**Server-driven UI.** The backend describes a screen as a tree of `UIConfigType` nodes:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
interface UIConfigType {
|
|
69
|
+
card: string // registry name of the component to render
|
|
70
|
+
data: any // props bag passed to the component as `data`
|
|
71
|
+
content: UIConfigType | UIConfigType[] // nested child config(s), if any
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**The registry.** Every renderable component is registered under a `name`. The renderer (`UI`) reads `config.card`, looks it up in the registry, and renders it — passing `data`, `content`, and `setUiAjaxConfiguration` as appropriate.
|
|
76
|
+
|
|
77
|
+
**Cards.** A "card" is just a registered React component. PieUI ships a handful of built-in container/leaf cards (`SequenceCard`, `BoxCard`, `HTMLEmbedCard`, …) and you register your own for everything app-specific.
|
|
78
|
+
|
|
79
|
+
**Side-effect registration.** Importing from `@swarm.ing/pieui` (or `@swarm.ing/pieui/components`) registers the built-in cards automatically as a side effect — there is **no `initializePieComponents()` call to make** anymore. Your own cards register themselves when their module is imported (see [Registering components](#registering-components)).
|
|
80
|
+
|
|
81
|
+
---
|
|
13
82
|
|
|
14
|
-
|
|
83
|
+
## Quick start
|
|
15
84
|
|
|
16
85
|
```tsx
|
|
17
|
-
|
|
86
|
+
'use client'
|
|
18
87
|
|
|
19
|
-
|
|
88
|
+
import { PieRoot } from '@swarm.ing/pieui'
|
|
89
|
+
// Importing your registry module triggers side-effect registration of your cards.
|
|
90
|
+
import './piecomponents/registry'
|
|
20
91
|
|
|
21
92
|
export function App() {
|
|
22
93
|
return (
|
|
@@ -25,8 +96,8 @@ export function App() {
|
|
|
25
96
|
pathname: window.location.pathname,
|
|
26
97
|
search: window.location.search,
|
|
27
98
|
}}
|
|
28
|
-
fallback={<>Loading
|
|
29
|
-
onError={() =>
|
|
99
|
+
fallback={<>Loading…</>}
|
|
100
|
+
onError={() => window.location.reload()}
|
|
30
101
|
onNavigate={(url) => {
|
|
31
102
|
window.location.href = url
|
|
32
103
|
}}
|
|
@@ -36,17 +107,77 @@ export function App() {
|
|
|
36
107
|
'wss://realtime.example.com/connection/websocket',
|
|
37
108
|
enableRenderingLog: false,
|
|
38
109
|
}}
|
|
39
|
-
initializePie={() => {
|
|
40
|
-
// Register custom components here if needed.
|
|
41
|
-
}}
|
|
42
110
|
/>
|
|
43
111
|
)
|
|
44
112
|
}
|
|
45
113
|
```
|
|
46
114
|
|
|
47
|
-
|
|
115
|
+
`PieRoot` fetches the screen config from `` `${config.apiServer}/api/content${pathname}?${search}` `` with React Query + Axios, sets up every provider PieUI needs, and renders the resulting tree.
|
|
116
|
+
|
|
117
|
+
- **Telegram Mini App?** Use `PieTelegramRoot` from `@swarm.ing/pieui/telegram`.
|
|
118
|
+
- **MAX mini-app?** Use `PieMaxRoot` from `@swarm.ing/pieui/max`.
|
|
119
|
+
- **React Native?** Use `PieRoot`/`PieNativeRoot` from `@swarm.ing/pieui/native`.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Package entry points
|
|
124
|
+
|
|
125
|
+
PieUI is split into focused entry points so apps only ship what they use:
|
|
126
|
+
|
|
127
|
+
| Import path | Contents |
|
|
128
|
+
| ---------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
129
|
+
| `@swarm.ing/pieui` | Main barrel: roots, `UI`, `PieCard`, registry API, hooks, types, built-in card side-effect |
|
|
130
|
+
| `@swarm.ing/pieui/components` | Just the built-in cards + `UI`/`PieCard` (registers built-ins on import) |
|
|
131
|
+
| `@swarm.ing/pieui/telegram` | `PieTelegramRoot`, Telegram WebApp hooks, `CloudStorageCard`/`SecureStorageCard` |
|
|
132
|
+
| `@swarm.ing/pieui/max` | `PieMaxRoot` and MAX (VK) WebApp hooks |
|
|
133
|
+
| `@swarm.ing/pieui/native` | React Native core + native card variants + native source wiring |
|
|
134
|
+
| `@swarm.ing/pieui/agent` | OpenAI agent tools (`getMittAgentTools`, `useOpenAIWebRTC`) — pulls in `@openai/agents` |
|
|
135
|
+
| `@swarm.ing/pieui/storybook` | Storybook providers/decorators for testing cards in isolation |
|
|
136
|
+
| `@swarm.ing/pieui/storybook/addon` | Storybook addon (panel + manager) for firing PieCard methods from the Storybook UI |
|
|
137
|
+
|
|
138
|
+
The Telegram, MAX, and agent integrations are deliberately split out so apps that don't target those hosts never bundle their code.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Root components
|
|
143
|
+
|
|
144
|
+
All roots wrap children in the PieUI provider stack (React Query, Mitt, Socket.IO, Centrifuge, config, navigation, and — unless disabled — a global `<form>`).
|
|
145
|
+
|
|
146
|
+
### `PieRoot`
|
|
48
147
|
|
|
49
|
-
|
|
148
|
+
Fetches a `UIConfigType` from `api/content{pathname}{search}` and renders it.
|
|
149
|
+
|
|
150
|
+
| Prop | Type | Description |
|
|
151
|
+
| ------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
152
|
+
| `location` | `{ pathname: string; search: string }` | Current route. Used to build the request URL and as part of the React Query key. |
|
|
153
|
+
| `config` | `PieConfig` | Runtime configuration (API URLs, logging, page processor). **Required.** |
|
|
154
|
+
| `fallback` | `ReactNode` | Rendered while loading or on fetch failure. |
|
|
155
|
+
| `piecache` | `Record<string, UIConfigType>` | Optional per-pathname snapshot; a cached shell is shown via `UILoading` instead of the plain `fallback`. |
|
|
156
|
+
| `onError` | `(error?: unknown) => void` | Called on a render-blocking error (config fetch throws, or a lazy card chunk fails after retries). |
|
|
157
|
+
| `onNavigate` | `(url: string) => void` | Navigation handler forwarded through `NavigateContext` so cards route via the host router, not a full reload. |
|
|
158
|
+
| `queryOptions` | `PieQueryOptions` | React Query overrides (everything except `queryKey`/`queryFn`/`enabled`, which PieRoot manages). |
|
|
159
|
+
| `queryClient` | `QueryClient` | Supply a stable (module-singleton) client so the config cache survives remounts. Otherwise one is made per mount. |
|
|
160
|
+
| `disableGlobalForm` | `boolean` | When `true`, the implicit `<form id="piedata_global_form">` wrapper is not rendered. |
|
|
161
|
+
|
|
162
|
+
### `PieBaseRoot`
|
|
163
|
+
|
|
164
|
+
The provider stack **without** any fetch. Renders `children` inside the same providers and (optional) form shell. Use it when you already have a `UIConfigType` (render it with `UI`) or want PieUI context without a network round-trip.
|
|
165
|
+
|
|
166
|
+
### `PiePreviewRoot`
|
|
167
|
+
|
|
168
|
+
A root tailored to the CLI preview harness (`pieui registry dev`/`build`) for previewing a single card.
|
|
169
|
+
|
|
170
|
+
### Platform roots
|
|
171
|
+
|
|
172
|
+
- **`PieTelegramRoot`** (`/telegram`) — like `PieRoot`, but appends Telegram WebApp `initData` to the request query string via `useWebApp`. Throws if `apiServer` is missing.
|
|
173
|
+
- **`PieMaxRoot`** (`/max`) — MAX (VK) equivalent.
|
|
174
|
+
- **`PieNativeRoot`** (`/native`) — `PieBaseRoot` for React Native (no HTML form).
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Registering components
|
|
179
|
+
|
|
180
|
+
A card is any React component registered under a name. The CLI generates a per-card `index.ts` that calls `registerPieComponent`, and a `piecomponents/registry.ts` that side-effect-imports each card. Registering manually:
|
|
50
181
|
|
|
51
182
|
```tsx
|
|
52
183
|
import { registerPieComponent } from '@swarm.ing/pieui'
|
|
@@ -55,167 +186,507 @@ import MyCard from './MyCard'
|
|
|
55
186
|
registerPieComponent({
|
|
56
187
|
name: 'MyCard',
|
|
57
188
|
component: MyCard,
|
|
58
|
-
metadata: {
|
|
59
|
-
|
|
60
|
-
|
|
189
|
+
metadata: { author: 'You', version: '1.0.0', description: 'A custom card' },
|
|
190
|
+
})
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Lazy / code-split cards** — pass a `loader` instead of `component`; PieUI wraps it in `React.lazy` and renders it inside `Suspense` (with an optional `fallback`):
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
registerPieComponent({
|
|
197
|
+
name: 'HeavyChart',
|
|
198
|
+
loader: () => import('./HeavyChart'),
|
|
199
|
+
fallback: <Spinner />,
|
|
200
|
+
})
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`ComponentRegistration` shape:
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
interface ComponentRegistration<TProps> {
|
|
207
|
+
name: string
|
|
208
|
+
component?: ComponentType<TProps>
|
|
209
|
+
loader?: () => Promise<{ default: ComponentType<TProps> }>
|
|
210
|
+
fallback?: ComponentType<{}>
|
|
211
|
+
metadata?: { author?: string; version?: string; description?: string; tags?: string[] }
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
> A registration must provide a `name` **and** either `component` or `loader`, otherwise `registerPieComponent` throws.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Component prop shapes
|
|
220
|
+
|
|
221
|
+
The renderer passes different props depending on a card's "kind". Pick the matching prop type for your component:
|
|
222
|
+
|
|
223
|
+
| Kind | Prop type | Props received | `card add` type |
|
|
224
|
+
| ------------------- | -------------------------------------- | -------------------------------------------------------- | ------------------- |
|
|
225
|
+
| Simple | `PieSimpleComponentProps<T>` | `{ data }` | `simple` |
|
|
226
|
+
| Complex | `PieComplexComponentProps<T>` | `{ data, setUiAjaxConfiguration? }` | `complex` |
|
|
227
|
+
| Container | `PieContainerComponentProps<T>` | `{ data, content: UIConfigType, setUiAjaxConfiguration? }` | `simple-container` |
|
|
228
|
+
| Complex container | `PieComplexContainerComponentProps<T>` | `{ data, content: UIConfigType[], setUiAjaxConfiguration? }` | `complex-container` |
|
|
229
|
+
|
|
230
|
+
Each has an `InputPie…ComponentProps<T, TStored>` variant that adds a typed `stored` prop (used when a card needs locally stored state — wired through `<PieCard stored={…} />`).
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
import type { PieContainerComponentProps } from '@swarm.ing/pieui'
|
|
234
|
+
|
|
235
|
+
interface MyData { title: string }
|
|
236
|
+
|
|
237
|
+
export default function Panel({
|
|
238
|
+
data,
|
|
239
|
+
content,
|
|
240
|
+
}: PieContainerComponentProps<MyData>) {
|
|
241
|
+
return (
|
|
242
|
+
<section>
|
|
243
|
+
<h2>{data.title}</h2>
|
|
244
|
+
<UI uiConfig={content} />
|
|
245
|
+
</section>
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Built-in cards
|
|
253
|
+
|
|
254
|
+
These register automatically when you import `@swarm.ing/pieui` (or `/components`).
|
|
255
|
+
|
|
256
|
+
### Containers
|
|
257
|
+
|
|
258
|
+
| Card | Kind | Description |
|
|
259
|
+
| --------------- | ----------------- | ----------------------------------------------------------------------------- |
|
|
260
|
+
| `SequenceCard` | complex-container | Renders an array of children sequentially inside a styled wrapper. |
|
|
261
|
+
| `UnionCard` | complex-container | Renders an array of children with no wrapping element. |
|
|
262
|
+
| `OneOfCard` | complex-container | Renders children in a styled wrapper (typically for conditional selection). |
|
|
263
|
+
| `BoxCard` | container | Single-child wrapper with optional click-to-navigate and inline styling. |
|
|
264
|
+
| `AjaxGroupCard` | container | Single-child group that loads/replaces its content via AJAX and emits events. |
|
|
265
|
+
|
|
266
|
+
### Common (leaf)
|
|
267
|
+
|
|
268
|
+
| Card | Kind | Description |
|
|
269
|
+
| -------------------- | ------ | ----------------------------------------------------------------------------------- |
|
|
270
|
+
| `HiddenCard` | simple | Renders a hidden input with state management and real-time value sync. |
|
|
271
|
+
| `HTMLEmbedCard` | simple | Parses and renders arbitrary HTML (optionally driven by OpenAI WebRTC generation). |
|
|
272
|
+
| `AutoRedirectCard` | simple | Redirects on mount (internal route or external URL). |
|
|
273
|
+
| `IOEventsCard` | simple | Handles toast notifications, alerts, push notifications, and redirect/reload events. |
|
|
274
|
+
| `DeviceStorageCard` | simple | Persists data to `localStorage`, mirrored into a hidden input for form submission. |
|
|
275
|
+
| `SessionStorageCard` | simple | Persists data to `sessionStorage`, mirrored into a hidden input. |
|
|
276
|
+
|
|
277
|
+
### Telegram-only (register via `@swarm.ing/pieui/telegram`)
|
|
278
|
+
|
|
279
|
+
| Card | Kind | Description |
|
|
280
|
+
| ------------------- | ------ | ----------------------------------------------------------------- |
|
|
281
|
+
| `CloudStorageCard` | simple | Persists data to Telegram `CloudStorage` (async), hidden-input mirror. |
|
|
282
|
+
| `SecureStorageCard` | simple | Persists data to Telegram `SecureStorage` (async), hidden-input mirror. |
|
|
283
|
+
|
|
284
|
+
The storage cards pair with the AJAX `depsNames` prefixes: `localStorage:` ↔ `DeviceStorageCard`, `sessionStorage:` ↔ `SessionStorageCard`, `telegram:cloud:` ↔ `CloudStorageCard`, `telegram:secure:` ↔ `SecureStorageCard` (see [`depsNames`](#depsnames--client-side-submit-sources)).
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Real-time messaging
|
|
289
|
+
|
|
290
|
+
`PieCard` wires a card into PieUI's real-time transports. It renders no UI of its own — it returns its `children` and, on mount, subscribes the supplied `methods` map to whichever transports are enabled:
|
|
291
|
+
|
|
292
|
+
| Transport | Event / channel format | Enable with |
|
|
293
|
+
| ------------- | --------------------------------------------------- | ----------------------- |
|
|
294
|
+
| **Socket.IO** | `pie{methodName}_{data.name}` | `useSocketioSupport` |
|
|
295
|
+
| **Centrifuge**| `pie{methodName}_{data.name}_{centrifugeChannel}` | `useCentrifugeSupport` + `centrifugeChannel` |
|
|
296
|
+
| **Mitt** | `pie{methodName}_{data.name}` | `useMittSupport` |
|
|
297
|
+
|
|
298
|
+
```tsx
|
|
299
|
+
import { PieCard } from '@swarm.ing/pieui'
|
|
300
|
+
|
|
301
|
+
function LiveCounter({ data }) {
|
|
302
|
+
const [count, setCount] = useState(0)
|
|
303
|
+
return (
|
|
304
|
+
<PieCard
|
|
305
|
+
card="LiveCounter"
|
|
306
|
+
data={data}
|
|
307
|
+
useMittSupport
|
|
308
|
+
useSocketioSupport
|
|
309
|
+
methods={{
|
|
310
|
+
increment: (payload) => setCount((c) => c + (payload?.by ?? 1)),
|
|
311
|
+
reset: () => setCount(0),
|
|
312
|
+
}}
|
|
313
|
+
>
|
|
314
|
+
<span>{count}</span>
|
|
315
|
+
</PieCard>
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
The `methods` map is held in a ref, so you can pass freshly-created closures every render without re-subscribing. Cleanup runs on unmount or when `data.name`/the support flags change.
|
|
321
|
+
|
|
322
|
+
### Emitting Mitt events — `usePieEmit`
|
|
323
|
+
|
|
324
|
+
Trigger a card's Mitt-subscribed method from anywhere in the tree:
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
import { usePieEmit } from '@swarm.ing/pieui'
|
|
328
|
+
|
|
329
|
+
function Controls() {
|
|
330
|
+
const emit = usePieEmit('LiveCounter') // card name
|
|
331
|
+
return <button onClick={() => emit('increment', { by: 5 })}>+5</button>
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
`getEmitter()` returns the shared emitter for imperative use outside React.
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Server-driven AJAX updates
|
|
340
|
+
|
|
341
|
+
Cards that trigger updates receive a `setUiAjaxConfiguration` callback. Combined with `useAjaxSubmit`, a card can POST to the backend and swap part of the UI — or stream UI events — without a full reload.
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
import { useAjaxSubmit } from '@swarm.ing/pieui'
|
|
345
|
+
|
|
346
|
+
function SubmitButton({ data, setUiAjaxConfiguration }) {
|
|
347
|
+
const submit = useAjaxSubmit(
|
|
348
|
+
setUiAjaxConfiguration,
|
|
349
|
+
data.kwargs, // static key/values from the card config
|
|
350
|
+
data.deps_names, // client-side values resolved at submit time
|
|
351
|
+
data.pathname, // backend handler path
|
|
352
|
+
{ timeout: 10_000, retryPolicy: { maxRetries: 2, baseDelay: 1000 } }
|
|
353
|
+
)
|
|
354
|
+
return <button onClick={() => submit({ extra: 'value' })}>Submit</button>
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The request is `POST {apiServer}/api/ajax_content{pathname}`, and the response either replaces the `UIConfigType` subtree or streams JSON-line UI events through `setUiAjaxConfiguration`. The body is assembled from three sources:
|
|
359
|
+
|
|
360
|
+
1. **`kwargs`** — static key/value pairs from the card config.
|
|
361
|
+
2. **`extraKwargs`** — values passed to the returned submit function at call time.
|
|
362
|
+
3. **`depsNames`** — names whose **current client-side value** is read at submit time (see below).
|
|
363
|
+
|
|
364
|
+
### `RetryPolicy`
|
|
365
|
+
|
|
366
|
+
```ts
|
|
367
|
+
type RetryPolicy = {
|
|
368
|
+
maxRetries?: number // default 0 (no retries)
|
|
369
|
+
baseDelay?: number // default 1000 ms; doubled each attempt
|
|
370
|
+
retryOn?: number[] // default [502, 503, 504]; timeouts/network errors always retry
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## `depsNames` — client-side submit sources
|
|
377
|
+
|
|
378
|
+
Each entry in `depsNames` is a "magic name": an optional **source prefix** plus a key. The value is submitted under the **bare key** (the part after the prefix), so `localStorage:token` is sent as the field `token`.
|
|
379
|
+
|
|
380
|
+
| `depsNames` entry | Read from |
|
|
381
|
+
| ------------------------ | ------------------------------------------------------------- |
|
|
382
|
+
| `email` *(no prefix)* | DOM input named `email` (`document.getElementsByName`) |
|
|
383
|
+
| `sid` | `window.sid` — Socket.IO session id (awaits the socket) |
|
|
384
|
+
| `localStorage:<key>` | `localStorage.getItem(key)` |
|
|
385
|
+
| `sessionStorage:<key>` | `sessionStorage.getItem(key)` |
|
|
386
|
+
| `cookie:<name>` | matching cookie from `document.cookie` (URL-decoded) |
|
|
387
|
+
| `url:<param>` | `?<param>` query params (repeated → multiple values) |
|
|
388
|
+
| `telegram:cloud:<key>` | `Telegram.WebApp.CloudStorage.getItem` *(async)* |
|
|
389
|
+
| `telegram:secure:<key>` | `Telegram.WebApp.SecureStorage.getItem` *(async)* |
|
|
390
|
+
|
|
391
|
+
```ts
|
|
392
|
+
depsNames: ['email', 'localStorage:token', 'url:ref', 'sid']
|
|
393
|
+
// POST body fields: email, token, ref, sid
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Notes:
|
|
397
|
+
|
|
398
|
+
- A **missing value contributes nothing** — the field is simply omitted (same as an absent DOM input).
|
|
399
|
+
- A single entry can yield **multiple values** (a multi-file `<input>`, repeated `url:` params); each is appended under the same bare key.
|
|
400
|
+
- `telegram:cloud:` / `telegram:secure:` are **async**. The submit flow awaits them; the sync `readAjaxKey` returns `[]` for them, so use `readAjaxKeyAsync` to read directly. `parseDepName(name)` returns `{ source, key }`.
|
|
401
|
+
- `depsNames` is normally supplied by the backend `UIConfig` at runtime — it is data interpreted by the frontend, not a CLI surface.
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Configuration & environment
|
|
406
|
+
|
|
407
|
+
`PieConfig` (passed to roots as `config`):
|
|
408
|
+
|
|
409
|
+
```ts
|
|
410
|
+
interface PieConfig {
|
|
411
|
+
apiServer: string // base URL of the PieUI API (build endpoints from it)
|
|
412
|
+
centrifugeServer?: string // Centrifuge websocket URL
|
|
413
|
+
enableRenderingLog?: boolean // verbose render/AJAX/realtime logging
|
|
414
|
+
pageProcessor?: string // page-processing configuration
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
When PieUI is wired through the CLI scaffold, these are read from environment variables (multiple framework prefixes supported):
|
|
419
|
+
|
|
420
|
+
- `PIE_API_SERVER` / `VITE_PIE_API_SERVER` / `NEXT_PUBLIC_PIE_API_SERVER`
|
|
421
|
+
- `PIE_CENTRIFUGE_SERVER` / `VITE_PIE_CENTRIFUGE_SERVER` / `NEXT_PUBLIC_PIE_CENTRIFUGE_SERVER`
|
|
422
|
+
- `PIE_ENABLE_RENDERING_LOG` (optional)
|
|
423
|
+
- `PIE_PAGE_PROCESSOR` (optional)
|
|
424
|
+
|
|
425
|
+
Use the literal value `auto-api` for a server URL to derive it automatically from the current hostname.
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## Registry API
|
|
430
|
+
|
|
431
|
+
All exported from `@swarm.ing/pieui` (and `/native`):
|
|
432
|
+
|
|
433
|
+
| Function | Description |
|
|
434
|
+
| --------------------------------- | ---------------------------------------------------------------------------- |
|
|
435
|
+
| `registerPieComponent(reg)` | Register a component or lazy loader. Returns the (possibly lazy) component. |
|
|
436
|
+
| `registerMultipleComponents([…])` | Register an array of registrations at once. |
|
|
437
|
+
| `unregisterComponent(name)` | Remove a component from the registry. |
|
|
438
|
+
| `hasComponent(name)` | `true` if a name is registered. |
|
|
439
|
+
| `getRegistryEntry(name)` | Full `ComponentRegistration` (incl. `fallback` / `isLazy`). |
|
|
440
|
+
| `getComponentMeta(name)` | The `metadata` supplied at registration, if any. |
|
|
441
|
+
| `getAllRegisteredComponents()` | Array of all registered names. |
|
|
442
|
+
| `getRegistrySize()` | Number of registered components. |
|
|
443
|
+
| `getLazyComponentNames()` | Names of code-split (lazy) components. |
|
|
444
|
+
| `preloadComponent(name)` | Warm a single lazy chunk so the next render resolves without a fallback flash. |
|
|
445
|
+
| `prefetchLazyComponents()` | Idle-time, connection-aware background warm-up of every lazy chunk (idempotent). |
|
|
446
|
+
| `registry` | The underlying `Map` (shared singleton across all entry points). |
|
|
447
|
+
| `trackLazy(loader, name)` | Low-level `React.lazy` wrapper with named tracking. |
|
|
448
|
+
|
|
449
|
+
> The registry is stored on `globalThis` under a shared `Symbol.for` key, so a card registered through one entry point (`/components`) is visible to a renderer loaded from another (`/telegram`). This avoids "[UI] Component not found in registry" across bundles.
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Styling helpers
|
|
454
|
+
|
|
455
|
+
- **`cn(...classes)`** — class-name merge built on `clsx` + `tailwind-merge` (dedupes conflicting Tailwind utilities).
|
|
456
|
+
- **`sx2radium(style)`** — converts a style object into Radium-friendly `CSSProperties`, including turning an object `animationName` into Radium keyframes.
|
|
457
|
+
- **`PIEBREAK`** — the `__piedemo__` delimiter used internally to build form field names.
|
|
458
|
+
- **`pieName(...)`** — helper for composing Pie event/field names.
|
|
459
|
+
- **`submitGlobalForm()`** — programmatically submits the implicit global `<form>`.
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## Platform integrations
|
|
464
|
+
|
|
465
|
+
### Telegram Mini Apps
|
|
466
|
+
|
|
467
|
+
```tsx
|
|
468
|
+
import { PieTelegramRoot, useWebApp, useInitData } from '@swarm.ing/pieui/telegram'
|
|
469
|
+
|
|
470
|
+
function App() {
|
|
471
|
+
return <PieTelegramRoot location={location} config={config} />
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
- `useWebApp()` — the full `Telegram.WebApp` object (typed: `MainButton`, `BackButton`, `HapticFeedback`, `CloudStorage`, `BiometricManager`, theme params, safe-area insets, fullscreen/orientation, and the Bot API methods).
|
|
476
|
+
- `useInitData()` — the parsed init data.
|
|
477
|
+
- Importing this entry also registers `CloudStorageCard` and `SecureStorageCard`.
|
|
478
|
+
|
|
479
|
+
### MAX (VK Messenger)
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
import {
|
|
483
|
+
PieMaxRoot,
|
|
484
|
+
useMaxWebApp,
|
|
485
|
+
useMaxInitData,
|
|
486
|
+
useMaxBackButton,
|
|
487
|
+
useMaxHapticFeedback,
|
|
488
|
+
} from '@swarm.ing/pieui/max'
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Typed access to the MAX bridge (`BackButton`, `HapticFeedback`, `DeviceStorage`/`SecureStorage`, `BiometricManager`, share/download helpers, screen capture, etc.).
|
|
492
|
+
|
|
493
|
+
### React Native
|
|
494
|
+
|
|
495
|
+
The `/native` entry exposes the platform-agnostic core (registry, `UI`, `PieCard`, real-time contexts, AJAX helpers) plus native-specific wiring. It deliberately does **not** export the DOM container/leaf cards — on native the host registers its own React Native leaf components and renders them through `UI`/`PieCard`. Metro resolves the `.native` platform layer automatically.
|
|
496
|
+
|
|
497
|
+
Wire the host's storage / route / form sources once at startup:
|
|
498
|
+
|
|
499
|
+
```ts
|
|
500
|
+
import { configureNativeClientSources } from '@swarm.ing/pieui/native'
|
|
501
|
+
import { MMKV } from 'react-native-mmkv'
|
|
502
|
+
|
|
503
|
+
const mmkv = new MMKV()
|
|
504
|
+
|
|
505
|
+
configureNativeClientSources({
|
|
506
|
+
storage: {
|
|
507
|
+
getItem: (k) => mmkv.getString(k) ?? null,
|
|
508
|
+
setItem: (k, v) => mmkv.set(k, v),
|
|
509
|
+
removeItem: (k) => mmkv.delete(k),
|
|
61
510
|
},
|
|
511
|
+
getRouteParams: (key) => getCurrentRoute().params[key] ?? [],
|
|
512
|
+
getInput: (name) => readNativeField(name),
|
|
513
|
+
submitForm: () => {/* host submit */},
|
|
62
514
|
})
|
|
63
515
|
```
|
|
64
516
|
|
|
65
|
-
|
|
66
|
-
|
|
517
|
+
`NativeClientConfig` supports sync (`storage`, `sessionStorage`) and async (`asyncStorage`, `asyncSessionStorage`) adapters, `getCookie`, `getRouteParams`, `getInput`, and `submitForm`. Unconfigured sources degrade to the same "missing value" semantics as web (`null` / `[]`). Render with `PieRoot`/`PieNativeRoot` and pass `disableGlobalForm` (there is no HTML form on native). A small native form store is exposed via `setNativeField` / `clearNativeField` / `readNativeField`.
|
|
518
|
+
|
|
519
|
+
---
|
|
520
|
+
|
|
521
|
+
## OpenAI agent integration
|
|
67
522
|
|
|
68
|
-
|
|
69
|
-
- `PieRoot`: Fetches UI configuration from `config.apiServer + "/api/content"` using the current `location` and renders `UI` inside PieUI providers (React Query, Socket.IO, Centrifuge, Mitt, Radium). Calls `initializePieComponents()` and your `initializePie` callback once.
|
|
70
|
-
- `PieTelegramRoot`: Same as `PieRoot`, but adds Telegram WebApp `initData` to the request query string via `useWebApp`. Throws if `apiServer` is missing.
|
|
71
|
-
- `PieBaseRoot`: Provider wrapper without fetching UI configuration. Renders `children` inside the same PieUI provider stack and form shell.
|
|
72
|
-
- `PieCard`: Wrapper for card components that wires optional Socket.IO, Centrifuge, or Mitt event handlers based on `methods` and `data.name`. Returns `children` unchanged.
|
|
73
|
-
- `registerPieComponent`: Registers a component (or lazy loader) into the PieUI registry, with optional metadata and fallback.
|
|
74
|
-
- `initializePieComponents`: Registers the built-in card components once (SequenceCard, BoxCard, UnionCard, AjaxGroupCard, AjaxButtonCard, RedirectButtonCard, ChatCard, HiddenCard, AutoRedirectCard, HTMLEmbedCard, IOEventsCard, OpenAIVoiceAgentCard, TableCard).
|
|
75
|
-
- `isPieComponentsInitialized`: Returns `true` if `initializePieComponents` has already been called.
|
|
76
|
-
- `useAjaxSubmit`: Hook that returns a function to `POST` to `api/ajax_content` and updates UI state via `setUiAjaxConfiguration`. Supports streamed JSON line events.
|
|
77
|
-
- `sx2radium`: Converts a style object to Radium-friendly `CSSProperties`, including converting object `animationName` into Radium keyframes.
|
|
78
|
-
- `cn`: Class name merge helper using `clsx` and `tailwind-merge`.
|
|
79
|
-
- `PIEBREAK`: String delimiter (`__piedemo__`) used internally to build form field names.
|
|
523
|
+
The `/agent` entry exposes PieCard methods as OpenAI function tools and provides a WebRTC voice hook. It pulls in `@openai/agents`, so it's a separate entry to keep it out of apps that don't need it.
|
|
80
524
|
|
|
81
|
-
|
|
525
|
+
```tsx
|
|
526
|
+
import {
|
|
527
|
+
usePieMittAgentTools, // hook: build tools from the active Mitt emitter
|
|
528
|
+
getMittAgentTools, // imperative variant
|
|
529
|
+
useOpenAIWebRTC, // WebRTC voice session hook
|
|
530
|
+
} from '@swarm.ing/pieui/agent'
|
|
531
|
+
```
|
|
82
532
|
|
|
83
|
-
- `
|
|
84
|
-
- `
|
|
85
|
-
- `PieComplexComponentProps`: `{ data, setUiAjaxConfiguration? }` props for components that trigger AJAX or updates.
|
|
86
|
-
- `PieContainerComponentProps`: `{ data, content, setUiAjaxConfiguration? }` props for components that render a single nested `UIConfigType`.
|
|
87
|
-
- `PieComplexContainerComponentProps`: `{ data, content: UIConfigType[], setUiAjaxConfiguration? }` props for components that render an array of nested configs.
|
|
88
|
-
- `PieConfig`: Configuration object for Pie roots. Includes `apiServer` and optional `centrifugeServer`, `enableRenderingLog`, `pageProcessor`.
|
|
89
|
-
- `UIConfigType`: Server-driven UI configuration with `card`, `data`, and `content` (nested `UIConfigType` or array).
|
|
90
|
-
- `SetUiAjaxConfigurationType`: Setter type for updating the UI configuration or streaming UI events.
|
|
533
|
+
- `getMittAgentTools(descriptors, options)` / `usePieMittAgentTools(...)` — turn PieCard methods into agent tools. Options: `filter`, `describe`, and `nameFor` to control which descriptors become tools, their descriptions, and tool names.
|
|
534
|
+
- `useOpenAIWebRTC(audioElement?, onEvent?)` — returns `{ isSessionActive, startSession(ephemeralKey, useMicrophone?), stopSession(), sendTextMessage(text) }` for an OpenAI Realtime WebRTC session (pass an `<audio>` element to play remote audio). Pairs with `HTMLEmbedCard`'s AI-generation support.
|
|
91
535
|
|
|
92
|
-
|
|
536
|
+
---
|
|
93
537
|
|
|
94
|
-
|
|
538
|
+
## Storybook integration
|
|
95
539
|
|
|
96
|
-
|
|
97
|
-
|
|
540
|
+
Test cards in isolation with the PieUI providers and fire their real-time methods from the Storybook UI.
|
|
541
|
+
|
|
542
|
+
```tsx
|
|
543
|
+
// .storybook/preview.tsx
|
|
544
|
+
import { withPieCard } from '@swarm.ing/pieui/storybook'
|
|
545
|
+
export const decorators = [withPieCard]
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
```tsx
|
|
549
|
+
// MyCard.stories.tsx
|
|
550
|
+
import { PieStorybookProviders, PieMethodTrigger } from '@swarm.ing/pieui/storybook'
|
|
551
|
+
|
|
552
|
+
export const Live = () => (
|
|
553
|
+
<PieStorybookProviders>
|
|
554
|
+
<MyCard data={{ name: 'MyCard' }} />
|
|
555
|
+
<PieMethodTrigger card="MyCard" method="increment" payload={{ by: 1 }} />
|
|
556
|
+
</PieStorybookProviders>
|
|
557
|
+
)
|
|
98
558
|
```
|
|
99
559
|
|
|
100
|
-
|
|
560
|
+
- `PieStorybookProviders` — mounts the full provider stack with a stubbed config and a local Mitt emitter.
|
|
561
|
+
- `withPieCard` — decorator wrapping a story in those providers + a channel bridge.
|
|
562
|
+
- `PieMethodTrigger` — a button that fires a `pie{method}_{card}` Mitt event.
|
|
563
|
+
- `firePieMethod(emitter, card, method, payload)` / `usePieStorybookEmitter()` — imperative helpers.
|
|
564
|
+
- The **addon** (`@swarm.ing/pieui/storybook/addon`) adds a Storybook panel to fire methods interactively; register it in `.storybook/main` (the CLI's `card add-story` does this automatically).
|
|
565
|
+
|
|
566
|
+
---
|
|
101
567
|
|
|
102
|
-
|
|
103
|
-
- initializes `piecomponents/registry.ts` and PieUI config in the new app
|
|
104
|
-
- prepares the app for `bunx pieui card add ...`
|
|
568
|
+
## CLI reference
|
|
105
569
|
|
|
106
|
-
|
|
570
|
+
The CLI ships as `pieui` (run via `bunx pieui …` or the installed bin). It mirrors the backend `pie` Python CLI — subcommand names, positionals, and flags are kept in sync.
|
|
571
|
+
|
|
572
|
+
### Scaffolding
|
|
107
573
|
|
|
108
574
|
```sh
|
|
109
|
-
|
|
110
|
-
#
|
|
111
|
-
|
|
575
|
+
pieui create <AppName> # create a Next.js app and run `pieui init` inside it
|
|
576
|
+
pieui create-pie-app <AppName> # create a blank PieUI Next.js template (alias: create-pieui)
|
|
577
|
+
pieui init [--out-dir <dir>] # add piecomponents/, registry.ts, Tailwind & Next config to an existing app
|
|
112
578
|
```
|
|
113
579
|
|
|
114
|
-
|
|
580
|
+
`create` scaffolds Next.js (`next-app@latest`), installs `@swarm.ing/pieui`, runs `init`, installs Storybook, then `bun run dev`. `init` also searches your home directory (depth ≤ 2) for a backend project with `pages/` and `components/` dirs and, in a TTY, offers to link them (saved to `.pie/config.json`).
|
|
115
581
|
|
|
116
|
-
|
|
117
|
-
- copies a standard `_shared` folder into the new app (sourced from `ai-exchange-bot` when found)
|
|
118
|
-
- rewrites `dev/build/start` scripts to `bun --bun next ...`
|
|
119
|
-
- appends a TODO marker in `app/page.tsx` for future backend (Python Unicorn) linking
|
|
582
|
+
### Build
|
|
120
583
|
|
|
121
|
-
|
|
584
|
+
```sh
|
|
585
|
+
pieui postbuild [--src-dir <dir>] [--out-dir <dir>] [--append]
|
|
586
|
+
```
|
|
122
587
|
|
|
123
|
-
|
|
588
|
+
Scans for `registerPieComponent()` calls, generates a JSON Schema per card data type, and writes `pieui.components.json`. Defaults: `--src-dir src`, `--out-dir public`. `--append` merges with the library manifest in `node_modules`.
|
|
124
589
|
|
|
125
590
|
```sh
|
|
126
|
-
|
|
591
|
+
pieui self-upgrade [--pm <bun|pnpm|yarn|npm>] # upgrade the global CLI
|
|
127
592
|
```
|
|
128
593
|
|
|
129
|
-
|
|
594
|
+
### Auth
|
|
130
595
|
|
|
131
596
|
```sh
|
|
132
|
-
|
|
597
|
+
pieui login # browser auth; writes .pie/config.json and PIE_* keys into .env
|
|
133
598
|
```
|
|
134
599
|
|
|
135
|
-
|
|
600
|
+
### Pages (`pieui page …`)
|
|
136
601
|
|
|
137
602
|
```sh
|
|
138
|
-
|
|
603
|
+
pieui page add <path> # create app/<path>/page.tsx from the Pie page template
|
|
604
|
+
pieui page view <path> # print the page source
|
|
605
|
+
pieui page ajax <path> <add|remove> <handler> # add/remove an AJAX handler (delegates to the backend)
|
|
139
606
|
```
|
|
140
607
|
|
|
141
|
-
|
|
608
|
+
`add` normalizes the path under `app/`, derives a `PascalCasePage` component name, and rejects traversal outside `app/`.
|
|
142
609
|
|
|
143
|
-
|
|
144
|
-
|
|
610
|
+
### Cards (`pieui card …`)
|
|
611
|
+
|
|
612
|
+
```sh
|
|
613
|
+
pieui card add [<type>] <Name> [--io] [--ajax] [--input] [--from <ref>]
|
|
614
|
+
```
|
|
145
615
|
|
|
146
|
-
|
|
147
|
-
import { Suspense } from 'react'
|
|
148
|
-
import LoadingScreen from '@/components/LoadingScreen'
|
|
616
|
+
Creates `piecomponents/<Name>/` (`index.ts`, `types/index.ts`, `ui/<Name>.tsx`) and registers it in `registry.ts`. `<type>` is one of `simple`, `complex`, `simple-container`, `complex-container` (default). Flags:
|
|
149
617
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
618
|
+
- `--io` — add real-time support fields (`use_*_support`) to the data interface.
|
|
619
|
+
- `--ajax` — add AJAX fields (`pathname`, `deps_names`, `kwargs`).
|
|
620
|
+
- `--input` — generate the `InputPie…ComponentProps` variant with a typed `stored` prop.
|
|
621
|
+
- `--from <ref>` — port from backend Python metadata (a `.py`/JSON path, a card name, or auto-detected from the configured `backendComponentsDir`).
|
|
622
|
+
|
|
623
|
+
```sh
|
|
624
|
+
pieui card list [<filter>] [--src-dir <dir>] # list cards (filter: all|simple|complex|simple-container|complex-container)
|
|
625
|
+
pieui card view <Name> # print a card's props, ajax, io, and events
|
|
626
|
+
pieui card remove <Name> # delete a card directory
|
|
627
|
+
pieui card list-events <Name> # list a card's methods (event handlers)
|
|
628
|
+
pieui card add-event <Name> <EventName> # add a method to a card
|
|
629
|
+
pieui card pull <ref> # restore a card from a URL, local JSON file, or remote name
|
|
157
630
|
```
|
|
158
631
|
|
|
159
|
-
|
|
632
|
+
Metadata & Storybook:
|
|
160
633
|
|
|
161
634
|
```sh
|
|
162
|
-
|
|
635
|
+
pieui card dump-metadata <Name> [--out <file.json>] # emit full PieMetadata JSON (props/events/imports/ajax/io)
|
|
636
|
+
pieui card check-sync <Name> # compare TypeScript ↔ Python metadata, report mismatches
|
|
637
|
+
pieui card add-story <Name> [--force] # generate <Name>.stories.tsx wired to PieCard methods
|
|
638
|
+
pieui card generate-preview <Name> [--out <file.png>] # render the story via storycap to a PNG
|
|
163
639
|
```
|
|
164
640
|
|
|
165
|
-
|
|
641
|
+
### Remote card storage (`pieui card remote …`)
|
|
166
642
|
|
|
167
643
|
```sh
|
|
168
|
-
|
|
644
|
+
pieui card remote list [--user <id>] [--project <slug>]
|
|
645
|
+
pieui card remote push <Name>
|
|
646
|
+
pieui card remote pull <Name>[@rev]
|
|
647
|
+
pieui card remote remove <Name>
|
|
648
|
+
pieui card remote history <Name> [--page <n>] [--per-page <n>] [--from <r>] [--to <r>]
|
|
649
|
+
pieui card remote public <Name> # make readable as r/<user>/<Name>
|
|
650
|
+
pieui card remote private <Name> # revert to private
|
|
169
651
|
```
|
|
170
652
|
|
|
171
|
-
|
|
653
|
+
### Registry preview harness (`pieui registry …`)
|
|
172
654
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
655
|
+
```sh
|
|
656
|
+
pieui registry dev [--port <n>] [--api-server <url>] # run the PiePreviewRoot harness (default port 3210)
|
|
657
|
+
pieui registry build [--out <dir>] # static-export the harness (default .pie/registry/out)
|
|
658
|
+
```
|
|
176
659
|
|
|
177
|
-
|
|
178
|
-
2. `extraKwargs` — values passed at call time.
|
|
179
|
-
3. `depsNames` — names whose **current client-side value** is read and appended
|
|
180
|
-
at submit time.
|
|
660
|
+
### Configuration & environment
|
|
181
661
|
|
|
182
|
-
|
|
183
|
-
key. The value is always submitted under the **bare key** (the part after the
|
|
184
|
-
prefix), so `localStorage:token` is sent as the field `token`.
|
|
662
|
+
`.pie/config.json` (written by `login` / `init`) holds `user_id`, `project`, `api_key`, and optional `backendPagesDir` / `backendComponentsDir`. Notable env vars: `PIE_USER_ID`, `PIE_PROJECT`/`PIE_PROJECT_SLUG`, `PIE_API_KEY`; `PIEUI_CREATE_NEXT_APP_SPEC`, `PIEUI_CREATE_PACKAGE_SPEC`, `PIEUI_CREATE_BUN_BIN`, `PIEUI_CREATE_SKIP_STORYBOOK`; `PIEUI_LOGIN_CONNECT_BASE`, `PIEUI_LOGIN_CREDENTIALS_API`. Add `--help`/`-h` to any command for scoped help.
|
|
185
663
|
|
|
186
|
-
|
|
187
|
-
| ------------------------- | ------------------------------------------------------------- |
|
|
188
|
-
| `email` _(no prefix)_ | DOM input named `email` (`document.getElementsByName`) |
|
|
189
|
-
| `sid` | `window.sid` — SocketIO session id (awaits the socket) |
|
|
190
|
-
| `localStorage:<key>` | `localStorage.getItem(key)` |
|
|
191
|
-
| `sessionStorage:<key>` | `sessionStorage.getItem(key)` |
|
|
192
|
-
| `cookie:<name>` | matching cookie from `document.cookie` (URL-decoded) |
|
|
193
|
-
| `url:<param>` | `?<param>` query params (repeated params → multiple values) |
|
|
194
|
-
| `telegram:cloud:<key>` | `Telegram.WebApp.CloudStorage.getItem` _(async)_ |
|
|
195
|
-
| `telegram:secure:<key>` | `Telegram.WebApp.SecureStorage.getItem` _(async)_ |
|
|
664
|
+
---
|
|
196
665
|
|
|
197
|
-
|
|
666
|
+
## API reference
|
|
198
667
|
|
|
199
|
-
|
|
200
|
-
field is simply omitted from the request.
|
|
201
|
-
- A single entry can yield **multiple values** (a multi-file `<input>`, repeated
|
|
202
|
-
`url:` params); each is appended under the same bare key.
|
|
203
|
-
- `telegram:cloud:` / `telegram:secure:` are **asynchronous**. The submit flow
|
|
204
|
-
awaits them automatically; the sync `readAjaxKey` returns `[]` for them, so use
|
|
205
|
-
`readAjaxKeyAsync` if reading directly.
|
|
206
|
-
- The storage prefixes mirror the storage cards: `localStorage:` ↔
|
|
207
|
-
`DeviceStorageCard`, `sessionStorage:` ↔ `SessionStorageCard`,
|
|
208
|
-
`telegram:cloud:` ↔ `CloudStorageCard`, `telegram:secure:` ↔
|
|
209
|
-
`SecureStorageCard`. The Telegram cards live under the
|
|
210
|
-
`@swarm.ing/pieui/telegram` entry.
|
|
211
|
-
|
|
212
|
-
Example — submit a DOM field, a localStorage token, a URL param and the socket
|
|
213
|
-
id together:
|
|
668
|
+
### Runtime exports (`@swarm.ing/pieui`)
|
|
214
669
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
670
|
+
| Export | Description |
|
|
671
|
+
| ------ | ----------- |
|
|
672
|
+
| `UI` | Renders a `UIConfigType` by resolving `uiConfig.card` from the registry (Suspense for lazy cards; passes `data`, `content`, `setUiAjaxConfiguration`). |
|
|
673
|
+
| `UILoading` | Renders a cached/placeholder shell while a screen loads. |
|
|
674
|
+
| `UIRendererContext` | Context carrying renderer props (`UIRendererProps`). |
|
|
675
|
+
| `PieRoot` / `PieBaseRoot` / `PiePreviewRoot` | Root components (see [Root components](#root-components)). |
|
|
676
|
+
| `PieCard` | Wires a card into Socket.IO / Centrifuge / Mitt messaging. |
|
|
677
|
+
| `registerPieComponent` & registry helpers | See [Registry API](#registry-api). |
|
|
678
|
+
| `trackLazy` | Named `React.lazy` wrapper. |
|
|
679
|
+
| `useAjaxSubmit` / `readAjaxKey` / `readAjaxKeyAsync` / `parseDepName` | AJAX submit + dep-name resolution. |
|
|
680
|
+
| `usePieEmit` / `getEmitter` / `MittContext` | Mitt event emission. |
|
|
681
|
+
| `SocketIOContext` / `CentrifugeIOContext` / `FallbackContext` / `PieConfigContext` | PieUI contexts. |
|
|
682
|
+
| `cn` / `sx2radium` / `pieName` / `submitGlobalForm` / `PIEBREAK` | Utilities. |
|
|
683
|
+
|
|
684
|
+
### Type exports
|
|
685
|
+
|
|
686
|
+
`PieComponentProps`, `PieSimpleComponentProps`, `PieComplexComponentProps`, `PieContainerComponentProps`, `PieComplexContainerComponentProps`, and their `InputPie…` variants; `PieConfig`, `UIConfigType`, `SetUiAjaxConfigurationType`, `PieQueryOptions`, `RetryPolicy`, `DepSource`. Telegram/MAX entries export their respective `WebApp`/init-data types; the `/native` entry adds `PieRootProps`, `PieBaseRootProps`, and the `NativeClientConfig`/adapter types.
|
|
687
|
+
|
|
688
|
+
---
|
|
689
|
+
|
|
690
|
+
## License
|
|
219
691
|
|
|
220
|
-
|
|
221
|
-
Python card field that produces it, see the `pie` repo (`deps_names`).
|
|
692
|
+
MIT
|