@ciderpress/ui 1.0.0-rc.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 (428) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -0
  3. package/dist/0~142.js +2 -0
  4. package/dist/0~164.js +2 -0
  5. package/dist/0~2.js +2 -0
  6. package/dist/0~225.js +2 -0
  7. package/dist/0~288.js +2 -0
  8. package/dist/0~299.js +2 -0
  9. package/dist/0~3.js +2 -0
  10. package/dist/0~301.js +2 -0
  11. package/dist/0~311.js +2 -0
  12. package/dist/0~326.js +2 -0
  13. package/dist/0~40.js +2 -0
  14. package/dist/0~43.js +2 -0
  15. package/dist/0~433.js +2 -0
  16. package/dist/0~453.js +2 -0
  17. package/dist/0~457.js +2 -0
  18. package/dist/0~497.js +2 -0
  19. package/dist/0~511.js +2 -0
  20. package/dist/0~603.js +2 -0
  21. package/dist/0~616.js +2 -0
  22. package/dist/0~659.js +2 -0
  23. package/dist/0~670.js +2 -0
  24. package/dist/0~687.js +2 -0
  25. package/dist/0~706.js +2 -0
  26. package/dist/0~729.js +2 -0
  27. package/dist/0~768.js +2 -0
  28. package/dist/0~819.js +2 -0
  29. package/dist/0~830.js +2 -0
  30. package/dist/0~854.js +2 -0
  31. package/dist/0~863.js +2 -0
  32. package/dist/0~879.js +2 -0
  33. package/dist/0~96.js +2 -0
  34. package/dist/0~97.js +2 -0
  35. package/dist/components/FileTree/FileTree.css +90 -0
  36. package/dist/components/FileTree/FileTree.d.ts +7 -0
  37. package/dist/components/FileTree/FileTree.js +531 -0
  38. package/dist/components/FileTree/FileTreeItem.d.ts +8 -0
  39. package/dist/components/FileTree/RemoteSvgIcon.d.ts +11 -0
  40. package/dist/components/FileTree/index.d.ts +4 -0
  41. package/dist/components/folder-icons.d.ts +32 -0
  42. package/dist/components/languages.d.ts +7 -0
  43. package/dist/components/tree-parser/tree-parser.d.ts +12 -0
  44. package/dist/components/tree-parser/types.d.ts +11 -0
  45. package/dist/head/css/loader-apple.css +1 -0
  46. package/dist/head/css/loader-backdrop.css +1 -0
  47. package/dist/head/css/loader-dots.css +1 -0
  48. package/dist/head/css/themes/amber.css +1 -0
  49. package/dist/head/css/themes/arcade.css +1 -0
  50. package/dist/head/css/themes/grannysmith.css +1 -0
  51. package/dist/head/css/themes/honeycrisp.css +1 -0
  52. package/dist/head/css/themes/midnight.css +1 -0
  53. package/dist/head/css/themes/mulled.css +1 -0
  54. package/dist/head/js/loader-dots.js +1 -0
  55. package/dist/head/js/vscode-nav.js +1 -0
  56. package/dist/index.d.ts +43 -0
  57. package/dist/index.mjs +40 -0
  58. package/dist/node.d.ts +81 -0
  59. package/dist/node.mjs +17762 -0
  60. package/dist/plugins/mermaid/MermaidRenderer.tsx +480 -0
  61. package/dist/plugins/mermaid/mermaid.css +199 -0
  62. package/dist/theme/components/announcement/announcement-bar.css +103 -0
  63. package/dist/theme/components/announcement/announcement-bar.tsx +173 -0
  64. package/dist/theme/components/ask-ai/ask-ai-button.css +52 -0
  65. package/dist/theme/components/ask-ai/ask-ai-button.tsx +56 -0
  66. package/dist/theme/components/content-footer/content-footer-portal.tsx +70 -0
  67. package/dist/theme/components/content-footer/feedback.css +47 -0
  68. package/dist/theme/components/content-footer/feedback.tsx +96 -0
  69. package/dist/theme/components/content-footer/meta-actions.css +25 -0
  70. package/dist/theme/components/content-footer/meta-actions.tsx +57 -0
  71. package/dist/theme/components/content-footer/page-pager.css +61 -0
  72. package/dist/theme/components/content-footer/page-pager.tsx +110 -0
  73. package/dist/theme/components/edit-source-button.tsx +97 -0
  74. package/dist/theme/components/footer/site-footer.css +179 -0
  75. package/dist/theme/components/footer/site-footer.tsx +115 -0
  76. package/dist/theme/components/home/cta.css +67 -0
  77. package/dist/theme/components/home/cta.tsx +77 -0
  78. package/dist/theme/components/home/feature-card.css +52 -0
  79. package/dist/theme/components/home/feature-card.tsx +131 -0
  80. package/dist/theme/components/home/feature.tsx +79 -0
  81. package/dist/theme/components/home/hero-demo.css +66 -0
  82. package/dist/theme/components/home/hero-demo.tsx +46 -0
  83. package/dist/theme/components/home/hero.css +96 -0
  84. package/dist/theme/components/home/hero.tsx +111 -0
  85. package/dist/theme/components/home/layout.tsx +183 -0
  86. package/dist/theme/components/home/page-rail.css +21 -0
  87. package/dist/theme/components/home/page-rail.tsx +19 -0
  88. package/dist/theme/components/home/split.css +148 -0
  89. package/dist/theme/components/home/split.tsx +120 -0
  90. package/dist/theme/components/home/trust-strip.css +33 -0
  91. package/dist/theme/components/home/trust-strip.tsx +43 -0
  92. package/dist/theme/components/home/workspaces.tsx +71 -0
  93. package/dist/theme/components/nav/branch-tag.css +54 -0
  94. package/dist/theme/components/nav/branch-tag.tsx +101 -0
  95. package/dist/theme/components/nav/ciderpress-doc-layout.tsx +247 -0
  96. package/dist/theme/components/nav/ciderpress-docs-bar.css +505 -0
  97. package/dist/theme/components/nav/ciderpress-docs-bar.tsx +426 -0
  98. package/dist/theme/components/nav/ciderpress-header.css +172 -0
  99. package/dist/theme/components/nav/ciderpress-header.tsx +113 -0
  100. package/dist/theme/components/nav/ciderpress-layout-context.tsx +49 -0
  101. package/dist/theme/components/nav/ciderpress-nav-hamburger.css +193 -0
  102. package/dist/theme/components/nav/ciderpress-nav-hamburger.tsx +112 -0
  103. package/dist/theme/components/nav/ciderpress-nav-menu.css +130 -0
  104. package/dist/theme/components/nav/ciderpress-nav-menu.tsx +372 -0
  105. package/dist/theme/components/nav/ciderpress-nav-search.css +73 -0
  106. package/dist/theme/components/nav/ciderpress-nav-search.tsx +55 -0
  107. package/dist/theme/components/nav/ciderpress-nav-social-links.css +35 -0
  108. package/dist/theme/components/nav/ciderpress-nav-social-links.tsx +87 -0
  109. package/dist/theme/components/nav/floating-branch-indicator.css +106 -0
  110. package/dist/theme/components/nav/floating-branch-indicator.tsx +109 -0
  111. package/dist/theme/components/nav/layout.tsx +268 -0
  112. package/dist/theme/components/nav/mobile-nav-cta.tsx +79 -0
  113. package/dist/theme/components/nav/nav-divider.css +15 -0
  114. package/dist/theme/components/nav/nav-divider.tsx +19 -0
  115. package/dist/theme/components/nav/nav-logo.css +42 -0
  116. package/dist/theme/components/nav/nav-logo.tsx +262 -0
  117. package/dist/theme/components/nav/theme-switcher.css +92 -0
  118. package/dist/theme/components/nav/theme-switcher.tsx +298 -0
  119. package/dist/theme/components/nav/topbar-cta.css +45 -0
  120. package/dist/theme/components/nav/topbar-cta.tsx +39 -0
  121. package/dist/theme/components/nav/variant-toggle.css +70 -0
  122. package/dist/theme/components/nav/variant-toggle.tsx +83 -0
  123. package/dist/theme/components/nav/version-chip.css +31 -0
  124. package/dist/theme/components/nav/version-chip.tsx +45 -0
  125. package/dist/theme/components/nav/vscode-tag.css +32 -0
  126. package/dist/theme/components/nav/vscode-tag.tsx +20 -0
  127. package/dist/theme/components/openapi/code-sample.tsx +341 -0
  128. package/dist/theme/components/openapi/copy-markdown-button.tsx +41 -0
  129. package/dist/theme/components/openapi/icons.tsx +45 -0
  130. package/dist/theme/components/openapi/index.ts +6 -0
  131. package/dist/theme/components/openapi/method-badge.tsx +24 -0
  132. package/dist/theme/components/openapi/openapi.css +665 -0
  133. package/dist/theme/components/openapi/operation.tsx +200 -0
  134. package/dist/theme/components/openapi/overview.tsx +207 -0
  135. package/dist/theme/components/openapi/parameters-table.tsx +149 -0
  136. package/dist/theme/components/openapi/request-body.tsx +90 -0
  137. package/dist/theme/components/openapi/response-list.tsx +112 -0
  138. package/dist/theme/components/openapi/schema-viewer.tsx +277 -0
  139. package/dist/theme/components/openapi/security-badges.tsx +63 -0
  140. package/dist/theme/components/openapi/spec-utils.ts +122 -0
  141. package/dist/theme/components/shared/accordion.css +118 -0
  142. package/dist/theme/components/shared/accordion.stories.tsx +96 -0
  143. package/dist/theme/components/shared/accordion.tsx +191 -0
  144. package/dist/theme/components/shared/brand-logo.stories.tsx +49 -0
  145. package/dist/theme/components/shared/brand-mark.stories.tsx +53 -0
  146. package/dist/theme/components/shared/browser-window.css +1 -0
  147. package/dist/theme/components/shared/browser-window.stories.tsx +100 -0
  148. package/dist/theme/components/shared/browser-window.tsx +2 -0
  149. package/dist/theme/components/shared/card.stories.tsx +50 -0
  150. package/dist/theme/components/shared/card.tsx +35 -0
  151. package/dist/theme/components/shared/ciderpress-logo.tsx +93 -0
  152. package/dist/theme/components/shared/ciderpress-mark.tsx +77 -0
  153. package/dist/theme/components/shared/color.css +56 -0
  154. package/dist/theme/components/shared/color.stories.tsx +47 -0
  155. package/dist/theme/components/shared/color.tsx +69 -0
  156. package/dist/theme/components/shared/columns.css +37 -0
  157. package/dist/theme/components/shared/columns.stories.tsx +91 -0
  158. package/dist/theme/components/shared/columns.tsx +50 -0
  159. package/dist/theme/components/shared/desktop-window.css +339 -0
  160. package/dist/theme/components/shared/desktop-window.tsx +535 -0
  161. package/dist/theme/components/shared/field.css +158 -0
  162. package/dist/theme/components/shared/field.stories.tsx +100 -0
  163. package/dist/theme/components/shared/field.tsx +186 -0
  164. package/dist/theme/components/shared/frame.css +39 -0
  165. package/dist/theme/components/shared/frame.stories.tsx +49 -0
  166. package/dist/theme/components/shared/frame.tsx +76 -0
  167. package/dist/theme/components/shared/icon.stories.tsx +90 -0
  168. package/dist/theme/components/shared/icon.tsx +41 -0
  169. package/dist/theme/components/shared/prompt.css +178 -0
  170. package/dist/theme/components/shared/prompt.stories.tsx +57 -0
  171. package/dist/theme/components/shared/prompt.tsx +369 -0
  172. package/dist/theme/components/shared/resolve-card-icon.ts +28 -0
  173. package/dist/theme/components/shared/section-card.stories.tsx +51 -0
  174. package/dist/theme/components/shared/section-card.tsx +44 -0
  175. package/dist/theme/components/shared/section-grid.stories.tsx +46 -0
  176. package/dist/theme/components/shared/section-grid.tsx +15 -0
  177. package/dist/theme/components/shared/status-badge.css +37 -0
  178. package/dist/theme/components/shared/status-badge.stories.tsx +61 -0
  179. package/dist/theme/components/shared/status-badge.tsx +74 -0
  180. package/dist/theme/components/shared/steps.css +88 -0
  181. package/dist/theme/components/shared/steps.stories.tsx +68 -0
  182. package/dist/theme/components/shared/steps.tsx +100 -0
  183. package/dist/theme/components/shared/tech-icon-table.stories.tsx +29 -0
  184. package/dist/theme/components/shared/tech-icon-table.tsx +71 -0
  185. package/dist/theme/components/shared/tech-tag.stories.tsx +40 -0
  186. package/dist/theme/components/shared/tech-tag.tsx +31 -0
  187. package/dist/theme/components/shared/theme-color-palette.css +80 -0
  188. package/dist/theme/components/shared/theme-color-palette.stories.tsx +52 -0
  189. package/dist/theme/components/shared/theme-color-palette.tsx +275 -0
  190. package/dist/theme/components/shared/tooltip.css +69 -0
  191. package/dist/theme/components/shared/tooltip.stories.tsx +72 -0
  192. package/dist/theme/components/shared/tooltip.tsx +77 -0
  193. package/dist/theme/components/sidebar/framework-picker.css +77 -0
  194. package/dist/theme/components/sidebar/framework-picker.tsx +78 -0
  195. package/dist/theme/components/sidebar/sidebar-filter.test.ts +140 -0
  196. package/dist/theme/components/sidebar/sidebar-filter.ts +79 -0
  197. package/dist/theme/components/sidebar/sidebar-links.css +102 -0
  198. package/dist/theme/components/sidebar/sidebar-links.tsx +122 -0
  199. package/dist/theme/components/sidebar/sidebar-promo.css +42 -0
  200. package/dist/theme/components/sidebar/sidebar-promo.tsx +52 -0
  201. package/dist/theme/components/sidebar/sidebar-scope.tsx +151 -0
  202. package/dist/theme/components/sidebar/sidebar-toggle.css +181 -0
  203. package/dist/theme/components/sidebar/sidebar-toggle.tsx +127 -0
  204. package/dist/theme/components/theme-provider.tsx +637 -0
  205. package/dist/theme/components/workspaces/card.css +151 -0
  206. package/dist/theme/components/workspaces/card.tsx +166 -0
  207. package/dist/theme/components/workspaces/grid.tsx +62 -0
  208. package/dist/theme/css.d.ts +1 -0
  209. package/dist/theme/env.d.ts +12 -0
  210. package/dist/theme/fonts/GeistMono-Variable.woff2 +0 -0
  211. package/dist/theme/fonts/GeistPixel-Square.woff2 +0 -0
  212. package/dist/theme/fonts/GeistSans-Variable.woff2 +0 -0
  213. package/dist/theme/hooks/use-ciderpress.ts +61 -0
  214. package/dist/theme/hooks/use-nav-items.ts +76 -0
  215. package/dist/theme/icons/index.ts +2 -0
  216. package/dist/theme/icons/tech-map.ts +228 -0
  217. package/dist/theme/index.tsx +180 -0
  218. package/dist/theme/lib/read-social-links.ts +27 -0
  219. package/dist/theme/lib/route-link.tsx +126 -0
  220. package/dist/theme/lib/safe-url.test.ts +0 -0
  221. package/dist/theme/lib/safe-url.ts +68 -0
  222. package/dist/theme/lib/theme-favicon.ts +125 -0
  223. package/dist/theme/lib/user-config-stub.ts +12 -0
  224. package/dist/theme/styles/layers.css +32 -0
  225. package/dist/theme/styles/overrides/badge.css +26 -0
  226. package/dist/theme/styles/overrides/content-footer.css +80 -0
  227. package/dist/theme/styles/overrides/details.css +61 -0
  228. package/dist/theme/styles/overrides/fonts.css +32 -0
  229. package/dist/theme/styles/overrides/home-card.css +133 -0
  230. package/dist/theme/styles/overrides/home.css +243 -0
  231. package/dist/theme/styles/overrides/rail.css +337 -0
  232. package/dist/theme/styles/overrides/rspress.css +62 -0
  233. package/dist/theme/styles/overrides/scrollbar.css +25 -0
  234. package/dist/theme/styles/overrides/section-card.css +114 -0
  235. package/dist/theme/styles/overrides/sidebar.css +144 -0
  236. package/dist/theme/styles/overrides/tokens.css +288 -0
  237. package/dist/theme/styles/overrides/vscode.css +88 -0
  238. package/dist/theme/styles/themes/amber.css +545 -0
  239. package/dist/theme/styles/themes/arcade-fx.css +366 -0
  240. package/dist/theme/styles/themes/arcade.css +273 -0
  241. package/dist/theme/styles/themes/grannysmith.css +545 -0
  242. package/dist/theme/styles/themes/honeycrisp.css +545 -0
  243. package/dist/theme/styles/themes/midnight.css +273 -0
  244. package/dist/theme/styles/themes/mulled.css +817 -0
  245. package/package.json +103 -0
  246. package/src/theme/components/announcement/announcement-bar.css +103 -0
  247. package/src/theme/components/announcement/announcement-bar.tsx +173 -0
  248. package/src/theme/components/ask-ai/ask-ai-button.css +52 -0
  249. package/src/theme/components/ask-ai/ask-ai-button.tsx +56 -0
  250. package/src/theme/components/content-footer/content-footer-portal.tsx +70 -0
  251. package/src/theme/components/content-footer/feedback.css +47 -0
  252. package/src/theme/components/content-footer/feedback.tsx +96 -0
  253. package/src/theme/components/content-footer/meta-actions.css +25 -0
  254. package/src/theme/components/content-footer/meta-actions.tsx +57 -0
  255. package/src/theme/components/content-footer/page-pager.css +61 -0
  256. package/src/theme/components/content-footer/page-pager.tsx +110 -0
  257. package/src/theme/components/edit-source-button.tsx +97 -0
  258. package/src/theme/components/footer/site-footer.css +179 -0
  259. package/src/theme/components/footer/site-footer.tsx +115 -0
  260. package/src/theme/components/home/cta.css +67 -0
  261. package/src/theme/components/home/cta.tsx +77 -0
  262. package/src/theme/components/home/feature-card.css +52 -0
  263. package/src/theme/components/home/feature-card.tsx +131 -0
  264. package/src/theme/components/home/feature.tsx +79 -0
  265. package/src/theme/components/home/hero-demo.css +66 -0
  266. package/src/theme/components/home/hero-demo.tsx +46 -0
  267. package/src/theme/components/home/hero.css +96 -0
  268. package/src/theme/components/home/hero.tsx +111 -0
  269. package/src/theme/components/home/layout.tsx +183 -0
  270. package/src/theme/components/home/page-rail.css +21 -0
  271. package/src/theme/components/home/page-rail.tsx +19 -0
  272. package/src/theme/components/home/split.css +148 -0
  273. package/src/theme/components/home/split.tsx +120 -0
  274. package/src/theme/components/home/trust-strip.css +33 -0
  275. package/src/theme/components/home/trust-strip.tsx +43 -0
  276. package/src/theme/components/home/workspaces.tsx +71 -0
  277. package/src/theme/components/nav/branch-tag.css +54 -0
  278. package/src/theme/components/nav/branch-tag.tsx +101 -0
  279. package/src/theme/components/nav/ciderpress-doc-layout.tsx +247 -0
  280. package/src/theme/components/nav/ciderpress-docs-bar.css +505 -0
  281. package/src/theme/components/nav/ciderpress-docs-bar.tsx +426 -0
  282. package/src/theme/components/nav/ciderpress-header.css +172 -0
  283. package/src/theme/components/nav/ciderpress-header.tsx +113 -0
  284. package/src/theme/components/nav/ciderpress-layout-context.tsx +49 -0
  285. package/src/theme/components/nav/ciderpress-nav-hamburger.css +193 -0
  286. package/src/theme/components/nav/ciderpress-nav-hamburger.tsx +112 -0
  287. package/src/theme/components/nav/ciderpress-nav-menu.css +130 -0
  288. package/src/theme/components/nav/ciderpress-nav-menu.tsx +372 -0
  289. package/src/theme/components/nav/ciderpress-nav-search.css +73 -0
  290. package/src/theme/components/nav/ciderpress-nav-search.tsx +55 -0
  291. package/src/theme/components/nav/ciderpress-nav-social-links.css +35 -0
  292. package/src/theme/components/nav/ciderpress-nav-social-links.tsx +87 -0
  293. package/src/theme/components/nav/floating-branch-indicator.css +106 -0
  294. package/src/theme/components/nav/floating-branch-indicator.tsx +109 -0
  295. package/src/theme/components/nav/layout.tsx +268 -0
  296. package/src/theme/components/nav/mobile-nav-cta.tsx +79 -0
  297. package/src/theme/components/nav/nav-divider.css +15 -0
  298. package/src/theme/components/nav/nav-divider.tsx +19 -0
  299. package/src/theme/components/nav/nav-logo.css +42 -0
  300. package/src/theme/components/nav/nav-logo.tsx +262 -0
  301. package/src/theme/components/nav/theme-switcher.css +92 -0
  302. package/src/theme/components/nav/theme-switcher.tsx +298 -0
  303. package/src/theme/components/nav/topbar-cta.css +45 -0
  304. package/src/theme/components/nav/topbar-cta.tsx +39 -0
  305. package/src/theme/components/nav/variant-toggle.css +70 -0
  306. package/src/theme/components/nav/variant-toggle.tsx +83 -0
  307. package/src/theme/components/nav/version-chip.css +31 -0
  308. package/src/theme/components/nav/version-chip.tsx +45 -0
  309. package/src/theme/components/nav/vscode-tag.css +32 -0
  310. package/src/theme/components/nav/vscode-tag.tsx +20 -0
  311. package/src/theme/components/openapi/code-sample.tsx +341 -0
  312. package/src/theme/components/openapi/copy-markdown-button.tsx +41 -0
  313. package/src/theme/components/openapi/icons.tsx +45 -0
  314. package/src/theme/components/openapi/index.ts +6 -0
  315. package/src/theme/components/openapi/method-badge.tsx +24 -0
  316. package/src/theme/components/openapi/openapi.css +665 -0
  317. package/src/theme/components/openapi/operation.tsx +200 -0
  318. package/src/theme/components/openapi/overview.tsx +207 -0
  319. package/src/theme/components/openapi/parameters-table.tsx +149 -0
  320. package/src/theme/components/openapi/request-body.tsx +90 -0
  321. package/src/theme/components/openapi/response-list.tsx +112 -0
  322. package/src/theme/components/openapi/schema-viewer.tsx +277 -0
  323. package/src/theme/components/openapi/security-badges.tsx +63 -0
  324. package/src/theme/components/openapi/spec-utils.ts +122 -0
  325. package/src/theme/components/shared/accordion.css +118 -0
  326. package/src/theme/components/shared/accordion.stories.tsx +96 -0
  327. package/src/theme/components/shared/accordion.tsx +191 -0
  328. package/src/theme/components/shared/brand-logo.stories.tsx +49 -0
  329. package/src/theme/components/shared/brand-mark.stories.tsx +53 -0
  330. package/src/theme/components/shared/browser-window.css +1 -0
  331. package/src/theme/components/shared/browser-window.stories.tsx +100 -0
  332. package/src/theme/components/shared/browser-window.tsx +2 -0
  333. package/src/theme/components/shared/card.stories.tsx +50 -0
  334. package/src/theme/components/shared/card.tsx +35 -0
  335. package/src/theme/components/shared/ciderpress-logo.tsx +93 -0
  336. package/src/theme/components/shared/ciderpress-mark.tsx +77 -0
  337. package/src/theme/components/shared/color.css +56 -0
  338. package/src/theme/components/shared/color.stories.tsx +47 -0
  339. package/src/theme/components/shared/color.tsx +69 -0
  340. package/src/theme/components/shared/columns.css +37 -0
  341. package/src/theme/components/shared/columns.stories.tsx +91 -0
  342. package/src/theme/components/shared/columns.tsx +50 -0
  343. package/src/theme/components/shared/desktop-window.css +339 -0
  344. package/src/theme/components/shared/desktop-window.tsx +535 -0
  345. package/src/theme/components/shared/field.css +158 -0
  346. package/src/theme/components/shared/field.stories.tsx +100 -0
  347. package/src/theme/components/shared/field.tsx +186 -0
  348. package/src/theme/components/shared/frame.css +39 -0
  349. package/src/theme/components/shared/frame.stories.tsx +49 -0
  350. package/src/theme/components/shared/frame.tsx +76 -0
  351. package/src/theme/components/shared/icon.stories.tsx +90 -0
  352. package/src/theme/components/shared/icon.tsx +41 -0
  353. package/src/theme/components/shared/prompt.css +178 -0
  354. package/src/theme/components/shared/prompt.stories.tsx +57 -0
  355. package/src/theme/components/shared/prompt.tsx +369 -0
  356. package/src/theme/components/shared/resolve-card-icon.ts +28 -0
  357. package/src/theme/components/shared/section-card.stories.tsx +51 -0
  358. package/src/theme/components/shared/section-card.tsx +44 -0
  359. package/src/theme/components/shared/section-grid.stories.tsx +46 -0
  360. package/src/theme/components/shared/section-grid.tsx +15 -0
  361. package/src/theme/components/shared/status-badge.css +37 -0
  362. package/src/theme/components/shared/status-badge.stories.tsx +61 -0
  363. package/src/theme/components/shared/status-badge.tsx +74 -0
  364. package/src/theme/components/shared/steps.css +88 -0
  365. package/src/theme/components/shared/steps.stories.tsx +68 -0
  366. package/src/theme/components/shared/steps.tsx +100 -0
  367. package/src/theme/components/shared/tech-icon-table.stories.tsx +29 -0
  368. package/src/theme/components/shared/tech-icon-table.tsx +71 -0
  369. package/src/theme/components/shared/tech-tag.stories.tsx +40 -0
  370. package/src/theme/components/shared/tech-tag.tsx +31 -0
  371. package/src/theme/components/shared/theme-color-palette.css +80 -0
  372. package/src/theme/components/shared/theme-color-palette.stories.tsx +52 -0
  373. package/src/theme/components/shared/theme-color-palette.tsx +275 -0
  374. package/src/theme/components/shared/tooltip.css +69 -0
  375. package/src/theme/components/shared/tooltip.stories.tsx +72 -0
  376. package/src/theme/components/shared/tooltip.tsx +77 -0
  377. package/src/theme/components/sidebar/framework-picker.css +77 -0
  378. package/src/theme/components/sidebar/framework-picker.tsx +78 -0
  379. package/src/theme/components/sidebar/sidebar-filter.test.ts +140 -0
  380. package/src/theme/components/sidebar/sidebar-filter.ts +79 -0
  381. package/src/theme/components/sidebar/sidebar-links.css +102 -0
  382. package/src/theme/components/sidebar/sidebar-links.tsx +122 -0
  383. package/src/theme/components/sidebar/sidebar-promo.css +42 -0
  384. package/src/theme/components/sidebar/sidebar-promo.tsx +52 -0
  385. package/src/theme/components/sidebar/sidebar-scope.tsx +151 -0
  386. package/src/theme/components/sidebar/sidebar-toggle.css +181 -0
  387. package/src/theme/components/sidebar/sidebar-toggle.tsx +127 -0
  388. package/src/theme/components/theme-provider.tsx +637 -0
  389. package/src/theme/components/workspaces/card.css +151 -0
  390. package/src/theme/components/workspaces/card.tsx +166 -0
  391. package/src/theme/components/workspaces/grid.tsx +62 -0
  392. package/src/theme/css.d.ts +1 -0
  393. package/src/theme/env.d.ts +12 -0
  394. package/src/theme/fonts/GeistMono-Variable.woff2 +0 -0
  395. package/src/theme/fonts/GeistPixel-Square.woff2 +0 -0
  396. package/src/theme/fonts/GeistSans-Variable.woff2 +0 -0
  397. package/src/theme/hooks/use-ciderpress.ts +61 -0
  398. package/src/theme/hooks/use-nav-items.ts +76 -0
  399. package/src/theme/icons/index.ts +2 -0
  400. package/src/theme/icons/tech-map.ts +228 -0
  401. package/src/theme/index.tsx +180 -0
  402. package/src/theme/lib/read-social-links.ts +27 -0
  403. package/src/theme/lib/route-link.tsx +126 -0
  404. package/src/theme/lib/safe-url.test.ts +0 -0
  405. package/src/theme/lib/safe-url.ts +68 -0
  406. package/src/theme/lib/theme-favicon.ts +125 -0
  407. package/src/theme/lib/user-config-stub.ts +12 -0
  408. package/src/theme/styles/layers.css +32 -0
  409. package/src/theme/styles/overrides/badge.css +26 -0
  410. package/src/theme/styles/overrides/content-footer.css +80 -0
  411. package/src/theme/styles/overrides/details.css +61 -0
  412. package/src/theme/styles/overrides/fonts.css +32 -0
  413. package/src/theme/styles/overrides/home-card.css +133 -0
  414. package/src/theme/styles/overrides/home.css +243 -0
  415. package/src/theme/styles/overrides/rail.css +337 -0
  416. package/src/theme/styles/overrides/rspress.css +62 -0
  417. package/src/theme/styles/overrides/scrollbar.css +25 -0
  418. package/src/theme/styles/overrides/section-card.css +114 -0
  419. package/src/theme/styles/overrides/sidebar.css +144 -0
  420. package/src/theme/styles/overrides/tokens.css +288 -0
  421. package/src/theme/styles/overrides/vscode.css +88 -0
  422. package/src/theme/styles/themes/amber.css +545 -0
  423. package/src/theme/styles/themes/arcade-fx.css +366 -0
  424. package/src/theme/styles/themes/arcade.css +273 -0
  425. package/src/theme/styles/themes/grannysmith.css +545 -0
  426. package/src/theme/styles/themes/honeycrisp.css +545 -0
  427. package/src/theme/styles/themes/midnight.css +273 -0
  428. package/src/theme/styles/themes/mulled.css +817 -0
@@ -0,0 +1,112 @@
1
+ import { match, P } from 'massaman/match'
2
+ import type React from 'react'
3
+ import { Button, Disclosure, DisclosurePanel } from 'react-aria-components'
4
+
5
+ import { ChevronIcon } from './icons'
6
+ import { SchemaViewer } from './schema-viewer'
7
+
8
+ export interface ResponseListProps {
9
+ /**
10
+ * OpenAPI responses object keyed by status code.
11
+ */
12
+ readonly responses: Record<string, unknown>
13
+ }
14
+
15
+ /**
16
+ * Renders the list of response status codes for an OpenAPI operation.
17
+ *
18
+ * Each response is collapsible via react-aria-components Disclosure,
19
+ * showing the response schema when expanded.
20
+ *
21
+ * @param props - Response list props
22
+ * @returns React element with collapsible response entries
23
+ */
24
+ export function ResponseList({ responses }: ResponseListProps): React.ReactElement {
25
+ const entries = Object.entries(responses)
26
+
27
+ return (
28
+ <div className="cp-oas-responses">
29
+ <div className="cp-oas-responses__title">Responses</div>
30
+ {entries.map(renderResponseItem)}
31
+ </div>
32
+ )
33
+ }
34
+
35
+ /**
36
+ * Determine the CSS class for a status code badge.
37
+ *
38
+ * @private
39
+ * @param code - HTTP status code string
40
+ * @returns CSS class name for the status code range
41
+ */
42
+ function statusClass(code: string): string {
43
+ return match(code.charAt(0))
44
+ .with('2', () => 'cp-oas-response__status--2xx')
45
+ .with('3', () => 'cp-oas-response__status--3xx')
46
+ .with('4', () => 'cp-oas-response__status--4xx')
47
+ .with('5', () => 'cp-oas-response__status--5xx')
48
+ .otherwise(() => '')
49
+ }
50
+
51
+ /**
52
+ * Extract the schema from a response's first content type entry.
53
+ *
54
+ * @private
55
+ * @param response - OpenAPI response object
56
+ * @returns Schema object or null
57
+ */
58
+ function extractSchema(response: Record<string, unknown>): Record<string, unknown> | null {
59
+ const content = response['content'] as Record<string, Record<string, unknown>> | undefined
60
+ const contentSchema = match(content)
61
+ .with(P.nonNullable, (c) => {
62
+ const entries = Object.entries(c)
63
+ return match(entries)
64
+ .with(
65
+ P.when((e): e is [string, Record<string, unknown>][] => e.length > 0),
66
+ (e) => {
67
+ const [[, mediaType]] = e
68
+ return (mediaType['schema'] ?? null) as Record<string, unknown> | null
69
+ }
70
+ )
71
+ .otherwise(() => null)
72
+ })
73
+ .otherwise(() => null)
74
+
75
+ if (contentSchema !== null) {
76
+ return contentSchema
77
+ }
78
+
79
+ return match(response['schema'] as Record<string, unknown> | undefined)
80
+ .with(P.nonNullable, (s) => s)
81
+ .otherwise(() => null)
82
+ }
83
+
84
+ /**
85
+ * Render a single response item as a collapsible disclosure.
86
+ *
87
+ * @private
88
+ * @param entry - Tuple of [status code, response value]
89
+ * @returns Collapsible response element
90
+ */
91
+ function renderResponseItem([code, value]: readonly [string, unknown]): React.ReactElement {
92
+ const response = (value ?? {}) as Record<string, unknown>
93
+ const description = String(response['description'] ?? '')
94
+ const schema = extractSchema(response)
95
+
96
+ const schemaEl = match(schema)
97
+ .with(P.nonNullable, (s) => <SchemaViewer schema={s} />)
98
+ .otherwise(() => <div className="cp-oas-response__description">No response body</div>)
99
+
100
+ return (
101
+ <Disclosure key={code} className="cp-oas-response">
102
+ <Button className="cp-oas-response__trigger" slot="trigger">
103
+ <span className={`cp-oas-response__status ${statusClass(code)}`}>{code}</span>
104
+ <span className="cp-oas-response__description">{description}</span>
105
+ <ChevronIcon className="cp-oas-response__chevron" />
106
+ </Button>
107
+ <DisclosurePanel>
108
+ <div className="cp-oas-response__content">{schemaEl}</div>
109
+ </DisclosurePanel>
110
+ </Disclosure>
111
+ )
112
+ }
@@ -0,0 +1,277 @@
1
+ import { match, P } from 'massaman/match'
2
+ import type React from 'react'
3
+ import { useState } from 'react'
4
+
5
+ import { ChevronIcon } from './icons'
6
+
7
+ export interface SchemaViewerProps {
8
+ /**
9
+ * JSON Schema object to render.
10
+ */
11
+ readonly schema: Record<string, unknown>
12
+ /**
13
+ * Current nesting depth (max 6).
14
+ */
15
+ readonly depth?: number
16
+ /**
17
+ * Property name displayed alongside the type.
18
+ */
19
+ readonly name?: string
20
+ /**
21
+ * Whether this property is required by its parent.
22
+ */
23
+ readonly isRequired?: boolean
24
+ }
25
+
26
+ const MAX_DEPTH = 6
27
+
28
+ /**
29
+ * Recursive JSON Schema renderer.
30
+ *
31
+ * Renders primitive types as inline badges, objects as expandable
32
+ * property lists, arrays with item schemas, and oneOf/anyOf as
33
+ * variant lists. Stops at depth 6.
34
+ *
35
+ * @param props - Schema viewer props
36
+ * @returns React element representing the schema
37
+ */
38
+ export function SchemaViewer({
39
+ schema,
40
+ depth = 0,
41
+ name,
42
+ isRequired = false,
43
+ }: SchemaViewerProps): React.ReactElement {
44
+ const schemaType = String(schema['type'] ?? '')
45
+ const description = schema['description'] as string | undefined
46
+ const enumValues = schema['enum'] as readonly unknown[] | undefined
47
+ const oneOf = schema['oneOf'] as readonly Record<string, unknown>[] | undefined
48
+ const anyOf = schema['anyOf'] as readonly Record<string, unknown>[] | undefined
49
+ const depthExceeded = depth >= MAX_DEPTH
50
+
51
+ const nameEl = match(name)
52
+ .with(P.nonNullable, (n) => <span className="cp-oas-schema__name">{n}</span>)
53
+ .otherwise(() => null)
54
+
55
+ const enumEl = match(enumValues)
56
+ .with(
57
+ P.when((e): e is readonly unknown[] => e !== undefined && e.length > 0),
58
+ (e) => <EnumValues values={e} />
59
+ )
60
+ .otherwise(() => null)
61
+
62
+ return match({ schemaType, oneOf, anyOf, depthExceeded })
63
+ .with({ depthExceeded: true }, () => (
64
+ <div className="cp-oas-schema__row">
65
+ {nameEl}
66
+ <span className="cp-oas-schema__type">{'...'}</span>
67
+ </div>
68
+ ))
69
+ .with({ oneOf: P.nonNullable }, ({ oneOf: variants }) => (
70
+ <>
71
+ <div className="cp-oas-schema__row">
72
+ {nameEl}
73
+ <RequiredBadge show={isRequired} />
74
+ <DescriptionText text={description} />
75
+ </div>
76
+ <VariantSchemas variants={variants} label="one of" depth={depth} />
77
+ </>
78
+ ))
79
+ .with({ anyOf: P.nonNullable }, ({ anyOf: variants }) => (
80
+ <>
81
+ <div className="cp-oas-schema__row">
82
+ {nameEl}
83
+ <RequiredBadge show={isRequired} />
84
+ <DescriptionText text={description} />
85
+ </div>
86
+ <VariantSchemas variants={variants} label="any of" depth={depth} />
87
+ </>
88
+ ))
89
+ .with({ schemaType: 'object' }, () => (
90
+ <>
91
+ <div className="cp-oas-schema__row">
92
+ {nameEl}
93
+ <RequiredBadge show={isRequired} />
94
+ <DescriptionText text={description} />
95
+ </div>
96
+ <ObjectProperties schema={schema} depth={depth} />
97
+ </>
98
+ ))
99
+ .with({ schemaType: 'array' }, () => (
100
+ <>
101
+ <div className="cp-oas-schema__row">
102
+ {nameEl}
103
+ <RequiredBadge show={isRequired} />
104
+ <DescriptionText text={description} />
105
+ </div>
106
+ <ArrayItems schema={schema} depth={depth} />
107
+ </>
108
+ ))
109
+ .otherwise(() => (
110
+ <div className="cp-oas-schema__row">
111
+ {nameEl}
112
+ <span className="cp-oas-schema__type">{schemaType}</span>
113
+ <RequiredBadge show={isRequired} />
114
+ {enumEl}
115
+ <DescriptionText text={description} />
116
+ </div>
117
+ ))
118
+ }
119
+
120
+ /**
121
+ * Render a required badge when the property is required.
122
+ *
123
+ * @private
124
+ * @param props - Props with show flag
125
+ * @returns Required badge element or null
126
+ */
127
+ function RequiredBadge({ show }: { readonly show: boolean }): React.ReactElement | null {
128
+ return match(show)
129
+ .with(true, () => <span className="cp-oas-schema__required">required</span>)
130
+ .otherwise(() => null)
131
+ }
132
+
133
+ /**
134
+ * Render a comma-separated list of enum values.
135
+ *
136
+ * @private
137
+ * @param props - Props with values array
138
+ * @returns Enum values element
139
+ */
140
+ function EnumValues({ values }: { readonly values: readonly unknown[] }): React.ReactElement {
141
+ return (
142
+ <span className="cp-oas-schema__enum">
143
+ {'enum: '}
144
+ {values.map(String).join(', ')}
145
+ </span>
146
+ )
147
+ }
148
+
149
+ /**
150
+ * Render a description text span if text is provided.
151
+ *
152
+ * @private
153
+ * @param props - Props with optional text
154
+ * @returns Description element or null
155
+ */
156
+ function DescriptionText({
157
+ text,
158
+ }: {
159
+ readonly text: string | undefined
160
+ }): React.ReactElement | null {
161
+ return match(text)
162
+ .with(P.nonNullable, (t) => <span className="cp-oas-schema__description">{t}</span>)
163
+ .otherwise(() => null)
164
+ }
165
+
166
+ /**
167
+ * Render an expandable object properties viewer.
168
+ *
169
+ * @private
170
+ * @param props - Props with schema and depth
171
+ * @returns Expandable object properties element
172
+ */
173
+ function ObjectProperties({
174
+ schema,
175
+ depth,
176
+ }: {
177
+ readonly schema: Record<string, unknown>
178
+ readonly depth: number
179
+ }): React.ReactElement {
180
+ const [expanded, setExpanded] = useState(depth < 2)
181
+ const properties = (schema['properties'] ?? {}) as Record<string, Record<string, unknown>>
182
+ const requiredList = (schema['required'] ?? []) as readonly string[]
183
+ const propEntries = Object.entries(properties)
184
+
185
+ function handleToggle() {
186
+ setExpanded((prev) => !prev)
187
+ }
188
+
189
+ return (
190
+ <div
191
+ className="cp-oas-schema"
192
+ data-expanded={match(expanded)
193
+ .with(true, () => '' as string | null)
194
+ .otherwise(() => null)}
195
+ >
196
+ <button type="button" className="cp-oas-schema__trigger" onClick={handleToggle}>
197
+ <ChevronIcon className="cp-oas-schema__trigger-chevron" />
198
+ <span className="cp-oas-schema__type">{'object'}</span>
199
+ <span className="cp-oas-schema__description">
200
+ {`{${String(propEntries.length)} properties}`}
201
+ </span>
202
+ </button>
203
+ {match(expanded)
204
+ .with(true, () => (
205
+ <div className="cp-oas-schema__indent">
206
+ {propEntries.map(([propName, propSchema]) => (
207
+ <SchemaViewer
208
+ key={propName}
209
+ schema={propSchema}
210
+ name={propName}
211
+ depth={depth + 1}
212
+ isRequired={requiredList.includes(propName)}
213
+ />
214
+ ))}
215
+ </div>
216
+ ))
217
+ .otherwise(() => null)}
218
+ </div>
219
+ )
220
+ }
221
+
222
+ /**
223
+ * Render an array items schema viewer.
224
+ *
225
+ * @private
226
+ * @param props - Props with schema and depth
227
+ * @returns Array items element
228
+ */
229
+ function ArrayItems({
230
+ schema,
231
+ depth,
232
+ }: {
233
+ readonly schema: Record<string, unknown>
234
+ readonly depth: number
235
+ }): React.ReactElement {
236
+ const items = (schema['items'] ?? {}) as Record<string, unknown>
237
+ return (
238
+ <div className="cp-oas-schema">
239
+ <div className="cp-oas-schema__row">
240
+ <span className="cp-oas-schema__type">{'array of'}</span>
241
+ </div>
242
+ <div className="cp-oas-schema__indent">
243
+ <SchemaViewer schema={items} depth={depth + 1} />
244
+ </div>
245
+ </div>
246
+ )
247
+ }
248
+
249
+ /**
250
+ * Render variant schemas for oneOf/anyOf unions.
251
+ *
252
+ * @private
253
+ * @param props - Props with variants array, label, and depth
254
+ * @returns Variant schemas element
255
+ */
256
+ function VariantSchemas({
257
+ variants,
258
+ label,
259
+ depth,
260
+ }: {
261
+ readonly variants: readonly Record<string, unknown>[]
262
+ readonly label: string
263
+ readonly depth: number
264
+ }): React.ReactElement {
265
+ return (
266
+ <div className="cp-oas-schema">
267
+ <div className="cp-oas-schema__row">
268
+ <span className="cp-oas-schema__type">{label}</span>
269
+ </div>
270
+ <div className="cp-oas-schema__indent">
271
+ {variants.map((variant, idx) => (
272
+ <SchemaViewer key={String(idx)} schema={variant} depth={depth + 1} />
273
+ ))}
274
+ </div>
275
+ </div>
276
+ )
277
+ }
@@ -0,0 +1,63 @@
1
+ import { match, P } from 'massaman/match'
2
+ import type React from 'react'
3
+
4
+ import { LockIcon } from './icons'
5
+
6
+ export interface SecurityBadgesProps {
7
+ /**
8
+ * Security requirement objects from the OpenAPI operation.
9
+ * Each entry is an alternative (OR); schemes within an entry are combined (AND).
10
+ */
11
+ readonly securities: readonly Record<string, unknown>[]
12
+ }
13
+
14
+ /**
15
+ * Renders badges for each security requirement of an operation.
16
+ *
17
+ * Each requirement is an alternative (OR). Schemes within a single
18
+ * requirement are combined (AND). OAuth scopes are shown in parentheses.
19
+ *
20
+ * @param props - Security badges props
21
+ * @returns React element or null if no securities
22
+ */
23
+ export function SecurityBadges({ securities }: SecurityBadgesProps): React.ReactElement | null {
24
+ return match(securities)
25
+ .with(
26
+ P.when((s): s is readonly Record<string, unknown>[] => s.length > 0),
27
+ (s) => (
28
+ <div className="cp-oas-security">
29
+ <div className="cp-oas-security__title">Authentication</div>
30
+ <div className="cp-oas-security__list">
31
+ {s.map((requirement, idx) => (
32
+ <span key={String(idx)} className="cp-oas-security__badge">
33
+ <LockIcon />
34
+ {formatSchemes(requirement)}
35
+ </span>
36
+ ))}
37
+ </div>
38
+ </div>
39
+ )
40
+ )
41
+ .otherwise(() => null)
42
+ }
43
+
44
+ /**
45
+ * Format security scheme names with optional OAuth scopes.
46
+ *
47
+ * @private
48
+ * @param requirement - Security requirement object
49
+ * @returns Formatted scheme string with AND-combined names
50
+ */
51
+ function formatSchemes(requirement: Record<string, unknown>): string {
52
+ return Object.entries(requirement)
53
+ .map(([name, scopes]) => {
54
+ const scopeSuffix = match(scopes)
55
+ .with(
56
+ P.when((s): s is readonly string[] => Array.isArray(s) && s.length > 0),
57
+ (s) => ` (${s.join(', ')})`
58
+ )
59
+ .otherwise(() => '')
60
+ return `${name}${scopeSuffix}`
61
+ })
62
+ .join(' + ')
63
+ }
@@ -0,0 +1,122 @@
1
+ import { match, P } from 'massaman/match'
2
+
3
+ /**
4
+ * All HTTP methods recognised by the OpenAPI specification.
5
+ */
6
+ export const HTTP_METHODS: readonly string[] = [
7
+ 'get',
8
+ 'post',
9
+ 'put',
10
+ 'patch',
11
+ 'delete',
12
+ 'options',
13
+ 'head',
14
+ 'trace',
15
+ ]
16
+
17
+ /**
18
+ * Resolve an operation object from the spec by path and method.
19
+ *
20
+ * @param input - Spec object, URL path, and HTTP method
21
+ * @returns The matched operation object or null if not found
22
+ */
23
+ export function resolveOperation(input: {
24
+ readonly spec: Record<string, unknown>
25
+ readonly path: string
26
+ readonly method: string
27
+ }): Record<string, unknown> | null {
28
+ const paths = input.spec['paths'] as Record<string, Record<string, unknown>> | undefined
29
+ return match(paths)
30
+ .with(P.nonNullable, (p) => {
31
+ const pathItem = p[input.path]
32
+ return match(pathItem)
33
+ .with(P.nonNullable, (pi) => {
34
+ const op = pi[input.method.toLowerCase()]
35
+ return match(op)
36
+ .with(P.nonNullable, (o) => o as Record<string, unknown>)
37
+ .otherwise(() => null)
38
+ })
39
+ .otherwise(() => null)
40
+ })
41
+ .otherwise(() => null)
42
+ }
43
+
44
+ /**
45
+ * Extract the first server URL from the spec, falling back to a placeholder.
46
+ *
47
+ * @param spec - Parsed OpenAPI spec object
48
+ * @returns First server URL string or `'https://api.example.com'`
49
+ */
50
+ export function resolveBaseUrl(spec: Record<string, unknown>): string {
51
+ const servers = spec['servers'] as readonly Record<string, unknown>[] | undefined
52
+ return match(servers)
53
+ .with(
54
+ P.when((s): s is readonly Record<string, unknown>[] => s !== undefined && s.length > 0),
55
+ (s) => String(s[0]['url'] ?? 'https://api.example.com')
56
+ )
57
+ .otherwise(() => 'https://api.example.com')
58
+ }
59
+
60
+ /**
61
+ * Resolve security requirements from the operation or global spec.
62
+ *
63
+ * @param input - Operation object and full spec object
64
+ * @returns Array of security requirement objects (operation-level takes precedence)
65
+ */
66
+ export function resolveSecurities(input: {
67
+ readonly operation: Record<string, unknown>
68
+ readonly spec: Record<string, unknown>
69
+ }): readonly Record<string, unknown>[] {
70
+ const opSecurity = input.operation['security'] as readonly Record<string, unknown>[] | undefined
71
+ const globalSecurity = input.spec['security'] as readonly Record<string, unknown>[] | undefined
72
+ return match(opSecurity)
73
+ .with(P.nonNullable, (s) => s)
74
+ .otherwise(() =>
75
+ match(globalSecurity)
76
+ .with(P.nonNullable, (s) => s)
77
+ .otherwise(() => [] as readonly Record<string, unknown>[])
78
+ )
79
+ }
80
+
81
+ /**
82
+ * Extract the first example value from a request body's content map.
83
+ *
84
+ * @param requestBody - OpenAPI request body object, or undefined
85
+ * @returns The first example value found, or null
86
+ */
87
+ export function extractBodyExample(
88
+ requestBody: Record<string, unknown> | undefined
89
+ ): unknown | null {
90
+ return match(requestBody)
91
+ .with(P.nonNullable, (rb) => {
92
+ const content = rb['content'] as Record<string, Record<string, unknown>> | undefined
93
+ return match(content)
94
+ .with(P.nonNullable, (c) => {
95
+ const entries = Object.entries(c)
96
+ return match(entries)
97
+ .with(
98
+ P.when((e): e is [string, Record<string, unknown>][] => e.length > 0),
99
+ (e) => {
100
+ const [[, mediaType]] = e
101
+ const { example } = mediaType as { readonly example?: unknown }
102
+ return match(example)
103
+ .with(P.nonNullable, (ex) => ex)
104
+ .otherwise(() => null)
105
+ }
106
+ )
107
+ .otherwise(() => null)
108
+ })
109
+ .otherwise(() => null)
110
+ })
111
+ .otherwise(() => null)
112
+ }
113
+
114
+ /**
115
+ * Check if an HTTP method typically carries a request body.
116
+ *
117
+ * @param method - Lowercase HTTP method string
118
+ * @returns True if the method is POST, PUT, or PATCH
119
+ */
120
+ export function isBodyMethod(method: string): boolean {
121
+ return method === 'post' || method === 'put' || method === 'patch'
122
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Accordion — expandable disclosure sections.
3
+ */
4
+
5
+ .cp-accordion-group {
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: 8px;
9
+ }
10
+
11
+ .cp-accordion {
12
+ border: 1px solid var(--cp-c-border);
13
+ border-radius: var(--rp-radius);
14
+ background: var(--cp-c-bg-soft);
15
+ overflow: hidden;
16
+ transition: border-color 0.2s;
17
+ }
18
+
19
+ .cp-accordion:hover {
20
+ border-color: var(--cp-c-brand-1);
21
+ }
22
+
23
+ .cp-accordion__trigger {
24
+ display: flex;
25
+ align-items: center;
26
+ gap: 10px;
27
+ width: 100%;
28
+ min-height: 40px;
29
+ margin: 0;
30
+ padding: 10px 14px;
31
+ border: none;
32
+ background: none;
33
+ cursor: pointer;
34
+ color: var(--cp-c-text-1);
35
+ font-size: 14px;
36
+ font-weight: 600;
37
+ font-family: var(--cp-font-family-base);
38
+ text-align: left;
39
+ line-height: 1.4;
40
+ }
41
+
42
+ .cp-accordion__trigger:focus-visible {
43
+ outline: 2px solid var(--cp-c-brand-1);
44
+ outline-offset: 2px;
45
+ }
46
+
47
+ .cp-accordion__icon {
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ flex-shrink: 0;
52
+ width: 16px;
53
+ height: 16px;
54
+ color: var(--cp-c-brand-1);
55
+ }
56
+
57
+ .cp-accordion__icon svg {
58
+ display: block;
59
+ }
60
+
61
+ .cp-accordion__header {
62
+ display: flex;
63
+ flex-direction: column;
64
+ gap: 2px;
65
+ flex: 1;
66
+ min-width: 0;
67
+ }
68
+
69
+ .cp-accordion__title {
70
+ line-height: 1.4;
71
+ }
72
+
73
+ .cp-accordion__description {
74
+ font-size: 12px;
75
+ font-weight: 400;
76
+ color: var(--cp-c-text-2);
77
+ line-height: 1.4;
78
+ }
79
+
80
+ .cp-accordion__chevron {
81
+ display: flex;
82
+ align-items: center;
83
+ justify-content: center;
84
+ flex-shrink: 0;
85
+ min-height: 40px;
86
+ width: 16px;
87
+ transition: transform 0.2s;
88
+ color: var(--cp-c-text-3);
89
+ }
90
+
91
+ .cp-accordion__chevron svg {
92
+ display: block;
93
+ }
94
+
95
+ .cp-accordion[data-expanded] .cp-accordion__chevron {
96
+ transform: rotate(90deg);
97
+ }
98
+
99
+ .cp-accordion__panel {
100
+ display: none;
101
+ padding: 0 14px 10px;
102
+ font-size: 14px;
103
+ line-height: 1.7;
104
+ color: var(--cp-c-text-2);
105
+ }
106
+
107
+ .cp-accordion[data-expanded] .cp-accordion__panel {
108
+ display: block;
109
+ }
110
+
111
+ .cp-accordion__panel > * {
112
+ margin-top: 0;
113
+ margin-bottom: 0;
114
+ }
115
+
116
+ .cp-accordion__panel > * + * {
117
+ margin-top: 8px;
118
+ }