angular-three 2.0.0-beta.3 → 2.0.0-beta.5

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 { signal, computed, untracked, Injectable, Optional, Inject, ElementRef, inject, Injector, assertInInjectionContext, runInInjectionContext, ChangeDetectorRef, effect, InjectionToken, EventEmitter, ViewContainerRef, NgZone, TemplateRef, Directive, Input, getDebugNode, RendererFactory2, makeEnvironmentProviders, provideZoneChangeDetection, EnvironmentInjector, DestroyRef, createEnvironmentInjector, Component, ChangeDetectionStrategy, Output, ViewChild, SkipSelf, ContentChild } from '@angular/core';
2
+ import { signal, computed, untracked, Injectable, Optional, Inject, ElementRef, inject, Injector, assertInInjectionContext, runInInjectionContext, ChangeDetectorRef, effect, InjectionToken, EventEmitter, ViewContainerRef, NgZone, TemplateRef, Directive, Input, getDebugNode, RendererFactory2, makeEnvironmentProviders, provideZoneChangeDetection, EnvironmentInjector, DestroyRef, createEnvironmentInjector, Component, ChangeDetectionStrategy, Output, ViewChild, ApplicationRef, SkipSelf, ContentChild } from '@angular/core';
3
3
  import { provideNgxResizeOptions, NgxResize } from 'ngx-resize';
4
4
  import * as THREE from 'three';
5
5
  import { DOCUMENT, NgForOf, NgIf } from '@angular/common';
@@ -38,28 +38,26 @@ class NgtSignalStore {
38
38
  constructor(initialState = {}) {
39
39
  initialState ??= {};
40
40
  this.#state = createSignal(Object.assign(initialState, { __ngt_dummy_state__: Date.now() }));
41
+ this.state = this.#state.asReadonly();
41
42
  }
42
43
  select(...keysAndOptions) {
43
44
  if (keysAndOptions.length === 0)
44
- return this.#state.asReadonly();
45
+ return this.state;
45
46
  if (keysAndOptions.length === 1 && typeof keysAndOptions[0] === 'object') {
46
47
  if (!this.#computedCache.has(STORE_COMPUTED_KEY)) {
47
- this.#computedCache.set(STORE_COMPUTED_KEY, computed(() => this.#state(), keysAndOptions));
48
+ this.#computedCache.set(STORE_COMPUTED_KEY, computed(this.state, keysAndOptions));
48
49
  return this.#computedCache.get(STORE_COMPUTED_KEY);
49
50
  }
50
51
  }
51
52
  const [keys, options] = parseOptions(keysAndOptions);
52
53
  const joinedKeys = keys.join('-');
53
54
  if (!this.#computedCache.has(joinedKeys)) {
54
- this.#computedCache.set(joinedKeys, computed(() => {
55
- const state = this.#state();
56
- return keys.reduce((value, key) => value[key], state);
57
- }, options));
55
+ this.#computedCache.set(joinedKeys, computed(() => keys.reduce((value, key) => value[key], this.state()), options));
58
56
  }
59
57
  return this.#computedCache.get(joinedKeys);
60
58
  }
61
59
  get(...keys) {
62
- const state = untracked(this.#state);
60
+ const state = untracked(this.state);
63
61
  if (keys.length === 0)
64
62
  return state;
65
63
  return keys.reduce((value, key) => value[key], state);
@@ -90,10 +88,10 @@ class NgtSignalStore {
90
88
  };
91
89
  this.#state.update((previous) => ({ ...updater(previous), ...previous }));
92
90
  }
93
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtSignalStore, deps: [{ token: 'INITIAL_STATE', optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
94
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtSignalStore }); }
91
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtSignalStore, deps: [{ token: 'INITIAL_STATE', optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
92
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtSignalStore }); }
95
93
  }
96
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtSignalStore, decorators: [{
94
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtSignalStore, decorators: [{
97
95
  type: Injectable
98
96
  }], ctorParameters: function () { return [{ type: undefined, decorators: [{
99
97
  type: Optional
@@ -751,62 +749,58 @@ function queueMacrotaskInInjectionContext(cb, injector) {
751
749
  }
752
750
 
753
751
  const cached = new Map();
752
+ function normalizeInputs(input) {
753
+ if (Array.isArray(input))
754
+ return input;
755
+ if (typeof input === 'string')
756
+ return [input];
757
+ return Object.values(input);
758
+ }
754
759
  function load(loaderConstructorFactory, inputs, { extensions, onProgress, } = {}) {
755
- const computedUrls = computed(() => {
756
- const input = inputs();
757
- if (Array.isArray(input))
758
- return input;
759
- if (typeof input === 'string')
760
- return [input];
761
- return Object.values(input);
762
- });
763
760
  return () => {
764
- const urls = computedUrls();
765
- const loaderConstructor = loaderConstructorFactory(urls);
766
- const loader = new loaderConstructor();
761
+ const urls = normalizeInputs(inputs());
762
+ const loader = new (loaderConstructorFactory(urls))();
767
763
  if (extensions)
768
764
  extensions(loader);
769
- return urls.map((url) => new Promise((resolve, reject) => {
770
- if (cached.has(url)) {
771
- resolve(cached.get(url));
772
- }
773
- else {
774
- loader.load(url, (data) => {
775
- if ('scene' in data)
776
- Object.assign(data, makeObjectGraph(data['scene']));
777
- cached.set(url, data);
778
- resolve(data);
779
- }, onProgress, (error) => reject(new Error(`[NGT] Could not load ${url}: ${error}`)));
765
+ // TODO: reevaluate this
766
+ return urls.map((url) => {
767
+ if (!cached.has(url)) {
768
+ cached.set(url, new Promise((resolve, reject) => {
769
+ loader.load(url, (data) => {
770
+ if ('scene' in data)
771
+ Object.assign(data, makeObjectGraph(data['scene']));
772
+ resolve(data);
773
+ }, onProgress, (error) => reject(new Error(`[NGT] Could not load ${url}: ${error}`)));
774
+ }));
780
775
  }
781
- }));
776
+ return cached.get(url);
777
+ });
782
778
  };
783
779
  }
784
780
  function injectNgtLoader(loaderConstructorFactory, inputs, { extensions, onProgress, injector, } = {}) {
785
781
  injector = assertInjectionContext(injectNgtLoader, injector);
782
+ const response = signal(null);
786
783
  return runInInjectionContext(injector, () => {
787
784
  const cdr = inject(ChangeDetectorRef);
788
- const response = signal(null);
789
785
  const effector = load(loaderConstructorFactory, inputs, { extensions, onProgress });
790
786
  requestAnimationInInjectionContext(() => {
791
787
  effect(() => {
792
- const originalUrls = untracked(inputs);
793
- Promise.all(effector())
794
- .then((results) => {
795
- if (Array.isArray(originalUrls))
796
- return results;
797
- if (typeof originalUrls === 'string')
798
- return results[0];
799
- const keys = Object.keys(originalUrls);
800
- return keys.reduce((result, key) => {
801
- result[key] = results[keys.indexOf(key)];
802
- return result;
803
- }, {});
804
- })
805
- .then((value) => {
806
- response.set(value);
788
+ const originalUrls = inputs();
789
+ Promise.all(effector()).then((results) => {
790
+ response.update(() => {
791
+ if (Array.isArray(originalUrls))
792
+ return results;
793
+ if (typeof originalUrls === 'string')
794
+ return results[0];
795
+ const keys = Object.keys(originalUrls);
796
+ return keys.reduce((result, key) => {
797
+ result[key] = results[keys.indexOf(key)];
798
+ return result;
799
+ }, {});
800
+ });
807
801
  safeDetectChanges(cdr);
808
802
  });
809
- });
803
+ }, { allowSignalWrites: true });
810
804
  });
811
805
  return response.asReadonly();
812
806
  });
@@ -957,7 +951,16 @@ function diffProps(instance, props) {
957
951
  const propsEntries = Object.entries(props);
958
952
  const changes = [];
959
953
  for (const [propKey, propValue] of propsEntries) {
960
- if (is.equ(propValue, instance[propKey]))
954
+ let key = propKey;
955
+ if (is.colorSpaceExist(instance)) {
956
+ if (propKey === 'encoding') {
957
+ key = 'colorSpace';
958
+ }
959
+ else if (propKey === 'outputEncoding') {
960
+ key = 'outputColorSpace';
961
+ }
962
+ }
963
+ if (is.equ(propValue, instance[key]))
961
964
  continue;
962
965
  changes.push([propKey, propValue]);
963
966
  }
@@ -972,9 +975,8 @@ function applyProps(instance, props) {
972
975
  const rootState = localState.store?.get();
973
976
  const changes = diffProps(instance, props);
974
977
  for (let i = 0; i < changes.length; i++) {
975
- let key = changes[i][0];
976
978
  const currentInstance = instance;
977
- const targetProp = currentInstance[key];
979
+ let key = changes[i][0];
978
980
  let value = changes[i][1];
979
981
  if (is.colorSpaceExist(currentInstance)) {
980
982
  const sRGBEncoding = 3001;
@@ -989,6 +991,7 @@ function applyProps(instance, props) {
989
991
  value = value === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
990
992
  }
991
993
  }
994
+ const targetProp = currentInstance[key];
992
995
  // special treatmen for objects with support for set/copy, and layers
993
996
  if (targetProp && targetProp['set'] && (targetProp['copy'] || targetProp instanceof THREE.Layers)) {
994
997
  const isColor = targetProp instanceof THREE.Color;
@@ -1445,15 +1448,12 @@ class NgtStore extends NgtSignalStore {
1445
1448
  }, { injector: this.#injector, allowSignalWrites: true });
1446
1449
  }
1447
1450
  #invalidate() {
1448
- const state = this.select();
1449
- effect(() => {
1450
- state().invalidate();
1451
- }, { injector: this.#injector });
1451
+ effect(() => void this.state().invalidate(), { injector: this.#injector });
1452
1452
  }
1453
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtStore, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1454
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtStore }); }
1453
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtStore, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1454
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtStore }); }
1455
1455
  }
1456
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtStore, decorators: [{
1456
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtStore, decorators: [{
1457
1457
  type: Injectable
1458
1458
  }] });
1459
1459
  function computeInitialSize(canvas, defaultSize) {
@@ -1712,14 +1712,14 @@ class NgtCommonDirective {
1712
1712
  }
1713
1713
  this.#zone.runOutsideAngular(() => {
1714
1714
  this.#view = this.#vcr.createEmbeddedView(this.#template);
1715
- this.#view.detectChanges();
1715
+ safeDetectChanges(this.#view);
1716
1716
  });
1717
1717
  }
1718
1718
  }
1719
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCommonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1720
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtCommonDirective, ngImport: i0 }); }
1719
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtCommonDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1720
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.2", type: NgtCommonDirective, ngImport: i0 }); }
1721
1721
  }
1722
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCommonDirective, decorators: [{
1722
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtCommonDirective, decorators: [{
1723
1723
  type: Directive
1724
1724
  }], ctorParameters: function () { return []; } });
1725
1725
 
@@ -1742,10 +1742,10 @@ class NgtArgs extends NgtCommonDirective {
1742
1742
  validate() {
1743
1743
  return !this.injected && !!this.#injectedArgs.length;
1744
1744
  }
1745
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtArgs, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
1746
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtArgs, isStandalone: true, selector: "[args]", inputs: { args: "args" }, usesInheritance: true, ngImport: i0 }); }
1745
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtArgs, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
1746
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.2", type: NgtArgs, isStandalone: true, selector: "[args]", inputs: { args: "args" }, usesInheritance: true, ngImport: i0 }); }
1747
1747
  }
1748
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtArgs, decorators: [{
1748
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtArgs, decorators: [{
1749
1749
  type: Directive,
1750
1750
  args: [{ selector: '[args]', standalone: true }]
1751
1751
  }], propDecorators: { args: [{
@@ -1771,10 +1771,10 @@ class NgtParent extends NgtCommonDirective {
1771
1771
  validate() {
1772
1772
  return !this.injected && !!this.#injectedParent;
1773
1773
  }
1774
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtParent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
1775
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtParent, isStandalone: true, selector: "[parent]", inputs: { parent: "parent" }, usesInheritance: true, ngImport: i0 }); }
1774
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtParent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
1775
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.2", type: NgtParent, isStandalone: true, selector: "[parent]", inputs: { parent: "parent" }, usesInheritance: true, ngImport: i0 }); }
1776
1776
  }
1777
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtParent, decorators: [{
1777
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtParent, decorators: [{
1778
1778
  type: Directive,
1779
1779
  args: [{ selector: '[parent]', standalone: true }]
1780
1780
  }], propDecorators: { parent: [{
@@ -1814,7 +1814,7 @@ class NgtRendererStore {
1814
1814
  state[14 /* NgtRendererClassId.injectorFactory */] = () => getDebugNode(rendererNode).injector;
1815
1815
  }
1816
1816
  if (state[0 /* NgtRendererClassId.type */] === 'comment') {
1817
- // we attach an arrow function to the Comment node
1817
+ // NOTE: we attach an arrow function to the Comment node
1818
1818
  // In our directives, we can call this function to then start tracking the RendererNode
1819
1819
  // this is done to limit the amount of Nodes we need to process for getCreationState
1820
1820
  rendererNode[SPECIAL_INTERNAL_ADD_COMMENT] = (node) => {
@@ -2016,9 +2016,9 @@ class NgtRendererStore {
2016
2016
  return null;
2017
2017
  }
2018
2018
  getCreationState() {
2019
- const injectedArgs = this.firstNonInjectedDirective(NgtArgs)?.args || [];
2020
- const injectedParent = this.firstNonInjectedDirective(NgtParent)?.parent || null;
2021
- const store = this.tryGetPortalStore();
2019
+ const injectedArgs = this.#firstNonInjectedDirective(NgtArgs)?.args || [];
2020
+ const injectedParent = this.#firstNonInjectedDirective(NgtParent)?.parent || null;
2021
+ const store = this.#tryGetPortalStore();
2022
2022
  return { injectedArgs, injectedParent, store };
2023
2023
  }
2024
2024
  destroy(node, parent) {
@@ -2094,7 +2094,7 @@ class NgtRendererStore {
2094
2094
  this.removeChild(parent, node);
2095
2095
  }
2096
2096
  }
2097
- firstNonInjectedDirective(dir) {
2097
+ #firstNonInjectedDirective(dir) {
2098
2098
  let directive;
2099
2099
  let i = this.#comments.length - 1;
2100
2100
  while (i >= 0) {
@@ -2117,7 +2117,7 @@ class NgtRendererStore {
2117
2117
  }
2118
2118
  return directive;
2119
2119
  }
2120
- tryGetPortalStore() {
2120
+ #tryGetPortalStore() {
2121
2121
  let store;
2122
2122
  // we only care about the portal states because NgtStore only differs per Portal
2123
2123
  let i = this.portals.length - 1;
@@ -2178,10 +2178,10 @@ class NgtRendererFactory {
2178
2178
  }
2179
2179
  return renderer;
2180
2180
  }
2181
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRendererFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2182
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRendererFactory }); }
2181
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtRendererFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2182
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtRendererFactory }); }
2183
2183
  }
2184
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRendererFactory, decorators: [{
2184
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtRendererFactory, decorators: [{
2185
2185
  type: Injectable
2186
2186
  }] });
2187
2187
  /**
@@ -2226,7 +2226,10 @@ class NgtRenderer {
2226
2226
  }
2227
2227
  // handle raw value
2228
2228
  if (name === SPECIAL_DOM_TAG.NGT_VALUE) {
2229
- return this.store.createNode('three', Object.assign({ __ngt_renderer__: { rawValue: undefined } }, { __ngt__: { isRaw: true, parent: createSignal(null) } }));
2229
+ return this.store.createNode('three', Object.assign({ __ngt_renderer__: { rawValue: undefined } },
2230
+ // NOTE: we assign this manually to a raw value node
2231
+ // because we say it is a 'three' node but we're not using prepare()
2232
+ { __ngt__: { isRaw: true, parent: createSignal(null) } }));
2230
2233
  }
2231
2234
  const { injectedArgs, injectedParent, store } = this.store.getCreationState();
2232
2235
  let parent = injectedParent;
@@ -2242,8 +2245,8 @@ class NgtRenderer {
2242
2245
  const object = injectedArgs[0];
2243
2246
  let localState = getLocalState(object);
2244
2247
  if (!Object.keys(localState).length) {
2245
- prepare(object, { store, args: injectedArgs, primitive: true });
2246
- localState = getLocalState(object);
2248
+ // NOTE: if an object isn't already "prepared", we prepare it
2249
+ localState = getLocalState(prepare(object, { store, args: injectedArgs, primitive: true }));
2247
2250
  }
2248
2251
  if (!localState.store)
2249
2252
  localState.store = store;
@@ -2615,6 +2618,7 @@ class NgtCanvas extends NgtSignalStore {
2615
2618
  this.#store.set({
2616
2619
  onPointerMissed: (event) => {
2617
2620
  this.pointerMissed.emit(event);
2621
+ safeDetectChanges(this.#cdr);
2618
2622
  },
2619
2623
  });
2620
2624
  }
@@ -2640,9 +2644,8 @@ class NgtCanvas extends NgtSignalStore {
2640
2644
  if (width > 0 && height > 0) {
2641
2645
  if (!this.#store.isInit)
2642
2646
  this.#store.init();
2643
- const inputs = this.select();
2644
2647
  this.#resizeRef = this.#zone.run(() => effect(() => {
2645
- const canvasInputs = inputs();
2648
+ const canvasInputs = this.state();
2646
2649
  this.#zone.runOutsideAngular(() => {
2647
2650
  this.#store.configure({ ...canvasInputs, size: { width, height, top, left } }, this.glCanvas.nativeElement);
2648
2651
  });
@@ -2712,14 +2715,14 @@ class NgtCanvas extends NgtSignalStore {
2712
2715
  }
2713
2716
  });
2714
2717
  }
2715
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCanvas, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2716
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0", type: NgtCanvas, isStandalone: true, selector: "ngt-canvas", inputs: { sceneGraph: "sceneGraph", sceneGraphInputs: "sceneGraphInputs", compoundPrefixes: "compoundPrefixes", linear: "linear", legacy: "legacy", flat: "flat", orthographic: "orthographic", frameloop: "frameloop", dpr: "dpr", raycaster: "raycaster", shadows: "shadows", camera: "camera", scene: "scene", gl: "gl", eventSource: "eventSource", eventPrefix: "eventPrefix", lookAt: "lookAt", performance: "performance" }, outputs: { created: "created", pointerMissed: "pointerMissed" }, host: { styleAttribute: "display: block;position: relative;width: 100%;height: 100%;overflow: hidden;" }, providers: [NgtStore, provideNgxResizeOptions({ emitInZone: false, emitInitialResult: true })], viewQueries: [{ propertyName: "glCanvas", first: true, predicate: ["glCanvas"], descendants: true, static: true }, { propertyName: "glAnchor", first: true, predicate: ["glCanvas"], descendants: true, read: ViewContainerRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
2718
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtCanvas, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2719
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: NgtCanvas, isStandalone: true, selector: "ngt-canvas", inputs: { sceneGraph: "sceneGraph", sceneGraphInputs: "sceneGraphInputs", compoundPrefixes: "compoundPrefixes", linear: "linear", legacy: "legacy", flat: "flat", orthographic: "orthographic", frameloop: "frameloop", dpr: "dpr", raycaster: "raycaster", shadows: "shadows", camera: "camera", scene: "scene", gl: "gl", eventSource: "eventSource", eventPrefix: "eventPrefix", lookAt: "lookAt", performance: "performance" }, outputs: { created: "created", pointerMissed: "pointerMissed" }, host: { styleAttribute: "display: block;position: relative;width: 100%;height: 100%;overflow: hidden;" }, providers: [NgtStore, provideNgxResizeOptions({ emitInZone: false, emitInitialResult: true })], viewQueries: [{ propertyName: "glCanvas", first: true, predicate: ["glCanvas"], descendants: true, static: true }, { propertyName: "glAnchor", first: true, predicate: ["glCanvas"], descendants: true, read: ViewContainerRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
2717
2720
  <div (ngxResize)="onResize($event)" style="height: 100%; width: 100%;">
2718
2721
  <canvas #glCanvas style="display: block;"> </canvas>
2719
2722
  </div>
2720
2723
  `, isInline: true, dependencies: [{ kind: "directive", type: NgxResize, selector: "[ngxResize]", inputs: ["ngxResizeOptions"], outputs: ["ngxResize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2721
2724
  }
2722
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtCanvas, decorators: [{
2725
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtCanvas, decorators: [{
2723
2726
  type: Component,
2724
2727
  args: [{
2725
2728
  selector: 'ngt-canvas',
@@ -2797,6 +2800,7 @@ function injectNgtRef(initial = null, injector) {
2797
2800
  injector = assertInjectionContext(injectNgtRef, injector);
2798
2801
  return runInInjectionContext(injector, () => {
2799
2802
  const cdr = inject(ChangeDetectorRef);
2803
+ const appRef = inject(ApplicationRef);
2800
2804
  const ref = is.ref(initial) ? initial : new ElementRef(initial);
2801
2805
  const signalRef = createSignal(ref.nativeElement);
2802
2806
  const readonlySignal = signalRef.asReadonly();
@@ -2824,14 +2828,13 @@ function injectNgtRef(initial = null, injector) {
2824
2828
  set: (newElement) => {
2825
2829
  if (newElement !== untracked(signalRef)) {
2826
2830
  signalRef.set(newElement);
2827
- safeDetectChanges(cdr);
2831
+ // trigger CDR
2832
+ requestAnimationFrame(() => void safeDetectChanges(cdr));
2828
2833
  }
2829
2834
  },
2830
2835
  get: () => readonlySignal(),
2831
2836
  });
2832
- Object.defineProperty(ref, 'untracked', {
2833
- get: () => untracked(readonlySignal),
2834
- });
2837
+ Object.defineProperty(ref, 'untracked', { get: () => untracked(readonlySignal) });
2835
2838
  return Object.assign(ref, { children });
2836
2839
  });
2837
2840
  }
@@ -2840,10 +2843,10 @@ class NgtRepeat extends NgForOf {
2840
2843
  set ngForRepeat(count) {
2841
2844
  this.ngForOf = Number.isInteger(count) ? Array.from({ length: count }, (_, i) => i) : [];
2842
2845
  }
2843
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRepeat, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
2844
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtRepeat, isStandalone: true, selector: "[ngFor][ngForRepeat]", inputs: { ngForRepeat: "ngForRepeat" }, usesInheritance: true, ngImport: i0 }); }
2846
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtRepeat, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
2847
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.2", type: NgtRepeat, isStandalone: true, selector: "[ngFor][ngForRepeat]", inputs: { ngForRepeat: "ngForRepeat" }, usesInheritance: true, ngImport: i0 }); }
2845
2848
  }
2846
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRepeat, decorators: [{
2849
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtRepeat, decorators: [{
2847
2850
  type: Directive,
2848
2851
  args: [{ selector: '[ngFor][ngForRepeat]', standalone: true }]
2849
2852
  }], propDecorators: { ngForRepeat: [{
@@ -2865,38 +2868,34 @@ const privateKeys = [
2865
2868
  ];
2866
2869
  class NgtPortalBeforeRender {
2867
2870
  #portalStore;
2868
- #subscription;
2869
2871
  constructor() {
2870
2872
  this.#portalStore = inject(NgtStore);
2871
2873
  this.renderPriority = 1;
2872
2874
  this.beforeRender = new EventEmitter();
2873
- inject(DestroyRef).onDestroy(() => {
2874
- this.#subscription?.();
2875
+ let oldClear;
2876
+ queueMicrotaskInInjectionContext(() => {
2877
+ injectBeforeRender(({ delta, frame }) => {
2878
+ this.beforeRender.emit({ ...this.#portalStore.get(), delta, frame });
2879
+ const { gl, scene, camera } = this.#portalStore.get();
2880
+ oldClear = gl.autoClear;
2881
+ if (this.renderPriority === 1) {
2882
+ // clear scene and render with default
2883
+ gl.autoClear = true;
2884
+ gl.render(this.parentScene, this.parentCamera);
2885
+ }
2886
+ // disable cleaning
2887
+ gl.autoClear = false;
2888
+ gl.clearDepth();
2889
+ gl.render(scene, camera);
2890
+ // restore
2891
+ gl.autoClear = oldClear;
2892
+ }, { priority: this.renderPriority });
2875
2893
  });
2876
2894
  }
2877
- ngOnInit() {
2878
- let oldClear;
2879
- this.#subscription = this.#portalStore.get('internal').subscribe(({ delta, frame }) => {
2880
- this.beforeRender.emit({ ...this.#portalStore.get(), delta, frame });
2881
- const { gl, scene, camera } = this.#portalStore.get();
2882
- oldClear = gl.autoClear;
2883
- if (this.renderPriority === 1) {
2884
- // clear scene and render with default
2885
- gl.autoClear = true;
2886
- gl.render(this.parentScene, this.parentCamera);
2887
- }
2888
- // disable cleaning
2889
- gl.autoClear = false;
2890
- gl.clearDepth();
2891
- gl.render(scene, camera);
2892
- // restore
2893
- gl.autoClear = oldClear;
2894
- }, this.renderPriority, this.#portalStore);
2895
- }
2896
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortalBeforeRender, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2897
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtPortalBeforeRender, isStandalone: true, selector: "[ngtPortalBeforeRender]", inputs: { renderPriority: "renderPriority", parentScene: "parentScene", parentCamera: "parentCamera" }, outputs: { beforeRender: "beforeRender" }, ngImport: i0 }); }
2895
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtPortalBeforeRender, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
2896
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.2", type: NgtPortalBeforeRender, isStandalone: true, selector: "[ngtPortalBeforeRender]", inputs: { renderPriority: "renderPriority", parentScene: "parentScene", parentCamera: "parentCamera" }, outputs: { beforeRender: "beforeRender" }, ngImport: i0 }); }
2898
2897
  }
2899
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortalBeforeRender, decorators: [{
2898
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtPortalBeforeRender, decorators: [{
2900
2899
  type: Directive,
2901
2900
  args: [{ selector: '[ngtPortalBeforeRender]', standalone: true }]
2902
2901
  }], ctorParameters: function () { return []; }, propDecorators: { renderPriority: [{
@@ -2918,10 +2917,10 @@ class NgtPortalContent {
2918
2917
  delete commentNode[SPECIAL_INTERNAL_ADD_COMMENT];
2919
2918
  }
2920
2919
  }
2921
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortalContent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ViewContainerRef, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); }
2922
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.0", type: NgtPortalContent, isStandalone: true, selector: "ng-template[ngtPortalContent]", ngImport: i0 }); }
2920
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtPortalContent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ViewContainerRef, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); }
2921
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.2", type: NgtPortalContent, isStandalone: true, selector: "ng-template[ngtPortalContent]", ngImport: i0 }); }
2923
2922
  }
2924
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortalContent, decorators: [{
2923
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtPortalContent, decorators: [{
2925
2924
  type: Directive,
2926
2925
  args: [{ selector: 'ng-template[ngtPortalContent]', standalone: true }]
2927
2926
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ViewContainerRef, decorators: [{
@@ -2931,7 +2930,7 @@ class NgtPortal extends NgtSignalStore {
2931
2930
  set container(container) {
2932
2931
  this.set({ container });
2933
2932
  }
2934
- set state(state) {
2933
+ set portalState(state) {
2935
2934
  this.set({ state });
2936
2935
  }
2937
2936
  #parentStore;
@@ -3036,8 +3035,8 @@ class NgtPortal extends NgtSignalStore {
3036
3035
  ...restInputsState,
3037
3036
  };
3038
3037
  }
3039
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3040
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0", type: NgtPortal, isStandalone: true, selector: "ngt-portal", inputs: { container: "container", state: "state", autoRender: "autoRender", autoRenderPriority: "autoRenderPriority" }, outputs: { beforeRender: "beforeRender" }, providers: [NgtStore], queries: [{ propertyName: "portalContentTemplate", first: true, predicate: NgtPortalContent, descendants: true, read: TemplateRef, static: true }], viewQueries: [{ propertyName: "portalContentAnchor", first: true, predicate: ["portalContentAnchor"], descendants: true, read: ViewContainerRef, static: true }], usesInheritance: true, ngImport: i0, template: `
3038
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtPortal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3039
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: NgtPortal, isStandalone: true, selector: "ngt-portal", inputs: { container: "container", portalState: "portalState", autoRender: "autoRender", autoRenderPriority: "autoRenderPriority" }, outputs: { beforeRender: "beforeRender" }, providers: [NgtStore], queries: [{ propertyName: "portalContentTemplate", first: true, predicate: NgtPortalContent, descendants: true, read: TemplateRef, static: true }], viewQueries: [{ propertyName: "portalContentAnchor", first: true, predicate: ["portalContentAnchor"], descendants: true, read: ViewContainerRef, static: true }], usesInheritance: true, ngImport: i0, template: `
3041
3040
  <ng-container #portalContentAnchor>
3042
3041
  <ng-container
3043
3042
  *ngIf="autoRender && portalContentRendered"
@@ -3050,7 +3049,7 @@ class NgtPortal extends NgtSignalStore {
3050
3049
  </ng-container>
3051
3050
  `, isInline: true, dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgtPortalBeforeRender, selector: "[ngtPortalBeforeRender]", inputs: ["renderPriority", "parentScene", "parentCamera"], outputs: ["beforeRender"] }] }); }
3052
3051
  }
3053
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtPortal, decorators: [{
3052
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtPortal, decorators: [{
3054
3053
  type: Component,
3055
3054
  args: [{
3056
3055
  selector: 'ngt-portal',
@@ -3072,7 +3071,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImpor
3072
3071
  }]
3073
3072
  }], ctorParameters: function () { return []; }, propDecorators: { container: [{
3074
3073
  type: Input
3075
- }], state: [{
3074
+ }], portalState: [{
3076
3075
  type: Input
3077
3076
  }], autoRender: [{
3078
3077
  type: Input
@@ -3097,10 +3096,10 @@ class NgtRoutedScene {
3097
3096
  .pipe(filter((event) => event instanceof ActivationEnd), takeUntilDestroyed())
3098
3097
  .subscribe(() => safeDetectChanges(cdr));
3099
3098
  }
3100
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRoutedScene, deps: [{ token: i1.Router }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3101
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.0", type: NgtRoutedScene, isStandalone: true, selector: "ngt-routed-scene", ngImport: i0, template: `<router-outlet />`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] }); }
3099
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtRoutedScene, deps: [{ token: i1.Router }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
3100
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: NgtRoutedScene, isStandalone: true, selector: "ngt-routed-scene", ngImport: i0, template: `<router-outlet />`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] }); }
3102
3101
  }
3103
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.0", ngImport: i0, type: NgtRoutedScene, decorators: [{
3102
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: NgtRoutedScene, decorators: [{
3104
3103
  type: Component,
3105
3104
  args: [{
3106
3105
  standalone: true,