@a2ui/angular 0.9.0-alpha.3 → 0.9.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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Inject, Injectable, signal, inject, DestroyRef, NgZone, input, ChangeDetectionStrategy, Component, computed as computed$1, effect as effect$1 } from '@angular/core';
2
+ import { InjectionToken, Inject, Injectable, signal, inject, DestroyRef, NgZone, input, ChangeDetectorRef, HostBinding, ChangeDetectionStrategy, Component, computed as computed$1, effect as effect$1 } from '@angular/core';
3
3
  import { MessageProcessor, effect, computed, ComponentContext, Catalog, DataContext } from '@a2ui/web_core/v0_9';
4
4
  export { signal as preactSignal } from '@a2ui/web_core/v0_9';
5
5
  import { NgComponentOutlet } from '@angular/common';
@@ -290,9 +290,16 @@ class ComponentHostComponent {
290
290
  rendererService = inject(A2uiRendererService);
291
291
  binder = inject(ComponentBinder);
292
292
  destroyRef = inject(DestroyRef);
293
+ cdr = inject(ChangeDetectorRef);
293
294
  componentType = null;
294
295
  props = {};
295
296
  context;
297
+ weight = signal(null, ...(ngDevMode ? [{ debugName: "weight" }] : /* istanbul ignore next */ []));
298
+ // TODO(#1199): Move weight handling to the catalog specification.
299
+ get flexStyle() {
300
+ const w = this.weight();
301
+ return w ? `${w}` : '';
302
+ }
296
303
  resolvedComponentId = '';
297
304
  resolvedDataContextPath = '/';
298
305
  ngOnInit() {
@@ -315,9 +322,20 @@ class ComponentHostComponent {
315
322
  this.resolvedComponentId = id;
316
323
  const componentModel = surface.componentsModel.get(id);
317
324
  if (!componentModel) {
318
- console.warn(`Component ${id} not found in surface ${this.surfaceId()}`);
325
+ console.warn(`Component ${id} not found in surface ${this.surfaceId()}. Waiting for it...`);
326
+ const sub = surface.componentsModel.onCreated.subscribe((comp) => {
327
+ if (comp.id === id) {
328
+ this.initializeComponent(surface, comp, id, basePath);
329
+ this.cdr.markForCheck();
330
+ sub.unsubscribe();
331
+ }
332
+ });
333
+ this.destroyRef.onDestroy(() => sub.unsubscribe());
319
334
  return;
320
335
  }
336
+ this.initializeComponent(surface, componentModel, id, basePath);
337
+ }
338
+ initializeComponent(surface, componentModel, id, basePath) {
321
339
  // Resolve component from the surface's catalog
322
340
  const catalog = surface.catalog;
323
341
  const api = catalog.components.get(componentModel.type);
@@ -330,23 +348,34 @@ class ComponentHostComponent {
330
348
  this.context = new ComponentContext(surface, id, basePath);
331
349
  this.props = this.binder.bind(this.context);
332
350
  this.resolvedDataContextPath = this.context.dataContext.path;
351
+ // Subscribes to updates to the component model properties, to get the
352
+ // component to react when a new prop is added after creation.
353
+ const onPropsUpdateSub = componentModel.onUpdated.subscribe(() => {
354
+ this.props = this.binder.bind(this.context);
355
+ // TODO(#1199): Move weight handling to the catalog specification.
356
+ this.weight.set(componentModel.properties['weight'] || null);
357
+ this.cdr.markForCheck();
358
+ });
359
+ this.weight.set(componentModel.properties['weight'] || null);
333
360
  this.destroyRef.onDestroy(() => {
334
361
  // ComponentContext itself doesn't have a dispose, but its inner components might.
335
362
  // However, SurfaceModel takes care of component disposal.
363
+ onPropsUpdateSub.unsubscribe();
336
364
  });
365
+ this.cdr.markForCheck();
337
366
  }
338
367
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ComponentHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
339
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: ComponentHostComponent, isStandalone: true, selector: "a2ui-v09-component-host", inputs: { componentKey: { classPropertyName: "componentKey", publicName: "componentKey", isSignal: true, isRequired: false, transformFunction: null }, surfaceId: { classPropertyName: "surfaceId", publicName: "surfaceId", isSignal: true, isRequired: true, transformFunction: null } }, host: { styleAttribute: "display: contents;" }, ngImport: i0, template: `
368
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: ComponentHostComponent, isStandalone: true, selector: "a2ui-v09-component-host", inputs: { componentKey: { classPropertyName: "componentKey", publicName: "componentKey", isSignal: true, isRequired: false, transformFunction: null }, surfaceId: { classPropertyName: "surfaceId", publicName: "surfaceId", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "style.flex": "this.flexStyle" }, styleAttribute: "display: contents;" }, ngImport: i0, template: `
340
369
  @if (componentType) {
341
370
  <ng-container
342
371
  *ngComponentOutlet="
343
372
  componentType;
344
373
  inputs: {
345
- props: props,
346
- surfaceId: surfaceId(),
347
- componentId: resolvedComponentId,
348
- dataContextPath: resolvedDataContextPath,
349
- }
374
+ props: props,
375
+ surfaceId: surfaceId(),
376
+ componentId: resolvedComponentId,
377
+ dataContextPath: resolvedDataContextPath,
378
+ }
350
379
  "
351
380
  ></ng-container>
352
381
  }
@@ -366,18 +395,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
366
395
  *ngComponentOutlet="
367
396
  componentType;
368
397
  inputs: {
369
- props: props,
370
- surfaceId: surfaceId(),
371
- componentId: resolvedComponentId,
372
- dataContextPath: resolvedDataContextPath,
373
- }
398
+ props: props,
399
+ surfaceId: surfaceId(),
400
+ componentId: resolvedComponentId,
401
+ dataContextPath: resolvedDataContextPath,
402
+ }
374
403
  "
375
404
  ></ng-container>
376
405
  }
377
406
  `,
378
407
  changeDetection: ChangeDetectionStrategy.OnPush,
379
408
  }]
380
- }], propDecorators: { componentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentKey", required: false }] }], surfaceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceId", required: true }] }] } });
409
+ }], propDecorators: { componentKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "componentKey", required: false }] }], surfaceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceId", required: true }] }], flexStyle: [{
410
+ type: HostBinding,
411
+ args: ['style.flex']
412
+ }] } });
381
413
 
382
414
  /**
383
415
  * Copyright 2026 Google LLC
@@ -454,32 +486,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
454
486
  * limitations under the License.
455
487
  */
456
488
 
457
- /**
458
- * Copyright 2026 Google LLC
459
- *
460
- * Licensed under the Apache License, Version 2.0 (the "License");
461
- * you may not use this file except in compliance with the License.
462
- * You may obtain a copy of the License at
463
- *
464
- * http://www.apache.org/licenses/LICENSE-2.0
465
- *
466
- * Unless required by applicable law or agreed to in writing, software
467
- * distributed under the License is distributed on an "AS IS" BASIS,
468
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
469
- * See the License for the specific language governing permissions and
470
- * limitations under the License.
471
- */
472
- /**
473
- * A collection of Angular component and function implementations mapped to
474
- * A2UI protocol types.
475
- *
476
- * Catalogs are used by the {@link MessageProcessor} to resolve component
477
- * definitions and by {@link ComponentHostComponent} to instantiate the
478
- * correct Angular components.
479
- */
480
- class AngularCatalog extends Catalog {
481
- }
482
-
483
489
  /**
484
490
  * Copyright 2026 Google LLC
485
491
  *
@@ -534,6 +540,32 @@ function provideMarkdownRenderer(renderFn) {
534
540
  return { provide: MarkdownRenderer, useClass: DefaultMarkdownRenderer };
535
541
  }
536
542
 
543
+ /**
544
+ * Copyright 2026 Google LLC
545
+ *
546
+ * Licensed under the Apache License, Version 2.0 (the "License");
547
+ * you may not use this file except in compliance with the License.
548
+ * You may obtain a copy of the License at
549
+ *
550
+ * http://www.apache.org/licenses/LICENSE-2.0
551
+ *
552
+ * Unless required by applicable law or agreed to in writing, software
553
+ * distributed under the License is distributed on an "AS IS" BASIS,
554
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
555
+ * See the License for the specific language governing permissions and
556
+ * limitations under the License.
557
+ */
558
+ /**
559
+ * A collection of Angular component and function implementations mapped to
560
+ * A2UI protocol types.
561
+ *
562
+ * Catalogs are used by the {@link MessageProcessor} to resolve component
563
+ * definitions and by {@link ComponentHostComponent} to instantiate the
564
+ * correct Angular components.
565
+ */
566
+ class AngularCatalog extends Catalog {
567
+ }
568
+
537
569
  /**
538
570
  * Copyright 2026 Google LLC
539
571
  *
@@ -1503,12 +1535,17 @@ class ListComponent extends BasicCatalogComponent {
1503
1535
  return 'none';
1504
1536
  return '';
1505
1537
  }, ...(ngDevMode ? [{ debugName: "styleType" }] : /* istanbul ignore next */ []));
1538
+ /**
1539
+ * Track-by function to ensure stable change detection for list items.
1540
+ * Uses the full resolved path (`basePath/id`) to uniquely identify items.
1541
+ */
1542
+ trackBy = (index, item) => `${item.basePath}/${item.id}`;
1506
1543
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: ListComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1507
1544
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: ListComponent, isStandalone: true, selector: "a2ui-v09-list", inputs: { props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, surfaceId: { classPropertyName: "surfaceId", publicName: "surfaceId", isSignal: true, isRequired: true, transformFunction: null }, componentId: { classPropertyName: "componentId", publicName: "componentId", isSignal: true, isRequired: false, transformFunction: null }, dataContextPath: { classPropertyName: "dataContextPath", publicName: "dataContextPath", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: `
1508
1545
  @switch (listTag()) {
1509
1546
  @case ('ol') {
1510
1547
  <ol [class]="'a2ui-list ' + orientation()" [style.list-style-type]="styleType()">
1511
- @for (child of children(); track child.id) {
1548
+ @for (child of children(); track trackBy($index, child)) {
1512
1549
  <li>
1513
1550
  <a2ui-v09-component-host
1514
1551
  [componentKey]="child"
@@ -1521,7 +1558,7 @@ class ListComponent extends BasicCatalogComponent {
1521
1558
  }
1522
1559
  @case ('ul') {
1523
1560
  <ul [class]="'a2ui-list ' + orientation()" [style.list-style-type]="styleType()">
1524
- @for (child of children(); track child.id) {
1561
+ @for (child of children(); track trackBy($index, child)) {
1525
1562
  <li>
1526
1563
  <a2ui-v09-component-host
1527
1564
  [componentKey]="child"
@@ -1534,7 +1571,7 @@ class ListComponent extends BasicCatalogComponent {
1534
1571
  }
1535
1572
  @default {
1536
1573
  <div [class]="'a2ui-list ' + orientation()" style="list-style-type: none;">
1537
- @for (child of children(); track child.id) {
1574
+ @for (child of children(); track trackBy($index, child)) {
1538
1575
  <div class="a2ui-list-item-none">
1539
1576
  <a2ui-v09-component-host
1540
1577
  [componentKey]="child"
@@ -1554,7 +1591,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
1554
1591
  @switch (listTag()) {
1555
1592
  @case ('ol') {
1556
1593
  <ol [class]="'a2ui-list ' + orientation()" [style.list-style-type]="styleType()">
1557
- @for (child of children(); track child.id) {
1594
+ @for (child of children(); track trackBy($index, child)) {
1558
1595
  <li>
1559
1596
  <a2ui-v09-component-host
1560
1597
  [componentKey]="child"
@@ -1567,7 +1604,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
1567
1604
  }
1568
1605
  @case ('ul') {
1569
1606
  <ul [class]="'a2ui-list ' + orientation()" [style.list-style-type]="styleType()">
1570
- @for (child of children(); track child.id) {
1607
+ @for (child of children(); track trackBy($index, child)) {
1571
1608
  <li>
1572
1609
  <a2ui-v09-component-host
1573
1610
  [componentKey]="child"
@@ -1580,7 +1617,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
1580
1617
  }
1581
1618
  @default {
1582
1619
  <div [class]="'a2ui-list ' + orientation()" style="list-style-type: none;">
1583
- @for (child of children(); track child.id) {
1620
+ @for (child of children(); track trackBy($index, child)) {
1584
1621
  <div class="a2ui-list-item-none">
1585
1622
  <a2ui-v09-component-host
1586
1623
  [componentKey]="child"
@@ -2521,5 +2558,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImpor
2521
2558
  * Generated bundle index. Do not edit.
2522
2559
  */
2523
2560
 
2524
- export { A2UI_RENDERER_CONFIG, A2uiRendererService, AngularCatalog, AudioPlayerComponent, BASIC_COMPONENTS, BasicCatalog, BasicCatalogBase, ButtonComponent, CardComponent, CheckBoxComponent, ChoicePickerComponent, ColumnComponent, ComponentBinder, ComponentHostComponent, DateTimeInputComponent, DividerComponent, IconComponent, ImageComponent, ListComponent, ModalComponent, RowComponent, SliderComponent, SurfaceComponent, TabsComponent, TextComponent, TextFieldComponent, VideoComponent, getNormalizedPath, toAngularSignal };
2561
+ export { A2UI_RENDERER_CONFIG, A2uiRendererService, AngularCatalog, AudioPlayerComponent, BASIC_COMPONENTS, BasicCatalog, BasicCatalogBase, ButtonComponent, CardComponent, CheckBoxComponent, ChoicePickerComponent, ColumnComponent, ComponentBinder, ComponentHostComponent, DateTimeInputComponent, DefaultMarkdownRenderer, DividerComponent, IconComponent, ImageComponent, ListComponent, MarkdownRenderer, ModalComponent, RowComponent, SliderComponent, SurfaceComponent, TabsComponent, TextComponent, TextFieldComponent, VideoComponent, getNormalizedPath, provideMarkdownRenderer, toAngularSignal };
2525
2562
  //# sourceMappingURL=a2ui-angular-src-v0_9.mjs.map