reflex-silverpoint-react 0.1.0__tar.gz → 0.3.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 (27) hide show
  1. reflex_silverpoint_react-0.3.0/PKG-INFO +379 -0
  2. reflex_silverpoint_react-0.3.0/README.md +353 -0
  3. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react/__init__.py +125 -2
  4. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react/base.py +16 -9
  5. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react/base.pyi +86 -82
  6. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react/catalog.py +12 -2
  7. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react/charts.pyi +1000 -932
  8. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react/dashboard.py +240 -0
  9. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react/dashboard.pyi +314 -0
  10. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react/ui.py +573 -0
  11. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react/ui.pyi +1687 -0
  12. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react/ui_catalog.py +330 -0
  13. reflex_silverpoint_react-0.3.0/custom_components/reflex_silverpoint_react.egg-info/PKG-INFO +379 -0
  14. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react.egg-info/SOURCES.txt +5 -0
  15. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/pyproject.toml +3 -3
  16. reflex_silverpoint_react-0.3.0/tests/test_components.py +229 -0
  17. reflex_silverpoint_react-0.1.0/PKG-INFO +0 -224
  18. reflex_silverpoint_react-0.1.0/README.md +0 -198
  19. reflex_silverpoint_react-0.1.0/custom_components/reflex_silverpoint_react.egg-info/PKG-INFO +0 -224
  20. reflex_silverpoint_react-0.1.0/tests/test_components.py +0 -84
  21. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/LICENSE +0 -0
  22. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react/charts.py +0 -0
  23. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react/helpers.py +0 -0
  24. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react.egg-info/dependency_links.txt +0 -0
  25. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react.egg-info/requires.txt +0 -0
  26. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/custom_components/reflex_silverpoint_react.egg-info/top_level.txt +0 -0
  27. {reflex_silverpoint_react-0.1.0 → reflex_silverpoint_react-0.3.0}/setup.cfg +0 -0
@@ -0,0 +1,379 @@
1
+ Metadata-Version: 2.4
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
5
+ Author-email: Ernesto Crespo <ecrespo@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/ecrespo/reflex-silverpoint-react
8
+ Project-URL: Source, https://github.com/ecrespo/reflex-silverpoint-react
9
+ Project-URL: Issues, https://github.com/ecrespo/reflex-silverpoint-react/issues
10
+ Project-URL: Upstream, https://github.com/ecrespo/silverpoint
11
+ Keywords: reflex,reflex-custom-components,charts,silverpoint,data-visualization,svg,ui-components
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Scientific/Engineering :: Visualization
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Requires-Dist: reflex>=0.9.12
20
+ Provides-Extra: dev
21
+ Requires-Dist: build; extra == "dev"
22
+ Requires-Dist: twine; extra == "dev"
23
+ Requires-Dist: pytest; extra == "dev"
24
+ Requires-Dist: ruff; extra == "dev"
25
+ Dynamic: license-file
26
+
27
+ # reflex-silverpoint-react
28
+
29
+ A [Reflex](https://reflex.dev) custom component for **[silverpoint](https://github.com/ecrespo/silverpoint)**:
30
+ charts drawn in the manner of a Renaissance silverpoint drawing, with a fine silver line on a
31
+ prepared ground, tone built from hatching, and white heightening on the live value.
32
+
33
+ The hand-drawn irregularity lives only in the ornament. The data geometry is exact, and every chart
34
+ has a `precision` mode that turns the inking off.
35
+
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
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.
41
+
42
+ ### New in 0.3
43
+
44
+ - **17 UI components**, drawn as the charts are: `sp_button`, `sp_input`, `sp_checkbox`,
45
+ `sp_switch`, `sp_radio_group`, `sp_slider`, `sp_rate`, `sp_segmented`, `sp_tabs` (with
46
+ `sp_tab_panel`), `sp_steps`, `sp_card`, `sp_tag`, `sp_badge`, `sp_divider`, `sp_progress`,
47
+ `sp_alert` and `sp_skeleton`. Native controls underneath, controlled from Python. See
48
+ [UI components](#ui-components).
49
+ - `UI_COMPONENTS` and `UI_DEMOS`: the catalog's 17 components, their 45 reference states, and
50
+ `ui_demo(slug, state)` to render any of them.
51
+ - `substrate="prussian"` is accepted everywhere (the `cyanotype` ground's substrate).
52
+
53
+ ### New in 0.2
54
+
55
+ - **`dashboard`**, **`dashboard_cell`** and **`dashboard_link`**: a titled grid of cards laid out from
56
+ a data-only layout, charts sized to their cells, and charts linked on a datum field.
57
+ - **The `cyanotype` ground**: a white line on Prussian blue. Tone is the weight of an exact line, so
58
+ nothing is hatched. Use `ground="cyanotype"` on a chart, the provider or a dashboard.
59
+
60
+ ![The gallery of the demo app](docs/gallery.png)
61
+
62
+ ## Installation
63
+
64
+ ```bash
65
+ pip install reflex-silverpoint-react
66
+ # or
67
+ uv add reflex-silverpoint-react
68
+ ```
69
+
70
+ Nothing else to do on the JavaScript side: Reflex installs `@silverpoint/react`,
71
+ `@silverpoint/core`, `@silverpoint/grounds` and `@silverpoint/fonts`, and every chart imports the two
72
+ stylesheets it needs (`@silverpoint/grounds/styles.css` and the self-hosted EB Garamond of
73
+ `@silverpoint/fonts/fonts.css`); the UI components also import `@silverpoint/grounds/ui.css`. No
74
+ Tailwind, no CDN.
75
+
76
+ Requires Reflex 0.9.12 or later (React 19).
77
+
78
+ ## Quickstart
79
+
80
+ ```python
81
+ import reflex as rx
82
+ from reflex_silverpoint_react import line_chart
83
+
84
+ DATA = [
85
+ {"hour": "00", "hits": 18},
86
+ {"hour": "04", "hits": 11},
87
+ {"hour": "08", "hits": 42},
88
+ {"hour": "12", "hits": 64},
89
+ {"hour": "16", "hits": 57},
90
+ {"hour": "20", "hits": 30},
91
+ ]
92
+
93
+
94
+ def index() -> rx.Component:
95
+ return rx.box(
96
+ line_chart(data=DATA, x_key="hour", value_key="hits", title="Hits per hour"),
97
+ width="480px",
98
+ )
99
+
100
+
101
+ app = rx.App()
102
+ app.add_page(index)
103
+ ```
104
+
105
+ The chart takes the width of its container; `height` is the height of the drawing area (160 px by
106
+ default). Omit `data` and a chart draws its own demo dataset.
107
+
108
+ Props are the React props in `snake_case`: `xKey` → `x_key`, `hatchFill` → `hatch_fill`,
109
+ `footerRight` → `footer_right`, `centerLabel` → `center_label`, and so on. `data` and every prop can
110
+ be a Reflex state var.
111
+
112
+ ## The 33 charts
113
+
114
+ | Family | Charts |
115
+ |---|---|
116
+ | Lines | `line_chart`, `step_chart`, `sparkline_rows`, `kpi_card` |
117
+ | Bars | `bar_chart`, `stacked_bar_chart`, `composed_chart`, `waterfall_chart`, `funnel_chart`, `bullet_chart`, `pyramid_chart`, `candlestick_chart` |
118
+ | Areas | `area_chart`, `range_band_chart`, `stream_chart` |
119
+ | Points & grids | `scatter_chart`, `bubble_chart`, `heatmap_chart`, `treemap_chart`, `activity_grid` |
120
+ | Flows | `sankey_chart`, `chord_ring` |
121
+ | 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` |
122
+
123
+ Every factory has a class of the same name in `PascalCase` (`LineChart`, `WindRose`…).
124
+ `reflex_silverpoint_react.CHARTS` is the whole catalog with each chart's family and the reference of
125
+ its own props (`COMMON_PROPS` holds the shared ones), handy for galleries and documentation.
126
+
127
+ ## Props every chart shares
128
+
129
+ | Prop | Default | |
130
+ |---|---|---|
131
+ | `data` | demo dataset | The rows to draw: a list of dicts. Without it, the accessor props (`*_key`, `keys`, `names`) are ignored. |
132
+ | `ground` / `substrate` / `mode` | `"silverpoint"` / `"cream"` / `"ink"` | Style. Grounds: `silverpoint` and `cyanotype`. The `silverpoint` substrates are `cream`, `green`, `blue` and `ochre`; `cyanotype` has one, `prussian`, whatever substrate a chart names. `mode="precision"` turns the inking off. |
133
+ | `seed`, `id` | derived, stable | The hand drawing is deterministic: same props, same strokes. |
134
+ | `height`, `width` | `160`, container width | Size of the drawing area in px. |
135
+ | `chrome` | `"card"` | `"bare"` draws only the plot. |
136
+ | `title`, `badge`, `value`, `unit`, `footer_left`, `footer_right` | — | The card's text. |
137
+ | `label`, `description`, `data_table` | from `title`, —, `"hidden"` | Accessibility. |
138
+ | `locale`, `number_format` | environment | Number formatting (`number_format` is a dict of `Intl.NumberFormatOptions`). |
139
+ | `hatch_fill` | `"tile"` | `"per-shape"` gives richer hatching at a much greater weight. |
140
+ | `tooltip` | built-in readout | A custom readout; see `tooltip_template`. |
141
+ | `on_active_change`, `on_select` | — | Events; see below. |
142
+
143
+ ## One ground for the whole app
144
+
145
+ ```python
146
+ from reflex_silverpoint_react import bar_chart, donut_chart, silverpoint_provider
147
+
148
+ silverpoint_provider(
149
+ bar_chart(data=sales, x_key="month", value_key="units", title="Units sold", unit="units"),
150
+ donut_chart(data=channels, name_key="channel", value_key="share", title="Sales by channel", center_label="%"),
151
+ ground="silverpoint",
152
+ substrate="green",
153
+ locale="en-GB",
154
+ )
155
+ ```
156
+
157
+ A prop on a chart always wins over the provider. The provider's props can be state vars, so one
158
+ select can re-ground a whole dashboard.
159
+
160
+ ## Dashboards
161
+
162
+ `dashboard` lays charts out in a titled grid. The layout is plain data: the number of columns, each
163
+ cell's column and row spans (per breakpoint if you like), the row height and the gap. The
164
+ breakpoints are the dashboard's own width: `sm` below 640 px, `md` up to 1024 px, and `lg` above.
165
+ The defaults are 1, 2 and 4 columns. Each chart is sized to its cell, and `ground`, `substrate`,
166
+ `mode` and `locale` pass to every chart inside.
167
+
168
+ ```python
169
+ from reflex_silverpoint_react import (
170
+ bar_chart,
171
+ dashboard,
172
+ dashboard_cell,
173
+ dashboard_cell_layout,
174
+ dashboard_layout,
175
+ kpi_card,
176
+ line_chart,
177
+ )
178
+
179
+ dashboard(
180
+ dashboard_cell(kpi_card(title="Revenue", metric="thousands", delta=6.4), cell="revenue"),
181
+ dashboard_cell(line_chart(data=State.ops, x_key="hour", value_key="hits", title="Traffic"), cell="traffic"),
182
+ dashboard_cell(bar_chart(data=State.ops, x_key="hour", value_key="errors", title="Errors"), cell="errors"),
183
+ id="ops", # required
184
+ title="Operations", # or label=... for no visible heading
185
+ description="Service health over the last day.",
186
+ layout=dashboard_layout(
187
+ ["revenue", dashboard_cell_layout("traffic", col_span={"md": 2, "lg": 3}, row_span=2), "errors"],
188
+ columns={"sm": 1, "md": 2, "lg": 4},
189
+ row_height=240,
190
+ gap=16,
191
+ ),
192
+ link="hour", # link the charts on the rows' "hour" field
193
+ on_link_change=State.on_link, # {"key": "hour", "value": "18"}, or None when it clears
194
+ )
195
+ ```
196
+
197
+ - `dashboard_cell(chart, cell="id")` puts a chart in a named layout cell. Children without one follow
198
+ the named cells, in source order, with span 1.
199
+ - With `link`, pointing at or focusing an item in one chart marks every item in the other charts
200
+ that has the same value in that field. `dashboard_link(..., link="hour")` does the same for charts
201
+ you lay out yourself, outside a dashboard grid.
202
+ - `heading_level` (2-6) sets the title's heading level. `ssr_width` is the width the grid is laid
203
+ out for before the browser measures it.
204
+ - `dashboard_layout` and `dashboard_cell_layout` write the camelCase keys the component reads. You
205
+ can also pass a plain dict.
206
+ - The layout values and the charts' props can be state vars.
207
+
208
+ ## UI components
209
+
210
+ New in silverpoint 0.3: seventeen interface components with frames hand-drawn by each ground's own
211
+ inker and tone laid as hatching (`silverpoint`) or as the weight of an exact white line
212
+ (`cyanotype`). Each is a native control underneath (a `<button>`, an `<input>`, a `<fieldset>` of
213
+ radios), so forms submit natively and the keyboard follows the WAI-ARIA patterns. They are imported
214
+ from `@silverpoint/react/ui`.
215
+
216
+ ![The UI components in the demo app](docs/ui-components.png)
217
+
218
+ | Group | Components |
219
+ |---|---|
220
+ | Actions | `sp_button` |
221
+ | Data entry | `sp_input`, `sp_checkbox`, `sp_radio_group`, `sp_switch`, `sp_slider`, `sp_rate`, `sp_segmented` |
222
+ | Navigation | `sp_tabs` + `sp_tab_panel`, `sp_steps` |
223
+ | Data display | `sp_card`, `sp_tag`, `sp_badge`, `sp_divider` |
224
+ | Feedback | `sp_progress`, `sp_alert`, `sp_skeleton` |
225
+
226
+ ```python
227
+ from reflex_silverpoint_react import sp_button, sp_input, sp_switch, sp_tab_panel, sp_tabs, ui_item
228
+
229
+
230
+ class State(rx.State):
231
+ city: str = "Caracas"
232
+ precision: bool = False
233
+ view: str = "traffic"
234
+
235
+ @rx.event
236
+ def set_city(self, value: str): # on_change gets the value, not an event
237
+ self.city = value
238
+
239
+ @rx.event
240
+ def set_precision(self, value: bool):
241
+ self.precision = value
242
+
243
+ @rx.event
244
+ def set_view(self, value: str):
245
+ self.view = value
246
+
247
+ @rx.event
248
+ def save(self, form: dict):
249
+ print(form) # {"city": "Caracas", ...}: the native inputs submit under their name
250
+
251
+
252
+ rx.el.form(
253
+ sp_input(
254
+ label="City",
255
+ name="city",
256
+ value=State.city,
257
+ on_change=State.set_city,
258
+ invalid=State.city == "",
259
+ message="Required: pick a city",
260
+ ),
261
+ sp_switch(label="Precision", checked=State.precision, on_change=State.set_precision),
262
+ sp_tabs(
263
+ sp_tab_panel(line_chart(...), value="traffic"),
264
+ sp_tab_panel(bar_chart(...), value="errors"),
265
+ items=[ui_item("traffic", "Traffic"), ui_item("errors", "Errors")],
266
+ value=State.view,
267
+ on_change=State.set_view,
268
+ ),
269
+ sp_button("Save", type="submit", variant="primary"),
270
+ on_submit=State.save,
271
+ )
272
+ ```
273
+
274
+ - **Shared props**: `id`, `ground`, `substrate`, `mode`, `seed`, `size` (`sm`/`md`/`lg`) and
275
+ `class_name`. Like charts, they fall back to the dashboard, then to `silverpoint_provider`.
276
+ - **Values**: value components are controlled (`value=` / `checked=` with `on_change`) or
277
+ uncontrolled (`default_value=` / `default_checked=`). `on_change` receives the new value itself (a
278
+ string, a bool or a number), never a DOM event.
279
+ - **Items**: `ui_item(key, label, disabled=False)` for tabs, segmented and radio groups;
280
+ `step_item(key, title, description=None, status=None)` for steps.
281
+ - **Slots**: children are a button's or tag's text, a card's or alert's body; `sp_card` also takes
282
+ `extra` and `footer`, and `sp_input` takes `prefix` and `suffix` (components or text).
283
+ - **Close events**: `sp_tag(closable=True, on_close=...)` and `sp_alert(closable=True, on_close=...)`.
284
+ - `UI_COMPONENTS` is the catalog (group, declared states, props reference) and `UI_DEMOS` the 45
285
+ reference states upstream ships; `ui_demo("radio-group", "selected", ground="cyanotype")` renders
286
+ one, uncontrolled.
287
+ - Text inputs controlled from state make a round trip per keystroke; for long text, prefer
288
+ `default_value` and read the value on submit.
289
+
290
+ ## Interaction
291
+
292
+ ```python
293
+ class State(rx.State):
294
+ active: str = "—"
295
+
296
+ @rx.event
297
+ def on_active(self, item: dict | None):
298
+ self.active = "—" if item is None else f"{item['datum']['hour']}: {item['value']}"
299
+
300
+ @rx.event
301
+ def on_select(self, item: dict):
302
+ print("selected", item["datum"])
303
+
304
+
305
+ line_chart(
306
+ data=DATA,
307
+ x_key="hour",
308
+ value_key="hits",
309
+ on_active_change=State.on_active,
310
+ on_select=State.on_select,
311
+ tooltip=tooltip_template("{datum.hour} h · {value} hits"),
312
+ )
313
+ ```
314
+
315
+ - `on_active_change` receives the item under the pointer or keyboard focus, and `None` when it
316
+ leaves. `on_select` fires on click, `Enter` or `Space`. The item is
317
+ `{"seriesKey", "index", "datum", "value", "point": {"x", "y"}}`.
318
+ - `tooltip_template(text)` builds the `tooltip` render function from a format string. Placeholders:
319
+ `{heading}`, `{text}` (the built-in readout's two lines), `{announcement}`, `{value}`, `{index}`,
320
+ `{series}` and `{datum.<field>}`. `{{` and `}}` print literal braces.
321
+
322
+ ## Export: the imperative handle
323
+
324
+ Give a chart an `id` and its `ChartHandle` is reachable from Python:
325
+
326
+ ```python
327
+ from reflex_silverpoint_react import download_svg, get_geometry, get_svg
328
+
329
+ line_chart(id="hits", data=DATA, x_key="hour", value_key="hits")
330
+
331
+ rx.button("Download SVG", on_click=download_svg("hits", "hits.svg")) # in the browser
332
+ rx.button("SVG to Python", on_click=get_svg("hits", State.receive_svg)) # handler gets a str
333
+ rx.button("Geometry", on_click=get_geometry("hits", State.receive_geometry)) # handler gets a dict
334
+ ```
335
+
336
+ The exported SVG carries its own ground colours, so it renders the same outside the app.
337
+
338
+ ## Notes
339
+
340
+ - `volvelle_chart`: `index_ring` and `index_value` apply to your own rings, so pass `data` when you
341
+ use them (the demo dataset keeps its own index).
342
+ - `gauge_arc` and `meter_chart` take `percent` (0-100) instead of `data`.
343
+ - Charts switch to `precision` by themselves under `prefers-contrast: more` or
344
+ `forced-colors: active`; no prop overrides that.
345
+ - Accessors are field names (strings). The JavaScript API also accepts functions; from Python, shape
346
+ your rows instead.
347
+
348
+ ## Demo app
349
+
350
+ ```bash
351
+ uv venv && uv pip install -e .
352
+ cd silverpoint_react_demo
353
+ uv run reflex run
354
+ ```
355
+
356
+ Pages: **Start** (quickstart, provider, ink vs precision), **Gallery** (the 33 charts, ground
357
+ controls, demo datasets vs data from Python state with a re-roll), **Playground** (one chart, every
358
+ 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
360
+ linked operations dashboard fed from Python state with ground, substrate, mode and column controls, a
361
+ KPI strip, and `dashboard_link` on its own), **UI components** (`/ui`: the components controlled from
362
+ Python state with a native form submit, and the three reference panels of the upstream example apps
363
+ 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`.
365
+
366
+ ![Interaction page](docs/interaction.png)
367
+
368
+ ## Development
369
+
370
+ ```bash
371
+ uv venv && uv pip install -e ".[dev]"
372
+ uv run pytest
373
+ uv run ruff check .
374
+ uv run reflex component build # .pyi stubs + sdist and wheel in dist/
375
+ ```
376
+
377
+ ## License
378
+
379
+ MIT. silverpoint is MIT; the EB Garamond typeface is under the SIL Open Font License.