@a2ui/angular 0.8.2 → 0.9.0-alpha.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.
Files changed (48) hide show
  1. package/LICENSE +203 -0
  2. package/README.md +111 -3
  3. package/fesm2022/a2ui-angular-src-v0_8.mjs +1797 -0
  4. package/fesm2022/a2ui-angular-src-v0_8.mjs.map +1 -0
  5. package/fesm2022/a2ui-angular-src-v0_9.mjs +2330 -0
  6. package/fesm2022/a2ui-angular-src-v0_9.mjs.map +1 -0
  7. package/fesm2022/a2ui-angular-v0_8.mjs +1797 -0
  8. package/fesm2022/a2ui-angular-v0_8.mjs.map +1 -0
  9. package/fesm2022/a2ui-angular-v0_9.mjs +2330 -0
  10. package/fesm2022/a2ui-angular-v0_9.mjs.map +1 -0
  11. package/fesm2022/a2ui-angular.mjs +1558 -616
  12. package/fesm2022/a2ui-angular.mjs.map +1 -1
  13. package/package.json +51 -7
  14. package/types/a2ui-angular-src-v0_8.d.ts +400 -0
  15. package/types/a2ui-angular-src-v0_9.d.ts +813 -0
  16. package/types/a2ui-angular-v0_8.d.ts +400 -0
  17. package/types/a2ui-angular-v0_9.d.ts +813 -0
  18. package/types/a2ui-angular.d.ts +362 -35
  19. package/fesm2022/a2ui-angular-audio-DoZb9mn_.mjs +0 -48
  20. package/fesm2022/a2ui-angular-audio-DoZb9mn_.mjs.map +0 -1
  21. package/fesm2022/a2ui-angular-button-CvH0kAtN.mjs +0 -61
  22. package/fesm2022/a2ui-angular-button-CvH0kAtN.mjs.map +0 -1
  23. package/fesm2022/a2ui-angular-card-Ix6OIdUv.mjs +0 -48
  24. package/fesm2022/a2ui-angular-card-Ix6OIdUv.mjs.map +0 -1
  25. package/fesm2022/a2ui-angular-checkbox-BN4EF2Ci.mjs +0 -78
  26. package/fesm2022/a2ui-angular-checkbox-BN4EF2Ci.mjs.map +0 -1
  27. package/fesm2022/a2ui-angular-datetime-input-dmZAjvrF.mjs +0 -120
  28. package/fesm2022/a2ui-angular-datetime-input-dmZAjvrF.mjs.map +0 -1
  29. package/fesm2022/a2ui-angular-divider-BizPl3qL.mjs +0 -30
  30. package/fesm2022/a2ui-angular-divider-BizPl3qL.mjs.map +0 -1
  31. package/fesm2022/a2ui-angular-icon-BE9Hj9V6.mjs +0 -48
  32. package/fesm2022/a2ui-angular-icon-BE9Hj9V6.mjs.map +0 -1
  33. package/fesm2022/a2ui-angular-image-BWzAw0rh.mjs +0 -54
  34. package/fesm2022/a2ui-angular-image-BWzAw0rh.mjs.map +0 -1
  35. package/fesm2022/a2ui-angular-list-nEeT59V3.mjs +0 -45
  36. package/fesm2022/a2ui-angular-list-nEeT59V3.mjs.map +0 -1
  37. package/fesm2022/a2ui-angular-modal-mr9LmczA.mjs +0 -108
  38. package/fesm2022/a2ui-angular-modal-mr9LmczA.mjs.map +0 -1
  39. package/fesm2022/a2ui-angular-multiple-choice-Bry7X74i.mjs +0 -78
  40. package/fesm2022/a2ui-angular-multiple-choice-Bry7X74i.mjs.map +0 -1
  41. package/fesm2022/a2ui-angular-slider-BgseUbN2.mjs +0 -79
  42. package/fesm2022/a2ui-angular-slider-BgseUbN2.mjs.map +0 -1
  43. package/fesm2022/a2ui-angular-tabs-q5Mn9vgq.mjs +0 -87
  44. package/fesm2022/a2ui-angular-tabs-q5Mn9vgq.mjs.map +0 -1
  45. package/fesm2022/a2ui-angular-text-field-Deokh07j.mjs +0 -85
  46. package/fesm2022/a2ui-angular-text-field-Deokh07j.mjs.map +0 -1
  47. package/fesm2022/a2ui-angular-video-DuFTfN0B.mjs +0 -48
  48. package/fesm2022/a2ui-angular-video-DuFTfN0B.mjs.map +0 -1
@@ -1,133 +1,274 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Injectable, inject, input, Directive, ViewContainerRef, effect, untracked, PLATFORM_ID, DOCUMENT, inputBinding, makeEnvironmentProviders, computed, Component, SecurityContext, ViewEncapsulation } from '@angular/core';
3
- import { Data, Styles } from '@a2ui/lit/0.8';
4
- import { Subject, firstValueFrom } from 'rxjs';
5
- import { isPlatformBrowser } from '@angular/common';
6
- import { DomSanitizer } from '@angular/platform-browser';
7
- import MarkdownIt from 'markdown-it';
2
+ import { signal, Injectable, inject, input, Directive, computed, ChangeDetectionStrategy, Component, InjectionToken, ViewContainerRef, PLATFORM_ID, effect, ViewEncapsulation, makeEnvironmentProviders } from '@angular/core';
3
+ import { Subject } from 'rxjs';
4
+ import * as WebCore from '@a2ui/web_core/v0_8';
5
+ import { DOCUMENT, isPlatformBrowser, AsyncPipe } from '@angular/common';
6
+ import * as Styles from '@a2ui/web_core/styles/index';
7
+ import { structuralStyles } from '@a2ui/web_core/styles/index';
8
8
 
9
9
  /*
10
- Copyright 2025 Google LLC
11
-
12
- Licensed under the Apache License, Version 2.0 (the "License");
13
- you may not use this file except in compliance with the License.
14
- You may obtain a copy of the License at
15
-
16
- https://www.apache.org/licenses/LICENSE-2.0
17
-
18
- Unless required by applicable law or agreed to in writing, software
19
- distributed under the License is distributed on an "AS IS" BASIS,
20
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
- See the License for the specific language governing permissions and
22
- limitations under the License.
23
- */
24
- const Catalog = new InjectionToken('Catalog');
25
-
26
- /*
27
- Copyright 2025 Google LLC
28
-
29
- Licensed under the Apache License, Version 2.0 (the "License");
30
- you may not use this file except in compliance with the License.
31
- You may obtain a copy of the License at
32
-
33
- https://www.apache.org/licenses/LICENSE-2.0
34
-
35
- Unless required by applicable law or agreed to in writing, software
36
- distributed under the License is distributed on an "AS IS" BASIS,
37
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
38
- See the License for the specific language governing permissions and
39
- limitations under the License.
10
+ * Copyright 2025 Google LLC
11
+ *
12
+ * Licensed under the Apache License, Version 2.0 (the "License");
13
+ * you may not use this file except in compliance with the License.
14
+ * You may obtain a copy of the License at
15
+ *
16
+ * https://www.apache.org/licenses/LICENSE-2.0
17
+ *
18
+ * Unless required by applicable law or agreed to in writing, software
19
+ * distributed under the License is distributed on an "AS IS" BASIS,
20
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ * See the License for the specific language governing permissions and
22
+ * limitations under the License.
40
23
  */
41
- class MessageProcessor extends Data.A2uiMessageProcessor {
42
- events = new Subject();
43
- setData(node, relativePath, value, surfaceId) {
44
- // Override setData to convert from optional inputs (which can be null)
45
- // to undefined so that this correctly falls back to the default value for
46
- // surfaceId.
47
- return super.setData(node, relativePath, value, surfaceId ?? undefined);
24
+ class MessageProcessor {
25
+ baseProcessor;
26
+ eventsSubject = new Subject();
27
+ events = this.eventsSubject.asObservable();
28
+ // Signal to track the version of the data in the MessageProcessor. Since the base processor updates
29
+ // surfaces in-place (mutating the Map), we use this to force Angular's change detection to
30
+ // re-evaluate any components or effects that depend on getSurfaces().
31
+ versionSignal = signal(0, ...(ngDevMode ? [{ debugName: "versionSignal" }] : /* istanbul ignore next */ []));
32
+ version = this.versionSignal.asReadonly();
33
+ constructor() {
34
+ this.baseProcessor = new WebCore.A2uiMessageProcessor();
35
+ }
36
+ /**
37
+ * Increments the version signal to notify Angular that the data model has changed.
38
+ * This should be called after any update to the underlying base processor's surfaces.
39
+ */
40
+ notify() {
41
+ this.versionSignal.update((v) => v + 1);
42
+ }
43
+ processMessages(messages) {
44
+ this.baseProcessor.processMessages(messages);
45
+ this.notify();
48
46
  }
49
47
  dispatch(message) {
50
48
  const completion = new Subject();
51
- this.events.next({ message, completion });
52
- return firstValueFrom(completion);
49
+ const promise = new Promise((resolve, reject) => {
50
+ completion.subscribe({
51
+ next: (msgs) => resolve(msgs),
52
+ error: (err) => reject(err),
53
+ });
54
+ });
55
+ this.eventsSubject.next({ message, completion });
56
+ return promise;
57
+ }
58
+ getData(node, path, surfaceId) {
59
+ return this.baseProcessor.getData(node, path, surfaceId ?? undefined);
60
+ }
61
+ setData(node, path, value, surfaceId) {
62
+ this.baseProcessor.setData(node, path, value, surfaceId);
63
+ this.notify();
64
+ }
65
+ resolvePath(path, dataContextPath) {
66
+ return this.baseProcessor.resolvePath(path, dataContextPath);
67
+ }
68
+ getSurfaces() {
69
+ this.versionSignal(); // Track dependency
70
+ const allSurfaces = this.baseProcessor.getSurfaces();
71
+ const readySurfaces = new Map();
72
+ for (const [id, surface] of allSurfaces.entries()) {
73
+ if (surface.rootComponentId != null) {
74
+ readySurfaces.set(id, surface);
75
+ }
76
+ }
77
+ return readySurfaces;
78
+ }
79
+ clearSurfaces() {
80
+ this.baseProcessor.clearSurfaces();
81
+ this.notify();
53
82
  }
54
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: MessageProcessor, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
55
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: MessageProcessor, providedIn: 'root' });
83
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MessageProcessor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
84
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MessageProcessor, providedIn: 'root' });
56
85
  }
57
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: MessageProcessor, decorators: [{
86
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MessageProcessor, decorators: [{
58
87
  type: Injectable,
59
- args: [{ providedIn: 'root' }]
60
- }] });
88
+ args: [{
89
+ providedIn: 'root',
90
+ }]
91
+ }], ctorParameters: () => [] });
61
92
 
62
93
  /*
63
- Copyright 2025 Google LLC
64
-
65
- Licensed under the Apache License, Version 2.0 (the "License");
66
- you may not use this file except in compliance with the License.
67
- You may obtain a copy of the License at
68
-
69
- https://www.apache.org/licenses/LICENSE-2.0
70
-
71
- Unless required by applicable law or agreed to in writing, software
72
- distributed under the License is distributed on an "AS IS" BASIS,
73
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
74
- See the License for the specific language governing permissions and
75
- limitations under the License.
94
+ * Copyright 2025 Google LLC
95
+ *
96
+ * Licensed under the Apache License, Version 2.0 (the "License");
97
+ * you may not use this file except in compliance with the License.
98
+ * You may obtain a copy of the License at
99
+ *
100
+ * https://www.apache.org/licenses/LICENSE-2.0
101
+ *
102
+ * Unless required by applicable law or agreed to in writing, software
103
+ * distributed under the License is distributed on an "AS IS" BASIS,
104
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
105
+ * See the License for the specific language governing permissions and
106
+ * limitations under the License.
76
107
  */
77
108
 
78
109
  /*
79
- Copyright 2025 Google LLC
80
-
81
- Licensed under the Apache License, Version 2.0 (the "License");
82
- you may not use this file except in compliance with the License.
83
- You may obtain a copy of the License at
84
-
85
- https://www.apache.org/licenses/LICENSE-2.0
86
-
87
- Unless required by applicable law or agreed to in writing, software
88
- distributed under the License is distributed on an "AS IS" BASIS,
89
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
90
- See the License for the specific language governing permissions and
91
- limitations under the License.
110
+ * Copyright 2025 Google LLC
111
+ *
112
+ * Licensed under the Apache License, Version 2.0 (the "License");
113
+ * you may not use this file except in compliance with the License.
114
+ * You may obtain a copy of the License at
115
+ *
116
+ * https://www.apache.org/licenses/LICENSE-2.0
117
+ *
118
+ * Unless required by applicable law or agreed to in writing, software
119
+ * distributed under the License is distributed on an "AS IS" BASIS,
120
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
121
+ * See the License for the specific language governing permissions and
122
+ * limitations under the License.
92
123
  */
124
+ class MarkdownRenderer {
125
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MarkdownRenderer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
126
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MarkdownRenderer, providedIn: 'root' });
127
+ }
128
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MarkdownRenderer, decorators: [{
129
+ type: Injectable,
130
+ args: [{
131
+ providedIn: 'root',
132
+ }]
133
+ }] });
134
+ class DefaultMarkdownRenderer extends MarkdownRenderer {
135
+ static warningLogged = false;
136
+ async render(markdown, options) {
137
+ try {
138
+ // @ts-ignore - optional peer dependency
139
+ const { renderMarkdown } = await import('@a2ui/markdown-it');
140
+ return await renderMarkdown(markdown, options);
141
+ }
142
+ catch (e) {
143
+ if (!DefaultMarkdownRenderer.warningLogged) {
144
+ console.warn("[DefaultMarkdownRenderer] Failed to load optional `@a2ui/markdown-it` renderer. Using fallback regex.");
145
+ DefaultMarkdownRenderer.warningLogged = true;
146
+ }
147
+ // Basic implementation for v0.8
148
+ return markdown;
149
+ }
150
+ }
151
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: DefaultMarkdownRenderer, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
152
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: DefaultMarkdownRenderer, providedIn: 'root' });
153
+ }
154
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: DefaultMarkdownRenderer, decorators: [{
155
+ type: Injectable,
156
+ args: [{
157
+ providedIn: 'root',
158
+ }]
159
+ }] });
160
+ function provideMarkdownRenderer(renderFn) {
161
+ if (renderFn) {
162
+ return {
163
+ provide: MarkdownRenderer,
164
+ useValue: {
165
+ render: renderFn,
166
+ },
167
+ };
168
+ }
169
+ return { provide: MarkdownRenderer, useClass: DefaultMarkdownRenderer };
170
+ }
93
171
 
94
172
  /*
95
- Copyright 2025 Google LLC
96
-
97
- Licensed under the Apache License, Version 2.0 (the "License");
98
- you may not use this file except in compliance with the License.
99
- You may obtain a copy of the License at
100
-
101
- https://www.apache.org/licenses/LICENSE-2.0
173
+ * Copyright 2025 Google LLC
174
+ *
175
+ * Licensed under the Apache License, Version 2.0 (the "License");
176
+ * you may not use this file except in compliance with the License.
177
+ * You may obtain a copy of the License at
178
+ *
179
+ * https://www.apache.org/licenses/LICENSE-2.0
180
+ *
181
+ * Unless required by applicable law or agreed to in writing, software
182
+ * distributed under the License is distributed on an "AS IS" BASIS,
183
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
184
+ * See the License for the specific language governing permissions and
185
+ * limitations under the License.
186
+ */
102
187
 
103
- Unless required by applicable law or agreed to in writing, software
104
- distributed under the License is distributed on an "AS IS" BASIS,
105
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
106
- See the License for the specific language governing permissions and
107
- limitations under the License.
188
+ /*
189
+ * Copyright 2025 Google LLC
190
+ *
191
+ * Licensed under the Apache License, Version 2.0 (the "License");
192
+ * you may not use this file except in compliance with the License.
193
+ * You may obtain a copy of the License at
194
+ *
195
+ * https://www.apache.org/licenses/LICENSE-2.0
196
+ *
197
+ * Unless required by applicable law or agreed to in writing, software
198
+ * distributed under the License is distributed on an "AS IS" BASIS,
199
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ * See the License for the specific language governing permissions and
201
+ * limitations under the License.
108
202
  */
109
- const Theme = new InjectionToken('Theme');
203
+ class Theme {
204
+ components = {};
205
+ elements = {};
206
+ markdown = {
207
+ p: [],
208
+ h1: [],
209
+ h2: [],
210
+ h3: [],
211
+ h4: [],
212
+ h5: [],
213
+ ul: [],
214
+ ol: [],
215
+ li: [],
216
+ a: [],
217
+ strong: [],
218
+ em: [],
219
+ };
220
+ additionalStyles;
221
+ update(theme) {
222
+ this.components = theme.components;
223
+ this.elements = theme.elements;
224
+ this.markdown = theme.markdown;
225
+ this.additionalStyles = theme.additionalStyles;
226
+ }
227
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Theme, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
228
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Theme, providedIn: 'root' });
229
+ }
230
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Theme, decorators: [{
231
+ type: Injectable,
232
+ args: [{
233
+ providedIn: 'root',
234
+ }]
235
+ }] });
110
236
 
237
+ /*
238
+ * Copyright 2025 Google LLC
239
+ *
240
+ * Licensed under the Apache License, Version 2.0 (the "License");
241
+ * you may not use this file except in compliance with the License.
242
+ * You may obtain a copy of the License at
243
+ *
244
+ * https://www.apache.org/licenses/LICENSE-2.0
245
+ *
246
+ * Unless required by applicable law or agreed to in writing, software
247
+ * distributed under the License is distributed on an "AS IS" BASIS,
248
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
249
+ * See the License for the specific language governing permissions and
250
+ * limitations under the License.
251
+ */
111
252
  let idCounter = 0;
112
253
  class DynamicComponent {
113
254
  processor = inject(MessageProcessor);
114
255
  theme = inject(Theme);
115
- surfaceId = input.required(...(ngDevMode ? [{ debugName: "surfaceId" }] : []));
116
- component = input.required(...(ngDevMode ? [{ debugName: "component" }] : []));
117
- weight = input.required(...(ngDevMode ? [{ debugName: "weight" }] : []));
256
+ surfaceId = input.required(...(ngDevMode ? [{ debugName: "surfaceId" }] : /* istanbul ignore next */ []));
257
+ component = input.required(...(ngDevMode ? [{ debugName: "component" }] : /* istanbul ignore next */ []));
258
+ weight = input.required(...(ngDevMode ? [{ debugName: "weight" }] : /* istanbul ignore next */ []));
118
259
  sendAction(action) {
119
260
  const component = this.component();
120
261
  const surfaceId = this.surfaceId() ?? undefined;
121
262
  const context = {};
122
263
  if (action.context) {
123
264
  for (const item of action.context) {
124
- if (item.value.literalBoolean) {
265
+ if (item.value.literalBoolean !== undefined) {
125
266
  context[item.key] = item.value.literalBoolean;
126
267
  }
127
- else if (item.value.literalNumber) {
268
+ else if (item.value.literalNumber !== undefined) {
128
269
  context[item.key] = item.value.literalNumber;
129
270
  }
130
- else if (item.value.literalString) {
271
+ else if (item.value.literalString !== undefined) {
131
272
  context[item.key] = item.value.literalString;
132
273
  }
133
274
  else if (item.value.path) {
@@ -154,7 +295,7 @@ class DynamicComponent {
154
295
  if (!value || typeof value !== 'object') {
155
296
  return null;
156
297
  }
157
- else if (value.literal != null) {
298
+ else if ('literal' in value && value.literal != null) {
158
299
  return value.literal;
159
300
  }
160
301
  else if (value.path) {
@@ -174,10 +315,10 @@ class DynamicComponent {
174
315
  getUniqueId(prefix) {
175
316
  return `${prefix}-${idCounter++}`;
176
317
  }
177
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DynamicComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
178
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.3", type: DynamicComponent, isStandalone: true, inputs: { surfaceId: { classPropertyName: "surfaceId", publicName: "surfaceId", isSignal: true, isRequired: true, transformFunction: null }, component: { classPropertyName: "component", publicName: "component", isSignal: true, isRequired: true, transformFunction: null }, weight: { classPropertyName: "weight", publicName: "weight", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "style.--weight": "weight()" } }, ngImport: i0 });
318
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: DynamicComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
319
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: DynamicComponent, isStandalone: true, inputs: { surfaceId: { classPropertyName: "surfaceId", publicName: "surfaceId", isSignal: true, isRequired: true, transformFunction: null }, component: { classPropertyName: "component", publicName: "component", isSignal: true, isRequired: true, transformFunction: null }, weight: { classPropertyName: "weight", publicName: "weight", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "style.--weight": "weight()" } }, ngImport: i0 });
179
320
  }
180
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: DynamicComponent, decorators: [{
321
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: DynamicComponent, decorators: [{
181
322
  type: Directive,
182
323
  args: [{
183
324
  host: {
@@ -187,345 +328,1097 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
187
328
  }], propDecorators: { surfaceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceId", required: true }] }], component: [{ type: i0.Input, args: [{ isSignal: true, alias: "component", required: true }] }], weight: [{ type: i0.Input, args: [{ isSignal: true, alias: "weight", required: true }] }] } });
188
329
 
189
330
  /*
190
- Copyright 2025 Google LLC
191
-
192
- Licensed under the Apache License, Version 2.0 (the "License");
193
- you may not use this file except in compliance with the License.
194
- You may obtain a copy of the License at
331
+ * Copyright 2025 Google LLC
332
+ *
333
+ * Licensed under the Apache License, Version 2.0 (the "License");
334
+ * you may not use this file except in compliance with the License.
335
+ * You may obtain a copy of the License at
336
+ *
337
+ * https://www.apache.org/licenses/LICENSE-2.0
338
+ *
339
+ * Unless required by applicable law or agreed to in writing, software
340
+ * distributed under the License is distributed on an "AS IS" BASIS,
341
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
342
+ * See the License for the specific language governing permissions and
343
+ * limitations under the License.
344
+ */
345
+ class AudioPlayer extends DynamicComponent {
346
+ url = input.required(...(ngDevMode ? [{ debugName: "url" }] : /* istanbul ignore next */ []));
347
+ resolvedUrl = computed(() => this.resolvePrimitive(this.url()), ...(ngDevMode ? [{ debugName: "resolvedUrl" }] : /* istanbul ignore next */ []));
348
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AudioPlayer, deps: null, target: i0.ɵɵFactoryTarget.Component });
349
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.5", type: AudioPlayer, isStandalone: true, selector: "a2ui-audio", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
350
+ <audio controls [src]="resolvedUrl()" [style]="theme.additionalStyles?.AudioPlayer"></audio>
351
+ `, isInline: true, styles: [":host{display:flex}audio{width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
352
+ }
353
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: AudioPlayer, decorators: [{
354
+ type: Component,
355
+ args: [{ selector: 'a2ui-audio', template: `
356
+ <audio controls [src]="resolvedUrl()" [style]="theme.additionalStyles?.AudioPlayer"></audio>
357
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:flex}audio{width:100%}\n"] }]
358
+ }], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }] } });
195
359
 
196
- https://www.apache.org/licenses/LICENSE-2.0
360
+ /*
361
+ * Copyright 2025 Google LLC
362
+ *
363
+ * Licensed under the Apache License, Version 2.0 (the "License");
364
+ * you may not use this file except in compliance with the License.
365
+ * You may obtain a copy of the License at
366
+ *
367
+ * https://www.apache.org/licenses/LICENSE-2.0
368
+ *
369
+ * Unless required by applicable law or agreed to in writing, software
370
+ * distributed under the License is distributed on an "AS IS" BASIS,
371
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
372
+ * See the License for the specific language governing permissions and
373
+ * limitations under the License.
374
+ */
375
+ const Catalog = new InjectionToken('Catalog');
197
376
 
198
- Unless required by applicable law or agreed to in writing, software
199
- distributed under the License is distributed on an "AS IS" BASIS,
200
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
- See the License for the specific language governing permissions and
202
- limitations under the License.
377
+ /*
378
+ * Copyright 2025 Google LLC
379
+ *
380
+ * Licensed under the Apache License, Version 2.0 (the "License");
381
+ * you may not use this file except in compliance with the License.
382
+ * You may obtain a copy of the License at
383
+ *
384
+ * https://www.apache.org/licenses/LICENSE-2.0
385
+ *
386
+ * Unless required by applicable law or agreed to in writing, software
387
+ * distributed under the License is distributed on an "AS IS" BASIS,
388
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
389
+ * See the License for the specific language governing permissions and
390
+ * limitations under the License.
203
391
  */
204
392
  class Renderer {
205
- viewContainerRef = inject(ViewContainerRef);
206
- catalog = inject(Catalog);
207
393
  static hasInsertedStyles = false;
208
- currentRef = null;
209
- isDestroyed = false;
210
- surfaceId = input.required(...(ngDevMode ? [{ debugName: "surfaceId" }] : []));
211
- component = input.required(...(ngDevMode ? [{ debugName: "component" }] : []));
394
+ catalog = inject(Catalog);
395
+ container = inject(ViewContainerRef);
396
+ processor = inject(MessageProcessor);
397
+ surfaceId = input.required(...(ngDevMode ? [{ debugName: "surfaceId" }] : /* istanbul ignore next */ []));
398
+ component = input.required(...(ngDevMode ? [{ debugName: "component" }] : /* istanbul ignore next */ []));
399
+ currentId = null;
400
+ currentType = null;
401
+ currentComponentRef = null;
212
402
  constructor() {
213
- effect(() => {
214
- const surfaceId = this.surfaceId();
215
- const component = this.component();
216
- untracked(() => this.render(surfaceId, component));
217
- });
218
403
  const platformId = inject(PLATFORM_ID);
219
404
  const document = inject(DOCUMENT);
220
405
  if (!Renderer.hasInsertedStyles && isPlatformBrowser(platformId)) {
221
- const styles = document.createElement('style');
222
- styles.textContent = Styles.structuralStyles;
223
- document.head.appendChild(styles);
406
+ const styleElement = document.createElement('style');
407
+ styleElement.textContent = structuralStyles;
408
+ document.head.appendChild(styleElement);
224
409
  Renderer.hasInsertedStyles = true;
225
410
  }
411
+ effect(() => {
412
+ // Explicitly depend on the MessageProcessor's version signal. This ensures that the effect re-runs
413
+ // whenever data model changes occur, even if the node's object reference remains identical
414
+ // (as in the case of in-place mutations from local updates).
415
+ this.processor.version();
416
+ let node = this.component();
417
+ const surfaceId = this.surfaceId();
418
+ // Handle v0.8 wrapped component format
419
+ if (!node.type && node.component) {
420
+ const wrapped = node.component;
421
+ const type = Object.keys(wrapped)[0];
422
+ if (type) {
423
+ node = {
424
+ ...node,
425
+ type: type,
426
+ properties: wrapped[type],
427
+ };
428
+ }
429
+ }
430
+ const id = node.id;
431
+ const type = node.type;
432
+ // Focus Loss Prevention:
433
+ // If we have an existing component and its unique identity (ID and Type) hasn't changed,
434
+ // we update its @Input() values in-place. This preserves the underlying DOM element,
435
+ // maintaining focus, text selection, and cursor position.
436
+ if (this.currentComponentRef && this.currentId === id && this.currentType === type) {
437
+ this.updateInputs(this.currentComponentRef, node, surfaceId);
438
+ return;
439
+ }
440
+ // Otherwise, clear and re-create the component because its identity has changed.
441
+ const container = this.container;
442
+ container.clear();
443
+ this.currentComponentRef = null;
444
+ this.currentId = id;
445
+ this.currentType = type;
446
+ const config = this.catalog[node.type];
447
+ if (!config) {
448
+ console.error(`Unknown component type: ${node.type}`);
449
+ return;
450
+ }
451
+ this.render(container, node, surfaceId, config);
452
+ });
226
453
  }
227
- ngOnDestroy() {
228
- this.isDestroyed = true;
229
- this.clear();
454
+ render(container, node, surfaceId, config) {
455
+ const componentTypeOrPromise = this.resolveComponentType(config);
456
+ if (componentTypeOrPromise instanceof Promise) {
457
+ componentTypeOrPromise.then((componentType) => {
458
+ // Ensure we are still supposed to render this component
459
+ if (this.currentId === node.id && this.currentType === node.type) {
460
+ const componentRef = container.createComponent(componentType);
461
+ this.currentComponentRef = componentRef;
462
+ this.updateInputs(componentRef, node, surfaceId);
463
+ }
464
+ });
465
+ }
466
+ else if (componentTypeOrPromise) {
467
+ const componentRef = container.createComponent(componentTypeOrPromise);
468
+ this.currentComponentRef = componentRef;
469
+ this.updateInputs(componentRef, node, surfaceId);
470
+ }
230
471
  }
231
- async render(surfaceId, component) {
232
- const config = this.catalog[component.type];
233
- let newComponent = null;
234
- let componentBindings = null;
472
+ resolveComponentType(config) {
235
473
  if (typeof config === 'function') {
236
- newComponent = await config();
237
- }
238
- else if (typeof config === 'object') {
239
- newComponent = await config.type();
240
- componentBindings = config.bindings(component);
241
- }
242
- this.clear();
243
- if (newComponent && !this.isDestroyed) {
244
- const bindings = [
245
- inputBinding('surfaceId', () => surfaceId),
246
- inputBinding('component', () => component),
247
- inputBinding('weight', () => component.weight ?? 'initial'),
248
- ];
249
- if (componentBindings) {
250
- bindings.push(...componentBindings);
474
+ return config();
475
+ }
476
+ else if (typeof config === 'object' && config !== null) {
477
+ if (typeof config.type === 'function') {
478
+ return config.type();
479
+ }
480
+ else {
481
+ return config.type;
251
482
  }
252
- this.currentRef = this.viewContainerRef.createComponent(newComponent, {
253
- bindings,
254
- injector: this.viewContainerRef.injector,
255
- });
256
483
  }
484
+ return null;
257
485
  }
258
- clear() {
259
- this.currentRef?.destroy();
260
- this.currentRef = null;
486
+ /**
487
+ * Updates the inputs of an existing component instance with the latest data from the node.
488
+ * This is called during component reuse to keep the UI in sync without losing DOM state (like focus).
489
+ */
490
+ updateInputs(componentRef, node, surfaceId) {
491
+ componentRef.setInput('surfaceId', surfaceId);
492
+ componentRef.setInput('component', node);
493
+ componentRef.setInput('weight', node.weight ?? 0);
494
+ const props = node.properties;
495
+ for (const [key, value] of Object.entries(props)) {
496
+ try {
497
+ componentRef.setInput(key, value);
498
+ }
499
+ catch (e) {
500
+ console.warn(`[Renderer] Property "${key}" could not be set on component ${node.type}. If this property is required by the specification, ensure the component declares it as an input.`);
501
+ }
502
+ }
503
+ componentRef.changeDetectorRef.markForCheck();
261
504
  }
262
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Renderer, deps: [], target: i0.ɵɵFactoryTarget.Directive });
263
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.3", type: Renderer, isStandalone: true, selector: "ng-container[a2ui-renderer]", inputs: { surfaceId: { classPropertyName: "surfaceId", publicName: "surfaceId", isSignal: true, isRequired: true, transformFunction: null }, component: { classPropertyName: "component", publicName: "component", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
505
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Renderer, deps: [], target: i0.ɵɵFactoryTarget.Directive });
506
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.5", type: Renderer, isStandalone: true, selector: "[a2ui-renderer]", inputs: { surfaceId: { classPropertyName: "surfaceId", publicName: "surfaceId", isSignal: true, isRequired: true, transformFunction: null }, component: { classPropertyName: "component", publicName: "component", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
264
507
  }
265
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Renderer, decorators: [{
508
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Renderer, decorators: [{
266
509
  type: Directive,
267
510
  args: [{
268
- selector: 'ng-container[a2ui-renderer]',
511
+ selector: '[a2ui-renderer]',
512
+ standalone: true,
269
513
  }]
270
514
  }], ctorParameters: () => [], propDecorators: { surfaceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceId", required: true }] }], component: [{ type: i0.Input, args: [{ isSignal: true, alias: "component", required: true }] }] } });
271
515
 
272
516
  /*
273
- Copyright 2025 Google LLC
517
+ * Copyright 2025 Google LLC
518
+ *
519
+ * Licensed under the Apache License, Version 2.0 (the "License");
520
+ * you may not use this file except in compliance with the License.
521
+ * You may obtain a copy of the License at
522
+ *
523
+ * https://www.apache.org/licenses/LICENSE-2.0
524
+ *
525
+ * Unless required by applicable law or agreed to in writing, software
526
+ * distributed under the License is distributed on an "AS IS" BASIS,
527
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
528
+ * See the License for the specific language governing permissions and
529
+ * limitations under the License.
530
+ */
531
+ class Button extends DynamicComponent {
532
+ action = input(null, ...(ngDevMode ? [{ debugName: "action" }] : /* istanbul ignore next */ []));
533
+ child = input(null, ...(ngDevMode ? [{ debugName: "child" }] : /* istanbul ignore next */ []));
534
+ // This is currently not handled by the template.
535
+ primary = input(false, ...(ngDevMode ? [{ debugName: "primary" }] : /* istanbul ignore next */ []));
536
+ handleClick() {
537
+ const action = this.action();
538
+ if (action) {
539
+ super.sendAction(action);
540
+ }
541
+ }
542
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Button, deps: null, target: i0.ɵɵFactoryTarget.Component });
543
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Button, isStandalone: true, selector: "a2ui-button", inputs: { action: { classPropertyName: "action", publicName: "action", isSignal: true, isRequired: false, transformFunction: null }, child: { classPropertyName: "child", publicName: "child", isSignal: true, isRequired: false, transformFunction: null }, primary: { classPropertyName: "primary", publicName: "primary", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
544
+ <button
545
+ [class]="theme.components.Button"
546
+ [style]="theme.additionalStyles?.Button"
547
+ (click)="handleClick()"
548
+ >
549
+ @if (child()) {
550
+ <ng-container
551
+ a2ui-renderer
552
+ [surfaceId]="surfaceId()!"
553
+ [component]="child() ?? component().properties.child"
554
+ />
555
+ }
556
+ </button>
557
+ `, isInline: true, styles: [":host{display:block;flex:var(--weight);min-height:0}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "[a2ui-renderer]", inputs: ["surfaceId", "component"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
558
+ }
559
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Button, decorators: [{
560
+ type: Component,
561
+ args: [{ selector: 'a2ui-button', imports: [Renderer], changeDetection: ChangeDetectionStrategy.Eager, template: `
562
+ <button
563
+ [class]="theme.components.Button"
564
+ [style]="theme.additionalStyles?.Button"
565
+ (click)="handleClick()"
566
+ >
567
+ @if (child()) {
568
+ <ng-container
569
+ a2ui-renderer
570
+ [surfaceId]="surfaceId()!"
571
+ [component]="child() ?? component().properties.child"
572
+ />
573
+ }
574
+ </button>
575
+ `, styles: [":host{display:block;flex:var(--weight);min-height:0}\n"] }]
576
+ }], propDecorators: { action: [{ type: i0.Input, args: [{ isSignal: true, alias: "action", required: false }] }], child: [{ type: i0.Input, args: [{ isSignal: true, alias: "child", required: false }] }], primary: [{ type: i0.Input, args: [{ isSignal: true, alias: "primary", required: false }] }] } });
274
577
 
275
- Licensed under the Apache License, Version 2.0 (the "License");
276
- you may not use this file except in compliance with the License.
277
- You may obtain a copy of the License at
578
+ /*
579
+ * Copyright 2025 Google LLC
580
+ *
581
+ * Licensed under the Apache License, Version 2.0 (the "License");
582
+ * you may not use this file except in compliance with the License.
583
+ * You may obtain a copy of the License at
584
+ *
585
+ * https://www.apache.org/licenses/LICENSE-2.0
586
+ *
587
+ * Unless required by applicable law or agreed to in writing, software
588
+ * distributed under the License is distributed on an "AS IS" BASIS,
589
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
590
+ * See the License for the specific language governing permissions and
591
+ * limitations under the License.
592
+ */
593
+ class Card extends DynamicComponent {
594
+ child = input(null, ...(ngDevMode ? [{ debugName: "child" }] : /* istanbul ignore next */ []));
595
+ children = input([], ...(ngDevMode ? [{ debugName: "children" }] : /* istanbul ignore next */ []));
596
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Card, deps: null, target: i0.ɵɵFactoryTarget.Component });
597
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Card, isStandalone: true, selector: "a2ui-card", inputs: { child: { classPropertyName: "child", publicName: "child", isSignal: true, isRequired: false, transformFunction: null }, children: { classPropertyName: "children", publicName: "children", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
598
+ <div [class]="theme.components.Card" [style]="theme.additionalStyles?.Card">
599
+ @if (child()) {
600
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child()!" />
601
+ }
278
602
 
279
- https://www.apache.org/licenses/LICENSE-2.0
603
+ @for (comp of children(); track comp.id) {
604
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="comp" />
605
+ }
606
+ </div>
607
+ `, isInline: true, styles: [":host{display:block}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "[a2ui-renderer]", inputs: ["surfaceId", "component"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
608
+ }
609
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Card, decorators: [{
610
+ type: Component,
611
+ args: [{ selector: 'a2ui-card', imports: [Renderer], template: `
612
+ <div [class]="theme.components.Card" [style]="theme.additionalStyles?.Card">
613
+ @if (child()) {
614
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child()!" />
615
+ }
616
+
617
+ @for (comp of children(); track comp.id) {
618
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="comp" />
619
+ }
620
+ </div>
621
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
622
+ }], propDecorators: { child: [{ type: i0.Input, args: [{ isSignal: true, alias: "child", required: false }] }], children: [{ type: i0.Input, args: [{ isSignal: true, alias: "children", required: false }] }] } });
280
623
 
281
- Unless required by applicable law or agreed to in writing, software
282
- distributed under the License is distributed on an "AS IS" BASIS,
283
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
284
- See the License for the specific language governing permissions and
285
- limitations under the License.
624
+ /*
625
+ * Copyright 2025 Google LLC
626
+ *
627
+ * Licensed under the Apache License, Version 2.0 (the "License");
628
+ * you may not use this file except in compliance with the License.
629
+ * You may obtain a copy of the License at
630
+ *
631
+ * https://www.apache.org/licenses/LICENSE-2.0
632
+ *
633
+ * Unless required by applicable law or agreed to in writing, software
634
+ * distributed under the License is distributed on an "AS IS" BASIS,
635
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
636
+ * See the License for the specific language governing permissions and
637
+ * limitations under the License.
286
638
  */
639
+ class Checkbox extends DynamicComponent {
640
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
641
+ checked = input.required(...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
642
+ inputChecked = computed(() => super.resolvePrimitive(this.checked()) ?? false, ...(ngDevMode ? [{ debugName: "inputChecked" }] : /* istanbul ignore next */ []));
643
+ resolvedLabel = computed(() => super.resolvePrimitive(this.label()), ...(ngDevMode ? [{ debugName: "resolvedLabel" }] : /* istanbul ignore next */ []));
644
+ inputId = super.getUniqueId('a2ui-checkbox');
645
+ onToggle(event) {
646
+ const checked = event.target.checked;
647
+ const checkedNode = this.checked();
648
+ if (checkedNode && typeof checkedNode === 'object' && 'path' in checkedNode && checkedNode.path) {
649
+ // Update the local data model directly to ensure immediate UI feedback and avoid unnecessary network requests.
650
+ this.processor.processMessages([{
651
+ dataModelUpdate: {
652
+ surfaceId: this.surfaceId(),
653
+ path: this.processor.resolvePath(checkedNode.path, this.component().dataContextPath),
654
+ contents: [{ key: '.', valueBoolean: checked }],
655
+ },
656
+ }]);
657
+ }
658
+ else {
659
+ this.sendAction({
660
+ name: 'toggle',
661
+ context: [{ key: 'checked', value: { literalBoolean: checked } }],
662
+ });
663
+ }
664
+ }
665
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Checkbox, deps: null, target: i0.ɵɵFactoryTarget.Component });
666
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.5", type: Checkbox, isStandalone: true, selector: "a2ui-checkbox", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
667
+ <label>
668
+ <input
669
+ type="checkbox"
670
+ [id]="inputId"
671
+ [checked]="inputChecked()"
672
+ (change)="onToggle($event)"
673
+ />
674
+ {{ resolvedLabel() }}
675
+ </label>
676
+ `, isInline: true, styles: [":host{display:flex;align-items:center;gap:.5rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
677
+ }
678
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Checkbox, decorators: [{
679
+ type: Component,
680
+ args: [{ selector: 'a2ui-checkbox', template: `
681
+ <label>
682
+ <input
683
+ type="checkbox"
684
+ [id]="inputId"
685
+ [checked]="inputChecked()"
686
+ (change)="onToggle($event)"
687
+ />
688
+ {{ resolvedLabel() }}
689
+ </label>
690
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:flex;align-items:center;gap:.5rem}\n"] }]
691
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: true }] }] } });
287
692
 
288
693
  /*
289
- Copyright 2025 Google LLC
694
+ * Copyright 2025 Google LLC
695
+ *
696
+ * Licensed under the Apache License, Version 2.0 (the "License");
697
+ * you may not use this file except in compliance with the License.
698
+ * You may obtain a copy of the License at
699
+ *
700
+ * https://www.apache.org/licenses/LICENSE-2.0
701
+ *
702
+ * Unless required by applicable law or agreed to in writing, software
703
+ * distributed under the License is distributed on an "AS IS" BASIS,
704
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
705
+ * See the License for the specific language governing permissions and
706
+ * limitations under the License.
707
+ */
708
+ class Column extends DynamicComponent {
709
+ alignment = input('stretch', ...(ngDevMode ? [{ debugName: "alignment" }] : /* istanbul ignore next */ []));
710
+ distribution = input('start', ...(ngDevMode ? [{ debugName: "distribution" }] : /* istanbul ignore next */ []));
711
+ children = input(...(ngDevMode ? [undefined, { debugName: "children" }] : /* istanbul ignore next */ []));
712
+ classes = computed(() => ({
713
+ ...this.theme.components.Column,
714
+ [`align-${this.alignment()}`]: true,
715
+ [`distribute-${this.distribution()}`]: true,
716
+ }), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
717
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Column, deps: null, target: i0.ɵɵFactoryTarget.Component });
718
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Column, isStandalone: true, selector: "a2ui-column", inputs: { alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null }, distribution: { classPropertyName: "distribution", publicName: "distribution", isSignal: true, isRequired: false, transformFunction: null }, children: { classPropertyName: "children", publicName: "children", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
719
+ <section [class]="classes()" [style]="theme.additionalStyles?.Column">
720
+ @for (child of children() ?? component().properties.children; track child?.id ?? child) {
721
+ @if (child) {
722
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child" />
723
+ }
724
+ }
725
+ </section>
726
+ `, isInline: true, styles: [":host{display:flex;flex:var(--weight)}section{display:flex;flex-direction:column;min-width:100%;height:100%;box-sizing:border-box}.align-start{align-items:start}.align-center{align-items:center}.align-end{align-items:end}.align-stretch{align-items:stretch}.distribute-start{justify-content:start}.distribute-center{justify-content:center}.distribute-end{justify-content:end}.distribute-spaceBetween{justify-content:space-between}.distribute-spaceAround{justify-content:space-around}.distribute-spaceEvenly{justify-content:space-evenly}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "[a2ui-renderer]", inputs: ["surfaceId", "component"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
727
+ }
728
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Column, decorators: [{
729
+ type: Component,
730
+ args: [{ selector: 'a2ui-column', imports: [Renderer], changeDetection: ChangeDetectionStrategy.Eager, template: `
731
+ <section [class]="classes()" [style]="theme.additionalStyles?.Column">
732
+ @for (child of children() ?? component().properties.children; track child?.id ?? child) {
733
+ @if (child) {
734
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child" />
735
+ }
736
+ }
737
+ </section>
738
+ `, styles: [":host{display:flex;flex:var(--weight)}section{display:flex;flex-direction:column;min-width:100%;height:100%;box-sizing:border-box}.align-start{align-items:start}.align-center{align-items:center}.align-end{align-items:end}.align-stretch{align-items:stretch}.distribute-start{justify-content:start}.distribute-center{justify-content:center}.distribute-end{justify-content:end}.distribute-spaceBetween{justify-content:space-between}.distribute-spaceAround{justify-content:space-around}.distribute-spaceEvenly{justify-content:space-evenly}\n"] }]
739
+ }], propDecorators: { alignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignment", required: false }] }], distribution: [{ type: i0.Input, args: [{ isSignal: true, alias: "distribution", required: false }] }], children: [{ type: i0.Input, args: [{ isSignal: true, alias: "children", required: false }] }] } });
290
740
 
291
- Licensed under the Apache License, Version 2.0 (the "License");
292
- you may not use this file except in compliance with the License.
293
- You may obtain a copy of the License at
741
+ /*
742
+ * Copyright 2025 Google LLC
743
+ *
744
+ * Licensed under the Apache License, Version 2.0 (the "License");
745
+ * you may not use this file except in compliance with the License.
746
+ * You may obtain a copy of the License at
747
+ *
748
+ * https://www.apache.org/licenses/LICENSE-2.0
749
+ *
750
+ * Unless required by applicable law or agreed to in writing, software
751
+ * distributed under the License is distributed on an "AS IS" BASIS,
752
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
753
+ * See the License for the specific language governing permissions and
754
+ * limitations under the License.
755
+ */
756
+ class DateTimeInput extends DynamicComponent {
757
+ label = input(null, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
758
+ value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
759
+ enableDate = input(true, ...(ngDevMode ? [{ debugName: "enableDate" }] : /* istanbul ignore next */ []));
760
+ enableTime = input(false, ...(ngDevMode ? [{ debugName: "enableTime" }] : /* istanbul ignore next */ []));
761
+ inputId = super.getUniqueId('a2ui-datetime-input');
762
+ inputType = computed(() => {
763
+ if (this.enableDate() && this.enableTime())
764
+ return 'datetime-local';
765
+ if (this.enableTime())
766
+ return 'time';
767
+ return 'date';
768
+ }, ...(ngDevMode ? [{ debugName: "inputType" }] : /* istanbul ignore next */ []));
769
+ resolvedLabel = computed(() => super.resolvePrimitive(this.label()), ...(ngDevMode ? [{ debugName: "resolvedLabel" }] : /* istanbul ignore next */ []));
770
+ resolvedValue = computed(() => super.resolvePrimitive(this.value()), ...(ngDevMode ? [{ debugName: "resolvedValue" }] : /* istanbul ignore next */ []));
771
+ onChange(event) {
772
+ const value = event.target.value;
773
+ const valueNode = this.value();
774
+ if (valueNode && typeof valueNode === 'object' && 'path' in valueNode && valueNode.path) {
775
+ // Update the local data model directly to ensure immediate UI feedback and avoid unnecessary network requests.
776
+ this.processor.processMessages([{
777
+ dataModelUpdate: {
778
+ surfaceId: this.surfaceId(),
779
+ path: this.processor.resolvePath(valueNode.path, this.component().dataContextPath),
780
+ contents: [{ key: '.', valueString: value }],
781
+ },
782
+ }]);
783
+ }
784
+ else {
785
+ this.handleAction('change', { value });
786
+ }
787
+ }
788
+ handleAction(name, context) {
789
+ super.sendAction({
790
+ name,
791
+ context: Object.entries(context).map(([key, val]) => ({
792
+ key,
793
+ value: typeof val === 'number' ? { literalNumber: val } : { literalString: String(val) },
794
+ })),
795
+ });
796
+ }
797
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: DateTimeInput, deps: null, target: i0.ɵɵFactoryTarget.Component });
798
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.5", type: DateTimeInput, isStandalone: true, selector: "a2ui-datetime-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, enableDate: { classPropertyName: "enableDate", publicName: "enableDate", isSignal: true, isRequired: false, transformFunction: null }, enableTime: { classPropertyName: "enableTime", publicName: "enableTime", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
799
+ <div
800
+ [class]="theme.components.DateTimeInput.container"
801
+ [style]="theme.additionalStyles?.DateTimeInput"
802
+ >
803
+ <label [class]="theme.components.DateTimeInput.label" [for]="inputId">
804
+ {{ resolvedLabel() }}
805
+ </label>
806
+ <input
807
+ [type]="inputType()"
808
+ [class]="theme.components.DateTimeInput.element"
809
+ [id]="inputId"
810
+ [value]="resolvedValue() ?? ''"
811
+ (change)="onChange($event)"
812
+ />
813
+ </div>
814
+ `, isInline: true, styles: [":host{display:block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
815
+ }
816
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: DateTimeInput, decorators: [{
817
+ type: Component,
818
+ args: [{ selector: 'a2ui-datetime-input', template: `
819
+ <div
820
+ [class]="theme.components.DateTimeInput.container"
821
+ [style]="theme.additionalStyles?.DateTimeInput"
822
+ >
823
+ <label [class]="theme.components.DateTimeInput.label" [for]="inputId">
824
+ {{ resolvedLabel() }}
825
+ </label>
826
+ <input
827
+ [type]="inputType()"
828
+ [class]="theme.components.DateTimeInput.element"
829
+ [id]="inputId"
830
+ [value]="resolvedValue() ?? ''"
831
+ (change)="onChange($event)"
832
+ />
833
+ </div>
834
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
835
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], enableDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableDate", required: false }] }], enableTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableTime", required: false }] }] } });
294
836
 
295
- https://www.apache.org/licenses/LICENSE-2.0
837
+ /*
838
+ * Copyright 2025 Google LLC
839
+ *
840
+ * Licensed under the Apache License, Version 2.0 (the "License");
841
+ * you may not use this file except in compliance with the License.
842
+ * You may obtain a copy of the License at
843
+ *
844
+ * https://www.apache.org/licenses/LICENSE-2.0
845
+ *
846
+ * Unless required by applicable law or agreed to in writing, software
847
+ * distributed under the License is distributed on an "AS IS" BASIS,
848
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
849
+ * See the License for the specific language governing permissions and
850
+ * limitations under the License.
851
+ */
852
+ class Divider extends DynamicComponent {
853
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Divider, deps: null, target: i0.ɵɵFactoryTarget.Component });
854
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.5", type: Divider, isStandalone: true, selector: "a2ui-divider", usesInheritance: true, ngImport: i0, template: '<hr [class]="theme.components.Divider" [style]="theme.additionalStyles?.Divider"/>', isInline: true, styles: [":host{display:block;min-height:0;overflow:auto}hr{height:1px;background:#ccc;border:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
855
+ }
856
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Divider, decorators: [{
857
+ type: Component,
858
+ args: [{ selector: 'a2ui-divider', changeDetection: ChangeDetectionStrategy.OnPush, template: '<hr [class]="theme.components.Divider" [style]="theme.additionalStyles?.Divider"/>', styles: [":host{display:block;min-height:0;overflow:auto}hr{height:1px;background:#ccc;border:none}\n"] }]
859
+ }] });
296
860
 
297
- Unless required by applicable law or agreed to in writing, software
298
- distributed under the License is distributed on an "AS IS" BASIS,
299
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
300
- See the License for the specific language governing permissions and
301
- limitations under the License.
861
+ /*
862
+ * Copyright 2025 Google LLC
863
+ *
864
+ * Licensed under the Apache License, Version 2.0 (the "License");
865
+ * you may not use this file except in compliance with the License.
866
+ * You may obtain a copy of the License at
867
+ *
868
+ * https://www.apache.org/licenses/LICENSE-2.0
869
+ *
870
+ * Unless required by applicable law or agreed to in writing, software
871
+ * distributed under the License is distributed on an "AS IS" BASIS,
872
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
873
+ * See the License for the specific language governing permissions and
874
+ * limitations under the License.
302
875
  */
303
- function provideA2UI(config) {
304
- return makeEnvironmentProviders([
305
- { provide: Catalog, useValue: config.catalog },
306
- { provide: Theme, useValue: config.theme },
307
- ]);
876
+ class Icon extends DynamicComponent {
877
+ name = input(null, ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
878
+ resolvedName = computed(() => this.resolvePrimitive(this.name()), ...(ngDevMode ? [{ debugName: "resolvedName" }] : /* istanbul ignore next */ []));
879
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Icon, deps: null, target: i0.ɵɵFactoryTarget.Component });
880
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Icon, isStandalone: true, selector: "a2ui-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-hidden": "true", "tabindex": "-1" } }, usesInheritance: true, ngImport: i0, template: `
881
+ @let resolvedName = this.resolvedName();
882
+
883
+ @if (resolvedName) {
884
+ <section [class]="theme.components.Icon" [style]="theme.additionalStyles?.Icon">
885
+ <span class="g-icon">{{ resolvedName }}</span>
886
+ </section>
887
+ }
888
+ `, isInline: true, styles: [":host{display:block;flex:var(--weight);min-height:0;overflow:auto}\n"], changeDetection: i0.ChangeDetectionStrategy.Eager });
308
889
  }
890
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Icon, decorators: [{
891
+ type: Component,
892
+ args: [{ selector: 'a2ui-icon', host: {
893
+ 'aria-hidden': 'true',
894
+ tabindex: '-1',
895
+ }, changeDetection: ChangeDetectionStrategy.Eager, template: `
896
+ @let resolvedName = this.resolvedName();
897
+
898
+ @if (resolvedName) {
899
+ <section [class]="theme.components.Icon" [style]="theme.additionalStyles?.Icon">
900
+ <span class="g-icon">{{ resolvedName }}</span>
901
+ </section>
902
+ }
903
+ `, styles: [":host{display:block;flex:var(--weight);min-height:0;overflow:auto}\n"] }]
904
+ }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }] } });
309
905
 
310
906
  /*
311
- Copyright 2025 Google LLC
907
+ * Copyright 2025 Google LLC
908
+ *
909
+ * Licensed under the Apache License, Version 2.0 (the "License");
910
+ * you may not use this file except in compliance with the License.
911
+ * You may obtain a copy of the License at
912
+ *
913
+ * https://www.apache.org/licenses/LICENSE-2.0
914
+ *
915
+ * Unless required by applicable law or agreed to in writing, software
916
+ * distributed under the License is distributed on an "AS IS" BASIS,
917
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
918
+ * See the License for the specific language governing permissions and
919
+ * limitations under the License.
920
+ */
921
+ class Image extends DynamicComponent {
922
+ url = input(null, ...(ngDevMode ? [{ debugName: "url" }] : /* istanbul ignore next */ []));
923
+ usageHint = input(null, ...(ngDevMode ? [{ debugName: "usageHint" }] : /* istanbul ignore next */ []));
924
+ fit = input(null, ...(ngDevMode ? [{ debugName: "fit" }] : /* istanbul ignore next */ []));
925
+ altText = input(null, ...(ngDevMode ? [{ debugName: "altText" }] : /* istanbul ignore next */ []));
926
+ resolvedUrl = computed(() => this.resolvePrimitive(this.url()), ...(ngDevMode ? [{ debugName: "resolvedUrl" }] : /* istanbul ignore next */ []));
927
+ resolvedAltText = computed(() => this.resolvePrimitive(this.altText()) || '', ...(ngDevMode ? [{ debugName: "resolvedAltText" }] : /* istanbul ignore next */ []));
928
+ classes = computed(() => {
929
+ const usageHint = this.usageHint();
930
+ return Styles.merge(this.theme.components.Image.all, usageHint ? this.theme.components.Image[usageHint] : {});
931
+ }, ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
932
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Image, deps: null, target: i0.ɵɵFactoryTarget.Component });
933
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Image, isStandalone: true, selector: "a2ui-image", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null }, usageHint: { classPropertyName: "usageHint", publicName: "usageHint", isSignal: true, isRequired: false, transformFunction: null }, fit: { classPropertyName: "fit", publicName: "fit", isSignal: true, isRequired: false, transformFunction: null }, altText: { classPropertyName: "altText", publicName: "altText", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
934
+ @let resolvedUrl = this.resolvedUrl();
935
+ @let resolvedAltText = this.resolvedAltText();
936
+
937
+ @if (resolvedUrl) {
938
+ <section [class]="classes()" [style]="theme.additionalStyles?.Image">
939
+ <img [src]="resolvedUrl" [alt]="resolvedAltText" />
940
+ </section>
941
+ }
942
+ `, isInline: true, styles: [":host{display:block;flex:var(--weight);min-height:0;overflow:auto}img{display:block;width:100%;height:100%;box-sizing:border-box}\n"], changeDetection: i0.ChangeDetectionStrategy.Eager });
943
+ }
944
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Image, decorators: [{
945
+ type: Component,
946
+ args: [{ selector: 'a2ui-image', changeDetection: ChangeDetectionStrategy.Eager, template: `
947
+ @let resolvedUrl = this.resolvedUrl();
948
+ @let resolvedAltText = this.resolvedAltText();
949
+
950
+ @if (resolvedUrl) {
951
+ <section [class]="classes()" [style]="theme.additionalStyles?.Image">
952
+ <img [src]="resolvedUrl" [alt]="resolvedAltText" />
953
+ </section>
954
+ }
955
+ `, styles: [":host{display:block;flex:var(--weight);min-height:0;overflow:auto}img{display:block;width:100%;height:100%;box-sizing:border-box}\n"] }]
956
+ }], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: false }] }], usageHint: [{ type: i0.Input, args: [{ isSignal: true, alias: "usageHint", required: false }] }], fit: [{ type: i0.Input, args: [{ isSignal: true, alias: "fit", required: false }] }], altText: [{ type: i0.Input, args: [{ isSignal: true, alias: "altText", required: false }] }] } });
312
957
 
313
- Licensed under the Apache License, Version 2.0 (the "License");
314
- you may not use this file except in compliance with the License.
315
- You may obtain a copy of the License at
958
+ /*
959
+ * Copyright 2025 Google LLC
960
+ *
961
+ * Licensed under the Apache License, Version 2.0 (the "License");
962
+ * you may not use this file except in compliance with the License.
963
+ * You may obtain a copy of the License at
964
+ *
965
+ * https://www.apache.org/licenses/LICENSE-2.0
966
+ *
967
+ * Unless required by applicable law or agreed to in writing, software
968
+ * distributed under the License is distributed on an "AS IS" BASIS,
969
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
970
+ * See the License for the specific language governing permissions and
971
+ * limitations under the License.
972
+ */
973
+ class List extends DynamicComponent {
974
+ alignment = input('stretch', ...(ngDevMode ? [{ debugName: "alignment" }] : /* istanbul ignore next */ []));
975
+ direction = input('vertical', ...(ngDevMode ? [{ debugName: "direction" }] : /* istanbul ignore next */ []));
976
+ children = input(null, ...(ngDevMode ? [{ debugName: "children" }] : /* istanbul ignore next */ []));
977
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: List, deps: null, target: i0.ɵɵFactoryTarget.Component });
978
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: List, isStandalone: true, selector: "a2ui-list", inputs: { alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, children: { classPropertyName: "children", publicName: "children", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.direction": "direction()" } }, usesInheritance: true, ngImport: i0, template: `
979
+ <section [class]="theme.components.List" [style]="theme.additionalStyles?.List">
980
+ @for (child of children() ?? component().properties.children; track child?.id ?? child) {
981
+ @if (child) {
982
+ <div class="a2ui-list-item">
983
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child" />
984
+ </div>
985
+ }
986
+ }
987
+ </section>
988
+ `, isInline: true, styles: [":host{display:block;flex:var(--weight);min-height:0}:host([direction=\"vertical\"]) section{display:flex;flex-direction:column;max-height:100%;overflow-y:auto}:host([direction=\"horizontal\"]) section{display:flex;max-width:100%;overflow-x:auto;overflow-y:hidden;scrollbar-width:none}.a2ui-list-item{display:flex;cursor:pointer;box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "[a2ui-renderer]", inputs: ["surfaceId", "component"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
989
+ }
990
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: List, decorators: [{
991
+ type: Component,
992
+ args: [{ selector: 'a2ui-list', imports: [Renderer], changeDetection: ChangeDetectionStrategy.Eager, host: {
993
+ '[attr.direction]': 'direction()',
994
+ }, template: `
995
+ <section [class]="theme.components.List" [style]="theme.additionalStyles?.List">
996
+ @for (child of children() ?? component().properties.children; track child?.id ?? child) {
997
+ @if (child) {
998
+ <div class="a2ui-list-item">
999
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child" />
1000
+ </div>
1001
+ }
1002
+ }
1003
+ </section>
1004
+ `, styles: [":host{display:block;flex:var(--weight);min-height:0}:host([direction=\"vertical\"]) section{display:flex;flex-direction:column;max-height:100%;overflow-y:auto}:host([direction=\"horizontal\"]) section{display:flex;max-width:100%;overflow-x:auto;overflow-y:hidden;scrollbar-width:none}.a2ui-list-item{display:flex;cursor:pointer;box-sizing:border-box}\n"] }]
1005
+ }], propDecorators: { alignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignment", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], children: [{ type: i0.Input, args: [{ isSignal: true, alias: "children", required: false }] }] } });
316
1006
 
317
- https://www.apache.org/licenses/LICENSE-2.0
1007
+ /*
1008
+ * Copyright 2025 Google LLC
1009
+ *
1010
+ * Licensed under the Apache License, Version 2.0 (the "License");
1011
+ * you may not use this file except in compliance with the License.
1012
+ * You may obtain a copy of the License at
1013
+ *
1014
+ * https://www.apache.org/licenses/LICENSE-2.0
1015
+ *
1016
+ * Unless required by applicable law or agreed to in writing, software
1017
+ * distributed under the License is distributed on an "AS IS" BASIS,
1018
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1019
+ * See the License for the specific language governing permissions and
1020
+ * limitations under the License.
1021
+ */
1022
+ class Modal extends DynamicComponent {
1023
+ entryPointChild = input.required(...(ngDevMode ? [{ debugName: "entryPointChild" }] : /* istanbul ignore next */ []));
1024
+ contentChild = input.required(...(ngDevMode ? [{ debugName: "contentChild" }] : /* istanbul ignore next */ []));
1025
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
1026
+ openModal() {
1027
+ this.isOpen.set(true);
1028
+ }
1029
+ closeModal() {
1030
+ this.isOpen.set(false);
1031
+ }
1032
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Modal, deps: null, target: i0.ɵɵFactoryTarget.Component });
1033
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Modal, isStandalone: true, selector: "a2ui-modal", inputs: { entryPointChild: { classPropertyName: "entryPointChild", publicName: "entryPointChild", isSignal: true, isRequired: true, transformFunction: null }, contentChild: { classPropertyName: "contentChild", publicName: "contentChild", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1034
+ <div class="a2ui-modal-entry-point" (click)="openModal()">
1035
+ @if (entryPointChild()) {
1036
+ <ng-container
1037
+ a2ui-renderer
1038
+ [surfaceId]="surfaceId()!"
1039
+ [component]="entryPointChild()!"
1040
+ />
1041
+ }
1042
+ </div>
1043
+
1044
+ @if (isOpen()) {
1045
+ <div [class]="theme.components.Modal.backdrop" (click)="closeModal()">
1046
+ <div [class]="theme.components.Modal.element" (click)="$event.stopPropagation()">
1047
+ @if (contentChild()) {
1048
+ <ng-container
1049
+ a2ui-renderer
1050
+ [surfaceId]="surfaceId()!"
1051
+ [component]="contentChild()!"
1052
+ />
1053
+ }
1054
+ </div>
1055
+ </div>
1056
+ }
1057
+ `, isInline: true, styles: [":host{display:inline-block}.a2ui-modal-entry-point{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "[a2ui-renderer]", inputs: ["surfaceId", "component"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1058
+ }
1059
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Modal, decorators: [{
1060
+ type: Component,
1061
+ args: [{ selector: 'a2ui-modal', imports: [Renderer], template: `
1062
+ <div class="a2ui-modal-entry-point" (click)="openModal()">
1063
+ @if (entryPointChild()) {
1064
+ <ng-container
1065
+ a2ui-renderer
1066
+ [surfaceId]="surfaceId()!"
1067
+ [component]="entryPointChild()!"
1068
+ />
1069
+ }
1070
+ </div>
1071
+
1072
+ @if (isOpen()) {
1073
+ <div [class]="theme.components.Modal.backdrop" (click)="closeModal()">
1074
+ <div [class]="theme.components.Modal.element" (click)="$event.stopPropagation()">
1075
+ @if (contentChild()) {
1076
+ <ng-container
1077
+ a2ui-renderer
1078
+ [surfaceId]="surfaceId()!"
1079
+ [component]="contentChild()!"
1080
+ />
1081
+ }
1082
+ </div>
1083
+ </div>
1084
+ }
1085
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:inline-block}.a2ui-modal-entry-point{cursor:pointer}\n"] }]
1086
+ }], propDecorators: { entryPointChild: [{ type: i0.Input, args: [{ isSignal: true, alias: "entryPointChild", required: true }] }], contentChild: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentChild", required: true }] }] } });
318
1087
 
319
- Unless required by applicable law or agreed to in writing, software
320
- distributed under the License is distributed on an "AS IS" BASIS,
321
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
322
- See the License for the specific language governing permissions and
323
- limitations under the License.
1088
+ /*
1089
+ * Copyright 2025 Google LLC
1090
+ *
1091
+ * Licensed under the Apache License, Version 2.0 (the "License");
1092
+ * you may not use this file except in compliance with the License.
1093
+ * You may obtain a copy of the License at
1094
+ *
1095
+ * https://www.apache.org/licenses/LICENSE-2.0
1096
+ *
1097
+ * Unless required by applicable law or agreed to in writing, software
1098
+ * distributed under the License is distributed on an "AS IS" BASIS,
1099
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1100
+ * See the License for the specific language governing permissions and
1101
+ * limitations under the License.
1102
+ */
1103
+ class MultipleChoice extends DynamicComponent {
1104
+ label = input(null, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
1105
+ options = input.required(...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
1106
+ selections = input.required(...(ngDevMode ? [{ debugName: "selections" }] : /* istanbul ignore next */ []));
1107
+ selectId = super.getUniqueId('a2ui-multiple-choice');
1108
+ resolvedLabel = computed(() => this.resolvePrimitive(this.label()), ...(ngDevMode ? [{ debugName: "resolvedLabel" }] : /* istanbul ignore next */ []));
1109
+ resolvedOptions = computed(() => this.options().map((opt) => ({
1110
+ label: this.resolvePrimitive(opt.label),
1111
+ value: opt.value,
1112
+ })), ...(ngDevMode ? [{ debugName: "resolvedOptions" }] : /* istanbul ignore next */ []));
1113
+ resolvedSelections = computed(() => {
1114
+ const s = this.selections();
1115
+ if (s && typeof s === 'object' && 'literalArray' in s) {
1116
+ return s.literalArray;
1117
+ }
1118
+ return [];
1119
+ }, ...(ngDevMode ? [{ debugName: "resolvedSelections" }] : /* istanbul ignore next */ []));
1120
+ onChange(event) {
1121
+ const value = event.target.value;
1122
+ const selectionsNode = this.selections();
1123
+ if (selectionsNode && typeof selectionsNode === 'object' && 'path' in selectionsNode && selectionsNode.path) {
1124
+ // Update the local data model directly to ensure immediate UI feedback and avoid unnecessary network requests.
1125
+ this.processor.processMessages([{
1126
+ dataModelUpdate: {
1127
+ surfaceId: this.surfaceId(),
1128
+ path: this.processor.resolvePath(selectionsNode.path, this.component().dataContextPath),
1129
+ contents: [{ key: '.', valueString: JSON.stringify({ literalArray: [value] }) }],
1130
+ },
1131
+ }]);
1132
+ }
1133
+ else {
1134
+ this.handleAction('change', { value });
1135
+ }
1136
+ }
1137
+ handleAction(name, context) {
1138
+ super.sendAction({
1139
+ name,
1140
+ context: Object.entries(context).map(([key, val]) => ({
1141
+ key,
1142
+ value: typeof val === 'number' ? { literalNumber: val } : { literalString: String(val) },
1143
+ })),
1144
+ });
1145
+ }
1146
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MultipleChoice, deps: null, target: i0.ɵɵFactoryTarget.Component });
1147
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MultipleChoice, isStandalone: true, selector: "a2ui-multiple-choice", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, selections: { classPropertyName: "selections", publicName: "selections", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1148
+ <div
1149
+ [class]="theme.components.MultipleChoice.container"
1150
+ [style]="theme.additionalStyles?.MultipleChoice"
1151
+ >
1152
+ <label [class]="theme.components.MultipleChoice.label" [for]="selectId">
1153
+ {{ resolvedLabel() }}
1154
+ </label>
1155
+ <select
1156
+ [class]="theme.components.MultipleChoice.element"
1157
+ [id]="selectId"
1158
+ [value]="resolvedSelections()[0] || ''"
1159
+ (change)="onChange($event)"
1160
+ >
1161
+ @for (option of resolvedOptions(); track option.value) {
1162
+ <option [value]="option.value">{{ option.label }}</option>
1163
+ }
1164
+ </select>
1165
+ </div>
1166
+ `, isInline: true, styles: [":host{display:block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1167
+ }
1168
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MultipleChoice, decorators: [{
1169
+ type: Component,
1170
+ args: [{ selector: 'a2ui-multiple-choice', template: `
1171
+ <div
1172
+ [class]="theme.components.MultipleChoice.container"
1173
+ [style]="theme.additionalStyles?.MultipleChoice"
1174
+ >
1175
+ <label [class]="theme.components.MultipleChoice.label" [for]="selectId">
1176
+ {{ resolvedLabel() }}
1177
+ </label>
1178
+ <select
1179
+ [class]="theme.components.MultipleChoice.element"
1180
+ [id]="selectId"
1181
+ [value]="resolvedSelections()[0] || ''"
1182
+ (change)="onChange($event)"
1183
+ >
1184
+ @for (option of resolvedOptions(); track option.value) {
1185
+ <option [value]="option.value">{{ option.label }}</option>
1186
+ }
1187
+ </select>
1188
+ </div>
1189
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
1190
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], selections: [{ type: i0.Input, args: [{ isSignal: true, alias: "selections", required: true }] }] } });
1191
+
1192
+ /*
1193
+ * Copyright 2025 Google LLC
1194
+ *
1195
+ * Licensed under the Apache License, Version 2.0 (the "License");
1196
+ * you may not use this file except in compliance with the License.
1197
+ * You may obtain a copy of the License at
1198
+ *
1199
+ * https://www.apache.org/licenses/LICENSE-2.0
1200
+ *
1201
+ * Unless required by applicable law or agreed to in writing, software
1202
+ * distributed under the License is distributed on an "AS IS" BASIS,
1203
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1204
+ * See the License for the specific language governing permissions and
1205
+ * limitations under the License.
324
1206
  */
325
1207
  class Row extends DynamicComponent {
326
- alignment = input('stretch', ...(ngDevMode ? [{ debugName: "alignment" }] : []));
327
- distribution = input('start', ...(ngDevMode ? [{ debugName: "distribution" }] : []));
1208
+ alignment = input('stretch', ...(ngDevMode ? [{ debugName: "alignment" }] : /* istanbul ignore next */ []));
1209
+ distribution = input('start', ...(ngDevMode ? [{ debugName: "distribution" }] : /* istanbul ignore next */ []));
1210
+ children = input(...(ngDevMode ? [undefined, { debugName: "children" }] : /* istanbul ignore next */ []));
328
1211
  classes = computed(() => ({
329
1212
  ...this.theme.components.Row,
330
1213
  [`align-${this.alignment()}`]: true,
331
1214
  [`distribute-${this.distribution()}`]: true,
332
- }), ...(ngDevMode ? [{ debugName: "classes" }] : []));
333
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Row, deps: null, target: i0.ɵɵFactoryTarget.Component });
334
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: Row, isStandalone: true, selector: "a2ui-row", inputs: { alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null }, distribution: { classPropertyName: "distribution", publicName: "distribution", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.alignment": "alignment()", "attr.distribution": "distribution()" } }, usesInheritance: true, ngImport: i0, template: `
1215
+ }), ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
1216
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Row, deps: null, target: i0.ɵɵFactoryTarget.Component });
1217
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Row, isStandalone: true, selector: "a2ui-row", inputs: { alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null }, distribution: { classPropertyName: "distribution", publicName: "distribution", isSignal: true, isRequired: false, transformFunction: null }, children: { classPropertyName: "children", publicName: "children", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.alignment": "alignment()", "attr.distribution": "distribution()" } }, usesInheritance: true, ngImport: i0, template: `
335
1218
  <section [class]="classes()" [style]="theme.additionalStyles?.Row">
336
- @for (child of component().properties.children; track child) {
337
- <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child" />
1219
+ @for (child of children() ?? component().properties.children; track child?.id ?? child) {
1220
+ @if (child) {
1221
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child" />
1222
+ }
338
1223
  }
339
1224
  </section>
340
- `, isInline: true, styles: [":host{display:flex;flex:var(--weight)}section{display:flex;flex-direction:row;width:100%;min-height:100%;box-sizing:border-box}.align-start{align-items:start}.align-center{align-items:center}.align-end{align-items:end}.align-stretch{align-items:stretch}.distribute-start{justify-content:start}.distribute-center{justify-content:center}.distribute-end{justify-content:end}.distribute-spaceBetween{justify-content:space-between}.distribute-spaceAround{justify-content:space-around}.distribute-spaceEvenly{justify-content:space-evenly}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "ng-container[a2ui-renderer]", inputs: ["surfaceId", "component"] }] });
1225
+ `, isInline: true, styles: [":host{display:flex;flex:var(--weight)}section{display:flex;flex-direction:row;width:100%;min-height:100%;box-sizing:border-box}.align-start{align-items:start}.align-center{align-items:center}.align-end{align-items:end}.align-stretch{align-items:stretch}.distribute-start{justify-content:start}.distribute-center{justify-content:center}.distribute-end{justify-content:end}.distribute-spaceBetween{justify-content:space-between}.distribute-spaceAround{justify-content:space-around}.distribute-spaceEvenly{justify-content:space-evenly}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "[a2ui-renderer]", inputs: ["surfaceId", "component"] }], changeDetection: i0.ChangeDetectionStrategy.Eager });
341
1226
  }
342
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Row, decorators: [{
1227
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Row, decorators: [{
343
1228
  type: Component,
344
- args: [{ selector: 'a2ui-row', imports: [Renderer], host: {
1229
+ args: [{ selector: 'a2ui-row', imports: [Renderer], changeDetection: ChangeDetectionStrategy.Eager, host: {
345
1230
  '[attr.alignment]': 'alignment()',
346
1231
  '[attr.distribution]': 'distribution()',
347
1232
  }, template: `
348
1233
  <section [class]="classes()" [style]="theme.additionalStyles?.Row">
349
- @for (child of component().properties.children; track child) {
350
- <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child" />
1234
+ @for (child of children() ?? component().properties.children; track child?.id ?? child) {
1235
+ @if (child) {
1236
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child" />
1237
+ }
351
1238
  }
352
1239
  </section>
353
1240
  `, styles: [":host{display:flex;flex:var(--weight)}section{display:flex;flex-direction:row;width:100%;min-height:100%;box-sizing:border-box}.align-start{align-items:start}.align-center{align-items:center}.align-end{align-items:end}.align-stretch{align-items:stretch}.distribute-start{justify-content:start}.distribute-center{justify-content:center}.distribute-end{justify-content:end}.distribute-spaceBetween{justify-content:space-between}.distribute-spaceAround{justify-content:space-around}.distribute-spaceEvenly{justify-content:space-evenly}\n"] }]
354
- }], propDecorators: { alignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignment", required: false }] }], distribution: [{ type: i0.Input, args: [{ isSignal: true, alias: "distribution", required: false }] }] } });
1241
+ }], propDecorators: { alignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignment", required: false }] }], distribution: [{ type: i0.Input, args: [{ isSignal: true, alias: "distribution", required: false }] }], children: [{ type: i0.Input, args: [{ isSignal: true, alias: "children", required: false }] }] } });
355
1242
 
356
1243
  /*
357
- Copyright 2025 Google LLC
358
-
359
- Licensed under the Apache License, Version 2.0 (the "License");
360
- you may not use this file except in compliance with the License.
361
- You may obtain a copy of the License at
362
-
363
- https://www.apache.org/licenses/LICENSE-2.0
364
-
365
- Unless required by applicable law or agreed to in writing, software
366
- distributed under the License is distributed on an "AS IS" BASIS,
367
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
368
- See the License for the specific language governing permissions and
369
- limitations under the License.
1244
+ * Copyright 2025 Google LLC
1245
+ *
1246
+ * Licensed under the Apache License, Version 2.0 (the "License");
1247
+ * you may not use this file except in compliance with the License.
1248
+ * You may obtain a copy of the License at
1249
+ *
1250
+ * https://www.apache.org/licenses/LICENSE-2.0
1251
+ *
1252
+ * Unless required by applicable law or agreed to in writing, software
1253
+ * distributed under the License is distributed on an "AS IS" BASIS,
1254
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1255
+ * See the License for the specific language governing permissions and
1256
+ * limitations under the License.
370
1257
  */
371
- class Column extends DynamicComponent {
372
- alignment = input('stretch', ...(ngDevMode ? [{ debugName: "alignment" }] : []));
373
- distribution = input('start', ...(ngDevMode ? [{ debugName: "distribution" }] : []));
374
- classes = computed(() => ({
375
- ...this.theme.components.Column,
376
- [`align-${this.alignment()}`]: true,
377
- [`distribute-${this.distribution()}`]: true,
378
- }), ...(ngDevMode ? [{ debugName: "classes" }] : []));
379
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Column, deps: null, target: i0.ɵɵFactoryTarget.Component });
380
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: Column, isStandalone: true, selector: "a2ui-column", inputs: { alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null }, distribution: { classPropertyName: "distribution", publicName: "distribution", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
381
- <section [class]="classes()" [style]="theme.additionalStyles?.Column">
382
- @for (child of component().properties.children; track child) {
383
- <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child" />
1258
+ class Slider extends DynamicComponent {
1259
+ label = input(null, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
1260
+ value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
1261
+ minValue = input(0, ...(ngDevMode ? [{ debugName: "minValue" }] : /* istanbul ignore next */ []));
1262
+ maxValue = input(100, ...(ngDevMode ? [{ debugName: "maxValue" }] : /* istanbul ignore next */ []));
1263
+ inputId = super.getUniqueId('a2ui-slider-input');
1264
+ labelId = super.getUniqueId('a2ui-slider-label');
1265
+ resolvedLabel = computed(() => super.resolvePrimitive(this.label()), ...(ngDevMode ? [{ debugName: "resolvedLabel" }] : /* istanbul ignore next */ []));
1266
+ resolvedValue = computed(() => super.resolvePrimitive(this.value()), ...(ngDevMode ? [{ debugName: "resolvedValue" }] : /* istanbul ignore next */ []));
1267
+ onInput(event) {
1268
+ const value = Number(event.target.value);
1269
+ const valueNode = this.value();
1270
+ if (valueNode && typeof valueNode === 'object' && 'path' in valueNode && valueNode.path) {
1271
+ // Update the local data model directly to ensure immediate UI feedback and avoid unnecessary network requests.
1272
+ this.processor.processMessages([{
1273
+ dataModelUpdate: {
1274
+ surfaceId: this.surfaceId(),
1275
+ path: this.processor.resolvePath(valueNode.path, this.component().dataContextPath),
1276
+ contents: [{ key: '.', valueNumber: value }],
1277
+ },
1278
+ }]);
1279
+ }
1280
+ else {
1281
+ this.handleAction('change', { value });
1282
+ }
1283
+ }
1284
+ handleAction(name, context) {
1285
+ super.sendAction({
1286
+ name,
1287
+ context: Object.entries(context).map(([key, val]) => ({
1288
+ key,
1289
+ value: typeof val === 'number' ? { literalNumber: val } : { literalString: String(val) },
1290
+ })),
1291
+ });
1292
+ }
1293
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Slider, deps: null, target: i0.ɵɵFactoryTarget.Component });
1294
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Slider, isStandalone: true, selector: "a2ui-slider", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, minValue: { classPropertyName: "minValue", publicName: "minValue", isSignal: true, isRequired: false, transformFunction: null }, maxValue: { classPropertyName: "maxValue", publicName: "maxValue", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1295
+ <div [class]="theme.components.Slider.container" [style]="theme.additionalStyles?.Slider">
1296
+ @if (resolvedLabel()) {
1297
+ <label [class]="theme.components.Slider.label" [id]="labelId">{{ resolvedLabel() }}</label>
384
1298
  }
385
- </section>
386
- `, isInline: true, styles: [":host{display:flex;flex:var(--weight)}section{display:flex;flex-direction:column;min-width:100%;height:100%;box-sizing:border-box}.align-start{align-items:start}.align-center{align-items:center}.align-end{align-items:end}.align-stretch{align-items:stretch}.distribute-start{justify-content:start}.distribute-center{justify-content:center}.distribute-end{justify-content:end}.distribute-spaceBetween{justify-content:space-between}.distribute-spaceAround{justify-content:space-around}.distribute-spaceEvenly{justify-content:space-evenly}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "ng-container[a2ui-renderer]", inputs: ["surfaceId", "component"] }] });
1299
+ <input
1300
+ type="range"
1301
+ [class]="theme.components.Slider.element"
1302
+ [id]="inputId"
1303
+ [attr.aria-labelledby]="labelId"
1304
+ [min]="minValue()"
1305
+ [max]="maxValue()"
1306
+ [value]="resolvedValue() ?? 0"
1307
+ (input)="onInput($event)"
1308
+ />
1309
+ </div>
1310
+ `, isInline: true, styles: [":host{display:block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
387
1311
  }
388
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Column, decorators: [{
1312
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Slider, decorators: [{
389
1313
  type: Component,
390
- args: [{ selector: 'a2ui-column', imports: [Renderer], template: `
391
- <section [class]="classes()" [style]="theme.additionalStyles?.Column">
392
- @for (child of component().properties.children; track child) {
393
- <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="child" />
1314
+ args: [{ selector: 'a2ui-slider', template: `
1315
+ <div [class]="theme.components.Slider.container" [style]="theme.additionalStyles?.Slider">
1316
+ @if (resolvedLabel()) {
1317
+ <label [class]="theme.components.Slider.label" [id]="labelId">{{ resolvedLabel() }}</label>
394
1318
  }
395
- </section>
396
- `, styles: [":host{display:flex;flex:var(--weight)}section{display:flex;flex-direction:column;min-width:100%;height:100%;box-sizing:border-box}.align-start{align-items:start}.align-center{align-items:center}.align-end{align-items:end}.align-stretch{align-items:stretch}.distribute-start{justify-content:start}.distribute-center{justify-content:center}.distribute-end{justify-content:end}.distribute-spaceBetween{justify-content:space-between}.distribute-spaceAround{justify-content:space-around}.distribute-spaceEvenly{justify-content:space-evenly}\n"] }]
397
- }], propDecorators: { alignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignment", required: false }] }], distribution: [{ type: i0.Input, args: [{ isSignal: true, alias: "distribution", required: false }] }] } });
1319
+ <input
1320
+ type="range"
1321
+ [class]="theme.components.Slider.element"
1322
+ [id]="inputId"
1323
+ [attr.aria-labelledby]="labelId"
1324
+ [min]="minValue()"
1325
+ [max]="maxValue()"
1326
+ [value]="resolvedValue() ?? 0"
1327
+ (input)="onInput($event)"
1328
+ />
1329
+ </div>
1330
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
1331
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], minValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "minValue", required: false }] }], maxValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxValue", required: false }] }] } });
398
1332
 
399
1333
  /*
400
- Copyright 2025 Google LLC
401
-
402
- Licensed under the Apache License, Version 2.0 (the "License");
403
- you may not use this file except in compliance with the License.
404
- You may obtain a copy of the License at
405
-
406
- https://www.apache.org/licenses/LICENSE-2.0
407
-
408
- Unless required by applicable law or agreed to in writing, software
409
- distributed under the License is distributed on an "AS IS" BASIS,
410
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
411
- See the License for the specific language governing permissions and
412
- limitations under the License.
1334
+ * Copyright 2025 Google LLC
1335
+ *
1336
+ * Licensed under the Apache License, Version 2.0 (the "License");
1337
+ * you may not use this file except in compliance with the License.
1338
+ * You may obtain a copy of the License at
1339
+ *
1340
+ * https://www.apache.org/licenses/LICENSE-2.0
1341
+ *
1342
+ * Unless required by applicable law or agreed to in writing, software
1343
+ * distributed under the License is distributed on an "AS IS" BASIS,
1344
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1345
+ * See the License for the specific language governing permissions and
1346
+ * limitations under the License.
413
1347
  */
414
- class MarkdownRenderer {
415
- originalClassMap = new Map();
416
- sanitizer = inject(DomSanitizer);
417
- markdownIt = MarkdownIt({
418
- highlight: (str, lang) => {
419
- if (lang === 'html') {
420
- const iframe = document.createElement('iframe');
421
- iframe.classList.add('html-view');
422
- iframe.srcdoc = str;
423
- iframe.sandbox = '';
424
- return iframe.innerHTML;
425
- }
426
- return str;
427
- },
428
- });
429
- render(value, tagClassMap) {
430
- if (tagClassMap) {
431
- this.applyTagClassMap(tagClassMap);
432
- }
433
- const htmlString = this.markdownIt.render(value);
434
- this.unapplyTagClassMap();
435
- return this.sanitizer.sanitize(SecurityContext.HTML, htmlString);
436
- }
437
- applyTagClassMap(tagClassMap) {
438
- Object.entries(tagClassMap).forEach(([tag, classes]) => {
439
- let tokenName;
440
- switch (tag) {
441
- case 'p':
442
- tokenName = 'paragraph';
443
- break;
444
- case 'h1':
445
- case 'h2':
446
- case 'h3':
447
- case 'h4':
448
- case 'h5':
449
- case 'h6':
450
- tokenName = 'heading';
451
- break;
452
- case 'ul':
453
- tokenName = 'bullet_list';
454
- break;
455
- case 'ol':
456
- tokenName = 'ordered_list';
457
- break;
458
- case 'li':
459
- tokenName = 'list_item';
460
- break;
461
- case 'a':
462
- tokenName = 'link';
463
- break;
464
- case 'strong':
465
- tokenName = 'strong';
466
- break;
467
- case 'em':
468
- tokenName = 'em';
469
- break;
470
- }
471
- if (!tokenName) {
472
- return;
473
- }
474
- const key = `${tokenName}_open`;
475
- const original = this.markdownIt.renderer.rules[key];
476
- this.originalClassMap.set(key, original);
477
- this.markdownIt.renderer.rules[key] = (tokens, idx, options, env, self) => {
478
- const token = tokens[idx];
479
- for (const clazz of classes) {
480
- token.attrJoin('class', clazz);
481
- }
482
- if (original) {
483
- return original.call(this, tokens, idx, options, env, self);
484
- }
485
- else {
486
- return self.renderToken(tokens, idx, options);
487
- }
488
- };
489
- });
1348
+ class Tabs extends DynamicComponent {
1349
+ tabItems = input.required(...(ngDevMode ? [{ debugName: "tabItems" }] : /* istanbul ignore next */ []));
1350
+ selectedIndex = signal(0, ...(ngDevMode ? [{ debugName: "selectedIndex" }] : /* istanbul ignore next */ []));
1351
+ selectTab(index) {
1352
+ this.selectedIndex.set(index);
490
1353
  }
491
- unapplyTagClassMap() {
492
- for (const [key, original] of this.originalClassMap) {
493
- this.markdownIt.renderer.rules[key] = original;
1354
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Tabs, deps: null, target: i0.ɵɵFactoryTarget.Component });
1355
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Tabs, isStandalone: true, selector: "a2ui-tabs", inputs: { tabItems: { classPropertyName: "tabItems", publicName: "tabItems", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1356
+ <div [class]="theme.components.Tabs.container" [style]="theme.additionalStyles?.Tabs">
1357
+ <div [class]="theme.components.Tabs.controls.all">
1358
+ @for (item of tabItems(); track item.child; let i = $index) {
1359
+ <button
1360
+ [class]="selectedIndex() === i ? theme.components.Tabs.controls.selected : {}"
1361
+ (click)="selectTab(i)"
1362
+ >
1363
+ {{ resolvePrimitive(item.title) }}
1364
+ </button>
494
1365
  }
495
- this.originalClassMap.clear();
496
- }
497
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: MarkdownRenderer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
498
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: MarkdownRenderer, providedIn: 'root' });
1366
+ </div>
1367
+ <div class="a2ui-tabs-content">
1368
+ @if (tabItems()[selectedIndex()]; as selectedTab) {
1369
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="selectedTab.child" />
1370
+ }
1371
+ </div>
1372
+ </div>
1373
+ `, isInline: true, styles: [":host{display:block}.a2ui-tabs-content{flex:1;min-height:0}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "[a2ui-renderer]", inputs: ["surfaceId", "component"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
499
1374
  }
500
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: MarkdownRenderer, decorators: [{
501
- type: Injectable,
502
- args: [{ providedIn: 'root' }]
503
- }] });
1375
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Tabs, decorators: [{
1376
+ type: Component,
1377
+ args: [{ selector: 'a2ui-tabs', imports: [Renderer], template: `
1378
+ <div [class]="theme.components.Tabs.container" [style]="theme.additionalStyles?.Tabs">
1379
+ <div [class]="theme.components.Tabs.controls.all">
1380
+ @for (item of tabItems(); track item.child; let i = $index) {
1381
+ <button
1382
+ [class]="selectedIndex() === i ? theme.components.Tabs.controls.selected : {}"
1383
+ (click)="selectTab(i)"
1384
+ >
1385
+ {{ resolvePrimitive(item.title) }}
1386
+ </button>
1387
+ }
1388
+ </div>
1389
+ <div class="a2ui-tabs-content">
1390
+ @if (tabItems()[selectedIndex()]; as selectedTab) {
1391
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()!" [component]="selectedTab.child" />
1392
+ }
1393
+ </div>
1394
+ </div>
1395
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}.a2ui-tabs-content{flex:1;min-height:0}\n"] }]
1396
+ }], propDecorators: { tabItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabItems", required: true }] }] } });
504
1397
 
505
1398
  /*
506
- Copyright 2025 Google LLC
507
-
508
- Licensed under the Apache License, Version 2.0 (the "License");
509
- you may not use this file except in compliance with the License.
510
- You may obtain a copy of the License at
511
-
512
- https://www.apache.org/licenses/LICENSE-2.0
513
-
514
- Unless required by applicable law or agreed to in writing, software
515
- distributed under the License is distributed on an "AS IS" BASIS,
516
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
517
- See the License for the specific language governing permissions and
518
- limitations under the License.
1399
+ * Copyright 2025 Google LLC
1400
+ *
1401
+ * Licensed under the Apache License, Version 2.0 (the "License");
1402
+ * you may not use this file except in compliance with the License.
1403
+ * You may obtain a copy of the License at
1404
+ *
1405
+ * https://www.apache.org/licenses/LICENSE-2.0
1406
+ *
1407
+ * Unless required by applicable law or agreed to in writing, software
1408
+ * distributed under the License is distributed on an "AS IS" BASIS,
1409
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1410
+ * See the License for the specific language governing permissions and
1411
+ * limitations under the License.
519
1412
  */
520
1413
  class Text extends DynamicComponent {
521
1414
  markdownRenderer = inject(MarkdownRenderer);
522
- text = input.required(...(ngDevMode ? [{ debugName: "text" }] : []));
523
- usageHint = input.required(...(ngDevMode ? [{ debugName: "usageHint" }] : []));
1415
+ text = input.required(...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
1416
+ usageHint = input(null, ...(ngDevMode ? [{ debugName: "usageHint" }] : /* istanbul ignore next */ []));
524
1417
  resolvedText = computed(() => {
525
1418
  const usageHint = this.usageHint();
526
1419
  let value = super.resolvePrimitive(this.text());
527
1420
  if (value == null) {
528
- return '(empty)';
1421
+ return Promise.resolve('');
529
1422
  }
530
1423
  switch (usageHint) {
531
1424
  case 'h1':
@@ -550,12 +1443,14 @@ class Text extends DynamicComponent {
550
1443
  value = String(value);
551
1444
  break;
552
1445
  }
553
- return this.markdownRenderer.render(value, Styles.appendToAll(this.theme.markdown, ['ol', 'ul', 'li'], {}));
554
- }, ...(ngDevMode ? [{ debugName: "resolvedText" }] : []));
1446
+ return this.markdownRenderer.render(value, {
1447
+ tagClassMap: Styles.appendToAll(this.theme.markdown, ['ol', 'ul', 'li'], {}),
1448
+ });
1449
+ }, ...(ngDevMode ? [{ debugName: "resolvedText" }] : /* istanbul ignore next */ []));
555
1450
  classes = computed(() => {
556
1451
  const usageHint = this.usageHint();
557
1452
  return Styles.merge(this.theme.components.Text.all, usageHint ? this.theme.components.Text[usageHint] : {});
558
- }, ...(ngDevMode ? [{ debugName: "classes" }] : []));
1453
+ }, ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
559
1454
  additionalStyles = computed(() => {
560
1455
  const usageHint = this.usageHint();
561
1456
  const styles = this.theme.additionalStyles?.Text;
@@ -564,13 +1459,13 @@ class Text extends DynamicComponent {
564
1459
  }
565
1460
  let additionalStyles = {};
566
1461
  if (this.areHintedStyles(styles)) {
567
- additionalStyles = styles[usageHint ?? 'body'];
1462
+ additionalStyles = styles[usageHint ?? 'body'] || {};
568
1463
  }
569
- else {
1464
+ else if (typeof styles === 'object' && styles !== null) {
570
1465
  additionalStyles = styles;
571
1466
  }
572
1467
  return additionalStyles;
573
- }, ...(ngDevMode ? [{ debugName: "additionalStyles" }] : []));
1468
+ }, ...(ngDevMode ? [{ debugName: "additionalStyles" }] : /* istanbul ignore next */ []));
574
1469
  areHintedStyles(styles) {
575
1470
  if (typeof styles !== 'object' || !styles || Array.isArray(styles)) {
576
1471
  return false;
@@ -578,295 +1473,342 @@ class Text extends DynamicComponent {
578
1473
  const expected = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'caption', 'body'];
579
1474
  return expected.every((v) => v in styles);
580
1475
  }
581
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Text, deps: null, target: i0.ɵɵFactoryTarget.Component });
582
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.3", type: Text, isStandalone: true, selector: "a2ui-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, usageHint: { classPropertyName: "usageHint", publicName: "usageHint", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1476
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Text, deps: null, target: i0.ɵɵFactoryTarget.Component });
1477
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.5", type: Text, isStandalone: true, selector: "a2ui-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, usageHint: { classPropertyName: "usageHint", publicName: "usageHint", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
583
1478
  <section
584
1479
  [class]="classes()"
585
1480
  [style]="additionalStyles()"
586
- [innerHTML]="resolvedText()"
1481
+ [innerHTML]="resolvedText() | async"
587
1482
  ></section>
588
- `, isInline: true, styles: ["a2ui-text{display:block;flex:var(--weight)}a2ui-text h1,a2ui-text h2,a2ui-text h3,a2ui-text h4,a2ui-text h5{line-height:inherit;font:inherit}\n"], encapsulation: i0.ViewEncapsulation.None });
1483
+ `, isInline: true, styles: ["a2ui-text{display:block;flex:var(--weight)}a2ui-text h1,a2ui-text h2,a2ui-text h3,a2ui-text h4,a2ui-text h5{line-height:inherit;font:inherit}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.Eager, encapsulation: i0.ViewEncapsulation.None });
589
1484
  }
590
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Text, decorators: [{
1485
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Text, decorators: [{
591
1486
  type: Component,
592
- args: [{ selector: 'a2ui-text', template: `
1487
+ args: [{ selector: 'a2ui-text', changeDetection: ChangeDetectionStrategy.Eager, template: `
593
1488
  <section
594
1489
  [class]="classes()"
595
1490
  [style]="additionalStyles()"
596
- [innerHTML]="resolvedText()"
1491
+ [innerHTML]="resolvedText() | async"
597
1492
  ></section>
598
- `, encapsulation: ViewEncapsulation.None, styles: ["a2ui-text{display:block;flex:var(--weight)}a2ui-text h1,a2ui-text h2,a2ui-text h3,a2ui-text h4,a2ui-text h5{line-height:inherit;font:inherit}\n"] }]
599
- }], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: true }] }], usageHint: [{ type: i0.Input, args: [{ isSignal: true, alias: "usageHint", required: true }] }] } });
1493
+ `, encapsulation: ViewEncapsulation.None, imports: [AsyncPipe], styles: ["a2ui-text{display:block;flex:var(--weight)}a2ui-text h1,a2ui-text h2,a2ui-text h3,a2ui-text h4,a2ui-text h5{line-height:inherit;font:inherit}\n"] }]
1494
+ }], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: true }] }], usageHint: [{ type: i0.Input, args: [{ isSignal: true, alias: "usageHint", required: false }] }] } });
600
1495
 
601
1496
  /*
602
- Copyright 2025 Google LLC
1497
+ * Copyright 2025 Google LLC
1498
+ *
1499
+ * Licensed under the Apache License, Version 2.0 (the "License");
1500
+ * you may not use this file except in compliance with the License.
1501
+ * You may obtain a copy of the License at
1502
+ *
1503
+ * https://www.apache.org/licenses/LICENSE-2.0
1504
+ *
1505
+ * Unless required by applicable law or agreed to in writing, software
1506
+ * distributed under the License is distributed on an "AS IS" BASIS,
1507
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1508
+ * See the License for the specific language governing permissions and
1509
+ * limitations under the License.
1510
+ */
1511
+ class TextField extends DynamicComponent {
1512
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
1513
+ text = input(null, ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
1514
+ textFieldType = input('shortText', ...(ngDevMode ? [{ debugName: "textFieldType" }] : /* istanbul ignore next */ []));
1515
+ inputId = super.getUniqueId('a2ui-text-field');
1516
+ resolvedLabel = computed(() => super.resolvePrimitive(this.label()), ...(ngDevMode ? [{ debugName: "resolvedLabel" }] : /* istanbul ignore next */ []));
1517
+ resolvedText = computed(() => super.resolvePrimitive(this.text()), ...(ngDevMode ? [{ debugName: "resolvedText" }] : /* istanbul ignore next */ []));
1518
+ htmlInputType = computed(() => {
1519
+ switch (this.textFieldType()) {
1520
+ case 'number':
1521
+ return 'number';
1522
+ case 'date':
1523
+ return 'date';
1524
+ default:
1525
+ return 'text';
1526
+ }
1527
+ }, ...(ngDevMode ? [{ debugName: "htmlInputType" }] : /* istanbul ignore next */ []));
1528
+ onInput(event) {
1529
+ const value = event.target.value;
1530
+ const textNode = this.text();
1531
+ if (textNode && typeof textNode === 'object' && 'path' in textNode && textNode.path) {
1532
+ // Update the local data model directly to ensure immediate UI feedback and avoid unnecessary network requests.
1533
+ this.processor.processMessages([{
1534
+ dataModelUpdate: {
1535
+ surfaceId: this.surfaceId(),
1536
+ path: this.processor.resolvePath(textNode.path, this.component().dataContextPath),
1537
+ contents: [{ key: '.', valueString: value }],
1538
+ },
1539
+ }]);
1540
+ }
1541
+ else {
1542
+ this.handleAction('input', { value });
1543
+ }
1544
+ }
1545
+ handleAction(name, context) {
1546
+ super.sendAction({
1547
+ name,
1548
+ context: Object.entries(context).map(([key, val]) => ({
1549
+ key,
1550
+ value: typeof val === 'number' ? { literalNumber: val } : { literalString: String(val) },
1551
+ })),
1552
+ });
1553
+ }
1554
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: TextField, deps: null, target: i0.ɵɵFactoryTarget.Component });
1555
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.5", type: TextField, isStandalone: true, selector: "a2ui-text-field", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, textFieldType: { classPropertyName: "textFieldType", publicName: "textFieldType", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1556
+ <div [class]="theme.components.TextField.container" [style]="theme.additionalStyles?.TextField">
1557
+ <label [class]="theme.components.TextField.label" [for]="inputId">
1558
+ {{ resolvedLabel() }}
1559
+ </label>
1560
+ <input
1561
+ [type]="htmlInputType()"
1562
+ [class]="theme.components.TextField.element"
1563
+ [id]="inputId"
1564
+ [value]="resolvedText() ?? ''"
1565
+ (input)="onInput($event)"
1566
+ />
1567
+ </div>
1568
+ `, isInline: true, styles: [":host{display:block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1569
+ }
1570
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: TextField, decorators: [{
1571
+ type: Component,
1572
+ args: [{ selector: 'a2ui-text-field', template: `
1573
+ <div [class]="theme.components.TextField.container" [style]="theme.additionalStyles?.TextField">
1574
+ <label [class]="theme.components.TextField.label" [for]="inputId">
1575
+ {{ resolvedLabel() }}
1576
+ </label>
1577
+ <input
1578
+ [type]="htmlInputType()"
1579
+ [class]="theme.components.TextField.element"
1580
+ [id]="inputId"
1581
+ [value]="resolvedText() ?? ''"
1582
+ (input)="onInput($event)"
1583
+ />
1584
+ </div>
1585
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}\n"] }]
1586
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], textFieldType: [{ type: i0.Input, args: [{ isSignal: true, alias: "textFieldType", required: false }] }] } });
603
1587
 
604
- Licensed under the Apache License, Version 2.0 (the "License");
605
- you may not use this file except in compliance with the License.
606
- You may obtain a copy of the License at
1588
+ /*
1589
+ * Copyright 2025 Google LLC
1590
+ *
1591
+ * Licensed under the Apache License, Version 2.0 (the "License");
1592
+ * you may not use this file except in compliance with the License.
1593
+ * You may obtain a copy of the License at
1594
+ *
1595
+ * https://www.apache.org/licenses/LICENSE-2.0
1596
+ *
1597
+ * Unless required by applicable law or agreed to in writing, software
1598
+ * distributed under the License is distributed on an "AS IS" BASIS,
1599
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1600
+ * See the License for the specific language governing permissions and
1601
+ * limitations under the License.
1602
+ */
1603
+ class Video extends DynamicComponent {
1604
+ url = input.required(...(ngDevMode ? [{ debugName: "url" }] : /* istanbul ignore next */ []));
1605
+ resolvedUrl = computed(() => this.resolvePrimitive(this.url()), ...(ngDevMode ? [{ debugName: "resolvedUrl" }] : /* istanbul ignore next */ []));
1606
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Video, deps: null, target: i0.ɵɵFactoryTarget.Component });
1607
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Video, isStandalone: true, selector: "a2ui-video", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1608
+ @let resolvedUrl = this.resolvedUrl();
1609
+
1610
+ @if (resolvedUrl) {
1611
+ <section [class]="theme.components.Video" [style]="theme.additionalStyles?.Video">
1612
+ <video controls [src]="resolvedUrl"></video>
1613
+ </section>
1614
+ }
1615
+ `, isInline: true, styles: [":host{display:block;flex:var(--weight);min-height:0;overflow:auto}video{display:block;width:100%;box-sizing:border-box}\n"], changeDetection: i0.ChangeDetectionStrategy.Eager });
1616
+ }
1617
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Video, decorators: [{
1618
+ type: Component,
1619
+ args: [{ selector: 'a2ui-video', changeDetection: ChangeDetectionStrategy.Eager, template: `
1620
+ @let resolvedUrl = this.resolvedUrl();
607
1621
 
608
- https://www.apache.org/licenses/LICENSE-2.0
1622
+ @if (resolvedUrl) {
1623
+ <section [class]="theme.components.Video" [style]="theme.additionalStyles?.Video">
1624
+ <video controls [src]="resolvedUrl"></video>
1625
+ </section>
1626
+ }
1627
+ `, styles: [":host{display:block;flex:var(--weight);min-height:0;overflow:auto}video{display:block;width:100%;box-sizing:border-box}\n"] }]
1628
+ }], propDecorators: { url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }] } });
609
1629
 
610
- Unless required by applicable law or agreed to in writing, software
611
- distributed under the License is distributed on an "AS IS" BASIS,
612
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
613
- See the License for the specific language governing permissions and
614
- limitations under the License.
1630
+ /*
1631
+ * Copyright 2025 Google LLC
1632
+ *
1633
+ * Licensed under the Apache License, Version 2.0 (the "License");
1634
+ * you may not use this file except in compliance with the License.
1635
+ * You may obtain a copy of the License at
1636
+ *
1637
+ * https://www.apache.org/licenses/LICENSE-2.0
1638
+ *
1639
+ * Unless required by applicable law or agreed to in writing, software
1640
+ * distributed under the License is distributed on an "AS IS" BASIS,
1641
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1642
+ * See the License for the specific language governing permissions and
1643
+ * limitations under the License.
615
1644
  */
1645
+ // Components
616
1646
  const DEFAULT_CATALOG = {
617
- Row: {
618
- type: () => Row,
619
- bindings: (node) => {
620
- const properties = node.properties;
621
- return [
622
- inputBinding('alignment', () => properties.alignment ?? 'stretch'),
623
- inputBinding('distribution', () => properties.distribution ?? 'start'),
624
- ];
625
- },
626
- },
627
- Column: {
628
- type: () => Column,
629
- bindings: (node) => {
630
- const properties = node.properties;
631
- return [
632
- inputBinding('alignment', () => properties.alignment ?? 'stretch'),
633
- inputBinding('distribution', () => properties.distribution ?? 'start'),
634
- ];
635
- },
636
- },
637
- List: {
638
- type: () => import('./a2ui-angular-list-nEeT59V3.mjs').then((r) => r.List),
639
- bindings: (node) => {
640
- const properties = node.properties;
641
- return [inputBinding('direction', () => properties.direction ?? 'vertical')];
642
- },
643
- },
644
- Card: () => import('./a2ui-angular-card-Ix6OIdUv.mjs').then((r) => r.Card),
645
- Image: {
646
- type: () => import('./a2ui-angular-image-BWzAw0rh.mjs').then((r) => r.Image),
647
- bindings: (node) => {
648
- const properties = node.properties;
649
- return [
650
- inputBinding('url', () => properties.url),
651
- inputBinding('usageHint', () => properties.usageHint),
652
- ];
653
- },
654
- },
655
- Icon: {
656
- type: () => import('./a2ui-angular-icon-BE9Hj9V6.mjs').then((r) => r.Icon),
657
- bindings: (node) => {
658
- const properties = node.properties;
659
- return [inputBinding('name', () => properties.name)];
660
- },
661
- },
662
- Video: {
663
- type: () => import('./a2ui-angular-video-DuFTfN0B.mjs').then((r) => r.Video),
664
- bindings: (node) => {
665
- const properties = node.properties;
666
- return [inputBinding('url', () => properties.url)];
667
- },
668
- },
669
- AudioPlayer: {
670
- type: () => import('./a2ui-angular-audio-DoZb9mn_.mjs').then((r) => r.Audio),
671
- bindings: (node) => {
672
- const properties = node.properties;
673
- return [inputBinding('url', () => properties.url)];
674
- },
675
- },
676
- Text: {
677
- type: () => Text,
678
- bindings: (node) => {
679
- const properties = node.properties;
680
- return [
681
- inputBinding('text', () => properties.text),
682
- inputBinding('usageHint', () => properties.usageHint || null),
683
- ];
684
- },
685
- },
686
- Button: {
687
- type: () => import('./a2ui-angular-button-CvH0kAtN.mjs').then((r) => r.Button),
688
- bindings: (node) => {
689
- const properties = node.properties;
690
- return [inputBinding('action', () => properties.action)];
691
- },
692
- },
693
- Divider: () => import('./a2ui-angular-divider-BizPl3qL.mjs').then((r) => r.Divider),
694
- MultipleChoice: {
695
- type: () => import('./a2ui-angular-multiple-choice-Bry7X74i.mjs').then((r) => r.MultipleChoice),
696
- bindings: (node) => {
697
- const properties = node.properties;
698
- return [
699
- inputBinding('options', () => properties.options || []),
700
- inputBinding('value', () => properties.selections),
701
- inputBinding('description', () => 'Select an item'), // TODO: this should be defined in the properties
702
- ];
703
- },
704
- },
705
- TextField: {
706
- type: () => import('./a2ui-angular-text-field-Deokh07j.mjs').then((r) => r.TextField),
707
- bindings: (node) => {
708
- const properties = node.properties;
709
- return [
710
- inputBinding('text', () => properties.text ?? null),
711
- inputBinding('label', () => properties.label),
712
- inputBinding('inputType', () => properties.type),
713
- ];
714
- },
715
- },
716
- DateTimeInput: {
717
- type: () => import('./a2ui-angular-datetime-input-dmZAjvrF.mjs').then((r) => r.DatetimeInput),
718
- bindings: (node) => {
719
- const properties = node.properties;
720
- return [
721
- inputBinding('enableDate', () => properties.enableDate),
722
- inputBinding('enableTime', () => properties.enableTime),
723
- inputBinding('value', () => properties.value),
724
- ];
725
- },
726
- },
727
- CheckBox: {
728
- type: () => import('./a2ui-angular-checkbox-BN4EF2Ci.mjs').then((r) => r.Checkbox),
729
- bindings: (node) => {
730
- const properties = node.properties;
731
- return [
732
- inputBinding('label', () => properties.label),
733
- inputBinding('value', () => properties.value),
734
- ];
735
- },
736
- },
737
- Slider: {
738
- type: () => import('./a2ui-angular-slider-BgseUbN2.mjs').then((r) => r.Slider),
739
- bindings: (node) => {
740
- const properties = node.properties;
741
- return [
742
- inputBinding('value', () => properties.value),
743
- inputBinding('minValue', () => properties.minValue),
744
- inputBinding('maxValue', () => properties.maxValue),
745
- inputBinding('label', () => ''), // TODO: this should be defined in the properties
746
- ];
747
- },
748
- },
749
- Tabs: {
750
- type: () => import('./a2ui-angular-tabs-q5Mn9vgq.mjs').then((r) => r.Tabs),
751
- bindings: (node) => {
752
- const properties = node.properties;
753
- return [inputBinding('tabs', () => properties.tabItems)];
754
- },
755
- },
756
- Modal: {
757
- type: () => import('./a2ui-angular-modal-mr9LmczA.mjs').then((r) => r.Modal),
758
- bindings: () => [],
759
- },
1647
+ AudioPlayer: () => AudioPlayer,
1648
+ Button: () => Button,
1649
+ Card: () => Card,
1650
+ CheckBox: () => Checkbox,
1651
+ Column: () => Column,
1652
+ DateTimeInput: () => DateTimeInput,
1653
+ Divider: () => Divider,
1654
+ Icon: () => Icon,
1655
+ Image: () => Image,
1656
+ List: () => List,
1657
+ Modal: () => Modal,
1658
+ MultipleChoice: () => MultipleChoice,
1659
+ Row: () => Row,
1660
+ Slider: () => Slider,
1661
+ Tabs: () => Tabs,
1662
+ Text: () => Text,
1663
+ TextField: () => TextField,
1664
+ Video: () => Video,
760
1665
  };
1666
+ function registerStandardComponents(catalog) {
1667
+ for (const [key, value] of Object.entries(DEFAULT_CATALOG)) {
1668
+ catalog[key] = value;
1669
+ }
1670
+ }
761
1671
 
762
1672
  /*
763
- Copyright 2025 Google LLC
764
-
765
- Licensed under the Apache License, Version 2.0 (the "License");
766
- you may not use this file except in compliance with the License.
767
- You may obtain a copy of the License at
768
-
769
- https://www.apache.org/licenses/LICENSE-2.0
770
-
771
- Unless required by applicable law or agreed to in writing, software
772
- distributed under the License is distributed on an "AS IS" BASIS,
773
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
774
- See the License for the specific language governing permissions and
775
- limitations under the License.
1673
+ * Copyright 2025 Google LLC
1674
+ *
1675
+ * Licensed under the Apache License, Version 2.0 (the "License");
1676
+ * you may not use this file except in compliance with the License.
1677
+ * You may obtain a copy of the License at
1678
+ *
1679
+ * https://www.apache.org/licenses/LICENSE-2.0
1680
+ *
1681
+ * Unless required by applicable law or agreed to in writing, software
1682
+ * distributed under the License is distributed on an "AS IS" BASIS,
1683
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1684
+ * See the License for the specific language governing permissions and
1685
+ * limitations under the License.
776
1686
  */
777
1687
  class Surface {
778
- surfaceId = input.required(...(ngDevMode ? [{ debugName: "surfaceId" }] : []));
779
- surface = input.required(...(ngDevMode ? [{ debugName: "surface" }] : []));
780
- styles = computed(() => {
781
- const surface = this.surface();
782
- const styles = {};
783
- if (surface?.styles) {
784
- for (const [key, value] of Object.entries(surface.styles)) {
785
- switch (key) {
786
- // Here we generate a palette from the singular primary color received
787
- // from the surface data. We will want the values to range from
788
- // 0 <= x <= 100, where 0 = back, 100 = white, and 50 = the primary
789
- // color itself. As such we use a color-mix to create the intermediate
790
- // values.
791
- //
792
- // Note: since we use half the range for black to the primary color,
793
- // and half the range for primary color to white the mixed values have
794
- // to go up double the amount, i.e., a range from black to primary
795
- // color needs to fit in 0 -> 50 rather than 0 -> 100.
796
- case 'primaryColor': {
797
- styles['--p-100'] = '#ffffff';
798
- styles['--p-99'] = `color-mix(in srgb, ${value} 2%, white 98%)`;
799
- styles['--p-98'] = `color-mix(in srgb, ${value} 4%, white 96%)`;
800
- styles['--p-95'] = `color-mix(in srgb, ${value} 10%, white 90%)`;
801
- styles['--p-90'] = `color-mix(in srgb, ${value} 20%, white 80%)`;
802
- styles['--p-80'] = `color-mix(in srgb, ${value} 40%, white 60%)`;
803
- styles['--p-70'] = `color-mix(in srgb, ${value} 60%, white 40%)`;
804
- styles['--p-60'] = `color-mix(in srgb, ${value} 80%, white 20%)`;
805
- styles['--p-50'] = value;
806
- styles['--p-40'] = `color-mix(in srgb, ${value} 80%, black 20%)`;
807
- styles['--p-35'] = `color-mix(in srgb, ${value} 70%, black 30%)`;
808
- styles['--p-30'] = `color-mix(in srgb, ${value} 60%, black 40%)`;
809
- styles['--p-25'] = `color-mix(in srgb, ${value} 50%, black 50%)`;
810
- styles['--p-20'] = `color-mix(in srgb, ${value} 40%, black 60%)`;
811
- styles['--p-15'] = `color-mix(in srgb, ${value} 30%, black 70%)`;
812
- styles['--p-10'] = `color-mix(in srgb, ${value} 20%, black 80%)`;
813
- styles['--p-5'] = `color-mix(in srgb, ${value} 10%, black 90%)`;
814
- styles['--0'] = '#00000';
815
- break;
816
- }
817
- case 'font': {
818
- styles['--font-family'] = value;
819
- styles['--font-family-flex'] = value;
820
- break;
821
- }
822
- }
823
- }
824
- }
825
- return styles;
826
- }, ...(ngDevMode ? [{ debugName: "styles" }] : []));
827
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Surface, deps: [], target: i0.ɵɵFactoryTarget.Component });
828
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.3", type: Surface, isStandalone: true, selector: "a2ui-surface", inputs: { surfaceId: { classPropertyName: "surfaceId", publicName: "surfaceId", isSignal: true, isRequired: true, transformFunction: null }, surface: { classPropertyName: "surface", publicName: "surface", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "style": "styles()" } }, ngImport: i0, template: `
829
- @let surfaceId = this.surfaceId();
830
- @let surface = this.surface();
831
-
832
- @if (surfaceId && surface) {
833
- <ng-container a2ui-renderer [surfaceId]="surfaceId" [component]="surface.componentTree!" />
1688
+ processor = inject(MessageProcessor);
1689
+ surfaceId = input.required(...(ngDevMode ? [{ debugName: "surfaceId" }] : /* istanbul ignore next */ []));
1690
+ surfaceInput = input(null, { ...(ngDevMode ? { debugName: "surfaceInput" } : /* istanbul ignore next */ {}), alias: 'surface' });
1691
+ surface = computed(() => {
1692
+ this.processor.version(); // Track dependency on in-place mutations
1693
+ return this.surfaceInput() ?? this.processor.getSurfaces().get(this.surfaceId()) ?? null;
1694
+ }, ...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
1695
+ rootComponent = computed(() => {
1696
+ this.processor.version(); // Track dependency on in-place mutations
1697
+ return this.surface()?.componentTree ?? null;
1698
+ }, ...(ngDevMode ? [{ debugName: "rootComponent" }] : /* istanbul ignore next */ []));
1699
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Surface, deps: [], target: i0.ɵɵFactoryTarget.Component });
1700
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: Surface, isStandalone: true, selector: "a2ui-surface", inputs: { surfaceId: { classPropertyName: "surfaceId", publicName: "surfaceId", isSignal: true, isRequired: true, transformFunction: null }, surfaceInput: { classPropertyName: "surfaceInput", publicName: "surface", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
1701
+ @if (rootComponent()) {
1702
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()" [component]="rootComponent()!" />
834
1703
  }
835
- `, isInline: true, styles: [":host{display:flex;min-height:0;max-height:100%;flex-direction:column;gap:16px}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "ng-container[a2ui-renderer]", inputs: ["surfaceId", "component"] }] });
1704
+ `, isInline: true, styles: [":host{display:block;width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: Renderer, selector: "[a2ui-renderer]", inputs: ["surfaceId", "component"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
836
1705
  }
837
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: Surface, decorators: [{
1706
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: Surface, decorators: [{
838
1707
  type: Component,
839
1708
  args: [{ selector: 'a2ui-surface', imports: [Renderer], template: `
840
- @let surfaceId = this.surfaceId();
841
- @let surface = this.surface();
842
-
843
- @if (surfaceId && surface) {
844
- <ng-container a2ui-renderer [surfaceId]="surfaceId" [component]="surface.componentTree!" />
1709
+ @if (rootComponent()) {
1710
+ <ng-container a2ui-renderer [surfaceId]="surfaceId()" [component]="rootComponent()!" />
845
1711
  }
846
- `, host: {
847
- '[style]': 'styles()',
848
- }, styles: [":host{display:flex;min-height:0;max-height:100%;flex-direction:column;gap:16px}\n"] }]
849
- }], propDecorators: { surfaceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceId", required: true }] }], surface: [{ type: i0.Input, args: [{ isSignal: true, alias: "surface", required: true }] }] } });
1712
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;width:100%;height:100%}\n"] }]
1713
+ }], propDecorators: { surfaceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceId", required: true }] }], surfaceInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "surface", required: false }] }] } });
850
1714
 
851
1715
  /*
852
- Copyright 2025 Google LLC
1716
+ * Copyright 2025 Google LLC
1717
+ *
1718
+ * Licensed under the Apache License, Version 2.0 (the "License");
1719
+ * you may not use this file except in compliance with the License.
1720
+ * You may obtain a copy of the License at
1721
+ *
1722
+ * https://www.apache.org/licenses/LICENSE-2.0
1723
+ *
1724
+ * Unless required by applicable law or agreed to in writing, software
1725
+ * distributed under the License is distributed on an "AS IS" BASIS,
1726
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1727
+ * See the License for the specific language governing permissions and
1728
+ * limitations under the License.
1729
+ */
853
1730
 
854
- Licensed under the Apache License, Version 2.0 (the "License");
855
- you may not use this file except in compliance with the License.
856
- You may obtain a copy of the License at
1731
+ /*
1732
+ * Copyright 2025 Google LLC
1733
+ *
1734
+ * Licensed under the Apache License, Version 2.0 (the "License");
1735
+ * you may not use this file except in compliance with the License.
1736
+ * You may obtain a copy of the License at
1737
+ *
1738
+ * https://www.apache.org/licenses/LICENSE-2.0
1739
+ *
1740
+ * Unless required by applicable law or agreed to in writing, software
1741
+ * distributed under the License is distributed on an "AS IS" BASIS,
1742
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1743
+ * See the License for the specific language governing permissions and
1744
+ * limitations under the License.
1745
+ */
1746
+ function provideA2UI(config) {
1747
+ return makeEnvironmentProviders([
1748
+ { provide: Catalog, useValue: config.catalog },
1749
+ {
1750
+ provide: Theme,
1751
+ useFactory: () => {
1752
+ const theme = new Theme();
1753
+ theme.update(config.theme);
1754
+ return theme;
1755
+ },
1756
+ },
1757
+ ]);
1758
+ }
857
1759
 
858
- https://www.apache.org/licenses/LICENSE-2.0
1760
+ /*
1761
+ * Copyright 2025 Google LLC
1762
+ *
1763
+ * Licensed under the Apache License, Version 2.0 (the "License");
1764
+ * you may not use this file except in compliance with the License.
1765
+ * You may obtain a copy of the License at
1766
+ *
1767
+ * https://www.apache.org/licenses/LICENSE-2.0
1768
+ *
1769
+ * Unless required by applicable law or agreed to in writing, software
1770
+ * distributed under the License is distributed on an "AS IS" BASIS,
1771
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1772
+ * See the License for the specific language governing permissions and
1773
+ * limitations under the License.
1774
+ */
859
1775
 
860
- Unless required by applicable law or agreed to in writing, software
861
- distributed under the License is distributed on an "AS IS" BASIS,
862
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
863
- See the License for the specific language governing permissions and
864
- limitations under the License.
1776
+ /**
1777
+ * Copyright 2026 Google LLC
1778
+ *
1779
+ * Licensed under the Apache License, Version 2.0 (the "License");
1780
+ * you may not use this file except in compliance with the License.
1781
+ * You may obtain a copy of the License at
1782
+ *
1783
+ * http://www.apache.org/licenses/LICENSE-2.0
1784
+ *
1785
+ * Unless required by applicable law or agreed to in writing, software
1786
+ * distributed under the License is distributed on an "AS IS" BASIS,
1787
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1788
+ * See the License for the specific language governing permissions and
1789
+ * limitations under the License.
1790
+ */
1791
+
1792
+ /**
1793
+ * Copyright 2026 Google LLC
1794
+ *
1795
+ * Licensed under the Apache License, Version 2.0 (the "License");
1796
+ * you may not use this file except in compliance with the License.
1797
+ * You may obtain a copy of the License at
1798
+ *
1799
+ * http://www.apache.org/licenses/LICENSE-2.0
1800
+ *
1801
+ * Unless required by applicable law or agreed to in writing, software
1802
+ * distributed under the License is distributed on an "AS IS" BASIS,
1803
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1804
+ * See the License for the specific language governing permissions and
1805
+ * limitations under the License.
865
1806
  */
1807
+ const A2UI_ANGULAR_VERSION = '0.9.0';
866
1808
 
867
1809
  /**
868
1810
  * Generated bundle index. Do not edit.
869
1811
  */
870
1812
 
871
- export { Catalog, DEFAULT_CATALOG, DynamicComponent, MessageProcessor, Renderer, Surface, Theme, provideA2UI };
1813
+ export { A2UI_ANGULAR_VERSION, AudioPlayer, Button, Card, Catalog, Checkbox, Column, DEFAULT_CATALOG, DateTimeInput, Divider, DynamicComponent, Icon, Image, List, MessageProcessor, Modal, MultipleChoice, Renderer, Row, Slider, Surface, Tabs, Text, TextField, Theme, Video, provideA2UI, provideMarkdownRenderer, registerStandardComponents };
872
1814
  //# sourceMappingURL=a2ui-angular.mjs.map