Explorar o código

refactor(架构调整): 初步整理utils与新增hooks

gemercheung %!s(int64=2) %!d(string=hai) anos
pai
achega
267ad60fc3

+ 2 - 1
package.json

@@ -18,13 +18,14 @@
         "postinstall": "husky install",
         "changeset": "changeset",
         "version-packages": "changeset version",
-        "dev:playground": "pnpm -C playground dev"
+        "dev": "pnpm -C playground dev"
     },
     "peerDependencies": {
         "vue": "^3.2.0"
     },
     "dependencies": {
         "@kankan/components": "workspace:*",
+        "@kankan/hooks": "workspace:*",
         "@vueuse/core": "^9.1.0",
         "lodash": "^4.17.21",
         "lodash-es": "^4.17.21",

+ 4 - 0
packages/components/basic/dialog/index.ts

@@ -0,0 +1,4 @@
+import Dialog from './src/dialog'
+
+export default Dialog
+export * from './src/dialog'

+ 3 - 2
packages/components/basic/dialog/src/alert.vue

@@ -10,9 +10,10 @@
         </template>
     </ui-dialog>
 </template>
-<script>
+
+<script lang="ts">
 import { defineComponent } from 'vue'
-import { isFunction, omit } from '../../utils'
+import { isFunction, omit } from '@kankan/utils'
 export default defineComponent({
     name: 'UiAlert',
     props: {

+ 3 - 3
packages/components/basic/dialog/src/confirm.vue

@@ -16,9 +16,9 @@
         </template>
     </ui-dialog>
 </template>
-<script>
+<script lang="ts">
 import { defineComponent } from 'vue'
-import { isFunction, omit } from '../../utils'
+import { isFunction, omit } from '@kankan/utils'
 
 export default defineComponent({
     name: 'UiConfirm',
@@ -47,7 +47,7 @@ export default defineComponent({
         content: String,
         destroy: Function,
     },
-    setup: function (props) {
+    setup: function (props, _) {
         const close = result => {
             if (isFunction(props.func) && props.func(result) === false) {
                 return

+ 1 - 1
packages/components/basic/dialog/src/dialog-content.vue

@@ -12,6 +12,6 @@
     </div>
 </template>
 
-<script>
+<script lang="ts">
 export default { name: 'UiDialogContent' }
 </script>

+ 7 - 7
packages/components/basic/dialog/src/dialog.ts

@@ -1,10 +1,10 @@
-import Dialog from './Dialog'
-import Window from './Window'
-import Toast from './Toast'
-import Alert from './Alert'
-import Confirm from './Confirm'
-import DialogContent from './Dialog-content'
-import { mount } from '../../utils/componentHelper'
+import Dialog from './dialog.vue'
+import Window from './window.vue'
+import Toast from './toast.vue'
+import Alert from './alert.vue'
+import Confirm from './confirm.vue'
+import DialogContent from './dialog-content.vue'
+import { mount } from '@vue/test-utils'
 
 Dialog.use = function use(app) {
     Dialog.toast = function (options) {

+ 6 - 4
packages/components/basic/dialog/src/dialog.vue

@@ -9,10 +9,12 @@
         </div>
     </teleport>
 </template>
-<script>
+<script lang="ts">
 import { defineComponent, ref } from 'vue'
-import zindex from '../../utils/zindex'
-import DialogContent from './Dialog-content.vue'
+import { useZIndex } from '@kankan/hooks'
+const { currentZIndex } = useZIndex()
+
+import DialogContent from './dialog-content.vue'
 export default defineComponent({
     name: 'UiDialog',
     components: { DialogContent },
@@ -20,7 +22,7 @@ export default defineComponent({
         const show = ref(true)
         return {
             show,
-            zIndex: zindex(),
+            zIndex: currentZIndex,
         }
     },
 })

+ 5 - 4
packages/components/basic/dialog/src/toast.vue

@@ -11,9 +11,10 @@
         </transition>
     </teleport>
 </template>
-<script>
+<script lang="ts">
 import { defineComponent, nextTick, ref } from 'vue'
-import zindex from '../../utils/zindex'
+import { useZIndex } from '@kankan/hooks'
+const { currentZIndex } = useZIndex()
 
 export default defineComponent({
     name: 'UiToast',
@@ -45,12 +46,12 @@ export default defineComponent({
             // type: props.type,
             // close,
             // content: props.content,
-            zIndex: zindex(),
+            zIndex: currentZIndex,
         }
     },
 })
 </script>
-<style lang="scss" scoped>
+<style scoped>
 .slide-down-enter-active,
 .slide-down-leave-active {
     will-change: transform;

+ 9 - 0
packages/components/basic/floating/index.ts

@@ -0,0 +1,9 @@
+import { withInstall } from '@kankan/utils'
+
+import floating from './src/floating.vue'
+
+export const UIFloating = withInstall(floating)
+
+export default UIFloating
+
+export * from './src/floating'

+ 0 - 0
packages/components/basic/floating/src/floating.ts


+ 8 - 7
packages/components/basic/floating/index.vue

@@ -6,11 +6,12 @@
     </teleport>
 </template>
 
-<script setup>
+<script setup lang="ts">
 // onUpdated
 import { defineProps, defineExpose, onUnmounted, reactive, watch, computed, onActivated } from 'vue'
-import { getPostionByTarget, getScrollParents, getZIndex } from '../../utils'
-
+import { getPostionByTarget, getScrollParents } from '@kankan/utils'
+import { useZIndex } from '@kankan/hooks'
+const { currentZIndex } = useZIndex()
 const Horizontal = {
     center: 'center',
     right: 'right',
@@ -82,7 +83,7 @@ watch(
     { immediate: true }
 )
 
-const zIndex = getZIndex()
+// const zIndex = currentZIndex
 
 const style = computed(() => {
     let style = {
@@ -90,7 +91,7 @@ const style = computed(() => {
         height: height.value && height.value + 'px',
         left: location.x + 'px',
         top: location.y + 'px',
-        zIndex: zIndex,
+        zIndex: currentZIndex,
     }
     if (location.x > 0 && location.y > 0) {
         return style
@@ -156,7 +157,7 @@ defineExpose({
     updateLocation,
 })
 </script>
-
+<!-- 
 <script>
 export default { name: 'UiFloating' }
-</script>
+</script> -->

+ 2 - 2
packages/components/basic/input/src/checkbox/checkbox.vue

@@ -19,10 +19,10 @@
 
 <script setup lang="ts">
 import UIIcon from '../../../icon/src/icon.vue'
-import { CheckboxInputProps } from './checkbox'
+import { checkboxInputProps } from './checkbox'
 import { randomId } from '@kankan/utils'
 import { defineProps, defineEmits } from 'vue'
-const props = defineProps(CheckboxInputProps)
+const props = defineProps(checkboxInputProps)
 const emit = defineEmits(['update:modelValue'])
 const id = randomId(4)
 </script>

+ 3 - 3
packages/components/basic/input/src/file/file.vue

@@ -40,10 +40,10 @@
 import { fileProps } from './file'
 import { toRawType } from '@kankan/utils'
 // import Message from '../message';
-import Dialog from '../dialog'
+import Dialog from '@kankan/components/basic/dialog'
 import { defineProps, defineEmits, defineExpose, ref, computed } from 'vue'
-import { useI18n } from '@/i18n'
-const { t } = useI18n({ useScope: 'global' })
+// import { useI18n } from '@/i18n'
+// const { t } = useI18n({ useScope: 'global' })
 const props = defineProps(fileProps)
 const emit = defineEmits(['update:modelValue'])
 const inputRef = ref(null)

+ 2 - 0
packages/components/basic/input/src/input.ts

@@ -15,6 +15,7 @@ import { selectProps } from './select/select'
 import { switchProps } from './switch/switch'
 import { textInputProps } from './text/text'
 import { textareaProps } from './textarea/textarea'
+
 import radio from './radio/radio.vue'
 import * as UISwitch from './switch/switch.vue'
 import text from './text/text.vue'
@@ -103,6 +104,7 @@ export const InputComponents: ComponentsType = {
 
 // export type
 export * from './checkbox/checkbox'
+export * from './richtext/richtext'
 export * from './checkRadio/checkRadio'
 export * from './file/file'
 export * from './radio/radio'

+ 2 - 2
packages/components/basic/input/src/number/number.vue

@@ -24,11 +24,11 @@
 </template>
 
 <script setup lang="ts">
-import UIText from './text.vue'
+import UIText from '../text/text.vue'
 import { numberProps } from './number'
 import { defineProps, defineEmits, watchEffect, ref } from 'vue'
 import { toRawType } from '@kankan/utils'
-import UIIcon from '../../icon/src/icon.vue'
+import UIIcon from '@kankan/components/basic/icon'
 
 const emit = defineEmits(['update:modelValue'])
 const props = defineProps(numberProps)

+ 2 - 2
packages/components/basic/input/src/select/select.vue

@@ -56,9 +56,9 @@
 </template>
 
 <script setup lang="ts">
-import icon from '../icon'
+import icon from '@kankan/components/basic/icon'
 import UItext from '../text/text.vue'
-import UIFloating from '../floating/index.vue'
+import UIFloating from '@kankan/components/basic/floating'
 import { ref, computed, defineExpose } from 'vue'
 import { selectProps } from './select'
 

+ 2 - 2
packages/components/basic/input/src/text/text.vue

@@ -36,9 +36,9 @@
 </template>
 
 <script setup lang="ts">
-import { TextInputProps } from './text'
+import { textInputProps } from './text'
 import { defineProps, defineEmits, defineExpose, nextTick, ref } from 'vue'
-const props = defineProps(TextInputProps)
+const props = defineProps(textInputProps)
 const emit = defineEmits(['update:modelValue', 'focus', 'blur', 'click'])
 // const test = () => {
 //   emit('focus');

+ 1 - 0
packages/hooks/index.ts

@@ -0,0 +1 @@
+export * from './use-z-index'

+ 14 - 0
packages/hooks/package.json

@@ -0,0 +1,14 @@
+{
+    "name": "@kankan/hooks",
+    "version": "0.0.1",
+    "description": "kankan composables",
+    "license": "MIT",
+    "main": "index.ts",
+    "module": "index.ts",
+    "unpkg": "index.js",
+    "jsdelivr": "index.js",
+    "types": "index.d.ts",
+    "peerDependencies": {
+        "vue": "^3.2.0"
+    }
+}

+ 21 - 0
packages/hooks/use-z-index/index.ts

@@ -0,0 +1,21 @@
+import { computed, ref } from 'vue'
+// import { useGlobalConfig } from '../use-global-config'
+
+const zIndex = ref(0)
+
+export const useZIndex = () => {
+    // const initialZIndex = useGlobalConfig('zIndex', 2000) // TODO: move to @element-plus/constants
+    const initialZIndex = ref(1000)
+    const currentZIndex = computed(() => initialZIndex.value + zIndex.value)
+
+    const nextZIndex = () => {
+        zIndex.value++
+        return currentZIndex.value
+    }
+
+    return {
+        initialZIndex,
+        currentZIndex,
+        nextZIndex,
+    }
+}

+ 2 - 0
packages/utils/dom/index.ts

@@ -3,3 +3,5 @@ export * from './event'
 export * from './position'
 export * from './scroll'
 export * from './style'
+export * from './others'
+export * from './parent'

packages/utils/dom.ts → packages/utils/dom/others.ts


+ 96 - 0
packages/utils/dom/parent.ts

@@ -0,0 +1,96 @@
+import { ref, onMounted, computed } from 'vue'
+
+/**
+ * 获取真实DOM的高度
+ * @returns [heightRef, VMRef, readyRef]
+ */
+export const getVMDomWH = attr => {
+    const origin = ref(0)
+    const domRef = ref(null)
+    const ready = ref(false)
+    const referWH = () => {
+        origin.value = 0
+        ready.value = false
+        if (domRef.value) {
+            setTimeout(() => {
+                origin.value = attr === 'width' ? domRef.value.offsetWidth : domRef.value.offsetHeight
+                setTimeout(() => (ready.value = true))
+            })
+        }
+    }
+
+    onMounted(referWH)
+
+    return [origin, domRef, ready, referWH]
+}
+
+/**
+ * 生成切换高度的方法
+ * @returns [VMRef, fn, maxHeightRef, originHeightRef, showRef, readyRef]
+ */
+export const changeWHFactory = (isShow = false, attr = 'height') => {
+    const [origin, domRef, ready, referWH] = getVMDomWH(attr)
+    const max = ref(0)
+    const show = computed({
+        get: () => {
+            return max.value == origin.value
+        },
+        set: val => {
+            max.value = val ? origin.value : 0
+        },
+    })
+    const changeShow = (val = !show.value) => {
+        show.value = val
+    }
+
+    onMounted(() => {
+        show.value = isShow
+    })
+
+    return [domRef, changeShow, max, origin, show, ready, referWH]
+}
+
+/**
+ * 获取父级滚动
+ * @param {*} node
+ * @returns
+ */
+export const getScrollParent = (node: HTMLElement): HTMLElement => {
+    if (node == null) {
+        return null
+    }
+    if (node === document.documentElement) {
+        return node
+    }
+
+    const cssScrollY = getComputedStyle(node).overflowY
+    const cssScrollX = getComputedStyle(node).overflowX
+    if (node.scrollHeight > node.clientHeight || cssScrollY === 'auto' || cssScrollY === 'scroll' || cssScrollX === 'auto' || cssScrollX === 'scroll') {
+        return node
+    } else {
+        return getScrollParent(node.parentNode)
+    }
+}
+
+/**
+ * 获取所有父级滚动
+ * @param {*} origin
+ * @param {*} target
+ */
+export const getScrollParents = (origin, target) => {
+    const parents = []
+    let temporary = origin
+    while (temporary && temporary !== target && temporary !== document.documentElement && target.contains(temporary)) {
+        const scrollParent = getScrollParent(temporary)
+        if (scrollParent) {
+            if (scrollParent !== origin) {
+                parents.push(scrollParent)
+            }
+            temporary = scrollParent.parentNode
+        } else {
+            break
+        }
+    }
+
+    return parents
+}

+ 2 - 0
packages/utils/index.ts

@@ -1,3 +1,5 @@
 export * from './vue'
 export * from './dom'
 export * from './normal'
+export * from './types'
+export * from './objects'

+ 32 - 0
packages/utils/normal.ts

@@ -7,3 +7,35 @@ export const randomId = (e = 6): string => {
     }
     return n
 }
+
+export function omit(obj, ...props) {
+    const result = { ...obj }
+    props.forEach(function (prop) {
+        delete result[prop]
+    })
+    return result
+}
+
+/**
+ * 获取制定dom在相对于目标中的位置
+ * @param {*} origin 或获取的DOM
+ * @param {*} target 目标DOM
+ * @param {*} isIncludeSelf 是否要包含自身宽高
+ * @returns 位置信息 {x, y}
+ */
+export const getPostionByTarget = (origin, target, isIncludeSelf = false) => {
+    const pos = { x: 0, y: 0, width: origin.offsetWidth, height: origin.offsetHeight }
+
+    let temporary = origin
+    while (temporary && temporary !== target && temporary !== document.documentElement && target.contains(temporary)) {
+        pos.x += temporary.offsetLeft + temporary.clientLeft
+        pos.y += temporary.offsetTop + temporary.clientTop
+        temporary = temporary.offsetParent
+    }
+
+    if (isIncludeSelf) {
+        pos.x += pos.width
+        pos.y += pos.height
+    }
+    return pos
+}

+ 14 - 0
packages/utils/strings.ts

@@ -0,0 +1,14 @@
+import { capitalize as toCapitalize } from '@vue/shared'
+export {
+    camelize,
+    hyphenate,
+    hyphenate as kebabCase, // alias
+} from '@vue/shared'
+
+/**
+ * fork from {@link https://github.com/sindresorhus/escape-string-regexp}
+ */
+export const escapeStringRegexp = (string = '') => string.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')
+
+// NOTE: improve capitalize types. Restore previous code after the [PR](https://github.com/vuejs/core/pull/6212) merge
+export const capitalize = <T extends string>(str: T) => toCapitalize(str) as Capitalize<T>

+ 8 - 0
pnpm-lock.yaml

@@ -7,6 +7,7 @@ importers:
       '@changesets/cli': ^2.24.4
       '@commitlint/cli': ^17.1.2
       '@kankan/components': workspace:*
+      '@kankan/hooks': workspace:*
       '@types/jsdom': ^16.2.14
       '@types/node': '*'
       '@typescript-eslint/eslint-plugin': ^5.38.1
@@ -39,6 +40,7 @@ importers:
       vue: ^3.2.0
     dependencies:
       '@kankan/components': link:packages/components
+      '@kankan/hooks': link:packages/hooks
       '@vueuse/core': 9.3.0_vue@3.2.39
       lodash: 4.17.21
       lodash-es: 4.17.21
@@ -113,6 +115,12 @@ importers:
       tslib: 2.4.0
       typescript: 4.7.4
 
+  packages/hooks:
+    specifiers:
+      vue: ^3.2.0
+    dependencies:
+      vue: 3.2.39
+
   packages/utils:
     specifiers:
       '@vue/shared': ^3.2.39