Repository navigation
feat(a2ui_flutter): add the v1.0 examples to the gallery - #3620
Closed
andrewkolos wants to merge 196 commits into
Closed
andrewkolos wants to merge 196 commits into
andrewkolos wants to merge 196 commits into
Conversation
a2ui_explorer is the renderer's gallery app, as section 8 of the framework adapter blueprint describes. It lists the v0.9 basic catalog examples, steps through each one's messages with Advance, Run all and Reset, and shows each surface next to its live data model and the actions and errors it reports. A demo catalog adds the custom components the examples name. Its integration tests drive the examples through static rendering, layout, two-way binding, reactive updates and action context inside a template.
🤖 Agent-generated
#3194 renamed A2uiClientError to A2uiRendererError and MessageProcessor.groupModel to model, and replaced EventSource.addListener with subscribe, so the gallery no longer analyzed against main. The demo catalog also passes the basic catalog's definitions, which the generated component schemas reference as #/$defs/CatalogComponentCommon. Without them every example failed to resolve its schemas and rendered nothing.⚠️ Agent-generated
⚠️ Agent-generated
Same ignore line #3249 added to a2ui_flutter. Pull request CI runs Flutter stable only, but pushes to main also run beta, where the material.dart import is reported as deprecated.⚠️ Agent-generated
⚠️ Agent-generated
copyWith keeps the basic catalog's protocol version, title, description and instructions, which the hand-built catalog left out.⚠️ Agent-generated
DataModel.subscribe already skips the current value when it is subscribed to, so the data model view no longer needs its own flag for that. ExampleRun.dispose now disposes the whole message processor, not only its surface group, as its doc says.⚠️ Agent-generated
…tions An example name or description with a newline or carriage return put a raw line break inside a single-quoted literal, which does not compile.⚠️ Agent-generated
flutter_markdown_plus styles links as tappable and shows a click cursor over them, but does nothing on a tap without onTapLink. The Markdown builder now opens the link with url_launcher.⚠️ Agent-generated
…indow - Each run gets new Messages, Data Model and Action Log lists, so a newly selected example opens at the top instead of keeping the last one's scroll offset. Only the lists are keyed by the run, so the Reset button keeps keyboard focus. - CustomGrid's stretched column of Expanded cells threw "BoxConstraints forces an infinite width" inside a horizontal List. It now limits itself to the screen's width there, as the basic catalog's components do. - The macOS window opens at 1280x800. The template's 800x600 window is narrower than the layout's 1120 pixel minimum, so the right column opened off-screen. The Native Grid test now checks the grid's two columns, and the Markdown test a heading's text.⚠️ Agent-generated
Each entry now shows the action or error as toJson gives it, so an action's time and an error's details appear, as in the TypeScript galleries. New tests cover the errors the processor throws, the errors a surface reports, and a deleteSurface message.⚠️ Agent-generated
The label rounded the value, so 0.3 showed as 0, while the data model, the basic Slider and the TypeScript galleries show 0.3. A move rounded to a whole number could also land outside fractional bounds, or let a slider from 0.2 to 0.8 write only its two bounds. A move now writes min plus a whole number of steps of 1, as far as max allows.⚠️ Agent-generated
…rately The gallery README now says the gallery is for protocol v0.9, that the log also holds the errors the message processor reports, and that the examples are generated because a Flutter build does not ship assets declared from outside the app's directory. The comments on the gallery's processor and on examples_test say each message is checked against the surface it leaves behind, which is what a2ui_core does, and list what those checks allow.⚠️ Agent-generated
scrollUntilVisible ends by jumping the list to the tile without a frame, so the app tests tapped the tile's old position and missed for 15 of the 44 examples, leaving the first example selected. They now pump before the tap. A new test runs every example through ExampleRun and renders its surfaces, failing on any logged error or exception. It catches a demo catalog that cannot process the examples, and errors raised while they build, without opening each example in the app. The generator test also covers a backslash.⚠️ Agent-generated
Expanded takes a key itself, so the KeyedSubtree around it added nothing.⚠️ Agent-generated
assets/examples is a link to the specification's v0.9 basic catalog examples, and the app loads them from its asset bundle at startup. This replaces the generated copy in examples.g.dart and the tool that had to be rerun whenever an example changed. A test checks that the bundle holds every specification example.⚠️ Agent-generated
⚠️ Agent-generated
⚠️ Agent-generated
…queue SurfaceModel.dispatchError and dispatchWarning now put the report in a FIFO queue and return once it is queued. The queue hands reports to listeners in a microtask, never inside the call that found them, so a listener may change framework state directly. SurfaceGroupModel owns one queue for its surfaces and exposes onError and onWarning, which receive every surface's reports after that surface's own listeners. addSurface moves a surface's undelivered reports into the group's queue, detachSurface holds them until the surface is added again, and deleteSurface and SurfaceModel.dispose drop them. SurfaceModel.onReportsDelivered fires after a delivery that included the surface's reports. A listener that throws no longer stops later reports. Its error goes to the current zone's uncaught-error handler, or is printed in the root zone. An error that no listener receives is printed, and an unheard warning is logged at FINE. Tests that read reports right after building a resolver, changing data or evaluating an expression now wait for the delivery. Disposing a resolver inside a listener no longer cancels the reports already queued.⚠️ Agent-generated
MessageProcessor takes onError and onWarning beside onAction, and subscribes them to the group's events of the same name, so an app can set one listener for every surface before the first message. processMessages and processMessagesAsync open a delivery scope around the synchronous application of each message. Errors and warnings that mounted resolvers report while a message is applied reach their listeners when that message ends, before the next message and before an exception from a later message propagates. A report found inside processMessages is therefore seen right after it returns, as before the queue, also when the same payload deletes the surface afterwards. processMessages called from a listener delivers after that listener returns. Problems in a message still throw. The resolver test that read a report right after processMessages no longer waits for a microtask.⚠️ Agent-generated
NodeResolver no longer keeps its own queues of errors and warnings, its fallback microtask or its discard on dispose and on a failed update. It dispatches each diagnostic to the surface as it finds it, so the surface's queue delivers it after the resolver call returns and disposing the resolver drops nothing. The per-resolver deduplication of unknown types and cycles is unchanged. The note about a deeper unresolved ChildList is logged where it is found. The constructor, updates and dispose of a resolver, and every catalog function call in DataContext, run under a resolution guard. While it is open, a processMessages that ends a message defers its delivery to a microtask, so no listener runs inside resolver work or a catalog function. Tests that pinned the dropped behaviour now expect an unchanged-null expression error to arrive after disposal, a failed update to deliver what it found once, and the unresolved-reference warning to be logged before the root is published.⚠️ Agent-generated
A2uiSurface builds its resolver as before, and the diagnostics it finds now reach the surface's and the processor's listeners after the build, so a listener may call setState directly. While it is mounted, the widget requests a frame from SurfaceModel.onReportsDelivered, so a host that defers its setState to a frame callback gets that frame. error_listener_set_state_test.dart, carried from the superseded fix branch, covers a processor listener and a surface listener. New tests cover a deferring host whose surface mounts after the app settles, a jump through a list that builds and drops surfaces, and a mounted surface updated and deleted in one payload.⚠️ Agent-generated
…e README listener The a2ui_core CHANGELOG lists the breaking changes to error and warning delivery and the new processor, group and surface events. The a2ui_flutter CHANGELOG records that listeners may call setState and that the widget requests a frame after delivery, and that it needs the next a2ui_core release. The README Quick Start subscribes one error listener on the processor's group model next to the action listener, instead of one per surface in onSurfaceCreated. It passes decoded JSON to processMessages and a version to getRendererDataModel. The advice to defer a setState caused by an error listener is replaced by: listeners call setState directly, or schedule a frame if they defer.⚠️ Agent-generated
…alone drop A node's destruction listener that calls processMessages while NodeResolver.dispose runs no longer delivers inside dispose. Without the resolution guard around dispose that report arrived before dispose returned, and no test noticed. Disposing a standalone surface drops its queued report. The detached variant could not show this, because a held report is never delivered either way. The new test observes the drop through the platform log, which would print an undelivered error.⚠️ Agent-generated
Six existing tests build a resolver over a surface whose unknown type or cycle they expect, with no error listener, so each run printed seven "A2UI error with no listener" lines. They now subscribe a listener that ignores the reports. The conformance harness does the same where it builds a resolver only to read the tree.⚠️ Agent-generated
attachProblemChannel, runInMessageScope and listenersOf are hidden from the package barrel. Marking them @internal also makes an import of them through lib/src from another package an analyzer warning.⚠️ Agent-generated
…iled updates The processMessages doc and the README say that processMessages called from a widget's build runs its listeners inside that build, and the doc says that a listener which deletes a surface or processes more messages changes what the later messages of the same payload see. The a2ui_core CHANGELOG records that a resolver update that throws now delivers what it found and keeps it deduplicated, and that the nested ChildList warning is logged when found. The processMessages doc and the CHANGELOG also say that a catalog function returning a signal runs its body when the result is read, so a processMessages call from that body during a data write delivers its reports inside the write. The NodeResolver class doc names data writes among the calls whose diagnostics are delivered after they return. ComponentContext's doc no longer says its default reporter dispatches immediately, and the A2uiSurface doc no longer ties delivery to the surface's own listeners.⚠️ Agent-generated
Add `expect_reports` and the layer 1 problem reporting actions to `conformance_schema.json`, and add the delivery timing, channel lifetime, and lazy evaluation cases (`T1` to `T10`, `X1` to `X4`, and `L1`) in `conformance/core/problems.yaml`.⚠️ Agent-generated
Add `problems_conformance_test.dart` to execute `conformance/core/problems.yaml` against `MessageProcessor`, `SurfaceGroupModel`, `SurfaceModel`, and `NodeResolver`.⚠️ Agent-generated
…ir validity `Catalog.invoke` has checked a function's resolved arguments against its argument schema since #2995, and the RPC layer added in #3086 shares that check through `argumentErrors`. The v1.0 validation rules (`required`, `regex`, `length`, `numeric`, `email`) return a ValidationResult, so `and`, `or` and `not` over them received an object json_schema_builder cannot read. It threw "Unknown JSON type", the binder reported EXPRESSION_ERROR, and a Button gated by such a check stayed disabled with valid data. The v1.0 basic catalog examples 09_login-form and 32_advanced-form-validator do this. A validation result bound from the data model, such as `{"valid": false}`, failed the DynamicBoolean schema check with EXPRESSION_ERROR. Rule 1 of the v1.0 protocol's "DynamicBoolean and CheckRule Coercion" says a DynamicBoolean that evaluates to a validation result stands for its `valid` boolean. `argumentErrors` now does this on a catalog for v1.0 or later: the arguments match when they do with each ValidationResult, and each object with a boolean `valid`, replaced by that boolean, at any depth. Any object with a boolean `valid` counts, because the protocol lets a validation result carry more properties. When the arguments fail with every replacement made, they are all checked again with none made. So an argument whose schema is an object, and which holds an object with a `valid` key, still matches, unless another value in the same call needs the replacement. When both checks fail, the errors reported are those of the check with none made. Only the check uses the replacement: the function receives each argument as it was resolved. The v1.0 `and`, `or` and `not` read their operands through `ValidationResult.validityOf`, so they work either way, and the v1.0 `formatNumber` and `formatCurrency` now read their DynamicBoolean `grouping` the same way, since a validation result can now reach it. Passing plain booleans to functions, as rule 1 also describes, would need the coercion directed by each argument's schema. On a v0.9 catalog nothing is replaced: the v0.9 `and`, `or` and `not` read a `{"valid": ...}` map as an object, so a check that let it stand for a boolean would pass an operand the function then reads as truthy. On every catalog a ValidationResult is checked as its JSON object rather than throwing, so an unsupported one is an argument error.⚠️ Agent-generated
…talog.dart The framework adapter blueprint (section 5) has an adapter export its v1.0 basic catalog from the primary catalog entry point and its v0.9 catalog from a `v0_9` subpath. This frees the primary entry point for the v1.0 catalog: `package:a2ui_flutter/basic_catalog.dart` moves to `package:a2ui_flutter/v0_9/basic_catalog.dart`, and its source to `lib/src/catalog/basic/basic_catalog_v0_9.dart`, so the v1.0 source can take the plain name as the v1.0 library does. Nothing else changes: the library exports the same `basicCatalog()`, `BasicComponents`, `A2uiMarkdown` and `A2uiMarkdownBuilder`. Section 1 of the blueprint describes such legacy entry points as aliases that re-export the root runtime. Here the runtime has always been a library of its own, `package:a2ui_flutter/a2ui_flutter.dart`, which is version-agnostic, and the catalog another. So the v0.9 path holds only the catalog, as `basic_catalog.dart` does, and a v0.9 app changes one import. The tests that exercise the v0.9 catalog import it from the new path. To port this onto a tree where `basic_catalog.dart` is already the v1.0 catalog, apply the moves by hand. Git would move that v1.0 library to the v0.9 path without a conflict, and would move the v1.0 source away from `lib/src/catalog/basic/basic_catalog.dart`, which conflicts where `basic_catalog_v0_9.dart` already exists. BREAKING CHANGE: `package:a2ui_flutter/basic_catalog.dart` no longer exists until the v1.0 catalog takes its place. Import the v0.9 catalog from `package:a2ui_flutter/v0_9/basic_catalog.dart`.⚠️ Agent-generated
`package:a2ui_flutter/basic_catalog.dart` now implements the v1.0 basic catalog: `basicCatalog()` carries the id, protocol version, functions, instructions and definitions of a2ui_core's `BasicCatalog.v1_0()`, and `BasicComponents` pairs each shared widget builder with its v1.0 component schema. This follows the framework adapter blueprint (section 5): one set of builders, and one catalog per protocol version with that version's schemas and core functions. This commit adds the v1.0 catalog and leaves the shared builders unchanged, so at this commit a v1.0 surface accepts TextField `placeholder`, Slider `steps` and Video `posterUrl` but ignores them, and its TextField still checks `validationRegexp`. Each has a commit of its own. A v1.0 `BasicComponents` exists, rather than reusing the v0.9 one with v1.0 schemas swapped in, because an app that builds a catalog of its own from basic components needs them checked against the v1.0 schemas. The v0.9 TextField schema ends in `unevaluatedProperties: false` and has no `placeholder`, so a v0.9 component would reject the v1.0 props. The v1.0 components are not wrapped in the v0.9 `BasicTheme`. v1.0 removed `theme` and `primaryColor`, and a2ui_core rejects a v1.0 `createSurface` that carries a theme, so the components use the app's Material theme as they find it. The module blueprint's "Theme ignored" test, which expects such a message to render, therefore does not apply, and the codebase blueprint records that. The test harness passes raw JSON to `processMessages`, which routes each message by its own `version`, so one harness serves both versions, and takes extra catalogs for mixed surfaces. The examples test renders all 43 v1.0 basic catalog examples, as well as the 44 v0.9 ones. Two of the v1.0 examples, 09_login-form and 32_advanced-form-validator, need the a2ui_core fix for validation results in function arguments. `test/v1_0_test.dart` covers a `createSurface` carrying its components and data, `@index`, `openUrl` running from a tap and refused from a binding, a failing check disabling a Button, a boolean `false` check, and a bound Icon `svgPath`. A custom catalog test renders a component from its own catalog, named by `catalogId`, beside the basic one. The README now starts from v1.0: - The host passes the agent's JSON to `processMessages` and gives the processor an `outboundListener`, which receives the `rendererFunctionResponse` to each `callRendererFunction` and each `callAgentFunction`. - The host sends `a2uiRendererCapabilities` and `a2uiRendererDataModel`, the v1.0 names, and disposes the processor. - Custom components go in a catalog of their own, with relative `common_types.json` references, and an agent without a2ui_core gets the catalog's document from `toJson()`. - Actions run as a user activation, so builders call them from gesture handlers. A Protocol v0.9 section covers the v0.9 import, custom v0.9 catalogs, and, for a host that serves both versions, the per-version envelopes, data model key and capabilities key, and the version that `getRendererDataModel` then needs. The codebase blueprint describes both entry points, both schema sources and the theme deviation. BREAKING CHANGE: `package:a2ui_flutter/basic_catalog.dart` returns as the v1.0 catalog under the same names. v0.9 code that still imports it compiles, but registers the v1.0 catalog, which its v0.9 surfaces do not name. Import the v0.9 catalog from `package:a2ui_flutter/v0_9/basic_catalog.dart`.⚠️ Agent-generated
…catalog v1.0 removed `TextField.validationRegexp` in favour of `checks` with the `regex` function (evolution guide, section 2.2). The v1.0 TextField schema has no `unevaluatedProperties: false`, so a2ui_core still accepts the property on a v1.0 surface. Only the builder can ignore it, and the shared builder enforced it on both versions: a v1.0 TextField carrying `validationRegexp` showed "Invalid format" for text the agent never asked to check. Both TextFields now build through a new private `_build`, which takes the pattern as a parameter. `buildTextField`, used by the v1.0 catalog, passes none and checks no pattern, while the TextField's `checks` still apply. `buildTextFieldV0_9`, used by the v0.9 catalog, passes `validationRegexp` as before.⚠️ Agent-generated
v1.0 adds a `placeholder` to TextField. The builder passes it to the field as `InputDecoration.hintText`, shown while the field is empty. When a field has a label, Material shows hint text only while the label floats above the field, and a resting label sits where the hint would be. TextField requires `label`, so with the label left to rest the placeholder would stay invisible until the field takes focus. While a placeholder is set, the label therefore always floats. The test checks the placeholder's opacity, which a check that it is merely built would miss. The shared builder reads `placeholder` on both versions. The v0.9 TextField schema ends in `unevaluatedProperties: false` and has no `placeholder`, so a2ui_core rejects it there.⚠️ Agent-generated
v1.0 adds `steps` to Slider, "the number of discrete divisions in the slider range", an integer of at least 1. With `steps`, the builder sets the Flutter Slider's `divisions` to it and writes the value on that grid as `min + range * k / steps`. Computing each value from the range, rather than adding `k` steps of `range / steps`, keeps more grid values exact: 10 steps over 0 to 1 give 0.3 rather than 0.30000000000000004. A value with no fraction is written as an int, as before. Any number of steps snaps. A large count costs nothing to draw, because Flutter's Slider leaves out tick marks closer than three tick widths (`slider.dart`, `adjustedTrackWidth / divisions! >= 3.0 * tickMarkWidth`). `steps` is ignored when the range is empty, which has nothing to divide, or too large for a double, which renders the slider disabled. Without `steps` nothing changes: a range that is a whole number from 2 to 1000 moves in steps of 1 and writes `min + (moved - min).round()`, and any other range moves continuously. A v0.9 test pins that path for a fractional `min`, which a shared step formula would turn into float noise. The shared builder reads `steps` on both versions, but the v0.9 Slider schema ends in `unevaluatedProperties: false` and has no `steps`, so a2ui_core rejects it there.⚠️ Agent-generated
v1.0 adds `posterUrl` to Video, an image "to display before the video plays". The media player shows an `http` or `https` poster in the video frame until playback starts. The poster covers the frame, whose ratio is a 16:9 placeholder until the video reports its own, so a poster of another ratio leaves no bars around it. Once the current media has been played, the frame shows the video, even when it is paused at 0:00 or paused before the first position update. A new URL starts over. Before the first play, the poster gives way to the video while the position is past 0:00, as after scrubbing, and returns if the position comes back to 0:00. When the video fails, the poster gives way to the failure frame, so the error shows in the frame as well as in the controls. A poster that fails to load counts as none: the frame stays empty until the video is ready, then shows the video's first frame, as it does without a poster. The shared builder reads `posterUrl` on both versions. The v0.9 Video schema ends in `unevaluatedProperties: false` and has no `posterUrl`, so a2ui_core rejects it there.⚠️ Agent-generated
… A2uiMarkdown renders it The v0.9, v0.9.1 and v1.0 basic catalog implementation guides ask a renderer that cannot render Text as Markdown to strip common Markdown markers. v1.0 Text has no heading variants, so models write headings as `#` lines, and 17 of the 43 v1.0 basic catalog examples do. Before, an app without an `A2uiMarkdown` showed the `#`, `**` and backticks as written. Every Text that no `A2uiMarkdown` renders now shows its text without the opening heading marker and one quote marker on each line, link and image syntax (keeping the link text or the image's alt text), bold, italic, strikethrough and code delimiters, and backslash escapes. That is a body Text without an `A2uiMarkdown` above it, a caption Text, and a v0.9 heading Text, the last two of which an `A2uiMarkdown` never renders. A body Text that is a single heading line also takes the style of that heading level, so v1.0 headings still look like headings. Level 6 takes the `h5` style, the smallest heading variant v0.9 has. Choices, since the text comes from the agent: - Every pattern is linear in the text. None backtracks over more than one line, and single `*` or `_` emphasis cannot contain its own marker. A test renders lines of about 50,000 characters of unclosed `[`, links, emphasis and heading spaces in under five seconds. Patterns of the usual shape take tens of seconds on them. - The text of code spans and backslash escapes is kept as written, so `` `**kwargs` `` and `\*` stay literal, while markers around a code span, as in `` **`config.yaml`** ``, are removed. - A one-line heading in a body Text also loses its closing `#` sequence, but only when whitespace precedes it, so `# Learn C#` keeps its `#`. Other Text keeps a closing sequence. - List, table and fence structure is not parsed: list markers and table pipes stay, and markers inside them, fences included, are stripped like any others. A heading line inside multi-line text loses its `#` but keeps the body style, since styling one line of a Text needs the rich text an `A2uiMarkdown` provides. - The stripping is best effort. An escaped backtick pair can still read as a code span, and a one-line body Text that is a `#` line indented four spaces still reads as a heading. The README describes this next to `A2uiMarkdown`.⚠️ Agent-generated
In v1.0 a check's condition can return a validation result with a `severity`. a2ui_core normalizes every check into `isValid`, `validationErrors` and `validationResults` on `node.props`: only a failure of `error` severity, which a check without a severity has, makes `isValid` false and fills `validationErrors`, while `validationResults` holds every failure, the `warning` and `info` ones too. The framework adapter blueprint (section 5) says the inputs SHOULD render failing `warning` and `info` results "as non-blocking hints styled by severity". `ComponentProps.validationResults` reads that list, and the docs of `isValid`, `validationErrors` and the Button builder now say they cover `error` severity only. Each basic input other than Button shows the message of the first failing `warning` or `info` check as a hint, only while it has no error: TextField and DateTimeInput as their decoration's helper text, and CheckBox, ChoicePicker and Slider as small text under the control. A hint does not block, so a Button stays enabled. Two departures from the blueprint, which the codebase blueprint records: - Warnings and info notes share one style rather than one each, because Material's color scheme has no warning role. - A Button shows no hint. Its only place for a message is the Tooltip it gets while a check fails with an error, and a Tooltip that came and went with a hint would remount the enabled button and drop its focus. The TypeScript web elements show no hints at all. No basic validation function produces a hint: the v0.9 ones return booleans, and the v1.0 ones return results without a severity, which count as errors. A check bound to a validation result object in the data model produces one on either version, since a2ui_core does not gate check normalization by version.⚠️ Agent-generated
Rule 1 of the v1.0 protocol's "DynamicBoolean and CheckRule Coercion"
says that whenever a DynamicBoolean, such as a boolean component
property, evaluates to a validation result, the renderer uses its
`valid` boolean. a2ui_core resolves the property to the result itself,
and `ComponentProps.asBoolean` read anything but a `bool` as null. In
the v1.0 basic catalog, a CheckBox `value` bound to a validation rule,
such as `{"@call": "required", ...}`, therefore read as unchecked.
`asBoolean`, and so `props.boolean`, now reads a ValidationResult, or a
map with a `valid` key, by its validity through
`ValidationResult.validityOf`, the rule a2ui_core's v1.0 `and`, `or`
and `not` use. Any other value that is not a `bool` still reads as
null.
The rule applies on both versions. `asBoolean` is static and has no
catalog version to gate on, and v0.9 gives an object in a boolean
property no meaning, so reading one by its `valid` changes only payloads
whose v0.9 meaning is undefined. A v0.9 boolean property holding a
`{"valid": ...}` object read as null before. This differs from the v0.9
`and`, `or` and `not`, whose argument check rejects such an object.
The test relies on the `hide ValidationResult` import that the hints
commit added to `component_props_test.dart`, so a port that takes this
commit without that one needs the import as well.
⚠️ Agent-generated
v1.0 adds `live` ("off", "polite" or "assertive") and `hidden` (a
DynamicBoolean) to a component's `accessibility`. The framework adapter
blueprint (section 3) asks for the attributes to be mapped in one place
per adapter, such as the node dispatcher, so custom components get them
too. NodeView already put `label` and `description` on a Semantics node
around each resolved component, and now maps the other two there:
- `polite` and `assertive` make that node a live region. Flutter's
`Semantics.liveRegion` is a single flag with no assertive level, so
both announce politely. `off`, or no `live`, sets no flag at all,
which leaves the semantics of every other component as it was.
- A `hidden` that reads as true excludes the component and its whole
subtree from semantics, as `aria-hidden` does. A bound `hidden`
follows the data through the a2ui_core binding fix for
`accessibility.hidden`, and one set by a validation rule reads by its
validity through `ComponentProps.asBoolean`.
The semantics widgets stay in the tree whatever the attributes are, so
changing one keeps the subtree's state.
The mapping applies on both versions. v0.9 defines neither attribute,
but a v0.9 payload that writes one as a literal gets it. A bound
`hidden` on a v0.9 basic component is not resolved, since the v0.9
ComponentCommon schema has no `hidden`.
Known limits:
- A live region announces changes to its own label. On a TextField the
region is the control's own node, so changes to its label are
announced, but not its typed value. On a Slider the region is a parent
node that takes in the label and value text above the control, and on
a CheckBox, ChoicePicker or Slider it takes in the check message below
the control, so changes to these are announced. A Button's child text
and a CheckBox's label sit in the control's own node below the region,
so their changes are not announced. The README says this.
- An explicit `accessibility.label` does not replace the label a
control takes from its own text, which the v1.0 protocol asks for. On
a Button, CheckBox or Slider, `label`, `description` and `live` land
on a parent node of the focusable control, and on a TextField or Text
the explicit label is joined to the widget's own label. This predates
v1.0 support, and replacing a label needs the controls to place it
themselves. The README and the codebase blueprint record it.
- An open Modal's content is drawn in the Overlay, outside the Modal's
subtree, so a `hidden` Modal hides its trigger but not its open
content.
With this commit the adapter covers the v1.0 sections of the framework
adapter blueprint, apart from the deviations the codebase blueprint
records, so the codebase blueprint now pins the blueprint's current
commit, b1dd650: the v1.0 alignment of b161f9b plus later edits that
only change paths.
⚠️ Agent-generated
…booleans in one pass `argumentErrors` tried the schema with each validation result swapped for its validity and, when that failed, again with none swapped, for a function whose argument schema takes an object that holds `valid`. No v1.0 function takes one. On v1.0 the single swapped pass now stands, and its errors are the errors.⚠️ Agent-generated
…arker list alone The fallback for a Text with no `A2uiMarkdown` protected code spans and backslash escapes behind sentinels and trimmed a heading's closing `#` run. Code delimiters and escape backslashes are now two more entries in the marker list, so a marker inside a code span is stripped too, and a closing `#` run stays in the heading text.⚠️ Agent-generated
⚠️ Agent-generated
…ject `argumentErrors` on a v1.0 catalog swapped every `ValidationResult`, and every object with a boolean `valid`, for that boolean before the schema check, so a function taking an `object` argument that held `valid`, or a `ValidationResult` itself, failed the check with EXPRESSION_ERROR, "Value `true` is not of type `object`". The check now leaves arguments as their JSON and instead widens the function's resolved argument schema, once per catalog and function, so that on v1.0 or later each boolean position also accepts an object with a boolean `valid`. A validation result still passes where a DynamicBoolean coerces it, and passes as itself where an object is expected.⚠️ Agent-generated
A Text that no A2uiMarkdown renders removed backslash escapes and code span backticks before the emphasis markers, so the text they protect was then stripped as markers: `\*not italic\*` showed as "not italic", and `__init__` in backticks as "init". Escaped characters and code span text are now hidden from the marker patterns as private-use characters and restored afterwards, so they show as written. A heading's closing sequence of #s, as in `## Heading ##`, showed after its text. A pattern that stays linear in the text now drops it, in a one-line Text and in the heading lines of a longer one.⚠️ Agent-generated
The snapped value was bounded by `max` alone, in each of the two stepping branches. A single `clamp(min, max)` on the stepped value says the same thing once, and holds the lower bound too, although a move cannot cross it: Flutter's Slider hands `onChanged` a value from `min` to `max`, and each branch adds a non-negative amount to `min`.⚠️ Agent-generated
⚠️ Agent-generated
…-gallery⚠️ Agent-generated
…-v1-example⚠️ Agent-generated
…ter-v1-gallery⚠️ Agent-generated
andrewkolos
force-pushed
the
feat/flutter-adapter-v1-example
branch
from
October 27, 2026 18:51
c7bceef to
50303e1
Compare
Collaborator
|
The diff here looks bigger than expected! I might wait for you to have a chance to merge some of the underlying PRs then take another look! |
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the v1.0 basic catalog examples to the gallery from #3094, which runs on the v1.0 adapter from #3619, and a v0.9 / v1.0 selector above the examples list, as the Lit, React and Angular explorers have.
Changes
example.dart: each example carries its protocol version.assets/examples/v0_9andassets/examples/v1_0link to each version's basic catalog examples.example_run.dart: each run's processor registers the demo catalog and the v1.0 basic catalog, and reads the messages at the example's version.explorer_app.dart: the selector. Switching versions opens the example of the same file name, or the version's first example.37_native-grid.json.Testing
The test that runs and renders every example now covers the 43 v1.0 examples as well. New widget tests switch to v1.0 and type into a v1.0 TextField bound to the data model, and switch away from an example that v1.0 lacks.
Pre-launch Checklist
One time:
For this PR:
I have updated the relevant CHANGELOG.md file.If my branch is on a fork, I have verified that scripts/e2e_test.sh passes.ℹ️ Initial text drafted by agent