@veltra/desktop 1.2.18 → 1.2.20

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 (31) hide show
  1. package/dist/components/code-editor/code-editor.js +8 -13
  2. package/dist/components/code-editor/code-editor.js.map +1 -1
  3. package/dist/components/code-editor/lang-loaders.js +16 -0
  4. package/dist/components/code-editor/lang-loaders.js.map +1 -0
  5. package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js +1 -0
  6. package/dist/components/form/form.vue_vue_type_script_setup_true_lang.js.map +1 -1
  7. package/dist/components/form-item/form-item.js.map +1 -1
  8. package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js +5 -1
  9. package/dist/components/form-item/form-item.vue_vue_type_script_setup_true_lang.js.map +1 -1
  10. package/dist/components/form-item/style2.css +13 -0
  11. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
  12. package/dist/components/steps/steps.vue.d.ts +2 -2
  13. package/dist/components/tip/tip.vue.d.ts +1 -1
  14. package/dist/node_modules/.bun/@codemirror_commands@6.10.4/node_modules/@codemirror/commands/dist/index.js +1 -1
  15. package/dist/node_modules/.bun/@codemirror_lang-java@6.0.2/node_modules/@codemirror/lang-java/dist/index.js +1 -1
  16. package/dist/node_modules/.bun/@codemirror_lang-javascript@6.2.5/node_modules/@codemirror/lang-javascript/dist/index.js +2 -2
  17. package/dist/node_modules/.bun/@codemirror_lang-sql@6.10.0/node_modules/@codemirror/lang-sql/dist/index.js +1 -1
  18. package/dist/node_modules/.bun/@codemirror_language@6.12.4/node_modules/@codemirror/language/dist/index.js +2 -2
  19. package/dist/node_modules/.bun/@codemirror_theme-one-dark@6.1.3/node_modules/@codemirror/theme-one-dark/dist/index.js +1 -1
  20. package/dist/node_modules/.bun/@lezer_java@1.1.3/node_modules/@lezer/java/dist/index.js +1 -1
  21. package/dist/node_modules/.bun/@lezer_javascript@1.5.4/node_modules/@lezer/javascript/dist/index.js +1 -1
  22. package/dist/node_modules/.bun/@lezer_json@1.0.3/node_modules/@lezer/json/dist/index.js +1 -1
  23. package/dist/types/form-item.d.ts +2 -0
  24. package/dist/types/form.d.ts +2 -0
  25. package/package.json +6 -6
  26. package/src/components/code-editor/code-editor.vue +11 -15
  27. package/src/components/code-editor/lang-loaders.ts +16 -0
  28. package/src/components/form-item/form-item.vue +9 -1
  29. package/src/components/form-item/style.scss +15 -0
  30. package/src/types/form-item.ts +2 -0
  31. package/src/types/form.ts +2 -0
@@ -1,12 +1,9 @@
1
1
  import _sfc_main$1 from "../scroll/scroll.js";
2
2
  import { Compartment, EditorState } from "../../node_modules/.bun/@codemirror_state@6.7.0/node_modules/@codemirror/state/dist/index.js";
3
3
  import { EditorView, ViewPlugin, tooltips } from "../../node_modules/.bun/@codemirror_view@6.43.4/node_modules/@codemirror/view/dist/index.js";
4
- import { java } from "../../node_modules/.bun/@codemirror_lang-java@6.0.2/node_modules/@codemirror/lang-java/dist/index.js";
5
- import { javascript } from "../../node_modules/.bun/@codemirror_lang-javascript@6.2.5/node_modules/@codemirror/lang-javascript/dist/index.js";
6
- import { json } from "../../node_modules/.bun/@codemirror_lang-json@6.0.2/node_modules/@codemirror/lang-json/dist/index.js";
7
- import { sql } from "../../node_modules/.bun/@codemirror_lang-sql@6.10.0/node_modules/@codemirror/lang-sql/dist/index.js";
8
4
  import { oneDark } from "../../node_modules/.bun/@codemirror_theme-one-dark@6.1.3/node_modules/@codemirror/theme-one-dark/dist/index.js";
9
5
  import { basicSetup } from "./basic-setup.js";
6
+ import { loadLanguage } from "./lang-loaders.js";
10
7
  import { computed, createBlock, createElementVNode, defineComponent, mergeModels, normalizeClass, normalizeStyle, onBeforeUnmount, openBlock, shallowRef, unref, useModel, useTemplateRef, watch, withCtx, withKeys, withModifiers } from "vue";
11
8
  import { useFormFallbackProps } from "@veltra/compositions";
12
9
  import { bem, injectFormContext, zIndex } from "@veltra/utils";
@@ -59,13 +56,6 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
59
56
  const rootStyle = computed(() => ({ "--u-code-editor-default-lines": Math.max(1, props.defaultLines) }));
60
57
  const containerRef = useTemplateRef("container");
61
58
  const editor = shallowRef(null);
62
- /** 静态导入语言包,避免动态 import 在打包/Vite 预构建下产生多份 @codemirror/* 实例 */
63
- const langExtensions = {
64
- js: javascript({ typescript: true }),
65
- sql: sql(),
66
- java: java(),
67
- json: json()
68
- };
69
59
  const themeCompartment = new Compartment();
70
60
  const editableCompartment = new Compartment();
71
61
  const readOnlyCompartment = new Compartment();
@@ -130,12 +120,17 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
130
120
  }
131
121
  let editorToken = 0;
132
122
  let langToken = 0;
133
- function applyLanguage() {
123
+ async function applyLanguage() {
134
124
  const view = editor.value;
135
125
  if (!view) return;
136
126
  const myToken = ++langToken;
137
127
  const { language } = props;
138
- const ext = language ? langExtensions[language] : [];
128
+ if (!language) {
129
+ if (myToken !== langToken || editor.value !== view) return;
130
+ view.dispatch({ effects: langCompartment.reconfigure([]) });
131
+ return;
132
+ }
133
+ const ext = await loadLanguage(language);
139
134
  if (myToken !== langToken || editor.value !== view) return;
140
135
  view.dispatch({ effects: langCompartment.reconfigure(ext) });
141
136
  }
@@ -1 +1 @@
1
- {"version":3,"file":"code-editor.js","names":[],"sources":["../../../src/components/code-editor/code-editor.vue"],"sourcesContent":["<template>\n <u-scroll :class=\"className\" :style=\"rootStyle\" @keyup.enter.stop>\n <div ref=\"container\"></div>\n </u-scroll>\n</template>\n\n<script lang=\"ts\" setup>\nimport { java } from '@codemirror/lang-java'\nimport { javascript } from '@codemirror/lang-javascript'\nimport { json } from '@codemirror/lang-json'\nimport { sql } from '@codemirror/lang-sql'\nimport { Compartment, EditorState, type Extension } from '@codemirror/state'\nimport { oneDark } from '@codemirror/theme-one-dark'\nimport { EditorView, ViewPlugin, tooltips, type ViewUpdate } from '@codemirror/view'\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { bem, zIndex } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport {\n computed,\n onBeforeUnmount,\n shallowRef,\n useTemplateRef,\n watch,\n type CSSProperties\n} from 'vue'\n\nimport type { CodeEditorLang, CodeEditorProps } from '../../types'\nimport { UScroll } from '../scroll'\nimport { basicSetup } from './basic-setup'\n\ndefineOptions({ name: 'UCodeEditor' })\n\nconst props = withDefaults(defineProps<CodeEditorProps>(), {\n disabled: undefined,\n readonly: undefined,\n dark: false,\n defaultLines: 8\n})\n\nconst model = defineModel<string>()\n\nconst cls = bem('code-editor')\n\nconst { formProps } = injectFormContext()\n\nconst { disabled, readonly } = useFormFallbackProps([formProps ?? {}, props], {\n disabled: false,\n readonly: false\n})\n\nconst className = computed<string[]>(() => [\n cls.b,\n bem.is('disabled', disabled.value),\n bem.is('readonly', readonly.value),\n bem.is('dark', props.dark)\n])\n\nconst rootStyle = computed<CSSProperties>(() => ({\n '--u-code-editor-default-lines': Math.max(1, props.defaultLines)\n}))\n\nconst containerRef = useTemplateRef('container')\nconst editor = shallowRef<EditorView | null>(null)\n\n/** 静态导入语言包,避免动态 import 在打包/Vite 预构建下产生多份 @codemirror/* 实例 */\nconst langExtensions: Record<CodeEditorLang, Extension> = {\n js: javascript({ typescript: true }),\n sql: sql(),\n java: java(),\n json: json()\n}\n\nconst themeCompartment = new Compartment()\nconst editableCompartment = new Compartment()\nconst readOnlyCompartment = new Compartment()\nconst langCompartment = new Compartment()\n\nlet phantomGutter: HTMLElement | null = null\nlet phantomContainer: HTMLElement | null = null\nlet lastPhantomKey = ''\n\nfunction resetPhantomCache() {\n phantomGutter = null\n phantomContainer = null\n lastPhantomKey = ''\n}\n\n/**\n * 在 .cm-lineNumbers 末尾追加占位行号 DOM,使可视行号数量补齐到 defaultLines。\n * CodeMirror 的 lineNumbers() 仅为真实文档行渲染行号,超出部分由本逻辑补全。\n */\nfunction syncPhantomLineNumbers() {\n const view = editor.value\n if (!view) return\n\n if (!phantomGutter || !phantomGutter.isConnected) {\n phantomGutter = view.dom.querySelector<HTMLElement>('.cm-gutter.cm-lineNumbers')\n }\n if (!phantomGutter) return\n\n if (!phantomContainer) {\n phantomContainer = document.createElement('div')\n phantomContainer.className = 'cm-phantom-lines'\n }\n if (\n phantomContainer.parentElement !== phantomGutter ||\n phantomContainer !== phantomGutter.lastElementChild\n ) {\n phantomGutter.appendChild(phantomContainer)\n }\n\n const realLines = view.state.doc.lines\n const target = Math.max(0, Math.max(1, props.defaultLines) - realLines)\n const lineHeight = view.defaultLineHeight\n\n const key = `${realLines}|${target}|${lineHeight}`\n if (key === lastPhantomKey) return\n lastPhantomKey = key\n\n while (phantomContainer.children.length > target) {\n phantomContainer.lastElementChild!.remove()\n }\n while (phantomContainer.children.length < target) {\n const el = document.createElement('div')\n el.className = 'cm-gutterElement cm-gutterElement-phantom'\n phantomContainer.appendChild(el)\n }\n for (let i = 0; i < target; i++) {\n const el = phantomContainer.children[i] as HTMLElement\n const num = String(realLines + i + 1)\n if (el.textContent !== num) el.textContent = num\n if (lineHeight && el.style.height !== `${lineHeight}px`) {\n el.style.height = `${lineHeight}px`\n }\n }\n}\n\nconst phantomLineNumbersPlugin = ViewPlugin.fromClass(\n class {\n update(update: ViewUpdate) {\n if (update.docChanged || update.geometryChanged) {\n syncPhantomLineNumbers()\n }\n }\n }\n)\n\nfunction buildExtensions(): Extension[] {\n return [\n basicSetup,\n tooltips({ parent: document.body }),\n EditorView.theme({ '.cm-tooltip': { zIndex: zIndex() } }),\n themeCompartment.of(props.dark ? oneDark : []),\n editableCompartment.of(EditorView.editable.of(!disabled.value)),\n readOnlyCompartment.of(EditorState.readOnly.of(readonly.value)),\n langCompartment.of([]),\n phantomLineNumbersPlugin\n ]\n}\n\nlet editorToken = 0\nlet langToken = 0\n\nfunction applyLanguage() {\n const view = editor.value\n if (!view) return\n const myToken = ++langToken\n const { language } = props\n const ext = language ? langExtensions[language] : []\n if (myToken !== langToken || editor.value !== view) return\n view.dispatch({ effects: langCompartment.reconfigure(ext) })\n}\n\nfunction destroyEditor() {\n ++editorToken\n ++langToken\n editor.value?.destroy()\n editor.value = null\n resetPhantomCache()\n}\n\nfunction createEditor() {\n destroyEditor()\n const myToken = ++editorToken\n const parent = containerRef.value\n if (!parent) return\n\n const view = new EditorView({\n doc: model.value,\n extensions: buildExtensions(),\n parent,\n dispatch(tr) {\n view.update([tr])\n if (tr.docChanged) {\n model.value = tr.state.doc.toString()\n }\n }\n })\n\n if (myToken !== editorToken) {\n view.destroy()\n return\n }\n\n editor.value = view\n syncPhantomLineNumbers()\n applyLanguage()\n}\n\nwatch(\n containerRef,\n (el) => {\n if (el) createEditor()\n else destroyEditor()\n },\n { immediate: true, flush: 'post' }\n)\n\nwatch(() => props.language, applyLanguage)\n\nwatch(\n () => props.dark,\n (dark) => {\n editor.value?.dispatch({ effects: themeCompartment.reconfigure(dark ? oneDark : []) })\n }\n)\n\nwatch(disabled, (v) => {\n editor.value?.dispatch({ effects: editableCompartment.reconfigure(EditorView.editable.of(!v)) })\n})\n\nwatch(readonly, (v) => {\n editor.value?.dispatch({ effects: readOnlyCompartment.reconfigure(EditorState.readOnly.of(v)) })\n})\n\nwatch(() => props.defaultLines, syncPhantomLineNumbers)\n\nwatch(\n [() => props.modelValue, editor],\n ([v, e]) => {\n if (!e) return\n if (e.composing) return\n const next = v ?? ''\n if (e.state.doc.toString() === next) return\n\n const valueLength = next.length\n const inRange = e.state.selection.ranges.every(\n (range) => range.anchor <= valueLength && range.head <= valueLength\n )\n e.dispatch({\n changes: { from: 0, to: e.state.doc.length, insert: next },\n selection: inRange ? e.state.selection : { anchor: 0, head: 0 },\n scrollIntoView: true\n })\n },\n { immediate: true }\n)\n\nonBeforeUnmount(destroyEditor)\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"code-editor.js","names":[],"sources":["../../../src/components/code-editor/code-editor.vue"],"sourcesContent":["<template>\n <u-scroll :class=\"className\" :style=\"rootStyle\" @keyup.enter.stop>\n <div ref=\"container\"></div>\n </u-scroll>\n</template>\n\n<script lang=\"ts\" setup>\nimport { Compartment, EditorState, type Extension } from '@codemirror/state'\nimport { oneDark } from '@codemirror/theme-one-dark'\nimport { EditorView, ViewPlugin, tooltips, type ViewUpdate } from '@codemirror/view'\nimport { useFormFallbackProps } from '@veltra/compositions'\nimport { bem, zIndex } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport {\n computed,\n onBeforeUnmount,\n shallowRef,\n useTemplateRef,\n watch,\n type CSSProperties\n} from 'vue'\n\nimport type { CodeEditorProps } from '../../types'\nimport { UScroll } from '../scroll'\nimport { basicSetup } from './basic-setup'\nimport { loadLanguage } from './lang-loaders'\n\ndefineOptions({ name: 'UCodeEditor' })\n\nconst props = withDefaults(defineProps<CodeEditorProps>(), {\n disabled: undefined,\n readonly: undefined,\n dark: false,\n defaultLines: 8\n})\n\nconst model = defineModel<string>()\n\nconst cls = bem('code-editor')\n\nconst { formProps } = injectFormContext()\n\nconst { disabled, readonly } = useFormFallbackProps([formProps ?? {}, props], {\n disabled: false,\n readonly: false\n})\n\nconst className = computed<string[]>(() => [\n cls.b,\n bem.is('disabled', disabled.value),\n bem.is('readonly', readonly.value),\n bem.is('dark', props.dark)\n])\n\nconst rootStyle = computed<CSSProperties>(() => ({\n '--u-code-editor-default-lines': Math.max(1, props.defaultLines)\n}))\n\nconst containerRef = useTemplateRef('container')\nconst editor = shallowRef<EditorView | null>(null)\n\nconst themeCompartment = new Compartment()\nconst editableCompartment = new Compartment()\nconst readOnlyCompartment = new Compartment()\nconst langCompartment = new Compartment()\n\nlet phantomGutter: HTMLElement | null = null\nlet phantomContainer: HTMLElement | null = null\nlet lastPhantomKey = ''\n\nfunction resetPhantomCache() {\n phantomGutter = null\n phantomContainer = null\n lastPhantomKey = ''\n}\n\n/**\n * 在 .cm-lineNumbers 末尾追加占位行号 DOM,使可视行号数量补齐到 defaultLines。\n * CodeMirror 的 lineNumbers() 仅为真实文档行渲染行号,超出部分由本逻辑补全。\n */\nfunction syncPhantomLineNumbers() {\n const view = editor.value\n if (!view) return\n\n if (!phantomGutter || !phantomGutter.isConnected) {\n phantomGutter = view.dom.querySelector<HTMLElement>('.cm-gutter.cm-lineNumbers')\n }\n if (!phantomGutter) return\n\n if (!phantomContainer) {\n phantomContainer = document.createElement('div')\n phantomContainer.className = 'cm-phantom-lines'\n }\n if (\n phantomContainer.parentElement !== phantomGutter ||\n phantomContainer !== phantomGutter.lastElementChild\n ) {\n phantomGutter.appendChild(phantomContainer)\n }\n\n const realLines = view.state.doc.lines\n const target = Math.max(0, Math.max(1, props.defaultLines) - realLines)\n const lineHeight = view.defaultLineHeight\n\n const key = `${realLines}|${target}|${lineHeight}`\n if (key === lastPhantomKey) return\n lastPhantomKey = key\n\n while (phantomContainer.children.length > target) {\n phantomContainer.lastElementChild!.remove()\n }\n while (phantomContainer.children.length < target) {\n const el = document.createElement('div')\n el.className = 'cm-gutterElement cm-gutterElement-phantom'\n phantomContainer.appendChild(el)\n }\n for (let i = 0; i < target; i++) {\n const el = phantomContainer.children[i] as HTMLElement\n const num = String(realLines + i + 1)\n if (el.textContent !== num) el.textContent = num\n if (lineHeight && el.style.height !== `${lineHeight}px`) {\n el.style.height = `${lineHeight}px`\n }\n }\n}\n\nconst phantomLineNumbersPlugin = ViewPlugin.fromClass(\n class {\n update(update: ViewUpdate) {\n if (update.docChanged || update.geometryChanged) {\n syncPhantomLineNumbers()\n }\n }\n }\n)\n\nfunction buildExtensions(): Extension[] {\n return [\n basicSetup,\n tooltips({ parent: document.body }),\n EditorView.theme({ '.cm-tooltip': { zIndex: zIndex() } }),\n themeCompartment.of(props.dark ? oneDark : []),\n editableCompartment.of(EditorView.editable.of(!disabled.value)),\n readOnlyCompartment.of(EditorState.readOnly.of(readonly.value)),\n langCompartment.of([]),\n phantomLineNumbersPlugin\n ]\n}\n\nlet editorToken = 0\nlet langToken = 0\n\nasync function applyLanguage() {\n const view = editor.value\n if (!view) return\n const myToken = ++langToken\n const { language } = props\n\n if (!language) {\n if (myToken !== langToken || editor.value !== view) return\n view.dispatch({ effects: langCompartment.reconfigure([]) })\n return\n }\n\n const ext = await loadLanguage(language)\n if (myToken !== langToken || editor.value !== view) return\n view.dispatch({ effects: langCompartment.reconfigure(ext) })\n}\n\nfunction destroyEditor() {\n ++editorToken\n ++langToken\n editor.value?.destroy()\n editor.value = null\n resetPhantomCache()\n}\n\nfunction createEditor() {\n destroyEditor()\n const myToken = ++editorToken\n const parent = containerRef.value\n if (!parent) return\n\n const view = new EditorView({\n doc: model.value,\n extensions: buildExtensions(),\n parent,\n dispatch(tr) {\n view.update([tr])\n if (tr.docChanged) {\n model.value = tr.state.doc.toString()\n }\n }\n })\n\n if (myToken !== editorToken) {\n view.destroy()\n return\n }\n\n editor.value = view\n syncPhantomLineNumbers()\n applyLanguage()\n}\n\nwatch(\n containerRef,\n (el) => {\n if (el) createEditor()\n else destroyEditor()\n },\n { immediate: true, flush: 'post' }\n)\n\nwatch(() => props.language, applyLanguage)\n\nwatch(\n () => props.dark,\n (dark) => {\n editor.value?.dispatch({ effects: themeCompartment.reconfigure(dark ? oneDark : []) })\n }\n)\n\nwatch(disabled, (v) => {\n editor.value?.dispatch({ effects: editableCompartment.reconfigure(EditorView.editable.of(!v)) })\n})\n\nwatch(readonly, (v) => {\n editor.value?.dispatch({ effects: readOnlyCompartment.reconfigure(EditorState.readOnly.of(v)) })\n})\n\nwatch(() => props.defaultLines, syncPhantomLineNumbers)\n\nwatch(\n [() => props.modelValue, editor],\n ([v, e]) => {\n if (!e) return\n if (e.composing) return\n const next = v ?? ''\n if (e.state.doc.toString() === next) return\n\n const valueLength = next.length\n const inRange = e.state.selection.ranges.every(\n (range) => range.anchor <= valueLength && range.head <= valueLength\n )\n e.dispatch({\n changes: { from: 0, to: e.state.doc.length, insert: next },\n selection: inRange ? e.state.selection : { anchor: 0, head: 0 },\n scrollIntoView: true\n })\n },\n { immediate: true }\n)\n\nonBeforeUnmount(destroyEditor)\n</script>\n"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ //#region src/components/code-editor/lang-loaders.ts
2
+ /** 语言包动态加载器,新增语言只需在此注册一条 */
3
+ const LANG_LOADERS = {
4
+ js: () => import("../../node_modules/.bun/@codemirror_lang-javascript@6.2.5/node_modules/@codemirror/lang-javascript/dist/index.js").then((m) => m.javascript({ typescript: true })),
5
+ sql: () => import("../../node_modules/.bun/@codemirror_lang-sql@6.10.0/node_modules/@codemirror/lang-sql/dist/index.js").then((m) => m.sql()),
6
+ java: () => import("../../node_modules/.bun/@codemirror_lang-java@6.0.2/node_modules/@codemirror/lang-java/dist/index.js").then((m) => m.java()),
7
+ json: () => import("../../node_modules/.bun/@codemirror_lang-json@6.0.2/node_modules/@codemirror/lang-json/dist/index.js").then((m) => m.json())
8
+ };
9
+ /** 按需加载语言扩展;模块缓存由运行时保证,重复切换同一语言不会重复下载 */
10
+ function loadLanguage(lang) {
11
+ return LANG_LOADERS[lang]();
12
+ }
13
+ //#endregion
14
+ export { loadLanguage };
15
+
16
+ //# sourceMappingURL=lang-loaders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lang-loaders.js","names":[],"sources":["../../../src/components/code-editor/lang-loaders.ts"],"sourcesContent":["import type { Extension } from '@codemirror/state'\n\nimport type { CodeEditorLang } from '../../types'\n\n/** 语言包动态加载器,新增语言只需在此注册一条 */\nconst LANG_LOADERS: Record<CodeEditorLang, () => Promise<Extension>> = {\n js: () => import('@codemirror/lang-javascript').then((m) => m.javascript({ typescript: true })),\n sql: () => import('@codemirror/lang-sql').then((m) => m.sql()),\n java: () => import('@codemirror/lang-java').then((m) => m.java()),\n json: () => import('@codemirror/lang-json').then((m) => m.json())\n}\n\n/** 按需加载语言扩展;模块缓存由运行时保证,重复切换同一语言不会重复下载 */\nexport function loadLanguage(lang: CodeEditorLang): Promise<Extension> {\n return LANG_LOADERS[lang]()\n}\n"],"mappings":";;AAKA,MAAM,eAAiE;CACrE,UAAU,OAAO,mHAA8B,CAAC,MAAM,MAAM,EAAE,WAAW,EAAE,YAAY,KAAK,CAAC,CAAC;CAC9F,WAAW,OAAO,sGAAuB,CAAC,MAAM,MAAM,EAAE,IAAI,CAAC;CAC7D,YAAY,OAAO,uGAAwB,CAAC,MAAM,MAAM,EAAE,KAAK,CAAC;CAChE,YAAY,OAAO,uGAAwB,CAAC,MAAM,MAAM,EAAE,KAAK,CAAC;AAClE;;AAGA,SAAgB,aAAa,MAA0C;CACrE,OAAO,aAAa,KAAK,CAAC;AAC5B"}
@@ -13,6 +13,7 @@ var form_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCompo
13
13
  cols: {},
14
14
  model: {},
15
15
  labelWidth: {},
16
+ labelPosition: {},
16
17
  noTips: { type: Boolean },
17
18
  readonly: { type: Boolean },
18
19
  disabled: { type: Boolean },
@@ -1 +1 @@
1
- {"version":3,"file":"form.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/form/form.vue"],"sourcesContent":["<template>\n <u-grid\n tag=\"form\"\n ref=\"grid\"\n @submit.prevent\n :cols=\"cols || breakpointCols\"\n :class=\"[cls.b, bem.is('readonly', readonly)]\"\n >\n <template\n v-for=\"{ node, isFormItem, formItemProps, field, modelValue } of getSlotsNodes()\"\n :key=\"node.key\"\n >\n <u-form-item v-if=\"!isFormItem && field\" v-bind=\"formItemProps\">\n <component\n :is=\"node\"\n :model-value=\"modelValue ?? o(model ?? {}).get(field)\"\n @update:model-value=\"handleUpdateValue(field, $event)\"\n />\n </u-form-item>\n\n <component v-else :is=\"node\" />\n </template>\n </u-grid>\n</template>\n\n<script lang=\"tsx\" setup>\nimport { o } from '@cat-kit/core'\nimport { bem } from '@veltra/utils'\nimport { provideFormContext } from '@veltra/utils'\nimport { nextTick, toRef, useTemplateRef } from 'vue'\n\nimport type { BreakCols, FormProps, _FormExposed, FormEmits } from '../../types'\nimport { UFormItem } from '../form-item'\nimport { UGrid } from '../grid'\nimport { useFormFields } from './use-form-fields'\nimport { useNodeInterceptor } from './use-node-interceptor'\n\ndefineOptions({ name: 'UForm' })\n\nconst props = defineProps<FormProps>()\n\nconst emit = defineEmits<FormEmits>()\n\ndefineSlots<{ default(props?: { data: Record<string, any> | undefined }): any }>()\n\nconst cls = bem('form')\nconst formItemCls = bem('form-item')\nconst gridRef = useTemplateRef('grid')\n\nconst breakpointCols: BreakCols = { xs: 1, md: 2, lg: 3, xl: 4, default: 4 }\n\nconst {\n validate: runValidate,\n clearValidate,\n reset,\n registerField,\n unregisterField,\n shouldValidate\n} = useFormFields({ props })\n\nasync function validate(keys?: string[]) {\n const valid = await runValidate(keys)\n if (!valid) {\n await nextTick()\n\n gridRef.value?.el\n ?.querySelector(`.${formItemCls.e('error-text')}`)\n ?.scrollIntoView({ block: 'center' })\n }\n return valid\n}\n\nfunction handleFieldChange(field: string, value: any) {\n emit('field:change', field, value)\n}\n\nprovideFormContext({\n formProps: props,\n registerField,\n unregisterField,\n validateFields: validate,\n shouldValidate,\n handleFieldChange\n})\n\nconst { getSlotsNodes } = useNodeInterceptor()\n\nfunction handleUpdateValue(field: string, value: any) {\n if (!props.model) return\n o(props.model).set(field, value)\n}\n\ndefineExpose<_FormExposed>({ el: toRef(() => gridRef.value?.el), validate, clearValidate, reset })\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;EAuCA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAIb,MAAM,MAAM,IAAI,MAAM;EACtB,MAAM,cAAc,IAAI,WAAW;EACnC,MAAM,UAAU,eAAe,MAAM;EAErC,MAAM,iBAA4B;GAAE,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG,SAAS;EAAE;EAE3E,MAAM,EACJ,UAAU,aACV,eACA,OACA,eACA,iBACA,mBACE,cAAc,EAAE,MAAM,CAAC;EAE3B,eAAe,SAAS,MAAiB;GACvC,MAAM,QAAQ,MAAM,YAAY,IAAI;GACpC,IAAI,CAAC,OAAO;IACV,MAAM,SAAS;IAEf,QAAQ,OAAO,IACX,cAAc,IAAI,YAAY,EAAE,YAAY,GAAG,CAAA,EAC/C,eAAe,EAAE,OAAO,SAAS,CAAC;GACxC;GACA,OAAO;EACT;EAEA,SAAS,kBAAkB,OAAe,OAAY;GACpD,KAAK,gBAAgB,OAAO,KAAK;EACnC;EAEA,mBAAmB;GACjB,WAAW;GACX;GACA;GACA,gBAAgB;GAChB;GACA;EACF,CAAC;EAED,MAAM,EAAE,kBAAkB,mBAAmB;EAE7C,SAAS,kBAAkB,OAAe,OAAY;GACpD,IAAI,CAAC,MAAM,OAAO;GAClB,EAAE,MAAM,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK;EACjC;EAEA,SAA2B;GAAE,IAAI,YAAY,QAAQ,OAAO,EAAE;GAAG;GAAU;GAAe;EAAM,CAAC;;uBA3F/F,YAqBS,MAAA,SAAA,GAAA;IApBP,KAAI;IACJ,KAAI;IACH,UAAM,OAAA,OAAA,OAAA,KAAA,oBAAP,CAAA,GAAe,CAAA,SAAA,CAAA;IACd,MAAM,QAAA,QAAQ;IACd,OAAK,eAAA,CAAG,MAAA,GAAA,CAAG,CAAC,GAAG,MAAA,GAAA,CAAG,CAAC,GAAE,YAAa,QAAA,QAAQ,CAAA,CAAA;;2BAGwC,EAAA,UAAA,IAAA,GADnF,mBAaW,UAAA,MAAA,WAZwD,MAAA,aAAA,CAAa,CAAA,IAAA,EAArE,MAAM,YAAY,eAAe,OAAO,iBAAU;6DACrD,KAAK,IAAA,GAAA,CAAA,CAES,cAAc,SAAA,UAAA,GAAlC,YAMc,MAAA,iBAAA,GANd,WAMc;;;QANmC,aAAa,GAAA;6BAK1D,EAAA,UAAA,GAJF,YAIE,wBAHK,IAAI,GAAA;OACR,eAAa,cAAc,MAAA,CAAA,CAAC,CAAC,QAAA,SAAK,CAAA,CAAA,CAAA,CAAQ,IAAI,KAAK;OACnD,wBAAkB,WAAE,kBAAkB,OAAO,MAAM;;;+BAIxD,YAA+B,wBAAR,IAAI,GAAA,EAAA,KAAA,EAAA,CAAA,EAAA,GAAA,EAAA"}
1
+ {"version":3,"file":"form.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../../src/components/form/form.vue"],"sourcesContent":["<template>\n <u-grid\n tag=\"form\"\n ref=\"grid\"\n @submit.prevent\n :cols=\"cols || breakpointCols\"\n :class=\"[cls.b, bem.is('readonly', readonly)]\"\n >\n <template\n v-for=\"{ node, isFormItem, formItemProps, field, modelValue } of getSlotsNodes()\"\n :key=\"node.key\"\n >\n <u-form-item v-if=\"!isFormItem && field\" v-bind=\"formItemProps\">\n <component\n :is=\"node\"\n :model-value=\"modelValue ?? o(model ?? {}).get(field)\"\n @update:model-value=\"handleUpdateValue(field, $event)\"\n />\n </u-form-item>\n\n <component v-else :is=\"node\" />\n </template>\n </u-grid>\n</template>\n\n<script lang=\"tsx\" setup>\nimport { o } from '@cat-kit/core'\nimport { bem } from '@veltra/utils'\nimport { provideFormContext } from '@veltra/utils'\nimport { nextTick, toRef, useTemplateRef } from 'vue'\n\nimport type { BreakCols, FormProps, _FormExposed, FormEmits } from '../../types'\nimport { UFormItem } from '../form-item'\nimport { UGrid } from '../grid'\nimport { useFormFields } from './use-form-fields'\nimport { useNodeInterceptor } from './use-node-interceptor'\n\ndefineOptions({ name: 'UForm' })\n\nconst props = defineProps<FormProps>()\n\nconst emit = defineEmits<FormEmits>()\n\ndefineSlots<{ default(props?: { data: Record<string, any> | undefined }): any }>()\n\nconst cls = bem('form')\nconst formItemCls = bem('form-item')\nconst gridRef = useTemplateRef('grid')\n\nconst breakpointCols: BreakCols = { xs: 1, md: 2, lg: 3, xl: 4, default: 4 }\n\nconst {\n validate: runValidate,\n clearValidate,\n reset,\n registerField,\n unregisterField,\n shouldValidate\n} = useFormFields({ props })\n\nasync function validate(keys?: string[]) {\n const valid = await runValidate(keys)\n if (!valid) {\n await nextTick()\n\n gridRef.value?.el\n ?.querySelector(`.${formItemCls.e('error-text')}`)\n ?.scrollIntoView({ block: 'center' })\n }\n return valid\n}\n\nfunction handleFieldChange(field: string, value: any) {\n emit('field:change', field, value)\n}\n\nprovideFormContext({\n formProps: props,\n registerField,\n unregisterField,\n validateFields: validate,\n shouldValidate,\n handleFieldChange\n})\n\nconst { getSlotsNodes } = useNodeInterceptor()\n\nfunction handleUpdateValue(field: string, value: any) {\n if (!props.model) return\n o(props.model).set(field, value)\n}\n\ndefineExpose<_FormExposed>({ el: toRef(() => gridRef.value?.el), validate, clearValidate, reset })\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;EAuCA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAIb,MAAM,MAAM,IAAI,MAAM;EACtB,MAAM,cAAc,IAAI,WAAW;EACnC,MAAM,UAAU,eAAe,MAAM;EAErC,MAAM,iBAA4B;GAAE,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG,SAAS;EAAE;EAE3E,MAAM,EACJ,UAAU,aACV,eACA,OACA,eACA,iBACA,mBACE,cAAc,EAAE,MAAM,CAAC;EAE3B,eAAe,SAAS,MAAiB;GACvC,MAAM,QAAQ,MAAM,YAAY,IAAI;GACpC,IAAI,CAAC,OAAO;IACV,MAAM,SAAS;IAEf,QAAQ,OAAO,IACX,cAAc,IAAI,YAAY,EAAE,YAAY,GAAG,CAAA,EAC/C,eAAe,EAAE,OAAO,SAAS,CAAC;GACxC;GACA,OAAO;EACT;EAEA,SAAS,kBAAkB,OAAe,OAAY;GACpD,KAAK,gBAAgB,OAAO,KAAK;EACnC;EAEA,mBAAmB;GACjB,WAAW;GACX;GACA;GACA,gBAAgB;GAChB;GACA;EACF,CAAC;EAED,MAAM,EAAE,kBAAkB,mBAAmB;EAE7C,SAAS,kBAAkB,OAAe,OAAY;GACpD,IAAI,CAAC,MAAM,OAAO;GAClB,EAAE,MAAM,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK;EACjC;EAEA,SAA2B;GAAE,IAAI,YAAY,QAAQ,OAAO,EAAE;GAAG;GAAU;GAAe;EAAM,CAAC;;uBA3F/F,YAqBS,MAAA,SAAA,GAAA;IApBP,KAAI;IACJ,KAAI;IACH,UAAM,OAAA,OAAA,OAAA,KAAA,oBAAP,CAAA,GAAe,CAAA,SAAA,CAAA;IACd,MAAM,QAAA,QAAQ;IACd,OAAK,eAAA,CAAG,MAAA,GAAA,CAAG,CAAC,GAAG,MAAA,GAAA,CAAG,CAAC,GAAE,YAAa,QAAA,QAAQ,CAAA,CAAA;;2BAGwC,EAAA,UAAA,IAAA,GADnF,mBAaW,UAAA,MAAA,WAZwD,MAAA,aAAA,CAAa,CAAA,IAAA,EAArE,MAAM,YAAY,eAAe,OAAO,iBAAU;6DACrD,KAAK,IAAA,GAAA,CAAA,CAES,cAAc,SAAA,UAAA,GAAlC,YAMc,MAAA,iBAAA,GANd,WAMc;;;QANmC,aAAa,GAAA;6BAK1D,EAAA,UAAA,GAJF,YAIE,wBAHK,IAAI,GAAA;OACR,eAAa,cAAc,MAAA,CAAA,CAAC,CAAC,QAAA,SAAK,CAAA,CAAA,CAAA,CAAQ,IAAI,KAAK;OACnD,wBAAkB,WAAE,kBAAkB,OAAO,MAAM;;;+BAIxD,YAA+B,wBAAR,IAAI,GAAA,EAAA,KAAA,EAAA,CAAA,EAAA,GAAA,EAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"form-item.js","names":[],"sources":["../../../src/components/form-item/form-item.vue"],"sourcesContent":["<template>\n <u-grid-item :span=\"span\" :class=\"className\">\n <label\n v-if=\"props.label || $slots.label\"\n :class=\"[cls.e('label'), bem.is('required', !!rules?.required)]\"\n :style=\"labelStyles\"\n >\n <u-tip v-if=\"tips\" :content=\"tips\" :class=\"cls.e('tips')\">\n <span :class=\"cls.e('tip-label')\">\n <slot name=\"label\">{{ label }}:</slot>\n </span>\n </u-tip>\n <template v-else>\n <slot name=\"label\">{{ label }}:</slot>\n </template>\n </label>\n\n <section :class=\"cls.e('wrapper')\">\n <div :class=\"cls.e('content')\">\n <slot></slot>\n </div>\n\n <!-- 只有表单控件处于非只读状态时,才显示错误提示 -->\n <section :class=\"cls.e('error')\" v-if=\"!readonly && !formProps?.noTips\">\n <transition name=\"form-item-tips\" mode=\"out-in\">\n <span :class=\"cls.e('error-text')\" v-if=\"!!errorTip\">\n {{ errorTip }}\n </span>\n </transition>\n </section>\n </section>\n </u-grid-item>\n</template>\n\n<script lang=\"tsx\" setup>\nimport { o } from '@cat-kit/core'\nimport { useConfig, useFallbackProps } from '@veltra/compositions'\nimport { bem, withUnit } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { type CSSProperties, computed, onBeforeUnmount, shallowRef, watch } from 'vue'\n\nimport type { FormItemProps, ComponentSize } from '../../types'\nimport { UGridItem } from '../grid'\nimport { UTip } from '../tip'\nimport { formItemCls as cls, defineField } from './helper'\nimport { validateField } from './validate'\n\ndefineOptions({ name: 'UFormItem' })\n\nconst props = withDefaults(defineProps<FormItemProps>(), { readonly: undefined })\n\ndefineSlots<{\n /** 标签插槽 */\n label?: () => any\n default?: () => any\n}>()\n\n/** 表单组件上下文 */\nconst { formProps, registerField, unregisterField, shouldValidate, handleFieldChange } =\n injectFormContext()\n\nconst { config } = useConfig()\n\nconst { size, readonly } = useFallbackProps([formProps ?? {}, props], {\n size: 'default' as ComponentSize,\n readonly: false\n})\n\nconst errorTip = shallowRef<string>()\n/** 递增序号,丢弃过期的异步校验结果 */\nlet validateSeq = 0\n/** 最近一次 validate 的 Promise,供过期调用等待最新结果 */\nlet latestValidatePromise: Promise<boolean> = Promise.resolve(true)\n\nconst className = computed(() => {\n return [cls.b, cls.m(size.value), bem.is('error', !!errorTip.value)].join(' ')\n})\n\n/** label样式 */\nconst labelStyles = computed<CSSProperties>(() => {\n return {\n width: withUnit(props.labelWidth ?? formProps?.labelWidth ?? config.form.labelWidth, 'px')\n }\n})\n\nconst fieldItem = defineField({\n clearValidate() {\n errorTip.value = ''\n },\n async validate() {\n if (!props.field || !formProps?.model || !props.rules || !shouldValidate?.()) return true\n\n const seq = ++validateSeq\n\n latestValidatePromise = validateField(formProps.model!, props.field!, props.rules!).then(\n (tip) => {\n if (seq !== validateSeq) return latestValidatePromise\n\n errorTip.value = tip\n return !errorTip.value\n }\n )\n return latestValidatePromise\n }\n})\n\nwatch(\n () => props.field,\n (field, oldField) => {\n if (oldField) {\n unregisterField?.(oldField)\n }\n if (field) {\n registerField?.(field, fieldItem)\n }\n },\n { immediate: true }\n)\n\nlet stopWatchFieldValue: (() => void) | undefined\n\nwatch(\n [() => formProps?.model, () => props.field],\n ([model, field]) => {\n stopWatchFieldValue?.()\n\n if (!field || !model) return\n\n stopWatchFieldValue = watch(\n () => o(model).get(field),\n (value) => {\n handleFieldChange?.(field, value)\n fieldItem.validate()\n }\n )\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n props.field && unregisterField?.(props.field)\n})\n</script>\n"],"mappings":""}
1
+ {"version":3,"file":"form-item.js","names":[],"sources":["../../../src/components/form-item/form-item.vue"],"sourcesContent":["<template>\n <u-grid-item :span=\"span\" :class=\"className\">\n <label\n v-if=\"props.label || $slots.label\"\n :class=\"[cls.e('label'), bem.is('required', !!rules?.required)]\"\n :style=\"labelStyles\"\n >\n <u-tip v-if=\"tips\" :content=\"tips\" :class=\"cls.e('tips')\">\n <span :class=\"cls.e('tip-label')\">\n <slot name=\"label\">{{ label }}:</slot>\n </span>\n </u-tip>\n <template v-else>\n <slot name=\"label\">{{ label }}:</slot>\n </template>\n </label>\n\n <section :class=\"cls.e('wrapper')\">\n <div :class=\"cls.e('content')\">\n <slot></slot>\n </div>\n\n <!-- 只有表单控件处于非只读状态时,才显示错误提示 -->\n <section :class=\"cls.e('error')\" v-if=\"!readonly && !formProps?.noTips\">\n <transition name=\"form-item-tips\" mode=\"out-in\">\n <span :class=\"cls.e('error-text')\" v-if=\"!!errorTip\">\n {{ errorTip }}\n </span>\n </transition>\n </section>\n </section>\n </u-grid-item>\n</template>\n\n<script lang=\"tsx\" setup>\nimport { o } from '@cat-kit/core'\nimport { useConfig, useFallbackProps } from '@veltra/compositions'\nimport { bem, withUnit } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { type CSSProperties, computed, onBeforeUnmount, shallowRef, watch } from 'vue'\n\nimport type { FormItemProps, ComponentSize } from '../../types'\nimport { UGridItem } from '../grid'\nimport { UTip } from '../tip'\nimport { formItemCls as cls, defineField } from './helper'\nimport { validateField } from './validate'\n\ndefineOptions({ name: 'UFormItem' })\n\nconst props = withDefaults(defineProps<FormItemProps>(), { readonly: undefined })\n\ndefineSlots<{\n /** 标签插槽 */\n label?: () => any\n default?: () => any\n}>()\n\n/** 表单组件上下文 */\nconst { formProps, registerField, unregisterField, shouldValidate, handleFieldChange } =\n injectFormContext()\n\nconst { config } = useConfig()\n\nconst { size, readonly } = useFallbackProps([formProps ?? {}, props], {\n size: 'default' as ComponentSize,\n readonly: false\n})\n\nconst errorTip = shallowRef<string>()\n/** 递增序号,丢弃过期的异步校验结果 */\nlet validateSeq = 0\n/** 最近一次 validate 的 Promise,供过期调用等待最新结果 */\nlet latestValidatePromise: Promise<boolean> = Promise.resolve(true)\n\nconst labelPosition = computed(() => props.labelPosition ?? formProps?.labelPosition ?? 'left')\n\nconst className = computed(() => {\n return [\n cls.b,\n cls.m(size.value),\n bem.is('error', !!errorTip.value),\n bem.is('label-top', labelPosition.value === 'top')\n ].join(' ')\n})\n\n/** label样式 */\nconst labelStyles = computed<CSSProperties>(() => {\n if (labelPosition.value === 'top') return {}\n return {\n width: withUnit(props.labelWidth ?? formProps?.labelWidth ?? config.form.labelWidth, 'px')\n }\n})\n\nconst fieldItem = defineField({\n clearValidate() {\n errorTip.value = ''\n },\n async validate() {\n if (!props.field || !formProps?.model || !props.rules || !shouldValidate?.()) return true\n\n const seq = ++validateSeq\n\n latestValidatePromise = validateField(formProps.model!, props.field!, props.rules!).then(\n (tip) => {\n if (seq !== validateSeq) return latestValidatePromise\n\n errorTip.value = tip\n return !errorTip.value\n }\n )\n return latestValidatePromise\n }\n})\n\nwatch(\n () => props.field,\n (field, oldField) => {\n if (oldField) {\n unregisterField?.(oldField)\n }\n if (field) {\n registerField?.(field, fieldItem)\n }\n },\n { immediate: true }\n)\n\nlet stopWatchFieldValue: (() => void) | undefined\n\nwatch(\n [() => formProps?.model, () => props.field],\n ([model, field]) => {\n stopWatchFieldValue?.()\n\n if (!field || !model) return\n\n stopWatchFieldValue = watch(\n () => o(model).get(field),\n (value) => {\n handleFieldChange?.(field, value)\n fieldItem.validate()\n }\n )\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n props.field && unregisterField?.(props.field)\n})\n</script>\n"],"mappings":""}
@@ -12,6 +12,7 @@ var form_item_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
12
12
  __name: "form-item",
13
13
  props: {
14
14
  labelWidth: {},
15
+ labelPosition: {},
15
16
  tips: {},
16
17
  span: {},
17
18
  label: {},
@@ -38,15 +39,18 @@ var form_item_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
38
39
  let validateSeq = 0;
39
40
  /** 最近一次 validate 的 Promise,供过期调用等待最新结果 */
40
41
  let latestValidatePromise = Promise.resolve(true);
42
+ const labelPosition = computed(() => props.labelPosition ?? formProps?.labelPosition ?? "left");
41
43
  const className = computed(() => {
42
44
  return [
43
45
  formItemCls.b,
44
46
  formItemCls.m(size.value),
45
- bem.is("error", !!errorTip.value)
47
+ bem.is("error", !!errorTip.value),
48
+ bem.is("label-top", labelPosition.value === "top")
46
49
  ].join(" ");
47
50
  });
48
51
  /** label样式 */
49
52
  const labelStyles = computed(() => {
53
+ if (labelPosition.value === "top") return {};
50
54
  return { width: withUnit(props.labelWidth ?? formProps?.labelWidth ?? config.form.labelWidth, "px") };
51
55
  });
52
56
  const fieldItem = defineField({
@@ -1 +1 @@
1
- {"version":3,"file":"form-item.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/form-item/form-item.vue"],"sourcesContent":["<template>\n <u-grid-item :span=\"span\" :class=\"className\">\n <label\n v-if=\"props.label || $slots.label\"\n :class=\"[cls.e('label'), bem.is('required', !!rules?.required)]\"\n :style=\"labelStyles\"\n >\n <u-tip v-if=\"tips\" :content=\"tips\" :class=\"cls.e('tips')\">\n <span :class=\"cls.e('tip-label')\">\n <slot name=\"label\">{{ label }}:</slot>\n </span>\n </u-tip>\n <template v-else>\n <slot name=\"label\">{{ label }}:</slot>\n </template>\n </label>\n\n <section :class=\"cls.e('wrapper')\">\n <div :class=\"cls.e('content')\">\n <slot></slot>\n </div>\n\n <!-- 只有表单控件处于非只读状态时,才显示错误提示 -->\n <section :class=\"cls.e('error')\" v-if=\"!readonly && !formProps?.noTips\">\n <transition name=\"form-item-tips\" mode=\"out-in\">\n <span :class=\"cls.e('error-text')\" v-if=\"!!errorTip\">\n {{ errorTip }}\n </span>\n </transition>\n </section>\n </section>\n </u-grid-item>\n</template>\n\n<script lang=\"tsx\" setup>\nimport { o } from '@cat-kit/core'\nimport { useConfig, useFallbackProps } from '@veltra/compositions'\nimport { bem, withUnit } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { type CSSProperties, computed, onBeforeUnmount, shallowRef, watch } from 'vue'\n\nimport type { FormItemProps, ComponentSize } from '../../types'\nimport { UGridItem } from '../grid'\nimport { UTip } from '../tip'\nimport { formItemCls as cls, defineField } from './helper'\nimport { validateField } from './validate'\n\ndefineOptions({ name: 'UFormItem' })\n\nconst props = withDefaults(defineProps<FormItemProps>(), { readonly: undefined })\n\ndefineSlots<{\n /** 标签插槽 */\n label?: () => any\n default?: () => any\n}>()\n\n/** 表单组件上下文 */\nconst { formProps, registerField, unregisterField, shouldValidate, handleFieldChange } =\n injectFormContext()\n\nconst { config } = useConfig()\n\nconst { size, readonly } = useFallbackProps([formProps ?? {}, props], {\n size: 'default' as ComponentSize,\n readonly: false\n})\n\nconst errorTip = shallowRef<string>()\n/** 递增序号,丢弃过期的异步校验结果 */\nlet validateSeq = 0\n/** 最近一次 validate 的 Promise,供过期调用等待最新结果 */\nlet latestValidatePromise: Promise<boolean> = Promise.resolve(true)\n\nconst className = computed(() => {\n return [cls.b, cls.m(size.value), bem.is('error', !!errorTip.value)].join(' ')\n})\n\n/** label样式 */\nconst labelStyles = computed<CSSProperties>(() => {\n return {\n width: withUnit(props.labelWidth ?? formProps?.labelWidth ?? config.form.labelWidth, 'px')\n }\n})\n\nconst fieldItem = defineField({\n clearValidate() {\n errorTip.value = ''\n },\n async validate() {\n if (!props.field || !formProps?.model || !props.rules || !shouldValidate?.()) return true\n\n const seq = ++validateSeq\n\n latestValidatePromise = validateField(formProps.model!, props.field!, props.rules!).then(\n (tip) => {\n if (seq !== validateSeq) return latestValidatePromise\n\n errorTip.value = tip\n return !errorTip.value\n }\n )\n return latestValidatePromise\n }\n})\n\nwatch(\n () => props.field,\n (field, oldField) => {\n if (oldField) {\n unregisterField?.(oldField)\n }\n if (field) {\n registerField?.(field, fieldItem)\n }\n },\n { immediate: true }\n)\n\nlet stopWatchFieldValue: (() => void) | undefined\n\nwatch(\n [() => formProps?.model, () => props.field],\n ([model, field]) => {\n stopWatchFieldValue?.()\n\n if (!field || !model) return\n\n stopWatchFieldValue = watch(\n () => o(model).get(field),\n (value) => {\n handleFieldChange?.(field, value)\n fieldItem.validate()\n }\n )\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n props.field && unregisterField?.(props.field)\n})\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"form-item.vue_vue_type_script_setup_true_lang.js","names":["$slots"],"sources":["../../../src/components/form-item/form-item.vue"],"sourcesContent":["<template>\n <u-grid-item :span=\"span\" :class=\"className\">\n <label\n v-if=\"props.label || $slots.label\"\n :class=\"[cls.e('label'), bem.is('required', !!rules?.required)]\"\n :style=\"labelStyles\"\n >\n <u-tip v-if=\"tips\" :content=\"tips\" :class=\"cls.e('tips')\">\n <span :class=\"cls.e('tip-label')\">\n <slot name=\"label\">{{ label }}:</slot>\n </span>\n </u-tip>\n <template v-else>\n <slot name=\"label\">{{ label }}:</slot>\n </template>\n </label>\n\n <section :class=\"cls.e('wrapper')\">\n <div :class=\"cls.e('content')\">\n <slot></slot>\n </div>\n\n <!-- 只有表单控件处于非只读状态时,才显示错误提示 -->\n <section :class=\"cls.e('error')\" v-if=\"!readonly && !formProps?.noTips\">\n <transition name=\"form-item-tips\" mode=\"out-in\">\n <span :class=\"cls.e('error-text')\" v-if=\"!!errorTip\">\n {{ errorTip }}\n </span>\n </transition>\n </section>\n </section>\n </u-grid-item>\n</template>\n\n<script lang=\"tsx\" setup>\nimport { o } from '@cat-kit/core'\nimport { useConfig, useFallbackProps } from '@veltra/compositions'\nimport { bem, withUnit } from '@veltra/utils'\nimport { injectFormContext } from '@veltra/utils'\nimport { type CSSProperties, computed, onBeforeUnmount, shallowRef, watch } from 'vue'\n\nimport type { FormItemProps, ComponentSize } from '../../types'\nimport { UGridItem } from '../grid'\nimport { UTip } from '../tip'\nimport { formItemCls as cls, defineField } from './helper'\nimport { validateField } from './validate'\n\ndefineOptions({ name: 'UFormItem' })\n\nconst props = withDefaults(defineProps<FormItemProps>(), { readonly: undefined })\n\ndefineSlots<{\n /** 标签插槽 */\n label?: () => any\n default?: () => any\n}>()\n\n/** 表单组件上下文 */\nconst { formProps, registerField, unregisterField, shouldValidate, handleFieldChange } =\n injectFormContext()\n\nconst { config } = useConfig()\n\nconst { size, readonly } = useFallbackProps([formProps ?? {}, props], {\n size: 'default' as ComponentSize,\n readonly: false\n})\n\nconst errorTip = shallowRef<string>()\n/** 递增序号,丢弃过期的异步校验结果 */\nlet validateSeq = 0\n/** 最近一次 validate 的 Promise,供过期调用等待最新结果 */\nlet latestValidatePromise: Promise<boolean> = Promise.resolve(true)\n\nconst labelPosition = computed(() => props.labelPosition ?? formProps?.labelPosition ?? 'left')\n\nconst className = computed(() => {\n return [\n cls.b,\n cls.m(size.value),\n bem.is('error', !!errorTip.value),\n bem.is('label-top', labelPosition.value === 'top')\n ].join(' ')\n})\n\n/** label样式 */\nconst labelStyles = computed<CSSProperties>(() => {\n if (labelPosition.value === 'top') return {}\n return {\n width: withUnit(props.labelWidth ?? formProps?.labelWidth ?? config.form.labelWidth, 'px')\n }\n})\n\nconst fieldItem = defineField({\n clearValidate() {\n errorTip.value = ''\n },\n async validate() {\n if (!props.field || !formProps?.model || !props.rules || !shouldValidate?.()) return true\n\n const seq = ++validateSeq\n\n latestValidatePromise = validateField(formProps.model!, props.field!, props.rules!).then(\n (tip) => {\n if (seq !== validateSeq) return latestValidatePromise\n\n errorTip.value = tip\n return !errorTip.value\n }\n )\n return latestValidatePromise\n }\n})\n\nwatch(\n () => props.field,\n (field, oldField) => {\n if (oldField) {\n unregisterField?.(oldField)\n }\n if (field) {\n registerField?.(field, fieldItem)\n }\n },\n { immediate: true }\n)\n\nlet stopWatchFieldValue: (() => void) | undefined\n\nwatch(\n [() => formProps?.model, () => props.field],\n ([model, field]) => {\n stopWatchFieldValue?.()\n\n if (!field || !model) return\n\n stopWatchFieldValue = watch(\n () => o(model).get(field),\n (value) => {\n handleFieldChange?.(field, value)\n fieldItem.validate()\n }\n )\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n props.field && unregisterField?.(props.field)\n})\n</script>\n"],"mappings":"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"}
@@ -121,6 +121,19 @@
121
121
  border-bottom: 1px dashed var(--u-color-info);
122
122
  color: var(--u-color-info);
123
123
  }
124
+ .u-form-item.is-label-top {
125
+ display: flex;
126
+ flex-direction: column;
127
+ align-items: stretch;
128
+ width: 100%;
129
+ }
130
+ .u-form-item.is-label-top .u-form-item__label {
131
+ min-height: auto;
132
+ padding-right: 0;
133
+ padding-bottom: 4px;
134
+ text-align: left;
135
+ justify-content: flex-start;
136
+ }
124
137
 
125
138
  .form-item-tips-enter-from,
126
139
  .form-item-tips-leave-to {
@@ -12,8 +12,8 @@ declare const __VLS_base: import("vue").DefineComponent<PopConfirmProps, {}, {},
12
12
  onConfirm?: (() => any) | undefined;
13
13
  onCancel?: (() => any) | undefined;
14
14
  }>, {
15
- direction: TipDirection;
16
15
  trigger: "hover" | "click";
16
+ direction: TipDirection;
17
17
  icon: import("vue").Component;
18
18
  iconColor: string;
19
19
  confirmText: string;
@@ -6,11 +6,11 @@ type __VLS_Slots = {
6
6
  tip?: (scope: StepsSlotScope) => any;
7
7
  };
8
8
  declare const __VLS_base: import("vue").DefineComponent<StepsProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
9
- "item-click": (item: Record<string, any>, index: number) => any;
10
9
  "update:current": (value?: string | number | undefined) => any;
10
+ "item-click": (item: Record<string, any>, index: number) => any;
11
11
  }, string, import("vue").PublicProps, Readonly<StepsProps> & Readonly<{
12
- "onItem-click"?: ((item: Record<string, any>, index: number) => any) | undefined;
13
12
  "onUpdate:current"?: ((value?: string | number | undefined) => any) | undefined;
13
+ "onItem-click"?: ((item: Record<string, any>, index: number) => any) | undefined;
14
14
  }>, {
15
15
  labelKey: string;
16
16
  direction: "horizontal" | "vertical";
@@ -9,10 +9,10 @@ declare const __VLS_base: import("vue").DefineComponent<TipProps, {}, {}, {}, {}
9
9
  }, string, import("vue").PublicProps, Readonly<TipProps> & Readonly<{
10
10
  "onUpdate:visible"?: ((value: boolean) => any) | undefined;
11
11
  }>, {
12
- direction: TipDirection;
13
12
  trigger: "hover" | "click";
14
13
  contentTag: string;
15
14
  visible: boolean;
15
+ direction: TipDirection;
16
16
  content: string;
17
17
  alignment: TipAlign;
18
18
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -1,6 +1,6 @@
1
- import { NodeProp } from "../../../../../@lezer_common@1.5.2/node_modules/@lezer/common/dist/index.js";
2
1
  import { Annotation, ChangeDesc, ChangeSet, EditorSelection, Facet, StateEffect, StateField, Text, Transaction, combineConfig, countColumn, findClusterBreak } from "../../../../../@codemirror_state@6.7.0/node_modules/@codemirror/state/dist/index.js";
3
2
  import { Direction, EditorView } from "../../../../../@codemirror_view@6.43.4/node_modules/@codemirror/view/dist/index.js";
3
+ import { NodeProp } from "../../../../../@lezer_common@1.5.2/node_modules/@lezer/common/dist/index.js";
4
4
  import { IndentContext, getIndentUnit, getIndentation, indentString, indentUnit, matchBrackets, syntaxTree } from "../../../../../@codemirror_language@6.12.4/node_modules/@codemirror/language/dist/index.js";
5
5
  //#region ../../node_modules/.bun/@codemirror+commands@6.10.4/node_modules/@codemirror/commands/dist/index.js
6
6
  /**
@@ -1,5 +1,5 @@
1
- import { parser } from "../../../../../@lezer_java@1.1.3/node_modules/@lezer/java/dist/index.js";
2
1
  import { LRLanguage, LanguageSupport, continuedIndent, delimitedIndent, flatIndent, foldInside, foldNodeProp, indentNodeProp } from "../../../../../@codemirror_language@6.12.4/node_modules/@codemirror/language/dist/index.js";
2
+ import { parser } from "../../../../../@lezer_java@1.1.3/node_modules/@lezer/java/dist/index.js";
3
3
  //#region ../../node_modules/.bun/@codemirror+lang-java@6.0.2/node_modules/@codemirror/lang-java/dist/index.js
4
4
  /**
5
5
  A language provider based on the [Lezer Java
@@ -1,9 +1,9 @@
1
- import { IterMode, NodeWeakMap } from "../../../../../@lezer_common@1.5.2/node_modules/@lezer/common/dist/index.js";
2
1
  import { EditorSelection } from "../../../../../@codemirror_state@6.7.0/node_modules/@codemirror/state/dist/index.js";
3
2
  import { EditorView } from "../../../../../@codemirror_view@6.43.4/node_modules/@codemirror/view/dist/index.js";
3
+ import { IterMode, NodeWeakMap } from "../../../../../@lezer_common@1.5.2/node_modules/@lezer/common/dist/index.js";
4
4
  import { LRLanguage, LanguageSupport, continuedIndent, defineLanguageFacet, delimitedIndent, flatIndent, foldInside, foldNodeProp, indentNodeProp, sublanguageProp, syntaxTree } from "../../../../../@codemirror_language@6.12.4/node_modules/@codemirror/language/dist/index.js";
5
- import { parser } from "../../../../../@lezer_javascript@1.5.4/node_modules/@lezer/javascript/dist/index.js";
6
5
  import { completeFromList, ifNotIn, snippetCompletion } from "../../../../../@codemirror_autocomplete@6.20.3/node_modules/@codemirror/autocomplete/dist/index.js";
6
+ import { parser } from "../../../../../@lezer_javascript@1.5.4/node_modules/@lezer/javascript/dist/index.js";
7
7
  //#region ../../node_modules/.bun/@codemirror+lang-javascript@6.2.5/node_modules/@codemirror/lang-javascript/dist/index.js
8
8
  /**
9
9
  A collection of JavaScript-related
@@ -1,7 +1,7 @@
1
- import { ExternalTokenizer, LRParser } from "../../../../../@lezer_lr@1.4.10/node_modules/@lezer/lr/dist/index.js";
2
1
  import { styleTags, tags } from "../../../../../@lezer_highlight@1.2.3/node_modules/@lezer/highlight/dist/index.js";
3
2
  import { LRLanguage, LanguageSupport, continuedIndent, foldNodeProp, indentNodeProp, syntaxTree } from "../../../../../@codemirror_language@6.12.4/node_modules/@codemirror/language/dist/index.js";
4
3
  import { completeFromList, ifNotIn } from "../../../../../@codemirror_autocomplete@6.20.3/node_modules/@codemirror/autocomplete/dist/index.js";
4
+ import { ExternalTokenizer, LRParser } from "../../../../../@lezer_lr@1.4.10/node_modules/@lezer/lr/dist/index.js";
5
5
  //#region ../../node_modules/.bun/@codemirror+lang-sql@6.10.0/node_modules/@codemirror/lang-sql/dist/index.js
6
6
  const whitespace = 36, LineComment = 1, BlockComment = 2, String$1 = 3, Number = 4, Bool = 5, Null = 6, ParenL = 7, ParenR = 8, BraceL = 9, BraceR = 10, BracketL = 11, BracketR = 12, Semi = 13, Dot = 14, Operator = 15, Punctuation = 16, SpecialVar = 17, Identifier = 18, QuotedIdentifier = 19, Keyword = 20, Type = 21, Bits = 22, Bytes = 23, Builtin = 24;
7
7
  function isAlpha(ch) {
@@ -1,8 +1,8 @@
1
- import { IterMode, NodeProp, NodeType, Parser, Tree, TreeFragment } from "../../../../../@lezer_common@1.5.2/node_modules/@lezer/common/dist/index.js";
2
- import { highlightTree, styleTags, tagHighlighter, tags } from "../../../../../@lezer_highlight@1.2.3/node_modules/@lezer/highlight/dist/index.js";
3
1
  import { EditorState, Facet, Prec, RangeSet, RangeSetBuilder, StateEffect, StateField, combineConfig, countColumn } from "../../../../../@codemirror_state@6.7.0/node_modules/@codemirror/state/dist/index.js";
4
2
  import { StyleModule } from "../../../../../style-mod@4.1.3/node_modules/style-mod/src/style-mod.js";
5
3
  import { Decoration, Direction, EditorView, GutterMarker, ViewPlugin, WidgetType, gutter, logException } from "../../../../../@codemirror_view@6.43.4/node_modules/@codemirror/view/dist/index.js";
4
+ import { IterMode, NodeProp, NodeType, Parser, Tree, TreeFragment } from "../../../../../@lezer_common@1.5.2/node_modules/@lezer/common/dist/index.js";
5
+ import { highlightTree, styleTags, tagHighlighter, tags } from "../../../../../@lezer_highlight@1.2.3/node_modules/@lezer/highlight/dist/index.js";
6
6
  //#region ../../node_modules/.bun/@codemirror+language@6.12.4/node_modules/@codemirror/language/dist/index.js
7
7
  var _a;
8
8
  /**
@@ -1,5 +1,5 @@
1
- import { tags } from "../../../../../@lezer_highlight@1.2.3/node_modules/@lezer/highlight/dist/index.js";
2
1
  import { EditorView } from "../../../../../@codemirror_view@6.43.4/node_modules/@codemirror/view/dist/index.js";
2
+ import { tags } from "../../../../../@lezer_highlight@1.2.3/node_modules/@lezer/highlight/dist/index.js";
3
3
  import { HighlightStyle, syntaxHighlighting } from "../../../../../@codemirror_language@6.12.4/node_modules/@codemirror/language/dist/index.js";
4
4
  //#region ../../node_modules/.bun/@codemirror+theme-one-dark@6.1.3/node_modules/@codemirror/theme-one-dark/dist/index.js
5
5
  const chalky = "#e5c07b", coral = "#e06c75", cyan = "#56b6c2", invalid = "#ffffff", ivory = "#abb2bf", stone = "#7d8799", malibu = "#61afef", sage = "#98c379", whiskey = "#d19a66", violet = "#c678dd", darkBackground = "#21252b", highlightBackground = "#2c313a", background = "#282c34", tooltipBackground = "#353a42", selection = "#3E4451", cursor = "#528bff";
@@ -1,5 +1,5 @@
1
- import { LRParser } from "../../../../../@lezer_lr@1.4.10/node_modules/@lezer/lr/dist/index.js";
2
1
  import { styleTags, tags } from "../../../../../@lezer_highlight@1.2.3/node_modules/@lezer/highlight/dist/index.js";
2
+ import { LRParser } from "../../../../../@lezer_lr@1.4.10/node_modules/@lezer/lr/dist/index.js";
3
3
  //#region ../../node_modules/.bun/@lezer+java@1.1.3/node_modules/@lezer/java/dist/index.js
4
4
  const javaHighlighting = styleTags({
5
5
  null: tags.null,
@@ -1,5 +1,5 @@
1
- import { ContextTracker, ExternalTokenizer, LRParser, LocalTokenGroup } from "../../../../../@lezer_lr@1.4.10/node_modules/@lezer/lr/dist/index.js";
2
1
  import { styleTags, tags } from "../../../../../@lezer_highlight@1.2.3/node_modules/@lezer/highlight/dist/index.js";
2
+ import { ContextTracker, ExternalTokenizer, LRParser, LocalTokenGroup } from "../../../../../@lezer_lr@1.4.10/node_modules/@lezer/lr/dist/index.js";
3
3
  //#region ../../node_modules/.bun/@lezer+javascript@1.5.4/node_modules/@lezer/javascript/dist/index.js
4
4
  const noSemi = 316, noSemiType = 317, incdec = 1, incdecPrefix = 2, questionDot = 3, JSXStartTag = 4, insertSemi = 318, spaces = 320, newline = 321, LineComment = 5, BlockComment = 6, Dialect_jsx = 0;
5
5
  const space = [
@@ -1,5 +1,5 @@
1
- import { LRParser } from "../../../../../@lezer_lr@1.4.10/node_modules/@lezer/lr/dist/index.js";
2
1
  import { styleTags, tags } from "../../../../../@lezer_highlight@1.2.3/node_modules/@lezer/highlight/dist/index.js";
2
+ import { LRParser } from "../../../../../@lezer_lr@1.4.10/node_modules/@lezer/lr/dist/index.js";
3
3
  //#region ../../node_modules/.bun/@lezer+json@1.0.3/node_modules/@lezer/json/dist/index.js
4
4
  const jsonHighlighting = styleTags({
5
5
  String: tags.string,
@@ -5,6 +5,8 @@ import { FormComponentProps } from "@veltra/utils";
5
5
  interface FormItemProps extends FormComponentProps {
6
6
  /** 标签宽度 */
7
7
  labelWidth?: string | number;
8
+ /** 标签位置 */
9
+ labelPosition?: 'top' | 'left';
8
10
  }
9
11
  /** 组件项组件定义的事件 */
10
12
  interface FormItemEmits {}
@@ -13,6 +13,8 @@ interface FormProps extends ComponentProps {
13
13
  model?: Record<string, any>;
14
14
  /** 表单项label宽度 */
15
15
  labelWidth?: string | number;
16
+ /** 表单项 label 位置 */
17
+ labelPosition?: 'top' | 'left';
16
18
  /** 是否不显示tips */
17
19
  noTips?: boolean;
18
20
  /** 是否只读 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veltra/desktop",
3
- "version": "1.2.18",
3
+ "version": "1.2.20",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
@@ -57,11 +57,11 @@
57
57
  "@cat-kit/core": ">=1.1.8",
58
58
  "@cat-kit/excel": ">=1.0.0",
59
59
  "@cat-kit/fe": "^1.1.8",
60
- "@veltra/compositions": "1.2.18",
61
- "@veltra/directives": "1.2.18",
62
- "@veltra/icons": "1.2.18",
63
- "@veltra/styles": "1.2.18",
64
- "@veltra/utils": "1.2.18",
60
+ "@veltra/compositions": "1.2.20",
61
+ "@veltra/directives": "1.2.20",
62
+ "@veltra/icons": "1.2.20",
63
+ "@veltra/styles": "1.2.20",
64
+ "@veltra/utils": "1.2.20",
65
65
  "vue": ">=3.5.39"
66
66
  },
67
67
  "devDependencies": {
@@ -5,10 +5,6 @@
5
5
  </template>
6
6
 
7
7
  <script lang="ts" setup>
8
- import { java } from '@codemirror/lang-java'
9
- import { javascript } from '@codemirror/lang-javascript'
10
- import { json } from '@codemirror/lang-json'
11
- import { sql } from '@codemirror/lang-sql'
12
8
  import { Compartment, EditorState, type Extension } from '@codemirror/state'
13
9
  import { oneDark } from '@codemirror/theme-one-dark'
14
10
  import { EditorView, ViewPlugin, tooltips, type ViewUpdate } from '@codemirror/view'
@@ -24,9 +20,10 @@ import {
24
20
  type CSSProperties
25
21
  } from 'vue'
26
22
 
27
- import type { CodeEditorLang, CodeEditorProps } from '../../types'
23
+ import type { CodeEditorProps } from '../../types'
28
24
  import { UScroll } from '../scroll'
29
25
  import { basicSetup } from './basic-setup'
26
+ import { loadLanguage } from './lang-loaders'
30
27
 
31
28
  defineOptions({ name: 'UCodeEditor' })
32
29
 
@@ -62,14 +59,6 @@ const rootStyle = computed<CSSProperties>(() => ({
62
59
  const containerRef = useTemplateRef('container')
63
60
  const editor = shallowRef<EditorView | null>(null)
64
61
 
65
- /** 静态导入语言包,避免动态 import 在打包/Vite 预构建下产生多份 @codemirror/* 实例 */
66
- const langExtensions: Record<CodeEditorLang, Extension> = {
67
- js: javascript({ typescript: true }),
68
- sql: sql(),
69
- java: java(),
70
- json: json()
71
- }
72
-
73
62
  const themeCompartment = new Compartment()
74
63
  const editableCompartment = new Compartment()
75
64
  const readOnlyCompartment = new Compartment()
@@ -161,12 +150,19 @@ function buildExtensions(): Extension[] {
161
150
  let editorToken = 0
162
151
  let langToken = 0
163
152
 
164
- function applyLanguage() {
153
+ async function applyLanguage() {
165
154
  const view = editor.value
166
155
  if (!view) return
167
156
  const myToken = ++langToken
168
157
  const { language } = props
169
- const ext = language ? langExtensions[language] : []
158
+
159
+ if (!language) {
160
+ if (myToken !== langToken || editor.value !== view) return
161
+ view.dispatch({ effects: langCompartment.reconfigure([]) })
162
+ return
163
+ }
164
+
165
+ const ext = await loadLanguage(language)
170
166
  if (myToken !== langToken || editor.value !== view) return
171
167
  view.dispatch({ effects: langCompartment.reconfigure(ext) })
172
168
  }
@@ -0,0 +1,16 @@
1
+ import type { Extension } from '@codemirror/state'
2
+
3
+ import type { CodeEditorLang } from '../../types'
4
+
5
+ /** 语言包动态加载器,新增语言只需在此注册一条 */
6
+ const LANG_LOADERS: Record<CodeEditorLang, () => Promise<Extension>> = {
7
+ js: () => import('@codemirror/lang-javascript').then((m) => m.javascript({ typescript: true })),
8
+ sql: () => import('@codemirror/lang-sql').then((m) => m.sql()),
9
+ java: () => import('@codemirror/lang-java').then((m) => m.java()),
10
+ json: () => import('@codemirror/lang-json').then((m) => m.json())
11
+ }
12
+
13
+ /** 按需加载语言扩展;模块缓存由运行时保证,重复切换同一语言不会重复下载 */
14
+ export function loadLanguage(lang: CodeEditorLang): Promise<Extension> {
15
+ return LANG_LOADERS[lang]()
16
+ }
@@ -72,12 +72,20 @@ let validateSeq = 0
72
72
  /** 最近一次 validate 的 Promise,供过期调用等待最新结果 */
73
73
  let latestValidatePromise: Promise<boolean> = Promise.resolve(true)
74
74
 
75
+ const labelPosition = computed(() => props.labelPosition ?? formProps?.labelPosition ?? 'left')
76
+
75
77
  const className = computed(() => {
76
- return [cls.b, cls.m(size.value), bem.is('error', !!errorTip.value)].join(' ')
78
+ return [
79
+ cls.b,
80
+ cls.m(size.value),
81
+ bem.is('error', !!errorTip.value),
82
+ bem.is('label-top', labelPosition.value === 'top')
83
+ ].join(' ')
77
84
  })
78
85
 
79
86
  /** label样式 */
80
87
  const labelStyles = computed<CSSProperties>(() => {
88
+ if (labelPosition.value === 'top') return {}
81
89
  return {
82
90
  width: withUnit(props.labelWidth ?? formProps?.labelWidth ?? config.form.labelWidth, 'px')
83
91
  }
@@ -97,6 +97,21 @@ $root-name: form-item;
97
97
  border-bottom: 1px dashed fn.use-var(color, info);
98
98
  color: fn.use-var(color, info);
99
99
  }
100
+
101
+ @include m.is(label-top) {
102
+ display: flex;
103
+ flex-direction: column;
104
+ align-items: stretch;
105
+ width: 100%;
106
+
107
+ @include m.bem($root-name, label) {
108
+ min-height: auto;
109
+ padding-right: 0;
110
+ padding-bottom: 4px;
111
+ text-align: left;
112
+ justify-content: flex-start;
113
+ }
114
+ }
100
115
  }
101
116
 
102
117
  .#{$root-name}-tips-enter-from,
@@ -4,6 +4,8 @@ import type { FormComponentProps } from '@veltra/utils'
4
4
  export interface FormItemProps extends FormComponentProps {
5
5
  /** 标签宽度 */
6
6
  labelWidth?: string | number
7
+ /** 标签位置 */
8
+ labelPosition?: 'top' | 'left'
7
9
  }
8
10
 
9
11
  /** 组件项组件定义的事件 */
package/src/types/form.ts CHANGED
@@ -13,6 +13,8 @@ export interface FormProps extends ComponentProps {
13
13
  // showModified?: boolean
14
14
  /** 表单项label宽度 */
15
15
  labelWidth?: string | number
16
+ /** 表单项 label 位置 */
17
+ labelPosition?: 'top' | 'left'
16
18
  /** 是否不显示tips */
17
19
  noTips?: boolean
18
20
  /** 是否只读 */