@gcsa/console-vue 0.1.2 → 0.1.4

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.
Files changed (38) hide show
  1. package/dist/components/GcsaCascader.vue.js +8 -7
  2. package/dist/components/GcsaCascader.vue.js.map +1 -1
  3. package/dist/components/GcsaPopover.vue.d.ts +3 -0
  4. package/dist/components/GcsaPopover.vue.js +61 -59
  5. package/dist/components/GcsaPopover.vue.js.map +1 -1
  6. package/dist/components/GcsaPortal.vue.js +30 -16
  7. package/dist/components/GcsaPortal.vue.js.map +1 -1
  8. package/dist/components/GcsaTransfer.vue.js +117 -79
  9. package/dist/components/GcsaTransfer.vue.js.map +1 -1
  10. package/dist/components/GcsaUpload.vue.js +1 -1
  11. package/dist/components/GcsaUpload.vue.js.map +1 -1
  12. package/dist/icons/iconNames.d.ts +2 -2
  13. package/dist/icons/iconNames.js +1 -0
  14. package/dist/icons/iconNames.js.map +1 -1
  15. package/dist/icons/registry.d.ts +1 -1
  16. package/dist/icons/registry.js +38 -35
  17. package/dist/icons/registry.js.map +1 -1
  18. package/dist/icons/svg/result-empty.svg.js +12 -2
  19. package/dist/icons/svg/result-empty.svg.js.map +1 -1
  20. package/dist/icons/svg/upload.svg.js +10 -0
  21. package/dist/icons/svg/upload.svg.js.map +1 -0
  22. package/dist/icons/svg/users.svg.js.map +1 -1
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +56 -55
  25. package/dist/style.css +223 -140
  26. package/dist/types/componentProps.d.ts +2 -0
  27. package/package.json +3 -3
  28. package/src/components/GcsaCascader.vue +1 -1
  29. package/src/components/GcsaPopover.vue +11 -13
  30. package/src/components/GcsaPortal.vue +26 -2
  31. package/src/components/GcsaTransfer.vue +125 -13
  32. package/src/components/GcsaUpload.vue +1 -1
  33. package/src/icons/iconNames.ts +1 -0
  34. package/src/icons/registry.ts +3 -1
  35. package/src/icons/svg/result-empty.svg +11 -1
  36. package/src/icons/svg/upload.svg +5 -0
  37. package/src/index.ts +1 -1
  38. package/src/types/componentProps.ts +2 -0
@@ -160,6 +160,8 @@ export type GcsaPopoverProps = {
160
160
  portalled?: boolean;
161
161
  gutter?: number;
162
162
  open?: boolean;
163
+ /** 启用 size middleware,写入 --reference-width(Cascader 等需对齐触发器最小宽度) */
164
+ fitViewport?: boolean;
163
165
  size?: GcsaPopoverSize;
164
166
  width?: string | number;
165
167
  minWidth?: string | number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gcsa/console-vue",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "GCSA console UI — Vue 3 components (Ark UI + TanStack + GCSA styles)",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -46,8 +46,8 @@
46
46
  "@tanstack/vue-form": "^1.12.2",
47
47
  "@tanstack/vue-table": "^8.21.3",
48
48
  "zod": "^3.24.4",
49
- "@gcsa/console-core": "0.1.2",
50
- "@gcsa/console-styles": "0.1.2"
49
+ "@gcsa/console-core": "0.1.4",
50
+ "@gcsa/console-styles": "0.1.4"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "vue": "^3.4.0"
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <GcsaPopover :arrow="false" :portalled="portalled" :gutter="6" class="gcsa-cascader-popover">
2
+ <GcsaPopover :arrow="false" :portalled="portalled" :gutter="6" :fit-viewport="true" class="gcsa-cascader-popover">
3
3
  <template #trigger>
4
4
  <button type="button" class="gcsa-cascader__trigger gcsa-focus-ring" :disabled="disabled" :data-invalid="invalid || undefined">
5
5
  <span class="gcsa-cascader__value" :data-placeholder="!displayLabel || undefined">{{ displayLabel || resolvedPlaceholder }}</span>
@@ -1,8 +1,8 @@
1
1
  <template>
2
2
  <Popover.Root
3
- :open="resolvedOpen"
3
+ :open="open"
4
4
  :positioning="positioningOptions"
5
- @open-change="(details) => handleOpenChange(details.open)"
5
+ @update:open="handleOpenChange"
6
6
  >
7
7
  <Popover.Trigger v-if="hasTriggerSlot" as-child>
8
8
  <slot name="trigger" />
@@ -48,12 +48,14 @@ const props = withDefaults(
48
48
  arrow: true,
49
49
  portalled: true,
50
50
  gutter: 8,
51
- size: 'default'
51
+ size: 'default',
52
+ fitViewport: false
52
53
  }
53
54
  );
54
55
 
55
56
  const emit = defineEmits<{
56
57
  'open-change': [open: boolean];
58
+ 'update:open': [open: boolean];
57
59
  }>();
58
60
 
59
61
  const messages = useGcsaLocaleMessages();
@@ -63,16 +65,12 @@ const slots = useSlots();
63
65
  const hasTriggerSlot = computed(() => Boolean(slots.trigger));
64
66
  const hasFooterSlot = computed(() => Boolean(slots.footer));
65
67
 
66
- const isControlled = computed(() => props.open !== undefined);
67
- const internalOpen = ref(false);
68
- const resolvedOpen = computed(() => (isControlled.value ? props.open : internalOpen.value));
68
+ const open = ref(props.open ?? false);
69
69
 
70
70
  watch(
71
71
  () => props.open,
72
72
  (next) => {
73
- if (next !== undefined) {
74
- internalOpen.value = next;
75
- }
73
+ if (next !== undefined) open.value = next;
76
74
  }
77
75
  );
78
76
 
@@ -107,14 +105,14 @@ const contentClassNames = computed(() =>
107
105
  const positioningOptions = computed(() =>
108
106
  createGcsaPopupPositioning({
109
107
  placement: props.placement,
110
- gutter: props.gutter
108
+ gutter: props.gutter,
109
+ fitViewport: props.fitViewport
111
110
  })
112
111
  );
113
112
 
114
113
  function handleOpenChange(nextOpen: boolean) {
115
- if (!isControlled.value) {
116
- internalOpen.value = nextOpen;
117
- }
114
+ open.value = nextOpen;
115
+ emit('update:open', nextOpen);
118
116
  emit('open-change', nextOpen);
119
117
  onPopupOpenChange(nextOpen);
120
118
  }
@@ -8,7 +8,7 @@
8
8
  </template>
9
9
 
10
10
  <script setup lang="ts">
11
- import { computed, inject, onMounted, ref, type ComputedRef } from 'vue';
11
+ import { computed, inject, onMounted, onUnmounted, ref, type ComputedRef } from 'vue';
12
12
  import type { GcsaConsoleTheme } from '@gcsa/console-core';
13
13
  import type { GcsaPortalProps } from '../types/componentProps';
14
14
  import { GCSA_THEME_KEY } from '../composables/useGcsaTheme';
@@ -22,8 +22,15 @@ const props = withDefaults(
22
22
  }
23
23
  );
24
24
 
25
+ function readDocumentTheme(): GcsaConsoleTheme {
26
+ if (typeof document === 'undefined') return 'dark';
27
+ const value = document.documentElement.getAttribute('data-gcsa-theme');
28
+ return value === 'light' || value === 'dark' ? value : 'dark';
29
+ }
30
+
25
31
  const injectedTheme = inject<ComputedRef<GcsaConsoleTheme> | null>(GCSA_THEME_KEY, null);
26
- const theme = computed(() => injectedTheme?.value ?? 'dark');
32
+ const documentTheme = ref<GcsaConsoleTheme>(readDocumentTheme());
33
+ const theme = computed(() => injectedTheme?.value ?? documentTheme.value);
27
34
 
28
35
  /**
29
36
  * 延迟到客户端挂载后再创建 Teleport,避免 Suspense / 异步父组件初次渲染时
@@ -31,8 +38,25 @@ const theme = computed(() => injectedTheme?.value ?? 'dark');
31
38
  * 浮层统一挂 body,层级由 useGcsaZIndex 栈管理(勿挂到 modal 内 fixed 容器,会破坏定位)。
32
39
  */
33
40
  const mounted = ref(false);
41
+ let themeObserver: MutationObserver | null = null;
42
+
34
43
  onMounted(() => {
35
44
  mounted.value = true;
45
+ documentTheme.value = readDocumentTheme();
46
+ if (typeof MutationObserver !== 'undefined') {
47
+ themeObserver = new MutationObserver(() => {
48
+ documentTheme.value = readDocumentTheme();
49
+ });
50
+ themeObserver.observe(document.documentElement, {
51
+ attributes: true,
52
+ attributeFilter: ['data-gcsa-theme']
53
+ });
54
+ }
55
+ });
56
+
57
+ onUnmounted(() => {
58
+ themeObserver?.disconnect();
59
+ themeObserver = null;
36
60
  });
37
61
 
38
62
  const resolvedTarget = computed(() => props.to ?? 'body');
@@ -1,19 +1,96 @@
1
1
  <template>
2
2
  <div class="gcsa-transfer" :class="{ 'gcsa-transfer--disabled': disabled }">
3
3
  <section class="gcsa-transfer__panel" :aria-label="resolvedSourceTitle">
4
- <header class="gcsa-transfer__header"><span>{{ resolvedSourceTitle }}</span><span>{{ availableItems.length }}</span></header>
5
- <div class="gcsa-transfer__search"><GcsaInput v-model="sourceQuery" :placeholder="messages.searchPlaceholder" :disabled="disabled" /></div>
4
+ <header class="gcsa-transfer__header">
5
+ <span>{{ resolvedSourceTitle }}</span>
6
+ <span>{{ availableItems.length }}</span>
7
+ </header>
8
+ <div class="gcsa-transfer__search">
9
+ <GcsaInput v-model="sourceQuery" :placeholder="messages.searchPlaceholder" :disabled="disabled" />
10
+ </div>
6
11
  <div class="gcsa-transfer__list" role="listbox" aria-multiselectable="true">
7
- <button v-for="item in availableItems" :key="item.value" type="button" class="gcsa-transfer__item gcsa-focus-ring" :class="{ 'gcsa-transfer__item--selected': sourceSelected.includes(item.value) }" :disabled="disabled || item.disabled" role="option" :aria-selected="sourceSelected.includes(item.value)" @click="toggleSelected(item.value, 'source')"><span class="gcsa-transfer__check" aria-hidden="true">{{ sourceSelected.includes(item.value) ? '✓' : '' }}</span><span>{{ item.label }}</span></button>
12
+ <div
13
+ v-for="item in availableItems"
14
+ :key="item.value"
15
+ class="gcsa-transfer__item gcsa-focus-ring"
16
+ :class="{ 'gcsa-transfer__item--selected': sourceSelected.includes(item.value) }"
17
+ role="option"
18
+ :tabindex="disabled || item.disabled ? -1 : 0"
19
+ :aria-selected="sourceSelected.includes(item.value)"
20
+ :aria-disabled="disabled || item.disabled || undefined"
21
+ @click="onItemActivate(item, 'source')"
22
+ @keydown.enter.prevent="onItemActivate(item, 'source')"
23
+ @keydown.space.prevent="onItemActivate(item, 'source')"
24
+ >
25
+ <span class="gcsa-transfer__check-wrap" @click.stop>
26
+ <GcsaCheckbox
27
+ :model-value="sourceSelected.includes(item.value)"
28
+ :disabled="disabled || item.disabled"
29
+ :aria-label="item.label"
30
+ tabindex="-1"
31
+ @update:model-value="checked => setSelected(item.value, 'source', checked)"
32
+ />
33
+ </span>
34
+ <span class="gcsa-transfer__label">{{ item.label }}</span>
35
+ </div>
8
36
  <span v-if="!availableItems.length" class="gcsa-transfer__empty">{{ messages.noOptions }}</span>
9
37
  </div>
10
38
  </section>
11
- <div class="gcsa-transfer__actions"><button type="button" class="gcsa-transfer__action gcsa-focus-ring" :disabled="disabled || !sourceSelected.length" :aria-label="messages.transferMoveRight" @click="moveRight">›</button><button type="button" class="gcsa-transfer__action gcsa-focus-ring" :disabled="disabled || !targetSelected.length" :aria-label="messages.transferMoveLeft" @click="moveLeft">‹</button></div>
39
+
40
+ <div class="gcsa-transfer__actions">
41
+ <button
42
+ type="button"
43
+ class="gcsa-transfer__action gcsa-focus-ring"
44
+ :disabled="disabled || !sourceSelected.length"
45
+ :aria-label="messages.transferMoveRight"
46
+ @click="moveRight"
47
+ >
48
+
49
+ </button>
50
+ <button
51
+ type="button"
52
+ class="gcsa-transfer__action gcsa-focus-ring"
53
+ :disabled="disabled || !targetSelected.length"
54
+ :aria-label="messages.transferMoveLeft"
55
+ @click="moveLeft"
56
+ >
57
+
58
+ </button>
59
+ </div>
60
+
12
61
  <section class="gcsa-transfer__panel" :aria-label="resolvedTargetTitle">
13
- <header class="gcsa-transfer__header"><span>{{ resolvedTargetTitle }}</span><span>{{ targetItems.length }}</span></header>
14
- <div class="gcsa-transfer__search"><GcsaInput v-model="targetQuery" :placeholder="messages.searchPlaceholder" :disabled="disabled" /></div>
62
+ <header class="gcsa-transfer__header">
63
+ <span>{{ resolvedTargetTitle }}</span>
64
+ <span>{{ targetItems.length }}</span>
65
+ </header>
66
+ <div class="gcsa-transfer__search">
67
+ <GcsaInput v-model="targetQuery" :placeholder="messages.searchPlaceholder" :disabled="disabled" />
68
+ </div>
15
69
  <div class="gcsa-transfer__list" role="listbox" aria-multiselectable="true">
16
- <button v-for="item in filteredTargetItems" :key="item.value" type="button" class="gcsa-transfer__item gcsa-focus-ring" :class="{ 'gcsa-transfer__item--selected': targetSelected.includes(item.value) }" :disabled="disabled || item.disabled" role="option" :aria-selected="targetSelected.includes(item.value)" @click="toggleSelected(item.value, 'target')"><span class="gcsa-transfer__check" aria-hidden="true">{{ targetSelected.includes(item.value) ? '✓' : '' }}</span><span>{{ item.label }}</span></button>
70
+ <div
71
+ v-for="item in filteredTargetItems"
72
+ :key="item.value"
73
+ class="gcsa-transfer__item gcsa-focus-ring"
74
+ :class="{ 'gcsa-transfer__item--selected': targetSelected.includes(item.value) }"
75
+ role="option"
76
+ :tabindex="disabled || item.disabled ? -1 : 0"
77
+ :aria-selected="targetSelected.includes(item.value)"
78
+ :aria-disabled="disabled || item.disabled || undefined"
79
+ @click="onItemActivate(item, 'target')"
80
+ @keydown.enter.prevent="onItemActivate(item, 'target')"
81
+ @keydown.space.prevent="onItemActivate(item, 'target')"
82
+ >
83
+ <span class="gcsa-transfer__check-wrap" @click.stop>
84
+ <GcsaCheckbox
85
+ :model-value="targetSelected.includes(item.value)"
86
+ :disabled="disabled || item.disabled"
87
+ :aria-label="item.label"
88
+ tabindex="-1"
89
+ @update:model-value="checked => setSelected(item.value, 'target', checked)"
90
+ />
91
+ </span>
92
+ <span class="gcsa-transfer__label">{{ item.label }}</span>
93
+ </div>
17
94
  <span v-if="!filteredTargetItems.length" class="gcsa-transfer__empty">{{ messages.noOptions }}</span>
18
95
  </div>
19
96
  </section>
@@ -22,8 +99,10 @@
22
99
 
23
100
  <script setup lang="ts">
24
101
  import { computed, ref } from 'vue';
102
+ import type { GcsaTransferOption } from '@gcsa/console-core';
25
103
  import type { GcsaTransferProps } from '../types/componentProps';
26
104
  import { useGcsaLocaleMessages } from '../composables/useGcsaLocale';
105
+ import GcsaCheckbox from './GcsaCheckbox.vue';
27
106
  import GcsaInput from './GcsaInput.vue';
28
107
 
29
108
  defineOptions({ name: 'GcsaTransfer' });
@@ -40,11 +119,44 @@ const sourceSelected = ref<string[]>([]);
40
119
  const targetSelected = ref<string[]>([]);
41
120
  const sourceQuery = ref('');
42
121
  const targetQuery = ref('');
122
+
43
123
  const targetItems = computed(() => props.options.filter(item => props.modelValue.includes(item.value)));
44
- const availableItems = computed(() => props.options.filter(item => !props.modelValue.includes(item.value) && item.label.toLowerCase().includes(sourceQuery.value.trim().toLowerCase())));
45
- const filteredTargetItems = computed(() => targetItems.value.filter(item => item.label.toLowerCase().includes(targetQuery.value.trim().toLowerCase())));
46
- function toggleSelected(value: string, side: 'source' | 'target') { const selected = side === 'source' ? sourceSelected : targetSelected; const next = selected.value.includes(value) ? selected.value.filter(item => item !== value) : [...selected.value, value]; selected.value = next; }
47
- function update(next: string[]) { emit('update:modelValue', next); emit('change', next); sourceSelected.value = []; targetSelected.value = []; }
48
- function moveRight() { update([...props.modelValue, ...sourceSelected.value.filter(value => !props.modelValue.includes(value))]); }
49
- function moveLeft() { update(props.modelValue.filter(value => !targetSelected.value.includes(value))); }
124
+ const availableItems = computed(() =>
125
+ props.options.filter(
126
+ item => !props.modelValue.includes(item.value) && item.label.toLowerCase().includes(sourceQuery.value.trim().toLowerCase())
127
+ )
128
+ );
129
+ const filteredTargetItems = computed(() =>
130
+ targetItems.value.filter(item => item.label.toLowerCase().includes(targetQuery.value.trim().toLowerCase()))
131
+ );
132
+
133
+ function setSelected(value: string, side: 'source' | 'target', checked: boolean) {
134
+ const selected = side === 'source' ? sourceSelected : targetSelected;
135
+ if (checked) {
136
+ if (!selected.value.includes(value)) selected.value = [...selected.value, value];
137
+ } else {
138
+ selected.value = selected.value.filter(item => item !== value);
139
+ }
140
+ }
141
+
142
+ function onItemActivate(item: GcsaTransferOption, side: 'source' | 'target') {
143
+ if (props.disabled || item.disabled) return;
144
+ const selected = side === 'source' ? sourceSelected : targetSelected;
145
+ setSelected(item.value, side, !selected.value.includes(item.value));
146
+ }
147
+
148
+ function update(next: string[]) {
149
+ emit('update:modelValue', next);
150
+ emit('change', next);
151
+ sourceSelected.value = [];
152
+ targetSelected.value = [];
153
+ }
154
+
155
+ function moveRight() {
156
+ update([...props.modelValue, ...sourceSelected.value.filter(value => !props.modelValue.includes(value))]);
157
+ }
158
+
159
+ function moveLeft() {
160
+ update(props.modelValue.filter(value => !targetSelected.value.includes(value)));
161
+ }
50
162
  </script>
@@ -23,7 +23,7 @@
23
23
  @drop.prevent="onDrop"
24
24
  >
25
25
  <span class="gcsa-upload__icon" aria-hidden="true">
26
- <GcsaIcon name="plus" />
26
+ <GcsaIcon name="upload" />
27
27
  </span>
28
28
  <span class="gcsa-upload__title">{{ resolvedButtonLabel }}</span>
29
29
  <p v-if="resolvedHint" class="gcsa-upload__hint">{{ resolvedHint }}</p>
@@ -18,6 +18,7 @@ export const GCSA_UI_ICON_NAMES = [
18
18
  'close',
19
19
  'menu',
20
20
  'plus',
21
+ 'upload',
21
22
  'resultEmpty'
22
23
  ] as const;
23
24
 
@@ -5,6 +5,7 @@ import {
5
5
  // 显式导入:避免 dev 下 glob 缓存未收录新 SVG 时模块加载即抛错白屏
6
6
  import chevronLeftSvg from './svg/chevron-left.svg?raw';
7
7
  import menuSvg from './svg/menu.svg?raw';
8
+ import uploadSvg from './svg/upload.svg?raw';
8
9
 
9
10
  const svgModules = import.meta.glob('./svg/*.svg', {
10
11
  query: '?raw',
@@ -27,7 +28,8 @@ const registry = {
27
28
  Object.entries(svgModules).map(([path, svg]) => [toIconKey(fileStem(path)), svg])
28
29
  ),
29
30
  menu: menuSvg,
30
- chevronLeft: chevronLeftSvg
31
+ chevronLeft: chevronLeftSvg,
32
+ upload: uploadSvg
31
33
  } as Record<GcsaIconName, string>;
32
34
 
33
35
  for (const name of GCSA_ICON_NAMES) {
@@ -1 +1,11 @@
1
- <svg viewBox="0 0 29 36" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path opacity="0.3" d="M2 0C0.895432 0 0 0.895431 0 2V34C0 35.1046 0.895431 36 2 36H27C28.1046 36 29 35.1046 29 34V11H17.9511V0H2Z" fill="currentColor"/><path d="M14.1667 23.5V21.8333H15C16.4167 21.8333 17.5 20.75 17.5 19.3333V18.5C17.5 17.0833 16.4167 16 15 16C13.5833 16 12.5 17.0833 12.5 18.5V19.3333H10.8333V18.5C10.8333 16.1667 12.6667 14.3333 15 14.3333C17.3333 14.3333 19.1667 16.1667 19.1667 18.5V19.3333C19.1667 21.3333 17.75 23 15.8333 23.4167V25.1667H14.1667V23.5ZM14.1667 26H15.8333V27.6667H14.1667V26Z" fill="currentColor"/><path opacity="0.3" d="M20.0234 0V9H29L20.0234 0Z" fill="currentColor"/></svg>
1
+ <svg width="66" height="66" viewBox="0 0 66 66" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <ellipse cx="33" cy="53" rx="33" ry="8" fill="#00BBCC" fill-opacity="0.1"/>
3
+ <path d="M35 19.5L12 26V49L35 47.5V19.5Z" fill="#00BBCC" fill-opacity="0.3"/>
4
+ <path d="M55 46.5V25L35 19.5V42L55 46.5Z" fill="#00BBCC" fill-opacity="0.4"/>
5
+ <path d="M54.4179 7.58906L57 9.00955L54.4106 10.4173L52.9909 13L51.5821 10.4109L49 8.99045L51.5894 7.5827L53.0091 5L54.4179 7.58906Z" fill="#00BBCC" fill-opacity="0.4"/>
6
+ <path d="M32 56.0806V32L55 25V48L32 56.0806Z" fill="#7CDBE4"/>
7
+ <path d="M32 56.0806V32L12 26V49L32 56.0806Z" fill="#97E3EA"/>
8
+ <path d="M25 7.5L35 19.5L12 26L2 14L25 7.5Z" fill="#CCF1F5"/>
9
+ <circle cx="35" cy="17.5" r="9" fill="#00BBCC"/>
10
+ <path d="M34.4 19.875V18.625H35C36.02 18.625 36.8 17.8125 36.8 16.75V16.125C36.8 15.0625 36.02 14.25 35 14.25C33.98 14.25 33.2 15.0625 33.2 16.125V16.75H32V16.125C32 14.375 33.32 13 35 13C36.68 13 38 14.375 38 16.125V16.75C38 18.25 36.98 19.5 35.6 19.8125V21.125H34.4V19.875ZM34.4 21.75H35.6V23H34.4V21.75Z" fill="white"/>
11
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
2
+ <path d="M32.5 20.2C31.4 15.7 27.5 12.5 22.8 12.5C18.6 12.5 15 15 13.5 18.6C10 19.1 7.5 22.1 7.5 25.7C7.5 29.6 10.7 32.8 14.6 32.8H32.2C35.6 32.8 38.5 30 38.5 26.5C38.5 23.3 35.9 20.7 32.5 20.2Z" stroke="currentColor" stroke-width="1.75" stroke-linejoin="round"/>
3
+ <path d="M24 22.5V36" stroke="currentColor" stroke-width="1.75" stroke-linecap="round"/>
4
+ <path d="M19.5 27L24 22.5L28.5 27" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
5
+ </svg>
package/src/index.ts CHANGED
@@ -78,7 +78,7 @@ export { default as GcsaMenu } from './components/GcsaMenu.vue';
78
78
  export { default as GcsaPopconfirm } from './components/GcsaPopconfirm.vue';
79
79
 
80
80
  export { useGcsaMessage } from './composables/useGcsaMessage';
81
- export { useGcsaTheme } from './composables/useGcsaTheme';
81
+ export { useGcsaTheme, GCSA_THEME_KEY } from './composables/useGcsaTheme';
82
82
  export { useGcsaComponentSize, useGcsaComponentSizeConfig, useGcsaButtonSize } from './composables/useGcsaComponentSize';
83
83
  export { useGcsaLocale, useGcsaLocaleMessages } from './composables/useGcsaLocale';
84
84
  export { useGcsaZIndex } from './composables/useGcsaZIndex';
@@ -246,6 +246,8 @@ export type GcsaPopoverProps = {
246
246
  portalled?: boolean;
247
247
  gutter?: number;
248
248
  open?: boolean;
249
+ /** 启用 size middleware,写入 --reference-width(Cascader 等需对齐触发器最小宽度) */
250
+ fitViewport?: boolean;
249
251
  size?: GcsaPopoverSize;
250
252
  width?: string | number;
251
253
  minWidth?: string | number;