@analogjs/astro-angular 2.8.0-beta.1 → 2.8.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -428,7 +428,82 @@ import { HelloComponent } from "../../components/hello.component.ts";
428
428
 
429
429
  > Important: In `.mdx` files the component import must end with the `.ts` suffix. Otherwise the dynamic import of the component will fail and the component won't be hydrated.
430
430
 
431
+ ## Content Projection
432
+
433
+ Children passed to an Angular component in an Astro file are projected into the component's `ng-content` slots. Angular's own `select` semantics apply, so existing components work unchanged.
434
+
435
+ ```ts
436
+ import { Component } from '@angular/core';
437
+
438
+ @Component({
439
+ selector: 'app-card',
440
+ template: `
441
+ <div class="card">
442
+ <div class="card__header">
443
+ <ng-content select="[question]"></ng-content>
444
+ </div>
445
+ <div class="card__body">
446
+ <ng-content></ng-content>
447
+ </div>
448
+ </div>
449
+ `,
450
+ })
451
+ export class CardComponent {}
452
+ ```
453
+
454
+ ```html
455
+ ---
456
+ import { CardComponent } from '../components/card.component';
457
+ ---
458
+
459
+ <CardComponent client:visible>
460
+ <p question>Is content projection cool?</p>
461
+ <p>Let's learn about content projection!</p>
462
+ </CardComponent>
463
+ ```
464
+
465
+ Content that does not match any `select` is projected into the default `<ng-content>`. Without a default slot it is dropped, as in Angular. `ngProjectAs` is honored as well.
466
+
467
+ Astro's `slot` attribute is not needed to target a slot. Astro removes the attribute before rendering, so use Angular selectors such as attributes, classes, or element names instead.
468
+
469
+ > Note: for hydrated islands, Astro also emits the projected content in an inert `<template data-astro-template>` so it is available on the client. The slot markup therefore appears twice in the HTML response of hydrated components.
470
+
471
+ ### Components in Projected Content
472
+
473
+ Angular components used inside the slot are rendered and hydrated as islands of their own, the same way nested React, Vue or Svelte components behave in Astro. The parent component only receives their markup, so `@ContentChild`, `@ContentChildren`, input and output bindings, and dependency injection do not cross the island boundary.
474
+
475
+ ```html
476
+ ---
477
+ import { CardComponent } from '../components/card.component';
478
+ import { BadgeComponent } from '../components/badge.component';
479
+ ---
480
+
481
+ <!-- Two separate islands: the card cannot query or bind to the badge -->
482
+ <CardComponent client:visible>
483
+ <BadgeComponent client:visible label="New" />
484
+ </CardComponent>
485
+ ```
486
+
487
+ For a real parent and child relationship, compose the components in an Angular template and use that component as the island.
488
+
489
+ ```ts
490
+ import { Component } from '@angular/core';
491
+ import { CardComponent } from './card.component';
492
+ import { BadgeComponent } from './badge.component';
493
+
494
+ @Component({
495
+ selector: 'app-card-with-badge',
496
+ imports: [CardComponent, BadgeComponent],
497
+ template: `
498
+ <app-card>
499
+ <app-badge label="New" />
500
+ </app-card>
501
+ `,
502
+ })
503
+ export class CardWithBadgeComponent {}
504
+ ```
505
+
431
506
  ## Current Limitations
432
507
 
433
508
  - Only standalone Angular components in version v14.2+ are supported
434
- - Content projection to island components is not supported
509
+ - Angular components inside projected content are separate islands. Content queries, bindings and dependency injection from the parent component do not reach them, see [Components in Projected Content](#components-in-projected-content)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@analogjs/astro-angular",
3
- "version": "2.8.0-beta.1",
3
+ "version": "2.8.0-beta.10",
4
4
  "description": "Use Angular components within Astro",
5
5
  "type": "module",
6
6
  "author": "Brandon Roberts <robertsbt@gmail.com>",
@@ -34,7 +34,7 @@
34
34
  "url": "https://github.com/sponsors/brandonroberts"
35
35
  },
36
36
  "dependencies": {
37
- "@analogjs/vite-plugin-angular": "^2.8.0-beta.1",
37
+ "@analogjs/vite-plugin-angular": "^2.8.0-beta.10",
38
38
  "rehype": "^13.0.2"
39
39
  },
40
40
  "peerDependencies": {
@@ -3,6 +3,6 @@ import { type HydrationFeature, type HydrationFeatureKind } from '@angular/platf
3
3
  declare const _default: (element: HTMLElement) => (Component: Type<unknown> & {
4
4
  clientProviders?: (Provider | EnvironmentProviders)[];
5
5
  hydrationFeatures?: () => HydrationFeature<HydrationFeatureKind>[];
6
- }, props?: Record<string, unknown>) => void;
6
+ }, props?: Record<string, unknown>, slots?: unknown) => Promise<void | import("@angular/core").ApplicationRef> | undefined;
7
7
  export default _default;
8
8
  //# sourceMappingURL=client-ngh.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-ngh.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client-ngh.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,QAAQ,EAGb,IAAI,EAIL,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAE1B,MAAM,2BAA2B,CAAC;yBAQnB,SAAS,WAAW,MAEhC,WAAW,IAAI,CAAC,OAAO,CAAC,GAAG;IACzB,eAAe,CAAC,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;IACtD,iBAAiB,CAAC,EAAE,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,CAAC;CACpE,EACD,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;AANnC,wBA6DE"}
1
+ {"version":3,"file":"client-ngh.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client-ngh.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,QAAQ,EAGb,IAAI,EAGL,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAE1B,MAAM,2BAA2B,CAAC;yBAUnB,SAAS,WAAW,MAEhC,WAAW,IAAI,CAAC,OAAO,CAAC,GAAG;IACzB,eAAe,CAAC,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;IACtD,iBAAiB,CAAC,EAAE,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,CAAC;CACpE,EACD,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,OAAO;AAPnB,wBAkEE"}
package/src/client-ngh.js CHANGED
@@ -1,10 +1,11 @@
1
- import { reflectComponentType, provideZonelessChangeDetection, APP_ID, createComponent, APP_BOOTSTRAP_LISTENER, } from '@angular/core';
1
+ import { reflectComponentType, provideZonelessChangeDetection, APP_ID, createComponent, } from '@angular/core';
2
2
  import { createApplication, provideClientHydration, } from '@angular/platform-browser';
3
- import { createComponentBindings, getComponentElementTag, } from "./create-component.js";
3
+ import { createComponentBindings, getComponentElementTag, registerRootComponent, } from "./create-component.js";
4
4
  import { ID_PROP_NAME } from "./id.js";
5
5
  import { ensureSsrIntegrityMarker } from "./ssr-integrity.js";
6
+ import { buildProjectableNodes, collectProjectedNodes } from "./projection.js";
6
7
  export default (element) => {
7
- return (Component, props) => {
8
+ return (Component, props, slots) => {
8
9
  const mirror = reflectComponentType(Component);
9
10
  if (!mirror) {
10
11
  // Not an Angular component
@@ -20,7 +21,12 @@ export default (element) => {
20
21
  reuseDom = false;
21
22
  }
22
23
  const ngAppId = hostElement?.getAttribute(ID_PROP_NAME);
23
- createApplication({
24
+ // Hydration reuses the server-rendered DOM, so hand Angular the projected
25
+ // nodes it already rendered instead of freshly parsed copies.
26
+ const projectableNodes = (reuseDom && ngAppId
27
+ ? collectProjectedNodes(hostElement, mirror, ngAppId)
28
+ : undefined) ?? buildProjectableNodes(mirror, slots, document);
29
+ return createApplication({
24
30
  providers: [
25
31
  provideZonelessChangeDetection(),
26
32
  reuseDom
@@ -37,13 +43,11 @@ export default (element) => {
37
43
  const componentRef = createComponent(Component, {
38
44
  environmentInjector: appRef.injector,
39
45
  hostElement,
46
+ projectableNodes,
40
47
  bindings: createComponentBindings(mirror, props, hostElement),
41
48
  });
42
- appRef.attachView(componentRef.hostView);
43
- appRef.components.push(componentRef);
44
- appRef.injector
45
- .get(APP_BOOTSTRAP_LISTENER, [])
46
- .forEach((cb) => cb(componentRef));
49
+ registerRootComponent(appRef, componentRef);
50
+ return appRef;
47
51
  })
48
52
  .catch((error) => {
49
53
  console.error('Failed to hydrate Angular component:', error);
@@ -1 +1 @@
1
- {"version":3,"file":"client-ngh.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client-ngh.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,oBAAoB,EACpB,8BAA8B,EAE9B,MAAM,EACN,eAAe,EACf,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EAGjB,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,eAAe,CAAC,OAAoB,EAAE,EAAE;IACtC,OAAO,CACL,SAGC,EACD,KAA+B,EAC/B,EAAE;QACF,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAE/C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,2BAA2B;YAC3B,OAAO;QACT,CAAC;QAED,wBAAwB,EAAE,CAAC;QAE3B,IAAI,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,QAAQ,GAAG,IAAI,CAAC;QAEpB,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,kCAAkC;YAClC,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC;YACrE,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;YACjC,QAAQ,GAAG,KAAK,CAAC;QACnB,CAAC;QAED,MAAM,OAAO,GAAG,WAAW,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;QAExD,iBAAiB,CAAC;YAChB,SAAS,EAAE;gBACT,8BAA8B,EAAE;gBAChC,QAAQ;oBACN,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;oBACpE,CAAC,CAAC,EAAE;gBACN;oBACE,OAAO,EAAE,MAAM;oBACf,QAAQ,EAAE,OAAO,IAAI,IAAI;iBAC1B;gBACD,GAAG,CAAC,SAAS,CAAC,eAAe,IAAI,EAAE,CAAC;aACrC;SACF,CAAC;aACC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,EAAE;gBAC9C,mBAAmB,EAAE,MAAM,CAAC,QAAQ;gBACpC,WAAW;gBACX,QAAQ,EAAE,uBAAuB,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC;aAC9D,CAAC,CAAC;YAEH,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAEzC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAErC,MAAM,CAAC,QAAQ;iBACZ,GAAG,CAAC,sBAAsB,EAAE,EAAE,CAAC;iBAC/B,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n type EnvironmentProviders,\n type Provider,\n reflectComponentType,\n provideZonelessChangeDetection,\n Type,\n APP_ID,\n createComponent,\n APP_BOOTSTRAP_LISTENER,\n} from '@angular/core';\nimport {\n createApplication,\n type HydrationFeature,\n type HydrationFeatureKind,\n provideClientHydration,\n} from '@angular/platform-browser';\nimport {\n createComponentBindings,\n getComponentElementTag,\n} from './create-component.ts';\nimport { ID_PROP_NAME } from './id.ts';\nimport { ensureSsrIntegrityMarker } from './ssr-integrity.ts';\n\nexport default (element: HTMLElement) => {\n return (\n Component: Type<unknown> & {\n clientProviders?: (Provider | EnvironmentProviders)[];\n hydrationFeatures?: () => HydrationFeature<HydrationFeatureKind>[];\n },\n props?: Record<string, unknown>,\n ) => {\n const mirror = reflectComponentType(Component);\n\n if (!mirror) {\n // Not an Angular component\n return;\n }\n\n ensureSsrIntegrityMarker();\n\n let hostElement = element.querySelector(mirror.selector);\n let reuseDom = true;\n\n if (!hostElement) {\n // This is a client-only component\n hostElement = document.createElement(getComponentElementTag(mirror));\n element.appendChild(hostElement);\n reuseDom = false;\n }\n\n const ngAppId = hostElement?.getAttribute(ID_PROP_NAME);\n\n createApplication({\n providers: [\n provideZonelessChangeDetection(),\n reuseDom\n ? provideClientHydration(...(Component.hydrationFeatures?.() || []))\n : [],\n {\n provide: APP_ID,\n useValue: ngAppId || 'ng',\n },\n ...(Component.clientProviders || []),\n ],\n })\n .then((appRef) => {\n const componentRef = createComponent(Component, {\n environmentInjector: appRef.injector,\n hostElement,\n bindings: createComponentBindings(mirror, props, hostElement),\n });\n\n appRef.attachView(componentRef.hostView);\n\n appRef.components.push(componentRef);\n\n appRef.injector\n .get(APP_BOOTSTRAP_LISTENER, [])\n .forEach((cb) => cb(componentRef));\n })\n .catch((error) => {\n console.error('Failed to hydrate Angular component:', error);\n });\n };\n};\n"]}
1
+ {"version":3,"file":"client-ngh.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client-ngh.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,oBAAoB,EACpB,8BAA8B,EAE9B,MAAM,EACN,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EAGjB,sBAAsB,GACvB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE/E,eAAe,CAAC,OAAoB,EAAE,EAAE;IACtC,OAAO,CACL,SAGC,EACD,KAA+B,EAC/B,KAAe,EACf,EAAE;QACF,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;QAE/C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,2BAA2B;YAC3B,OAAO;QACT,CAAC;QAED,wBAAwB,EAAE,CAAC;QAE3B,IAAI,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,QAAQ,GAAG,IAAI,CAAC;QAEpB,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,kCAAkC;YAClC,WAAW,GAAG,QAAQ,CAAC,aAAa,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC,CAAC;YACrE,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;YACjC,QAAQ,GAAG,KAAK,CAAC;QACnB,CAAC;QAED,MAAM,OAAO,GAAG,WAAW,EAAE,YAAY,CAAC,YAAY,CAAC,CAAC;QAExD,0EAA0E;QAC1E,8DAA8D;QAC9D,MAAM,gBAAgB,GACpB,CAAC,QAAQ,IAAI,OAAO;YAClB,CAAC,CAAC,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC;YACrD,CAAC,CAAC,SAAS,CAAC,IAAI,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QAEnE,OAAO,iBAAiB,CAAC;YACvB,SAAS,EAAE;gBACT,8BAA8B,EAAE;gBAChC,QAAQ;oBACN,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;oBACpE,CAAC,CAAC,EAAE;gBACN;oBACE,OAAO,EAAE,MAAM;oBACf,QAAQ,EAAE,OAAO,IAAI,IAAI;iBAC1B;gBACD,GAAG,CAAC,SAAS,CAAC,eAAe,IAAI,EAAE,CAAC;aACrC;SACF,CAAC;aACC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,EAAE;gBAC9C,mBAAmB,EAAE,MAAM,CAAC,QAAQ;gBACpC,WAAW;gBACX,gBAAgB;gBAChB,QAAQ,EAAE,uBAAuB,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC;aAC9D,CAAC,CAAC;YAEH,qBAAqB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;YAE5C,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n type EnvironmentProviders,\n type Provider,\n reflectComponentType,\n provideZonelessChangeDetection,\n Type,\n APP_ID,\n createComponent,\n} from '@angular/core';\nimport {\n createApplication,\n type HydrationFeature,\n type HydrationFeatureKind,\n provideClientHydration,\n} from '@angular/platform-browser';\nimport {\n createComponentBindings,\n getComponentElementTag,\n registerRootComponent,\n} from './create-component.ts';\nimport { ID_PROP_NAME } from './id.ts';\nimport { ensureSsrIntegrityMarker } from './ssr-integrity.ts';\nimport { buildProjectableNodes, collectProjectedNodes } from './projection.ts';\n\nexport default (element: HTMLElement) => {\n return (\n Component: Type<unknown> & {\n clientProviders?: (Provider | EnvironmentProviders)[];\n hydrationFeatures?: () => HydrationFeature<HydrationFeatureKind>[];\n },\n props?: Record<string, unknown>,\n slots?: unknown,\n ) => {\n const mirror = reflectComponentType(Component);\n\n if (!mirror) {\n // Not an Angular component\n return;\n }\n\n ensureSsrIntegrityMarker();\n\n let hostElement = element.querySelector(mirror.selector);\n let reuseDom = true;\n\n if (!hostElement) {\n // This is a client-only component\n hostElement = document.createElement(getComponentElementTag(mirror));\n element.appendChild(hostElement);\n reuseDom = false;\n }\n\n const ngAppId = hostElement?.getAttribute(ID_PROP_NAME);\n\n // Hydration reuses the server-rendered DOM, so hand Angular the projected\n // nodes it already rendered instead of freshly parsed copies.\n const projectableNodes =\n (reuseDom && ngAppId\n ? collectProjectedNodes(hostElement, mirror, ngAppId)\n : undefined) ?? buildProjectableNodes(mirror, slots, document);\n\n return createApplication({\n providers: [\n provideZonelessChangeDetection(),\n reuseDom\n ? provideClientHydration(...(Component.hydrationFeatures?.() || []))\n : [],\n {\n provide: APP_ID,\n useValue: ngAppId || 'ng',\n },\n ...(Component.clientProviders || []),\n ],\n })\n .then((appRef) => {\n const componentRef = createComponent(Component, {\n environmentInjector: appRef.injector,\n hostElement,\n projectableNodes,\n bindings: createComponentBindings(mirror, props, hostElement),\n });\n\n registerRootComponent(appRef, componentRef);\n\n return appRef;\n })\n .catch((error) => {\n console.error('Failed to hydrate Angular component:', error);\n });\n };\n};\n"]}
package/src/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { EnvironmentProviders, Provider, ɵComponentType as ComponentType } from '@angular/core';
2
2
  declare const _default: (element: HTMLElement) => (Component: ComponentType<unknown> & {
3
3
  clientProviders?: (Provider | EnvironmentProviders)[];
4
- }, props?: Record<string, unknown>, _childHTML?: unknown) => void;
4
+ }, props?: Record<string, unknown>, slots?: unknown) => void;
5
5
  export default _default;
6
6
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,QAAQ,EAER,cAAc,IAAI,aAAa,EAEhC,MAAM,eAAe,CAAC;yBAKP,SAAS,WAAW,MAEhC,WAAW,aAAa,CAAC,OAAO,CAAC,GAAG;IAClC,eAAe,CAAC,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;CACvD,EACD,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,aAAa,OAAO;AANxB,wBAoEE"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,QAAQ,EAER,cAAc,IAAI,aAAa,EAEhC,MAAM,eAAe,CAAC;yBAMP,SAAS,WAAW,MAEhC,WAAW,aAAa,CAAC,OAAO,CAAC,GAAG;IAClC,eAAe,CAAC,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;CACvD,EACD,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,OAAO;AANnB,wBA2EE"}
package/src/client.js CHANGED
@@ -2,8 +2,14 @@ import { reflectComponentType, provideZonelessChangeDetection, } from '@angular/
2
2
  import { createComponent } from '@angular/core';
3
3
  import { createApplication } from '@angular/platform-browser';
4
4
  import { Subject, takeUntil } from 'rxjs';
5
+ import { buildProjectableNodes } from "./projection.js";
5
6
  export default (element) => {
6
- return (Component, props, _childHTML) => {
7
+ return (Component, props, slots) => {
8
+ const mirror = reflectComponentType(Component);
9
+ if (!mirror) {
10
+ // Not an Angular component
11
+ return;
12
+ }
7
13
  createApplication({
8
14
  providers: [
9
15
  provideZonelessChangeDetection(),
@@ -13,16 +19,16 @@ export default (element) => {
13
19
  const componentRef = createComponent(Component, {
14
20
  environmentInjector: appRef.injector,
15
21
  hostElement: element,
22
+ projectableNodes: buildProjectableNodes(mirror, slots, document),
16
23
  });
17
- const mirror = reflectComponentType(Component);
18
- if (props && mirror) {
24
+ if (props) {
19
25
  for (const [key, value] of Object.entries(props)) {
20
26
  if (mirror.inputs.some(({ templateName, propName }) => templateName === key || propName === key)) {
21
27
  componentRef.setInput(key, value);
22
28
  }
23
29
  }
24
30
  }
25
- if (mirror?.outputs.length && props?.['data-analog-id']) {
31
+ if (mirror.outputs.length && props?.['data-analog-id']) {
26
32
  const destroySubject = new Subject();
27
33
  element.setAttribute('data-analog-id', props['data-analog-id']);
28
34
  mirror.outputs.forEach(({ templateName, propName }) => {
package/src/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,oBAAoB,EAEpB,8BAA8B,GAC/B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAkB,eAAe,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAc,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtD,eAAe,CAAC,OAAoB,EAAE,EAAE;IACtC,OAAO,CACL,SAEC,EACD,KAA+B,EAC/B,UAAoB,EACpB,EAAE;QACF,iBAAiB,CAAC;YAChB,SAAS,EAAE;gBACT,8BAA8B,EAAE;gBAChC,GAAG,CAAC,SAAS,CAAC,eAAe,IAAI,EAAE,CAAC;aACrC;SACF,CAAC,CAAC,IAAI,CAAC,CAAC,MAAsB,EAAE,EAAE;YACjC,MAAM,YAAY,GAAG,eAAe,CAAC,SAAS,EAAE;gBAC9C,mBAAmB,EAAE,MAAM,CAAC,QAAQ;gBACpC,WAAW,EAAE,OAAO;aACrB,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;YAC/C,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;gBACpB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBACjD,IACE,MAAM,CAAC,MAAM,CAAC,IAAI,CAChB,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC7B,YAAY,KAAK,GAAG,IAAI,QAAQ,KAAK,GAAG,CAC3C,EACD,CAAC;wBACD,YAAY,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;oBACpC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBACxD,MAAM,cAAc,GAAG,IAAI,OAAO,EAAQ,CAAC;gBAC3C,OAAO,CAAC,YAAY,CAClB,gBAAgB,EAChB,KAAK,CAAC,gBAAgB,CAAW,CAClC,CAAC;gBAEF,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,EAAE;oBACpD,MAAM,UAAU,GAAG,YAAY,IAAI,QAAQ,CAAC;oBAC5C,MAAM,SAAS,GAAG,YAAY,CAAC,QAG9B,CAAC;oBACF,SAAS,CAAC,UAAU,CAAC;yBAClB,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;yBAC/B,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;wBACpB,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,UAAU,EAAE;4BACxC,OAAO,EAAE,IAAI;4BACb,UAAU,EAAE,IAAI;4BAChB,QAAQ,EAAE,IAAI;4BACd,MAAM;yBACP,CAAC,CAAC;wBACH,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;oBAC/B,CAAC,CAAC,CAAC;gBACP,CAAC,CAAC,CAAC;gBAEH,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE;oBACpB,cAAc,CAAC,IAAI,EAAE,CAAC;oBACtB,cAAc,CAAC,QAAQ,EAAE,CAAC;gBAC5B,CAAC,CAAC,CAAC;YACL,CAAC;YAED,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import {\n EnvironmentProviders,\n Provider,\n reflectComponentType,\n ɵComponentType as ComponentType,\n provideZonelessChangeDetection,\n} from '@angular/core';\nimport { ApplicationRef, createComponent } from '@angular/core';\nimport { createApplication } from '@angular/platform-browser';\nimport { Observable, Subject, takeUntil } from 'rxjs';\n\nexport default (element: HTMLElement) => {\n return (\n Component: ComponentType<unknown> & {\n clientProviders?: (Provider | EnvironmentProviders)[];\n },\n props?: Record<string, unknown>,\n _childHTML?: unknown,\n ) => {\n createApplication({\n providers: [\n provideZonelessChangeDetection(),\n ...(Component.clientProviders || []),\n ],\n }).then((appRef: ApplicationRef) => {\n const componentRef = createComponent(Component, {\n environmentInjector: appRef.injector,\n hostElement: element,\n });\n\n const mirror = reflectComponentType(Component);\n if (props && mirror) {\n for (const [key, value] of Object.entries(props)) {\n if (\n mirror.inputs.some(\n ({ templateName, propName }) =>\n templateName === key || propName === key,\n )\n ) {\n componentRef.setInput(key, value);\n }\n }\n }\n\n if (mirror?.outputs.length && props?.['data-analog-id']) {\n const destroySubject = new Subject<void>();\n element.setAttribute(\n 'data-analog-id',\n props['data-analog-id'] as string,\n );\n\n mirror.outputs.forEach(({ templateName, propName }) => {\n const outputName = templateName || propName;\n const component = componentRef.instance as Record<\n string,\n Observable<unknown>\n >;\n component[outputName]\n .pipe(takeUntil(destroySubject))\n .subscribe((detail) => {\n const event = new CustomEvent(outputName, {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail,\n });\n element.dispatchEvent(event);\n });\n });\n\n appRef.onDestroy(() => {\n destroySubject.next();\n destroySubject.complete();\n });\n }\n\n appRef.attachView(componentRef.hostView);\n });\n };\n};\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/client.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n EnvironmentProviders,\n Provider,\n reflectComponentType,\n ɵComponentType as ComponentType,\n provideZonelessChangeDetection,\n} from '@angular/core';\nimport { ApplicationRef, createComponent } from '@angular/core';\nimport { createApplication } from '@angular/platform-browser';\nimport { Observable, Subject, takeUntil } from 'rxjs';\nimport { buildProjectableNodes } from './projection.ts';\n\nexport default (element: HTMLElement) => {\n return (\n Component: ComponentType<unknown> & {\n clientProviders?: (Provider | EnvironmentProviders)[];\n },\n props?: Record<string, unknown>,\n slots?: unknown,\n ) => {\n const mirror = reflectComponentType(Component);\n\n if (!mirror) {\n // Not an Angular component\n return;\n }\n\n createApplication({\n providers: [\n provideZonelessChangeDetection(),\n ...(Component.clientProviders || []),\n ],\n }).then((appRef: ApplicationRef) => {\n const componentRef = createComponent(Component, {\n environmentInjector: appRef.injector,\n hostElement: element,\n projectableNodes: buildProjectableNodes(mirror, slots, document),\n });\n\n if (props) {\n for (const [key, value] of Object.entries(props)) {\n if (\n mirror.inputs.some(\n ({ templateName, propName }) =>\n templateName === key || propName === key,\n )\n ) {\n componentRef.setInput(key, value);\n }\n }\n }\n\n if (mirror.outputs.length && props?.['data-analog-id']) {\n const destroySubject = new Subject<void>();\n element.setAttribute(\n 'data-analog-id',\n props['data-analog-id'] as string,\n );\n\n mirror.outputs.forEach(({ templateName, propName }) => {\n const outputName = templateName || propName;\n const component = componentRef.instance as Record<\n string,\n Observable<unknown>\n >;\n component[outputName]\n .pipe(takeUntil(destroySubject))\n .subscribe((detail) => {\n const event = new CustomEvent(outputName, {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail,\n });\n element.dispatchEvent(event);\n });\n });\n\n appRef.onDestroy(() => {\n destroySubject.next();\n destroySubject.complete();\n });\n }\n\n appRef.attachView(componentRef.hostView);\n });\n };\n};\n"]}
@@ -1,6 +1,13 @@
1
- import { type Binding, type ComponentMirror } from '@angular/core';
1
+ import { type ApplicationRef, type Binding, type ComponentMirror, type ComponentRef } from '@angular/core';
2
2
  export declare function getComponentElementTag(mirror: ComponentMirror<unknown>): string;
3
3
  export declare function createInputBindings(mirror: ComponentMirror<unknown>, props?: Record<string, unknown>): Binding[];
4
4
  export declare function createOutputBindings(hostElement: Element, mirror: ComponentMirror<unknown>): Binding[];
5
5
  export declare function createComponentBindings(mirror: ComponentMirror<unknown>, props?: Record<string, unknown>, hostElement?: Element): Binding[];
6
+ /**
7
+ * Registers a component created with `createComponent` as a root component,
8
+ * the way `bootstrapApplication` does: attach the view, track it on the
9
+ * application, run the initial change detection and notify
10
+ * `APP_BOOTSTRAP_LISTENER`s such as the router's.
11
+ */
12
+ export declare function registerRootComponent(appRef: ApplicationRef, componentRef: ComponentRef<unknown>): void;
6
13
  //# sourceMappingURL=create-component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-component.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/create-component.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,eAAe,EAGrB,MAAM,eAAe,CAAC;AAGvB,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAC/B,MAAM,CAER;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,EAAE,CAYX;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,OAAO,EACpB,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAC/B,OAAO,EAAE,CAcX;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,WAAW,CAAC,EAAE,OAAO,GACpB,OAAO,EAAE,CAUX"}
1
+ {"version":3,"file":"create-component.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/create-component.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,OAAO,EACZ,KAAK,eAAe,EACpB,KAAK,YAAY,EAGlB,MAAM,eAAe,CAAC;AAGvB,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAC/B,MAAM,CAER;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,EAAE,CAYX;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,OAAO,EACpB,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAC/B,OAAO,EAAE,CAcX;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,WAAW,CAAC,EAAE,OAAO,GACpB,OAAO,EAAE,CAUX;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,cAAc,EACtB,YAAY,EAAE,YAAY,CAAC,OAAO,CAAC,GAClC,IAAI,CAON"}
@@ -1,4 +1,4 @@
1
- import { inputBinding, outputBinding, } from '@angular/core';
1
+ import { APP_BOOTSTRAP_LISTENER, inputBinding, outputBinding, } from '@angular/core';
2
2
  import { ID_PROP_NAME } from "./id.js";
3
3
  export function getComponentElementTag(mirror) {
4
4
  return mirror.selector.split(',')[0] || 'ng-component';
@@ -32,4 +32,18 @@ export function createComponentBindings(mirror, props, hostElement) {
32
32
  const outputBindings = createOutputBindings(hostElement, mirror);
33
33
  return [...inputBindings, ...outputBindings];
34
34
  }
35
+ /**
36
+ * Registers a component created with `createComponent` as a root component,
37
+ * the way `bootstrapApplication` does: attach the view, track it on the
38
+ * application, run the initial change detection and notify
39
+ * `APP_BOOTSTRAP_LISTENER`s such as the router's.
40
+ */
41
+ export function registerRootComponent(appRef, componentRef) {
42
+ appRef.attachView(componentRef.hostView);
43
+ appRef.tick();
44
+ appRef.components.push(componentRef);
45
+ appRef.injector
46
+ .get(APP_BOOTSTRAP_LISTENER, [])
47
+ .forEach((listener) => listener(componentRef));
48
+ }
35
49
  //# sourceMappingURL=create-component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create-component.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/create-component.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,UAAU,sBAAsB,CACpC,MAAgC;IAEhC,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAAgC,EAChC,KAA+B;IAE/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;SACxC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAChB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,YAAY,KAAK,GAAG,CAAC,CAC/D;SACA,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEzD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAoB,EACpB,MAAgC;IAEhC,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAC7D,aAAa,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,YAAY,EAAE;YAC1C,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE,IAAI;YACd,MAAM;SACP,CAAC,CAAC;QACH,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAAgC,EAChC,KAA+B,EAC/B,WAAqB;IAErB,MAAM,aAAa,GAAG,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAEzD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACrE,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,cAAc,GAAG,oBAAoB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAEjE,OAAO,CAAC,GAAG,aAAa,EAAE,GAAG,cAAc,CAAC,CAAC;AAC/C,CAAC","sourcesContent":["import {\n type Binding,\n type ComponentMirror,\n inputBinding,\n outputBinding,\n} from '@angular/core';\nimport { ID_PROP_NAME } from './id.ts';\n\nexport function getComponentElementTag(\n mirror: ComponentMirror<unknown>,\n): string {\n return mirror.selector.split(',')[0] || 'ng-component';\n}\n\nexport function createInputBindings(\n mirror: ComponentMirror<unknown>,\n props?: Record<string, unknown>,\n): Binding[] {\n if (!props) {\n return [];\n }\n\n const inputBindings = Object.entries(props)\n .filter(([key]) =>\n mirror.inputs.some(({ templateName }) => templateName === key),\n )\n .map(([key, value]) => inputBinding(key, () => value));\n\n return inputBindings;\n}\n\nexport function createOutputBindings(\n hostElement: Element,\n mirror: ComponentMirror<unknown>,\n): Binding[] {\n const outputBindings = mirror.outputs.map(({ templateName }) =>\n outputBinding(templateName, (detail) => {\n const event = new CustomEvent(templateName, {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail,\n });\n hostElement.dispatchEvent(event);\n }),\n );\n\n return outputBindings;\n}\n\nexport function createComponentBindings(\n mirror: ComponentMirror<unknown>,\n props?: Record<string, unknown>,\n hostElement?: Element,\n): Binding[] {\n const inputBindings = createInputBindings(mirror, props);\n\n if (!mirror.outputs.length || !props?.[ID_PROP_NAME] || !hostElement) {\n return inputBindings;\n }\n\n const outputBindings = createOutputBindings(hostElement, mirror);\n\n return [...inputBindings, ...outputBindings];\n}\n"]}
1
+ {"version":3,"file":"create-component.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/create-component.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EAKtB,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,UAAU,sBAAsB,CACpC,MAAgC;IAEhC,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,MAAgC,EAChC,KAA+B;IAE/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;SACxC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAChB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,YAAY,KAAK,GAAG,CAAC,CAC/D;SACA,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEzD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAoB,EACpB,MAAgC;IAEhC,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAC7D,aAAa,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,YAAY,EAAE;YAC1C,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE,IAAI;YACd,MAAM;SACP,CAAC,CAAC;QACH,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAAgC,EAChC,KAA+B,EAC/B,WAAqB;IAErB,MAAM,aAAa,GAAG,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAEzD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACrE,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,cAAc,GAAG,oBAAoB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAEjE,OAAO,CAAC,GAAG,aAAa,EAAE,GAAG,cAAc,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAsB,EACtB,YAAmC;IAEnC,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,CAAC,IAAI,EAAE,CAAC;IACd,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACrC,MAAM,CAAC,QAAQ;SACZ,GAAG,CAAC,sBAAsB,EAAE,EAAE,CAAC;SAC/B,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;AACnD,CAAC","sourcesContent":["import {\n APP_BOOTSTRAP_LISTENER,\n type ApplicationRef,\n type Binding,\n type ComponentMirror,\n type ComponentRef,\n inputBinding,\n outputBinding,\n} from '@angular/core';\nimport { ID_PROP_NAME } from './id.ts';\n\nexport function getComponentElementTag(\n mirror: ComponentMirror<unknown>,\n): string {\n return mirror.selector.split(',')[0] || 'ng-component';\n}\n\nexport function createInputBindings(\n mirror: ComponentMirror<unknown>,\n props?: Record<string, unknown>,\n): Binding[] {\n if (!props) {\n return [];\n }\n\n const inputBindings = Object.entries(props)\n .filter(([key]) =>\n mirror.inputs.some(({ templateName }) => templateName === key),\n )\n .map(([key, value]) => inputBinding(key, () => value));\n\n return inputBindings;\n}\n\nexport function createOutputBindings(\n hostElement: Element,\n mirror: ComponentMirror<unknown>,\n): Binding[] {\n const outputBindings = mirror.outputs.map(({ templateName }) =>\n outputBinding(templateName, (detail) => {\n const event = new CustomEvent(templateName, {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail,\n });\n hostElement.dispatchEvent(event);\n }),\n );\n\n return outputBindings;\n}\n\nexport function createComponentBindings(\n mirror: ComponentMirror<unknown>,\n props?: Record<string, unknown>,\n hostElement?: Element,\n): Binding[] {\n const inputBindings = createInputBindings(mirror, props);\n\n if (!mirror.outputs.length || !props?.[ID_PROP_NAME] || !hostElement) {\n return inputBindings;\n }\n\n const outputBindings = createOutputBindings(hostElement, mirror);\n\n return [...inputBindings, ...outputBindings];\n}\n\n/**\n * Registers a component created with `createComponent` as a root component,\n * the way `bootstrapApplication` does: attach the view, track it on the\n * application, run the initial change detection and notify\n * `APP_BOOTSTRAP_LISTENER`s such as the router's.\n */\nexport function registerRootComponent(\n appRef: ApplicationRef,\n componentRef: ComponentRef<unknown>,\n): void {\n appRef.attachView(componentRef.hostView);\n appRef.tick();\n appRef.components.push(componentRef);\n appRef.injector\n .get(APP_BOOTSTRAP_LISTENER, [])\n .forEach((listener) => listener(componentRef));\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import type { ComponentMirror } from '@angular/core';
2
+ /**
3
+ * Distributes the HTML Astro rendered for the component's slots across the
4
+ * component's `<ng-content>` slots, using Angular's own selector semantics.
5
+ *
6
+ * The result is indexed to match `mirror.ngContentSelectors`. Angular does not
7
+ * apply `select` matching to `projectableNodes`, so the matching happens here.
8
+ * @param mirror The component mirror, to read the `ng-content` selectors
9
+ * @param slots The slot HTML passed by Astro, keyed by slot name
10
+ * @param document The document the component is rendered into
11
+ * @returns The nodes to project, or `undefined` when the component has no `ng-content`
12
+ */
13
+ export declare function buildProjectableNodes(mirror: ComponentMirror<unknown>, slots: unknown, document: Document): Node[][] | undefined;
14
+ /**
15
+ * Wraps each non-empty slot in comment markers, so the client can find the
16
+ * server-rendered nodes again when hydrating. Angular reuses the DOM during
17
+ * hydration, so it must be handed those nodes rather than freshly parsed ones.
18
+ * @param projectableNodes The distributed nodes, see `buildProjectableNodes`
19
+ * @param appId The island's APP_ID, to keep markers apart from nested islands
20
+ * @param document The document the component is rendered into
21
+ */
22
+ export declare function markProjectableNodes(projectableNodes: Node[][], appId: string, document: Document): Node[][];
23
+ /**
24
+ * Collects the server-rendered projected nodes from the host element using the
25
+ * markers added by `markProjectableNodes`.
26
+ * @returns The nodes per slot, or `undefined` when the host carries no markers
27
+ */
28
+ export declare function collectProjectedNodes(hostElement: Element, mirror: ComponentMirror<unknown>, appId: string): Node[][] | undefined;
29
+ //# sourceMappingURL=projection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/projection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAUrD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,QAAQ,GACjB,IAAI,EAAE,EAAE,GAAG,SAAS,CA6BtB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,gBAAgB,EAAE,IAAI,EAAE,EAAE,EAC1B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,GACjB,IAAI,EAAE,EAAE,CAUV;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,OAAO,EACpB,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,MAAM,GACZ,IAAI,EAAE,EAAE,GAAG,SAAS,CA4CtB"}
@@ -0,0 +1,124 @@
1
+ import { isSameSelector, parseSelectorList } from "./selector.js";
2
+ const ELEMENT_NODE = 1;
3
+ const TEXT_NODE = 3;
4
+ const COMMENT_NODE = 8;
5
+ const SHOW_COMMENT = 128;
6
+ const MARKER_PREFIX = 'analog-slot:';
7
+ /**
8
+ * Distributes the HTML Astro rendered for the component's slots across the
9
+ * component's `<ng-content>` slots, using Angular's own selector semantics.
10
+ *
11
+ * The result is indexed to match `mirror.ngContentSelectors`. Angular does not
12
+ * apply `select` matching to `projectableNodes`, so the matching happens here.
13
+ * @param mirror The component mirror, to read the `ng-content` selectors
14
+ * @param slots The slot HTML passed by Astro, keyed by slot name
15
+ * @param document The document the component is rendered into
16
+ * @returns The nodes to project, or `undefined` when the component has no `ng-content`
17
+ */
18
+ export function buildProjectableNodes(mirror, slots, document) {
19
+ const selectors = mirror.ngContentSelectors;
20
+ if (!selectors.length) {
21
+ return undefined;
22
+ }
23
+ const projectableNodes = selectors.map(() => []);
24
+ // As in Angular, unmatched content goes to the last default slot.
25
+ const wildcardIndex = selectors.lastIndexOf('*');
26
+ for (const node of parseSlots(slots, document)) {
27
+ // Angular drops whitespace-only text nodes between elements at compile
28
+ // time, so projecting them would only suppress `ng-content` fallbacks.
29
+ if (node.nodeType === TEXT_NODE && !node.textContent?.trim()) {
30
+ continue;
31
+ }
32
+ const matched = selectors.findIndex((selector) => selector !== '*' && matches(node, selector));
33
+ const target = matched > -1 ? matched : wildcardIndex;
34
+ if (target > -1) {
35
+ projectableNodes[target].push(node);
36
+ }
37
+ }
38
+ return projectableNodes;
39
+ }
40
+ /**
41
+ * Wraps each non-empty slot in comment markers, so the client can find the
42
+ * server-rendered nodes again when hydrating. Angular reuses the DOM during
43
+ * hydration, so it must be handed those nodes rather than freshly parsed ones.
44
+ * @param projectableNodes The distributed nodes, see `buildProjectableNodes`
45
+ * @param appId The island's APP_ID, to keep markers apart from nested islands
46
+ * @param document The document the component is rendered into
47
+ */
48
+ export function markProjectableNodes(projectableNodes, appId, document) {
49
+ return projectableNodes.map((nodes, index) => nodes.length
50
+ ? [
51
+ document.createComment(`${MARKER_PREFIX}${appId}:${index}`),
52
+ ...nodes,
53
+ document.createComment(`/${MARKER_PREFIX}${appId}:${index}`),
54
+ ]
55
+ : nodes);
56
+ }
57
+ /**
58
+ * Collects the server-rendered projected nodes from the host element using the
59
+ * markers added by `markProjectableNodes`.
60
+ * @returns The nodes per slot, or `undefined` when the host carries no markers
61
+ */
62
+ export function collectProjectedNodes(hostElement, mirror, appId) {
63
+ const selectors = mirror.ngContentSelectors;
64
+ if (!selectors.length) {
65
+ return undefined;
66
+ }
67
+ const projectableNodes = selectors.map(() => []);
68
+ const walker = hostElement.ownerDocument.createTreeWalker(hostElement, SHOW_COMMENT);
69
+ let found = false;
70
+ for (let start = walker.nextNode(); start; start = walker.nextNode()) {
71
+ const match = start.textContent?.startsWith(`${MARKER_PREFIX}${appId}:`)
72
+ ? Number(start.textContent.slice(`${MARKER_PREFIX}${appId}:`.length))
73
+ : NaN;
74
+ if (Number.isNaN(match) || match >= selectors.length) {
75
+ continue;
76
+ }
77
+ const end = `/${MARKER_PREFIX}${appId}:${match}`;
78
+ const nodes = [start];
79
+ let node = start.nextSibling;
80
+ while (node &&
81
+ !(node.nodeType === COMMENT_NODE && node.textContent === end)) {
82
+ nodes.push(node);
83
+ node = node.nextSibling;
84
+ }
85
+ if (node) {
86
+ nodes.push(node);
87
+ }
88
+ projectableNodes[match] = nodes;
89
+ found = true;
90
+ }
91
+ return found ? projectableNodes : undefined;
92
+ }
93
+ function parseSlots(slots, document) {
94
+ const html = slots && typeof slots === 'object'
95
+ ? Object.values(slots).join('')
96
+ : String(slots ?? '');
97
+ if (!html) {
98
+ return [];
99
+ }
100
+ const template = document.createElement('template');
101
+ template.innerHTML = html;
102
+ return Array.from(template.content.childNodes);
103
+ }
104
+ function matches(node, selector) {
105
+ if (node.nodeType !== ELEMENT_NODE) {
106
+ return false;
107
+ }
108
+ const element = node;
109
+ const projectAs = element.getAttribute('ngProjectAs');
110
+ // As in Angular, `ngProjectAs` replaces the element's own selector and is
111
+ // compared structurally against the `select` list.
112
+ if (projectAs !== null) {
113
+ const [alias] = parseSelectorList(projectAs);
114
+ return parseSelectorList(selector).some((candidate) => isSameSelector(alias, candidate));
115
+ }
116
+ try {
117
+ return element.matches(selector);
118
+ }
119
+ catch {
120
+ // `ngContentSelectors` may contain selectors that `matches()` rejects.
121
+ return false;
122
+ }
123
+ }
124
+ //# sourceMappingURL=projection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/projection.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ComponentMirror } from '@angular/core';\nimport { isSameSelector, parseSelectorList } from './selector.ts';\n\nconst ELEMENT_NODE = 1;\nconst TEXT_NODE = 3;\nconst COMMENT_NODE = 8;\nconst SHOW_COMMENT = 128;\n\nconst MARKER_PREFIX = 'analog-slot:';\n\n/**\n * Distributes the HTML Astro rendered for the component's slots across the\n * component's `<ng-content>` slots, using Angular's own selector semantics.\n *\n * The result is indexed to match `mirror.ngContentSelectors`. Angular does not\n * apply `select` matching to `projectableNodes`, so the matching happens here.\n * @param mirror The component mirror, to read the `ng-content` selectors\n * @param slots The slot HTML passed by Astro, keyed by slot name\n * @param document The document the component is rendered into\n * @returns The nodes to project, or `undefined` when the component has no `ng-content`\n */\nexport function buildProjectableNodes(\n mirror: ComponentMirror<unknown>,\n slots: unknown,\n document: Document,\n): Node[][] | undefined {\n const selectors = mirror.ngContentSelectors;\n\n if (!selectors.length) {\n return undefined;\n }\n\n const projectableNodes: Node[][] = selectors.map(() => []);\n // As in Angular, unmatched content goes to the last default slot.\n const wildcardIndex = selectors.lastIndexOf('*');\n\n for (const node of parseSlots(slots, document)) {\n // Angular drops whitespace-only text nodes between elements at compile\n // time, so projecting them would only suppress `ng-content` fallbacks.\n if (node.nodeType === TEXT_NODE && !node.textContent?.trim()) {\n continue;\n }\n\n const matched = selectors.findIndex(\n (selector) => selector !== '*' && matches(node, selector),\n );\n const target = matched > -1 ? matched : wildcardIndex;\n\n if (target > -1) {\n projectableNodes[target].push(node);\n }\n }\n\n return projectableNodes;\n}\n\n/**\n * Wraps each non-empty slot in comment markers, so the client can find the\n * server-rendered nodes again when hydrating. Angular reuses the DOM during\n * hydration, so it must be handed those nodes rather than freshly parsed ones.\n * @param projectableNodes The distributed nodes, see `buildProjectableNodes`\n * @param appId The island's APP_ID, to keep markers apart from nested islands\n * @param document The document the component is rendered into\n */\nexport function markProjectableNodes(\n projectableNodes: Node[][],\n appId: string,\n document: Document,\n): Node[][] {\n return projectableNodes.map((nodes, index) =>\n nodes.length\n ? [\n document.createComment(`${MARKER_PREFIX}${appId}:${index}`),\n ...nodes,\n document.createComment(`/${MARKER_PREFIX}${appId}:${index}`),\n ]\n : nodes,\n );\n}\n\n/**\n * Collects the server-rendered projected nodes from the host element using the\n * markers added by `markProjectableNodes`.\n * @returns The nodes per slot, or `undefined` when the host carries no markers\n */\nexport function collectProjectedNodes(\n hostElement: Element,\n mirror: ComponentMirror<unknown>,\n appId: string,\n): Node[][] | undefined {\n const selectors = mirror.ngContentSelectors;\n\n if (!selectors.length) {\n return undefined;\n }\n\n const projectableNodes: Node[][] = selectors.map(() => []);\n const walker = hostElement.ownerDocument.createTreeWalker(\n hostElement,\n SHOW_COMMENT,\n );\n let found = false;\n\n for (let start = walker.nextNode(); start; start = walker.nextNode()) {\n const match = start.textContent?.startsWith(`${MARKER_PREFIX}${appId}:`)\n ? Number(start.textContent.slice(`${MARKER_PREFIX}${appId}:`.length))\n : NaN;\n\n if (Number.isNaN(match) || match >= selectors.length) {\n continue;\n }\n\n const end = `/${MARKER_PREFIX}${appId}:${match}`;\n const nodes: Node[] = [start];\n let node = start.nextSibling;\n\n while (\n node &&\n !(node.nodeType === COMMENT_NODE && node.textContent === end)\n ) {\n nodes.push(node);\n node = node.nextSibling;\n }\n\n if (node) {\n nodes.push(node);\n }\n\n projectableNodes[match] = nodes;\n found = true;\n }\n\n return found ? projectableNodes : undefined;\n}\n\nfunction parseSlots(slots: unknown, document: Document): Node[] {\n const html =\n slots && typeof slots === 'object'\n ? Object.values(slots).join('')\n : String(slots ?? '');\n\n if (!html) {\n return [];\n }\n\n const template = document.createElement('template');\n template.innerHTML = html;\n\n return Array.from(template.content.childNodes);\n}\n\nfunction matches(node: Node, selector: string): boolean {\n if (node.nodeType !== ELEMENT_NODE) {\n return false;\n }\n\n const element = node as Element;\n const projectAs = element.getAttribute('ngProjectAs');\n\n // As in Angular, `ngProjectAs` replaces the element's own selector and is\n // compared structurally against the `select` list.\n if (projectAs !== null) {\n const [alias] = parseSelectorList(projectAs);\n return parseSelectorList(selector).some((candidate) =>\n isSameSelector(alias, candidate),\n );\n }\n\n try {\n return element.matches(selector);\n } catch {\n // `ngContentSelectors` may contain selectors that `matches()` rejects.\n return false;\n }\n}\n"]}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A CSS selector in the shape Angular's compiler uses for `ng-content` and
3
+ * `ngProjectAs` matching. Ported from `CssSelector` in `@angular/compiler`.
4
+ */
5
+ export interface ParsedSelector {
6
+ element: string;
7
+ attrs: [string, string][];
8
+ classNames: string[];
9
+ notSelectors: ParsedSelector[];
10
+ }
11
+ export declare function parseSelectorList(selector: string): ParsedSelector[];
12
+ /**
13
+ * Structural equality, matching how Angular compares an `ngProjectAs` selector
14
+ * against the selectors of an `ng-content`.
15
+ */
16
+ export declare function isSameSelector(a: ParsedSelector, b: ParsedSelector): boolean;
17
+ //# sourceMappingURL=selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/selector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE,cAAc,EAAE,CAAC;CAChC;AAuBD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CA+CpE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,cAAc,GAAG,OAAO,CAa5E"}
@@ -0,0 +1,78 @@
1
+ const SELECTOR_REGEXP = new RegExp('(\\:not\\()|' + // 1: ":not("
2
+ '(([\\.\\#]?)[-\\w]+)|' + // 2: "tag"; 3: "."/"#"
3
+ '(?:\\[([-.\\w*\\\\$]+)(?:=(["\']?)([^\\]"\']*)\\5)?\\])|' + // 4: attribute; 5: quote; 6: value
4
+ '(\\))|' + // 7: ")"
5
+ '(\\s*,\\s*)', // 8: ","
6
+ 'g');
7
+ const NOT = 1;
8
+ const TAG = 2;
9
+ const PREFIX = 3;
10
+ const ATTRIBUTE = 4;
11
+ const ATTRIBUTE_VALUE = 6;
12
+ const NOT_END = 7;
13
+ const SEPARATOR = 8;
14
+ function createSelector() {
15
+ return { element: '', attrs: [], classNames: [], notSelectors: [] };
16
+ }
17
+ export function parseSelectorList(selector) {
18
+ const results = [];
19
+ let cssSelector = createSelector();
20
+ let current = cssSelector;
21
+ let inNot = false;
22
+ let match;
23
+ const regexp = new RegExp(SELECTOR_REGEXP.source, 'g');
24
+ while ((match = regexp.exec(selector))) {
25
+ if (match[NOT]) {
26
+ inNot = true;
27
+ current = createSelector();
28
+ cssSelector.notSelectors.push(current);
29
+ }
30
+ const tag = match[TAG];
31
+ if (tag) {
32
+ const prefix = match[PREFIX];
33
+ if (prefix === '#') {
34
+ current.attrs.push(['id', tag.slice(1)]);
35
+ }
36
+ else if (prefix === '.') {
37
+ current.classNames.push(tag.slice(1).toLowerCase());
38
+ }
39
+ else {
40
+ current.element = tag;
41
+ }
42
+ }
43
+ const attribute = match[ATTRIBUTE];
44
+ if (attribute) {
45
+ current.attrs.push([attribute, match[ATTRIBUTE_VALUE] ?? '']);
46
+ }
47
+ if (match[NOT_END]) {
48
+ inNot = false;
49
+ current = cssSelector;
50
+ }
51
+ if (match[SEPARATOR]) {
52
+ results.push(cssSelector);
53
+ cssSelector = current = createSelector();
54
+ }
55
+ }
56
+ results.push(cssSelector);
57
+ return results;
58
+ }
59
+ /**
60
+ * Structural equality, matching how Angular compares an `ngProjectAs` selector
61
+ * against the selectors of an `ng-content`.
62
+ */
63
+ export function isSameSelector(a, b) {
64
+ return (normalizeElement(a.element) === normalizeElement(b.element) &&
65
+ a.attrs.length === b.attrs.length &&
66
+ a.attrs.every(([name, value], i) => {
67
+ const [otherName, otherValue] = b.attrs[i];
68
+ return name === otherName && value === otherValue;
69
+ }) &&
70
+ a.classNames.length === b.classNames.length &&
71
+ a.classNames.every((name, i) => name === b.classNames[i]) &&
72
+ a.notSelectors.length === b.notSelectors.length &&
73
+ a.notSelectors.every((not, i) => isSameSelector(not, b.notSelectors[i])));
74
+ }
75
+ function normalizeElement(element) {
76
+ return element === '*' ? '' : element;
77
+ }
78
+ //# sourceMappingURL=selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/selector.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A CSS selector in the shape Angular's compiler uses for `ng-content` and\n * `ngProjectAs` matching. Ported from `CssSelector` in `@angular/compiler`.\n */\nexport interface ParsedSelector {\n element: string;\n attrs: [string, string][];\n classNames: string[];\n notSelectors: ParsedSelector[];\n}\n\nconst SELECTOR_REGEXP = new RegExp(\n '(\\\\:not\\\\()|' + // 1: \":not(\"\n '(([\\\\.\\\\#]?)[-\\\\w]+)|' + // 2: \"tag\"; 3: \".\"/\"#\"\n '(?:\\\\[([-.\\\\w*\\\\\\\\$]+)(?:=([\"\\']?)([^\\\\]\"\\']*)\\\\5)?\\\\])|' + // 4: attribute; 5: quote; 6: value\n '(\\\\))|' + // 7: \")\"\n '(\\\\s*,\\\\s*)', // 8: \",\"\n 'g',\n);\n\nconst NOT = 1;\nconst TAG = 2;\nconst PREFIX = 3;\nconst ATTRIBUTE = 4;\nconst ATTRIBUTE_VALUE = 6;\nconst NOT_END = 7;\nconst SEPARATOR = 8;\n\nfunction createSelector(): ParsedSelector {\n return { element: '', attrs: [], classNames: [], notSelectors: [] };\n}\n\nexport function parseSelectorList(selector: string): ParsedSelector[] {\n const results: ParsedSelector[] = [];\n let cssSelector = createSelector();\n let current = cssSelector;\n let inNot = false;\n let match: RegExpExecArray | null;\n\n const regexp = new RegExp(SELECTOR_REGEXP.source, 'g');\n\n while ((match = regexp.exec(selector))) {\n if (match[NOT]) {\n inNot = true;\n current = createSelector();\n cssSelector.notSelectors.push(current);\n }\n\n const tag = match[TAG];\n if (tag) {\n const prefix = match[PREFIX];\n if (prefix === '#') {\n current.attrs.push(['id', tag.slice(1)]);\n } else if (prefix === '.') {\n current.classNames.push(tag.slice(1).toLowerCase());\n } else {\n current.element = tag;\n }\n }\n\n const attribute = match[ATTRIBUTE];\n if (attribute) {\n current.attrs.push([attribute, match[ATTRIBUTE_VALUE] ?? '']);\n }\n\n if (match[NOT_END]) {\n inNot = false;\n current = cssSelector;\n }\n\n if (match[SEPARATOR]) {\n results.push(cssSelector);\n cssSelector = current = createSelector();\n }\n }\n\n results.push(cssSelector);\n\n return results;\n}\n\n/**\n * Structural equality, matching how Angular compares an `ngProjectAs` selector\n * against the selectors of an `ng-content`.\n */\nexport function isSameSelector(a: ParsedSelector, b: ParsedSelector): boolean {\n return (\n normalizeElement(a.element) === normalizeElement(b.element) &&\n a.attrs.length === b.attrs.length &&\n a.attrs.every(([name, value], i) => {\n const [otherName, otherValue] = b.attrs[i];\n return name === otherName && value === otherValue;\n }) &&\n a.classNames.length === b.classNames.length &&\n a.classNames.every((name, i) => name === b.classNames[i]) &&\n a.notSelectors.length === b.notSelectors.length &&\n a.notSelectors.every((not, i) => isSameSelector(not, b.notSelectors[i]))\n );\n}\n\nfunction normalizeElement(element: string): string {\n return element === '*' ? '' : element;\n}\n"]}
@@ -6,7 +6,7 @@ declare function check(Component: Type<unknown>): Promise<boolean>;
6
6
  declare function renderToStaticMarkup(this: RendererContext, Component: Type<unknown> & {
7
7
  renderProviders?: (Provider | EnvironmentProviders)[];
8
8
  hydrationFeatures?: () => HydrationFeature<HydrationFeatureKind>[];
9
- }, props: Record<string, unknown>, _children: unknown, metadata?: AstroComponentMetadata): Promise<{
9
+ }, props: Record<string, unknown>, children: unknown, metadata?: AstroComponentMetadata): Promise<{
10
10
  html: string;
11
11
  }>;
12
12
  declare const _default: {
@@ -1 +1 @@
1
- {"version":3,"file":"server-ngh.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-ngh.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAa1E,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAG1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,sBAAsB,EAA0B,MAAM,OAAO,CAAC;AAC5E,OAAO,EAA2B,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAqB7E,iBAAe,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,oBAE5C;AAED,iBAAe,oBAAoB,CACjC,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG;IACzB,eAAe,CAAC,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;IACtD,iBAAiB,CAAC,EAAE,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,CAAC;CACpE,EACD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,OAAO,EAClB,QAAQ,CAAC,EAAE,sBAAsB;;GAoElC;;;;;;AAED,wBAImC"}
1
+ {"version":3,"file":"server-ngh.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-ngh.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAc1E,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EAG1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,sBAAsB,EAA0B,MAAM,OAAO,CAAC;AAC5E,OAAO,EAA2B,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAyB7E,iBAAe,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,oBAE5C;AAED,iBAAe,oBAAoB,CACjC,IAAI,EAAE,eAAe,EACrB,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG;IACzB,eAAe,CAAC,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;IACtD,iBAAiB,CAAC,EAAE,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,EAAE,CAAC;CACpE,EACD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,EAAE,OAAO,EACjB,QAAQ,CAAC,EAAE,sBAAsB;;GAyFlC;;;;;;AAED,wBAImC"}
package/src/server-ngh.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import { createRequire } from 'node:module';
3
- import { reflectComponentType, provideZonelessChangeDetection, DOCUMENT, APP_ID, } from '@angular/core';
3
+ import { createComponent, reflectComponentType, provideZonelessChangeDetection, DOCUMENT, APP_ID, } from '@angular/core';
4
4
  import { provideServerRendering, renderApplication, ɵSERVER_CONTEXT, platformServer, } from '@angular/platform-server';
5
- import { bootstrapApplication, provideClientHydration, } from '@angular/platform-browser';
5
+ import { createApplication, provideClientHydration, } from '@angular/platform-browser';
6
6
  import { getContext, incrementId } from "./context.js";
7
- import { provideBootstrapListener } from "./server-providers.js";
8
7
  import { ID_PROP_NAME } from "./id.js";
9
- import { getComponentElementTag } from "./create-component.js";
8
+ import { createInputBindings, getComponentElementTag, registerRootComponent, } from "./create-component.js";
9
+ import { buildProjectableNodes, markProjectableNodes } from "./projection.js";
10
10
  const require = createRequire(import.meta.url);
11
11
  let jsActionContractScript = undefined;
12
12
  const HYDRATION_SCRIPT_ID = 'ng-event-dispatch-contract';
@@ -20,7 +20,7 @@ function getHydrationScript() {
20
20
  async function check(Component) {
21
21
  return !!reflectComponentType(Component);
22
22
  }
23
- async function renderToStaticMarkup(Component, props, _children, metadata) {
23
+ async function renderToStaticMarkup(Component, props, children, metadata) {
24
24
  const mirror = reflectComponentType(Component);
25
25
  if (!mirror) {
26
26
  // This should be unreachable: the `check` function verifies that Component is an Angular component.
@@ -36,22 +36,36 @@ async function renderToStaticMarkup(Component, props, _children, metadata) {
36
36
  const document = platformRef.injector.get(DOCUMENT);
37
37
  // Incremental hydration requires the event dispatch script to be present.
38
38
  document.body.innerHTML = `${getHydrationScript()}<${elementTag} ${ID_PROP_NAME}="${ngAppId}"></${elementTag}>`;
39
- const bootstrap = (context) => bootstrapApplication(Component, {
40
- providers: [
41
- provideBootstrapListener(mirror, props),
42
- provideServerRendering(),
43
- { provide: ɵSERVER_CONTEXT, useValue: 'analog' },
44
- provideZonelessChangeDetection(),
45
- metadata?.hydrate
46
- ? provideClientHydration(...(Component.hydrationFeatures?.() || []))
47
- : [],
48
- {
49
- provide: APP_ID,
50
- useValue: ngAppId,
51
- },
52
- ...(Component.renderProviders || []),
53
- ],
54
- }, context);
39
+ const hostElement = document.querySelector(elementTag);
40
+ let projectableNodes = buildProjectableNodes(mirror, children, document);
41
+ if (metadata?.hydrate && projectableNodes) {
42
+ projectableNodes = markProjectableNodes(projectableNodes, String(ngAppId), document);
43
+ }
44
+ const bootstrap = async (context) => {
45
+ const appRef = await createApplication({
46
+ providers: [
47
+ provideServerRendering(),
48
+ { provide: ɵSERVER_CONTEXT, useValue: 'analog' },
49
+ provideZonelessChangeDetection(),
50
+ metadata?.hydrate
51
+ ? provideClientHydration(...(Component.hydrationFeatures?.() || []))
52
+ : [],
53
+ {
54
+ provide: APP_ID,
55
+ useValue: ngAppId,
56
+ },
57
+ ...(Component.renderProviders || []),
58
+ ],
59
+ }, context);
60
+ const componentRef = createComponent(Component, {
61
+ environmentInjector: appRef.injector,
62
+ hostElement,
63
+ projectableNodes,
64
+ bindings: createInputBindings(mirror, props),
65
+ });
66
+ registerRootComponent(appRef, componentRef);
67
+ return appRef;
68
+ };
55
69
  const html = await renderApplication(bootstrap, {
56
70
  document,
57
71
  });
@@ -1 +1 @@
1
- {"version":3,"file":"server-ngh.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-ngh.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\n\nimport type { EnvironmentProviders, Provider, Type } from '@angular/core';\nimport {\n reflectComponentType,\n provideZonelessChangeDetection,\n DOCUMENT,\n APP_ID,\n} from '@angular/core';\nimport {\n provideServerRendering,\n renderApplication,\n ɵSERVER_CONTEXT,\n platformServer,\n} from '@angular/platform-server';\nimport {\n bootstrapApplication,\n type HydrationFeature,\n type HydrationFeatureKind,\n provideClientHydration,\n type BootstrapContext,\n} from '@angular/platform-browser';\nimport type { AstroComponentMetadata, SSRLoadedRendererValue } from 'astro';\nimport { getContext, incrementId, type RendererContext } from './context.ts';\nimport { provideBootstrapListener } from './server-providers.ts';\nimport { ID_PROP_NAME } from './id.ts';\nimport { getComponentElementTag } from './create-component.ts';\n\nconst require = createRequire(import.meta.url);\nlet jsActionContractScript: string | undefined = undefined;\n\nconst HYDRATION_SCRIPT_ID = 'ng-event-dispatch-contract';\n\nfunction getHydrationScript(): string {\n jsActionContractScript ??=\n `<script type=\"text/javascript\" id=\"${HYDRATION_SCRIPT_ID}\">` +\n readFileSync(\n require.resolve('@angular/core/event-dispatch-contract.min.js'),\n 'utf-8',\n ) +\n '</script>';\n return jsActionContractScript;\n}\n\nasync function check(Component: Type<unknown>) {\n return !!reflectComponentType(Component);\n}\n\nasync function renderToStaticMarkup(\n this: RendererContext,\n Component: Type<unknown> & {\n renderProviders?: (Provider | EnvironmentProviders)[];\n hydrationFeatures?: () => HydrationFeature<HydrationFeatureKind>[];\n },\n props: Record<string, unknown>,\n _children: unknown,\n metadata?: AstroComponentMetadata,\n) {\n const mirror = reflectComponentType(Component);\n\n if (!mirror) {\n // This should be unreachable: the `check` function verifies that Component is an Angular component.\n throw new Error(\n (metadata?.displayName || '<unknown component>') +\n ' is not an Angular component',\n );\n }\n\n const elementTag = getComponentElementTag(mirror);\n const ngAppId = props?.[ID_PROP_NAME] || incrementId(getContext(this.result));\n\n // When the platform ref is destroyed, it will reset ngServerMode back to `undefined` if it was not defined when it is\n // created. See https://github.com/angular/angular/blob/2ce0e98f79a02ddc550d00580e8e232cfed3bfb2/packages/platform-server/src/server.ts#L138\n globalThis.ngServerMode = true;\n\n const platformRef = platformServer();\n const document = platformRef.injector.get(DOCUMENT);\n\n // Incremental hydration requires the event dispatch script to be present.\n document.body.innerHTML = `${getHydrationScript()}<${elementTag} ${ID_PROP_NAME}=\"${ngAppId}\"></${elementTag}>`;\n\n const bootstrap = (context?: BootstrapContext) =>\n bootstrapApplication(\n Component,\n {\n providers: [\n provideBootstrapListener(mirror, props),\n provideServerRendering(),\n { provide: ɵSERVER_CONTEXT, useValue: 'analog' },\n provideZonelessChangeDetection(),\n metadata?.hydrate\n ? provideClientHydration(...(Component.hydrationFeatures?.() || []))\n : [],\n {\n provide: APP_ID,\n useValue: ngAppId,\n },\n ...(Component.renderProviders || []),\n ],\n },\n context,\n );\n\n const html = await renderApplication(bootstrap, {\n document,\n });\n\n document.documentElement.innerHTML = html;\n let styleTags = '';\n\n document.head.childNodes.forEach((node) => {\n if (node.nodeName === 'STYLE') {\n styleTags += (node as HTMLElement).outerHTML;\n }\n });\n\n // Remove the hydration script, so only one is present on the page.\n document.getElementById(HYDRATION_SCRIPT_ID)?.remove();\n\n const correctedHtml = styleTags + document.body.innerHTML;\n\n platformRef.destroy();\n\n return { html: correctedHtml };\n}\n\nexport default {\n check,\n renderToStaticMarkup,\n renderHydrationScript: () => getHydrationScript(),\n} satisfies SSRLoadedRendererValue;\n"]}
1
+ {"version":3,"file":"server-ngh.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-ngh.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\n\nimport type { EnvironmentProviders, Provider, Type } from '@angular/core';\nimport {\n createComponent,\n reflectComponentType,\n provideZonelessChangeDetection,\n DOCUMENT,\n APP_ID,\n} from '@angular/core';\nimport {\n provideServerRendering,\n renderApplication,\n ɵSERVER_CONTEXT,\n platformServer,\n} from '@angular/platform-server';\nimport {\n createApplication,\n type HydrationFeature,\n type HydrationFeatureKind,\n provideClientHydration,\n type BootstrapContext,\n} from '@angular/platform-browser';\nimport type { AstroComponentMetadata, SSRLoadedRendererValue } from 'astro';\nimport { getContext, incrementId, type RendererContext } from './context.ts';\nimport { ID_PROP_NAME } from './id.ts';\nimport {\n createInputBindings,\n getComponentElementTag,\n registerRootComponent,\n} from './create-component.ts';\nimport { buildProjectableNodes, markProjectableNodes } from './projection.ts';\n\nconst require = createRequire(import.meta.url);\nlet jsActionContractScript: string | undefined = undefined;\n\nconst HYDRATION_SCRIPT_ID = 'ng-event-dispatch-contract';\n\nfunction getHydrationScript(): string {\n jsActionContractScript ??=\n `<script type=\"text/javascript\" id=\"${HYDRATION_SCRIPT_ID}\">` +\n readFileSync(\n require.resolve('@angular/core/event-dispatch-contract.min.js'),\n 'utf-8',\n ) +\n '</script>';\n return jsActionContractScript;\n}\n\nasync function check(Component: Type<unknown>) {\n return !!reflectComponentType(Component);\n}\n\nasync function renderToStaticMarkup(\n this: RendererContext,\n Component: Type<unknown> & {\n renderProviders?: (Provider | EnvironmentProviders)[];\n hydrationFeatures?: () => HydrationFeature<HydrationFeatureKind>[];\n },\n props: Record<string, unknown>,\n children: unknown,\n metadata?: AstroComponentMetadata,\n) {\n const mirror = reflectComponentType(Component);\n\n if (!mirror) {\n // This should be unreachable: the `check` function verifies that Component is an Angular component.\n throw new Error(\n (metadata?.displayName || '<unknown component>') +\n ' is not an Angular component',\n );\n }\n\n const elementTag = getComponentElementTag(mirror);\n const ngAppId = props?.[ID_PROP_NAME] || incrementId(getContext(this.result));\n\n // When the platform ref is destroyed, it will reset ngServerMode back to `undefined` if it was not defined when it is\n // created. See https://github.com/angular/angular/blob/2ce0e98f79a02ddc550d00580e8e232cfed3bfb2/packages/platform-server/src/server.ts#L138\n globalThis.ngServerMode = true;\n\n const platformRef = platformServer();\n const document = platformRef.injector.get(DOCUMENT);\n\n // Incremental hydration requires the event dispatch script to be present.\n document.body.innerHTML = `${getHydrationScript()}<${elementTag} ${ID_PROP_NAME}=\"${ngAppId}\"></${elementTag}>`;\n\n const hostElement = document.querySelector(elementTag) as Element;\n let projectableNodes = buildProjectableNodes(mirror, children, document);\n\n if (metadata?.hydrate && projectableNodes) {\n projectableNodes = markProjectableNodes(\n projectableNodes,\n String(ngAppId),\n document,\n );\n }\n\n const bootstrap = async (context?: BootstrapContext) => {\n const appRef = await createApplication(\n {\n providers: [\n provideServerRendering(),\n { provide: ɵSERVER_CONTEXT, useValue: 'analog' },\n provideZonelessChangeDetection(),\n metadata?.hydrate\n ? provideClientHydration(...(Component.hydrationFeatures?.() || []))\n : [],\n {\n provide: APP_ID,\n useValue: ngAppId,\n },\n ...(Component.renderProviders || []),\n ],\n },\n context,\n );\n\n const componentRef = createComponent(Component, {\n environmentInjector: appRef.injector,\n hostElement,\n projectableNodes,\n bindings: createInputBindings(mirror, props),\n });\n\n registerRootComponent(appRef, componentRef);\n\n return appRef;\n };\n\n const html = await renderApplication(bootstrap, {\n document,\n });\n\n document.documentElement.innerHTML = html;\n let styleTags = '';\n\n document.head.childNodes.forEach((node) => {\n if (node.nodeName === 'STYLE') {\n styleTags += (node as HTMLElement).outerHTML;\n }\n });\n\n // Remove the hydration script, so only one is present on the page.\n document.getElementById(HYDRATION_SCRIPT_ID)?.remove();\n\n const correctedHtml = styleTags + document.body.innerHTML;\n\n platformRef.destroy();\n\n return { html: correctedHtml };\n}\n\nexport default {\n check,\n renderToStaticMarkup,\n renderHydrationScript: () => getHydrationScript(),\n} satisfies SSRLoadedRendererValue;\n"]}
package/src/server.d.ts CHANGED
@@ -2,7 +2,7 @@ import type { EnvironmentProviders, Provider, ɵComponentType as ComponentType }
2
2
  declare function check(Component: ComponentType<unknown>, _props: Record<string, unknown>, _children: unknown): boolean;
3
3
  declare function renderToStaticMarkup(Component: ComponentType<unknown> & {
4
4
  renderProviders: (Provider | EnvironmentProviders)[];
5
- }, props: Record<string, unknown>, _children: unknown): Promise<{
5
+ }, props: Record<string, unknown>, children: unknown): Promise<{
6
6
  html: string;
7
7
  }>;
8
8
  declare const _default: {
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,oBAAoB,EACpB,QAAQ,EACR,cAAc,IAAI,aAAa,EAChC,MAAM,eAAe,CAAC;AA6BvB,iBAAS,KAAK,CACZ,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,SAAS,EAAE,OAAO,WAGnB;AAwCD,iBAAe,oBAAoB,CACjC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG;IAClC,eAAe,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;CACtD,EACD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,OAAO;;GA+CnB;;;;;AAED,wBAGE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,QAAQ,EACR,cAAc,IAAI,aAAa,EAChC,MAAM,eAAe,CAAC;AAwBvB,iBAAS,KAAK,CACZ,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,EACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,SAAS,EAAE,OAAO,WAGnB;AAED,iBAAe,oBAAoB,CACjC,SAAS,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG;IAClC,eAAe,EAAE,CAAC,QAAQ,GAAG,oBAAoB,CAAC,EAAE,CAAC;CACtD,EACD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,EAAE,OAAO;;GA6DlB;;;;;AAED,wBAGE"}
package/src/server.js CHANGED
@@ -1,57 +1,41 @@
1
- import { ApplicationRef, InjectionToken, reflectComponentType, provideZonelessChangeDetection, DOCUMENT, } from '@angular/core';
2
- import { BEFORE_APP_SERIALIZED, provideServerRendering, renderApplication, ɵSERVER_CONTEXT, platformServer, } from '@angular/platform-server';
3
- import { bootstrapApplication, } from '@angular/platform-browser';
4
- const ANALOG_ASTRO_STATIC_PROPS = new InjectionToken('@analogjs/astro-angular: Static Props w/ Mirror Provider', {
5
- factory() {
6
- return { props: {}, mirror: {} };
7
- },
8
- });
1
+ import { createComponent, reflectComponentType, provideZonelessChangeDetection, DOCUMENT, } from '@angular/core';
2
+ import { provideServerRendering, renderApplication, ɵSERVER_CONTEXT, platformServer, } from '@angular/platform-server';
3
+ import { createApplication, } from '@angular/platform-browser';
4
+ import { createInputBindings, getComponentElementTag, registerRootComponent, } from "./create-component.js";
5
+ import { buildProjectableNodes } from "./projection.js";
9
6
  function check(Component, _props, _children) {
10
7
  return !!reflectComponentType(Component);
11
8
  }
12
- // Run beforeAppInitialized hook to set Input on the ComponentRef
13
- // before the platform renders to string
14
- const STATIC_PROPS_HOOK_PROVIDER = {
15
- provide: BEFORE_APP_SERIALIZED,
16
- useFactory: (appRef, { props, mirror, }) => {
17
- return () => {
18
- const compRef = appRef.components[0];
19
- if (compRef && props && mirror) {
20
- for (const [key, value] of Object.entries(props)) {
21
- if (
22
- // we double-check inputs on ComponentMirror
23
- // because Astro might add additional props
24
- // that aren't actually Input defined on the Component
25
- mirror.inputs.some(({ templateName, propName }) => templateName === key || propName === key)) {
26
- compRef.setInput(key, value);
27
- }
28
- }
29
- compRef.changeDetectorRef.detectChanges();
30
- }
31
- };
32
- },
33
- deps: [ApplicationRef, ANALOG_ASTRO_STATIC_PROPS],
34
- multi: true,
35
- };
36
- async function renderToStaticMarkup(Component, props, _children) {
9
+ async function renderToStaticMarkup(Component, props, children) {
37
10
  const mirror = reflectComponentType(Component);
38
- const appId = mirror?.selector.split(',')[0] || Component.name.toString().toLowerCase();
11
+ if (!mirror) {
12
+ // This should be unreachable: the `check` function verifies that Component is an Angular component.
13
+ throw new Error(Component.name + ' is not an Angular component');
14
+ }
15
+ const elementTag = getComponentElementTag(mirror);
39
16
  const platformRef = platformServer();
40
17
  const document = platformRef.injector.get(DOCUMENT);
41
- document.body.innerHTML = `<${appId}></${appId}>`;
42
- const bootstrap = (context) => bootstrapApplication(Component, {
43
- providers: [
44
- {
45
- provide: ANALOG_ASTRO_STATIC_PROPS,
46
- useValue: { props, mirror },
47
- },
48
- STATIC_PROPS_HOOK_PROVIDER,
49
- provideServerRendering(),
50
- { provide: ɵSERVER_CONTEXT, useValue: 'analog' },
51
- provideZonelessChangeDetection(),
52
- ...(Component.renderProviders || []),
53
- ],
54
- }, context);
18
+ document.body.innerHTML = `<${elementTag}></${elementTag}>`;
19
+ const hostElement = document.querySelector(elementTag);
20
+ const projectableNodes = buildProjectableNodes(mirror, children, document);
21
+ const bootstrap = async (context) => {
22
+ const appRef = await createApplication({
23
+ providers: [
24
+ provideServerRendering(),
25
+ { provide: ɵSERVER_CONTEXT, useValue: 'analog' },
26
+ provideZonelessChangeDetection(),
27
+ ...(Component.renderProviders || []),
28
+ ],
29
+ }, context);
30
+ const componentRef = createComponent(Component, {
31
+ environmentInjector: appRef.injector,
32
+ hostElement,
33
+ projectableNodes,
34
+ bindings: createInputBindings(mirror, props),
35
+ });
36
+ registerRootComponent(appRef, componentRef);
37
+ return appRef;
38
+ };
55
39
  const html = await renderApplication(bootstrap, {
56
40
  document,
57
41
  });
package/src/server.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ComponentMirror,\n EnvironmentProviders,\n Provider,\n ɵComponentType as ComponentType,\n} from '@angular/core';\nimport {\n ApplicationRef,\n InjectionToken,\n reflectComponentType,\n provideZonelessChangeDetection,\n DOCUMENT,\n} from '@angular/core';\nimport {\n BEFORE_APP_SERIALIZED,\n provideServerRendering,\n renderApplication,\n ɵSERVER_CONTEXT,\n platformServer,\n} from '@angular/platform-server';\nimport {\n bootstrapApplication,\n type BootstrapContext,\n} from '@angular/platform-browser';\n\nconst ANALOG_ASTRO_STATIC_PROPS = new InjectionToken<{\n props: Record<string, unknown>;\n mirror: ComponentMirror<unknown>;\n}>('@analogjs/astro-angular: Static Props w/ Mirror Provider', {\n factory() {\n return { props: {}, mirror: {} as ComponentMirror<unknown> };\n },\n});\n\nfunction check(\n Component: ComponentType<unknown>,\n _props: Record<string, unknown>,\n _children: unknown,\n) {\n return !!reflectComponentType(Component);\n}\n\n// Run beforeAppInitialized hook to set Input on the ComponentRef\n// before the platform renders to string\nconst STATIC_PROPS_HOOK_PROVIDER: Provider = {\n provide: BEFORE_APP_SERIALIZED,\n useFactory: (\n appRef: ApplicationRef,\n {\n props,\n mirror,\n }: {\n props: Record<string, unknown>;\n mirror: ComponentMirror<unknown>;\n },\n ) => {\n return () => {\n const compRef = appRef.components[0];\n if (compRef && props && mirror) {\n for (const [key, value] of Object.entries(props)) {\n if (\n // we double-check inputs on ComponentMirror\n // because Astro might add additional props\n // that aren't actually Input defined on the Component\n mirror.inputs.some(\n ({ templateName, propName }) =>\n templateName === key || propName === key,\n )\n ) {\n compRef.setInput(key, value);\n }\n }\n compRef.changeDetectorRef.detectChanges();\n }\n };\n },\n deps: [ApplicationRef, ANALOG_ASTRO_STATIC_PROPS],\n multi: true,\n};\n\nasync function renderToStaticMarkup(\n Component: ComponentType<unknown> & {\n renderProviders: (Provider | EnvironmentProviders)[];\n },\n props: Record<string, unknown>,\n _children: unknown,\n) {\n const mirror = reflectComponentType(Component);\n const appId =\n mirror?.selector.split(',')[0] || Component.name.toString().toLowerCase();\n\n const platformRef = platformServer();\n const document = platformRef.injector.get(DOCUMENT);\n document.body.innerHTML = `<${appId}></${appId}>`;\n\n const bootstrap = (context?: BootstrapContext) =>\n bootstrapApplication(\n Component,\n {\n providers: [\n {\n provide: ANALOG_ASTRO_STATIC_PROPS,\n useValue: { props, mirror },\n },\n STATIC_PROPS_HOOK_PROVIDER,\n provideServerRendering(),\n { provide: ɵSERVER_CONTEXT, useValue: 'analog' },\n provideZonelessChangeDetection(),\n ...(Component.renderProviders || []),\n ],\n },\n context,\n );\n\n const html = await renderApplication(bootstrap, {\n document,\n });\n\n document.documentElement.innerHTML = html;\n let styleTags = '';\n\n document.head.childNodes.forEach((node) => {\n if (node.nodeName === 'STYLE') {\n styleTags += (node as HTMLElement).outerHTML;\n }\n });\n\n const correctedHtml = styleTags + document.body.innerHTML;\n\n platformRef.destroy();\n\n return { html: correctedHtml };\n}\n\nexport default {\n check,\n renderToStaticMarkup,\n};\n"]}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n EnvironmentProviders,\n Provider,\n ɵComponentType as ComponentType,\n} from '@angular/core';\nimport {\n createComponent,\n reflectComponentType,\n provideZonelessChangeDetection,\n DOCUMENT,\n} from '@angular/core';\nimport {\n provideServerRendering,\n renderApplication,\n ɵSERVER_CONTEXT,\n platformServer,\n} from '@angular/platform-server';\nimport {\n createApplication,\n type BootstrapContext,\n} from '@angular/platform-browser';\nimport {\n createInputBindings,\n getComponentElementTag,\n registerRootComponent,\n} from './create-component.ts';\nimport { buildProjectableNodes } from './projection.ts';\n\nfunction check(\n Component: ComponentType<unknown>,\n _props: Record<string, unknown>,\n _children: unknown,\n) {\n return !!reflectComponentType(Component);\n}\n\nasync function renderToStaticMarkup(\n Component: ComponentType<unknown> & {\n renderProviders: (Provider | EnvironmentProviders)[];\n },\n props: Record<string, unknown>,\n children: unknown,\n) {\n const mirror = reflectComponentType(Component);\n\n if (!mirror) {\n // This should be unreachable: the `check` function verifies that Component is an Angular component.\n throw new Error(Component.name + ' is not an Angular component');\n }\n\n const elementTag = getComponentElementTag(mirror);\n\n const platformRef = platformServer();\n const document = platformRef.injector.get(DOCUMENT);\n document.body.innerHTML = `<${elementTag}></${elementTag}>`;\n\n const hostElement = document.querySelector(elementTag) as Element;\n const projectableNodes = buildProjectableNodes(mirror, children, document);\n\n const bootstrap = async (context?: BootstrapContext) => {\n const appRef = await createApplication(\n {\n providers: [\n provideServerRendering(),\n { provide: ɵSERVER_CONTEXT, useValue: 'analog' },\n provideZonelessChangeDetection(),\n ...(Component.renderProviders || []),\n ],\n },\n context,\n );\n\n const componentRef = createComponent(Component, {\n environmentInjector: appRef.injector,\n hostElement,\n projectableNodes,\n bindings: createInputBindings(mirror, props),\n });\n\n registerRootComponent(appRef, componentRef);\n\n return appRef;\n };\n\n const html = await renderApplication(bootstrap, {\n document,\n });\n\n document.documentElement.innerHTML = html;\n let styleTags = '';\n\n document.head.childNodes.forEach((node) => {\n if (node.nodeName === 'STYLE') {\n styleTags += (node as HTMLElement).outerHTML;\n }\n });\n\n const correctedHtml = styleTags + document.body.innerHTML;\n\n platformRef.destroy();\n\n return { html: correctedHtml };\n}\n\nexport default {\n check,\n renderToStaticMarkup,\n};\n"]}
@@ -1,9 +0,0 @@
1
- import { type ComponentMirror, type Provider } from '@angular/core';
2
- /**
3
- * Provide bootstrap listeners to ensure the rendered state matches the settled component state after applying component inputs.
4
- * @param mirror The component mirror, to detect component inputs
5
- * @param props Properties applied to the component in the Astro file
6
- * @returns A providers array for the server renderer
7
- */
8
- export declare function provideBootstrapListener(mirror: ComponentMirror<unknown>, props: Record<string, unknown>): Provider[];
9
- //# sourceMappingURL=server-providers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-providers.d.ts","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-providers.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EAEpB,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AAEvB;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,QAAQ,EAAE,CAkBZ"}
@@ -1,25 +0,0 @@
1
- import { APP_BOOTSTRAP_LISTENER, } from '@angular/core';
2
- /**
3
- * Provide bootstrap listeners to ensure the rendered state matches the settled component state after applying component inputs.
4
- * @param mirror The component mirror, to detect component inputs
5
- * @param props Properties applied to the component in the Astro file
6
- * @returns A providers array for the server renderer
7
- */
8
- export function provideBootstrapListener(mirror, props) {
9
- return [
10
- {
11
- provide: APP_BOOTSTRAP_LISTENER,
12
- useValue: (compRef) => {
13
- if (props) {
14
- for (const [key, value] of Object.entries(props)) {
15
- if (mirror.inputs.some(({ templateName }) => templateName === key)) {
16
- compRef.setInput(key, value);
17
- }
18
- }
19
- }
20
- },
21
- multi: true,
22
- },
23
- ];
24
- }
25
- //# sourceMappingURL=server-providers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-providers.js","sourceRoot":"","sources":["../../../../packages/astro-angular/src/server-providers.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,GAIvB,MAAM,eAAe,CAAC;AAEvB;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACtC,MAAgC,EAChC,KAA8B;IAE9B,OAAO;QACL;YACE,OAAO,EAAE,sBAAsB;YAC/B,QAAQ,EAAE,CAAC,OAA8B,EAAE,EAAE;gBAC3C,IAAI,KAAK,EAAE,CAAC;oBACV,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;wBACjD,IACE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,YAAY,KAAK,GAAG,CAAC,EAC9D,CAAC;4BACD,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;wBAC/B,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YACD,KAAK,EAAE,IAAI;SACZ;KACF,CAAC;AACJ,CAAC","sourcesContent":["import {\n APP_BOOTSTRAP_LISTENER,\n type ComponentMirror,\n type ComponentRef,\n type Provider,\n} from '@angular/core';\n\n/**\n * Provide bootstrap listeners to ensure the rendered state matches the settled component state after applying component inputs.\n * @param mirror The component mirror, to detect component inputs\n * @param props Properties applied to the component in the Astro file\n * @returns A providers array for the server renderer\n */\nexport function provideBootstrapListener(\n mirror: ComponentMirror<unknown>,\n props: Record<string, unknown>,\n): Provider[] {\n return [\n {\n provide: APP_BOOTSTRAP_LISTENER,\n useValue: (compRef: ComponentRef<unknown>) => {\n if (props) {\n for (const [key, value] of Object.entries(props)) {\n if (\n mirror.inputs.some(({ templateName }) => templateName === key)\n ) {\n compRef.setInput(key, value);\n }\n }\n }\n },\n multi: true,\n },\n ];\n}\n"]}