reflex-silverpoint-react 0.3.0__tar.gz → 0.7.0__tar.gz

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.
Files changed (41) hide show
  1. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/PKG-INFO +252 -15
  2. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/README.md +244 -10
  3. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react/__init__.py +195 -0
  4. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/assets/surface.jsx +219 -0
  5. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/assets/surfaces.css +375 -0
  6. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/assets/timeline.css +225 -0
  7. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/assets/timeline.jsx +64 -0
  8. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react/base.py +37 -1
  9. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/base.pyi +159 -0
  10. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react/catalog.py +468 -1
  11. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/charts.py +1283 -0
  12. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react/charts.pyi +1999 -1900
  13. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/composed.py +702 -0
  14. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react/dashboard.py +6 -1
  15. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/dashboard.pyi +179 -0
  16. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/overlays.py +835 -0
  17. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/palette.py +362 -0
  18. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/surfaces.py +329 -0
  19. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/surfaces.pyi +364 -0
  20. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/timeline.py +157 -0
  21. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/timeline.pyi +72 -0
  22. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react/ui.py +16 -0
  23. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react/ui.pyi +942 -0
  24. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react.egg-info/PKG-INFO +252 -15
  25. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react.egg-info/SOURCES.txt +14 -1
  26. reflex_silverpoint_react-0.7.0/custom_components/reflex_silverpoint_react.egg-info/requires.txt +11 -0
  27. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/pyproject.toml +14 -6
  28. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/tests/test_components.py +109 -6
  29. reflex_silverpoint_react-0.7.0/tests/test_demo_data.py +85 -0
  30. reflex_silverpoint_react-0.7.0/tests/test_v07.py +234 -0
  31. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react/base.pyi +0 -274
  32. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react/charts.py +0 -645
  33. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react/dashboard.pyi +0 -314
  34. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react/ui.pyi +0 -1687
  35. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react.egg-info/requires.txt +0 -7
  36. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/LICENSE +0 -0
  37. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react/helpers.py +0 -0
  38. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react/ui_catalog.py +0 -0
  39. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react.egg-info/dependency_links.txt +0 -0
  40. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/custom_components/reflex_silverpoint_react.egg-info/top_level.txt +0 -0
  41. {reflex_silverpoint_react-0.3.0 → reflex_silverpoint_react-0.7.0}/setup.cfg +0 -0
@@ -1,27 +1,30 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reflex-silverpoint-react
3
- Version: 0.3.0
4
- Summary: The 33 silverpoint charts, the linked Dashboard and the 17 UI components (Renaissance silverpoint drawing style) for Reflex, wrapping @silverpoint/react
3
+ Version: 0.7.0
4
+ Summary: The 60 silverpoint charts, the Dashboard, 17 UI components, palettes, 20 composed components and a Knight Lab timeline (Renaissance silverpoint drawing style) for Reflex, wrapping @silverpoint/react
5
5
  Author-email: Ernesto Crespo <ecrespo@gmail.com>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://github.com/ecrespo/reflex-silverpoint-react
8
8
  Project-URL: Source, https://github.com/ecrespo/reflex-silverpoint-react
9
9
  Project-URL: Issues, https://github.com/ecrespo/reflex-silverpoint-react/issues
10
10
  Project-URL: Upstream, https://github.com/ecrespo/silverpoint
11
- Keywords: reflex,reflex-custom-components,charts,silverpoint,data-visualization,svg,ui-components
11
+ Keywords: reflex,reflex-custom-components,charts,silverpoint,data-visualization,svg,ui-components,palette,timeline
12
12
  Classifier: Development Status :: 4 - Beta
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Programming Language :: Python :: 3
15
15
  Classifier: Topic :: Scientific/Engineering :: Visualization
16
- Requires-Python: >=3.10
16
+ Requires-Python: >=3.11
17
17
  Description-Content-Type: text/markdown
18
18
  License-File: LICENSE
19
- Requires-Dist: reflex>=0.9.12
19
+ Requires-Dist: reflex>=0.10.0
20
+ Provides-Extra: timeline
21
+ Requires-Dist: reflex-knightlab-timeline>=0.1.2; extra == "timeline"
20
22
  Provides-Extra: dev
21
23
  Requires-Dist: build; extra == "dev"
22
24
  Requires-Dist: twine; extra == "dev"
23
25
  Requires-Dist: pytest; extra == "dev"
24
26
  Requires-Dist: ruff; extra == "dev"
27
+ Requires-Dist: reflex-knightlab-timeline>=0.1.2; extra == "dev"
25
28
  Dynamic: license-file
26
29
 
27
30
  # reflex-silverpoint-react
@@ -33,12 +36,50 @@ prepared ground, tone built from hatching, and white heightening on the live val
33
36
  The hand-drawn irregularity lives only in the ornament. The data geometry is exact, and every chart
34
37
  has a `precision` mode that turns the inking off.
35
38
 
36
- It wraps [`@silverpoint/react`](https://www.npmjs.com/package/@silverpoint/react) 0.3.0 and exposes
37
- **all 33 charts**, the **`Dashboard`** (a laid-out, linkable grid of charts), the **17 UI
39
+ It wraps [`@silverpoint/react`](https://www.npmjs.com/package/@silverpoint/react) 0.6.0 and exposes
40
+ **all 60 charts**, the **`Dashboard`** (a laid-out, linkable grid of charts), the **17 UI
38
41
  components** (buttons, inputs, tabs, cards, alerts…), the `SilverpointProvider`, both grounds
39
42
  (`silverpoint` and `cyanotype`), the interaction events, custom readouts and the imperative handle
40
43
  (SVG export and geometry) as Python.
41
44
 
45
+ On top of that it adds, in Reflex: **palettes** for every chart and component, **20 composed
46
+ components** built on silverpoint's own frames and tones (tables, overlays, toasts…), and the
47
+ **Knight Lab timeline** drawn in silverpoint.
48
+
49
+ ### New in 0.7
50
+
51
+ - **Reflex 0.10.0**, and therefore **Python 3.11 or later** (Python 3.10 is no longer supported).
52
+ Reflex 0.10 removed `reflex component build`: stubs are regenerated with `scripts/make_stubs.py`.
53
+ - **Palettes** — `palette=` on every chart, UI component, dashboard and composed component,
54
+ `silverpoint_palette(...)` for a whole section, six presets named after drawing media
55
+ (`silverpoint`, `sanguine`, `sepia`, `iron_gall`, `verdigris`, `indigo`) and `check_palette()`
56
+ against the contrast thresholds of the data model. See [Palettes](#palettes).
57
+ - **Composed components, level A** (native markup): `sp_table` (+ `sort_rows`), `sp_pagination`,
58
+ `sp_breadcrumb`, `sp_avatar` (+ `sp_avatar_group`), `sp_statistic`, `sp_descriptions`,
59
+ `sp_timeline_list`, `sp_collapse` (+ `sp_collapse_item`), `sp_empty`, `sp_result`, `sp_textarea`
60
+ and `sp_input_number`.
61
+ - **Composed components, level B** (overlays on Radix primitives): `sp_modal`, `sp_drawer`,
62
+ `sp_popover`, `sp_tooltip`, `sp_select`, `sp_dropdown_menu` and `sp_toast` (+ `sp_toaster`), with
63
+ `sp_trigger` as their drawn button. See [Composed components](#composed-components).
64
+ - **`sp_timeline`** — Knight Lab TimelineJS drawn in silverpoint: a skin on the ground's colours and
65
+ type, plus the ground's own hand-inked frames and tone tiles on its markers, eras and buttons.
66
+ Optional extra: `pip install "reflex-silverpoint-react[timeline]"`. See [Timeline](#timeline).
67
+ - `sp_surface`, `sp_glyph`: the building blocks, for components of your own.
68
+
69
+ ### New in 0.6
70
+
71
+ - **27 new charts**, the second catalog of silverpoint 0.6:
72
+ - distributions & comparisons: `histogram_chart`, `ecdf_chart`, `box_plot_chart`, `violin_chart`,
73
+ `ridgeline_chart`, `beeswarm_chart`, `lollipop_chart`, `dumbbell_chart`, `slope_chart`,
74
+ `bump_chart`, `error_bar_chart`, `interval_chart`, `diverging_bar_chart`, `connected_scatter_chart`;
75
+ - hierarchies & dimensions: `waffle_chart`, `marimekko_chart`, `squarified_treemap`,
76
+ `sunburst_chart`, `tree_chart`, `parallel_coordinates_chart`, `polar_line_chart`,
77
+ `polar_scatter_chart`;
78
+ - fields & networks: `density_bin_chart`, `contour_chart`, `delaunay_chart`, `vector_field_chart`,
79
+ `network_chart` (with the `network_node` helper).
80
+ - **Drill-down** on `squarified_treemap` and `sunburst_chart`: `root_id` plus the `on_root_change`
81
+ event. See [Drill-down](#drill-down).
82
+
42
83
  ### New in 0.3
43
84
 
44
85
  - **17 UI components**, drawn as the charts are: `sp_button`, `sp_input`, `sp_checkbox`,
@@ -73,7 +114,7 @@ stylesheets it needs (`@silverpoint/grounds/styles.css` and the self-hosted EB G
73
114
  `@silverpoint/fonts/fonts.css`); the UI components also import `@silverpoint/grounds/ui.css`. No
74
115
  Tailwind, no CDN.
75
116
 
76
- Requires Reflex 0.9.12 or later (React 19).
117
+ Requires Reflex 0.10.0 or later (React 19) and Python 3.11 or later.
77
118
 
78
119
  ## Quickstart
79
120
 
@@ -109,7 +150,7 @@ Props are the React props in `snake_case`: `xKey` → `x_key`, `hatchFill` → `
109
150
  `footerRight` → `footer_right`, `centerLabel` → `center_label`, and so on. `data` and every prop can
110
151
  be a Reflex state var.
111
152
 
112
- ## The 33 charts
153
+ ## The 60 charts
113
154
 
114
155
  | Family | Charts |
115
156
  |---|---|
@@ -119,11 +160,60 @@ be a Reflex state var.
119
160
  | Points & grids | `scatter_chart`, `bubble_chart`, `heatmap_chart`, `treemap_chart`, `activity_grid` |
120
161
  | Flows | `sankey_chart`, `chord_ring` |
121
162
  | Radial | `donut_chart`, `radar_chart`, `polar_bar_chart`, `radial_arc_group`, `radial_rings`, `gauge_arc`, `meter_chart`, `coxcomb_chart`, `wind_rose`, `volvelle_chart`, `orbit_chart` |
163
+ | Distributions & comparisons (0.6) | `histogram_chart`, `ecdf_chart`, `box_plot_chart`, `violin_chart`, `ridgeline_chart`, `beeswarm_chart`, `lollipop_chart`, `dumbbell_chart`, `slope_chart`, `bump_chart`, `error_bar_chart`, `interval_chart`, `diverging_bar_chart`, `connected_scatter_chart` |
164
+ | Hierarchies & dimensions (0.6) | `waffle_chart`, `marimekko_chart`, `squarified_treemap`, `sunburst_chart`, `tree_chart`, `parallel_coordinates_chart`, `polar_line_chart`, `polar_scatter_chart` |
165
+ | Fields & networks (0.6) | `density_bin_chart`, `contour_chart`, `delaunay_chart`, `vector_field_chart`, `network_chart` |
122
166
 
123
167
  Every factory has a class of the same name in `PascalCase` (`LineChart`, `WindRose`…).
124
168
  `reflex_silverpoint_react.CHARTS` is the whole catalog with each chart's family and the reference of
125
169
  its own props (`COMMON_PROPS` holds the shared ones), handy for galleries and documentation.
126
170
 
171
+ With your own `data`, `ridgeline_chart` needs `group_key`, `diverging_bar_chart` needs `levels` (the
172
+ level columns, most negative first) and `parallel_coordinates_chart` needs `dimensions` (the columns,
173
+ in axis order). The demo datasets ignore them.
174
+
175
+ `network_chart` lays its nodes out by force, the same on the server and in every browser for a given
176
+ `seed`. Pass `nodes` to name and group them, built with `network_node`. A node with an `x` and a `y`
177
+ is drawn there, and when every node has both no layout runs:
178
+
179
+ ```python
180
+ from reflex_silverpoint_react import network_chart, network_node
181
+
182
+ network_chart(
183
+ data=State.links, # [{"source": "a", "target": "b", "weight": 3}, ...]
184
+ source_key="source",
185
+ target_key="target",
186
+ value_key="weight",
187
+ nodes=[network_node("a", label="Archive", group="storage"), network_node("b", label="Billing")],
188
+ )
189
+ ```
190
+
191
+ ### Drill-down
192
+
193
+ `squarified_treemap` and `sunburst_chart` drill down under your control. The chart keeps no root of
194
+ its own: a click, Enter or Space on a node sends its id to `on_root_change` (the parent's id from the
195
+ centre or the frame, `None` at the top), and you pass it back as `root_id`:
196
+
197
+ ```python
198
+ class Budget(rx.State):
199
+ root: str | None = None
200
+
201
+ @rx.event
202
+ def drill(self, node_id: str | None):
203
+ self.root = node_id
204
+
205
+
206
+ squarified_treemap(
207
+ data=rows, # one row per node: {"id": ..., "parent": ... or None, "name": ..., "amount": ...}
208
+ id_key="id",
209
+ parent_key="parent",
210
+ label_key="name",
211
+ value_key="amount",
212
+ root_id=Budget.root,
213
+ on_root_change=Budget.drill,
214
+ )
215
+ ```
216
+
127
217
  ## Props every chart shares
128
218
 
129
219
  | Prop | Default | |
@@ -287,6 +377,132 @@ rx.el.form(
287
377
  - Text inputs controlled from state make a round trip per keystroke; for long text, prefer
288
378
  `default_value` and read the value on submit.
289
379
 
380
+ ## Palettes
381
+
382
+ silverpoint never writes a colour into its drawing: every stroke and fill is painted by CSS through
383
+ the ground's `--sp-` custom properties. A palette sets them, so it re-colours without re-rendering.
384
+
385
+ ```python
386
+ from reflex_silverpoint_react import PALETTES, Palette, bar_chart, check_palette, silverpoint_palette, sp_button
387
+
388
+ bar_chart(title="Orders", palette="sanguine") # a preset
389
+ sp_button("Save", variant="primary", palette={"ink": "#2C6355"}) # a dict of fields
390
+ bar_chart(title="Orders", palette=State.palette) # a state var holding a dict
391
+
392
+ MINE = Palette(substrate="#F2E8DC", ink="#8A3A24", ink_secondary="#6A4A3A", text="#4A2216")
393
+ assert not check_palette(MINE) # [] when every field meets its contrast threshold
394
+
395
+ silverpoint_palette(dashboard(...), sp_card(...), palette="indigo") # a whole section
396
+ ```
397
+
398
+ Fields: `substrate`, `ink`, `ink_secondary`, `heighten`, `rule`, `grid`, `text`, `text_muted` and
399
+ `focus` (the UI focus ring). Unset fields keep the ground's own. An element's own `palette` always
400
+ wins over its section's. A palette is **monochrome by design**: tone is built from hatch density
401
+ (Art. 6), so a chart has two inks (`ink` for the main series, `ink_secondary` for the second), never
402
+ a colour per series. `precision` mode and the system's high-contrast modes still apply on top.
403
+ `silverpoint_provider` takes no palette (it renders no element): use `silverpoint_palette`.
404
+
405
+ ## Composed components
406
+
407
+ Components built in Reflex on silverpoint's markup contract: `@silverpoint/grounds/ui.css` draws its
408
+ hand-inked frames, hatched tones and heightening on any element that follows it, so these are drawn
409
+ with exactly the same pieces as the `Sp` components. They are **Reflex-only** (silverpoint's React,
410
+ Vue and Angular adapters do not have them) and, unlike the `Sp` components, they do not read
411
+ `silverpoint_provider`: pass `ground`, `substrate`, `mode` and `palette` explicitly.
412
+
413
+ ```python
414
+ from reflex_silverpoint_react import sort_rows, sp_pagination, sp_table
415
+
416
+ sp_table(
417
+ [
418
+ {"key": "team", "title": "Team", "sortable": True},
419
+ {"key": "load", "title": "Load", "align": "end", "sortable": True},
420
+ ],
421
+ State.rows,
422
+ caption="On-call teams",
423
+ sort_key=State.sort_key,
424
+ sort_order=State.sort_order,
425
+ on_sort=State.sort, # receives the key; sort with sort_rows(rows, key, order)
426
+ striped=True,
427
+ )
428
+ sp_pagination(total=240, current=State.page, on_change=State.set_page, show_total=True)
429
+ ```
430
+
431
+ | Level A (native) | |
432
+ |---|---|
433
+ | `sp_table` | Card-framed table: small-caps header, tabular figures, hatched striping, sortable headers with `aria-sort` |
434
+ | `sp_pagination` | Previous/next, first/last, a window around the current page (heightened); `on_change(page)` |
435
+ | `sp_breadcrumb` | `<nav>` of links; the last item is the current page |
436
+ | `sp_avatar`, `sp_avatar_group` | Portrait or initials in a drawn round (or square) frame |
437
+ | `sp_statistic` | Small-caps title, large tabular figure, prefix/suffix, trend arrow |
438
+ | `sp_descriptions` | Label–value grid (`<dl>`), optionally card-framed |
439
+ | `sp_timeline_list` | Vertical list: `done` (hatched), `current` (heightened), `pending`, `error` |
440
+ | `sp_collapse`, `sp_collapse_item` | Native `<details>`; `accordion=True` keeps one open |
441
+ | `sp_empty`, `sp_result` | Empty state; outcome with a drawn round mark |
442
+ | `sp_textarea`, `sp_input_number` | On the `SpInput` contract; `on_change` receives the value (text or number) |
443
+
444
+ | Level B (Radix primitives) | |
445
+ |---|---|
446
+ | `sp_modal`, `sp_drawer` | Dialog on a card frame over a hatched backdrop; drawer from any edge |
447
+ | `sp_popover`, `sp_tooltip` | Anchored content; tooltip on hover or keyboard focus |
448
+ | `sp_select` | Single choice with typeahead; the chosen option ticked, the highlighted one heightened |
449
+ | `sp_dropdown_menu` | Commands with shortcuts, separators and labels; `on_select(key)` |
450
+ | `sp_toast`, `sp_toaster` | Notices that stack in a corner; `error`/`warning` are announced assertively |
451
+
452
+ Behaviour (focus trapping, keyboard, dismissal, positioning, ARIA) is Radix's, at the versions
453
+ Reflex already installs. Overlays render in a portal at the end of `<body>`, outside any
454
+ `silverpoint_palette` section, so give them `palette` directly. A string `trigger` becomes
455
+ `sp_trigger(...)`, the drawn button that can forward Radix's props (`sp_button` cannot).
456
+
457
+ ```python
458
+ sp_modal(
459
+ rx.el.p("Apply the new ground?"),
460
+ trigger="Open",
461
+ title="Apply changes",
462
+ footer=sp_trigger("Apply", variant="primary", on_click=State.confirm),
463
+ open=State.modal_open,
464
+ on_open_change=State.set_modal_open,
465
+ )
466
+ sp_select(["North", "East", "South", "West"], value=State.region, on_change=State.set_region)
467
+ sp_toaster(sp_toast("Saved", State.text, kind="success", open=State.toast_open, on_open_change=State.set_toast_open))
468
+ ```
469
+
470
+ ![Composed components](docs/components.png)
471
+
472
+ ## Timeline
473
+
474
+ ```bash
475
+ pip install "reflex-silverpoint-react[timeline]" # adds reflex-knightlab-timeline
476
+ ```
477
+
478
+ ```python
479
+ from reflex_silverpoint_react import sp_timeline
480
+
481
+ sp_timeline(
482
+ DATA, # TimelineJS data: title, events, eras (or a TimelineData)
483
+ height=560,
484
+ ground="silverpoint",
485
+ substrate="cream",
486
+ mode="ink",
487
+ palette="sepia",
488
+ inked_frames=True, # the ground's hand-drawn frames and tone tiles
489
+ on_change=State.on_change, # the unique_id of the slide shown
490
+ )
491
+ ```
492
+
493
+ It works in two layers. The **skin** replaces TimelineJS's colours, type and rules with the
494
+ ground's `--sp-` properties: substrate, inks, EB Garamond, hairline rules, eras hatched by density,
495
+ the current marker heightened. The **hand** reads the ground's own frame and tone masks from hidden
496
+ probes and lays them on the markers, eras and menubar, so they are drawn with the same pieces as
497
+ the `Sp` components; `inked_frames=False` keeps the skin only, and `precision`, `cyanotype` and
498
+ forced colours fall back to exact rules by themselves. Note that TimelineJS requests its icon font
499
+ from a relative path (`/css/icons/tl-icons.*`); the Reflex dev server answers it with HTML, so the
500
+ browser logs font-decoding warnings. They come from TimelineJS, not from this package.
501
+
502
+ ![The Knight Lab timeline in silverpoint](docs/timeline.png)
503
+
504
+ ![The palettes page](docs/palettes.png)
505
+
290
506
  ## Interaction
291
507
 
292
508
  ```python
@@ -348,32 +564,53 @@ The exported SVG carries its own ground colours, so it renders the same outside
348
564
  ## Demo app
349
565
 
350
566
  ```bash
351
- uv venv && uv pip install -e .
567
+ uv venv && uv pip install -e ".[timeline]"
352
568
  cd silverpoint_react_demo
353
569
  uv run reflex run
354
570
  ```
355
571
 
356
- Pages: **Start** (quickstart, provider, ink vs precision), **Gallery** (the 33 charts, ground
572
+ Pages: **Start** (quickstart, provider, ink vs precision), **Gallery** (the 60 charts, ground
357
573
  controls, demo datasets vs data from Python state with a re-roll), **Playground** (one chart, every
358
574
  rendering choice and the Python that reproduces it), **Interaction** (events, custom readout, a
359
- volvelle that turns on click, live KPI/gauge/meter, SVG and geometry export), **Dashboard** (a
575
+ volvelle that turns on click, a treemap and a sunburst that drill down together, live
576
+ KPI/gauge/meter, SVG and geometry export), **Dashboard** (a
360
577
  linked operations dashboard fed from Python state with ground, substrate, mode and column controls, a
361
578
  KPI strip, and `dashboard_link` on its own), **UI components** (`/ui`: the components controlled from
362
579
  Python state with a native form submit, and the three reference panels of the upstream example apps
363
580
  in silverpoint ink, precision and cyanotype), one **reference page per chart** (`/chart/<slug>`) and
364
- one per UI component (`/ui/<slug>`: every declared state on both grounds, usage and props). The Gallery and Playground also get a ground control, for `cyanotype`.
581
+ one per UI component (`/ui/<slug>`: every declared state on both grounds, usage and props). The
582
+ Gallery and Playground also get a ground control, for `cyanotype`, and a palette control.
583
+ New in 0.7: **More components** (`/components`: the 20 composed components wired to Python, with
584
+ ground, substrate, mode and palette controls and an event log), **Palettes** (`/palettes`: the
585
+ presets, a palette builder with colour pickers and `check_palette`, a coloured section) and
586
+ **Timeline** (`/timeline`: the Knight Lab timeline on every ground, mode and palette).
365
587
 
366
588
  ![Interaction page](docs/interaction.png)
367
589
 
368
590
  ## Development
369
591
 
370
592
  ```bash
371
- uv venv && uv pip install -e ".[dev]"
593
+ uv sync --extra dev
372
594
  uv run pytest
373
595
  uv run ruff check .
374
- uv run reflex component build # .pyi stubs + sdist and wheel in dist/
596
+ # Reflex 0.10 removed `reflex component build`: regenerate the .pyi stubs with the generator
597
+ # Reflex itself uses (plus this package's fixes), then build the sdist and wheel.
598
+ uv run python scripts/make_stubs.py
599
+ uv build
375
600
  ```
376
601
 
602
+ Before committing, run the hooks of [`.pre-commit-config.yaml`](.pre-commit-config.yaml) (ruff check
603
+ and format — including the Python blocks of this README — file hygiene and `uv lock --check`):
604
+
605
+ ```bash
606
+ pre-commit install
607
+ pre-commit run --all-files
608
+ ```
609
+
610
+ Changes per version are in [CHANGELOG.md](CHANGELOG.md); the guide for coding agents is
611
+ [AGENTS.md](AGENTS.md). Releases are published to PyPI by pushing a `vX.Y.Z` tag on `main` that
612
+ matches `version` in `pyproject.toml`.
613
+
377
614
  ## License
378
615
 
379
616
  MIT. silverpoint is MIT; the EB Garamond typeface is under the SIL Open Font License.