@textui/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/adapters/index.d.ts +12 -0
  4. package/dist/adapters/index.d.ts.map +1 -0
  5. package/dist/adapters/index.js +11 -0
  6. package/dist/app/app.d.ts +200 -0
  7. package/dist/app/app.d.ts.map +1 -0
  8. package/dist/app/app.js +980 -0
  9. package/dist/core/animation.d.ts +34 -0
  10. package/dist/core/animation.d.ts.map +1 -0
  11. package/dist/core/animation.js +125 -0
  12. package/dist/core/clipboard.d.ts +29 -0
  13. package/dist/core/clipboard.d.ts.map +1 -0
  14. package/dist/core/clipboard.js +30 -0
  15. package/dist/core/commands.d.ts +42 -0
  16. package/dist/core/commands.d.ts.map +1 -0
  17. package/dist/core/commands.js +146 -0
  18. package/dist/core/components.d.ts +27 -0
  19. package/dist/core/components.d.ts.map +1 -0
  20. package/dist/core/components.js +78 -0
  21. package/dist/core/events.d.ts +23 -0
  22. package/dist/core/events.d.ts.map +1 -0
  23. package/dist/core/events.js +77 -0
  24. package/dist/core/focus.d.ts +69 -0
  25. package/dist/core/focus.d.ts.map +1 -0
  26. package/dist/core/focus.js +336 -0
  27. package/dist/core/i18n.d.ts +27 -0
  28. package/dist/core/i18n.d.ts.map +1 -0
  29. package/dist/core/i18n.js +88 -0
  30. package/dist/core/keybindings.d.ts +53 -0
  31. package/dist/core/keybindings.d.ts.map +1 -0
  32. package/dist/core/keybindings.js +163 -0
  33. package/dist/core/layers.d.ts +28 -0
  34. package/dist/core/layers.d.ts.map +1 -0
  35. package/dist/core/layers.js +84 -0
  36. package/dist/core/manifest.d.ts +22 -0
  37. package/dist/core/manifest.d.ts.map +1 -0
  38. package/dist/core/manifest.js +85 -0
  39. package/dist/core/navigation.d.ts +47 -0
  40. package/dist/core/navigation.d.ts.map +1 -0
  41. package/dist/core/navigation.js +110 -0
  42. package/dist/core/resources.d.ts +115 -0
  43. package/dist/core/resources.d.ts.map +1 -0
  44. package/dist/core/resources.js +321 -0
  45. package/dist/core/services.d.ts +21 -0
  46. package/dist/core/services.d.ts.map +1 -0
  47. package/dist/core/services.js +63 -0
  48. package/dist/core/store.d.ts +60 -0
  49. package/dist/core/store.d.ts.map +1 -0
  50. package/dist/core/store.js +593 -0
  51. package/dist/core/surfaces.d.ts +81 -0
  52. package/dist/core/surfaces.d.ts.map +1 -0
  53. package/dist/core/surfaces.js +237 -0
  54. package/dist/core/syntax.d.ts +49 -0
  55. package/dist/core/syntax.d.ts.map +1 -0
  56. package/dist/core/syntax.js +172 -0
  57. package/dist/core/when.d.ts +15 -0
  58. package/dist/core/when.d.ts.map +1 -0
  59. package/dist/core/when.js +224 -0
  60. package/dist/index.d.ts +49 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +54 -0
  63. package/dist/jsx/factory.d.ts +27 -0
  64. package/dist/jsx/factory.d.ts.map +1 -0
  65. package/dist/jsx/factory.js +102 -0
  66. package/dist/jsx/intrinsics.d.ts +96 -0
  67. package/dist/jsx/intrinsics.d.ts.map +1 -0
  68. package/dist/jsx/intrinsics.js +1 -0
  69. package/dist/jsx/jsx-dev-runtime.d.ts +13 -0
  70. package/dist/jsx/jsx-dev-runtime.d.ts.map +1 -0
  71. package/dist/jsx/jsx-dev-runtime.js +12 -0
  72. package/dist/jsx/jsx-runtime.d.ts +42 -0
  73. package/dist/jsx/jsx-runtime.d.ts.map +1 -0
  74. package/dist/jsx/jsx-runtime.js +16 -0
  75. package/dist/render/buffer.d.ts +77 -0
  76. package/dist/render/buffer.d.ts.map +1 -0
  77. package/dist/render/buffer.js +275 -0
  78. package/dist/render/color.d.ts +35 -0
  79. package/dist/render/color.d.ts.map +1 -0
  80. package/dist/render/color.js +160 -0
  81. package/dist/render/diff.d.ts +37 -0
  82. package/dist/render/diff.d.ts.map +1 -0
  83. package/dist/render/diff.js +66 -0
  84. package/dist/render/layout.d.ts +72 -0
  85. package/dist/render/layout.d.ts.map +1 -0
  86. package/dist/render/layout.js +633 -0
  87. package/dist/render/static.d.ts +63 -0
  88. package/dist/render/static.d.ts.map +1 -0
  89. package/dist/render/static.js +209 -0
  90. package/dist/runtime/bindings.d.ts +46 -0
  91. package/dist/runtime/bindings.d.ts.map +1 -0
  92. package/dist/runtime/bindings.js +116 -0
  93. package/dist/runtime/hooks.d.ts +284 -0
  94. package/dist/runtime/hooks.d.ts.map +1 -0
  95. package/dist/runtime/hooks.js +846 -0
  96. package/dist/runtime/instance.d.ts +106 -0
  97. package/dist/runtime/instance.d.ts.map +1 -0
  98. package/dist/runtime/instance.js +181 -0
  99. package/dist/runtime/paint.d.ts +27 -0
  100. package/dist/runtime/paint.d.ts.map +1 -0
  101. package/dist/runtime/paint.js +567 -0
  102. package/dist/runtime/reconcile.d.ts +23 -0
  103. package/dist/runtime/reconcile.d.ts.map +1 -0
  104. package/dist/runtime/reconcile.js +260 -0
  105. package/dist/runtime/runtime.d.ts +42 -0
  106. package/dist/runtime/runtime.d.ts.map +1 -0
  107. package/dist/runtime/runtime.js +1 -0
  108. package/dist/runtime/style.d.ts +55 -0
  109. package/dist/runtime/style.d.ts.map +1 -0
  110. package/dist/runtime/style.js +143 -0
  111. package/dist/themes/borders.d.ts +10 -0
  112. package/dist/themes/borders.d.ts.map +1 -0
  113. package/dist/themes/borders.js +88 -0
  114. package/dist/themes/builtin.d.ts +31 -0
  115. package/dist/themes/builtin.d.ts.map +1 -0
  116. package/dist/themes/builtin.js +291 -0
  117. package/dist/themes/glyphs.d.ts +15 -0
  118. package/dist/themes/glyphs.d.ts.map +1 -0
  119. package/dist/themes/glyphs.js +97 -0
  120. package/dist/themes/index.d.ts +5 -0
  121. package/dist/themes/index.d.ts.map +1 -0
  122. package/dist/themes/index.js +4 -0
  123. package/dist/themes/registry.d.ts +20 -0
  124. package/dist/themes/registry.d.ts.map +1 -0
  125. package/dist/themes/registry.js +204 -0
  126. package/dist/types/adapter.d.ts +38 -0
  127. package/dist/types/adapter.d.ts.map +1 -0
  128. package/dist/types/adapter.js +1 -0
  129. package/dist/types/animation.d.ts +31 -0
  130. package/dist/types/animation.d.ts.map +1 -0
  131. package/dist/types/animation.js +1 -0
  132. package/dist/types/app.d.ts +148 -0
  133. package/dist/types/app.d.ts.map +1 -0
  134. package/dist/types/app.js +1 -0
  135. package/dist/types/async.d.ts +30 -0
  136. package/dist/types/async.d.ts.map +1 -0
  137. package/dist/types/async.js +1 -0
  138. package/dist/types/capabilities.d.ts +44 -0
  139. package/dist/types/capabilities.d.ts.map +1 -0
  140. package/dist/types/capabilities.js +33 -0
  141. package/dist/types/cells.d.ts +72 -0
  142. package/dist/types/cells.d.ts.map +1 -0
  143. package/dist/types/cells.js +10 -0
  144. package/dist/types/command.d.ts +127 -0
  145. package/dist/types/command.d.ts.map +1 -0
  146. package/dist/types/command.js +1 -0
  147. package/dist/types/component-registry.d.ts +77 -0
  148. package/dist/types/component-registry.d.ts.map +1 -0
  149. package/dist/types/component-registry.js +1 -0
  150. package/dist/types/disposable.d.ts +8 -0
  151. package/dist/types/disposable.d.ts.map +1 -0
  152. package/dist/types/disposable.js +1 -0
  153. package/dist/types/focus.d.ts +72 -0
  154. package/dist/types/focus.d.ts.map +1 -0
  155. package/dist/types/focus.js +1 -0
  156. package/dist/types/geometry.d.ts +28 -0
  157. package/dist/types/geometry.d.ts.map +1 -0
  158. package/dist/types/geometry.js +14 -0
  159. package/dist/types/graph.d.ts +129 -0
  160. package/dist/types/graph.d.ts.map +1 -0
  161. package/dist/types/graph.js +31 -0
  162. package/dist/types/i18n.d.ts +23 -0
  163. package/dist/types/i18n.d.ts.map +1 -0
  164. package/dist/types/i18n.js +1 -0
  165. package/dist/types/index.d.ts +32 -0
  166. package/dist/types/index.d.ts.map +1 -0
  167. package/dist/types/index.js +31 -0
  168. package/dist/types/input.d.ts +65 -0
  169. package/dist/types/input.d.ts.map +1 -0
  170. package/dist/types/input.js +1 -0
  171. package/dist/types/keybinding.d.ts +49 -0
  172. package/dist/types/keybinding.d.ts.map +1 -0
  173. package/dist/types/keybinding.js +1 -0
  174. package/dist/types/layer.d.ts +54 -0
  175. package/dist/types/layer.d.ts.map +1 -0
  176. package/dist/types/layer.js +1 -0
  177. package/dist/types/manifest.d.ts +114 -0
  178. package/dist/types/manifest.d.ts.map +1 -0
  179. package/dist/types/manifest.js +1 -0
  180. package/dist/types/markdown.d.ts +58 -0
  181. package/dist/types/markdown.d.ts.map +1 -0
  182. package/dist/types/markdown.js +1 -0
  183. package/dist/types/navigation.d.ts +40 -0
  184. package/dist/types/navigation.d.ts.map +1 -0
  185. package/dist/types/navigation.js +1 -0
  186. package/dist/types/render.d.ts +72 -0
  187. package/dist/types/render.d.ts.map +1 -0
  188. package/dist/types/render.js +1 -0
  189. package/dist/types/resource.d.ts +170 -0
  190. package/dist/types/resource.d.ts.map +1 -0
  191. package/dist/types/resource.js +1 -0
  192. package/dist/types/services.d.ts +24 -0
  193. package/dist/types/services.d.ts.map +1 -0
  194. package/dist/types/services.js +3 -0
  195. package/dist/types/shell.d.ts +32 -0
  196. package/dist/types/shell.d.ts.map +1 -0
  197. package/dist/types/shell.js +1 -0
  198. package/dist/types/store.d.ts +124 -0
  199. package/dist/types/store.d.ts.map +1 -0
  200. package/dist/types/store.js +1 -0
  201. package/dist/types/stream.d.ts +18 -0
  202. package/dist/types/stream.d.ts.map +1 -0
  203. package/dist/types/stream.js +1 -0
  204. package/dist/types/style.d.ts +166 -0
  205. package/dist/types/style.d.ts.map +1 -0
  206. package/dist/types/style.js +1 -0
  207. package/dist/types/surface.d.ts +97 -0
  208. package/dist/types/surface.d.ts.map +1 -0
  209. package/dist/types/surface.js +1 -0
  210. package/dist/types/syntax.d.ts +68 -0
  211. package/dist/types/syntax.d.ts.map +1 -0
  212. package/dist/types/syntax.js +5 -0
  213. package/dist/types/terminal.d.ts +52 -0
  214. package/dist/types/terminal.d.ts.map +1 -0
  215. package/dist/types/terminal.js +1 -0
  216. package/dist/types/theme.d.ts +117 -0
  217. package/dist/types/theme.d.ts.map +1 -0
  218. package/dist/types/theme.js +1 -0
  219. package/dist/types/when.d.ts +19 -0
  220. package/dist/types/when.d.ts.map +1 -0
  221. package/dist/types/when.js +1 -0
  222. package/dist/ui/primitives.d.ts +56 -0
  223. package/dist/ui/primitives.d.ts.map +1 -0
  224. package/dist/ui/primitives.js +108 -0
  225. package/dist/ui/screen.d.ts +23 -0
  226. package/dist/ui/screen.d.ts.map +1 -0
  227. package/dist/ui/screen.js +18 -0
  228. package/dist/util/disposable.d.ts +6 -0
  229. package/dist/util/disposable.d.ts.map +1 -0
  230. package/dist/util/disposable.js +49 -0
  231. package/dist/util/markdown.d.ts +24 -0
  232. package/dist/util/markdown.d.ts.map +1 -0
  233. package/dist/util/markdown.js +220 -0
  234. package/dist/util/paths.d.ts +47 -0
  235. package/dist/util/paths.d.ts.map +1 -0
  236. package/dist/util/paths.js +134 -0
  237. package/dist/util/stream.d.ts +32 -0
  238. package/dist/util/stream.d.ts.map +1 -0
  239. package/dist/util/stream.js +206 -0
  240. package/dist/util/text.d.ts +65 -0
  241. package/dist/util/text.d.ts.map +1 -0
  242. package/dist/util/text.js +419 -0
  243. package/package.json +70 -0
  244. package/src/adapters/index.ts +11 -0
  245. package/src/app/app.ts +1096 -0
  246. package/src/core/animation.ts +144 -0
  247. package/src/core/clipboard.ts +40 -0
  248. package/src/core/commands.ts +169 -0
  249. package/src/core/components.ts +91 -0
  250. package/src/core/events.ts +95 -0
  251. package/src/core/focus.ts +358 -0
  252. package/src/core/i18n.ts +107 -0
  253. package/src/core/keybindings.ts +184 -0
  254. package/src/core/layers.ts +94 -0
  255. package/src/core/manifest.ts +84 -0
  256. package/src/core/navigation.ts +135 -0
  257. package/src/core/resources.ts +362 -0
  258. package/src/core/services.ts +69 -0
  259. package/src/core/store.ts +640 -0
  260. package/src/core/surfaces.ts +292 -0
  261. package/src/core/syntax.ts +200 -0
  262. package/src/core/when.ts +238 -0
  263. package/src/index.ts +76 -0
  264. package/src/jsx/factory.ts +124 -0
  265. package/src/jsx/intrinsics.ts +99 -0
  266. package/src/jsx/jsx-dev-runtime.ts +23 -0
  267. package/src/jsx/jsx-runtime.ts +76 -0
  268. package/src/render/buffer.ts +318 -0
  269. package/src/render/color.ts +180 -0
  270. package/src/render/diff.ts +99 -0
  271. package/src/render/layout.ts +764 -0
  272. package/src/render/static.ts +290 -0
  273. package/src/runtime/bindings.ts +150 -0
  274. package/src/runtime/hooks.ts +1057 -0
  275. package/src/runtime/instance.ts +284 -0
  276. package/src/runtime/paint.ts +737 -0
  277. package/src/runtime/reconcile.ts +335 -0
  278. package/src/runtime/runtime.ts +47 -0
  279. package/src/runtime/style.ts +205 -0
  280. package/src/themes/borders.ts +95 -0
  281. package/src/themes/builtin.ts +301 -0
  282. package/src/themes/glyphs.ts +101 -0
  283. package/src/themes/index.ts +4 -0
  284. package/src/themes/registry.ts +224 -0
  285. package/src/types/adapter.ts +41 -0
  286. package/src/types/animation.ts +34 -0
  287. package/src/types/app.ts +149 -0
  288. package/src/types/async.ts +35 -0
  289. package/src/types/capabilities.ts +79 -0
  290. package/src/types/cells.ts +79 -0
  291. package/src/types/command.ts +139 -0
  292. package/src/types/component-registry.ts +82 -0
  293. package/src/types/disposable.ts +8 -0
  294. package/src/types/focus.ts +77 -0
  295. package/src/types/geometry.ts +50 -0
  296. package/src/types/graph.ts +174 -0
  297. package/src/types/i18n.ts +25 -0
  298. package/src/types/index.ts +31 -0
  299. package/src/types/input.ts +81 -0
  300. package/src/types/keybinding.ts +51 -0
  301. package/src/types/layer.ts +46 -0
  302. package/src/types/manifest.ts +101 -0
  303. package/src/types/markdown.ts +47 -0
  304. package/src/types/navigation.ts +42 -0
  305. package/src/types/render.ts +86 -0
  306. package/src/types/resource.ts +185 -0
  307. package/src/types/services.ts +28 -0
  308. package/src/types/shell.ts +30 -0
  309. package/src/types/store.ts +148 -0
  310. package/src/types/stream.ts +24 -0
  311. package/src/types/style.ts +205 -0
  312. package/src/types/surface.ts +119 -0
  313. package/src/types/syntax.ts +93 -0
  314. package/src/types/terminal.ts +58 -0
  315. package/src/types/theme.ts +121 -0
  316. package/src/types/when.ts +21 -0
  317. package/src/ui/primitives.ts +118 -0
  318. package/src/ui/screen.ts +41 -0
  319. package/src/util/disposable.ts +49 -0
  320. package/src/util/markdown.ts +225 -0
  321. package/src/util/paths.ts +138 -0
  322. package/src/util/stream.ts +213 -0
  323. package/src/util/text.ts +428 -0
@@ -0,0 +1,50 @@
1
+ /** Terminal geometry is integral cells. Never fractional. */
2
+ export interface Point {
3
+ x: number;
4
+ y: number;
5
+ }
6
+
7
+ export interface Size {
8
+ width: number;
9
+ height: number;
10
+ }
11
+
12
+ export interface Rect {
13
+ x: number;
14
+ y: number;
15
+ width: number;
16
+ height: number;
17
+ }
18
+
19
+ /** padding / margin / border widths, in cells. */
20
+ export interface Edges {
21
+ top: number;
22
+ right: number;
23
+ bottom: number;
24
+ left: number;
25
+ }
26
+
27
+ export type EdgeSpec =
28
+ | number
29
+ | [vertical: number, horizontal: number]
30
+ | [top: number, horizontal: number, bottom: number]
31
+ | [top: number, right: number, bottom: number, left: number]
32
+ | Partial<Edges>;
33
+
34
+ export const ZERO_EDGES: Edges = { top: 0, right: 0, bottom: 0, left: 0 };
35
+
36
+ export function rectContains(r: Rect, x: number, y: number): boolean {
37
+ return x >= r.x && x < r.x + r.width && y >= r.y && y < r.y + r.height;
38
+ }
39
+
40
+ export function rectIntersect(a: Rect, b: Rect): Rect {
41
+ const x = Math.max(a.x, b.x);
42
+ const y = Math.max(a.y, b.y);
43
+ const right = Math.min(a.x + a.width, b.x + b.width);
44
+ const bottom = Math.min(a.y + a.height, b.y + b.height);
45
+ return { x, y, width: Math.max(0, right - x), height: Math.max(0, bottom - y) };
46
+ }
47
+
48
+ export function rectEquals(a: Rect, b: Rect): boolean {
49
+ return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
50
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * The component graph.
3
+ *
4
+ * A screen IS its root ComponentNode. JSX compiles to exactly this shape -
5
+ * `<Row gap={1}/>` and `{ component: 'Row', gap: 1 }` are the same value - so
6
+ * a screen can be written in TypeScript, loaded from JSON, generated, edited
7
+ * or sent over a wire without changing the runtime that mounts it.
8
+ *
9
+ * Three keys are reserved on every node: `id`, `component`, `$meta`.
10
+ * Everything else is props, and props are the component's business.
11
+ */
12
+ export type NodeId = string;
13
+
14
+ /**
15
+ * JSON-Pointer-shaped store path.
16
+ *
17
+ * `$/seg/seg` - absolute; the first segment is a scope.
18
+ * `/seg/seg` - relative to the surrounding data context.
19
+ * `..` - forbidden. Escape to the root with `$/` instead, so a node's
20
+ * meaning never depends on where it was pasted.
21
+ * `*` - wildcard segment, subscriptions only (writes throw).
22
+ * `#/seg` - the value AT this path is itself a path; one extra hop.
23
+ * `{{ /seg }}` inside a path substitutes another path's value first.
24
+ */
25
+ export type BindingPath = `$/${string}` | `/${string}`;
26
+
27
+ /**
28
+ * Transient event path. Same shape, different lifetime: events are delivered
29
+ * and forgotten, never stored. `@/dialog/confirm`, `@/agent/restart`.
30
+ */
31
+ export type EventPath = `@/${string}`;
32
+
33
+ export type DataBinding = { path: BindingPath };
34
+
35
+ export type FunctionCall = {
36
+ call: string;
37
+ args?: Record<string, PropValue>;
38
+ /** Refuse to route this to a remote dispatcher. */
39
+ callableFrom?: 'clientOnly';
40
+ };
41
+
42
+ export type DynamicValue =
43
+ | string | number | boolean | string[]
44
+ | DataBinding | FunctionCall;
45
+
46
+ export type DynamicString = string | DataBinding | FunctionCall;
47
+ export type DynamicNumber = number | DataBinding | FunctionCall;
48
+ export type DynamicBoolean = boolean | DataBinding | FunctionCall;
49
+ export type DynamicStringList = string[] | DataBinding | FunctionCall;
50
+
51
+ /** Inline children, or one instance of `template` per item at `path`. */
52
+ export type ChildList =
53
+ | ComponentNode[]
54
+ | { template: ComponentNode; path: BindingPath };
55
+
56
+ /**
57
+ * Discriminated by key presence:
58
+ * 'emit' in action -> publish on an event path
59
+ * 'functionCall' in action -> run a registered command
60
+ * 'handler' in action -> a closure. Never serializable; only legal for
61
+ * nodes built in-process (JSX), and stripped
62
+ * when a graph is exported.
63
+ */
64
+ export type Action =
65
+ | { emit: { path: EventPath; payload?: PropValue; } }
66
+ | { functionCall: FunctionCall }
67
+ | { handler: (...args: any[]) => void };
68
+
69
+ export type PropValue =
70
+ | string | number | boolean | null | undefined
71
+ | DataBinding
72
+ | FunctionCall
73
+ | Action
74
+ | ComponentNode
75
+ | ComponentNode[]
76
+ | { template: ComponentNode; path: BindingPath }
77
+ | { [k: string]: PropValue }
78
+ | PropValue[]
79
+ | ((...args: any[]) => unknown);
80
+
81
+ /** What a component threw, and which component threw it. */
82
+ export interface RenderError {
83
+ /** The thrown value, whatever it was. */
84
+ error: unknown;
85
+ /** `error.message`, or the value stringified. */
86
+ message: string;
87
+ /** The component that threw. */
88
+ component: string;
89
+ }
90
+
91
+ /**
92
+ * What to render when a component throws.
93
+ *
94
+ * A node keeps the graph data, and is handed the failure as the `error` and
95
+ * `errorMessage` props - so a registered `ErrorPanel` can show what happened
96
+ * without the registry holding a function. A function is for the local case,
97
+ * where the fallback wants the failure itself rather than two props.
98
+ */
99
+ export type ErrorFallback =
100
+ | ComponentNode
101
+ | ((failure: RenderError) => ComponentNode);
102
+
103
+ /** Internal only - stripped before a node is serialized back to a sender. */
104
+ export type NodeMeta = {
105
+ origin?: { format: string; version?: string; sourceNodeId?: NodeId };
106
+ /** Rendered instead when this node's subtree throws. */
107
+ fallback?: ErrorFallback;
108
+ /** Set by the JSX factory for a function component, so the registry can
109
+ * resolve the same function without a name collision. */
110
+ fn?: unknown;
111
+ /** Source location, when the JSX transform provides one. */
112
+ source?: { file: string; line: number; column: number };
113
+ };
114
+
115
+ export type ComponentNode = {
116
+ id?: NodeId;
117
+ component: string;
118
+ $meta?: NodeMeta;
119
+ /** Reconciliation identity among siblings. */
120
+ key?: string | number;
121
+ children?: PropValue | unknown;
122
+ [prop: string]: unknown;
123
+ };
124
+
125
+ /** A screen IS its root node. No separate {root, nodes} map. */
126
+ export type ScreenState = ComponentNode;
127
+
128
+ export function isComponentNode(v: unknown): v is ComponentNode {
129
+ return (
130
+ typeof v === 'object' && v !== null &&
131
+ 'component' in v && typeof (v as ComponentNode).component === 'string'
132
+ );
133
+ }
134
+
135
+ export function isDataBinding(v: unknown): v is DataBinding {
136
+ // Exactly one key, because that is what the type says: `{ path }`. Testing
137
+ // only that `path` is present made a binding out of anything that happens to
138
+ // carry one - `{ kind: 'unix', path: '/tmp/room' }` is a socket address, and
139
+ // it was resolved against the store and thrown as a PathError instead. The
140
+ // shape is far too common to claim loosely: a route, a file entry, a config
141
+ // section. The old guard listed `component` and `template` as exceptions,
142
+ // which was this same problem met twice and patched twice.
143
+ return (
144
+ typeof v === 'object' && v !== null &&
145
+ typeof (v as DataBinding).path === 'string' &&
146
+ Object.keys(v).length === 1
147
+ );
148
+ }
149
+
150
+ export function isFunctionCall(v: unknown): v is FunctionCall {
151
+ return (
152
+ typeof v === 'object' && v !== null &&
153
+ 'call' in v && typeof (v as FunctionCall).call === 'string' &&
154
+ !('component' in v)
155
+ );
156
+ }
157
+
158
+ export function isAction(v: unknown): v is Action {
159
+ return (
160
+ typeof v === 'object' && v !== null &&
161
+ ('emit' in v || 'functionCall' in v || 'handler' in v) &&
162
+ !('component' in v)
163
+ );
164
+ }
165
+
166
+ export function isTemplatedChildren(
167
+ v: unknown,
168
+ ): v is { template: ComponentNode; path: BindingPath } {
169
+ return (
170
+ typeof v === 'object' && v !== null &&
171
+ 'template' in v && 'path' in v &&
172
+ isComponentNode((v as { template: unknown }).template)
173
+ );
174
+ }
@@ -0,0 +1,25 @@
1
+ import type { Disposable } from './disposable.js';
2
+
3
+ export type LocaleId = string;
4
+
5
+ export interface TranslationBundle {
6
+ locale: LocaleId;
7
+ /** Flat or nested; nested keys are addressed with dots. */
8
+ messages: Record<string, unknown>;
9
+ }
10
+
11
+ export interface I18n {
12
+ locale: LocaleId;
13
+ setLocale(locale: LocaleId): void;
14
+ register(bundle: TranslationBundle): Disposable;
15
+ locales(): LocaleId[];
16
+ /** Missing keys fall back to the fallback locale, then to the key itself. */
17
+ t(key: string, values?: Record<string, unknown>): string;
18
+ /** Intl-backed; TextUI does not reimplement formatting. */
19
+ number(value: number, options?: Intl.NumberFormatOptions): string;
20
+ date(value: Date | number, options?: Intl.DateTimeFormatOptions): string;
21
+ relative(value: number, unit: Intl.RelativeTimeFormatUnit): string;
22
+ list(items: string[], options?: Intl.ListFormatOptions): string;
23
+ plural(count: number, forms: Record<string, string>): string;
24
+ onChange(fn: (locale: LocaleId) => void): Disposable;
25
+ }
@@ -0,0 +1,31 @@
1
+ export * from './disposable.js';
2
+ export * from './geometry.js';
3
+ export * from './capabilities.js';
4
+ export * from './cells.js';
5
+ export * from './style.js';
6
+ export * from './theme.js';
7
+ export * from './graph.js';
8
+ export * from './store.js';
9
+ export * from './input.js';
10
+ export * from './focus.js';
11
+ export * from './when.js';
12
+ export * from './command.js';
13
+ export * from './keybinding.js';
14
+ export * from './render.js';
15
+ export * from './component-registry.js';
16
+ export * from './resource.js';
17
+ export * from './surface.js';
18
+ export * from './shell.js';
19
+ export * from './navigation.js';
20
+ export * from './layer.js';
21
+ export * from './async.js';
22
+ export * from './stream.js';
23
+ export * from './animation.js';
24
+ export * from './i18n.js';
25
+ export * from './terminal.js';
26
+ export * from './services.js';
27
+ export * from './manifest.js';
28
+ export * from './app.js';
29
+ export * from './syntax.js';
30
+ export * from './adapter.js';
31
+ export * from './markdown.js';
@@ -0,0 +1,81 @@
1
+ import type { Disposable } from './disposable.js';
2
+
3
+ export interface KeyModifiers {
4
+ ctrl: boolean;
5
+ alt: boolean;
6
+ shift: boolean;
7
+ meta: boolean;
8
+ }
9
+
10
+ /**
11
+ * Canonical key name. Printable keys carry the character itself; everything
12
+ * else uses these names, so a keybinding string is stable across terminals.
13
+ */
14
+ export type KeyName =
15
+ | 'up' | 'down' | 'left' | 'right'
16
+ | 'enter' | 'escape' | 'tab' | 'backspace' | 'delete' | 'space'
17
+ | 'home' | 'end' | 'pageup' | 'pagedown' | 'insert'
18
+ | 'f1' | 'f2' | 'f3' | 'f4' | 'f5' | 'f6'
19
+ | 'f7' | 'f8' | 'f9' | 'f10' | 'f11' | 'f12'
20
+ | (string & {});
21
+
22
+ export interface KeyEvent {
23
+ type: 'key';
24
+ /** Canonical name, or the printable character. */
25
+ name: KeyName;
26
+ /** The character produced, when printable. */
27
+ char?: string;
28
+ ctrl: boolean;
29
+ alt: boolean;
30
+ shift: boolean;
31
+ meta: boolean;
32
+ /** Raw bytes, for adapters and diagnostics. */
33
+ raw: string;
34
+ /** Set by a handler to stop propagation up the focus chain. */
35
+ handled: boolean;
36
+ /** Kitty protocol only - press/repeat/release. */
37
+ kind?: 'press' | 'repeat' | 'release';
38
+ }
39
+
40
+ export type MouseButton = 'left' | 'middle' | 'right' | 'none';
41
+ export type MouseAction = 'down' | 'up' | 'move' | 'drag' | 'wheel';
42
+
43
+ export interface MouseEvent {
44
+ type: 'mouse';
45
+ action: MouseAction;
46
+ button: MouseButton;
47
+ /** Terminal cell coordinates, 0-based. */
48
+ x: number;
49
+ y: number;
50
+ /** Negative up, positive down. */
51
+ wheel?: number;
52
+ ctrl: boolean;
53
+ alt: boolean;
54
+ shift: boolean;
55
+ handled: boolean;
56
+ }
57
+
58
+ export interface PasteEvent {
59
+ type: 'paste';
60
+ text: string;
61
+ handled: boolean;
62
+ }
63
+
64
+ /** Terminal-level focus (the window), not component focus. */
65
+ export interface TerminalFocusEvent {
66
+ type: 'terminal-focus';
67
+ focused: boolean;
68
+ }
69
+
70
+ export interface ResizeEvent {
71
+ type: 'resize';
72
+ width: number;
73
+ height: number;
74
+ }
75
+
76
+ export type InputEvent =
77
+ | KeyEvent | MouseEvent | PasteEvent | TerminalFocusEvent | ResizeEvent;
78
+
79
+ export interface InputSource extends Disposable {
80
+ on(fn: (event: InputEvent) => void): Disposable;
81
+ }
@@ -0,0 +1,51 @@
1
+ import type { Disposable } from './disposable.js';
2
+ import type { WhenClause } from './when.js';
3
+ import type { KeyEvent } from './input.js';
4
+
5
+ /**
6
+ * A chord string: `ctrl+p`, `ctrl+k ctrl+s` (a sequence), `shift+tab`, `g g`.
7
+ * Names match `KeyName`; modifiers are ctrl/alt/shift/meta in that order.
8
+ */
9
+ export type Chord = string;
10
+
11
+ export interface KeybindingDefinition {
12
+ keys: Chord;
13
+ commandId: string;
14
+ args?: Record<string, unknown>;
15
+ /**
16
+ * What *this key* does, when the command's own title does not say it.
17
+ *
18
+ * A binding that carries arguments runs one invocation of a command, not the
19
+ * command: `ctrl+b` is "Toggle Sidebar" and the command is "Toggle Surface".
20
+ * Without this the shortcut sheet files the key under the general title and
21
+ * says something that is not true of the key.
22
+ */
23
+ title?: string;
24
+ when?: WhenClause;
25
+ /** Only fires while this focus scope (or one inside it) is active. */
26
+ scopeId?: string;
27
+ /** Higher wins on conflict. Defaults to registration order. */
28
+ priority?: number;
29
+ }
30
+
31
+ export interface KeybindingRegistry {
32
+ register(def: KeybindingDefinition): Disposable;
33
+ unregister(keys: Chord, commandId?: string): void;
34
+ list(): KeybindingDefinition[];
35
+ /**
36
+ * Chords bound to a command, for rendering hints next to menu rows.
37
+ *
38
+ * Argument-bearing bindings are left out: they run one invocation and not
39
+ * the command, so offering one as *the* key for the command's menu row
40
+ * names a key that does something else. Match on `args` through `list()`
41
+ * when the specific invocation is what is wanted.
42
+ */
43
+ forCommand(commandId: string): Chord[];
44
+ /**
45
+ * Feed a key in. Returns 'handled', 'pending' (a prefix of a longer chord),
46
+ * or 'unhandled'.
47
+ */
48
+ handle(event: KeyEvent): 'handled' | 'pending' | 'unhandled';
49
+ /** Abandon a partially typed chord. */
50
+ reset(): void;
51
+ }
@@ -0,0 +1,46 @@
1
+ import type { Disposable } from './disposable.js';
2
+ import type { ComponentNode } from './graph.js';
3
+ import type { Rect } from './geometry.js';
4
+
5
+ /** Painting and input order. A layer is a plane, not a component. */
6
+ export type LayerName = 'base' | 'floating' | 'modal' | 'notification' | 'debug';
7
+
8
+ export type AnchorSide = 'top' | 'right' | 'bottom' | 'left';
9
+ export type AnchorAlign = 'start' | 'center' | 'end';
10
+
11
+ /** Position a layer entry relative to a focusable, a rect, or the screen. */
12
+ export type LayerPosition =
13
+ | { kind: 'center' }
14
+ | { kind: 'screen'; rect: Partial<Rect> }
15
+ | { kind: 'anchor'; targetId: string; side: AnchorSide; align?: AnchorAlign; offset?: number }
16
+ | { kind: 'point'; x: number; y: number }
17
+ | { kind: 'cursor' };
18
+
19
+ export interface LayerEntry {
20
+ id: string;
21
+ layer: LayerName;
22
+ node: ComponentNode;
23
+ position?: LayerPosition;
24
+ /** Dim everything beneath. Modals want this. */
25
+ scrim?: boolean;
26
+ /** Trap focus inside and restore it on close. */
27
+ trapFocus?: boolean;
28
+ /** Escape closes it. */
29
+ dismissOnEscape?: boolean;
30
+ /** A click outside closes it. */
31
+ dismissOnOutsideClick?: boolean;
32
+ /** Auto-remove after this many ms. Toasts want this. */
33
+ timeoutMs?: number;
34
+ onClose?(reason: 'escape' | 'outside' | 'timeout' | 'api'): void;
35
+ order?: number;
36
+ }
37
+
38
+ export interface LayerManager {
39
+ open(entry: LayerEntry): Disposable;
40
+ close(id: string, reason?: 'escape' | 'outside' | 'timeout' | 'api'): void;
41
+ closeLayer(layer: LayerName): void;
42
+ entries(layer?: LayerName): LayerEntry[];
43
+ /** The innermost entry that traps focus, if any. */
44
+ topmostTrap(): LayerEntry | null;
45
+ update(id: string, patch: Partial<LayerEntry>): void;
46
+ }
@@ -0,0 +1,101 @@
1
+ import type { Disposable } from './disposable.js';
2
+ import type { ComponentDefinition } from './component-registry.js';
3
+ import type { CommandDefinition } from './command.js';
4
+ import type { KeybindingDefinition } from './keybinding.js';
5
+ import type { ThemeDefinition } from './theme.js';
6
+ import type { ShellDefinition } from './shell.js';
7
+ import type { LayoutDefinition, Mount } from './surface.js';
8
+ import type { ScreenDefinition } from './navigation.js';
9
+ import type {
10
+ ResourceActionDefinition, ResourceEditorDefinition, ResourceKind,
11
+ ResourceProvider, ResourceViewerDefinition,
12
+ } from './resource.js';
13
+ import type { ComputedDefinition, DataProviderDefinition } from './store.js';
14
+ import type { BindingPath } from './graph.js';
15
+ import type { CapabilityName } from './capabilities.js';
16
+
17
+ /**
18
+ * One source contributing to the typed registries. Deliberately not a generic
19
+ * plugin bag: every category is its own list with its own type, so a bad
20
+ * contribution fails where it is written.
21
+ */
22
+ export interface ManifestSource {
23
+ id: string;
24
+ version?: string;
25
+ displayName?: string;
26
+ /** One line, for a list of sources that has room to say what each one is. */
27
+ description?: string;
28
+ }
29
+
30
+ export interface Contributes {
31
+ components?: ComponentDefinition[];
32
+ commands?: CommandDefinition[];
33
+ keybindings?: KeybindingDefinition[];
34
+ themes?: ThemeDefinition[];
35
+ shells?: ShellDefinition[];
36
+ layouts?: LayoutDefinition[];
37
+ screens?: ScreenDefinition[];
38
+ views?: Mount[];
39
+ resourceKinds?: ResourceKind[];
40
+ resourceProviders?: ResourceProvider[];
41
+ resourceViewers?: ResourceViewerDefinition[];
42
+ resourceEditors?: ResourceEditorDefinition[];
43
+ resourceActions?: ResourceActionDefinition[];
44
+ dataProviders?: DataProviderDefinition[];
45
+ computed?: { path: BindingPath; def: ComputedDefinition }[];
46
+ }
47
+
48
+ export interface Manifest {
49
+ source: ManifestSource;
50
+ /** Other manifest ids that must load first. */
51
+ requires?: string[];
52
+ engine?: { textui: string };
53
+ /** Refuse to load without these terminal capabilities. */
54
+ requiresCapabilities?: CapabilityName[];
55
+ contributes?: Contributes;
56
+ }
57
+
58
+ export interface ManifestAPI {
59
+ load(manifest: Manifest): Promise<Disposable>;
60
+ unload(sourceId: string): void;
61
+ sources(): ManifestSource[];
62
+ loaded(sourceId: string): boolean;
63
+ }
64
+
65
+ /**
66
+ * Registry manifest metadata - what the CLI reads to copy a component's source
67
+ * into a user's project and to tell later what changed upstream.
68
+ */
69
+ export interface RegistryComponentManifest {
70
+ name: string;
71
+ description?: string;
72
+ category?: string;
73
+ version: string;
74
+ /** Files copied into the project, relative to the registry root. */
75
+ files: { path: string; target?: string; type?: 'component' | 'style' | 'test' | 'example' }[];
76
+ /** Other registry components this one needs. */
77
+ dependencies?: string[];
78
+ /** npm packages this one needs. */
79
+ npmDependencies?: Record<string, string>;
80
+ requiredCapabilities?: CapabilityName[];
81
+ optionalCapabilities?: CapabilityName[];
82
+ variants?: string[];
83
+ /** Store paths this component binds to by convention. */
84
+ storeBindings?: string[];
85
+ related?: string[];
86
+ examples?: { name: string; file: string }[];
87
+ /** Templates that include this component. */
88
+ templates?: string[];
89
+ /** Content hash of the copied files, so the CLI can detect local edits. */
90
+ hash?: string;
91
+ }
92
+
93
+ export interface RegistryManifest {
94
+ name: string;
95
+ version: string;
96
+ description?: string;
97
+ homepage?: string;
98
+ components: RegistryComponentManifest[];
99
+ themes?: { name: string; file: string; appearance: 'light' | 'dark' }[];
100
+ templates?: { name: string; description?: string; files: string[]; components: string[] }[];
101
+ }
@@ -0,0 +1,47 @@
1
+ import type { StyleColor } from './style.js';
2
+
3
+ /**
4
+ * Markdown, as rows a terminal can scroll.
5
+ *
6
+ * Two shapes and one invariant: **every row is exactly one row tall.** That is
7
+ * what makes "how far can this scroll" a length rather than an estimate - one
8
+ * source line becomes three rows when it wraps and none when it is a fence
9
+ * marker, so counting source lines is counting the wrong unit and the tail of
10
+ * a long document becomes unreachable.
11
+ *
12
+ * A fence is the exception that proves it: it is several rows, so it becomes
13
+ * several rows here, each tagged with the fence it belongs to so a painter can
14
+ * put the visible ones back into one box.
15
+ */
16
+
17
+ /** A run of text with one style. Inline emphasis is why rows are not strings. */
18
+ export interface MarkdownRun {
19
+ text: string;
20
+ bold?: boolean;
21
+ italic?: boolean;
22
+ code?: boolean;
23
+ /** An OSC 8 target, where the terminal has hyperlinks. */
24
+ link?: string;
25
+ }
26
+
27
+ export type MarkdownRow =
28
+ | { kind: 'rule' }
29
+ | { kind: 'heading'; runs: MarkdownRun[]; level: number }
30
+ | { kind: 'text'; runs: MarkdownRun[]; prefix?: string; prefixFg?: StyleColor; fg?: StyleColor }
31
+ | { kind: 'fence'; fence: number; part: 'open' | 'code' | 'close'; text?: string; language?: string };
32
+
33
+ export interface MarkdownLayoutOptions {
34
+ /** Cells to wrap to. Zero means "not measured yet" - nothing is wrapped. */
35
+ width: number;
36
+ /** The bullet glyph. Passed in, because glyphs come from the theme. */
37
+ bullet?: string;
38
+ /** The rule down the left of a block quote. Also a theme glyph. */
39
+ quoteBar?: string;
40
+ /**
41
+ * Whether a fence gets an opening and closing rule row.
42
+ *
43
+ * A borderless theme draws neither, and a layout that reserved two rows for
44
+ * rules nobody draws stops two rows short of the end of the document.
45
+ */
46
+ ruled?: boolean;
47
+ }
@@ -0,0 +1,42 @@
1
+ import type { Disposable } from './disposable.js';
2
+ import type { ComponentNode } from './graph.js';
3
+ import type { MountDisplay, SurfaceName } from './surface.js';
4
+
5
+ /**
6
+ * Screens and a stack, not a router. An application that wants URLs maps them
7
+ * onto screens itself.
8
+ */
9
+ export interface ScreenDefinition {
10
+ id: string;
11
+ /** Component name, or the node itself. */
12
+ component: string | ComponentNode;
13
+ display?: MountDisplay;
14
+ /**
15
+ * Where it mounts. `main` unless a screen wants to live somewhere else - a
16
+ * surface is the application's word, so this is open like the rest of them.
17
+ */
18
+ surface?: SurfaceName;
19
+ /** Screens keep their store scope when navigated away from. */
20
+ keepAlive?: boolean;
21
+ }
22
+
23
+ export interface ScreenEntry {
24
+ id: string;
25
+ params?: Record<string, unknown>;
26
+ /** Focus id to restore when this entry becomes current again. */
27
+ restoreFocus?: string | null;
28
+ }
29
+
30
+ export interface Navigator {
31
+ register(screen: ScreenDefinition): Disposable;
32
+ screens(): ScreenDefinition[];
33
+ get(id: string): ScreenDefinition | undefined;
34
+ push(id: string, params?: Record<string, unknown>): void;
35
+ replace(id: string, params?: Record<string, unknown>): void;
36
+ pop(): boolean;
37
+ popTo(id: string): boolean;
38
+ reset(id: string, params?: Record<string, unknown>): void;
39
+ current(): ScreenEntry | null;
40
+ stack(): ScreenEntry[];
41
+ canGoBack(): boolean;
42
+ }