@theoremjs/react 0.0.0-stage → 0.3.1

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 (320) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +772 -2
  3. package/client/attachment-hover-preview.d.ts +11 -0
  4. package/client/attachment-hover-preview.js +36 -0
  5. package/client/audio-level.d.ts +5 -0
  6. package/client/audio-level.js +24 -0
  7. package/client/composer-attachments.d.ts +30 -0
  8. package/client/composer-attachments.js +33 -0
  9. package/client/composer-drawer.d.ts +19 -0
  10. package/client/composer-drawer.js +15 -0
  11. package/client/composer-hints.d.ts +25 -0
  12. package/client/composer-hints.js +20 -0
  13. package/client/composer-primary.d.ts +16 -0
  14. package/client/composer-primary.js +25 -0
  15. package/client/decision-images.d.ts +76 -0
  16. package/client/decision-images.js +139 -0
  17. package/client/decision-transport.d.ts +70 -0
  18. package/client/decision-transport.js +175 -0
  19. package/client/decode-composer-draft.d.ts +11 -0
  20. package/client/decode-composer-draft.js +12 -0
  21. package/client/embedding-input.d.ts +84 -0
  22. package/client/embedding-input.js +194 -0
  23. package/client/embedding-space.d.ts +82 -0
  24. package/client/embedding-space.js +389 -0
  25. package/client/embedding-transport.d.ts +40 -0
  26. package/client/embedding-transport.js +71 -0
  27. package/client/encode-composer-draft.d.ts +9 -0
  28. package/client/encode-composer-draft.js +34 -0
  29. package/client/encode-files.d.ts +18 -0
  30. package/client/encode-files.js +54 -0
  31. package/client/failure.d.ts +29 -0
  32. package/client/failure.js +34 -0
  33. package/client/generation-selection.d.ts +15 -0
  34. package/client/generation-selection.js +24 -0
  35. package/client/host-call.d.ts +51 -0
  36. package/client/host-call.js +47 -0
  37. package/client/host-transport.d.ts +70 -0
  38. package/client/host-transport.js +75 -0
  39. package/client/image-output.d.ts +6 -0
  40. package/client/image-output.js +13 -0
  41. package/client/index.d.ts +28 -0
  42. package/client/index.js +22 -0
  43. package/client/ink-waveform.d.ts +17 -0
  44. package/client/ink-waveform.js +68 -0
  45. package/client/live/apply-live-turn-tool-event.d.ts +14 -0
  46. package/client/live/apply-live-turn-tool-event.js +39 -0
  47. package/client/live/live-captions.d.ts +53 -0
  48. package/client/live/live-captions.js +174 -0
  49. package/client/live/live-mic-forward.d.ts +30 -0
  50. package/client/live/live-mic-forward.js +46 -0
  51. package/client/live/live-page-tool.d.ts +34 -0
  52. package/client/live/live-page-tool.js +11 -0
  53. package/client/live/live-state.d.ts +13 -0
  54. package/client/live/live-state.js +22 -0
  55. package/client/live/live-tool.d.ts +11 -0
  56. package/client/live/live-tool.js +1 -0
  57. package/client/live/live-video.d.ts +10 -0
  58. package/client/live/live-video.js +71 -0
  59. package/client/live/run-live-tool-call.d.ts +22 -0
  60. package/client/live/run-live-tool-call.js +70 -0
  61. package/client/live/use-live-caption-log.d.ts +17 -0
  62. package/client/live/use-live-caption-log.js +51 -0
  63. package/client/live-client.d.ts +189 -0
  64. package/client/live-client.js +829 -0
  65. package/client/live-errors.d.ts +2 -0
  66. package/client/live-errors.js +9 -0
  67. package/client/live-messages.d.ts +148 -0
  68. package/client/live-messages.js +100 -0
  69. package/client/mic-capture.d.ts +4 -0
  70. package/client/mic-capture.js +6 -0
  71. package/client/oauth-popup.d.ts +26 -0
  72. package/client/oauth-popup.js +30 -0
  73. package/client/page-dispatch.d.ts +15 -0
  74. package/client/page-dispatch.js +63 -0
  75. package/client/pcm-downsample.d.ts +4 -0
  76. package/client/pcm-downsample.js +45 -0
  77. package/client/run-commit.d.ts +34 -0
  78. package/client/run-commit.js +49 -0
  79. package/client/run-session.d.ts +79 -0
  80. package/client/run-session.js +207 -0
  81. package/client/schema-fields.d.ts +63 -0
  82. package/client/schema-fields.js +199 -0
  83. package/client/shaped-data.d.ts +118 -0
  84. package/client/shaped-data.js +343 -0
  85. package/client/source-citations.d.ts +13 -0
  86. package/client/source-citations.js +56 -0
  87. package/client/space-geometry.d.ts +39 -0
  88. package/client/space-geometry.js +183 -0
  89. package/client/state-fields.d.ts +16 -0
  90. package/client/state-fields.js +44 -0
  91. package/client/tool-result.d.ts +78 -0
  92. package/client/tool-result.js +293 -0
  93. package/client/tool-resume.d.ts +50 -0
  94. package/client/tool-resume.js +14 -0
  95. package/client/trace-feed.d.ts +13 -0
  96. package/client/trace-feed.js +18 -0
  97. package/client/trace-story.d.ts +163 -0
  98. package/client/trace-story.js +440 -0
  99. package/client/trace-view.d.ts +130 -0
  100. package/client/trace-view.js +333 -0
  101. package/client/transcript-groups.d.ts +140 -0
  102. package/client/transcript-groups.js +217 -0
  103. package/client/transcript-schema.d.ts +10 -0
  104. package/client/transcript-schema.js +120 -0
  105. package/client/transcript-scroll.d.ts +7 -0
  106. package/client/transcript-scroll.js +6 -0
  107. package/client/transport.d.ts +264 -0
  108. package/client/transport.js +330 -0
  109. package/client/turn-client.d.ts +44 -0
  110. package/client/turn-client.js +88 -0
  111. package/client/voice-label.d.ts +2 -0
  112. package/client/voice-label.js +15 -0
  113. package/client/voice-recorder.d.ts +27 -0
  114. package/client/voice-recorder.js +162 -0
  115. package/client/wire-line.d.ts +56 -0
  116. package/client/wire-line.js +90 -0
  117. package/client/worklets/mic-capture.js +16 -0
  118. package/components/InkWaveform.d.ts +21 -0
  119. package/components/InkWaveform.js +131 -0
  120. package/components/live/use-live-runner-controls.d.ts +47 -0
  121. package/components/live/use-live-runner-controls.js +96 -0
  122. package/components/live/use-live-runner-model.d.ts +49 -0
  123. package/components/live/use-live-runner-model.js +190 -0
  124. package/components/live/use-live-runner-ui.d.ts +67 -0
  125. package/components/live/use-live-runner-ui.js +167 -0
  126. package/components/live/use-live-session-client.d.ts +41 -0
  127. package/components/live/use-live-session-client.js +126 -0
  128. package/components/use-composer-voice.d.ts +28 -0
  129. package/components/use-composer-voice.js +90 -0
  130. package/components/use-editor-selection.d.ts +3 -0
  131. package/components/use-editor-selection.js +19 -0
  132. package/components/use-voice-playback.d.ts +17 -0
  133. package/components/use-voice-playback.js +68 -0
  134. package/hooks/use-described.d.ts +12 -0
  135. package/hooks/use-described.js +25 -0
  136. package/hooks/use-embedding-index.d.ts +27 -0
  137. package/hooks/use-embedding-index.js +43 -0
  138. package/hooks/use-one-call.d.ts +31 -0
  139. package/hooks/use-one-call.js +76 -0
  140. package/hooks/use-page-tool-warnings.d.ts +6 -0
  141. package/hooks/use-page-tool-warnings.js +25 -0
  142. package/hooks/use-second-ticker.d.ts +2 -0
  143. package/hooks/use-second-ticker.js +13 -0
  144. package/hooks/use-theorem-chat-actions.d.ts +79 -0
  145. package/hooks/use-theorem-chat-actions.js +287 -0
  146. package/hooks/use-theorem-chat-state.d.ts +66 -0
  147. package/hooks/use-theorem-chat-state.js +122 -0
  148. package/hooks/use-theorem-chat.d.ts +97 -0
  149. package/hooks/use-theorem-chat.js +528 -0
  150. package/hooks/use-theorem-decision.d.ts +18 -0
  151. package/hooks/use-theorem-decision.js +12 -0
  152. package/hooks/use-theorem-embedding.d.ts +18 -0
  153. package/hooks/use-theorem-embedding.js +12 -0
  154. package/hooks/use-theorem-host.d.ts +45 -0
  155. package/hooks/use-theorem-host.js +135 -0
  156. package/hooks/use-theorem-interface.d.ts +22 -0
  157. package/hooks/use-theorem-interface.js +15 -0
  158. package/hooks/use-trace-records.d.ts +4 -0
  159. package/hooks/use-trace-records.js +7 -0
  160. package/index.d.ts +17 -0
  161. package/index.js +17 -0
  162. package/live.d.ts +9 -0
  163. package/live.js +10 -0
  164. package/package.json +74 -4
  165. package/server/checkpoint-ownership.d.ts +6 -0
  166. package/server/checkpoint-ownership.js +42 -0
  167. package/server/conversation-store.d.ts +92 -0
  168. package/server/conversation-store.js +131 -0
  169. package/server/conversation.d.ts +193 -0
  170. package/server/conversation.js +552 -0
  171. package/server/credential-store.d.ts +24 -0
  172. package/server/credential-store.js +14 -0
  173. package/server/decision-handler.d.ts +42 -0
  174. package/server/decision-handler.js +46 -0
  175. package/server/embedding-handler.d.ts +33 -0
  176. package/server/embedding-handler.js +45 -0
  177. package/server/handler.d.ts +152 -0
  178. package/server/handler.js +771 -0
  179. package/server/json-response.d.ts +2 -0
  180. package/server/json-response.js +7 -0
  181. package/server/mod.d.ts +25 -0
  182. package/server/mod.js +23 -0
  183. package/server/page-dispatch.d.ts +22 -0
  184. package/server/page-dispatch.js +127 -0
  185. package/server/request-body.d.ts +2 -0
  186. package/server/request-body.js +42 -0
  187. package/server/request-check.d.ts +21 -0
  188. package/server/request-check.js +49 -0
  189. package/server/session-authority.d.ts +8 -0
  190. package/server/session-authority.js +78 -0
  191. package/server/session-boundary.d.ts +26 -0
  192. package/server/session-boundary.js +64 -0
  193. package/server/session-identity.d.ts +16 -0
  194. package/server/session-identity.js +41 -0
  195. package/server/session-limits.d.ts +12 -0
  196. package/server/session-limits.js +59 -0
  197. package/server/session-store.d.ts +123 -0
  198. package/server/session-store.js +264 -0
  199. package/server/single-action.d.ts +21 -0
  200. package/server/single-action.js +30 -0
  201. package/server/steer-inbox.d.ts +35 -0
  202. package/server/steer-inbox.js +52 -0
  203. package/server/tool-operations.d.ts +6 -0
  204. package/server/tool-operations.js +132 -0
  205. package/server/turn-input.d.ts +10 -0
  206. package/server/turn-input.js +29 -0
  207. package/styles/ink-controls.css +134 -0
  208. package/ui/CardWall.d.ts +10 -0
  209. package/ui/CardWall.js +61 -0
  210. package/ui/ChatComposerBar.d.ts +62 -0
  211. package/ui/ChatComposerBar.js +306 -0
  212. package/ui/ChatTranscript.d.ts +43 -0
  213. package/ui/ChatTranscript.js +527 -0
  214. package/ui/ConsoleFrame.d.ts +104 -0
  215. package/ui/ConsoleFrame.js +146 -0
  216. package/ui/DecisionAnswers.d.ts +53 -0
  217. package/ui/DecisionAnswers.js +233 -0
  218. package/ui/DecisionImages.d.ts +16 -0
  219. package/ui/DecisionImages.js +46 -0
  220. package/ui/EmbeddingDocuments.d.ts +78 -0
  221. package/ui/EmbeddingDocuments.js +278 -0
  222. package/ui/EmbeddingQuery.d.ts +27 -0
  223. package/ui/EmbeddingQuery.js +95 -0
  224. package/ui/EmbeddingResults.d.ts +41 -0
  225. package/ui/EmbeddingResults.js +165 -0
  226. package/ui/EmbeddingSpace.d.ts +26 -0
  227. package/ui/EmbeddingSpace.js +106 -0
  228. package/ui/LiveCaptionsPanel.d.ts +22 -0
  229. package/ui/LiveCaptionsPanel.js +27 -0
  230. package/ui/LiveRunner.d.ts +30 -0
  231. package/ui/LiveRunner.js +180 -0
  232. package/ui/PaneState.d.ts +33 -0
  233. package/ui/PaneState.js +50 -0
  234. package/ui/SchemaFields.d.ts +10 -0
  235. package/ui/SchemaFields.js +150 -0
  236. package/ui/ShapedData.d.ts +11 -0
  237. package/ui/ShapedData.js +196 -0
  238. package/ui/SidePanel.d.ts +126 -0
  239. package/ui/SidePanel.js +123 -0
  240. package/ui/StateFields.d.ts +44 -0
  241. package/ui/StateFields.js +139 -0
  242. package/ui/TheoremChat.d.ts +122 -0
  243. package/ui/TheoremChat.js +134 -0
  244. package/ui/TheoremDecision.d.ts +30 -0
  245. package/ui/TheoremDecision.js +130 -0
  246. package/ui/TheoremEmbedding.d.ts +27 -0
  247. package/ui/TheoremEmbedding.js +122 -0
  248. package/ui/TheoremHost.d.ts +55 -0
  249. package/ui/TheoremHost.js +240 -0
  250. package/ui/ToolGateCard.d.ts +32 -0
  251. package/ui/ToolGateCard.js +107 -0
  252. package/ui/ToolResult.d.ts +10 -0
  253. package/ui/ToolResult.js +62 -0
  254. package/ui/ToolResultCharts.d.ts +5 -0
  255. package/ui/ToolResultCharts.js +103 -0
  256. package/ui/TraceCharts.d.ts +13 -0
  257. package/ui/TraceCharts.js +266 -0
  258. package/ui/TraceGuardrails.d.ts +11 -0
  259. package/ui/TraceGuardrails.js +74 -0
  260. package/ui/TraceInspector.d.ts +16 -0
  261. package/ui/TraceInspector.js +206 -0
  262. package/ui/TraceInspectorPanel.d.ts +46 -0
  263. package/ui/TraceInspectorPanel.js +95 -0
  264. package/ui/TraceOverview.d.ts +38 -0
  265. package/ui/TraceOverview.js +126 -0
  266. package/ui/TraceSpanDetail.d.ts +10 -0
  267. package/ui/TraceSpanDetail.js +190 -0
  268. package/ui/TraceStory.d.ts +20 -0
  269. package/ui/TraceStory.js +108 -0
  270. package/ui/TraceValues.d.ts +36 -0
  271. package/ui/TraceValues.js +123 -0
  272. package/ui/TraceWaterfall.d.ts +13 -0
  273. package/ui/TraceWaterfall.js +135 -0
  274. package/ui/VoiceNote.d.ts +12 -0
  275. package/ui/VoiceNote.js +28 -0
  276. package/ui/approval-heading.d.ts +4 -0
  277. package/ui/approval-heading.js +9 -0
  278. package/ui/arrive.d.ts +18 -0
  279. package/ui/arrive.js +46 -0
  280. package/ui/built/theme.css +792 -0
  281. package/ui/built/theme.css.d.ts +9 -0
  282. package/ui/built/theorem.d.ts +13 -0
  283. package/ui/built/theorem.js +660 -0
  284. package/ui/built/theorem.variants.d.ts +22 -0
  285. package/ui/code-language.d.ts +12 -0
  286. package/ui/code-language.js +50 -0
  287. package/ui/disclosure-motion.d.ts +6 -0
  288. package/ui/disclosure-motion.js +207 -0
  289. package/ui/embedding-space-gl.d.ts +37 -0
  290. package/ui/embedding-space-gl.js +663 -0
  291. package/ui/embedding-space-view.d.ts +8 -0
  292. package/ui/embedding-space-view.js +8 -0
  293. package/ui/glide.d.ts +7 -0
  294. package/ui/glide.js +44 -0
  295. package/ui/icons.d.ts +4 -0
  296. package/ui/icons.js +38 -0
  297. package/ui/index.d.ts +36 -0
  298. package/ui/index.js +39 -0
  299. package/ui/labels-provider.d.ts +16 -0
  300. package/ui/labels-provider.js +64 -0
  301. package/ui/labels.d.ts +1442 -0
  302. package/ui/labels.js +1443 -0
  303. package/ui/markdown-plugins.d.ts +9 -0
  304. package/ui/markdown-plugins.js +13 -0
  305. package/ui/mcp-icon.d.ts +6 -0
  306. package/ui/mcp-icon.js +8 -0
  307. package/ui/row-keys.d.ts +19 -0
  308. package/ui/row-keys.js +33 -0
  309. package/ui/theme.d.ts +10 -0
  310. package/ui/theme.js +13 -0
  311. package/ui/theorem-theme.d.ts +10 -0
  312. package/ui/theorem-theme.js +105 -0
  313. package/ui/trace-palette.d.ts +10 -0
  314. package/ui/trace-palette.js +10 -0
  315. package/ui/trace-patterns.d.ts +40 -0
  316. package/ui/trace-patterns.js +57 -0
  317. package/ui/transcript-copy-text.d.ts +4 -0
  318. package/ui/transcript-copy-text.js +40 -0
  319. package/ui/wall-columns.d.ts +8 -0
  320. package/ui/wall-columns.js +19 -0
@@ -0,0 +1,12 @@
1
+ import type { MarkdownAstRoot } from '@astryxdesign/core/Markdown';
2
+ import type { MarkdownExtensionNode } from '@astryxdesign/core/Markdown/plugins';
3
+ /** The language of untagged code, or `undefined` when the detector is unsure or the language would not be coloured. */
4
+ export declare function detectedCodeLanguage(code: string): string | undefined;
5
+ /** The document with its untagged fences labelled. Unsettled while streaming: the last block may be an open fence. */
6
+ export declare function labelUntaggedCode(document: MarkdownAstRoot<MarkdownExtensionNode>, isFinal: boolean): MarkdownAstRoot<MarkdownExtensionNode>;
7
+ /**
8
+ * A Markdown plugin that labels fenced code the reply left untagged, so it is coloured like a tagged
9
+ * fence. A fence with a language is left as written. While the reply streams, the last block is left
10
+ * alone: it may be a fence still open, and its language would change as it grows.
11
+ */
12
+ export declare const codeLanguagePlugin: import("@astryxdesign/core/Markdown/plugins").MarkdownPluginEntry<never>;
@@ -0,0 +1,50 @@
1
+ import { createMarkdownPlugin } from '@astryxdesign/core/Markdown/plugins';
2
+ import { detectLanguage } from '@speed-highlight/core/detect';
3
+ /** The languages Astryx's `CodeBlock` colours, as the detector names them. A guess outside it would only add a label. */
4
+ const COLOURED = new Set(['js', 'ts', 'py', 'bash', 'json', 'css', 'html', 'xml', 'yaml', 'md']);
5
+ /** The language of untagged code, or `undefined` when the detector is unsure or the language would not be coloured. */
6
+ export function detectedCodeLanguage(code) {
7
+ const language = detectLanguage(code);
8
+ return COLOURED.has(language) ? language : undefined;
9
+ }
10
+ function tagged(node) {
11
+ if (node.type === 'code') {
12
+ const code = node;
13
+ if (code.lang !== null)
14
+ return node;
15
+ const lang = detectedCodeLanguage(code.value);
16
+ return lang === undefined ? node : { ...code, lang };
17
+ }
18
+ if (node.children === undefined)
19
+ return node;
20
+ let changed = false;
21
+ const children = node.children.map((child) => {
22
+ const next = tagged(child);
23
+ if (next !== child)
24
+ changed = true;
25
+ return next;
26
+ });
27
+ return changed ? { ...node, children } : node;
28
+ }
29
+ /** The document with its untagged fences labelled. Unsettled while streaming: the last block may be an open fence. */
30
+ export function labelUntaggedCode(document, isFinal) {
31
+ const { children } = document;
32
+ const settled = isFinal ? children : children.slice(0, -1);
33
+ const next = settled.map((child) => tagged(child));
34
+ if (next.every((child, index) => child === settled[index]))
35
+ return document;
36
+ return {
37
+ ...document,
38
+ children: [...next, ...children.slice(settled.length)],
39
+ };
40
+ }
41
+ /**
42
+ * A Markdown plugin that labels fenced code the reply left untagged, so it is coloured like a tagged
43
+ * fence. A fence with a language is left as written. While the reply streams, the last block is left
44
+ * alone: it may be a fence still open, and its language would change as it grows.
45
+ */
46
+ export const codeLanguagePlugin = createMarkdownPlugin({
47
+ apiVersion: 1,
48
+ name: 'theorem-code-language',
49
+ transform: (document, { isFinal }) => labelUntaggedCode(document, isFinal),
50
+ });
@@ -0,0 +1,6 @@
1
+ import { type RefObject } from 'react';
2
+ /**
3
+ * Eases every disclosure under `ref` open and shut. `onOpened` runs once the
4
+ * new panel is in the DOM, with a promise for its motion finishing.
5
+ */
6
+ export declare function useDisclosureMotion(ref: RefObject<HTMLElement | null>, onOpened?: (trigger: Element, panel: HTMLElement, motion: Promise<unknown>) => void): void;
@@ -0,0 +1,207 @@
1
+ import { useEffect } from 'react';
2
+ /**
3
+ * Easing for disclosures whose panel mounts on open and unmounts on close
4
+ * (ChatToolCalls row details, TreeList branches): CSS can't ease an element
5
+ * that's already gone, so a close is held until the panel has eased shut,
6
+ * then replayed; an open eases the new panel up from nothing. Panels that
7
+ * carry their own transition (the themed Collapsible) are left alone.
8
+ */
9
+ /** The panel a disclosure trigger shows: its aria-controls target, or a tree item's group. */
10
+ function panelOf(trigger) {
11
+ const id = trigger.getAttribute('aria-controls');
12
+ if (id)
13
+ return document.getElementById(id);
14
+ return (trigger.closest('[role="treeitem"]')?.querySelector(':scope > [role="group"]') ??
15
+ null);
16
+ }
17
+ function ownsMotion(panel) {
18
+ return getComputedStyle(panel)
19
+ .transitionDuration.split(',')
20
+ .some((d) => Number.parseFloat(d) > 0);
21
+ }
22
+ function isToggleKey(event) {
23
+ return !(event instanceof KeyboardEvent) || event.key === 'Enter' || event.key === ' ';
24
+ }
25
+ /**
26
+ * The element pressed and the disclosure trigger it sits in, when that trigger is under `root`. In a
27
+ * tree, the press is the row's own: a leaf's row toggles nothing, and a row with an action of its own
28
+ * (a label that selects it, a button at its end) toggles only at its chevron.
29
+ */
30
+ function pressedToggle(event, root) {
31
+ if (!(event.target instanceof Element))
32
+ return undefined;
33
+ const row = event.target.closest('[role="treeitem"]');
34
+ const trigger = row ? treeToggle(event.target, row) : event.target.closest('[aria-expanded]');
35
+ if (!trigger || !root.contains(trigger))
36
+ return undefined;
37
+ return { target: event.target, trigger };
38
+ }
39
+ /** The tree row a press toggles: none for a leaf, and for a row with an action of its own, only a press at its chevron. */
40
+ function treeToggle(target, row) {
41
+ if (!row.hasAttribute('aria-expanded'))
42
+ return undefined;
43
+ if (target.closest('[data-tree-toggle]') !== null)
44
+ return row;
45
+ const acts = row.querySelector(':scope > div :is(button:not([data-tree-toggle]), a[href])') !== null;
46
+ return acts ? undefined : row;
47
+ }
48
+ /** Stops the event: the component does not see it. */
49
+ function hold(event) {
50
+ event.stopPropagation();
51
+ event.preventDefault();
52
+ }
53
+ /** A copy of the pressed key or click, to send once the panel has eased shut. */
54
+ function replayOf(event) {
55
+ return event instanceof KeyboardEvent
56
+ ? new KeyboardEvent(event.type, { key: event.key, bubbles: true, cancelable: true })
57
+ : new MouseEvent(event.type, { bubbles: true, cancelable: true });
58
+ }
59
+ /** CSS time (`0.3s`, `300ms`) in milliseconds. */
60
+ function ms(time) {
61
+ const value = Number.parseFloat(time);
62
+ return time.trim().endsWith('ms') ? value : value * 1000;
63
+ }
64
+ /** Eases a panel's height between shut and its natural height, the theme's medium duration and standard curve. */
65
+ function ease(panel, direction) {
66
+ const style = getComputedStyle(panel);
67
+ const open = {
68
+ height: `${String(panel.getBoundingClientRect().height)}px`,
69
+ paddingTop: style.paddingTop,
70
+ paddingBottom: style.paddingBottom,
71
+ };
72
+ const shut = { height: '0px', paddingTop: '0px', paddingBottom: '0px' };
73
+ const frames = direction === 'open' ? [shut, open] : [open, shut];
74
+ for (const animation of panel.getAnimations())
75
+ animation.cancel();
76
+ return panel.animate(frames.map((frame) => ({ ...frame, boxSizing: 'border-box', overflow: 'clip' })), {
77
+ duration: ms(style.getPropertyValue('--duration-medium')),
78
+ easing: style.getPropertyValue('--ease-standard').trim(),
79
+ // why: A shut panel stays shut until its unmount; an open one hands back to its natural height.
80
+ fill: direction === 'close' ? 'forwards' : 'none',
81
+ });
82
+ }
83
+ /** Every animation on a panel, settled; a cancelled one rejects `finished`, so settle rather than await all. */
84
+ function settled(panel) {
85
+ return Promise.allSettled(panel.getAnimations().map((animation) => animation.finished));
86
+ }
87
+ /** The attribute Astryx's chat sets on its scroller while it follows new content to the bottom. */
88
+ const FOLLOWING = 'data-astryx-chat-following';
89
+ /** How far from its bottom a scroll up must land for Astryx's chat to stop following: past its 10px lock threshold. */
90
+ const LET_GO = 11;
91
+ /**
92
+ * Keeps a trigger the reader opened where it was while its panel grows. A
93
+ * chat that follows its bottom would spring past it, so the follow is let go
94
+ * first: a scroll up just past the chat's threshold reads as the reader's.
95
+ * The panel's growth then gives the room back, and the trigger ends where it
96
+ * was. A chat too short to scroll yet is held after each layout instead,
97
+ * after the follow's own frame, which also lets it go.
98
+ */
99
+ function holdInPlace(trigger, panel, motion) {
100
+ const scroller = trigger.closest(`[${FOLLOWING}]`);
101
+ if (!scroller)
102
+ return;
103
+ const top = trigger.getBoundingClientRect().top;
104
+ const room = () => scroller.scrollHeight - scroller.clientHeight - scroller.scrollTop;
105
+ scroller.scrollTop -= Math.max(0, LET_GO - room());
106
+ let done = false;
107
+ void motion.then(() => setTimeout(() => (done = true), 1000));
108
+ const held = new ResizeObserver(() => {
109
+ const drift = trigger.getBoundingClientRect().top - top;
110
+ if (drift && scroller.hasAttribute(FOLLOWING))
111
+ scroller.scrollTop += drift;
112
+ });
113
+ held.observe(panel);
114
+ const giveBack = () => {
115
+ const drift = trigger.getBoundingClientRect().top - top;
116
+ // invariant: Never back within the threshold, or the chat would follow again.
117
+ if (drift > 0 && !scroller.hasAttribute(FOLLOWING)) {
118
+ scroller.scrollTop += Math.max(0, Math.min(drift, room() - LET_GO));
119
+ }
120
+ if (done || (drift <= 0.5 && !scroller.hasAttribute(FOLLOWING)))
121
+ held.disconnect();
122
+ else
123
+ requestAnimationFrame(giveBack);
124
+ };
125
+ requestAnimationFrame(giveBack);
126
+ }
127
+ /**
128
+ * Eases every disclosure under `ref` open and shut. `onOpened` runs once the
129
+ * new panel is in the DOM, with a promise for its motion finishing.
130
+ */
131
+ export function useDisclosureMotion(ref, onOpened) {
132
+ useEffect(() => {
133
+ const root = ref.current;
134
+ if (!root)
135
+ return;
136
+ const still = matchMedia('(prefers-reduced-motion: reduce)');
137
+ const closing = new WeakSet();
138
+ const replaying = new WeakSet();
139
+ // why: The trigger the reader just pressed to open; opens the page makes itself aren't eased or followed.
140
+ let opening;
141
+ /** The trigger the reader pressed opens: note it until the toggle commits, within this event. */
142
+ const noteOpening = (trigger) => {
143
+ opening = trigger;
144
+ // why: A stale note must not claim a later change.
145
+ setTimeout(() => {
146
+ if (opening === trigger)
147
+ opening = undefined;
148
+ });
149
+ };
150
+ /** The panel a close should ease shut first; none when motion is off or the panel eases itself. */
151
+ const panelToEase = (trigger) => {
152
+ const panel = panelOf(trigger);
153
+ return panel && !still.matches && !ownsMotion(panel) ? panel : undefined;
154
+ };
155
+ const before = (event) => {
156
+ if (!isToggleKey(event) || replaying.has(event))
157
+ return;
158
+ const pressed = pressedToggle(event, root);
159
+ if (!pressed)
160
+ return;
161
+ const { target, trigger } = pressed;
162
+ if (closing.has(trigger)) {
163
+ hold(event);
164
+ return;
165
+ }
166
+ if (trigger.getAttribute('aria-expanded') !== 'true') {
167
+ noteOpening(trigger);
168
+ return;
169
+ }
170
+ const panel = panelToEase(trigger);
171
+ if (!panel)
172
+ return;
173
+ hold(event);
174
+ closing.add(trigger);
175
+ const replay = replayOf(event);
176
+ void ease(panel, 'close').finished.then(() => {
177
+ closing.delete(trigger);
178
+ replaying.add(replay);
179
+ target.dispatchEvent(replay);
180
+ });
181
+ };
182
+ // why: After the component commits the toggle (a component may stop the event, so
183
+ // watch the attribute rather than wait for the event to bubble): ease the new panel.
184
+ const opened = new MutationObserver(() => {
185
+ const trigger = opening;
186
+ if (trigger?.getAttribute('aria-expanded') !== 'true')
187
+ return;
188
+ opening = undefined;
189
+ const panel = panelOf(trigger);
190
+ if (!panel)
191
+ return;
192
+ if (!still.matches && !ownsMotion(panel))
193
+ ease(panel, 'open');
194
+ const motion = settled(panel);
195
+ holdInPlace(trigger, panel, motion);
196
+ onOpened?.(trigger, panel, motion);
197
+ });
198
+ opened.observe(root, { subtree: true, attributeFilter: ['aria-expanded'] });
199
+ root.addEventListener('click', before, true);
200
+ root.addEventListener('keydown', before, true);
201
+ return () => {
202
+ opened.disconnect();
203
+ root.removeEventListener('click', before, true);
204
+ root.removeEventListener('keydown', before, true);
205
+ };
206
+ }, [ref, onOpened]);
207
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Draws the embedding space with WebGL2 and nothing else: anti-aliased lines,
3
+ * solid dots and the query's white dot, laid over the card with premultiplied
4
+ * alpha so the card shows through. Dots cover whatever lies behind them, and
5
+ * every line stops just short of the dot it reaches; the far side of the
6
+ * ball draws smaller and fainter. No React here: the component owns one
7
+ * renderer and feeds it.
8
+ *
9
+ * @module
10
+ */
11
+ import type { EmbeddingSpace, SpacePoint } from '../client/embedding-space.ts';
12
+ import { type QueryMatch } from '../client/space-geometry.ts';
13
+ /** What the space highlights: a query's matches, and the document under the pointer. */
14
+ export type SpaceFocus = {
15
+ query: SpacePoint | null;
16
+ matches: readonly QueryMatch[];
17
+ hovered: number | null;
18
+ };
19
+ export type SpaceRenderer = {
20
+ /** Shows a new index: its clusters grow in, one after another. */
21
+ setSpace(space: EmbeddingSpace): void;
22
+ setFocus(focus: SpaceFocus): void;
23
+ /** The document nearest a point in CSS pixels from the canvas's corner, if one is close and facing. */
24
+ pick(x: number, y: number): number | null;
25
+ /** Turns the sphere as a drag moves, in CSS pixels. */
26
+ drag(dx: number, dy: number): void;
27
+ release(): void;
28
+ };
29
+ /**
30
+ * One renderer for one canvas. Throws {@link SpaceUnavailable} when the
31
+ * browser cannot draw it, so the caller shows the list instead.
32
+ */
33
+ export declare function createSpaceRenderer(canvas: HTMLCanvasElement, { still }: {
34
+ still: boolean;
35
+ }): SpaceRenderer & {
36
+ destroy(): void;
37
+ };