From 44c9495469b99d49343f0a20ecf30d406d76e844 Mon Sep 17 00:00:00 2001 From: haoziqaq <357229046@qq.com> Date: Thu, 31 Dec 2020 11:34:57 +0800 Subject: [PATCH] =?UTF-8?q?fix(cli=20ui/tabs=20ui/tab):=20cli=E4=BF=AE?= =?UTF-8?q?=E8=AE=A2=E4=BE=9D=E8=B5=96=E7=89=88=E6=9C=AC=20tabs=20tab?= =?UTF-8?q?=E9=80=9A=E4=BF=A1=E5=AE=8C=E6=88=90=20=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E6=95=88=E6=9E=9C=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit affects: @varlet/cli, @varlet/ui --- .gitignore | 6 +- package.json | 1 - packages/varlet-cli/lib/index.js | 23 +++ packages/varlet-cli/package.json | 1 + .../varlet-cli/src/compiler/compileModule.ts | 2 +- .../varlet-ui/src/sticky/example/index.vue | 2 +- packages/varlet-ui/src/tab/Tab.vue | 65 +++++++ .../varlet-ui/src/tab/__tests__/index.spec.js | 7 + packages/varlet-ui/src/tab/docs/en_US.md | 0 packages/varlet-ui/src/tab/docs/zh_CN.md | 0 packages/varlet-ui/src/tab/example/index.vue | 21 +++ packages/varlet-ui/src/tab/index.ts | 8 + packages/varlet-ui/src/tab/props.ts | 11 ++ packages/varlet-ui/src/tab/tab.less | 16 ++ packages/varlet-ui/src/tabs/Tabs.vue | 70 +++++++- packages/varlet-ui/src/tabs/example/index.vue | 36 +++- packages/varlet-ui/src/tabs/props.ts | 29 +++ packages/varlet-ui/src/tabs/tabs.less | 24 +++ packages/varlet-ui/src/utils/components.ts | 167 ++++++++++++++---- packages/varlet-ui/src/utils/elements.ts | 6 +- packages/varlet-ui/src/utils/shared.ts | 4 - yarn.lock | 8 +- 22 files changed, 449 insertions(+), 58 deletions(-) create mode 100644 packages/varlet-cli/lib/index.js create mode 100644 packages/varlet-ui/src/tab/Tab.vue create mode 100644 packages/varlet-ui/src/tab/__tests__/index.spec.js create mode 100644 packages/varlet-ui/src/tab/docs/en_US.md create mode 100644 packages/varlet-ui/src/tab/docs/zh_CN.md create mode 100644 packages/varlet-ui/src/tab/example/index.vue create mode 100644 packages/varlet-ui/src/tab/index.ts create mode 100644 packages/varlet-ui/src/tab/props.ts create mode 100644 packages/varlet-ui/src/tab/tab.less create mode 100644 packages/varlet-ui/src/tabs/props.ts create mode 100644 packages/varlet-ui/src/tabs/tabs.less diff --git a/.gitignore b/.gitignore index b5569e98e6f..d3f457976a5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,11 @@ node_modules *.log .DS_Store -packages/varlet-cli/lib +packages/varlet-cli/lib/commands +packages/varlet-cli/lib/compiler +packages/varlet-cli/lib/config +packages/varlet-cli/lib/shared +packages/varlet-cli/lib/index.d.ts packages/varlet-cli/site/mobile/routes.ts packages/varlet-cli/site/pc/routes.ts diff --git a/package.json b/package.json index bb569b32497..7eca771daf5 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,6 @@ "lint-staged": "^10.5.0", "prettier": "^2.1.2", "stylelint": "^13.7.2", - "typescript": "^4.0.5", "vue": "3.0.2" } } diff --git a/packages/varlet-cli/lib/index.js b/packages/varlet-cli/lib/index.js new file mode 100644 index 00000000000..46de7cf7f13 --- /dev/null +++ b/packages/varlet-cli/lib/index.js @@ -0,0 +1,23 @@ +#!/usr/bin/env node +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +var commander_1 = require('commander') +var dev_1 = require('./commands/dev') +var build_1 = require('./commands/build') +var compile_1 = require('./commands/compile') +var create_1 = require('./commands/create') +var jest_1 = require('./commands/jest') +commander_1.command('dev').description('Run varlet development environment').action(dev_1.dev) +commander_1.command('build').description('Build varlet site for production').action(build_1.build) +commander_1 + .command('compile') + .description('Compile varlet components library code') + .option('-w, --watch', 'Watch files change auto compile') + .action(compile_1.compile) +commander_1.command('create ').description('Create a component directory').action(create_1.create) +commander_1 + .command('jest') + .option('-c, --component [componentName]', 'Run Jest in component directory') + .description('Run Jest in work directory') + .action(jest_1.jest) +commander_1.parse() diff --git a/packages/varlet-cli/package.json b/packages/varlet-cli/package.json index 0de36a53a86..0a3b46483e3 100644 --- a/packages/varlet-cli/package.json +++ b/packages/varlet-cli/package.json @@ -61,6 +61,7 @@ "slash": "^3.0.0", "style-loader": "^2.0.0", "ts-loader": "^8.0.7", + "typescript": "^4.1.3", "url-loader": "^4.1.1", "vue-loader": "^16.0.0-beta.9", "vue-router": "4.0.0-rc.1", diff --git a/packages/varlet-cli/src/compiler/compileModule.ts b/packages/varlet-cli/src/compiler/compileModule.ts index 53d94aa09fa..54b95d4a52a 100644 --- a/packages/varlet-cli/src/compiler/compileModule.ts +++ b/packages/varlet-cli/src/compiler/compileModule.ts @@ -11,7 +11,7 @@ import webpack, { Stats } from 'webpack' import logger from '../shared/logger' export function compileUMD() { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { setProd() const config = getUmdConfig() diff --git a/packages/varlet-ui/src/sticky/example/index.vue b/packages/varlet-ui/src/sticky/example/index.vue index e138845ce7b..06867db19f1 100644 --- a/packages/varlet-ui/src/sticky/example/index.vue +++ b/packages/varlet-ui/src/sticky/example/index.vue @@ -30,7 +30,7 @@ export default defineComponent({ }, setup() { return { - handleScroll(top, isFixed) { + handleScroll(top: number, isFixed: boolean) { console.log(top) console.log(isFixed) }, diff --git a/packages/varlet-ui/src/tab/Tab.vue b/packages/varlet-ui/src/tab/Tab.vue new file mode 100644 index 00000000000..e121bcc0981 --- /dev/null +++ b/packages/varlet-ui/src/tab/Tab.vue @@ -0,0 +1,65 @@ + + + + + diff --git a/packages/varlet-ui/src/tab/__tests__/index.spec.js b/packages/varlet-ui/src/tab/__tests__/index.spec.js new file mode 100644 index 00000000000..7c80586f717 --- /dev/null +++ b/packages/varlet-ui/src/tab/__tests__/index.spec.js @@ -0,0 +1,7 @@ +const Tab = require('../../../cjs/tab').default +const { render } = require('@testing-library/vue') + +test('test tab', async () => { + const wrapper = render(Tab) + console.log(wrapper) +}) diff --git a/packages/varlet-ui/src/tab/docs/en_US.md b/packages/varlet-ui/src/tab/docs/en_US.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/varlet-ui/src/tab/docs/zh_CN.md b/packages/varlet-ui/src/tab/docs/zh_CN.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/varlet-ui/src/tab/example/index.vue b/packages/varlet-ui/src/tab/example/index.vue new file mode 100644 index 00000000000..ce3e25af84b --- /dev/null +++ b/packages/varlet-ui/src/tab/example/index.vue @@ -0,0 +1,21 @@ + + + + + diff --git a/packages/varlet-ui/src/tab/index.ts b/packages/varlet-ui/src/tab/index.ts new file mode 100644 index 00000000000..7d02e86b251 --- /dev/null +++ b/packages/varlet-ui/src/tab/index.ts @@ -0,0 +1,8 @@ +import { App } from 'vue' +import Tab from './Tab.vue' + +Tab.install = function (app: App) { + app.component(Tab.name, Tab) +} + +export default Tab diff --git a/packages/varlet-ui/src/tab/props.ts b/packages/varlet-ui/src/tab/props.ts new file mode 100644 index 00000000000..dd8564bfd40 --- /dev/null +++ b/packages/varlet-ui/src/tab/props.ts @@ -0,0 +1,11 @@ +export const props = { + name: { + type: [String, Number], + }, + title: { + type: String, + }, + onClick: { + type: Function, + }, +} diff --git a/packages/varlet-ui/src/tab/tab.less b/packages/varlet-ui/src/tab/tab.less new file mode 100644 index 00000000000..be661114854 --- /dev/null +++ b/packages/varlet-ui/src/tab/tab.less @@ -0,0 +1,16 @@ +@import "../styles/var"; + +@tab-color: #fff; +@tab-padding: 4px; + +.var-tab { + height: 100%; + display: flex; + justify-content: center; + align-items: center; + flex: 1 0 auto; + padding: 0 @tab-padding; + font-size: @font-size-md; + background: @color-primary; + color: @tab-color; +} diff --git a/packages/varlet-ui/src/tabs/Tabs.vue b/packages/varlet-ui/src/tabs/Tabs.vue index 1e985d9ab99..b6785d27b06 100644 --- a/packages/varlet-ui/src/tabs/Tabs.vue +++ b/packages/varlet-ui/src/tabs/Tabs.vue @@ -1,17 +1,77 @@ diff --git a/packages/varlet-ui/src/tabs/example/index.vue b/packages/varlet-ui/src/tabs/example/index.vue index 56cec3e2611..f98e48f9277 100644 --- a/packages/varlet-ui/src/tabs/example/index.vue +++ b/packages/varlet-ui/src/tabs/example/index.vue @@ -1,21 +1,51 @@ - diff --git a/packages/varlet-ui/src/tabs/props.ts b/packages/varlet-ui/src/tabs/props.ts new file mode 100644 index 00000000000..8563f495931 --- /dev/null +++ b/packages/varlet-ui/src/tabs/props.ts @@ -0,0 +1,29 @@ +import { ComputedRef } from 'vue' + +export interface TabMessage { + name: string | number | undefined + index: ComputedRef + element: HTMLElement | null +} + +export interface TabsController { + receiveTabMessage(tabMessage: TabMessage): void + clearTabMessage(tabMessage: TabMessage): void + onTabClick(tabMessage: TabMessage): void +} + +export const TABS_CONTROLLER_KEY = Symbol('TABS_CONTROLLER_KEY') +export const TAB_COUNTER_KEY = Symbol('TAB_COUNTER_KEY') + +export const props = { + active: { + type: [String, Number], + default: 0, + }, + 'onUpdate:active': { + type: Function, + }, + onChange: { + type: Function, + }, +} diff --git a/packages/varlet-ui/src/tabs/tabs.less b/packages/varlet-ui/src/tabs/tabs.less new file mode 100644 index 00000000000..861236bc3c9 --- /dev/null +++ b/packages/varlet-ui/src/tabs/tabs.less @@ -0,0 +1,24 @@ +@tabs-width: 100%; +@tabs-height: 44px; +@tabs-radius: 2px; +@tabs-indicator-height: 2px; +@tabs-indicator-background-color: #fff; + +.var-tabs { + position: relative; + display: flex; + width: @tabs-width; + height: @tabs-height; + border-radius: @tabs-radius; + overflow-x: auto; + + &__indicator { + position: absolute; + z-index: 10; + left: 0; + bottom: 0; + height: 2px; + background-color: #fff; + transition: transform .3s; + } +} diff --git a/packages/varlet-ui/src/utils/components.ts b/packages/varlet-ui/src/utils/components.ts index 3b88d55ecb6..3f9e775cc7a 100644 --- a/packages/varlet-ui/src/utils/components.ts +++ b/packages/varlet-ui/src/utils/components.ts @@ -1,51 +1,150 @@ -import { createApp, Component, h } from 'vue' +import { + createApp, + Component, + h, + getCurrentInstance, + inject, + onUnmounted, + computed, + provide, + reactive, + VNodeNormalizedChildren, + VNode, + isVNode, + ComponentInternalInstance, + ComputedRef, + onUpdated, + onMounted, +} from 'vue' +import { removeItem } from './shared' export interface MountInstance { - instance: any, - unmount: () => void + instance: any + unmount: () => void +} + +export interface ChildrenCounter { + collect(instance: ComponentInternalInstance): void + clear(instance: ComponentInternalInstance): void + instances: ComponentInternalInstance[] } export function pickProps(props: any, propsKey: string): any export function pickProps(props: any, propsKey: string[]): any export function pickProps(props: any, propsKey: any): any { - return Array.isArray(propsKey) - ? propsKey.reduce((pickedProps: any, key) => { - pickedProps[key] = props[key] - return pickedProps - }, {}) - : props[propsKey] + return Array.isArray(propsKey) + ? propsKey.reduce((pickedProps: any, key) => { + pickedProps[key] = props[key] + return pickedProps + }, {}) + : props[propsKey] } export function mount(component: Component): MountInstance { - const app = createApp(component) - const host = document.createElement('div') - document.body.appendChild(host) + const app = createApp(component) + const host = document.createElement('div') + document.body.appendChild(host) - return { - instance: app.mount(host), - unmount() { - app.unmount(host) - document.body.removeChild(host) - } - } + return { + instance: app.mount(host), + unmount() { + app.unmount(host) + document.body.removeChild(host) + }, + } } export function mountInstance( - component: any, - props: Record = {}, - eventListener: Record = {} + component: any, + props: Record = {}, + eventListener: Record = {} ): { - unmountInstance: () => void + unmountInstance: () => void } { - const Host = { - setup() { - return () => h(component, { - ...props, - ...eventListener - }) - } - } - - const { unmount } = mount(Host) - return { unmountInstance: unmount } + const Host = { + setup() { + return () => + h(component, { + ...props, + ...eventListener, + }) + }, + } + + const { unmount } = mount(Host) + return { unmountInstance: unmount } +} + +export function flatVNodes(children: VNodeNormalizedChildren) { + const vNodes: VNode[] = [] + + const flat = (children: VNodeNormalizedChildren) => { + if (Array.isArray(children)) { + children.forEach((child) => { + if (isVNode(child)) { + vNodes.push(child) + + if (child.component?.subTree) { + flat(child.component.subTree.children) + } + + if (child.children) { + flat(child.children) + } + } + }) + } + } + + flat(children) + + return vNodes +} + +export function countChildren(key: symbol) { + const instances: ComponentInternalInstance[] = reactive([]) + const parentInstance: ComponentInternalInstance = getCurrentInstance() as ComponentInternalInstance + + const sortInstances = () => { + const vNodes = flatVNodes(parentInstance.subTree?.children) + instances.sort((a, b) => { + return vNodes.indexOf(a.vnode) - vNodes.indexOf(b.vnode) + }) + } + + onMounted(() => { + sortInstances() + }) + onUpdated(() => { + sortInstances() + }) + + provide(key, { + collect(instance: ComponentInternalInstance) { + instances.push(instance) + }, + clear(instance: ComponentInternalInstance) { + removeItem(instances, instance) + }, + instances, + }) +} + +export function useAtParentIndex(key: symbol): ComputedRef | never { + const childrenCounter: ChildrenCounter | undefined = inject(key) + if (!childrenCounter) { + throw new Error('Children counter provider not found') + } + + const { collect, clear, instances } = childrenCounter + + const instance: ComponentInternalInstance = getCurrentInstance() as ComponentInternalInstance + + collect(instance) + + onUnmounted(() => { + clear(instance) + }) + + return computed(() => instances.indexOf(instance)) } diff --git a/packages/varlet-ui/src/utils/elements.ts b/packages/varlet-ui/src/utils/elements.ts index ee7f91eca94..28136672782 100644 --- a/packages/varlet-ui/src/utils/elements.ts +++ b/packages/varlet-ui/src/utils/elements.ts @@ -1,5 +1,3 @@ -import { isUndef } from './shared' - export function getTop(element: HTMLElement): number { const { top } = element.getBoundingClientRect() @@ -37,8 +35,8 @@ export function getParentScroller(el: HTMLElement, direction?: 'x' | 'y') { const { overflow, overflowX, overflowY } = window.getComputedStyle(element) const passOverflow = scrollRE.test(overflow) - const passOverflowX = (direction === 'x' || isUndef(direction)) && scrollRE.test(overflowX) - const passOverflowY = (direction === 'y' || isUndef(direction)) && scrollRE.test(overflowY) + const passOverflowX = (direction === 'x' || direction == null) && scrollRE.test(overflowX) + const passOverflowY = (direction === 'y' || direction == null) && scrollRE.test(overflowY) if (passOverflow || passOverflowX || passOverflowY) { return element } diff --git a/packages/varlet-ui/src/utils/shared.ts b/packages/varlet-ui/src/utils/shared.ts index fbdb158f5c0..c809a690201 100644 --- a/packages/varlet-ui/src/utils/shared.ts +++ b/packages/varlet-ui/src/utils/shared.ts @@ -9,10 +9,6 @@ export const isString = (val: unknown): val is string => typeof val === 'string' export const isBaseObject = (val: unknown) => Object.prototype.toString.call(val) === '[object Object]' -export const isDef = (val: unknown): boolean => val !== null && val !== undefined - -export const isUndef = (val: unknown): boolean => val === null || val === undefined - export const removeItem = (arr: Array, item: unknown) => { if (arr.length) { const index: number = arr.indexOf(item) diff --git a/yarn.lock b/yarn.lock index 76f0726699d..bf1eedc1735 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12522,10 +12522,10 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389" - integrity sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ== +typescript@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" + integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6"