Skip to content

Data-bound chart components 2/8: typed figure handles - #462

Open
FarhanAliRaza wants to merge 3 commits into
stack/1-design-and-pinsfrom
stack/2-typed-handles
Open

Data-bound chart components 2/8: typed figure handles#462
FarhanAliRaza wants to merge 3 commits into
stack/1-design-and-pinsfrom
stack/2-typed-handles

Conversation

@FarhanAliRaza

@FarhanAliRaza FarhanAliRaza commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Stacked on #461. Base is stack/1-design-and-pins — the Files-changed tab shows only this layer.

Problem

Chart state vars carried a bare token string, so the component's source was untyped. reflex_xy.chart(Dash.points) — the wrong var — compiled fine and failed at hydrate as a blank mount with an err frame.

Change

Wrap the token in a frozen dataclass (handles.py: FigureHandle, plus DataHandle[S] for the tier above) and give the component a Var[FigureHandle] figure prop. The wrong var or a raw string now fails at create() — page evaluation — with the framework's own TypeError, before a browser is involved.

@reflex_xy.figure vars, register(), and inline() all return handles. The empty-token handle keeps the existing "not ready / no chart" sentinel, so the var type stays non-optional.

Two compile-time refusals come with it:

  • kernel-backed event props (on_point_hover/on_point_click/on_select_end) on a static src source now raise instead of silently never firing;
  • the positional live spellings chart(var) / chart(token_string) warn while routing to figure=.

chart(Chart) — the positional static form — is deliberately NOT deprecated. It's the only route for arbitrary Charts such as facet grids, and it predates no replacement.

Public helpers that take "a figure" (append, set_view, reset_view, select, clear_selection, release) accept a handle or its bare token for one release cycle.

The wrapper reduces figure and legacy token to one subscription token; nothing below the subscribe path changes.

Spec

reflex-integration.md §3.1 (handle-valued vars), §5 (figure= prop, deprecation shim, event refusal), file map.

Test plan

  • uv run pytest tests/reflex_adapter tests/test_validation_timing.py — 170 passed
  • pre-commit run --all-files, ruff check, ruff format --check, ty check — clean

Review in cubic

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3c294258-6052-4e38-865e-640fdb673681

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 5, 2026

Copy link
Copy Markdown

Greptile Summary

The PR replaces bare live-chart tokens with typed figure handles and adds a typed figure= component prop while retaining a one-release compatibility path.

  • Adds serialized FigureHandle and generic DataHandle value types.
  • Updates figure vars, registry helpers, and the React wrapper to pass and consume handles.
  • Rejects active kernel-backed handlers on static chart sources while permitting explicitly disabled handlers.
  • Updates the Reflex example, design specification, and adapter tests for the new API.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported static-chart rejection of explicitly disabled handlers is fixed and covered by a focused regression test.

Important Files Changed

Filename Overview
python/reflex_xy/component.py Adds the typed live-source path, compatibility routing, and static-event validation; the previous disabled-handler issue is fixed by removing None event props before validation.
python/reflex_xy/handles.py Introduces immutable serialized figure and data handles plus strict figure-token normalization.
python/reflex_xy/vars.py Changes synchronous and asynchronous figure vars from raw token strings to FigureHandle values while preserving the empty-token sentinel.
python/reflex_xy/assets/XYChart.jsx Normalizes the typed figure prop and legacy token prop into one live subscription token.
tests/reflex_adapter/test_component.py Covers typed figure props, compatibility warnings, static event refusal, and the explicitly disabled-handler regression.
spec/design/reflex-integration.md Updates the authoritative Reflex integration contract for typed handles, compatibility behavior, and static event validation.

Reviews (4): Last reviewed commit: "fix(reflex): review follow-ups on the ty..." | Re-trigger Greptile

Comment thread python/reflex_xy/component.py Outdated
@codspeed-hq

codspeed-hq Bot commented Aug 5, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 109 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing stack/2-typed-handles (3e98589) with stack/1-design-and-pins (c0ebb88)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 12 files

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread python/reflex_xy/assets/XYChart.jsx Outdated
Comment thread python/reflex_xy/handles.py Outdated
Comment thread python/reflex_xy/component.py Outdated
Comment thread python/reflex_xy/__init__.py Outdated
Comment thread tests/reflex_adapter/test_component.py Outdated
Comment thread spec/design/reflex-integration.md Outdated
Comment thread python/reflex_xy/component.py
Chart state vars carried a bare token string, so the component's source was
untyped: reflex_xy.chart(Dash.points) — the wrong var — compiled fine and
failed at hydrate as a blank mount with an err frame.

Wrap the token in a frozen dataclass (handles.py: FigureHandle, and
DataHandle[S] for the tier above this one) and give the component a
Var[FigureHandle] `figure` prop. The wrong var or a raw string now fails at
create(), which is page evaluation — the framework's own TypeError, before
a browser is involved. @reflex_xy.figure vars, register(), and inline() all
return handles; the empty-token handle keeps the existing "not ready / no
chart" sentinel, so the var type stays non-optional.

Two compile-time refusals come with it: kernel-backed event props
(on_point_hover/on_point_click/on_select_end) on a static src source now
raise instead of silently never firing, and the positional live spellings
chart(var) / chart(token_string) warn while routing to figure=. The static
positional chart(Chart) form is NOT deprecated — it remains the only route
for arbitrary Charts such as facet grids. Public helpers that take "a
figure" (append, set_view, reset_view, select, clear_selection, release)
accept a handle or its bare token for one release cycle.

The wrapper reduces `figure` and legacy `token` to one subscription token;
nothing below the subscribe path changes.

Spec: reflex-integration.md §3.1 (handle-valued vars), §5 (figure= prop,
deprecation shim, event refusal), file map.
@FarhanAliRaza
FarhanAliRaza force-pushed the stack/2-typed-handles branch from c42e175 to d0886d6 Compare August 5, 2026 14:51
Review follow-ups on the typed-handle seam:

- create() drops None-valued on_* props (explicitly disabled handlers)
  before validation, so on_point_hover=None compiles on every tier and
  the static-source kernel-event check tests values, not key presence.
- token_of() no longer accepts DataHandle: figure-only helpers (append,
  set_view, release, ...) fail immediately with TypeError instead of
  addressing a room that can never exist.
- release() raises on invalid input instead of silently degrading to
  registry.release("").
@FarhanAliRaza FarhanAliRaza changed the title Data-bound chart components 2/7: typed figure handles Data-bound chart components 2/8: typed figure handles Aug 6, 2026
@FarhanAliRaza

Copy link
Copy Markdown
Contributor Author

Review addressed in 3e98589:

  • create() now drops None-valued on_* props (explicitly disabled handlers) before validation, so on_point_hover=None compiles on every tier and the static-source check tests values, not key presence.
  • token_of() no longer accepts DataHandle: figure-only helpers (append, set_view, release, …) raise TypeError immediately.
  • release() raises on invalid input instead of degrading to registry.release("").

Pinned by test_component.py::test_explicitly_disabled_kernel_events_pass_on_static_source and test_registry.py::test_figure_only_helpers_reject_data_handles_and_junk; spec §5 updated.

masenf
masenf previously approved these changes Aug 6, 2026
- XYChart.jsx: a present figure handle always wins over the legacy token
  prop; its empty token is the "not ready" sentinel, never a fallback to
  a stale legacy spelling.
- The positional-string deprecation warning now says what actually works
  for a held bare token (figure=FigureHandle(token)) instead of pointing
  string sources at a prop that rejects raw strings.
- test_component anchors the token assertion to the figure prop itself so
  a regression to the legacy wire path is caught.
- reflex-integration.md §5 names the failure point create()/page
  evaluation, matching §3.1 instead of the looser 'at compile'.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants