Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion typescript/web_core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## Unreleased

- Fix `ResolveA2uiProp` resolving props declared as `Record<string, unknown>` (for example `z.record(z.unknown())`) to action thunks instead of their data type: every object type is assignable to the `{functionCall?: any}` member of `ActionLike`, so object types with a string index signature are now treated as data. [#2939](https://github.com/a2ui-project/a2ui/pull/2939)
- Add `ComponentNode.id`, a string unique across the document and stable for the node's lifetime, for renderers and components to use as a rendering key or as the base of DOM `id`s and accessibility references. [#2887](https://github.com/a2ui-project/a2ui/pull/2887)

- Universal elements accept an optional `node` (`A2uiWebComponentElement.node`): `A2uiLitElement` takes its `context` from it and passes each child its own node, and `renderA2uiNode` accepts a `ComponentNode`. `context` remains supported, so parents can move to nodes one at a time. [#2880](https://github.com/a2ui-project/a2ui/pull/2880)

- Expose `ComponentNode.context`, the context the resolver bound the node with (undefined on placeholders). [#2879](https://github.com/a2ui-project/a2ui/pull/2879)
Expand Down
12 changes: 11 additions & 1 deletion typescript/web_core/src/resolution/generic-binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,14 @@ type ActionLike =
| {event: {name: string; context?: Record<string, unknown>}}
| {functionCall: {call: string; catalogId?: string; args?: Record<string, unknown>}};

/**
* Evaluates to true for object types with a string index signature, such as
* `Record<string, unknown>`. Every object type is assignable to the weak
* `{functionCall?: any}` member of `ActionLike`, so these are checked
* separately: they carry data, not an action.
*/
type HasStringIndex<T> = string extends keyof T ? true : false;

/** Evaluates to true if type T can contain a dynamic binding. */
type IsDynamic<T> = DataBinding extends NonNullable<T> ? true : false;

Expand All @@ -316,7 +324,9 @@ export interface ResolvedChildRef {
* For example, an `Action` object becomes a callable `() => Promise<void>` function.
*/
export type ResolveA2uiProp<T> = [NonNullable<T>] extends [ActionLike]
? (() => Promise<void>) | Extract<T, undefined>
? HasStringIndex<NonNullable<T>> extends true
? Exclude<T, DynamicTypes>
: (() => Promise<void>) | Extract<T, undefined>
: [NonNullable<T>] extends [ChildList]
? (string | ResolvedChildRef)[] | Extract<T, undefined>
: Exclude<T, DynamicTypes> extends never
Expand Down
Loading