niuma-ui 1.1.3 → 1.1.6
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/CHANGELOG.md +41 -1
- package/package.json +5 -1
- package/src/__tests__/RsDialog.spec.ts +13 -0
- package/src/__tests__/RsIcon.spec.ts +14 -0
- package/src/__tests__/RsSelect.spec.ts +96 -0
- package/src/__tests__/RsTable.spec.ts +17 -0
- package/src/__tests__/createRsDialog.spec.ts +17 -4
- package/src/components/RsDialog.vue +14 -9
- package/src/components/RsMonacoEditor.vue +14 -4
- package/src/components/RsSelect.vue +10 -0
- package/src/components/RsTerminal.vue +182 -78
- package/src/components/dialog-utils.ts +3 -2
- package/src/components/table/rs-table.css +3 -3
- package/src/components/table-utils.ts +2 -2
- package/src/components/terminal-utils.ts +22 -0
- package/src/components/terminal-wheel.ts +32 -7
- package/src/components/use-rs-select.ts +17 -2
- package/src/composables/createRsDialog.ts +58 -7
- package/src/composables/useRsTableEditLayer.ts +1 -1
- package/src/composables/useTableCellTooltip.ts +4 -3
- package/src/dev/vite-xterm-deps.ts +8 -0
- package/src/icons/custom/postgres.ts +52 -0
- package/src/icons/lucide.ts +2 -0
- package/src/index.ts +3 -0
- package/src/monaco/index.ts +1 -0
- package/src/monaco/languages/index.ts +1 -0
- package/src/monaco/languages/types.ts +4 -0
- package/src/styles.css +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,43 @@
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.1.6] - 2026-08-20
|
|
10
|
+
|
|
11
|
+
### 变更
|
|
12
|
+
|
|
13
|
+
- `package.json` 增加 `sideEffects`(仅 CSS):宿主从入口 barrel 按需导入时,可摇掉未使用的 Monaco / Terminal / CodeMirror。按文档具名导入并引入 `niuma-ui/styles.css` 的用法不受影响。
|
|
14
|
+
|
|
15
|
+
## [1.1.5] - 2026-08-19
|
|
16
|
+
|
|
17
|
+
### 修复
|
|
18
|
+
|
|
19
|
+
- 命令式 `rsConfirm` / `openRsDialog`:销毁改为幂等,并在测试收尾走正规 `unmount`(不再先拆 Teleport 节点)。避免 Vue 卸载时 `nextSibling` 未处理异常导致 CI 失败。
|
|
20
|
+
|
|
21
|
+
## [1.1.4] - 2026-08-19
|
|
22
|
+
|
|
23
|
+
### 新增
|
|
24
|
+
|
|
25
|
+
- `RsDialog`:`layout="form"` 作为居中轻量表单/说明窗的正式布局;`layout="confirm"` 仍可用,开发环境继续警告并视作 form 的历史别名。确认/提示请用 `RsConfirmDialog` / `rsConfirm`。
|
|
26
|
+
- `RsSelect.fillSearchWithValue`:打开下拉时把当前选中项写入搜索框并参与过滤(默认 `false`,搜索框保持空白)。
|
|
27
|
+
- **RsIcon `postgres`**:PostgreSQL 官方大象品牌图标,token `--rs-icon-postgres-accent`。
|
|
28
|
+
- `MONACO_POSTGRESQL_LANGUAGE`(`postgresql`):官方 PostgreSQL 的 Monaco languageId,走 Bridge LSP;`RsMonacoEditor` 对 postgresql / clickhouse / sqlite / sqlserver / oracle 同样不再注册实例级补全。
|
|
29
|
+
- `RsTerminal`:`selectionChange` 事件;expose `getSelection` / `hasSelection` / `getGeometry` 与类型 `RsTerminalExpose` / `RsTerminalGeometry`。
|
|
30
|
+
- `src/dev/vite-xterm-deps.ts`:供宿主 Vite `optimizeDeps` 预构建 xterm,避免控制台首次加载 504。
|
|
31
|
+
|
|
32
|
+
### 变更
|
|
33
|
+
|
|
34
|
+
- `RsSelect`:`filterOption` 默认 `true`(修复 Vue 把 boolean 联合类型当成 Boolean prop,未传入即 `false`、可搜索列表永远不过滤)。
|
|
35
|
+
- `RsSelect`:`searchable` 一律走本地过滤并关掉 Reka 内置 filter,避免手输关键字时匹配项被挡住。
|
|
36
|
+
- `RsTerminal`:`inheritAttrs: false`,`class` / `style` 落到 `.rs-terminal`;`wheelScrollModifier="shift"` 仅在备用屏(vim/top)把滚轮转成方向键,普通 shell 滚历史。
|
|
37
|
+
- `RsTableColumn.tooltip`:只写格子里看不到的额外提示;可见文本被截断时用 `ellipsis`。
|
|
38
|
+
- `RsMonacoEditor`:当前行高亮改为整行 `line`(不再只画 gutter)。
|
|
39
|
+
|
|
40
|
+
### 修复
|
|
41
|
+
|
|
42
|
+
- `RsTable`:自定义 slot + `ellipsis` 也能挂溢出 tooltip;slot 不再 `max-width: 100%` 导致溢出检测失效。
|
|
43
|
+
- `RsTable` 共享 tooltip:z-index 改为 `--rs-z-dropdown`;`findTipHost` 兼容文本节点,避免悬停到文字时丢宿主。
|
|
44
|
+
- `RsTerminal`:宿主负字距不再让 xterm 行尾被裁;xterm 6 空 viewport 滚动条不再挡住最后一列;滑块对齐 RsScrollbar;flex 项 `min-width: 0` 以便列数随容器收缩。
|
|
45
|
+
|
|
9
46
|
## [1.1.3] - 2026-08-14
|
|
10
47
|
|
|
11
48
|
### 新增
|
|
@@ -122,7 +159,10 @@
|
|
|
122
159
|
|
|
123
160
|
- 1.0 之前的私有 tag(如 `v0.1.0`)仅作历史记录;新接入请依赖 `v1.0.0` 及之后版本。
|
|
124
161
|
|
|
125
|
-
[Unreleased]: https://github.com/Blair-Shang/niuma-ui/compare/v1.1.
|
|
162
|
+
[Unreleased]: https://github.com/Blair-Shang/niuma-ui/compare/v1.1.6...HEAD
|
|
163
|
+
[1.1.6]: https://github.com/Blair-Shang/niuma-ui/releases/tag/v1.1.6
|
|
164
|
+
[1.1.5]: https://github.com/Blair-Shang/niuma-ui/releases/tag/v1.1.5
|
|
165
|
+
[1.1.4]: https://github.com/Blair-Shang/niuma-ui/releases/tag/v1.1.4
|
|
126
166
|
[1.1.3]: https://github.com/Blair-Shang/niuma-ui/releases/tag/v1.1.3
|
|
127
167
|
[1.1.2]: https://github.com/Blair-Shang/niuma-ui/releases/tag/v1.1.2
|
|
128
168
|
[1.1.1]: https://github.com/Blair-Shang/niuma-ui/releases/tag/v1.1.1
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "niuma-ui",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Vue 3 设计系统与 Rs* 组件库(--rs-* token)",
|
|
@@ -44,6 +44,10 @@
|
|
|
44
44
|
"README.en.md",
|
|
45
45
|
"CHANGELOG.md"
|
|
46
46
|
],
|
|
47
|
+
"sideEffects": [
|
|
48
|
+
"**/*.css",
|
|
49
|
+
"**/*.scss"
|
|
50
|
+
],
|
|
47
51
|
"peerDependencies": {
|
|
48
52
|
"vue": "^3.5.39"
|
|
49
53
|
},
|
|
@@ -107,10 +107,23 @@ describe('RsDialog', () => {
|
|
|
107
107
|
await flushPromises()
|
|
108
108
|
const content = document.body.querySelector('.rs-dialog__content')
|
|
109
109
|
expect(content?.classList.contains('rs-dialog__content--confirm')).toBe(true)
|
|
110
|
+
expect(content?.classList.contains('rs-dialog__content--form')).toBe(true)
|
|
110
111
|
expect(content?.classList.contains('rs-dialog__content--sm')).toBe(true)
|
|
111
112
|
wrapper.unmount()
|
|
112
113
|
})
|
|
113
114
|
|
|
115
|
+
it('applies form layout without confirm deprecation class-only alias', async () => {
|
|
116
|
+
const wrapper = mount(RsDialog, {
|
|
117
|
+
props: { open: true, title: '表单', width: 'sm', layout: 'form', resizable: false, fullscreenable: false },
|
|
118
|
+
attachTo: document.body,
|
|
119
|
+
})
|
|
120
|
+
await flushPromises()
|
|
121
|
+
const content = document.body.querySelector('.rs-dialog__content')
|
|
122
|
+
expect(content?.classList.contains('rs-dialog__content--form')).toBe(true)
|
|
123
|
+
expect(content?.classList.contains('rs-dialog__content--confirm')).toBe(false)
|
|
124
|
+
wrapper.unmount()
|
|
125
|
+
})
|
|
126
|
+
|
|
114
127
|
it('renders footer slot', async () => {
|
|
115
128
|
const wrapper = mount(RsDialog, {
|
|
116
129
|
props: { open: true, title: '保存' },
|
|
@@ -109,6 +109,15 @@ describe('RsIcon', () => {
|
|
|
109
109
|
expect(isRsIconName('sqlserver')).toBe(true)
|
|
110
110
|
})
|
|
111
111
|
|
|
112
|
+
it('loads custom postgres icon', () => {
|
|
113
|
+
const icon = resolveLucideIcon('postgres')
|
|
114
|
+
expect(icon).toBeTruthy()
|
|
115
|
+
const wrapper = mount(RsIcon, { props: { name: 'postgres' } })
|
|
116
|
+
expect(wrapper.find('svg.rs-icon').exists()).toBe(true)
|
|
117
|
+
expect(wrapper.find('.postgres-icon__mark').exists()).toBe(true)
|
|
118
|
+
expect(isRsIconName('postgres')).toBe(true)
|
|
119
|
+
})
|
|
120
|
+
|
|
112
121
|
it('loads arbitrary lucide icon by name', () => {
|
|
113
122
|
const icon = resolveLucideIcon('trash-2')
|
|
114
123
|
expect(icon).toBeTruthy()
|
|
@@ -205,6 +214,11 @@ describe('RsIcon', () => {
|
|
|
205
214
|
expect(wrapper.find('svg').attributes('style')).toContain('--rs-icon-sqlserver-accent: #34C759')
|
|
206
215
|
})
|
|
207
216
|
|
|
217
|
+
it('applies accent color to custom postgres icon', () => {
|
|
218
|
+
const wrapper = mount(RsIcon, { props: { name: 'postgres', color: '#34C759' } })
|
|
219
|
+
expect(wrapper.find('svg').attributes('style')).toContain('--rs-icon-postgres-accent: #34C759')
|
|
220
|
+
})
|
|
221
|
+
|
|
208
222
|
it('applies rotate transform', () => {
|
|
209
223
|
const wrapper = mount(RsIcon, { props: { name: 'chevron-right', rotate: 90 } })
|
|
210
224
|
expect(wrapper.find('svg').attributes('style')).toContain('rotate(90deg)')
|
|
@@ -296,6 +296,68 @@ describe('RsSelect', () => {
|
|
|
296
296
|
expect(root.props('ignoreFilter')).toBe(true)
|
|
297
297
|
})
|
|
298
298
|
|
|
299
|
+
it('enables manual filter when searchable so query hides non-matches', async () => {
|
|
300
|
+
const typeOptions = [
|
|
301
|
+
{ label: 'INT', value: 'INT' },
|
|
302
|
+
{ label: 'BIGINT', value: 'BIGINT' },
|
|
303
|
+
{ label: 'NVARCHAR', value: 'NVARCHAR' },
|
|
304
|
+
{ label: 'NVARCHAR(MAX)', value: 'NVARCHAR(MAX)' },
|
|
305
|
+
]
|
|
306
|
+
const wrapper = mount(RsSelect, {
|
|
307
|
+
props: {
|
|
308
|
+
options: typeOptions,
|
|
309
|
+
modelValue: 'BIGINT',
|
|
310
|
+
searchable: true,
|
|
311
|
+
creatable: true,
|
|
312
|
+
},
|
|
313
|
+
attachTo: document.body,
|
|
314
|
+
})
|
|
315
|
+
const root = wrapper.getComponent({ name: 'ComboboxRoot' })
|
|
316
|
+
expect(root.props('ignoreFilter')).toBe(true)
|
|
317
|
+
|
|
318
|
+
await wrapper.find('.rs-select__trigger').trigger('click')
|
|
319
|
+
await flushPromises()
|
|
320
|
+
const input = document.querySelector('.rs-select__search') as HTMLInputElement | null
|
|
321
|
+
expect(input).toBeTruthy()
|
|
322
|
+
input!.value = 'NVA'
|
|
323
|
+
input!.dispatchEvent(new Event('input', { bubbles: true }))
|
|
324
|
+
await flushPromises()
|
|
325
|
+
|
|
326
|
+
const labels = [...document.querySelectorAll('.rs-select__item-label')].map(
|
|
327
|
+
(el) => el.textContent?.trim() ?? '',
|
|
328
|
+
)
|
|
329
|
+
expect(labels).toContain('NVARCHAR')
|
|
330
|
+
expect(labels).toContain('NVARCHAR(MAX)')
|
|
331
|
+
expect(labels).not.toContain('INT')
|
|
332
|
+
expect(labels).not.toContain('BIGINT')
|
|
333
|
+
expect(document.querySelector('.rs-select__item--create')?.textContent).toContain('NVA')
|
|
334
|
+
wrapper.unmount()
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('filterOption false keeps the full list while typing', async () => {
|
|
338
|
+
const wrapper = mount(RsSelect, {
|
|
339
|
+
props: {
|
|
340
|
+
options,
|
|
341
|
+
modelValue: '',
|
|
342
|
+
searchable: true,
|
|
343
|
+
filterOption: false,
|
|
344
|
+
},
|
|
345
|
+
attachTo: document.body,
|
|
346
|
+
})
|
|
347
|
+
await wrapper.find('.rs-select__trigger').trigger('click')
|
|
348
|
+
await flushPromises()
|
|
349
|
+
const input = document.querySelector('.rs-select__search') as HTMLInputElement | null
|
|
350
|
+
input!.value = 'zzz'
|
|
351
|
+
input!.dispatchEvent(new Event('input', { bubbles: true }))
|
|
352
|
+
await flushPromises()
|
|
353
|
+
const labels = [...document.querySelectorAll('.rs-select__item-label')].map(
|
|
354
|
+
(el) => el.textContent?.trim() ?? '',
|
|
355
|
+
)
|
|
356
|
+
expect(labels).toContain('GPT-4o')
|
|
357
|
+
expect(labels).toContain('Claude')
|
|
358
|
+
wrapper.unmount()
|
|
359
|
+
})
|
|
360
|
+
|
|
299
361
|
it('creatable enables search and commits typed value on Enter', async () => {
|
|
300
362
|
const wrapper = mount(RsSelect, {
|
|
301
363
|
props: { options, modelValue: '', creatable: true },
|
|
@@ -574,6 +636,40 @@ describe('RsSelect', () => {
|
|
|
574
636
|
wrapper.unmount()
|
|
575
637
|
})
|
|
576
638
|
|
|
639
|
+
it('does not fill search with the selected value when opening', async () => {
|
|
640
|
+
const wrapper = mount(RsSelect, {
|
|
641
|
+
props: { options, modelValue: 'claude', searchable: true },
|
|
642
|
+
attachTo: document.body,
|
|
643
|
+
})
|
|
644
|
+
await wrapper.find('.rs-select__trigger').trigger('click')
|
|
645
|
+
await flushPromises()
|
|
646
|
+
const input = document.querySelector('.rs-select__search') as HTMLInputElement | null
|
|
647
|
+
expect(input?.value).toBe('')
|
|
648
|
+
const labels = [...document.querySelectorAll('.rs-select__item-label')].map(
|
|
649
|
+
(el) => el.textContent?.trim() ?? '',
|
|
650
|
+
)
|
|
651
|
+
expect(labels).toContain('GPT-4o')
|
|
652
|
+
expect(labels).toContain('Claude')
|
|
653
|
+
wrapper.unmount()
|
|
654
|
+
})
|
|
655
|
+
|
|
656
|
+
it('fills search with the selected label when fillSearchWithValue', async () => {
|
|
657
|
+
const wrapper = mount(RsSelect, {
|
|
658
|
+
props: { options, modelValue: 'claude', searchable: true, fillSearchWithValue: true },
|
|
659
|
+
attachTo: document.body,
|
|
660
|
+
})
|
|
661
|
+
await wrapper.find('.rs-select__trigger').trigger('click')
|
|
662
|
+
await flushPromises()
|
|
663
|
+
const input = document.querySelector('.rs-select__search') as HTMLInputElement | null
|
|
664
|
+
expect(input?.value).toBe('Claude')
|
|
665
|
+
const labels = [...document.querySelectorAll('.rs-select__item-label')].map(
|
|
666
|
+
(el) => el.textContent?.trim() ?? '',
|
|
667
|
+
)
|
|
668
|
+
expect(labels).toContain('Claude')
|
|
669
|
+
expect(labels).not.toContain('GPT-4o')
|
|
670
|
+
wrapper.unmount()
|
|
671
|
+
})
|
|
672
|
+
|
|
577
673
|
it('renders dropdownRender instead of the default panel body', async () => {
|
|
578
674
|
const wrapper = mount(RsSelect, {
|
|
579
675
|
props: { options, modelValue: '' },
|
|
@@ -372,6 +372,23 @@ describe('RsTable', () => {
|
|
|
372
372
|
expect(cell.attributes('style')).toContain('width: 80px')
|
|
373
373
|
})
|
|
374
374
|
|
|
375
|
+
it('attaches overflow tooltip on slotted ellipsis columns', () => {
|
|
376
|
+
const wrapper = mount(RsTable, {
|
|
377
|
+
props: {
|
|
378
|
+
columns: [{ key: 'name', title: '名称', ellipsis: true, width: 80 }],
|
|
379
|
+
data: [{ id: '1', name: '很长的名字' }],
|
|
380
|
+
},
|
|
381
|
+
slots: {
|
|
382
|
+
name: ({ row }: { row: { name: string } }) => row.name,
|
|
383
|
+
},
|
|
384
|
+
})
|
|
385
|
+
const tip = wrapper.find('.rs-table__cell-tip')
|
|
386
|
+
expect(tip.exists()).toBe(true)
|
|
387
|
+
expect(tip.attributes('data-rs-table-tip-mode')).toBe('overflow')
|
|
388
|
+
expect(tip.attributes('data-rs-table-tip-text')).toBe('很长的名字')
|
|
389
|
+
wrapper.unmount()
|
|
390
|
+
})
|
|
391
|
+
|
|
375
392
|
it('shows shared cell tooltip on ellipsis overflow hover', async () => {
|
|
376
393
|
vi.useFakeTimers()
|
|
377
394
|
const wrapper = mount(RsTable, {
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { h } from 'vue'
|
|
2
2
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
3
3
|
import { flushPromises } from '@vue/test-utils'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
destroyAllRsDialogHosts,
|
|
6
|
+
openRsDialog,
|
|
7
|
+
rsConfirm,
|
|
8
|
+
} from '../composables/createRsDialog'
|
|
5
9
|
|
|
6
10
|
describe('createRsDialog', () => {
|
|
7
11
|
afterEach(() => {
|
|
8
|
-
|
|
9
|
-
el.closest('body > div')?.remove()
|
|
10
|
-
})
|
|
12
|
+
destroyAllRsDialogHosts()
|
|
11
13
|
})
|
|
12
14
|
|
|
13
15
|
it('rsConfirm resolves true when confirm clicked', async () => {
|
|
@@ -83,6 +85,17 @@ describe('createRsDialog', () => {
|
|
|
83
85
|
await expect(promise).resolves.toBe(true)
|
|
84
86
|
})
|
|
85
87
|
|
|
88
|
+
it('destroy does not throw after portal node was removed', async () => {
|
|
89
|
+
const handle = openRsDialog({
|
|
90
|
+
title: '残留',
|
|
91
|
+
showOverlay: false,
|
|
92
|
+
body: () => 'portal',
|
|
93
|
+
})
|
|
94
|
+
await flushPromises()
|
|
95
|
+
document.body.querySelector('.rs-dialog__content')?.closest('body > div')?.remove()
|
|
96
|
+
expect(() => handle.destroy()).not.toThrow()
|
|
97
|
+
})
|
|
98
|
+
|
|
86
99
|
it('openRsDialog mounts builtin footer and can destroy', async () => {
|
|
87
100
|
const handle = openRsDialog({
|
|
88
101
|
title: '命令式',
|
|
@@ -47,13 +47,14 @@ const props = withDefaults(
|
|
|
47
47
|
/**
|
|
48
48
|
* 宽度:`sm` / `md` / `lg`,或 number(px) / `px` / `rem` / `%`。
|
|
49
49
|
* window:打开时折成像素后居中(`%` 相对视口扣除 inset),之后可拖拽缩放。
|
|
50
|
-
* confirm:自定义宽度按 CSS 写入。
|
|
50
|
+
* form / confirm:自定义宽度按 CSS 写入。
|
|
51
51
|
*/
|
|
52
52
|
width?: RsDialogWidth
|
|
53
53
|
tone?: RsFeedbackTone
|
|
54
54
|
/**
|
|
55
|
-
* window
|
|
56
|
-
*
|
|
55
|
+
* window:可拖拽/缩放工作窗。
|
|
56
|
+
* form:居中轻量表单/说明窗(高度随内容,默认不可缩放)。
|
|
57
|
+
* confirm:历史别名,等同 form;确认/提示请用 RsConfirmDialog。
|
|
57
58
|
*/
|
|
58
59
|
layout?: RsDialogLayout
|
|
59
60
|
draggable?: boolean
|
|
@@ -143,8 +144,8 @@ const attrs = useAttrs()
|
|
|
143
144
|
const slots = useSlots()
|
|
144
145
|
const { t } = useRsI18n()
|
|
145
146
|
|
|
146
|
-
const
|
|
147
|
-
const
|
|
147
|
+
const isCompactLayout = computed(() => props.layout === 'form' || props.layout === 'confirm')
|
|
148
|
+
const isWindowLayout = computed(() => !isCompactLayout.value)
|
|
148
149
|
const enableDraggable = computed(() => props.draggable && isWindowLayout.value)
|
|
149
150
|
const enableResizable = computed(() => props.resizable && isWindowLayout.value)
|
|
150
151
|
const deferBodyMount = computed(() => props.deferBodyMount ?? isWindowLayout.value)
|
|
@@ -263,7 +264,8 @@ const contentClass = computed(() => {
|
|
|
263
264
|
? `rs-dialog__content--${props.width}`
|
|
264
265
|
: 'rs-dialog__content--custom-width'
|
|
265
266
|
return [
|
|
266
|
-
|
|
267
|
+
isCompactLayout.value ? 'rs-dialog__content--form' : 'rs-dialog__content--window',
|
|
268
|
+
props.layout === 'confirm' ? 'rs-dialog__content--confirm' : undefined,
|
|
267
269
|
presetClass,
|
|
268
270
|
`rs-dialog__content--tone-${props.tone}`,
|
|
269
271
|
{
|
|
@@ -368,7 +370,7 @@ const {
|
|
|
368
370
|
initialWidth: initialWidthPx,
|
|
369
371
|
draggable: enableDraggable,
|
|
370
372
|
resizable: enableResizable,
|
|
371
|
-
compact:
|
|
373
|
+
compact: isCompactLayout,
|
|
372
374
|
boundsTransition: toRef(props, 'boundsTransition'),
|
|
373
375
|
})
|
|
374
376
|
|
|
@@ -551,7 +553,8 @@ defineExpose({
|
|
|
551
553
|
color: var(--rs-dialog-title-fg);
|
|
552
554
|
}
|
|
553
555
|
|
|
554
|
-
/* 亮色
|
|
556
|
+
/* 亮色 form:轻微 vibrancy;window 用实底避免 CEF 下 blur 合成开销 */
|
|
557
|
+
[data-rs-theme='light'] .rs-dialog__content--form,
|
|
555
558
|
[data-rs-theme='light'] .rs-dialog__content--confirm {
|
|
556
559
|
background: color-mix(in srgb, var(--rs-dialog-bg) 94%, transparent);
|
|
557
560
|
backdrop-filter: blur(24px) saturate(180%);
|
|
@@ -560,10 +563,12 @@ defineExpose({
|
|
|
560
563
|
[data-rs-theme='light'] .rs-dialog__content--window {
|
|
561
564
|
background: var(--rs-dialog-bg);
|
|
562
565
|
}
|
|
563
|
-
/*
|
|
566
|
+
/* form 布局:缩放 + 淡入(居中,含 translate);苹果 sheet 缓动曲线 */
|
|
567
|
+
.rs-dialog__content--form[data-state='open'],
|
|
564
568
|
.rs-dialog__content--confirm[data-state='open'] {
|
|
565
569
|
animation: rs-dialog-pop-in 240ms cubic-bezier(0.32, 0.72, 0, 1);
|
|
566
570
|
}
|
|
571
|
+
.rs-dialog__content--form[data-state='closed'],
|
|
567
572
|
.rs-dialog__content--confirm[data-state='closed'] {
|
|
568
573
|
animation: rs-dialog-pop-out 180ms ease;
|
|
569
574
|
}
|
|
@@ -10,6 +10,11 @@ import {
|
|
|
10
10
|
MONACO_MYSQL_LANGUAGE,
|
|
11
11
|
MONACO_DAMENG_LANGUAGE,
|
|
12
12
|
MONACO_KINGBASE_LANGUAGE,
|
|
13
|
+
MONACO_POSTGRESQL_LANGUAGE,
|
|
14
|
+
MONACO_CLICKHOUSE_LANGUAGE,
|
|
15
|
+
MONACO_SQLITE_LSP_LANGUAGE,
|
|
16
|
+
MONACO_SQLSERVER_LANGUAGE,
|
|
17
|
+
MONACO_ORACLE_LANGUAGE,
|
|
13
18
|
} from '../monaco/languages'
|
|
14
19
|
/** VS Code 式调试装饰样式(断点 / 当前行);业务组件勿再自定义 glyph CSS */
|
|
15
20
|
import '../monaco/debug-decorations.css'
|
|
@@ -220,11 +225,16 @@ function completionPrefix(line: string): string {
|
|
|
220
225
|
}
|
|
221
226
|
|
|
222
227
|
function isManagedSqlDialect(language: string | undefined): boolean {
|
|
223
|
-
//
|
|
228
|
+
// Bridge LSP 接管补全;勿再注册实例级 Provider / wordBased
|
|
224
229
|
return (
|
|
225
230
|
language === MONACO_MYSQL_LANGUAGE ||
|
|
226
231
|
language === MONACO_DAMENG_LANGUAGE ||
|
|
227
|
-
language === MONACO_KINGBASE_LANGUAGE
|
|
232
|
+
language === MONACO_KINGBASE_LANGUAGE ||
|
|
233
|
+
language === MONACO_POSTGRESQL_LANGUAGE ||
|
|
234
|
+
language === MONACO_CLICKHOUSE_LANGUAGE ||
|
|
235
|
+
language === MONACO_SQLITE_LSP_LANGUAGE ||
|
|
236
|
+
language === MONACO_SQLSERVER_LANGUAGE ||
|
|
237
|
+
language === MONACO_ORACLE_LANGUAGE
|
|
228
238
|
)
|
|
229
239
|
}
|
|
230
240
|
|
|
@@ -377,7 +387,7 @@ function initEditor(): void {
|
|
|
377
387
|
wordWrap: 'on',
|
|
378
388
|
bracketPairColorization: { enabled: true },
|
|
379
389
|
padding: { top: 8, bottom: 8 },
|
|
380
|
-
renderLineHighlight: '
|
|
390
|
+
renderLineHighlight: 'line',
|
|
381
391
|
smoothScrolling: true,
|
|
382
392
|
cursorSmoothCaretAnimation: 'on',
|
|
383
393
|
folding: true,
|
|
@@ -388,7 +398,7 @@ function initEditor(): void {
|
|
|
388
398
|
lineDecorationsWidth: props.glyphMargin ? 16 : 4,
|
|
389
399
|
overviewRulerLanes: 0,
|
|
390
400
|
hideCursorInOverviewRuler: true,
|
|
391
|
-
// Shell:业务 completionRequest;
|
|
401
|
+
// Shell:业务 completionRequest;SQL 方言:Bridge LSP;避免 wordBased 抢补全
|
|
392
402
|
quickSuggestions: props.language === MONACO_MONGODB_SHELL_LANGUAGE
|
|
393
403
|
? { other: true, comments: false, strings: true }
|
|
394
404
|
: true,
|
|
@@ -90,6 +90,9 @@ const props = withDefaults(
|
|
|
90
90
|
block?: boolean
|
|
91
91
|
invalid?: boolean
|
|
92
92
|
showValidateMessage?: boolean
|
|
93
|
+
/**
|
|
94
|
+
* 自定义过滤;`false` 关闭。默认 `true`(必须显式默认,否则 Vue 会把 boolean 联合类型当成 Boolean prop,未传入即 `false`,可搜索列表永远不过滤)。
|
|
95
|
+
*/
|
|
93
96
|
filterOption?: RsSelectFilterOption | boolean
|
|
94
97
|
optionFilterProp?: RsSelectOptionFilterProp
|
|
95
98
|
maxTagCount?: number
|
|
@@ -101,6 +104,11 @@ const props = withDefaults(
|
|
|
101
104
|
maxTagTooltip?: boolean
|
|
102
105
|
tokenSeparators?: string[]
|
|
103
106
|
autoClearSearchValue?: boolean
|
|
107
|
+
/**
|
|
108
|
+
* 打开下拉时把当前选中项写入搜索框并参与过滤。
|
|
109
|
+
* 默认 false:搜索框保持空白(Reka 挂载时会写选中值,需显式清掉)。
|
|
110
|
+
*/
|
|
111
|
+
fillSearchWithValue?: boolean
|
|
104
112
|
showArrow?: boolean
|
|
105
113
|
listHeight?: number
|
|
106
114
|
placement?: RsSelectPlacement
|
|
@@ -126,11 +134,13 @@ const props = withDefaults(
|
|
|
126
134
|
loading: false,
|
|
127
135
|
matchTriggerWidth: false,
|
|
128
136
|
block: false,
|
|
137
|
+
filterOption: true,
|
|
129
138
|
optionFilterProp: 'label',
|
|
130
139
|
optionLabelProp: 'label',
|
|
131
140
|
labelInValue: false,
|
|
132
141
|
maxTagTooltip: true,
|
|
133
142
|
autoClearSearchValue: true,
|
|
143
|
+
fillSearchWithValue: false,
|
|
134
144
|
showArrow: true,
|
|
135
145
|
listHeight: 256,
|
|
136
146
|
placement: 'bottom',
|