Repository: vue-gl/vue-gl
Pull request #1048 (2020-10-22 06:15:54)

Tag name of components
* VglNamespace accepts the `tag` prop that determines what element should be rendered as real dom.
* Invisible components rendered as template elements.


Patch:
diff --git a/src/core/vgl-geometry.js b/src/core/vgl-geometry.js
index fb323c9..19968e4 100644
--- a/src/core/vgl-geometry.js
+++ b/src/core/vgl-geometry.js
@@ -122,7 +122,6 @@ export default {
     },
   },
   render(h) {
-    if (!this.$slots.default) return undefined;
-    return h('div', { style: { display: 'none' } }, this.$slots.default);
+    return this.$slots.default ? h('template', this.$slots.default) : undefined;
   },
 };
diff --git a/src/core/vgl-namespace.js b/src/core/vgl-namespace.js
index d12d5bd..86e9875 100644
--- a/src/core/vgl-namespace.js
+++ b/src/core/vgl-namespace.js
@@ -1,4 +1,5 @@
 import Namespace from './namespace';
+import { string } from '../types';
 
 /**
  * This component provides maps for managing objects by name (string), and also provides utility
@@ -34,6 +35,10 @@ import Namespace from './namespace';
  */
 
 export default {
+  props: {
+    /** What element should be rendered. */
+    tag: { type: string, default: 'div' },
+  },
   inject: {
     vglNamespace: {
       default: () => ({ cameras: new Namespace(), scenes: new Namespace() }),
@@ -64,6 +69,6 @@ export default {
     if (curves) curves.destroy();
   },
   render(h) {
-    return this.$slots.default ? h('div', this.$slots.default) : undefined;
+    return h(this.tag, this.$slots.default);
   },
 };
diff --git a/src/core/vgl-object3d.js b/src/core/vgl-object3d.js
index c428583..024668f 100644
--- a/src/core/vgl-object3d.js
+++ b/src/core/vgl-object3d.js
@@ -137,7 +137,6 @@ export default {
     },
   },
   render(h) {
-    if (!this.$slots.default) return undefined;
-    return h('div', { style: { display: 'none' } }, this.$slots.default);
+    return this.$slots.default ? h('template', this.$slots.default) : undefined;
   },
 };
diff --git a/src/extras/vgl-curve.js b/src/extras/vgl-curve.js
index e48f602..7ee889f 100644
--- a/src/extras/vgl-curve.js
+++ b/src/extras/vgl-curve.js
@@ -34,7 +34,6 @@ export default {
     },
   },
   render(h) {
-    if (!this.$slots.default) return undefined;
-    return h('div', { style: { display: 'none' } }, this.$slots.default);
+    return this.$slots.default ? h('template', this.$slots.default) : undefined;
   },
 };
diff --git a/src/materials/vgl-material.js b/src/materials/vgl-material.js
index ea3d2d2..914ee18 100644
--- a/src/materials/vgl-material.js
+++ b/src/materials/vgl-material.js
@@ -70,7 +70,6 @@ export default {
     if (this.name !== undefined) this.vglNamespace.materials.delete(this.name, this.inst);
   },
   render(h) {
-    if (!this.$slots.default) return undefined;
-    return h('div', { style: { display: 'none' } }, this.$slots.default);
+    return this.$slots.default ? h('template', this.$slots.default) : undefined;
   },
 };
diff --git a/src/textures/vgl-texture.js b/src/textures/vgl-texture.js
index f2a4fb2..3b3b070 100644
--- a/src/textures/vgl-texture.js
+++ b/src/textures/vgl-texture.js
@@ -220,7 +220,6 @@ export default {
     },
   },
   render(h) {
-    if (!this.$slots.default) return undefined;
-    return h('div', { style: { display: 'none' } }, this.$slots.default);
+    return this.$slots.default ? h('template', this.$slots.default) : undefined;
   },
 };


Test patch:
diff --git a/test/core/vgl-geometry.spec.js b/test/core/vgl-geometry.spec.js
index d854dac..880e811 100644
--- a/test/core/vgl-geometry.spec.js
+++ b/test/core/vgl-geometry.spec.js
@@ -113,4 +113,19 @@ describe('VglGeometry', () => {
       expect(vm.inst).toHaveProperty('attributes', expected.attributes);
     });
   });
+  describe('rendered real DOM', () => {
+    test('is nothing when the component has no children', () => {
+      const vm = new (Vue.extend(VglGeometry))({ inject }).$mount();
+      expect(vm.$el).toBeInstanceOf(Comment);
+    });
+    test('is template element when the component has children', () => {
+      const vm = new Vue({
+        components: { VglGeometry, VglNamespace },
+        render(h) {
+          return h('vgl-namespace', [h('vgl-geometry', { ref: 'examin' }, ['child text'])]);
+        },
+      }).$mount();
+      expect(vm.$refs.examin.$el.tagName.toLowerCase()).toBe('template');
+    });
+  });
 });
diff --git a/test/core/vgl-namespace.spec.js b/test/core/vgl-namespace.spec.js
new file mode 100644
index 0000000..bd17e65
--- /dev/null
+++ b/test/core/vgl-namespace.spec.js
@@ -0,0 +1,13 @@
+import Vue from 'vue/dist/vue';
+import { VglNamespace } from '../../src';
+
+describe('VglNamespace', () => {
+  test('renders a element specified by tag prop', () => {
+    const vm = new (Vue.extend(VglNamespace))({ propsData: { tag: 'p' } }).$mount();
+    expect(vm.$el.tagName.toLowerCase()).toBe('p');
+  });
+  test('renders a div element by default', () => {
+    const vm = new Vue(VglNamespace).$mount();
+    expect(vm.$el.tagName.toLowerCase()).toBe('div');
+  });
+});
diff --git a/test/core/vgl-object3d.spec.js b/test/core/vgl-object3d.spec.js
index 7fd4054..e435c74 100644
--- a/test/core/vgl-object3d.spec.js
+++ b/test/core/vgl-object3d.spec.js
@@ -142,4 +142,19 @@ describe('VglObject3d', () => {
     await vm.$nextTick();
     expect(vm.inst.name).toBe('newName');
   });
+  describe('rendered real DOM', () => {
+    test('is nothing when the component has no children', () => {
+      const vm = new (Vue.extend(VglObject3d))({ inject }).$mount();
+      expect(vm.$el).toBeInstanceOf(Comment);
+    });
+    test('is template element when the component has children', () => {
+      const vm = new Vue({
+        components: { VglObject3d, VglNamespace },
+        render(h) {
+          return h('vgl-namespace', [h('vgl-object3d', { ref: 'examin' }, ['child text'])]);
+        },
+      }).$mount();
+      expect(vm.$refs.examin.$el.tagName.toLowerCase()).toBe('template');
+    });
+  });
 });
diff --git a/test/extras/vgl-shape.spec.js b/test/extras/vgl-shape.spec.js
index eefedce..a9d1eaf 100644
--- a/test/extras/vgl-shape.spec.js
+++ b/test/extras/vgl-shape.spec.js
@@ -56,4 +56,19 @@ describe('VglShape', () => {
     delete expected.uuid;
     expect(inst).toStrictEqual(expected);
   });
+  describe('rendered real DOM', () => {
+    test('is nothing when the component has no children', () => {
+      const vm = new (Vue.extend(VglShape))({ inject }).$mount();
+      expect(vm.$el).toBeInstanceOf(Comment);
+    });
+    test('is template element when the component has children', () => {
+      const vm = new Vue({
+        components: { VglShape, VglNamespace },
+        render(h) {
+          return h('vgl-namespace', [h('vgl-shape', { ref: 'examin' }, ['child text'])]);
+        },
+      }).$mount();
+      expect(vm.$refs.examin.$el.tagName.toLowerCase()).toBe('template');
+    });
+  });
 });
diff --git a/test/materials/vgl-material.spec.js b/test/materials/vgl-material.spec.js
index 6da22c0..83ac770 100644
--- a/test/materials/vgl-material.spec.js
+++ b/test/materials/vgl-material.spec.js
@@ -38,4 +38,19 @@ describe('VglMaterial', () => {
     expect(inst).toHaveProperty('vertexColors', vertexColors);
     expect(inst).toHaveProperty('side', side);
   });
+  describe('rendered real DOM', () => {
+    test('is nothing when the component has no children', () => {
+      const vm = new (Vue.extend(VglMaterial))({ inject }).$mount();
+      expect(vm.$el).toBeInstanceOf(Comment);
+    });
+    test('is template element when the component has children', () => {
+      const vm = new Vue({
+        components: { VglMaterial, VglNamespace },
+        render(h) {
+          return h('vgl-namespace', [h('vgl-material', { ref: 'examin' }, ['child text'])]);
+        },
+      }).$mount();
+      expect(vm.$refs.examin.$el.tagName.toLowerCase()).toBe('template');
+    });
+  });
 });
diff --git a/test/textures/vgl-texture.spec.js b/test/textures/vgl-texture.spec.js
index f3a497f..3b02b0b 100644
--- a/test/textures/vgl-texture.spec.js
+++ b/test/textures/vgl-texture.spec.js
@@ -230,4 +230,19 @@ describe('VglTexture', () => {
     expect(inst.center).toHaveProperty('x', center.x);
     expect(inst.center).toHaveProperty('y', center.y);
   });
+  describe('rendered real DOM', () => {
+    test('is nothing when the component has no children', () => {
+      const vm = new (Vue.extend(VglTexture))({ inject }).$mount();
+      expect(vm.$el).toBeInstanceOf(Comment);
+    });
+    test('is template element when the component has children', () => {
+      const vm = new Vue({
+        components: { VglTexture, VglNamespace },
+        render(h) {
+          return h('vgl-namespace', [h('vgl-texture', { ref: 'examin' }, ['child text'])]);
+        },
+      }).$mount();
+      expect(vm.$refs.examin.$el.tagName.toLowerCase()).toBe('template');
+    });
+  });
 });