@close-by/clay 0.2.19 → 0.2.20
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/docs/api.md +15 -0
- package/docs/examples.md +1 -0
- package/docs/protocol.md +1 -0
- package/docs/updating-in-place.md +27 -2
- package/package.json +5 -5
- package/src/index.ts +16 -11
package/docs/api.md
CHANGED
|
@@ -1220,6 +1220,21 @@ ui.radialChart({
|
|
|
1220
1220
|
});
|
|
1221
1221
|
```
|
|
1222
1222
|
|
|
1223
|
+
#### Live chart updates
|
|
1224
|
+
|
|
1225
|
+
Every chart factory and `ui.chart.*` builder returns a `ChartElement`:
|
|
1226
|
+
|
|
1227
|
+
| Method | What it sends |
|
|
1228
|
+
|--------|---------------|
|
|
1229
|
+
| `appendData(rows, { max? })` | `appendRows` with only the new rows; client trims to the last `max` |
|
|
1230
|
+
| `setData(rows)` | `updateProps` (`data`) |
|
|
1231
|
+
| `upsertData(row, { key?, max? })` | Replaces the row with the same `key` (default `xKey`, or `nameKey` for pies) or appends it |
|
|
1232
|
+
| `setSeries(series)` / `setHeadline(h)` / `setTitle(t)` / `setDescription(d)` / `setLoading(b)` | `updateProps` for that prop |
|
|
1233
|
+
|
|
1234
|
+
`ui.stat(items)` returns a `StatElement` with `setItems(items)`, `updateItem(titleOrIndex, patch)` and `appendSparkline(titleOrIndex, points, { max? })`. Each sends one `updateProps` (`items`).
|
|
1235
|
+
|
|
1236
|
+
All charts accept `animate?: boolean` (default `true`). See [Updating in place](./updating-in-place.md#live-charts-appenddata--setdata--upsertdata).
|
|
1237
|
+
|
|
1223
1238
|
#### Structured charts (`ui.chart`)
|
|
1224
1239
|
|
|
1225
1240
|
Optional sugar over the props APIs above. Mode-first builders compile to the same `Element` types — legacy `ui.areaChart` / `ui.pieChart` / etc. remain fully supported.
|
package/docs/examples.md
CHANGED
|
@@ -26,6 +26,7 @@ Each page sets `group` / `groupIcon` in its `pageMeta`, so the sidebar and the h
|
|
|
26
26
|
| `/examples/reui-batches` | `ReuiBatchesDemo.ts` | ReUI batches 3–6: `buttonGroup`, `empty`, `pagination`, `filterBar`, form inputs, `navigationMenu`, `notice`, `stat`+sparkline, `eventCalendar`, datatable `showFilterChips` |
|
|
27
27
|
| `/examples/reui-batch-7` | `ReuiBatch7Demo.ts` | ReUI batch 7: `inputGroup`, `toggle`, `descriptionList`, `staticTable`, `aspectRatio`, `itemList`, `checkboxGroup` |
|
|
28
28
|
| `/examples/charts` | `ChartDemo.ts` | `ui.chart.*`, `ui.sparkline`, composed/scatter charts |
|
|
29
|
+
| `/examples/live-charts` | `LiveCharts.ts` | Live charts: `appendData` sliding windows, `setData` tweens, `upsertData` buckets, live gauge and sparklines |
|
|
29
30
|
| `/examples/slider-demo` | `SliderDemo.ts` | Slider, checkbox, select + bindings |
|
|
30
31
|
| `/examples/themes` | `ThemesDemo.ts` | Palette gallery: `ui.theme.palette`, light/dark, component preview |
|
|
31
32
|
| `/examples/layout` | `LayoutDemo.ts` | Fill layout: `fillViewport`, `grow`, `scroll`, `ui.grid` |
|
package/docs/protocol.md
CHANGED
|
@@ -79,6 +79,7 @@ Browser Back/Forward (or other `popstate`) changed the query and/or hash **witho
|
|
|
79
79
|
| `replace` | `id`, `node` | Replace entire subtree at `id` |
|
|
80
80
|
| `updateProps` | `id`, `props` | Shallow-merge props |
|
|
81
81
|
| `setChildren` | `id`, `children` | Replace children array |
|
|
82
|
+
| `appendRows` | `id`, `prop`, `rows`, `max?` | Append `rows` to the array prop `prop`, then keep the last `max` items (chart streaming) |
|
|
82
83
|
| `remove` | `id` | Remove node from parent |
|
|
83
84
|
|
|
84
85
|
### `navigate`
|
|
@@ -20,6 +20,7 @@ The flicker is caused by the remount, not by the new value. If a frame carries o
|
|
|
20
20
|
| Change one value (a label, badge, or input) | `label.setText(…)`, `el.setValue(…)`, `el.update({ … })` | `updateProps` for that element |
|
|
21
21
|
| Live table data | `table.setRows(rows)` on a table created with a stable `keyField` (add `highlightChanges: true` to flash changed rows) | `updateProps` on the table; rows keyed by `keyField` keep their DOM |
|
|
22
22
|
| Table refetch | `table.setLoading(true)` / `table.withLoading(fn)` | `updateProps` (`loading`); previous rows stay, dimmed, instead of blanking |
|
|
23
|
+
| Live chart data (any chart) | `chart.appendData(point, { max })` for a stream, `chart.setData(rows)` for a snapshot, `chart.upsertData(row)` for a growing bucket | `appendRows` with only the new points, or `updateProps` (`data`); the chart stays mounted |
|
|
23
24
|
| A section whose structure depends on data | `ui.refreshable(() => …)` + `.refresh()`, or `ui.auto(() => …)` | Reconciled: matched children get `updateProps` only; added, removed, or reordered children cause one `setChildren` per affected parent |
|
|
24
25
|
| Items in a list inside either of the above | `.key(item.id)` on each item | Items keep their identity through reorder, filter, and prepend |
|
|
25
26
|
|
|
@@ -31,7 +32,7 @@ When a `refreshable` or `auto` block re-runs, Clay builds a fresh tree and match
|
|
|
31
32
|
|
|
32
33
|
1. **Keyed first.** A new child with `.key(k)` matches the old child with the same key and the same element type. Keyed children are matched only by key.
|
|
33
34
|
2. **Unkeyed by position.** Unkeyed children are matched in order, by element type. If the next old child matches the current new one, the current old child was removed and is skipped. If the current old child matches the next new one, the new child was inserted. Otherwise the pair is treated as a replacement at that position. This lookahead covers a single insert or remove; larger reshuffles should be keyed.
|
|
34
|
-
3. **Matched pairs keep the
|
|
35
|
+
3. **Matched pairs keep the id on screen.** The freshly built element takes over the old element's id and the old one is destroyed. Only props that actually changed are sent, as one `updateProps`. Because the fresh instance is the one that stays live, its built-in handlers (table search, sort and paging, map drags) and any reference you saved while building (`table = ui.dataTable(...)`) keep working after the refresh.
|
|
35
36
|
4. **Leftovers.** Old children with no match are destroyed. New children with no match are mounted. The parent sends one `setChildren` only if its list of ids changed. A child whose type changed at a position is replaced; its siblings keep their ids.
|
|
36
37
|
5. **Nested blocks keep their instance.** A nested `refreshable` or `auto` keeps its id and its subscriptions and adopts the new builder, so its own refreshes keep working.
|
|
37
38
|
|
|
@@ -103,11 +104,35 @@ async function refresh() {
|
|
|
103
104
|
|
|
104
105
|
If you want columns to stay fixed across refreshes, pass `columns` explicitly. Otherwise columns are inferred again on each `setRows`.
|
|
105
106
|
|
|
107
|
+
### Live charts (`appendData` / `setData` / `upsertData`)
|
|
108
|
+
|
|
109
|
+
Every chart (`ui.lineChart`, `areaChart`, `barChart`, `composedChart`, `scatterChart`, `pieChart`, `radarChart`, `radialChart`, `sparkline`, and the `ui.chart.*` builders) returns a `ChartElement`. Create it once and push data into it.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const latency = ui.lineChart({ data: seed, xKey: 't', series: [{ key: 'p50', label: 'p50' }] });
|
|
113
|
+
const byRegion = ui.barChart({ data: regions, xKey: 'region', series: [{ key: 'orders', label: 'Orders' }] });
|
|
114
|
+
|
|
115
|
+
ui.timer(1, () => {
|
|
116
|
+
latency.appendData({ t: clock(), p50: sample() }, { max: 60 }); // only the new point is sent
|
|
117
|
+
latency.setHeadline({ value: `${p50} ms` });
|
|
118
|
+
});
|
|
119
|
+
ui.timer(5, async () => byRegion.setData(await fetchRegions())); // bars tween to the new values
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- **`appendData(rows, { max })`** sends only the new rows. The client appends them and drops the oldest past `max`, so a sliding window costs one point per tick.
|
|
123
|
+
- **`setData(rows)`** replaces the data. When the row count and first x value are unchanged, the marks tween to their new values.
|
|
124
|
+
- **`upsertData(row, { key, max })`** replaces the row with the same x value (or `nameKey` for pies), or appends it. Use it for a bucket that keeps growing, such as the current minute.
|
|
125
|
+
- **`setSeries`, `setHeadline`, `setTitle`, `setDescription`, `setLoading`** patch one prop each. Anything else goes through `update({ … })`.
|
|
126
|
+
|
|
127
|
+
KPI stat grids work the same way: `ui.stat(items)` returns a `StatElement`. `updateItem(titleOrIndex, patch)` changes one card, `appendSparkline(titleOrIndex, points, { max })` extends that card's sparkline, and `setItems(items)` replaces them all.
|
|
128
|
+
|
|
129
|
+
Appends and sliding windows draw without animation, so lines don't slide sideways or replay their entrance. Pass `animate: false` to turn chart animation off entirely. The interactive period tabs keep the selected period while data streams in.
|
|
130
|
+
|
|
106
131
|
## Anti-patterns
|
|
107
132
|
|
|
108
133
|
- **Rebuilding a whole section when one value changes.** Wrapping a whole page in `ui.refreshable` and calling `.refresh()` every second to update a clock. Keep a reference to the clock label and call `setText`.
|
|
109
134
|
- **Unkeyed lists that get sorted or filtered.** Without `.key()`, position is the identity. After a sort, the element in slot 3 is reused for whatever item is now third, so focus and typed text stay in the slot instead of following the row.
|
|
110
|
-
- **Creating a new table instead of `setRows`.** A `ui.dataTable(...)`
|
|
135
|
+
- **Creating a new table instead of `setRows`.** A `ui.dataTable(...)` rebuilt inside a refreshable keeps its id and stays interactive, but each rebuild starts the table's server-side state over, so sort, search, page and selection reset. Create the table once and call `setRows`.
|
|
111
136
|
- **Tables without `keyField`.** Rows are stamped `__rowId` by their index, so inserting or re-sorting the source shifts every row's identity. Set `keyField` to your primary key.
|
|
112
137
|
- **Toggling a constructor option by rebuilding.** Recreating a table with `zebra: on` inside an `auto` block. Use the setters instead: `setZebra`, `setDensity`, `setHighlightChanges`.
|
|
113
138
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@close-by/clay",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.20",
|
|
4
4
|
"description": "NiceGUI-like ui.* facade for Clay apps",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@close-by/clay-compiler": "0.2.
|
|
41
|
-
"@close-by/clay-core": "0.2.
|
|
42
|
-
"@close-by/clay-components": "0.2.
|
|
43
|
-
"@close-by/clay-server": "0.2.
|
|
40
|
+
"@close-by/clay-compiler": "0.2.20",
|
|
41
|
+
"@close-by/clay-core": "0.2.20",
|
|
42
|
+
"@close-by/clay-components": "0.2.20",
|
|
43
|
+
"@close-by/clay-server": "0.2.20",
|
|
44
44
|
"@tailwindcss/cli": "^4.3.3",
|
|
45
45
|
"tailwindcss": "^4.3.3"
|
|
46
46
|
}
|
package/src/index.ts
CHANGED
|
@@ -203,6 +203,8 @@ import {
|
|
|
203
203
|
type CheckboxGroupProps,
|
|
204
204
|
type CheckboxGroupOption,
|
|
205
205
|
type StatItem,
|
|
206
|
+
type StatItemRef,
|
|
207
|
+
type StatElement,
|
|
206
208
|
type DataTableProps,
|
|
207
209
|
type DataTableAction,
|
|
208
210
|
type DataTableView,
|
|
@@ -235,6 +237,7 @@ import {
|
|
|
235
237
|
type ComposedChartProps,
|
|
236
238
|
type ComposedChartSeries,
|
|
237
239
|
type ComposedSeriesType,
|
|
240
|
+
type ChartElement,
|
|
238
241
|
type CartesianChartProps,
|
|
239
242
|
type ChartSeries,
|
|
240
243
|
type ChartHeadline,
|
|
@@ -423,7 +426,6 @@ import {
|
|
|
423
426
|
DialogElement,
|
|
424
427
|
DialogStackElement,
|
|
425
428
|
StepperElement,
|
|
426
|
-
NavigationMenuElement,
|
|
427
429
|
AlertDialogElement,
|
|
428
430
|
DropdownMenuElement,
|
|
429
431
|
ContextMenuElement,
|
|
@@ -527,6 +529,9 @@ export {
|
|
|
527
529
|
} from './tailwind';
|
|
528
530
|
|
|
529
531
|
|
|
532
|
+
export { ChartElement, StatElement } from '@close-by/clay-components';
|
|
533
|
+
export type { StatItemRef } from '@close-by/clay-components';
|
|
534
|
+
|
|
530
535
|
export type {
|
|
531
536
|
GridProps,
|
|
532
537
|
LayoutProps,
|
|
@@ -1223,7 +1228,7 @@ export function flow(a: any, b?: any): FlowElement {
|
|
|
1223
1228
|
}
|
|
1224
1229
|
|
|
1225
1230
|
/** Stat strip (label/value items). Prefer `ui.stat`. */
|
|
1226
|
-
export function stat(items: StatItem[], props?: { className?: string }):
|
|
1231
|
+
export function stat(items: StatItem[], props?: { className?: string }): StatElement {
|
|
1227
1232
|
return statFactory(items, props);
|
|
1228
1233
|
}
|
|
1229
1234
|
|
|
@@ -1247,47 +1252,47 @@ export const chart = chartNamespace;
|
|
|
1247
1252
|
export const ai = aiNamespace;
|
|
1248
1253
|
|
|
1249
1254
|
/** Area chart. Prefer `ui.areaChart`. See {@link AreaChartProps}. */
|
|
1250
|
-
export function areaChart(props: AreaChartProps):
|
|
1255
|
+
export function areaChart(props: AreaChartProps): ChartElement {
|
|
1251
1256
|
return areaChartFactory(props);
|
|
1252
1257
|
}
|
|
1253
1258
|
|
|
1254
1259
|
/** Bar chart. Prefer `ui.barChart`. See {@link BarChartProps}. */
|
|
1255
|
-
export function barChart(props: BarChartProps):
|
|
1260
|
+
export function barChart(props: BarChartProps): ChartElement {
|
|
1256
1261
|
return barChartFactory(props);
|
|
1257
1262
|
}
|
|
1258
1263
|
|
|
1259
1264
|
/** Line chart. Prefer `ui.lineChart`. See {@link LineChartProps}. */
|
|
1260
|
-
export function lineChart(props: LineChartProps):
|
|
1265
|
+
export function lineChart(props: LineChartProps): ChartElement {
|
|
1261
1266
|
return lineChartFactory(props);
|
|
1262
1267
|
}
|
|
1263
1268
|
|
|
1264
1269
|
/** Pie / donut chart. Prefer `ui.pieChart`. See {@link PieChartProps}. */
|
|
1265
|
-
export function pieChart(props: PieChartProps):
|
|
1270
|
+
export function pieChart(props: PieChartProps): ChartElement {
|
|
1266
1271
|
return pieChartFactory(props);
|
|
1267
1272
|
}
|
|
1268
1273
|
|
|
1269
1274
|
/** Radar chart. Prefer `ui.radarChart`. See {@link RadarChartProps}. */
|
|
1270
|
-
export function radarChart(props: RadarChartProps):
|
|
1275
|
+
export function radarChart(props: RadarChartProps): ChartElement {
|
|
1271
1276
|
return radarChartFactory(props);
|
|
1272
1277
|
}
|
|
1273
1278
|
|
|
1274
1279
|
/** Radial / gauge chart. Prefer `ui.radialChart`. See {@link RadialChartProps}. */
|
|
1275
|
-
export function radialChart(props: RadialChartProps):
|
|
1280
|
+
export function radialChart(props: RadialChartProps): ChartElement {
|
|
1276
1281
|
return radialChartFactory(props);
|
|
1277
1282
|
}
|
|
1278
1283
|
|
|
1279
1284
|
/** Scatter chart. Prefer `ui.scatterChart`. See {@link ScatterChartProps}. */
|
|
1280
|
-
export function scatterChart(props: ScatterChartProps):
|
|
1285
|
+
export function scatterChart(props: ScatterChartProps): ChartElement {
|
|
1281
1286
|
return scatterChartFactory(props);
|
|
1282
1287
|
}
|
|
1283
1288
|
|
|
1284
1289
|
/** Composed multi-geometry chart. Prefer `ui.composedChart`. See {@link ComposedChartProps}. */
|
|
1285
|
-
export function composedChart(props: ComposedChartProps):
|
|
1290
|
+
export function composedChart(props: ComposedChartProps): ChartElement {
|
|
1286
1291
|
return composedChartFactory(props);
|
|
1287
1292
|
}
|
|
1288
1293
|
|
|
1289
1294
|
/** KPI card with inline sparkline. Prefer `ui.sparkline`. See {@link SparklineProps}. */
|
|
1290
|
-
export function sparkline(props: SparklineProps):
|
|
1295
|
+
export function sparkline(props: SparklineProps): ChartElement {
|
|
1291
1296
|
return sparklineFactory(props);
|
|
1292
1297
|
}
|
|
1293
1298
|
|