Skip to content

Render gauges, charts and pulses; computed variables; formula functions; canvas previews - #83

Open
BuildCodelessly wants to merge 18 commits into
masterfrom
claude/eager-lamport-ceal5j
Open

BuildCodelessly wants to merge 18 commits into
masterfrom
claude/eager-lamport-ceal5j

Conversation

@BuildCodelessly

Copy link
Copy Markdown
Contributor

Summary

Runtime support for the model changes in Codelessly/CodelesslyAPI#48, found while recreating a factory-floor OEE dashboard in the editor. This PR is intended ONLY to add the rendering, evaluation and preview hooks below.

  • Gauge and chart rendering: PassiveGaugeWidget / GaugePainter and PassiveChartWidget / ChartPainter.
    • Tapping a chart selects a category and fires its changed trigger with ${value}.
  • Repeating and mirrored gradients: linear, radial and sweep.
  • Pulse: a node's pulse fades its opacity in a loop (PulseOpacity), applied in applyWidgetOpacity.
  • Computed variables: a ${= ...} variable reads as its formula's result, typed, in bindings, formulas, conditions and getVariableValue.
    • Results are cached until a variable they read changes, even transitively.
    • Bindings listen to those inputs. Cycles stop. SetVariable leaves computed variables alone.
  • Formula functions: obj, set, get, take, skip, indexOf, split, pad, concat, range, thousands, duration. All are documented in the formula help.
  • Design-canvas hooks:
    • VariablePreview.resolve(node, context) gives a list row's item to the editor's resolver.
    • Gauge, chart, progress bar and dropdown widgets take scopedValues, so a canvas can preview their bindings.

The changelog has an Unreleased section.

Checks run locally against the API PR (through a path override):

  • dart format: clean
  • flutter analyze: no issues
  • flutter test: 665 tests pass
  • example: flutter build web --wasm builds

Known Issues


Generated by Claude Code

claude added 18 commits October 23, 2026 16:46
PassiveGaugeTransformer paints GaugeNode dials (top-anchored, animated
value, zone colors, segments, ticks, labels in Google Fonts, target and
needle). PassiveChartTransformer paints bar, line and timeline charts
from the node's bound data, keeps a selected category, and fires changed
reactions with the tapped index as ${value}. Gradients honor the paint's
tile mode; a repeating linear gradient spans 1 / scale of the box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
A computed variable (its value is a formula) reads as the formula's
result, converted to its type, wherever a variable is read: bindings,
formulas, conditions and CodelesslyContext.getVariableValue. Results are
cached until the formula or a variable it reads (directly or through other
computed variables) changes, unless it reads item, index, screen and the
like. Whatever is bound to it listens to those variables too, so it stays
live. A cycle stops at the variable that started it. SetVariable leaves a
computed variable alone.

New formula functions: obj and set build and update maps, get reads a
field by a computed key, take and skip slice lists, indexOf finds an item,
split and pad handle clock times.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
… preview scoped values

VariablePreview.resolve(node, context) passes the row's IndexedItem to the
editor's scope resolver, so ${item...} text in row N shows row N.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
…iew values

concat(list, ...) joins lists (rule-raised alerts with stored ones),
range(n) counts, thousands(n, decimals) writes 17,402 and duration(min)
writes 6m / 2h 04m. PassiveProgressBarWidget takes scopedValues so the
design canvas can bind its value and color.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
…l opacity

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
…s and selection

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
A dialog keeps its canvas's design size, so a responsive dialog showed
whichever breakpoint the editor last left the canvas at. A canvas holding
a responsive layout now fills the space it is given.

A formula span that evaluates to empty text showed a placeholder on the
design canvas; it now shows nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
The triggers existed in the API but nothing fired them, so press and
hold (start on down, cancel on release) couldn't be built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
A one-line text field with a fixed height expanded to fill it, which
drops the line limit; Flutter only obscures one-line fields, so the
text showed. obscureText also reads a variable binding or condition,
so a show/hide toggle drives one field.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FeVQ6NCLHS9Vrfxhii4Mj8
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