handoff-app 2.0.0-0 → 2.0.0-10

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 (555) hide show
  1. package/AGENTS.md +7 -0
  2. package/CLAUDE.md +7 -0
  3. package/README.md +732 -304
  4. package/UPGRADE.md +218 -0
  5. package/config/config.template.js +1 -4
  6. package/config/config.template.ts +1 -2
  7. package/config/docs/foundations/colors/guidelines.md +9 -0
  8. package/config/docs/foundations/effects/guidelines.md +9 -0
  9. package/config/docs/foundations/effects/resources.md +9 -0
  10. package/config/docs/foundations/grid.md +10 -0
  11. package/config/docs/foundations/icons/guidelines.md +9 -0
  12. package/config/docs/foundations/images/guidelines.md +9 -0
  13. package/config/docs/foundations/images/resources.md +9 -0
  14. package/config/docs/foundations/images.md +10 -0
  15. package/config/docs/foundations/logo/resources.md +9 -0
  16. package/config/docs/foundations/typography/guidelines.md +9 -0
  17. package/config/docs/foundations/typography/resources.md +9 -0
  18. package/config/docs/foundations.md +5 -3
  19. package/dist/ai/connections.d.ts +64 -0
  20. package/dist/ai/connections.js +136 -0
  21. package/dist/ai/define.d.ts +10 -0
  22. package/dist/ai/define.js +13 -0
  23. package/dist/ai/types.d.ts +27 -0
  24. package/dist/ai/types.js +10 -0
  25. package/dist/app-builder/build.d.ts +12 -0
  26. package/dist/app-builder/build.js +227 -69
  27. package/dist/app-builder/client-config.js +16 -12
  28. package/dist/app-builder/config-diff/strategies/pattern.js +3 -3
  29. package/dist/app-builder/nav-shell.js +8 -15
  30. package/dist/app-builder/paths.js +23 -1
  31. package/dist/app-builder/static-export.js +25 -0
  32. package/dist/app-builder/vercel-output.js +6 -6
  33. package/dist/app-builder/watchers/component.js +5 -5
  34. package/dist/app-builder/watchers/utils.d.ts +2 -3
  35. package/dist/app-builder/watchers.d.ts +8 -15
  36. package/dist/app-builder/watchers.js +70 -61
  37. package/dist/artifacts/index.d.ts +1 -1
  38. package/dist/artifacts/index.js +4 -1
  39. package/dist/artifacts/url.d.ts +18 -0
  40. package/dist/artifacts/url.js +31 -1
  41. package/dist/cache/build-cache.js +23 -23
  42. package/dist/catalog/define.d.ts +6 -0
  43. package/dist/catalog/define.js +72 -0
  44. package/dist/catalog/implementation.d.ts +27 -0
  45. package/dist/catalog/implementation.js +133 -0
  46. package/dist/catalog/index.d.ts +6 -0
  47. package/dist/catalog/index.js +22 -0
  48. package/dist/catalog/normalize.d.ts +16 -0
  49. package/dist/catalog/normalize.js +118 -0
  50. package/dist/catalog/previews.d.ts +18 -0
  51. package/dist/catalog/previews.js +107 -0
  52. package/dist/catalog/renderers.d.ts +43 -0
  53. package/dist/catalog/renderers.js +62 -0
  54. package/dist/catalog/types.d.ts +71 -0
  55. package/dist/cli/auth/browser.d.ts +2 -0
  56. package/dist/cli/auth/browser.js +33 -0
  57. package/dist/cli/auth/device.d.ts +16 -0
  58. package/dist/cli/auth/device.js +158 -0
  59. package/dist/cli/auth/store.d.ts +38 -0
  60. package/dist/cli/auth/store.js +199 -0
  61. package/dist/cli/create.js +48 -3
  62. package/dist/cli/make.d.ts +0 -5
  63. package/dist/cli/make.js +24 -69
  64. package/dist/cli/scaffold.js +39 -181
  65. package/dist/cli.js +39 -7
  66. package/dist/commands/build/app.js +1 -5
  67. package/dist/commands/build/components.js +1 -5
  68. package/dist/commands/build/index.js +1 -5
  69. package/dist/commands/checkout/index.d.ts +18 -12
  70. package/dist/commands/checkout/index.js +19 -59
  71. package/dist/commands/compat/deprecations.d.ts +46 -0
  72. package/dist/commands/compat/deprecations.js +62 -0
  73. package/dist/commands/compat/push-args.d.ts +48 -0
  74. package/dist/commands/compat/push-args.js +73 -0
  75. package/dist/commands/db/migrate.js +1 -5
  76. package/dist/commands/dev/index.js +1 -5
  77. package/dist/commands/eject/config.js +1 -5
  78. package/dist/commands/eject/pages.js +1 -5
  79. package/dist/commands/eject/theme.js +1 -5
  80. package/dist/commands/fetch/index.js +1 -5
  81. package/dist/commands/index.js +8 -2
  82. package/dist/commands/login/index.d.ts +13 -0
  83. package/dist/commands/login/index.js +61 -0
  84. package/dist/commands/logout/index.d.ts +12 -0
  85. package/dist/commands/logout/index.js +89 -0
  86. package/dist/commands/make/component.js +1 -5
  87. package/dist/commands/make/page.js +3 -7
  88. package/dist/commands/publish/index.d.ts +21 -11
  89. package/dist/commands/publish/index.js +22 -58
  90. package/dist/commands/pull/index.d.ts +13 -0
  91. package/dist/commands/pull/index.js +20 -0
  92. package/dist/commands/push/index.d.ts +23 -0
  93. package/dist/commands/push/index.js +58 -0
  94. package/dist/commands/scaffold/index.js +1 -5
  95. package/dist/commands/start/index.js +1 -5
  96. package/dist/commands/types.d.ts +12 -0
  97. package/dist/commands/utils.d.ts +100 -1
  98. package/dist/commands/utils.js +103 -2
  99. package/dist/commands/validate/components.js +1 -5
  100. package/dist/config/catalog-include.d.ts +43 -0
  101. package/dist/config/catalog-include.js +203 -0
  102. package/dist/config/defaults.d.ts +4 -2
  103. package/dist/config/defaults.js +58 -49
  104. package/dist/config/env.d.ts +9 -0
  105. package/dist/config/env.js +43 -0
  106. package/dist/config/errors.d.ts +4 -0
  107. package/dist/config/errors.js +11 -0
  108. package/dist/config/from-env.d.ts +24 -0
  109. package/dist/config/from-env.js +7 -0
  110. package/dist/config/helpers.d.ts +2 -0
  111. package/dist/config/helpers.js +3 -1
  112. package/dist/config/index.d.ts +6 -2
  113. package/dist/config/index.js +12 -1
  114. package/dist/config/loader.d.ts +40 -9
  115. package/dist/config/loader.js +148 -35
  116. package/dist/config/normalizers/page.d.ts +4 -4
  117. package/dist/config/normalizers/page.js +2 -2
  118. package/dist/config/resolve-env.d.ts +6 -0
  119. package/dist/config/resolve-env.js +115 -0
  120. package/dist/config/runtime.d.ts +15 -16
  121. package/dist/config/runtime.js +178 -196
  122. package/dist/config/validator.d.ts +2 -2
  123. package/dist/config/validator.js +2 -4
  124. package/dist/handlebars.d.ts +17 -0
  125. package/dist/handlebars.js +16 -0
  126. package/dist/index.d.ts +120 -27
  127. package/dist/index.js +242 -53
  128. package/dist/nav/resolver.js +3 -1
  129. package/dist/nav/workspace.js +2 -2
  130. package/dist/pattern.d.ts +7 -0
  131. package/dist/pattern.js +13 -0
  132. package/dist/pipeline/index.d.ts +1 -1
  133. package/dist/pipeline/index.js +1 -1
  134. package/dist/react.d.ts +43 -0
  135. package/dist/react.js +11 -0
  136. package/dist/registry/asset-storage/adapters/vercel-blob.js +1 -1
  137. package/dist/registry/asset-storage/define.d.ts +1 -1
  138. package/dist/registry/asset-storage/define.js +1 -1
  139. package/dist/registry/asset-storage/resolve.d.ts +3 -3
  140. package/dist/registry/asset-storage/resolve.js +5 -2
  141. package/dist/registry/auth/access-tokens.d.ts +54 -0
  142. package/dist/registry/auth/access-tokens.js +191 -0
  143. package/dist/registry/auth/action-tokens.d.ts +66 -0
  144. package/dist/registry/auth/action-tokens.js +178 -0
  145. package/dist/registry/auth/ai-keys.d.ts +32 -0
  146. package/dist/registry/auth/ai-keys.js +69 -0
  147. package/dist/registry/auth/crypto.d.ts +21 -0
  148. package/dist/registry/auth/crypto.js +76 -0
  149. package/dist/registry/auth/database.d.ts +7 -0
  150. package/dist/registry/auth/database.js +22 -0
  151. package/dist/registry/auth/device-authorizations.d.ts +51 -0
  152. package/dist/registry/auth/device-authorizations.js +170 -0
  153. package/dist/registry/auth/gravatar.d.ts +1 -0
  154. package/dist/registry/auth/gravatar.js +8 -0
  155. package/dist/registry/auth/index.d.ts +13 -0
  156. package/dist/registry/auth/index.js +89 -0
  157. package/dist/registry/auth/installation.d.ts +42 -0
  158. package/dist/registry/auth/installation.js +105 -0
  159. package/dist/registry/auth/password.d.ts +12 -0
  160. package/dist/registry/auth/password.js +58 -0
  161. package/dist/registry/auth/rate-limits.d.ts +22 -0
  162. package/dist/registry/auth/rate-limits.js +75 -0
  163. package/dist/registry/auth/sync-secret.d.ts +27 -0
  164. package/dist/registry/auth/sync-secret.js +65 -0
  165. package/dist/registry/auth/types.d.ts +45 -0
  166. package/dist/registry/auth/types.js +11 -0
  167. package/dist/registry/auth/user-record.d.ts +13 -0
  168. package/dist/registry/auth/user-record.js +16 -0
  169. package/dist/registry/auth/users.d.ts +31 -0
  170. package/dist/registry/auth/users.js +135 -0
  171. package/dist/registry/auth/validation.d.ts +14 -0
  172. package/dist/registry/auth/validation.js +45 -0
  173. package/dist/registry/checkout/assets.d.ts +1 -1
  174. package/dist/registry/checkout/assets.js +25 -8
  175. package/dist/registry/checkout/index.d.ts +27 -6
  176. package/dist/registry/checkout/index.js +479 -131
  177. package/dist/registry/checkout/tokens.d.ts +1 -1
  178. package/dist/registry/checkout/tokens.js +16 -7
  179. package/dist/registry/client.d.ts +2 -1
  180. package/dist/registry/client.js +8 -0
  181. package/dist/registry/connection.d.ts +34 -11
  182. package/dist/registry/connection.js +77 -18
  183. package/dist/registry/content-kinds.d.ts +27 -0
  184. package/dist/registry/content-kinds.js +33 -0
  185. package/dist/registry/db/client.d.ts +14 -9
  186. package/dist/registry/db/client.js +22 -9
  187. package/dist/registry/db/driver.d.ts +39 -0
  188. package/dist/registry/db/driver.js +50 -0
  189. package/dist/registry/db/index.d.ts +2 -2
  190. package/dist/registry/db/index.js +14 -9
  191. package/dist/registry/db/migrate.d.ts +1 -1
  192. package/dist/registry/db/migrate.js +5 -5
  193. package/dist/registry/db/schema.d.ts +2992 -963
  194. package/dist/registry/db/schema.js +158 -8
  195. package/dist/registry/publish/assets.d.ts +2 -2
  196. package/dist/registry/publish/assets.js +46 -35
  197. package/dist/registry/publish/errors.js +3 -3
  198. package/dist/registry/publish/index.d.ts +45 -3
  199. package/dist/registry/publish/index.js +247 -24
  200. package/dist/registry/publish/package.js +14 -1
  201. package/dist/registry/publish/tokens.d.ts +2 -2
  202. package/dist/registry/publish/tokens.js +30 -24
  203. package/dist/registry/selection.d.ts +32 -0
  204. package/dist/registry/selection.js +58 -0
  205. package/dist/registry/transfer.d.ts +13 -0
  206. package/dist/store/filesystem.d.ts +3 -3
  207. package/dist/store/filesystem.js +7 -7
  208. package/dist/store/registry.d.ts +48 -0
  209. package/dist/store/registry.js +99 -15
  210. package/dist/transformers/plugins/csf-render.js +4 -2
  211. package/dist/transformers/plugins/ssr-render.js +52 -18
  212. package/dist/transformers/preview/component/api.d.ts +8 -0
  213. package/dist/transformers/preview/component/api.js +11 -15
  214. package/dist/transformers/preview/component/artifacts.d.ts +1 -1
  215. package/dist/transformers/preview/component/artifacts.js +11 -7
  216. package/dist/transformers/preview/component/builder.js +15 -18
  217. package/dist/transformers/preview/component/css.d.ts +3 -0
  218. package/dist/transformers/preview/component/css.js +93 -58
  219. package/dist/transformers/preview/component/html.js +18 -16
  220. package/dist/transformers/preview/component/javascript.js +2 -4
  221. package/dist/transformers/preview/pattern/builder.js +31 -18
  222. package/dist/transformers/preview/pattern/html.js +3 -1
  223. package/dist/transformers/preview/types.d.ts +30 -3
  224. package/dist/transformers/utils/build.d.ts +19 -0
  225. package/dist/transformers/utils/build.js +83 -1
  226. package/dist/transformers/utils/module.js +2 -1
  227. package/dist/types/config.d.ts +156 -45
  228. package/dist/utils/markdown.d.ts +10 -0
  229. package/dist/utils/markdown.js +17 -0
  230. package/dist/utils/menu-shell.js +14 -7
  231. package/dist/utils/pages.d.ts +22 -0
  232. package/dist/utils/pages.js +73 -0
  233. package/dist/utils/path.d.ts +5 -0
  234. package/dist/utils/path.js +9 -0
  235. package/docs/api.md +35 -3
  236. package/docs/cli.md +6 -2
  237. package/drizzle/0002_add_pages.sql +5 -3
  238. package/drizzle/0005_add_registry_auth.sql +95 -0
  239. package/drizzle/0006_add_component_source_format.sql +3 -0
  240. package/drizzle/0007_add_ai_keys.sql +11 -0
  241. package/drizzle/meta/0002_snapshot.json +17 -8
  242. package/drizzle/meta/0003_snapshot.json +17 -8
  243. package/drizzle/meta/0004_snapshot.json +17 -8
  244. package/drizzle/meta/0005_snapshot.json +1935 -0
  245. package/drizzle/meta/0006_snapshot.json +1941 -0
  246. package/drizzle/meta/0007_snapshot.json +2013 -0
  247. package/drizzle/meta/_journal.json +21 -0
  248. package/drizzle.config.ts +1 -1
  249. package/package.json +44 -5
  250. package/src/ai/README.md +42 -0
  251. package/src/ai/connections.ts +172 -0
  252. package/src/ai/define.ts +15 -0
  253. package/src/ai/types.ts +31 -0
  254. package/src/app/components/AiAssistant/AiAssistantPanel.tsx +144 -0
  255. package/src/app/components/AiAssistant/AiAssistantProvider.tsx +215 -0
  256. package/src/app/components/AiAssistant/AiConversation.tsx +674 -0
  257. package/src/app/components/AiAssistant/AiToolResult.tsx +99 -0
  258. package/src/app/components/AiAssistant/dockState.ts +86 -0
  259. package/src/app/components/AiAssistant/toolLabel.ts +22 -0
  260. package/src/app/components/AiAssistant/useAiChat.ts +147 -0
  261. package/src/app/components/AiAssistant/useAiConnections.ts +86 -0
  262. package/src/app/components/AiAssistant/usePageContext.ts +59 -0
  263. package/src/app/components/Auth/AccountLayout.tsx +124 -0
  264. package/src/app/components/Auth/AuthControls.tsx +99 -0
  265. package/src/app/components/Auth/AuthShell.tsx +73 -0
  266. package/src/app/components/Auth/RegistryInstallGate.tsx +23 -0
  267. package/src/app/components/Auth/RegistrySessionProvider.tsx +15 -0
  268. package/src/app/components/Auth/api.ts +20 -0
  269. package/src/app/components/Component/PageSliceResolver.tsx +1 -0
  270. package/src/app/components/Component/Preview.tsx +406 -226
  271. package/src/app/components/Component/slices/ComponentDisplaySlice.tsx +4 -0
  272. package/src/app/components/CopyToClipboard.tsx +27 -26
  273. package/src/app/components/Foundations/DisplayLogo.tsx +8 -2
  274. package/src/app/components/Layout/Header.tsx +10 -14
  275. package/src/app/components/Layout/RuntimeModeBadge.tsx +18 -0
  276. package/src/app/components/Markdown/CodeHighlight.tsx +73 -70
  277. package/src/app/components/Markdown/MarkdownComponents.tsx +30 -32
  278. package/src/app/components/McpIntegration/McpConfigDialog.tsx +349 -0
  279. package/src/app/components/McpIntegration/McpIcon.tsx +10 -0
  280. package/src/app/components/Navigation/MobileNav.tsx +7 -1
  281. package/src/app/components/Navigation/SideNav.tsx +1 -15
  282. package/src/app/components/context/PreviewContext.tsx +5 -5
  283. package/src/app/components/ui/attachment.tsx +50 -0
  284. package/src/app/components/ui/bubble.tsx +57 -0
  285. package/src/app/components/ui/button.tsx +3 -1
  286. package/src/app/components/ui/dialog.tsx +73 -0
  287. package/src/app/components/ui/marker.tsx +56 -0
  288. package/src/app/components/ui/sidebar.tsx +3 -1
  289. package/src/app/components/util/index.ts +14 -38
  290. package/src/app/css/index.css +64 -0
  291. package/src/app/lib/ai/auth.ts +33 -0
  292. package/src/app/lib/ai/context.ts +96 -0
  293. package/src/app/lib/ai/model.ts +85 -0
  294. package/src/app/lib/ai/prompt.ts +36 -0
  295. package/src/app/lib/ai/resolve.ts +97 -0
  296. package/src/app/lib/ai/tools.ts +120 -0
  297. package/src/app/lib/api/methods.ts +13 -0
  298. package/src/app/lib/auth/api.ts +105 -0
  299. package/src/app/lib/auth/config.ts +175 -0
  300. package/src/app/lib/auth/email.ts +34 -0
  301. package/src/app/lib/docs-api/backend.ts +16 -1
  302. package/src/app/lib/docs-api/errors.ts +8 -7
  303. package/src/app/lib/docs-api/handler.ts +2 -3
  304. package/src/app/lib/docs-api/index.ts +2 -0
  305. package/src/app/lib/docs-api/page-discovery.ts +121 -0
  306. package/src/app/lib/docs-api/page-rendering.ts +37 -0
  307. package/src/app/lib/docs-api/page-search.ts +191 -0
  308. package/src/app/lib/docs-api/records.ts +31 -24
  309. package/src/app/lib/docs-api/registry.ts +92 -11
  310. package/src/app/lib/docs-api/runtime-config.ts +42 -35
  311. package/src/app/lib/docs-api/search.ts +120 -0
  312. package/src/app/lib/mcp/auth.ts +64 -0
  313. package/src/app/lib/mcp/index.ts +2 -0
  314. package/src/app/lib/mcp/server.ts +357 -0
  315. package/src/app/lib/mcp/shape.ts +628 -0
  316. package/src/app/lib/registry-api/allowlist.ts +7 -5
  317. package/src/app/lib/registry-api/asset-transfer.ts +58 -31
  318. package/src/app/lib/registry-api/auth.ts +108 -45
  319. package/src/app/lib/registry-api/entity-routes.ts +17 -7
  320. package/src/app/lib/registry-api/errors.ts +12 -6
  321. package/src/app/lib/registry-api/handler.ts +22 -19
  322. package/src/app/lib/registry-api/meta.ts +4 -0
  323. package/src/app/lib/registry-api/revalidate.ts +31 -12
  324. package/src/app/lib/registry-api/store.ts +89 -26
  325. package/src/app/lib/registry-api/sync-compat.ts +166 -0
  326. package/src/app/lib/registry-api/token-transfer.ts +45 -13
  327. package/src/app/lib/registry-api/transfer-batch.ts +116 -0
  328. package/src/app/lib/registry-api/transfer.ts +99 -41
  329. package/src/app/lib/registry-api/validation.ts +33 -1
  330. package/src/app/lib/registry-connection.ts +2 -2
  331. package/src/app/lib/utils.ts +13 -0
  332. package/src/app/next.config.mjs +62 -16
  333. package/src/app/pages/[...slug]/index.tsx +52 -51
  334. package/src/app/pages/_app.tsx +14 -4
  335. package/src/app/pages/_document.tsx +6 -0
  336. package/src/app/pages/account/ai.tsx +162 -0
  337. package/src/app/pages/account/index.tsx +148 -0
  338. package/src/app/pages/account/tokens.tsx +232 -0
  339. package/src/app/pages/account/users.tsx +310 -0
  340. package/src/app/pages/api/account/ai/keys/[connectionId].ts +60 -0
  341. package/src/app/pages/api/account/ai/keys/index.ts +20 -0
  342. package/src/app/pages/api/account/index.ts +26 -0
  343. package/src/app/pages/api/account/tokens/[id].ts +17 -0
  344. package/src/app/pages/api/account/tokens/index.ts +35 -0
  345. package/src/app/pages/api/admin/users/[id]/[action].ts +89 -0
  346. package/src/app/pages/api/admin/users/index.ts +53 -0
  347. package/src/app/pages/api/ai/chat.ts +115 -0
  348. package/src/app/pages/api/ai/connections.ts +23 -0
  349. package/src/app/pages/api/auth/[...nextauth].ts +4 -0
  350. package/src/app/pages/api/auth/request-reset.ts +53 -0
  351. package/src/app/pages/api/auth/reset-password.ts +29 -0
  352. package/src/app/pages/api/docs/search/pages.json.ts +25 -0
  353. package/src/app/pages/api/install.ts +102 -0
  354. package/src/app/pages/api/mcp.ts +56 -0
  355. package/src/app/pages/api/oauth/device/approve.ts +23 -0
  356. package/src/app/pages/api/oauth/device/index.ts +41 -0
  357. package/src/app/pages/api/oauth/revoke.ts +31 -0
  358. package/src/app/pages/api/oauth/token.ts +31 -0
  359. package/src/app/pages/api/registry/components/[id]/files/[...filePath].ts +1 -1
  360. package/src/app/pages/api/registry/components/[id].ts +2 -2
  361. package/src/app/pages/api/registry/components/index.ts +1 -1
  362. package/src/app/pages/api/registry/health.ts +4 -3
  363. package/src/app/pages/api/registry/pages/[...id].ts +20 -0
  364. package/src/app/pages/api/registry/pages/index.ts +19 -0
  365. package/src/app/pages/api/registry/patterns/[id]/files/[...filePath].ts +1 -1
  366. package/src/app/pages/api/registry/patterns/[id].ts +2 -2
  367. package/src/app/pages/api/registry/patterns/index.ts +1 -1
  368. package/src/app/pages/api/registry/transfer/[kind]/[id].ts +3 -3
  369. package/src/app/pages/api/registry/transfer/[kind]/index.ts +21 -0
  370. package/src/app/pages/api/registry/transfer/assets/[collection].ts +2 -1
  371. package/src/app/pages/api/registry/transfer/assets/blobs/[hash].ts +2 -1
  372. package/src/app/pages/api/registry/transfer/assets/blobs/have.ts +2 -2
  373. package/src/app/pages/api/registry/transfer/tokens/[...setId].ts +2 -2
  374. package/src/app/pages/api/sync/upload.ts +21 -0
  375. package/src/app/pages/assets/logos.tsx +4 -1
  376. package/src/app/pages/cli/device.tsx +143 -0
  377. package/src/app/pages/foundations/icons/index.tsx +7 -5
  378. package/src/app/pages/foundations/icons/{[name] → library/[name]}/index.tsx +8 -8
  379. package/src/app/pages/foundations/logo.tsx +5 -4
  380. package/src/app/pages/index/index.tsx +14 -0
  381. package/src/app/pages/index.tsx +31 -5
  382. package/src/app/pages/install.tsx +336 -0
  383. package/src/app/pages/login.tsx +117 -0
  384. package/src/app/pages/reset-password.tsx +159 -0
  385. package/src/app/types/next-auth.d.ts +27 -0
  386. package/src/app-builder/build.ts +225 -86
  387. package/src/app-builder/client-config.ts +18 -14
  388. package/src/app-builder/config-diff/strategies/pattern.ts +1 -1
  389. package/src/app-builder/nav-shell.ts +8 -13
  390. package/src/app-builder/paths.ts +25 -1
  391. package/src/app-builder/static-export.ts +27 -0
  392. package/src/app-builder/vercel-output.ts +6 -6
  393. package/src/app-builder/watchers/component.ts +3 -3
  394. package/src/app-builder/watchers/utils.ts +2 -3
  395. package/src/app-builder/watchers.ts +63 -57
  396. package/src/artifacts/index.ts +8 -1
  397. package/src/artifacts/url.ts +32 -0
  398. package/src/cache/build-cache.ts +16 -15
  399. package/src/catalog/README.md +95 -0
  400. package/src/catalog/define.ts +79 -0
  401. package/src/catalog/implementation.ts +145 -0
  402. package/src/catalog/index.ts +31 -0
  403. package/src/catalog/normalize.ts +145 -0
  404. package/src/catalog/previews.ts +114 -0
  405. package/src/catalog/renderers.ts +94 -0
  406. package/src/catalog/types.ts +82 -0
  407. package/src/cli/README.md +1 -1
  408. package/src/cli/auth/browser.ts +29 -0
  409. package/src/cli/auth/device.ts +186 -0
  410. package/src/cli/auth/store.ts +194 -0
  411. package/src/cli/create.ts +58 -3
  412. package/src/cli/make.ts +22 -74
  413. package/src/cli/scaffold.ts +39 -222
  414. package/src/cli.ts +31 -7
  415. package/src/commands/README.md +1 -1
  416. package/src/commands/build/app.ts +2 -3
  417. package/src/commands/build/components.ts +2 -3
  418. package/src/commands/build/index.ts +2 -3
  419. package/src/commands/checkout/index.ts +29 -50
  420. package/src/commands/compat/deprecations.ts +79 -0
  421. package/src/commands/compat/push-args.ts +106 -0
  422. package/src/commands/db/migrate.ts +2 -3
  423. package/src/commands/dev/index.ts +2 -3
  424. package/src/commands/eject/config.ts +2 -3
  425. package/src/commands/eject/pages.ts +2 -3
  426. package/src/commands/eject/theme.ts +2 -3
  427. package/src/commands/fetch/index.ts +2 -3
  428. package/src/commands/index.ts +8 -2
  429. package/src/commands/login/index.ts +61 -0
  430. package/src/commands/logout/index.ts +104 -0
  431. package/src/commands/make/component.ts +2 -3
  432. package/src/commands/make/page.ts +4 -5
  433. package/src/commands/publish/index.ts +32 -49
  434. package/src/commands/pull/index.ts +32 -0
  435. package/src/commands/push/index.ts +115 -0
  436. package/src/commands/scaffold/index.ts +2 -3
  437. package/src/commands/start/index.ts +2 -3
  438. package/src/commands/types.ts +13 -1
  439. package/src/commands/utils.ts +107 -2
  440. package/src/commands/validate/components.ts +2 -3
  441. package/src/config/README.md +63 -2
  442. package/src/config/catalog-include.ts +227 -0
  443. package/src/config/defaults.ts +26 -13
  444. package/src/config/env.ts +41 -0
  445. package/src/config/errors.ts +7 -0
  446. package/src/config/from-env.ts +26 -0
  447. package/src/config/helpers.ts +4 -2
  448. package/src/config/index.ts +10 -2
  449. package/src/config/loader.ts +208 -43
  450. package/src/config/normalizers/page.ts +4 -4
  451. package/src/config/resolve-env.ts +107 -0
  452. package/src/config/runtime.ts +212 -226
  453. package/src/config/validator.ts +4 -6
  454. package/src/handlebars.ts +24 -0
  455. package/src/index.d.ts +2 -2
  456. package/src/index.ts +325 -72
  457. package/src/nav/resolver.ts +3 -1
  458. package/src/nav/workspace.ts +2 -2
  459. package/src/pattern.ts +14 -0
  460. package/src/pipeline/index.ts +1 -1
  461. package/src/react.ts +52 -0
  462. package/src/registry/asset-storage/adapters/vercel-blob.ts +1 -1
  463. package/src/registry/asset-storage/define.ts +1 -1
  464. package/src/registry/asset-storage/resolve.ts +7 -4
  465. package/src/registry/auth/access-tokens.ts +222 -0
  466. package/src/registry/auth/action-tokens.ts +225 -0
  467. package/src/registry/auth/ai-keys.ts +62 -0
  468. package/src/registry/auth/crypto.ts +75 -0
  469. package/src/registry/auth/database.ts +15 -0
  470. package/src/registry/auth/device-authorizations.ts +223 -0
  471. package/src/registry/auth/gravatar.ts +6 -0
  472. package/src/registry/auth/index.ts +105 -0
  473. package/src/registry/auth/installation.ts +117 -0
  474. package/src/registry/auth/password.ts +46 -0
  475. package/src/registry/auth/rate-limits.ts +84 -0
  476. package/src/registry/auth/sync-secret.ts +67 -0
  477. package/src/registry/auth/types.ts +57 -0
  478. package/src/registry/auth/user-record.ts +25 -0
  479. package/src/registry/auth/users.ts +145 -0
  480. package/src/registry/auth/validation.ts +42 -0
  481. package/src/registry/checkout/assets.ts +28 -9
  482. package/src/registry/checkout/index.ts +582 -130
  483. package/src/registry/checkout/tokens.ts +16 -8
  484. package/src/registry/client.ts +7 -1
  485. package/src/registry/connection.ts +91 -19
  486. package/src/registry/content-kinds.ts +39 -0
  487. package/src/registry/db/client.ts +34 -14
  488. package/src/registry/db/driver.ts +66 -0
  489. package/src/registry/db/index.ts +16 -5
  490. package/src/registry/db/migrate.ts +5 -5
  491. package/src/registry/db/schema.ts +225 -25
  492. package/src/registry/publish/assets.ts +47 -37
  493. package/src/registry/publish/errors.ts +3 -3
  494. package/src/registry/publish/index.ts +286 -27
  495. package/src/registry/publish/package.ts +14 -1
  496. package/src/registry/publish/tokens.ts +35 -26
  497. package/src/registry/selection.ts +63 -0
  498. package/src/registry/transfer.ts +14 -0
  499. package/src/store/filesystem.ts +6 -6
  500. package/src/store/registry.ts +131 -15
  501. package/src/transformers/plugins/csf-render.ts +4 -2
  502. package/src/transformers/plugins/ssr-render.ts +66 -19
  503. package/src/transformers/preview/component/api.ts +13 -1
  504. package/src/transformers/preview/component/artifacts.ts +8 -4
  505. package/src/transformers/preview/component/builder.ts +17 -4
  506. package/src/transformers/preview/component/css.ts +99 -60
  507. package/src/transformers/preview/component/html.ts +30 -19
  508. package/src/transformers/preview/component/javascript.ts +1 -3
  509. package/src/transformers/preview/pattern/builder.ts +33 -20
  510. package/src/transformers/preview/pattern/html.ts +3 -1
  511. package/src/transformers/preview/types.ts +31 -3
  512. package/src/transformers/utils/build.ts +80 -0
  513. package/src/transformers/utils/module.ts +4 -2
  514. package/src/types/config.ts +168 -45
  515. package/src/utils/README.md +1 -0
  516. package/src/utils/markdown.ts +11 -0
  517. package/src/utils/menu-shell.ts +14 -7
  518. package/src/utils/pages.ts +52 -0
  519. package/src/utils/path.ts +15 -6
  520. package/templates/default/README.md.tpl +68 -1
  521. package/templates/default/components/button/button.react.handoff.js.tpl +19 -23
  522. package/templates/default/components/button/button.react.handoff.ts.tpl +22 -22
  523. package/templates/default/env.tpl +10 -0
  524. package/templates/default/gitignore.tpl +26 -3
  525. package/templates/default/handoff.config.js.tpl +21 -166
  526. package/templates/default/handoff.config.ts.tpl +21 -150
  527. package/templates/default/handoff.config.with-examples.js.tpl +22 -164
  528. package/templates/default/handoff.config.with-examples.ts.tpl +22 -148
  529. package/templates/default/package.json.tpl +6 -1
  530. package/templates/default/vercel.json.tpl +4 -0
  531. package/config/docs/foundations/logos.md +0 -7
  532. package/config/templates/component/template.json +0 -49
  533. package/config/templates/template.html +0 -7
  534. package/dist/commands/make/template.d.ts +0 -8
  535. package/dist/commands/make/template.js +0 -47
  536. package/dist/config/normalizers/declaration.d.ts +0 -11
  537. package/dist/config/normalizers/declaration.js +0 -122
  538. package/dist/config/normalizers/pattern.d.ts +0 -8
  539. package/dist/config/normalizers/pattern.js +0 -41
  540. package/dist/declarations/helpers.d.ts +0 -6
  541. package/dist/declarations/helpers.js +0 -19
  542. package/dist/declarations/index.d.ts +0 -2
  543. package/dist/declarations/index.js +0 -9
  544. package/dist/declarations/types.d.ts +0 -60
  545. package/dist/registry/db/adapter.d.ts +0 -43
  546. package/dist/registry/db/adapter.js +0 -59
  547. package/src/app/lib/api/redact.ts +0 -46
  548. package/src/commands/make/template.ts +0 -47
  549. package/src/config/normalizers/declaration.ts +0 -179
  550. package/src/config/normalizers/pattern.ts +0 -59
  551. package/src/declarations/helpers.ts +0 -36
  552. package/src/declarations/index.ts +0 -19
  553. package/src/declarations/types.ts +0 -70
  554. package/src/registry/db/adapter.ts +0 -74
  555. /package/dist/{declarations → catalog}/types.js +0 -0
@@ -1,3 +1,4 @@
1
+ import { PreviewWidth } from '@handoff/transformers/preview/types';
1
2
  import { PreviewObject } from '@handoff/types/preview';
2
3
  import { Filter, evaluateFilter } from '@handoff/utils/filter';
3
4
  import React from 'react';
@@ -13,6 +14,7 @@ export interface ComponentDisplaySliceProps {
13
14
  showPreview?: boolean;
14
15
  showCodeHighlight?: boolean;
15
16
  defaultHeight?: string;
17
+ defaultWidth?: PreviewWidth;
16
18
  filterBy?: Filter;
17
19
  codeHighlight?: boolean;
18
20
  }
@@ -38,6 +40,7 @@ const ComponentDisplaySlice: React.FC<ComponentDisplaySliceProps> = ({
38
40
  showPreview = true,
39
41
  showCodeHighlight,
40
42
  defaultHeight,
43
+ defaultWidth,
41
44
  filterBy,
42
45
  codeHighlight = true,
43
46
  }) => {
@@ -68,6 +71,7 @@ const ComponentDisplaySlice: React.FC<ComponentDisplaySliceProps> = ({
68
71
  title={title}
69
72
  component={filteredPreview}
70
73
  defaultHeight={finalDefaultHeight}
74
+ defaultWidth={defaultWidth}
71
75
  onPreviewChange={onPreviewChange}
72
76
  />
73
77
  )}
@@ -7,11 +7,14 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/t
7
7
 
8
8
  type CopyToClipboardProps = {
9
9
  value: string;
10
+ /** Accessible name for the control, and the hover tooltip unless `showTooltip` is off. */
10
11
  tooltip: string;
12
+ /** Hide the tooltip where the surrounding UI already says what the button copies. */
13
+ showTooltip?: boolean;
11
14
  className?: string;
12
15
  };
13
16
 
14
- export const CopyToClipboard: React.FC<CopyToClipboardProps> = ({ value, tooltip, className }) => {
17
+ export const CopyToClipboard: React.FC<CopyToClipboardProps> = ({ value, tooltip, showTooltip = true, className }) => {
15
18
  const [copied, setCopied] = React.useState<boolean>(false);
16
19
 
17
20
  const handleCopy = async () => {
@@ -24,33 +27,32 @@ export const CopyToClipboard: React.FC<CopyToClipboardProps> = ({ value, tooltip
24
27
  }
25
28
  };
26
29
 
30
+ const button = (
31
+ <Button
32
+ variant="outline"
33
+ size="icon"
34
+ className={cn('disabled:opacity-100', className)}
35
+ onClick={handleCopy}
36
+ aria-label={copied ? 'Copied' : tooltip}
37
+ disabled={copied}
38
+ >
39
+ <div className={cn('transition-all', copied ? 'scale-100 opacity-100' : 'scale-0 opacity-0')}>
40
+ <CheckIcon className="stroke-gray-600" size={16} aria-hidden="true" />
41
+ </div>
42
+ <div className={cn('absolute transition-all', copied ? 'scale-0 opacity-0' : 'scale-100 opacity-100')}>
43
+ <CopyIcon aria-hidden="true" />
44
+ </div>
45
+ </Button>
46
+ );
47
+
48
+ if (!showTooltip) {
49
+ return button;
50
+ }
51
+
27
52
  return (
28
53
  <TooltipProvider delayDuration={0}>
29
54
  <Tooltip>
30
- <TooltipTrigger asChild>
31
- <Button
32
- variant="outline"
33
- size="icon"
34
- className={cn('disabled:opacity-100', className)}
35
- onClick={handleCopy}
36
- aria-label={copied ? 'Copied' : 'Copy to clipboard'}
37
- disabled={copied}
38
- >
39
- <div
40
- className={cn('transition-all', copied ? 'scale-100 opacity-100' : 'scale-0 opacity-0')}
41
- >
42
- <CheckIcon className="stroke-gray-600" size={16} aria-hidden="true" />
43
- </div>
44
- <div
45
- className={cn(
46
- 'absolute transition-all',
47
- copied ? 'scale-0 opacity-0' : 'scale-100 opacity-100'
48
- )}
49
- >
50
- <CopyIcon aria-hidden="true" />
51
- </div>
52
- </Button>
53
- </TooltipTrigger>
55
+ <TooltipTrigger asChild>{button}</TooltipTrigger>
54
56
  <TooltipContent className="px-2 py-1 text-xs">{tooltip}</TooltipContent>
55
57
  </Tooltip>
56
58
  </TooltipProvider>
@@ -58,4 +60,3 @@ export const CopyToClipboard: React.FC<CopyToClipboardProps> = ({ value, tooltip
58
60
  };
59
61
 
60
62
  export default CopyToClipboard;
61
-
@@ -2,11 +2,17 @@ import React from 'react';
2
2
  import type { DisplayableAsset } from '../util/useCollectionAssets';
3
3
 
4
4
  export const DisplayLogo: React.FC<{ logo: DisplayableAsset; content?: string; correct?: boolean }> = ({ logo, content }) => {
5
- // Registry serves the individual asset content URL; workspace/static serves the mirrored file.
5
+ // Workspace/static ships the SVG body inline in tokens.json (`data`), so render it directly and
6
+ // avoid depending on the fetch-only `/api/assets/logos/*` files that a static host won't have.
7
+ // Registry has no inline body, so it falls back to the individual asset content URL (`src`).
6
8
  const src = logo.src ?? `${process.env.HANDOFF_APP_BASE_PATH ?? ''}/api/assets/logos/${logo.path}`;
7
9
  return (
8
10
  <div className="flex flex-col gap-5">
9
- <img src={src} alt="Usage Cards" className="rounded-3xl" />
11
+ {logo.data ? (
12
+ <div className="rounded-3xl" dangerouslySetInnerHTML={{ __html: logo.data }} />
13
+ ) : (
14
+ <img src={src} alt={logo.name} className="rounded-3xl" />
15
+ )}
10
16
  <div className="flex flex-row gap-4">
11
17
  <img src={`${process.env.HANDOFF_APP_BASE_PATH ?? ''}/assets/images/check-circle.svg`} alt="Do" className="h-6 w-6" />
12
18
  <p className="leading-normal text-gray-500">
@@ -1,22 +1,19 @@
1
1
  import Link from 'next/link';
2
2
  import { useEffect, useState } from 'react';
3
+ import { AiAssistantTrigger } from '../../components/AiAssistant/AiAssistantProvider';
4
+ import { McpConfigDialog } from '../../components/McpIntegration/McpConfigDialog';
3
5
  import { ModeToggle } from '../../components/ModeSwitcher';
4
6
  import { MainNav } from '../../components/Navigation/MainNav';
5
7
  import { MobileNav } from '../../components/Navigation/MobileNav';
6
8
  import { cn } from '../../lib/utils';
7
- import { Badge } from '../ui/badge';
8
9
  import { useConfigContext } from '../context/ConfigContext';
9
-
10
- const RUNTIME_MODE_LABEL: Record<'workspace' | 'registry', string> = {
11
- workspace: 'Workspace',
12
- registry: 'Registry',
13
- };
10
+ import { AuthControls } from '../Auth/AuthControls';
11
+ import { RuntimeModeBadge } from './RuntimeModeBadge';
14
12
 
15
13
  export function Header() {
16
14
  const context = useConfigContext();
17
15
  const [isScrolled, setIsScrolled] = useState(false);
18
16
  const runtimeMode = context.config?.runtime?.mode ?? 'workspace';
19
- const runtimeModeLabel = RUNTIME_MODE_LABEL[runtimeMode];
20
17
  // The static export is a self-contained snapshot of the workspace, not a live runtime, so the
21
18
  // runtime-mode badge carries no meaning there and is omitted.
22
19
  const isStaticSnapshot = process.env.HANDOFF_BUILD_TARGET === 'static';
@@ -33,8 +30,8 @@ export function Header() {
33
30
  return (
34
31
  <div
35
32
  className={cn(
36
- 'sticky top-0 z-50 py-4 shadow-[0_0_3px_0_rgba(0,0,0,0.15)] backdrop-blur-sm transition-all duration-300',
37
- isScrolled && 'bg-background/70 py-3 shadow-[0_0_4px_0_rgba(0,0,0,0.15)]'
33
+ 'ai-dock-bleed h-17 sticky top-0 z-50 py-4 shadow-[0_0_3px_0_rgba(0,0,0,0.15)] backdrop-blur-sm transition-all duration-300',
34
+ isScrolled && 'bg-background/70 shadow-[0_0_4px_0_rgba(0,0,0,0.15)]'
38
35
  )}
39
36
  >
40
37
  <header className="border-grid container mx-auto w-full max-w-[1500px] bg-transparent px-8">
@@ -43,14 +40,13 @@ export function Header() {
43
40
  <Link href="/">
44
41
  <img className="max-h-5" src={`${process.env.HANDOFF_APP_BASE_PATH ?? ''}/logo.svg`} alt={context.config?.app?.title} />
45
42
  </Link>
46
- {!isStaticSnapshot && (
47
- <Badge variant={runtimeMode === 'registry' ? 'info' : 'default'} aria-label={`Runtime mode: ${runtimeModeLabel}`}>
48
- {runtimeModeLabel}
49
- </Badge>
50
- )}
43
+ {!isStaticSnapshot && <RuntimeModeBadge mode={runtimeMode} />}
51
44
  </div>
52
45
  <div className="hidden items-center gap-4 @2xl:flex">
53
46
  <MainNav />
47
+ <AiAssistantTrigger />
48
+ <McpConfigDialog />
49
+ {runtimeMode === 'registry' ? <AuthControls /> : null}
54
50
  <ModeToggle />
55
51
  </div>
56
52
  <div className="flex items-center gap-4 @2xl:hidden">
@@ -0,0 +1,18 @@
1
+ import type { RuntimeMode } from '@handoff/types/config';
2
+ import { Badge } from '../ui/badge';
3
+
4
+ const LABEL: Record<RuntimeMode, string> = {
5
+ workspace: 'Workspace',
6
+ registry: 'Registry',
7
+ };
8
+
9
+ /**
10
+ * The Workspace/Registry marker, shared by the header and the MCP connect dialog. `mode` is a prop
11
+ * because the header reads the projected client config while the dialog reads the mode baked into
12
+ * the bundle.
13
+ */
14
+ export const RuntimeModeBadge: React.FC<{ mode: RuntimeMode; className?: string }> = ({ mode, className }) => (
15
+ <Badge variant={mode === 'registry' ? 'info' : 'default'} className={className} aria-label={`Runtime mode: ${LABEL[mode]}`}>
16
+ {LABEL[mode]}
17
+ </Badge>
18
+ );
@@ -1,3 +1,4 @@
1
+ import type { RendererKind } from '@handoff/catalog/renderers';
1
2
  import { PreviewObject } from '@handoff/types/preview';
2
3
  // @ts-ignore
3
4
  import { CollapsibleTrigger } from '@radix-ui/react-collapsible';
@@ -34,6 +35,60 @@ SyntaxHighlighter.registerLanguage('html', html);
34
35
  SyntaxHighlighter.registerLanguage('xml', html);
35
36
  SyntaxHighlighter.registerLanguage('handlebars', handlebars);
36
37
  SyntaxHighlighter.registerLanguage('hbs', handlebars);
38
+
39
+ type CodeFormat = { label: string; language: string };
40
+
41
+ /**
42
+ * How each renderer's implementation code is shown. Exhaustive over `RendererKind`, so a new
43
+ * renderer fails to compile until its label and highlighting are declared. `RENDERER_PLUGINS`
44
+ * puts the same guard on preview support.
45
+ */
46
+ const CODE_FORMATS: Record<RendererKind, CodeFormat> = {
47
+ react: { label: 'React (TSX)', language: 'tsx' },
48
+ handlebars: { label: 'Handlebars', language: 'handlebars' },
49
+ };
50
+
51
+ /**
52
+ * Formats that are not a renderer name: the synthetic `html` that the string and empty-data
53
+ * branches set, and the language names that older artifacts carry in `format`.
54
+ */
55
+ const FORMAT_ALIASES: Record<string, CodeFormat> = {
56
+ html: { label: 'HTML', language: 'html' },
57
+ tsx: CODE_FORMATS.react,
58
+ jsx: { label: 'React (JSX)', language: 'jsx' },
59
+ ts: { label: 'TypeScript', language: 'typescript' },
60
+ typescript: { label: 'TypeScript', language: 'typescript' },
61
+ js: { label: 'JavaScript', language: 'javascript' },
62
+ javascript: { label: 'JavaScript', language: 'javascript' },
63
+ };
64
+
65
+ const formatFor = (format?: string): CodeFormat => {
66
+ const key = format?.toLowerCase() ?? '';
67
+ // Legacy default: an unrecognized format reads as plain code and highlights as Handlebars.
68
+ return CODE_FORMATS[key as RendererKind] ?? FORMAT_ALIASES[key] ?? { label: 'Code', language: 'handlebars' };
69
+ };
70
+
71
+ type CodeView = { label?: string; language?: string };
72
+
73
+ /**
74
+ * The code views, in the order they are offered. An allowlist rather than a denylist of metadata:
75
+ * a field added to the record later cannot become a view by default. An absent `label` or
76
+ * `language` is computed: from the item's format for `code`, from the `type` prop for `html`, and
77
+ * by JSX detection for `js`.
78
+ */
79
+ const CODE_VIEWS: Record<string, CodeView> = {
80
+ usage: { label: 'Usage', language: 'tsx' },
81
+ code: {},
82
+ html: { label: 'HTML' },
83
+ css: { label: 'CSS', language: 'css' },
84
+ js: { label: 'JavaScript' },
85
+ sass: { label: 'SASS', language: 'scss' },
86
+ sharedStyles: { label: 'Shared CSS', language: 'css' },
87
+ };
88
+
89
+ /** `usage` is derived from the previews, not read off the record, so it is offered separately. */
90
+ const RECORD_VIEWS = Object.keys(CODE_VIEWS).filter((key) => key !== 'usage');
91
+
37
92
  /**
38
93
  * Highlight code for preview elements
39
94
  * @param param0
@@ -88,14 +143,7 @@ export const CodeHighlight: React.FC<{
88
143
  }
89
144
  if (!type) type = 'html';
90
145
 
91
- const metadataKeys = [
92
- 'id', 'preview', 'image', 'categories', 'title', 'format',
93
- 'description', 'type', 'group', 'tags', 'previews', 'properties',
94
- 'should_do', 'should_not_do', 'figma', 'usage',
95
- ];
96
-
97
- const states = Object.keys(data)
98
- .filter((key) => !metadataKeys.includes(key) && !!(data as Record<string, any>)[key]);
146
+ const states = RECORD_VIEWS.filter((key) => !!(data as Record<string, any>)[key]);
99
147
  const hasPerPreviewUsage =
100
148
  typeof data === 'object' &&
101
149
  !!data.previews &&
@@ -116,35 +164,11 @@ export const CodeHighlight: React.FC<{
116
164
  theme['pre[class*="language-"]'].maxHeight = height ?? '450px';
117
165
  theme['pre[class*="language-"]'].margin = '0';
118
166
 
119
- const labels: Record<string, string> = {
120
- code: 'Code',
121
- handlebars: 'Handlebars',
122
- hbs: 'Handlebars',
123
- html: 'HTML',
124
- css: 'CSS',
125
- js: 'JavaScript',
126
- javascript: 'JavaScript',
127
- jsx: 'JSX',
128
- tsx: 'TSX',
129
- typescript: 'TypeScript',
130
- ts: 'TypeScript',
131
- sass: 'SASS',
132
- scss: 'SCSS',
133
- sharedStyles: 'Shared CSS',
134
- usage: 'Usage',
135
- json: 'JSON',
136
- markdown: 'Markdown',
137
- };
138
-
139
167
  const getLabel = (state: string): string => {
140
168
  if (state === 'code' && typeof data === 'object') {
141
- const format = data.format?.toLowerCase();
142
- if (format === 'react' || format === 'tsx') return 'React (TSX)';
143
- if (format === 'jsx') return 'React (JSX)';
144
- if (format === 'typescript' || format === 'ts') return 'TypeScript';
145
- if (format === 'javascript' || format === 'js') return 'JavaScript';
169
+ return formatFor(data.format).label;
146
170
  }
147
- return labels[state] || state.charAt(0).toUpperCase() + state.slice(1);
171
+ return CODE_VIEWS[state]?.label ?? state.charAt(0).toUpperCase() + state.slice(1);
148
172
  };
149
173
 
150
174
  /**
@@ -155,39 +179,22 @@ export const CodeHighlight: React.FC<{
155
179
  return activeState === 'html' ? type : activeState;
156
180
  }
157
181
 
158
- // Handle React/JSX/TSX code format
159
- if ('code' in data && !!data.code && activeState === 'code') {
160
- const format = data.format?.toLowerCase();
161
- if (format === 'react' || format === 'tsx') return 'tsx';
162
- if (format === 'jsx') return 'jsx';
163
- if (format === 'typescript' || format === 'ts') return 'typescript';
164
- if (format === 'javascript' || format === 'js') return 'javascript';
165
- return 'handlebars';
182
+ if (activeState === 'code') {
183
+ return formatFor(data.format).language;
184
+ }
185
+
186
+ // The `type` prop names the markup language of the rendered preview.
187
+ if (activeState === 'html') {
188
+ return type || 'html';
166
189
  }
167
190
 
168
- // Handle JavaScript state
191
+ // A component's compiled JS can be plain JavaScript or still hold JSX.
169
192
  if (activeState === 'js') {
170
- // Check if the JS code contains JSX syntax (common patterns)
171
193
  const jsCode = 'js' in data ? data.js : '';
172
- if (typeof jsCode === 'string' && hasJsxSyntax(jsCode)) {
173
- return 'jsx';
174
- }
175
- return 'javascript';
194
+ return typeof jsCode === 'string' && hasJsxSyntax(jsCode) ? 'jsx' : 'javascript';
176
195
  }
177
196
 
178
- // Map common state names to language identifiers
179
- const languageMap: Record<string, string> = {
180
- html: type || 'html',
181
- css: 'css',
182
- sass: 'scss',
183
- sharedStyles: 'css',
184
- usage: 'tsx',
185
- json: 'json',
186
- handlebars: 'handlebars',
187
- hbs: 'handlebars',
188
- };
189
-
190
- return languageMap[activeState] || activeState;
197
+ return CODE_VIEWS[activeState]?.language ?? activeState;
191
198
  };
192
199
 
193
200
  /**
@@ -285,15 +292,11 @@ export const CodeHighlight: React.FC<{
285
292
  <SelectValue placeholder="Code View" />
286
293
  </SelectTrigger>
287
294
  <SelectContent>
288
- {selectableStates
289
- .filter((value) => ['usage', 'code', 'html', 'css', 'js', 'sass', 'sharedStyles'].includes(value))
290
- .map((state) => {
291
- return (
292
- <SelectItem key={state} value={state}>
293
- {getLabel(state)}
294
- </SelectItem>
295
- );
296
- })}
295
+ {selectableStates.map((state) => (
296
+ <SelectItem key={state} value={state}>
297
+ {getLabel(state)}
298
+ </SelectItem>
299
+ ))}
297
300
  </SelectContent>
298
301
  </Select>
299
302
  )}
@@ -70,38 +70,36 @@ function extractText(node: any): string {
70
70
 
71
71
  const Headings = (element: any) => {
72
72
  const { children, node } = element;
73
- if (children[0]) {
74
- const type = node.tagName || 'h6';
75
-
76
- let anchor = extractText(children).toLowerCase();
77
- anchor = anchor.replace(/[^a-zA-Z0-9 ]/g, '');
78
- anchor = anchor.replace(/ /g, '-');
79
-
80
- const container = (children: React.ReactNode): React.ReactNode => (
81
- <>
82
- {children}
83
- <a id={anchor} href={`#${anchor}`} className="doc-link"></a>
84
- </>
85
- );
86
-
87
- switch (type) {
88
- case 'h1':
89
- return <h1 className="text-2xl font-bold">{container(children)}</h1>;
90
- case 'h2':
91
- return <h2 className="text-xl font-bold">{container(children)}</h2>;
92
- case 'h3':
93
- return <h3 className="text-lg font-bold">{container(children)}</h3>;
94
- case 'h4':
95
- return <h4 className="text-base font-bold">{container(children)}</h4>;
96
- case 'h5':
97
- return <h5 className="text-sm font-bold">{container(children)}</h5>;
98
- case 'h6':
99
- return <h6 className="text-xs font-bold">{container(children)}</h6>;
100
- default:
101
- return <h6 className="text-xs font-bold">{container(children)}</h6>;
102
- }
103
- } else {
104
- return <h1>children</h1>;
73
+ if (React.Children.count(children) === 0) return <></>;
74
+
75
+ const type = node.tagName || 'h6';
76
+
77
+ let anchor = extractText(children).toLowerCase();
78
+ anchor = anchor.replace(/[^a-zA-Z0-9 ]/g, '');
79
+ anchor = anchor.replace(/ /g, '-');
80
+
81
+ const container = (children: React.ReactNode): React.ReactNode => (
82
+ <>
83
+ {children}
84
+ <a id={anchor} href={`#${anchor}`} className="doc-link"></a>
85
+ </>
86
+ );
87
+
88
+ switch (type) {
89
+ case 'h1':
90
+ return <h1 className="text-2xl font-bold">{container(children)}</h1>;
91
+ case 'h2':
92
+ return <h2 className="text-xl font-bold">{container(children)}</h2>;
93
+ case 'h3':
94
+ return <h3 className="text-lg font-bold">{container(children)}</h3>;
95
+ case 'h4':
96
+ return <h4 className="text-base font-bold">{container(children)}</h4>;
97
+ case 'h5':
98
+ return <h5 className="text-sm font-bold">{container(children)}</h5>;
99
+ case 'h6':
100
+ return <h6 className="text-xs font-bold">{container(children)}</h6>;
101
+ default:
102
+ return <h6 className="text-xs font-bold">{container(children)}</h6>;
105
103
  }
106
104
  };
107
105