@manohub/app-kit 0.1.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.
Files changed (103) hide show
  1. package/CONTRACT.md +592 -0
  2. package/README.md +27 -0
  3. package/dist/atoms/app-button.d.ts +90 -0
  4. package/dist/atoms/app-button.js +74 -0
  5. package/dist/atoms/app-checkbox.d.ts +86 -0
  6. package/dist/atoms/app-checkbox.js +78 -0
  7. package/dist/atoms/app-icon-button.d.ts +79 -0
  8. package/dist/atoms/app-icon-button.js +54 -0
  9. package/dist/atoms/app-input.d.ts +118 -0
  10. package/dist/atoms/app-input.js +83 -0
  11. package/dist/atoms/app-layout.d.ts +348 -0
  12. package/dist/atoms/app-layout.js +102 -0
  13. package/dist/atoms/app-notice.d.ts +90 -0
  14. package/dist/atoms/app-notice.js +59 -0
  15. package/dist/atoms/app-query-state.d.ts +191 -0
  16. package/dist/atoms/app-query-state.js +161 -0
  17. package/dist/atoms/app-radio-card.d.ts +80 -0
  18. package/dist/atoms/app-radio-card.js +72 -0
  19. package/dist/atoms/app-search-box.d.ts +80 -0
  20. package/dist/atoms/app-search-box.js +64 -0
  21. package/dist/atoms/app-select.d.ts +106 -0
  22. package/dist/atoms/app-select.js +74 -0
  23. package/dist/atoms/app-switch.d.ts +72 -0
  24. package/dist/atoms/app-switch.js +66 -0
  25. package/dist/atoms/app-textarea.d.ts +89 -0
  26. package/dist/atoms/app-textarea.js +61 -0
  27. package/dist/atoms/app-tooltip.d.ts +70 -0
  28. package/dist/atoms/app-tooltip.js +48 -0
  29. package/dist/atoms/atoms.css +679 -0
  30. package/dist/atoms/state-illustration.d.ts +21 -0
  31. package/dist/atoms/state-illustration.js +101 -0
  32. package/dist/components/app-badge.d.ts +72 -0
  33. package/dist/components/app-badge.js +40 -0
  34. package/dist/components/app-dialog.d.ts +164 -0
  35. package/dist/components/app-dialog.js +121 -0
  36. package/dist/components/app-filter.d.ts +173 -0
  37. package/dist/components/app-filter.js +200 -0
  38. package/dist/components/app-form.d.ts +446 -0
  39. package/dist/components/app-form.js +159 -0
  40. package/dist/components/app-pagination.d.ts +78 -0
  41. package/dist/components/app-pagination.js +57 -0
  42. package/dist/components/app-panel.d.ts +399 -0
  43. package/dist/components/app-panel.js +213 -0
  44. package/dist/components/app-section.d.ts +68 -0
  45. package/dist/components/app-section.js +28 -0
  46. package/dist/components/app-steps.d.ts +115 -0
  47. package/dist/components/app-steps.js +108 -0
  48. package/dist/components/app-table.d.ts +415 -0
  49. package/dist/components/app-table.js +479 -0
  50. package/dist/components/app-tabs.d.ts +58 -0
  51. package/dist/components/app-tabs.js +54 -0
  52. package/dist/components/app-tree.d.ts +273 -0
  53. package/dist/components/app-tree.js +222 -0
  54. package/dist/components/components.css +597 -0
  55. package/dist/composables/use-client-pagination.d.ts +39 -0
  56. package/dist/composables/use-client-pagination.js +29 -0
  57. package/dist/entry/create-query-client.d.ts +8 -0
  58. package/dist/entry/create-query-client.js +14 -0
  59. package/dist/entry/create-sub-app.d.ts +45 -0
  60. package/dist/entry/create-sub-app.js +110 -0
  61. package/dist/entry/index.d.ts +4 -0
  62. package/dist/entry/index.js +12 -0
  63. package/dist/entry/initial-guard.d.ts +12 -0
  64. package/dist/entry/initial-guard.js +23 -0
  65. package/dist/index.d.ts +37 -0
  66. package/dist/index.js +67 -0
  67. package/dist/providers/setup-i18n.d.ts +19 -0
  68. package/dist/providers/setup-i18n.js +24 -0
  69. package/dist/services/app-container.d.ts +15 -0
  70. package/dist/services/app-container.js +7 -0
  71. package/dist/services/app-context.d.ts +4 -0
  72. package/dist/services/app-context.js +17 -0
  73. package/dist/services/index.d.ts +5 -0
  74. package/dist/services/loading.d.ts +16 -0
  75. package/dist/services/loading.js +27 -0
  76. package/dist/services/message-box.d.ts +84 -0
  77. package/dist/services/message-box.js +65 -0
  78. package/dist/services/modal.d.ts +51 -0
  79. package/dist/services/modal.js +51 -0
  80. package/dist/services/notify.d.ts +24 -0
  81. package/dist/services/notify.js +22 -0
  82. package/dist/shell/AppShell.d.ts +139 -0
  83. package/dist/shell/AppShell.js +171 -0
  84. package/dist/shell/shell.css +153 -0
  85. package/dist/styles/farris-bridge.css +129 -0
  86. package/dist/styles/index.css +16 -0
  87. package/dist/styles/markdown.css +85 -0
  88. package/dist/styles/reset.css +74 -0
  89. package/dist/styles/tokens.css +111 -0
  90. package/lint/__tests__/fixtures/clean-src/styles.css +14 -0
  91. package/lint/__tests__/fixtures/clean-src/views/good-page.tsx +15 -0
  92. package/lint/__tests__/fixtures/violations-src/styles.css +18 -0
  93. package/lint/__tests__/fixtures/violations-src/views/bad-page.tsx +38 -0
  94. package/lint/__tests__/fixtures/violations-src/views/no-shell-page.tsx +4 -0
  95. package/lint/__tests__/guardrails.spec.mjs +144 -0
  96. package/lint/component-audit.mjs +131 -0
  97. package/lint/guardrails.config.schema.json +74 -0
  98. package/lint/pre-commit.sample +26 -0
  99. package/lint/run-all.mjs +59 -0
  100. package/lint/shared.mjs +347 -0
  101. package/lint/structure-audit.mjs +254 -0
  102. package/lint/style-audit.mjs +200 -0
  103. package/package.json +78 -0
@@ -0,0 +1,399 @@
1
+ import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
+ /**
3
+ * 区域容器(页面内分区)—— 与 `AppShell` 的分工:
4
+ *
5
+ * - `AppShell`:**页面级**(唯一)。管页头规格、Footer 固定、页面级滚动归属(`Body.mode`)。
6
+ * - `AppPanel`:**区域级**(可多个)。只管区域内的三件(Header / Body / Footer)与区域内滚动
7
+ * (Header 与 Footer 固定、只有 Body 滚),**不参与页面高度分配**,也不决定页面级滚动归属。
8
+ *
9
+ * ## 三件结构(与 AppShell 同款复合写法)
10
+ *
11
+ * ```
12
+ * <AppPanel>
13
+ * <AppPanel.Header title="值映射列表" toolbar={…} actions={…} />
14
+ * <AppPanel.Body>…内容(表格 / 树 / 表单)…</AppPanel.Body>
15
+ * <AppPanel.Footer><AppPagination … /></AppPanel.Footer>
16
+ * </AppPanel>
17
+ * ```
18
+ *
19
+ * 简写仍可用(等价于「内建 Header + 包一层的 Body」):`<AppPanel title=… toolbar=… actions=…>内容</AppPanel>`;
20
+ * 两种写法可混用 —— 显式的 `AppPanel.Header/ Body/ Footer` 会被提到对应位置,其余子节点自动进 Body。
21
+ *
22
+ * ## 分页归属(**跟承载表格的容器走**)
23
+ *
24
+ * 分页条不按「页面」决定位置,而按**表格所在容器**:
25
+ * - 表格在 `AppPanel` 里(区域级列表)→ 放 `AppPanel.Footer`(面板内表 + 分页是一个整体,面板体滚动、分页常驻);
26
+ * - 表格直接挂在 `AppShell.Body` 下(页面级列表)→ 放 `AppShell.Footer`。
27
+ * 把区域列表的分页提到 `AppShell.Footer`(或把页面级分页塞进面板)都属于错位。
28
+ *
29
+ * ## 无框契约
30
+ *
31
+ * `AppPanel` 自身**不加描边、不加圆角、不加阴影、不设独立底色、不加单侧边框** ——
32
+ * 分区感只由 Header 下方的 1px 分隔线提供(与 `.ak-shell-header` 同一手法);
33
+ * 两栏之间的竖直分隔线由 `AppShell.Split` 提供。
34
+ * 需要卡片外观时由**内容件**承载(表格用 `AppTable.framed`),业务侧不得给面板补描边/圆角/阴影。
35
+ *
36
+ * ## 内距(`padding`)
37
+ *
38
+ * 面板与它的三件吃**同一套** `padding`(px 数字 / `{ y, x }`),缺省都不吃(贴各自的边):
39
+ *
40
+ * - 根件 = 整块面板的内距:页面里的区域通常不吃(内外距由 `AppShell` 的各部件给);
41
+ * 弹窗内的区域没有别的东西可给内距,用它自带(`padding={{ y: 12, x: 20 }}`)——
42
+ * 这样就不必再给面板挂一个「只写 padding」的应用侧类(那类规则曾经每个弹窗各写一份)。
43
+ * - `AppPanel.Body` = 内容区的内距,**弹窗里最常用的一条**:如向导内容区
44
+ * `padding={{ y: 24, x: 100 }}` —— `y` 是上下留白,`x` 开大即充当**限宽**
45
+ * (宽弹窗里不让表单行一路拉到右边缘);这条以前是应用侧的「只写 padding」类。
46
+ * - `AppPanel.Footer` = 常驻控件(分页条等)与内容的距离,如 `padding={{ y: 10 }}`。
47
+ * - `AppPanel.Header` = 内建头那一行的内距;走 `header` 插槽时(整行替换)会把自定义头**包一层**
48
+ * 只带内距的 div(自定义头内部的几何仍归消费方)。
49
+ *
50
+ * ## 两位分工(不可互换)
51
+ *
52
+ * - `toolbar`:**本区域的筛选/搜索位**(≤3 个字段,过滤本区域数据)
53
+ * - `actions`:**本区域的操作位**(该区域的新建 / 刷新等)
54
+ *
55
+ * 筛选归属判据:**先问「过滤谁的数据」决定放哪个区域的 toolbar,再问「几个字段」** ——
56
+ * 字段数 > 3 时上提为页面级 `AppShell.Filter`。把筛选塞进 `actions`、或把操作塞进 `toolbar` 均属违规。
57
+ *
58
+ * 完全自定义的面板头请走 `AppPanel.Header`(不传 `title`)或 `header` 插槽(需在接入方登记为白名单)。
59
+ * **只给 `toolbar` / `actions`、不给 `title` 也是合法形态**:那一行照渲染(标题在容器外层时用,如弹窗内的区域
60
+ * —— 弹窗标题栏已写了区域名,面板头只剩一行「搜索 + 操作」);三样都不给才不渲染头。
61
+ *
62
+ * @example 区域级列表(表格 + 分页都在本区域内)
63
+ * <AppPanel>
64
+ * <AppPanel.Header title="值映射列表" toolbar={<AppSearchBox … />} actions={<AppButton>新建</AppButton>} />
65
+ * <AppPanel.Body><AppTable framed rows={rows} columns={columns} rowKey="id" /></AppPanel.Body>
66
+ * <AppPanel.Footer><AppPagination page={page} pageSize={size} total={total} onPageChange={…} /></AppPanel.Footer>
67
+ * </AppPanel>
68
+ */
69
+ export interface AppPanelProps {
70
+ /** 面板标题;缺省时若提供了 `header` 插槽则走完全自定义面板头 */
71
+ title?: string;
72
+ /** 本区域的筛选/搜索位(≤3 字段),与 `actions` 分工不可互换 */
73
+ toolbar?: unknown;
74
+ /** 本区域的操作位(新建 / 刷新等) */
75
+ actions?: unknown;
76
+ /**
77
+ * 面板内距(**px 数字**,与 `AppForm.labelWidth` / `AppTable.rowHeight` 同口径:几何值是设计基准,不跟根字号):
78
+ * - `number` → 四边同值(`padding={16}`);
79
+ * - `{ y, x }` → 上下 / 左右分别给(`{ y: 12, x: 20 }`,弹窗内的区域常用 —— 与 Shell 的页面左右内距同档)。
80
+ *
81
+ * **缺省 0**:面板贴容器边,内距由所在容器给(页面里是 `AppShell` 的各部件,弹窗里没有别的东西可给)。
82
+ * 无框契约不变:这里只是内距,描边 / 圆角 / 底色仍一概不加。
83
+ *
84
+ * 三件(`Header` / `Body` / `Footer`)有**同名同口径**的 `padding`,管各自那块的内距。
85
+ */
86
+ padding?: AppPanelPadding;
87
+ }
88
+ /** 面板(及其三件)的内距:`number` = 四边同值;`{ y, x }` = 上下 / 左右分别给(缺哪边不落哪边) */
89
+ export type AppPanelPadding = number | {
90
+ y?: number;
91
+ x?: number;
92
+ };
93
+ /** 面板标题行(区域级):标题 + 本区域筛选位(toolbar) + 本区域操作位(actions) */
94
+ export declare const AppPanelHeader: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
95
+ /**
96
+ * 面板标题;缺省时**不渲染标题节点**,但仍会渲染 `toolbar` / `actions` 那一行
97
+ * (无标题的区域头,见组件头注释);要给完全自定义的头走 `header` 插槽。
98
+ */
99
+ title: {
100
+ type: StringConstructor;
101
+ default: undefined;
102
+ };
103
+ /** 本区域的筛选/搜索位(≤3 字段);节点或返回节点的函数 */
104
+ toolbar: {
105
+ type: PropType<any>;
106
+ default: undefined;
107
+ };
108
+ /** 本区域的操作位(新建 / 刷新等);节点或返回节点的函数 */
109
+ actions: {
110
+ type: PropType<any>;
111
+ default: undefined;
112
+ };
113
+ /** 头这一行的内距(与根件同一口径);内建头自带 `0 8px` 的内距,本项按需覆盖 */
114
+ padding: {
115
+ type: PropType<AppPanelPadding>;
116
+ default: undefined;
117
+ };
118
+ }>, () => VNodeChild, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
119
+ /**
120
+ * 面板标题;缺省时**不渲染标题节点**,但仍会渲染 `toolbar` / `actions` 那一行
121
+ * (无标题的区域头,见组件头注释);要给完全自定义的头走 `header` 插槽。
122
+ */
123
+ title: {
124
+ type: StringConstructor;
125
+ default: undefined;
126
+ };
127
+ /** 本区域的筛选/搜索位(≤3 字段);节点或返回节点的函数 */
128
+ toolbar: {
129
+ type: PropType<any>;
130
+ default: undefined;
131
+ };
132
+ /** 本区域的操作位(新建 / 刷新等);节点或返回节点的函数 */
133
+ actions: {
134
+ type: PropType<any>;
135
+ default: undefined;
136
+ };
137
+ /** 头这一行的内距(与根件同一口径);内建头自带 `0 8px` 的内距,本项按需覆盖 */
138
+ padding: {
139
+ type: PropType<AppPanelPadding>;
140
+ default: undefined;
141
+ };
142
+ }>> & Readonly<{}>, {
143
+ title: string;
144
+ toolbar: any;
145
+ actions: any;
146
+ padding: AppPanelPadding;
147
+ }, SlotsType<{
148
+ header?: () => VNodeChild;
149
+ toolbar?: () => VNodeChild;
150
+ actions?: () => VNodeChild;
151
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
152
+ /**
153
+ * 面板内容区:**区域内的滚动唯一归属**(Header / Footer 固定,只有它滚)。
154
+ *
155
+ * 表格场景天然不双滚:`.ak-table { height: 100% }` 让表格恰好填满 Body、由底层网格内部滚。
156
+ * 反例:别在 Body 里给 `AppTable` 外套一层 `height:auto` 的 div,否则 Body 整块滚、表头跟着走。
157
+ *
158
+ * `padding` 是**内容的内距**(不改变滚动归属):弹窗里的内容区最常用它
159
+ * (`padding={{ y: 24, x: 100 }}` —— `x` 开大即充当限宽),从此不必再给 Body 挂一个「只写 padding」的应用侧类。
160
+ */
161
+ export declare const AppPanelBody: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
162
+ /** 内容区内距(与根件同一口径);缺省 0 = 内容贴面板边(页面里的区域通常如此) */
163
+ padding: {
164
+ type: PropType<AppPanelPadding>;
165
+ default: undefined;
166
+ };
167
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
168
+ /** 内容区内距(与根件同一口径);缺省 0 = 内容贴面板边(页面里的区域通常如此) */
169
+ padding: {
170
+ type: PropType<AppPanelPadding>;
171
+ default: undefined;
172
+ };
173
+ }>> & Readonly<{}>, {
174
+ padding: AppPanelPadding;
175
+ }, SlotsType<{
176
+ default?: () => VNodeChild;
177
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
178
+ /**
179
+ * 面板页脚:区域内**常驻**控件(本区域表格的分页条等),不随内容滚动。
180
+ *
181
+ * `padding` 用来把常驻控件与上面的内容拉开(如 `padding={{ y: 10 }}`)——
182
+ * 页脚自己没有内距,以前这条距离各弹窗各写一个 `padding-top` 的应用侧类。
183
+ */
184
+ export declare const AppPanelFooter: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
185
+ /** 页脚内距(与根件同一口径);缺省 0 = 贴面板边 */
186
+ padding: {
187
+ type: PropType<AppPanelPadding>;
188
+ default: undefined;
189
+ };
190
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
191
+ /** 页脚内距(与根件同一口径);缺省 0 = 贴面板边 */
192
+ padding: {
193
+ type: PropType<AppPanelPadding>;
194
+ default: undefined;
195
+ };
196
+ }>> & Readonly<{}>, {
197
+ padding: AppPanelPadding;
198
+ }, SlotsType<{
199
+ default?: () => VNodeChild;
200
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
201
+ /**
202
+ * 复合件入口:`AppPanel` + `AppPanel.Header` / `AppPanel.Body` / `AppPanel.Footer`
203
+ * (与 `AppShell` 同款 Object.assign 复合写法)
204
+ */
205
+ export declare const AppPanel: {
206
+ new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<Readonly<import("vue").ExtractPropTypes<{
207
+ /** 简写标题:等价于内建 `AppPanel.Header` */
208
+ title: {
209
+ type: StringConstructor;
210
+ default: undefined;
211
+ };
212
+ /** 简写筛选位:等价于内建 `AppPanel.Header` 的 toolbar */
213
+ toolbar: {
214
+ type: PropType<any>;
215
+ default: undefined;
216
+ };
217
+ /** 简写操作位:等价于内建 `AppPanel.Header` 的 actions */
218
+ actions: {
219
+ type: PropType<any>;
220
+ default: undefined;
221
+ };
222
+ /** 面板内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边 */
223
+ padding: {
224
+ type: PropType<AppPanelPadding>;
225
+ default: undefined;
226
+ };
227
+ }>> & Readonly<{}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, import("vue").PublicProps, {
228
+ title: string;
229
+ toolbar: any;
230
+ actions: any;
231
+ padding: AppPanelPadding;
232
+ }, true, {}, SlotsType<{
233
+ default?: () => VNodeChild;
234
+ header?: () => VNodeChild;
235
+ toolbar?: () => VNodeChild;
236
+ actions?: () => VNodeChild;
237
+ }>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
238
+ P: {};
239
+ B: {};
240
+ D: {};
241
+ C: {};
242
+ M: {};
243
+ Defaults: {};
244
+ }, Readonly<import("vue").ExtractPropTypes<{
245
+ /** 简写标题:等价于内建 `AppPanel.Header` */
246
+ title: {
247
+ type: StringConstructor;
248
+ default: undefined;
249
+ };
250
+ /** 简写筛选位:等价于内建 `AppPanel.Header` 的 toolbar */
251
+ toolbar: {
252
+ type: PropType<any>;
253
+ default: undefined;
254
+ };
255
+ /** 简写操作位:等价于内建 `AppPanel.Header` 的 actions */
256
+ actions: {
257
+ type: PropType<any>;
258
+ default: undefined;
259
+ };
260
+ /** 面板内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边 */
261
+ padding: {
262
+ type: PropType<AppPanelPadding>;
263
+ default: undefined;
264
+ };
265
+ }>> & Readonly<{}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, {
266
+ title: string;
267
+ toolbar: any;
268
+ actions: any;
269
+ padding: AppPanelPadding;
270
+ }>;
271
+ __isFragment?: never;
272
+ __isTeleport?: never;
273
+ __isSuspense?: never;
274
+ } & import("vue").ComponentOptionsBase<Readonly<import("vue").ExtractPropTypes<{
275
+ /** 简写标题:等价于内建 `AppPanel.Header` */
276
+ title: {
277
+ type: StringConstructor;
278
+ default: undefined;
279
+ };
280
+ /** 简写筛选位:等价于内建 `AppPanel.Header` 的 toolbar */
281
+ toolbar: {
282
+ type: PropType<any>;
283
+ default: undefined;
284
+ };
285
+ /** 简写操作位:等价于内建 `AppPanel.Header` 的 actions */
286
+ actions: {
287
+ type: PropType<any>;
288
+ default: undefined;
289
+ };
290
+ /** 面板内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边 */
291
+ padding: {
292
+ type: PropType<AppPanelPadding>;
293
+ default: undefined;
294
+ };
295
+ }>> & Readonly<{}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, {
296
+ title: string;
297
+ toolbar: any;
298
+ actions: any;
299
+ padding: AppPanelPadding;
300
+ }, {}, string, SlotsType<{
301
+ default?: () => VNodeChild;
302
+ header?: () => VNodeChild;
303
+ toolbar?: () => VNodeChild;
304
+ actions?: () => VNodeChild;
305
+ }>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & {
306
+ Header: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
307
+ /**
308
+ * 面板标题;缺省时**不渲染标题节点**,但仍会渲染 `toolbar` / `actions` 那一行
309
+ * (无标题的区域头,见组件头注释);要给完全自定义的头走 `header` 插槽。
310
+ */
311
+ title: {
312
+ type: StringConstructor;
313
+ default: undefined;
314
+ };
315
+ /** 本区域的筛选/搜索位(≤3 字段);节点或返回节点的函数 */
316
+ toolbar: {
317
+ type: PropType<any>;
318
+ default: undefined;
319
+ };
320
+ /** 本区域的操作位(新建 / 刷新等);节点或返回节点的函数 */
321
+ actions: {
322
+ type: PropType<any>;
323
+ default: undefined;
324
+ };
325
+ /** 头这一行的内距(与根件同一口径);内建头自带 `0 8px` 的内距,本项按需覆盖 */
326
+ padding: {
327
+ type: PropType<AppPanelPadding>;
328
+ default: undefined;
329
+ };
330
+ }>, () => VNodeChild, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
331
+ /**
332
+ * 面板标题;缺省时**不渲染标题节点**,但仍会渲染 `toolbar` / `actions` 那一行
333
+ * (无标题的区域头,见组件头注释);要给完全自定义的头走 `header` 插槽。
334
+ */
335
+ title: {
336
+ type: StringConstructor;
337
+ default: undefined;
338
+ };
339
+ /** 本区域的筛选/搜索位(≤3 字段);节点或返回节点的函数 */
340
+ toolbar: {
341
+ type: PropType<any>;
342
+ default: undefined;
343
+ };
344
+ /** 本区域的操作位(新建 / 刷新等);节点或返回节点的函数 */
345
+ actions: {
346
+ type: PropType<any>;
347
+ default: undefined;
348
+ };
349
+ /** 头这一行的内距(与根件同一口径);内建头自带 `0 8px` 的内距,本项按需覆盖 */
350
+ padding: {
351
+ type: PropType<AppPanelPadding>;
352
+ default: undefined;
353
+ };
354
+ }>> & Readonly<{}>, {
355
+ title: string;
356
+ toolbar: any;
357
+ actions: any;
358
+ padding: AppPanelPadding;
359
+ }, SlotsType<{
360
+ header?: () => VNodeChild;
361
+ toolbar?: () => VNodeChild;
362
+ actions?: () => VNodeChild;
363
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
364
+ Body: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
365
+ /** 内容区内距(与根件同一口径);缺省 0 = 内容贴面板边(页面里的区域通常如此) */
366
+ padding: {
367
+ type: PropType<AppPanelPadding>;
368
+ default: undefined;
369
+ };
370
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
371
+ /** 内容区内距(与根件同一口径);缺省 0 = 内容贴面板边(页面里的区域通常如此) */
372
+ padding: {
373
+ type: PropType<AppPanelPadding>;
374
+ default: undefined;
375
+ };
376
+ }>> & Readonly<{}>, {
377
+ padding: AppPanelPadding;
378
+ }, SlotsType<{
379
+ default?: () => VNodeChild;
380
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
381
+ Footer: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
382
+ /** 页脚内距(与根件同一口径);缺省 0 = 贴面板边 */
383
+ padding: {
384
+ type: PropType<AppPanelPadding>;
385
+ default: undefined;
386
+ };
387
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
388
+ /** 页脚内距(与根件同一口径);缺省 0 = 贴面板边 */
389
+ padding: {
390
+ type: PropType<AppPanelPadding>;
391
+ default: undefined;
392
+ };
393
+ }>> & Readonly<{}>, {
394
+ padding: AppPanelPadding;
395
+ }, SlotsType<{
396
+ default?: () => VNodeChild;
397
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
398
+ };
399
+ export type AppPanelCompound = typeof AppPanel;
@@ -0,0 +1,213 @@
1
+ import { defineComponent, createVNode, h } from "vue";
2
+ function panelPaddingStyle(padding) {
3
+ if (padding === void 0) return void 0;
4
+ if (typeof padding === "number") return {
5
+ padding: `${padding}px`
6
+ };
7
+ const style = {};
8
+ if (padding.y !== void 0) {
9
+ style.paddingTop = `${padding.y}px`;
10
+ style.paddingBottom = `${padding.y}px`;
11
+ }
12
+ if (padding.x !== void 0) {
13
+ style.paddingLeft = `${padding.x}px`;
14
+ style.paddingRight = `${padding.x}px`;
15
+ }
16
+ return style;
17
+ }
18
+ function mergePartStyle(attrsStyle, padding) {
19
+ const paddingStyle = panelPaddingStyle(padding);
20
+ if (paddingStyle === void 0) return attrsStyle;
21
+ return [attrsStyle, paddingStyle];
22
+ }
23
+ const AppPanelHeader = /* @__PURE__ */ defineComponent({
24
+ name: "AppPanelHeader",
25
+ inheritAttrs: false,
26
+ props: {
27
+ /**
28
+ * 面板标题;缺省时**不渲染标题节点**,但仍会渲染 `toolbar` / `actions` 那一行
29
+ * (无标题的区域头,见组件头注释);要给完全自定义的头走 `header` 插槽。
30
+ */
31
+ title: {
32
+ type: String,
33
+ default: void 0
34
+ },
35
+ /** 本区域的筛选/搜索位(≤3 字段);节点或返回节点的函数 */
36
+ toolbar: {
37
+ type: [Function, Object, Array, String],
38
+ default: void 0
39
+ },
40
+ /** 本区域的操作位(新建 / 刷新等);节点或返回节点的函数 */
41
+ actions: {
42
+ type: [Function, Object, Array, String],
43
+ default: void 0
44
+ },
45
+ /** 头这一行的内距(与根件同一口径);内建头自带 `0 8px` 的内距,本项按需覆盖 */
46
+ padding: {
47
+ type: [Number, Object],
48
+ default: void 0
49
+ }
50
+ },
51
+ slots: Object,
52
+ setup(props, {
53
+ slots,
54
+ attrs
55
+ }) {
56
+ const renderSlotValue = (slotFn, propValue) => {
57
+ if (slotFn) return slotFn();
58
+ if (typeof propValue === "function") return propValue();
59
+ return propValue;
60
+ };
61
+ return () => {
62
+ const toolbar = renderSlotValue(slots.toolbar, props.toolbar);
63
+ const actions = renderSlotValue(slots.actions, props.actions);
64
+ if (slots.header) {
65
+ const custom = slots.header();
66
+ const paddingStyle = panelPaddingStyle(props.padding);
67
+ return paddingStyle === void 0 ? custom : createVNode("div", {
68
+ "style": paddingStyle
69
+ }, [custom]);
70
+ }
71
+ if (!props.title && !toolbar && !actions) return null;
72
+ return createVNode("div", {
73
+ "class": ["ak-panel__header", attrs.class].filter(Boolean).join(" "),
74
+ "style": mergePartStyle(attrs.style, props.padding)
75
+ }, [props.title ? createVNode("span", {
76
+ "class": "ak-panel__header-title"
77
+ }, [props.title]) : null, createVNode("div", {
78
+ "class": "ak-panel__header-right"
79
+ }, [toolbar ? createVNode("div", {
80
+ "class": "ak-panel__header-toolbar"
81
+ }, [toolbar]) : null, actions ? createVNode("div", {
82
+ "class": "ak-panel__header-actions"
83
+ }, [actions]) : null])]);
84
+ };
85
+ }
86
+ });
87
+ const AppPanelBody = /* @__PURE__ */ defineComponent({
88
+ name: "AppPanelBody",
89
+ inheritAttrs: false,
90
+ props: {
91
+ /** 内容区内距(与根件同一口径);缺省 0 = 内容贴面板边(页面里的区域通常如此) */
92
+ padding: {
93
+ type: [Number, Object],
94
+ default: void 0
95
+ }
96
+ },
97
+ slots: Object,
98
+ setup(props, {
99
+ slots,
100
+ attrs
101
+ }) {
102
+ return () => createVNode("div", {
103
+ "class": ["ak-panel__body", attrs.class].filter(Boolean).join(" "),
104
+ "style": mergePartStyle(attrs.style, props.padding)
105
+ }, [slots.default?.()]);
106
+ }
107
+ });
108
+ const AppPanelFooter = /* @__PURE__ */ defineComponent({
109
+ name: "AppPanelFooter",
110
+ inheritAttrs: false,
111
+ props: {
112
+ /** 页脚内距(与根件同一口径);缺省 0 = 贴面板边 */
113
+ padding: {
114
+ type: [Number, Object],
115
+ default: void 0
116
+ }
117
+ },
118
+ slots: Object,
119
+ setup(props, {
120
+ slots,
121
+ attrs
122
+ }) {
123
+ return () => createVNode("div", {
124
+ "class": ["ak-panel__footer", attrs.class].filter(Boolean).join(" "),
125
+ "style": mergePartStyle(attrs.style, props.padding)
126
+ }, [slots.default?.()]);
127
+ }
128
+ });
129
+ function splitParts(children) {
130
+ const header = [];
131
+ const body = [];
132
+ const footer = [];
133
+ const rest = [];
134
+ for (const child of children) {
135
+ if (child.type === AppPanelHeader) header.push(child);
136
+ else if (child.type === AppPanelBody) body.push(child);
137
+ else if (child.type === AppPanelFooter) footer.push(child);
138
+ else rest.push(child);
139
+ }
140
+ return {
141
+ header,
142
+ body,
143
+ footer,
144
+ rest
145
+ };
146
+ }
147
+ const AppPanelRoot = /* @__PURE__ */ defineComponent({
148
+ name: "AppPanel",
149
+ inheritAttrs: false,
150
+ props: {
151
+ /** 简写标题:等价于内建 `AppPanel.Header` */
152
+ title: {
153
+ type: String,
154
+ default: void 0
155
+ },
156
+ /** 简写筛选位:等价于内建 `AppPanel.Header` 的 toolbar */
157
+ toolbar: {
158
+ type: [Function, Object, Array, String],
159
+ default: void 0
160
+ },
161
+ /** 简写操作位:等价于内建 `AppPanel.Header` 的 actions */
162
+ actions: {
163
+ type: [Function, Object, Array, String],
164
+ default: void 0
165
+ },
166
+ /** 面板内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边 */
167
+ padding: {
168
+ type: [Number, Object],
169
+ default: void 0
170
+ }
171
+ },
172
+ slots: Object,
173
+ setup(props, {
174
+ slots,
175
+ attrs
176
+ }) {
177
+ return () => {
178
+ const raw = slots.default?.();
179
+ const children = (Array.isArray(raw) ? raw : raw == null ? [] : [raw]).filter((child) => !!child && typeof child === "object");
180
+ const {
181
+ header,
182
+ body,
183
+ footer,
184
+ rest
185
+ } = splitParts(children);
186
+ const hasBuiltinHeader = !!props.title || !slots.header && (props.toolbar !== void 0 || props.actions !== void 0);
187
+ const headerNode = header.length > 0 ? header : hasBuiltinHeader ? createVNode(AppPanelHeader, {
188
+ "title": props.title,
189
+ "toolbar": props.toolbar,
190
+ "actions": props.actions
191
+ }, null) : slots.header?.() ?? null;
192
+ const bodyNode = body.length > 0 ? body : rest.length > 0 ? h(AppPanelBody, null, {
193
+ default: () => rest
194
+ }) : null;
195
+ const panelStyle = mergePartStyle(attrs.style, props.padding);
196
+ return createVNode("section", {
197
+ "class": ["ak-panel", attrs.class].filter(Boolean).join(" "),
198
+ "style": panelStyle
199
+ }, [headerNode, bodyNode, footer]);
200
+ };
201
+ }
202
+ });
203
+ const AppPanel = Object.assign(AppPanelRoot, {
204
+ Header: AppPanelHeader,
205
+ Body: AppPanelBody,
206
+ Footer: AppPanelFooter
207
+ });
208
+ export {
209
+ AppPanel,
210
+ AppPanelBody,
211
+ AppPanelFooter,
212
+ AppPanelHeader
213
+ };
@@ -0,0 +1,68 @@
1
+ import { type SlotsType, type VNodeChild } from 'vue';
2
+ export interface AppSectionProps {
3
+ /**
4
+ * 区块标题。不传则该区块**不渲染标题行**,只提供「区块间距」——
5
+ * 用于「这一块是独立的一件事」但不需要文字的场合。
6
+ */
7
+ title?: string;
8
+ }
9
+ /**
10
+ * 区块:**区块标题 + 一组内容**,负责标题排版与区块之间的距离。
11
+ *
12
+ * 它是「区块」这件事的**唯一实现**:页面级(详情/长表单里的小节)与表单内(分组行)
13
+ * 用的是同一个件 —— 表单里写 `AppForm.Section`,它就是本件(同一个对象、同一套样式),
14
+ * 名字只是让调用处读起来贴语境,**不存在第二套实现**。
15
+ *
16
+ * ## 它管什么 / 不管什么
17
+ *
18
+ * - 管:**标题排版**(14px/600,与字段 label 的 14px/400 拉开一个"这是标题"的层级差)、
19
+ * **内容行距**(8px:内容块/表单行之间的统一档)、**区块间距**(16px 叠父级 gap)。
20
+ * - 不管:任何滚动归属(那是 `AppPanel` 的区域职责)、工具位(筛选/操作属于 `AppPanel` 的
21
+ * `toolbar` / `actions`)、卡片外观(外观一律由内容件承载,如 `AppTable framed`)。
22
+ *
23
+ * 为什么**内容行距也必须由本件给**:父容器(如 `AppForm`)的 `gap` 只作用于它的**直接子元素**,
24
+ * 内容一旦被包进本件,里面的行距就没人管了 —— 自绘 `<div class="xx-sub-title">` 最常踩的坑
25
+ * 正是「标题有了、间距乱了」。所以两档间距固定在本件:内容 8px、区块 16px(3:1 的对比才读得出
26
+ * 「这是两块」)。
27
+ *
28
+ * 可以脱离表单单独用(如「校验结果」这类不成表单的区块):区块间距走 `:not(:first-child)`,
29
+ * 不依赖兄弟结构。
30
+ *
31
+ * **嵌套(区块里再分组)时二级分组自动降级**:直接子区块不叠区块间距(父级 gap 即组内行距)、
32
+ * 其标题转常规字重 —— 层级差由「一级 14/600 ↔ 二级 14/400」表达(两级都吃 600 就读不出从属)。
33
+ * 需要二级分组直接嵌套即可,应用侧不要自写 margin / font-weight 去修(视觉属性也在应用侧护栏内)。
34
+ *
35
+ * 与 `AppPanel` 的判据:**内容会不会自己滚?有没有区域级筛选/操作/分页?** 有 → `AppPanel`;
36
+ * 只是「给一段内容起个名」→ 本件。
37
+ *
38
+ * @example 表单内的分组
39
+ * <AppForm labelAlign="left">
40
+ * <AppForm.Section title="基本信息">
41
+ * <AppForm.Item label="编码" text={definition.code} />
42
+ * </AppForm.Section>
43
+ * <AppForm.Section title="来源列" v-slots={{ extra: () => <span>{n} / 10</span> }}>
44
+ * <AppTable … />
45
+ * </AppForm.Section>
46
+ * </AppForm>
47
+ *
48
+ * @example 页面级区块
49
+ * <AppSection title="映射策略">
50
+ * <AppTable framed … />
51
+ * </AppSection>
52
+ */
53
+ export declare const AppSection: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
54
+ title: {
55
+ type: StringConstructor;
56
+ default: undefined;
57
+ };
58
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
59
+ title: {
60
+ type: StringConstructor;
61
+ default: undefined;
62
+ };
63
+ }>> & Readonly<{}>, {
64
+ title: string;
65
+ }, SlotsType<{
66
+ default?: () => VNodeChild;
67
+ extra?: () => VNodeChild;
68
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;