@robot-admin/naive-ui-components 0.14.3 → 0.15.0
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 +24 -0
- package/README.md +130 -741
- package/README_EN.md +137 -678
- package/dist/C_ActionBar.css +57 -58
- package/dist/C_ActionBar2.cjs +1 -1
- package/dist/C_ActionBar2.js +1 -1
- package/dist/C_AntV.css +232 -238
- package/dist/C_AntV2.cjs +2 -2
- package/dist/C_AntV2.js +2 -2
- package/dist/C_AudioPlayer.css +9 -9
- package/dist/C_AvatarGroup.css +5 -6
- package/dist/C_Barcode.css +1 -1
- package/dist/C_Breadcrumb.css +15 -18
- package/dist/C_Breadcrumb2.cjs +1 -1
- package/dist/C_Breadcrumb2.js +1 -1
- package/dist/C_Captcha.css +46 -49
- package/dist/C_Captcha2.cjs +1 -1
- package/dist/C_Captcha2.js +1 -1
- package/dist/C_Cascade.css +5 -6
- package/dist/C_Chat.css +8 -8
- package/dist/C_City.css +2 -2
- package/dist/C_Code.css +9 -9
- package/dist/C_CollapsePanel.css +9 -9
- package/dist/C_ContextMenu.css +31 -31
- package/dist/C_Cron.css +271 -274
- package/dist/C_Date.css +1 -1
- package/dist/C_Draggable.css +10 -11
- package/dist/C_Editor.css +2 -2
- package/dist/C_FilePreview.css +423 -423
- package/dist/C_Form.base.css +608 -602
- package/dist/C_Form.cjs +1 -1
- package/dist/C_Form.css +610 -604
- package/dist/C_Form.d.cts +2 -2
- package/dist/C_Form.d.ts +2 -2
- package/dist/C_Form.js +1 -1
- package/dist/C_FormModal.cjs +1 -1
- package/dist/C_FormModal.css +12 -17
- package/dist/C_FormModal.js +1 -1
- package/dist/C_FormModal2.cjs +1 -1
- package/dist/C_FormModal2.js +1 -1
- package/dist/C_FormSearch.css +53 -55
- package/dist/C_FormSearch2.cjs +1 -1
- package/dist/C_FormSearch2.js +1 -1
- package/dist/C_FormulaEditor.css +204 -205
- package/dist/C_FullCalendar.css +13 -15
- package/dist/C_FullCalendar2.cjs +1 -1
- package/dist/C_FullCalendar2.js +1 -1
- package/dist/C_GlobalSearch.css +11 -12
- package/dist/C_Guide.css +10 -10
- package/dist/C_Icon.css +7 -8
- package/dist/C_ImageCropper.css +69 -69
- package/dist/C_Language.css +8 -8
- package/dist/C_Loading.css +22 -25
- package/dist/C_Loading2.cjs +1 -1
- package/dist/C_Loading2.js +1 -1
- package/dist/C_Login.css +130 -135
- package/dist/C_Login2.cjs +1 -1
- package/dist/C_Login2.js +1 -1
- package/dist/C_Map.css +22 -23
- package/dist/C_Markdown.css +6 -7
- package/dist/C_Menu.css +2 -5
- package/dist/C_Menu2.cjs +1 -1
- package/dist/C_Menu2.js +1 -1
- package/dist/C_NotificationCenter.css +252 -253
- package/dist/C_OrgChart.css +8 -8
- package/dist/C_PageLoading.css +34 -39
- package/dist/C_QRCode.css +5 -6
- package/dist/C_Signature.css +5 -6
- package/dist/C_Skeleton.css +2 -2
- package/dist/C_SplitPane.css +2 -2
- package/dist/C_Steps.css +5 -6
- package/dist/C_Table.base.css +1090 -879
- package/dist/C_Table.cjs +1 -1
- package/dist/C_Table.css +1096 -885
- package/dist/C_Table.d.cts +1 -1
- package/dist/C_Table.d.ts +1 -1
- package/dist/C_Table.js +1 -1
- package/dist/C_Tabs.css +5 -6
- package/dist/C_TagsView.css +60 -63
- package/dist/C_TagsView2.cjs +1 -1
- package/dist/C_TagsView2.js +1 -1
- package/dist/C_Theme.css +7 -8
- package/dist/C_Time.css +1 -1
- package/dist/C_Timeline.css +8 -8
- package/dist/C_Transfer.css +10 -11
- package/dist/C_Tree.css +16 -17
- package/dist/C_Upload.css +156 -157
- package/dist/C_VideoPlayer.css +267 -267
- package/dist/C_VtableGantt.css +2 -2
- package/dist/C_WaterFall.css +2 -2
- package/dist/C_WorkFlow.css +466 -470
- package/dist/C_WorkFlow2.cjs +1 -1
- package/dist/C_WorkFlow2.js +1 -1
- package/dist/Card.cjs +1 -0
- package/dist/Card.js +1 -0
- package/dist/Custom.cjs +1 -0
- package/dist/Custom.js +1 -0
- package/dist/Dynamic.cjs +1 -0
- package/dist/Dynamic.js +1 -0
- package/dist/Steps.cjs +1 -0
- package/dist/Steps.js +1 -0
- package/dist/Tabs.cjs +1 -0
- package/dist/Tabs.js +1 -0
- package/dist/cascader.cjs +1 -0
- package/dist/cascader.js +1 -0
- package/dist/color-picker.cjs +1 -0
- package/dist/color-picker.js +1 -0
- package/dist/constants.d.cts +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants3.d.cts +2 -2
- package/dist/constants3.d.ts +2 -2
- package/dist/constants4.d.cts +4 -4
- package/dist/constants4.d.ts +4 -4
- package/dist/constants5.d.cts +2 -2
- package/dist/constants5.d.ts +2 -2
- package/dist/context.cjs +1 -0
- package/dist/context.js +1 -0
- package/dist/contracts.d.cts +24 -0
- package/dist/contracts.d.ts +24 -0
- package/dist/createPageLoading.cjs +1 -1
- package/dist/createPageLoading.js +1 -1
- package/dist/data.cjs +1 -1
- package/dist/data.d.cts +4 -4
- package/dist/data.d.ts +4 -4
- package/dist/data.js +1 -1
- package/dist/date-picker.cjs +1 -0
- package/dist/date-picker.js +1 -0
- package/dist/feedback.cjs +1 -0
- package/dist/feedback.js +1 -0
- package/dist/helpers.cjs +1 -1
- package/dist/helpers.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +1 -1
- package/dist/index.vue.d.cts +4 -4
- package/dist/index.vue.d.ts +4 -4
- package/dist/index10.vue.d.cts +3 -3
- package/dist/index10.vue.d.ts +3 -3
- package/dist/index11.vue.d.cts +3 -3
- package/dist/index11.vue.d.ts +2 -2
- package/dist/index12.vue.d.cts +2 -2
- package/dist/index12.vue.d.ts +1 -1
- package/dist/index13.vue.d.cts +1 -1
- package/dist/index13.vue.d.ts +2 -2
- package/dist/index14.vue.d.cts +2 -2
- package/dist/index14.vue.d.ts +7 -7
- package/dist/index15.vue.d.cts +7 -7
- package/dist/index16.vue.d.ts +1 -1
- package/dist/index17.vue.d.cts +1 -1
- package/dist/index17.vue.d.ts +2 -2
- package/dist/index18.vue.d.cts +2 -2
- package/dist/index18.vue.d.ts +2 -2
- package/dist/index19.vue.d.cts +2 -2
- package/dist/index19.vue.d.ts +1 -8
- package/dist/index2.vue.d.cts +1 -1
- package/dist/index2.vue.d.ts +1 -1
- package/dist/index20.vue.d.cts +1 -1
- package/dist/index20.vue.d.ts +1 -1
- package/dist/index21.vue.d.cts +2 -2
- package/dist/index21.vue.d.ts +2 -2
- package/dist/index22.vue.d.cts +3 -3
- package/dist/index22.vue.d.ts +3 -3
- package/dist/index23.vue.d.cts +1 -1
- package/dist/index23.vue.d.ts +1 -1
- package/dist/index25.vue.d.cts +4 -4
- package/dist/index25.vue.d.ts +4 -4
- package/dist/index26.vue.d.cts +1 -1
- package/dist/index26.vue.d.ts +1 -1
- package/dist/index27.vue.d.cts +3 -3
- package/dist/index27.vue.d.ts +3 -3
- package/dist/index3.vue.d.cts +4 -4
- package/dist/index3.vue.d.ts +4 -4
- package/dist/index4.vue.d.cts +1 -8
- package/dist/index6.vue.d.ts +2 -2
- package/dist/index7.vue.d.cts +2 -2
- package/dist/index8.vue.d.ts +3 -3
- package/dist/index9.vue.d.cts +3 -3
- package/dist/index9.vue.d.ts +3 -3
- package/dist/mapUtils.d.cts +2 -2
- package/dist/mapUtils.d.ts +2 -2
- package/dist/presets.d.cts +8 -2
- package/dist/presets.d.ts +8 -2
- package/dist/rate.cjs +1 -0
- package/dist/rate.js +1 -0
- package/dist/slider.cjs +1 -0
- package/dist/slider.js +1 -0
- package/dist/style.css +10671 -10704
- package/dist/time-picker.cjs +1 -0
- package/dist/time-picker.js +1 -0
- package/dist/upload.cjs +1 -0
- package/dist/upload.js +1 -0
- package/dist/useActionTask.cjs +1 -0
- package/dist/useActionTask.js +1 -0
- package/dist/useCalendarEvents.d.cts +1 -1
- package/dist/useCalendarEvents.d.ts +1 -1
- package/dist/useCollapsePanel.d.cts +6 -6
- package/dist/useCollapsePanel.d.ts +6 -6
- package/dist/useComponentLocale.cjs +1 -0
- package/dist/useComponentLocale.js +1 -0
- package/dist/useCropperCore.d.cts +4 -4
- package/dist/useCropperCore.d.ts +4 -4
- package/dist/useDraggableLayout.d.cts +8 -8
- package/dist/useDraggableLayout.d.ts +8 -8
- package/dist/useDynamicFormState.cjs +1 -0
- package/dist/useDynamicFormState.d.cts +62 -38
- package/dist/useDynamicFormState.d.ts +62 -38
- package/dist/useDynamicFormState.js +1 -0
- package/dist/useEdgeInteraction.d.cts +2 -2
- package/dist/useEdgeInteraction.d.ts +2 -2
- package/dist/useFullscreen.d.cts +2 -2
- package/dist/useFullscreen.d.ts +2 -2
- package/dist/useInfiniteScroll.d.cts +1 -1
- package/dist/useInfiniteScroll.d.ts +1 -1
- package/dist/useQRCode.d.cts +3 -3
- package/dist/useQRCode.d.ts +3 -3
- package/dist/useSearchState.d.cts +16 -726
- package/dist/useSearchState.d.ts +16 -835
- package/dist/useSignatureHistory.d.cts +2 -2
- package/dist/useSignatureHistory.d.ts +2 -2
- package/dist/useSplitResize.d.cts +9 -9
- package/dist/useSplitResize.d.ts +9 -9
- package/dist/useTableQuery.cjs +3 -3
- package/dist/useTableQuery.d.cts +66 -33
- package/dist/useTableQuery.d.ts +66 -33
- package/dist/useTableQuery.js +3 -3
- package/dist/useTimeSelection.d.cts +2 -2
- package/dist/useTimeSelection.d.ts +2 -2
- package/dist/useTreeOperations.d.cts +4 -4
- package/dist/useTreeOperations.d.ts +4 -4
- package/dist/useWorkflowValidation.d.cts +3 -3
- package/dist/useWorkflowValidation.d.ts +3 -3
- package/dist/verification.d.cts +2 -2
- package/dist/verification.d.ts +2 -2
- package/docs/architecture.en.md +83 -0
- package/docs/architecture.md +83 -0
- package/docs/assets/README.md +47 -0
- package/docs/assets/naive-ui-components-banner.png +0 -0
- package/docs/assets/naive-ui-components-banner.svg +69 -0
- package/docs/assets/naive-ui-components-logo.png +0 -0
- package/docs/assets/naive-ui-components-logo.svg +22 -0
- package/docs/components.en.md +118 -0
- package/docs/components.md +118 -0
- package/docs/engineering.en.md +132 -0
- package/docs/engineering.md +133 -0
- package/docs/guides/usage.en.md +638 -0
- package/docs/guides/usage.md +699 -0
- package/docs/performance-0.15.0.md +20 -0
- package/docs/security-scan-2026-10-06.md +11 -0
- package/docs/security-scan-2026-10-18.md +16 -0
- package/package.json +29 -11
- package/dist/C_Form2.cjs +0 -1
- package/dist/C_Form2.js +0 -1
- package/dist/config.cjs +0 -1
- package/dist/config.d.cts +0 -33
- package/dist/config.d.ts +0 -33
- package/dist/config.js +0 -1
|
@@ -0,0 +1,638 @@
|
|
|
1
|
+
[← English README](../../README_EN.md) · [中文](./usage.md)
|
|
2
|
+
|
|
3
|
+
# Usage guide
|
|
4
|
+
|
|
5
|
+
Import strategies, component configuration and integration examples.
|
|
6
|
+
|
|
7
|
+
## On this page
|
|
8
|
+
|
|
9
|
+
- [Import strategies](#import-strategies)
|
|
10
|
+
- [Cron and formula workspaces](#cron-and-formula-workspaces)
|
|
11
|
+
- [Configure C_Guide](#configure-c_guide)
|
|
12
|
+
- [Recommended C_Form / C_Table setup](#recommended-c_form--c_table-setup)
|
|
13
|
+
- [Common component contracts](#common-component-contracts)
|
|
14
|
+
- [Recommended C_Map setup](#recommended-c_map-setup)
|
|
15
|
+
- [C_Captcha Server Verification](#c_captcha-server-verification)
|
|
16
|
+
- [Table loading](#table-loading)
|
|
17
|
+
- [C_Login form extension](#c_login-form-extension)
|
|
18
|
+
- [Page navigation loading](#page-navigation-loading)
|
|
19
|
+
- [Application extensions and migration](#application-extensions-and-migration)
|
|
20
|
+
|
|
21
|
+
## Import strategies
|
|
22
|
+
|
|
23
|
+
### Global Registration
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { createApp } from 'vue'
|
|
27
|
+
import App from './App.vue'
|
|
28
|
+
import NaiveUIComponents from '@robot-admin/naive-ui-components'
|
|
29
|
+
import '@robot-admin/naive-ui-components/style.css'
|
|
30
|
+
|
|
31
|
+
const app = createApp(App)
|
|
32
|
+
app.use(NaiveUIComponents)
|
|
33
|
+
app.mount('#app')
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Root imports aggregate all components and need `vue-router` at runtime. Prefer component subpaths when navigation is not needed.
|
|
37
|
+
|
|
38
|
+
### On-demand Import (Tree-Shaking)
|
|
39
|
+
|
|
40
|
+
```vue
|
|
41
|
+
<script setup lang="ts">
|
|
42
|
+
import { C_Icon, C_Table, C_Form } from '@robot-admin/naive-ui-components'
|
|
43
|
+
import '@robot-admin/naive-ui-components/style.css'
|
|
44
|
+
</script>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Subpath Import (Recommended, Smallest Bundle)
|
|
48
|
+
|
|
49
|
+
Each component provides an independent subpath entry that loads only the target component's code and types:
|
|
50
|
+
|
|
51
|
+
```vue
|
|
52
|
+
<script setup lang="ts">
|
|
53
|
+
import { C_Form } from '@robot-admin/naive-ui-components/C_Form'
|
|
54
|
+
import { C_Table } from '@robot-admin/naive-ui-components/C_Table'
|
|
55
|
+
import { C_Icon } from '@robot-admin/naive-ui-components/C_Icon'
|
|
56
|
+
import { createMenuOptions } from '@robot-admin/naive-ui-components/C_Menu'
|
|
57
|
+
import '@robot-admin/naive-ui-components/C_Form/base.css'
|
|
58
|
+
import '@robot-admin/naive-ui-components/C_Table/base.css'
|
|
59
|
+
import '@robot-admin/naive-ui-components/C_Icon/style.css'
|
|
60
|
+
</script>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
> Subpath imports provide full TypeScript support (`.d.ts`) with IDE auto-completion for props / emits / slots. Component-specific utilities such as `createMenuOptions` are exported from the same component subpath, so consumers do not need the root entry for one helper.
|
|
64
|
+
|
|
65
|
+
### Standalone Composables
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { useTableManager } from '@robot-admin/naive-ui-components/C_Table'
|
|
69
|
+
import { useFormState } from '@robot-admin/naive-ui-components/C_Form'
|
|
70
|
+
import { usePlayerCore } from '@robot-admin/naive-ui-components/C_VideoPlayer'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Automatic On-demand Imports (Recommended)
|
|
74
|
+
|
|
75
|
+
The resolver loads component subpaths by default, preventing unused components and heavyweight runtime dependencies from entering the initial bundle:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import Components from 'unplugin-vue-components/vite'
|
|
79
|
+
import { RobotNaiveUiResolver } from '@robot-admin/naive-ui-components/resolver'
|
|
80
|
+
|
|
81
|
+
Components({
|
|
82
|
+
resolvers: [RobotNaiveUiResolver({ importStyle: true })],
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`importStyle: true` (an alias of `'full'`) preserves the existing complete style behavior. When C_Form/C_Table only use base fields and no built-in rich-text editor, set `importStyle: 'base'` to avoid editor CSS; other components safely fall back to their standard style entry. Set `importOnDemand: false` only when a legacy project still requires the package root.
|
|
87
|
+
|
|
88
|
+
Every `C_*/style.css` file is a self-contained component style entry. When a component composes public components such as `C_Icon` or `C_Captcha`, their required styles are included automatically, so consumers do not need duplicate imports or the global `style.css` fallback.
|
|
89
|
+
|
|
90
|
+
`C_Menu` emits a non-mutating `intent` event when a leaf item is hovered or keyboard-focused. Hosts may connect it to route prefetching without changing the existing `select` behavior.
|
|
91
|
+
|
|
92
|
+
The style tiers can also be imported explicitly:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import '@robot-admin/naive-ui-components/C_Form/base.css'
|
|
96
|
+
import '@robot-admin/naive-ui-components/C_Table/base.css'
|
|
97
|
+
// Full mode is also available as C_Form/full.css and C_Table/full.css.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Cron and formula workspaces
|
|
101
|
+
|
|
102
|
+
Use a model and one flat config. Existing individual props remain supported; templates, validation, previews and initial-state reset are owned by the components.
|
|
103
|
+
|
|
104
|
+
```vue
|
|
105
|
+
<script setup lang="ts">
|
|
106
|
+
import { ref } from 'vue'
|
|
107
|
+
import {
|
|
108
|
+
C_Cron,
|
|
109
|
+
type CronConfig,
|
|
110
|
+
} from '@robot-admin/naive-ui-components/C_Cron'
|
|
111
|
+
import {
|
|
112
|
+
C_FormulaEditor,
|
|
113
|
+
type FormulaEditorConfig,
|
|
114
|
+
} from '@robot-admin/naive-ui-components/C_FormulaEditor'
|
|
115
|
+
import '@robot-admin/naive-ui-components/C_Cron/style.css'
|
|
116
|
+
import '@robot-admin/naive-ui-components/C_FormulaEditor/style.css'
|
|
117
|
+
|
|
118
|
+
const expression = ref('0 30 8 * * ?')
|
|
119
|
+
const cronConfig: CronConfig = { previewCount: 5 }
|
|
120
|
+
const formula = ref('IF([完成值] > 0, 100 / [完成值], 0)')
|
|
121
|
+
const formulaConfig: FormulaEditorConfig = {
|
|
122
|
+
variables: [{ name: '完成值', field: 'completed', type: 'number' }],
|
|
123
|
+
sampleData: { completed: 5 },
|
|
124
|
+
editableSampleData: true,
|
|
125
|
+
}
|
|
126
|
+
</script>
|
|
127
|
+
<template>
|
|
128
|
+
<C_Cron
|
|
129
|
+
v-model="expression"
|
|
130
|
+
:config="cronConfig"
|
|
131
|
+
/>
|
|
132
|
+
<C_FormulaEditor
|
|
133
|
+
v-model="formula"
|
|
134
|
+
:config="formulaConfig"
|
|
135
|
+
/>
|
|
136
|
+
</template>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Cron supports six numeric fields, ranges, steps, lists and day/weekday exclusion with `?`; L/W/# extensions are not supported. Preview dates use the browser local timezone and never schedule jobs. Formula trials do not mutate caller `sampleData`; validation and calculation share a bounded parser with lazy conditions. Compact modes use `showPreview`, `showKeyboard` and `showVariablePanel`. Read-only mode protects trial inputs too. Reset restores the initial model and data; remount with a new key when switching independent records.
|
|
140
|
+
|
|
141
|
+
## Configure C_Guide
|
|
142
|
+
|
|
143
|
+
Provide targets and steps; the component owns its theme, optional SVG illustrations, and cleanup without depending on a host router or store:
|
|
144
|
+
|
|
145
|
+
```vue
|
|
146
|
+
<script setup lang="ts">
|
|
147
|
+
import {
|
|
148
|
+
C_Guide,
|
|
149
|
+
type GuideStep,
|
|
150
|
+
} from '@robot-admin/naive-ui-components/C_Guide'
|
|
151
|
+
import '@robot-admin/naive-ui-components/C_Guide/style.css'
|
|
152
|
+
|
|
153
|
+
const steps: GuideStep[] = [
|
|
154
|
+
{
|
|
155
|
+
element: '[data-guide="search"]',
|
|
156
|
+
popover: {
|
|
157
|
+
title: 'Search',
|
|
158
|
+
description: 'Find a feature.',
|
|
159
|
+
illustration: 'search',
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
]
|
|
163
|
+
</script>
|
|
164
|
+
|
|
165
|
+
<template>
|
|
166
|
+
<C_Guide :steps="steps" />
|
|
167
|
+
</template>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Inside `NConfigProvider`, the popover follows its light/dark theme and primary color. Targets accept selectors, elements, or resolver functions; invisible targets are skipped by default and omitting a target creates a centered step. The engine loads when opened. With `persistence` enabled, only completion is remembered; the trigger always allows replay. Every step shows a skip button by default. Skipping emits `skip` and `close` without recording completion; configure it with `showSkipButton` and `skipBtnText`. `GuideExpose` provides `startGuide(force?)`, `stopGuide()`, `isCompleted()`, and `resetCompleted()` for host lifecycle integration.
|
|
171
|
+
|
|
172
|
+
## Recommended C_Form / C_Table setup
|
|
173
|
+
|
|
174
|
+
Declare the business model once and keep nested field paths, values, column keys, callbacks, and exposed methods type-safe:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import {
|
|
178
|
+
defineFormConfig,
|
|
179
|
+
defineFormOptions,
|
|
180
|
+
useCForm,
|
|
181
|
+
} from '@robot-admin/naive-ui-components/C_Form'
|
|
182
|
+
|
|
183
|
+
interface UserForm {
|
|
184
|
+
name: string
|
|
185
|
+
profile: { email: string }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const options = defineFormOptions<UserForm>([
|
|
189
|
+
{ type: 'input', prop: 'name', required: true },
|
|
190
|
+
{ type: 'input', prop: 'profile.email' },
|
|
191
|
+
])
|
|
192
|
+
const config = defineFormConfig<UserForm>({
|
|
193
|
+
onSubmit: ({ model }) => save(model),
|
|
194
|
+
})
|
|
195
|
+
const { model, formRef, bindings } = useCForm({
|
|
196
|
+
initialValues: { name: '', profile: { email: '' } },
|
|
197
|
+
options,
|
|
198
|
+
config,
|
|
199
|
+
})
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`C_Form` includes `@robot-admin/form-validate`; consumers need no local type adapter or separate validation installation. `rules` and `rulesWhen` accept native Naive UI rules, the package's `NaiveRule`, and framework-independent `RuleSpec` objects, including mixed lists. `required: true` uses the same empty-value rules and preserves valid `0` and `false` values.
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
import {
|
|
206
|
+
defineFormOptions,
|
|
207
|
+
PRESET_RULES,
|
|
208
|
+
NAIVE_COMBOS,
|
|
209
|
+
SPEC_RULES,
|
|
210
|
+
} from '@robot-admin/naive-ui-components/C_Form'
|
|
211
|
+
|
|
212
|
+
const fields = defineFormOptions([
|
|
213
|
+
{
|
|
214
|
+
type: 'input',
|
|
215
|
+
prop: 'name',
|
|
216
|
+
label: 'Name',
|
|
217
|
+
required: true,
|
|
218
|
+
rules: [SPEC_RULES.length('Name', 2, 20)],
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
type: 'input',
|
|
222
|
+
prop: 'email',
|
|
223
|
+
label: 'Email',
|
|
224
|
+
rules: NAIVE_COMBOS.email('Email'),
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
type: 'input',
|
|
228
|
+
prop: 'mobile',
|
|
229
|
+
label: 'Mobile',
|
|
230
|
+
rules: [PRESET_RULES.mobile('Mobile')],
|
|
231
|
+
},
|
|
232
|
+
])
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Normal forms provide submit/reset controls; step forms provide a submit button on their last step. Configure `submitText`, `resetText`, and `onSubmit`. Use `action-extra` for business controls such as previews while retaining the built-in buttons and loading state. Full customization remains available through `action` and `step-actions`; call the slot's `submit()` rather than treating `validate()` as submission.
|
|
236
|
+
|
|
237
|
+
Put asynchronous work in `config.onSubmit`; `@submit` is a completion notification and does not await an event listener's promise. The second argument provides `context?.signal` for cancellable requests. Unmount aborts that signal and suppresses late submit events and feedback. `submitSuccessText` and `resetSuccessText` opt in to feedback; no success message is shown by default, and validation alone does not imply persistence.
|
|
238
|
+
|
|
239
|
+
For create/edit flows, `C_FormModal` consumes a structural headless `editor` directly. Fields, validation, and layout remain data-driven by `C_Form`, while pages no longer own duplicate modal, draft, or loading state:
|
|
240
|
+
|
|
241
|
+
```vue
|
|
242
|
+
<script setup lang="ts">
|
|
243
|
+
import { C_FormModal } from '@robot-admin/naive-ui-components/C_FormModal'
|
|
244
|
+
import type { FormModalEditor } from '@robot-admin/naive-ui-components/C_FormModal'
|
|
245
|
+
import {
|
|
246
|
+
defineFormConfig,
|
|
247
|
+
defineFormOptions,
|
|
248
|
+
} from '@robot-admin/naive-ui-components/C_Form'
|
|
249
|
+
|
|
250
|
+
interface UserForm {
|
|
251
|
+
name: string
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
defineProps<{ editor: FormModalEditor<UserForm> }>()
|
|
255
|
+
|
|
256
|
+
const fields = defineFormOptions<UserForm>([
|
|
257
|
+
{ type: 'input', prop: 'name', label: 'Name', required: true },
|
|
258
|
+
])
|
|
259
|
+
const formConfig = defineFormConfig<UserForm>({ labelPlacement: 'top' })
|
|
260
|
+
</script>
|
|
261
|
+
|
|
262
|
+
<template>
|
|
263
|
+
<C_FormModal
|
|
264
|
+
:editor="editor"
|
|
265
|
+
:options="fields"
|
|
266
|
+
:config="formConfig"
|
|
267
|
+
/>
|
|
268
|
+
</template>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The editor contract is structural: the component package does not depend on a request library. Any controller exposing `visible/mode/model/title/loading/setModel/close/submit` can drive it. The default uses a responsive 620px width, `small` form controls, and a right-aligned icon-based `C_ActionBar` for a compact admin workflow. Close button, mask close, and Escape remain enabled by default and can be disabled for high-risk forms.
|
|
272
|
+
|
|
273
|
+
For remote tables, `useTableQuery` owns cancellation, latest-request-wins behavior, pagination, and loading. Destructure its `bindings` and use `<C_Table v-bind="bindings" />`:
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
import {
|
|
277
|
+
defineTableColumns,
|
|
278
|
+
useTableQuery,
|
|
279
|
+
} from '@robot-admin/naive-ui-components/C_Table'
|
|
280
|
+
|
|
281
|
+
interface UserRow {
|
|
282
|
+
id: string
|
|
283
|
+
name: string
|
|
284
|
+
}
|
|
285
|
+
const columns = defineTableColumns<UserRow>([{ key: 'name', title: 'Name' }])
|
|
286
|
+
const { bindings } = useTableQuery<UserRow, { keyword: string }>({
|
|
287
|
+
initialQuery: { keyword: '' },
|
|
288
|
+
columns,
|
|
289
|
+
rowKey: 'id',
|
|
290
|
+
request: ({ page, pageSize, query, signal }) =>
|
|
291
|
+
fetchUsers({ page, pageSize, ...query }, signal),
|
|
292
|
+
})
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
When binding a headless CRUD controller through `:crud`, the table recognizes `{ error }` action results: failed deletes do not emit a successful-deletion event, and feedback already shown by the controller is not duplicated. Custom `actions.delete` callbacks may return a promise or a `{ data, error }` result.
|
|
296
|
+
|
|
297
|
+
Tree data can use `<C_Table :data="rows" :columns="columns" :config="{ tree: { defaultExpandAll: true }, pagination: false }" />` directly. `children` is the default child key and can be changed with `tree.childrenKey`. Default expansion includes parent rows added later without reopening rows the user collapsed.
|
|
298
|
+
|
|
299
|
+
`C_Tabs` is the data-driven page-scenario switcher for the global `C_*` system. It defaults to the compact
|
|
300
|
+
`small` size, lazy pane display, and supports controlled or uncontrolled state. Set `tabsOnly` for filters or
|
|
301
|
+
view switching; pane content is not executed, avoiding hidden render work and side effects. Most pages only maintain an item array; complex
|
|
302
|
+
content can opt into `render`, `pane`, or `pane-{key}` slots:
|
|
303
|
+
|
|
304
|
+
```vue
|
|
305
|
+
<script setup lang="ts">
|
|
306
|
+
import { ref } from 'vue'
|
|
307
|
+
import { C_Tabs, defineTabs } from '@robot-admin/naive-ui-components/C_Tabs'
|
|
308
|
+
|
|
309
|
+
const activeView = ref('basic')
|
|
310
|
+
const views = defineTabs([
|
|
311
|
+
{ key: 'basic', label: 'Basic table', icon: 'mdi:table' },
|
|
312
|
+
{ key: 'tree', label: 'Tree table', icon: 'mdi:file-tree-outline' },
|
|
313
|
+
])
|
|
314
|
+
</script>
|
|
315
|
+
|
|
316
|
+
<template>
|
|
317
|
+
<C_Tabs
|
|
318
|
+
v-model="activeView"
|
|
319
|
+
:items="views"
|
|
320
|
+
type="segment"
|
|
321
|
+
tabs-only
|
|
322
|
+
/>
|
|
323
|
+
</template>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
| API | Description |
|
|
327
|
+
| ----------------------------- | --------------------------------------------------------------------------------------------- |
|
|
328
|
+
| `items` | Requires `key/label`; supports icons, badges, disabled/closable state, and `renderTab/render` |
|
|
329
|
+
| `modelValue` / `defaultValue` | Controlled and uncontrolled state |
|
|
330
|
+
| `type` / `size` / `placement` | `line/card/bar/segment`, common sizes and placements; defaults to `line/small/top` |
|
|
331
|
+
| `tabsOnly` | Renders navigation only for table scenarios and query switches |
|
|
332
|
+
| `beforeChange` | Sync/async guard; `false` or an error keeps the current tab |
|
|
333
|
+
| Slots | `tab`, `pane`, and `pane-{key}`, each with item and active state |
|
|
334
|
+
| Events | `change`, `close`, `add`, and standard `update:modelValue` |
|
|
335
|
+
|
|
336
|
+
Use `C_ActionBar` as the single page/table action model instead of maintaining another toolbar abstraction. It defaults to compact `tiny` buttons with icons and a `6px` gap. Semantic keys such as `add`, `refresh`, `export`, `columns`, and `settings` supply consistent labels, icons, and button types; custom actions receive a neutral icon when none is provided. `show`, `disabled`, and `loading` accept booleans, refs, or getters; async handlers are guarded against duplicate clicks and receive automatic loading feedback. `C_Table` consumes the same actions through `toolbar.actions` / `toolbar.rightActions` while preserving its existing toolbar slots. Override `actionBar.size` or an individual action's `size` when a larger control is required:
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
import { defineActions } from '@robot-admin/naive-ui-components/C_ActionBar'
|
|
340
|
+
import { defineTableConfig } from '@robot-admin/naive-ui-components/C_Table'
|
|
341
|
+
|
|
342
|
+
const actions = defineActions([
|
|
343
|
+
{ key: 'add', onClick: openCreate },
|
|
344
|
+
{ key: 'refresh', disabled: () => loading.value, onClick: refresh },
|
|
345
|
+
{ key: 'settings', group: 'right', onClick: openSettings },
|
|
346
|
+
])
|
|
347
|
+
|
|
348
|
+
const config = defineTableConfig({
|
|
349
|
+
toolbar: {
|
|
350
|
+
actions,
|
|
351
|
+
actionBar: { size: 'small' }, // optional; tiny by default
|
|
352
|
+
},
|
|
353
|
+
})
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
For fixed-height tables, use `flex-height` with `wrapper-class`. The root wrapper allocates height between toolbars, the table and pagination. Give the wrapper or its parent a definite height; the component does not guess the page height. `wrapper-class` accepts Vue string, array and object class bindings, so scoped consumer styles can target the root directly. Existing `class`, `style` and native table attributes continue to reach the internal `NDataTable`.
|
|
357
|
+
|
|
358
|
+
```vue
|
|
359
|
+
<template>
|
|
360
|
+
<C_Table
|
|
361
|
+
wrapper-class="inventory-table"
|
|
362
|
+
flex-height
|
|
363
|
+
:columns="columns"
|
|
364
|
+
:data="rows"
|
|
365
|
+
/>
|
|
366
|
+
</template>
|
|
367
|
+
<style scoped>
|
|
368
|
+
.inventory-table {
|
|
369
|
+
height: 480px;
|
|
370
|
+
}
|
|
371
|
+
</style>
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Add `{ type: 'selection' }` explicitly. Receive keys and rows through `@selection-change="(keys, rows) => ..."`; use the public `clearSelection()` instance method instead of observing internal manager state.
|
|
375
|
+
|
|
376
|
+
`C_Table` remains owned by its current Naive UI table implementation. A MachTable mode should render MachTable with its native columns, events, and instance API as a complete engine boundary rather than translating between the two engines. They only share engine-neutral page actions such as `C_ActionBar`.
|
|
377
|
+
|
|
378
|
+
## Common component contracts
|
|
379
|
+
|
|
380
|
+
### Form values and validation
|
|
381
|
+
|
|
382
|
+
Continue with `useCForm()` from the example above to read and update values without duplicating model synchronization or waiting for rendering:
|
|
383
|
+
|
|
384
|
+
```ts
|
|
385
|
+
const { formRef, bindings, setValues, getValues, reset, submit } =
|
|
386
|
+
useCForm<UserForm>({
|
|
387
|
+
initialValues: { name: '', profile: { email: '' } },
|
|
388
|
+
options,
|
|
389
|
+
config,
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
async function loadUser(user: UserForm) {
|
|
393
|
+
await setValues(user)
|
|
394
|
+
formRef.value?.markAsClean() // Make the loaded record the reset baseline.
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function preview() {
|
|
398
|
+
return getValues() // Independent snapshot, including edits before the parent model's next update.
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
`setValues(values, shouldValidate = false)` delegates to the mounted form instance, or updates the bound model before mounting. `getValues()` returns a copy. `reset()` restores the current clean snapshot; `markAsClean()` updates that baseline. Supply a complete nested object when setting it, or call the instance's `setFieldValue('profile.email', value)` for one path.
|
|
403
|
+
|
|
404
|
+
Vue unwraps state exposed through a component template ref: scripts read `formRef.value?.isSubmitting`, `formRef.value?.isDirty`, and `formRef.value?.formModel` without a second `.value`. The helper's own `model`, `formRef`, and `bindings` remain Vue refs.
|
|
405
|
+
|
|
406
|
+
Default, inline, and grid layouts are synchronous. Card, tabs, steps, dynamic, and custom layouts load on demand. Before an asynchronous layout mounts, `submit()` returns `false` and `validate()` rejects rather than accepting fields that have not rendered. Once ready, tab and step layouts mount fields across their panels, so full submission also validates unvisited panels. Async option requests are isolated per field; late responses from superseded requests cannot replace newer options.
|
|
407
|
+
|
|
408
|
+
### Table pagination, selection, and export
|
|
409
|
+
|
|
410
|
+
Use `config.pagination` for new pages. For remote tables, bind the `useTableQuery().bindings` shown above so pagination, totals, loading, and requests have one owner. The compatibility `:pagination="..."` prop delegates pagination to Naive UI. Explicitly passing that prop, including `false`, takes precedence over `config.pagination`; the component does not render a second pager. With native remote pagination, also pass `remote` and manage requests and native update events yourself.
|
|
411
|
+
|
|
412
|
+
Local data is filtered and sorted before pagination. Remote mode displays the server's page without slicing it again. `crossPageSelection: true` retains selected row objects from visited remote pages; `selectAll()` only adds the currently loaded page and cannot represent unseen server records. Use `getSelectedRows()` or the row objects from `@selection-change` for batch work. Server-wide operations need an explicit query or a server-side task supplied by the application.
|
|
413
|
+
|
|
414
|
+
Choose export scope explicitly:
|
|
415
|
+
|
|
416
|
+
| `config.export` option | Data source |
|
|
417
|
+
| --------------------------- | ------------------------------------------------------------------------------------------ |
|
|
418
|
+
| `scope: 'source'` (default) | All currently supplied source rows; remote mode usually has only the loaded page |
|
|
419
|
+
| `scope: 'page'` | The displayed page, including local filtering, sorting, and pagination |
|
|
420
|
+
| `scope: 'selected'` | Available selected row objects, including selections retained from visited pages |
|
|
421
|
+
| `requestData` | An explicit request made when export is clicked; overrides `scope` for server-wide exports |
|
|
422
|
+
|
|
423
|
+
```ts
|
|
424
|
+
const config = defineTableConfig({
|
|
425
|
+
export: {
|
|
426
|
+
scope: 'page',
|
|
427
|
+
filename: 'users',
|
|
428
|
+
format: 'csv',
|
|
429
|
+
},
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
// Supply full data explicitly; export never walks server pages automatically.
|
|
433
|
+
const fullExport = defineTableConfig({
|
|
434
|
+
export: { requestData: () => fetchAllUsers(), filename: 'all-users' },
|
|
435
|
+
})
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Failed asynchronous expansion retains its error state and provides retry in the default content. Call the public `retryExpand(key)` method to reload, or `invalidateExpand(key?)` to clear one row's cached data and error, or all caches when omitted. Invalidation does not request data. Concurrent loads of one row share a request; replacing its source row invalidates the old cache and prevents late old responses from writing it back.
|
|
439
|
+
|
|
440
|
+
Dynamic add/copy operations must generate keys consistent with the table. Prefer a string `row-key="uuid"`. If the table requires `:row-key="row => row.uuid"`, also set `config.dynamicRows.rowKey: 'uuid'` so add/copy operations know which field to generate. Arbitrary composite keys are not inferred. Missing or duplicate keys reject insertion; the related instance methods do not mutate data when dynamic rows are disabled.
|
|
441
|
+
|
|
442
|
+
### Connect search to a remote table
|
|
443
|
+
|
|
444
|
+
Use `C_FormSearch` with `v-model`; legacy `formParams` remains supported. Put requests in `config.onSearch` and use `@search` for notification. Sending requests from both paths executes both application handlers. The following example gives a single table controller ownership of requests, pagination, and loading:
|
|
445
|
+
|
|
446
|
+
```vue
|
|
447
|
+
<script setup lang="ts">
|
|
448
|
+
import { ref } from 'vue'
|
|
449
|
+
import {
|
|
450
|
+
C_FormSearch,
|
|
451
|
+
type SearchConfig,
|
|
452
|
+
type SearchFormItem,
|
|
453
|
+
type SearchFormParams,
|
|
454
|
+
} from '@robot-admin/naive-ui-components/C_FormSearch'
|
|
455
|
+
import {
|
|
456
|
+
C_Table,
|
|
457
|
+
useTableQuery,
|
|
458
|
+
} from '@robot-admin/naive-ui-components/C_Table'
|
|
459
|
+
import '@robot-admin/naive-ui-components/C_FormSearch/style.css'
|
|
460
|
+
import '@robot-admin/naive-ui-components/C_Table/base.css'
|
|
461
|
+
|
|
462
|
+
const filters = ref<SearchFormParams>({ keyword: '' })
|
|
463
|
+
const searchFields: SearchFormItem[] = [
|
|
464
|
+
{ type: 'input', prop: 'keyword', placeholder: 'Keyword' },
|
|
465
|
+
]
|
|
466
|
+
const { bindings, loading, setQuery } = useTableQuery({
|
|
467
|
+
initialQuery: { keyword: '' },
|
|
468
|
+
columns,
|
|
469
|
+
rowKey: 'id',
|
|
470
|
+
request: loadUsers,
|
|
471
|
+
})
|
|
472
|
+
const applyQuery = async (params: SearchFormParams) => {
|
|
473
|
+
await setQuery({ keyword: String(params.keyword ?? '') })
|
|
474
|
+
}
|
|
475
|
+
const searchConfig: SearchConfig = {
|
|
476
|
+
requireValue: false,
|
|
477
|
+
onSearch: applyQuery,
|
|
478
|
+
}
|
|
479
|
+
</script>
|
|
480
|
+
|
|
481
|
+
<template>
|
|
482
|
+
<C_FormSearch
|
|
483
|
+
v-model="filters"
|
|
484
|
+
:form-item-list="searchFields"
|
|
485
|
+
:config="searchConfig"
|
|
486
|
+
:loading="loading"
|
|
487
|
+
@reset="applyQuery"
|
|
488
|
+
/>
|
|
489
|
+
<C_Table v-bind="bindings" />
|
|
490
|
+
</template>
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
The search button, native form submission (including Enter in an input), and exposed `searchFn()` share validation and duplicate prevention. Only currently mounted search controls participate in Naive form validation. Editing conditions, enabling external loading, or unmounting during async validation cancels dispatch; requests receive the successfully validated snapshot. At least one non-pagination value is required by default; set `requireValue: false` to allow an empty query.
|
|
494
|
+
|
|
495
|
+
The `reset(params)` event follows the synchronous v-model update and carries the complete reset snapshot. Existing no-argument handlers remain compatible. Reset restores field defaults while retaining `pageNum/pageSize`; it does not automatically request or debounce. This example explicitly reloads through `@reset="applyQuery"`, and `setQuery()` resets the table page. Avoid reading a separately maintained stale query in the reset handler.
|
|
496
|
+
|
|
497
|
+
### Action configuration and asynchronous work
|
|
498
|
+
|
|
499
|
+
Stable semantic keys and Promise callbacks provide labels, icons, and mutual exclusion without a loading ref for every button:
|
|
500
|
+
|
|
501
|
+
```ts
|
|
502
|
+
const actions = defineActions([
|
|
503
|
+
{ key: 'save', onClick: () => saveCurrentUser() },
|
|
504
|
+
{ key: 'refresh', disabled: () => loading.value, onClick: reload },
|
|
505
|
+
{
|
|
506
|
+
key: 'more',
|
|
507
|
+
dropdown: [{ key: 'export', label: 'Export', onClick: exportUsers }],
|
|
508
|
+
},
|
|
509
|
+
])
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
Duplicate keys in one ActionBar share a task lock. Replacing action objects or moving them between left/right groups preserves that key's busy state. Unkeyed actions use their group and position, so dynamic lists should supply explicit keys. Dropdown items follow the same disabled/loading guards and async mutual exclusion as regular buttons. `autoLoading: false` only hides the automatic spinner; duplicate execution remains blocked.
|
|
513
|
+
|
|
514
|
+
`action-click` and `dropdown-click` are notifications and do not await listeners' promises; put async commands in the action's `onClick`. Failures emit `action-error(error, action, item?)` and continue to Vue's `errorHandler` or error-capture boundary. `buttonProps.disabled/loading` merge with action state and cannot override internal busy protection. `buttonProps.onClick` remains a native click observer rather than replacing the executor. Table row actions reuse lightweight task locks without mounting a complete action bar per row.
|
|
515
|
+
|
|
516
|
+
## Recommended C_Map setup
|
|
517
|
+
|
|
518
|
+
`C_Map` consistently accepts `[latitude, longitude]` for centers and markers. It converts coordinates to AMap's `[longitude, latitude]` order internally, filters invalid markers, and only removes markers owned by the component.
|
|
519
|
+
|
|
520
|
+
```vue
|
|
521
|
+
<script setup lang="ts">
|
|
522
|
+
import { ref } from 'vue'
|
|
523
|
+
import {
|
|
524
|
+
C_Map,
|
|
525
|
+
type MapExpose,
|
|
526
|
+
type MapMarker,
|
|
527
|
+
} from '@robot-admin/naive-ui-components/C_Map'
|
|
528
|
+
import '@robot-admin/naive-ui-components/C_Map/style.css'
|
|
529
|
+
|
|
530
|
+
const mapRef = ref<MapExpose>()
|
|
531
|
+
const markers: MapMarker[] = [
|
|
532
|
+
{ id: 'beijing', lat: 39.9042, lng: 116.4074, popup: 'Beijing' },
|
|
533
|
+
]
|
|
534
|
+
</script>
|
|
535
|
+
|
|
536
|
+
<template>
|
|
537
|
+
<C_Map
|
|
538
|
+
ref="mapRef"
|
|
539
|
+
:markers="markers"
|
|
540
|
+
fit-markers-on-init
|
|
541
|
+
:tile-config="{ maxZoom: 18 }"
|
|
542
|
+
@error="reportError"
|
|
543
|
+
/>
|
|
544
|
+
<button @click="mapRef?.fitToMarkers({ maxZoom: 14 })">Fit markers</button>
|
|
545
|
+
</template>
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
The exposed instance provides `getMap()`, `refresh()`, and `fitToMarkers()` for tab visibility changes, container resizes, and custom business layers. OpenStreetMap mode normalizes both the Leaflet ESM namespace and CommonJS `default` shape internally, so hosts do not need whole-package prebundling for correctness. `map-type="amap"` requires `amap-key`; keys created after 2021-12-02 also require `:amap-security-config="{ serviceHost: '/_AMapService' }"` (recommended in production so the server proxy retains the security secret), or `{ securityJsCode: '...' }` for development only, as described by the [official AMap security guidance](https://lbs.amap.com/api/javascript-api-v2/guide/abc/jscode). The config is installed before the SDK script and conflicting keys on one page are rejected. The host CSP must also allow `https://webapi.amap.com` in `script-src`, with domain allowlists and quotas enforced in the AMap console.
|
|
549
|
+
|
|
550
|
+
`C_Date`, `C_Time`, `C_Menu`, and `C_FormSearch` support standard `v-model`. Message/dialog providers are optional; application-wide feedback, locale, form defaults, and `table.defaults` can be supplied through plugin options.
|
|
551
|
+
|
|
552
|
+
## C_Captcha Server Verification
|
|
553
|
+
|
|
554
|
+
The captcha trigger uses package-owned SVG status icons and does not depend on platform emoji or an online icon service. Idle, verifying, success, and error states keep consistent sizing and semantic colors. `C_Login` places the verification action before submit, keeps the action label explicit, and forwards `captcha-visible-change` so hosts can pause expensive background animation during puzzle interaction. Brand styling can be adjusted from the host with `--cc-height`, `--cc-radius`, `--cc-color`, `--cc-icon-color`, `--cc-bg`, `--cc-bg-hover`, `--cc-border`, `--cc-border-hover`, and `--cc-focus`, without reaching into internal DOM.
|
|
555
|
+
|
|
556
|
+
The default local mode only proves that the browser-side puzzle interaction completed. It is not a security credential for login, payment, or other sensitive actions. In production, provide a `verifier` and enable `require-server-verification`. Timeout, cancellation, and stale attempts are handled by the component, and `success` is emitted only after approval by an independent server/provider challenge. Request `token` and `timestamp` values are client-generated telemetry and must never be trusted as proof by the server.
|
|
557
|
+
|
|
558
|
+
For a permanently free, network-independent option, explicitly select the open-source MIT ALTCHA self-hosted provider. It is lazy-loaded only when selected, so the default puzzle path keeps its startup cost. ALTCHA mode always fails closed through server verification: the application server must issue fresh single-use challenges, verify the PoW payload, prevent replay, and rate-limit attempts while retaining all secrets server-side.
|
|
559
|
+
|
|
560
|
+
```vue
|
|
561
|
+
<C_Captcha
|
|
562
|
+
provider="altcha"
|
|
563
|
+
challenge-url="/api/auth/captcha/challenge"
|
|
564
|
+
:verifier="
|
|
565
|
+
async ({ token, signal }) => {
|
|
566
|
+
const response = await fetch('/api/auth/captcha/verify', {
|
|
567
|
+
method: 'POST',
|
|
568
|
+
headers: { 'content-type': 'application/json' },
|
|
569
|
+
body: JSON.stringify({ payload: token }),
|
|
570
|
+
signal,
|
|
571
|
+
})
|
|
572
|
+
return response.json() // { valid: boolean, token: 'single-use-server-token' }
|
|
573
|
+
}
|
|
574
|
+
"
|
|
575
|
+
/>
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
```vue
|
|
579
|
+
<C_Captcha
|
|
580
|
+
require-server-verification
|
|
581
|
+
:verification-timeout="8000"
|
|
582
|
+
:verifier="
|
|
583
|
+
async ({ signal }) => {
|
|
584
|
+
// This proof must come from a trusted server/provider challenge.
|
|
585
|
+
const providerProof = await obtainTrustedCaptchaProof({ signal })
|
|
586
|
+
const response = await fetch('/api/captcha/verify', {
|
|
587
|
+
method: 'POST',
|
|
588
|
+
headers: { 'content-type': 'application/json' },
|
|
589
|
+
body: JSON.stringify({ providerProof }),
|
|
590
|
+
signal,
|
|
591
|
+
})
|
|
592
|
+
return response.json() // { valid: boolean, token: 'server-issued-token' }
|
|
593
|
+
}
|
|
594
|
+
"
|
|
595
|
+
@verify-error="reportError"
|
|
596
|
+
/>
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
With `require-server-verification`, a successful response must include a server token. Server tokens should be short-lived, single-use, and bound to the current session or operation. `C_Login` forwards the same policy through `captchaProvider`, `captchaChallengeUrl`, `captchaVerifier`, `requireCaptchaServerVerification`, and `captchaVerificationTimeout`; its `submit` payload identifies the result through `captchaType` and `captchaVerifiedBy`. See [SECURITY.md](../../SECURITY.md) for trust-boundary details.
|
|
600
|
+
|
|
601
|
+
`C_Login` remembers only the username, never the password. SMS events require a valid phone number; the local countdown starts immediately, while delivery results and server-side rate limits remain the host's responsibility. `C_City` loads its city index on first open and scopes letter navigation to its own instance; the default trigger, letters, and city items are keyboard-operable.
|
|
602
|
+
|
|
603
|
+
## Table loading
|
|
604
|
+
|
|
605
|
+
`C_Table` uses a data-orbit SVG indicator in the theme's primary color, with an orbit, data rows, and a subtle beam to indicate waiting. It retains existing data and respects reduced-motion preferences without page configuration. Built-in asynchronous expansion also uses `C_Loading`; custom expansion renderers retain control of their content. Override the `loading` slot for custom content. The standalone `C_Loading` accepts `size` (16–120, default 48), optional `label`, and optional `color`. Disable rotation when using it with native `NSpin`:
|
|
606
|
+
|
|
607
|
+
```vue
|
|
608
|
+
<NSpin :show="loading" :size="48" :rotate="false">
|
|
609
|
+
<template #icon><C_Loading /></template>
|
|
610
|
+
<section>Page content</section>
|
|
611
|
+
</NSpin>
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
## C_Login form extension
|
|
615
|
+
|
|
616
|
+
The `password-fields` slot appears below the password field and exposes `username` and `loading`. The synchronous `username-change` event covers initial defaults, remembered usernames and input changes. Use `submitDisabled` to block clicks and Enter while application fields are incomplete. Credential inputs are disabled while `loading`. Workspace discovery and authorization remain in the host application.
|
|
617
|
+
|
|
618
|
+
## Page navigation loading
|
|
619
|
+
|
|
620
|
+
Connect navigation lifecycles through `start()` / `finish(id)`. The component handles visuals, themes and reduced motion. A 160ms default delay avoids flashes; stale completions cannot hide a newer task.
|
|
621
|
+
|
|
622
|
+
```vue
|
|
623
|
+
<C_PageLoading :show="loading.visible.value" />
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
```ts
|
|
627
|
+
import { createPageLoading } from '@robot-admin/naive-ui-components/C_PageLoading'
|
|
628
|
+
const loading = createPageLoading({ delay: 160 })
|
|
629
|
+
const id = loading.start()
|
|
630
|
+
// After completion, cancellation or failure
|
|
631
|
+
loading.finish(id)
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
## Application extensions and migration
|
|
635
|
+
|
|
636
|
+
`createHighlight()` and `setupHighlight()` own isolated highlighters. Component `useHighlight()` reads the app injection; standalone calls create separate APIs. Default installation does not write `window.hljs`; use `exposeToWindow: true` only for explicit legacy integration.
|
|
637
|
+
|
|
638
|
+
The full plugin owns one form registry per application. Migrate global `registerRenderer()` usage to `createFormRendererRegistry()` and the plugin's `formRenderers` option. With component subpaths, provide `FORM_RENDERER_REGISTRY_KEY` explicitly. See [architecture and isolation](../architecture.en.md) for examples, precedence and ownership rules.
|