reflex-silverpoint-react 0.6.0__tar.gz → 0.7.1__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 (38) hide show
  1. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/PKG-INFO +214 -14
  2. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/README.md +208 -9
  3. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react/__init__.py +137 -1
  4. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/assets/trigger.jsx +63 -0
  5. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react/base.py +67 -3
  6. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/base.pyi +162 -0
  7. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react/charts.pyi +125 -3596
  8. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/composed.py +633 -0
  9. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/composed.pyi +684 -0
  10. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react/dashboard.py +8 -1
  11. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/dashboard.pyi +179 -0
  12. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/overlays.py +784 -0
  13. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/overlays.pyi +674 -0
  14. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/palette.py +377 -0
  15. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/surfaces.py +235 -0
  16. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/surfaces.pyi +288 -0
  17. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/timeline.py +172 -0
  18. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/timeline.pyi +100 -0
  19. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react/ui.py +19 -0
  20. reflex_silverpoint_react-0.7.1/custom_components/reflex_silverpoint_react/ui.pyi +942 -0
  21. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react.egg-info/PKG-INFO +214 -14
  22. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react.egg-info/SOURCES.txt +12 -1
  23. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react.egg-info/requires.txt +3 -1
  24. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/pyproject.toml +14 -5
  25. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/tests/test_components.py +3 -3
  26. reflex_silverpoint_react-0.7.1/tests/test_v07.py +322 -0
  27. reflex_silverpoint_react-0.6.0/custom_components/reflex_silverpoint_react/base.pyi +0 -274
  28. reflex_silverpoint_react-0.6.0/custom_components/reflex_silverpoint_react/dashboard.pyi +0 -314
  29. reflex_silverpoint_react-0.6.0/custom_components/reflex_silverpoint_react/ui.pyi +0 -1687
  30. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/LICENSE +0 -0
  31. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react/catalog.py +0 -0
  32. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react/charts.py +0 -0
  33. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react/helpers.py +0 -0
  34. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react/ui_catalog.py +0 -0
  35. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react.egg-info/dependency_links.txt +0 -0
  36. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/custom_components/reflex_silverpoint_react.egg-info/top_level.txt +0 -0
  37. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/setup.cfg +0 -0
  38. {reflex_silverpoint_react-0.6.0 → reflex_silverpoint_react-0.7.1}/tests/test_demo_data.py +0 -0
@@ -1,22 +1,23 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reflex-silverpoint-react
3
- Version: 0.6.0
4
- Summary: The 60 silverpoint charts, the linked Dashboard and the 17 UI components (Renaissance silverpoint drawing style) for Reflex, wrapping @silverpoint/react
3
+ Version: 0.7.1
4
+ Summary: The 60 silverpoint charts, the Dashboard, 38 UI, composed and overlay components, palettes and a Knight Lab timeline (Renaissance silverpoint drawing style) for Reflex, wrapping @silverpoint/react 0.7
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
20
21
  Provides-Extra: dev
21
22
  Requires-Dist: build; extra == "dev"
22
23
  Requires-Dist: twine; extra == "dev"
@@ -33,11 +34,58 @@ prepared ground, tone built from hatching, and white heightening on the live val
33
34
  The hand-drawn irregularity lives only in the ornament. The data geometry is exact, and every chart
34
35
  has a `precision` mode that turns the inking off.
35
36
 
36
- It wraps [`@silverpoint/react`](https://www.npmjs.com/package/@silverpoint/react) 0.6.0 and exposes
37
+ It wraps [`@silverpoint/react`](https://www.npmjs.com/package/@silverpoint/react) **0.7.0** and exposes
37
38
  **all 60 charts**, the **`Dashboard`** (a laid-out, linkable grid of charts), the **17 UI
38
- components** (buttons, inputs, tabs, cards, alerts…), the `SilverpointProvider`, both grounds
39
- (`silverpoint` and `cyanotype`), the interaction events, custom readouts and the imperative handle
40
- (SVG export and geometry) as Python.
39
+ components** (buttons, inputs, tabs, cards, alerts…), the **12 composed components** (table,
40
+ pagination, breadcrumb, avatar…), the **7 overlays** and the toaster (modal, drawer, popover,
41
+ tooltip, select, dropdown menu, toast), the **palettes**, the **Knight Lab timeline**, the
42
+ `SilverpointProvider`, both grounds (`silverpoint` and `cyanotype`), the interaction events, custom
43
+ readouts and the imperative handle (SVG export and geometry) as Python.
44
+
45
+ Everything it renders is an npm component of silverpoint, under its parity contract: the same
46
+ markup React, Vue and Angular render.
47
+
48
+ ### New in 0.7.1
49
+
50
+ - Wraps **`@silverpoint/react` 0.7.0** (0.7.0 wrapped 0.6.0). silverpoint 0.7 took this package's
51
+ palettes, composed components, overlays and timeline into the library itself, so they are now the
52
+ npm components, not Reflex-composed copies: same Python builders, the library's markup.
53
+ - **Palettes** are the npm `palette` prop: they merge element → dashboard → provider field by field,
54
+ `silverpoint_provider(palette=...)` works, and `silverpoint_palette(...)` is a provider with a
55
+ palette. `check_palette()` measures the core's nine contrast pairs (the focus ring and the white
56
+ heightening included); `"ironGall"` names the `iron_gall` preset too.
57
+ - **Composed components and overlays read `silverpoint_provider`**, as the `Sp` components do.
58
+ Overlays are a native `<dialog>` and the Popover API (no Radix); they render in place, so a
59
+ section's palette reaches them.
60
+ - **Logical sides**: `side="start"`/`"end"` and `position="bottom-end"`…; `left`/`right` still work
61
+ with a `DeprecationWarning`. `sp_drawer(size=)` is `extent=`, `sp_popover(side_offset=)` is
62
+ `offset=`; `sp_modal` gains `label` and `dismissible`, `sp_result`/`sp_descriptions`
63
+ `heading_level`.
64
+ - `sp_textarea(textarea_id=)` and `sp_input_number(input_id=)` are `id=` (deprecated aliases kept);
65
+ `sp_textarea` has no `on_blur`. `sp_collapse_item(on_toggle=)` receives the new open state (a bool).
66
+ - **`sp_timeline`** is the npm `SpTimeline`: TimelineJS is an npm dependency of that component, so the
67
+ `[timeline]` extra pulls in nothing any more (it is kept so existing installs keep working).
68
+ - `sort_rows()` follows the core's `uiSortRows` order (numbers first, then text by code point).
69
+
70
+ ### New in 0.7.0
71
+
72
+ - **Reflex 0.10.0**, and therefore **Python 3.11 or later** (Python 3.10 is no longer supported).
73
+ Reflex 0.10 removed `reflex component build`: stubs are regenerated with `scripts/make_stubs.py`.
74
+ - **Palettes** — `palette=` on every chart, UI component, dashboard and composed component,
75
+ `silverpoint_palette(...)` for a whole section, six presets named after drawing media
76
+ (`silverpoint`, `sanguine`, `sepia`, `iron_gall`, `verdigris`, `indigo`) and `check_palette()`
77
+ against the contrast thresholds of the data model. See [Palettes](#palettes).
78
+ - **Composed components, level A** (native markup): `sp_table` (+ `sort_rows`), `sp_pagination`,
79
+ `sp_breadcrumb`, `sp_avatar` (+ `sp_avatar_group`), `sp_statistic`, `sp_descriptions`,
80
+ `sp_timeline_list`, `sp_collapse` (+ `sp_collapse_item`), `sp_empty`, `sp_result`, `sp_textarea`
81
+ and `sp_input_number`.
82
+ - **Composed components, level B** (overlays on Radix primitives): `sp_modal`, `sp_drawer`,
83
+ `sp_popover`, `sp_tooltip`, `sp_select`, `sp_dropdown_menu` and `sp_toast` (+ `sp_toaster`), with
84
+ `sp_trigger` as their drawn button. See [Composed components](#composed-components).
85
+ - **`sp_timeline`** — Knight Lab TimelineJS drawn in silverpoint: a skin on the ground's colours and
86
+ type, plus the ground's own hand-inked frames and tone tiles on its markers, eras and buttons.
87
+ Optional extra (until 0.7.1): `pip install "reflex-silverpoint-react[timeline]"`. See [Timeline](#timeline).
88
+ - `sp_surface`, `sp_glyph`: the building blocks, for components of your own.
41
89
 
42
90
  ### New in 0.6
43
91
 
@@ -87,7 +135,7 @@ stylesheets it needs (`@silverpoint/grounds/styles.css` and the self-hosted EB G
87
135
  `@silverpoint/fonts/fonts.css`); the UI components also import `@silverpoint/grounds/ui.css`. No
88
136
  Tailwind, no CDN.
89
137
 
90
- Requires Reflex 0.9.12 or later (React 19).
138
+ Requires Reflex 0.10.0 or later (React 19) and Python 3.11 or later.
91
139
 
92
140
  ## Quickstart
93
141
 
@@ -350,6 +398,137 @@ rx.el.form(
350
398
  - Text inputs controlled from state make a round trip per keystroke; for long text, prefer
351
399
  `default_value` and read the value on submit.
352
400
 
401
+ ## Palettes
402
+
403
+ silverpoint never writes a colour into its drawing: every stroke and fill is painted by CSS through
404
+ the ground's `--sp-` custom properties. A palette sets them, so it re-colours without re-rendering.
405
+
406
+ ```python
407
+ from reflex_silverpoint_react import PALETTES, Palette, bar_chart, check_palette, silverpoint_palette, sp_button
408
+
409
+ bar_chart(title="Orders", palette="sanguine") # a preset
410
+ sp_button("Save", variant="primary", palette={"ink": "#2C6355"}) # a dict of fields
411
+ bar_chart(title="Orders", palette=State.palette) # a state var holding a dict
412
+
413
+ MINE = Palette(substrate="#F2E8DC", ink="#8A3A24", ink_secondary="#6A4A3A", text="#4A2216")
414
+ assert not check_palette(MINE) # [] when every field meets its contrast threshold
415
+
416
+ silverpoint_palette(dashboard(...), sp_card(...), palette="indigo") # a whole section
417
+ ```
418
+
419
+ Fields: `substrate`, `ink`, `ink_secondary`, `heighten`, `rule`, `grid`, `text`, `text_muted` and
420
+ `focus` (the UI focus ring). Unset fields keep the ground's own. Palettes merge field by field,
421
+ element → dashboard → provider, so an element's own `palette` wins over its section's. A palette is
422
+ **monochrome by design**: tone is built from hatch density (Art. 6), so a chart has two inks (`ink`
423
+ for the main series, `ink_secondary` for the second), never a colour per series. `precision` mode and
424
+ the system's high-contrast modes still apply on top. `silverpoint_palette(...)` is
425
+ `silverpoint_provider(palette=...)` around the section.
426
+
427
+ ## Composed components
428
+
429
+ silverpoint 0.7's composed components and overlays, the npm components of `@silverpoint/react/ui`:
430
+ native markup drawn by the core with the ground's hand-inked frames, hatched tones and
431
+ heightening, exactly as the `Sp` components are. Like them they read `silverpoint_provider` (and
432
+ the dashboard they sit in); a prop on the component always wins.
433
+
434
+ ```python
435
+ from reflex_silverpoint_react import sort_rows, sp_pagination, sp_table
436
+
437
+ sp_table(
438
+ [
439
+ {"key": "team", "title": "Team", "sortable": True},
440
+ {"key": "load", "title": "Load", "align": "end", "sortable": True},
441
+ ],
442
+ State.rows,
443
+ caption="On-call teams",
444
+ sort_key=State.sort_key,
445
+ sort_order=State.sort_order,
446
+ on_sort=State.sort, # receives the key; sort with sort_rows(rows, key, order)
447
+ striped=True,
448
+ )
449
+ sp_pagination(total=240, current=State.page, on_change=State.set_page, show_total=True)
450
+ ```
451
+
452
+ | Composed (native markup) | |
453
+ |---|---|
454
+ | `sp_table` | Card-framed table: small-caps header, tabular figures, hatched striping, sortable headers with `aria-sort` |
455
+ | `sp_pagination` | Previous/next, first/last, a window around the current page (heightened); `on_change(page)` |
456
+ | `sp_breadcrumb` | `<nav>` of links; the last item is the current page |
457
+ | `sp_avatar`, `sp_avatar_group` | Portrait or initials in a drawn round (or square) frame |
458
+ | `sp_statistic` | Small-caps title, large tabular figure, prefix/suffix, trend arrow |
459
+ | `sp_descriptions` | Label–value grid (`<dl>`), optionally card-framed |
460
+ | `sp_timeline_list` | Vertical list: `done` (hatched), `current` (heightened), `pending`, `error` |
461
+ | `sp_collapse`, `sp_collapse_item` | Native `<details>`; `accordion=True` keeps one open |
462
+ | `sp_empty`, `sp_result` | Empty state; outcome with a drawn round mark |
463
+ | `sp_textarea`, `sp_input_number` | On the `SpInput` contract; `on_change` receives the value (text or number) |
464
+
465
+ | Overlays (`<dialog>`, Popover API) | |
466
+ |---|---|
467
+ | `sp_modal`, `sp_drawer` | Dialog on a card frame over a hatched backdrop; drawer from any edge |
468
+ | `sp_popover`, `sp_tooltip` | Anchored content; tooltip on hover or keyboard focus |
469
+ | `sp_select` | Single choice with typeahead; the chosen option ticked, the highlighted one heightened |
470
+ | `sp_dropdown_menu` | Commands with shortcuts, separators and labels; `on_select(key)` |
471
+ | `sp_toast`, `sp_toaster` | Notices that stack in a corner; `error`/`warning` are announced assertively |
472
+
473
+ Behaviour is the platform's: `showModal()` for the modal and the drawer (focus stays inside, Escape
474
+ and the backdrop close it unless `dismissible=False`), the Popover API for the rest (light
475
+ dismiss), keyboard and placement from `@silverpoint/core` (APG listbox and menu, typeahead, flip and
476
+ shift). Overlays render in place (the top layer, no portal), so a section's palette reaches them.
477
+ Sides are logical (`start`/`end`) and mirror in right-to-left text. An overlay clones its `trigger`
478
+ with its ARIA and a toggling click, so the trigger must keep the props it is given: a native
479
+ `rx.el.button`, or `sp_trigger(...)`, the drawn button strings become (`sp_button` drops them in
480
+ silverpoint 0.7.0). `sp_trigger` does not read the provider: give it `ground`, `substrate`, `mode`
481
+ and `palette`.
482
+
483
+ ```python
484
+ sp_modal(
485
+ rx.el.p("Apply the new ground?"),
486
+ trigger="Open",
487
+ title="Apply changes",
488
+ footer=sp_trigger("Apply", variant="primary", on_click=State.confirm),
489
+ open=State.modal_open,
490
+ on_open_change=State.set_modal_open,
491
+ )
492
+ sp_select(["North", "East", "South", "West"], value=State.region, on_change=State.set_region)
493
+ sp_toaster(sp_toast("Saved", State.text, kind="success", open=State.toast_open, on_open_change=State.set_toast_open))
494
+ ```
495
+
496
+ ![Composed components](docs/components.png)
497
+
498
+ ## Timeline
499
+
500
+ The npm `SpTimeline` of `@silverpoint/react/timeline`. TimelineJS (`@knight-lab/timelinejs` 3.9.13)
501
+ is an npm dependency of this component: Reflex installs it when a page uses `sp_timeline`, and no
502
+ Python extra is needed. If it cannot be loaded, the component warns `SP025` and renders `fallback`.
503
+
504
+ ```python
505
+ from reflex_silverpoint_react import sp_timeline
506
+
507
+ sp_timeline(
508
+ DATA, # TimelineJS data: title, events, eras (or any object with to_dict())
509
+ height=560,
510
+ ground="silverpoint",
511
+ substrate="cream",
512
+ mode="ink",
513
+ palette="sepia",
514
+ inked_frames=True, # the ground's hand-drawn frames and tone tiles
515
+ on_change=State.on_change, # the unique_id of the slide shown
516
+ )
517
+ ```
518
+
519
+ It works in two layers. The **skin** replaces TimelineJS's colours, type and rules with the
520
+ ground's `--sp-` properties: substrate, inks, EB Garamond, hairline rules, eras hatched by density,
521
+ the current marker heightened. The **hand** reads the ground's own frame and tone masks from hidden
522
+ probes and lays them on the markers, eras and menubar, so they are drawn with the same pieces as
523
+ the `Sp` components; `inked_frames=False` keeps the skin only, and `precision`, `cyanotype` and
524
+ forced colours fall back to exact rules by themselves. Note that TimelineJS requests its icon font
525
+ from a relative path (`/css/icons/tl-icons.*`); the Reflex dev server answers it with HTML, so the
526
+ browser logs font-decoding warnings. They come from TimelineJS, not from this package.
527
+
528
+ ![The Knight Lab timeline in silverpoint](docs/timeline.png)
529
+
530
+ ![The palettes page](docs/palettes.png)
531
+
353
532
  ## Interaction
354
533
 
355
534
  ```python
@@ -419,24 +598,45 @@ uv run reflex run
419
598
  Pages: **Start** (quickstart, provider, ink vs precision), **Gallery** (the 60 charts, ground
420
599
  controls, demo datasets vs data from Python state with a re-roll), **Playground** (one chart, every
421
600
  rendering choice and the Python that reproduces it), **Interaction** (events, custom readout, a
422
- volvelle that turns on click, a treemap and a sunburst that drill down together, live KPI/gauge/meter, SVG and geometry export), **Dashboard** (a
601
+ volvelle that turns on click, a treemap and a sunburst that drill down together, live
602
+ KPI/gauge/meter, SVG and geometry export), **Dashboard** (a
423
603
  linked operations dashboard fed from Python state with ground, substrate, mode and column controls, a
424
604
  KPI strip, and `dashboard_link` on its own), **UI components** (`/ui`: the components controlled from
425
605
  Python state with a native form submit, and the three reference panels of the upstream example apps
426
606
  in silverpoint ink, precision and cyanotype), one **reference page per chart** (`/chart/<slug>`) and
427
- 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`.
607
+ one per UI component (`/ui/<slug>`: every declared state on both grounds, usage and props). The
608
+ Gallery and Playground also get a ground control, for `cyanotype`, and a palette control.
609
+ New in 0.7: **More components** (`/components`: the 20 composed components wired to Python, with
610
+ ground, substrate, mode and palette controls and an event log), **Palettes** (`/palettes`: the
611
+ presets, a palette builder with colour pickers and `check_palette`, a coloured section) and
612
+ **Timeline** (`/timeline`: the Knight Lab timeline on every ground, mode and palette).
428
613
 
429
614
  ![Interaction page](docs/interaction.png)
430
615
 
431
616
  ## Development
432
617
 
433
618
  ```bash
434
- uv venv && uv pip install -e ".[dev]"
619
+ uv sync --extra dev
435
620
  uv run pytest
436
621
  uv run ruff check .
437
- uv run reflex component build # .pyi stubs + sdist and wheel in dist/
622
+ # Reflex 0.10 removed `reflex component build`: regenerate the .pyi stubs with the generator
623
+ # Reflex itself uses (plus this package's fixes), then build the sdist and wheel.
624
+ uv run python scripts/make_stubs.py
625
+ uv build
438
626
  ```
439
627
 
628
+ Before committing, run the hooks of [`.pre-commit-config.yaml`](.pre-commit-config.yaml) (ruff check
629
+ and format — including the Python blocks of this README — file hygiene and `uv lock --check`):
630
+
631
+ ```bash
632
+ pre-commit install
633
+ pre-commit run --all-files
634
+ ```
635
+
636
+ Changes per version are in [CHANGELOG.md](CHANGELOG.md); the guide for coding agents is
637
+ [AGENTS.md](AGENTS.md). Releases are published to PyPI by pushing a `vX.Y.Z` tag on `main` that
638
+ matches `version` in `pyproject.toml`.
639
+
440
640
  ## License
441
641
 
442
642
  MIT. silverpoint is MIT; the EB Garamond typeface is under the SIL Open Font License.
@@ -7,11 +7,58 @@ prepared ground, tone built from hatching, and white heightening on the live val
7
7
  The hand-drawn irregularity lives only in the ornament. The data geometry is exact, and every chart
8
8
  has a `precision` mode that turns the inking off.
9
9
 
10
- It wraps [`@silverpoint/react`](https://www.npmjs.com/package/@silverpoint/react) 0.6.0 and exposes
10
+ It wraps [`@silverpoint/react`](https://www.npmjs.com/package/@silverpoint/react) **0.7.0** and exposes
11
11
  **all 60 charts**, the **`Dashboard`** (a laid-out, linkable grid of charts), the **17 UI
12
- components** (buttons, inputs, tabs, cards, alerts…), the `SilverpointProvider`, both grounds
13
- (`silverpoint` and `cyanotype`), the interaction events, custom readouts and the imperative handle
14
- (SVG export and geometry) as Python.
12
+ components** (buttons, inputs, tabs, cards, alerts…), the **12 composed components** (table,
13
+ pagination, breadcrumb, avatar…), the **7 overlays** and the toaster (modal, drawer, popover,
14
+ tooltip, select, dropdown menu, toast), the **palettes**, the **Knight Lab timeline**, the
15
+ `SilverpointProvider`, both grounds (`silverpoint` and `cyanotype`), the interaction events, custom
16
+ readouts and the imperative handle (SVG export and geometry) as Python.
17
+
18
+ Everything it renders is an npm component of silverpoint, under its parity contract: the same
19
+ markup React, Vue and Angular render.
20
+
21
+ ### New in 0.7.1
22
+
23
+ - Wraps **`@silverpoint/react` 0.7.0** (0.7.0 wrapped 0.6.0). silverpoint 0.7 took this package's
24
+ palettes, composed components, overlays and timeline into the library itself, so they are now the
25
+ npm components, not Reflex-composed copies: same Python builders, the library's markup.
26
+ - **Palettes** are the npm `palette` prop: they merge element → dashboard → provider field by field,
27
+ `silverpoint_provider(palette=...)` works, and `silverpoint_palette(...)` is a provider with a
28
+ palette. `check_palette()` measures the core's nine contrast pairs (the focus ring and the white
29
+ heightening included); `"ironGall"` names the `iron_gall` preset too.
30
+ - **Composed components and overlays read `silverpoint_provider`**, as the `Sp` components do.
31
+ Overlays are a native `<dialog>` and the Popover API (no Radix); they render in place, so a
32
+ section's palette reaches them.
33
+ - **Logical sides**: `side="start"`/`"end"` and `position="bottom-end"`…; `left`/`right` still work
34
+ with a `DeprecationWarning`. `sp_drawer(size=)` is `extent=`, `sp_popover(side_offset=)` is
35
+ `offset=`; `sp_modal` gains `label` and `dismissible`, `sp_result`/`sp_descriptions`
36
+ `heading_level`.
37
+ - `sp_textarea(textarea_id=)` and `sp_input_number(input_id=)` are `id=` (deprecated aliases kept);
38
+ `sp_textarea` has no `on_blur`. `sp_collapse_item(on_toggle=)` receives the new open state (a bool).
39
+ - **`sp_timeline`** is the npm `SpTimeline`: TimelineJS is an npm dependency of that component, so the
40
+ `[timeline]` extra pulls in nothing any more (it is kept so existing installs keep working).
41
+ - `sort_rows()` follows the core's `uiSortRows` order (numbers first, then text by code point).
42
+
43
+ ### New in 0.7.0
44
+
45
+ - **Reflex 0.10.0**, and therefore **Python 3.11 or later** (Python 3.10 is no longer supported).
46
+ Reflex 0.10 removed `reflex component build`: stubs are regenerated with `scripts/make_stubs.py`.
47
+ - **Palettes** — `palette=` on every chart, UI component, dashboard and composed component,
48
+ `silverpoint_palette(...)` for a whole section, six presets named after drawing media
49
+ (`silverpoint`, `sanguine`, `sepia`, `iron_gall`, `verdigris`, `indigo`) and `check_palette()`
50
+ against the contrast thresholds of the data model. See [Palettes](#palettes).
51
+ - **Composed components, level A** (native markup): `sp_table` (+ `sort_rows`), `sp_pagination`,
52
+ `sp_breadcrumb`, `sp_avatar` (+ `sp_avatar_group`), `sp_statistic`, `sp_descriptions`,
53
+ `sp_timeline_list`, `sp_collapse` (+ `sp_collapse_item`), `sp_empty`, `sp_result`, `sp_textarea`
54
+ and `sp_input_number`.
55
+ - **Composed components, level B** (overlays on Radix primitives): `sp_modal`, `sp_drawer`,
56
+ `sp_popover`, `sp_tooltip`, `sp_select`, `sp_dropdown_menu` and `sp_toast` (+ `sp_toaster`), with
57
+ `sp_trigger` as their drawn button. See [Composed components](#composed-components).
58
+ - **`sp_timeline`** — Knight Lab TimelineJS drawn in silverpoint: a skin on the ground's colours and
59
+ type, plus the ground's own hand-inked frames and tone tiles on its markers, eras and buttons.
60
+ Optional extra (until 0.7.1): `pip install "reflex-silverpoint-react[timeline]"`. See [Timeline](#timeline).
61
+ - `sp_surface`, `sp_glyph`: the building blocks, for components of your own.
15
62
 
16
63
  ### New in 0.6
17
64
 
@@ -61,7 +108,7 @@ stylesheets it needs (`@silverpoint/grounds/styles.css` and the self-hosted EB G
61
108
  `@silverpoint/fonts/fonts.css`); the UI components also import `@silverpoint/grounds/ui.css`. No
62
109
  Tailwind, no CDN.
63
110
 
64
- Requires Reflex 0.9.12 or later (React 19).
111
+ Requires Reflex 0.10.0 or later (React 19) and Python 3.11 or later.
65
112
 
66
113
  ## Quickstart
67
114
 
@@ -324,6 +371,137 @@ rx.el.form(
324
371
  - Text inputs controlled from state make a round trip per keystroke; for long text, prefer
325
372
  `default_value` and read the value on submit.
326
373
 
374
+ ## Palettes
375
+
376
+ silverpoint never writes a colour into its drawing: every stroke and fill is painted by CSS through
377
+ the ground's `--sp-` custom properties. A palette sets them, so it re-colours without re-rendering.
378
+
379
+ ```python
380
+ from reflex_silverpoint_react import PALETTES, Palette, bar_chart, check_palette, silverpoint_palette, sp_button
381
+
382
+ bar_chart(title="Orders", palette="sanguine") # a preset
383
+ sp_button("Save", variant="primary", palette={"ink": "#2C6355"}) # a dict of fields
384
+ bar_chart(title="Orders", palette=State.palette) # a state var holding a dict
385
+
386
+ MINE = Palette(substrate="#F2E8DC", ink="#8A3A24", ink_secondary="#6A4A3A", text="#4A2216")
387
+ assert not check_palette(MINE) # [] when every field meets its contrast threshold
388
+
389
+ silverpoint_palette(dashboard(...), sp_card(...), palette="indigo") # a whole section
390
+ ```
391
+
392
+ Fields: `substrate`, `ink`, `ink_secondary`, `heighten`, `rule`, `grid`, `text`, `text_muted` and
393
+ `focus` (the UI focus ring). Unset fields keep the ground's own. Palettes merge field by field,
394
+ element → dashboard → provider, so an element's own `palette` wins over its section's. A palette is
395
+ **monochrome by design**: tone is built from hatch density (Art. 6), so a chart has two inks (`ink`
396
+ for the main series, `ink_secondary` for the second), never a colour per series. `precision` mode and
397
+ the system's high-contrast modes still apply on top. `silverpoint_palette(...)` is
398
+ `silverpoint_provider(palette=...)` around the section.
399
+
400
+ ## Composed components
401
+
402
+ silverpoint 0.7's composed components and overlays, the npm components of `@silverpoint/react/ui`:
403
+ native markup drawn by the core with the ground's hand-inked frames, hatched tones and
404
+ heightening, exactly as the `Sp` components are. Like them they read `silverpoint_provider` (and
405
+ the dashboard they sit in); a prop on the component always wins.
406
+
407
+ ```python
408
+ from reflex_silverpoint_react import sort_rows, sp_pagination, sp_table
409
+
410
+ sp_table(
411
+ [
412
+ {"key": "team", "title": "Team", "sortable": True},
413
+ {"key": "load", "title": "Load", "align": "end", "sortable": True},
414
+ ],
415
+ State.rows,
416
+ caption="On-call teams",
417
+ sort_key=State.sort_key,
418
+ sort_order=State.sort_order,
419
+ on_sort=State.sort, # receives the key; sort with sort_rows(rows, key, order)
420
+ striped=True,
421
+ )
422
+ sp_pagination(total=240, current=State.page, on_change=State.set_page, show_total=True)
423
+ ```
424
+
425
+ | Composed (native markup) | |
426
+ |---|---|
427
+ | `sp_table` | Card-framed table: small-caps header, tabular figures, hatched striping, sortable headers with `aria-sort` |
428
+ | `sp_pagination` | Previous/next, first/last, a window around the current page (heightened); `on_change(page)` |
429
+ | `sp_breadcrumb` | `<nav>` of links; the last item is the current page |
430
+ | `sp_avatar`, `sp_avatar_group` | Portrait or initials in a drawn round (or square) frame |
431
+ | `sp_statistic` | Small-caps title, large tabular figure, prefix/suffix, trend arrow |
432
+ | `sp_descriptions` | Label–value grid (`<dl>`), optionally card-framed |
433
+ | `sp_timeline_list` | Vertical list: `done` (hatched), `current` (heightened), `pending`, `error` |
434
+ | `sp_collapse`, `sp_collapse_item` | Native `<details>`; `accordion=True` keeps one open |
435
+ | `sp_empty`, `sp_result` | Empty state; outcome with a drawn round mark |
436
+ | `sp_textarea`, `sp_input_number` | On the `SpInput` contract; `on_change` receives the value (text or number) |
437
+
438
+ | Overlays (`<dialog>`, Popover API) | |
439
+ |---|---|
440
+ | `sp_modal`, `sp_drawer` | Dialog on a card frame over a hatched backdrop; drawer from any edge |
441
+ | `sp_popover`, `sp_tooltip` | Anchored content; tooltip on hover or keyboard focus |
442
+ | `sp_select` | Single choice with typeahead; the chosen option ticked, the highlighted one heightened |
443
+ | `sp_dropdown_menu` | Commands with shortcuts, separators and labels; `on_select(key)` |
444
+ | `sp_toast`, `sp_toaster` | Notices that stack in a corner; `error`/`warning` are announced assertively |
445
+
446
+ Behaviour is the platform's: `showModal()` for the modal and the drawer (focus stays inside, Escape
447
+ and the backdrop close it unless `dismissible=False`), the Popover API for the rest (light
448
+ dismiss), keyboard and placement from `@silverpoint/core` (APG listbox and menu, typeahead, flip and
449
+ shift). Overlays render in place (the top layer, no portal), so a section's palette reaches them.
450
+ Sides are logical (`start`/`end`) and mirror in right-to-left text. An overlay clones its `trigger`
451
+ with its ARIA and a toggling click, so the trigger must keep the props it is given: a native
452
+ `rx.el.button`, or `sp_trigger(...)`, the drawn button strings become (`sp_button` drops them in
453
+ silverpoint 0.7.0). `sp_trigger` does not read the provider: give it `ground`, `substrate`, `mode`
454
+ and `palette`.
455
+
456
+ ```python
457
+ sp_modal(
458
+ rx.el.p("Apply the new ground?"),
459
+ trigger="Open",
460
+ title="Apply changes",
461
+ footer=sp_trigger("Apply", variant="primary", on_click=State.confirm),
462
+ open=State.modal_open,
463
+ on_open_change=State.set_modal_open,
464
+ )
465
+ sp_select(["North", "East", "South", "West"], value=State.region, on_change=State.set_region)
466
+ sp_toaster(sp_toast("Saved", State.text, kind="success", open=State.toast_open, on_open_change=State.set_toast_open))
467
+ ```
468
+
469
+ ![Composed components](docs/components.png)
470
+
471
+ ## Timeline
472
+
473
+ The npm `SpTimeline` of `@silverpoint/react/timeline`. TimelineJS (`@knight-lab/timelinejs` 3.9.13)
474
+ is an npm dependency of this component: Reflex installs it when a page uses `sp_timeline`, and no
475
+ Python extra is needed. If it cannot be loaded, the component warns `SP025` and renders `fallback`.
476
+
477
+ ```python
478
+ from reflex_silverpoint_react import sp_timeline
479
+
480
+ sp_timeline(
481
+ DATA, # TimelineJS data: title, events, eras (or any object with to_dict())
482
+ height=560,
483
+ ground="silverpoint",
484
+ substrate="cream",
485
+ mode="ink",
486
+ palette="sepia",
487
+ inked_frames=True, # the ground's hand-drawn frames and tone tiles
488
+ on_change=State.on_change, # the unique_id of the slide shown
489
+ )
490
+ ```
491
+
492
+ It works in two layers. The **skin** replaces TimelineJS's colours, type and rules with the
493
+ ground's `--sp-` properties: substrate, inks, EB Garamond, hairline rules, eras hatched by density,
494
+ the current marker heightened. The **hand** reads the ground's own frame and tone masks from hidden
495
+ probes and lays them on the markers, eras and menubar, so they are drawn with the same pieces as
496
+ the `Sp` components; `inked_frames=False` keeps the skin only, and `precision`, `cyanotype` and
497
+ forced colours fall back to exact rules by themselves. Note that TimelineJS requests its icon font
498
+ from a relative path (`/css/icons/tl-icons.*`); the Reflex dev server answers it with HTML, so the
499
+ browser logs font-decoding warnings. They come from TimelineJS, not from this package.
500
+
501
+ ![The Knight Lab timeline in silverpoint](docs/timeline.png)
502
+
503
+ ![The palettes page](docs/palettes.png)
504
+
327
505
  ## Interaction
328
506
 
329
507
  ```python
@@ -393,24 +571,45 @@ uv run reflex run
393
571
  Pages: **Start** (quickstart, provider, ink vs precision), **Gallery** (the 60 charts, ground
394
572
  controls, demo datasets vs data from Python state with a re-roll), **Playground** (one chart, every
395
573
  rendering choice and the Python that reproduces it), **Interaction** (events, custom readout, a
396
- volvelle that turns on click, a treemap and a sunburst that drill down together, live KPI/gauge/meter, SVG and geometry export), **Dashboard** (a
574
+ volvelle that turns on click, a treemap and a sunburst that drill down together, live
575
+ KPI/gauge/meter, SVG and geometry export), **Dashboard** (a
397
576
  linked operations dashboard fed from Python state with ground, substrate, mode and column controls, a
398
577
  KPI strip, and `dashboard_link` on its own), **UI components** (`/ui`: the components controlled from
399
578
  Python state with a native form submit, and the three reference panels of the upstream example apps
400
579
  in silverpoint ink, precision and cyanotype), one **reference page per chart** (`/chart/<slug>`) and
401
- 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`.
580
+ one per UI component (`/ui/<slug>`: every declared state on both grounds, usage and props). The
581
+ Gallery and Playground also get a ground control, for `cyanotype`, and a palette control.
582
+ New in 0.7: **More components** (`/components`: the 20 composed components wired to Python, with
583
+ ground, substrate, mode and palette controls and an event log), **Palettes** (`/palettes`: the
584
+ presets, a palette builder with colour pickers and `check_palette`, a coloured section) and
585
+ **Timeline** (`/timeline`: the Knight Lab timeline on every ground, mode and palette).
402
586
 
403
587
  ![Interaction page](docs/interaction.png)
404
588
 
405
589
  ## Development
406
590
 
407
591
  ```bash
408
- uv venv && uv pip install -e ".[dev]"
592
+ uv sync --extra dev
409
593
  uv run pytest
410
594
  uv run ruff check .
411
- uv run reflex component build # .pyi stubs + sdist and wheel in dist/
595
+ # Reflex 0.10 removed `reflex component build`: regenerate the .pyi stubs with the generator
596
+ # Reflex itself uses (plus this package's fixes), then build the sdist and wheel.
597
+ uv run python scripts/make_stubs.py
598
+ uv build
412
599
  ```
413
600
 
601
+ Before committing, run the hooks of [`.pre-commit-config.yaml`](.pre-commit-config.yaml) (ruff check
602
+ and format — including the Python blocks of this README — file hygiene and `uv lock --check`):
603
+
604
+ ```bash
605
+ pre-commit install
606
+ pre-commit run --all-files
607
+ ```
608
+
609
+ Changes per version are in [CHANGELOG.md](CHANGELOG.md); the guide for coding agents is
610
+ [AGENTS.md](AGENTS.md). Releases are published to PyPI by pushing a `vX.Y.Z` tag on `main` that
611
+ matches `version` in `pyproject.toml`.
612
+
414
613
  ## License
415
614
 
416
615
  MIT. silverpoint is MIT; the EB Garamond typeface is under the SIL Open Font License.