@ulearning/ai-generative-frame 0.0.0-stage → 1.0.0-next.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 +233 -2
  3. package/dist/assistant-ui/entry.d.ts +34 -0
  4. package/dist/assistant-ui/entry.d.ts.map +1 -0
  5. package/dist/assistant-ui/entry.js +50 -0
  6. package/dist/assistant-ui/entry.js.map +1 -0
  7. package/dist/assistant-ui/extension.d.ts +18 -0
  8. package/dist/assistant-ui/extension.d.ts.map +1 -0
  9. package/dist/assistant-ui/extension.js +0 -0
  10. package/dist/assistant-ui/history.d.ts +15 -0
  11. package/dist/assistant-ui/history.d.ts.map +1 -0
  12. package/dist/assistant-ui/history.js +39 -0
  13. package/dist/assistant-ui/history.js.map +1 -0
  14. package/dist/assistant-ui/modelContext.d.ts +45 -0
  15. package/dist/assistant-ui/modelContext.d.ts.map +1 -0
  16. package/dist/assistant-ui/modelContext.js +88 -0
  17. package/dist/assistant-ui/modelContext.js.map +1 -0
  18. package/dist/assistant-ui/snapshotSaver.d.ts +11 -0
  19. package/dist/assistant-ui/snapshotSaver.d.ts.map +1 -0
  20. package/dist/assistant-ui/snapshotSaver.js +83 -0
  21. package/dist/assistant-ui/snapshotSaver.js.map +1 -0
  22. package/dist/assistant-ui/tool-calls.d.ts +21 -0
  23. package/dist/assistant-ui/tool-calls.d.ts.map +1 -0
  24. package/dist/assistant-ui/tool-calls.js +65 -0
  25. package/dist/assistant-ui/tool-calls.js.map +1 -0
  26. package/dist/assistant-ui/toolkit.d.ts +96 -0
  27. package/dist/assistant-ui/toolkit.d.ts.map +1 -0
  28. package/dist/assistant-ui/toolkit.js +456 -0
  29. package/dist/assistant-ui/toolkit.js.map +1 -0
  30. package/dist/assistant-ui/useSharedContext.d.ts +14 -0
  31. package/dist/assistant-ui/useSharedContext.d.ts.map +1 -0
  32. package/dist/assistant-ui/useSharedContext.js +27 -0
  33. package/dist/assistant-ui/useSharedContext.js.map +1 -0
  34. package/dist/assistant-ui.d.ts +3 -0
  35. package/dist/assistant-ui.d.ts.map +1 -0
  36. package/dist/assistant-ui.js +1 -0
  37. package/dist/bootstrap.d.ts +23 -0
  38. package/dist/bootstrap.d.ts.map +1 -0
  39. package/dist/bootstrap.js +78 -0
  40. package/dist/bootstrap.js.map +1 -0
  41. package/dist/csp.d.ts +25 -0
  42. package/dist/csp.d.ts.map +1 -0
  43. package/dist/csp.js +78 -0
  44. package/dist/csp.js.map +1 -0
  45. package/dist/index.d.ts +6 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +5 -0
  48. package/dist/json-schema.d.ts +70 -0
  49. package/dist/json-schema.d.ts.map +1 -0
  50. package/dist/json-schema.js +163 -0
  51. package/dist/json-schema.js.map +1 -0
  52. package/dist/preview.d.ts +30 -0
  53. package/dist/preview.d.ts.map +1 -0
  54. package/dist/preview.js +60 -0
  55. package/dist/preview.js.map +1 -0
  56. package/dist/prompts/guidance.d.ts +41 -0
  57. package/dist/prompts/guidance.d.ts.map +1 -0
  58. package/dist/prompts/guidance.js +268 -0
  59. package/dist/prompts/guidance.js.map +1 -0
  60. package/dist/prompts.d.ts +2 -0
  61. package/dist/prompts.d.ts.map +1 -0
  62. package/dist/prompts.js +1 -0
  63. package/dist/protocol.d.ts +114 -0
  64. package/dist/protocol.d.ts.map +1 -0
  65. package/dist/protocol.js +49 -0
  66. package/dist/protocol.js.map +1 -0
  67. package/dist/repair/repair.d.ts +72 -0
  68. package/dist/repair/repair.d.ts.map +1 -0
  69. package/dist/repair/repair.js +103 -0
  70. package/dist/repair/repair.js.map +1 -0
  71. package/dist/repair.d.ts +2 -0
  72. package/dist/repair.d.ts.map +1 -0
  73. package/dist/repair.js +1 -0
  74. package/dist/rpc.d.ts +60 -0
  75. package/dist/rpc.d.ts.map +1 -0
  76. package/dist/rpc.js +127 -0
  77. package/dist/rpc.js.map +1 -0
  78. package/dist/runtime/diagnostics.d.ts +17 -0
  79. package/dist/runtime/diagnostics.d.ts.map +1 -0
  80. package/dist/runtime/diagnostics.js +128 -0
  81. package/dist/runtime/diagnostics.js.map +1 -0
  82. package/dist/runtime/generated.d.ts +2 -0
  83. package/dist/runtime/generated.d.ts.map +1 -0
  84. package/dist/runtime/generated.js +5 -0
  85. package/dist/runtime/generated.js.map +1 -0
  86. package/dist/runtime/index.d.ts +7 -0
  87. package/dist/runtime/index.d.ts.map +1 -0
  88. package/dist/runtime/index.js +264 -0
  89. package/dist/runtime/index.js.map +1 -0
  90. package/dist/runtime/morph.d.ts +51 -0
  91. package/dist/runtime/morph.d.ts.map +1 -0
  92. package/dist/runtime/morph.js +251 -0
  93. package/dist/runtime/morph.js.map +1 -0
  94. package/dist/runtime/screenshot.d.ts +23 -0
  95. package/dist/runtime/screenshot.d.ts.map +1 -0
  96. package/dist/runtime/screenshot.js +188 -0
  97. package/dist/runtime/screenshot.js.map +1 -0
  98. package/dist/runtime/size.d.ts +10 -0
  99. package/dist/runtime/size.d.ts.map +1 -0
  100. package/dist/runtime/size.js +21 -0
  101. package/dist/runtime/size.js.map +1 -0
  102. package/dist/runtime/storage.d.ts +4 -0
  103. package/dist/runtime/storage.d.ts.map +1 -0
  104. package/dist/runtime/storage.js +38 -0
  105. package/dist/runtime/storage.js.map +1 -0
  106. package/dist/spec/actions.d.ts +40 -0
  107. package/dist/spec/actions.d.ts.map +1 -0
  108. package/dist/spec/actions.js +53 -0
  109. package/dist/spec/actions.js.map +1 -0
  110. package/dist/spec/assistant-ui/thread.d.ts +66 -0
  111. package/dist/spec/assistant-ui/thread.d.ts.map +1 -0
  112. package/dist/spec/assistant-ui/thread.js +252 -0
  113. package/dist/spec/assistant-ui/thread.js.map +1 -0
  114. package/dist/spec/assistant-ui/toolkit.d.ts +33 -0
  115. package/dist/spec/assistant-ui/toolkit.d.ts.map +1 -0
  116. package/dist/spec/assistant-ui/toolkit.js +142 -0
  117. package/dist/spec/assistant-ui/toolkit.js.map +1 -0
  118. package/dist/spec/assistant-ui/web.d.ts +6 -0
  119. package/dist/spec/assistant-ui/web.d.ts.map +1 -0
  120. package/dist/spec/assistant-ui/web.js +48 -0
  121. package/dist/spec/assistant-ui/web.js.map +1 -0
  122. package/dist/spec/assistant-ui.d.ts +3 -0
  123. package/dist/spec/assistant-ui.d.ts.map +1 -0
  124. package/dist/spec/assistant-ui.js +1 -0
  125. package/dist/spec/calc.d.ts +8 -0
  126. package/dist/spec/calc.d.ts.map +1 -0
  127. package/dist/spec/calc.js +498 -0
  128. package/dist/spec/calc.js.map +1 -0
  129. package/dist/spec/catalog.d.ts +52 -0
  130. package/dist/spec/catalog.d.ts.map +1 -0
  131. package/dist/spec/catalog.js +104 -0
  132. package/dist/spec/catalog.js.map +1 -0
  133. package/dist/spec/expressions.d.ts +45 -0
  134. package/dist/spec/expressions.d.ts.map +1 -0
  135. package/dist/spec/expressions.js +199 -0
  136. package/dist/spec/expressions.js.map +1 -0
  137. package/dist/spec/patch.d.ts +20 -0
  138. package/dist/spec/patch.d.ts.map +1 -0
  139. package/dist/spec/patch.js +77 -0
  140. package/dist/spec/patch.js.map +1 -0
  141. package/dist/spec/pending.d.ts +15 -0
  142. package/dist/spec/pending.d.ts.map +1 -0
  143. package/dist/spec/pending.js +33 -0
  144. package/dist/spec/pending.js.map +1 -0
  145. package/dist/spec/pointer.d.ts +17 -0
  146. package/dist/spec/pointer.d.ts.map +1 -0
  147. package/dist/spec/pointer.js +88 -0
  148. package/dist/spec/pointer.js.map +1 -0
  149. package/dist/spec/prompt.d.ts +29 -0
  150. package/dist/spec/prompt.d.ts.map +1 -0
  151. package/dist/spec/prompt.js +145 -0
  152. package/dist/spec/prompt.js.map +1 -0
  153. package/dist/spec/render-spec.d.ts +50 -0
  154. package/dist/spec/render-spec.d.ts.map +1 -0
  155. package/dist/spec/render-spec.js +104 -0
  156. package/dist/spec/render-spec.js.map +1 -0
  157. package/dist/spec/resolve.d.ts +39 -0
  158. package/dist/spec/resolve.d.ts.map +1 -0
  159. package/dist/spec/resolve.js +51 -0
  160. package/dist/spec/resolve.js.map +1 -0
  161. package/dist/spec/resolved.d.ts +3 -0
  162. package/dist/spec/resolved.d.ts.map +1 -0
  163. package/dist/spec/resolved.js +36 -0
  164. package/dist/spec/resolved.js.map +1 -0
  165. package/dist/spec/state.d.ts +34 -0
  166. package/dist/spec/state.d.ts.map +1 -0
  167. package/dist/spec/state.js +111 -0
  168. package/dist/spec/state.js.map +1 -0
  169. package/dist/spec/stream.d.ts +50 -0
  170. package/dist/spec/stream.d.ts.map +1 -0
  171. package/dist/spec/stream.js +168 -0
  172. package/dist/spec/stream.js.map +1 -0
  173. package/dist/spec/tools.d.ts +3 -0
  174. package/dist/spec/tools.d.ts.map +1 -0
  175. package/dist/spec/tools.js +3 -0
  176. package/dist/spec/tree.d.ts +21 -0
  177. package/dist/spec/tree.d.ts.map +1 -0
  178. package/dist/spec/tree.js +27 -0
  179. package/dist/spec/tree.js.map +1 -0
  180. package/dist/spec/types.d.ts +66 -0
  181. package/dist/spec/types.d.ts.map +1 -0
  182. package/dist/spec/types.js +9 -0
  183. package/dist/spec/types.js.map +1 -0
  184. package/dist/spec/validate.d.ts +32 -0
  185. package/dist/spec/validate.d.ts.map +1 -0
  186. package/dist/spec/validate.js +264 -0
  187. package/dist/spec/validate.js.map +1 -0
  188. package/dist/spec/vue/SpecRenderer.d.ts +43 -0
  189. package/dist/spec/vue/SpecRenderer.d.ts.map +1 -0
  190. package/dist/spec/vue/SpecRenderer.js +357 -0
  191. package/dist/spec/vue/SpecRenderer.js.map +1 -0
  192. package/dist/spec/vue/useSpecStream.d.ts +19 -0
  193. package/dist/spec/vue/useSpecStream.d.ts.map +1 -0
  194. package/dist/spec/vue/useSpecStream.js +115 -0
  195. package/dist/spec/vue/useSpecStream.js.map +1 -0
  196. package/dist/spec/vue.d.ts +3 -0
  197. package/dist/spec/vue.d.ts.map +1 -0
  198. package/dist/spec/vue.js +3 -0
  199. package/dist/spec.d.ts +12 -0
  200. package/dist/spec.d.ts.map +1 -0
  201. package/dist/spec.js +8 -0
  202. package/dist/theme.d.ts +38 -0
  203. package/dist/theme.d.ts.map +1 -0
  204. package/dist/theme.js +370 -0
  205. package/dist/theme.js.map +1 -0
  206. package/dist/tools/define.d.ts +43 -0
  207. package/dist/tools/define.d.ts.map +1 -0
  208. package/dist/tools/define.js +31 -0
  209. package/dist/tools/define.js.map +1 -0
  210. package/dist/tools/edits.d.ts +19 -0
  211. package/dist/tools/edits.d.ts.map +1 -0
  212. package/dist/tools/edits.js +55 -0
  213. package/dist/tools/edits.js.map +1 -0
  214. package/dist/tools/registry.d.ts +19 -0
  215. package/dist/tools/registry.d.ts.map +1 -0
  216. package/dist/tools/registry.js +33 -0
  217. package/dist/tools/registry.js.map +1 -0
  218. package/dist/tools/tools.d.ts +88 -0
  219. package/dist/tools/tools.d.ts.map +1 -0
  220. package/dist/tools/tools.js +235 -0
  221. package/dist/tools/tools.js.map +1 -0
  222. package/dist/tools.d.ts +5 -0
  223. package/dist/tools.d.ts.map +1 -0
  224. package/dist/tools.js +5 -0
  225. package/dist/version.d.ts +2 -0
  226. package/dist/version.d.ts.map +1 -0
  227. package/dist/version.js +5 -0
  228. package/dist/version.js.map +1 -0
  229. package/dist/vue/Widget.d.ts +16 -0
  230. package/dist/vue/Widget.d.ts.map +1 -0
  231. package/dist/vue/Widget.js +58 -0
  232. package/dist/vue/Widget.js.map +1 -0
  233. package/dist/vue/sync.d.ts +19 -0
  234. package/dist/vue/sync.d.ts.map +1 -0
  235. package/dist/vue/sync.js +31 -0
  236. package/dist/vue/sync.js.map +1 -0
  237. package/dist/vue/themeStore.d.ts +23 -0
  238. package/dist/vue/themeStore.d.ts.map +1 -0
  239. package/dist/vue/themeStore.js +115 -0
  240. package/dist/vue/themeStore.js.map +1 -0
  241. package/dist/vue/useThemeTokens.d.ts +6 -0
  242. package/dist/vue/useThemeTokens.d.ts.map +1 -0
  243. package/dist/vue/useThemeTokens.js +49 -0
  244. package/dist/vue/useThemeTokens.js.map +1 -0
  245. package/dist/vue/useWidget.d.ts +10 -0
  246. package/dist/vue/useWidget.d.ts.map +1 -0
  247. package/dist/vue/useWidget.js +81 -0
  248. package/dist/vue/useWidget.js.map +1 -0
  249. package/dist/vue.d.ts +5 -0
  250. package/dist/vue.d.ts.map +1 -0
  251. package/dist/vue.js +4 -0
  252. package/dist/widget.d.ts +129 -0
  253. package/dist/widget.d.ts.map +1 -0
  254. package/dist/widget.js +655 -0
  255. package/dist/widget.js.map +1 -0
  256. package/package.json +125 -3
  257. package/src/assistant-ui/entry.ts +124 -0
  258. package/src/assistant-ui/extension.ts +19 -0
  259. package/src/assistant-ui/history.ts +63 -0
  260. package/src/assistant-ui/modelContext.ts +162 -0
  261. package/src/assistant-ui/snapshotSaver.ts +116 -0
  262. package/src/assistant-ui/tool-calls.ts +115 -0
  263. package/src/assistant-ui/toolkit.tsx +747 -0
  264. package/src/assistant-ui/useSharedContext.ts +40 -0
  265. package/src/assistant-ui.ts +14 -0
  266. package/src/bootstrap.ts +112 -0
  267. package/src/csp.ts +96 -0
  268. package/src/index.ts +44 -0
  269. package/src/json-schema.ts +353 -0
  270. package/src/preview.ts +120 -0
  271. package/src/prompts/guidance.ts +369 -0
  272. package/src/prompts.ts +8 -0
  273. package/src/protocol.ts +141 -0
  274. package/src/repair/repair.ts +202 -0
  275. package/src/repair.ts +11 -0
  276. package/src/rpc.ts +228 -0
  277. package/src/runtime/diagnostics.ts +165 -0
  278. package/src/runtime/generated.ts +2 -0
  279. package/src/runtime/index.ts +343 -0
  280. package/src/runtime/morph.ts +352 -0
  281. package/src/runtime/screenshot.ts +288 -0
  282. package/src/runtime/size.ts +17 -0
  283. package/src/runtime/storage.ts +49 -0
  284. package/src/spec/actions.ts +111 -0
  285. package/src/spec/assistant-ui/thread.ts +381 -0
  286. package/src/spec/assistant-ui/toolkit.tsx +295 -0
  287. package/src/spec/assistant-ui/web.tsx +63 -0
  288. package/src/spec/assistant-ui.ts +2 -0
  289. package/src/spec/calc.ts +598 -0
  290. package/src/spec/catalog.ts +196 -0
  291. package/src/spec/expressions.ts +301 -0
  292. package/src/spec/patch.ts +112 -0
  293. package/src/spec/pending.ts +36 -0
  294. package/src/spec/pointer.ts +170 -0
  295. package/src/spec/prompt.ts +243 -0
  296. package/src/spec/render-spec.ts +144 -0
  297. package/src/spec/resolve.ts +123 -0
  298. package/src/spec/resolved.ts +53 -0
  299. package/src/spec/state.ts +193 -0
  300. package/src/spec/stream.ts +230 -0
  301. package/src/spec/tools.ts +17 -0
  302. package/src/spec/tree.ts +37 -0
  303. package/src/spec/types.ts +51 -0
  304. package/src/spec/validate.ts +429 -0
  305. package/src/spec/vue/SpecRenderer.tsx +544 -0
  306. package/src/spec/vue/__tests__/harness.ts +50 -0
  307. package/src/spec/vue/useSpecStream.ts +162 -0
  308. package/src/spec/vue.ts +13 -0
  309. package/src/spec.ts +55 -0
  310. package/src/theme.ts +423 -0
  311. package/src/tools/define.ts +65 -0
  312. package/src/tools/edits.ts +73 -0
  313. package/src/tools/registry.ts +44 -0
  314. package/src/tools/tools.ts +361 -0
  315. package/src/tools.ts +32 -0
  316. package/src/version.ts +4 -0
  317. package/src/vue/Widget.tsx +74 -0
  318. package/src/vue/sync.ts +36 -0
  319. package/src/vue/themeStore.ts +157 -0
  320. package/src/vue/useThemeTokens.ts +71 -0
  321. package/src/vue/useWidget.ts +117 -0
  322. package/src/vue.ts +8 -0
  323. package/src/widget.ts +1080 -0
@@ -0,0 +1,157 @@
1
+ import {
2
+ DEFAULT_LIGHT_TOKENS,
3
+ readThemeTokens,
4
+ type ThemeTokenSources,
5
+ type ThemeTokens,
6
+ } from "../theme";
7
+
8
+ export type ThemeObserveOptions = {
9
+ /**
10
+ * Also re-read when `<body>`'s `style` attribute changes. Off by default,
11
+ * because scroll-lock and dialog libraries rewrite it constantly; turn it on
12
+ * when the app sets theme variables through body styles.
13
+ */
14
+ observeBodyStyle?: boolean;
15
+ };
16
+
17
+ const THEME_ATTRIBUTES = ["class", "data-theme", "data-mode"];
18
+
19
+ const sameTokens = (a: ThemeTokens, b: ThemeTokens) =>
20
+ a.colorScheme === b.colorScheme &&
21
+ JSON.stringify(a.variables) === JSON.stringify(b.variables);
22
+
23
+ /** Runs `callback` on the next animation frame and returns a cancel function. */
24
+ const nextFrame = (callback: () => void): (() => void) => {
25
+ if (typeof requestAnimationFrame === "function") {
26
+ const id = requestAnimationFrame(callback);
27
+ return () => cancelAnimationFrame(id);
28
+ }
29
+ const id = setTimeout(callback, 16);
30
+ return () => clearTimeout(id);
31
+ };
32
+
33
+ type Entry = {
34
+ tokens: ThemeTokens | undefined;
35
+ /** Snapshot read while nobody subscribes; valid for the current task. */
36
+ fresh: boolean;
37
+ listeners: Set<() => void>;
38
+ stop: (() => void) | undefined;
39
+ };
40
+
41
+ /**
42
+ * One reader per (element, sources, options): every subscriber shares one
43
+ * MutationObserver and one media listener, and a burst of mutations costs one
44
+ * `readThemeTokens` per animation frame.
45
+ */
46
+ export function createThemeTokenStore(
47
+ target: Element,
48
+ sources: ThemeTokenSources,
49
+ options: ThemeObserveOptions,
50
+ ) {
51
+ const entry: Entry = {
52
+ tokens: undefined,
53
+ fresh: false,
54
+ listeners: new Set(),
55
+ stop: undefined,
56
+ };
57
+
58
+ const read = () => {
59
+ const next = readThemeTokens(target, sources);
60
+ if (entry.tokens && sameTokens(entry.tokens, next)) return false;
61
+ entry.tokens = next;
62
+ return true;
63
+ };
64
+
65
+ const start = () => {
66
+ let cancelFrame: (() => void) | undefined;
67
+ const update = () => {
68
+ cancelFrame = undefined;
69
+ if (read()) for (const listener of entry.listeners) listener();
70
+ };
71
+ const schedule = () => {
72
+ cancelFrame ??= nextFrame(update);
73
+ };
74
+ const doc = target.ownerDocument;
75
+ const observer = new MutationObserver(schedule);
76
+ observer.observe(doc.documentElement, {
77
+ attributes: true,
78
+ attributeFilter: [...THEME_ATTRIBUTES, "style"],
79
+ });
80
+ if (doc.body) {
81
+ observer.observe(doc.body, {
82
+ attributes: true,
83
+ attributeFilter: options.observeBodyStyle
84
+ ? [...THEME_ATTRIBUTES, "style"]
85
+ : THEME_ATTRIBUTES,
86
+ });
87
+ }
88
+ if (target !== doc.documentElement && target !== doc.body) {
89
+ observer.observe(target, {
90
+ attributes: true,
91
+ attributeFilter: [...THEME_ATTRIBUTES, "style"],
92
+ });
93
+ }
94
+ const media = doc.defaultView?.matchMedia?.("(prefers-color-scheme: dark)");
95
+ media?.addEventListener("change", schedule);
96
+ // Anything that changed between the last read and now.
97
+ schedule();
98
+ return () => {
99
+ observer.disconnect();
100
+ media?.removeEventListener("change", schedule);
101
+ cancelFrame?.();
102
+ };
103
+ };
104
+
105
+ return {
106
+ subscribe(listener: () => void) {
107
+ entry.listeners.add(listener);
108
+ entry.stop ??= start();
109
+ return () => {
110
+ entry.listeners.delete(listener);
111
+ if (entry.listeners.size === 0) {
112
+ entry.stop?.();
113
+ entry.stop = undefined;
114
+ entry.fresh = false;
115
+ }
116
+ };
117
+ },
118
+ getSnapshot(): ThemeTokens {
119
+ if (entry.stop && entry.tokens) return entry.tokens;
120
+ if (!entry.fresh) {
121
+ read();
122
+ entry.fresh = true;
123
+ queueMicrotask(() => {
124
+ entry.fresh = false;
125
+ });
126
+ }
127
+ return entry.tokens ?? DEFAULT_LIGHT_TOKENS;
128
+ },
129
+ get subscribers() {
130
+ return entry.listeners.size;
131
+ },
132
+ };
133
+ }
134
+
135
+ export type ThemeTokenStore = ReturnType<typeof createThemeTokenStore>;
136
+
137
+ const stores = new WeakMap<Element, Map<string, ThemeTokenStore>>();
138
+
139
+ /** The shared store for this element, sources, and options. */
140
+ export function getThemeTokenStore(
141
+ target: Element,
142
+ sources: ThemeTokenSources = {},
143
+ options: ThemeObserveOptions = {},
144
+ ): ThemeTokenStore {
145
+ const key = JSON.stringify([sources, options.observeBodyStyle ?? false]);
146
+ let byKey = stores.get(target);
147
+ if (!byKey) {
148
+ byKey = new Map();
149
+ stores.set(target, byKey);
150
+ }
151
+ let store = byKey.get(key);
152
+ if (!store) {
153
+ store = createThemeTokenStore(target, sources, options);
154
+ byKey.set(key, store);
155
+ }
156
+ return store;
157
+ }
@@ -0,0 +1,71 @@
1
+ import {
2
+ onActivated,
3
+ onBeforeUnmount,
4
+ onDeactivated,
5
+ onMounted,
6
+ onServerPrefetch,
7
+ readonly,
8
+ shallowRef,
9
+ toValue,
10
+ watch,
11
+ type MaybeRefOrGetter,
12
+ type ShallowRef,
13
+ } from "vue";
14
+ import {
15
+ DEFAULT_LIGHT_TOKENS,
16
+ type ThemeTokenSources,
17
+ type ThemeTokens,
18
+ } from "../theme";
19
+ import { getThemeTokenStore, type ThemeObserveOptions } from "./themeStore";
20
+ /** One shared observer per element/source/options; subscriptions follow the component lifecycle. */
21
+ export function useThemeTokens(
22
+ element?: MaybeRefOrGetter<Element | null | undefined>,
23
+ sources?: ThemeTokenSources,
24
+ options: ThemeObserveOptions = {},
25
+ ): Readonly<ShallowRef<ThemeTokens>> {
26
+ const target = () =>
27
+ toValue(element) ??
28
+ (typeof document === "undefined" ? undefined : document.documentElement);
29
+ const tokens = shallowRef(
30
+ target()
31
+ ? getThemeTokenStore(target()!, sources, options).getSnapshot()
32
+ : DEFAULT_LIGHT_TOKENS,
33
+ );
34
+ let stop: (() => void) | undefined;
35
+ let active = false;
36
+ const disconnect = () => {
37
+ stop?.();
38
+ stop = undefined;
39
+ };
40
+ const connect = () => {
41
+ disconnect();
42
+ const current = target();
43
+ if (!active || !current) return;
44
+ const store = getThemeTokenStore(current, sources, options);
45
+ tokens.value = store.getSnapshot();
46
+ stop = store.subscribe(() => {
47
+ tokens.value = store.getSnapshot();
48
+ });
49
+ };
50
+ onServerPrefetch(() => {
51
+ tokens.value = DEFAULT_LIGHT_TOKENS;
52
+ });
53
+ onMounted(() => {
54
+ active = true;
55
+ connect();
56
+ });
57
+ onActivated(() => {
58
+ active = true;
59
+ connect();
60
+ });
61
+ onDeactivated(() => {
62
+ active = false;
63
+ disconnect();
64
+ });
65
+ onBeforeUnmount(() => {
66
+ active = false;
67
+ disconnect();
68
+ });
69
+ watch(target, connect, { flush: "post" });
70
+ return readonly(tokens);
71
+ }
@@ -0,0 +1,117 @@
1
+ import {
2
+ onActivated,
3
+ onBeforeUnmount,
4
+ onDeactivated,
5
+ onMounted,
6
+ shallowReadonly,
7
+ shallowRef,
8
+ toValue,
9
+ watch,
10
+ type ComponentPublicInstance,
11
+ type MaybeRefOrGetter,
12
+ type ShallowRef,
13
+ } from "vue";
14
+ import { RPC_ERROR, RpcError } from "../rpc";
15
+ import {
16
+ createWidget,
17
+ type CreateWidgetOptions,
18
+ type WidgetHandle,
19
+ type WidgetHandlers,
20
+ } from "../widget";
21
+
22
+ export type UseWidgetOptions = Omit<CreateWidgetOptions, "container" | "code">;
23
+ export type UseWidgetResult = {
24
+ ref: (element: Element | ComponentPublicInstance | null) => void;
25
+ widget: Readonly<ShallowRef<WidgetHandle | null>>;
26
+ };
27
+ const HANDLER_KEYS = Object.keys({
28
+ onPrompt: true,
29
+ onMessage: true,
30
+ onOpenLink: true,
31
+ onCallTool: true,
32
+ onInitialized: true,
33
+ onRequestDisplayMode: true,
34
+ onUpdateModelContext: true,
35
+ onCopyText: true,
36
+ onWidgetState: true,
37
+ onResize: true,
38
+ onError: true,
39
+ onLog: true,
40
+ } satisfies Record<keyof WidgetHandlers, true>) as (keyof WidgetHandlers)[];
41
+
42
+ /** Mount options are read per activation. Handlers and tokens follow the latest options. */
43
+ export function useWidget(
44
+ options: MaybeRefOrGetter<UseWidgetOptions> = {},
45
+ ): UseWidgetResult {
46
+ const element = shallowRef<HTMLElement | null>(null);
47
+ const active = shallowRef(false);
48
+ const widget = shallowRef<WidgetHandle | null>(null);
49
+ let widgetState: { value: unknown } | undefined;
50
+ let sentTokens: UseWidgetOptions["tokens"];
51
+ onMounted(() => {
52
+ active.value = true;
53
+ });
54
+ onActivated(() => {
55
+ active.value = true;
56
+ });
57
+ onDeactivated(() => {
58
+ active.value = false;
59
+ });
60
+ onBeforeUnmount(() => {
61
+ active.value = false;
62
+ });
63
+ watch(
64
+ [element, active],
65
+ ([container, enabled], _previous, onCleanup) => {
66
+ if (!container || !enabled) return;
67
+ const initial = toValue(options);
68
+ const handlers: Record<string, unknown> = {};
69
+ for (const key of HANDLER_KEYS) {
70
+ if (!initial[key]) continue;
71
+ handlers[key] = (...args: unknown[]) => {
72
+ const handler = toValue(options)[key] as
73
+ | ((...args: unknown[]) => unknown)
74
+ | undefined;
75
+ if (!handler)
76
+ throw new RpcError(
77
+ RPC_ERROR.methodNotFound,
78
+ `${key} is no longer handled`,
79
+ );
80
+ return handler(...args);
81
+ };
82
+ }
83
+ const handle = createWidget({
84
+ ...initial,
85
+ ...(handlers as WidgetHandlers),
86
+ ...(widgetState ? { initialState: widgetState.value } : {}),
87
+ onWidgetState: (state) => {
88
+ widgetState = { value: state };
89
+ toValue(options).onWidgetState?.(state);
90
+ },
91
+ container,
92
+ });
93
+ sentTokens = initial.tokens;
94
+ widget.value = handle;
95
+ onCleanup(() => {
96
+ widget.value = null;
97
+ handle.dispose();
98
+ });
99
+ },
100
+ { flush: "sync" },
101
+ );
102
+ watch(
103
+ () => toValue(options).tokens,
104
+ (tokens) => {
105
+ if (!widget.value || !tokens || sentTokens === tokens) return;
106
+ sentTokens = tokens;
107
+ widget.value.setTheme(tokens);
108
+ },
109
+ { flush: "post" },
110
+ );
111
+ return {
112
+ ref: (next) => {
113
+ element.value = next instanceof HTMLElement ? next : null;
114
+ },
115
+ widget: shallowReadonly(widget),
116
+ };
117
+ }
package/src/vue.ts ADDED
@@ -0,0 +1,8 @@
1
+ export { Widget, type WidgetProps } from "./vue/Widget";
2
+ export {
3
+ useWidget,
4
+ type UseWidgetOptions,
5
+ type UseWidgetResult,
6
+ } from "./vue/useWidget";
7
+ export { useThemeTokens } from "./vue/useThemeTokens";
8
+ export type { ThemeObserveOptions } from "./vue/themeStore";