@yschimke/livery-a2ui 0.0.0-stage → 0.12.0
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.
- package/README.md +194 -2
- package/dist/angular.d.ts +32 -0
- package/dist/angular.js +51 -0
- package/dist/api.d.ts +35 -0
- package/dist/api.js +35 -0
- package/dist/catalog.d.ts +18 -0
- package/dist/catalog.js +55 -0
- package/dist/cmp-player.d.ts +3 -0
- package/dist/cmp-player.js +125 -0
- package/dist/controller.d.ts +61 -0
- package/dist/controller.js +330 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +4 -0
- package/dist/livery-web/livery-livery-web.d.mts +75 -0
- package/dist/livery-web/livery-livery-web.import-object.mjs +370 -0
- package/dist/livery-web/livery-livery-web.js-builtins.mjs +52 -0
- package/dist/livery-web/livery-livery-web.mjs +104 -0
- package/dist/livery-web/livery-livery-web.wasm +0 -0
- package/dist/livery-web-compose/fonts/NotoSansSymbols2-OFL.txt +117 -0
- package/dist/livery-web-compose/fonts/NotoSansSymbols2-Regular.ttf +0 -0
- package/dist/livery-web-compose/fonts/README.md +8 -0
- package/dist/livery-web-compose/fonts/RobotoFlex-OFL.txt +93 -0
- package/dist/livery-web-compose/fonts/RobotoFlex.ttf +0 -0
- package/dist/livery-web-compose/livery-livery-web-compose.d.mts +60 -0
- package/dist/livery-web-compose/livery-livery-web-compose.import-object.mjs +653 -0
- package/dist/livery-web-compose/livery-livery-web-compose.js-builtins.mjs +52 -0
- package/dist/livery-web-compose/livery-livery-web-compose.mjs +89 -0
- package/dist/livery-web-compose/livery-livery-web-compose.wasm +0 -0
- package/dist/livery-web-compose/skiko.mjs +1118 -0
- package/dist/livery-web-compose/skiko.wasm +0 -0
- package/dist/livery.d.ts +165 -0
- package/dist/livery.js +87 -0
- package/dist/player.d.ts +2 -0
- package/dist/player.js +2 -0
- package/dist/react.d.ts +24 -0
- package/dist/react.js +36 -0
- package/node_modules/@js-joda/core/CHANGELOG.md +363 -0
- package/node_modules/@js-joda/core/CheatSheet.md +947 -0
- package/node_modules/@js-joda/core/LICENSE +34 -0
- package/node_modules/@js-joda/core/README.md +155 -0
- package/node_modules/@js-joda/core/bower.json +21 -0
- package/node_modules/@js-joda/core/dist/js-joda.d.ts +2452 -0
- package/node_modules/@js-joda/core/dist/js-joda.esm.js +13564 -0
- package/node_modules/@js-joda/core/dist/js-joda.flow.js +949 -0
- package/node_modules/@js-joda/core/dist/js-joda.js +13630 -0
- package/node_modules/@js-joda/core/dist/js-joda.js.map +1 -0
- package/node_modules/@js-joda/core/dist/js-joda.min.js +5 -0
- package/node_modules/@js-joda/core/package.json +76 -0
- package/node_modules/@js-joda/core/src/Clock.js +330 -0
- package/node_modules/@js-joda/core/src/DayOfWeek.js +451 -0
- package/node_modules/@js-joda/core/src/Duration.js +1205 -0
- package/node_modules/@js-joda/core/src/Enum.js +30 -0
- package/node_modules/@js-joda/core/src/Instant.js +1012 -0
- package/node_modules/@js-joda/core/src/LocalDate.js +1703 -0
- package/node_modules/@js-joda/core/src/LocalDateTime.js +1686 -0
- package/node_modules/@js-joda/core/src/LocalTime.js +1415 -0
- package/node_modules/@js-joda/core/src/MathUtil.js +236 -0
- package/node_modules/@js-joda/core/src/Month.js +600 -0
- package/node_modules/@js-joda/core/src/MonthDay.js +730 -0
- package/node_modules/@js-joda/core/src/OffsetDateTime.js +757 -0
- package/node_modules/@js-joda/core/src/OffsetTime.js +621 -0
- package/node_modules/@js-joda/core/src/Period.js +933 -0
- package/node_modules/@js-joda/core/src/StringUtil.js +43 -0
- package/node_modules/@js-joda/core/src/Year.js +1015 -0
- package/node_modules/@js-joda/core/src/YearConstants.js +21 -0
- package/node_modules/@js-joda/core/src/YearMonth.js +1096 -0
- package/node_modules/@js-joda/core/src/ZoneId.js +236 -0
- package/node_modules/@js-joda/core/src/ZoneIdFactory.js +201 -0
- package/node_modules/@js-joda/core/src/ZoneOffset.js +486 -0
- package/node_modules/@js-joda/core/src/ZoneRegion.js +72 -0
- package/node_modules/@js-joda/core/src/ZonedDateTime.js +2007 -0
- package/node_modules/@js-joda/core/src/_init.js +68 -0
- package/node_modules/@js-joda/core/src/assert.js +33 -0
- package/node_modules/@js-joda/core/src/chrono/ChronoLocalDate.js +230 -0
- package/node_modules/@js-joda/core/src/chrono/ChronoLocalDateTime.js +130 -0
- package/node_modules/@js-joda/core/src/chrono/ChronoZonedDateTime.js +194 -0
- package/node_modules/@js-joda/core/src/chrono/IsoChronology.js +235 -0
- package/node_modules/@js-joda/core/src/convert.js +83 -0
- package/node_modules/@js-joda/core/src/errors.js +54 -0
- package/node_modules/@js-joda/core/src/format/DateTimeBuilder.js +535 -0
- package/node_modules/@js-joda/core/src/format/DateTimeFormatter.js +728 -0
- package/node_modules/@js-joda/core/src/format/DateTimeFormatterBuilder.js +1545 -0
- package/node_modules/@js-joda/core/src/format/DateTimeParseContext.js +297 -0
- package/node_modules/@js-joda/core/src/format/DateTimePrintContext.js +138 -0
- package/node_modules/@js-joda/core/src/format/DecimalStyle.js +113 -0
- package/node_modules/@js-joda/core/src/format/EnumMap.js +70 -0
- package/node_modules/@js-joda/core/src/format/ParsePosition.js +31 -0
- package/node_modules/@js-joda/core/src/format/ResolverStyle.js +93 -0
- package/node_modules/@js-joda/core/src/format/SignStyle.js +38 -0
- package/node_modules/@js-joda/core/src/format/StringBuilder.js +47 -0
- package/node_modules/@js-joda/core/src/format/TextStyle.js +114 -0
- package/node_modules/@js-joda/core/src/format/parser/CharLiteralPrinterParser.js +46 -0
- package/node_modules/@js-joda/core/src/format/parser/CompositePrinterParser.js +89 -0
- package/node_modules/@js-joda/core/src/format/parser/FractionPrinterParser.js +162 -0
- package/node_modules/@js-joda/core/src/format/parser/NumberPrinterParser.js +367 -0
- package/node_modules/@js-joda/core/src/format/parser/OffsetIdPrinterParser.js +177 -0
- package/node_modules/@js-joda/core/src/format/parser/PadPrinterParserDecorator.js +81 -0
- package/node_modules/@js-joda/core/src/format/parser/SettingsParser.js +44 -0
- package/node_modules/@js-joda/core/src/format/parser/StringLiteralPrinterParser.js +39 -0
- package/node_modules/@js-joda/core/src/format/parser/ZoneIdPrinterParser.js +218 -0
- package/node_modules/@js-joda/core/src/js-joda.js +210 -0
- package/node_modules/@js-joda/core/src/license-preamble.js +3 -0
- package/node_modules/@js-joda/core/src/temporal/ChronoField.js +470 -0
- package/node_modules/@js-joda/core/src/temporal/ChronoUnit.js +310 -0
- package/node_modules/@js-joda/core/src/temporal/DefaultInterfaceTemporal.js +118 -0
- package/node_modules/@js-joda/core/src/temporal/IsoFields.js +859 -0
- package/node_modules/@js-joda/core/src/temporal/NativeJsTemporal.js +105 -0
- package/node_modules/@js-joda/core/src/temporal/Temporal.js +346 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalAccessor.js +125 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalAdjuster.js +92 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalAdjusters.js +464 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalAmount.js +166 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalField.js +248 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalQueries.js +223 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalQueriesFactory.js +77 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalQuery.js +107 -0
- package/node_modules/@js-joda/core/src/temporal/TemporalUnit.js +179 -0
- package/node_modules/@js-joda/core/src/temporal/ValueRange.js +257 -0
- package/node_modules/@js-joda/core/src/use.js +20 -0
- package/node_modules/@js-joda/core/src/zone/SystemDefaultZoneId.js +31 -0
- package/node_modules/@js-joda/core/src/zone/SystemDefaultZoneRules.js +162 -0
- package/node_modules/@js-joda/core/src/zone/ZoneOffsetTransition.js +289 -0
- package/node_modules/@js-joda/core/src/zone/ZoneRules.js +464 -0
- package/node_modules/@js-joda/core/src/zone/ZoneRulesProvider.js +36 -0
- package/node_modules/@yschimke/livery-web/README.md +112 -0
- package/node_modules/@yschimke/livery-web/dist/descriptor.d.ts +24 -0
- package/node_modules/@yschimke/livery-web/dist/descriptor.js +32 -0
- package/node_modules/@yschimke/livery-web/dist/index.d.ts +9 -0
- package/node_modules/@yschimke/livery-web/dist/index.js +5 -0
- package/node_modules/@yschimke/livery-web/dist/livery-web/livery-livery-web-core.d.mts +63 -0
- package/node_modules/@yschimke/livery-web/dist/livery-web/livery-livery-web-core.import-object.mjs +333 -0
- package/node_modules/@yschimke/livery-web/dist/livery-web/livery-livery-web-core.js-builtins.mjs +52 -0
- package/node_modules/@yschimke/livery-web/dist/livery-web/livery-livery-web-core.mjs +92 -0
- package/node_modules/@yschimke/livery-web/dist/livery-web/livery-livery-web-core.wasm +0 -0
- package/node_modules/@yschimke/livery-web/dist/player.d.ts +65 -0
- package/node_modules/@yschimke/livery-web/dist/player.js +117 -0
- package/node_modules/@yschimke/livery-web/dist/preview.d.ts +57 -0
- package/node_modules/@yschimke/livery-web/dist/preview.js +214 -0
- package/node_modules/@yschimke/livery-web/dist/publication.d.ts +7 -0
- package/node_modules/@yschimke/livery-web/dist/publication.js +103 -0
- package/node_modules/@yschimke/livery-web/dist/session.d.ts +71 -0
- package/node_modules/@yschimke/livery-web/dist/session.js +55 -0
- package/node_modules/@yschimke/livery-web/dist/viewer.d.ts +1 -0
- package/node_modules/@yschimke/livery-web/dist/viewer.js +18 -0
- package/node_modules/@yschimke/livery-web/package.json +39 -0
- package/node_modules/@yschimke/livery-web/vendor/PROVENANCE.md +18 -0
- package/node_modules/@yschimke/livery-web/vendor/remote-compose-player.d.mts +30 -0
- package/node_modules/@yschimke/livery-web/vendor/remote-compose-player.mjs +86 -0
- package/package.json +102 -4
package/README.md
CHANGED
|
@@ -1,3 +1,195 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @yschimke/livery-a2ui
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Livery contracts as [A2UI](https://a2ui.org) components on the web, for A2UI's Lit, React and Angular renderers. An agent places a component per contract and sends its data. The page then picks a
|
|
4
|
+
reviewed, signed template for it, binds the data through the contract, and plays the template on a
|
|
5
|
+
canvas in the page with the TypeScript Remote Compose player (the default), or Compose Multiplatform
|
|
6
|
+
compiled to Wasm (`player: 'cmp'`). A data change sets named values on the
|
|
7
|
+
playing document; it never reloads it. Actions in the template become A2UI events, or are written
|
|
8
|
+
back to the data model.
|
|
9
|
+
|
|
10
|
+
The player is vendored from the commit recorded in `../core/vendor/PROVENANCE.md`, with the fixes this package needs
|
|
11
|
+
([yschimke/rc-players#829](https://github.com/yschimke/rc-players/pull/829)): without them, these
|
|
12
|
+
templates lay out at `NaN` and their buttons don't fire.
|
|
13
|
+
|
|
14
|
+
The work is done by Livery's own Kotlin client compiled to Wasm (`livery-web`), which this package
|
|
15
|
+
ships in `dist/livery-web/`. That covers selection, trust, binding, instantiation and the action
|
|
16
|
+
gate, so the web behaves like every other Livery client. See [docs/A2UI.md](../../docs/A2UI.md).
|
|
17
|
+
|
|
18
|
+
## Use
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import '@a2ui/lit/v0_9';
|
|
22
|
+
import { MessageProcessor } from '@a2ui/web_core/v0_9';
|
|
23
|
+
import { LiverySession, liveryCatalog } from '@yschimke/livery-a2ui';
|
|
24
|
+
|
|
25
|
+
const session = await LiverySession.open({
|
|
26
|
+
catalog: 'https://example.com/catalog/', // manifest.json is beside it
|
|
27
|
+
keys: [{ keyId: 'main', publicKey: '<base64 raw Ed25519 key>' }],
|
|
28
|
+
appKinds: ['navigate'], // kinds this page handles itself
|
|
29
|
+
});
|
|
30
|
+
const { catalog } = await liveryCatalog(session, {
|
|
31
|
+
catalogId: 'https://example.com/a2ui/catalog/v1', // what the client advertises
|
|
32
|
+
onAppAction: (kind, action, args) => { /* navigate, … */ },
|
|
33
|
+
onProblem: (component, message) => { /* tell the agent */ },
|
|
34
|
+
});
|
|
35
|
+
const processor = new MessageProcessor([catalog], (action) => sendToAgent(action));
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Then render surfaces with `<a2ui-surface>` as usual. `session.catalogSchema(catalogId)` returns
|
|
39
|
+
the components' JSON schema to prompt an agent with. `livery build --a2ui` writes the same schema
|
|
40
|
+
at publish time.
|
|
41
|
+
|
|
42
|
+
### Player choice
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const { catalog } = await liveryCatalog(session, {
|
|
46
|
+
catalogId: 'https://example.com/a2ui/catalog/v1',
|
|
47
|
+
player: 'cmp', // omit or use 'ts' for the default
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`'cmp'` prepares the optional `livery-web-compose` module, Skiko and bundled Roboto Flex / Noto
|
|
52
|
+
Sans Symbols 2 fonts before returning the catalog. Rendering and value updates never fetch fonts.
|
|
53
|
+
It mounts one Compose viewport in the component's DOM, with no iframe. Both players keep the
|
|
54
|
+
same document loaded across data changes; changes to baked images or `long` values change its key.
|
|
55
|
+
The theme, height rule, session, decision ID and action gate are shared.
|
|
56
|
+
|
|
57
|
+
Each CMP viewport owns a Skia context. At most eight are reserved across the page; additional
|
|
58
|
+
components use TS for their lifetime. Disconnecting releases the viewport and its reservation.
|
|
59
|
+
This keeps long chats from exhausting browser WebGL contexts; it is not a performance guarantee.
|
|
60
|
+
|
|
61
|
+
A custom `player: (box, onAction) => LiveryPlayer` implements `show`, `resize`, `forget`, `dispose`
|
|
62
|
+
and `stats`. `show` resolves `false` when superseded or disposed; it resolves `true` after drawing.
|
|
63
|
+
For the synchronous `liveryComponent` API, pass `player: await prepareCmpPlayer()` instead of the
|
|
64
|
+
`'cmp'` shorthand. Runtime or font preparation failures reject `liveryCatalog`; a document the
|
|
65
|
+
prepared CMP player cannot render follows the usual chosen-design/automatic fallback route.
|
|
66
|
+
|
|
67
|
+
See [the comparison and measured costs](../../docs/A2UI-CMP.md). CMP uses the same Kotlin player
|
|
68
|
+
as desktop, but no player is the specification or a promise of Android-identical pixels.
|
|
69
|
+
|
|
70
|
+
### Serving
|
|
71
|
+
|
|
72
|
+
The page serves this package's `dist/livery-web/` (fetched beside `dist/livery.js`, `.wasm` as
|
|
73
|
+
`application/wasm`) and the catalog (its `manifest.json` and blobs). The player is in the bundle:
|
|
74
|
+
`vendor/remote-compose-player.mjs` (vendor/PROVENANCE.md).
|
|
75
|
+
|
|
76
|
+
The module's glue imports `@js-joda/core`, a dependency of this package. A bundler resolves it; a
|
|
77
|
+
page without one uses an import map. For CMP, also serve `dist/livery-web-compose/` beside the
|
|
78
|
+
package's JS modules, preserving its `fonts/` subdirectory. A TS-only page never requests it.
|
|
79
|
+
`prepareCmpPlayer` and the catalog option compute asset URLs relative to their module; when
|
|
80
|
+
bundling, copy both Wasm directories beside the resulting bundle. Serve `.wasm` as `application/wasm`.
|
|
81
|
+
|
|
82
|
+
### Theme and size
|
|
83
|
+
|
|
84
|
+
Each theme role (`primary`, `surface`, `onSurface`, …) comes from the first of these that is set:
|
|
85
|
+
|
|
86
|
+
1. For `primary`, the agent's `createSurface` theme: `primaryColor`.
|
|
87
|
+
2. `--livery-<role>`, for example `--livery-on-surface`.
|
|
88
|
+
3. A2UI's `--a2ui-color-<role>`.
|
|
89
|
+
4. Material 3's baseline colour.
|
|
90
|
+
|
|
91
|
+
Templates therefore match the basic components around them. The width the element gets selects
|
|
92
|
+
the design. The height is `--livery-a2ui-height` when the page sets it; otherwise it's the
|
|
93
|
+
measured root content at that width, clamped to the target's `minHeightDp` when declared.
|
|
94
|
+
Documents without a finite root measurement use their authored height as the fallback.
|
|
95
|
+
The sample banner wraps to 112dp instead of its 160dp authored viewport.
|
|
96
|
+
|
|
97
|
+
## Develop
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
build-brief ./gradlew :livery-web:webDist :livery-web-compose:webDist :livery-publish:installDist :livery-capture-cmp:sampleCatalogs # the Wasm module, the CLI the test builds a catalog with, and the built sample catalogs
|
|
101
|
+
npm ci && npm run check && npm run build
|
|
102
|
+
npm test # headless Chromium (Playwright)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`npm test` serves the sample catalog to a page that runs A2UI's own engine with each of the Lit, React and Angular renderers, then
|
|
106
|
+
checks rendering, interactions and offline behavior for both players:
|
|
107
|
+
|
|
108
|
+
- both templates draw on a canvas in the page, with no iframe;
|
|
109
|
+
- an action reaches the agent with only its declared arguments, and a `set` writes the data model;
|
|
110
|
+
- a data change sets values on the playing document without reloading it, and redraws it;
|
|
111
|
+
- Livery's events carry the A2UI decision id, `a2ui:<surfaceId>/<componentId>`;
|
|
112
|
+
- a surface's `primaryColor` colours its templates over the page's CSS theme;
|
|
113
|
+
- a component wraps measured content unless the page sets its height;
|
|
114
|
+
- a second catalog's components keep their own session;
|
|
115
|
+
- container resizing, disconnect/reconnect, queued shows and disposal during loading;
|
|
116
|
+
- fifteen simultaneous components respect the eight-CMP-viewport bound.
|
|
117
|
+
|
|
118
|
+
### npm releases
|
|
119
|
+
|
|
120
|
+
`@yschimke/livery-a2ui` follows the repository version. Release-please updates its package and lockfile;
|
|
121
|
+
merging the release PR builds and checks the npm tarball, then publishes it alongside Maven.
|
|
122
|
+
The first publication is bootstrapped manually under the npm account owning `@yschimke`.
|
|
123
|
+
Then configure npm trusted publishing for GitHub owner `yschimke`, repository `livery`,
|
|
124
|
+
workflow `release.yml`, with no environment and direct publishing allowed. Subsequent releases
|
|
125
|
+
use GitHub Actions OIDC; no `NPM_TOKEN` secret is required. The bundled
|
|
126
|
+
`@yschimke/livery-web` dependency does not need a separate registry publication.
|
|
127
|
+
See the [first-publish instructions](https://github.com/yschimke/livery/blob/main/web/a2ui/PUBLISHING.md). `npm run pack:check` checks the files and
|
|
128
|
+
relative runtime imports in the actual tarball in CI. The TypeScript player remains vendored
|
|
129
|
+
with its provenance until rc-players publishes a supported npm package.
|
|
130
|
+
|
|
131
|
+
### React and Angular
|
|
132
|
+
|
|
133
|
+
The same session and controller power all three web renderers. Use
|
|
134
|
+
`liveryReactCatalog(session, options)` from `@yschimke/livery-a2ui/react` with React's `A2uiSurface`, or
|
|
135
|
+
`liveryAngularCatalog(session, options)` from `@yschimke/livery-a2ui/angular` with Angular's
|
|
136
|
+
`provideA2Ui({ catalogs: [catalog] })` and `SurfaceComponent`. Install the matching optional peers:
|
|
137
|
+
React 18/19 with `@a2ui/react` 0.15; Angular 21 with `@a2ui/angular` 0.14 (which uses web_core 0.15).
|
|
138
|
+
Angular applications also configure A2UI's `provideMarkdownRenderer()` for the basic components.
|
|
139
|
+
The Angular entry ships partial compilation for the application's Angular linker.
|
|
140
|
+
|
|
141
|
+
`options.base` extends the selected renderer's catalog. Actions, data-model paths, themes,
|
|
142
|
+
decision ids, retry and height behavior are shared. `fallback` returns a Lit template for Lit,
|
|
143
|
+
a React node for React, or a DOM node/string for Angular. `npm test` runs the same sample catalog
|
|
144
|
+
and all interaction checks once per renderer; `CHROMIUM_PATH` can select a local Chromium binary.
|
|
145
|
+
|
|
146
|
+
### Persistent browser cache
|
|
147
|
+
|
|
148
|
+
Web sessions default to IndexedDB for blobs and small named documents. A session with playable cached templates reads
|
|
149
|
+
its catalog immediately and refreshes in the background. A cached manifest without playable
|
|
150
|
+
blobs first retries prefetch, so an interrupted download cannot register an empty component catalog.
|
|
151
|
+
Template rendering does not
|
|
152
|
+
wait for a network response. The existing repository still owns expiry, stale grace, install
|
|
153
|
+
policy, blob eviction and image-cache metadata. Browser storage can be cleared or evicted by
|
|
154
|
+
the browser; this is a cache, not durable application data.
|
|
155
|
+
|
|
156
|
+
Set `persistentCache: false` in `LiverySession.open` for memory-only sessions (also useful in
|
|
157
|
+
hosts that deny IndexedDB or Web Locks). Persistent caching requires a secure origin
|
|
158
|
+
(HTTPS or localhost) and Web Locks; refreshes sharing a namespace are serialized across sessions and tabs. Cache namespaces include the catalog and trust configuration:
|
|
159
|
+
switching from an unsigned development catalog to signed trust cannot reuse the old manifest.
|
|
160
|
+
The browser suite reloads with all catalog requests blocked and checks that cached templates
|
|
161
|
+
draw, that memory-only sessions cannot use this cache offline, and that a different trust configuration
|
|
162
|
+
cannot inherit the cached unsigned catalog. Serving an application's shell offline remains the
|
|
163
|
+
host application's responsibility.
|
|
164
|
+
|
|
165
|
+
### Wasm distribution size
|
|
166
|
+
|
|
167
|
+
`webDist` runs Kotlin's pinned Binaryen optimizer before packaging. On the 0.6.0 baseline this
|
|
168
|
+
reduces raw Wasm from 4,749,595 to 1,454,082 bytes (69.4%). Ktor remains in the module to preserve
|
|
169
|
+
its fetch and redirect contract. `docs/WASM-SIZE.md` records section and dependency measurements;
|
|
170
|
+
`scripts/wasm-size.py` reproduces the breakdown for subsequent builds.
|
|
171
|
+
|
|
172
|
+
`LIVERY_TEST_PLAYER=ts` or `cmp` selects one player; `LIVERY_RENDERER=lit`, `react` or `angular`
|
|
173
|
+
selects a framework when running `node test/e2e.mjs` directly. `LIVERY_RENDER_OUT` saves screenshots
|
|
174
|
+
and load measurements. `CHROMIUM_PATH` (or `PLAYWRIGHT_CHROMIUM_EXECUTABLE`) selects an installed
|
|
175
|
+
Chromium. CMP retains authored height when it cannot expose a finite root measurement.
|
|
176
|
+
|
|
177
|
+
Content height is read from the player's normal layout at the current viewport constraints.
|
|
178
|
+
The size query does not run a second measure pass or alter expressions, animations or scroll
|
|
179
|
+
state. Fill-height, weighted-height and scrolling layouts retain their authored-height fallback.
|
|
180
|
+
|
|
181
|
+
When replacing a cached catalog, refresh keeps the previous manifest active until its required
|
|
182
|
+
replacement templates and assets finish downloading. Failed downloads keep the playable cache;
|
|
183
|
+
the accepted serial watermark is still persisted immediately so rollback protection survives a
|
|
184
|
+
failure or interruption. Kotlin and Swift use the same activation order.
|
|
185
|
+
|
|
186
|
+
CI uses Binaryen 130.0.0 from the npm lockfile with `-Plivery.wasmOpt=<path-to-wasm-opt>`.
|
|
187
|
+
This keeps the same optimizer version and Kotlin arguments while avoiding the GitHub release
|
|
188
|
+
asset endpoint, which repeatedly returned HTTP 504. Ordinary Gradle builds retain Kotlin's
|
|
189
|
+
native Binaryen download unless an executable is supplied.
|
|
190
|
+
|
|
191
|
+
The optional A2UI facade delegates shared document preparation and action routing to
|
|
192
|
+
`livery-web-core`. Its canvas player comes from the neutral `@yschimke/livery-web/player`
|
|
193
|
+
package, bundled into the published A2UI tarball. In a checkout, build `web/core`
|
|
194
|
+
before installing/building this package; `npm ci` copies that local package.
|
|
195
|
+
Standalone component previews are documented in [../core/README.md](../core/README.md).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type OnDestroy } from '@angular/core';
|
|
2
|
+
import { AngularCatalog, CatalogComponent } from '@a2ui/angular/v0_9';
|
|
3
|
+
import { type LiveryComponentApi, type LiveryCatalogOptions } from './api.js';
|
|
4
|
+
import type { LiverySession } from './livery.js';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
export { LiverySession, loadLiveryWeb } from './livery.js';
|
|
7
|
+
export declare class LiveryAngularComponent extends CatalogComponent<LiveryComponentApi> implements OnDestroy {
|
|
8
|
+
private readonly host;
|
|
9
|
+
private readonly service;
|
|
10
|
+
private api?;
|
|
11
|
+
private readonly fallbackBox;
|
|
12
|
+
private readonly controller;
|
|
13
|
+
constructor();
|
|
14
|
+
ngOnDestroy(): void;
|
|
15
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LiveryAngularComponent, never>;
|
|
16
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<LiveryAngularComponent, "livery-angular-view", never, {}, {}, never, never, true, never>;
|
|
17
|
+
}
|
|
18
|
+
export declare function liveryAngularCatalog(session: LiverySession, options: LiveryCatalogOptions): Promise<{
|
|
19
|
+
catalog: AngularCatalog;
|
|
20
|
+
components: {
|
|
21
|
+
component: import("@angular/core").Type<import("@a2ui/angular").CatalogComponentInstance>;
|
|
22
|
+
name: string;
|
|
23
|
+
schema: import("zod").ZodTypeAny;
|
|
24
|
+
allowedParents?: string[];
|
|
25
|
+
allowedChildren?: string[];
|
|
26
|
+
metadata?: import("@a2ui/web_core").A2uiMetadata;
|
|
27
|
+
tagName: string;
|
|
28
|
+
spec: import("./livery.js").LiveryComponentSpec;
|
|
29
|
+
session: LiverySession;
|
|
30
|
+
options: LiveryCatalogOptions;
|
|
31
|
+
}[];
|
|
32
|
+
}>;
|
package/dist/angular.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Component, ElementRef, effect, inject } from '@angular/core';
|
|
2
|
+
import { A2uiRendererService, AngularCatalog, CatalogComponent, createComponentImplementation, BasicCatalog } from '@a2ui/angular/v0_9';
|
|
3
|
+
import { ComponentContext } from '@a2ui/web_core/v0_9';
|
|
4
|
+
import { componentApi, preparePlayerOptions } from './api.js';
|
|
5
|
+
import { hostStyle, LiveryController } from './controller.js';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
export { LiverySession, loadLiveryWeb } from './livery.js';
|
|
8
|
+
export class LiveryAngularComponent extends CatalogComponent {
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
this.host = inject((ElementRef)).nativeElement;
|
|
12
|
+
this.service = inject(A2uiRendererService);
|
|
13
|
+
this.fallbackBox = document.createElement('div');
|
|
14
|
+
this.controller = new LiveryController(this.host, () => {
|
|
15
|
+
const reason = this.controller.fallback;
|
|
16
|
+
this.controller.box.style.display = reason === undefined ? '' : 'none';
|
|
17
|
+
const content = reason === undefined ? '' : this.api?.options.fallback?.(this.api.spec, reason) ?? '';
|
|
18
|
+
this.fallbackBox.replaceChildren(content instanceof Node ? content : String(content));
|
|
19
|
+
}, () => new Promise(requestAnimationFrame));
|
|
20
|
+
this.host.style.cssText = hostStyle;
|
|
21
|
+
this.host.attachShadow({ mode: 'open' }).append(this.controller.box, this.fallbackBox);
|
|
22
|
+
this.controller.connect();
|
|
23
|
+
effect(() => {
|
|
24
|
+
const surface = this.service.surfaceGroup.getSurface(this.surfaceId());
|
|
25
|
+
if (!surface)
|
|
26
|
+
return;
|
|
27
|
+
const context = new ComponentContext(surface, this.componentId(), this.dataContextPath());
|
|
28
|
+
this.api = context.componentModel.catalog.components.get(context.componentModel.type);
|
|
29
|
+
this.host.dataset.liveryComponent = this.api.name;
|
|
30
|
+
const props = Object.fromEntries(Object.entries(this.props()).map(([key, binding]) => [key, binding.value()]));
|
|
31
|
+
this.controller.update(this.api, context, props);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
ngOnDestroy() { this.controller.disconnect(); }
|
|
35
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: LiveryAngularComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
36
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.5", type: LiveryAngularComponent, isStandalone: true, selector: "livery-angular-view", usesInheritance: true, ngImport: i0, template: '', isInline: true }); }
|
|
37
|
+
}
|
|
38
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: LiveryAngularComponent, decorators: [{
|
|
39
|
+
type: Component,
|
|
40
|
+
args: [{ selector: 'livery-angular-view', standalone: true, template: '' }]
|
|
41
|
+
}], ctorParameters: () => [] });
|
|
42
|
+
export async function liveryAngularCatalog(session, options) {
|
|
43
|
+
options = await preparePlayerOptions(options);
|
|
44
|
+
const components = (await session.components()).map((spec) => {
|
|
45
|
+
const api = componentApi(session, spec, options);
|
|
46
|
+
return { ...api, ...createComponentImplementation(api, LiveryAngularComponent) };
|
|
47
|
+
});
|
|
48
|
+
const base = options.base ?? new BasicCatalog();
|
|
49
|
+
const catalog = new AngularCatalog(options.catalogId, '0.9', [...base.components.values(), ...components], [...base.functions.values()], base.themeSchema);
|
|
50
|
+
return { catalog, components };
|
|
51
|
+
}
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { LiveryPlayerFactory } from './player.js';
|
|
2
|
+
import { type Catalog } from '@a2ui/web_core/v0_9';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import type { LiveryComponentSpec, LiverySession } from './livery.js';
|
|
5
|
+
export interface LiveryCatalogOptions {
|
|
6
|
+
/** In-page player; optional CMP is prepared before any framework registers its catalog. */
|
|
7
|
+
player?: 'ts' | 'cmp' | LiveryPlayerFactory;
|
|
8
|
+
/** The catalog id the client advertises: basic components plus one per Livery contract. */
|
|
9
|
+
catalogId: string;
|
|
10
|
+
/** The catalog to extend; A2UI's basic catalog by default. */
|
|
11
|
+
base?: Catalog<any, any>;
|
|
12
|
+
/** An action of a kind the page handles (`navigate`, `dismiss`, `app:…`) that the agent didn't wire. */
|
|
13
|
+
onAppAction?: (kind: string, action: string, args: Record<string, string>, component: string) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Something the agent should hear about: data that doesn't bind, no playable template, a `set` on
|
|
16
|
+
* an input it didn't bind to a path. The page tells its agent (A2UI's `error` message).
|
|
17
|
+
*/
|
|
18
|
+
onProblem?: (component: string, message: string) => void;
|
|
19
|
+
/** What draws when there is no template (the agent is told through [onProblem]); nothing by default. */
|
|
20
|
+
fallback?: (spec: LiveryComponentSpec, reason: string) => unknown;
|
|
21
|
+
}
|
|
22
|
+
/** One Livery component's A2UI API: its name, tag, element and props schema, and the session it draws with. */
|
|
23
|
+
export interface LiveryComponentApi {
|
|
24
|
+
name: string;
|
|
25
|
+
tagName: string;
|
|
26
|
+
schema: z.ZodTypeAny;
|
|
27
|
+
spec: LiveryComponentSpec;
|
|
28
|
+
session: LiverySession;
|
|
29
|
+
options: LiveryCatalogOptions;
|
|
30
|
+
}
|
|
31
|
+
/** The props schema, from the same projection as Kotlin's (`livery-a2ui`): A2UI's own dynamic types. */
|
|
32
|
+
export declare function schemaOf(spec: LiveryComponentSpec): z.ZodTypeAny;
|
|
33
|
+
export declare function componentApi(session: LiverySession, spec: LiveryComponentSpec, options: LiveryCatalogOptions): LiveryComponentApi;
|
|
34
|
+
export declare function kebab(s: string): string;
|
|
35
|
+
export declare function preparePlayerOptions(options: LiveryCatalogOptions): Promise<LiveryCatalogOptions>;
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { prepareCmpPlayer } from './cmp-player.js';
|
|
2
|
+
import { ActionSchema, DynamicBooleanSchema, DynamicNumberSchema, DynamicStringSchema, DynamicValueSchema } from '@a2ui/web_core/v0_9';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
/** The props schema, from the same projection as Kotlin's (`livery-a2ui`): A2UI's own dynamic types. */
|
|
5
|
+
export function schemaOf(spec) {
|
|
6
|
+
const shape = {};
|
|
7
|
+
for (const p of spec.properties) {
|
|
8
|
+
const s = propertySchema(p);
|
|
9
|
+
shape[p.key] = p.required ? s : s.optional();
|
|
10
|
+
}
|
|
11
|
+
return z.object(shape).describe(spec.description);
|
|
12
|
+
}
|
|
13
|
+
function propertySchema(p) {
|
|
14
|
+
switch (p.kind) {
|
|
15
|
+
case 'DynamicString': return DynamicStringSchema;
|
|
16
|
+
case 'DynamicNumber': return DynamicNumberSchema;
|
|
17
|
+
case 'DynamicBoolean': return DynamicBooleanSchema;
|
|
18
|
+
case 'DynamicValue': return DynamicValueSchema;
|
|
19
|
+
case 'String': return z.string();
|
|
20
|
+
case 'Action': return ActionSchema;
|
|
21
|
+
case 'Actions': return z.object(Object.fromEntries((p.properties ?? []).map((a) => [a, ActionSchema.optional()]))).strict();
|
|
22
|
+
default: return z.any();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function componentApi(session, spec, options) {
|
|
26
|
+
if (options.player === 'cmp')
|
|
27
|
+
throw new Error("Use an async catalog factory with player: 'cmp', or pass await prepareCmpPlayer() to liveryComponent");
|
|
28
|
+
return { name: spec.name, tagName: `livery-${kebab(spec.name)}`, schema: schemaOf(spec), session, spec, options };
|
|
29
|
+
}
|
|
30
|
+
export function kebab(s) {
|
|
31
|
+
return s.replace(/([a-z0-9])([A-Z])/g, '$1-$2').replace(/[^A-Za-z0-9]+/g, '-').toLowerCase();
|
|
32
|
+
}
|
|
33
|
+
export async function preparePlayerOptions(options) {
|
|
34
|
+
return options.player === 'cmp' ? { ...options, player: await prepareCmpPlayer() } : options;
|
|
35
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Catalog } from '@a2ui/web_core/v0_9';
|
|
2
|
+
import type { LiveryComponentSpec, LiverySession } from './livery.js';
|
|
3
|
+
import { type LiveryComponentApi as SharedComponentApi, type LiveryCatalogOptions } from './api.js';
|
|
4
|
+
export type { LiveryCatalogOptions } from './api.js';
|
|
5
|
+
/** Lit retains its custom-element constructor alongside the renderer-neutral API. */
|
|
6
|
+
export interface LiveryComponentApi extends SharedComponentApi {
|
|
7
|
+
element: CustomElementConstructor;
|
|
8
|
+
}
|
|
9
|
+
export declare function liveryCatalog(session: LiverySession, options: LiveryCatalogOptions): Promise<{
|
|
10
|
+
catalog: Catalog<any, any>;
|
|
11
|
+
components: LiveryComponentApi[];
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* The A2UI component for one contract ([spec]). Its element is defined once per tag, and takes its
|
|
15
|
+
* session, spec and options from the catalog entry it was rendered from, never from the first
|
|
16
|
+
* catalog that defined the tag: two catalogs (or a session opened again) each draw with their own.
|
|
17
|
+
*/
|
|
18
|
+
export declare function liveryComponent(session: LiverySession, spec: LiveryComponentSpec, options: LiveryCatalogOptions): LiveryComponentApi;
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { A2uiLitElement, basicCatalog } from '@a2ui/lit/v0_9';
|
|
2
|
+
import { css, html, nothing } from 'lit';
|
|
3
|
+
import { componentApi, preparePlayerOptions } from './api.js';
|
|
4
|
+
import { LiveryController } from './controller.js';
|
|
5
|
+
export async function liveryCatalog(session, options) {
|
|
6
|
+
options = await preparePlayerOptions(options);
|
|
7
|
+
const base = options.base ?? basicCatalog;
|
|
8
|
+
const components = (await session.components()).map((spec) => liveryComponent(session, spec, options));
|
|
9
|
+
const catalog = base.derive({ catalogId: options.catalogId, components: [...base.components.keys(), ...components] });
|
|
10
|
+
return { catalog, components };
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The A2UI component for one contract ([spec]). Its element is defined once per tag, and takes its
|
|
14
|
+
* session, spec and options from the catalog entry it was rendered from, never from the first
|
|
15
|
+
* catalog that defined the tag: two catalogs (or a session opened again) each draw with their own.
|
|
16
|
+
*/
|
|
17
|
+
export function liveryComponent(session, spec, options) {
|
|
18
|
+
const api = componentApi(session, spec, options);
|
|
19
|
+
const { tagName } = api;
|
|
20
|
+
let element = customElements.get(tagName);
|
|
21
|
+
if (!element) {
|
|
22
|
+
// One constructor per tag (the registry allows no other), all of them the same element.
|
|
23
|
+
element = class extends LiveryElement {
|
|
24
|
+
};
|
|
25
|
+
customElements.define(tagName, element);
|
|
26
|
+
}
|
|
27
|
+
return { ...api, element };
|
|
28
|
+
}
|
|
29
|
+
class LiveryElement extends A2uiLitElement {
|
|
30
|
+
constructor() {
|
|
31
|
+
super(...arguments);
|
|
32
|
+
this.liveryController = new LiveryController(this, () => this.requestUpdate(), () => this.updateComplete);
|
|
33
|
+
}
|
|
34
|
+
static { this.styles = css `:host { display:block; width:100%; height:var(--livery-a2ui-height,var(--livery-template-height,200px)); }`; }
|
|
35
|
+
get liveryApi() {
|
|
36
|
+
const model = this.context?.componentModel;
|
|
37
|
+
return model?.catalog?.components.get(model.type);
|
|
38
|
+
}
|
|
39
|
+
get liveryStats() { return this.liveryController.liveryStats; }
|
|
40
|
+
get liveryTheme() { return this.liveryController.liveryTheme; }
|
|
41
|
+
liveryHostAction(action) { return this.liveryController.liveryHostAction(action); }
|
|
42
|
+
connectedCallback() { super.connectedCallback(); this.liveryController.connect(); }
|
|
43
|
+
disconnectedCallback() { this.liveryController.disconnect(); super.disconnectedCallback(); }
|
|
44
|
+
updated(changed) {
|
|
45
|
+
super.updated(changed);
|
|
46
|
+
if (this.liveryApi)
|
|
47
|
+
this.dataset.liveryComponent = this.liveryApi.name;
|
|
48
|
+
if (this.context)
|
|
49
|
+
this.liveryController.update(this.liveryApi, this.context, this.controller.props ?? {});
|
|
50
|
+
}
|
|
51
|
+
render() {
|
|
52
|
+
const reason = this.liveryController.fallback;
|
|
53
|
+
return reason === undefined ? html `${this.liveryController.box}` : html `${this.liveryApi?.options.fallback?.(this.liveryApi.spec, reason) ?? nothing}`;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { RcCanvasPlayer } from './player.js';
|
|
2
|
+
let prepared;
|
|
3
|
+
let activeViewports = 0;
|
|
4
|
+
// Each viewport owns a Skia/WebGL context. Leave room for other canvas users on a chat page.
|
|
5
|
+
const MAX_VIEWPORTS = 8;
|
|
6
|
+
/** Preload the optional Wasm/Skiko runtime and bundled font before rendering any components. */
|
|
7
|
+
export function prepareCmpPlayer() {
|
|
8
|
+
return prepared ??= prepare().catch((e) => { prepared = undefined; throw e; });
|
|
9
|
+
}
|
|
10
|
+
async function prepare() {
|
|
11
|
+
const base = new URL('./livery-web-compose/', import.meta.url);
|
|
12
|
+
const url = new URL('livery-livery-web-compose.mjs', base).href;
|
|
13
|
+
const font = async (name) => {
|
|
14
|
+
const r = await fetch(new URL(`fonts/${name}`, base));
|
|
15
|
+
if (!r.ok)
|
|
16
|
+
throw new Error(`CMP font ${name}: HTTP ${r.status}`);
|
|
17
|
+
return base64(new Uint8Array(await r.arrayBuffer()));
|
|
18
|
+
};
|
|
19
|
+
const [lib, roboto, symbols] = await Promise.all([
|
|
20
|
+
import(/* @vite-ignore */ url),
|
|
21
|
+
font('RobotoFlex.ttf'),
|
|
22
|
+
font('NotoSansSymbols2-Regular.ttf'),
|
|
23
|
+
]);
|
|
24
|
+
// Importing Skiko starts its fetch but does not await it. Finish it during preparation, too.
|
|
25
|
+
const skikoUrl = new URL('skiko.mjs', base).href;
|
|
26
|
+
await (await import(/* @vite-ignore */ skikoUrl)).awaitSkiko;
|
|
27
|
+
// Compose's Locale parser rejects some OS tags (for example en-US@posix). Leave valid
|
|
28
|
+
// browser settings untouched; repair only the invalid entries before composition starts.
|
|
29
|
+
const languages = navigator.languages.map((tag) => tag.replaceAll('_', '-').split('@')[0]);
|
|
30
|
+
const usable = languages.filter((tag) => { try {
|
|
31
|
+
new Intl.Locale(tag);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
} });
|
|
37
|
+
if (usable.join('\0') !== navigator.languages.join('\0')) {
|
|
38
|
+
const safe = usable.length ? usable : ['en-US'];
|
|
39
|
+
Object.defineProperty(navigator, 'languages', { configurable: true, get: () => safe });
|
|
40
|
+
Object.defineProperty(navigator, 'language', { configurable: true, get: () => safe[0] });
|
|
41
|
+
}
|
|
42
|
+
lib.liveryCmpPrepare(roboto, symbols);
|
|
43
|
+
return (box, onAction) => {
|
|
44
|
+
if (activeViewports >= MAX_VIEWPORTS)
|
|
45
|
+
return new RcCanvasPlayer(box, onAction);
|
|
46
|
+
activeViewports++;
|
|
47
|
+
return new CmpPlayer(lib, box, onAction, () => activeViewports--);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
class CmpPlayer {
|
|
51
|
+
constructor(lib, box, onAction, release) {
|
|
52
|
+
this.lib = lib;
|
|
53
|
+
this.box = box;
|
|
54
|
+
this.onAction = onAction;
|
|
55
|
+
this.release = release;
|
|
56
|
+
this.latest = 0;
|
|
57
|
+
this.disposed = false;
|
|
58
|
+
this.size = '';
|
|
59
|
+
this.queue = Promise.resolve();
|
|
60
|
+
this.stats = { loads: 0, sets: 0 };
|
|
61
|
+
}
|
|
62
|
+
show(key, document, values, width, height, density) {
|
|
63
|
+
const mine = ++this.latest;
|
|
64
|
+
const run = this.queue.then(async () => {
|
|
65
|
+
if (this.disposed || mine !== this.latest)
|
|
66
|
+
return false;
|
|
67
|
+
this.resize(width, height, density);
|
|
68
|
+
// Mount only after the element's height rule has sized its container.
|
|
69
|
+
this.id ??= this.lib.liveryCmpMount(this.box, (name, type, value) => {
|
|
70
|
+
if (!this.disposed)
|
|
71
|
+
this.onAction({ name, valueType: type, value: type === 'int' || type === 'float' ? Number(value) : value });
|
|
72
|
+
});
|
|
73
|
+
const frame = this.lib.liveryCmpShow(this.id, key, key === this.key ? '' : base64(document), JSON.stringify(values), density);
|
|
74
|
+
this.key = key;
|
|
75
|
+
const drawn = await frame;
|
|
76
|
+
if (this.disposed)
|
|
77
|
+
return false;
|
|
78
|
+
Object.assign(this.stats, JSON.parse(this.lib.liveryCmpStats(this.id)));
|
|
79
|
+
return drawn && mine === this.latest;
|
|
80
|
+
});
|
|
81
|
+
this.queue = run.catch(() => { });
|
|
82
|
+
return run;
|
|
83
|
+
}
|
|
84
|
+
resize(width, height, density) {
|
|
85
|
+
if (this.disposed)
|
|
86
|
+
return;
|
|
87
|
+
if (width > 0 && height > 0) {
|
|
88
|
+
this.box.style.width = `${width}px`;
|
|
89
|
+
this.box.style.height = `${height}px`;
|
|
90
|
+
const size = `${width}/${height}/${density}`;
|
|
91
|
+
if (size !== this.size) {
|
|
92
|
+
this.size = size;
|
|
93
|
+
// Compose 1.12's viewport observes window resize, not its container's ResizeObserver.
|
|
94
|
+
window.dispatchEvent(new Event('resize'));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (this.id !== undefined)
|
|
98
|
+
this.lib.liveryCmpResize(this.id, density);
|
|
99
|
+
}
|
|
100
|
+
forget() {
|
|
101
|
+
this.latest++;
|
|
102
|
+
this.key = undefined;
|
|
103
|
+
if (this.id !== undefined)
|
|
104
|
+
this.lib.liveryCmpForget(this.id);
|
|
105
|
+
}
|
|
106
|
+
dispose() {
|
|
107
|
+
if (this.disposed)
|
|
108
|
+
return;
|
|
109
|
+
this.disposed = true;
|
|
110
|
+
this.latest++;
|
|
111
|
+
try {
|
|
112
|
+
if (this.id !== undefined)
|
|
113
|
+
this.lib.liveryCmpDispose(this.id);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
this.release();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function base64(bytes) {
|
|
121
|
+
let s = '';
|
|
122
|
+
for (let i = 0; i < bytes.length; i += 8192)
|
|
123
|
+
s += String.fromCharCode(...bytes.subarray(i, i + 8192));
|
|
124
|
+
return btoa(s);
|
|
125
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ComponentContext } from '@a2ui/web_core/v0_9';
|
|
2
|
+
import type { LiveryComponentApi } from './api.js';
|
|
3
|
+
import { type NamedAction } from './player.js';
|
|
4
|
+
export declare const hostStyle = "display:block;width:100%;height:var(--livery-a2ui-height,var(--livery-template-height,200px))";
|
|
5
|
+
export declare class LiveryController {
|
|
6
|
+
readonly element: HTMLElement;
|
|
7
|
+
private readonly changed;
|
|
8
|
+
private readonly settled;
|
|
9
|
+
private livery?;
|
|
10
|
+
private context?;
|
|
11
|
+
private resolved;
|
|
12
|
+
private connected;
|
|
13
|
+
constructor(element: HTMLElement, changed: () => void, settled: () => Promise<unknown>);
|
|
14
|
+
connect(): void;
|
|
15
|
+
update(api: LiveryComponentApi | undefined, context: ComponentContext, resolved: Record<string, unknown>): void;
|
|
16
|
+
private invalidate;
|
|
17
|
+
disconnect(): void;
|
|
18
|
+
private player?;
|
|
19
|
+
/** The player's canvas lives here across framework renders. */
|
|
20
|
+
readonly box: HTMLDivElement;
|
|
21
|
+
private render_?;
|
|
22
|
+
private request;
|
|
23
|
+
fallback?: string;
|
|
24
|
+
private sequence;
|
|
25
|
+
/** The agent's design failed to play: render the automatic choice instead, until the props change. */
|
|
26
|
+
private automatic;
|
|
27
|
+
private lastTheme?;
|
|
28
|
+
private automaticFor?;
|
|
29
|
+
/** A fetch for this element's images failed: if it renders waiting again, it can't draw. */
|
|
30
|
+
private imagesFailed;
|
|
31
|
+
private shownPresentation?;
|
|
32
|
+
private resize?;
|
|
33
|
+
private widthDp;
|
|
34
|
+
/** Documents this element's player loaded and values it set: a data change sets values, never reloads. */
|
|
35
|
+
get liveryStats(): {
|
|
36
|
+
loads: number;
|
|
37
|
+
sets: number;
|
|
38
|
+
} | undefined;
|
|
39
|
+
/** The theme roles of the last render, as `#AARRGGBB`. @internal For tests. */
|
|
40
|
+
get liveryTheme(): Record<string, string> | undefined;
|
|
41
|
+
/** The props Livery renders from: inputs and lists as A2UI resolved them, the rest as the agent wrote them. */
|
|
42
|
+
private props;
|
|
43
|
+
/** Whether the page sets the component's height (`--livery-a2ui-height`), so selection can use it. */
|
|
44
|
+
private pageHeight;
|
|
45
|
+
/** `a2ui:<surfaceId>/<componentId>`: on every event of this component, so analytics can tell agent-placed templates from the app's own. */
|
|
46
|
+
private decisionId;
|
|
47
|
+
sync(): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* This render can't draw. The agent hears why. A chosen design falls back to the automatic
|
|
50
|
+
* choice, never to nothing; the agent's own document is never replaced (PROTOCOL.md §5.3), so
|
|
51
|
+
* it, and an automatic choice that can't draw either, show the page's fallback.
|
|
52
|
+
*/
|
|
53
|
+
private cannotPlay;
|
|
54
|
+
/**
|
|
55
|
+
* A host named action, exactly as the player's callback delivers one. @internal For tests that
|
|
56
|
+
* send a document's action with values its buttons wouldn't (an undeclared argument).
|
|
57
|
+
*/
|
|
58
|
+
liveryHostAction(a: NamedAction): Promise<void>;
|
|
59
|
+
private onAction;
|
|
60
|
+
private dispatch;
|
|
61
|
+
}
|