@adia-ai/gen-ui 0.8.37

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 (631) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +77 -0
  3. package/compose/CHANGELOG.md +1707 -0
  4. package/compose/README.md +215 -0
  5. package/compose/core/artifacts.js +262 -0
  6. package/compose/core/context-store.js +218 -0
  7. package/compose/core/generator.d.ts +4 -0
  8. package/compose/core/generator.js +602 -0
  9. package/compose/core/pipeline/engine.js +289 -0
  10. package/compose/core/pipeline/types.js +91 -0
  11. package/compose/core/plan-primitives.js +120 -0
  12. package/compose/core/plan-turn.js +145 -0
  13. package/compose/core/reference.js +150 -0
  14. package/compose/core/state.js +15 -0
  15. package/compose/evals/harness.d.ts +4 -0
  16. package/compose/evals/harness.mjs +193 -0
  17. package/compose/index.d.ts +4 -0
  18. package/compose/index.js +16 -0
  19. package/compose/shared/validate-and-repair.js +122 -0
  20. package/compose/strategies/_shared/chunk-loader.js +282 -0
  21. package/compose/strategies/cascade.d.ts +67 -0
  22. package/compose/strategies/cascade.js +165 -0
  23. package/compose/strategies/escalation.d.ts +13 -0
  24. package/compose/strategies/escalation.js +132 -0
  25. package/compose/strategies/free-form-composer/index.js +254 -0
  26. package/compose/strategies/free-form-composer/system-prompt.js +205 -0
  27. package/compose/strategies/free-form-composer/transpile.js +279 -0
  28. package/compose/strategies/monolithic/_shared.js +1619 -0
  29. package/compose/strategies/monolithic/generate-instant.js +228 -0
  30. package/compose/strategies/monolithic/generate-pro.js +490 -0
  31. package/compose/strategies/monolithic/generate-thinking.js +206 -0
  32. package/compose/strategies/registry.d.ts +20 -0
  33. package/compose/strategies/registry.js +495 -0
  34. package/compose/strategies/zettel/_smoke.js +27 -0
  35. package/compose/strategies/zettel/chunk-composer.js +214 -0
  36. package/compose/strategies/zettel/chunk-refiner.js +582 -0
  37. package/compose/strategies/zettel/chunk-synthesizer.js +458 -0
  38. package/compose/strategies/zettel/composer.js +78 -0
  39. package/compose/strategies/zettel/composition-library.js +418 -0
  40. package/compose/strategies/zettel/generate.js +15 -0
  41. package/compose/strategies/zettel/generator-adapter.d.ts +4 -0
  42. package/compose/strategies/zettel/generator-adapter.js +242 -0
  43. package/compose/strategies/zettel/issue-reporter.js +607 -0
  44. package/compose/strategies/zettel/session-store.js +121 -0
  45. package/compose/strategies/zettel/state-cache.js +158 -0
  46. package/compose/transpiler/transpiler-maps.js +675 -0
  47. package/compose/transpiler/transpiler.d.ts +4 -0
  48. package/compose/transpiler/transpiler.js +962 -0
  49. package/corpus/CHANGELOG.md +1957 -0
  50. package/corpus/README.md +279 -0
  51. package/corpus/catalog-a2ui_0_9.d.ts +4 -0
  52. package/corpus/catalog-a2ui_0_9.json +29571 -0
  53. package/corpus/catalog-a2ui_0_9_rules.txt +1215 -0
  54. package/corpus/chunk-embeddings.d.ts +4 -0
  55. package/corpus/chunk-embeddings.json +1 -0
  56. package/corpus/chunks/_index.json +16658 -0
  57. package/corpus/chunks/_source-hashes.json +571 -0
  58. package/corpus/chunks/access-denied-with-request.json +124 -0
  59. package/corpus/chunks/access-request-form.json +166 -0
  60. package/corpus/chunks/access-request-pending.json +133 -0
  61. package/corpus/chunks/accordion-settings.json +176 -0
  62. package/corpus/chunks/achievement-badges.json +413 -0
  63. package/corpus/chunks/achievement-unlock.json +104 -0
  64. package/corpus/chunks/action-list-record-actions.json +84 -0
  65. package/corpus/chunks/activity-feed.json +390 -0
  66. package/corpus/chunks/admin-page-header-flush.json +83 -0
  67. package/corpus/chunks/admin-page-header-title-description.json +80 -0
  68. package/corpus/chunks/admin-page-header-with-actions.json +107 -0
  69. package/corpus/chunks/admin-page-header-with-tabs.json +144 -0
  70. package/corpus/chunks/admin-shell-rounded-borderless.json +287 -0
  71. package/corpus/chunks/admin-shell-standard.json +310 -0
  72. package/corpus/chunks/admin-sidebar-brand-signin.json +158 -0
  73. package/corpus/chunks/admin-sidebar-brand-version.json +130 -0
  74. package/corpus/chunks/admin-sidebar-flat-nav.json +131 -0
  75. package/corpus/chunks/admin-sidebar-nav-dividers.json +150 -0
  76. package/corpus/chunks/admin-sidebar-nav-groups.json +171 -0
  77. package/corpus/chunks/admin-sidebar-workspace-switcher.json +139 -0
  78. package/corpus/chunks/admin-topbar-breadcrumb-actions.json +130 -0
  79. package/corpus/chunks/admin-topbar-breadcrumb-minimal.json +79 -0
  80. package/corpus/chunks/admin-topbar-deep-breadcrumb.json +129 -0
  81. package/corpus/chunks/admin-topbar-search.json +104 -0
  82. package/corpus/chunks/admin-topbar-status-indicator.json +122 -0
  83. package/corpus/chunks/admin-topbar-trailing-toggle.json +114 -0
  84. package/corpus/chunks/agent-activity-feed.json +163 -0
  85. package/corpus/chunks/agent-artifact-stub-card.json +115 -0
  86. package/corpus/chunks/agent-canvas-shell.json +305 -0
  87. package/corpus/chunks/agent-citations-source-chips.json +82 -0
  88. package/corpus/chunks/agent-command-palette-search.json +120 -0
  89. package/corpus/chunks/agent-cost-detailed.json +260 -0
  90. package/corpus/chunks/agent-cost-inline.json +78 -0
  91. package/corpus/chunks/agent-memory-detail.json +181 -0
  92. package/corpus/chunks/agent-memory-editor.json +173 -0
  93. package/corpus/chunks/agent-memory-list.json +207 -0
  94. package/corpus/chunks/agent-pipeline-status-stages.json +61 -0
  95. package/corpus/chunks/agent-prompt-card.json +179 -0
  96. package/corpus/chunks/agent-prompt-library-grid.json +341 -0
  97. package/corpus/chunks/agent-prompt-picker.json +282 -0
  98. package/corpus/chunks/agent-rate-limit.json +100 -0
  99. package/corpus/chunks/agent-reasoning-collapsed.json +128 -0
  100. package/corpus/chunks/agent-tool-call-accordion.json +109 -0
  101. package/corpus/chunks/agent-tool-call-collapsed.json +98 -0
  102. package/corpus/chunks/agent-tool-call-error.json +112 -0
  103. package/corpus/chunks/agent-tool-call-result.json +145 -0
  104. package/corpus/chunks/agent-tool-call-running.json +85 -0
  105. package/corpus/chunks/agent-tool-call-success.json +137 -0
  106. package/corpus/chunks/agent-trace-timeline.json +244 -0
  107. package/corpus/chunks/ai-streaming-response.json +147 -0
  108. package/corpus/chunks/alert-banner-stack.json +78 -0
  109. package/corpus/chunks/alert-banner.json +55 -0
  110. package/corpus/chunks/alert-dialog-simple.json +72 -0
  111. package/corpus/chunks/alert-dialog-typed.json +107 -0
  112. package/corpus/chunks/alert-dialog-unsaved.json +81 -0
  113. package/corpus/chunks/analytics-chart.json +213 -0
  114. package/corpus/chunks/analytics-sparklines-dashboard.json +259 -0
  115. package/corpus/chunks/anchor-bar-selection-bar.json +226 -0
  116. package/corpus/chunks/api-key-table.json +148 -0
  117. package/corpus/chunks/api-keys-create.json +140 -0
  118. package/corpus/chunks/api-keys-list.json +271 -0
  119. package/corpus/chunks/app-nav-badges-counts.json +77 -0
  120. package/corpus/chunks/app-nav-badges-group-rollup-badges.json +100 -0
  121. package/corpus/chunks/app-nav-badges-plan-tiers.json +76 -0
  122. package/corpus/chunks/app-nav-badges-status-callouts.json +75 -0
  123. package/corpus/chunks/app-nav-full-example.json +195 -0
  124. package/corpus/chunks/app-nav-groups.json +103 -0
  125. package/corpus/chunks/app-nav-items.json +74 -0
  126. package/corpus/chunks/app-nav-labels-and-dividers.json +92 -0
  127. package/corpus/chunks/app-nav-spacer.json +77 -0
  128. package/corpus/chunks/app-product-listing-card.json +214 -0
  129. package/corpus/chunks/approvals-detail.json +240 -0
  130. package/corpus/chunks/approvals-queue.json +321 -0
  131. package/corpus/chunks/audit-log-basic.json +184 -0
  132. package/corpus/chunks/audit-log.json +174 -0
  133. package/corpus/chunks/auth-account-deleted-actions.json +51 -0
  134. package/corpus/chunks/auth-account-deleted.json +202 -0
  135. package/corpus/chunks/auth-card-content.json +260 -0
  136. package/corpus/chunks/auth-card-header.json +205 -0
  137. package/corpus/chunks/auth-email-entry.json +65 -0
  138. package/corpus/chunks/auth-email-verify-confirm.json +52 -0
  139. package/corpus/chunks/auth-email-verify.json +196 -0
  140. package/corpus/chunks/auth-forbidden-actions.json +59 -0
  141. package/corpus/chunks/auth-forbidden.json +203 -0
  142. package/corpus/chunks/auth-invite-actions.json +49 -0
  143. package/corpus/chunks/auth-invite-team-card.json +86 -0
  144. package/corpus/chunks/auth-link-expired-form.json +65 -0
  145. package/corpus/chunks/auth-link-expired.json +196 -0
  146. package/corpus/chunks/auth-locked-account.json +211 -0
  147. package/corpus/chunks/auth-locked-recovery-options.json +60 -0
  148. package/corpus/chunks/auth-mfa-enrollment-submit.json +54 -0
  149. package/corpus/chunks/auth-mfa-enrollment.json +284 -0
  150. package/corpus/chunks/auth-mfa-fallback-actions.json +52 -0
  151. package/corpus/chunks/auth-mfa-recovery.json +61 -0
  152. package/corpus/chunks/auth-new-password-form.json +75 -0
  153. package/corpus/chunks/auth-new-password.json +217 -0
  154. package/corpus/chunks/auth-oauth-fallback-actions.json +52 -0
  155. package/corpus/chunks/auth-oauth-interstitial.json +160 -0
  156. package/corpus/chunks/auth-password-challenge.json +94 -0
  157. package/corpus/chunks/auth-password-reset-form.json +64 -0
  158. package/corpus/chunks/auth-password-reset.json +195 -0
  159. package/corpus/chunks/auth-profile-form.json +72 -0
  160. package/corpus/chunks/auth-profile-setup.json +194 -0
  161. package/corpus/chunks/auth-reset-sent.json +188 -0
  162. package/corpus/chunks/auth-session-expired-actions.json +52 -0
  163. package/corpus/chunks/auth-session-expired.json +201 -0
  164. package/corpus/chunks/auth-signin-card-email.json +245 -0
  165. package/corpus/chunks/auth-signin-card-magic-link.json +147 -0
  166. package/corpus/chunks/auth-signin-card-mfa.json +231 -0
  167. package/corpus/chunks/auth-signin-card-otp.json +205 -0
  168. package/corpus/chunks/auth-signin-card-password.json +264 -0
  169. package/corpus/chunks/auth-signin-card-recovery.json +218 -0
  170. package/corpus/chunks/auth-signout-actions.json +51 -0
  171. package/corpus/chunks/auth-signout.json +184 -0
  172. package/corpus/chunks/auth-signup-email-entry.json +66 -0
  173. package/corpus/chunks/auth-signup-entry.json +281 -0
  174. package/corpus/chunks/auth-signup-social-auths.json +54 -0
  175. package/corpus/chunks/auth-signup-verify.json +227 -0
  176. package/corpus/chunks/auth-social-auths.json +62 -0
  177. package/corpus/chunks/auth-sso-providers.json +55 -0
  178. package/corpus/chunks/auth-sso-required.json +213 -0
  179. package/corpus/chunks/auth-team-invite.json +288 -0
  180. package/corpus/chunks/avatar-group-overflow.json +137 -0
  181. package/corpus/chunks/avatar-stack-overflow.json +124 -0
  182. package/corpus/chunks/banner-announcement-beta.json +99 -0
  183. package/corpus/chunks/banner-announcement-promo.json +102 -0
  184. package/corpus/chunks/banner-live-update.json +102 -0
  185. package/corpus/chunks/banner-system-maintenance.json +101 -0
  186. package/corpus/chunks/banner-system-offline.json +85 -0
  187. package/corpus/chunks/banner-system-update.json +102 -0
  188. package/corpus/chunks/bell-menu-empty.json +107 -0
  189. package/corpus/chunks/bell-menu-unread.json +395 -0
  190. package/corpus/chunks/billing-cancel-subscription-danger.json +61 -0
  191. package/corpus/chunks/billing-invoice-history-table.json +75 -0
  192. package/corpus/chunks/billing-overview.json +202 -0
  193. package/corpus/chunks/billing-payment-method-card-on-file.json +157 -0
  194. package/corpus/chunks/billing-progress-label.json +101 -0
  195. package/corpus/chunks/blog-post-card.json +212 -0
  196. package/corpus/chunks/breadcrumb-navigation.json +72 -0
  197. package/corpus/chunks/bulk-action-toolbar-floating.json +199 -0
  198. package/corpus/chunks/bulk-action-toolbar-swap.json +158 -0
  199. package/corpus/chunks/bulk-selection-actions-bar.json +162 -0
  200. package/corpus/chunks/business-address-form.json +953 -0
  201. package/corpus/chunks/calendar-month-view.json +74 -0
  202. package/corpus/chunks/card-grid-images.json +459 -0
  203. package/corpus/chunks/card-header-with-description.json +47 -0
  204. package/corpus/chunks/card-with-empty-state.json +96 -0
  205. package/corpus/chunks/card-with-form.json +143 -0
  206. package/corpus/chunks/card-with-sparkline.json +90 -0
  207. package/corpus/chunks/card-with-stat-kpi.json +86 -0
  208. package/corpus/chunks/changelog-feed-basic.json +470 -0
  209. package/corpus/chunks/chart-in-card-chart-plus-breakdown.json +188 -0
  210. package/corpus/chunks/chart-in-card-chart-plus-stat.json +89 -0
  211. package/corpus/chunks/chart-in-card-chart-with-filter-pills.json +124 -0
  212. package/corpus/chunks/chart-in-card-full-bleed-legend.json +116 -0
  213. package/corpus/chunks/chart-in-card-full-chart.json +107 -0
  214. package/corpus/chunks/chart-in-card-sparkline-tile.json +93 -0
  215. package/corpus/chunks/chart-in-card-stat-with-sparkline.json +73 -0
  216. package/corpus/chunks/chart-in-card-trend-footer.json +115 -0
  217. package/corpus/chunks/chart-with-filter-pills.json +169 -0
  218. package/corpus/chunks/chat-empty-state-hero.json +102 -0
  219. package/corpus/chunks/chat-message-assistant-byline.json +85 -0
  220. package/corpus/chunks/chat-message-user-byline.json +84 -0
  221. package/corpus/chunks/chat-page-shell.json +379 -0
  222. package/corpus/chunks/chat-streaming-surface.json +169 -0
  223. package/corpus/chunks/checkout-order-summary-card.json +140 -0
  224. package/corpus/chunks/code-snippet.json +107 -0
  225. package/corpus/chunks/col-form-stack.json +93 -0
  226. package/corpus/chunks/col-heading-body-action.json +79 -0
  227. package/corpus/chunks/col-stat-label.json +63 -0
  228. package/corpus/chunks/color-picker-swatches.json +153 -0
  229. package/corpus/chunks/command-palette.json +327 -0
  230. package/corpus/chunks/comments-composer.json +158 -0
  231. package/corpus/chunks/comments-mention-menu.json +237 -0
  232. package/corpus/chunks/comments-thread.json +344 -0
  233. package/corpus/chunks/commerce-pricing-tiers.json +401 -0
  234. package/corpus/chunks/comparison-table.json +246 -0
  235. package/corpus/chunks/contact-form-card.json +197 -0
  236. package/corpus/chunks/contact-form.json +157 -0
  237. package/corpus/chunks/contact-support-form.json +702 -0
  238. package/corpus/chunks/conversion-funnel-4-step-funnel.json +139 -0
  239. package/corpus/chunks/conversion-funnel-6step.json +151 -0
  240. package/corpus/chunks/conversion-funnel-wide-summary.json +192 -0
  241. package/corpus/chunks/conversion-funnel-with-segment-compare.json +202 -0
  242. package/corpus/chunks/cta-banner-centered.json +102 -0
  243. package/corpus/chunks/dashboard-acquisition-panel.json +212 -0
  244. package/corpus/chunks/dashboard-admin-page.json +104 -0
  245. package/corpus/chunks/dashboard-audience-kpis.json +165 -0
  246. package/corpus/chunks/dashboard-audience-panel.json +756 -0
  247. package/corpus/chunks/dashboard-behavior-panel.json +114 -0
  248. package/corpus/chunks/dashboard-chart-recent.json +566 -0
  249. package/corpus/chunks/dashboard-cohort-retention.json +83 -0
  250. package/corpus/chunks/dashboard-conversion-panel.json +234 -0
  251. package/corpus/chunks/dashboard-country-list.json +304 -0
  252. package/corpus/chunks/dashboard-filter-bar.json +118 -0
  253. package/corpus/chunks/dashboard-funnel.json +142 -0
  254. package/corpus/chunks/dashboard-notifications-panel.json +423 -0
  255. package/corpus/chunks/dashboard-overview-panel.json +1644 -0
  256. package/corpus/chunks/dashboard-page-header.json +166 -0
  257. package/corpus/chunks/dashboard-pages-table.json +86 -0
  258. package/corpus/chunks/dashboard-quick-actions.json +116 -0
  259. package/corpus/chunks/dashboard-reports-panel.json +166 -0
  260. package/corpus/chunks/dashboard-reports-table.json +138 -0
  261. package/corpus/chunks/dashboard-storage-card.json +117 -0
  262. package/corpus/chunks/dashboard-tabs.json +86 -0
  263. package/corpus/chunks/dashboard-team-actions-storage.json +605 -0
  264. package/corpus/chunks/dashboard-team-list.json +334 -0
  265. package/corpus/chunks/dashboard-traffic-channels.json +184 -0
  266. package/corpus/chunks/dashboard-transactions-table.json +145 -0
  267. package/corpus/chunks/data-export-history.json +192 -0
  268. package/corpus/chunks/data-export-request.json +197 -0
  269. package/corpus/chunks/data-import-wizard.json +391 -0
  270. package/corpus/chunks/date-range-picker.json +156 -0
  271. package/corpus/chunks/date-time-picker-form.json +222 -0
  272. package/corpus/chunks/departments-checkbox-form.json +390 -0
  273. package/corpus/chunks/destructive-confirm-modal.json +149 -0
  274. package/corpus/chunks/diff-inline.json +84 -0
  275. package/corpus/chunks/diff-side-by-side.json +131 -0
  276. package/corpus/chunks/diff-structured.json +216 -0
  277. package/corpus/chunks/digest-email-preview.json +374 -0
  278. package/corpus/chunks/divider-text-label.json +87 -0
  279. package/corpus/chunks/doc-editor-shell.json +356 -0
  280. package/corpus/chunks/drawer-2fa-key.json +273 -0
  281. package/corpus/chunks/drawer-2fa-sms.json +261 -0
  282. package/corpus/chunks/drawer-2fa-totp.json +385 -0
  283. package/corpus/chunks/drawer-cancel-sub.json +636 -0
  284. package/corpus/chunks/drawer-change-plan.json +561 -0
  285. package/corpus/chunks/drawer-custom-roles.json +696 -0
  286. package/corpus/chunks/drawer-data-start.json +171 -0
  287. package/corpus/chunks/drawer-delete-account.json +341 -0
  288. package/corpus/chunks/drawer-delete-workspace.json +362 -0
  289. package/corpus/chunks/drawer-discord.json +434 -0
  290. package/corpus/chunks/drawer-figma.json +401 -0
  291. package/corpus/chunks/drawer-first-dashboard.json +220 -0
  292. package/corpus/chunks/drawer-gcal.json +475 -0
  293. package/corpus/chunks/drawer-github.json +589 -0
  294. package/corpus/chunks/drawer-invite.json +397 -0
  295. package/corpus/chunks/drawer-record-detail.json +44 -0
  296. package/corpus/chunks/drawer-report.json +528 -0
  297. package/corpus/chunks/drawer-revoke-session.json +331 -0
  298. package/corpus/chunks/drawer-role.json +190 -0
  299. package/corpus/chunks/drawer-slack.json +429 -0
  300. package/corpus/chunks/drawer-smtp.json +476 -0
  301. package/corpus/chunks/drawer-source.json +294 -0
  302. package/corpus/chunks/drawer-transaction.json +493 -0
  303. package/corpus/chunks/drawer-with-create-form.json +43 -0
  304. package/corpus/chunks/editor-code-pane.json +204 -0
  305. package/corpus/chunks/editor-page-shell.json +149 -0
  306. package/corpus/chunks/editor-preview-pane.json +136 -0
  307. package/corpus/chunks/editor-statusbar-ready.json +99 -0
  308. package/corpus/chunks/editor-toolbar-import-export.json +195 -0
  309. package/corpus/chunks/email-inbox-list.json +678 -0
  310. package/corpus/chunks/empty-state-danger.json +58 -0
  311. package/corpus/chunks/empty-state-minimal.json +44 -0
  312. package/corpus/chunks/empty-state-warning.json +53 -0
  313. package/corpus/chunks/empty-state.json +65 -0
  314. package/corpus/chunks/error-404-actions.json +54 -0
  315. package/corpus/chunks/error-404.json +204 -0
  316. package/corpus/chunks/error-500-actions.json +61 -0
  317. package/corpus/chunks/error-500.json +220 -0
  318. package/corpus/chunks/error-maintenance-actions.json +53 -0
  319. package/corpus/chunks/error-maintenance.json +203 -0
  320. package/corpus/chunks/error-page-shell.json +132 -0
  321. package/corpus/chunks/export-flow-async.json +210 -0
  322. package/corpus/chunks/export-flow-delivery.json +163 -0
  323. package/corpus/chunks/export-flow-sync.json +162 -0
  324. package/corpus/chunks/extended-profile-form.json +512 -0
  325. package/corpus/chunks/faq-accordion.json +123 -0
  326. package/corpus/chunks/feature-grid-icons.json +314 -0
  327. package/corpus/chunks/feature-grid-three-cards.json +187 -0
  328. package/corpus/chunks/feature-toggle-switch-grid.json +213 -0
  329. package/corpus/chunks/file-upload-dnd.json +166 -0
  330. package/corpus/chunks/file-upload-field.json +97 -0
  331. package/corpus/chunks/file-upload-form.json +251 -0
  332. package/corpus/chunks/filter-bar-active-filters.json +176 -0
  333. package/corpus/chunks/filter-bar-filter-bar-with-table.json +113 -0
  334. package/corpus/chunks/filter-bar-saved-views.json +117 -0
  335. package/corpus/chunks/filter-popover-form.json +137 -0
  336. package/corpus/chunks/footer-multi-column.json +270 -0
  337. package/corpus/chunks/footer-primary-only.json +41 -0
  338. package/corpus/chunks/form-checkbox-group.json +65 -0
  339. package/corpus/chunks/form-drawer-edit-form.json +178 -0
  340. package/corpus/chunks/form-drawer-simple-form.json +151 -0
  341. package/corpus/chunks/form-drawer-tall-form.json +325 -0
  342. package/corpus/chunks/form-field-email-hint.json +53 -0
  343. package/corpus/chunks/form-field-range.json +54 -0
  344. package/corpus/chunks/form-field-required.json +52 -0
  345. package/corpus/chunks/form-field-select.json +66 -0
  346. package/corpus/chunks/form-field-textarea.json +51 -0
  347. package/corpus/chunks/form-field-with-error.json +151 -0
  348. package/corpus/chunks/form-fields-two-column.json +69 -0
  349. package/corpus/chunks/form-page-shell.json +146 -0
  350. package/corpus/chunks/form-switch-toggle.json +41 -0
  351. package/corpus/chunks/form-system-live-demo.json +123 -0
  352. package/corpus/chunks/forms-address-autocomplete.json +277 -0
  353. package/corpus/chunks/forms-address-fields.json +221 -0
  354. package/corpus/chunks/forms-conditional-reveal.json +195 -0
  355. package/corpus/chunks/gallery-page-shell.json +444 -0
  356. package/corpus/chunks/grid-2col-entry-cards.json +140 -0
  357. package/corpus/chunks/grid-kpi-4col.json +164 -0
  358. package/corpus/chunks/grid-responsive-kpi.json +165 -0
  359. package/corpus/chunks/hero-cta-simple.json +107 -0
  360. package/corpus/chunks/hero-cta-split.json +183 -0
  361. package/corpus/chunks/hero-section-split.json +111 -0
  362. package/corpus/chunks/icon-text-row.json +60 -0
  363. package/corpus/chunks/image-caption-tile.json +99 -0
  364. package/corpus/chunks/image-carousel.json +156 -0
  365. package/corpus/chunks/image-thumbnail-grid.json +77 -0
  366. package/corpus/chunks/image-upload-preview.json +118 -0
  367. package/corpus/chunks/import-mapping-flow.json +972 -0
  368. package/corpus/chunks/inline-dialog-rename.json +128 -0
  369. package/corpus/chunks/inline-dialog-schedule.json +154 -0
  370. package/corpus/chunks/inline-dialog-status.json +179 -0
  371. package/corpus/chunks/integrations-api-keys-card-list.json +475 -0
  372. package/corpus/chunks/integrations-connect-form.json +550 -0
  373. package/corpus/chunks/integrations-grid.json +141 -0
  374. package/corpus/chunks/integrations-webhooks-empty-state.json +66 -0
  375. package/corpus/chunks/inventory-list-stock.json +137 -0
  376. package/corpus/chunks/invite-members.json +153 -0
  377. package/corpus/chunks/invoice-line-items.json +493 -0
  378. package/corpus/chunks/kanban-board-3col.json +713 -0
  379. package/corpus/chunks/kanban-page-shell.json +671 -0
  380. package/corpus/chunks/key-value-detail-list.json +242 -0
  381. package/corpus/chunks/keyboard-shortcut-display.json +250 -0
  382. package/corpus/chunks/labeled-textarea.json +45 -0
  383. package/corpus/chunks/leaderboard-table.json +140 -0
  384. package/corpus/chunks/library-browser-search-filter.json +109 -0
  385. package/corpus/chunks/linked-record-row.json +61 -0
  386. package/corpus/chunks/loading-skeleton-placeholder.json +387 -0
  387. package/corpus/chunks/login-form-card.json +207 -0
  388. package/corpus/chunks/logo-cloud-trusted-by.json +235 -0
  389. package/corpus/chunks/map-with-location-list.json +293 -0
  390. package/corpus/chunks/marketing-hero-cta.json +102 -0
  391. package/corpus/chunks/marketing-page-shell.json +352 -0
  392. package/corpus/chunks/masonry-gallery.json +154 -0
  393. package/corpus/chunks/member-edit-drawer.json +236 -0
  394. package/corpus/chunks/members-active-table-search-filter.json +184 -0
  395. package/corpus/chunks/members-pending-invites-cards.json +251 -0
  396. package/corpus/chunks/members-roles-permissions-list.json +146 -0
  397. package/corpus/chunks/menu-context-actions.json +113 -0
  398. package/corpus/chunks/metadata-description-list.json +178 -0
  399. package/corpus/chunks/modal-create-project-form.json +133 -0
  400. package/corpus/chunks/modal-preferences-tabs.json +147 -0
  401. package/corpus/chunks/multi-field-form-validation.json +394 -0
  402. package/corpus/chunks/nav-menu-icons.json +74 -0
  403. package/corpus/chunks/newsletter-subscription.json +190 -0
  404. package/corpus/chunks/notification-badges-feed.json +411 -0
  405. package/corpus/chunks/notification-preferences-panel.json +238 -0
  406. package/corpus/chunks/onb-completion.json +139 -0
  407. package/corpus/chunks/onb-extension-install.json +172 -0
  408. package/corpus/chunks/onb-hero-welcome.json +156 -0
  409. package/corpus/chunks/onb-import-picker.json +86 -0
  410. package/corpus/chunks/onb-mobile-handoff.json +121 -0
  411. package/corpus/chunks/onb-notification-prefs.json +83 -0
  412. package/corpus/chunks/onb-persona-picker.json +82 -0
  413. package/corpus/chunks/onb-provider-tiles.json +137 -0
  414. package/corpus/chunks/onb-settings-review.json +257 -0
  415. package/corpus/chunks/onb-step-footer.json +121 -0
  416. package/corpus/chunks/onb-step-header.json +121 -0
  417. package/corpus/chunks/onb-step-progress.json +140 -0
  418. package/corpus/chunks/onb-step-shell.json +380 -0
  419. package/corpus/chunks/onb-story-pane.json +121 -0
  420. package/corpus/chunks/onb-tutorial-steps.json +193 -0
  421. package/corpus/chunks/order-confirmation-success-card.json +177 -0
  422. package/corpus/chunks/order-tracking-timeline.json +131 -0
  423. package/corpus/chunks/pagination-controls.json +82 -0
  424. package/corpus/chunks/pane-settings-sidebar.json +204 -0
  425. package/corpus/chunks/patient-visit-shell.json +191 -0
  426. package/corpus/chunks/payment-checkout-form.json +341 -0
  427. package/corpus/chunks/payment-method-form.json +328 -0
  428. package/corpus/chunks/period-comparison.json +236 -0
  429. package/corpus/chunks/permission-matrix-table.json +438 -0
  430. package/corpus/chunks/permissions-matrix-grid.json +111 -0
  431. package/corpus/chunks/permissions-matrix-summary.json +157 -0
  432. package/corpus/chunks/permissions-role-picker-radio.json +107 -0
  433. package/corpus/chunks/permissions-role-picker-select.json +101 -0
  434. package/corpus/chunks/permissions-share-link.json +256 -0
  435. package/corpus/chunks/permissions-share-people.json +297 -0
  436. package/corpus/chunks/permissions-sharing-scopes.json +109 -0
  437. package/corpus/chunks/plan-selection-form.json +529 -0
  438. package/corpus/chunks/playground-a2ui.json +181 -0
  439. package/corpus/chunks/playground-agent-admin.json +117 -0
  440. package/corpus/chunks/playground-agent-chat.json +126 -0
  441. package/corpus/chunks/playground-app-shell.json +488 -0
  442. package/corpus/chunks/playground-chat.json +265 -0
  443. package/corpus/chunks/playground-construct-canvas.json +118 -0
  444. package/corpus/chunks/playground-css-channel.json +487 -0
  445. package/corpus/chunks/playground-gen-ui.json +224 -0
  446. package/corpus/chunks/playground-render-preview.json +369 -0
  447. package/corpus/chunks/playground-streams-bridge.json +437 -0
  448. package/corpus/chunks/playground-table-toolbar.json +38 -0
  449. package/corpus/chunks/popover-with-content.json +118 -0
  450. package/corpus/chunks/pricing-tiers.json +561 -0
  451. package/corpus/chunks/product-tour.json +158 -0
  452. package/corpus/chunks/profile-public.json +297 -0
  453. package/corpus/chunks/progress-tracker-milestones.json +294 -0
  454. package/corpus/chunks/radio-button-group.json +83 -0
  455. package/corpus/chunks/rating-stars-review-summary.json +259 -0
  456. package/corpus/chunks/reactions-bar.json +75 -0
  457. package/corpus/chunks/reactions-picker.json +245 -0
  458. package/corpus/chunks/real-time-metrics-dashboard.json +344 -0
  459. package/corpus/chunks/record-detail-drawer-simple-detail.json +296 -0
  460. package/corpus/chunks/record-detail-drawer-tabbed-detail.json +443 -0
  461. package/corpus/chunks/referral-share-link.json +128 -0
  462. package/corpus/chunks/referral-status.json +243 -0
  463. package/corpus/chunks/reg-address-form.json +825 -0
  464. package/corpus/chunks/reg-billing-card.json +210 -0
  465. package/corpus/chunks/reg-brand-scrape.json +599 -0
  466. package/corpus/chunks/reg-departments-toggle.json +259 -0
  467. package/corpus/chunks/reg-extended-profile.json +356 -0
  468. package/corpus/chunks/reg-final-done.json +457 -0
  469. package/corpus/chunks/reg-helpdesk-grid.json +571 -0
  470. package/corpus/chunks/reg-import-picker.json +112 -0
  471. package/corpus/chunks/reg-integrations-grid.json +418 -0
  472. package/corpus/chunks/reg-invite-form.json +245 -0
  473. package/corpus/chunks/reg-legal-entity.json +260 -0
  474. package/corpus/chunks/reg-org-chart-review.json +891 -0
  475. package/corpus/chunks/reg-profile-identity.json +188 -0
  476. package/corpus/chunks/reg-step-footer.json +201 -0
  477. package/corpus/chunks/reg-step-header.json +201 -0
  478. package/corpus/chunks/reg-step-progress.json +236 -0
  479. package/corpus/chunks/reg-step-shell.json +605 -0
  480. package/corpus/chunks/reg-story-pane.json +201 -0
  481. package/corpus/chunks/reg-success-summary.json +257 -0
  482. package/corpus/chunks/reg-team-size.json +128 -0
  483. package/corpus/chunks/reg-usecase-picker.json +104 -0
  484. package/corpus/chunks/reg-workspace-name.json +159 -0
  485. package/corpus/chunks/responsive-grid-pattern.json +71 -0
  486. package/corpus/chunks/responsive-kpi-grid.json +166 -0
  487. package/corpus/chunks/responsive-row-pattern.json +71 -0
  488. package/corpus/chunks/responsive-shell-sidebar.json +308 -0
  489. package/corpus/chunks/responsive-wrap-at-pattern.json +124 -0
  490. package/corpus/chunks/retention-cohort-default-retention.json +80 -0
  491. package/corpus/chunks/retention-cohort-stat-pair.json +163 -0
  492. package/corpus/chunks/retention-cohort-with-legend.json +135 -0
  493. package/corpus/chunks/revenue-heatmap.json +82 -0
  494. package/corpus/chunks/role-management.json +272 -0
  495. package/corpus/chunks/row-action-cluster.json +54 -0
  496. package/corpus/chunks/row-avatar-name-role.json +71 -0
  497. package/corpus/chunks/row-icon-label.json +52 -0
  498. package/corpus/chunks/row-spread-label-value.json +54 -0
  499. package/corpus/chunks/row-wrap-tags.json +72 -0
  500. package/corpus/chunks/schedule-meeting-form-card.json +229 -0
  501. package/corpus/chunks/search-recents-menu.json +195 -0
  502. package/corpus/chunks/search-results-grouped.json +357 -0
  503. package/corpus/chunks/search-results-list.json +202 -0
  504. package/corpus/chunks/search-saved-views.json +356 -0
  505. package/corpus/chunks/search-with-filters.json +311 -0
  506. package/corpus/chunks/searchable-picker-modal.json +164 -0
  507. package/corpus/chunks/section-with-stack.json +48 -0
  508. package/corpus/chunks/security-active-sessions-devices.json +287 -0
  509. package/corpus/chunks/security-change-password-form.json +102 -0
  510. package/corpus/chunks/security-delete-account-danger.json +79 -0
  511. package/corpus/chunks/segmented-control-billing-tabs.json +164 -0
  512. package/corpus/chunks/select-multiple-preselected.json +70 -0
  513. package/corpus/chunks/settings-2fa-setup.json +307 -0
  514. package/corpus/chunks/settings-admin-page.json +1205 -0
  515. package/corpus/chunks/settings-appearance-primitives.json +145 -0
  516. package/corpus/chunks/settings-appearance-theme-panel.json +55 -0
  517. package/corpus/chunks/settings-appearance.json +81 -0
  518. package/corpus/chunks/settings-danger-zone-delete-workspace.json +93 -0
  519. package/corpus/chunks/settings-general-form.json +69 -0
  520. package/corpus/chunks/settings-integrations.json +298 -0
  521. package/corpus/chunks/settings-members-invite.json +112 -0
  522. package/corpus/chunks/settings-notification-activity-checkboxes.json +108 -0
  523. package/corpus/chunks/settings-notification-channels-switches.json +101 -0
  524. package/corpus/chunks/settings-page-shell.json +190 -0
  525. package/corpus/chunks/settings-privacy.json +83 -0
  526. package/corpus/chunks/settings-profile-security.json +122 -0
  527. package/corpus/chunks/settings-toggle-switches.json +66 -0
  528. package/corpus/chunks/sidebar-nav.json +120 -0
  529. package/corpus/chunks/sidebar-navigation-panel.json +165 -0
  530. package/corpus/chunks/signup-form-card.json +218 -0
  531. package/corpus/chunks/signup-team-size-form.json +259 -0
  532. package/corpus/chunks/single-select-card-form.json +231 -0
  533. package/corpus/chunks/slider-range-controls.json +119 -0
  534. package/corpus/chunks/social-media-post-card.json +159 -0
  535. package/corpus/chunks/sortable-list.json +307 -0
  536. package/corpus/chunks/sortable-search-paginate-table.json +162 -0
  537. package/corpus/chunks/split-pane-editor.json +146 -0
  538. package/corpus/chunks/stack-avatar-badge-overlay.json +53 -0
  539. package/corpus/chunks/stack-image-shimmer.json +51 -0
  540. package/corpus/chunks/stat-cards-kpi-dashboard.json +178 -0
  541. package/corpus/chunks/stats-band-big-numbers.json +175 -0
  542. package/corpus/chunks/status-dashboard.json +282 -0
  543. package/corpus/chunks/stepper-form-wizard.json +165 -0
  544. package/corpus/chunks/subscription-status-renewal-card.json +285 -0
  545. package/corpus/chunks/survey-rating-form.json +165 -0
  546. package/corpus/chunks/swiper-product-carousel.json +349 -0
  547. package/corpus/chunks/swiper-testimonial-carousel.json +279 -0
  548. package/corpus/chunks/table-empty-state.json +116 -0
  549. package/corpus/chunks/table-inline-edit-row.json +269 -0
  550. package/corpus/chunks/table-spreadsheet-cells.json +334 -0
  551. package/corpus/chunks/table-toolbar-no-search.json +42 -0
  552. package/corpus/chunks/table-toolbar-with-table.json +208 -0
  553. package/corpus/chunks/table-with-toolbar-card.json +80 -0
  554. package/corpus/chunks/tabs-with-panels.json +187 -0
  555. package/corpus/chunks/tag-chips-filter.json +100 -0
  556. package/corpus/chunks/team-invite-form.json +380 -0
  557. package/corpus/chunks/team-members-list.json +341 -0
  558. package/corpus/chunks/testimonial-grid.json +269 -0
  559. package/corpus/chunks/testimonial-pull-quote.json +137 -0
  560. package/corpus/chunks/testimonials-avatar-cards.json +286 -0
  561. package/corpus/chunks/timeline-events.json +89 -0
  562. package/corpus/chunks/timezone-selector-basic.json +99 -0
  563. package/corpus/chunks/timezone-selector-preview.json +104 -0
  564. package/corpus/chunks/toolbar-icons.json +216 -0
  565. package/corpus/chunks/toolbar-rich-text-editor.json +230 -0
  566. package/corpus/chunks/toolbar-tooltips.json +191 -0
  567. package/corpus/chunks/tooltip-hover-button.json +106 -0
  568. package/corpus/chunks/tree-file-explorer.json +136 -0
  569. package/corpus/chunks/tree-table-basic.json +171 -0
  570. package/corpus/chunks/trial-banner.json +158 -0
  571. package/corpus/chunks/url-import-form.json +728 -0
  572. package/corpus/chunks/usage-quota-meter-card.json +217 -0
  573. package/corpus/chunks/user-identity-row.json +81 -0
  574. package/corpus/chunks/user-onboarding-checklist.json +301 -0
  575. package/corpus/chunks/user-profile-card.json +192 -0
  576. package/corpus/chunks/users-table-badge.json +135 -0
  577. package/corpus/chunks/verification-document-upload.json +179 -0
  578. package/corpus/chunks/verification-status.json +97 -0
  579. package/corpus/chunks/verification-stepper.json +111 -0
  580. package/corpus/chunks/video-player-controls.json +120 -0
  581. package/corpus/chunks/webhook-config.json +209 -0
  582. package/corpus/chunks/webhooks-list.json +204 -0
  583. package/corpus/chunks/wizard-drawer-three-step-wizard.json +443 -0
  584. package/corpus/manifest.d.ts +4 -0
  585. package/corpus/manifest.json +6 -0
  586. package/corpus/scripts/chunk-library.d.ts +4 -0
  587. package/corpus/scripts/chunk-library.js +335 -0
  588. package/node-shims.d.ts +48 -0
  589. package/package.json +215 -0
  590. package/retrieval/CHANGELOG.md +1073 -0
  591. package/retrieval/README.md +71 -0
  592. package/retrieval/anti-patterns.js +189 -0
  593. package/retrieval/authoring/index.d.ts +4 -0
  594. package/retrieval/authoring/index.js +9 -0
  595. package/retrieval/authoring/web-research.js +220 -0
  596. package/retrieval/catalog.js +250 -0
  597. package/retrieval/component-catalog.js +168 -0
  598. package/retrieval/component-entry.js +80 -0
  599. package/retrieval/context-assembler.js +174 -0
  600. package/retrieval/domain-router.js +417 -0
  601. package/retrieval/embedding/chunk-embedding-retriever.js +117 -0
  602. package/retrieval/embedding/embedding-provider.js +72 -0
  603. package/retrieval/embedding/index.d.ts +4 -0
  604. package/retrieval/embedding/index.js +2 -0
  605. package/retrieval/feedback/dialog-recorder.js +107 -0
  606. package/retrieval/feedback/feedback-analyzer.js +180 -0
  607. package/retrieval/feedback/feedback-store.js +194 -0
  608. package/retrieval/feedback/feedback.js +117 -0
  609. package/retrieval/feedback/gap-registry.js +80 -0
  610. package/retrieval/feedback/human-signal.js +113 -0
  611. package/retrieval/feedback/index.d.ts +4 -0
  612. package/retrieval/feedback/index.js +24 -0
  613. package/retrieval/feedback/submit-feedback.js +45 -0
  614. package/retrieval/index.d.ts +4 -0
  615. package/retrieval/index.js +53 -0
  616. package/retrieval/intent/clarity.js +139 -0
  617. package/retrieval/intent/decomposer.js +124 -0
  618. package/retrieval/intent/index.d.ts +4 -0
  619. package/retrieval/intent/index.js +18 -0
  620. package/retrieval/intent/intent-alignment.js +172 -0
  621. package/retrieval/intent/intent-categorizer.js +69 -0
  622. package/retrieval/intent/intent-gate.js +96 -0
  623. package/retrieval/intent/prompt-analyzer.js +162 -0
  624. package/retrieval/wiring-catalog.js +168 -0
  625. package/validate/catalog-validator.d.ts +4 -0
  626. package/validate/catalog-validator.js +327 -0
  627. package/validate/semantic/cache.js +54 -0
  628. package/validate/semantic/classify-intent.js +128 -0
  629. package/validate/semantic/index.js +163 -0
  630. package/validate/semantic/intent-specs.js +162 -0
  631. package/validate/semantic/judge.js +180 -0
@@ -0,0 +1,675 @@
1
+ /**
2
+ * Transpiler Maps — Static tag mapping tables and attribute extractors
3
+ * for the HTML → A2UI transpiler.
4
+ *
5
+ * Three mapping layers:
6
+ * 1. Reverse A2UI registry (tag → type, for *-n elements)
7
+ * 2. HTML tag map (native HTML → A2UI type)
8
+ * 3. Input type / ARIA role sub-maps
9
+ *
10
+ * §163 (v0.5.4) — Prop-fidelity fix: extractProps() now runs a
11
+ * catalog-driven generic pass AFTER the legacy per-type blocks. The
12
+ * catalog (`@adia-ai/gen-ui/corpus`'s v0.9 sidecars) is the single source
13
+ * of truth for which attributes are first-class props per component
14
+ * type. Pre-§163, the per-type blocks hardcoded an allowlist that
15
+ * omitted `label`, `icon`, literal `variant=`, and similar — see
16
+ * `.brain/postmortems/2026-05-14-lossy-transpiler-boundary.md`.
17
+ * The catalog-driven pass closes the drift class: when a new prop is
18
+ * added to the catalog (regenerated from `<name>.yaml`), the extractor
19
+ * picks it up automatically without manual sync.
20
+ */
21
+
22
+ import catalogData from '../../corpus/catalog-a2ui_0_9.json' with { type: 'json' };
23
+
24
+ import { registry } from '@adia-ai/a2ui';
25
+
26
+ // ── §163 Catalog-driven prop schema ──────────────────────────────────────
27
+ //
28
+ // Build CATALOG_PROPS at module-init by reading the v0.9 catalog. Each
29
+ // component's `properties` block declares its first-class props with
30
+ // type hints (string / boolean / number / enum). The transpiler uses
31
+ // this map to extract any prop the catalog declares, closing the
32
+ // pre-§163 drift class where the per-type allowlists (lines ~155-249
33
+ // below) omitted `label`, `icon`, literal `variant=`, etc.
34
+ //
35
+ // Aliasing: the runtime registry maps multiple A2UI type names to the
36
+ // same tag (e.g. CheckBox → check-ui, Toggle → switch-ui, Select →
37
+ // select-ui = ChoicePicker). The catalog is keyed by ONE canonical
38
+ // name per tag (e.g. `Check`, `Switch`, `ChoicePicker`). We build an
39
+ // alias map below so `extractProps(el, 'CheckBox')` resolves to the
40
+ // `Check` catalog entry.
41
+
42
+ // TKT-0010: dynamic props are compiled to a bare `$ref` (DynamicString /
43
+ // DynamicNumber / DynamicBoolean / DynamicStringList / DynamicObjectList),
44
+ // which carries no inline `type` — so `pdef.type || 'string'` below silently
45
+ // treated EVERY dynamic array prop (Chart.data, Table.data) as a string,
46
+ // copying the raw `data='[...]'` attribute text through unparsed instead of
47
+ // JSON-parsing it into a real array. Resolve the ref name to its primitive
48
+ // kind first so extractCatalogProps' array branch actually fires.
49
+ const REF_TYPE_MAP = {
50
+ DynamicString: 'string',
51
+ DynamicNumber: 'number',
52
+ DynamicBoolean: 'boolean',
53
+ DynamicStringList: 'array',
54
+ DynamicObjectList: 'array',
55
+ };
56
+
57
+ /** @type {Map<string, {props: Map<string, {type: string, enum?: string[]}>, canonical: string}>} */
58
+ const CATALOG_PROPS = (() => {
59
+ const map = new Map();
60
+ const components = catalogData?.components || {};
61
+ for (const [name, def] of Object.entries(components)) {
62
+ const props = def?.properties || {};
63
+ const propMap = new Map();
64
+ for (const [pname, pdef] of Object.entries(props)) {
65
+ // Skip internal/computed props that aren't HTML attributes
66
+ if (pname === 'component' || pname === 'textContent') continue;
67
+ if (typeof pdef !== 'object' || !pdef) continue;
68
+ let type = pdef.type;
69
+ if (!type && typeof pdef.$ref === 'string') {
70
+ const refName = pdef.$ref.split('/').pop();
71
+ type = REF_TYPE_MAP[refName];
72
+ }
73
+ propMap.set(pname, {
74
+ type: type || 'string',
75
+ enum: pdef.enum || null,
76
+ });
77
+ }
78
+ map.set(name, { props: propMap, canonical: name });
79
+ }
80
+ return map;
81
+ })();
82
+
83
+ /**
84
+ * Map an A2UI type name (which may be an alias used by the runtime
85
+ * registry but not the catalog) to the canonical catalog name.
86
+ *
87
+ * Examples (driven by runtime/registry.js mappings):
88
+ * CheckBox → Check (registry: CheckBox→check-ui; catalog: Check)
89
+ * Toggle → Switch (registry: Toggle→switch-ui; catalog: Switch)
90
+ * Select → ChoicePicker (registry: Select→select-ui; catalog: ChoicePicker)
91
+ *
92
+ * Strategy: for every registry alias type, find the catalog entry whose
93
+ * tag (= kebab-cased catalog name + '-ui', or registry forward-lookup)
94
+ * matches the alias's runtime tag. The catalog often uses a name that
95
+ * is NOT in the registry as a forward entry (e.g. `Check` is in the
96
+ * catalog but the registry only has `CheckBox → check-ui`).
97
+ *
98
+ * Cached at module-init.
99
+ */
100
+ const TYPE_ALIAS = (() => {
101
+ const m = new Map();
102
+ // Pre-pass: every catalog name maps to itself (catalog names ARE valid A2UI types
103
+ // even when the runtime registry doesn't carry them as forward entries — e.g.
104
+ // `Check` is in catalog but registry only has `CheckBox → check-ui`).
105
+ for (const catName of CATALOG_PROPS.keys()) {
106
+ m.set(catName, catName);
107
+ }
108
+ // First pass: direct match (typeName IS the catalog canonical)
109
+ for (const typeName of registry.keys()) {
110
+ if (CATALOG_PROPS.has(typeName)) {
111
+ m.set(typeName, typeName);
112
+ }
113
+ }
114
+ // Second pass: type's tag matches another registry entry that's in the catalog
115
+ for (const [typeName, tagName] of registry.entries()) {
116
+ if (m.has(typeName)) continue;
117
+ for (const [otherType, otherTag] of registry.entries()) {
118
+ if (otherTag === tagName && CATALOG_PROPS.has(otherType)) {
119
+ m.set(typeName, otherType);
120
+ break;
121
+ }
122
+ }
123
+ }
124
+ // Third pass: derive canonical from tag — `check-ui` → `Check`,
125
+ // `switch-ui` → `Switch`. The catalog often has the canonical
126
+ // PascalCase that the registry doesn't list as a forward entry.
127
+ // We convert tag kebab → PascalCase and check the catalog.
128
+ for (const [typeName, tagName] of registry.entries()) {
129
+ if (m.has(typeName)) continue;
130
+ // 'check-ui' → 'Check'; 'switch-ui' → 'Switch'; 'list-item-ui' → 'ListItem'
131
+ const stripped = tagName.replace(/-ui$/, '');
132
+ const pascal = stripped.split('-').map(s => s[0]?.toUpperCase() + s.slice(1)).join('');
133
+ if (CATALOG_PROPS.has(pascal)) {
134
+ m.set(typeName, pascal);
135
+ }
136
+ }
137
+ return m;
138
+ })();
139
+
140
+ /**
141
+ * §163 generic extractor: pull every catalog-declared prop from the
142
+ * element's attributes. Type-aware (booleans become true on presence,
143
+ * numbers parse, enums validate optimistically).
144
+ *
145
+ * Runs AFTER the legacy per-type blocks below — so type-specific
146
+ * extraction (e.g. Button.text from textContent, Image.alt) wins on
147
+ * conflict. The generic pass FILLS IN props the legacy blocks miss
148
+ * (the prop-fidelity gap this fix closes).
149
+ *
150
+ * @param {object} el — DOM element or MinimalElement
151
+ * @param {string} a2uiType — Resolved A2UI type name (may be alias)
152
+ * @returns {Record<string, unknown>}
153
+ */
154
+ function extractCatalogProps(el, a2uiType) {
155
+ const canonical = TYPE_ALIAS.get(a2uiType);
156
+ if (!canonical) return {};
157
+ const schema = CATALOG_PROPS.get(canonical);
158
+ if (!schema) return {};
159
+ const attr = (name) => el.getAttribute?.(name) ?? el.attributes?.get?.(name) ?? null;
160
+ const props = {};
161
+ for (const [pname, pdef] of schema.props.entries()) {
162
+ // gh#853: camelCase catalog prop names (e.g. `channelEnabled`,
163
+ // `hrefPattern`) are authored as kebab-case HTML attributes per the
164
+ // yaml's own `attribute:` override — but that override isn't preserved
165
+ // into the generated catalog (catalog-a2ui_0_9.json keys stay
166
+ // camelCase), and HTML attribute names are always lowercased on parse
167
+ // (`channelenabled` !== `channelEnabled`), so the direct lookup below
168
+ // silently missed every one of them. Fall back to the kebab-cased form.
169
+ const kebab = pname.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
170
+ const raw = attr(pname) ?? (kebab !== pname ? attr(kebab) : null);
171
+ if (raw === null || raw === undefined) continue;
172
+
173
+ if (pdef.type === 'boolean') {
174
+ // HTML boolean attr convention: presence (incl. empty string) = true.
175
+ // <input required> → raw === '' → true
176
+ // <input required=""> → raw === '' → true
177
+ // <input required="required"> → raw === 'required' → true
178
+ // <input required="false"> → raw === 'false' → false (defensive)
179
+ props[pname] = raw !== 'false';
180
+ } else if (pdef.type === 'number' || pdef.type === 'integer') {
181
+ if (raw === '') continue;
182
+ const n = Number(raw);
183
+ props[pname] = Number.isFinite(n) ? n : raw;
184
+ } else if (pdef.type === 'array') {
185
+ // TKT-0010: declarative JSON-array attribute (e.g. chart-ui/table-ui's
186
+ // data='[{...}]'), hydrated once at connect per those components' own
187
+ // yaml docs. Parse it — the raw string never satisfies the catalog's
188
+ // array schema, and per chart.yaml's own contract a non-array value
189
+ // is meant to render empty, so a parse failure/non-array is skipped,
190
+ // not passed through.
191
+ if (raw === '') continue;
192
+ try {
193
+ const parsed = JSON.parse(raw);
194
+ if (Array.isArray(parsed)) props[pname] = parsed;
195
+ } catch { /* not valid JSON — skip */ }
196
+ } else if (pdef.type === 'object') {
197
+ // gh#853 sibling of the array branch above: object-typed props (e.g.
198
+ // InvoiceDetail.invoice, NotificationPreferences.channelEnabled) are
199
+ // JSON-encoded HTML attributes too — same declarative-data convention,
200
+ // just a plain object instead of an array.
201
+ if (raw === '') continue;
202
+ try {
203
+ const parsed = JSON.parse(raw);
204
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) props[pname] = parsed;
205
+ } catch { /* not valid JSON — skip */ }
206
+ } else {
207
+ // string (incl. enum) — skip empty
208
+ if (raw === '') continue;
209
+ props[pname] = raw;
210
+ }
211
+ }
212
+ return props;
213
+ }
214
+
215
+ // ── Alias types to skip in reverse registry (prefer primary type) ────────
216
+
217
+ const ALIAS_TYPES = new Set([
218
+ 'Select', 'LoadingIndicator', 'ErrorContainer', 'Keyboard',
219
+ 'DatePicker', 'CommandPalette', 'Segmented', 'OTP', 'SideNav', 'IconSource',
220
+ ]);
221
+
222
+ // ── Reverse Registry: tag → primary A2UI type ────────────────────────────
223
+
224
+ /** @type {Map<string, string>} */
225
+ export const reverseRegistry = new Map();
226
+
227
+ for (const [type, tag] of registry) {
228
+ if (ALIAS_TYPES.has(type)) continue;
229
+ // First-write wins — skip if tag already mapped (avoids alias overwrite)
230
+ if (!reverseRegistry.has(tag)) {
231
+ reverseRegistry.set(tag, type);
232
+ }
233
+ }
234
+
235
+ // ── HTML Tag → A2UI Type ─────────────────────────────────────────────────
236
+
237
+ /** @type {Record<string, { type: string, props?: Record<string, unknown> }>} */
238
+ export const HTML_TAG_MAP = {
239
+ // §210 (v0.5.7, FEEDBACK-17 §1): map native heading levels to working
240
+ // text-ui variants. Pre-§210 these mapped to `h1`-`h6` strings that
241
+ // text.css had no `:scope[variant=…]` rule for — silent body-default
242
+ // rendering. The retired variants (`h1`-`h6` + `subheading`) were
243
+ // removed from text.yaml/text.d.ts/text.a2ui.json in §210 because no
244
+ // matching tokens shipped. Replacement mapping prefers role tokens
245
+ // that actually render:
246
+ // <h1> → 'display' (largest type — marketing hero)
247
+ // <h2> → 'title' (page title)
248
+ // <h3> → 'heading' (section division)
249
+ // <h4> → 'subsection' (sub-grouping inside a heading section)
250
+ // <h5>, <h6> → 'subsection' (no smaller subsection token ships;
251
+ // consistent fallback over silent
252
+ // body-default)
253
+ h1: { type: 'Text', props: { variant: 'display' } },
254
+ h2: { type: 'Text', props: { variant: 'title' } },
255
+ h3: { type: 'Text', props: { variant: 'heading' } },
256
+ h4: { type: 'Text', props: { variant: 'subsection' } },
257
+ h5: { type: 'Text', props: { variant: 'subsection' } },
258
+ h6: { type: 'Text', props: { variant: 'subsection' } },
259
+ p: { type: 'Text', props: { variant: 'body' } },
260
+ small: { type: 'Text', props: { variant: 'caption' } },
261
+ strong: { type: 'Text', props: { variant: 'body' } },
262
+ em: { type: 'Text', props: { variant: 'body' } },
263
+ blockquote: { type: 'Text', props: { variant: 'body' } },
264
+ code: { type: 'Code' },
265
+ pre: { type: 'Code' },
266
+ kbd: { type: 'Kbd' },
267
+ button: { type: 'Button' },
268
+ select: { type: 'ChoicePicker' },
269
+ textarea: { type: 'TextArea' },
270
+ form: { type: 'FormContainer' },
271
+ img: { type: 'Image' },
272
+ video: { type: 'Embed' },
273
+ iframe: { type: 'Embed' },
274
+ audio: { type: 'Embed' },
275
+ table: { type: 'Table' },
276
+ ul: { type: 'List' },
277
+ ol: { type: 'List' },
278
+ li: { type: 'Text', props: { variant: 'body' } },
279
+ // gh#848 — description lists. `<dl>` IS description-list-ui (it renders a
280
+ // native dl), and its documented children are native `<dt>`/`<dd>`
281
+ // (description-list.yaml slots: "Consumer passes <dt>/<dd> children
282
+ // inline"). Without these three the pair fell to the Unknown fallback and
283
+ // the term/detail grid collapsed into nested containers.
284
+ dl: { type: 'DescriptionList' },
285
+ dt: { type: 'DescriptionTerm' },
286
+ dd: { type: 'DescriptionDetail' },
287
+ // gh#853 — `<figure>` is a self-contained content unit (image + caption),
288
+ // the same "self-contained block" semantic already given to `<article>`
289
+ // (→ Card). `<figcaption>` is the annotation UNDER that unit — text.yaml's
290
+ // own `caption` variant docstring names this exact use case ("Annotation
291
+ // under a primary line … Use for image captions, footnotes."), so it maps
292
+ // there rather than falling to the generic `body` variant every other
293
+ // untyped inline tag gets.
294
+ figure: { type: 'Card' },
295
+ figcaption: { type: 'Text', props: { variant: 'caption' } },
296
+ // gh#853 — `<s>` (strikethrough) has no dedicated A2UI decoration prop
297
+ // (text.yaml carries no strike/decoration prop today — a platform gap
298
+ // beyond this tag-mapping fix). Until one exists, treat it as the phrasing
299
+ // content it is, same as the `strong`/`em`/`blockquote` mappings above.
300
+ s: { type: 'Text', props: { variant: 'body' } },
301
+ nav: { type: 'Nav' },
302
+ aside: { type: 'Sidebar' },
303
+ main: { type: 'Column' },
304
+ article: { type: 'Card' },
305
+ details: { type: 'Accordion' },
306
+ summary: { type: 'Text', props: { variant: 'subsection' } },
307
+ dialog: { type: 'Modal' },
308
+ hr: { type: 'Divider' },
309
+ a: { type: 'Link' }, // §47 — was: Button + variant=ghost (button.yaml line 60: "for inline navigation use `<link-ui>` instead")
310
+ header: { type: 'Header' },
311
+ footer: { type: 'Footer' },
312
+ section: { type: 'Section' },
313
+ label: { type: 'Text', props: { variant: 'body' } },
314
+ span: { type: 'Text', props: { variant: 'body' } },
315
+ };
316
+
317
+ // ── Input Type Sub-Map ───────────────────────────────────────────────────
318
+
319
+ /** @type {Record<string, { type: string, props?: Record<string, unknown> }>} */
320
+ export const INPUT_TYPE_MAP = {
321
+ text: { type: 'TextField' },
322
+ email: { type: 'TextField', props: { type: 'email' } },
323
+ password: { type: 'TextField', props: { type: 'password' } },
324
+ number: { type: 'TextField', props: { type: 'number' } },
325
+ tel: { type: 'TextField', props: { type: 'tel' } },
326
+ url: { type: 'TextField', props: { type: 'url' } },
327
+ search: { type: 'Search' },
328
+ checkbox: { type: 'CheckBox' },
329
+ radio: { type: 'Radio' },
330
+ range: { type: 'Slider' },
331
+ date: { type: 'DateTimeInput' },
332
+ time: { type: 'DateTimeInput' },
333
+ 'datetime-local': { type: 'DateTimeInput' },
334
+ file: { type: 'Upload' },
335
+ color: { type: 'ColorPicker' },
336
+ submit: { type: 'Button', props: { variant: 'primary', type: 'submit' } },
337
+ reset: { type: 'Button', props: { variant: 'outline', type: 'reset' } },
338
+ };
339
+
340
+ // ── ARIA Role Map ────────────────────────────────────────────────────────
341
+
342
+ /** @type {Record<string, string>} */
343
+ export const ARIA_ROLE_MAP = {
344
+ tablist: 'Tabs',
345
+ tab: 'Tab',
346
+ tabpanel: 'Panel',
347
+ alert: 'Alert',
348
+ alertdialog: 'Dialog',
349
+ dialog: 'Modal',
350
+ navigation: 'Nav',
351
+ progressbar: 'Progress',
352
+ slider: 'Slider',
353
+ switch: 'Toggle',
354
+ menu: 'Menu',
355
+ menubar: 'Menu',
356
+ toolbar: 'Toolbar',
357
+ tooltip: 'Tooltip',
358
+ search: 'Search',
359
+ banner: 'Header',
360
+ contentinfo: 'Footer',
361
+ complementary: 'Sidebar',
362
+ };
363
+
364
+ // ── Skip Tags ────────────────────────────────────────────────────────────
365
+
366
+ export const SKIP_TAGS = new Set([
367
+ 'script', 'style', 'link', 'meta', 'head', 'br', 'wbr',
368
+ 'noscript', 'template', 'slot', 'svg', 'path', 'circle',
369
+ 'rect', 'line', 'polyline', 'polygon', 'g', 'defs', 'use',
370
+ ]);
371
+
372
+ // ── Attribute Extractors ─────────────────────────────────────────────────
373
+
374
+ /**
375
+ * Extract A2UI props from an HTML element based on the resolved A2UI type.
376
+ *
377
+ * @param {object} el — DOM element or MinimalElement
378
+ * @param {string} a2uiType — Resolved A2UI type name
379
+ * @returns {Record<string, unknown>}
380
+ */
381
+ export function extractProps(el, a2uiType) {
382
+ const props = {};
383
+ const attr = (name) => el.getAttribute?.(name) ?? el.attributes?.get?.(name) ?? null;
384
+
385
+ // Universal: preserve [slot] for every element. Slot is a layout-bearing
386
+ // HTML attribute that card-ui / drawer-ui / etc. depend on via :has(> [slot])
387
+ // grid activation. Yamls don't declare slot as a prop (it's an HTML standard
388
+ // attribute, not a component prop), so the catalog pass below won't pick it up.
389
+ const slotAttr = attr('slot');
390
+ if (slotAttr) props.slot = slotAttr;
391
+
392
+ // Universal: preserve [span] for every element. Span is a layout-bearing
393
+ // attribute grid-ui's child reads via a pure CSS attribute selector
394
+ // (grid.css: `& > [span="3"] { grid-column: span 3; }`) — it belongs to
395
+ // "whatever this grid child happens to be," never to a specific
396
+ // component's own prop schema, so no .yaml declares it and the
397
+ // catalog-driven pass below silently drops it (TKT-0002: collapsed the
398
+ // admin-dashboard Overview/Recent Sales 3:2 split to two equal, unspanned
399
+ // columns).
400
+ const spanAttr = attr('span');
401
+ if (spanAttr) props.span = spanAttr;
402
+
403
+ // §163 (v0.5.4) — Catalog-driven generic extraction FIRST. Fills in
404
+ // every prop the v0.9 catalog declares for this type (label, icon,
405
+ // variant=, etc.). Legacy per-type blocks below run AFTER and can
406
+ // overwrite specific values (e.g. Button.text inferred from
407
+ // textContent when no `text=` attribute is set).
408
+ Object.assign(props, extractCatalogProps(el, a2uiType));
409
+
410
+ // ── Text content (for leaf elements) ──
411
+ if (['Text', 'Kbd', 'Code'].includes(a2uiType)) {
412
+ const text = (el.textContent || '').trim().replace(/\s+/g, ' ');
413
+ if (text) props.textContent = text;
414
+ }
415
+
416
+ // ── Button ──
417
+ if (a2uiType === 'Button') {
418
+ if (props.text === undefined) {
419
+ const text = (el.textContent || '').trim().replace(/\s+/g, ' ');
420
+ if (text) props.text = text;
421
+ }
422
+ if (props.type === undefined) {
423
+ const type = attr('type');
424
+ if (type && type !== 'button') props.type = type;
425
+ }
426
+ if (props.disabled === undefined && attr('disabled') !== null) props.disabled = true;
427
+ // Variant inference from class (only if generic pass didn't already extract literal `variant=` attr)
428
+ if (props.variant === undefined) {
429
+ const cls = attr('class') || '';
430
+ if (cls.includes('primary')) props.variant = 'primary';
431
+ else if (cls.includes('danger')) props.variant = 'danger';
432
+ else if (cls.includes('ghost')) props.variant = 'ghost';
433
+ else if (cls.includes('outline')) props.variant = 'outline';
434
+ }
435
+ }
436
+
437
+ // ── Tag ── (TKT-0004: tag-ui renders its label via CSS attr(text) —
438
+ // tag.yaml documents textContent as routing to the text attribute. The
439
+ // authored form is light-DOM content (<tag-ui size="sm">label</tag-ui>),
440
+ // so fall back to textContent when no text= attribute is set.)
441
+ if (a2uiType === 'Tag' && props.text === undefined) {
442
+ const text = (el.textContent || '').trim().replace(/\s+/g, ' ');
443
+ if (text) props.text = text;
444
+ }
445
+
446
+ // ── Link ── (§47 — <a> tags map to Link, not Button; carries href, target, rel)
447
+ if (a2uiType === 'Link') {
448
+ const text = (el.textContent || '').trim().replace(/\s+/g, ' ');
449
+ if (text) props.text = text;
450
+ const href = attr('href');
451
+ if (href) props.href = href;
452
+ const target = attr('target');
453
+ if (target) props.target = target;
454
+ const rel = attr('rel');
455
+ if (rel) props.rel = rel;
456
+ }
457
+
458
+ // ── TextField / Input ──
459
+ if (['TextField', 'Search'].includes(a2uiType)) {
460
+ for (const name of ['placeholder', 'name', 'value', 'pattern', 'min', 'max', 'minlength', 'maxlength', 'autocomplete']) {
461
+ const v = attr(name);
462
+ if (v !== null && v !== '') props[name] = v;
463
+ }
464
+ if (attr('required') !== null) props.required = true;
465
+ if (attr('disabled') !== null) props.disabled = true;
466
+ if (attr('readonly') !== null) props.readonly = true;
467
+ const type = attr('type');
468
+ if (type && type !== 'text') props.type = type;
469
+ }
470
+
471
+ // ── CheckBox / Toggle / Radio ──
472
+ if (['CheckBox', 'Toggle', 'Radio'].includes(a2uiType)) {
473
+ const name = attr('name');
474
+ if (name) props.name = name;
475
+ const value = attr('value');
476
+ if (value) props.value = value;
477
+ if (attr('checked') !== null) props.checked = true;
478
+ if (attr('disabled') !== null) props.disabled = true;
479
+ if (attr('required') !== null) props.required = true;
480
+ }
481
+
482
+ // ── Slider ──
483
+ if (a2uiType === 'Slider') {
484
+ for (const name of ['min', 'max', 'value', 'step', 'name']) {
485
+ if (props[name] !== undefined) continue; // catalog pass already filled this
486
+ const v = attr(name);
487
+ if (v !== null && v !== '') props[name] = name === 'step' ? v : Number(v) || v;
488
+ }
489
+ if (props.disabled === undefined && attr('disabled') !== null) props.disabled = true;
490
+ }
491
+
492
+ // ── Image ──
493
+ if (a2uiType === 'Image') {
494
+ const src = attr('src');
495
+ if (src) props.src = src;
496
+ const alt = attr('alt');
497
+ if (alt) props.alt = alt;
498
+ }
499
+
500
+ // ── TextArea ──
501
+ if (a2uiType === 'TextArea') {
502
+ for (const name of ['placeholder', 'name', 'rows', 'cols', 'minlength', 'maxlength']) {
503
+ const v = attr(name);
504
+ if (v !== null && v !== '') props[name] = v;
505
+ }
506
+ if (attr('required') !== null) props.required = true;
507
+ if (attr('disabled') !== null) props.disabled = true;
508
+ const text = (el.textContent || '').trim();
509
+ if (text) props.value = text;
510
+ }
511
+
512
+ // ── Embed ──
513
+ if (a2uiType === 'Embed') {
514
+ const src = attr('src');
515
+ if (src) props.src = src;
516
+ }
517
+
518
+ // ── Layout (Column, Row, Grid) ──
519
+ if (['Column', 'Row', 'Grid', 'List'].includes(a2uiType)) {
520
+ const gap = attr('gap');
521
+ if (gap) props.gap = gap;
522
+ }
523
+
524
+ // ── Label extraction from adjacent <label> or aria-label ──
525
+ if (['TextField', 'CheckBox', 'Toggle', 'Radio', 'Slider', 'Search', 'TextArea', 'ChoicePicker', 'DateTimeInput'].includes(a2uiType)) {
526
+ const ariaLabel = attr('aria-label');
527
+ if (ariaLabel) props.label = ariaLabel;
528
+ }
529
+
530
+ // ── ChoicePicker / Select, Combobox, Command — build the options[]
531
+ // model from declarative <option> / <optgroup> children (FB-79;
532
+ // extended to Combobox per gh#860, to Command per gh#887).
533
+ // <select-ui>/<combobox-ui>/<command-ui> render natively from
534
+ // `el.options = [{value, label, disabled?}]` (select.yaml /
535
+ // combobox.yaml / command.yaml `options`), so the options must
536
+ // travel as a PROP. Without this, the tree walker emits each
537
+ // <option> as a Text child, which the component rejects (renders
538
+ // empty + "ignoring unrecognized child element" warning).
539
+ // command.yaml's option model additionally carries data-icon/
540
+ // data-shortcut per <option> — extractSelectOptions captures those
541
+ // only for Command (withIcons) so ChoicePicker/Combobox's model
542
+ // stays exactly {value, label, disabled?} (no unused fields).
543
+ if (a2uiType === 'ChoicePicker' || a2uiType === 'Combobox' || a2uiType === 'Command') {
544
+ const options = extractSelectOptions(el, { withIcons: a2uiType === 'Command' });
545
+ if (options.length) {
546
+ props.options = options;
547
+ }
548
+ // Mirror <option selected> into the value when not set via attr,
549
+ // matching select-ui/combobox-ui #parseOptions. Command has no
550
+ // `value` prop (command.yaml declares only open/placeholder) — no
551
+ // value to mirror there.
552
+ if (a2uiType !== 'Command' && (props.value === undefined || props.value === '')) {
553
+ const selected = collectSelectedOptionValues(el);
554
+ if (selected.length) {
555
+ // gh#887 adjacent finding: combobox-ui is single-select —
556
+ // first-selected-wins, matching its own #parseOptions (which
557
+ // only sets `preSelected` from the FIRST `<option selected>` it
558
+ // sees). select-ui's [multiple] mode is the one that legitimately
559
+ // comma-joins several selected values.
560
+ props.value = a2uiType === 'Combobox' ? selected[0] : selected.join(',');
561
+ }
562
+ }
563
+ }
564
+
565
+ // ── Data attributes pass-through ──
566
+ if (el.attributes) {
567
+ const attrs = el.attributes instanceof Map ? el.attributes : el.attributes;
568
+ if (typeof attrs[Symbol.iterator] === 'function') {
569
+ for (const a of attrs) {
570
+ const name = a.name || a[0];
571
+ const value = a.value || a[1];
572
+ if (name?.startsWith('data-') && name !== 'data-a2ui-id') {
573
+ props[name] = value;
574
+ }
575
+ }
576
+ }
577
+ }
578
+
579
+ return props;
580
+ }
581
+
582
+ // ── Select option model (FB-79) ──────────────────────────────────────────
583
+
584
+ /**
585
+ * Build the <select-ui> / <combobox-ui> / <command-ui> options[] model
586
+ * from an element's declarative <option> / <optgroup> children. Mirrors
587
+ * select-ui #parseOptions:
588
+ * <option value disabled>Label</option> → { value, label, disabled? }
589
+ * <optgroup label>…</optgroup> → { label, options: [...] }
590
+ *
591
+ * @param {object} el — DOM element or MinimalElement
592
+ * @param {{withIcons?: boolean}} [opts] — withIcons: also capture
593
+ * data-icon/data-shortcut per <option> (command.yaml's option model,
594
+ * gh#887) — select/combobox's model has no such fields.
595
+ * @returns {Array<object>}
596
+ */
597
+ function extractSelectOptions(el, { withIcons = false } = {}) {
598
+ const out = [];
599
+ for (const child of (el.children || [])) {
600
+ const ctag = (child.tagName || '').toLowerCase();
601
+ if (ctag === 'option') {
602
+ out.push(optionToModel(child, { withIcons }));
603
+ } else if (ctag === 'optgroup') {
604
+ const label = optionAttr(child, 'label') || '';
605
+ const groupOptions = [];
606
+ for (const opt of (child.children || [])) {
607
+ if ((opt.tagName || '').toLowerCase() === 'option') groupOptions.push(optionToModel(opt, { withIcons }));
608
+ }
609
+ out.push({ label, options: groupOptions });
610
+ }
611
+ }
612
+ return out;
613
+ }
614
+
615
+ /**
616
+ * @param {object} opt
617
+ * @param {{withIcons?: boolean}} [modelOpts]
618
+ * @returns {{value: string, label: string, disabled?: boolean, icon?: string, shortcut?: string}}
619
+ */
620
+ function optionToModel(opt, { withIcons = false } = {}) {
621
+ const value = optionAttr(opt, 'value');
622
+ const label = (opt.textContent || '').trim().replace(/\s+/g, ' ');
623
+ const model = { value: value != null ? value : label, label };
624
+ if (optionAttr(opt, 'disabled') !== null) model.disabled = true;
625
+ if (withIcons) {
626
+ const icon = optionAttr(opt, 'data-icon');
627
+ const shortcut = optionAttr(opt, 'data-shortcut');
628
+ if (icon) model.icon = icon;
629
+ if (shortcut) model.shortcut = shortcut;
630
+ }
631
+ return model;
632
+ }
633
+
634
+ /** Collect values of <option selected> children (recursing <optgroup>). */
635
+ function collectSelectedOptionValues(el) {
636
+ const values = [];
637
+ const walk = (nodes) => {
638
+ for (const child of (nodes || [])) {
639
+ const ctag = (child.tagName || '').toLowerCase();
640
+ if (ctag === 'option') {
641
+ if (optionAttr(child, 'selected') !== null) {
642
+ const v = optionAttr(child, 'value');
643
+ values.push(v != null ? v : (child.textContent || '').trim().replace(/\s+/g, ' '));
644
+ }
645
+ } else if (ctag === 'optgroup') {
646
+ walk(child.children);
647
+ }
648
+ }
649
+ };
650
+ walk(el.children);
651
+ return values;
652
+ }
653
+
654
+ /** Read an attribute from either a DOM element or a MinimalElement. */
655
+ function optionAttr(el, name) {
656
+ return el.getAttribute?.(name) ?? el.attributes?.get?.(name) ?? null;
657
+ }
658
+
659
+ // ── Gap Inference ────────────────────────────────────────────────────────
660
+
661
+ /**
662
+ * Map a pixel gap value to a token size.
663
+ * @param {string} gapValue — CSS gap value (e.g., "8px", "1rem")
664
+ * @returns {string} — "xs" | "sm" | "md" | "lg" | "xl"
665
+ */
666
+ export function inferGap(gapValue) {
667
+ if (!gapValue) return 'md';
668
+ const px = parseFloat(gapValue);
669
+ if (isNaN(px)) return 'md';
670
+ if (px <= 4) return 'xs';
671
+ if (px <= 8) return 'sm';
672
+ if (px <= 16) return 'md';
673
+ if (px <= 24) return 'lg';
674
+ return 'xl';
675
+ }
@@ -0,0 +1,4 @@
1
+ // v0.5.21 hotfix stub — TS-migration Phase 1 (568bb998d) declared this
2
+ // types: export but Phase 2 hasn't generated real declarations yet.
3
+ // Replace with real type declarations when Phase 2 lands.
4
+ export {};