@shwfed/config 2.11.4 → 2.11.6

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 (146) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.prototype/config.vue +1 -0
  3. package/dist/runtime/components/actions/config.vue +2 -0
  4. package/dist/runtime/components/form/fields/2026-04-22/com.shwfed.form.field.text/config.d.vue.ts +22 -22
  5. package/dist/runtime/components/form/fields/2026-04-22/com.shwfed.form.field.text/config.vue.d.ts +22 -22
  6. package/dist/runtime/components/form/fields/2026-04-24/com.shwfed.form.field.combobox.single/config.d.vue.ts +16 -16
  7. package/dist/runtime/components/form/fields/2026-04-24/com.shwfed.form.field.combobox.single/config.vue.d.ts +16 -16
  8. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.date/config.d.vue.ts +16 -16
  9. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.date/config.vue.d.ts +16 -16
  10. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +18 -18
  11. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +18 -18
  12. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/config.d.vue.ts +16 -16
  13. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetime/config.vue.d.ts +16 -16
  14. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +18 -18
  15. package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +18 -18
  16. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.number/config.d.vue.ts +28 -28
  17. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.number/config.vue.d.ts +28 -28
  18. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/config.d.vue.ts +6 -6
  19. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/config.vue.d.ts +6 -6
  20. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.switch/config.d.vue.ts +22 -22
  21. package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.switch/config.vue.d.ts +22 -22
  22. package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/config.d.vue.ts +16 -16
  23. package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/config.vue.d.ts +16 -16
  24. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.d.vue.ts +8 -8
  25. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.vue.d.ts +8 -8
  26. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.month/config.d.vue.ts +16 -16
  27. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.month/config.vue.d.ts +16 -16
  28. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.d.vue.ts +18 -18
  29. package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.vue.d.ts +18 -18
  30. package/dist/runtime/components/form/fields/2026-05-25/com.shwfed.form.field.combobox.multi/config.d.vue.ts +16 -16
  31. package/dist/runtime/components/form/fields/2026-05-25/com.shwfed.form.field.combobox.multi/config.vue.d.ts +16 -16
  32. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.d.vue.ts +8 -8
  33. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.vue.d.ts +8 -8
  34. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.d.vue.ts +8 -8
  35. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.vue.d.ts +8 -8
  36. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.d.vue.ts +8 -8
  37. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.vue.d.ts +8 -8
  38. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.d.vue.ts +8 -8
  39. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.vue.d.ts +8 -8
  40. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.d.vue.ts +8 -8
  41. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.vue.d.ts +8 -8
  42. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.d.vue.ts +8 -8
  43. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.vue.d.ts +8 -8
  44. package/dist/runtime/components/table/columns/2026-04-14/com.shwfed.table.column.icon/runtime.vue +3 -4
  45. package/dist/runtime/components/table/columns/2026-04-14/com.shwfed.table.column.markdown/runtime.vue +3 -3
  46. package/dist/runtime/components/table/columns/2026-04-14/com.shwfed.table.column.select/runtime.vue +2 -2
  47. package/dist/runtime/components/table/columns/2026-04-14/com.shwfed.table.column.text/runtime.vue +2 -2
  48. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch/runtime.vue +5 -6
  49. package/dist/runtime/components/table/columns/2026-05-13/com.shwfed.table.column.switch.remote/runtime.vue +5 -6
  50. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.combobox-single/runtime.vue +2 -2
  51. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.number-input/runtime.vue +2 -2
  52. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch/runtime.vue +2 -2
  53. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.switch.local/runtime.vue +2 -2
  54. package/dist/runtime/components/table/columns/2026-05-20/com.shwfed.table.column.text-input/runtime.vue +2 -2
  55. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.d.vue.ts +6 -6
  56. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.vue.d.ts +6 -6
  57. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/runtime.vue +2 -2
  58. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/runtime.vue +2 -2
  59. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi/runtime.vue +2 -2
  60. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.d.vue.ts +6 -6
  61. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.vue.d.ts +6 -6
  62. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/runtime.vue +2 -2
  63. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/runtime.vue +2 -2
  64. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi/runtime.vue +2 -2
  65. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/runtime.vue +2 -2
  66. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single/runtime.vue +2 -2
  67. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/runtime.vue +2 -2
  68. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +8 -8
  69. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +8 -8
  70. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/runtime.vue +2 -2
  71. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +8 -8
  72. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +8 -8
  73. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/runtime.vue +2 -2
  74. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/runtime.vue +2 -2
  75. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/runtime.vue +2 -2
  76. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +8 -8
  77. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +8 -8
  78. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/runtime.vue +2 -2
  79. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +8 -8
  80. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +8 -8
  81. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/runtime.vue +2 -2
  82. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-multi/runtime.vue +7 -3
  83. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-single/runtime.vue +7 -3
  84. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +8 -8
  85. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +8 -8
  86. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-multi/runtime.vue +2 -2
  87. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +8 -8
  88. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +8 -8
  89. package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-single/runtime.vue +2 -2
  90. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/config.vue +81 -2
  91. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/runtime.vue +38 -4
  92. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/schema.d.ts +132 -0
  93. package/dist/runtime/components/table/columns/2026-06-17/com.shwfed.table.column.date-input/schema.js +28 -2
  94. package/dist/runtime/components/table/columns/2026-06-22/com.shwfed.table.column.date-range-input/runtime.vue +4 -4
  95. package/dist/runtime/components/table/config.vue +1 -0
  96. package/dist/runtime/components/table/row-provider.vue +2 -2
  97. package/dist/runtime/components/ui/alert-dialog/AlertDialogFooter.vue +1 -1
  98. package/dist/runtime/components/ui/date-picker/DatePicker.d.vue.ts +11 -1
  99. package/dist/runtime/components/ui/date-picker/DatePicker.vue +8 -1
  100. package/dist/runtime/components/ui/date-picker/DatePicker.vue.d.ts +11 -1
  101. package/dist/runtime/components/ui/date-picker/DatePickerInput.d.vue.ts +11 -1
  102. package/dist/runtime/components/ui/date-picker/DatePickerInput.vue +4 -0
  103. package/dist/runtime/components/ui/date-picker/DatePickerInput.vue.d.ts +11 -1
  104. package/dist/runtime/utils/cel-context.d.ts +1 -0
  105. package/dist/runtime/utils/cel-context.js +28 -0
  106. package/dist/runtime/vendor/cel-js/CLAUDE.md +1 -1
  107. package/dist/runtime/vendor/cel-js/PROMPT.md +7 -0
  108. package/dist/runtime/vendor/cel-js/lib/functions.js +25 -1
  109. package/package.json +3 -8
  110. package/dist/mcp.mjs +0 -102267
  111. package/dist/preview/assets/FieldGroup.vue_vue_type_script_setup_true_lang-BE68tZWF.js +0 -1
  112. package/dist/preview/assets/badge-CGMjdhLX.js +0 -1
  113. package/dist/preview/assets/config-B7TZ-128.js +0 -1
  114. package/dist/preview/assets/config-BSym_jQg.js +0 -1
  115. package/dist/preview/assets/config-ByCFJbd-.js +0 -1
  116. package/dist/preview/assets/config-C4cv2S64.js +0 -1
  117. package/dist/preview/assets/config-ChrJHusi.js +0 -1
  118. package/dist/preview/assets/config-CxbYENZ0.js +0 -1
  119. package/dist/preview/assets/config-DFS2XL3-.js +0 -1
  120. package/dist/preview/assets/config-DWj1CTai.js +0 -1
  121. package/dist/preview/assets/config-DZI21_UB.js +0 -1
  122. package/dist/preview/assets/config-D_O4ACtH.js +0 -1
  123. package/dist/preview/assets/config-DjA8bfLm.js +0 -1
  124. package/dist/preview/assets/config-DwPGLI3R.js +0 -1
  125. package/dist/preview/assets/config-dkVvsr4h.js +0 -1
  126. package/dist/preview/assets/config-hsH0bSZh.js +0 -1
  127. package/dist/preview/assets/config-xrfje67L.js +0 -1
  128. package/dist/preview/assets/definition.vue_vue_type_script_setup_true_lang-BGk00yfB.js +0 -1
  129. package/dist/preview/assets/index-B4oT9ZrQ.js +0 -1
  130. package/dist/preview/assets/index-BSQlKkJR.js +0 -775
  131. package/dist/preview/assets/index-CzQKNngS.js +0 -1
  132. package/dist/preview/assets/index-DPFQgj9g.css +0 -1
  133. package/dist/preview/assets/item-D4gmvDO-.js +0 -1
  134. package/dist/preview/assets/runtime--e0UxK6b.js +0 -1
  135. package/dist/preview/assets/runtime-BWH8ForT.js +0 -1
  136. package/dist/preview/assets/runtime-BgO2briD.js +0 -1
  137. package/dist/preview/assets/runtime-BmEP7xID.js +0 -1
  138. package/dist/preview/assets/runtime-C66GF-2d.js +0 -1
  139. package/dist/preview/assets/runtime-CJCOS6D_.js +0 -1
  140. package/dist/preview/assets/runtime-CREolKJd.js +0 -1
  141. package/dist/preview/assets/runtime-CjU46djh.js +0 -1
  142. package/dist/preview/assets/runtime-e59FkBkL.js +0 -1
  143. package/dist/preview/assets/runtime-pYLX1Bb-.js +0 -1
  144. package/dist/preview/assets/runtime-wvP7jhBK.js +0 -1
  145. package/dist/preview/assets/schema-meta-C4Ttq3eE.js +0 -1
  146. package/dist/preview/index.html +0 -19
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { computed } from "vue";
2
+ import { computed, inject, onBeforeUnmount, ref, watch } from "vue";
3
3
  import { Icon } from "@iconify/vue";
4
4
  import { format as formatDate } from "date-fns";
5
5
  import { ExpressionEditor } from "../../../../ui/expression-editor";
@@ -22,9 +22,13 @@ import {
22
22
  DropdownMenuItem,
23
23
  DropdownMenuTrigger
24
24
  } from "../../../../ui/dropdown-menu";
25
+ import ActionsConfigEditor from "../../../../actions/config.vue";
25
26
  import { getStructFieldDescription, getStructFieldTitle } from "../../../utils/schema-meta";
26
27
  import { Markdown } from "../../../../ui/markdown";
27
28
  import DerivedValueEditor from "../../../../form/DerivedValueEditor.vue";
29
+ import { TABLE_COLUMN_LAYOUT_KEY } from "../../../column-layout";
30
+ import { BREADCRUMB_EXTENSION_KEY } from "../../../../config/breadcrumb-extension";
31
+ import { registerRowVariablesIfAbsent } from "../../../utils/shared";
28
32
  import { presetSchema, schema } from "./schema";
29
33
  defineOptions({ name: "ShwfedTableDateInputRendererConfig" });
30
34
  const value = defineModel({ type: Object, ...{ required: true } });
@@ -48,6 +52,47 @@ const ROW_VARS = {
48
52
  row: { type: "dyn", label: "\u5F53\u524D\u884C\u6570\u636E" },
49
53
  index: { type: "number", label: "\u884C\u7D22\u5F15" }
50
54
  };
55
+ const layout = inject(TABLE_COLUMN_LAYOUT_KEY, null);
56
+ const breadcrumbExt = inject(BREADCRUMB_EXTENSION_KEY, null);
57
+ const editingAddon = ref(false);
58
+ function closeAddon() {
59
+ editingAddon.value = false;
60
+ }
61
+ const addonCrumb = breadcrumbExt?.add();
62
+ watch(editingAddon, (on) => {
63
+ if (layout) layout.fullPane.value = on;
64
+ if (addonCrumb) {
65
+ addonCrumb.label.value = on ? "\u8F93\u5165\u6846\u5185\u6309\u94AE" : null;
66
+ addonCrumb.back.value = on ? closeAddon : null;
67
+ }
68
+ });
69
+ onBeforeUnmount(() => {
70
+ if (layout) layout.fullPane.value = false;
71
+ addonCrumb?.dispose();
72
+ });
73
+ const addonItemCount = computed(() => value.value.addon?.items.length ?? 0);
74
+ const addonValue = computed({
75
+ get: () => ({
76
+ kind: "shwfed.component.action",
77
+ size: value.value.addon?.size ?? "xs",
78
+ gap: value.value.addon?.gap ?? 4,
79
+ style: value.value.addon?.style,
80
+ groups: value.value.addon?.groups ?? [],
81
+ items: value.value.addon?.items ?? []
82
+ }),
83
+ set: (next) => {
84
+ const { size, gap, style, groups, items } = next;
85
+ if (groups.length === 0 && items.length === 0) {
86
+ const { addon: _omit, ...rest } = value.value;
87
+ value.value = rest;
88
+ return;
89
+ }
90
+ value.value = {
91
+ ...value.value,
92
+ addon: { size, gap, groups, items, ...style === void 0 ? {} : { style } }
93
+ };
94
+ }
95
+ });
51
96
  const presets = computed(() => value.value.presets ?? []);
52
97
  function newId() {
53
98
  return typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
@@ -170,7 +215,17 @@ const derivedModel = computed({
170
215
  </script>
171
216
 
172
217
  <template>
173
- <div class="space-y-5">
218
+ <ActionsConfigEditor
219
+ v-if="editingAddon"
220
+ v-model="addonValue"
221
+ :configure="registerRowVariablesIfAbsent"
222
+ hide-size
223
+ />
224
+
225
+ <div
226
+ v-else
227
+ class="space-y-5"
228
+ >
174
229
  <div class="grid grid-cols-2 gap-x-6 gap-y-4">
175
230
  <Field orientation="vertical">
176
231
  <FieldLabel class="text-xs text-zinc-500">
@@ -574,5 +629,29 @@ const derivedModel = computed({
574
629
  </div>
575
630
  </Field>
576
631
  </div>
632
+ <Separator />
633
+ <Field orientation="vertical">
634
+ <FieldLabel class="text-xs text-zinc-500">
635
+ <template
636
+ v-if="fieldDescription('addon')"
637
+ #tooltip
638
+ >
639
+ <Markdown
640
+ :source="fieldDescription('addon')"
641
+ block
642
+ class="prose prose-sm prose-zinc"
643
+ />
644
+ </template>
645
+ {{ fieldTitle("addon") }}
646
+ </FieldLabel>
647
+ <Button
648
+ type="button"
649
+ class="w-full justify-center"
650
+ @click="editingAddon = true"
651
+ >
652
+ <Icon icon="fluent:add-20-regular" />
653
+ <span>{{ addonItemCount > 0 ? "\u914D\u7F6E\u6309\u94AE" : "\u6DFB\u52A0\u6309\u94AE" }}</span>
654
+ </Button>
655
+ </Field>
577
656
  </div>
578
657
  </template>
@@ -4,10 +4,12 @@ import { computed } from "vue";
4
4
  import { useI18n } from "vue-i18n";
5
5
  import { format as formatDate } from "date-fns";
6
6
  import { cel as $cel } from "../../../../../utils/cel";
7
- import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
7
+ import { celScope, injectCELContext } from "../../../../../utils/cel-context";
8
8
  import { useFormReadonly } from "../../../../form/utils/readonly";
9
9
  import { getLocalizedText } from "../../../../../share/locale";
10
10
  import { DATE_PICKER_DEFAULT_FORMATS, DatePicker } from "../../../../ui/date-picker";
11
+ import { InputGroupAddon } from "../../../../ui/input-group";
12
+ import ShwfedActions from "../../../../actions/components/group.vue";
11
13
  import { useFormState } from "../../../../form/utils/state";
12
14
  import { JUSTIFY_CLASS, TEXT_ALIGN_CLASS } from "../../../utils/runtime";
13
15
  defineOptions({ name: "ShwfedTableDateInputRendererRuntime" });
@@ -24,7 +26,7 @@ const placeholderText = computed(
24
26
  function evalBool(expression, label) {
25
27
  if (!expression) return false;
26
28
  try {
27
- return Effect.runSync($cel(expression, celBindings(celContext))) === true;
29
+ return Effect.runSync($cel(expression, celScope(celContext))) === true;
28
30
  } catch (e) {
29
31
  console.error(`[shwfed-table] date-input ${label} failed`, e);
30
32
  return false;
@@ -50,7 +52,7 @@ const shortcuts = computed(() => {
50
52
  name: preset.label,
51
53
  value: () => {
52
54
  try {
53
- const d = Effect.runSync($cel(preset.value, celBindings(celContext)));
55
+ const d = Effect.runSync($cel(preset.value, celScope(celContext)));
54
56
  return formatDate(d, resolvedValueFormat.value);
55
57
  } catch (e) {
56
58
  console.error(`[shwfed-table] date-input preset "${preset.value}" failed`, e);
@@ -59,6 +61,18 @@ const shortcuts = computed(() => {
59
61
  }
60
62
  }));
61
63
  });
64
+ const addonConfig = computed(() => {
65
+ const addon = props.column.addon;
66
+ if (!addon || addon.items.length === 0) return null;
67
+ return {
68
+ kind: "shwfed.component.action",
69
+ size: addon.size ?? "xs",
70
+ gap: addon.gap,
71
+ style: addon.style,
72
+ groups: addon.groups.map((group) => ({ ...group, variant: group.variant ?? "ghost" })),
73
+ items: addon.items
74
+ };
75
+ });
62
76
  const model = computed({
63
77
  get: () => {
64
78
  const v = formState.getAt(props.column.binding);
@@ -111,6 +125,26 @@ const model = computed({
111
125
  :placeholder="placeholderText"
112
126
  :disabled="isDisabled"
113
127
  :shortcuts="shortcuts"
114
- />
128
+ >
129
+ <!-- `mr-[-0.45rem]` mirrors the clear addon's `has-[>button]:mr-[-0.45rem]`
130
+ pull-back: that compensation only fires when the addon's direct child
131
+ is a `<button>`, but `ShwfedActions` roots a `<div>`, so without it the
132
+ `inline-end` `pr-3` would leave a ~12px dead gap before the border. -->
133
+ <template
134
+ v-if="addonConfig"
135
+ #trailing
136
+ >
137
+ <InputGroupAddon
138
+ align="inline-end"
139
+ class="field-addon-actions mr-[-0.45rem]"
140
+ >
141
+ <ShwfedActions :config="addonConfig" />
142
+ </InputGroupAddon>
143
+ </template>
144
+ </DatePicker>
115
145
  </div>
116
146
  </template>
147
+
148
+ <style scoped>
149
+ .field-addon-actions :deep([data-slot=buttons]){align-items:center;gap:.125rem}.field-addon-actions :deep([data-slot=buttons-dropdown-trigger]),.field-addon-actions :deep([data-slot=buttons-item]){border-radius:.125rem;color:#71717a;height:1rem;min-width:1rem;padding:0}.field-addon-actions :deep([data-slot=buttons-dropdown-trigger] svg),.field-addon-actions :deep([data-slot=buttons-item] svg){height:.75rem;width:.75rem}.field-addon-actions :deep([data-slot=buttons-dropdown-trigger]:hover:not(:disabled)),.field-addon-actions :deep([data-slot=buttons-item]:hover:not(:disabled)){color:#3f3f46}
150
+ </style>
@@ -49,6 +49,138 @@ export declare function schema(configure: (env: Environment) => void): Schema.St
49
49
  }>]>;
50
50
  value: Schema.Schema<string, string, never>;
51
51
  }>>>;
52
+ addon: Schema.optional<Schema.Struct<{
53
+ groups: Schema.optionalWith<Schema.Array$<Schema.Struct<{
54
+ id: Schema.refine<string, typeof Schema.String>;
55
+ variant: Schema.optional<Schema.Literal<["default", "primary", "destructive", "ghost", "link"]>>;
56
+ }>>, {
57
+ default: () => never[];
58
+ }>;
59
+ items: Schema.optionalWith<Schema.Array$<Schema.Schema<import("../../../../actions/schema.js").RegistryItemValue | {
60
+ readonly disabled?: string | undefined;
61
+ readonly id: string;
62
+ readonly title: readonly [{
63
+ readonly locale: "zh";
64
+ readonly message: string;
65
+ }, ...{
66
+ readonly locale: "en" | "ja" | "ko";
67
+ readonly message: string;
68
+ }[]];
69
+ readonly icon?: string | undefined;
70
+ readonly hidden?: string | undefined;
71
+ readonly tooltip?: readonly [{
72
+ readonly locale: "zh";
73
+ readonly message: string;
74
+ }, ...{
75
+ readonly locale: "en" | "ja" | "ko";
76
+ readonly message: string;
77
+ }[]] | undefined;
78
+ readonly variant?: "default" | "link" | "destructive" | "primary" | "ghost" | undefined;
79
+ readonly action?: any;
80
+ readonly groupId: string;
81
+ readonly hideTitle?: boolean | undefined;
82
+ } | {
83
+ readonly id: string;
84
+ readonly title: readonly [{
85
+ readonly locale: "zh";
86
+ readonly message: string;
87
+ }, ...{
88
+ readonly locale: "en" | "ja" | "ko";
89
+ readonly message: string;
90
+ }[]];
91
+ readonly icon?: string | undefined;
92
+ readonly items: readonly (import("../../../../actions/schema.js").RegistrySubItemValue | {
93
+ readonly disabled?: string | undefined;
94
+ readonly id: string;
95
+ readonly title: readonly [{
96
+ readonly locale: "zh";
97
+ readonly message: string;
98
+ }, ...{
99
+ readonly locale: "en" | "ja" | "ko";
100
+ readonly message: string;
101
+ }[]];
102
+ readonly icon?: string | undefined;
103
+ readonly hidden?: string | undefined;
104
+ readonly tooltip?: readonly [{
105
+ readonly locale: "zh";
106
+ readonly message: string;
107
+ }, ...{
108
+ readonly locale: "en" | "ja" | "ko";
109
+ readonly message: string;
110
+ }[]] | undefined;
111
+ readonly variant?: "default" | "link" | "destructive" | "primary" | "ghost" | undefined;
112
+ readonly action?: any;
113
+ })[];
114
+ readonly groupId: string;
115
+ readonly hideTitle?: boolean | undefined;
116
+ }, import("../../../../actions/schema.js").RegistryItemValue | {
117
+ readonly id: string;
118
+ readonly title: readonly [{
119
+ readonly locale: "zh";
120
+ readonly message: string;
121
+ }, ...{
122
+ readonly locale: "en" | "ja" | "ko";
123
+ readonly message: string;
124
+ }[]];
125
+ readonly groupId: string;
126
+ readonly disabled?: string | undefined;
127
+ readonly icon?: string | undefined;
128
+ readonly hidden?: string | undefined;
129
+ readonly tooltip?: readonly [{
130
+ readonly locale: "zh";
131
+ readonly message: string;
132
+ }, ...{
133
+ readonly locale: "en" | "ja" | "ko";
134
+ readonly message: string;
135
+ }[]] | undefined;
136
+ readonly variant?: "default" | "link" | "destructive" | "primary" | "ghost" | undefined;
137
+ readonly action?: any;
138
+ readonly hideTitle?: boolean | undefined;
139
+ } | {
140
+ readonly id: string;
141
+ readonly title: readonly [{
142
+ readonly locale: "zh";
143
+ readonly message: string;
144
+ }, ...{
145
+ readonly locale: "en" | "ja" | "ko";
146
+ readonly message: string;
147
+ }[]];
148
+ readonly items: readonly (import("../../../../actions/schema.js").RegistrySubItemValue | {
149
+ readonly id: string;
150
+ readonly title: readonly [{
151
+ readonly locale: "zh";
152
+ readonly message: string;
153
+ }, ...{
154
+ readonly locale: "en" | "ja" | "ko";
155
+ readonly message: string;
156
+ }[]];
157
+ readonly disabled?: string | undefined;
158
+ readonly icon?: string | undefined;
159
+ readonly hidden?: string | undefined;
160
+ readonly tooltip?: readonly [{
161
+ readonly locale: "zh";
162
+ readonly message: string;
163
+ }, ...{
164
+ readonly locale: "en" | "ja" | "ko";
165
+ readonly message: string;
166
+ }[]] | undefined;
167
+ readonly variant?: "default" | "link" | "destructive" | "primary" | "ghost" | undefined;
168
+ readonly action?: any;
169
+ })[];
170
+ readonly groupId: string;
171
+ readonly icon?: string | undefined;
172
+ readonly hideTitle?: boolean | undefined;
173
+ }, never>>, {
174
+ default: () => never[];
175
+ }>;
176
+ size: Schema.optionalWith<Schema.Literal<["default", "sm", "xs"]>, {
177
+ default: () => "default";
178
+ }>;
179
+ gap: Schema.optionalWith<Schema.filter<Schema.filter<typeof Schema.Number>>, {
180
+ default: () => number;
181
+ }>;
182
+ style: Schema.optional<typeof Schema.String>;
183
+ }>>;
52
184
  title: Schema.TupleType<readonly [Schema.Struct<{
53
185
  locale: Schema.Literal<["zh"]>;
54
186
  message: Schema.SchemaClass<string, string, never>;
@@ -1,13 +1,29 @@
1
1
  import { Schema } from "effect";
2
2
  import { getProperty } from "dot-prop";
3
3
  import { Locale } from "../../../../../share/locale.js";
4
- import { Align, CelRowAccess, derivedRowField, editableColumnFields, editableHeader } from "../../../utils/shared.js";
4
+ import { ActionSchemaFields } from "../../../../actions/schema.js";
5
+ import { Align, CelRowAccess, derivedRowField, editableColumnFields, editableHeader, registerRowVariablesIfAbsent } from "../../../utils/shared.js";
5
6
  export const type = "com.shwfed.table.column.date-input";
6
7
  export const compatibilityDate = "2026-06-17";
7
8
  export const metadata = {
8
9
  name: "\u65E5\u671F\u8F93\u5165",
9
10
  icon: "fluent:calendar-ltr-20-regular"
10
11
  };
12
+ function AddonActions(configure) {
13
+ const configureWithRow = (env) => {
14
+ configure(env);
15
+ registerRowVariablesIfAbsent(env);
16
+ };
17
+ const { groups, items, ...rest } = ActionSchemaFields(configureWithRow).fields;
18
+ return Schema.Struct({
19
+ ...rest,
20
+ groups: Schema.optionalWith(groups, { default: () => [] }),
21
+ items: Schema.optionalWith(items, { default: () => [] })
22
+ }).annotations({
23
+ title: "\u8F93\u5165\u6846\u5185\u6309\u94AE",
24
+ description: "\u5728\u8F93\u5165\u6846\u53F3\u4FA7\u5185\u5D4C\u4E00\u7EC4\u64CD\u4F5C\u6309\u94AE"
25
+ });
26
+ }
11
27
  export function presetSchema(configure) {
12
28
  const CelDate = CelRowAccess(configure, { resultType: "Date" });
13
29
  return Schema.Struct({
@@ -56,7 +72,17 @@ export function schema(configure) {
56
72
  presets: Schema.optional(Schema.Array(Preset).annotations({
57
73
  title: "\u5FEB\u6377\u9009\u9879",
58
74
  description: "\u5728\u9009\u62E9\u5668\u4FA7\u680F\u5C55\u793A\u7684\u5FEB\u6377\u9884\u8BBE\uFF1B\u7559\u7A7A\u5219\u4E0D\u6E32\u67D3\u4FA7\u680F"
59
- }))
75
+ })),
76
+ // `Schema.optional` rebuilds the struct's union member, and because the
77
+ // `optionalWith`-default fields make `AddonActions` a `Transformation`, the
78
+ // inner struct's `title`/`description` don't survive onto the rebuilt
79
+ // member. The config editor's `getStructFieldTitle('addon')` would then fall
80
+ // back to the raw key "addon". Re-state them on the property signature,
81
+ // which the meta reader checks before the field type.
82
+ addon: Schema.optional(AddonActions(configure)).annotations({
83
+ title: "\u8F93\u5165\u6846\u5185\u6309\u94AE",
84
+ description: "\u5728\u8F93\u5165\u6846\u53F3\u4FA7\u5185\u5D4C\u4E00\u7EC4\u64CD\u4F5C\u6309\u94AE"
85
+ })
60
86
  }).annotations({ title: "DateInputRenderer", description: "\u65E5\u671F\u8F93\u5165\u6E32\u67D3\u5668\uFF08\u53EF\u7F16\u8F91\uFF09" });
61
87
  }
62
88
  export function defaults() {
@@ -4,7 +4,7 @@ import { computed } from "vue";
4
4
  import { useI18n } from "vue-i18n";
5
5
  import { format as formatDate } from "date-fns";
6
6
  import { cel as $cel } from "../../../../../utils/cel";
7
- import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
7
+ import { celScope, injectCELContext } from "../../../../../utils/cel-context";
8
8
  import { useFormReadonly } from "../../../../form/utils/readonly";
9
9
  import { getLocalizedText } from "../../../../../share/locale";
10
10
  import { DATE_RANGE_PICKER_DEFAULT_FORMATS, DateRangePicker } from "../../../../ui/date-range-picker";
@@ -27,7 +27,7 @@ const endPlaceholderText = computed(
27
27
  function evalBool(expression, label) {
28
28
  if (!expression) return false;
29
29
  try {
30
- return Effect.runSync($cel(expression, celBindings(celContext))) === true;
30
+ return Effect.runSync($cel(expression, celScope(celContext))) === true;
31
31
  } catch (e) {
32
32
  console.error(`[shwfed-table] date-range-input ${label} failed`, e);
33
33
  return false;
@@ -52,8 +52,8 @@ const shortcuts = computed(() => {
52
52
  name: preset.label,
53
53
  value: () => {
54
54
  try {
55
- const start = Effect.runSync($cel(preset.start, celBindings(celContext)));
56
- const end = Effect.runSync($cel(preset.end, celBindings(celContext)));
55
+ const start = Effect.runSync($cel(preset.start, celScope(celContext)));
56
+ const end = Effect.runSync($cel(preset.end, celScope(celContext)));
57
57
  return [
58
58
  formatDate(start, resolvedValueFormat.value),
59
59
  formatDate(end, resolvedValueFormat.value)
@@ -1263,6 +1263,7 @@ const tableQueryValue = computed({
1263
1263
  v-for="entry in pickerEntries"
1264
1264
  :key="`${entry.type}@${entry.compatibilityDate}`"
1265
1265
  :value="`${entry.type}@${entry.compatibilityDate}`"
1266
+ :keywords="entry.type"
1266
1267
  @select="addColumn(entry.type, entry.compatibilityDate)"
1267
1268
  >
1268
1269
  <Icon
@@ -2,7 +2,7 @@
2
2
  import { Effect } from "effect";
3
3
  import { customRef } from "vue";
4
4
  import { cel as _rawCel } from "../../utils/cel";
5
- import { celBindings, injectCELContext, provideCELContext, provideScopeAddress } from "../../utils/cel-context";
5
+ import { celScope, injectCELContext, provideCELContext, provideScopeAddress } from "../../utils/cel-context";
6
6
  import { provideSelectionsRegistry } from "../../utils/selections-registry";
7
7
  import { useDerived, useDerivedQuiescence } from "../form/utils/derived";
8
8
  import { provideFormState } from "../form/utils/state";
@@ -53,7 +53,7 @@ if (props.scopeId) {
53
53
  });
54
54
  }
55
55
  const inherited = injectCELContext();
56
- const $cel = (expression, context) => _rawCel(expression, { ...celBindings(inherited), ...context });
56
+ const $cel = (expression, context) => _rawCel(expression, celScope(inherited, context));
57
57
  const formState = provideFormState(rowRef, "row");
58
58
  useDerived({
59
59
  fields: () => props.derivedColumns,
@@ -8,7 +8,7 @@ const props = defineProps({
8
8
  <template>
9
9
  <div
10
10
  data-slot="alert-dialog-footer"
11
- :class="cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end sm:mx-auto', props.class)"
11
+ :class="cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-center sm:mx-auto', props.class)"
12
12
  >
13
13
  <slot />
14
14
  </div>
@@ -28,7 +28,11 @@ type __VLS_Props = {
28
28
  shortcuts?: ReadonlyArray<DatePickerShortcut>;
29
29
  size?: 'sm' | 'md' | 'lg';
30
30
  };
31
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
+ declare var __VLS_33: {};
32
+ type __VLS_Slots = {} & {
33
+ trailing?: (props: typeof __VLS_33) => any;
34
+ };
35
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
32
36
  clear: () => any;
33
37
  blur: (args_0: FocusEvent) => any;
34
38
  change: (args_0: string | undefined) => any;
@@ -47,5 +51,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
47
51
  clearable: boolean;
48
52
  timeGranularity: "hour" | "minute" | "second";
49
53
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
54
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
50
55
  declare const _default: typeof __VLS_export;
51
56
  export default _default;
57
+ type __VLS_WithSlots<T, S> = T & {
58
+ new (): {
59
+ $slots: S;
60
+ };
61
+ };
@@ -212,7 +212,14 @@ function applyShortcut(index) {
212
212
  @focus="onInputFocus"
213
213
  @blur="onInputBlur"
214
214
  @clear="onInputClear"
215
- />
215
+ >
216
+ <template
217
+ v-if="$slots.trailing"
218
+ #trailing
219
+ >
220
+ <slot name="trailing" />
221
+ </template>
222
+ </DatePickerInput>
216
223
  </PopoverAnchor>
217
224
  <PopoverContent
218
225
  align="start"
@@ -28,7 +28,11 @@ type __VLS_Props = {
28
28
  shortcuts?: ReadonlyArray<DatePickerShortcut>;
29
29
  size?: 'sm' | 'md' | 'lg';
30
30
  };
31
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
31
+ declare var __VLS_33: {};
32
+ type __VLS_Slots = {} & {
33
+ trailing?: (props: typeof __VLS_33) => any;
34
+ };
35
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
32
36
  clear: () => any;
33
37
  blur: (args_0: FocusEvent) => any;
34
38
  change: (args_0: string | undefined) => any;
@@ -47,5 +51,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
47
51
  clearable: boolean;
48
52
  timeGranularity: "hour" | "minute" | "second";
49
53
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
54
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
50
55
  declare const _default: typeof __VLS_export;
51
56
  export default _default;
57
+ type __VLS_WithSlots<T, S> = T & {
58
+ new (): {
59
+ $slots: S;
60
+ };
61
+ };
@@ -12,7 +12,11 @@ type __VLS_Props = {
12
12
  size?: 'sm' | 'md' | 'lg';
13
13
  class?: HTMLAttributes['class'];
14
14
  };
15
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
+ declare var __VLS_49: {};
16
+ type __VLS_Slots = {} & {
17
+ trailing?: (props: typeof __VLS_49) => any;
18
+ };
19
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
16
20
  clear: () => any;
17
21
  blur: (args_0: FocusEvent) => any;
18
22
  focus: (args_0: FocusEvent) => any;
@@ -27,5 +31,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
27
31
  clearable: boolean;
28
32
  clearIcon: string;
29
33
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
34
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
30
35
  declare const _default: typeof __VLS_export;
31
36
  export default _default;
37
+ type __VLS_WithSlots<T, S> = T & {
38
+ new (): {
39
+ $slots: S;
40
+ };
41
+ };
@@ -120,5 +120,9 @@ const showClear = computed(
120
120
  />
121
121
  </InputGroupButton>
122
122
  </InputGroupAddon>
123
+ <!-- A trailing slot for consumer-supplied addons (e.g. the table date-input
124
+ column's embedded action buttons). Rendered inside the `InputGroup` so
125
+ the consumer can drop its own `InputGroupAddon`. -->
126
+ <slot name="trailing" />
123
127
  </InputGroup>
124
128
  </template>
@@ -12,7 +12,11 @@ type __VLS_Props = {
12
12
  size?: 'sm' | 'md' | 'lg';
13
13
  class?: HTMLAttributes['class'];
14
14
  };
15
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
+ declare var __VLS_49: {};
16
+ type __VLS_Slots = {} & {
17
+ trailing?: (props: typeof __VLS_49) => any;
18
+ };
19
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
16
20
  clear: () => any;
17
21
  blur: (args_0: FocusEvent) => any;
18
22
  focus: (args_0: FocusEvent) => any;
@@ -27,5 +31,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
27
31
  clearable: boolean;
28
32
  clearIcon: string;
29
33
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
34
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
30
35
  declare const _default: typeof __VLS_export;
31
36
  export default _default;
37
+ type __VLS_WithSlots<T, S> = T & {
38
+ new (): {
39
+ $slots: S;
40
+ };
41
+ };
@@ -122,3 +122,4 @@ export declare function provideStepRoster(roster: Ref<ReadonlyArray<StepRef>>):
122
122
  */
123
123
  export declare function useStepRoster(): Ref<ReadonlyArray<StepRef>>;
124
124
  export declare function celBindings(context: CELContext): Record<string, unknown>;
125
+ export declare function celScope(context: CELContext, locals?: Record<string, unknown>): Record<string, unknown>;
@@ -69,3 +69,31 @@ export function celBindings(context) {
69
69
  }
70
70
  return out;
71
71
  }
72
+ function resolveCelVar(entry) {
73
+ if (entry === void 0) return void 0;
74
+ const value = entry.value;
75
+ return typeof value === "function" ? value() : value;
76
+ }
77
+ export function celScope(context, locals) {
78
+ return new Proxy(/* @__PURE__ */ Object.create(null), {
79
+ get(_target, key) {
80
+ if (typeof key !== "string") return void 0;
81
+ if (locals && key in locals) return locals[key];
82
+ return resolveCelVar(context[key]);
83
+ },
84
+ has(_target, key) {
85
+ if (typeof key !== "string") return false;
86
+ return !!locals && key in locals || key in context;
87
+ },
88
+ ownKeys() {
89
+ return [.../* @__PURE__ */ new Set([...Object.keys(context), ...Object.keys(locals ?? {})])];
90
+ },
91
+ getOwnPropertyDescriptor(_target, key) {
92
+ if (typeof key !== "string") return void 0;
93
+ if (locals && key in locals || key in context) {
94
+ return { enumerable: true, configurable: true, writable: true, value: void 0 };
95
+ }
96
+ return void 0;
97
+ }
98
+ });
99
+ }
@@ -10,7 +10,7 @@ When modifying this library, keep both `CLAUDE.md` and `PROMPT.md` in sync with
10
10
 
11
11
  `int` and `uint` types have been removed in favor of a unified `number` type backed by `Decimal` (arbitrary-precision arithmetic via BigInt). All numeric literals, arithmetic results, and size/index returns are `Decimal` instances. The `int()`, `uint()`, and `double()` conversion functions still exist as aliases but all return `number`.
12
12
 
13
- `google.protobuf.Timestamp` and `google.protobuf.Duration` have been removed. Replaced with a `Date` type backed by `TZDate` from `@date-fns/tz`, constructed via `date(string)` or `date(number)` (a Unix timestamp — the seconds-vs-milliseconds unit is auto-detected by magnitude: values `< 1e11` are read as seconds, the rest as milliseconds). Date manipulation uses date-fns functions (`startOf`, `endOf`, `offset`, `set`, `format`).
13
+ `google.protobuf.Timestamp` and `google.protobuf.Duration` have been removed. Replaced with a `Date` type backed by `TZDate` from `@date-fns/tz`, constructed via `date(string)` or `date(number)` (a Unix timestamp — the seconds-vs-milliseconds unit is auto-detected by magnitude: values `< 1e11` are read as seconds, the rest as milliseconds). Date manipulation uses date-fns functions (`startOf`, `endOf`, `offset`, `set`, `format`). `Date.diff(Date, string): number` returns the signed, truncated-toward-zero distance between two dates in a given unit (`millisecond` / `second` / `minute` / `hour` / `day` / `week` / `month` / `year`, plural tolerated) — the receiver is the minuend (`a.diff(b, unit)` = `a − b`, mirroring date-fns `differenceInX(left, right)`); there is no `Date − Date` operator and no duration type, so this is the way to measure elapsed time.
14
14
 
15
15
  A `range()` built-in has been added (not from upstream) — `range(number, number)`, `range(number, number, number)` and `range(Date, Date, string)`. It builds an end-exclusive list; the direction follows the operands (counts down when `start > end`); `step` is a positive magnitude; the date unit is `year` / `month` / `day` / `hour` / `minute`. Output length is capped at 100000.
16
16
 
@@ -234,6 +234,13 @@ d.offset(-1, "month") // 1 month earlier
234
234
  d.offset(2, "weeks") // 2 weeks later
235
235
  d.offset(1, "year") // 1 year later
236
236
 
237
+ // Difference between two dates (signed, truncated toward zero):
238
+ // receiver is the minuend, so `a.diff(b, unit)` == a − b
239
+ d.diff(other, "day") // whole days from other to d (negative if d is earlier)
240
+ d.diff(other, "hour") // whole hours
241
+ d.diff(other, "minute") // whole minutes
242
+ // units: millisecond / second / minute / hour / day / week / month / year (plural ok)
243
+
237
244
  // Set specific fields:
238
245
  d.set("day", 15) // set day of month to 15
239
246
  d.set("month", 6) // set to June (1-based)