瀏覽代碼

[ui] Vue 3 - Migrated Tabs component

sreenaths 4 年之前
父節點
當前提交
16389fa57b

+ 8 - 6
desktop/core/src/desktop/js/components/Tab.test.ts

@@ -22,12 +22,14 @@ describe('Tab.vue', () => {
     let reportedTab: Tab | undefined;
     let reportedTab: Tab | undefined;
     const wrapper = shallowMount(Tab, {
     const wrapper = shallowMount(Tab, {
       propsData: { title: 'Tab title' },
       propsData: { title: 'Tab title' },
-      provide: {
-        addTab: (tab: Tab): void => {
-          reportedTab = tab;
-        },
-        removeTab: () => {
-          // Empty
+      global: {
+        provide: {
+          addTab: (tab: Tab): void => {
+            reportedTab = tab;
+          },
+          removeTab: () => {
+            // Empty
+          }
         }
         }
       },
       },
       slots: {
       slots: {

+ 43 - 24
desktop/core/src/desktop/js/components/Tab.vue

@@ -17,16 +17,20 @@
 -->
 -->
 
 
 <template>
 <template>
-  <div v-if="!lazy || rendered" v-show="isActive">
+  <div v-if="!lazy || rendered" v-show="def.isActive">
     <slot />
     <slot />
   </div>
   </div>
 </template>
 </template>
 
 
 <script lang="ts">
 <script lang="ts">
-  import { defineComponent, inject, Component } from 'vue';
+  import { defineComponent, inject } from 'vue';
 
 
-  const Tab:Component = defineComponent({
-    name: 'Tab',
+  export interface TabRef {
+    title: string;
+    isActive: boolean;
+  }
+
+  export default defineComponent({
     props: {
     props: {
       title: {
       title: {
         type: String,
         type: String,
@@ -38,44 +42,59 @@
       }
       }
     },
     },
 
 
-    setup(): {
-      addTab?: (tab: typeof Tab) => void,
-      removeTab?: (tab: typeof Tab) => void,
+    setup(
+      props
+    ): {
+      addTab?: (tab: TabRef) => void;
+      removeTab?: (tab: TabRef) => void;
 
 
-        isActive: boolean,
-        rendered: boolean
+      def: TabRef;
     } {
     } {
       return {
       return {
         addTab: inject('addTab'),
         addTab: inject('addTab'),
         removeTab: inject('removeTab'),
         removeTab: inject('removeTab'),
 
 
-        isActive: false,
+        def: {
+          title: props.title,
+          isActive: false
+        }
+      };
+    },
+
+    data(): {
+      rendered: boolean;
+    } {
+      return {
         rendered: false
         rendered: false
       };
       };
     },
     },
 
 
-    watch: {
-      isActive(): void {
-        if (this.isActive) {
-          this.rendered = true;
+    created() {
+      this.$watch(
+        (): boolean => this.def.isActive,
+        (isActive: boolean): void => {
+          if (isActive) {
+            this.rendered = true;
+          }
         }
         }
-      }
+      );
     },
     },
 
 
     mounted(): void {
     mounted(): void {
       if (this.addTab) {
       if (this.addTab) {
-        this.addTab(this);
-      }
-    },
-
-    destroyed(): void {
-      if (this.removeTab) {
-        this.removeTab(this);
+        this.addTab(this.def);
       }
       }
     }
     }
-  })
 
 
-  export default Tab;
+    // TODO
+    // destroyed(): was deprecated, need to rearchitect the component.
+    // Whenever parent is rendered mount, unmount is called causing an to prevent infinit loop.
+    // unmounted(): void {
+    //   if (this.removeTab) {
+    //     this.removeTab(this.def);
+    //   }
+    // }
+  });
 </script>
 </script>
 
 
 <style lang="scss" scoped></style>
 <style lang="scss" scoped></style>

+ 7 - 4
desktop/core/src/desktop/js/components/Tabs.test.ts

@@ -14,7 +14,7 @@
 // See the License for the specific language governing permissions and
 // See the License for the specific language governing permissions and
 // limitations under the License.
 // limitations under the License.
 
 
-import Vue from 'vue';
+import { nextTick } from 'vue';
 import { mount, shallowMount } from '@vue/test-utils';
 import { mount, shallowMount } from '@vue/test-utils';
 import Tabs from './Tabs.vue';
 import Tabs from './Tabs.vue';
 import Tab from './Tab.vue';
 import Tab from './Tab.vue';
@@ -30,11 +30,14 @@ describe('Tabs.vue', () => {
       slots: {
       slots: {
         default: '<tab title="foo">foo</tab><tab title="bar">bar</tab>'
         default: '<tab title="foo">foo</tab><tab title="bar">bar</tab>'
       },
       },
-      stubs: {
-        tab: Tab
+      global: {
+        stubs: {
+          tab: Tab
+        }
       }
       }
     });
     });
-    await Vue.nextTick();
+
+    await nextTick();
     expect(wrapper.element).toMatchSnapshot();
     expect(wrapper.element).toMatchSnapshot();
   });
   });
 });
 });

+ 41 - 29
desktop/core/src/desktop/js/components/Tabs.vue

@@ -35,40 +35,52 @@
 </template>
 </template>
 
 
 <script lang="ts">
 <script lang="ts">
-  import Vue from 'vue';
-  import Component from 'vue-class-component';
-  import { Provide } from 'vue-property-decorator';
-  import Tab from './Tab.vue';
+  import { defineComponent } from 'vue';
 
 
-  @Component
-  export default class Tabs extends Vue {
-    tabs: Tab[] = [];
+  import { TabRef } from './Tab.vue';
 
 
-    @Provide()
-    addTab(tab: Tab): void {
-      this.tabs.push(tab);
-      if (this.tabs.length === 1) {
-        this.selectTab(this.tabs[0]);
-      }
-    }
-
-    @Provide()
-    removeTab(tab: Tab): void {
-      const index = this.tabs.indexOf(tab);
-      if (index !== -1) {
-        this.$delete(this.tabs, index);
-        if (tab.isActive && this.tabs.length) {
-          this.tabs[Math.max(0, index - 1)].isActive = true;
+  export default defineComponent({
+    provide(): {
+      addTab: (tab: TabRef) => void;
+      removeTab: (tab: TabRef) => void;
+    } {
+      return {
+        addTab: (tab: TabRef): void => {
+          if (!this.tabs.find(t => t.title === tab.title)) {
+            this.tabs.push(tab);
+            if (this.tabs.length === 1) {
+              this.selectTab(this.tabs[0]);
+            }
+          }
+        },
+        removeTab: (tab: TabRef): void => {
+          const index = this.tabs.indexOf(tab);
+          if (index !== -1) {
+            this.tabs.splice(index, 1);
+            if (tab.isActive && this.tabs.length) {
+              this.tabs[Math.max(0, index - 1)].isActive = true;
+            }
+          }
         }
         }
-      }
-    }
+      };
+    },
+
+    data(): {
+      tabs: TabRef[];
+    } {
+      return {
+        tabs: []
+      };
+    },
 
 
-    selectTab(tab: Tab): void {
-      this.tabs.forEach(other => {
-        other.isActive = other === tab;
-      });
+    methods: {
+      selectTab(tab: TabRef): void {
+        this.tabs.forEach(other => {
+          other.isActive = other === tab;
+        });
+      }
     }
     }
-  }
+  });
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>

+ 3 - 3
desktop/core/src/desktop/js/components/__snapshots__/Tab.test.ts.snap

@@ -4,8 +4,8 @@ exports[`Tab.vue should render 1`] = `
 <div
 <div
   style="display: none;"
   style="display: none;"
 >
 >
-  <div>
-    Some tab content
-  </div>
+  
+  <stub />
+  
 </div>
 </div>
 `;
 `;

+ 19 - 9
desktop/core/src/desktop/js/components/__snapshots__/Tabs.test.ts.snap

@@ -4,11 +4,16 @@ exports[`Tabs.vue should render empty tabs 1`] = `
 <div
 <div
   class="hue-tabs"
   class="hue-tabs"
 >
 >
-  <ul />
-   
+  <ul>
+    
+    
+  </ul>
   <div
   <div
     class="hue-tab-container"
     class="hue-tab-container"
-  />
+  >
+    
+    
+  </div>
 </div>
 </div>
 `;
 `;
 
 
@@ -17,35 +22,40 @@ exports[`Tabs.vue should render tabs 1`] = `
   class="hue-tabs"
   class="hue-tabs"
 >
 >
   <ul>
   <ul>
+    
     <li
     <li
       class="active"
       class="active"
     >
     >
-      
       foo
       foo
-    
     </li>
     </li>
     <li
     <li
       class=""
       class=""
     >
     >
-      
       bar
       bar
-    
     </li>
     </li>
+    
   </ul>
   </ul>
-   
   <div
   <div
     class="hue-tab-container"
     class="hue-tab-container"
   >
   >
+    
+    
     <div
     <div
-      style=""
+      style="display: none;"
     >
     >
+      
       foo
       foo
+      
     </div>
     </div>
     <div
     <div
       style="display: none;"
       style="display: none;"
     >
     >
+      
       bar
       bar
+      
     </div>
     </div>
+    
+    
   </div>
   </div>
 </div>
 </div>
 `;
 `;