gi-component 0.0.47 → 0.0.49

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gi-component",
3
3
  "type": "module",
4
- "version": "0.0.47",
4
+ "version": "0.0.49",
5
5
  "description": "Vue3中基于Element Plus二次封装基础组件库",
6
6
  "author": "lin",
7
7
  "license": "MIT",
@@ -53,7 +53,7 @@ const bindProps = computed(() => {
53
53
  })
54
54
 
55
55
  const btnText = computed(() => {
56
- return obj[props.type].btnText
56
+ return obj?.[props.type]?.btnText || ''
57
57
  })
58
58
  </script>
59
59
 
@@ -15,12 +15,19 @@ const props = withDefaults(defineProps<FlexProps>(), {
15
15
  wrap: false,
16
16
  justify: 'normal',
17
17
  align: 'normal',
18
- flex: 'normal'
18
+ flex: 'normal',
19
+ full: false
19
20
  })
20
21
 
21
22
  const { b } = useBemClass()
22
23
 
23
- const classNames = computed(() => [b('flex'), b(`flex__size--${props.gap}`)])
24
+ const classNames = computed(() => {
25
+ const arr: string[] = [b('flex'), b(`flex__size--${props.gap}`)]
26
+ if (props.full) {
27
+ arr.push(b('flex--full'))
28
+ }
29
+ return arr
30
+ })
24
31
 
25
32
  const SIZE_MAP = ['small', 'middle', 'large']
26
33
 
@@ -67,6 +74,12 @@ const style = computed<CSSProperties>(() => {
67
74
  }
68
75
 
69
76
  .#{a.$prefix}-flex {
77
+ &--full {
78
+ width: 100%;
79
+ height: 100%;
80
+ overflow: hidden;
81
+ }
82
+
70
83
  &__size--small {
71
84
  gap: 8px;
72
85
  }
@@ -13,4 +13,6 @@ export interface FlexProps {
13
13
  flex?: string
14
14
  /** 设置网格之间的间隙,可选预设 small / middle / large 或 string / number */
15
15
  gap?: 'small' | 'middle' | 'large' | string | number
16
+ /** 是否撑满父容器宽高 */
17
+ full?: boolean
16
18
  }
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <ElSplitter :class="getClass">
2
+ <ElSplitter ref="splitterRef" :class="getClass">
3
3
  <ElSplitterPanel v-if="slots.left" v-model:size="size">
4
4
  <div :class="b('page-layout__left')" :style="props.leftStyle">
5
5
  <slot name="left"></slot>
@@ -27,14 +27,17 @@
27
27
  <script lang="ts" setup>
28
28
  import type { PageLayoutProps } from './type'
29
29
  import { ElSplitter, ElSplitterPanel } from 'element-plus'
30
- import { computed, ref, useSlots } from 'vue'
30
+ import { computed, onBeforeUnmount, ref, useSlots } from 'vue'
31
31
  import { useBemClass } from '../../../hooks'
32
32
  import SplitButton from './split-button.vue'
33
+ import { useAutoCollapse } from './useAutoCollapse'
33
34
 
34
35
  const props = withDefaults(defineProps<PageLayoutProps>(), {
35
36
  size: 270,
36
37
  bordered: false,
37
38
  collapse: true,
39
+ autoCollapse: false,
40
+ collapseBreakpoint: 850,
38
41
  leftStyle: () => ({}),
39
42
  headerStyle: () => ({}),
40
43
  toolStyle: () => ({}),
@@ -50,8 +53,42 @@ defineSlots<{
50
53
 
51
54
  const slots = useSlots()
52
55
  const { b } = useBemClass()
56
+ const splitterRef = ref<InstanceType<typeof ElSplitter>>()
53
57
  const size = ref(props.size)
54
58
  const collapsing = ref(false)
59
+ let collapsingTimer: ReturnType<typeof setTimeout> | null = null
60
+
61
+ const COLLAPSE_TRANSITION_MS = 300
62
+
63
+ function setCollapsingSize(newSize: typeof size.value) {
64
+ if (collapsingTimer) {
65
+ clearTimeout(collapsingTimer)
66
+ }
67
+ collapsing.value = true
68
+ collapsingTimer = setTimeout(() => {
69
+ collapsing.value = false
70
+ collapsingTimer = null
71
+ }, COLLAPSE_TRANSITION_MS)
72
+ size.value = newSize
73
+ }
74
+
75
+ const autoCollapseEnabled = props.collapse && props.autoCollapse && !!slots.left && !!props.collapseBreakpoint
76
+
77
+ useAutoCollapse({
78
+ splitterRef,
79
+ size,
80
+ enabled: autoCollapseEnabled,
81
+ collapseBreakpoint: props.collapseBreakpoint,
82
+ panelSize: () => props.size,
83
+ setCollapsingSize
84
+ })
85
+
86
+ onBeforeUnmount(() => {
87
+ if (collapsingTimer) {
88
+ clearTimeout(collapsingTimer)
89
+ collapsingTimer = null
90
+ }
91
+ })
55
92
 
56
93
  const getClass = computed(() => {
57
94
  const arr: string[] = [b('page-layout')]
@@ -71,11 +108,7 @@ const getClass = computed(() => {
71
108
  })
72
109
 
73
110
  function handleClick() {
74
- collapsing.value = true
75
- setTimeout(() => {
76
- collapsing.value = false
77
- }, 300)
78
- size.value = Number(size.value) > 30 ? 0 : props.size
111
+ setCollapsingSize(Number(size.value) > 30 ? 0 : props.size)
79
112
  }
80
113
  </script>
81
114
 
@@ -5,6 +5,10 @@ export interface PageLayoutProps {
5
5
  size?: SplitterPanelProps['size']
6
6
  bordered?: boolean
7
7
  collapse?: boolean
8
+ /** 是否开启容器宽度自动折叠左侧面板 */
9
+ autoCollapse?: boolean
10
+ /** 容器宽度小于该值时自动折叠左侧面板,大于该值时自动展开(单位 px) */
11
+ collapseBreakpoint?: number
8
12
  leftStyle?: CSSProperties
9
13
  headerStyle?: CSSProperties
10
14
  toolStyle?: CSSProperties
@@ -0,0 +1,88 @@
1
+ import type { ElSplitter, SplitterPanelProps } from 'element-plus'
2
+ import type { Ref } from 'vue'
3
+ import { nextTick, onBeforeUnmount, onMounted } from 'vue'
4
+
5
+ const RESIZE_DEBOUNCE_MS = 150
6
+
7
+ export interface UseAutoCollapseOptions<TSize extends SplitterPanelProps['size'] = SplitterPanelProps['size']> {
8
+ splitterRef: Ref<InstanceType<typeof ElSplitter> | undefined>
9
+ size: Ref<TSize>
10
+ enabled: boolean
11
+ collapseBreakpoint: number
12
+ panelSize: () => TSize
13
+ setCollapsingSize: (newSize: TSize) => void
14
+ }
15
+
16
+ export function useAutoCollapse<TSize extends SplitterPanelProps['size']>(
17
+ options: UseAutoCollapseOptions<TSize>
18
+ ) {
19
+ if (!options.enabled) {
20
+ return
21
+ }
22
+
23
+ let resizeObserver: ResizeObserver | null = null
24
+ let debounceTimer: ReturnType<typeof setTimeout> | null = null
25
+
26
+ function getSplitterWidth() {
27
+ const el = options.splitterRef.value?.$el as HTMLElement | undefined
28
+ return el?.clientWidth ?? 0
29
+ }
30
+
31
+ function applyAutoCollapseWidth(width: number) {
32
+ const threshold = options.collapseBreakpoint
33
+
34
+ if (width < threshold && Number(options.size.value) > 30) {
35
+ options.setCollapsingSize(0 as TSize)
36
+ }
37
+ else if (width > threshold && Number(options.size.value) === 0) {
38
+ options.setCollapsingSize(options.panelSize())
39
+ }
40
+ }
41
+
42
+ function debouncedApplyAutoCollapseWidth() {
43
+ if (debounceTimer) {
44
+ clearTimeout(debounceTimer)
45
+ }
46
+ debounceTimer = setTimeout(() => {
47
+ debounceTimer = null
48
+ applyAutoCollapseWidth(getSplitterWidth())
49
+ }, RESIZE_DEBOUNCE_MS)
50
+ }
51
+
52
+ function clearDebounceTimer() {
53
+ if (debounceTimer) {
54
+ clearTimeout(debounceTimer)
55
+ debounceTimer = null
56
+ }
57
+ }
58
+
59
+ function bindResizeObserver() {
60
+ unbindResizeObserver()
61
+
62
+ const el = options.splitterRef.value?.$el as HTMLElement | undefined
63
+ if (!el || typeof ResizeObserver === 'undefined') {
64
+ return
65
+ }
66
+
67
+ resizeObserver = new ResizeObserver(() => {
68
+ debouncedApplyAutoCollapseWidth()
69
+ })
70
+ resizeObserver.observe(el)
71
+ applyAutoCollapseWidth(getSplitterWidth())
72
+ }
73
+
74
+ function unbindResizeObserver() {
75
+ resizeObserver?.disconnect()
76
+ resizeObserver = null
77
+ }
78
+
79
+ onMounted(async () => {
80
+ await nextTick()
81
+ bindResizeObserver()
82
+ })
83
+
84
+ onBeforeUnmount(() => {
85
+ clearDebounceTimer()
86
+ unbindResizeObserver()
87
+ })
88
+ }
@@ -84,6 +84,6 @@ defineExpose({
84
84
  }
85
85
 
86
86
  .#{a.$prefix}-table-pagination {
87
- margin-top: 10px;
87
+ margin-top: 12px;
88
88
  }
89
89
  </style>
@@ -2,7 +2,7 @@
2
2
  <div :class="getClass">
3
3
  <div :class="b('tabs__default')">
4
4
  <slot>
5
- <ElTabs v-model="model" :type="props.type" :stretch="props.stretch"
5
+ <ElTabs :key="props.type" v-model="model" :type="props.type" :stretch="props.stretch"
6
6
  @tab-click="(p, e) => emits('tab-click', p, e)" @tab-change="emits('tab-change', $event as any)">
7
7
  <ElTabPane v-for="item in props.options" :key="item.name" :name="item.name" :disabled="item?.disabled">
8
8
  <template #label>
@@ -349,7 +349,7 @@ $tag-size-large-padding: 0 10px;
349
349
  .#{a.$prefix}-tag__type--outline,
350
350
  .#{a.$prefix}-tag__type--light-outline {
351
351
  &.#{a.$prefix}-tag__color--info {
352
- color: var(--el-color-text-primary);
352
+ color: var(--el-text-color-primary);
353
353
  }
354
354
  }
355
355
  </style>
@@ -3,8 +3,8 @@
3
3
 
4
4
  body {
5
5
  // 主要作用于页面
6
- --padding: 14px;
7
- --margin: 14px;
6
+ --padding: 16px;
7
+ --margin: 16px;
8
8
  }
9
9
 
10
10
  .g-card-title {