polen 0.10.0-next.11 → 0.10.0-next.12

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 (324) hide show
  1. package/build/api/builder/builder.js +1 -1
  2. package/build/api/builder/builder.js.map +1 -1
  3. package/build/api/config/load.js +1 -1
  4. package/build/api/config/load.js.map +1 -1
  5. package/build/api/vite/plugins/build.js +1 -1
  6. package/build/api/vite/plugins/build.js.map +1 -1
  7. package/build/api/vite/plugins/core.d.ts.map +1 -1
  8. package/build/api/vite/plugins/core.js +0 -2
  9. package/build/api/vite/plugins/core.js.map +1 -1
  10. package/build/api/vite/plugins/pages.js +1 -1
  11. package/build/api/vite/plugins/pages.js.map +1 -1
  12. package/build/exports/components.d.ts +4 -1
  13. package/build/exports/components.d.ts.map +1 -1
  14. package/build/exports/components.js +4 -1
  15. package/build/exports/components.js.map +1 -1
  16. package/build/lib/demos/config-schema.d.ts +6 -6
  17. package/build/lib/github-actions/runner.js +2 -2
  18. package/build/lib/github-actions/runner.js.map +1 -1
  19. package/build/lib/graphql-document/$$.d.ts +5 -0
  20. package/build/lib/graphql-document/$$.d.ts.map +1 -0
  21. package/build/lib/graphql-document/$$.js +5 -0
  22. package/build/lib/graphql-document/$$.js.map +1 -0
  23. package/build/lib/graphql-document/$.d.ts +2 -0
  24. package/build/lib/graphql-document/$.d.ts.map +1 -0
  25. package/build/lib/graphql-document/$.js +2 -0
  26. package/build/lib/graphql-document/$.js.map +1 -0
  27. package/build/lib/graphql-document/analysis.d.ts +44 -0
  28. package/build/lib/graphql-document/analysis.d.ts.map +1 -0
  29. package/build/lib/graphql-document/analysis.js +361 -0
  30. package/build/lib/graphql-document/analysis.js.map +1 -0
  31. package/build/lib/graphql-document/components/GraphQLDocument.d.ts +42 -0
  32. package/build/lib/graphql-document/components/GraphQLDocument.d.ts.map +1 -0
  33. package/build/lib/graphql-document/components/GraphQLDocument.js +173 -0
  34. package/build/lib/graphql-document/components/GraphQLDocument.js.map +1 -0
  35. package/build/lib/graphql-document/components/GraphQLDocumentWithSchema.d.ts +7 -0
  36. package/build/lib/graphql-document/components/GraphQLDocumentWithSchema.d.ts.map +1 -0
  37. package/build/lib/graphql-document/components/GraphQLDocumentWithSchema.js +45 -0
  38. package/build/lib/graphql-document/components/GraphQLDocumentWithSchema.js.map +1 -0
  39. package/build/lib/graphql-document/components/HoverTooltip.d.ts +35 -0
  40. package/build/lib/graphql-document/components/HoverTooltip.d.ts.map +1 -0
  41. package/build/lib/graphql-document/components/HoverTooltip.js +132 -0
  42. package/build/lib/graphql-document/components/HoverTooltip.js.map +1 -0
  43. package/build/lib/graphql-document/components/IdentifierLink.d.ts +37 -0
  44. package/build/lib/graphql-document/components/IdentifierLink.d.ts.map +1 -0
  45. package/build/lib/graphql-document/components/IdentifierLink.js +141 -0
  46. package/build/lib/graphql-document/components/IdentifierLink.js.map +1 -0
  47. package/build/lib/graphql-document/components/index.d.ts +5 -0
  48. package/build/lib/graphql-document/components/index.d.ts.map +1 -0
  49. package/build/lib/graphql-document/components/index.js +5 -0
  50. package/build/lib/graphql-document/components/index.js.map +1 -0
  51. package/build/lib/graphql-document/example.d.ts +25 -0
  52. package/build/lib/graphql-document/example.d.ts.map +1 -0
  53. package/build/lib/graphql-document/example.js +140 -0
  54. package/build/lib/graphql-document/example.js.map +1 -0
  55. package/build/lib/graphql-document/graphql-document.d.ts +35 -0
  56. package/build/lib/graphql-document/graphql-document.d.ts.map +1 -0
  57. package/build/lib/graphql-document/graphql-document.js +36 -0
  58. package/build/lib/graphql-document/graphql-document.js.map +1 -0
  59. package/build/lib/graphql-document/positioning-simple.d.ts +68 -0
  60. package/build/lib/graphql-document/positioning-simple.d.ts.map +1 -0
  61. package/build/lib/graphql-document/positioning-simple.js +197 -0
  62. package/build/lib/graphql-document/positioning-simple.js.map +1 -0
  63. package/build/lib/graphql-document/schema-context.d.ts +8 -0
  64. package/build/lib/graphql-document/schema-context.d.ts.map +1 -0
  65. package/build/lib/graphql-document/schema-context.js +11 -0
  66. package/build/lib/graphql-document/schema-context.js.map +1 -0
  67. package/build/lib/graphql-document/schema-integration-example.d.ts +27 -0
  68. package/build/lib/graphql-document/schema-integration-example.d.ts.map +1 -0
  69. package/build/lib/graphql-document/schema-integration-example.js +297 -0
  70. package/build/lib/graphql-document/schema-integration-example.js.map +1 -0
  71. package/build/lib/graphql-document/schema-integration.d.ts +135 -0
  72. package/build/lib/graphql-document/schema-integration.d.ts.map +1 -0
  73. package/build/lib/graphql-document/schema-integration.js +328 -0
  74. package/build/lib/graphql-document/schema-integration.js.map +1 -0
  75. package/build/lib/graphql-document/types.d.ts +117 -0
  76. package/build/lib/graphql-document/types.d.ts.map +1 -0
  77. package/build/lib/graphql-document/types.js +2 -0
  78. package/build/lib/graphql-document/types.js.map +1 -0
  79. package/build/template/components/ArgumentAnnotation.js +10 -0
  80. package/build/template/components/ArgumentAnnotation.js.map +1 -0
  81. package/build/template/components/ArgumentList.js +9 -0
  82. package/build/template/components/ArgumentList.js.map +1 -0
  83. package/build/template/components/ArgumentListAnnotation.js +15 -0
  84. package/build/template/components/ArgumentListAnnotation.js.map +1 -0
  85. package/build/template/components/Changelog.js +44 -0
  86. package/build/template/components/Changelog.js.map +1 -0
  87. package/build/template/components/{CodeBlock.jsx → CodeBlock.js} +4 -5
  88. package/build/template/components/{CodeBlock.jsx.map → CodeBlock.js.map} +1 -1
  89. package/build/template/components/{CodeBlockEnhancer.jsx → CodeBlockEnhancer.js} +4 -4
  90. package/build/template/components/CodeBlockEnhancer.js.map +1 -0
  91. package/build/template/components/DeprecationReason.js +9 -0
  92. package/build/template/components/DeprecationReason.js.map +1 -0
  93. package/build/template/components/Description.js +9 -0
  94. package/build/template/components/Description.js.map +1 -0
  95. package/build/template/components/Field.js +14 -0
  96. package/build/template/components/Field.js.map +1 -0
  97. package/build/template/components/{FieldList.jsx → FieldList.js} +4 -5
  98. package/build/template/components/FieldList.js.map +1 -0
  99. package/build/template/components/{FieldListSection.jsx → FieldListSection.js} +4 -6
  100. package/build/template/components/FieldListSection.js.map +1 -0
  101. package/build/template/components/HamburgerMenu.js +30 -0
  102. package/build/template/components/HamburgerMenu.js.map +1 -0
  103. package/build/template/components/Link.d.ts +1 -1
  104. package/build/template/components/{Link.jsx → Link.js} +4 -5
  105. package/build/template/components/Link.js.map +1 -0
  106. package/build/template/components/Logo.js +20 -0
  107. package/build/template/components/Logo.js.map +1 -0
  108. package/build/template/components/MDXComponents.d.ts +11 -0
  109. package/build/template/components/MDXComponents.d.ts.map +1 -0
  110. package/build/template/components/MDXComponents.js +70 -0
  111. package/build/template/components/MDXComponents.js.map +1 -0
  112. package/build/template/components/{Markdown.jsx → Markdown.js} +3 -2
  113. package/build/template/components/Markdown.js.map +1 -0
  114. package/build/template/components/MissingSchema.d.ts +1 -1
  115. package/build/template/components/MissingSchema.d.ts.map +1 -1
  116. package/build/template/components/MissingSchema.js +5 -0
  117. package/build/template/components/MissingSchema.js.map +1 -0
  118. package/build/template/components/NamedType.js +12 -0
  119. package/build/template/components/NamedType.js.map +1 -0
  120. package/build/template/components/NotFound.js +7 -0
  121. package/build/template/components/NotFound.js.map +1 -0
  122. package/build/template/components/{RadixLink.jsx → RadixLink.js} +1 -1
  123. package/build/template/components/RadixLink.js.map +1 -0
  124. package/build/template/components/TestComponent.d.ts +5 -0
  125. package/build/template/components/TestComponent.d.ts.map +1 -0
  126. package/build/template/components/TestComponent.js +7 -0
  127. package/build/template/components/TestComponent.js.map +1 -0
  128. package/build/template/components/Texts/{MinorHeading.jsx → MinorHeading.js} +4 -3
  129. package/build/template/components/Texts/MinorHeading.js.map +1 -0
  130. package/build/template/components/Texts/texts.js +1 -1
  131. package/build/template/components/Texts/texts.js.map +1 -1
  132. package/build/template/components/ThemeToggle.js +9 -0
  133. package/build/template/components/ThemeToggle.js.map +1 -0
  134. package/build/template/components/{TypeAnnotation.jsx → TypeAnnotation.js} +8 -18
  135. package/build/template/components/TypeAnnotation.js.map +1 -0
  136. package/build/template/components/TypeFieldsLinkList.js +9 -0
  137. package/build/template/components/TypeFieldsLinkList.js.map +1 -0
  138. package/build/template/components/TypeIndex.js +17 -0
  139. package/build/template/components/TypeIndex.js.map +1 -0
  140. package/build/template/components/content/$$.d.ts +1 -0
  141. package/build/template/components/content/$$.d.ts.map +1 -1
  142. package/build/template/components/content/$$.js +1 -0
  143. package/build/template/components/content/$$.js.map +1 -1
  144. package/build/template/components/content/GraphQLDocumentWithSchema.d.ts +8 -0
  145. package/build/template/components/content/GraphQLDocumentWithSchema.d.ts.map +1 -0
  146. package/build/template/components/content/GraphQLDocumentWithSchema.js +16 -0
  147. package/build/template/components/content/GraphQLDocumentWithSchema.js.map +1 -0
  148. package/build/template/components/content/GraphQLDocumentWrapper.d.ts +7 -0
  149. package/build/template/components/content/GraphQLDocumentWrapper.d.ts.map +1 -0
  150. package/build/template/components/content/GraphQLDocumentWrapper.js +62 -0
  151. package/build/template/components/content/GraphQLDocumentWrapper.js.map +1 -0
  152. package/build/template/components/graphql/graphql.d.ts +2 -2
  153. package/build/template/components/graphql/graphql.js +3 -0
  154. package/build/template/components/graphql/graphql.js.map +1 -0
  155. package/build/template/components/graphql/index.d.ts +1 -1
  156. package/build/template/components/graphql/index.js +1 -1
  157. package/build/template/components/graphql/index.js.map +1 -1
  158. package/build/template/components/graphql/{type-kind-icon.jsx → type-kind-icon.js} +3 -2
  159. package/build/template/components/graphql/type-kind-icon.js.map +1 -0
  160. package/build/template/components/graphql/type-link.js +11 -0
  161. package/build/template/components/graphql/type-link.js.map +1 -0
  162. package/build/template/components/sidebar/Sidebar.d.ts +1 -1
  163. package/build/template/components/sidebar/Sidebar.d.ts.map +1 -1
  164. package/build/template/components/sidebar/Sidebar.js +11 -0
  165. package/build/template/components/sidebar/Sidebar.js.map +1 -0
  166. package/build/template/components/sidebar/{SidebarItem.jsx → SidebarItem.js} +15 -32
  167. package/build/template/components/sidebar/SidebarItem.js.map +1 -0
  168. package/build/template/components/sidebar/ToggleButton.d.ts +1 -1
  169. package/build/template/components/sidebar/ToggleButton.d.ts.map +1 -1
  170. package/build/template/components/sidebar/ToggleButton.js +5 -0
  171. package/build/template/components/sidebar/ToggleButton.js.map +1 -0
  172. package/build/template/contexts/{ThemeContext.jsx → ThemeContext.js} +3 -4
  173. package/build/template/contexts/{ThemeContext.jsx.map → ThemeContext.js.map} +1 -1
  174. package/build/template/entry.client.d.ts +1 -0
  175. package/build/template/entry.client.d.ts.map +1 -1
  176. package/build/template/{entry.client.jsx → entry.client.js} +5 -6
  177. package/build/template/entry.client.js.map +1 -0
  178. package/build/template/routes/changelog.d.ts +1 -1
  179. package/build/template/routes/{changelog.jsx → changelog.js} +5 -4
  180. package/build/template/routes/changelog.js.map +1 -0
  181. package/build/template/routes/{index.jsx → index.js} +3 -2
  182. package/build/template/routes/index.js.map +1 -0
  183. package/build/template/routes/reference.$type.$field.d.ts +1 -1
  184. package/build/template/routes/{reference.$type.$field.jsx → reference.$type.$field.js} +6 -5
  185. package/build/template/routes/reference.$type.$field.js.map +1 -0
  186. package/build/template/routes/reference.$type.d.ts +1 -1
  187. package/build/template/routes/{reference.$type.jsx → reference.$type.js} +6 -5
  188. package/build/template/routes/reference.$type.js.map +1 -0
  189. package/build/template/routes/reference.d.ts +2 -2
  190. package/build/template/routes/{reference.jsx → reference.js} +6 -7
  191. package/build/template/routes/reference.js.map +1 -0
  192. package/build/template/routes/root.d.ts +2 -2
  193. package/build/template/routes/root.d.ts.map +1 -1
  194. package/build/template/routes/{root.jsx → root.js} +46 -88
  195. package/build/template/routes/root.js.map +1 -0
  196. package/build/template/routes.js +5 -0
  197. package/build/template/routes.js.map +1 -0
  198. package/build/template/server/app.js +1 -1
  199. package/build/template/server/app.js.map +1 -1
  200. package/build/template/server/{render-page.jsx → render-page.js} +3 -4
  201. package/build/template/server/render-page.js.map +1 -0
  202. package/build/template/server/ssg/generate.js +1 -1
  203. package/build/template/server/ssg/generate.js.map +1 -1
  204. package/build/template/server/ssg/get-route-paths.js +1 -1
  205. package/build/template/server/ssg/get-route-paths.js.map +1 -1
  206. package/build/template/server/view.js +1 -1
  207. package/build/template/server/view.js.map +1 -1
  208. package/package.json +56 -8
  209. package/src/api/vite/plugins/core.ts +0 -3
  210. package/src/api/vite/plugins/pages.ts +1 -1
  211. package/src/exports/components.ts +4 -1
  212. package/src/lib/graphql-document/$$.ts +4 -0
  213. package/src/lib/graphql-document/$.test.ts +132 -0
  214. package/src/lib/graphql-document/$.ts +1 -0
  215. package/src/lib/graphql-document/README.md +102 -0
  216. package/src/lib/graphql-document/analysis.ts +415 -0
  217. package/src/lib/graphql-document/components/GraphQLDocument.tsx +284 -0
  218. package/src/lib/graphql-document/components/GraphQLDocument.unit.test.ts +188 -0
  219. package/src/lib/graphql-document/components/GraphQLDocumentWithSchema.tsx +70 -0
  220. package/src/lib/graphql-document/components/HoverTooltip.tsx +282 -0
  221. package/src/lib/graphql-document/components/IdentifierLink.tsx +221 -0
  222. package/src/lib/graphql-document/components/index.ts +4 -0
  223. package/src/lib/graphql-document/demo.md +155 -0
  224. package/src/lib/graphql-document/example.ts +163 -0
  225. package/src/lib/graphql-document/graphql-document.ts +37 -0
  226. package/src/lib/graphql-document/positioning-simple.test.ts +252 -0
  227. package/src/lib/graphql-document/positioning-simple.ts +271 -0
  228. package/src/lib/graphql-document/schema-context.tsx +20 -0
  229. package/src/lib/graphql-document/schema-integration-example.ts +341 -0
  230. package/src/lib/graphql-document/schema-integration.test.ts +365 -0
  231. package/src/lib/graphql-document/schema-integration.ts +497 -0
  232. package/src/lib/graphql-document/types.ts +129 -0
  233. package/src/template/components/ArgumentAnnotation.tsx +1 -1
  234. package/src/template/components/ArgumentList.tsx +1 -1
  235. package/src/template/components/ArgumentListAnnotation.tsx +2 -2
  236. package/src/template/components/CodeBlockEnhancer.tsx +21 -21
  237. package/src/template/components/DeprecationReason.tsx +1 -1
  238. package/src/template/components/Description.tsx +1 -1
  239. package/src/template/components/Field.tsx +4 -4
  240. package/src/template/components/FieldList.tsx +1 -1
  241. package/src/template/components/FieldListSection.tsx +1 -1
  242. package/src/template/components/Link.tsx +2 -2
  243. package/src/template/components/MDXComponents.tsx +101 -0
  244. package/src/template/components/NamedType.tsx +2 -2
  245. package/src/template/components/TestComponent.tsx +6 -0
  246. package/src/template/components/TypeAnnotation.tsx +1 -1
  247. package/src/template/components/TypeFieldsLinkList.tsx +1 -1
  248. package/src/template/components/TypeIndex.tsx +1 -1
  249. package/src/template/components/content/$$.ts +1 -0
  250. package/src/template/components/content/GraphQLDocumentWithSchema.tsx +18 -0
  251. package/src/template/components/content/GraphQLDocumentWrapper.tsx +82 -0
  252. package/src/template/components/graphql/graphql.tsx +2 -2
  253. package/src/template/components/graphql/index.ts +1 -1
  254. package/src/template/components/graphql/type-link.tsx +2 -2
  255. package/src/template/entry.client.tsx +2 -2
  256. package/src/template/routes/changelog.tsx +1 -1
  257. package/src/template/routes/reference.$type.$field.tsx +3 -3
  258. package/src/template/routes/reference.$type.tsx +3 -3
  259. package/src/template/routes/reference.tsx +3 -3
  260. package/src/template/routes/root.tsx +36 -25
  261. package/src/template/routes.tsx +1 -1
  262. package/src/template/server/app.ts +1 -1
  263. package/src/template/server/ssg/generate.ts +1 -1
  264. package/src/template/server/ssg/get-route-paths.ts +1 -1
  265. package/src/template/server/view.ts +1 -1
  266. package/src/template/styles/code-block.css +32 -0
  267. package/build/template/components/ArgumentAnnotation.jsx +0 -16
  268. package/build/template/components/ArgumentAnnotation.jsx.map +0 -1
  269. package/build/template/components/ArgumentList.jsx +0 -16
  270. package/build/template/components/ArgumentList.jsx.map +0 -1
  271. package/build/template/components/ArgumentListAnnotation.jsx +0 -23
  272. package/build/template/components/ArgumentListAnnotation.jsx.map +0 -1
  273. package/build/template/components/Changelog.jsx +0 -68
  274. package/build/template/components/Changelog.jsx.map +0 -1
  275. package/build/template/components/CodeBlockEnhancer.jsx.map +0 -1
  276. package/build/template/components/DeprecationReason.jsx +0 -10
  277. package/build/template/components/DeprecationReason.jsx.map +0 -1
  278. package/build/template/components/Description.jsx +0 -10
  279. package/build/template/components/Description.jsx.map +0 -1
  280. package/build/template/components/Field.jsx +0 -22
  281. package/build/template/components/Field.jsx.map +0 -1
  282. package/build/template/components/FieldList.jsx.map +0 -1
  283. package/build/template/components/FieldListSection.jsx.map +0 -1
  284. package/build/template/components/HamburgerMenu.jsx +0 -53
  285. package/build/template/components/HamburgerMenu.jsx.map +0 -1
  286. package/build/template/components/Link.jsx.map +0 -1
  287. package/build/template/components/Logo.jsx +0 -29
  288. package/build/template/components/Logo.jsx.map +0 -1
  289. package/build/template/components/Markdown.jsx.map +0 -1
  290. package/build/template/components/MissingSchema.jsx +0 -4
  291. package/build/template/components/MissingSchema.jsx.map +0 -1
  292. package/build/template/components/NamedType.jsx +0 -17
  293. package/build/template/components/NamedType.jsx.map +0 -1
  294. package/build/template/components/NotFound.jsx +0 -26
  295. package/build/template/components/NotFound.jsx.map +0 -1
  296. package/build/template/components/RadixLink.jsx.map +0 -1
  297. package/build/template/components/Texts/MinorHeading.jsx.map +0 -1
  298. package/build/template/components/ThemeToggle.jsx +0 -10
  299. package/build/template/components/ThemeToggle.jsx.map +0 -1
  300. package/build/template/components/TypeAnnotation.jsx.map +0 -1
  301. package/build/template/components/TypeFieldsLinkList.jsx +0 -17
  302. package/build/template/components/TypeFieldsLinkList.jsx.map +0 -1
  303. package/build/template/components/TypeIndex.jsx +0 -27
  304. package/build/template/components/TypeIndex.jsx.map +0 -1
  305. package/build/template/components/graphql/graphql.jsx +0 -3
  306. package/build/template/components/graphql/graphql.jsx.map +0 -1
  307. package/build/template/components/graphql/type-kind-icon.jsx.map +0 -1
  308. package/build/template/components/graphql/type-link.jsx +0 -16
  309. package/build/template/components/graphql/type-link.jsx.map +0 -1
  310. package/build/template/components/sidebar/Sidebar.jsx +0 -15
  311. package/build/template/components/sidebar/Sidebar.jsx.map +0 -1
  312. package/build/template/components/sidebar/SidebarItem.jsx.map +0 -1
  313. package/build/template/components/sidebar/ToggleButton.jsx +0 -6
  314. package/build/template/components/sidebar/ToggleButton.jsx.map +0 -1
  315. package/build/template/entry.client.jsx.map +0 -1
  316. package/build/template/routes/changelog.jsx.map +0 -1
  317. package/build/template/routes/index.jsx.map +0 -1
  318. package/build/template/routes/reference.$type.$field.jsx.map +0 -1
  319. package/build/template/routes/reference.$type.jsx.map +0 -1
  320. package/build/template/routes/reference.jsx.map +0 -1
  321. package/build/template/routes/root.jsx.map +0 -1
  322. package/build/template/routes.jsx +0 -5
  323. package/build/template/routes.jsx.map +0 -1
  324. package/build/template/server/render-page.jsx.map +0 -1
@@ -0,0 +1,284 @@
1
+ import type { React } from '#dep/react/index'
2
+ import type { GraphQLSchema } from 'graphql'
3
+ import { useEffect, useMemo, useRef, useState } from 'react'
4
+ import { useNavigate } from 'react-router'
5
+ import { analyze } from '../analysis.ts'
6
+ import { createSimplePositionCalculator } from '../positioning-simple.ts'
7
+ import { createPolenSchemaResolver } from '../schema-integration.ts'
8
+ import type { Identifier } from '../types.ts'
9
+ import { hoverTooltipStyles } from './HoverTooltip.tsx'
10
+ import { IdentifierLink } from './IdentifierLink.tsx'
11
+ import { identifierLinkStyles } from './IdentifierLink.tsx'
12
+
13
+ /**
14
+ * Options for the GraphQL document component
15
+ */
16
+ export interface GraphQLDocumentOptions {
17
+ /** Whether to show debug overlays */
18
+ debug?: boolean
19
+ /** Whether to disable interactive features */
20
+ plain?: boolean
21
+ /** Custom navigation handler */
22
+ onNavigate?: (url: string) => void
23
+ /** Whether to validate against schema */
24
+ validate?: boolean
25
+ /** Custom class name for the container */
26
+ className?: string
27
+ }
28
+
29
+ /**
30
+ * Props for the GraphQL document component
31
+ */
32
+ export interface GraphQLDocumentProps {
33
+ /** The GraphQL document source code */
34
+ children: string
35
+ /** GraphQL schema for validation and linking */
36
+ schema?: GraphQLSchema
37
+ /** Component options */
38
+ options?: GraphQLDocumentOptions
39
+ /** Pre-rendered Shiki HTML (from build time) */
40
+ highlightedHtml?: string
41
+ }
42
+
43
+ /**
44
+ * Interactive GraphQL document component
45
+ *
46
+ * Transforms static GraphQL code blocks into interactive documentation
47
+ * with hyperlinks, tooltips, and schema validation.
48
+ */
49
+ export const GraphQLDocument: React.FC<GraphQLDocumentProps> = ({
50
+ children,
51
+ schema,
52
+ options = {},
53
+ highlightedHtml,
54
+ }) => {
55
+ const {
56
+ debug = false,
57
+ plain = false,
58
+ onNavigate,
59
+ validate = true,
60
+ className = '',
61
+ } = options
62
+
63
+ const navigate = useNavigate()
64
+ const handleNavigate = onNavigate || ((url: string) => navigate(url))
65
+
66
+ // Container ref for positioning calculations
67
+ const containerRef = useRef<HTMLDivElement>(null)
68
+ const [isReady, setIsReady] = useState(false)
69
+ const [openTooltipId, setOpenTooltipId] = useState<string | null>(null)
70
+
71
+ // Handle click outside to close tooltips
72
+ useEffect(() => {
73
+ if (!openTooltipId) return
74
+
75
+ const handleClickOutside = (event: MouseEvent) => {
76
+ // Check if click is outside the tooltip and identifier links
77
+ const target = event.target as HTMLElement
78
+
79
+ // Don't close if clicking on an identifier link or tooltip
80
+ if (
81
+ target.closest('.graphql-identifier-overlay')
82
+ || target.closest('.graphql-hover-tooltip')
83
+ ) {
84
+ return
85
+ }
86
+
87
+ // Close the tooltip
88
+ setOpenTooltipId(null)
89
+ }
90
+
91
+ // Add event listener
92
+ document.addEventListener('mousedown', handleClickOutside)
93
+
94
+ return () => {
95
+ document.removeEventListener('mousedown', handleClickOutside)
96
+ }
97
+ }, [openTooltipId])
98
+
99
+ // Layer 1: Parse and analyze
100
+ const analysisResult = useMemo(() => {
101
+ if (plain) return null
102
+ const result = analyze(children, { schema })
103
+ return result
104
+ }, [children, plain, schema])
105
+
106
+ // Layer 2: Schema resolution
107
+ const resolver = useMemo(() => {
108
+ if (!schema || plain) return null
109
+ return createPolenSchemaResolver(schema)
110
+ }, [schema, plain])
111
+
112
+ const resolutions = useMemo(() => {
113
+ if (!analysisResult || !resolver) {
114
+ return new Map()
115
+ }
116
+
117
+ const results = new Map()
118
+ for (const [position, identifier] of analysisResult.identifiers.byPosition) {
119
+ const resolution = resolver.resolveIdentifier(identifier)
120
+ if (resolution) {
121
+ results.set(position, resolution)
122
+ }
123
+ }
124
+ return results
125
+ }, [analysisResult, resolver])
126
+
127
+ // Layer 3: Position calculation
128
+ const positionCalculator = useMemo(() => {
129
+ if (plain) return null
130
+ return createSimplePositionCalculator()
131
+ }, [plain])
132
+
133
+ const [positions, setPositions] = useState<Map<string, { position: any; identifier: Identifier }>>(new Map())
134
+
135
+ // Prepare code block and calculate positions after render
136
+ useEffect(() => {
137
+ if (!containerRef.current || !analysisResult || !positionCalculator || plain) {
138
+ return
139
+ }
140
+
141
+ // Get the code element within the container
142
+ const codeElement = containerRef.current.querySelector('pre.shiki code')
143
+ || containerRef.current.querySelector('pre code')
144
+ || containerRef.current.querySelector('code')
145
+ if (!codeElement) {
146
+ return
147
+ }
148
+
149
+ // Prepare the code block (wrap identifiers)
150
+ const identifiers = Array.from(analysisResult.identifiers.byPosition.values())
151
+ positionCalculator.prepareCodeBlock(codeElement as Element, identifiers)
152
+
153
+ // Get positions after DOM update
154
+ requestAnimationFrame(() => {
155
+ // Pass containerRef.current as the reference element for positioning
156
+ if (containerRef.current) {
157
+ const newPositions = positionCalculator.getIdentifierPositions(codeElement as Element, containerRef.current)
158
+ setPositions(newPositions)
159
+ setIsReady(true)
160
+ }
161
+ })
162
+ }, [analysisResult, positionCalculator, plain, highlightedHtml])
163
+
164
+ // Handle resize events
165
+ useEffect(() => {
166
+ if (!containerRef.current || !positionCalculator || plain) return
167
+
168
+ const handleResize = () => {
169
+ const codeElement = containerRef.current?.querySelector('pre.shiki code')
170
+ || containerRef.current?.querySelector('pre code')
171
+ || containerRef.current?.querySelector('code')
172
+ if (codeElement && containerRef.current) {
173
+ const newPositions = positionCalculator.getIdentifierPositions(codeElement as Element, containerRef.current)
174
+ setPositions(newPositions)
175
+ }
176
+ }
177
+
178
+ window.addEventListener('resize', handleResize)
179
+ return () => window.removeEventListener('resize', handleResize)
180
+ }, [positionCalculator, plain])
181
+
182
+ // Validation errors
183
+ const validationErrors = useMemo(() => {
184
+ if (!validate || !analysisResult || !schema) return []
185
+ return analysisResult.errors
186
+ }, [validate, analysisResult, schema])
187
+
188
+ return (
189
+ <>
190
+ {/* Inject styles */}
191
+ <style dangerouslySetInnerHTML={{ __html: identifierLinkStyles + '\n' + hoverTooltipStyles }} />
192
+
193
+ <div
194
+ ref={containerRef}
195
+ className={`graphql-document ${className} ${debug ? 'graphql-debug-mode' : ''}`}
196
+ style={{ position: 'relative' }}
197
+ >
198
+ {/* Base syntax highlighting */}
199
+ {highlightedHtml ? <div dangerouslySetInnerHTML={{ __html: highlightedHtml }} /> : (
200
+ <pre className='shiki'>
201
+ <code>{children}</code>
202
+ </pre>
203
+ )}
204
+
205
+ {/* Interactive overlay layer */}
206
+ {!plain && isReady && (
207
+ <div className='graphql-interaction-layer' style={{ pointerEvents: 'none' }}>
208
+ {Array.from(positions.entries()).map(([id, { position, identifier }]) => {
209
+ const startPos = identifier.position.start
210
+ const resolution = resolutions.get(startPos)
211
+
212
+ if (!resolution) return null
213
+
214
+ return (
215
+ <IdentifierLink
216
+ key={id}
217
+ identifier={identifier}
218
+ resolution={resolution}
219
+ position={position}
220
+ onNavigate={handleNavigate}
221
+ debug={debug}
222
+ isOpen={openTooltipId === id}
223
+ onToggle={(open) => setOpenTooltipId(open ? id : null)}
224
+ />
225
+ )
226
+ })}
227
+ </div>
228
+ )}
229
+
230
+ {/* Validation errors overlay */}
231
+ {validationErrors.length > 0 && (
232
+ <div className='graphql-validation-errors'>
233
+ {validationErrors.map((error: any, index: number) => (
234
+ <div key={index} className='graphql-error'>
235
+ {error.message}
236
+ </div>
237
+ ))}
238
+ </div>
239
+ )}
240
+ </div>
241
+ </>
242
+ )
243
+ }
244
+
245
+ /**
246
+ * Default styles for the GraphQL document component
247
+ */
248
+ export const graphqlDocumentStyles = `
249
+ .graphql-document {
250
+ position: relative;
251
+ }
252
+
253
+ .graphql-interaction-layer {
254
+ position: absolute;
255
+ top: 0;
256
+ left: 0;
257
+ right: 0;
258
+ bottom: 0;
259
+ pointer-events: none;
260
+ }
261
+
262
+ .graphql-interaction-layer > * {
263
+ pointer-events: auto;
264
+ }
265
+
266
+ .graphql-validation-errors {
267
+ margin-top: 1rem;
268
+ padding: 0.5rem;
269
+ background-color: var(--red-2);
270
+ border: 1px solid var(--red-6);
271
+ border-radius: 4px;
272
+ }
273
+
274
+ .graphql-error {
275
+ color: var(--red-11);
276
+ font-size: 0.875rem;
277
+ margin: 0.25rem 0;
278
+ }
279
+
280
+ .graphql-debug-mode [data-graphql-id] {
281
+ background-color: rgba(59, 130, 246, 0.1);
282
+ outline: 1px solid rgba(59, 130, 246, 0.3);
283
+ }
284
+ `
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Unit tests for GraphQL Document component logic
3
+ *
4
+ * Tests the core functionality without rendering React components
5
+ */
6
+
7
+ import { buildSchema } from 'graphql'
8
+ import { describe, expect, it } from 'vitest'
9
+ import { analyze } from '../analysis.ts'
10
+ import { createSimplePositionCalculator } from '../positioning-simple.ts'
11
+ import { analyzeWithSchema, createPolenSchemaResolver } from '../schema-integration.ts'
12
+
13
+ describe('GraphQLDocument logic', () => {
14
+ const testSchema = buildSchema(`
15
+ type Query {
16
+ user(id: ID!): User
17
+ users: [User!]!
18
+ }
19
+
20
+ type User {
21
+ id: ID!
22
+ name: String!
23
+ email: String!
24
+ posts: [Post!]!
25
+ }
26
+
27
+ type Post {
28
+ id: ID!
29
+ title: String!
30
+ content: String!
31
+ author: User!
32
+ }
33
+ `)
34
+
35
+ const testQuery = `
36
+ query GetUser($id: ID!) {
37
+ user(id: $id) {
38
+ id
39
+ name
40
+ email
41
+ posts {
42
+ title
43
+ }
44
+ }
45
+ }`
46
+
47
+ describe('analysis integration', () => {
48
+ it('should analyze GraphQL document and extract identifiers', () => {
49
+ const result = analyze(testQuery)
50
+
51
+ expect(result.identifiers.byKind.get('Field')).toBeDefined()
52
+ expect(result.identifiers.byKind.get('Variable')).toBeDefined()
53
+ expect(result.identifiers.byKind.get('Type')).toBeDefined()
54
+
55
+ // Check specific identifiers
56
+ const fields = result.identifiers.byKind.get('Field') || []
57
+ const fieldNames = fields.map(f => f.name)
58
+ expect(fieldNames).toContain('user')
59
+ expect(fieldNames).toContain('id')
60
+ expect(fieldNames).toContain('name')
61
+ expect(fieldNames).toContain('email')
62
+ expect(fieldNames).toContain('posts')
63
+ expect(fieldNames).toContain('title')
64
+ })
65
+
66
+ it('should handle empty document', () => {
67
+ const result = analyze('')
68
+ expect(result.identifiers.byPosition.size).toBe(0)
69
+ // Empty string is technically parseable as an empty document
70
+ expect(result.ast).toBeDefined()
71
+ })
72
+ })
73
+
74
+ describe('schema resolution integration', () => {
75
+ it('should resolve identifiers against schema', () => {
76
+ // Use analyzeWithSchema for proper schema-aware analysis
77
+ const { analysis, resolutions } = analyzeWithSchema(testQuery, testSchema)
78
+
79
+ // Check that analysis found identifiers
80
+ expect(analysis.identifiers.all.length).toBeGreaterThan(0)
81
+
82
+ // Check that we have resolutions
83
+ expect(resolutions.size).toBeGreaterThan(0)
84
+
85
+ // Check that analysis is valid
86
+ expect(analysis.isValid).toBe(true)
87
+
88
+ // Basic check that resolutions were created
89
+ const hasValidResolutions = Array.from(resolutions.values()).some(
90
+ res => res.exists && res.referenceUrl.includes('/reference/'),
91
+ )
92
+ expect(hasValidResolutions).toBe(true)
93
+ })
94
+
95
+ it('should detect non-existent fields', () => {
96
+ const invalidQuery = `query { nonExistentField }`
97
+ const result = analyze(invalidQuery)
98
+ const resolver = createPolenSchemaResolver(testSchema)
99
+
100
+ const field = Array.from(result.identifiers.byPosition.values())[0]
101
+ const resolution = resolver.resolveIdentifier(field!)
102
+
103
+ expect(resolution).toBeDefined()
104
+ expect(resolution!.exists).toBe(false)
105
+ })
106
+ })
107
+
108
+ describe('position calculation', () => {
109
+ it('should create position calculator', () => {
110
+ const calculator = createSimplePositionCalculator()
111
+ expect(calculator).toBeDefined()
112
+ expect(calculator.prepareCodeBlock).toBeDefined()
113
+ expect(calculator.getIdentifierPositions).toBeDefined()
114
+ })
115
+ })
116
+
117
+ describe('options handling', () => {
118
+ it('should skip analysis when plain option is true', () => {
119
+ const options = { plain: true }
120
+ // When plain is true, no analysis should be performed
121
+ expect(options.plain).toBe(true)
122
+ })
123
+
124
+ it('should enable debug mode', () => {
125
+ const options = { debug: true }
126
+ expect(options.debug).toBe(true)
127
+ })
128
+
129
+ it('should handle custom navigation', () => {
130
+ const onNavigate = (url: string) => {
131
+ expect(url).toContain('/reference/')
132
+ }
133
+ const options = { onNavigate }
134
+ expect(options.onNavigate).toBeDefined()
135
+ })
136
+
137
+ it('should handle validation option', () => {
138
+ const options = { validate: true }
139
+ expect(options.validate).toBe(true)
140
+ })
141
+
142
+ it('should handle custom className', () => {
143
+ const options = { className: 'custom-graphql-block' }
144
+ expect(options.className).toBe('custom-graphql-block')
145
+ })
146
+ })
147
+
148
+ describe('validation', () => {
149
+ it('should validate valid queries', () => {
150
+ const { analysis, resolutions } = analyzeWithSchema(testQuery, testSchema)
151
+
152
+ // Check that validation passed
153
+ expect(analysis.isValid).toBe(true)
154
+
155
+ // Check that we have resolutions
156
+ expect(resolutions.size).toBeGreaterThan(0)
157
+
158
+ // Check that the user field resolved correctly
159
+ const userResolution = Array.from(resolutions.values()).find(
160
+ res => res.referenceUrl.includes('query') && res.referenceUrl.includes('user'),
161
+ )
162
+
163
+ if (userResolution) {
164
+ expect(userResolution.exists).toBe(true)
165
+ }
166
+ })
167
+
168
+ it('should detect validation errors', () => {
169
+ const invalidQuery = `
170
+ query {
171
+ user {
172
+ nonExistentField
173
+ }
174
+ }
175
+ `
176
+
177
+ const result = analyze(invalidQuery)
178
+ const resolver = createPolenSchemaResolver(testSchema)
179
+
180
+ const resolutions = Array.from(result.identifiers.byPosition.values())
181
+ .map(id => ({ id, resolution: resolver.resolveIdentifier(id) }))
182
+
183
+ const invalidField = resolutions.find(r => r.id.name === 'nonExistentField')
184
+ expect(invalidField).toBeDefined()
185
+ expect(invalidField!.resolution!.exists).toBe(false)
186
+ })
187
+ })
188
+ })
@@ -0,0 +1,70 @@
1
+ import type { React } from '#dep/react/index'
2
+ import { useEffect, useState } from 'react'
3
+ import { useGraphQLSchema } from '../schema-context.tsx'
4
+ import { GraphQLDocument, type GraphQLDocumentProps } from './GraphQLDocument.tsx'
5
+
6
+ // Cache for highlighter
7
+ let highlighterCache: any = null
8
+
9
+ /**
10
+ * GraphQL Document component that uses the schema context and handles syntax highlighting
11
+ */
12
+ export const GraphQLDocumentWithSchema: React.FC<Omit<GraphQLDocumentProps, 'schema' | 'highlightedHtml'>> = (
13
+ props,
14
+ ) => {
15
+ const schema = useGraphQLSchema()
16
+ const [mounted, setMounted] = useState(false)
17
+ const [highlightedHtml, setHighlightedHtml] = useState<string | null>(null)
18
+
19
+ useEffect(() => {
20
+ setMounted(true)
21
+
22
+ const loadHighlighter = async () => {
23
+ try {
24
+ // Load highlighter if not cached
25
+ if (!highlighterCache) {
26
+ const { highlightCode } = await import('#lib/shiki/index')
27
+ highlighterCache = highlightCode
28
+ }
29
+
30
+ // Generate highlighted HTML
31
+ const highlighted = await highlighterCache({
32
+ code: props['children'],
33
+ lang: 'graphql',
34
+ theme: 'light',
35
+ })
36
+
37
+ setHighlightedHtml(highlighted)
38
+ } catch (error) {
39
+ console.error('Failed to load GraphQL document highlighter:', error)
40
+ }
41
+ }
42
+
43
+ loadHighlighter()
44
+ }, [props['children']])
45
+
46
+ // Always render the same structure to avoid hydration issues
47
+ const isInteractive = mounted && schema && highlightedHtml
48
+
49
+ if (!isInteractive) {
50
+ // Static fallback that looks like Shiki output
51
+ return (
52
+ <div className='graphql-document graphql-document-static' data-testid='graphql-document'>
53
+ <pre
54
+ className='shiki shiki-themes github-light tokyo-night'
55
+ style={{ backgroundColor: 'var(--shiki-light-bg)', color: 'var(--shiki-light)' }}
56
+ >
57
+ <code className="language-graphql">{props['children']}</code>
58
+ </pre>
59
+ </div>
60
+ )
61
+ }
62
+
63
+ return (
64
+ <GraphQLDocument
65
+ {...props}
66
+ schema={schema}
67
+ highlightedHtml={highlightedHtml}
68
+ />
69
+ )
70
+ }