@veltra/sheet 2.5.0 → 2.5.1
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.
|
@@ -38,6 +38,10 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
38
38
|
const mirroring = ref(false);
|
|
39
39
|
let mirrorAddr = null;
|
|
40
40
|
const fxDraft = ref("");
|
|
41
|
+
/** 鼠标是否悬停在公式栏输入区 */
|
|
42
|
+
const fxHovered = ref(false);
|
|
43
|
+
/** 输入框是否处于 focus 状态 */
|
|
44
|
+
const fxFocused = ref(false);
|
|
41
45
|
/** 输入面板是否因内容增高而浮出(文档流仍保持单行) */
|
|
42
46
|
const fxExpanded = ref(false);
|
|
43
47
|
/** textarea 光标(selectionStart);输入/点击/方向键后同步 */
|
|
@@ -76,7 +80,13 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
76
80
|
}
|
|
77
81
|
function nameText(state) {
|
|
78
82
|
const range = state.ranges[0];
|
|
79
|
-
if (range)
|
|
83
|
+
if (range) {
|
|
84
|
+
if (state.activeCell) {
|
|
85
|
+
const merge = props.sheet.merges.getMergeAt(state.activeCell);
|
|
86
|
+
if (merge && range.start.row === merge.start.row && range.start.col === merge.start.col && range.end.row === merge.end.row && range.end.col === merge.end.col) return formatAddress(state.activeCell);
|
|
87
|
+
}
|
|
88
|
+
return formatRange(range);
|
|
89
|
+
}
|
|
80
90
|
return state.activeCell ? formatAddress(state.activeCell) : "";
|
|
81
91
|
}
|
|
82
92
|
function cellText(addr) {
|
|
@@ -93,7 +103,16 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
93
103
|
fxDraft.value = active ? cellText(active) : "";
|
|
94
104
|
fxCursor.value = fxDraft.value.length;
|
|
95
105
|
closeSuggest();
|
|
96
|
-
scheduleAutosize();
|
|
106
|
+
if (fxHovered.value || fxFocused.value || editing.value) scheduleAutosize();
|
|
107
|
+
else collapseFx();
|
|
108
|
+
}
|
|
109
|
+
/** 恢复单行高度并重置展开状态 */
|
|
110
|
+
function collapseFx() {
|
|
111
|
+
const el = fxRef.value;
|
|
112
|
+
if (!el) return;
|
|
113
|
+
el.style.height = "";
|
|
114
|
+
el.scrollTop = 0;
|
|
115
|
+
fxExpanded.value = false;
|
|
97
116
|
}
|
|
98
117
|
/** 每帧合并一次的 autosizeFx(批量 cell-change 同帧 N 次 nextTick → 1 次强制布局) */
|
|
99
118
|
let autosizePending = false;
|
|
@@ -106,20 +125,33 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
106
125
|
});
|
|
107
126
|
}
|
|
108
127
|
/**
|
|
109
|
-
*
|
|
128
|
+
* 仅在鼠标悬停、获得焦点或编辑时按内容增高浮出面板,不超过 CSS max-height。
|
|
110
129
|
* 增高走绝对定位,公式栏文档流高度始终单行。
|
|
111
130
|
*/
|
|
112
131
|
function autosizeFx() {
|
|
113
132
|
const el = fxRef.value;
|
|
114
133
|
if (!el) return;
|
|
134
|
+
if (!fxHovered.value && !fxFocused.value && !editing.value) {
|
|
135
|
+
collapseFx();
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
115
138
|
el.style.height = "0px";
|
|
116
139
|
const styles = getComputedStyle(el);
|
|
117
140
|
const max = Number.parseFloat(styles.maxHeight);
|
|
118
141
|
const min = Number.parseFloat(styles.minHeight);
|
|
142
|
+
const hasMultipleLines = fxDraft.value.includes("\n");
|
|
119
143
|
const content = el.scrollHeight;
|
|
120
144
|
const next = Number.isFinite(max) && max > 0 ? Math.min(content, max) : content;
|
|
121
145
|
el.style.height = `${next}px`;
|
|
122
|
-
fxExpanded.value = Number.isFinite(min) ? next > min + 1 : next > 1;
|
|
146
|
+
fxExpanded.value = (Number.isFinite(min) ? next > min + 1 : next > 1) || hasMultipleLines;
|
|
147
|
+
}
|
|
148
|
+
function handleFxMouseEnter() {
|
|
149
|
+
fxHovered.value = true;
|
|
150
|
+
if (fxDraft.value) autosizeFx();
|
|
151
|
+
}
|
|
152
|
+
function handleFxMouseLeave() {
|
|
153
|
+
fxHovered.value = false;
|
|
154
|
+
if (!fxFocused.value && !editing.value) collapseFx();
|
|
123
155
|
}
|
|
124
156
|
function syncFxCursor() {
|
|
125
157
|
const el = fxRef.value;
|
|
@@ -193,23 +225,30 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
193
225
|
}
|
|
194
226
|
function handleFxFocus() {
|
|
195
227
|
if (fxDisabled.value) return;
|
|
228
|
+
fxFocused.value = true;
|
|
196
229
|
mirroring.value = false;
|
|
197
230
|
mirrorAddr = null;
|
|
198
231
|
editing.value = true;
|
|
199
232
|
editAddr = selection.value.activeCell;
|
|
200
233
|
syncFxCursor();
|
|
234
|
+
scheduleAutosize();
|
|
201
235
|
}
|
|
202
236
|
/**
|
|
203
237
|
* 失焦提交;引用选择期间(画布 pointerdown 已挂起)跳过。
|
|
204
238
|
* ✓/✗ / 候选列表用 mousedown.prevent 拦截失焦。
|
|
205
239
|
*/
|
|
206
240
|
function handleFxBlur() {
|
|
207
|
-
|
|
241
|
+
fxFocused.value = false;
|
|
242
|
+
if (!editing.value) {
|
|
243
|
+
if (!fxHovered.value) collapseFx();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
208
246
|
if (suppressBlurCommit) {
|
|
209
247
|
suppressBlurCommit = false;
|
|
210
248
|
return;
|
|
211
249
|
}
|
|
212
250
|
commitEdit();
|
|
251
|
+
if (!fxHovered.value) collapseFx();
|
|
213
252
|
}
|
|
214
253
|
function handleFxKeydown(event) {
|
|
215
254
|
if (suggestOpen.value) {
|
|
@@ -345,7 +384,11 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
345
384
|
onKeydown: handleNameKeydown
|
|
346
385
|
}, null, 34), [[vModelText, nameDraft.value]]),
|
|
347
386
|
createElementVNode("span", { class: normalizeClass(unref(cls).e("fx-label")) }, "fx", 2),
|
|
348
|
-
createElementVNode("div", {
|
|
387
|
+
createElementVNode("div", {
|
|
388
|
+
class: normalizeClass(unref(cls).e("fx-editor")),
|
|
389
|
+
onMouseenter: handleFxMouseEnter,
|
|
390
|
+
onMouseleave: handleFxMouseLeave
|
|
391
|
+
}, [createCommentVNode(" 文档流只占单行;面板绝对定位向下浮起,不撑开公式栏 "), createElementVNode("div", { class: normalizeClass([unref(cls).e("fx-input-panel"), unref(bem).is("expanded", fxExpanded.value)]) }, [withDirectives(createElementVNode("textarea", {
|
|
349
392
|
ref_key: "fxRef",
|
|
350
393
|
ref: fxRef,
|
|
351
394
|
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => fxDraft.value = $event),
|
|
@@ -368,7 +411,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
368
411
|
"active-index": suggestIndex.value,
|
|
369
412
|
onSelect: confirmSuggest,
|
|
370
413
|
onHover: _cache[3] || (_cache[3] = (i) => suggestIndex.value = i)
|
|
371
|
-
}, null, 8, ["items", "active-index"])], 2)],
|
|
414
|
+
}, null, 8, ["items", "active-index"])], 2)], 34),
|
|
372
415
|
editing.value ? (openBlock(), createElementBlock("button", {
|
|
373
416
|
key: 0,
|
|
374
417
|
type: "button",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* --u-height-default: 32px;
|
|
15
15
|
* --u-height-small: 24px;
|
|
16
16
|
*/
|
|
17
|
-
/**
|
|
17
|
+
/** 暗色:`UITheme.render()` 按主题系列写入 html[data-theme] */
|
|
18
18
|
.u-sheet {
|
|
19
19
|
position: relative;
|
|
20
20
|
display: flex;
|
|
@@ -246,7 +246,7 @@
|
|
|
246
246
|
line-height: 1.4;
|
|
247
247
|
resize: none;
|
|
248
248
|
overflow-x: hidden;
|
|
249
|
-
overflow-y:
|
|
249
|
+
overflow-y: hidden;
|
|
250
250
|
outline: none;
|
|
251
251
|
}
|
|
252
252
|
.u-sheet__fx-input:focus {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veltra/sheet",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"homepage": "https://github.com/cabinet-fe/ultra-ui#readme",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/cabinet-fe/ultra-ui/issues"
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"@cat-kit/core": ">=1.1.8",
|
|
38
38
|
"@cat-kit/fe": ">=1.1.8",
|
|
39
|
-
"@veltra/desktop": "^1.
|
|
39
|
+
"@veltra/desktop": "^1.7.0",
|
|
40
40
|
"@veltra/icons": "^1.5.0",
|
|
41
|
-
"@veltra/sheet-core": "^2.5.
|
|
42
|
-
"@veltra/styles": "^1.
|
|
43
|
-
"@veltra/utils": "^1.
|
|
41
|
+
"@veltra/sheet-core": "^2.5.1",
|
|
42
|
+
"@veltra/styles": "^1.7.0",
|
|
43
|
+
"@veltra/utils": "^1.7.0",
|
|
44
44
|
"vue": ">=3.5.41"
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -471,4 +471,33 @@ describe('USheet 公式栏:函数补全与引用选择', () => {
|
|
|
471
471
|
await nextTick()
|
|
472
472
|
expect(fxInput(el).value).toBe('=A1+B1')
|
|
473
473
|
})
|
|
474
|
+
|
|
475
|
+
it('多行文本:默认保持单行高度,鼠标进入展开,移出后收起', async () => {
|
|
476
|
+
const workbook = new Workbook()
|
|
477
|
+
const sheet = workbook.activeSheet
|
|
478
|
+
sheet.setCellValue({ row: 0, col: 0 }, 'Line1\nLine2\nLine3\nLine4\nLine5')
|
|
479
|
+
const { el } = mount(() => ({ workbook, rows: 20, cols: 8 }))
|
|
480
|
+
await nextTick()
|
|
481
|
+
sheet.selectCell({ row: 0, col: 0 })
|
|
482
|
+
await nextTick()
|
|
483
|
+
|
|
484
|
+
const input = fxInput(el)
|
|
485
|
+
const panel = el.querySelector('.u-sheet__fx-input-panel')!
|
|
486
|
+
const editor = el.querySelector('.u-sheet__fx-editor')!
|
|
487
|
+
|
|
488
|
+
// 默认单行未展开,无 is-expanded 类,height 为空(由 CSS min-height 承载)
|
|
489
|
+
expect(panel.classList.contains('is-expanded')).toBe(false)
|
|
490
|
+
expect(input.style.height).toBe('')
|
|
491
|
+
|
|
492
|
+
// 鼠标移入公式栏编辑区:触发展开
|
|
493
|
+
editor.dispatchEvent(new MouseEvent('mouseenter'))
|
|
494
|
+
await nextTick()
|
|
495
|
+
expect(panel.classList.contains('is-expanded')).toBe(true)
|
|
496
|
+
|
|
497
|
+
// 鼠标移出公式栏编辑区:收起为单行
|
|
498
|
+
editor.dispatchEvent(new MouseEvent('mouseleave'))
|
|
499
|
+
await nextTick()
|
|
500
|
+
expect(panel.classList.contains('is-expanded')).toBe(false)
|
|
501
|
+
expect(input.style.height).toBe('')
|
|
502
|
+
})
|
|
474
503
|
})
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
@keydown="handleNameKeydown"
|
|
12
12
|
/>
|
|
13
13
|
<span :class="cls.e('fx-label')">fx</span>
|
|
14
|
-
<div
|
|
14
|
+
<div
|
|
15
|
+
:class="cls.e('fx-editor')"
|
|
16
|
+
@mouseenter="handleFxMouseEnter"
|
|
17
|
+
@mouseleave="handleFxMouseLeave"
|
|
18
|
+
>
|
|
15
19
|
<!-- 文档流只占单行;面板绝对定位向下浮起,不撑开公式栏 -->
|
|
16
20
|
<div :class="[cls.e('fx-input-panel'), bem.is('expanded', fxExpanded)]">
|
|
17
21
|
<textarea
|
|
@@ -122,6 +126,10 @@ let editAddr: CellAddress | null = null
|
|
|
122
126
|
const mirroring = ref(false)
|
|
123
127
|
let mirrorAddr: CellAddress | null = null
|
|
124
128
|
const fxDraft = ref('')
|
|
129
|
+
/** 鼠标是否悬停在公式栏输入区 */
|
|
130
|
+
const fxHovered = ref(false)
|
|
131
|
+
/** 输入框是否处于 focus 状态 */
|
|
132
|
+
const fxFocused = ref(false)
|
|
125
133
|
/** 输入面板是否因内容增高而浮出(文档流仍保持单行) */
|
|
126
134
|
const fxExpanded = ref(false)
|
|
127
135
|
/** textarea 光标(selectionStart);输入/点击/方向键后同步 */
|
|
@@ -170,7 +178,21 @@ function handleRefSelect(range: CellRange): void {
|
|
|
170
178
|
|
|
171
179
|
function nameText(state: SelectionState): string {
|
|
172
180
|
const range = state.ranges[0]
|
|
173
|
-
if (range)
|
|
181
|
+
if (range) {
|
|
182
|
+
if (state.activeCell) {
|
|
183
|
+
const merge = props.sheet.merges.getMergeAt(state.activeCell)
|
|
184
|
+
if (
|
|
185
|
+
merge &&
|
|
186
|
+
range.start.row === merge.start.row &&
|
|
187
|
+
range.start.col === merge.start.col &&
|
|
188
|
+
range.end.row === merge.end.row &&
|
|
189
|
+
range.end.col === merge.end.col
|
|
190
|
+
) {
|
|
191
|
+
return formatAddress(state.activeCell)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return formatRange(range)
|
|
195
|
+
}
|
|
174
196
|
return state.activeCell ? formatAddress(state.activeCell) : ''
|
|
175
197
|
}
|
|
176
198
|
|
|
@@ -190,7 +212,20 @@ function refreshFx(): void {
|
|
|
190
212
|
fxDraft.value = active ? cellText(active) : ''
|
|
191
213
|
fxCursor.value = fxDraft.value.length
|
|
192
214
|
closeSuggest()
|
|
193
|
-
|
|
215
|
+
if (fxHovered.value || fxFocused.value || editing.value) {
|
|
216
|
+
scheduleAutosize()
|
|
217
|
+
} else {
|
|
218
|
+
collapseFx()
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** 恢复单行高度并重置展开状态 */
|
|
223
|
+
function collapseFx(): void {
|
|
224
|
+
const el = fxRef.value
|
|
225
|
+
if (!el) return
|
|
226
|
+
el.style.height = ''
|
|
227
|
+
el.scrollTop = 0
|
|
228
|
+
fxExpanded.value = false
|
|
194
229
|
}
|
|
195
230
|
|
|
196
231
|
/** 每帧合并一次的 autosizeFx(批量 cell-change 同帧 N 次 nextTick → 1 次强制布局) */
|
|
@@ -205,20 +240,39 @@ function scheduleAutosize(): void {
|
|
|
205
240
|
}
|
|
206
241
|
|
|
207
242
|
/**
|
|
208
|
-
*
|
|
243
|
+
* 仅在鼠标悬停、获得焦点或编辑时按内容增高浮出面板,不超过 CSS max-height。
|
|
209
244
|
* 增高走绝对定位,公式栏文档流高度始终单行。
|
|
210
245
|
*/
|
|
211
246
|
function autosizeFx(): void {
|
|
212
247
|
const el = fxRef.value
|
|
213
248
|
if (!el) return
|
|
249
|
+
if (!fxHovered.value && !fxFocused.value && !editing.value) {
|
|
250
|
+
collapseFx()
|
|
251
|
+
return
|
|
252
|
+
}
|
|
214
253
|
el.style.height = '0px'
|
|
215
254
|
const styles = getComputedStyle(el)
|
|
216
255
|
const max = Number.parseFloat(styles.maxHeight)
|
|
217
256
|
const min = Number.parseFloat(styles.minHeight)
|
|
257
|
+
const hasMultipleLines = fxDraft.value.includes('\n')
|
|
218
258
|
const content = el.scrollHeight
|
|
219
259
|
const next = Number.isFinite(max) && max > 0 ? Math.min(content, max) : content
|
|
220
260
|
el.style.height = `${next}px`
|
|
221
|
-
fxExpanded.value = Number.isFinite(min) ? next > min + 1 : next > 1
|
|
261
|
+
fxExpanded.value = (Number.isFinite(min) ? next > min + 1 : next > 1) || hasMultipleLines
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function handleFxMouseEnter(): void {
|
|
265
|
+
fxHovered.value = true
|
|
266
|
+
if (fxDraft.value) {
|
|
267
|
+
autosizeFx()
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function handleFxMouseLeave(): void {
|
|
272
|
+
fxHovered.value = false
|
|
273
|
+
if (!fxFocused.value && !editing.value) {
|
|
274
|
+
collapseFx()
|
|
275
|
+
}
|
|
222
276
|
}
|
|
223
277
|
|
|
224
278
|
function syncFxCursor(): void {
|
|
@@ -311,11 +365,13 @@ function commitName(): void {
|
|
|
311
365
|
|
|
312
366
|
function handleFxFocus(): void {
|
|
313
367
|
if (fxDisabled.value) return
|
|
368
|
+
fxFocused.value = true
|
|
314
369
|
mirroring.value = false
|
|
315
370
|
mirrorAddr = null
|
|
316
371
|
editing.value = true
|
|
317
372
|
editAddr = selection.value.activeCell
|
|
318
373
|
syncFxCursor()
|
|
374
|
+
scheduleAutosize()
|
|
319
375
|
}
|
|
320
376
|
|
|
321
377
|
/**
|
|
@@ -323,12 +379,17 @@ function handleFxFocus(): void {
|
|
|
323
379
|
* ✓/✗ / 候选列表用 mousedown.prevent 拦截失焦。
|
|
324
380
|
*/
|
|
325
381
|
function handleFxBlur(): void {
|
|
326
|
-
|
|
382
|
+
fxFocused.value = false
|
|
383
|
+
if (!editing.value) {
|
|
384
|
+
if (!fxHovered.value) collapseFx()
|
|
385
|
+
return
|
|
386
|
+
}
|
|
327
387
|
if (suppressBlurCommit) {
|
|
328
388
|
suppressBlurCommit = false
|
|
329
389
|
return
|
|
330
390
|
}
|
|
331
391
|
commitEdit()
|
|
392
|
+
if (!fxHovered.value) collapseFx()
|
|
332
393
|
}
|
|
333
394
|
|
|
334
395
|
function handleFxKeydown(event: KeyboardEvent): void {
|