uidl-runtime 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/LICENSE +21 -0
- package/README.md +175 -0
- package/bin/validate.mjs +44 -0
- package/dist/actions/eventBus.d.ts +7 -0
- package/dist/actions/index.d.ts +5 -0
- package/dist/actions/interpreter.d.ts +54 -0
- package/dist/compiler/dashboard.d.ts +10 -0
- package/dist/compiler/form.d.ts +22 -0
- package/dist/compiler/index.d.ts +16 -0
- package/dist/compiler/list.d.ts +20 -0
- package/dist/compiler/report.d.ts +10 -0
- package/dist/compiler/settings.d.ts +10 -0
- package/dist/compiler/tree.d.ts +10 -0
- package/dist/compiler/types.d.ts +315 -0
- package/dist/compiler/wizard.d.ts +10 -0
- package/dist/components/BarcodeAndQRCode.d.ts +29 -0
- package/dist/components/charts.d.ts +66 -0
- package/dist/components/iconPaths.d.ts +5 -0
- package/dist/components/icons.d.ts +31 -0
- package/dist/components/primitives.d.ts +411 -0
- package/dist/data/adapters/http.d.ts +37 -0
- package/dist/data/adapters/inMemory.d.ts +62 -0
- package/dist/data/errors.d.ts +15 -0
- package/dist/data/index.d.ts +7 -0
- package/dist/data/testing/mockHttpServer.d.ts +16 -0
- package/dist/data/types.d.ts +74 -0
- package/dist/editor/Canvas.d.ts +22 -0
- package/dist/editor/Editor.d.ts +18 -0
- package/dist/editor/LayerTree.d.ts +12 -0
- package/dist/editor/PropertyPanel.d.ts +7 -0
- package/dist/editor/StylePanel.d.ts +7 -0
- package/dist/editor/ValidationStatus.d.ts +9 -0
- package/dist/editor/WidgetPalette.d.ts +6 -0
- package/dist/editor/document.d.ts +10 -0
- package/dist/editor/index.d.ts +2 -0
- package/dist/editor/store.d.ts +46 -0
- package/dist/expr/evaluate.d.ts +51 -0
- package/dist/hooks/useElementWidth.d.ts +14 -0
- package/dist/index.d.ts +61 -0
- package/dist/registry/defaults.d.ts +2 -0
- package/dist/registry/registry.d.ts +4 -0
- package/dist/renderer/RenderNode.d.ts +16 -0
- package/dist/renderer/UIDocumentRenderer.d.ts +13 -0
- package/dist/renderer/instantiateComponent.d.ts +18 -0
- package/dist/renderer/renderDocument.d.ts +63 -0
- package/dist/schema/action.schema.json +515 -0
- package/dist/schema/design-tokens.schema.json +51 -0
- package/dist/schema/jsonSchema.d.ts +11 -0
- package/dist/schema/theme-presets.schema.json +952 -0
- package/dist/schema/uidl-document.schema.json +187 -0
- package/dist/schemas/actions.d.ts +5 -0
- package/dist/schemas/document.d.ts +35 -0
- package/dist/schemas/theme.d.ts +260 -0
- package/dist/services/aiPromptGenerator.d.ts +11 -0
- package/dist/state/createDocumentState.d.ts +18 -0
- package/dist/state/dataSources.d.ts +58 -0
- package/dist/state/index.d.ts +4 -0
- package/dist/style.css +2 -0
- package/dist/theme/engine.d.ts +9 -0
- package/dist/theme/index.d.ts +7 -0
- package/dist/theme/meridianPreset.d.ts +5 -0
- package/dist/theme/presets.d.ts +5 -0
- package/dist/theme/registry.d.ts +15 -0
- package/dist/theme/serialize.d.ts +5 -0
- package/dist/theme/tailwind.d.ts +11 -0
- package/dist/types/actions.d.ts +116 -0
- package/dist/types/editor.d.ts +45 -0
- package/dist/types/index.d.ts +82 -0
- package/dist/types/theme.d.ts +95 -0
- package/dist/uidl-runtime.js +98 -0
- package/dist/uidl-runtime.js.map +1 -0
- package/dist/uidl-runtime.mjs +17779 -0
- package/dist/uidl-runtime.mjs.map +1 -0
- package/dist/utils/chart.d.ts +12 -0
- package/dist/utils/cn.d.ts +1 -0
- package/dist/utils/formLayout.d.ts +93 -0
- package/dist/utils/i18n.d.ts +132 -0
- package/dist/utils/listCell.d.ts +21 -0
- package/dist/utils/responsive.d.ts +3 -0
- package/dist/utils/tailwind.d.ts +23 -0
- package/dist/validate/validateResponsive.d.ts +7 -0
- package/dist/version.d.ts +10 -0
- package/package.json +109 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import { default as React, ReactNode, HTMLAttributes, ButtonHTMLAttributes, ChangeEvent } from 'react';
|
|
2
|
+
import { CellFormat } from '../utils/listCell';
|
|
3
|
+
export interface ContainerProps extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
}
|
|
6
|
+
export declare function Container({ children, ...props }: ContainerProps): React.JSX.Element;
|
|
7
|
+
export interface RowProps extends HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare function Row({ children, ...props }: RowProps): React.JSX.Element;
|
|
11
|
+
export interface ColumnProps extends HTMLAttributes<HTMLDivElement> {
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
export declare function Column({ children, ...props }: ColumnProps): React.JSX.Element;
|
|
15
|
+
export interface StackProps extends HTMLAttributes<HTMLDivElement> {
|
|
16
|
+
children?: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
export declare function Stack({ children, ...props }: StackProps): React.JSX.Element;
|
|
19
|
+
export type SpacerProps = HTMLAttributes<HTMLDivElement>;
|
|
20
|
+
export declare function Spacer(props: SpacerProps): React.JSX.Element;
|
|
21
|
+
export type DividerProps = HTMLAttributes<HTMLHRElement>;
|
|
22
|
+
/** Meridian separates every list row and dashboard section with a 1px gray-200 rule. */
|
|
23
|
+
export declare function Divider({ children: _children, ...props }: DividerProps): React.JSX.Element;
|
|
24
|
+
export interface TextProps extends HTMLAttributes<HTMLParagraphElement> {
|
|
25
|
+
value?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Render as `<h1>`…`<h6>` instead of `<p>`. Meridian's page and form titles are real headings
|
|
28
|
+
* (PageHeader's `<h1>`, FormHeader's `<h1>`, Sidebar's `<h6>`), and a document
|
|
29
|
+
* that titles a page needs the same landmark rather than a styled paragraph.
|
|
30
|
+
*/
|
|
31
|
+
heading?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
32
|
+
/**
|
|
33
|
+
* Print a bound numeric/date value the way a list cell would. A list's summary figures are
|
|
34
|
+
* the same money as the column they total, so they have to read the same way — an aggregate
|
|
35
|
+
* bound straight into a Text otherwise renders the raw `1500000`.
|
|
36
|
+
*/
|
|
37
|
+
format?: CellFormat;
|
|
38
|
+
/** BCP 47 tag used when `format` is set. */
|
|
39
|
+
locale?: string;
|
|
40
|
+
/** ISO 4217 code used when `format` is `currency`. */
|
|
41
|
+
currency?: string;
|
|
42
|
+
}
|
|
43
|
+
export declare function Text({ value, heading, format, locale, currency, ...props }: TextProps): React.JSX.Element;
|
|
44
|
+
export interface ImageProps extends HTMLAttributes<HTMLImageElement> {
|
|
45
|
+
src?: string;
|
|
46
|
+
alt?: string;
|
|
47
|
+
}
|
|
48
|
+
export declare function Image({ src, alt, children: _children, ...props }: ImageProps): React.JSX.Element;
|
|
49
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
50
|
+
label?: string;
|
|
51
|
+
/** Meridian's `type` prop, renamed to avoid colliding with the DOM `type` attribute. */
|
|
52
|
+
variant?: "primary" | "secondary";
|
|
53
|
+
/** Icon-only buttons get the narrower `px-3` instead of `px-6`. */
|
|
54
|
+
icon?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Name of an outline icon (see `ICON_NAMES`) drawn beside the label — Meridian's Button
|
|
57
|
+
* keeps an icon slot ahead of its default slot for exactly this.
|
|
58
|
+
*/
|
|
59
|
+
iconName?: string;
|
|
60
|
+
/** Which side of the label the icon sits on. */
|
|
61
|
+
iconPosition?: "start" | "end";
|
|
62
|
+
/** Drop the filled background (and the fixed `h-8`) for a bare text button. */
|
|
63
|
+
background?: boolean;
|
|
64
|
+
/** Drop horizontal padding entirely. */
|
|
65
|
+
padding?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/** Button */
|
|
68
|
+
export declare function Button({ label, children, variant, icon, iconName, iconPosition, background, padding, ...props }: ButtonProps): React.JSX.Element;
|
|
69
|
+
/**
|
|
70
|
+
* Meridian's status colors — `getBgTextColorClass` in src/utils/colors.ts is
|
|
71
|
+
* `bg-{color}-200 dark:bg-{color}-800` + `text-{color}-700 dark:text-{color}-200`. Written
|
|
72
|
+
* out per color rather than interpolated, because a class assembled at runtime is invisible
|
|
73
|
+
* to Tailwind's scanner (the same reason src/style.css exists at all).
|
|
74
|
+
*/
|
|
75
|
+
export type BadgeColor = "gray" | "orange" | "green" | "red" | "yellow" | "blue" | "indigo" | "pink" | "purple" | "teal";
|
|
76
|
+
export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
|
|
77
|
+
children?: ReactNode;
|
|
78
|
+
/** One of Meridian's status colors (src/utils/colors.ts). Anything else falls back to gray. */
|
|
79
|
+
color?: string;
|
|
80
|
+
/**
|
|
81
|
+
* `badge` is Meridian's Badge (`px-2 py-1`); `pill` is its StatusPill / `.pill`
|
|
82
|
+
* utility (`py-0.5 px-1.5`, `text-xs`, `font-medium`) used for document statuses.
|
|
83
|
+
*/
|
|
84
|
+
variant?: "badge" | "pill";
|
|
85
|
+
label?: string;
|
|
86
|
+
/** Optional leading outline icon — used for statuses that read better with a mark ("Balanced"). */
|
|
87
|
+
iconName?: string;
|
|
88
|
+
}
|
|
89
|
+
/** {Badge,StatusPill} */
|
|
90
|
+
export declare function Badge({ children, color, variant, label, iconName, ...props }: BadgeProps): React.JSX.Element;
|
|
91
|
+
export interface TextFieldProps extends HTMLAttributes<HTMLInputElement> {
|
|
92
|
+
label?: string;
|
|
93
|
+
value?: string;
|
|
94
|
+
error?: string;
|
|
95
|
+
/** Meridian's Base sizes: `small` = px-2 py-1 (form rows), `large` = px-3 py-2. */
|
|
96
|
+
size?: "small" | "large";
|
|
97
|
+
/** Meridian draws the box only where the field isn't already inside a bordered form row. */
|
|
98
|
+
border?: boolean;
|
|
99
|
+
placeholder?: string;
|
|
100
|
+
readOnly?: boolean;
|
|
101
|
+
}
|
|
102
|
+
/** Controls/{Base,Data} */
|
|
103
|
+
export declare function TextField({ label, value, error, children: _children, id, size, border, ...props }: TextFieldProps): React.JSX.Element;
|
|
104
|
+
export interface CheckboxProps extends HTMLAttributes<HTMLInputElement> {
|
|
105
|
+
label?: string;
|
|
106
|
+
checked?: boolean;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Controls/Check — a 14px box with Meridian's #A1ABB4
|
|
110
|
+
* stroke. Meridian hand-draws the SVG; a native input keeps it keyboard- and
|
|
111
|
+
* screen-reader-operable, with `accent-color` set inline so no arbitrary Tailwind class
|
|
112
|
+
* (which would need safelisting) is involved.
|
|
113
|
+
*/
|
|
114
|
+
export declare function Checkbox({ label, checked, children: _children, ...props }: CheckboxProps): React.JSX.Element;
|
|
115
|
+
export interface SwitchProps extends HTMLAttributes<HTMLDivElement> {
|
|
116
|
+
checked?: boolean;
|
|
117
|
+
}
|
|
118
|
+
/** Meridian has no switch control; this follows its blue-500 accent and 4px-radius language. */
|
|
119
|
+
export declare function Switch({ checked, ...props }: SwitchProps): React.JSX.Element;
|
|
120
|
+
export interface SliderProps extends HTMLAttributes<HTMLInputElement> {
|
|
121
|
+
value?: number;
|
|
122
|
+
min?: number;
|
|
123
|
+
max?: number;
|
|
124
|
+
}
|
|
125
|
+
export declare function Slider({ value, min, max, children: _children, ...props }: SliderProps): React.JSX.Element;
|
|
126
|
+
export interface SelectOption {
|
|
127
|
+
value: string;
|
|
128
|
+
label: string;
|
|
129
|
+
disabled?: boolean;
|
|
130
|
+
}
|
|
131
|
+
export interface SelectProps extends HTMLAttributes<HTMLSelectElement> {
|
|
132
|
+
label?: string;
|
|
133
|
+
value?: string;
|
|
134
|
+
placeholder?: string;
|
|
135
|
+
options?: SelectOption[];
|
|
136
|
+
error?: string;
|
|
137
|
+
size?: "small" | "large";
|
|
138
|
+
border?: boolean;
|
|
139
|
+
/** Key holding an option's stored value. A lookup binds rows keyed by the target's own id. */
|
|
140
|
+
optionValueKey?: string;
|
|
141
|
+
/** Key holding an option's visible text. */
|
|
142
|
+
optionLabelKey?: string;
|
|
143
|
+
}
|
|
144
|
+
/** Controls/Select */
|
|
145
|
+
export declare function Select({ optionValueKey, optionLabelKey, label, value, placeholder, options, error, children: _children, id, size, border, ...props }: SelectProps): React.JSX.Element;
|
|
146
|
+
export interface TextareaProps extends HTMLAttributes<HTMLTextAreaElement> {
|
|
147
|
+
label?: string;
|
|
148
|
+
value?: string;
|
|
149
|
+
rows?: number;
|
|
150
|
+
error?: string;
|
|
151
|
+
size?: "small" | "large";
|
|
152
|
+
border?: boolean;
|
|
153
|
+
placeholder?: string;
|
|
154
|
+
}
|
|
155
|
+
/** Controls/Text */
|
|
156
|
+
export declare function Textarea({ label, value, rows, error, children: _children, id, size, border, ...props }: TextareaProps): React.JSX.Element;
|
|
157
|
+
export interface RadioOption {
|
|
158
|
+
value: string;
|
|
159
|
+
label: string;
|
|
160
|
+
disabled?: boolean;
|
|
161
|
+
}
|
|
162
|
+
export interface RadioGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange"> {
|
|
163
|
+
label?: string;
|
|
164
|
+
name?: string;
|
|
165
|
+
value?: string;
|
|
166
|
+
options?: RadioOption[];
|
|
167
|
+
error?: string;
|
|
168
|
+
onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
|
|
169
|
+
}
|
|
170
|
+
export declare function RadioGroup({ label, name, value, options, error, onChange, children: _children, ...props }: RadioGroupProps): React.JSX.Element;
|
|
171
|
+
export interface FormProps extends HTMLAttributes<HTMLFormElement> {
|
|
172
|
+
children?: ReactNode;
|
|
173
|
+
}
|
|
174
|
+
export declare function Form({ children, onSubmit, ...props }: FormProps): React.JSX.Element;
|
|
175
|
+
export interface ListViewProps extends HTMLAttributes<HTMLDivElement> {
|
|
176
|
+
children?: ReactNode;
|
|
177
|
+
}
|
|
178
|
+
export declare function ListView({ children, ...props }: ListViewProps): React.JSX.Element;
|
|
179
|
+
export interface GridViewProps extends HTMLAttributes<HTMLDivElement> {
|
|
180
|
+
children?: ReactNode;
|
|
181
|
+
}
|
|
182
|
+
export declare function GridView({ children, ...props }: GridViewProps): React.JSX.Element;
|
|
183
|
+
export interface DataTableColumn {
|
|
184
|
+
key: string;
|
|
185
|
+
label: string;
|
|
186
|
+
align?: "left" | "center" | "right";
|
|
187
|
+
/**
|
|
188
|
+
* ListCell's its column format rule — how this column's raw value is printed.
|
|
189
|
+
* `status` renders StatusPill's coloured pill instead of text. Numeric formats are
|
|
190
|
+
* right-aligned unless `align` says otherwise, matching Meridian's `isNumeric` rule.
|
|
191
|
+
*/
|
|
192
|
+
format?: CellFormat;
|
|
193
|
+
}
|
|
194
|
+
export interface DataTableAction {
|
|
195
|
+
label: string;
|
|
196
|
+
event?: string;
|
|
197
|
+
}
|
|
198
|
+
export interface DataTableProps extends HTMLAttributes<HTMLDivElement> {
|
|
199
|
+
title?: string;
|
|
200
|
+
dataSource?: string;
|
|
201
|
+
columns?: DataTableColumn[];
|
|
202
|
+
rows?: Array<Record<string, unknown>>;
|
|
203
|
+
rowActions?: DataTableAction[];
|
|
204
|
+
emptyMessage?: string;
|
|
205
|
+
/** Meridian numbers every list row in a narrow leading column. */
|
|
206
|
+
showIndex?: boolean;
|
|
207
|
+
/** Meridian's Paginator: page sizes [50, 100, 500, All], first one active. */
|
|
208
|
+
paginate?: boolean;
|
|
209
|
+
pageSizes?: number[];
|
|
210
|
+
/**
|
|
211
|
+
* Fired when a row action button is clicked, with the full row data and which action was
|
|
212
|
+
* clicked (matched by `DataTableAction.event`, the JSON `events` key it maps to — wired by
|
|
213
|
+
* RenderNode.tsx's `resolveEvents`). Not fired for actions with no `event` set.
|
|
214
|
+
*/
|
|
215
|
+
onRowAction?: (row: Record<string, unknown>, action: DataTableAction, index: number) => void;
|
|
216
|
+
/**
|
|
217
|
+
* Meridian's List makes the whole row the affordance and has no action
|
|
218
|
+
* column at all. Supplying this turns rows into buttons; `rowActions` stays for callers that
|
|
219
|
+
* genuinely need per-row verbs.
|
|
220
|
+
*/
|
|
221
|
+
onRowOpen?: (row: Record<string, unknown>, index: number) => void;
|
|
222
|
+
/** BCP 47 tag used to format date and numeric cells. */
|
|
223
|
+
locale?: string;
|
|
224
|
+
/** ISO 4217 code used to format `currency` columns. */
|
|
225
|
+
currency?: string;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* {List,ListCell} + components/Row.
|
|
229
|
+
*
|
|
230
|
+
* Meridian's list is not a `<table>` and not a card: it is a stack of CSS-grid rows on the page
|
|
231
|
+
* background, each `h-row-mid` (3rem) tall, separated by 1px `hr`s, with a 1rem grid gap and
|
|
232
|
+
* a `w-8` index gutter. Nothing is boxed, nothing is shadowed, and the only fill in the whole
|
|
233
|
+
* control is `hover:bg-gray-50` on a row. That flatness is the single biggest difference from
|
|
234
|
+
* a conventional bordered data table, so it is reproduced structurally here rather than
|
|
235
|
+
* approximated with table styling.
|
|
236
|
+
*/
|
|
237
|
+
export declare function DataTable({ title, dataSource: _dataSource, columns, rows, rowActions, emptyMessage, showIndex, paginate, pageSizes, onRowAction, onRowOpen, locale, currency, ...props }: DataTableProps): React.JSX.Element;
|
|
238
|
+
export interface PageBarProps extends Omit<HTMLAttributes<HTMLDivElement>, "onChange"> {
|
|
239
|
+
/** Rows in the whole result, not just the loaded page — a server total. */
|
|
240
|
+
total?: number;
|
|
241
|
+
page?: number;
|
|
242
|
+
pageSize?: number;
|
|
243
|
+
pageSizes?: number[];
|
|
244
|
+
onPageChange?: (page: number) => void;
|
|
245
|
+
onPageSizeChange?: (size: number) => void;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Paginator as a document-addressable widget, for lists whose paging happens on the
|
|
249
|
+
* server. DataTable's built-in paginator slices the rows it was handed, which is the wrong
|
|
250
|
+
* answer when the query already returned exactly one page: it would report "1 - 1 / 1" no
|
|
251
|
+
* matter how many records exist. This one is told the real total and reports the state the
|
|
252
|
+
* document holds, so a generated list can page for real instead of carrying the fixed
|
|
253
|
+
* "Displaying records" caption and Previous/Next buttons that jumped to pages 1 and 2.
|
|
254
|
+
*
|
|
255
|
+
* The arithmetic (page count, clamping, the visible range) lives here because the JSON
|
|
256
|
+
* expression language has no arithmetic — and should not grow any just to count pages.
|
|
257
|
+
*/
|
|
258
|
+
export declare function PageBar({ total, page, pageSize, pageSizes, onPageChange, onPageSizeChange, ...props }: PageBarProps): React.JSX.Element;
|
|
259
|
+
export interface ChartSeries {
|
|
260
|
+
key: string;
|
|
261
|
+
label?: string;
|
|
262
|
+
color?: string;
|
|
263
|
+
}
|
|
264
|
+
export interface ChartProps extends HTMLAttributes<HTMLDivElement> {
|
|
265
|
+
title?: string;
|
|
266
|
+
dataSource?: string;
|
|
267
|
+
chartType?: "bar" | "line" | "donut" | "area";
|
|
268
|
+
rows?: Array<Record<string, unknown>>;
|
|
269
|
+
xKey?: string;
|
|
270
|
+
yKey?: string;
|
|
271
|
+
series?: ChartSeries[];
|
|
272
|
+
emptyMessage?: string;
|
|
273
|
+
/** Meridian's dashboard sections pair the title with a period/filter control on the end edge. */
|
|
274
|
+
action?: ReactNode;
|
|
275
|
+
/** Donut only — the label inside the hole (Meridian: "Total Spending"). */
|
|
276
|
+
totalLabel?: string;
|
|
277
|
+
/**
|
|
278
|
+
* Drawn height in px for bar/line charts. Meridian's dashboard charts all land near 235px
|
|
279
|
+
* regardless of column width, because each call site picks an aspect ratio to make that
|
|
280
|
+
* true; here the ratio is derived from the measured width and this height instead.
|
|
281
|
+
*/
|
|
282
|
+
height?: number;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* {Cashflow,ProfitAndLoss,Expenses}.
|
|
286
|
+
*
|
|
287
|
+
* A Meridian dashboard widget is a `p-4` region on the page — no card, no border of its own
|
|
288
|
+
* (the neighbouring section supplies a `border-e`/`hr`) — made of `SectionHeader`
|
|
289
|
+
* (`flex items-baseline justify-between`, `font-semibold text-base`), an optional inline
|
|
290
|
+
* legend, and the SVG chart. Donuts sit beside their legend at half width each, which is how
|
|
291
|
+
* Top Expenses is laid out.
|
|
292
|
+
*/
|
|
293
|
+
export declare function Chart({ title, dataSource: _dataSource, chartType, rows, xKey, yKey, series, emptyMessage, action, totalLabel, height, ...props }: ChartProps): React.JSX.Element;
|
|
294
|
+
export interface KanbanColumn {
|
|
295
|
+
id: string;
|
|
296
|
+
title: string;
|
|
297
|
+
color?: string;
|
|
298
|
+
}
|
|
299
|
+
export interface KanbanCardItem {
|
|
300
|
+
id: string;
|
|
301
|
+
columnId: string;
|
|
302
|
+
title: string;
|
|
303
|
+
subtitle?: string;
|
|
304
|
+
value?: string | number;
|
|
305
|
+
badge?: string;
|
|
306
|
+
route?: string;
|
|
307
|
+
meta?: Record<string, unknown>;
|
|
308
|
+
[key: string]: unknown;
|
|
309
|
+
}
|
|
310
|
+
export interface KanbanBoardProps extends HTMLAttributes<HTMLDivElement> {
|
|
311
|
+
title?: string;
|
|
312
|
+
dataSource?: string;
|
|
313
|
+
columns?: KanbanColumn[];
|
|
314
|
+
rows?: KanbanCardItem[];
|
|
315
|
+
emptyMessage?: string;
|
|
316
|
+
onCardClick?: (card: KanbanCardItem) => void;
|
|
317
|
+
}
|
|
318
|
+
export declare function KanbanBoard({ title, dataSource: _dataSource, columns, rows, emptyMessage, onCardClick, ...props }: KanbanBoardProps): React.JSX.Element;
|
|
319
|
+
export interface TreeNodeItem {
|
|
320
|
+
id: string;
|
|
321
|
+
label: string;
|
|
322
|
+
value?: string | number;
|
|
323
|
+
badge?: string;
|
|
324
|
+
subtitle?: string;
|
|
325
|
+
defaultExpanded?: boolean;
|
|
326
|
+
children?: TreeNodeItem[];
|
|
327
|
+
route?: string;
|
|
328
|
+
[key: string]: unknown;
|
|
329
|
+
}
|
|
330
|
+
export interface TreeViewProps extends HTMLAttributes<HTMLDivElement> {
|
|
331
|
+
title?: string;
|
|
332
|
+
dataSource?: string;
|
|
333
|
+
items?: TreeNodeItem[];
|
|
334
|
+
rows?: TreeNodeItem[];
|
|
335
|
+
emptyMessage?: string;
|
|
336
|
+
onNodeClick?: (node: TreeNodeItem) => void;
|
|
337
|
+
}
|
|
338
|
+
export declare function TreeView({ title, dataSource: _dataSource, items, rows, emptyMessage, onNodeClick, ...props }: TreeViewProps): React.JSX.Element;
|
|
339
|
+
export interface SidebarProps extends HTMLAttributes<HTMLElement> {
|
|
340
|
+
children?: ReactNode;
|
|
341
|
+
}
|
|
342
|
+
/** Sidebar — 14rem wide, gray-25, 0.5rem vertical inset. */
|
|
343
|
+
export declare function Sidebar({ children, ...props }: SidebarProps): React.JSX.Element;
|
|
344
|
+
export interface NavbarProps extends HTMLAttributes<HTMLElement> {
|
|
345
|
+
children?: ReactNode;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* PageHeader — the 4rem (`h-row-largest`) page header:
|
|
349
|
+
* `px-4`, title and left slot on the start edge with `gap-4`, actions on the end edge with
|
|
350
|
+
* `gap-2`, one hairline rule underneath.
|
|
351
|
+
*/
|
|
352
|
+
export declare function Navbar({ children, ...props }: NavbarProps): React.JSX.Element;
|
|
353
|
+
export interface ToolbarProps extends HTMLAttributes<HTMLDivElement> {
|
|
354
|
+
children?: ReactNode;
|
|
355
|
+
}
|
|
356
|
+
export declare function Toolbar({ children, ...props }: ToolbarProps): React.JSX.Element;
|
|
357
|
+
export interface DrawerProps extends HTMLAttributes<HTMLDivElement> {
|
|
358
|
+
open?: boolean;
|
|
359
|
+
onClose?: () => void;
|
|
360
|
+
title?: string;
|
|
361
|
+
/** Which screen edge the drawer slides from. Defaults to "right". */
|
|
362
|
+
side?: "left" | "right" | "top" | "bottom";
|
|
363
|
+
/** Show the dimming backdrop (click-to-close). Defaults to true. */
|
|
364
|
+
backdrop?: boolean;
|
|
365
|
+
children?: ReactNode;
|
|
366
|
+
}
|
|
367
|
+
export declare function Drawer({ open, onClose, title, side, backdrop, children, ...props }: DrawerProps): React.JSX.Element | null;
|
|
368
|
+
export interface PanelProps extends HTMLAttributes<HTMLDivElement> {
|
|
369
|
+
open?: boolean;
|
|
370
|
+
onClose?: () => void;
|
|
371
|
+
/** Show the dimming backdrop (click-to-close). Defaults to true. */
|
|
372
|
+
backdrop?: boolean;
|
|
373
|
+
children?: ReactNode;
|
|
374
|
+
}
|
|
375
|
+
export declare function Panel({ open, onClose, backdrop, children, ...props }: PanelProps): React.JSX.Element | null;
|
|
376
|
+
export interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
|
377
|
+
open?: boolean;
|
|
378
|
+
onClose?: () => void;
|
|
379
|
+
/** Which edge the panel hangs from. Meridian's FilterDropdown is `bottom-end`. */
|
|
380
|
+
align?: "start" | "end";
|
|
381
|
+
children?: ReactNode;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Popover, as Meridian actually uses it: a panel anchored to
|
|
385
|
+
* the control that opened it, not a centred modal.
|
|
386
|
+
*
|
|
387
|
+
* Deliberately *not* portalled. Meridian wraps trigger and panel in one `relative` element and
|
|
388
|
+
* positions the panel absolutely inside it (ListView's FilterDropdown, the Create dropdown),
|
|
389
|
+
* which needs no anchor math and keeps the panel inside the same stacking and shadow-root
|
|
390
|
+
* context as its trigger. A document places this node next to its trigger inside a container
|
|
391
|
+
* styled `position: relative`.
|
|
392
|
+
*
|
|
393
|
+
* Escape and click-outside close it through the same overlay stack the Drawer and Panel use, so
|
|
394
|
+
* a popover opened above a drawer still closes in the right order.
|
|
395
|
+
*/
|
|
396
|
+
export declare function Popover({ open, onClose, align, children, ...props }: PopoverProps): React.JSX.Element | null;
|
|
397
|
+
export interface SnackbarProps extends HTMLAttributes<HTMLDivElement> {
|
|
398
|
+
message?: string;
|
|
399
|
+
duration?: number;
|
|
400
|
+
onClose?: () => void;
|
|
401
|
+
/** Leading outline icon. Toasts read as confirmations, so a check is the default. */
|
|
402
|
+
iconName?: string;
|
|
403
|
+
}
|
|
404
|
+
export declare function Snackbar({ message, duration, onClose, iconName, ...props }: SnackbarProps): React.JSX.Element | null;
|
|
405
|
+
export interface DialogProps extends Omit<HTMLAttributes<HTMLDivElement>, "content"> {
|
|
406
|
+
title?: string;
|
|
407
|
+
content?: ReactNode;
|
|
408
|
+
open?: boolean;
|
|
409
|
+
onClose?: () => void;
|
|
410
|
+
}
|
|
411
|
+
export declare function Dialog({ title, content, open, onClose, ...props }: DialogProps): React.JSX.Element | null;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { DataAdapter, Mutation, Query, QueryResult, RecordMeta } from '../types';
|
|
2
|
+
export interface HttpAdapterOptions {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
fetchImpl?: typeof fetch;
|
|
5
|
+
headers?: HeadersInit;
|
|
6
|
+
timeoutMs?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class HttpAdapter implements DataAdapter {
|
|
9
|
+
private readonly baseUrl;
|
|
10
|
+
private readonly fetchImpl;
|
|
11
|
+
private readonly headers?;
|
|
12
|
+
private readonly timeoutMs;
|
|
13
|
+
constructor(options: HttpAdapterOptions);
|
|
14
|
+
query<T = Record<string, unknown>>(query: Query, signal?: AbortSignal): Promise<QueryResult<T>>;
|
|
15
|
+
get<T = Record<string, unknown>>(collection: string, id: string, signal?: AbortSignal): Promise<{
|
|
16
|
+
record: T;
|
|
17
|
+
meta: RecordMeta;
|
|
18
|
+
} | undefined>;
|
|
19
|
+
create<T = Record<string, unknown>>(mutation: Mutation, signal?: AbortSignal): Promise<{
|
|
20
|
+
record: T;
|
|
21
|
+
meta: RecordMeta;
|
|
22
|
+
}>;
|
|
23
|
+
update<T = Record<string, unknown>>(mutation: Mutation, signal?: AbortSignal): Promise<{
|
|
24
|
+
record: T;
|
|
25
|
+
meta: RecordMeta;
|
|
26
|
+
}>;
|
|
27
|
+
remove(collection: string, id: string, signal?: AbortSignal): Promise<void>;
|
|
28
|
+
transition<T = Record<string, unknown>>(mutation: Mutation & {
|
|
29
|
+
transition: string;
|
|
30
|
+
}, signal?: AbortSignal): Promise<{
|
|
31
|
+
record: T;
|
|
32
|
+
meta: RecordMeta;
|
|
33
|
+
}>;
|
|
34
|
+
report<T = unknown>(name: string, params: Record<string, unknown>, signal?: AbortSignal): Promise<T>;
|
|
35
|
+
private request;
|
|
36
|
+
}
|
|
37
|
+
export declare function createHttpAdapter(options: HttpAdapterOptions): HttpAdapter;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { DataAdapter, Mutation, Query, QueryResult, RecordMeta } from '../types';
|
|
2
|
+
export interface InMemoryAdapterOptions {
|
|
3
|
+
/** Initial collections, e.g. `{ SalesInvoice: [...] }`. Copied on construction — the caller's
|
|
4
|
+
* array is never mutated. */
|
|
5
|
+
seed?: Record<string, Array<Record<string, unknown>>>;
|
|
6
|
+
/** `"localStorage"` persists every mutation and reloads it on construction; `"none"` (default
|
|
7
|
+
* in tests) keeps everything in memory only. */
|
|
8
|
+
persist?: "localStorage" | "none";
|
|
9
|
+
/** Key the store is saved under when `persist: "localStorage"`. */
|
|
10
|
+
storageKey?: string;
|
|
11
|
+
/** Artificial delay applied to every call, so loading/skeleton states are actually exercised
|
|
12
|
+
* in mock mode instead of resolving instantly. Default 0. */
|
|
13
|
+
latencyMs?: number;
|
|
14
|
+
/** Fraction (0–1) of calls that fail with a synthetic `DataError("server")`, so error states
|
|
15
|
+
* are exercised in mock mode too. Default 0. */
|
|
16
|
+
failureRate?: number;
|
|
17
|
+
/** Injectable clock/random for deterministic tests. */
|
|
18
|
+
now?: () => number;
|
|
19
|
+
random?: () => number;
|
|
20
|
+
}
|
|
21
|
+
/** In-memory `DataAdapter`. Default for demos and tests; every failure it raises is a real
|
|
22
|
+
* `DataError` with the same `.code` an `HttpAdapter` would raise for the same situation — see
|
|
23
|
+
* `src/data/__tests__/contract.test.ts` for the shared case matrix that keeps the two honest. */
|
|
24
|
+
export declare class InMemoryAdapter implements DataAdapter {
|
|
25
|
+
private stores;
|
|
26
|
+
private readonly persist;
|
|
27
|
+
private readonly storageKey;
|
|
28
|
+
private readonly latencyMs;
|
|
29
|
+
private readonly failureRate;
|
|
30
|
+
private readonly now;
|
|
31
|
+
private readonly random;
|
|
32
|
+
constructor(options?: InMemoryAdapterOptions);
|
|
33
|
+
private simulate;
|
|
34
|
+
private collection;
|
|
35
|
+
query<T = Record<string, unknown>>(query: Query, signal?: AbortSignal): Promise<QueryResult<T>>;
|
|
36
|
+
get<T = Record<string, unknown>>(collection: string, id: string, signal?: AbortSignal): Promise<{
|
|
37
|
+
record: T;
|
|
38
|
+
meta: RecordMeta;
|
|
39
|
+
} | undefined>;
|
|
40
|
+
create<T = Record<string, unknown>>(mutation: Mutation, signal?: AbortSignal): Promise<{
|
|
41
|
+
record: T;
|
|
42
|
+
meta: RecordMeta;
|
|
43
|
+
}>;
|
|
44
|
+
update<T = Record<string, unknown>>(mutation: Mutation, signal?: AbortSignal): Promise<{
|
|
45
|
+
record: T;
|
|
46
|
+
meta: RecordMeta;
|
|
47
|
+
}>;
|
|
48
|
+
remove(collection: string, id: string, signal?: AbortSignal): Promise<void>;
|
|
49
|
+
transition<T = Record<string, unknown>>(mutation: Mutation & {
|
|
50
|
+
transition: string;
|
|
51
|
+
}, signal?: AbortSignal): Promise<{
|
|
52
|
+
record: T;
|
|
53
|
+
meta: RecordMeta;
|
|
54
|
+
}>;
|
|
55
|
+
report<T = unknown>(_name: string, _params: Record<string, unknown>, signal?: AbortSignal): Promise<T>;
|
|
56
|
+
/** Test/demo-only escape hatch: reseed everything from scratch. Not part of `DataAdapter`. */
|
|
57
|
+
reset(seed?: Record<string, Array<Record<string, unknown>>>): void;
|
|
58
|
+
private generateId;
|
|
59
|
+
private saveToStorage;
|
|
60
|
+
private loadFromStorage;
|
|
61
|
+
}
|
|
62
|
+
export declare function createInMemoryAdapter(options?: InMemoryAdapterOptions): InMemoryAdapter;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single failure shape both `InMemoryAdapter` and `HttpAdapter` are required to raise for the
|
|
3
|
+
* same situation (record missing, bad input, stale version, no permission, network/timeout, or
|
|
4
|
+
* server fault). A document/host that branches on `.code` behaves identically no matter which
|
|
5
|
+
* adapter is wired in — that's the whole point of the seam: switching mock → HTTP must not
|
|
6
|
+
* surface a failure mode the UI has never seen.
|
|
7
|
+
*/
|
|
8
|
+
export type DataErrorCode = "not_found" | "validation" | "conflict" | "forbidden" | "network" | "timeout" | "server";
|
|
9
|
+
export declare class DataError extends Error {
|
|
10
|
+
readonly code: DataErrorCode;
|
|
11
|
+
/** Per-field messages, e.g. from server-side validation — maps directly to `state.formErrors.*`. */
|
|
12
|
+
readonly fields?: Record<string, string>;
|
|
13
|
+
constructor(message: string, code: DataErrorCode, fields?: Record<string, string>);
|
|
14
|
+
}
|
|
15
|
+
export declare function isDataError(value: unknown): value is DataError;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { DataAdapter, Mutation, Query, QueryFilter, QueryOp, QueryPage, QueryResult, QuerySort, RecordMeta, } from './types';
|
|
2
|
+
export { DataError, isDataError } from './errors';
|
|
3
|
+
export type { DataErrorCode } from './errors';
|
|
4
|
+
export { InMemoryAdapter, createInMemoryAdapter } from './adapters/inMemory';
|
|
5
|
+
export type { InMemoryAdapterOptions } from './adapters/inMemory';
|
|
6
|
+
export { HttpAdapter, createHttpAdapter } from './adapters/http';
|
|
7
|
+
export type { HttpAdapterOptions } from './adapters/http';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IncomingMessage, Server, ServerResponse } from 'node:http';
|
|
2
|
+
import { DataAdapter } from '../types';
|
|
3
|
+
export interface MockHttpServerOptions {
|
|
4
|
+
adapter?: DataAdapter;
|
|
5
|
+
seed?: Record<string, Array<Record<string, unknown>>>;
|
|
6
|
+
host?: string;
|
|
7
|
+
port?: number;
|
|
8
|
+
basePath?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface RunningMockHttpServer {
|
|
11
|
+
server: Server;
|
|
12
|
+
url: string;
|
|
13
|
+
close: () => Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export declare function createDataAdapterHttpHandler(adapter: DataAdapter, basePath?: string): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
16
|
+
export declare function startMockHttpServer(options?: MockHttpServerOptions): Promise<RunningMockHttpServer>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The data contract every demo/document talks to instead of a specific storage. Two
|
|
3
|
+
* implementations exist — `InMemoryAdapter` (default, mock) and `HttpAdapter` (real backend) —
|
|
4
|
+
* and a shared contract test (`__tests__/contract.test.ts`) runs the same case matrix against
|
|
5
|
+
* both, so switching the adapter a host wires up is the only thing that changes.
|
|
6
|
+
*/
|
|
7
|
+
export type QueryOp = "eq" | "ne" | "in" | "gt" | "gte" | "lt" | "lte" | "like" | "between";
|
|
8
|
+
export interface QueryFilter {
|
|
9
|
+
field: string;
|
|
10
|
+
op: QueryOp;
|
|
11
|
+
/** `in`/`between` take an array; every other op takes a scalar. */
|
|
12
|
+
value: unknown;
|
|
13
|
+
}
|
|
14
|
+
export interface QuerySort {
|
|
15
|
+
field: string;
|
|
16
|
+
dir: "asc" | "desc";
|
|
17
|
+
}
|
|
18
|
+
export interface QueryPage {
|
|
19
|
+
number: number;
|
|
20
|
+
size: number;
|
|
21
|
+
}
|
|
22
|
+
export interface Query {
|
|
23
|
+
collection: string;
|
|
24
|
+
filters?: QueryFilter[];
|
|
25
|
+
sort?: QuerySort[];
|
|
26
|
+
page?: QueryPage;
|
|
27
|
+
/** Free-text search across whatever fields the collection marks searchable. */
|
|
28
|
+
search?: string;
|
|
29
|
+
/** Column projection; omitted = every field. */
|
|
30
|
+
fields?: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface QueryResult<T = Record<string, unknown>> {
|
|
33
|
+
rows: T[];
|
|
34
|
+
total: number;
|
|
35
|
+
page: number;
|
|
36
|
+
pageSize: number;
|
|
37
|
+
}
|
|
38
|
+
export interface Mutation {
|
|
39
|
+
collection: string;
|
|
40
|
+
id?: string;
|
|
41
|
+
data?: Record<string, unknown>;
|
|
42
|
+
/** State-machine transition name, e.g. "submit" | "cancel" | "pay". */
|
|
43
|
+
transition?: string;
|
|
44
|
+
/** Optimistic-concurrency token: the version the client last read. */
|
|
45
|
+
version?: number;
|
|
46
|
+
}
|
|
47
|
+
export interface RecordMeta {
|
|
48
|
+
version: number;
|
|
49
|
+
}
|
|
50
|
+
export interface DataAdapter {
|
|
51
|
+
query<T = Record<string, unknown>>(query: Query, signal?: AbortSignal): Promise<QueryResult<T>>;
|
|
52
|
+
get<T = Record<string, unknown>>(collection: string, id: string, signal?: AbortSignal): Promise<{
|
|
53
|
+
record: T;
|
|
54
|
+
meta: RecordMeta;
|
|
55
|
+
} | undefined>;
|
|
56
|
+
create<T = Record<string, unknown>>(mutation: Mutation, signal?: AbortSignal): Promise<{
|
|
57
|
+
record: T;
|
|
58
|
+
meta: RecordMeta;
|
|
59
|
+
}>;
|
|
60
|
+
update<T = Record<string, unknown>>(mutation: Mutation, signal?: AbortSignal): Promise<{
|
|
61
|
+
record: T;
|
|
62
|
+
meta: RecordMeta;
|
|
63
|
+
}>;
|
|
64
|
+
remove(collection: string, id: string, signal?: AbortSignal): Promise<void>;
|
|
65
|
+
transition<T = Record<string, unknown>>(mutation: Mutation & {
|
|
66
|
+
transition: string;
|
|
67
|
+
}, signal?: AbortSignal): Promise<{
|
|
68
|
+
record: T;
|
|
69
|
+
meta: RecordMeta;
|
|
70
|
+
}>;
|
|
71
|
+
report<T = unknown>(name: string, params: Record<string, unknown>, signal?: AbortSignal): Promise<T>;
|
|
72
|
+
}
|
|
73
|
+
export { DataError, isDataError } from './errors';
|
|
74
|
+
export type { DataErrorCode } from './errors';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { UIDLDocument } from '../types';
|
|
3
|
+
import { ApiAllowlist } from '../actions/interpreter';
|
|
4
|
+
import { DocumentStateStore } from '../state/createDocumentState';
|
|
5
|
+
import { CommandHandler, MutationHandler } from '../types/actions';
|
|
6
|
+
export interface CanvasProps {
|
|
7
|
+
document: UIDLDocument;
|
|
8
|
+
selectedNodeId: string | null;
|
|
9
|
+
hoveredNodeId: string | null;
|
|
10
|
+
onSelectNode: (nodeId: string | null) => void;
|
|
11
|
+
onHoverNode: (nodeId: string | null) => void;
|
|
12
|
+
themeMode?: "light" | "dark";
|
|
13
|
+
stateStore?: DocumentStateStore;
|
|
14
|
+
dataSources?: Record<string, unknown>;
|
|
15
|
+
mutationHandler?: MutationHandler;
|
|
16
|
+
commandHandler?: CommandHandler;
|
|
17
|
+
apiAllowlist?: ApiAllowlist;
|
|
18
|
+
apiMaxResponseBytes?: number;
|
|
19
|
+
apiMaxConcurrentCalls?: number;
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function Canvas({ document, onSelectNode, onHoverNode, themeMode, stateStore, dataSources, mutationHandler, commandHandler, apiAllowlist, apiMaxResponseBytes, apiMaxConcurrentCalls, className, }: CanvasProps): React.JSX.Element;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { UIDLDocument } from '../types';
|
|
2
|
+
import { ApiAllowlist } from '../actions/interpreter';
|
|
3
|
+
import { CommandHandler, MutationHandler } from '../types/actions';
|
|
4
|
+
export interface EditorProps {
|
|
5
|
+
initialDocument?: UIDLDocument;
|
|
6
|
+
/** Host-owned handler for live-preview `mutate` actions; unset means mutations are disabled. */
|
|
7
|
+
mutationHandler?: MutationHandler;
|
|
8
|
+
/** Host-owned handler for live-preview `command` actions; unset means commands are disabled. */
|
|
9
|
+
commandHandler?: CommandHandler;
|
|
10
|
+
/** Hosts the live preview's `api` actions are allowed to call; unset means they're disabled. */
|
|
11
|
+
apiAllowlist?: ApiAllowlist;
|
|
12
|
+
/** Max `api` response body size in bytes before the request is aborted. Default 5MB. */
|
|
13
|
+
apiMaxResponseBytes?: number;
|
|
14
|
+
/** Max number of `api` actions to run concurrently; further calls fail fast. Default 6. */
|
|
15
|
+
apiMaxConcurrentCalls?: number;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function Editor({ initialDocument, mutationHandler, commandHandler, apiAllowlist, apiMaxResponseBytes, apiMaxConcurrentCalls, className, }: EditorProps): import("react").JSX.Element;
|