@manohub/app-kit 0.2.7 → 0.2.8

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/CONTRACT.md CHANGED
@@ -168,6 +168,8 @@ import { AppShell, AppPanel, AppTable, AppButton, notify } from '@manohub/app-ki
168
168
  - `AppPanel.Header.padding` = 内建头那一行的内距;走 `header` 插槽(整行替换)时会把自定义头
169
169
  **包一层**只带内距的 div —— 头内部的几何仍归消费方,组件不碰。
170
170
  - 四件缺省都**不落任何行内 style**(DOM 与没有这个维度时一致)。
171
+ - 同一套口径与实现在**表单**上也有一份(§4.7 `AppForm.padding`):弹窗 / 抽屉里的表单自带内距,
172
+ 同样不必挂「只写 padding」的应用侧类 —— 两处的实现是同一个 `part-padding` 模块,改一处两处同变。
171
173
  - **只给「区域」用**:区块标题(没有区域级筛选/操作、内容也不自己滚)用 `AppSection`(§4.11)。
172
174
  拿本件当「带标题的卡片」用,会把区域头的高度与 Body 的滚动契约带进不需要它的地方。
173
175
 
@@ -241,6 +243,11 @@ import { AppShell, AppPanel, AppTable, AppButton, notify } from '@manohub/app-ki
241
243
  label 宽度固定为 `labelWidth`:对齐与宽度都属于组件,应用侧不要写 CSS 去改。
242
244
  - `labelWidth`(px,缺省 120)与 `controlWidth`(px,缺省撑满)都可写在 `AppForm` 上(下发给每个 Item),
243
245
  Item 上再写则覆盖表单级。
246
+ - **容器内距用 `padding`(px 数字 / `{ y, x }`)**:与 §4.3 `AppPanel` 是**同一口径同一实现** ——
247
+ `padding={16}` 四边同值、`padding={{ y: 16, x: 20 }}` 上下 / 左右分别给(只给 `y` 时不覆盖你 `style` 里的左右内距)。
248
+ **缺省 0**(表单贴容器边):页面里的表单在 `AppPanel.Body` 里,内距由那块给;**弹窗 / 抽屉里没有别的容器**
249
+ 给内距,就用表单自带的 `padding={{ y: 16, x: 20 }}` —— 不要为此给表单挂一个「只写 padding」的应用侧类,
250
+ 也不要在外面套一层只为加内距的 div。
244
251
  - **表单太宽时的两条杠杆(可叠加)**:
245
252
  ① **限宽** —— 表单级或逐行给 `controlWidth`(如 360)封住控件列,输入框不会被拉成长条;
246
253
  ② **分列** —— `columns={2}` 让行并排:**上限 2 列**,窄容器自动回落成一列(与 §4.12 的栅格同一公式,
@@ -1,4 +1,7 @@
1
1
  import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
+ import { type AppPadding } from './part-padding';
3
+ /** 表单内距:与 `AppPanelPadding` **同一口径同一实现**(`number` = 四边同值;`{ y, x }` = 上下 / 左右分别给) */
4
+ export type AppFormPadding = AppPadding;
2
5
  /** label 列的水平对齐:`right`(默认,与 farris / 主流水平表单一致)或 `left` */
3
6
  export type AppFormLabelAlign = 'left' | 'right';
4
7
  export interface AppFormProps {
@@ -24,6 +27,14 @@ export interface AppFormProps {
24
27
  * 在对应 `AppForm.Item` 上给 `fullWidth`,否则会被压成半宽。
25
28
  */
26
29
  columns?: 1 | 2;
30
+ /**
31
+ * 表单内距(**px 数字**,与 `AppPanel` 同一口径):`number` = 四边同值;`{ y, x }` = 上下 / 左右分别给。
32
+ *
33
+ * **缺省 0**:表单贴容器边,内距由所在容器给(页面里的表单在 `AppPanel.Body` 里,那块自带内距)。
34
+ * 弹窗 / 抽屉里没有别的容器给内距时用它自带 —— 如 `padding={{ y: 16, x: 20 }}`,
35
+ * 这样就不必再给表单挂一个「只写 padding」的应用侧类。
36
+ */
37
+ padding?: AppFormPadding;
27
38
  }
28
39
  export interface AppFormItemProps {
29
40
  /**
@@ -85,9 +96,15 @@ export interface AppFormItemProps {
85
96
  * `--ui-form-column-min`(默认 320),所以窄容器会**自动回落成一列**,不需要消费方写媒体查询。
86
97
  * 两列下「整块内容」记得 `fullWidth`。
87
98
  *
88
- * `AppForm.Item` 是唯一入口(`AppForm` 只承载表单级设置与行间距/列数),
99
+ * `AppForm.Item` 是唯一入口(`AppForm` 只承载表单级设置、行间距/列数与容器内距),
89
100
  * 控件从默认插槽进,因此输入框 / 下拉 / 文本域 / 自绘分组卡片共用同一个容器。
90
101
  *
102
+ * ## 容器内距(`padding`)
103
+ *
104
+ * 与 `AppPanel` **同一口径同一实现**(`src/components/part-padding.ts`):`number` 四边同值、
105
+ * `{ y, x }` 上下 / 左右分别给,缺省 0(贴容器边)。页面里的表单在 `AppPanel.Body` 里、内距由那块给;
106
+ * **弹窗 / 抽屉里没有别的容器**给内距,就用表单自带的 `padding={{ y: 16, x: 20 }}`。
107
+ *
91
108
  * ## 静态表单(摘要 / 详情)
92
109
  *
93
110
  * `AppForm.Item` 传 `text` 即切成**只读文本行**,三类行可以在同一个表单里混排 ——
@@ -253,7 +270,13 @@ export declare const AppForm: {
253
270
  type: PropType<1 | 2>;
254
271
  default: number;
255
272
  };
273
+ /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
274
+ padding: {
275
+ type: PropType<AppFormPadding>;
276
+ default: undefined;
277
+ };
256
278
  }>> & Readonly<{}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, import("vue").PublicProps, {
279
+ padding: AppPadding;
257
280
  columns: 1 | 2;
258
281
  labelWidth: number;
259
282
  labelAlign: AppFormLabelAlign;
@@ -288,7 +311,13 @@ export declare const AppForm: {
288
311
  type: PropType<1 | 2>;
289
312
  default: number;
290
313
  };
314
+ /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
315
+ padding: {
316
+ type: PropType<AppFormPadding>;
317
+ default: undefined;
318
+ };
291
319
  }>> & Readonly<{}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, {
320
+ padding: AppPadding;
292
321
  columns: 1 | 2;
293
322
  labelWidth: number;
294
323
  labelAlign: AppFormLabelAlign;
@@ -318,7 +347,13 @@ export declare const AppForm: {
318
347
  type: PropType<1 | 2>;
319
348
  default: number;
320
349
  };
350
+ /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
351
+ padding: {
352
+ type: PropType<AppFormPadding>;
353
+ default: undefined;
354
+ };
321
355
  }>> & Readonly<{}>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, {
356
+ padding: AppPadding;
322
357
  columns: 1 | 2;
323
358
  labelWidth: number;
324
359
  labelAlign: AppFormLabelAlign;
@@ -1,5 +1,6 @@
1
1
  import { defineComponent, provide, toRef, createVNode, inject, createTextVNode } from "vue";
2
2
  import { AppSection } from "./app-section.js";
3
+ import { mergePartStyle } from "./part-padding.js";
3
4
  const FORM_LABEL_WIDTH = /* @__PURE__ */ Symbol("ak-form-label-width");
4
5
  const FORM_CONTROL_WIDTH = /* @__PURE__ */ Symbol("ak-form-control-width");
5
6
  const FORM_LABEL_ALIGN = /* @__PURE__ */ Symbol("ak-form-label-align");
@@ -134,6 +135,11 @@ const AppFormRoot = /* @__PURE__ */ defineComponent({
134
135
  columns: {
135
136
  type: Number,
136
137
  default: 1
138
+ },
139
+ /** 表单内距(px 数字,或 `{ y, x }`);缺省 0 = 贴容器边(弹窗 / 抽屉里常用它自带内距) */
140
+ padding: {
141
+ type: [Number, Object],
142
+ default: void 0
137
143
  }
138
144
  },
139
145
  slots: Object,
@@ -145,7 +151,8 @@ const AppFormRoot = /* @__PURE__ */ defineComponent({
145
151
  provide(FORM_LABEL_ALIGN, toRef(props, "labelAlign"));
146
152
  provide(FORM_CONTROL_WIDTH, toRef(props, "controlWidth"));
147
153
  return () => createVNode("div", {
148
- "class": ["ak-form", props.columns === 2 ? "ak-form--two-column" : "", attrs.class].filter(Boolean).join(" ")
154
+ "class": ["ak-form", props.columns === 2 ? "ak-form--two-column" : "", attrs.class].filter(Boolean).join(" "),
155
+ "style": mergePartStyle(attrs.style, props.padding)
149
156
  }, [slots.default?.()]);
150
157
  }
151
158
  });
@@ -1,4 +1,5 @@
1
1
  import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
+ import { type AppPadding } from './part-padding';
2
3
  /**
3
4
  * 区域容器(页面内分区)—— 与 `AppShell` 的分工:
4
5
  *
@@ -85,11 +86,8 @@ export interface AppPanelProps {
85
86
  */
86
87
  padding?: AppPanelPadding;
87
88
  }
88
- /** 面板(及其三件)的内距:`number` = 四边同值;`{ y, x }` = 上下 / 左右分别给(缺哪边不落哪边) */
89
- export type AppPanelPadding = number | {
90
- y?: number;
91
- x?: number;
92
- };
89
+ /** 面板(及其三件)的内距:与 `AppForm` / `AppPanel` 共用一套口径(`number` = 四边同值;`{ y, x }` 分别给) */
90
+ export type AppPanelPadding = AppPadding;
93
91
  /** 面板标题行(区域级):标题 + 本区域筛选位(toolbar) + 本区域操作位(actions) */
94
92
  export declare const AppPanelHeader: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
95
93
  /**
@@ -143,7 +141,7 @@ export declare const AppPanelHeader: import("vue").DefineComponent<import("vue")
143
141
  title: string;
144
142
  toolbar: any;
145
143
  actions: any;
146
- padding: AppPanelPadding;
144
+ padding: AppPadding;
147
145
  }, SlotsType<{
148
146
  header?: () => VNodeChild;
149
147
  toolbar?: () => VNodeChild;
@@ -171,7 +169,7 @@ export declare const AppPanelBody: import("vue").DefineComponent<import("vue").E
171
169
  default: undefined;
172
170
  };
173
171
  }>> & Readonly<{}>, {
174
- padding: AppPanelPadding;
172
+ padding: AppPadding;
175
173
  }, SlotsType<{
176
174
  default?: () => VNodeChild;
177
175
  }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -194,7 +192,7 @@ export declare const AppPanelFooter: import("vue").DefineComponent<import("vue")
194
192
  default: undefined;
195
193
  };
196
194
  }>> & Readonly<{}>, {
197
- padding: AppPanelPadding;
195
+ padding: AppPadding;
198
196
  }, SlotsType<{
199
197
  default?: () => VNodeChild;
200
198
  }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -228,7 +226,7 @@ export declare const AppPanel: {
228
226
  title: string;
229
227
  toolbar: any;
230
228
  actions: any;
231
- padding: AppPanelPadding;
229
+ padding: AppPadding;
232
230
  }, true, {}, SlotsType<{
233
231
  default?: () => VNodeChild;
234
232
  header?: () => VNodeChild;
@@ -266,7 +264,7 @@ export declare const AppPanel: {
266
264
  title: string;
267
265
  toolbar: any;
268
266
  actions: any;
269
- padding: AppPanelPadding;
267
+ padding: AppPadding;
270
268
  }>;
271
269
  __isFragment?: never;
272
270
  __isTeleport?: never;
@@ -296,7 +294,7 @@ export declare const AppPanel: {
296
294
  title: string;
297
295
  toolbar: any;
298
296
  actions: any;
299
- padding: AppPanelPadding;
297
+ padding: AppPadding;
300
298
  }, {}, string, SlotsType<{
301
299
  default?: () => VNodeChild;
302
300
  header?: () => VNodeChild;
@@ -355,7 +353,7 @@ export declare const AppPanel: {
355
353
  title: string;
356
354
  toolbar: any;
357
355
  actions: any;
358
- padding: AppPanelPadding;
356
+ padding: AppPadding;
359
357
  }, SlotsType<{
360
358
  header?: () => VNodeChild;
361
359
  toolbar?: () => VNodeChild;
@@ -374,7 +372,7 @@ export declare const AppPanel: {
374
372
  default: undefined;
375
373
  };
376
374
  }>> & Readonly<{}>, {
377
- padding: AppPanelPadding;
375
+ padding: AppPadding;
378
376
  }, SlotsType<{
379
377
  default?: () => VNodeChild;
380
378
  }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -391,7 +389,7 @@ export declare const AppPanel: {
391
389
  default: undefined;
392
390
  };
393
391
  }>> & Readonly<{}>, {
394
- padding: AppPanelPadding;
392
+ padding: AppPadding;
395
393
  }, SlotsType<{
396
394
  default?: () => VNodeChild;
397
395
  }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -1,25 +1,5 @@
1
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
- }
2
+ import { mergePartStyle, partPaddingStyle } from "./part-padding.js";
23
3
  const AppPanelHeader = /* @__PURE__ */ defineComponent({
24
4
  name: "AppPanelHeader",
25
5
  inheritAttrs: false,
@@ -63,7 +43,7 @@ const AppPanelHeader = /* @__PURE__ */ defineComponent({
63
43
  const actions = renderSlotValue(slots.actions, props.actions);
64
44
  if (slots.header) {
65
45
  const custom = slots.header();
66
- const paddingStyle = panelPaddingStyle(props.padding);
46
+ const paddingStyle = partPaddingStyle(props.padding);
67
47
  return paddingStyle === void 0 ? custom : createVNode("div", {
68
48
  "style": paddingStyle
69
49
  }, [custom]);
@@ -0,0 +1,27 @@
1
+ import type { StyleValue } from 'vue';
2
+ /**
3
+ * 骨架件的**内距**口径(`AppPanel` 及其三件、`AppForm` 共用同一套)。
4
+ *
5
+ * - `number` → 四边同值(`padding={16}`);
6
+ * - `{ y, x }` → 上下 / 左右分别给(`{ y: 12, x: 20 }`,弹窗里的容器常用 —— 与 Shell 的页面左右内距同档),
7
+ * **缺哪边就不落哪边的声明**(只给 `y` 时不覆盖消费方在 `style` 里写的左右内距)。
8
+ *
9
+ * 为什么是 px 数字而不是 CSS 字符串:几何值在本仓是**设计基准**,不跟根字号
10
+ * (与 `AppForm.labelWidth` / `AppTable.rowHeight` 同口径);要写自适应内距的场合请走 `class`。
11
+ */
12
+ export type AppPadding = number | {
13
+ y?: number;
14
+ x?: number;
15
+ };
16
+ /**
17
+ * 内距 → 行内样式。缺省(`undefined`)时返回 `undefined`:**不额外产生 style 属性**,
18
+ * DOM 与「没有这个维度」时完全一致。
19
+ */
20
+ export declare function partPaddingStyle(padding: AppPadding | undefined): StyleValue | undefined;
21
+ /**
22
+ * 合并「消费方给的 `style`」与「内距行内样式」:两者都可能有,内距排在后面
23
+ * —— 同一属性以组件的 `padding` 为准(消费方要覆盖就用 `class` 里更具体的规则)。
24
+ *
25
+ * 不给 `padding` 时**原样返回消费方的 style**(含 `undefined`)。
26
+ */
27
+ export declare function mergePartStyle(attrsStyle: unknown, padding: AppPadding | undefined): StyleValue | undefined;
@@ -0,0 +1,23 @@
1
+ function partPaddingStyle(padding) {
2
+ if (padding === void 0) return void 0;
3
+ if (typeof padding === "number") return { padding: `${padding}px` };
4
+ const style = {};
5
+ if (padding.y !== void 0) {
6
+ style.paddingTop = `${padding.y}px`;
7
+ style.paddingBottom = `${padding.y}px`;
8
+ }
9
+ if (padding.x !== void 0) {
10
+ style.paddingLeft = `${padding.x}px`;
11
+ style.paddingRight = `${padding.x}px`;
12
+ }
13
+ return style;
14
+ }
15
+ function mergePartStyle(attrsStyle, padding) {
16
+ const paddingStyle = partPaddingStyle(padding);
17
+ if (paddingStyle === void 0) return attrsStyle;
18
+ return [attrsStyle, paddingStyle];
19
+ }
20
+ export {
21
+ mergePartStyle,
22
+ partPaddingStyle
23
+ };
package/dist/index.d.ts CHANGED
@@ -26,7 +26,7 @@ export { AppBadge, type AppBadgeTone, type AppBadgeShape, type AppBadgeSize, typ
26
26
  export { AppDialog } from './components/app-dialog';
27
27
  export { AppDrawer } from './components/app-drawer';
28
28
  export { AppTabs, type AppTabItem } from './components/app-tabs';
29
- export { AppForm, type AppFormProps, type AppFormItemProps, type AppFormLabelAlign, type AppFormCompound, } from './components/app-form';
29
+ export { AppForm, type AppFormProps, type AppFormItemProps, type AppFormLabelAlign, type AppFormPadding, type AppFormCompound, } from './components/app-form';
30
30
  export { AppSection, type AppSectionProps } from './components/app-section';
31
31
  export { AppLayout, type AppLayoutGap, type AppLayoutAlign, type AppLayoutJustify, type AppLayoutColumns, type AppLayoutSpan, } from './atoms/app-layout';
32
32
  export { AppSteps, type AppStepItem } from './components/app-steps';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manohub/app-kit",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "子应用统一骨架层:入口编排(createSubApp)、布局契约(AppShell)、页面组件、原子件、服务、样式底座。farris 被收敛在本包内部,对外只暴露标准 API。",
@@ -63,7 +63,7 @@
63
63
  },
64
64
  "dependencies": {
65
65
  "@farris/ui-vue": "^1.8.4",
66
- "@manohub/icon": "^0.2.7"
66
+ "@manohub/icon": "^0.2.8"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@tanstack/vue-query": "catalog:",