@kerfjs/ui 5.0.0-beta.4 → 5.0.0-beta.41

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 (498) hide show
  1. package/README.md +342 -108
  2. package/ai/application-ui-diagnostic-ids-v1.json +100 -0
  3. package/ai/application-ui-profile-sync.cjs +529 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +102 -0
  6. package/ai/application-ui-profile.defaults.json +41 -0
  7. package/ai/application-ui-profile.mjs +626 -0
  8. package/ai/application-ui-profile.schema.json +130 -0
  9. package/ai/catalog-authoring.json +25 -0
  10. package/ai/catalog-authoring.schema.json +61 -0
  11. package/ai/compile-time-contracts-v1.json +132 -0
  12. package/ai/compile-time-contracts-v1.schema.json +51 -0
  13. package/ai/component-catalog-extension-v2.d.ts +7 -0
  14. package/ai/component-catalog-extension-v2.schema.json +7 -0
  15. package/ai/component-catalog-extension.schema.json +79 -0
  16. package/ai/component-catalog-v2-overrides.json +496 -0
  17. package/ai/component-catalog-v2.d.ts +90 -0
  18. package/ai/component-catalog-v2.json +5678 -0
  19. package/ai/component-catalog-v2.schema.json +298 -0
  20. package/ai/component-catalog.json +2694 -417
  21. package/ai/component-catalog.schema.json +39 -0
  22. package/ai/public-api-signatures-v1.md +1591 -126
  23. package/ai/skill.md +140 -54
  24. package/ai/webawesome-jsx-signatures-v1.md +2 -1
  25. package/analyzer/cli.mjs +49 -0
  26. package/analyzer/index.d.mts +46 -0
  27. package/analyzer/index.mjs +1086 -0
  28. package/analyzer/report.schema.json +66 -0
  29. package/dist/app-tab.d.ts +15 -4
  30. package/dist/app-tab.js +3 -1
  31. package/dist/browser/app-tab.js +1 -0
  32. package/dist/browser/floating-toolbar.js +3 -0
  33. package/dist/browser/list-action-row.js +5 -0
  34. package/dist/browser/list-header.js +7 -0
  35. package/dist/browser/list-inset-control.js +3 -0
  36. package/dist/browser/list-inset-text.js +3 -0
  37. package/dist/browser/list-item.js +5 -0
  38. package/dist/browser/list.js +3 -0
  39. package/dist/browser/pane.js +3 -0
  40. package/dist/browser/row.js +3 -0
  41. package/dist/browser/segmented-control.js +1 -0
  42. package/dist/browser/select.js +1 -0
  43. package/dist/browser/skeleton.js +3 -0
  44. package/dist/browser/spacer.js +3 -0
  45. package/dist/browser/state-banner.js +1 -0
  46. package/dist/browser/sunken-panel.js +3 -0
  47. package/dist/browser/surface-scaffold.js +3 -0
  48. package/dist/browser/text.js +3 -0
  49. package/dist/browser/toolbar-text.js +1 -0
  50. package/dist/browser/value-table.js +1 -0
  51. package/dist/catalog-resources.d.ts +35 -0
  52. package/dist/catalog-resources.js +22 -0
  53. package/dist/catalog-resources.js.map +1 -0
  54. package/dist/catalog.d.ts +151 -0
  55. package/dist/catalog.js +396 -0
  56. package/dist/catalog.js.map +1 -0
  57. package/dist/chunk-2TYUFZUC.js +22 -0
  58. package/dist/chunk-2TYUFZUC.js.map +1 -0
  59. package/dist/chunk-6NDBE2OK.js +32 -0
  60. package/dist/chunk-6NDBE2OK.js.map +1 -0
  61. package/dist/chunk-6WTETUZ6.js +21 -0
  62. package/dist/chunk-6WTETUZ6.js.map +1 -0
  63. package/dist/chunk-AQFWBG23.js +83 -0
  64. package/dist/chunk-AQFWBG23.js.map +1 -0
  65. package/dist/chunk-B6JYRX3P.js +51 -0
  66. package/dist/chunk-B6JYRX3P.js.map +1 -0
  67. package/dist/chunk-C34NZOLJ.js +53 -0
  68. package/dist/chunk-C34NZOLJ.js.map +1 -0
  69. package/dist/chunk-CAB6NQ2T.js +102 -0
  70. package/dist/chunk-CAB6NQ2T.js.map +1 -0
  71. package/dist/chunk-CK6P5AUK.js +136 -0
  72. package/dist/chunk-CK6P5AUK.js.map +1 -0
  73. package/dist/chunk-DAO2VFTT.js +129 -0
  74. package/dist/chunk-DAO2VFTT.js.map +1 -0
  75. package/dist/chunk-DEYOGDE7.js +141 -0
  76. package/dist/chunk-DEYOGDE7.js.map +1 -0
  77. package/dist/chunk-DYBPI5O2.js +25 -0
  78. package/dist/chunk-DYBPI5O2.js.map +1 -0
  79. package/dist/{chunk-TRNBHPNW.js → chunk-E34TE2ZI.js} +12 -8
  80. package/dist/chunk-E34TE2ZI.js.map +1 -0
  81. package/dist/chunk-EYALJQQD.js +25 -0
  82. package/dist/chunk-EYALJQQD.js.map +1 -0
  83. package/dist/chunk-I45QO2IZ.js +88 -0
  84. package/dist/chunk-I45QO2IZ.js.map +1 -0
  85. package/dist/chunk-I4V3UDSA.js +79 -0
  86. package/dist/chunk-I4V3UDSA.js.map +1 -0
  87. package/dist/chunk-OGTJNHRG.js +42 -0
  88. package/dist/chunk-OGTJNHRG.js.map +1 -0
  89. package/dist/chunk-OL4TC3U2.js +156 -0
  90. package/dist/chunk-OL4TC3U2.js.map +1 -0
  91. package/dist/chunk-OMSRSL3B.js +120 -0
  92. package/dist/chunk-OMSRSL3B.js.map +1 -0
  93. package/dist/chunk-R3EBGEAW.js +46 -0
  94. package/dist/chunk-R3EBGEAW.js.map +1 -0
  95. package/dist/chunk-SOK5EUF7.js +25 -0
  96. package/dist/chunk-SOK5EUF7.js.map +1 -0
  97. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  98. package/dist/chunk-SRSJO5QE.js.map +1 -0
  99. package/dist/chunk-T7DOWS6T.js +61 -0
  100. package/dist/chunk-T7DOWS6T.js.map +1 -0
  101. package/dist/chunk-TIGSG6BX.js +218 -0
  102. package/dist/chunk-TIGSG6BX.js.map +1 -0
  103. package/dist/chunk-UDHHKZWO.js +41 -0
  104. package/dist/chunk-UDHHKZWO.js.map +1 -0
  105. package/dist/{chunk-MQIZAD4A.js → chunk-UKKSMZYT.js} +76 -22
  106. package/dist/chunk-UKKSMZYT.js.map +1 -0
  107. package/dist/chunk-V6GQKOX2.js +39 -0
  108. package/dist/chunk-V6GQKOX2.js.map +1 -0
  109. package/dist/chunk-V6HCTCVD.js +46 -0
  110. package/dist/chunk-V6HCTCVD.js.map +1 -0
  111. package/dist/chunk-VDUJZF5G.js +515 -0
  112. package/dist/chunk-VDUJZF5G.js.map +1 -0
  113. package/dist/chunk-VXFGMDA7.js +31 -0
  114. package/dist/chunk-VXFGMDA7.js.map +1 -0
  115. package/dist/chunk-WN52USHV.js +115 -0
  116. package/dist/chunk-WN52USHV.js.map +1 -0
  117. package/dist/chunk-WSXUPSID.js +43 -0
  118. package/dist/chunk-WSXUPSID.js.map +1 -0
  119. package/dist/chunk-X5GRDQ7V.js +50 -0
  120. package/dist/chunk-X5GRDQ7V.js.map +1 -0
  121. package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
  122. package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
  123. package/dist/chunk-ZASJJMGV.js +17 -0
  124. package/dist/chunk-ZASJJMGV.js.map +1 -0
  125. package/dist/chunk-ZPWZIVI6.js +47 -0
  126. package/dist/chunk-ZPWZIVI6.js.map +1 -0
  127. package/dist/collapsible-panel.d.ts +77 -0
  128. package/dist/collapsible-panel.js +84 -0
  129. package/dist/collapsible-panel.js.map +1 -0
  130. package/dist/css-values.d.ts +75 -0
  131. package/dist/css-values.js +3 -0
  132. package/dist/css-values.js.map +1 -0
  133. package/dist/device-class.d.ts +62 -0
  134. package/dist/device-class.js +103 -0
  135. package/dist/device-class.js.map +1 -0
  136. package/dist/disclosure-arrow.js +1 -1
  137. package/dist/divider-sides-BzB6rphT.d.ts +6 -0
  138. package/dist/empty-state.d.ts +3 -2
  139. package/dist/empty-state.js +1 -1
  140. package/dist/flex-alignment-CF8NLj7i.d.ts +4 -0
  141. package/dist/floating-toolbar.d.ts +29 -0
  142. package/dist/floating-toolbar.js +3 -0
  143. package/dist/floating-toolbar.js.map +1 -0
  144. package/dist/index.d.ts +28 -14
  145. package/dist/index.js +34 -23
  146. package/dist/{menu-action-row.d.ts → list-action-row.d.ts} +19 -8
  147. package/dist/list-action-row.js +7 -0
  148. package/dist/list-action-row.js.map +1 -0
  149. package/dist/list-header.d.ts +80 -0
  150. package/dist/list-header.js +9 -0
  151. package/dist/list-header.js.map +1 -0
  152. package/dist/list-inset-control.d.ts +20 -0
  153. package/dist/list-inset-control.js +3 -0
  154. package/dist/list-inset-control.js.map +1 -0
  155. package/dist/list-inset-text.d.ts +29 -0
  156. package/dist/list-inset-text.js +3 -0
  157. package/dist/list-inset-text.js.map +1 -0
  158. package/dist/list-item.d.ts +45 -0
  159. package/dist/list-item.js +7 -0
  160. package/dist/list-item.js.map +1 -0
  161. package/dist/list.d.ts +30 -0
  162. package/dist/list.js +5 -0
  163. package/dist/list.js.map +1 -0
  164. package/dist/loading-spinner.js +1 -1
  165. package/dist/nav-stack.d.ts +41 -0
  166. package/dist/nav-stack.js +6 -0
  167. package/dist/nav-stack.js.map +1 -0
  168. package/dist/pane.d.ts +50 -0
  169. package/dist/pane.js +4 -0
  170. package/dist/pane.js.map +1 -0
  171. package/dist/resizable-region.d.ts +21 -3
  172. package/dist/resizable-region.js +1 -1
  173. package/dist/row.d.ts +28 -0
  174. package/dist/row.js +5 -0
  175. package/dist/row.js.map +1 -0
  176. package/dist/segmented-control.d.ts +11 -8
  177. package/dist/segmented-control.js +3 -1
  178. package/dist/select-register.d.ts +5 -1
  179. package/dist/select-register.js +129 -1
  180. package/dist/select-register.js.map +1 -1
  181. package/dist/select.d.ts +34 -8
  182. package/dist/select.js +3 -1
  183. package/dist/semantic-content-BbzjvSu9.d.ts +14 -0
  184. package/dist/skeleton.d.ts +25 -0
  185. package/dist/skeleton.js +4 -0
  186. package/dist/skeleton.js.map +1 -0
  187. package/dist/spacer.d.ts +16 -0
  188. package/dist/spacer.js +4 -0
  189. package/dist/spacer.js.map +1 -0
  190. package/dist/split-view.d.ts +43 -0
  191. package/dist/split-view.js +82 -0
  192. package/dist/split-view.js.map +1 -0
  193. package/dist/state-banner.d.ts +11 -5
  194. package/dist/state-banner.js +3 -1
  195. package/dist/styles/app-tab.css +26 -0
  196. package/dist/styles/catalog.css +582 -0
  197. package/dist/styles/collapsible-panel.css +212 -0
  198. package/dist/styles/floating-toolbar.css +38 -0
  199. package/dist/styles/foundation.css +80 -0
  200. package/dist/styles/layout.css +2 -20
  201. package/dist/styles/list-action-row.css +224 -0
  202. package/dist/styles/list-header.css +224 -0
  203. package/dist/styles/list-inset-control.css +23 -0
  204. package/dist/styles/list-inset-text.css +30 -0
  205. package/dist/styles/list-item.css +171 -0
  206. package/dist/styles/list.css +118 -0
  207. package/dist/styles/nav-stack.css +141 -0
  208. package/dist/styles/pane.css +62 -0
  209. package/dist/styles/resizable-region.css +158 -0
  210. package/dist/styles/row.css +92 -0
  211. package/dist/styles/segmented-control.css +10 -7
  212. package/dist/styles/select.css +115 -2
  213. package/dist/styles/skeleton.css +31 -0
  214. package/dist/styles/spacer.css +11 -0
  215. package/dist/styles/split-view.css +35 -0
  216. package/dist/styles/state-banner.css +49 -10
  217. package/dist/styles/styles.css +10 -5
  218. package/dist/styles/sunken-panel.css +22 -0
  219. package/dist/styles/surface-scaffold.css +51 -0
  220. package/dist/styles/tab-bar.css +24 -0
  221. package/dist/styles/tab-scaffold.css +85 -0
  222. package/dist/styles/text.css +6 -0
  223. package/dist/styles/token-search-field.css +14 -2
  224. package/dist/styles/toolbar-control-group.css +235 -8
  225. package/dist/styles/toolbar-text.css +65 -2
  226. package/dist/styles/toolbar.css +47 -2
  227. package/dist/styles/webawesome.css +171 -0
  228. package/dist/styles/workbench.css +187 -0
  229. package/dist/sunken-panel.d.ts +20 -0
  230. package/dist/sunken-panel.js +3 -0
  231. package/dist/sunken-panel.js.map +1 -0
  232. package/dist/surface-scaffold.d.ts +26 -0
  233. package/dist/surface-scaffold.js +3 -0
  234. package/dist/surface-scaffold.js.map +1 -0
  235. package/dist/tab-bar.d.ts +24 -6
  236. package/dist/tab-bar.js +1 -1
  237. package/dist/tab-scaffold.d.ts +31 -0
  238. package/dist/tab-scaffold.js +51 -0
  239. package/dist/tab-scaffold.js.map +1 -0
  240. package/dist/text.d.ts +20 -0
  241. package/dist/text.js +3 -0
  242. package/dist/text.js.map +1 -0
  243. package/dist/token-search-field.d.ts +30 -13
  244. package/dist/token-search-field.js +1 -1
  245. package/dist/toolbar-control-group.d.ts +33 -7
  246. package/dist/toolbar-control-group.js +1 -1
  247. package/dist/toolbar-text.d.ts +31 -4
  248. package/dist/toolbar-text.js +3 -1
  249. package/dist/toolbar.d.ts +10 -7
  250. package/dist/toolbar.js +1 -1
  251. package/dist/value-table.d.ts +7 -3
  252. package/dist/value-table.js +3 -1
  253. package/dist/webawesome.d.ts +1 -0
  254. package/dist/wire-catalog.d.ts +57 -0
  255. package/dist/wire-catalog.js +302 -0
  256. package/dist/wire-catalog.js.map +1 -0
  257. package/dist/wire-nav-stack.d.ts +18 -0
  258. package/dist/wire-nav-stack.js +228 -0
  259. package/dist/wire-nav-stack.js.map +1 -0
  260. package/dist/wire-resizable-regions.d.ts +1 -1
  261. package/dist/wire-resizable-regions.js +1 -1
  262. package/dist/wire-sidebar.d.ts +48 -0
  263. package/dist/wire-sidebar.js +147 -0
  264. package/dist/wire-sidebar.js.map +1 -0
  265. package/dist/wire-tab-bars.d.ts +19 -2
  266. package/dist/wire-tab-bars.js +1 -1
  267. package/dist/wire-tab-scaffold.d.ts +11 -0
  268. package/dist/wire-tab-scaffold.js +21 -0
  269. package/dist/wire-tab-scaffold.js.map +1 -0
  270. package/dist/wire-token-search-fields.d.ts +104 -4
  271. package/dist/wire-token-search-fields.js +1 -1
  272. package/dist/workbench.d.ts +44 -0
  273. package/dist/workbench.js +106 -0
  274. package/dist/workbench.js.map +1 -0
  275. package/docs/accessibility.md +155 -20
  276. package/docs/app-layouts.md +61 -0
  277. package/docs/catalog.md +364 -0
  278. package/docs/collapsible-panel.md +142 -0
  279. package/docs/component-contract.md +258 -28
  280. package/docs/component-integration.md +63 -0
  281. package/docs/component-selection.md +219 -57
  282. package/docs/design/templates/empty-state/filtered-dark.svg +1 -0
  283. package/docs/design/templates/empty-state/filtered.svg +1 -0
  284. package/docs/design/templates/empty-state/with-action-dark.svg +1 -0
  285. package/docs/design/templates/empty-state/with-action.svg +1 -0
  286. package/docs/design/templates/empty-state-dark.svg +1 -0
  287. package/docs/design/templates/empty-state.svg +1 -0
  288. package/docs/design/templates/list/compact-dark.svg +1 -0
  289. package/docs/design/templates/list/compact.svg +1 -0
  290. package/docs/design/templates/list/stack-dark.svg +1 -0
  291. package/docs/design/templates/list/stack.svg +1 -0
  292. package/docs/design/templates/list-action-row/default-dark.svg +1 -0
  293. package/docs/design/templates/list-action-row/default.svg +1 -0
  294. package/docs/design/templates/list-action-row/selected-dark.svg +1 -0
  295. package/docs/design/templates/list-action-row/selected.svg +1 -0
  296. package/docs/design/templates/list-action-row-dark.svg +1 -0
  297. package/docs/design/templates/list-action-row.svg +1 -0
  298. package/docs/design/templates/list-dark.svg +1 -0
  299. package/docs/design/templates/list-header/action-dark.svg +1 -0
  300. package/docs/design/templates/list-header/action.svg +1 -0
  301. package/docs/design/templates/list-header/count-dark.svg +1 -0
  302. package/docs/design/templates/list-header/count.svg +1 -0
  303. package/docs/design/templates/list-header/inline-action-dark.svg +1 -0
  304. package/docs/design/templates/list-header/inline-action.svg +1 -0
  305. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -0
  306. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -0
  307. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -0
  308. package/docs/design/templates/list-header/toggle-expanded.svg +1 -0
  309. package/docs/design/templates/list-header-dark.svg +1 -0
  310. package/docs/design/templates/list-header.svg +1 -0
  311. package/docs/design/templates/list-item/default-dark.svg +1 -0
  312. package/docs/design/templates/list-item/default.svg +1 -0
  313. package/docs/design/templates/list-item/multiline-dark.svg +1 -0
  314. package/docs/design/templates/list-item/multiline.svg +1 -0
  315. package/docs/design/templates/list-item/selected-dark.svg +1 -0
  316. package/docs/design/templates/list-item/selected.svg +1 -0
  317. package/docs/design/templates/list-item/trailing-dark.svg +1 -0
  318. package/docs/design/templates/list-item/trailing.svg +1 -0
  319. package/docs/design/templates/list-item-dark.svg +1 -0
  320. package/docs/design/templates/list-item.svg +1 -0
  321. package/docs/design/templates/list.svg +1 -0
  322. package/docs/design/templates/segmented-control/equal-dark.svg +1 -0
  323. package/docs/design/templates/segmented-control/equal.svg +1 -0
  324. package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -0
  325. package/docs/design/templates/segmented-control/pill-small.svg +1 -0
  326. package/docs/design/templates/segmented-control-dark.svg +1 -0
  327. package/docs/design/templates/segmented-control.svg +1 -0
  328. package/docs/design/templates/skeleton/avatar-dark.svg +1 -0
  329. package/docs/design/templates/skeleton/avatar.svg +1 -0
  330. package/docs/design/templates/skeleton/block-dark.svg +1 -0
  331. package/docs/design/templates/skeleton/block.svg +1 -0
  332. package/docs/design/templates/skeleton/lines-dark.svg +1 -0
  333. package/docs/design/templates/skeleton/lines.svg +1 -0
  334. package/docs/design/templates/skeleton-dark.svg +1 -0
  335. package/docs/design/templates/skeleton.svg +1 -0
  336. package/docs/design/templates/state-banner/danger-dark.svg +1 -0
  337. package/docs/design/templates/state-banner/danger.svg +1 -0
  338. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  339. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  340. package/docs/design/templates/state-banner/info-dark.svg +1 -0
  341. package/docs/design/templates/state-banner/info.svg +1 -0
  342. package/docs/design/templates/state-banner/success-dark.svg +1 -0
  343. package/docs/design/templates/state-banner/success.svg +1 -0
  344. package/docs/design/templates/state-banner/warning-dark.svg +1 -0
  345. package/docs/design/templates/state-banner/warning.svg +1 -0
  346. package/docs/design/templates/state-banner-dark.svg +1 -0
  347. package/docs/design/templates/state-banner.svg +1 -0
  348. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -0
  349. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -0
  350. package/docs/design/templates/tab-bar-dark.svg +1 -0
  351. package/docs/design/templates/tab-bar.svg +1 -0
  352. package/docs/design/templates/token-search-field/empty-dark.svg +1 -0
  353. package/docs/design/templates/token-search-field/empty.svg +1 -0
  354. package/docs/design/templates/token-search-field/tokens-dark.svg +1 -0
  355. package/docs/design/templates/token-search-field/tokens.svg +1 -0
  356. package/docs/design/templates/token-search-field-dark.svg +1 -0
  357. package/docs/design/templates/token-search-field.svg +1 -0
  358. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -0
  359. package/docs/design/templates/toolbar/title-and-actions.svg +1 -0
  360. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -0
  361. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -0
  362. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -0
  363. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -0
  364. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -0
  365. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -0
  366. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -0
  367. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -0
  368. package/docs/design/templates/toolbar-control-group-dark.svg +1 -0
  369. package/docs/design/templates/toolbar-control-group.svg +1 -0
  370. package/docs/design/templates/toolbar-dark.svg +1 -0
  371. package/docs/design/templates/toolbar-text/default-dark.svg +1 -0
  372. package/docs/design/templates/toolbar-text/default.svg +1 -0
  373. package/docs/design/templates/toolbar-text/large-dark.svg +1 -0
  374. package/docs/design/templates/toolbar-text/large.svg +1 -0
  375. package/docs/design/templates/toolbar-text/small-dark.svg +1 -0
  376. package/docs/design/templates/toolbar-text/small.svg +1 -0
  377. package/docs/design/templates/toolbar-text-dark.svg +1 -0
  378. package/docs/design/templates/toolbar-text.svg +1 -0
  379. package/docs/design/templates/toolbar.svg +1 -0
  380. package/docs/design/templates/value-table/details-dark.svg +1 -0
  381. package/docs/design/templates/value-table/details.svg +1 -0
  382. package/docs/design/templates/value-table-dark.svg +1 -0
  383. package/docs/design/templates/value-table.svg +1 -0
  384. package/docs/design/templates.md +128 -0
  385. package/docs/design-philosophy.md +33 -11
  386. package/docs/device-class.md +54 -0
  387. package/docs/examples/application-ui-profile.json +60 -0
  388. package/docs/examples/command-palette-adapter.tsx +68 -17
  389. package/docs/examples/component-catalog-extension-v2.json +80 -0
  390. package/docs/examples/component-catalog-extension.json +45 -0
  391. package/docs/layout.md +169 -38
  392. package/docs/nav-stack.md +77 -0
  393. package/docs/recipes.md +64 -16
  394. package/docs/split-view.md +55 -0
  395. package/docs/sunken-panel.md +53 -0
  396. package/docs/surface-scaffold.md +25 -0
  397. package/docs/tab-scaffold.md +52 -0
  398. package/docs/type-contracts.md +127 -0
  399. package/docs/ui-analyzer.md +118 -0
  400. package/docs/ui-doctor.md +91 -0
  401. package/docs/ui-evaluator.md +122 -0
  402. package/docs/ux-demo.md +29 -10
  403. package/docs/webawesome-theme.md +82 -8
  404. package/docs/workbench.md +123 -0
  405. package/doctor/cli.mjs +115 -0
  406. package/doctor/config.schema.json +68 -0
  407. package/doctor/eslint-diagnostics.d.mts +24 -0
  408. package/doctor/eslint-diagnostics.mjs +24 -0
  409. package/doctor/index.d.mts +116 -0
  410. package/doctor/index.mjs +1272 -0
  411. package/doctor/report.schema.json +118 -0
  412. package/evaluator/cli.mjs +89 -0
  413. package/evaluator/index.d.mts +90 -0
  414. package/evaluator/index.mjs +1138 -0
  415. package/evaluator/report.schema.json +152 -0
  416. package/llms.txt +260 -32
  417. package/package.json +205 -38
  418. package/traversal-exclusions.mjs +27 -0
  419. package/ux-demo/recipes/app-shell.tsx +223 -13
  420. package/ux-demo/recipes/collapsible-sidebar.tsx +230 -0
  421. package/ux-demo/recipes/compact-toolbar.tsx +116 -12
  422. package/ux-demo/recipes/composer-form.tsx +120 -19
  423. package/ux-demo/recipes/list-detail-dialog.tsx +205 -0
  424. package/ux-demo/recipes/list-workspace-states.tsx +176 -9
  425. package/ux-demo/recipes/loaders.ts +13 -4
  426. package/ux-demo/recipes/loading-inspector.tsx +191 -0
  427. package/ux-demo/recipes/mount-recipe.ts +31 -5
  428. package/ux-demo/recipes/navigation-sidebar.tsx +123 -11
  429. package/ux-demo/recipes/navigation-stack.tsx +121 -0
  430. package/ux-demo/recipes/recipes.css +125 -16
  431. package/ux-demo/recipes/types.ts +9 -1
  432. package/ux-demo/recipes/workspace-header.tsx +72 -3
  433. package/dist/browser/dialog-header.js +0 -5
  434. package/dist/browser/menu-action-row.js +0 -3
  435. package/dist/browser/menu-header.js +0 -5
  436. package/dist/browser/menu-item.js +0 -3
  437. package/dist/browser/page-header.js +0 -3
  438. package/dist/chunk-2PES33HS.js +0 -13
  439. package/dist/chunk-2PES33HS.js.map +0 -1
  440. package/dist/chunk-55DATV3A.js +0 -10
  441. package/dist/chunk-55DATV3A.js.map +0 -1
  442. package/dist/chunk-7BR3DO2A.js.map +0 -1
  443. package/dist/chunk-7LDCTU7D.js +0 -134
  444. package/dist/chunk-7LDCTU7D.js.map +0 -1
  445. package/dist/chunk-AQNKJRFH.js +0 -79
  446. package/dist/chunk-AQNKJRFH.js.map +0 -1
  447. package/dist/chunk-CTQKI2XL.js +0 -28
  448. package/dist/chunk-CTQKI2XL.js.map +0 -1
  449. package/dist/chunk-DAFFDO33.js +0 -14
  450. package/dist/chunk-DAFFDO33.js.map +0 -1
  451. package/dist/chunk-EGHL5S4P.js +0 -33
  452. package/dist/chunk-EGHL5S4P.js.map +0 -1
  453. package/dist/chunk-GY5WH7TO.js +0 -10
  454. package/dist/chunk-GY5WH7TO.js.map +0 -1
  455. package/dist/chunk-H5AGGVU5.js +0 -75
  456. package/dist/chunk-H5AGGVU5.js.map +0 -1
  457. package/dist/chunk-K3G72I6D.js +0 -24
  458. package/dist/chunk-K3G72I6D.js.map +0 -1
  459. package/dist/chunk-M5JRI6MN.js +0 -27
  460. package/dist/chunk-M5JRI6MN.js.map +0 -1
  461. package/dist/chunk-MBR3TYNL.js +0 -14
  462. package/dist/chunk-MBR3TYNL.js.map +0 -1
  463. package/dist/chunk-MFKMHK5W.js +0 -10
  464. package/dist/chunk-MFKMHK5W.js.map +0 -1
  465. package/dist/chunk-MQIZAD4A.js.map +0 -1
  466. package/dist/chunk-NPPD2A6O.js +0 -40
  467. package/dist/chunk-NPPD2A6O.js.map +0 -1
  468. package/dist/chunk-R6JHHBKQ.js +0 -19
  469. package/dist/chunk-R6JHHBKQ.js.map +0 -1
  470. package/dist/chunk-S3TPM2LP.js +0 -23
  471. package/dist/chunk-S3TPM2LP.js.map +0 -1
  472. package/dist/chunk-TRNBHPNW.js.map +0 -1
  473. package/dist/chunk-VHW5YNIB.js +0 -17
  474. package/dist/chunk-VHW5YNIB.js.map +0 -1
  475. package/dist/chunk-WVPYVDXY.js +0 -15
  476. package/dist/chunk-WVPYVDXY.js.map +0 -1
  477. package/dist/chunk-XZXRLY5Q.js +0 -33
  478. package/dist/chunk-XZXRLY5Q.js.map +0 -1
  479. package/dist/dialog-header.d.ts +0 -15
  480. package/dist/dialog-header.js +0 -5
  481. package/dist/dialog-header.js.map +0 -1
  482. package/dist/menu-action-row.js +0 -4
  483. package/dist/menu-action-row.js.map +0 -1
  484. package/dist/menu-header.d.ts +0 -41
  485. package/dist/menu-header.js +0 -6
  486. package/dist/menu-header.js.map +0 -1
  487. package/dist/menu-item.d.ts +0 -31
  488. package/dist/menu-item.js +0 -4
  489. package/dist/menu-item.js.map +0 -1
  490. package/dist/page-header.d.ts +0 -9
  491. package/dist/page-header.js +0 -3
  492. package/dist/page-header.js.map +0 -1
  493. package/dist/styles/dialog-header.css +0 -87
  494. package/dist/styles/menu-action-row.css +0 -160
  495. package/dist/styles/menu-header.css +0 -143
  496. package/dist/styles/menu-item.css +0 -123
  497. package/dist/styles/page-header.css +0 -33
  498. package/ux-demo/recipes/master-detail-dialog.tsx +0 -45
@@ -4,10 +4,10 @@
4
4
  free components and the Kerf/Hot Sheet 2 design system.
5
5
 
6
6
  ```ts
7
- import type {} from '@kerfjs/ui/webawesome';
8
- import '@kerfjs/ui/webawesome.css';
9
- import '@awesome.me/webawesome/dist/components/button/button.js';
10
- import '@awesome.me/webawesome/dist/components/input/input.js';
7
+ import type {} from "@kerfjs/ui/webawesome";
8
+ import "@kerfjs/ui/webawesome.css";
9
+ import "@awesome.me/webawesome/dist/components/button/button.js";
10
+ import "@awesome.me/webawesome/dist/components/input/input.js";
11
11
  ```
12
12
 
13
13
  The type-only package import augments `kerfjs/jsx-runtime` with the 70
@@ -54,6 +54,80 @@ pointer targets. Override `--kui-wa-carousel-icon-size`,
54
54
  `--kui-wa-carousel-dot-hit-size` on a carousel or containing scope when a
55
55
  product needs different geometry.
56
56
 
57
+ Form fields carry the same content-item inset as the Kerf primitives: a 1px
58
+ border with 8px inside it (`--wa-form-control-border-width`,
59
+ `--wa-form-control-padding-block`, and `--wa-form-control-padding-inline` are set
60
+ to the `--kui-layout-item-border-width` / `--kui-layout-item-padding` values), so
61
+ a single-line control lands at the standard ~40px height and the value sits 9px
62
+ in from the field edge. Each field's top label is inset by that same border +
63
+ padding (9px) so it lines up with the value inside the field, and is styled
64
+ exactly like a `ListHeader` label — uppercase, `--kui-font-xs`, weight 650, quiet
65
+ foreground. This applies to every free field that exposes a top label
66
+ (`::part(form-control-label)` plus the Slider's `::part(label)`). OTP Input
67
+ exposes `label` instead of `form-control-label`; the theme gives it the same
68
+ uppercase 12px/650 treatment. Inline control labels (Checkbox, Switch) keep
69
+ their natural sentence case.
70
+
71
+ Known Date's field captions and bordered text-like field hints use the same 9px
72
+ inline inset, keeping secondary text aligned with the value rather than the
73
+ field's outer border. This covers Input, Known Date, Number Input, OTP Input,
74
+ Select, Textarea, and Time Input hints; unbordered group hints retain their own
75
+ natural geometry. OTP Input's label and hint both use the 9px field-text inset.
76
+
77
+ Checkbox Group and Radio Group option regions receive the shared 8px inline
78
+ outer inset through `::part(form-control-input)`. Unlike bordered fields, these
79
+ groups have no shell of their own, so the explicit margin places their controls
80
+ on the same content-item geometry without adding padding to each option. The
81
+ Color Picker trigger receives the same 8px inline outer inset because it also
82
+ has no bordered field shell. Slider's complete interactive region receives the
83
+ shared 8px logical inline outer inset through `::part(slider)`, keeping its
84
+ track, markers, references, and hint together without moving the label.
85
+
86
+ Non-field chrome follows explicit, overridable control, surface, and container
87
+ tiers:
88
+
89
+ - `--kui-wa-control-inset` defaults to the 8px content-item padding. It applies
90
+ to tabs, tree-item trailing content, tags, and dropdown items. Tree selection
91
+ also uses Kerf's 8px inline outer margin, so its background reads as an inset
92
+ list item instead of an edge-to-edge stripe. Buttons already consume the same
93
+ `--wa-form-control-padding-inline` 8px value at every size, so no extra part
94
+ override is needed.
95
+ - `--kui-wa-surface-margin` and `--kui-wa-surface-inset` default to 8px.
96
+ Accordion, Card, Details, Callout, and Include use the margin around their
97
+ complete surface and the inset within it. Accordion applies the outer margin
98
+ once to the group rather than separating connected items; Card's header,
99
+ body, and footer all receive the full inset.
100
+ - `--kui-wa-container-inset` defaults to the 16px homogeneous-group step. Tab
101
+ Panel retains this roomier tier for unframed panel content. Dialog body uses
102
+ the 8px surface inset, while its footer uses the 16px container inset so
103
+ content stays compact and the action group has a clearer boundary. These two
104
+ parts do not inherit the dialog's shared `--spacing` value.
105
+
106
+ Add `class="hide-actions"` to a `wa-dialog` when the dialog supplies its own
107
+ dismissal affordance and should omit Web Awesome's header action region. The
108
+ theme sets `display: none` on the directly exported `header-actions` part; it
109
+ does not attempt to chain `::part()` through the internal `dialog` and `header`
110
+ parts, which CSS shadow parts do not support.
111
+
112
+ Badge remains intentionally compact at Web Awesome's intrinsic `0.375em` block /
113
+ `0.625em` inline padding (4.5px / 7.5px at its default 12px text size): it is a
114
+ short status or count, not a content item. Breadcrumb has no bordered or filled
115
+ container, and Scroller delegates item chrome to its slotted children, so both
116
+ retain their upstream geometry. Web Awesome 3.12's free catalog has
117
+ `wa-dropdown-item`, but no `wa-menu-item`; the theme therefore styles the
118
+ supported dropdown item rather than carrying a dead selector.
119
+
120
+ Override a tier for a product scope after importing the theme:
121
+
122
+ ```css
123
+ .roomy-editor {
124
+ --kui-wa-control-inset: 0.75rem;
125
+ --kui-wa-surface-margin: 0.75rem;
126
+ --kui-wa-surface-inset: 0.75rem;
127
+ --kui-wa-container-inset: 1.5rem;
128
+ }
129
+ ```
130
+
57
131
  Accordion, Details, Breadcrumb, and Kerf Select share
58
132
  `--kui-disclosure-icon-scale` (default `.5`) so disclosure and traversal
59
133
  chevrons keep the same visual weight. The Accordion and Details components
@@ -73,12 +147,12 @@ subtree, or for one instance after the theme import:
73
147
 
74
148
  ```css
75
149
  :root {
76
- --wa-tooltip-arrow-size: .375rem;
77
- --kui-wa-popover-arrow-size: .375rem;
150
+ --wa-tooltip-arrow-size: 0.375rem;
151
+ --kui-wa-popover-arrow-size: 0.375rem;
78
152
  }
79
153
 
80
154
  .pointed-popover {
81
- --arrow-size: .5rem;
155
+ --arrow-size: 0.5rem;
82
156
  }
83
157
  ```
84
158
 
@@ -179,7 +253,7 @@ smallest subtree that needs a different identity:
179
253
  :root {
180
254
  --wa-color-brand-fill-loud: #7540a8;
181
255
  --wa-color-focus: #7540a8;
182
- --wa-form-control-border-radius: .5rem;
256
+ --wa-form-control-border-radius: 0.5rem;
183
257
  }
184
258
 
185
259
  .billing-workspace {
@@ -0,0 +1,123 @@
1
+ # Workbench
2
+
3
+ `@kerfjs/ui/workbench` is the Xcode-like multi-panel workspace: a collapsible
4
+ left rail, right rail, and bottom drawer around a central work area (any absent).
5
+ It generalizes the instant-width / sliding-content collapse used by the catalog
6
+ sidebar. One of the opt-in app layouts (see
7
+ [`../../docs/23-app-layouts.md`](../../docs/23-app-layouts.md)); best on
8
+ desktop-class devices.
9
+
10
+ ```ts
11
+ import { Workbench } from "@kerfjs/ui/workbench";
12
+ import "@kerfjs/ui/workbench.css";
13
+ ```
14
+
15
+ ## State lives in the app
16
+
17
+ `Workbench` is declarative and the collapse is **pure CSS** — no wire. The app
18
+ owns each panel's `collapsed` flag (usually a signal) and toggles it; the panel
19
+ animates itself.
20
+
21
+ ```tsx
22
+ const navCollapsed = signal(false);
23
+
24
+ <Workbench
25
+ id="studio"
26
+ label="Studio"
27
+ main={<Editor />}
28
+ leftRail={{
29
+ content: <Navigator />,
30
+ label: "Navigator",
31
+ collapsed: navCollapsed.value,
32
+ size: 280,
33
+ }}
34
+ rightRail={{
35
+ content: <Inspector />,
36
+ label: "Inspector",
37
+ collapsed: inspectorCollapsed.value,
38
+ }}
39
+ bottomDrawer={{
40
+ content: <Console />,
41
+ label: "Console",
42
+ collapsed: consoleCollapsed.value,
43
+ }}
44
+ />;
45
+ ```
46
+
47
+ Each `WorkbenchPanel` takes `content`, an optional `collapsed`, an optional
48
+ `size` (rail width or drawer height in px, overriding the CSS default —
49
+ `--kui-workbench-rail-width` 280px, `--kui-workbench-drawer-height` 220px), and
50
+ an optional `label`. Common shell behavior is configured rather than restyled:
51
+
52
+ - `separator: "auto" | "hidden"` controls the owned dock-edge separator;
53
+ - `collapseMotion: "slide" | "fade-slide" | "none"` keeps the track change
54
+ instant while choosing composited content motion;
55
+ - `contentOverflow: "clip" | "auto" | "visible"` lets a drawer temporarily
56
+ expose an open popup without a descendant override;
57
+ - `presentation: "inline" | "overlay" | "hidden"` supports compact overlays
58
+ or a responsive replacement. Overlay panels clamp both their track and fixed-size
59
+ animated content to the configured viewport-relative maximum;
60
+ - `restoreControl` places an application-owned restore affordance in a
61
+ safe-area-aware viewport corner (`restorePosition` chooses the corner).
62
+
63
+ The same policy props are available on `ResizableRegion` and
64
+ `CollapsiblePanel`, so a resizable application shell does not need to reach
65
+ into `.kui-resizable-region__content`.
66
+
67
+ ## Resizable application-shell migration
68
+
69
+ An application such as Hot Sheet can replace its shell descendant overrides
70
+ with state-derived props:
71
+
72
+ ```tsx
73
+ <ResizableRegion
74
+ id="terminal-drawer"
75
+ label="Terminal drawer"
76
+ axis="vertical"
77
+ edge="start"
78
+ size={drawerSize.value}
79
+ min={180}
80
+ max={520}
81
+ collapsed={!drawerVisible.value}
82
+ separator={magnified.value ? "hidden" : "auto"}
83
+ collapseMotion="fade-slide"
84
+ contentOverflow={createMenuOpen.value ? "visible" : "clip"}
85
+ presentation={mobile.value ? "overlay" : "inline"}
86
+ restoreControl={<button data-action="show-drawer">Show terminals</button>}
87
+ >
88
+ <TerminalDrawer />
89
+ </ResizableRegion>
90
+ ```
91
+
92
+ `wireResizableRegions` marks the active region with `data-resizing` and the
93
+ package CSS suppresses content motion during pointer resize. A collapsed,
94
+ overlay, or hidden region is not resizeable. Together these policies replace
95
+ app CSS for separator suppression, instant-track/composited-content collapse,
96
+ popup overflow, mobile overlay/hidden replacement, resize-transition guards,
97
+ and safe-area restore placement. The app still owns the signals and decides
98
+ when each policy applies.
99
+
100
+ ## Public styling boundary
101
+
102
+ Import `@kerfjs/ui/workbench.css` after the component subpath. Applications may
103
+ set `--kui-workbench-rail-width` and `--kui-workbench-drawer-height` on a
104
+ Workbench instance. The supported composition classes are `.kui-workbench`,
105
+ `.kui-workbench__rail`, `.kui-workbench__rail--left`,
106
+ `.kui-workbench__rail--right`, `.kui-workbench__center`,
107
+ `.kui-workbench__main`, `.kui-workbench__drawer`, and
108
+ `.kui-workbench__panel-content`, and `.kui-workbench__restore`; these exact hooks are cataloged for tools that
109
+ must classify public application selectors. Prefer the component props and two
110
+ size tokens before selecting internal anatomy, and do not target its data
111
+ attributes or descendant tags as styling contracts.
112
+
113
+ ## How the collapse animates
114
+
115
+ Collapsing snaps the panel's flex track to zero in a single reflow (so the work
116
+ area relayouts once, not per frame) while the panel's fixed-size content slides
117
+ out via a composited `transform` — a rail slides horizontally, the drawer
118
+ vertically — clipped by the shell's overflow. The drawer content is positioned
119
+ against the shell's stable bottom edge, so opening and closing move monotonically
120
+ through the transform rather than inheriting a changing normal-flow origin. It
121
+ honors `prefers-reduced-motion` (the slide collapses to instant). On smaller
122
+ device classes, present the rails' contents through a `NavStack` or overlay
123
+ drawers rather than shrinking the three-panel shell.
package/doctor/cli.mjs ADDED
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+
3
+ import console from 'node:console';
4
+ import { execFile } from 'node:child_process';
5
+ import { writeFile } from 'node:fs/promises';
6
+ import { resolve } from 'node:path';
7
+ import process from 'node:process';
8
+ import { promisify } from 'node:util';
9
+
10
+ import { formatUiDoctorText, runUiDoctor, UI_DOCTOR_EXIT } from './index.mjs';
11
+
12
+ const execFileAsync = promisify(execFile);
13
+ const args = process.argv.slice(2);
14
+ const take = (name, repeat = false) => {
15
+ const values = [];
16
+ while (args.includes(name)) {
17
+ const index = args.indexOf(name);
18
+ const value = args[index + 1];
19
+ if (!value || value.startsWith('--'))
20
+ throw new Error(`${name} requires a value.`);
21
+ args.splice(index, 2);
22
+ values.push(value);
23
+ if (!repeat) break;
24
+ }
25
+ return repeat ? values : values[0];
26
+ };
27
+
28
+ async function changedPaths(root) {
29
+ const { stdout: tracked } = await execFileAsync(
30
+ 'git',
31
+ ['diff', '--name-only', '--diff-filter=ACMR', 'HEAD', '--'],
32
+ { cwd: root },
33
+ );
34
+ const { stdout: untracked } = await execFileAsync(
35
+ 'git',
36
+ ['ls-files', '--others', '--exclude-standard'],
37
+ { cwd: root },
38
+ );
39
+ return [
40
+ ...new Set(`${tracked}\n${untracked}`.split(/\r?\n/).filter(Boolean)),
41
+ ].sort();
42
+ }
43
+
44
+ try {
45
+ if (args.includes('--help') || args.includes('-h')) {
46
+ console.log(`Usage: kerf-ui-doctor [--full | --changed] [options]
47
+
48
+ Options:
49
+ --root <path> Workspace root (default: current directory)
50
+ --package <name|path> Select one workspace package
51
+ --path <path> Restrict changed mode (repeatable)
52
+ --config <path> Doctor config (default: .kerf-ui-doctor.json)
53
+ --browser-url <url> Explicitly enable browser evaluation
54
+ --browser <list> Comma-separated chromium,firefox,webkit
55
+ --eslint <preset> recommended-ui or strict-ui
56
+ --format <format> text or json (default: text)
57
+ --output <path> Also write the merged report
58
+ --no-cache Disable the content-addressed cache
59
+
60
+ Exit codes: 0 clean, 1 findings, 2 configuration/tool failure, 130 cancelled.`);
61
+ process.exit(0);
62
+ }
63
+ const root = resolve(take('--root') ?? process.cwd());
64
+ const packageSelector = take('--package');
65
+ const explicitPaths = take('--path', true);
66
+ const configPath = take('--config');
67
+ const url = take('--browser-url');
68
+ const browserList = take('--browser');
69
+ const eslintConfig = take('--eslint') ?? 'recommended-ui';
70
+ const format = take('--format') ?? 'text';
71
+ const output = take('--output');
72
+ const full = args.includes('--full');
73
+ const changed = args.includes('--changed');
74
+ const noCache = args.includes('--no-cache');
75
+ const known = new Set(['--full', '--changed', '--no-cache']);
76
+ const unknown = args.filter((item) => !known.has(item));
77
+ if (unknown.length)
78
+ throw new Error(`Unknown arguments: ${unknown.join(' ')}`);
79
+ if (full && changed)
80
+ throw new Error('--full and --changed are mutually exclusive.');
81
+ if (!['text', 'json'].includes(format))
82
+ throw new Error('--format must be text or json.');
83
+ if (!['recommended-ui', 'strict-ui'].includes(eslintConfig))
84
+ throw new Error('--eslint must be recommended-ui or strict-ui.');
85
+ const abort = new globalThis.AbortController();
86
+ process.once('SIGINT', () => abort.abort());
87
+ const paths =
88
+ changed && !explicitPaths.length ? await changedPaths(root) : explicitPaths;
89
+ const report = await runUiDoctor({
90
+ root,
91
+ package: packageSelector,
92
+ mode: changed ? 'changed' : full ? 'full' : undefined,
93
+ paths,
94
+ configPath,
95
+ cache: !noCache,
96
+ signal: abort.signal,
97
+ eslintConfig,
98
+ browser: url
99
+ ? { url, browsers: browserList?.split(',').map((item) => item.trim()) }
100
+ : undefined,
101
+ });
102
+ const rendered =
103
+ format === 'json'
104
+ ? JSON.stringify(report, null, 2)
105
+ : formatUiDoctorText(report);
106
+ if (output) await writeFile(resolve(root, output), `${rendered}\n`);
107
+ else console.log(rendered);
108
+ process.exitCode = report.exitCode;
109
+ } catch (error) {
110
+ console.error(`kerf-ui-doctor: ${error.message}`);
111
+ process.exitCode =
112
+ process.exitCode === UI_DOCTOR_EXIT.cancelled
113
+ ? process.exitCode
114
+ : UI_DOCTOR_EXIT.configuration;
115
+ }
@@ -0,0 +1,68 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/brianwestphal/kerf/main/ui/doctor/config.schema.json",
4
+ "title": "Kerf UI doctor configuration",
5
+ "type": "object",
6
+ "required": ["schemaVersion"],
7
+ "properties": {
8
+ "$schema": { "type": "string" },
9
+ "schemaVersion": { "const": 1 },
10
+ "mode": { "enum": ["full", "changed"] },
11
+ "package": { "type": "string", "minLength": 1 },
12
+ "stages": {
13
+ "type": "object",
14
+ "properties": {
15
+ "catalog": { "type": "boolean" },
16
+ "typescript": { "type": "boolean" },
17
+ "eslint": { "type": "boolean" },
18
+ "analyzer": { "type": "boolean" },
19
+ "browser": { "type": "boolean" }
20
+ },
21
+ "additionalProperties": false
22
+ },
23
+ "browser": {
24
+ "type": "object",
25
+ "required": ["url"],
26
+ "properties": {
27
+ "url": { "type": "string", "pattern": "^https?://" },
28
+ "browsers": {
29
+ "type": "array",
30
+ "items": { "enum": ["chromium", "firefox", "webkit"] },
31
+ "uniqueItems": true
32
+ },
33
+ "retention": { "enum": ["always", "on-failure", "never"] },
34
+ "outputDirectory": { "$ref": "#/$defs/path" },
35
+ "reportPath": { "$ref": "#/$defs/path" }
36
+ },
37
+ "additionalProperties": false
38
+ },
39
+ "cache": { "type": "boolean" },
40
+ "suppressions": {
41
+ "type": "array",
42
+ "items": {
43
+ "type": "object",
44
+ "required": ["id", "rules", "target", "rationale"],
45
+ "properties": {
46
+ "id": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
47
+ "rules": {
48
+ "type": "array",
49
+ "items": { "type": "string", "minLength": 1 },
50
+ "minItems": 1,
51
+ "uniqueItems": true
52
+ },
53
+ "target": { "$ref": "#/$defs/path" },
54
+ "rationale": { "type": "string", "minLength": 12 }
55
+ },
56
+ "additionalProperties": false
57
+ }
58
+ }
59
+ },
60
+ "additionalProperties": false,
61
+ "$defs": {
62
+ "path": {
63
+ "type": "string",
64
+ "minLength": 1,
65
+ "pattern": "^(?!/)(?!.*(^|/)\\.\\.(/|$))(?!.*[?*]).+"
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,24 @@
1
+ export interface EslintDiagnosticLike {
2
+ ruleId?: string | null;
3
+ message: string;
4
+ }
5
+
6
+ export function isForeignRuleDefinitionDiagnostic(
7
+ item: EslintDiagnosticLike,
8
+ ): boolean;
9
+
10
+ export interface ConsumerEslintConfigLike {
11
+ rules?: Record<string, unknown>;
12
+ linterOptions?: Record<string, unknown>;
13
+ }
14
+
15
+ export interface ProjectedConsumerCoreConfig {
16
+ files: string[];
17
+ rules?: Record<string, unknown>;
18
+ linterOptions?: Record<string, unknown>;
19
+ }
20
+
21
+ export function projectConsumerCoreConfig(
22
+ config: ConsumerEslintConfigLike | undefined,
23
+ file: string,
24
+ ): ProjectedConsumerCoreConfig | undefined;
@@ -0,0 +1,24 @@
1
+ export function isForeignRuleDefinitionDiagnostic(item) {
2
+ return (
3
+ typeof item.ruleId === 'string' &&
4
+ !item.ruleId.startsWith('kerfjs/') &&
5
+ item.message === `Definition for rule '${item.ruleId}' was not found.`
6
+ );
7
+ }
8
+
9
+ export function projectConsumerCoreConfig(config, file) {
10
+ const rules = Object.fromEntries(
11
+ Object.entries(config?.rules ?? {}).filter(
12
+ ([ruleId]) => !ruleId.includes('/'),
13
+ ),
14
+ );
15
+ const linterOptions = config?.linterOptions
16
+ ? { ...config.linterOptions }
17
+ : undefined;
18
+ if (Object.keys(rules).length === 0 && !linterOptions) return undefined;
19
+ return {
20
+ files: [file],
21
+ ...(Object.keys(rules).length > 0 ? { rules } : {}),
22
+ ...(linterOptions ? { linterOptions } : {}),
23
+ };
24
+ }
@@ -0,0 +1,116 @@
1
+ export type UiDoctorSeverity = 'error' | 'warning' | 'review' | 'info';
2
+ export type UiDoctorStageId =
3
+ | 'catalog'
4
+ | 'typescript'
5
+ | 'eslint'
6
+ | 'analyzer'
7
+ | 'browser'
8
+ | 'doctor'
9
+ | 'merged';
10
+ export type UiDoctorStageStatus =
11
+ 'ran' | 'cached' | 'skipped' | 'unavailable' | 'failed' | 'cancelled';
12
+
13
+ export interface UiDoctorSuppression {
14
+ id: string;
15
+ rules: string[];
16
+ target: string;
17
+ rationale: string;
18
+ }
19
+
20
+ export interface UiDoctorConfig {
21
+ $schema?: string;
22
+ schemaVersion: 1;
23
+ mode?: 'full' | 'changed';
24
+ package?: string;
25
+ stages?: Partial<
26
+ Record<
27
+ 'catalog' | 'typescript' | 'eslint' | 'analyzer' | 'browser',
28
+ boolean
29
+ >
30
+ >;
31
+ browser?: {
32
+ url: string;
33
+ browsers?: Array<'chromium' | 'firefox' | 'webkit'>;
34
+ retention?: 'always' | 'on-failure' | 'never';
35
+ outputDirectory?: string;
36
+ reportPath?: string;
37
+ };
38
+ cache?: boolean;
39
+ suppressions?: UiDoctorSuppression[];
40
+ }
41
+
42
+ export interface UiDoctorDiagnostic {
43
+ id: string;
44
+ severity: UiDoctorSeverity;
45
+ stage: UiDoctorStageId | string;
46
+ message: string;
47
+ location?: { file: string; line: number; column: number; path?: string };
48
+ dom?: { context?: string; selector: string };
49
+ evidence?: unknown;
50
+ catalogFacts?: unknown;
51
+ documentation?: string;
52
+ action?: string;
53
+ sources?: string[];
54
+ }
55
+
56
+ export interface UiDoctorReport {
57
+ schemaVersion: 1;
58
+ tool: { name: '@kerfjs/ui/doctor'; reportVersion: 1 };
59
+ mode: 'full' | 'changed';
60
+ root: '.';
61
+ package: string;
62
+ paths: string[];
63
+ stages: Array<{ id: string; status: UiDoctorStageStatus; detail?: string }>;
64
+ diagnostics: UiDoctorDiagnostic[];
65
+ suppressions: Array<
66
+ UiDoctorDiagnostic & { suppression: { id: string; rationale: string } }
67
+ >;
68
+ summary: {
69
+ errors: number;
70
+ warnings: number;
71
+ review: number;
72
+ suppressed: number;
73
+ };
74
+ exitCode: 0 | 1 | 2 | 130;
75
+ cache: { hit: boolean; key: string };
76
+ }
77
+
78
+ export const UI_DOCTOR_SCHEMA_VERSION: 1;
79
+ export const UI_DOCTOR_EXIT: Readonly<{
80
+ clean: 0;
81
+ findings: 1;
82
+ configuration: 2;
83
+ cancelled: 130;
84
+ }>;
85
+ export const UI_DOCTOR_RULES: Readonly<
86
+ Record<string, { severity: UiDoctorSeverity; title: string }>
87
+ >;
88
+ export function validateUiDoctorConfig(
89
+ config: unknown,
90
+ source?: string,
91
+ ): UiDoctorDiagnostic[];
92
+ export function readUiDoctorConfig(
93
+ root: string,
94
+ path?: string,
95
+ ): Promise<{
96
+ path: string;
97
+ config: UiDoctorConfig;
98
+ diagnostics: UiDoctorDiagnostic[];
99
+ }>;
100
+ export function resolveUiDoctorPackage(
101
+ root: string,
102
+ selector?: string,
103
+ ): Promise<string>;
104
+ export function runUiDoctor(options?: {
105
+ root?: string;
106
+ package?: string;
107
+ mode?: 'full' | 'changed';
108
+ paths?: string[];
109
+ config?: UiDoctorConfig;
110
+ configPath?: string;
111
+ cache?: boolean;
112
+ signal?: AbortSignal;
113
+ browser?: UiDoctorConfig['browser'];
114
+ eslintConfig?: 'recommended-ui' | 'strict-ui';
115
+ }): Promise<UiDoctorReport>;
116
+ export function formatUiDoctorText(report: UiDoctorReport): string;