@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,101 @@
1
+ import { defineComponent, createVNode } from "vue";
2
+ const AppStateIllustrationEmpty = /* @__PURE__ */ defineComponent({
3
+ name: "AppStateIllustrationEmpty",
4
+ setup: () => () => createVNode("svg", {
5
+ "class": "ak-state-illustration",
6
+ "viewBox": "0 0 168 120",
7
+ "fill": "none",
8
+ "aria-hidden": "true",
9
+ "focusable": "false"
10
+ }, [createVNode("ellipse", {
11
+ "class": "ak-ill-shadow",
12
+ "cx": "84",
13
+ "cy": "106",
14
+ "rx": "50",
15
+ "ry": "6"
16
+ }, null), createVNode("path", {
17
+ "class": "ak-ill-face ak-ill-face--top",
18
+ "d": "M40 44 56 26h88l-16 18Z"
19
+ }, null), createVNode("path", {
20
+ "class": "ak-ill-face ak-ill-face--front",
21
+ "d": "M40 44h88v58H40Z"
22
+ }, null), createVNode("path", {
23
+ "class": "ak-ill-face ak-ill-face--side",
24
+ "d": "M128 44l16-18v58l-16 18Z"
25
+ }, null), createVNode("path", {
26
+ "class": "ak-ill-line",
27
+ "d": "M54 64h58M54 80h40"
28
+ }, null), createVNode("circle", {
29
+ "class": "ak-ill-dot",
30
+ "cx": "30",
31
+ "cy": "38",
32
+ "r": "3.5"
33
+ }, null), createVNode("circle", {
34
+ "class": "ak-ill-dot ak-ill-dot--accent",
35
+ "cx": "24",
36
+ "cy": "22",
37
+ "r": "2.5"
38
+ }, null), createVNode("g", {
39
+ "class": "ak-ill-badge"
40
+ }, [createVNode("circle", {
41
+ "class": "ak-ill-badge__disc",
42
+ "cx": "146",
43
+ "cy": "22",
44
+ "r": "12"
45
+ }, null), createVNode("path", {
46
+ "class": "ak-ill-badge__mark",
47
+ "d": "M146 17v10M141 22h10"
48
+ }, null)])])
49
+ });
50
+ const AppStateIllustrationError = /* @__PURE__ */ defineComponent({
51
+ name: "AppStateIllustrationError",
52
+ setup: () => () => createVNode("svg", {
53
+ "class": "ak-state-illustration",
54
+ "viewBox": "0 0 168 120",
55
+ "fill": "none",
56
+ "aria-hidden": "true",
57
+ "focusable": "false"
58
+ }, [createVNode("ellipse", {
59
+ "class": "ak-ill-shadow",
60
+ "cx": "84",
61
+ "cy": "106",
62
+ "rx": "50",
63
+ "ry": "6"
64
+ }, null), createVNode("path", {
65
+ "class": "ak-ill-face ak-ill-face--top",
66
+ "d": "M40 44 56 26h88l-16 18Z"
67
+ }, null), createVNode("path", {
68
+ "class": "ak-ill-face ak-ill-face--front",
69
+ "d": "M40 44h88v58H40Z"
70
+ }, null), createVNode("path", {
71
+ "class": "ak-ill-face ak-ill-face--side",
72
+ "d": "M128 44l16-18v58l-16 18Z"
73
+ }, null), createVNode("path", {
74
+ "class": "ak-ill-line ak-ill-line--broken",
75
+ "d": "M54 64h58M54 80h40"
76
+ }, null), createVNode("circle", {
77
+ "class": "ak-ill-dot",
78
+ "cx": "30",
79
+ "cy": "38",
80
+ "r": "3.5"
81
+ }, null), createVNode("g", {
82
+ "class": "ak-ill-badge ak-ill-badge--error"
83
+ }, [createVNode("circle", {
84
+ "class": "ak-ill-badge__disc",
85
+ "cx": "146",
86
+ "cy": "22",
87
+ "r": "12"
88
+ }, null), createVNode("path", {
89
+ "class": "ak-ill-badge__mark",
90
+ "d": "M146 16v8"
91
+ }, null), createVNode("circle", {
92
+ "class": "ak-ill-badge__dot",
93
+ "cx": "146",
94
+ "cy": "28",
95
+ "r": "1.75"
96
+ }, null)])])
97
+ });
98
+ export {
99
+ AppStateIllustrationEmpty,
100
+ AppStateIllustrationError
101
+ };
@@ -0,0 +1,72 @@
1
+ import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
+ export type AppBadgeTone = 'default' | 'primary' | 'info' | 'success' | 'warning' | 'error';
3
+ export type AppBadgeShape = 'soft' | 'outline' | 'plain';
4
+ export type AppBadgeSize = 'sm' | 'md';
5
+ export type AppBadgeDot = 'filled' | 'ring';
6
+ /**
7
+ * 徽标 / 标签(farris 无对应件,按设计稿自建)。
8
+ *
9
+ * 吃掉的分身:批次 5 前 4 个应用各自手搓徽标(`repository` 状态胶囊、`skill-admission`
10
+ * 准入状态、`skill-auth` 类型标签、`scan-report` 结论徽标),字号 / 圆角 / 色阶各写一遍。
11
+ *
12
+ * 形态(`shape`):
13
+ * - `soft`:浅底 + 同色文字(标签)
14
+ * - `outline`:浅底 + 同色描边;`tone="default"` 时退化为白底 + 中性描边 + 正文色(状态胶囊)
15
+ * - `plain`:无底无框,靠圆点表达状态(成功/中性用正文色、错误用危险色)
16
+ *
17
+ * @example
18
+ * // 状态胶囊(白底 + 中性描边 + 实心状态点)
19
+ * <AppBadge tone="success" shape="outline" size="md" dot="filled">运行中</AppBadge>
20
+ *
21
+ * @example
22
+ * // 类型标签 / 结论徽标 / 无底状态
23
+ * <AppBadge tone="primary">业务域</AppBadge>
24
+ * <AppBadge tone="error" shape="outline">风险</AppBadge>
25
+ * <AppBadge tone="default" shape="plain" dot="ring">待处理</AppBadge>
26
+ */
27
+ export declare const AppBadge: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
28
+ tone: {
29
+ type: PropType<AppBadgeTone>;
30
+ default: string;
31
+ };
32
+ /** 形态:soft(浅底)/ outline(描边)/ plain(无底 + 圆点) */
33
+ shape: {
34
+ type: PropType<AppBadgeShape>;
35
+ default: string;
36
+ };
37
+ size: {
38
+ type: PropType<AppBadgeSize>;
39
+ default: string;
40
+ };
41
+ /** 前置圆点:filled 实心 / ring 空心;不传则无圆点 */
42
+ dot: {
43
+ type: PropType<AppBadgeDot>;
44
+ default: undefined;
45
+ };
46
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
47
+ tone: {
48
+ type: PropType<AppBadgeTone>;
49
+ default: string;
50
+ };
51
+ /** 形态:soft(浅底)/ outline(描边)/ plain(无底 + 圆点) */
52
+ shape: {
53
+ type: PropType<AppBadgeShape>;
54
+ default: string;
55
+ };
56
+ size: {
57
+ type: PropType<AppBadgeSize>;
58
+ default: string;
59
+ };
60
+ /** 前置圆点:filled 实心 / ring 空心;不传则无圆点 */
61
+ dot: {
62
+ type: PropType<AppBadgeDot>;
63
+ default: undefined;
64
+ };
65
+ }>> & Readonly<{}>, {
66
+ size: AppBadgeSize;
67
+ tone: AppBadgeTone;
68
+ shape: AppBadgeShape;
69
+ dot: AppBadgeDot;
70
+ }, SlotsType<{
71
+ default?: () => VNodeChild;
72
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -0,0 +1,40 @@
1
+ import { defineComponent, createVNode } from "vue";
2
+ const AppBadge = /* @__PURE__ */ defineComponent({
3
+ name: "AppBadge",
4
+ inheritAttrs: false,
5
+ props: {
6
+ tone: {
7
+ type: String,
8
+ default: "default"
9
+ },
10
+ /** 形态:soft(浅底)/ outline(描边)/ plain(无底 + 圆点) */
11
+ shape: {
12
+ type: String,
13
+ default: "soft"
14
+ },
15
+ size: {
16
+ type: String,
17
+ default: "sm"
18
+ },
19
+ /** 前置圆点:filled 实心 / ring 空心;不传则无圆点 */
20
+ dot: {
21
+ type: String,
22
+ default: void 0
23
+ }
24
+ },
25
+ slots: Object,
26
+ setup(props, {
27
+ slots,
28
+ attrs
29
+ }) {
30
+ return () => createVNode("span", {
31
+ "class": ["ak-badge", `ak-badge--${props.tone}`, `ak-badge--${props.shape}`, `ak-badge--${props.size}`, props.dot ? `ak-badge--dot-${props.dot}` : "", attrs.class].filter(Boolean).join(" "),
32
+ "style": attrs.style
33
+ }, [props.dot ? createVNode("span", {
34
+ "class": "ak-badge__dot"
35
+ }, null) : null, slots.default?.()]);
36
+ }
37
+ });
38
+ export {
39
+ AppBadge
40
+ };
@@ -0,0 +1,164 @@
1
+ import { type PropType, type SlotsType, type VNodeChild } from 'vue';
2
+ /**
3
+ * 模态弹窗(封装 farris FModal)。
4
+ *
5
+ * 契约:`open` 受控 + `onUpdate:open`(关闭时同发 `onClose`),按钮默认 **不自绘**
6
+ * (`showButtons: false`)—— 需要按钮时用 `footer`(函数或节点)或 `footer` 插槽给,
7
+ * 也可以走命令式 `modalService.open`。
8
+ *
9
+ * 页脚几何由本件负责:`footer` 的内容会被包进上游内建同款的 `div.modal-footer`
10
+ * (右对齐 + 内距 + 常驻不滚)。**应用侧不要再自绘 footer 容器**(原先 vm 向导就为此补了一层)。
11
+ *
12
+ * 弹窗内容固定渲染进 `.app-container`(farris 默认投到 body,会同时丢掉令牌与应用侧样式,
13
+ * 详见 `resolveAppContainer` 的说明)—— 消费方不需要、也无法干预这一点。
14
+ *
15
+ * @example
16
+ * <AppDialog open={visible} title="查看详情" width={640}
17
+ * onUpdate:open={(v) => (visible = v)}>
18
+ * <pre>{detail}</pre>
19
+ * </AppDialog>
20
+ *
21
+ * @example 带页脚(按钮右对齐、常驻,不需要自绘容器)
22
+ * <AppDialog open={visible} title="新增分类" footer={() => (
23
+ * <>
24
+ * <AppButton tone="secondary" onClick={close}>取消</AppButton>
25
+ * <AppButton tone="primary" loading={saving} onClick={submit}>确定</AppButton>
26
+ * </>
27
+ * )}>…</AppDialog>
28
+ *
29
+ * @example 命令式(不在模板里声明弹窗时)
30
+ * const modal = modalService.open({ title: '新增分类', content: { render: () => <Form /> } })
31
+ * modal.disableButtons(['submit'], true) // 提交中禁用,防重复点击
32
+ */
33
+ export declare const AppDialog: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
34
+ open: {
35
+ type: BooleanConstructor;
36
+ default: boolean;
37
+ };
38
+ title: {
39
+ type: StringConstructor;
40
+ default: string;
41
+ };
42
+ width: {
43
+ type: NumberConstructor;
44
+ default: number;
45
+ };
46
+ minHeight: {
47
+ type: NumberConstructor;
48
+ default: undefined;
49
+ };
50
+ /** 固定高度(px)。与 `fitContent` 搭配:不传则按内容自适应 */
51
+ height: {
52
+ type: NumberConstructor;
53
+ default: undefined;
54
+ };
55
+ /**
56
+ * 是否按内容自适应高度。farris 默认 true;
57
+ * 需要「固定高度 + 内部滚动」的弹窗(如向导、大表格)显式传 false 并给 `height`。
58
+ */
59
+ fitContent: {
60
+ type: BooleanConstructor;
61
+ default: undefined;
62
+ };
63
+ /**
64
+ * 是否渲染 farris 自带标题栏。传 false 时由消费方在默认插槽里自绘标题
65
+ * (向导类弹窗常见:标题栏与步骤条合一)。
66
+ */
67
+ showHeader: {
68
+ type: BooleanConstructor;
69
+ default: boolean;
70
+ };
71
+ /**
72
+ * 关闭前钩子(点右上角关闭 / 遮罩时触发)。
73
+ * 返回 `false` 可阻止关闭(如「有未保存改动,请确认」)。
74
+ */
75
+ beforeClose: {
76
+ type: PropType<() => boolean | void | Promise<boolean | void>>;
77
+ default: undefined;
78
+ };
79
+ /** 是否显示 farris 自带按钮区;默认关闭(按钮由消费方自绘) */
80
+ showButtons: {
81
+ type: BooleanConstructor;
82
+ default: boolean;
83
+ };
84
+ /** 底部按钮区(等价于 `footer` 插槽;TSX 下推荐按本仓惯例用 prop 传节点) */
85
+ footer: {
86
+ type: PropType<any>;
87
+ default: undefined;
88
+ };
89
+ }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
90
+ [key: string]: any;
91
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("close" | "update:open")[], "close" | "update:open", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
92
+ open: {
93
+ type: BooleanConstructor;
94
+ default: boolean;
95
+ };
96
+ title: {
97
+ type: StringConstructor;
98
+ default: string;
99
+ };
100
+ width: {
101
+ type: NumberConstructor;
102
+ default: number;
103
+ };
104
+ minHeight: {
105
+ type: NumberConstructor;
106
+ default: undefined;
107
+ };
108
+ /** 固定高度(px)。与 `fitContent` 搭配:不传则按内容自适应 */
109
+ height: {
110
+ type: NumberConstructor;
111
+ default: undefined;
112
+ };
113
+ /**
114
+ * 是否按内容自适应高度。farris 默认 true;
115
+ * 需要「固定高度 + 内部滚动」的弹窗(如向导、大表格)显式传 false 并给 `height`。
116
+ */
117
+ fitContent: {
118
+ type: BooleanConstructor;
119
+ default: undefined;
120
+ };
121
+ /**
122
+ * 是否渲染 farris 自带标题栏。传 false 时由消费方在默认插槽里自绘标题
123
+ * (向导类弹窗常见:标题栏与步骤条合一)。
124
+ */
125
+ showHeader: {
126
+ type: BooleanConstructor;
127
+ default: boolean;
128
+ };
129
+ /**
130
+ * 关闭前钩子(点右上角关闭 / 遮罩时触发)。
131
+ * 返回 `false` 可阻止关闭(如「有未保存改动,请确认」)。
132
+ */
133
+ beforeClose: {
134
+ type: PropType<() => boolean | void | Promise<boolean | void>>;
135
+ default: undefined;
136
+ };
137
+ /** 是否显示 farris 自带按钮区;默认关闭(按钮由消费方自绘) */
138
+ showButtons: {
139
+ type: BooleanConstructor;
140
+ default: boolean;
141
+ };
142
+ /** 底部按钮区(等价于 `footer` 插槽;TSX 下推荐按本仓惯例用 prop 传节点) */
143
+ footer: {
144
+ type: PropType<any>;
145
+ default: undefined;
146
+ };
147
+ }>> & Readonly<{
148
+ onClose?: ((...args: any[]) => any) | undefined;
149
+ "onUpdate:open"?: ((...args: any[]) => any) | undefined;
150
+ }>, {
151
+ title: string;
152
+ footer: any;
153
+ width: number;
154
+ height: number;
155
+ open: boolean;
156
+ showHeader: boolean;
157
+ minHeight: number;
158
+ fitContent: boolean;
159
+ beforeClose: () => boolean | void | Promise<boolean | void>;
160
+ showButtons: boolean;
161
+ }, SlotsType<{
162
+ default?: () => VNodeChild;
163
+ footer?: () => VNodeChild;
164
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -0,0 +1,121 @@
1
+ import { FModal } from "@farris/ui-vue";
2
+ import { defineComponent, h } from "vue";
3
+ import { resolveAppContainer } from "../services/app-container.js";
4
+ const FarrisModal = FModal;
5
+ const AppDialog = /* @__PURE__ */ defineComponent({
6
+ name: "AppDialog",
7
+ inheritAttrs: false,
8
+ emits: ["update:open", "close"],
9
+ props: {
10
+ open: {
11
+ type: Boolean,
12
+ default: false
13
+ },
14
+ title: {
15
+ type: String,
16
+ default: ""
17
+ },
18
+ width: {
19
+ type: Number,
20
+ default: 640
21
+ },
22
+ minHeight: {
23
+ type: Number,
24
+ default: void 0
25
+ },
26
+ /** 固定高度(px)。与 `fitContent` 搭配:不传则按内容自适应 */
27
+ height: {
28
+ type: Number,
29
+ default: void 0
30
+ },
31
+ /**
32
+ * 是否按内容自适应高度。farris 默认 true;
33
+ * 需要「固定高度 + 内部滚动」的弹窗(如向导、大表格)显式传 false 并给 `height`。
34
+ */
35
+ fitContent: {
36
+ type: Boolean,
37
+ default: void 0
38
+ },
39
+ /**
40
+ * 是否渲染 farris 自带标题栏。传 false 时由消费方在默认插槽里自绘标题
41
+ * (向导类弹窗常见:标题栏与步骤条合一)。
42
+ */
43
+ showHeader: {
44
+ type: Boolean,
45
+ default: true
46
+ },
47
+ /**
48
+ * 关闭前钩子(点右上角关闭 / 遮罩时触发)。
49
+ * 返回 `false` 可阻止关闭(如「有未保存改动,请确认」)。
50
+ */
51
+ beforeClose: {
52
+ type: Function,
53
+ default: void 0
54
+ },
55
+ /** 是否显示 farris 自带按钮区;默认关闭(按钮由消费方自绘) */
56
+ showButtons: {
57
+ type: Boolean,
58
+ default: false
59
+ },
60
+ /** 底部按钮区(等价于 `footer` 插槽;TSX 下推荐按本仓惯例用 prop 传节点) */
61
+ footer: {
62
+ type: [Function, Object, Array, String],
63
+ default: void 0
64
+ }
65
+ },
66
+ slots: Object,
67
+ setup(props, {
68
+ slots,
69
+ attrs,
70
+ emit
71
+ }) {
72
+ const handleUpdate = (value) => {
73
+ emit("update:open", value);
74
+ if (!value) emit("close");
75
+ };
76
+ return () => h(FarrisModal, {
77
+ modelValue: props.open,
78
+ title: props.title,
79
+ width: props.width,
80
+ minHeight: props.minHeight,
81
+ height: props.height,
82
+ fitContent: props.fitContent,
83
+ showHeader: props.showHeader,
84
+ beforeClose: props.beforeClose,
85
+ showButtons: props.showButtons,
86
+ /**
87
+ * 渲染宿主:farris FModal 缺省把整棵弹窗 Teleport 到 `body`,而令牌(`--ui-*`)与主题桥接
88
+ * (`--f-theme-*`)都锚在 `.app-container` 上、微前端下应用侧 CSS 还被 scopecss 限定在容器内 ——
89
+ * 弹窗落到 body 会让**内容里所有组件与应用样式一起失效**(实测表现:弹窗「样式全丢」)。
90
+ * 这里固定改投 `.app-container`;传 Element 而非选择器字符串是因为 farris 的 `host` 声明为
91
+ * `Object`,传字符串会多刷一条 prop 类型告警。
92
+ */
93
+ host: resolveAppContainer(),
94
+ customClass: attrs.class,
95
+ "onUpdate:modelValue": handleUpdate
96
+ }, {
97
+ default: () => slots.default?.(),
98
+ /**
99
+ * 页脚:`footer` prop(函数或节点)与 `footer` 插槽两种传法都支持。
100
+ *
101
+ * ⚠️ farris 的 `footerTemplate` 是**裸渲染** —— 内建按钮那条路径(`me()`)自己会包一层
102
+ * `div.modal-footer` 拿到「右对齐 + 内距 + `flex-shrink:0` 常驻不滚」,模板路径不给。
103
+ * 直接透传会让消费方的按钮变成左对齐的裸节点(原先各应用只能各自补一层 footer 容器,
104
+ * 即 vm 那边的 `.vm-wizard-footer`)。这里补上游内建同款容器,页脚几何归本包。
105
+ */
106
+ ...(() => {
107
+ const hasFooter = !!slots.footer || props.footer !== void 0;
108
+ if (!hasFooter) return {};
109
+ const renderFooter = () => slots.footer ? slots.footer() : typeof props.footer === "function" ? props.footer() : props.footer;
110
+ return {
111
+ footerTemplate: () => h("div", {
112
+ class: "modal-footer"
113
+ }, [renderFooter()])
114
+ };
115
+ })()
116
+ });
117
+ }
118
+ });
119
+ export {
120
+ AppDialog
121
+ };
@@ -0,0 +1,173 @@
1
+ import { type PropType } from 'vue';
2
+ export interface AppFilterField {
3
+ id: string;
4
+ code: string;
5
+ labelCode?: string;
6
+ name: string;
7
+ controlType?: string;
8
+ visible?: boolean;
9
+ /** farris 编辑器配置(combo-list / input-group);由消费方按字段语义给出 */
10
+ editor?: Record<string, unknown>;
11
+ }
12
+ /** 归一化后的条件快照:`code → 值`(「全部」哨兵 `all` 已翻译为空串) */
13
+ export type AppFilterValues = Record<string, string>;
14
+ export interface AppFilterEventMeta {
15
+ /** 关键字字段(keywordCodes 命中者)的当前值 */
16
+ keyword: string;
17
+ /** 是否来自查询事件(查询按钮 / 回车),条件变化事件为 false */
18
+ query: boolean;
19
+ }
20
+ /**
21
+ * 条件字段编辑器工厂:下拉。
22
+ *
23
+ * `valueField` / `enumValueType` 必须显式指定,否则 farris 会把选中值整体丢弃
24
+ * (本仓 skill-admission / skill-auth 两处筛选栏都为此写过同款注释)。
25
+ * 应用侧只给标准 `{ label, value }` 选项,farris 语法不外泄。
26
+ */
27
+ export declare function appFilterSelect(options: {
28
+ label: string;
29
+ value: string;
30
+ }[]): Record<string, unknown>;
31
+ /** 条件字段编辑器工厂:单行文本(固定 updateOn=change,避免默认 blur 不实时) */
32
+ export declare function appFilterInput(placeholder: string): Record<string, unknown>;
33
+ /**
34
+ * 查询条件区(封装 farris FQuerySolution)—— 本方案最重的适配件之一。
35
+ *
36
+ * 内部一次消化 farris 的全部已知坑,调用方只给字段与默认值:
37
+ * - **payload 三形态归一**:`normalizeConditions` 统一输出 `code → 值`(见上)
38
+ * - **就绪轮询**:方案加载失败(如 dev 无 formId 走 404 catch)不会 emit loadedSolution,
39
+ * 故除 `onLoadedSolution` 外另以 100ms 轮询 `getConditions().length` 兜底(上限 `readyTries`)
40
+ * - **默认值注入时序**:`defaults` 必须在条件区就绪后应用(farris 要求内部已有当前方案,
41
+ * 否则静默跳过 —— 本仓曾因「仓库列表先于方案到位」出现竞态),故内部持有 `defaultValues`
42
+ * 计时注入,并在 `defaults` 变化时镜像更新
43
+ * - **字段可见性**:`fields` 变化自动 `updateFields`(替代各应用手写的 `solutionRef` 直调)
44
+ * - **重建后的空查询**:按 key 重建条件区时(如类别切换换字段集合)挂载即触发一次空条件查询,
45
+ * 传 `ignoreInitialEmpty` 可忽略该次(就绪后自动复位)
46
+ *
47
+ * @example
48
+ * <AppFilter fields={fields} defaults={{ 'field-repoId': repoId, 'field-category': 'all' }}
49
+ * searchFields="name" searchPlaceholder={t('filter.keywordPlaceholder')}
50
+ * onChange={(values) => applyFilter(values)}
51
+ * onQuery={(values) => applyFilter({ ...values, force: true })} />
52
+ */
53
+ export declare const AppFilter: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
54
+ fields: {
55
+ type: PropType<AppFilterField[]>;
56
+ required: true;
57
+ };
58
+ /** 默认值:字段 **id** → 业务值(哨兵 `all` 表示「全部」);内部翻译为 farris defaultValues */
59
+ defaults: {
60
+ type: PropType<Record<string, string | number | null>>;
61
+ default: undefined;
62
+ };
63
+ searchFields: {
64
+ type: StringConstructor;
65
+ default: undefined;
66
+ };
67
+ searchPlaceholder: {
68
+ type: StringConstructor;
69
+ default: string;
70
+ };
71
+ /** 条件区横向内联(farris isControlInline) */
72
+ inline: {
73
+ type: BooleanConstructor;
74
+ default: boolean;
75
+ };
76
+ expanded: {
77
+ type: BooleanConstructor;
78
+ default: boolean;
79
+ };
80
+ /** 关键字字段 code(命中者并入事件 meta.keyword,大小写不敏感) */
81
+ keywordCodes: {
82
+ type: PropType<string[]>;
83
+ default: () => string[];
84
+ };
85
+ /** 就绪轮询上限(100ms/次) */
86
+ readyTries: {
87
+ type: NumberConstructor;
88
+ default: number;
89
+ };
90
+ /** 忽略条件区重建后挂载即触发的首次空条件事件(就绪后自动复位) */
91
+ ignoreInitialEmpty: {
92
+ type: BooleanConstructor;
93
+ default: boolean;
94
+ };
95
+ onChange: {
96
+ type: PropType<(values: AppFilterValues, meta: AppFilterEventMeta) => void>;
97
+ default: undefined;
98
+ };
99
+ onQuery: {
100
+ type: PropType<(values: AppFilterValues, meta: AppFilterEventMeta) => void>;
101
+ default: undefined;
102
+ };
103
+ onReady: {
104
+ type: PropType<() => void>;
105
+ default: undefined;
106
+ };
107
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
108
+ fields: {
109
+ type: PropType<AppFilterField[]>;
110
+ required: true;
111
+ };
112
+ /** 默认值:字段 **id** → 业务值(哨兵 `all` 表示「全部」);内部翻译为 farris defaultValues */
113
+ defaults: {
114
+ type: PropType<Record<string, string | number | null>>;
115
+ default: undefined;
116
+ };
117
+ searchFields: {
118
+ type: StringConstructor;
119
+ default: undefined;
120
+ };
121
+ searchPlaceholder: {
122
+ type: StringConstructor;
123
+ default: string;
124
+ };
125
+ /** 条件区横向内联(farris isControlInline) */
126
+ inline: {
127
+ type: BooleanConstructor;
128
+ default: boolean;
129
+ };
130
+ expanded: {
131
+ type: BooleanConstructor;
132
+ default: boolean;
133
+ };
134
+ /** 关键字字段 code(命中者并入事件 meta.keyword,大小写不敏感) */
135
+ keywordCodes: {
136
+ type: PropType<string[]>;
137
+ default: () => string[];
138
+ };
139
+ /** 就绪轮询上限(100ms/次) */
140
+ readyTries: {
141
+ type: NumberConstructor;
142
+ default: number;
143
+ };
144
+ /** 忽略条件区重建后挂载即触发的首次空条件事件(就绪后自动复位) */
145
+ ignoreInitialEmpty: {
146
+ type: BooleanConstructor;
147
+ default: boolean;
148
+ };
149
+ onChange: {
150
+ type: PropType<(values: AppFilterValues, meta: AppFilterEventMeta) => void>;
151
+ default: undefined;
152
+ };
153
+ onQuery: {
154
+ type: PropType<(values: AppFilterValues, meta: AppFilterEventMeta) => void>;
155
+ default: undefined;
156
+ };
157
+ onReady: {
158
+ type: PropType<() => void>;
159
+ default: undefined;
160
+ };
161
+ }>> & Readonly<{}>, {
162
+ onChange: (values: AppFilterValues, meta: AppFilterEventMeta) => void;
163
+ inline: boolean;
164
+ expanded: boolean;
165
+ defaults: Record<string, string | number | null>;
166
+ searchFields: string;
167
+ searchPlaceholder: string;
168
+ keywordCodes: string[];
169
+ readyTries: number;
170
+ ignoreInitialEmpty: boolean;
171
+ onQuery: (values: AppFilterValues, meta: AppFilterEventMeta) => void;
172
+ onReady: () => void;
173
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;