@shwfed/config 2.3.10 → 2.3.12

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 (111) hide show
  1. package/dist/mcp.mjs +946 -544
  2. package/dist/module.json +1 -1
  3. package/dist/preview/assets/{config-CyScbxXy.js → config-B-1L3Ra-.js} +1 -1
  4. package/dist/preview/assets/{config-ja_GMXxV.js → config-Cf5kO84H.js} +1 -1
  5. package/dist/preview/assets/{config-bxqg3yuv.js → config-DTQkLHVw.js} +1 -1
  6. package/dist/preview/assets/{config-HdWYFZ09.js → config-DqxN0Byp.js} +1 -1
  7. package/dist/preview/assets/{config-2R4XkSGs.js → config-QUQ71Eo6.js} +1 -1
  8. package/dist/preview/assets/{config-ykJZssgx.js → config-oO93sSer.js} +1 -1
  9. package/dist/preview/assets/{config-KcLrpkc1.js → config-sJ5XKUJy.js} +1 -1
  10. package/dist/preview/assets/{config-BxzDT_57.js → config-zCMkbPQt.js} +1 -1
  11. package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-CWyVRSOh.js → definition.vue_vue_type_script_setup_true_lang-D-OVRv68.js} +1 -1
  12. package/dist/preview/assets/index-Br_eXThF.css +1 -0
  13. package/dist/preview/assets/index-D8QyOVfp.js +637 -0
  14. package/dist/preview/assets/index-b_t8yWJJ.js +1 -0
  15. package/dist/preview/assets/{runtime-B8aUJIpn.js → runtime-10_7L7Gz.js} +1 -1
  16. package/dist/preview/assets/{runtime-CxA8fvQP.js → runtime-B2EP6060.js} +1 -1
  17. package/dist/preview/assets/{runtime-LBdh1D75.js → runtime-BxlgShjU.js} +1 -1
  18. package/dist/preview/assets/{runtime-DqZhDPHl.js → runtime-Cv2doZNu.js} +1 -1
  19. package/dist/preview/assets/{runtime-CpSiaWMP.js → runtime-CzDUrqSa.js} +1 -1
  20. package/dist/preview/assets/{runtime-D2K1s33u.js → runtime-DcYhXvSk.js} +1 -1
  21. package/dist/preview/assets/{runtime-DAXQmtLg.js → runtime-DlDhRVII.js} +1 -1
  22. package/dist/preview/assets/{runtime-C9XnvD5A.js → runtime-cmkN6aik.js} +1 -1
  23. package/dist/preview/index.html +2 -2
  24. package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/schema.d.ts +1 -1
  25. package/dist/runtime/components/config/blocks/2026-05-17/com.shwfed.block.chart.xy/schema.d.ts +4 -0
  26. package/dist/runtime/components/config/blocks/2026-05-17/com.shwfed.block.chart.xy/schema.js +6 -17
  27. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +18 -18
  28. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +18 -18
  29. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/config.d.vue.ts +4 -4
  30. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/config.vue.d.ts +4 -4
  31. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +22 -22
  32. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +22 -22
  33. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.time/config.d.vue.ts +2 -2
  34. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.time/config.vue.d.ts +2 -2
  35. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.d.vue.ts +4 -4
  36. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue.d.ts +4 -4
  37. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/config.d.vue.ts +12 -12
  38. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/config.vue.d.ts +12 -12
  39. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.switch/config.d.vue.ts +10 -10
  40. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.switch/config.vue.d.ts +10 -10
  41. package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/config.d.vue.ts +12 -12
  42. package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/config.vue.d.ts +12 -12
  43. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.d.vue.ts +133 -0
  44. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.vue +605 -0
  45. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.vue.d.ts +133 -0
  46. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/runtime.d.vue.ts +8 -0
  47. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/runtime.vue +324 -0
  48. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/runtime.vue.d.ts +8 -0
  49. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/schema.d.ts +99 -0
  50. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/schema.js +129 -0
  51. package/dist/runtime/components/form/unit-config.vue +8 -27
  52. package/dist/runtime/components/form/utils/resolve.d.ts +48 -9
  53. package/dist/runtime/components/form/utils/resolve.js +59 -5
  54. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/config.d.vue.ts +10 -0
  55. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/config.vue +305 -0
  56. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/config.vue.d.ts +10 -0
  57. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/runtime.d.vue.ts +9 -0
  58. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/runtime.vue +81 -0
  59. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/runtime.vue.d.ts +9 -0
  60. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/schema.d.ts +55 -0
  61. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/schema.js +82 -0
  62. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/config.d.vue.ts +10 -0
  63. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/config.vue +310 -0
  64. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/config.vue.d.ts +10 -0
  65. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/runtime.d.vue.ts +9 -0
  66. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/runtime.vue +81 -0
  67. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/runtime.vue.d.ts +9 -0
  68. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/schema.d.ts +66 -0
  69. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/schema.js +71 -0
  70. package/dist/runtime/components/table/config.d.vue.ts +2 -2
  71. package/dist/runtime/components/table/config.vue +7 -46
  72. package/dist/runtime/components/table/config.vue.d.ts +2 -2
  73. package/dist/runtime/components/table/schema.d.ts +9 -2
  74. package/dist/runtime/components/table/schema.js +30 -14
  75. package/dist/runtime/components/table/utils/resolve.d.ts +53 -0
  76. package/dist/runtime/components/table/utils/resolve.js +66 -1
  77. package/dist/runtime/components/ui/date-range-picker/DateRangePickerDateTimePanel.d.vue.ts +1 -1
  78. package/dist/runtime/components/ui/date-range-picker/DateRangePickerDateTimePanel.vue.d.ts +1 -1
  79. package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.d.vue.ts +1 -1
  80. package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.vue.d.ts +1 -1
  81. package/dist/runtime/components/ui/tree/Tree.d.vue.ts +57 -0
  82. package/dist/runtime/components/ui/tree/Tree.vue +325 -0
  83. package/dist/runtime/components/ui/tree/Tree.vue.d.ts +57 -0
  84. package/dist/runtime/components/ui/tree/TreeNode.d.vue.ts +53 -0
  85. package/dist/runtime/components/ui/tree/TreeNode.vue +299 -0
  86. package/dist/runtime/components/ui/tree/TreeNode.vue.d.ts +53 -0
  87. package/dist/runtime/components/ui/tree/index.d.ts +3 -0
  88. package/dist/runtime/components/ui/tree/index.js +2 -0
  89. package/dist/runtime/components/ui/tree/types.d.ts +120 -0
  90. package/dist/runtime/components/ui/tree/types.js +0 -0
  91. package/dist/runtime/components/ui/tree/useTreeState.d.ts +95 -0
  92. package/dist/runtime/components/ui/tree/useTreeState.js +369 -0
  93. package/dist/runtime/shims.d.ts +2 -0
  94. package/package.json +1 -1
  95. package/dist/preview/assets/index-BPKK3hGV.css +0 -1
  96. package/dist/preview/assets/index-D3pf2RjG.js +0 -1
  97. package/dist/preview/assets/index-OUd02U3g.js +0 -1075
  98. package/dist/runtime/components/form/ai/fields-button.d.vue.ts +0 -13
  99. package/dist/runtime/components/form/ai/fields-button.vue +0 -458
  100. package/dist/runtime/components/form/ai/fields-button.vue.d.ts +0 -13
  101. package/dist/runtime/components/form/ai/fields-task.md +0 -71
  102. package/dist/runtime/components/table/ai/columns-button.d.vue.ts +0 -12
  103. package/dist/runtime/components/table/ai/columns-button.vue +0 -491
  104. package/dist/runtime/components/table/ai/columns-button.vue.d.ts +0 -12
  105. package/dist/runtime/components/table/ai/columns-task.md +0 -53
  106. package/dist/runtime/components/table/ai/data-source-button.d.vue.ts +0 -20
  107. package/dist/runtime/components/table/ai/data-source-button.vue +0 -324
  108. package/dist/runtime/components/table/ai/data-source-button.vue.d.ts +0 -20
  109. package/dist/runtime/components/table/ai/data-source-task.md +0 -17
  110. package/dist/runtime/utils/ai/cel-prompt.d.ts +0 -11
  111. package/dist/runtime/utils/ai/cel-prompt.js +0 -27
@@ -0,0 +1,129 @@
1
+ import { Schema } from "effect";
2
+ import { Expression, LocaleMarkdown } from "../../../../../share/expression.js";
3
+ import { Locale } from "../../../../../share/locale.js";
4
+ import { DataSource } from "../../../../table/schema.js";
5
+ import { commonFieldFields, derivedField } from "../../../utils/common.js";
6
+ export const type = "com.shwfed.form.field.tree.multi";
7
+ export const compatibilityDate = "2026-05-23";
8
+ export const metadata = {
9
+ name: "\u6811\uFF08\u591A\u9009\uFF09",
10
+ icon: "fluent:tree-evergreen-20-regular",
11
+ w: { initial: 8, min: 4, max: Infinity },
12
+ h: { initial: 8, min: 4, max: Infinity, grow: true }
13
+ };
14
+ export function schema(configure) {
15
+ const CelBool = Expression({ configure, resultType: "bool" });
16
+ const nodeConfigure = (env) => {
17
+ configure(env);
18
+ env.registerVariable("node", "dyn", { description: "\u5F53\u524D\u8282\u70B9\uFF1B\u7531 `\u6570\u636E` \u8868\u8FBE\u5F0F\u8FD4\u56DE\u7684\u6BCF\u4E00\u9879" });
19
+ };
20
+ const CelNodeKey = Expression({
21
+ configure: nodeConfigure,
22
+ resultType: (t) => t === "string" || t === "number" || t === "dyn"
23
+ });
24
+ const CelNodeChildren = Expression({
25
+ configure: nodeConfigure,
26
+ // Accept lists, optional lists, and `dyn` — CEL infers an empty literal
27
+ // such as `[]` as `list<dyn>` which a strict `list<dyn>` predicate would
28
+ // accept, but a configured expression like `has(node.kids) ? node.kids :
29
+ // null` lands on `dyn` once one branch is `null`. The looser predicate
30
+ // mirrors the table's `data` expression.
31
+ resultType: (t) => t === "dyn" || t.startsWith("list") || t.startsWith("optional")
32
+ });
33
+ const CelNodeBool = Expression({ configure: nodeConfigure, resultType: "bool" });
34
+ const NodeLocaleMd = LocaleMarkdown({ configure: nodeConfigure });
35
+ const CelKeywords = Expression({
36
+ configure: nodeConfigure,
37
+ // Empty list literals (`[]`) check as `list<dyn>`, and a
38
+ // `node.?keywords` access lands on `optional<dyn>` — accept either by
39
+ // sharing the same loose predicate the data expression uses.
40
+ resultType: (t) => t === "dyn" || t.startsWith("list") || t.startsWith("optional")
41
+ });
42
+ return Schema.Struct({
43
+ type: Schema.Literal(type),
44
+ compatibilityDate: Schema.Literal(compatibilityDate),
45
+ ...commonFieldFields(configure),
46
+ label: Schema.optional(Locale.annotations({
47
+ title: "\u6807\u7B7E",
48
+ description: "\u5B57\u6BB5\u524D\u5C55\u793A\u7684\u6587\u672C\uFF1B\u7559\u7A7A\u5219\u4E0D\u6E32\u67D3\u6807\u7B7E"
49
+ })),
50
+ tooltip: Schema.optional(Locale.annotations({
51
+ title: "\u63D0\u793A",
52
+ description: "\u9F20\u6807\u60AC\u505C\u5728\u6807\u7B7E\u4E0A\u65F6\u5C55\u793A\u7684\u8BF4\u660E"
53
+ })),
54
+ binding: Schema.optional(Schema.String.pipe(Schema.minLength(1)).annotations({
55
+ title: "\u7ED1\u5B9A\u8DEF\u5F84",
56
+ description: "\u5199\u5165\u8868\u5355\u72B6\u6001\u7684 `dot-prop` \u8DEF\u5F84\uFF1B\u5199\u5165\u503C\u4E3A\u5DF2\u52FE\u9009\u8282\u70B9 ID \u7684\u6570\u7EC4\uFF1B\u7559\u7A7A\u5219\u4E3A\u975E\u53D7\u63A7\u5B57\u6BB5"
57
+ })),
58
+ disabled: Schema.optional(CelBool.annotations({
59
+ title: "\u7981\u7528\u6761\u4EF6",
60
+ description: "\u8FD4\u56DE `true` \u65F6\u4ECD\u6E32\u67D3\u4F46\u4E0D\u53EF\u52FE\u9009"
61
+ })),
62
+ readonly: Schema.optional(CelBool.annotations({
63
+ title: "\u53EA\u8BFB\u6761\u4EF6",
64
+ description: "\u8FD4\u56DE `true` \u65F6\u4EC5\u4EE5\u7EAF\u6587\u672C\u5C55\u793A\u5F53\u524D\u5DF2\u52FE\u9009\u8282\u70B9\u7684\u6807\u7B7E"
65
+ })),
66
+ derived: derivedField(configure, "dyn"),
67
+ dataSource: DataSource(configure).annotations({
68
+ title: "\u6570\u636E\u6E90",
69
+ description: "\u8FD4\u56DE\u5B8C\u6574\u6811\uFF08\u6839\u8282\u70B9\u5217\u8868\uFF09\u7684\u6570\u636E\u6E90\uFF1B\u6811\u901A\u8FC7 `\u8282\u70B9\u5B50\u7EA7` \u8868\u8FBE\u5F0F\u9010\u5C42\u5411\u4E0B\u8BFB\u53D6\u5B50\u7EA7"
70
+ }),
71
+ nodeKey: CelNodeKey.annotations({
72
+ title: "\u8282\u70B9 ID",
73
+ description: "\u4E3A\u6BCF\u4E2A\u8282\u70B9\u8BA1\u7B97\u7A33\u5B9A\u552F\u4E00 ID \u7684 CEL \u8868\u8FBE\u5F0F\uFF0C\u53EF\u8BBF\u95EE `node`\uFF1B\u8FD0\u884C\u65F6\u4EE5\u5B57\u7B26\u4E32\u5F62\u5F0F\u5B58\u50A8"
74
+ }),
75
+ nodeChildren: CelNodeChildren.annotations({
76
+ title: "\u8282\u70B9\u5B50\u7EA7",
77
+ description: "\u8FD4\u56DE\u5F53\u524D\u8282\u70B9\u7684\u5B50\u7EA7\u5217\u8868\u7684 CEL \u8868\u8FBE\u5F0F\uFF1B\u8FD4\u56DE `none` / `null` \u89C6\u4E3A\u53F6\u5B50\u8282\u70B9"
78
+ }),
79
+ nodeLabel: NodeLocaleMd.annotations({
80
+ title: "\u8282\u70B9\u6807\u7B7E",
81
+ description: "\u8282\u70B9\u5C55\u793A\u7684\u672C\u5730\u5316\u6587\u672C\uFF0C\u652F\u6301 Markdown \u4E0E `{{ node.foo }}` / `{{ form.foo }}` \u63D2\u503C"
82
+ }),
83
+ nodeTooltip: Schema.optional(NodeLocaleMd.annotations({
84
+ title: "\u8282\u70B9\u63D0\u793A",
85
+ description: "\u9F20\u6807\u60AC\u505C\u5728\u8282\u70B9\u4E0A\u65F6\u5C55\u793A\u7684\u672C\u5730\u5316\u63D0\u793A\uFF0C\u652F\u6301 Markdown \u4E0E\u63D2\u503C"
86
+ })),
87
+ nodeSelectable: Schema.optional(CelNodeBool.annotations({
88
+ title: "\u8282\u70B9\u53EF\u9009\u6761\u4EF6",
89
+ description: "\u8FD4\u56DE `true` \u8868\u793A\u8BE5\u8282\u70B9\u53EF\u88AB\u52FE\u9009\uFF1B\u7EA7\u8054\u9009\u62E9\u4ECD\u5C0A\u91CD\u8BE5\u6761\u4EF6"
90
+ })),
91
+ cascade: Schema.optionalWith(Schema.Literal("independent", "cascade-down", "cascade-both"), {
92
+ default: () => "cascade-both"
93
+ }).annotations({
94
+ title: "\u7EA7\u8054\u6A21\u5F0F",
95
+ description: "`\u72EC\u7ACB`\uFF1A\u4EC5\u52FE\u9009\u5F53\u524D\u8282\u70B9\uFF1B`\u5411\u4E0B\u7EA7\u8054`\uFF1A\u52FE\u9009\u7236\u8282\u70B9\u540C\u65F6\u52FE\u9009\u6240\u6709\u53EF\u9009\u540E\u4EE3\uFF1B`\u53CC\u5411\u7EA7\u8054`\uFF1A\u5728\u5411\u4E0B\u7EA7\u8054\u57FA\u7840\u4E0A\uFF0C\u7236\u8282\u70B9\u53CD\u6620\u540E\u4EE3\u52FE\u9009\u72B6\u6001\uFF08\u90E8\u5206\u9009\u4E2D\u663E\u793A\u4E3A\u534A\u9009\uFF09"
96
+ }),
97
+ expandAll: Schema.optionalWith(Schema.Boolean, { default: () => false }).annotations({
98
+ title: "\u9ED8\u8BA4\u5168\u90E8\u5C55\u5F00",
99
+ description: "\u5F00\u542F\u540E\u6302\u8F7D\u65F6\u5C55\u5F00\u6240\u6709\u975E\u53F6\u5B50\u8282\u70B9"
100
+ }),
101
+ filter: Schema.optional(Schema.Struct({
102
+ enabled: Schema.Boolean.annotations({ title: "\u542F\u7528", description: "\u662F\u5426\u5728\u6811\u4E0A\u65B9\u663E\u793A\u641C\u7D22\u8F93\u5165\u6846" }),
103
+ label: Schema.optional(Locale.annotations({
104
+ title: "\u6807\u7B7E",
105
+ description: "\u641C\u7D22\u8F93\u5165\u6846\u7684\u6D6E\u52A8\u6807\u7B7E\uFF1B\u7559\u7A7A\u5219\u4F7F\u7528\u9ED8\u8BA4\u503C\u300C\u641C\u7D22\u300D"
106
+ })),
107
+ keywords: Schema.optional(CelKeywords.annotations({
108
+ title: "\u989D\u5916\u5173\u952E\u8BCD",
109
+ description: "\u8FD4\u56DE\u5B57\u7B26\u4E32\u5217\u8868\u7684 CEL \u8868\u8FBE\u5F0F\uFF0C\u53EF\u8BBF\u95EE `node`\uFF1B\u5339\u914D\u89C4\u5219\u4E3A\u300C\u8282\u70B9\u6807\u7B7E \u6216 \u4EFB\u4E00\u5173\u952E\u8BCD\u300D\u5305\u542B\u641C\u7D22\u8BCD\uFF08\u4E0D\u533A\u5206\u5927\u5C0F\u5199\uFF09"
110
+ }))
111
+ }).annotations({
112
+ title: "\u8FC7\u6EE4",
113
+ description: "\u5BA2\u6237\u7AEF\u8FC7\u6EE4\uFF1B\u8FC7\u6EE4\u4E0D\u4F1A\u5F71\u54CD\u5DF2\u9009\u4E2D\u7684\u8282\u70B9 ID"
114
+ }))
115
+ }).annotations({
116
+ title: "TreeMultiField",
117
+ description: "\u57FA\u4E8E\u6811\u5F62\u6570\u636E\u7684\u591A\u9009\u8F93\u5165"
118
+ });
119
+ }
120
+ export function defaults() {
121
+ return {
122
+ dataSource: { data: "[]" },
123
+ nodeKey: "string(node.id)",
124
+ nodeChildren: "has(node.children) ? node.children : null",
125
+ nodeLabel: [{ locale: "zh", message: "{{ node.label }}" }],
126
+ cascade: "cascade-both",
127
+ expandAll: false
128
+ };
129
+ }
@@ -21,7 +21,6 @@ import { Button } from "../ui/button";
21
21
  import { ScrollArea } from "../ui/scroll-area";
22
22
  import { Separator } from "../ui/separator";
23
23
  import { FIELDS, findField } from "./utils/resolve";
24
- import ShwfedFormAiFieldsButton from "./ai/fields-button.vue";
25
24
  defineOptions({ name: "ShwfedFormUnitConfig" });
26
25
  const unit = defineModel({ type: Object, ...{ required: true } });
27
26
  const selection = defineModel("selection", { type: Object, ...{
@@ -90,6 +89,7 @@ function addLayout() {
90
89
  const FIELD_PICKER_ENTRIES = computed(() => {
91
90
  const byType = /* @__PURE__ */ new Map();
92
91
  for (const f of FIELDS) {
92
+ if (f.deprecated) continue;
93
93
  const prev = byType.get(f.type);
94
94
  if (!prev || f.compatibilityDate > prev.compatibilityDate) {
95
95
  byType.set(f.type, {
@@ -176,16 +176,6 @@ function removeFields(ids) {
176
176
  stack.value = stack.value.slice(0, -1);
177
177
  }
178
178
  }
179
- function applyAiFields(generated) {
180
- const valid = generated.filter(
181
- (f) => !!findField(f.type, f.compatibilityDate)
182
- );
183
- if (valid.length === 0) return;
184
- unit.value = {
185
- ...unit.value,
186
- fields: [...unit.value.fields, ...valid]
187
- };
188
- }
189
179
  function updateActiveField(next) {
190
180
  const id = activeFieldId.value;
191
181
  if (!id) return;
@@ -203,7 +193,7 @@ const migrationContext = { $cel: celForMigration };
203
193
  const latestEntry = computed(() => {
204
194
  const e = activeFieldEntry.value;
205
195
  if (!e?.deprecated || !e.supersededBy) return null;
206
- return findField(e.type, e.supersededBy) ?? null;
196
+ return findField(e.supersededBy.type, e.supersededBy.compatibilityDate) ?? null;
207
197
  });
208
198
  const canMigrate = computed(() => !!latestEntry.value?.migrate);
209
199
  async function migrateActiveField() {
@@ -213,7 +203,10 @@ async function migrateActiveField() {
213
203
  try {
214
204
  const next = await Effect.runPromise(target.migrate(sel, migrationContext));
215
205
  updateActiveField(next);
216
- toast.success(`\u5DF2\u8FC1\u79FB\u5230 ${target.compatibilityDate} \u7248\u672C`);
206
+ const isSameType = target.type === sel.type;
207
+ toast.success(
208
+ isSameType ? `\u5DF2\u8FC1\u79FB\u5230 ${target.compatibilityDate} \u7248\u672C` : `\u5DF2\u8FC1\u79FB\u5230 ${target.type}@${target.compatibilityDate}`
209
+ );
217
210
  } catch (err) {
218
211
  const message = err instanceof Error ? err.message : String(err);
219
212
  toast.error("\u8FC1\u79FB\u5931\u8D25", { description: message });
@@ -326,12 +319,6 @@ function isExtraActive(id) {
326
319
  </button>
327
320
  </div>
328
321
  </ScrollArea>
329
-
330
- <ShwfedFormAiFieldsButton
331
- :configure="configure"
332
- :fields="unit.fields"
333
- @apply="applyAiFields"
334
- />
335
322
  </template>
336
323
  </Teleport>
337
324
 
@@ -409,12 +396,6 @@ function isExtraActive(id) {
409
396
  </button>
410
397
  </div>
411
398
  </ScrollArea>
412
-
413
- <ShwfedFormAiFieldsButton
414
- :configure="configure"
415
- :fields="unit.fields"
416
- @apply="applyAiFields"
417
- />
418
399
  </template>
419
400
  </div>
420
401
 
@@ -466,7 +447,7 @@ function isExtraActive(id) {
466
447
  v-if="activeFieldEntry"
467
448
  >
468
449
  <div
469
- v-if="activeFieldEntry.deprecated"
450
+ v-if="activeFieldEntry.deprecated && activeFieldEntry.supersededBy"
470
451
  class="mb-4 flex items-center gap-2 rounded border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800"
471
452
  role="alert"
472
453
  >
@@ -475,7 +456,7 @@ function isExtraActive(id) {
475
456
  class="size-4 shrink-0"
476
457
  />
477
458
  <span class="flex-1">
478
- 此字段类型已弃用,建议迁移至 <span class="tabular-nums font-medium">{{ activeFieldEntry.supersededBy }}</span> 版本。
459
+ 此字段类型已弃用,建议迁移至 <span class="tabular-nums font-medium">{{ activeFieldEntry.supersededBy.type === activeFieldEntry.type ? activeFieldEntry.supersededBy.compatibilityDate : `${activeFieldEntry.supersededBy.type}@${activeFieldEntry.supersededBy.compatibilityDate}` }}</span>。
479
460
  </span>
480
461
  <Button
481
462
  v-if="canMigrate"
@@ -13,12 +13,29 @@ export type MigrationContext = Readonly<{
13
13
  $cel: <T>(expression: string, context?: Record<string, unknown>) => Effect.Effect<T, unknown>;
14
14
  }>;
15
15
  /**
16
- * Migrates a value of the previous compatibilityDate's schema to this entry's
17
- * schema. Lives on the *target* (newer) entry. The Effect's success channel
18
- * is the migrated value; failures surface to the host as a toast — see
16
+ * Migrates a value of a source schema to this entry's schema. Lives on the
17
+ * target (newer) entry. The Effect's success channel is the migrated value;
18
+ * failures surface to the host as a toast — see
19
19
  * src/runtime/components/form/config.vue's migrate handler.
20
+ *
21
+ * The target is selected by one of two rules: (a) same `type` with a strictly
22
+ * newer `compatibilityDate`, or (b) an explicit `migrateFrom` declaration on
23
+ * the target naming this source `(type, compatibilityDate)`. Either way the
24
+ * migrate function only sees the previous value and the host capabilities.
20
25
  */
21
26
  export type MigrateFn = (prev: unknown, ctx: MigrationContext) => Effect.Effect<unknown, Error>;
27
+ /**
28
+ * Identifies an entry by `(type, compatibilityDate)`. Used for `migrateFrom`
29
+ * declarations on a target, and for the cross-type form of `supersededBy`
30
+ * exposed on a deprecated entry.
31
+ *
32
+ * Migration declarations only ever live on the *new* (target) code — old
33
+ * folders are never modified to announce that they have been superseded.
34
+ */
35
+ export type MigrateSource = Readonly<{
36
+ type: string;
37
+ compatibilityDate: string;
38
+ }>;
22
39
  export type FieldSizeRange = Readonly<{
23
40
  /** Span (in step units) used when the field is first placed. */
24
41
  initial: number;
@@ -54,16 +71,25 @@ export type FieldEntry = Readonly<{
54
71
  schema: SchemaFactory;
55
72
  config: Component;
56
73
  runtime: Component;
57
- /** True iff a newer entry with the same `type` exists in the registry. */
74
+ /**
75
+ * True iff this entry is shadowed by either (a) a newer-date entry sharing
76
+ * its `type`, or (b) another entry whose `migrateFrom` names this one.
77
+ */
58
78
  deprecated: boolean;
59
- /** `compatibilityDate` of the newest entry sharing this `type`, when deprecated. */
60
- supersededBy?: string;
61
79
  /**
62
- * Optional migration from the previous compatibilityDate's schema to this
63
- * entry's schema. When present, the host renders a "迁移" button on
64
- * deprecated fields whose superseding entry exposes this function.
80
+ * Identifies the entry that supersedes this one. Same `type` for the
81
+ * date-versioned rule; a different `type` for declared cross-type
82
+ * migrations.
83
+ */
84
+ supersededBy?: MigrateSource;
85
+ /**
86
+ * Optional migration from a recognized source schema to this entry's
87
+ * schema. When present, the host renders a "迁移" button on deprecated
88
+ * entries whose target exposes this function.
65
89
  */
66
90
  migrate?: MigrateFn;
91
+ /** Source schemas this entry accepts migration from. See module field. */
92
+ migrateFrom?: ReadonlyArray<MigrateSource>;
67
93
  /**
68
94
  * Optional creation-time defaults. The host merges the returned partial
69
95
  * onto the seed when the user adds a new field via the picker. Absent →
@@ -74,4 +100,17 @@ export type FieldEntry = Readonly<{
74
100
  export declare const FIELDS: ReadonlyArray<FieldEntry>;
75
101
  export declare function allFieldSchemas(configure: (env: Environment) => void): ReadonlyArray<AnySchema>;
76
102
  export declare function findField(type: string, compatibilityDate: string): FieldEntry | undefined;
103
+ /**
104
+ * Finds the registry entry that has declared `(type, compatibilityDate)` as a
105
+ * migration source on its `migrateFrom`. Use when a stored value's identity
106
+ * no longer matches any registry entry (the old folder was renamed away) —
107
+ * a present return means the value is still migratable via the target's
108
+ * `migrate`.
109
+ *
110
+ * Note: for the date-versioned rule (same `type`, newer `compatibilityDate`)
111
+ * the entry itself is in the registry and tagged `deprecated`/`supersededBy`;
112
+ * callers reach the target through `findField(supersededBy.type, …)` rather
113
+ * than this function.
114
+ */
115
+ export declare function findMigrationTarget(type: string, compatibilityDate: string): FieldEntry | undefined;
77
116
  export {};
@@ -11,28 +11,76 @@ const runtimeModules = import.meta.glob(
11
11
  "../fields/*/*/runtime.vue",
12
12
  { eager: true, import: "default", exhaustive: true }
13
13
  );
14
+ const sourceKey = (type, compatibilityDate) => `${type}@${compatibilityDate}`;
14
15
  const registry = defineRegistry({
15
16
  hostName: "shwfed-form",
16
17
  dirSegment: "fields",
17
18
  schemaModules,
18
19
  configModules,
19
20
  runtimeModules,
20
- // An entry is deprecated iff another entry shares its `type` with a strictly
21
- // greater `compatibilityDate`. The picker already shows only the latest per
22
- // type; this flag drives the deprecation alert in the right-pane inspector.
21
+ // An entry is deprecated by one of two rules:
22
+ // (a) another entry shares its `type` with a strictly greater
23
+ // `compatibilityDate` date-versioned supersession;
24
+ // (b) another entry declares this one in its `migrateFrom` — explicit
25
+ // cross-type supersession (rename, split, merge).
26
+ // Rule (a) wins on overlap, since the date-versioned rule is the implicit
27
+ // convention; an explicit `migrateFrom` against a still-current entry is
28
+ // almost always a mistake, but we let it slide as long as no two targets
29
+ // claim the same source (that collision throws below).
23
30
  deriveEntryExtras: (drafts) => {
24
31
  const latestByType = /* @__PURE__ */ new Map();
25
32
  for (const d of drafts) {
26
33
  const prev = latestByType.get(d.type);
27
34
  if (!prev || d.compatibilityDate > prev) latestByType.set(d.type, d.compatibilityDate);
28
35
  }
36
+ const migrationTargets = /* @__PURE__ */ new Map();
37
+ for (const d of drafts) {
38
+ const sources = d.module.migrateFrom;
39
+ if (!sources || sources.length === 0) continue;
40
+ for (const src of sources) {
41
+ const key = sourceKey(src.type, src.compatibilityDate);
42
+ const existing = migrationTargets.get(key);
43
+ if (existing) {
44
+ throw new Error(
45
+ `[shwfed-form] migrateFrom collision: source "${key}" is claimed by both "${sourceKey(existing.type, existing.compatibilityDate)}" and "${sourceKey(d.type, d.compatibilityDate)}"`
46
+ );
47
+ }
48
+ migrationTargets.set(key, { type: d.type, compatibilityDate: d.compatibilityDate });
49
+ }
50
+ }
29
51
  return (draft) => {
52
+ const declared = migrationTargets.get(sourceKey(draft.type, draft.compatibilityDate));
53
+ if (declared) {
54
+ return { deprecated: true, supersededBy: declared };
55
+ }
30
56
  const latest = latestByType.get(draft.type);
31
- const deprecated = draft.compatibilityDate < latest;
32
- return deprecated ? { deprecated: true, supersededBy: latest } : { deprecated: false };
57
+ if (draft.compatibilityDate < latest) {
58
+ return {
59
+ deprecated: true,
60
+ supersededBy: { type: draft.type, compatibilityDate: latest }
61
+ };
62
+ }
63
+ return { deprecated: false };
33
64
  };
34
65
  }
35
66
  });
67
+ let _migrationTargets = null;
68
+ function getMigrationTargets() {
69
+ if (_migrationTargets) return _migrationTargets;
70
+ const map = /* @__PURE__ */ new Map();
71
+ for (const entry of registry.ENTRIES) {
72
+ const sources = entry.module.migrateFrom;
73
+ if (!sources || sources.length === 0) continue;
74
+ for (const src of sources) {
75
+ map.set(sourceKey(src.type, src.compatibilityDate), {
76
+ type: entry.type,
77
+ compatibilityDate: entry.compatibilityDate
78
+ });
79
+ }
80
+ }
81
+ _migrationTargets = map;
82
+ return map;
83
+ }
36
84
  let _fields = null;
37
85
  function getFields() {
38
86
  if (_fields) return _fields;
@@ -46,6 +94,7 @@ function getFields() {
46
94
  deprecated: e.deprecated,
47
95
  ...e.supersededBy !== void 0 ? { supersededBy: e.supersededBy } : {},
48
96
  migrate: e.module.migrate,
97
+ ...e.module.migrateFrom !== void 0 ? { migrateFrom: e.module.migrateFrom } : {},
49
98
  defaults: e.module.defaults
50
99
  }));
51
100
  return _fields;
@@ -72,3 +121,8 @@ export function allFieldSchemas(configure) {
72
121
  export function findField(type, compatibilityDate) {
73
122
  return getFields().find((f) => f.type === type && f.compatibilityDate === compatibilityDate);
74
123
  }
124
+ export function findMigrationTarget(type, compatibilityDate) {
125
+ const target = getMigrationTargets().get(sourceKey(type, compatibilityDate));
126
+ if (!target) return void 0;
127
+ return findField(target.type, target.compatibilityDate);
128
+ }
@@ -0,0 +1,10 @@
1
+ type __VLS_ModelProps = {
2
+ modelValue: Record<string, any>;
3
+ };
4
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
5
+ "update:modelValue": (value: Record<string, any>) => any;
6
+ }, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
7
+ "onUpdate:modelValue"?: ((value: Record<string, any>) => any) | undefined;
8
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
9
+ declare const _default: typeof __VLS_export;
10
+ export default _default;