@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
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { kebab } from './api.js';
|
|
2
|
+
import { RcCanvasPlayer } from './player.js';
|
|
3
|
+
export const hostStyle = 'display:block;width:100%;height:var(--livery-a2ui-height,var(--livery-template-height,200px))';
|
|
4
|
+
const BASELINE = {
|
|
5
|
+
primary: '#FF6750A4', onPrimary: '#FFFFFFFF', secondary: '#FF625B71', onSecondary: '#FFFFFFFF',
|
|
6
|
+
surface: '#FFF3EDF7', onSurface: '#FF1D1B20', surfaceVariant: '#FFE7E0EC', onSurfaceVariant: '#FF49454F',
|
|
7
|
+
background: '#FFFEF7FF', onBackground: '#FF1D1B20', error: '#FFB3261E', onError: '#FFFFFFFF',
|
|
8
|
+
};
|
|
9
|
+
const THEME_ROLES = Object.keys(BASELINE);
|
|
10
|
+
const DYNAMIC = new Set(['DynamicString', 'DynamicNumber', 'DynamicBoolean', 'DynamicValue']);
|
|
11
|
+
const DESIGN = 'design';
|
|
12
|
+
const TEMPLATE = 'template';
|
|
13
|
+
export class LiveryController {
|
|
14
|
+
constructor(element, changed, settled) {
|
|
15
|
+
this.element = element;
|
|
16
|
+
this.changed = changed;
|
|
17
|
+
this.settled = settled;
|
|
18
|
+
this.resolved = {};
|
|
19
|
+
this.connected = false;
|
|
20
|
+
/** The player's canvas lives here across framework renders. */
|
|
21
|
+
this.box = Object.assign(document.createElement('div'), { className: 'player' });
|
|
22
|
+
this.request = '';
|
|
23
|
+
this.sequence = 0;
|
|
24
|
+
/** The agent's design failed to play: render the automatic choice instead, until the props change. */
|
|
25
|
+
this.automatic = false;
|
|
26
|
+
/** A fetch for this element's images failed: if it renders waiting again, it can't draw. */
|
|
27
|
+
this.imagesFailed = false;
|
|
28
|
+
this.widthDp = 0;
|
|
29
|
+
Object.defineProperties(element, {
|
|
30
|
+
liveryStats: { configurable: true, get: () => this.liveryStats },
|
|
31
|
+
liveryTheme: { configurable: true, get: () => this.liveryTheme },
|
|
32
|
+
liveryHostAction: { configurable: true, value: (a) => this.liveryHostAction(a) },
|
|
33
|
+
});
|
|
34
|
+
this.box.style.cssText = 'width:100%;height:100%;overflow:hidden';
|
|
35
|
+
}
|
|
36
|
+
connect() {
|
|
37
|
+
this.connected = true;
|
|
38
|
+
this.resize = new ResizeObserver(() => {
|
|
39
|
+
this.player?.resize(this.element.clientWidth, this.element.clientHeight, window.devicePixelRatio || 1);
|
|
40
|
+
const w = Math.round(this.element.clientWidth);
|
|
41
|
+
if (Math.abs(w - this.widthDp) > 8) {
|
|
42
|
+
this.widthDp = w;
|
|
43
|
+
this.request = '';
|
|
44
|
+
this.invalidate();
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
this.resize.observe(this.element);
|
|
48
|
+
}
|
|
49
|
+
update(api, context, resolved) {
|
|
50
|
+
if (this.livery && this.livery !== api) {
|
|
51
|
+
this.disconnect();
|
|
52
|
+
this.connect();
|
|
53
|
+
}
|
|
54
|
+
this.livery = api;
|
|
55
|
+
this.context = context;
|
|
56
|
+
this.resolved = resolved;
|
|
57
|
+
if (this.connected)
|
|
58
|
+
void this.sync();
|
|
59
|
+
}
|
|
60
|
+
invalidate() {
|
|
61
|
+
if (!this.connected)
|
|
62
|
+
return;
|
|
63
|
+
this.changed();
|
|
64
|
+
queueMicrotask(() => { if (this.connected)
|
|
65
|
+
void this.sync(); });
|
|
66
|
+
}
|
|
67
|
+
disconnect() {
|
|
68
|
+
this.connected = false;
|
|
69
|
+
this.resize?.disconnect();
|
|
70
|
+
this.sequence++;
|
|
71
|
+
if (this.render_ !== undefined)
|
|
72
|
+
this.livery?.session.release(this.render_);
|
|
73
|
+
this.render_ = undefined;
|
|
74
|
+
this.player?.dispose();
|
|
75
|
+
this.player = undefined;
|
|
76
|
+
this.shownPresentation = undefined;
|
|
77
|
+
this.request = '';
|
|
78
|
+
this.automatic = false;
|
|
79
|
+
this.automaticFor = undefined;
|
|
80
|
+
this.imagesFailed = false;
|
|
81
|
+
}
|
|
82
|
+
/** Documents this element's player loaded and values it set: a data change sets values, never reloads. */
|
|
83
|
+
get liveryStats() {
|
|
84
|
+
return this.player?.stats;
|
|
85
|
+
}
|
|
86
|
+
/** The theme roles of the last render, as `#AARRGGBB`. @internal For tests. */
|
|
87
|
+
get liveryTheme() {
|
|
88
|
+
return this.lastTheme;
|
|
89
|
+
}
|
|
90
|
+
/** The props Livery renders from: inputs and lists as A2UI resolved them, the rest as the agent wrote them. */
|
|
91
|
+
props(spec) {
|
|
92
|
+
const resolved = (this.resolved ?? {});
|
|
93
|
+
const raw = this.context.componentModel.properties;
|
|
94
|
+
const out = {};
|
|
95
|
+
for (const p of spec.properties) {
|
|
96
|
+
const value = DYNAMIC.has(p.kind) ? resolved[p.key] : raw[p.key];
|
|
97
|
+
if (value !== undefined)
|
|
98
|
+
out[p.key] = value;
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
/** Whether the page sets the component's height (`--livery-a2ui-height`), so selection can use it. */
|
|
103
|
+
pageHeight() {
|
|
104
|
+
return getComputedStyle(this.element).getPropertyValue('--livery-a2ui-height').trim() !== '';
|
|
105
|
+
}
|
|
106
|
+
/** `a2ui:<surfaceId>/<componentId>`: on every event of this component, so analytics can tell agent-placed templates from the app's own. */
|
|
107
|
+
decisionId() {
|
|
108
|
+
const component = this.context?.componentModel.id;
|
|
109
|
+
const surface = this.context?.dataContext.surface?.id;
|
|
110
|
+
return component && surface ? `a2ui:${surface}/${component}` : undefined;
|
|
111
|
+
}
|
|
112
|
+
async sync() {
|
|
113
|
+
const api = this.livery;
|
|
114
|
+
if (!api || !this.context)
|
|
115
|
+
return;
|
|
116
|
+
const { session, spec, options } = api;
|
|
117
|
+
// One player per element, for as long as the element lives: its document stays and values move.
|
|
118
|
+
this.player ??= typeof options.player === 'function'
|
|
119
|
+
? options.player(this.box, (a) => void this.onAction(a))
|
|
120
|
+
: new RcCanvasPlayer(this.box, (a) => void this.onAction(a));
|
|
121
|
+
const props = this.props(spec);
|
|
122
|
+
// After the chosen design failed to play, this element renders the automatic choice, until
|
|
123
|
+
// the agent changes the component.
|
|
124
|
+
const asked = JSON.stringify(props);
|
|
125
|
+
if (this.automaticFor !== undefined && this.automaticFor !== asked)
|
|
126
|
+
this.automatic = false;
|
|
127
|
+
if (this.automatic) {
|
|
128
|
+
this.automaticFor ??= asked;
|
|
129
|
+
delete props[DESIGN];
|
|
130
|
+
delete props[TEMPLATE];
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
this.automaticFor = undefined;
|
|
134
|
+
const density = window.devicePixelRatio || 1;
|
|
135
|
+
const space = { widthDp: this.widthDp || Math.round(this.element.clientWidth) || undefined, heightDp: this.pageHeight() ? Math.round(this.element.clientHeight) || undefined : undefined, density, colorScheme: matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light', theme: themeOf(this.element, this.context?.theme), decisionId: this.decisionId() };
|
|
136
|
+
this.lastTheme = space.theme;
|
|
137
|
+
const request = JSON.stringify([props, space]);
|
|
138
|
+
if (request === this.request)
|
|
139
|
+
return;
|
|
140
|
+
this.request = request;
|
|
141
|
+
const mine = ++this.sequence;
|
|
142
|
+
let r;
|
|
143
|
+
try {
|
|
144
|
+
r = await session.render(spec.name, props, space);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
if (mine === this.sequence)
|
|
148
|
+
this.cannotPlay(props, String(error));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (mine !== this.sequence) {
|
|
152
|
+
// A newer render is on its way: this one is never shown, so the session can drop its plan.
|
|
153
|
+
if (r.ok)
|
|
154
|
+
session.release(r.render);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (r.pending) {
|
|
158
|
+
// Draw the automatic plan while decisions and documents load off the render path.
|
|
159
|
+
void session.fetchPending().then(() => {
|
|
160
|
+
if (mine !== this.sequence || !this.connected)
|
|
161
|
+
return;
|
|
162
|
+
this.request = '';
|
|
163
|
+
this.invalidate();
|
|
164
|
+
});
|
|
165
|
+
if (!r.ok) {
|
|
166
|
+
this.fallback = r.reason;
|
|
167
|
+
this.invalidate();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (!r.ok && r.waiting && !this.imagesFailed) {
|
|
172
|
+
// An image isn't on the device: fetch it off the render path, then render again. Not the agent's problem.
|
|
173
|
+
session.whenImagesArrive((arrived) => {
|
|
174
|
+
if (mine !== this.sequence)
|
|
175
|
+
return;
|
|
176
|
+
this.imagesFailed = !arrived;
|
|
177
|
+
this.request = '';
|
|
178
|
+
this.invalidate();
|
|
179
|
+
});
|
|
180
|
+
void session.fetchImages();
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
this.imagesFailed = false;
|
|
184
|
+
if (!r.ok) {
|
|
185
|
+
this.cannotPlay(props, r.waiting ? `an image could not be fetched: ${r.reason}` : r.reason);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const wasFallback = this.fallback !== undefined;
|
|
189
|
+
this.fallback = undefined;
|
|
190
|
+
if (wasFallback) {
|
|
191
|
+
this.invalidate();
|
|
192
|
+
await this.settled();
|
|
193
|
+
}
|
|
194
|
+
// The height rule: the page's --livery-a2ui-height when it sets one, else the template's own.
|
|
195
|
+
// A template that doesn't say takes the default, never the last template's height.
|
|
196
|
+
if (r.heightDp)
|
|
197
|
+
this.element.style.setProperty('--livery-template-height', `${r.heightDp}px`);
|
|
198
|
+
else
|
|
199
|
+
this.element.style.removeProperty('--livery-template-height');
|
|
200
|
+
if (mine !== this.sequence) {
|
|
201
|
+
session.release(r.render);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const previous = this.render_;
|
|
205
|
+
this.render_ = r.render;
|
|
206
|
+
const player = this.player;
|
|
207
|
+
try {
|
|
208
|
+
const first = previous === undefined;
|
|
209
|
+
const shown = await player.show(r.documentKey, r.document, r.values, this.element.clientWidth, this.element.clientHeight, density);
|
|
210
|
+
if (shown && mine === this.sequence && !this.pageHeight() && player.measuredHeightDp) {
|
|
211
|
+
const height = Math.max(r.minHeightDp ?? 0, player.measuredHeightDp);
|
|
212
|
+
this.element.style.setProperty('--livery-template-height', `${height}px`);
|
|
213
|
+
player.resize(this.element.clientWidth, height, density);
|
|
214
|
+
}
|
|
215
|
+
// A decision can reuse the automatic document and still needs its own impression.
|
|
216
|
+
if (shown && mine === this.sequence && (first || this.shownPresentation !== r.presentationKey))
|
|
217
|
+
session.shown(r.render);
|
|
218
|
+
if (shown && mine === this.sequence)
|
|
219
|
+
this.shownPresentation = r.presentationKey;
|
|
220
|
+
}
|
|
221
|
+
catch (e) {
|
|
222
|
+
player.forget();
|
|
223
|
+
if (mine === this.sequence)
|
|
224
|
+
this.cannotPlay(props, `the player could not play ${r.design}: ${e.message}`);
|
|
225
|
+
}
|
|
226
|
+
if (previous !== undefined)
|
|
227
|
+
session.release(previous);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* This render can't draw. The agent hears why. A chosen design falls back to the automatic
|
|
231
|
+
* choice, never to nothing; the agent's own document is never replaced (PROTOCOL.md §5.3), so
|
|
232
|
+
* it, and an automatic choice that can't draw either, show the page's fallback.
|
|
233
|
+
*/
|
|
234
|
+
cannotPlay(props, reason) {
|
|
235
|
+
this.livery?.options.onProblem?.(this.livery.spec.name, reason);
|
|
236
|
+
if (!this.automatic && ((props[DESIGN] !== undefined && props[TEMPLATE] === undefined) || (props[TEMPLATE] && typeof props[TEMPLATE] === 'object' && 'query' in props[TEMPLATE]))) {
|
|
237
|
+
this.automatic = true;
|
|
238
|
+
this.request = '';
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
this.fallback = reason;
|
|
242
|
+
}
|
|
243
|
+
this.invalidate();
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* A host named action, exactly as the player's callback delivers one. @internal For tests that
|
|
247
|
+
* send a document's action with values its buttons wouldn't (an undeclared argument).
|
|
248
|
+
*/
|
|
249
|
+
liveryHostAction(a) {
|
|
250
|
+
return this.onAction(a);
|
|
251
|
+
}
|
|
252
|
+
async onAction(a) {
|
|
253
|
+
const api = this.livery;
|
|
254
|
+
if (this.render_ === undefined || !api)
|
|
255
|
+
return;
|
|
256
|
+
const { session, spec, options } = api;
|
|
257
|
+
const value = a.valueType === 'none' ? null : a.value;
|
|
258
|
+
const render = this.render_;
|
|
259
|
+
const routed = await session.action(render, a.name, a.valueType, value);
|
|
260
|
+
if (!this.connected || this.livery !== api || this.render_ !== render)
|
|
261
|
+
return;
|
|
262
|
+
switch (routed.route) {
|
|
263
|
+
case 'agent':
|
|
264
|
+
return this.dispatch(routed);
|
|
265
|
+
case 'set': {
|
|
266
|
+
const binding = this.context.componentModel.properties[routed.input];
|
|
267
|
+
if (binding && typeof binding === 'object' && typeof binding.path === 'string') {
|
|
268
|
+
this.context.dataContext.set(binding.path, routed.value);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
// A literal (or missing) binding has nowhere to write: tell the agent, as Kotlin does.
|
|
272
|
+
options.onProblem?.(spec.name, `${spec.name}.${routed.input} is not bound to a data-model path, so ${a.name} can't write it`);
|
|
273
|
+
}
|
|
274
|
+
if (routed.agent)
|
|
275
|
+
this.dispatch(routed.agent);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
case 'app':
|
|
279
|
+
return options.onAppAction?.(routed.kind, routed.action, routed.args, spec.name);
|
|
280
|
+
case 'dropped':
|
|
281
|
+
return; // Livery reported it as an event.
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
dispatch(agent) {
|
|
285
|
+
const api = this.livery;
|
|
286
|
+
if (api && agent.shadowed.length > 0)
|
|
287
|
+
api.options.onProblem?.(api.spec.name, `the event context names the template's own arguments ${JSON.stringify(agent.shadowed)}`);
|
|
288
|
+
void this.context.dispatchAction(agent.action);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Theme role inputs from CSS: `--livery-<role>` (kebab-case), else A2UI's own `--a2ui-color-<role>`,
|
|
293
|
+
* else Material 3's baseline, as `#AARRGGBB`.
|
|
294
|
+
*/
|
|
295
|
+
function themeOf(el, surface) {
|
|
296
|
+
const style = getComputedStyle(el);
|
|
297
|
+
const out = {};
|
|
298
|
+
// The agent's own colour first: A2UI's createSurface theme (`primaryColor` → `primary`).
|
|
299
|
+
const agent = { primary: surface?.primaryColor };
|
|
300
|
+
for (const role of THEME_ROLES) {
|
|
301
|
+
const name = kebab(role);
|
|
302
|
+
const asked = agent[role];
|
|
303
|
+
const fromAgent = typeof asked === 'string' ? cssColorToArgb(asked, el) : undefined;
|
|
304
|
+
const value = style.getPropertyValue(`--livery-${name}`).trim() || style.getPropertyValue(`--a2ui-color-${name}`).trim();
|
|
305
|
+
out[role] = fromAgent ?? (value ? cssColorToArgb(value, el) : undefined) ?? BASELINE[role];
|
|
306
|
+
}
|
|
307
|
+
return out;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Any CSS colour as `#AARRGGBB`, resolved where [el] is (so `light-dark()` and `var()` follow its
|
|
311
|
+
* colour scheme), or undefined when it isn't a colour.
|
|
312
|
+
*/
|
|
313
|
+
function cssColorToArgb(color, el) {
|
|
314
|
+
if (!CSS.supports('color', color))
|
|
315
|
+
return undefined;
|
|
316
|
+
const probe = document.createElement('span');
|
|
317
|
+
probe.style.display = 'none';
|
|
318
|
+
probe.style.color = color;
|
|
319
|
+
(el.shadowRoot ?? el).appendChild(probe);
|
|
320
|
+
const resolved = getComputedStyle(probe).color;
|
|
321
|
+
probe.remove();
|
|
322
|
+
const m = resolved.match(/^rgba?\(([^)]+)\)$/);
|
|
323
|
+
if (!m)
|
|
324
|
+
return undefined;
|
|
325
|
+
const parts = m[1].split(/[\s,/]+/).filter(Boolean).map(Number);
|
|
326
|
+
const [r, g, b] = parts;
|
|
327
|
+
const a = parts.length > 3 ? parts[3] : 1;
|
|
328
|
+
const hex = (n) => Math.round(Math.min(255, Math.max(0, n))).toString(16).padStart(2, '0').toUpperCase();
|
|
329
|
+
return `#${hex(a * 255)}${hex(r)}${hex(g)}${hex(b)}`;
|
|
330
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { LiverySession, loadLiveryWeb } from './livery.js';
|
|
2
|
+
export type { LiveryConfig, LiveryComponentSpec, LiveryPropertySpec, LiverySpace, LiveryWebModule, Rendered, Routed } from './livery.js';
|
|
3
|
+
export { liveryCatalog, liveryComponent } from './catalog.js';
|
|
4
|
+
export type { LiveryCatalogOptions, LiveryComponentApi } from './catalog.js';
|
|
5
|
+
export { RcCanvasPlayer } from './player.js';
|
|
6
|
+
export type { NamedAction, LiveryPlayer, LiveryPlayerFactory } from './player.js';
|
|
7
|
+
export { prepareCmpPlayer } from './cmp-player.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
type Nullable<T> = T | null | undefined
|
|
2
|
+
declare function KtSingleton<T>(): T & (abstract new() => any);
|
|
3
|
+
export declare function previewCreate(config: string): number;
|
|
4
|
+
export declare function previewConnect(session: number): not.exported.kotlin.js.Promise<unknown>;
|
|
5
|
+
export declare function previewRefresh(session: number): not.exported.kotlin.js.Promise<unknown>;
|
|
6
|
+
export declare function previewRender(session: number, contract: string, data: string, space: string, designId: Nullable<string>, sha256: Nullable<string>): not.exported.kotlin.js.Promise<unknown>;
|
|
7
|
+
export declare function previewFetchImages(session: number): not.exported.kotlin.js.Promise<unknown>;
|
|
8
|
+
export declare function previewShown(session: number, render: number): void;
|
|
9
|
+
export declare function previewRelease(session: number, render: number): void;
|
|
10
|
+
export declare function previewAction(session: number, render: number, name: string, valueType: string, value: Nullable<string>): not.exported.kotlin.js.Promise<unknown>;
|
|
11
|
+
export declare function previewEvents(session: number): string;
|
|
12
|
+
export declare function previewClose(id: number): void;
|
|
13
|
+
export declare function liveryOpen(config: string): not.exported.kotlin.js.Promise<unknown>;
|
|
14
|
+
export declare function liveryRefresh(session: number): not.exported.kotlin.js.Promise<unknown>;
|
|
15
|
+
export declare function liveryComponents(session: number): not.exported.kotlin.js.Promise<unknown>;
|
|
16
|
+
export declare function liveryCatalogSchema(session: number, catalogId: string): not.exported.kotlin.js.Promise<unknown>;
|
|
17
|
+
export declare function liveryRender(session: number, name: string, props: string, space: string): not.exported.kotlin.js.Promise<unknown>;
|
|
18
|
+
export declare function liveryFetchImages(session: number): not.exported.kotlin.js.Promise<unknown>;
|
|
19
|
+
export declare function liveryFetchPending(session: number): not.exported.kotlin.js.Promise<unknown>;
|
|
20
|
+
export declare function liveryShown(session: number, render: number): void;
|
|
21
|
+
export declare function liveryRelease(session: number, render: number): void;
|
|
22
|
+
export declare function liveryAction(session: number, render: number, name: string, valueType: string, value: Nullable<string>): not.exported.kotlin.js.Promise<unknown>;
|
|
23
|
+
export declare function liveryEvents(session: number): string;
|
|
24
|
+
export declare function liveryClose(session: number): void;
|
|
25
|
+
declare namespace not.exported.kotlin.js {
|
|
26
|
+
class Promise<out T> {
|
|
27
|
+
constructor(executor: (resolve: (p0: T) => void, reject: (p0: NonNullable<unknown>) => void) => void);
|
|
28
|
+
then<S>(onFulfilled: Nullable<(p0: T) => S>): not.exported.kotlin.js.Promise<S>;
|
|
29
|
+
then<S>(onFulfilled: Nullable<(p0: T) => S>, onRejected: Nullable<(p0: NonNullable<unknown>) => S>): not.exported.kotlin.js.Promise<S>;
|
|
30
|
+
catch<S>(onRejected: (p0: NonNullable<unknown>) => S): not.exported.kotlin.js.Promise<S>;
|
|
31
|
+
finally(onFinally: () => void): not.exported.kotlin.js.Promise<T>;
|
|
32
|
+
get _hashCode(): number;
|
|
33
|
+
set _hashCode(value: number);
|
|
34
|
+
}
|
|
35
|
+
namespace Promise {
|
|
36
|
+
/** @deprecated $metadata$ is used for internal purposes, please don't use it in your code, because it can be removed at any moment */
|
|
37
|
+
namespace $metadata$ {
|
|
38
|
+
const constructor: abstract new <T>() => Promise<T>;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
declare namespace not.exported.kotlin.js.Promise {
|
|
43
|
+
abstract class Companion extends KtSingleton<Companion.$metadata$.constructor>() {
|
|
44
|
+
private constructor();
|
|
45
|
+
}
|
|
46
|
+
namespace Companion {
|
|
47
|
+
/** @deprecated $metadata$ is used for internal purposes, please don't use it in your code, because it can be removed at any moment */
|
|
48
|
+
namespace $metadata$ {
|
|
49
|
+
abstract class constructor {
|
|
50
|
+
all<S>(promise: not.exported.kotlin.js.Array<not.exported.kotlin.js.Promise<S>>): not.exported.kotlin.js.Promise<not.exported.kotlin.js.Array<S>>;
|
|
51
|
+
race<S>(promise: not.exported.kotlin.js.Array<not.exported.kotlin.js.Promise<S>>): not.exported.kotlin.js.Promise<S>;
|
|
52
|
+
reject(e: NonNullable<unknown>): not.exported.kotlin.js.Promise<never>;
|
|
53
|
+
resolve<S>(e: S): not.exported.kotlin.js.Promise<S>;
|
|
54
|
+
resolve<S>(e: not.exported.kotlin.js.Promise<S>): not.exported.kotlin.js.Promise<S>;
|
|
55
|
+
get _hashCode(): number;
|
|
56
|
+
set _hashCode(value: number);
|
|
57
|
+
private constructor();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
declare namespace not.exported.kotlin.js {
|
|
63
|
+
class Array<T> {
|
|
64
|
+
constructor();
|
|
65
|
+
get length(): number;
|
|
66
|
+
get _hashCode(): number;
|
|
67
|
+
set _hashCode(value: number);
|
|
68
|
+
}
|
|
69
|
+
namespace Array {
|
|
70
|
+
/** @deprecated $metadata$ is used for internal purposes, please don't use it in your code, because it can be removed at any moment */
|
|
71
|
+
namespace $metadata$ {
|
|
72
|
+
const constructor: abstract new <T>() => Array<T>;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|