@shopware-ag/dive 1.18.5-beta.1 → 1.18.5-beta.3

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/build/dive.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./dive-C-5_QywE.cjs");exports.DIVE=e.DIVE;exports.DIVECommunication=e.DIVECommunication;exports.DIVEDefaultSettings=e.DIVEDefaultSettings;exports.DIVEMath=e.DIVEMath;exports.default=e.DIVE;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./dive-BTQZqHRt.cjs");exports.DIVE=e.DIVE;exports.DIVECommunication=e.DIVECommunication;exports.DIVEDefaultSettings=e.DIVEDefaultSettings;exports.DIVEMath=e.DIVEMath;exports.default=e.DIVE;
2
2
  //# sourceMappingURL=dive.cjs.map
package/build/dive.js CHANGED
@@ -1,9 +1,9 @@
1
- import { k as s, l as D, j as e, m, k as o } from "./dive-BmDCwQRo.js";
1
+ import { A as s, E as D, z as E, F as e, A as o } from "./dive-Dk0rFfvA.js";
2
2
  export {
3
3
  s as DIVE,
4
4
  D as DIVECommunication,
5
- e as DIVEDefaultSettings,
6
- m as DIVEMath,
5
+ E as DIVEDefaultSettings,
6
+ e as DIVEMath,
7
7
  o as default
8
8
  };
9
9
  //# sourceMappingURL=dive.js.map
@@ -1,8 +1,7 @@
1
1
  import { DIVEScene } from '../../scene/Scene';
2
2
  import { DIVEAROptions } from '../AR';
3
3
  export declare class DIVEARQuickLook {
4
- private static _usdzExporter;
5
4
  static Launch(scene: DIVEScene, options?: DIVEAROptions): Promise<void>;
6
- private static extractModels;
7
- private static launchARFromNode;
5
+ private static launchARQuickLook;
6
+ private static findARQuickLookSrc;
8
7
  }
@@ -1,6 +1,6 @@
1
1
  import { Vector3Like } from 'three';
2
2
  export default interface GENERATE_MEDIA {
3
- DESCRIPTION: 'Generates a screenshot, stores it in a Blob and writes the URL into the payload.';
3
+ DESCRIPTION: 'Generates a screenshot, stores it in a Blob and returns a Promise of a valid URI.';
4
4
  PAYLOAD: ({
5
5
  position: Vector3Like;
6
6
  target: Vector3Like;
@@ -9,7 +9,6 @@ export default interface GENERATE_MEDIA {
9
9
  }) & {
10
10
  width: number;
11
11
  height: number;
12
- dataUri: string;
13
12
  };
14
- RETURN: boolean;
13
+ RETURN: Promise<string>;
15
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopware-ag/dive",
3
- "version": "1.18.5-beta.1",
3
+ "version": "1.18.5-beta.3",
4
4
  "description": "Shopware Spatial Framework",
5
5
  "type": "module",
6
6
  "main": "build/dive.cjs",
@@ -1,64 +1,93 @@
1
- import { Object3D } from 'three';
2
- import { DIVEUSDZExporter } from '../../exporters/usdz/USDZExporter';
3
1
  import { type DIVEScene } from '../../scene/Scene';
4
2
  import { type DIVEAROptions } from '../AR';
5
3
 
6
4
  export class DIVEARQuickLook {
7
- private static _usdzExporter: DIVEUSDZExporter = new DIVEUSDZExporter();
8
-
9
5
  public static Launch(
10
6
  scene: DIVEScene,
11
7
  options?: DIVEAROptions,
12
8
  ): Promise<void> {
13
- // create node to build usdz from
14
- const quickLookScene = new Object3D();
15
-
16
- // extract models from scene
17
- quickLookScene.add(...this.extractModels(scene));
9
+ const url = this.findARQuickLookSrc(scene);
18
10
 
19
11
  // launch ARQuickLook
20
- return this.launchARFromNode(quickLookScene, options);
21
- }
22
-
23
- private static extractModels(scene: DIVEScene): Object3D[] {
24
- // extract models
25
- return scene.Root.children;
12
+ return this.launchARQuickLook(url, options);
26
13
  }
27
14
 
28
- private static launchARFromNode(
29
- node: Object3D,
15
+ private static launchARQuickLook(
16
+ uri: string,
30
17
  options?: DIVEAROptions,
31
18
  ): Promise<void> {
32
- // bundle USDZ
33
- return this._usdzExporter
34
- .parse(node, {
35
- quickLookCompatible: true,
36
- ar: {
37
- anchoring: { type: 'plane' },
38
- planeAnchoring: {
39
- alignment:
40
- options?.arPlacement === 'vertical'
41
- ? 'vertical'
42
- : 'horizontal',
43
- },
44
- },
45
- })
46
- .then((usdz: Uint8Array) => {
47
- // create blob
48
- const blob = new Blob([usdz], { type: 'model/vnd.usdz+zip' });
49
- let url = URL.createObjectURL(blob);
19
+ return new Promise((resolve) => {
20
+ if (options?.arScale === 'fixed') {
21
+ uri = uri.concat('#allowsContentScaling=0');
22
+ }
23
+
24
+ // launch ARQuickLook
25
+ const a = document.createElement('a');
26
+ a.innerHTML = '<picture></picture>'; // This is actually needed so the viewer opens instantly
27
+ a.rel = 'ar';
28
+ a.href = uri;
29
+ a.download = 'scene.usdz';
30
+ resolve();
31
+ a.click();
32
+ });
33
+ }
50
34
 
51
- if (options?.arScale === 'fixed') {
52
- url = url.concat('#allowsContentScaling=0');
53
- }
35
+ private static findARQuickLookSrc(scene: DIVEScene): string {
36
+ let uri: string | null = null;
54
37
 
55
- // launch ARQuickLook
56
- const a = document.createElement('a');
57
- a.innerHTML = '<picture></picture>'; // This is actually needed so the viewer opens instantly
58
- a.rel = 'ar';
59
- a.href = url;
60
- a.download = 'scene.usdz';
61
- a.click();
62
- });
38
+ scene.traverse((object) => {
39
+ if (uri) return;
40
+ if (object.userData.uri) {
41
+ uri = object.userData.uri;
42
+ }
43
+ });
44
+
45
+ if (!uri) {
46
+ throw new Error('No model found in scene');
47
+ }
48
+
49
+ return uri;
63
50
  }
51
+
52
+ // private static extractModels(scene: DIVEScene): Object3D[] {
53
+ // // extract models
54
+ // return scene.Root.children;
55
+ // }
56
+
57
+ // private static launchARFromNode(
58
+ // node: Object3D,
59
+ // options?: DIVEAROptions,
60
+ // ): Promise<void> {
61
+ // // bundle USDZ
62
+ // return this._usdzExporter
63
+ // .parse(node, {
64
+ // quickLookCompatible: true,
65
+ // ar: {
66
+ // anchoring: { type: 'plane' },
67
+ // planeAnchoring: {
68
+ // alignment:
69
+ // options?.arPlacement === 'vertical'
70
+ // ? 'vertical'
71
+ // : 'horizontal',
72
+ // },
73
+ // },
74
+ // })
75
+ // .then((usdz: Uint8Array) => {
76
+ // // create blob
77
+ // const blob = new Blob([usdz], { type: 'model/vnd.usdz+zip' });
78
+ // let url = URL.createObjectURL(blob);
79
+
80
+ // if (options?.arScale === 'fixed') {
81
+ // url = url.concat('#allowsContentScaling=0');
82
+ // }
83
+
84
+ // // launch ARQuickLook
85
+ // const a = document.createElement('a');
86
+ // a.innerHTML = '<picture></picture>'; // This is actually needed so the viewer opens instantly
87
+ // a.rel = 'ar';
88
+ // a.href = url;
89
+ // a.download = 'scene.usdz';
90
+ // a.click();
91
+ // });
92
+ // }
64
93
  }
@@ -3,14 +3,20 @@ import { DIVEScene } from '../../../scene/Scene';
3
3
  import { DIVEAROptions } from '../../AR';
4
4
  import { DIVEARQuickLook } from '../ARQuickLook';
5
5
 
6
- jest.mock('../../../exporters/usdz/USDZExporter', () => {
6
+ jest.mock('../../../scene/Scene', () => {
7
7
  return {
8
- DIVEUSDZExporter: jest.fn().mockImplementation(() => {
9
- return {
10
- parse: jest.fn(() => {
11
- return Promise.resolve(new Uint8Array());
12
- }),
8
+ DIVEScene: jest.fn(function () {
9
+ this.add = jest.fn();
10
+ this.children = [];
11
+ this.Root = {
12
+ children: [],
13
13
  };
14
+ this.traverse = jest.fn((callback) => {
15
+ this.Root.children.forEach((child: Object3D) => {
16
+ callback(child);
17
+ });
18
+ });
19
+ return this;
14
20
  }),
15
21
  };
16
22
  });
@@ -26,10 +32,12 @@ describe('DIVEARQuickLook', () => {
26
32
  mockModels = [
27
33
  new Object3D(),
28
34
  new Object3D(),
35
+ new Object3D(),
29
36
  ];
30
- mockScene = {
31
- Root: new Object3D(),
32
- } as DIVEScene;
37
+ mockModels[1].userData = {
38
+ uri: 'https://example.com',
39
+ };
40
+ mockScene = new DIVEScene();
33
41
  mockOptions = {
34
42
  arPlacement: 'horizontal',
35
43
  arScale: 'auto',
@@ -41,88 +49,45 @@ describe('DIVEARQuickLook', () => {
41
49
  expect(DIVEARQuickLook.Launch).toBeInstanceOf(Function);
42
50
  });
43
51
 
44
- it('should return a promise', () => {
45
- expect(
46
- DIVEARQuickLook.Launch(mockScene, mockOptions),
47
- ).toBeInstanceOf(Promise);
48
- });
49
-
50
- it('should not throw when called without options', () => {
51
- const usdzParseSpy = jest.spyOn(
52
- DIVEARQuickLook['_usdzExporter'],
53
- 'parse',
54
- );
55
-
56
- expect(
57
- async () => await DIVEARQuickLook.Launch(mockScene),
58
- ).not.toThrow();
59
-
60
- expect(usdzParseSpy).toHaveBeenCalled();
61
- });
62
-
63
- it('should not throw when called with empty scene', () => {
64
- const usdzParseSpy = jest.spyOn(
65
- DIVEARQuickLook['_usdzExporter'],
66
- 'parse',
67
- );
68
-
69
- expect(
70
- async () =>
71
- await DIVEARQuickLook.Launch(mockScene, mockOptions),
72
- ).not.toThrow();
52
+ it('should not throw without options', () => {
53
+ mockScene.Root.children = mockModels;
73
54
 
74
- expect(usdzParseSpy).toHaveBeenCalled();
55
+ expect(() => {
56
+ DIVEARQuickLook.Launch(mockScene);
57
+ }).not.toThrow();
75
58
  });
76
59
 
77
- it('should not throw when called with filled scene', () => {
78
- const usdzParseSpy = jest.spyOn(
79
- DIVEARQuickLook['_usdzExporter'],
80
- 'parse',
81
- );
82
-
60
+ it('should not throw with options', () => {
83
61
  mockScene.Root.children = mockModels;
84
62
 
85
- expect(
86
- async () =>
87
- await DIVEARQuickLook.Launch(mockScene, mockOptions),
88
- ).not.toThrow();
89
-
90
- expect(usdzParseSpy).toHaveBeenCalled();
63
+ expect(() => {
64
+ DIVEARQuickLook.Launch(mockScene, mockOptions);
65
+ }).not.toThrow();
91
66
  });
92
67
 
93
- it('should pass options to exporter', async () => {
94
- const usdzParseSpy = jest.spyOn(
95
- DIVEARQuickLook['_usdzExporter'],
96
- 'parse',
97
- );
98
-
99
- mockOptions.arPlacement = 'vertical';
100
- mockOptions.arScale = 'fixed';
68
+ it('should not throw with alternated options', () => {
69
+ mockScene.Root.children = mockModels;
101
70
 
102
- await DIVEARQuickLook.Launch(mockScene, mockOptions);
71
+ mockOptions = {
72
+ arPlacement: 'vertical',
73
+ arScale: 'fixed',
74
+ } as DIVEAROptions;
103
75
 
104
- expect(usdzParseSpy).toHaveBeenCalledWith(expect.any(Object3D), {
105
- quickLookCompatible: true,
106
- ar: {
107
- anchoring: { type: 'plane' },
108
- planeAnchoring: {
109
- alignment: 'vertical',
110
- },
111
- },
112
- });
76
+ expect(() => {
77
+ DIVEARQuickLook.Launch(mockScene, mockOptions);
78
+ }).not.toThrow();
113
79
  });
114
80
 
115
- it('should reject when USDZExporter fails', async () => {
116
- const usdzParseSpy = jest.spyOn(
117
- DIVEARQuickLook['_usdzExporter'],
118
- 'parse',
119
- );
120
-
121
- usdzParseSpy.mockReturnValueOnce(Promise.reject());
81
+ it('should throw if no url is found', () => {
82
+ mockScene.Root.children = [
83
+ new Object3D(),
84
+ new Object3D(),
85
+ new Object3D(),
86
+ ];
122
87
 
123
- await expect(
124
- DIVEARQuickLook.Launch(mockScene, mockOptions),
125
- ).rejects.toBeUndefined();
88
+ expect(() => {
89
+ DIVEARQuickLook.Launch(mockScene, mockOptions);
90
+ }).toThrow();
126
91
  });
127
92
  });
128
93
  });
@@ -21,18 +21,6 @@ jest.mock('../../../scene/Scene', () => {
21
21
  };
22
22
  });
23
23
 
24
- jest.mock('../../../exporters/usdz/USDZExporter', () => {
25
- return {
26
- DIVEUSDZExporter: jest.fn().mockImplementation(() => {
27
- return {
28
- parse: jest.fn(() => {
29
- return Promise.resolve(new Uint8Array());
30
- }),
31
- };
32
- }),
33
- };
34
- });
35
-
36
24
  URL.createObjectURL = jest.fn(() => 'blob:http://localhost:8080/');
37
25
 
38
26
  describe('DIVESceneViewer', () => {
@@ -75,27 +75,51 @@ export class DIVECommunication {
75
75
  private toolbox: DIVEToolbox;
76
76
 
77
77
  private _mediaGenerator: DIVEMediaCreator | null;
78
- private get mediaGenerator(): DIVEMediaCreator {
78
+ private get mediaGenerator(): Promise<DIVEMediaCreator> {
79
79
  if (!this._mediaGenerator) {
80
- const DIVEMediaCreator = require('../mediacreator/MediaCreator.ts')
81
- .DIVEMediaCreator as typeof import('../mediacreator/MediaCreator.ts').DIVEMediaCreator;
82
- this._mediaGenerator = new DIVEMediaCreator(
83
- this.renderer,
84
- this.scene,
85
- this.controller,
86
- );
80
+ return new Promise((resolve, reject) => {
81
+ import('../mediacreator/MediaCreator.ts')
82
+ .then((module) => {
83
+ const DIVEMediaCreator = module.DIVEMediaCreator;
84
+ this._mediaGenerator = new DIVEMediaCreator(
85
+ this.renderer,
86
+ this.scene,
87
+ this.controller,
88
+ );
89
+ resolve(this._mediaGenerator);
90
+ })
91
+ .catch((error) => {
92
+ console.error(
93
+ 'DIVE: Error while lazy-loading IO module:',
94
+ error,
95
+ );
96
+ reject(error);
97
+ });
98
+ });
87
99
  }
88
- return this._mediaGenerator;
100
+ return Promise.resolve(this._mediaGenerator);
89
101
  }
90
102
 
91
103
  private _io: DIVEIO | null;
92
- private get io(): DIVEIO {
104
+ private get io(): Promise<DIVEIO> {
93
105
  if (!this._io) {
94
- const DIVEIO = require('../io/IO.ts')
95
- .DIVEIO as typeof import('../io/IO.ts').DIVEIO;
96
- this._io = new DIVEIO(this.scene);
106
+ return new Promise((resolve, reject) => {
107
+ import('../io/IO.ts')
108
+ .then((module) => {
109
+ const DIVEIO = module.DIVEIO;
110
+ this._io = new DIVEIO(this.scene);
111
+ resolve(this._io);
112
+ })
113
+ .catch((error) => {
114
+ console.error(
115
+ 'DIVE: Error while lazy-loading IO module:',
116
+ error,
117
+ );
118
+ reject(error);
119
+ });
120
+ });
97
121
  }
98
- return this._io;
122
+ return Promise.resolve(this._io);
99
123
  }
100
124
 
101
125
  private _ar: DIVEAR | null;
@@ -760,14 +784,14 @@ export class DIVECommunication {
760
784
  target = payload.target;
761
785
  }
762
786
 
763
- payload.dataUri = this.mediaGenerator.GenerateMedia(
764
- position,
765
- target,
766
- payload.width,
767
- payload.height,
768
- );
769
-
770
- return true;
787
+ return this.mediaGenerator.then((module) => {
788
+ return module.GenerateMedia(
789
+ position,
790
+ target,
791
+ payload.width,
792
+ payload.height,
793
+ );
794
+ });
771
795
  }
772
796
 
773
797
  private setParent(
@@ -833,7 +857,13 @@ export class DIVECommunication {
833
857
  private exportScene(
834
858
  payload: Actions['EXPORT_SCENE']['PAYLOAD'],
835
859
  ): Actions['EXPORT_SCENE']['RETURN'] {
836
- return this.io.Export(payload.type);
860
+ return new Promise<string | null>((resolve, reject) => {
861
+ this.io
862
+ .then((ioModule) => {
863
+ resolve(ioModule.Export(payload.type));
864
+ })
865
+ .catch(reject);
866
+ });
837
867
  }
838
868
  }
839
869
 
@@ -842,7 +842,14 @@ describe('dive/communication/DIVECommunication', () => {
842
842
  expect(success1).toBe(true);
843
843
  });
844
844
 
845
- it('should perform action GENERATE_MEDIA', () => {
845
+ it('should perform action GENERATE_MEDIA', async () => {
846
+ const blobUri = 'blob:http://localhost:3000/1234';
847
+ const mediaGeneratorModule = await testCom['mediaGenerator'];
848
+
849
+ jest.spyOn(mediaGeneratorModule, 'GenerateMedia').mockReturnValue(
850
+ blobUri,
851
+ );
852
+
846
853
  const mock1 = {
847
854
  entityType: 'pov',
848
855
  id: 'test1',
@@ -851,22 +858,22 @@ describe('dive/communication/DIVECommunication', () => {
851
858
  } as COMPov;
852
859
  testCom.PerformAction('ADD_OBJECT', mock1);
853
860
 
854
- const success0 = testCom.PerformAction('GENERATE_MEDIA', {
861
+ const success0 = await testCom.PerformAction('GENERATE_MEDIA', {
855
862
  id: 'test1',
856
863
  width: 800,
857
864
  height: 600,
858
- dataUri: '',
859
865
  });
860
- expect(success0).toBe(true);
866
+ expect(success0).toBe(blobUri);
861
867
 
862
- const success1 = testCom.PerformAction('GENERATE_MEDIA', {
868
+ const success1 = await testCom.PerformAction('GENERATE_MEDIA', {
863
869
  position: { x: 0, y: 0, z: 0 },
864
870
  target: { x: 0, y: 0, z: 0 },
865
871
  width: 800,
866
872
  height: 600,
867
- dataUri: '',
868
873
  });
869
- expect(success1).toBe(true);
874
+ expect(success1).toBe(blobUri);
875
+
876
+ jest.restoreAllMocks();
870
877
  });
871
878
 
872
879
  it('should perform action SET_PARENT', () => {
@@ -955,8 +962,9 @@ describe('dive/communication/DIVECommunication', () => {
955
962
 
956
963
  it('should perform action EXPORT_SCENE', async () => {
957
964
  const url = 'https://example.com';
965
+ const ioModule = await testCom['io'];
958
966
 
959
- jest.spyOn(testCom['io'], 'Export').mockResolvedValueOnce(url);
967
+ jest.spyOn(ioModule, 'Export').mockResolvedValueOnce(url);
960
968
 
961
969
  const result = await testCom.PerformAction('EXPORT_SCENE', {
962
970
  type: 'glb',
@@ -1,7 +1,7 @@
1
1
  import { Vector3Like } from 'three';
2
2
 
3
3
  export default interface GENERATE_MEDIA {
4
- DESCRIPTION: 'Generates a screenshot, stores it in a Blob and writes the URL into the payload.';
4
+ DESCRIPTION: 'Generates a screenshot, stores it in a Blob and returns a Promise of a valid URI.';
5
5
  PAYLOAD: (
6
6
  | {
7
7
  position: Vector3Like;
@@ -13,7 +13,6 @@ export default interface GENERATE_MEDIA {
13
13
  ) & {
14
14
  width: number; // image width in pixels
15
15
  height: number; // image height in pixels
16
- dataUri: string;
17
16
  };
18
- RETURN: boolean;
17
+ RETURN: Promise<string>;
19
18
  }