@plumeai/plugin-sdk 0.0.0-stage → 0.1.2

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 (210) hide show
  1. package/LICENSE +21 -0
  2. package/bin/plume-plugin.mjs +70 -0
  3. package/dist/client/styles/src/index.d.ts +123 -0
  4. package/dist/client/ui/src/avatar/AgentAvatar.d.ts +42 -0
  5. package/dist/client/ui/src/avatar/AvatarPile.d.ts +36 -0
  6. package/dist/client/ui/src/avatar/AvatarStack.d.ts +26 -0
  7. package/dist/client/ui/src/avatar/art.d.ts +32 -0
  8. package/dist/client/ui/src/fileIcon.d.ts +33 -0
  9. package/dist/client/ui/src/hooks/useCopied.d.ts +16 -0
  10. package/dist/client/ui/src/hooks/useLiveRefresh.d.ts +22 -0
  11. package/dist/client/ui/src/hooks/useNarrow.d.ts +16 -0
  12. package/dist/client/ui/src/i18n/context.d.ts +17 -0
  13. package/dist/client/ui/src/i18n/index.d.ts +2 -0
  14. package/dist/client/ui/src/i18n/list.d.ts +20 -0
  15. package/dist/client/ui/src/i18n/locales.d.ts +10 -0
  16. package/dist/client/ui/src/i18n/messages/en.d.ts +1418 -0
  17. package/dist/client/ui/src/i18n/messages/index.d.ts +6 -0
  18. package/dist/client/ui/src/i18n/messages/zh-CN.d.ts +1263 -0
  19. package/dist/client/ui/src/i18n/plural.d.ts +16 -0
  20. package/dist/client/ui/src/i18n/translate.d.ts +43 -0
  21. package/dist/client/ui/src/icons/index.d.ts +5 -0
  22. package/dist/client/ui/src/image/AnnotateCanvas.d.ts +29 -0
  23. package/dist/client/ui/src/image/AnnotateToolbar.d.ts +73 -0
  24. package/dist/client/ui/src/image/Annotator.d.ts +154 -0
  25. package/dist/client/ui/src/image/annotate.d.ts +227 -0
  26. package/dist/client/ui/src/image/paint.d.ts +35 -0
  27. package/dist/client/ui/src/image/screenshot-geometry.d.ts +112 -0
  28. package/dist/client/ui/src/image/useBarDrag.d.ts +31 -0
  29. package/dist/client/ui/src/image/useMovableBar.d.ts +26 -0
  30. package/dist/client/ui/src/image/useToolbarPlacement.d.ts +42 -0
  31. package/dist/client/ui/src/index.d.ts +140 -0
  32. package/dist/client/ui/src/inputs/ColorField.d.ts +9 -0
  33. package/dist/client/ui/src/inputs/ComposerToggle.d.ts +23 -0
  34. package/dist/client/ui/src/inputs/DateRangeField.d.ts +25 -0
  35. package/dist/client/ui/src/inputs/NativeField.d.ts +5 -0
  36. package/dist/client/ui/src/inputs/SearchField.d.ts +21 -0
  37. package/dist/client/ui/src/inputs/Segmented.d.ts +23 -0
  38. package/dist/client/ui/src/inputs/Select.d.ts +32 -0
  39. package/dist/client/ui/src/inputs/ShortcutRecorder.d.ts +8 -0
  40. package/dist/client/ui/src/inputs/Slider.d.ts +13 -0
  41. package/dist/client/ui/src/inputs/TextArea.d.ts +30 -0
  42. package/dist/client/ui/src/inputs/Toggle.d.ts +10 -0
  43. package/dist/client/ui/src/inputs/WorktreeToggle.d.ts +19 -0
  44. package/dist/client/ui/src/inputs/day-range.d.ts +57 -0
  45. package/dist/client/ui/src/inputs/pickers.d.ts +40 -0
  46. package/dist/client/ui/src/inputs/useFieldFade.d.ts +1 -0
  47. package/dist/client/ui/src/keyboard.d.ts +21 -0
  48. package/dist/client/ui/src/layout/ApprovalFrame.d.ts +33 -0
  49. package/dist/client/ui/src/layout/Collapse.d.ts +9 -0
  50. package/dist/client/ui/src/layout/CopyMark.d.ts +19 -0
  51. package/dist/client/ui/src/layout/Disclosure.d.ts +66 -0
  52. package/dist/client/ui/src/layout/ErrorBoundary.d.ts +26 -0
  53. package/dist/client/ui/src/layout/PageTopRow.d.ts +19 -0
  54. package/dist/client/ui/src/layout/PanelEmpty.d.ts +17 -0
  55. package/dist/client/ui/src/layout/ResizeHandle.d.ts +24 -0
  56. package/dist/client/ui/src/layout/RetainedViews.d.ts +32 -0
  57. package/dist/client/ui/src/layout/Settings.d.ts +41 -0
  58. package/dist/client/ui/src/layout/Splitter.d.ts +25 -0
  59. package/dist/client/ui/src/lib/agent-avatar.d.ts +58 -0
  60. package/dist/client/ui/src/lib/code/font-stack.d.ts +12 -0
  61. package/dist/client/ui/src/lib/code/themes.d.ts +35 -0
  62. package/dist/client/ui/src/lib/date-format.d.ts +8 -0
  63. package/dist/client/ui/src/lib/dispatches.d.ts +8 -0
  64. package/dist/client/ui/src/lib/hour-style.d.ts +13 -0
  65. package/dist/client/ui/src/lib/number-draft.d.ts +24 -0
  66. package/dist/client/ui/src/lib/relative-time.d.ts +18 -0
  67. package/dist/client/ui/src/lib/tiling.d.ts +89 -0
  68. package/dist/client/ui/src/lib/typing.d.ts +19 -0
  69. package/dist/client/ui/src/motion/RollWords.d.ts +26 -0
  70. package/dist/client/ui/src/motion/RollingText.d.ts +43 -0
  71. package/dist/client/ui/src/motion/TypedText.d.ts +9 -0
  72. package/dist/client/ui/src/motion/freeze.d.ts +22 -0
  73. package/dist/client/ui/src/motion/held.d.ts +17 -0
  74. package/dist/client/ui/src/motion/loaders.d.ts +65 -0
  75. package/dist/client/ui/src/motion/reduced.d.ts +13 -0
  76. package/dist/client/ui/src/motion/ticked.d.ts +24 -0
  77. package/dist/client/ui/src/motion/ticker.d.ts +31 -0
  78. package/dist/client/ui/src/motion/tokens.d.ts +29 -0
  79. package/dist/client/ui/src/motion/useNow.d.ts +6 -0
  80. package/dist/client/ui/src/overlay/Confirm.d.ts +96 -0
  81. package/dist/client/ui/src/overlay/ContextMenu.d.ts +40 -0
  82. package/dist/client/ui/src/overlay/Dialog.d.ts +60 -0
  83. package/dist/client/ui/src/overlay/Menu.d.ts +90 -0
  84. package/dist/client/ui/src/overlay/Overlay.d.ts +17 -0
  85. package/dist/client/ui/src/overlay/Popover.d.ts +127 -0
  86. package/dist/client/ui/src/overlay/Tooltip.d.ts +14 -0
  87. package/dist/client/ui/src/overlay/afterimage.d.ts +20 -0
  88. package/dist/client/ui/src/overlay/chrome-top.d.ts +8 -0
  89. package/dist/client/ui/src/overlay/hover-layers.d.ts +41 -0
  90. package/dist/client/ui/src/overlay/portal.d.ts +21 -0
  91. package/dist/client/ui/src/overlay/scrims.d.ts +20 -0
  92. package/dist/client/ui/src/overlay/tooltip-attribute.d.ts +62 -0
  93. package/dist/client/ui/src/primitives/Button.d.ts +64 -0
  94. package/dist/client/ui/src/primitives/Caret.d.ts +25 -0
  95. package/dist/client/ui/src/primitives/ChoiceMark.d.ts +12 -0
  96. package/dist/client/ui/src/primitives/ClosableTab.d.ts +23 -0
  97. package/dist/client/ui/src/primitives/CountUp.d.ts +21 -0
  98. package/dist/client/ui/src/primitives/GitHubMark.d.ts +12 -0
  99. package/dist/client/ui/src/primitives/IconButton.d.ts +55 -0
  100. package/dist/client/ui/src/primitives/MarkNumber.d.ts +12 -0
  101. package/dist/client/ui/src/primitives/RowDeleteButton.d.ts +6 -0
  102. package/dist/client/ui/src/primitives/Skeleton.d.ts +36 -0
  103. package/dist/client/ui/src/primitives/TabStrip.d.ts +29 -0
  104. package/dist/client/ui/src/primitives/Text.d.ts +341 -0
  105. package/dist/client/ui/src/primitives/TimeAgo.d.ts +13 -0
  106. package/dist/client/ui/src/primitives/useCountUp.d.ts +23 -0
  107. package/dist/client/ui/src/row/FlowRow.d.ts +31 -0
  108. package/dist/client/ui/src/row/HoverRow.d.ts +28 -0
  109. package/dist/client/ui/src/scroll/BackToLatest.d.ts +19 -0
  110. package/dist/client/ui/src/scroll/OverlayScrollbar.d.ts +9 -0
  111. package/dist/client/ui/src/scroll/ScrollText.d.ts +24 -0
  112. package/dist/client/ui/src/scroll/Scroller.d.ts +66 -0
  113. package/dist/client/ui/src/scroll/Sideways.d.ts +30 -0
  114. package/dist/client/ui/src/scroll/fade.d.ts +2 -0
  115. package/dist/client/ui/src/scroll/follow.d.ts +157 -0
  116. package/dist/client/ui/src/scroll/measure-batch.d.ts +13 -0
  117. package/dist/client/ui/src/scroll/memory.d.ts +22 -0
  118. package/dist/client/ui/src/scroll/signature.d.ts +24 -0
  119. package/dist/client/ui/src/scroll/useFollowBottom.d.ts +80 -0
  120. package/dist/client/ui/src/scroll/useSideways.d.ts +29 -0
  121. package/dist/contract/src/app.d.ts +16 -0
  122. package/dist/contract/src/changes.d.ts +50 -0
  123. package/dist/contract/src/diagnostics.d.ts +86 -0
  124. package/dist/contract/src/index.d.ts +18 -0
  125. package/dist/contract/src/plugin.d.ts +1391 -0
  126. package/dist/contract/src/resources.d.ts +79 -0
  127. package/dist/contract/src/service.d.ts +806 -0
  128. package/dist/contract/src/ui.d.ts +1039 -0
  129. package/dist/contract/src/usage.d.ts +102 -0
  130. package/dist/core/llm/ai/anthropic-messages-request.d.ts +82 -0
  131. package/dist/core/llm/ai/anthropic-messages.d.ts +43 -0
  132. package/dist/core/llm/ai/cache-routing.d.ts +53 -0
  133. package/dist/core/llm/ai/chat-delta.d.ts +107 -0
  134. package/dist/core/llm/ai/compat-key.d.ts +19 -0
  135. package/dist/core/llm/ai/endpoint.d.ts +57 -0
  136. package/dist/core/llm/ai/failure.d.ts +181 -0
  137. package/dist/core/llm/ai/index.d.ts +16 -0
  138. package/dist/core/llm/ai/openai-chat-completions-request.d.ts +49 -0
  139. package/dist/core/llm/ai/openai-chat-completions.d.ts +37 -0
  140. package/dist/core/llm/ai/openai-responses-request.d.ts +63 -0
  141. package/dist/core/llm/ai/openai-responses.d.ts +11 -0
  142. package/dist/core/llm/ai/prefix-fingerprint.d.ts +20 -0
  143. package/dist/core/llm/ai/reasoning-compat.d.ts +69 -0
  144. package/dist/core/llm/ai/request-params-compat.d.ts +39 -0
  145. package/dist/core/llm/ai/retry.d.ts +130 -0
  146. package/dist/core/llm/ai/sanitize-history.d.ts +23 -0
  147. package/dist/core/llm/ai/think-tag.d.ts +37 -0
  148. package/dist/core/llm/ai/thinking-options.d.ts +35 -0
  149. package/dist/core/llm/ai/tool-names.d.ts +17 -0
  150. package/dist/core/llm/ai/tool-pairing-compat.d.ts +53 -0
  151. package/dist/core/llm/ai/tool-result-images-compat.d.ts +24 -0
  152. package/dist/core/llm/ai/tool-schema.d.ts +20 -0
  153. package/dist/core/llm/ai/usage-fields.d.ts +30 -0
  154. package/dist/core/llm/ai/vendors/index.d.ts +20 -0
  155. package/dist/core/llm/ai/vendors/thinking.d.ts +39 -0
  156. package/dist/core/llm/ai/vendors/types.d.ts +47 -0
  157. package/dist/core/llm/config/image-models.d.ts +34 -0
  158. package/dist/core/llm/config/retry-policy.d.ts +35 -0
  159. package/dist/core/llm/images/chat-images.d.ts +11 -0
  160. package/dist/core/llm/images/dimensions.d.ts +15 -0
  161. package/dist/core/llm/images/generate.d.ts +15 -0
  162. package/dist/core/llm/images/openai-images.d.ts +11 -0
  163. package/dist/core/llm/images/quota.d.ts +9 -0
  164. package/dist/core/llm/images/shape.d.ts +44 -0
  165. package/dist/core/llm/images/types.d.ts +118 -0
  166. package/dist/core/llm/model-catalog-format.d.ts +50 -0
  167. package/dist/core/llm/model-catalog.d.ts +51 -0
  168. package/dist/core/llm/types/message.d.ts +450 -0
  169. package/dist/core/llm/types/provider.d.ts +169 -0
  170. package/dist/core/llm/types/tool.d.ts +23 -0
  171. package/dist/core/llm/types.d.ts +10 -0
  172. package/dist/core/llm/utils/pricing.d.ts +18 -0
  173. package/dist/core/llm/utils/record.d.ts +2 -0
  174. package/dist/core/llm/utils/sse.d.ts +69 -0
  175. package/dist/infra/rpc/src/endpoint.d.ts +36 -0
  176. package/dist/infra/rpc/src/index.d.ts +2 -0
  177. package/dist/infra/rpc/src/rpc.d.ts +54 -0
  178. package/dist/theme.css +336 -0
  179. package/dist/ui.d.ts +2 -0
  180. package/lib/build.mjs +143 -0
  181. package/lib/check.mjs +23 -0
  182. package/lib/dev.mjs +52 -0
  183. package/lib/icons.mjs +2 -0
  184. package/lib/init.mjs +109 -0
  185. package/lib/install.mjs +80 -0
  186. package/lib/link.mjs +44 -0
  187. package/lib/lint/i18n.mjs +149 -0
  188. package/lib/lint/imports.mjs +83 -0
  189. package/lib/lint/index.mjs +54 -0
  190. package/lib/lint/styles.mjs +160 -0
  191. package/lib/manifest.d.mts +9 -0
  192. package/lib/manifest.mjs +99 -0
  193. package/lib/targets.mjs +60 -0
  194. package/package.json +34 -4
  195. package/skill/SKILL.md +150 -0
  196. package/skill/references/components.md +2830 -0
  197. package/skill/references/logic.md +526 -0
  198. package/skill/references/style-i18n.md +70 -0
  199. package/skill/references/ui.md +532 -0
  200. package/template/AGENTS.md +17 -0
  201. package/template/CLAUDE.md +1 -0
  202. package/template/README.md +12 -0
  203. package/template/gitignore +2 -0
  204. package/template/src/index.ts +28 -0
  205. package/template/src/messages.ts +16 -0
  206. package/template/src/types.ts +8 -0
  207. package/template/src/ui.tsx +30 -0
  208. package/template/tsconfig.json +7 -0
  209. package/tsconfig.json +25 -0
  210. package/README.md +0 -3
@@ -0,0 +1,112 @@
1
+ /**
2
+ * 选区在哪、它的手柄在哪、工具条能放在哪。
3
+ *
4
+ * 和浮层分开,是因为这些全是不带 React 的算术——所以能测,而那些容易错得很隐蔽的规矩(手柄报的是你没按的
5
+ * 那个角、拖动把矩形翻成负的、工具条跑出屏幕)正是值得测、而不是靠点来点去发现的。
6
+ */
7
+ export interface Rect {
8
+ x: number;
9
+ y: number;
10
+ width: number;
11
+ height: number;
12
+ }
13
+ export interface Point {
14
+ x: number;
15
+ y: number;
16
+ }
17
+ /**
18
+ * 八个方向,按 CSS 光标的叫法命名。
19
+ *
20
+ * 角在前,这样顺着这张表做的命中测试在角和边重叠的地方优先认角——它们总是重叠,而指针瞄的就是角。
21
+ */
22
+ export declare const HANDLES: readonly ["nw", "ne", "se", "sw", "n", "e", "s", "w"];
23
+ export type Handle = (typeof HANDLES)[number];
24
+ /** 每个手柄该显示的光标:它的名字加上 CSS 要的后缀。 */
25
+ export declare const HANDLE_CURSOR: Record<Handle, string>;
26
+ /** 手柄在哪,表示为选区边上的一个点。 */
27
+ export declare function handlePoint(rect: Rect, handle: Handle): Point;
28
+ /**
29
+ * 指针在哪个手柄上,没有就是 null。
30
+ *
31
+ * `tolerance` 是屏幕像素的半径,而不是手柄画出来的大小:目标得比记号大,理由和滚动条一样——八个像素见方
32
+ * 的一块,手落不准。
33
+ */
34
+ export declare function hitHandle(rect: Rect, at: Point, tolerance: number): Handle | null;
35
+ /** 点是否在选区里——在里面按下是移动,而不是重新拖一个。 */
36
+ export declare function insideRect(rect: Rect, at: Point): boolean;
37
+ /** 由两个角得到矩形,两个角哪个在前都行。 */
38
+ export declare function rectFromPoints(a: Point, b: Point): Rect;
39
+ /**
40
+ * 把一个手柄拖到某点之后的选区。
41
+ *
42
+ * 写成「挪动这个手柄管的那几条边,再规范化」,所以拖过对边时矩形会翻过来,而不是得到负的宽度——这是人在
43
+ * 其他任何地方改大小时预期的样子,`rectFromPoints` 本来就是这么写的。
44
+ */
45
+ export declare function resizeRect(rect: Rect, handle: Handle, to: Point): Rect;
46
+ /** 选区平移一段,保持完整、保持在屏幕里。 */
47
+ export declare function moveRect(rect: Rect, dx: number, dy: number, within: {
48
+ width: number;
49
+ height: number;
50
+ }): Rect;
51
+ /** 选区裁到屏幕以内,给拉过了边的改大小用。 */
52
+ export declare function clampRect(rect: Rect, within: {
53
+ width: number;
54
+ height: number;
55
+ }): Rect;
56
+ /**
57
+ * 工具条放在哪:选区下方,和它的左边对齐。
58
+ *
59
+ * 左对齐,因为第一个控件是最常按的,也因为从选区起点开始的工具条读起来属于它——把工具条右对齐到一个比它
60
+ * 窄的选区,会把控件推离它们作用的东西。
61
+ *
62
+ * 下面放不下就翻到上面,并且沿着边滑动而不是挂出去。这两样都很平常;不平常的是一块矮屏幕最底下的选区,
63
+ * 两边都放不下——那时它放进选区里面、贴着底,那是唯一剩下的地方。
64
+ */
65
+ /**
66
+ * 工具条放在哪,以及最后落在选区的哪一侧。
67
+ *
68
+ * 这一侧不是装饰:工具条打开的任何东西——比如粗细和颜色的气泡——都得**背着**选区开,不然就盖住了正要标注
69
+ * 的东西。只有这个函数的调用方知道是哪个方向,所以把它返回出去,而不是让下游去猜。
70
+ */
71
+ export interface ToolbarPlacement extends Point {
72
+ /** `over` 表示两侧都放不下,工具条压在选区上面。 */
73
+ side: "below" | "above" | "over";
74
+ }
75
+ export declare function toolbarPosition(rect: Rect, viewport: {
76
+ width: number;
77
+ height: number;
78
+ }, toolbar: {
79
+ width: number;
80
+ height: number;
81
+ },
82
+ /**
83
+ * 工具条打开的气泡有多高,如果它会打开一个的话。
84
+ *
85
+ * 以前放工具条时当它是唯一要放得下的东西,而粗细颜色气泡开在比工具条**更远**离选区的地方——所以一个
86
+ * 拉到屏幕底部的选区,把工具条放进了最后一条放得下的地方,气泡就落在那下面,整个到了屏幕外。能看见的
87
+ * 只有底边上一排像素。
88
+ *
89
+ * 两侧都把它算进这一摞里:只有工具条**和**它打开的东西都落在屏幕上,这一侧才算放得下。
90
+ */
91
+ bubble?: {
92
+ height: number;
93
+ }): ToolbarPlacement;
94
+ /**
95
+ * 被手拖动的工具条允许停在哪。
96
+ *
97
+ * 上面的自动摆放几乎总是对的,只在它看不见的那种情况下错:工具条盖住了正要标注的那部分图。所以它能被挪开,
98
+ * 挪过之后还作数的只剩这一条——它得始终够得着。
99
+ *
100
+ * `bubbleHeight` 是它上方留出的空间,因为只要工具条不贴着屏幕顶,属性气泡就往上开。不留的话,拖到紧贴顶边,
101
+ * 气泡开到屏幕外,手里那个工具的粗细和颜色就够不着了。
102
+ *
103
+ * 两个界限冲突时低的那个赢,这发生在比工具条加边距还矮的视口里。出了底边还能救回来——工具条还在拖它的
104
+ * 指针底下;出了顶边就救不回来了,屏幕上方没有地方能把它拖回来。
105
+ */
106
+ export declare function clampToolbar(at: Point, toolbar: {
107
+ width: number;
108
+ height: number;
109
+ }, viewport: {
110
+ width: number;
111
+ height: number;
112
+ }, bubbleHeight?: number): Point;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 一条浮着的标注工具栏,量它多大、按住能拖走。看图器(`useMovableBar`)和截图浮层
3
+ * (`useToolbarPlacement`)各有各的落点规矩,量和拖是同一套,从前各写一份。
4
+ *
5
+ * 「按住才拖、空隙处按下就拖」的手势在 `AnnotateToolbar` 里,这里只接它的 `onGrab`。
6
+ */
7
+ import type { Point } from "./screenshot-geometry.ts";
8
+ export interface BarSize {
9
+ width: number;
10
+ height: number;
11
+ /**
12
+ * 它最窄时有多宽。选中一个形状时它会多出一颗按钮;按当前宽度居中的话,每选中、取消一次整排就往旁边
13
+ * 滑 20pt——画完一个框,正要按的下一个工具挪了位置。按最窄的居中,它只往右长。
14
+ */
15
+ narrowest: number;
16
+ }
17
+ /**
18
+ * `clamp`:拖到的位置怎么夹回屏幕里,按此刻量到的尺寸(还没量到时是 null)。每一帧都读最新的那个,
19
+ * 窗口大小变了也作数。
20
+ */
21
+ export declare function useBarDrag(clamp: (at: Point, size: BarSize | null) => Point, initial?: Point | null): {
22
+ size: BarSize | null;
23
+ manual: Point | null;
24
+ dragging: boolean;
25
+ measure: (el: HTMLDivElement | null) => void;
26
+ startDrag: (grab: {
27
+ from: Point;
28
+ origin: Point;
29
+ }) => void;
30
+ reset: () => void;
31
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * 看图器里那条标注工具栏摆在哪:默认贴着窗口底边居中,按住能拖走,拖到哪记到哪。
3
+ *
4
+ * 截图浮层那条有自己的一套(`useToolbarPlacement`),它跟着选区走;这里没有选区,只有一张居中的图
5
+ * 和一扇窗。共用的是:夹在窗口里的那条规矩(`clampToolbar`),量它多大、拖到哪(`useBarDrag`)。
6
+ *
7
+ * 从前这一条钉死在窗口底边,理由是「没有别处可去」。可它要躲的从来不是窗口,是图:在图的下半部
8
+ * 写字、画框时,工具栏和它上面那排粗细颜色正好压在要标的地方,挪不开就只能放大了绕着画。
9
+ */
10
+ import { type Point } from "./screenshot-geometry.ts";
11
+ export interface MovableBar {
12
+ /** 画在哪,窗口坐标;还没量到时是 null。 */
13
+ at: Point | null;
14
+ /** 外框的位置样式:量到之前由 CSS 居中,之后按像素摆。 */
15
+ style: React.CSSProperties;
16
+ /** 正在被拖:位置不加缓动,光标也这么说。 */
17
+ dragging: boolean;
18
+ /** 挂在装着工具栏的那个元素上的 ref 回调。 */
19
+ measure: (el: HTMLDivElement | null) => void;
20
+ /** 一下按住变成拖动时,`AnnotateToolbar` 调它。 */
21
+ startDrag: (grab: {
22
+ from: Point;
23
+ origin: Point;
24
+ }) => void;
25
+ }
26
+ export declare function useMovableBar(avoid: React.RefObject<HTMLElement | null>): MovableBar;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * 截图工具条画在哪,以及被拖到哪。
3
+ *
4
+ * 从截图浮层里拆出来的。那个组件有 17 个 `useState`,这五个(两个 state、两个 ref、一个派生位置)只服务
5
+ * 一件事,彼此之间的来往比它们和别处的来往多得多——所以它们是一组,而剩下那个组件里再也看不到「工具条
6
+ * 现在多宽」这种东西。
7
+ *
8
+ * 对外只有五样:画在哪、正在拖吗、怎么量、怎么开始拖、怎么归位。工具条自己的尺寸、手动位置、
9
+ * 那个 `ResizeObserver`,调用方一个都不需要知道。
10
+ */
11
+ import { type Point, type Rect } from "./screenshot-geometry.ts";
12
+ /** 工具条最终落在哪,以及气泡该往哪一边开。只有下面那个接口用,所以不导出。 */
13
+ type ToolbarAt = (Point & {
14
+ side: "above" | "below" | "over";
15
+ }) | null;
16
+ export interface ToolbarPlacement {
17
+ /** 画在哪。`null` 表示还没有选区,也就没有工具条。 */
18
+ at: ToolbarAt;
19
+ /** 正在被拖动——调用方拿它改光标。 */
20
+ dragging: boolean;
21
+ /** 挂在工具条那个元素上的 ref 回调。 */
22
+ measure: (el: HTMLDivElement | null) => void;
23
+ /** 按住把手时调用,带上按下的点和当时工具条的位置。 */
24
+ startDrag: (grab: {
25
+ from: Point;
26
+ origin: Point;
27
+ }) => void;
28
+ /** 新一轮截图开始时调用:忘掉用户上一轮把它拖到了哪。 */
29
+ reset: () => void;
30
+ }
31
+ /**
32
+ * `bounds` 可以是 null。
33
+ *
34
+ * 组件在拿到第一帧数据之前就早返回了,而 hook 必须在那之前调用——所以这里收一个可能还不存在的
35
+ * 屏幕尺寸。它为 null 时 `selection` 必然也是 null(没有截图就没有选区),下面那两处算位置的
36
+ * 地方都走不到。
37
+ */
38
+ export declare function useToolbarPlacement(selection: Rect | null, bounds: {
39
+ width: number;
40
+ height: number;
41
+ } | null): ToolbarPlacement;
42
+ export {};
@@ -0,0 +1,140 @@
1
+ /**
2
+ * 基础组件。产品界面和插件共用,渲染进程经 import map 把同一份实例给插件。
3
+ * 卡片外框、代码块、diff 视图在这个文件里;其余的通用组件按目录分:
4
+ * primitives(按钮、标签条……)、inputs(输入框、选择框)、overlay(弹层、对话框、菜单、悬停提示)、
5
+ * scroll、layout、motion、avatar,以及 lib 里它们共用的函数。图标走 `@plume/ui/icons`。
6
+ * 类名都来自 @plume/styles 和 @plume/styles/ui.css,插件用这些组件不用自己带样式。
7
+ */
8
+ import { type ReactNode } from "react";
9
+ export { I18nProvider, useI18n } from "./i18n/context.tsx";
10
+ export { formatList } from "./i18n/list.ts";
11
+ export { LOCALE_OPTIONS, type UiLocale } from "./i18n/locales.ts";
12
+ export type { MessageKey, ResolvedUiLocale } from "./i18n/messages/index.ts";
13
+ export { activeLocale, translate } from "./i18n/translate.ts";
14
+ export * from "./avatar/AgentAvatar.tsx";
15
+ export * from "./avatar/AvatarPile.tsx";
16
+ export * from "./avatar/AvatarStack.tsx";
17
+ export * from "./avatar/art.ts";
18
+ export * from "./fileIcon.tsx";
19
+ export * from "./hooks/useCopied.ts";
20
+ export * from "./hooks/useLiveRefresh.ts";
21
+ export * from "./hooks/useNarrow.ts";
22
+ export * from "./inputs/ComposerToggle.tsx";
23
+ export * from "./inputs/DateRangeField.tsx";
24
+ export * from "./inputs/NativeField.tsx";
25
+ export * from "./inputs/pickers.tsx";
26
+ export * from "./inputs/SearchField.tsx";
27
+ export * from "./inputs/Segmented.tsx";
28
+ export * from "./inputs/Select.tsx";
29
+ export * from "./inputs/TextArea.tsx";
30
+ export * from "./inputs/ShortcutRecorder.tsx";
31
+ export * from "./inputs/Toggle.tsx";
32
+ export * from "./inputs/WorktreeToggle.tsx";
33
+ export * from "./inputs/day-range.ts";
34
+ export * from "./inputs/useFieldFade.ts";
35
+ export * from "./keyboard.ts";
36
+ export * from "./layout/ApprovalFrame.tsx";
37
+ export * from "./layout/Collapse.tsx";
38
+ export * from "./layout/CopyMark.tsx";
39
+ export * from "./layout/Disclosure.tsx";
40
+ export * from "./layout/ErrorBoundary.tsx";
41
+ export * from "./layout/PageTopRow.tsx";
42
+ export * from "./layout/PanelEmpty.tsx";
43
+ export * from "./layout/ResizeHandle.tsx";
44
+ export * from "./layout/Settings.tsx";
45
+ export * from "./layout/RetainedViews.tsx";
46
+ export * from "./layout/Splitter.tsx";
47
+ export * from "./lib/agent-avatar.ts";
48
+ export * from "./lib/code/font-stack.ts";
49
+ export * from "./lib/code/themes.ts";
50
+ export * from "./lib/date-format.ts";
51
+ export * from "./lib/dispatches.ts";
52
+ export * from "./lib/hour-style.ts";
53
+ export * from "./lib/number-draft.ts";
54
+ export * from "./lib/relative-time.ts";
55
+ export * from "./lib/tiling.ts";
56
+ export * from "./lib/typing.ts";
57
+ export * from "./motion/RollWords.tsx";
58
+ export * from "./motion/RollingText.tsx";
59
+ export * from "./motion/TypedText.tsx";
60
+ export * from "./motion/freeze.ts";
61
+ export * from "./motion/held.ts";
62
+ export * from "./motion/loaders.tsx";
63
+ export * from "./motion/reduced.ts";
64
+ export * from "./motion/ticked.ts";
65
+ export * from "./motion/ticker.ts";
66
+ export * from "./motion/tokens.ts";
67
+ export * from "./motion/useNow.ts";
68
+ export * from "./overlay/Confirm.tsx";
69
+ export * from "./overlay/ContextMenu.tsx";
70
+ export * from "./overlay/Dialog.tsx";
71
+ export * from "./overlay/Menu.tsx";
72
+ export * from "./overlay/Overlay.tsx";
73
+ export * from "./overlay/Popover.tsx";
74
+ export * from "./overlay/Tooltip.tsx";
75
+ export * from "./overlay/chrome-top.ts";
76
+ export * from "./overlay/hover-layers.ts";
77
+ export * from "./overlay/portal.ts";
78
+ export * from "./overlay/scrims.ts";
79
+ export * from "./overlay/tooltip-attribute.ts";
80
+ export * from "./primitives/Button.tsx";
81
+ export * from "./primitives/Caret.tsx";
82
+ export * from "./primitives/ChoiceMark.tsx";
83
+ export * from "./primitives/ClosableTab.tsx";
84
+ export * from "./primitives/CountUp.tsx";
85
+ export * from "./primitives/GitHubMark.tsx";
86
+ export * from "./primitives/IconButton.tsx";
87
+ export * from "./primitives/MarkNumber.tsx";
88
+ export * from "./primitives/RowDeleteButton.tsx";
89
+ export * from "./primitives/Skeleton.tsx";
90
+ export * from "./primitives/TabStrip.tsx";
91
+ export * from "./primitives/Text.tsx";
92
+ export * from "./primitives/TimeAgo.tsx";
93
+ export * from "./primitives/useCountUp.ts";
94
+ export * from "./row/FlowRow.tsx";
95
+ export * from "./row/HoverRow.tsx";
96
+ export * from "./scroll/BackToLatest.tsx";
97
+ export * from "./scroll/OverlayScrollbar.tsx";
98
+ export * from "./scroll/ScrollText.tsx";
99
+ export * from "./scroll/Scroller.tsx";
100
+ export * from "./scroll/Sideways.tsx";
101
+ export * from "./scroll/fade.ts";
102
+ export * from "./scroll/follow.ts";
103
+ export * from "./scroll/measure-batch.ts";
104
+ export * from "./scroll/memory.ts";
105
+ export * from "./scroll/signature.ts";
106
+ export * from "./scroll/useFollowBottom.ts";
107
+ export * from "./scroll/useSideways.ts";
108
+ export { clampZoom, wheelZoomFactor, ZOOM_MAX, ZOOM_MIN, ZOOM_STEP, zoomAt, type Shape, type Tool } from "./image/annotate.ts";
109
+ export { COLOURS, useAnnotator, type Annotator, type AnnotatorOptions, type RawPixels } from "./image/Annotator.tsx";
110
+ export { AnnotateCanvas, STAGE_FIT } from "./image/AnnotateCanvas.tsx";
111
+ export { AnnotateToolbar } from "./image/AnnotateToolbar.tsx";
112
+ export { clampRect, clampToolbar, HANDLE_CURSOR, HANDLES, handlePoint, hitHandle, insideRect, moveRect, rectFromPoints, resizeRect, toolbarPosition, type Handle, type Point, type Rect, } from "./image/screenshot-geometry.ts";
113
+ export { useBarDrag, type BarSize } from "./image/useBarDrag.ts";
114
+ export { useMovableBar, type MovableBar } from "./image/useMovableBar.ts";
115
+ export { useToolbarPlacement, type ToolbarPlacement } from "./image/useToolbarPlacement.ts";
116
+ export interface CardProps {
117
+ title: ReactNode;
118
+ /** 标题右边的简短说明,单行,超出省略。 */
119
+ subtitle?: ReactNode;
120
+ /** 右上角的状态文字。 */
121
+ status?: ReactNode;
122
+ tone?: "default" | "error" | "warning";
123
+ children?: ReactNode;
124
+ }
125
+ export declare function Card({ title, subtitle, status, tone, children }: CardProps): import("react").JSX.Element;
126
+ export declare function CodeBlock({ children }: {
127
+ children: string;
128
+ }): import("react").JSX.Element;
129
+ type DiffLine = {
130
+ kind: "same" | "add" | "remove";
131
+ text: string;
132
+ };
133
+ /** 按行比较。用 LCS,够看小段改动;大文件的 diff 不在这里做。 */
134
+ export declare function diffLines(before: string, after: string): DiffLine[];
135
+ export declare function DiffView({ before, after }: {
136
+ before: string;
137
+ after: string;
138
+ }): import("react").JSX.Element;
139
+ export * from "./inputs/ColorField.tsx";
140
+ export * from "./inputs/Slider.tsx";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 那枚色块。里面的输入框是色块的一部分(底色就是它编辑的颜色),不是一个单独的输入框,所以不用 Input 的外观。
3
+ */
4
+ export declare function ColorField({ value, onChange, label, readOnly, }: {
5
+ value: string;
6
+ onChange: (value: string) => void;
7
+ label: string;
8
+ readOnly?: boolean;
9
+ }): import("react").JSX.Element;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 输入框工具栏里一个有开、关两态的模式开关(工作树、计划模式)。
3
+ *
4
+ * 关着时是一颗淡色图标,常驻,免得这一排因为一个模式时有时无地跳宽度;开着时才带字、换成强调色——它改变的是
5
+ * 下一轮能做什么,开着却看不出来,人会奇怪 agent 为什么不照常做事。
6
+ *
7
+ * 开和关是同一颗按钮、同一个左内边距:左右 6px 让关着时正好是控件边长的方块,一点图标不横跳,颜色也能过渡。
8
+ */
9
+ import type { ReactNode } from "react";
10
+ export declare function ComposerToggle({ on, onChange, icon, label, tip, size, ...data }: {
11
+ on: boolean;
12
+ onChange: (on: boolean) => void;
13
+ /** 16px 的图标,颜色跟着文字走。 */
14
+ icon: ReactNode;
15
+ /** 开着时图标旁边的字。 */
16
+ label: string;
17
+ /** 悬停提示和无障碍名:说点了会怎样。 */
18
+ tip: string;
19
+ /** `sm` 放在 `Button size="sm"` 旁边:26px;主输入框的控件跟着 `--plume-composer-control`。 */
20
+ size?: "composer" | "sm";
21
+ } & {
22
+ [key: `data-${string}`]: string | undefined;
23
+ }): import("react").JSX.Element;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 选一段日子。
3
+ *
4
+ * 一个字段加一张浮出来的月历,和界面里每个下拉用的是同一套东西:`plume-field` 的触发器、
5
+ * `Popover` 的定位、翻转、层级和 120ms 的进出。自己写一张浮层意味着自己再答一遍「窗口底部放不下
6
+ * 怎么办」「Escape 关不关」「关的时候要不要动画」——那三个问题这里已经有答案了。
7
+ *
8
+ * **没有一条分隔线。** 层次靠留白和字色分:快捷那一排是药丸,月历是网格,两者之间是 10px 的气。
9
+ * 一张 240px 宽的卡片上画两条横线,得到的是三个盒子叠在一起,而不是一张卡片。
10
+ *
11
+ * 选中的那一段是**一条**,不是几个圆点:中间的日子铺一层淡底连起来,两端压在上面。这样「从哪天
12
+ * 到哪天」是看出来的,不用去读两个日期再在脑子里减一下。
13
+ */
14
+ import { type DayRange } from "./day-range.ts";
15
+ /** 字段上印的那一行:一段日子、一个开头、或者「全部时间」。 */
16
+ export declare function rangeLabel(range: DayRange): string;
17
+ export declare function DateRangeField({ value, onChange, earliest, today, ariaLabel, }: {
18
+ value: DayRange;
19
+ onChange: (range: DayRange) => void;
20
+ /** 最早有记录的那天。比它更早的日子画出来但点不动——那儿本来就没有东西可删。 */
21
+ earliest?: string | null;
22
+ /** 注入的「今天」,让测试不必等到明天才跑得一样。 */
23
+ today?: Date;
24
+ ariaLabel?: string;
25
+ }): import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { type ComponentPropsWithRef } from "react";
2
+ /** 不带样式的原生控件:布局、ref、选区和撤销历史都留在调用方手里。 */
3
+ export declare function Input(props: ComponentPropsWithRef<"input">): import("react").JSX.Element;
4
+ /** 同 `Input`,多行。要带框、滚动条和渐隐的多行框用 `TextArea`。 */
5
+ export declare function Textarea(props: ComponentPropsWithRef<"textarea">): import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * 搜索框。
3
+ *
4
+ * 侧栏的会话搜索、审阅面板的文件筛选、文件树的筛选共用这一个。各写各的话,每个都有自己的高度、
5
+ * 自己的描边、自己对放大镜在框里还是框旁的看法——一个只有一个答案的问题,得到三个答案。
6
+ *
7
+ * 两种尺寸,因为两种场合确实不同:独占一行的框(`comfortable`),和塞进面板标题行、周围的行都很矮
8
+ * 的框(`compact`)。
9
+ */
10
+ export declare function SearchField({ value, onChange, placeholder, size, autoFocus, onEscape, onEnter, className, }: {
11
+ value: string;
12
+ onChange: (next: string) => void;
13
+ placeholder?: string;
14
+ size?: "compact" | "comfortable";
15
+ autoFocus?: boolean;
16
+ /** Esc 先清空,已经空了才关闭,筛选框要的就是这样。 */
17
+ onEscape?: () => void;
18
+ /** 输入法组字结束后的 Enter——上屏候选词的那个 Enter 不算。 */
19
+ onEnter?: () => void;
20
+ className?: string;
21
+ }): import("react").JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { type ReactNode } from "react";
2
+ /**
3
+ * 一排互斥的选项,选中的那个下面垫着一块会滑过去的底。
4
+ *
5
+ * 一块共用的底从这里滑到那里,滑动本身就说明这几个选项是同一排里的几个位置,不是几个开关。
6
+ * 位置是量出来的,不按等分算:中英混排的标签不一样宽。量在 layout effect 里,赶在这一帧画出来之前——晚一帧的话,
7
+ * 第一次渲染就能看见那块底从左上角飞过来。
8
+ *
9
+ * 圆角外框 8px、滑块和每一格 6px:内衬 2px,两道圆弧才同心。
10
+ */
11
+ export declare function Segmented<T extends string>({ value, onChange, options, }: {
12
+ value: T;
13
+ onChange: (value: T) => void;
14
+ /**
15
+ * 给了 `icon` 这一格就画成图标,`label` 变成它的提示和无障碍名字。
16
+ * `label` 无论如何都要给:只有图标、没有名字的控件,读屏读不出,别人也猜不着。
17
+ */
18
+ options: {
19
+ value: T;
20
+ label: string;
21
+ icon?: ReactNode;
22
+ }[];
23
+ }): import("react").JSX.Element;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * 从一张单子里选一个:`Select` 填满表单的一行,`InlineSelect` 放在一项设置的末尾或面板的标题行里。
3
+ *
4
+ * 放在基础组件里而不是设置页里:设置以外的地方(任务板、卡片上的调整项、模型画出来的界面卡片)也要用它。
5
+ */
6
+ export declare function Select<T extends string>(props: {
7
+ value: T;
8
+ onChange: (value: T) => void;
9
+ options: {
10
+ value: T;
11
+ label: string;
12
+ detail?: string;
13
+ icon?: React.ReactNode;
14
+ }[];
15
+ ariaLabel?: string;
16
+ }): import("react").JSX.Element;
17
+ /** 设置行里用的紧凑行内下拉,像「Zed ˅」那样只有字和箭头。 */
18
+ export declare function InlineSelect<T extends string>(props: {
19
+ value: T;
20
+ onChange: (value: T) => void;
21
+ options: {
22
+ value: T;
23
+ label: string;
24
+ detail?: string;
25
+ icon?: React.ReactNode;
26
+ }[];
27
+ ariaLabel?: string;
28
+ quiet?: boolean;
29
+ set?: boolean;
30
+ /** 给面板标题行而不是设置行——见 `Dropdown` 的 `size`。 */
31
+ compact?: boolean;
32
+ }): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 录一组快捷键:点一下进入录制,按下的那组键就是值(Electron accelerator 的写法)。Esc 放弃,⌫ / Delete 清空。
3
+ */
4
+ export declare function ShortcutRecorder({ value, onChange, placeholder }: {
5
+ value?: string;
6
+ onChange: (shortcut: string) => void;
7
+ placeholder?: string;
8
+ }): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 轨道和把手自己画的滑块。原生 range 叠在最上面、完全透明,拖动、点轨道跳过去、方向键都是浏览器自己的,
3
+ * 画出来的部分只跟着 value 走。
4
+ */
5
+ export declare function Slider({ value, onChange, min, max, step, label, width, }: {
6
+ value: number;
7
+ onChange: (value: number) => void;
8
+ min?: number;
9
+ max?: number;
10
+ step?: number;
11
+ label: string;
12
+ width?: number | string;
13
+ }): import("react").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { type ComponentPropsWithoutRef } from "react";
2
+ /**
3
+ * 写很多字的地方,一种写法。
4
+ *
5
+ * 各处的多行输入框各写各的类名串,会长出好几种圆角、内衬和底色——而它们要人做的是同一件事。
6
+ * 样子由 `.plume-textarea-shell` / `.plume-textarea` 出(见 `@plume/styles` 的 `ui/controls.css`),
7
+ * 调用方只说高度和位置。
8
+ *
9
+ * 三样东西是一起来的,缺一件那个框就回到从前:
10
+ *
11
+ * - **边界在外壳上**。虚化收的是元素画出的一切,描边和字同在一个元素上,滚到顶时框的上下边会跟
12
+ * 着字一起淡掉,像破了个口子。
13
+ * - **滑块是自己画的**。原生滚动条在全局被关掉了(见 `OverlayScrollbar` 的开头),不补一个,一
14
+ * 篇长草稿滚起来没有任何东西说它有多长。
15
+ * - **两头化开**。硬切的半行字读起来像渲染坏了,见 `useFieldFade`。
16
+ *
17
+ * 主输入框、消息编辑框这类框里还站着别的东西(工具栏、附件条、那排按钮)的不走这里,外壳是各自的。
18
+ * 共享的是同一个 `useFieldFade` 和同一条遮罩。
19
+ */
20
+ export declare function TextArea({ value, onChange, shell, className, fieldRef, resizable, ...rest }: {
21
+ value: string;
22
+ onChange: (value: string) => void;
23
+ /** 外壳上的额外类。高度、外边距、宽度——和这个框在页面上待在哪儿有关的事,调用方说了算。 */
24
+ shell?: string;
25
+ /** 字那一层的额外类:等宽、字号、`h-[180px]` 这类只跟可写区域有关的。 */
26
+ className?: string;
27
+ fieldRef?: React.RefObject<HTMLTextAreaElement | null>;
28
+ /** 能不能用鼠标拉高。只给写长文的地方,比如一份系统提示词。 */
29
+ resizable?: boolean;
30
+ } & Omit<ComponentPropsWithoutRef<"textarea">, "value" | "onChange" | "className" | "ref">): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 所有布尔设置用的开关。轨道两种状态都跟着主题和强调色;圆点用 `.plume-knob`,和外观页的滑块同一种处理:
3
+ * 白底加细边和阴影,浅色轨道上也看得见,暗色下压暗一点不刺眼。
4
+ */
5
+ export declare function Toggle({ checked, onChange, ariaLabel, disabled, }: {
6
+ checked: boolean;
7
+ onChange: (checked: boolean) => void;
8
+ ariaLabel?: string;
9
+ disabled?: boolean;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * 这次对话在它自己的工作树里,还是就在项目本身里。
3
+ *
4
+ * 每次对话各自选,在发出第一条消息之前——只有这一刻选择才有意义,跑过的对话事后没法搬进一份副本。
5
+ * 起始值由用它的地方给(建议卡片从模型说的 `edits_in_parallel` 起步);没有「新会话默认开」的设置,开不开每一次由人定。
6
+ *
7
+ * 是项目和分支旁边的一个开关,不是菜单:答案只有两个,一眼都看得见——只有标志,或者标志加上它的名字、
8
+ * 用强调色,和计划模式开关说同一件事的方式一样。分叉图标是侧栏标在有工作树的对话上的那个,不是旁边
9
+ * 分支标记的那个。
10
+ *
11
+ * 放在基础组件里而不是某个功能里,因为有两处要问这个问题——主输入框,问正在写的这次对话;建议的
12
+ * 对话卡片,问它要开始的那一次。
13
+ */
14
+ export declare function WorktreeToggle({ on, onChange, size, }: {
15
+ on: boolean;
16
+ onChange: (on: boolean) => void;
17
+ /** `sm` 放在 `Button size="sm"` 旁边,比如建议卡片上:26px,主输入框的控件是 28px。 */
18
+ size?: "composer" | "sm";
19
+ }): import("react").JSX.Element;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * 一段日子,以及画出一个月需要的那点算术。
3
+ *
4
+ * 全部按**本地**日期算(`dayKey`),按日统计的地方都该用同一个口径。这不是随手选的:一次
5
+ * 23:00 的对话属于你过的那一天,换成 UTC 它会跑到第二天去,于是日历上圈出来的那一段和页面上
6
+ * 的数字对不上——而这两样东西正是给同一个人看的。
7
+ *
8
+ * 纯函数单独放,因为这里每一条都有一个说不清就会错的边界:月初那几格属于上个月、选反了的两头、
9
+ * 跨年的「上一个月」。这些用几行断言问清楚,比在一个画了四十二个格子的组件里翻出来便宜得多。
10
+ */
11
+ /** 一段日子,两头都含当天。null 表示那一头不设限。 */
12
+ export interface DayRange {
13
+ from: string | null;
14
+ to: string | null;
15
+ }
16
+ /** 本地日期键 `YYYY-MM-DD`。刻意不是 ISO/UTC——见文件开头。 */
17
+ export declare function dayKey(date: Date): string;
18
+ /** 把日期键读回本地当天的零点。读不出来给 null,调用方当作「没设」。 */
19
+ export declare function parseDay(key: string | null | undefined): Date | null;
20
+ /** 同一个月里的第一天。用来做月历的锚,也用来比较「是不是同一个月」。 */
21
+ export declare function monthStart(date: Date): Date;
22
+ /**
23
+ * 往前或往后几个月。
24
+ *
25
+ * 走 `new Date(年, 月 + n, 1)` 而不是 `setMonth`:后者在当前是 31 号时会溢出到下个月(3 月 31
26
+ * 日往前一个月得到 3 月 3 日),而这里永远从 1 号起算,没有这个问题。跨年也由它自己处理。
27
+ */
28
+ export declare function addMonths(date: Date, n: number): Date;
29
+ /**
30
+ * 画一个月要的六行七列。
31
+ *
32
+ * 固定六行,哪怕这个月五行就排得下——行数随月份变,面板的高度就会跟着跳,翻个月整张卡片弹一下。
33
+ * 头尾补的是真实的上下月日期,不是空格:它们照样可选,因为「8 月 31 日到 9 月 2 日」是一段人会
34
+ * 真的想选的日子,而它横跨两个月。
35
+ *
36
+ * `weekStart` 是一周从星期几开始(0 = 周日)。中文习惯从周一起,所以调用处传 1。
37
+ */
38
+ export declare function monthGrid(month: Date, weekStart?: number): Date[][];
39
+ /** 这一天落在这段里吗。两头都含当天,空的那头不设限。 */
40
+ export declare function inRange(day: string, range: DayRange): boolean;
41
+ /** 两头都有,而且这一天严格在中间——中间那几格是连起来的一条,两端另画。 */
42
+ export declare function isInterior(day: string, range: DayRange): boolean;
43
+ /**
44
+ * 点了一天之后,这段日子变成什么。
45
+ *
46
+ * 三种情形,而第三种是大多数日历弄拧的那一种:
47
+ *
48
+ * 还没开头,或者上一段已经选完 → 这一天是新的开头,结尾清空(开始重新选一段)
49
+ * 有开头没结尾,点的日子不比开头早 → 这一天是结尾,一段选完
50
+ * 有开头没结尾,点的日子比开头早 → **改开头**,不是选出一段倒着的日子
51
+ *
52
+ * 最后那条是关键:人想把范围往前扩的时候,做的动作就是点一个更早的日子。把它读成「结尾在开头
53
+ * 前面」得到的是一段空范围,而且没有任何提示说刚才发生了什么。
54
+ */
55
+ export declare function pickDay(range: DayRange, day: string): DayRange;
56
+ /** 这段日子有几天,两头都算。哪一头空着都数不出来。 */
57
+ export declare function rangeLength(range: DayRange): number | null;