@panphora/bevel 0.1.0

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 (539) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +226 -0
  3. package/bevel-fonts.css +16 -0
  4. package/bevel.css +3075 -0
  5. package/bevel.js +2126 -0
  6. package/dist/react/components/activity-feed.d.ts +89 -0
  7. package/dist/react/components/activity-feed.js +54 -0
  8. package/dist/react/components/alert-dialog.d.ts +14 -0
  9. package/dist/react/components/alert-dialog.js +19 -0
  10. package/dist/react/components/app-shell.d.ts +98 -0
  11. package/dist/react/components/app-shell.js +86 -0
  12. package/dist/react/components/app-toolbar.d.ts +19 -0
  13. package/dist/react/components/app-toolbar.js +22 -0
  14. package/dist/react/components/avatar-group.d.ts +67 -0
  15. package/dist/react/components/avatar-group.js +49 -0
  16. package/dist/react/components/badge-and-pill.d.ts +34 -0
  17. package/dist/react/components/badge-and-pill.js +12 -0
  18. package/dist/react/components/breadcrumbs.d.ts +56 -0
  19. package/dist/react/components/breadcrumbs.js +44 -0
  20. package/dist/react/components/bulk-bar.d.ts +22 -0
  21. package/dist/react/components/bulk-bar.js +59 -0
  22. package/dist/react/components/button.d.ts +15 -0
  23. package/dist/react/components/button.js +20 -0
  24. package/dist/react/components/callout-and-hint.d.ts +17 -0
  25. package/dist/react/components/callout-and-hint.js +8 -0
  26. package/dist/react/components/checkbox.d.ts +5 -0
  27. package/dist/react/components/checkbox.js +13 -0
  28. package/dist/react/components/chip.d.ts +149 -0
  29. package/dist/react/components/chip.js +29 -0
  30. package/dist/react/components/code-block.d.ts +50 -0
  31. package/dist/react/components/code-block.js +77 -0
  32. package/dist/react/components/code-editor.d.ts +122 -0
  33. package/dist/react/components/code-editor.js +695 -0
  34. package/dist/react/components/column-manager.d.ts +28 -0
  35. package/dist/react/components/column-manager.js +85 -0
  36. package/dist/react/components/combobox.d.ts +32 -0
  37. package/dist/react/components/combobox.js +37 -0
  38. package/dist/react/components/data-grid.d.ts +108 -0
  39. package/dist/react/components/data-grid.js +159 -0
  40. package/dist/react/components/data-table.d.ts +2 -0
  41. package/dist/react/components/data-table.js +6 -0
  42. package/dist/react/components/date.d.ts +23 -0
  43. package/dist/react/components/date.js +11 -0
  44. package/dist/react/components/details.d.ts +13 -0
  45. package/dist/react/components/details.js +20 -0
  46. package/dist/react/components/dialog.d.ts +74 -0
  47. package/dist/react/components/dialog.js +31 -0
  48. package/dist/react/components/diff-view.d.ts +73 -0
  49. package/dist/react/components/diff-view.js +68 -0
  50. package/dist/react/components/documents.d.ts +70 -0
  51. package/dist/react/components/documents.js +10 -0
  52. package/dist/react/components/drawer.d.ts +45 -0
  53. package/dist/react/components/drawer.js +35 -0
  54. package/dist/react/components/editable-grid-cells.d.ts +32 -0
  55. package/dist/react/components/editable-grid-cells.js +116 -0
  56. package/dist/react/components/eyebrow-kicker-lede-pull-quote.d.ts +39 -0
  57. package/dist/react/components/eyebrow-kicker-lede-pull-quote.js +12 -0
  58. package/dist/react/components/field.d.ts +32 -0
  59. package/dist/react/components/field.js +27 -0
  60. package/dist/react/components/file-tree.d.ts +75 -0
  61. package/dist/react/components/file-tree.js +247 -0
  62. package/dist/react/components/file.d.ts +43 -0
  63. package/dist/react/components/file.js +73 -0
  64. package/dist/react/components/files-table.d.ts +174 -0
  65. package/dist/react/components/files-table.js +237 -0
  66. package/dist/react/components/filter-builder.d.ts +37 -0
  67. package/dist/react/components/filter-builder.js +109 -0
  68. package/dist/react/components/form-error-summary.d.ts +16 -0
  69. package/dist/react/components/form-error-summary.js +49 -0
  70. package/dist/react/components/icon-button.d.ts +8 -0
  71. package/dist/react/components/icon-button.js +14 -0
  72. package/dist/react/components/icon.d.ts +7 -0
  73. package/dist/react/components/icon.js +15 -0
  74. package/dist/react/components/image.d.ts +72 -0
  75. package/dist/react/components/image.js +24 -0
  76. package/dist/react/components/inline-edit.d.ts +70 -0
  77. package/dist/react/components/inline-edit.js +149 -0
  78. package/dist/react/components/input.d.ts +29 -0
  79. package/dist/react/components/input.js +20 -0
  80. package/dist/react/components/kanban-board.d.ts +140 -0
  81. package/dist/react/components/kanban-board.js +374 -0
  82. package/dist/react/components/layout.d.ts +51 -0
  83. package/dist/react/components/layout.js +28 -0
  84. package/dist/react/components/list.d.ts +28 -0
  85. package/dist/react/components/list.js +6 -0
  86. package/dist/react/components/masthead-and-verdict.d.ts +60 -0
  87. package/dist/react/components/masthead-and-verdict.js +8 -0
  88. package/dist/react/components/menu.d.ts +26 -0
  89. package/dist/react/components/menu.js +31 -0
  90. package/dist/react/components/multi-select-picker.d.ts +49 -0
  91. package/dist/react/components/multi-select-picker.js +20 -0
  92. package/dist/react/components/note.d.ts +33 -0
  93. package/dist/react/components/note.js +8 -0
  94. package/dist/react/components/number-field.d.ts +16 -0
  95. package/dist/react/components/number-field.js +17 -0
  96. package/dist/react/components/pagination.d.ts +45 -0
  97. package/dist/react/components/pagination.js +87 -0
  98. package/dist/react/components/persistent-action-banner.d.ts +71 -0
  99. package/dist/react/components/persistent-action-banner.js +39 -0
  100. package/dist/react/components/popconfirm.d.ts +42 -0
  101. package/dist/react/components/popconfirm.js +59 -0
  102. package/dist/react/components/popover.d.ts +16 -0
  103. package/dist/react/components/popover.js +21 -0
  104. package/dist/react/components/progress-and-gauge.d.ts +44 -0
  105. package/dist/react/components/progress-and-gauge.js +19 -0
  106. package/dist/react/components/radio.d.ts +7 -0
  107. package/dist/react/components/radio.js +13 -0
  108. package/dist/react/components/rich-text-toolbar.d.ts +26 -0
  109. package/dist/react/components/rich-text-toolbar.js +64 -0
  110. package/dist/react/components/rows-and-card.d.ts +88 -0
  111. package/dist/react/components/rows-and-card.js +10 -0
  112. package/dist/react/components/save-status-indicator.d.ts +11 -0
  113. package/dist/react/components/save-status-indicator.js +33 -0
  114. package/dist/react/components/segmented-control.d.ts +21 -0
  115. package/dist/react/components/segmented-control.js +15 -0
  116. package/dist/react/components/select.d.ts +29 -0
  117. package/dist/react/components/select.js +29 -0
  118. package/dist/react/components/selectable-cards.d.ts +30 -0
  119. package/dist/react/components/selectable-cards.js +29 -0
  120. package/dist/react/components/settings-rows.d.ts +51 -0
  121. package/dist/react/components/settings-rows.js +8 -0
  122. package/dist/react/components/sidebar-nav.d.ts +77 -0
  123. package/dist/react/components/sidebar-nav.js +41 -0
  124. package/dist/react/components/skeleton-and-empty.d.ts +51 -0
  125. package/dist/react/components/skeleton-and-empty.js +14 -0
  126. package/dist/react/components/slider.d.ts +19 -0
  127. package/dist/react/components/slider.js +17 -0
  128. package/dist/react/components/small-charts.d.ts +60 -0
  129. package/dist/react/components/small-charts.js +76 -0
  130. package/dist/react/components/sortable.d.ts +30 -0
  131. package/dist/react/components/sortable.js +85 -0
  132. package/dist/react/components/split-button.d.ts +38 -0
  133. package/dist/react/components/split-button.js +43 -0
  134. package/dist/react/components/split-panes.d.ts +35 -0
  135. package/dist/react/components/split-panes.js +102 -0
  136. package/dist/react/components/stat-tiles.d.ts +54 -0
  137. package/dist/react/components/stat-tiles.js +8 -0
  138. package/dist/react/components/steps.d.ts +11 -0
  139. package/dist/react/components/steps.js +13 -0
  140. package/dist/react/components/switch.d.ts +6 -0
  141. package/dist/react/components/switch.js +13 -0
  142. package/dist/react/components/table.d.ts +61 -0
  143. package/dist/react/components/table.js +6 -0
  144. package/dist/react/components/tabs.d.ts +7 -0
  145. package/dist/react/components/tabs.js +13 -0
  146. package/dist/react/components/tags.d.ts +33 -0
  147. package/dist/react/components/tags.js +83 -0
  148. package/dist/react/components/textarea.d.ts +10 -0
  149. package/dist/react/components/textarea.js +6 -0
  150. package/dist/react/components/toast.d.ts +35 -0
  151. package/dist/react/components/toast.js +90 -0
  152. package/dist/react/components/tooltip-and-key.d.ts +20 -0
  153. package/dist/react/components/tooltip-and-key.js +20 -0
  154. package/dist/react/components/tree-view.d.ts +34 -0
  155. package/dist/react/components/tree-view.js +118 -0
  156. package/dist/react/components/upload-dropzone.d.ts +92 -0
  157. package/dist/react/components/upload-dropzone.js +116 -0
  158. package/dist/react/components/wizard-shell.d.ts +78 -0
  159. package/dist/react/components/wizard-shell.js +176 -0
  160. package/dist/react/fonts.css.d.ts +1 -0
  161. package/dist/react/index.d.ts +76 -0
  162. package/dist/react/index.js +77 -0
  163. package/dist/react/integrations/quickcrop.d.ts +58 -0
  164. package/dist/react/integrations/quickcrop.js +137 -0
  165. package/dist/react/integrations/richclay.d.ts +43 -0
  166. package/dist/react/integrations/richclay.js +129 -0
  167. package/dist/react/internal/classes.d.ts +3 -0
  168. package/dist/react/internal/classes.js +10 -0
  169. package/dist/react/internal/close-mark.d.ts +1 -0
  170. package/dist/react/internal/close-mark.js +10 -0
  171. package/dist/react/internal/controllable-state.d.ts +9 -0
  172. package/dist/react/internal/controllable-state.js +22 -0
  173. package/dist/react/internal/drop-effect.d.ts +28 -0
  174. package/dist/react/internal/drop-effect.js +8 -0
  175. package/dist/react/internal/form-reset.d.ts +2 -0
  176. package/dist/react/internal/form-reset.js +22 -0
  177. package/dist/react/internal/format.d.ts +1 -0
  178. package/dist/react/internal/format.js +14 -0
  179. package/dist/react/internal/link.d.ts +2 -0
  180. package/dist/react/internal/link.js +8 -0
  181. package/dist/react/internal/part.d.ts +20 -0
  182. package/dist/react/internal/part.js +47 -0
  183. package/dist/react/internal/pointer-session.d.ts +8 -0
  184. package/dist/react/internal/pointer-session.js +60 -0
  185. package/dist/react/internal/refs.d.ts +2 -0
  186. package/dist/react/internal/refs.js +22 -0
  187. package/dist/react/internal/rich-text.d.ts +28 -0
  188. package/dist/react/internal/rich-text.js +4 -0
  189. package/dist/react/internal/table-context.d.ts +39 -0
  190. package/dist/react/internal/table-context.js +12 -0
  191. package/dist/react/internal/use-object-url.d.ts +1 -0
  192. package/dist/react/internal/use-object-url.js +15 -0
  193. package/dist/react/layout.css +274 -0
  194. package/dist/react/layout.css.d.ts +1 -0
  195. package/dist/react/models/filter.d.ts +31 -0
  196. package/dist/react/models/filter.js +79 -0
  197. package/dist/react/models/kanban.d.ts +51 -0
  198. package/dist/react/models/kanban.js +35 -0
  199. package/dist/react/models/reorder.d.ts +9 -0
  200. package/dist/react/models/reorder.js +23 -0
  201. package/dist/react/models/table.d.ts +85 -0
  202. package/dist/react/models/table.js +144 -0
  203. package/dist/react/models/tree.d.ts +16 -0
  204. package/dist/react/models/tree.js +26 -0
  205. package/dist/react/provider.d.ts +18 -0
  206. package/dist/react/provider.js +31 -0
  207. package/dist/react/recipes/context-hypercms.d.ts +17 -0
  208. package/dist/react/recipes/context-hypercms.js +71 -0
  209. package/dist/react/recipes/context-quickcrop.d.ts +8 -0
  210. package/dist/react/recipes/context-quickcrop.js +49 -0
  211. package/dist/react/theme.css +8004 -0
  212. package/dist/react/theme.css.d.ts +1 -0
  213. package/examples/README.md +34 -0
  214. package/examples/components/activity-feed.html +28 -0
  215. package/examples/components/app-shell.html +12 -0
  216. package/examples/components/app-toolbar.html +38 -0
  217. package/examples/components/avatar-group.html +27 -0
  218. package/examples/components/breadcrumbs.html +26 -0
  219. package/examples/components/bulk-bar.html +22 -0
  220. package/examples/components/code-block.html +12 -0
  221. package/examples/components/code-editor.html +25 -0
  222. package/examples/components/column-manager.html +9 -0
  223. package/examples/components/combobox.html +13 -0
  224. package/examples/components/context-hypercms.css +41 -0
  225. package/examples/components/context-hypercms.html +40 -0
  226. package/examples/components/context-hypercms.js +62 -0
  227. package/examples/components/context-quickcrop.html +137 -0
  228. package/examples/components/diff-view.html +9 -0
  229. package/examples/components/drawer.html +11 -0
  230. package/examples/components/editable-grid-cells.html +9 -0
  231. package/examples/components/file-browser.html +53 -0
  232. package/examples/components/file-tree.html +34 -0
  233. package/examples/components/files-table.html +80 -0
  234. package/examples/components/filter-builder.html +11 -0
  235. package/examples/components/form-error-summary.html +11 -0
  236. package/examples/components/index.html +51 -0
  237. package/examples/components/inline-edit.html +42 -0
  238. package/examples/components/kanban-board.html +42 -0
  239. package/examples/components/manifest.json +3279 -0
  240. package/examples/components/modal.html +11 -0
  241. package/examples/components/multi-select-picker.html +13 -0
  242. package/examples/components/pagination.html +32 -0
  243. package/examples/components/persistent-action-banner.html +23 -0
  244. package/examples/components/popconfirm.html +13 -0
  245. package/examples/components/popover-menu.html +13 -0
  246. package/examples/components/reference/baseline/DECISIONS.md +85 -0
  247. package/examples/components/reference/baseline/README.md +58 -0
  248. package/examples/components/reference/baseline/bevel-fonts.css +16 -0
  249. package/examples/components/reference/baseline/bevel.css +1339 -0
  250. package/examples/components/reference/baseline/bevel.js +496 -0
  251. package/examples/components/reference/baseline/fonts/LICENSE-ibm-plex-mono.txt +93 -0
  252. package/examples/components/reference/baseline/fonts/LICENSE-ibm-plex-sans.txt +93 -0
  253. package/examples/components/reference/baseline/fonts/LICENSE-newsreader.txt +93 -0
  254. package/examples/components/reference/baseline/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  255. package/examples/components/reference/baseline/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  256. package/examples/components/reference/baseline/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  257. package/examples/components/reference/baseline/fonts/ibm-plex-sans-latin-400-italic.woff2 +0 -0
  258. package/examples/components/reference/baseline/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
  259. package/examples/components/reference/baseline/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
  260. package/examples/components/reference/baseline/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
  261. package/examples/components/reference/baseline/fonts/newsreader-latin-opsz-italic.woff2 +0 -0
  262. package/examples/components/reference/baseline/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
  263. package/examples/components/reference/fable/IMPROVEMENTS.md +106 -0
  264. package/examples/components/reference/fable/PARENT-REPAIRS.md +17 -0
  265. package/examples/components/reference/fable/__pycache__/build_repairs.cpython-311.pyc +0 -0
  266. package/examples/components/reference/fable/__pycache__/kanban.cpython-311.pyc +0 -0
  267. package/examples/components/reference/fable/as-authored/IMPROVEMENTS-completed.md +106 -0
  268. package/examples/components/reference/fable/as-authored/base-astra.css +17 -0
  269. package/examples/components/reference/fable/as-authored/base-parent.css +416 -0
  270. package/examples/components/reference/fable/as-authored/build.py +858 -0
  271. package/examples/components/reference/fable/as-authored/fable.css +823 -0
  272. package/examples/components/reference/fable/as-authored/kanban-completed.css +235 -0
  273. package/examples/components/reference/fable/as-authored/kanban-completed.html +53 -0
  274. package/examples/components/reference/fable/as-authored/kanban-completed.py +212 -0
  275. package/examples/components/reference/fable/as-authored/kanban.py +207 -0
  276. package/examples/components/reference/fable/base-astra.css +17 -0
  277. package/examples/components/reference/fable/base-parent.css +416 -0
  278. package/examples/components/reference/fable/build.py +858 -0
  279. package/examples/components/reference/fable/build_repairs.py +25 -0
  280. package/examples/components/reference/fable/components/activity-feed.html +3 -0
  281. package/examples/components/reference/fable/components/app-toolbar.html +3 -0
  282. package/examples/components/reference/fable/components/avatar-group.html +4 -0
  283. package/examples/components/reference/fable/components/breadcrumbs.html +3 -0
  284. package/examples/components/reference/fable/components/code-block.html +9 -0
  285. package/examples/components/reference/fable/components/column-manager.html +3 -0
  286. package/examples/components/reference/fable/components/combobox.html +6 -0
  287. package/examples/components/reference/fable/components/context-hypercms.html +3 -0
  288. package/examples/components/reference/fable/components/context-quickcrop.html +4 -0
  289. package/examples/components/reference/fable/components/diff-view.html +13 -0
  290. package/examples/components/reference/fable/components/drawer.html +3 -0
  291. package/examples/components/reference/fable/components/editable-grid-cells.html +3 -0
  292. package/examples/components/reference/fable/components/filter-builder.html +3 -0
  293. package/examples/components/reference/fable/components/form-error-summary.html +4 -0
  294. package/examples/components/reference/fable/components/inline-edit.html +3 -0
  295. package/examples/components/reference/fable/components/kanban-board.html +53 -0
  296. package/examples/components/reference/fable/components/modal.html +3 -0
  297. package/examples/components/reference/fable/components/multi-select-picker.html +5 -0
  298. package/examples/components/reference/fable/components/pagination.html +3 -0
  299. package/examples/components/reference/fable/components/persistent-action-banner.html +4 -0
  300. package/examples/components/reference/fable/components/popconfirm.html +5 -0
  301. package/examples/components/reference/fable/components/popover-menu.html +3 -0
  302. package/examples/components/reference/fable/components/rich-text-toolbar.html +3 -0
  303. package/examples/components/reference/fable/components/save-status-indicator.html +2 -0
  304. package/examples/components/reference/fable/components/selectable-cards.html +3 -0
  305. package/examples/components/reference/fable/components/settings-rows.html +3 -0
  306. package/examples/components/reference/fable/components/sidebar-nav.html +4 -0
  307. package/examples/components/reference/fable/components/small-charts.html +5 -0
  308. package/examples/components/reference/fable/components/split-button.html +4 -0
  309. package/examples/components/reference/fable/components/split-panes.html +8 -0
  310. package/examples/components/reference/fable/components/stat-tiles.html +3 -0
  311. package/examples/components/reference/fable/components/toast-stack.html +5 -0
  312. package/examples/components/reference/fable/components/tree-view.html +4 -0
  313. package/examples/components/reference/fable/components/upload-dropzone.html +6 -0
  314. package/examples/components/reference/fable/components/wizard-shell.html +3 -0
  315. package/examples/components/reference/fable/coverage.json +414 -0
  316. package/examples/components/reference/fable/fable.css +823 -0
  317. package/examples/components/reference/fable/index.html +5 -0
  318. package/examples/components/reference/fable/kanban.css +237 -0
  319. package/examples/components/reference/fable/kanban.py +212 -0
  320. package/examples/components/reference/fable/parent-repairs.css +9 -0
  321. package/examples/components/reference/fixtures/data.json +102 -0
  322. package/examples/components/reference/fixtures/host.js +47 -0
  323. package/examples/components/reference/fixtures/static-host.js +39 -0
  324. package/examples/components/reference/fixtures/workspace.jpg +0 -0
  325. package/examples/components/reference/parent/CHANGES.md +179 -0
  326. package/examples/components/reference/parent/__pycache__/kanban.cpython-311.pyc +0 -0
  327. package/examples/components/reference/parent/base-astra.css +17 -0
  328. package/examples/components/reference/parent/base-parent.css +416 -0
  329. package/examples/components/reference/parent/build.py +148 -0
  330. package/examples/components/reference/parent/components/activity-feed.html +2 -0
  331. package/examples/components/reference/parent/components/app-toolbar.html +2 -0
  332. package/examples/components/reference/parent/components/avatar-group.html +4 -0
  333. package/examples/components/reference/parent/components/breadcrumbs.html +2 -0
  334. package/examples/components/reference/parent/components/code-block.html +8 -0
  335. package/examples/components/reference/parent/components/column-manager.html +2 -0
  336. package/examples/components/reference/parent/components/combobox.html +6 -0
  337. package/examples/components/reference/parent/components/context-hypercms.html +2 -0
  338. package/examples/components/reference/parent/components/context-quickcrop.html +4 -0
  339. package/examples/components/reference/parent/components/diff-view.html +4 -0
  340. package/examples/components/reference/parent/components/drawer.html +2 -0
  341. package/examples/components/reference/parent/components/editable-grid-cells.html +2 -0
  342. package/examples/components/reference/parent/components/filter-builder.html +2 -0
  343. package/examples/components/reference/parent/components/form-error-summary.html +2 -0
  344. package/examples/components/reference/parent/components/inline-edit.html +2 -0
  345. package/examples/components/reference/parent/components/kanban-board.html +84 -0
  346. package/examples/components/reference/parent/components/modal.html +2 -0
  347. package/examples/components/reference/parent/components/multi-select-picker.html +5 -0
  348. package/examples/components/reference/parent/components/pagination.html +2 -0
  349. package/examples/components/reference/parent/components/persistent-action-banner.html +4 -0
  350. package/examples/components/reference/parent/components/popconfirm.html +5 -0
  351. package/examples/components/reference/parent/components/popover-menu.html +2 -0
  352. package/examples/components/reference/parent/components/rich-text-toolbar.html +2 -0
  353. package/examples/components/reference/parent/components/save-status-indicator.html +2 -0
  354. package/examples/components/reference/parent/components/selectable-cards.html +2 -0
  355. package/examples/components/reference/parent/components/settings-rows.html +2 -0
  356. package/examples/components/reference/parent/components/sidebar-nav.html +4 -0
  357. package/examples/components/reference/parent/components/small-charts.html +2 -0
  358. package/examples/components/reference/parent/components/split-button.html +5 -0
  359. package/examples/components/reference/parent/components/split-panes.html +8 -0
  360. package/examples/components/reference/parent/components/stat-tiles.html +2 -0
  361. package/examples/components/reference/parent/components/toast-stack.html +5 -0
  362. package/examples/components/reference/parent/components/tree-view.html +4 -0
  363. package/examples/components/reference/parent/components/upload-dropzone.html +6 -0
  364. package/examples/components/reference/parent/components/wizard-shell.html +2 -0
  365. package/examples/components/reference/parent/coverage.json +414 -0
  366. package/examples/components/reference/parent/index.html +1 -0
  367. package/examples/components/reference/parent/kanban.css +114 -0
  368. package/examples/components/reference/parent/kanban.py +55 -0
  369. package/examples/components/reference/parent/refinement.css +53 -0
  370. package/examples/components/reference/selected/build.py +70 -0
  371. package/examples/components/reference/selected/components/activity-feed.html +3 -0
  372. package/examples/components/reference/selected/components/app-toolbar.html +3 -0
  373. package/examples/components/reference/selected/components/avatar-group.html +4 -0
  374. package/examples/components/reference/selected/components/breadcrumbs.html +3 -0
  375. package/examples/components/reference/selected/components/code-block.html +9 -0
  376. package/examples/components/reference/selected/components/column-manager.html +3 -0
  377. package/examples/components/reference/selected/components/combobox.html +6 -0
  378. package/examples/components/reference/selected/components/context-hypercms.html +3 -0
  379. package/examples/components/reference/selected/components/context-quickcrop.html +4 -0
  380. package/examples/components/reference/selected/components/diff-view.html +13 -0
  381. package/examples/components/reference/selected/components/drawer.html +3 -0
  382. package/examples/components/reference/selected/components/editable-grid-cells.html +3 -0
  383. package/examples/components/reference/selected/components/filter-builder.html +3 -0
  384. package/examples/components/reference/selected/components/form-error-summary.html +4 -0
  385. package/examples/components/reference/selected/components/inline-edit.html +3 -0
  386. package/examples/components/reference/selected/components/kanban-board.html +53 -0
  387. package/examples/components/reference/selected/components/modal.html +2 -0
  388. package/examples/components/reference/selected/components/multi-select-picker.html +5 -0
  389. package/examples/components/reference/selected/components/pagination.html +3 -0
  390. package/examples/components/reference/selected/components/persistent-action-banner.html +4 -0
  391. package/examples/components/reference/selected/components/popconfirm.html +5 -0
  392. package/examples/components/reference/selected/components/popover-menu.html +3 -0
  393. package/examples/components/reference/selected/components/rich-text-toolbar.html +3 -0
  394. package/examples/components/reference/selected/components/save-status-indicator.html +2 -0
  395. package/examples/components/reference/selected/components/selectable-cards.html +3 -0
  396. package/examples/components/reference/selected/components/settings-rows.html +3 -0
  397. package/examples/components/reference/selected/components/sidebar-nav.html +4 -0
  398. package/examples/components/reference/selected/components/small-charts.html +5 -0
  399. package/examples/components/reference/selected/components/split-button.html +4 -0
  400. package/examples/components/reference/selected/components/split-panes.html +8 -0
  401. package/examples/components/reference/selected/components/stat-tiles.html +3 -0
  402. package/examples/components/reference/selected/components/toast-stack.html +5 -0
  403. package/examples/components/reference/selected/components/tree-view.html +4 -0
  404. package/examples/components/reference/selected/components/upload-dropzone.html +6 -0
  405. package/examples/components/reference/selected/components/wizard-shell.html +3 -0
  406. package/examples/components/reference/selected/corrections.css +11 -0
  407. package/examples/components/reference/selected/coverage.json +413 -0
  408. package/examples/components/reference/selected/gallery-build.mjs +49 -0
  409. package/examples/components/reference/selected/gallery-spec.json +12 -0
  410. package/examples/components/reference/selected/index.html +1 -0
  411. package/examples/components/reference/selected/kanban-comparison.json +6 -0
  412. package/examples/components/reference/selected/manifest.json +476 -0
  413. package/examples/components/reference/sha256.json +142 -0
  414. package/examples/components/reference/sources/diagonal-close.svg +1 -0
  415. package/examples/components/reference/sources/hyperclay/public-assets/css/hyperclay-app-source.css +614 -0
  416. package/examples/components/reference/sources/hyperclay/public-assets/js/app.js +94 -0
  417. package/examples/components/reference/sources/hyperclayjs/src/ui/theModal.js +897 -0
  418. package/examples/components/reference/sources/hypercms/scripts/build-theme.js +203 -0
  419. package/examples/components/reference/sources/hypercms/src/anchor.js +24 -0
  420. package/examples/components/reference/sources/hypercms/src/apply-loop.js +167 -0
  421. package/examples/components/reference/sources/hypercms/src/diagnostics.js +44 -0
  422. package/examples/components/reference/sources/hypercms/src/enhance.js +173 -0
  423. package/examples/components/reference/sources/hypercms/src/events.js +955 -0
  424. package/examples/components/reference/sources/hypercms/src/form-builder.js +518 -0
  425. package/examples/components/reference/sources/hypercms/src/form-rules.js +208 -0
  426. package/examples/components/reference/sources/hypercms/src/hooks.js +100 -0
  427. package/examples/components/reference/sources/hypercms/src/hypercms-bundle.js +10 -0
  428. package/examples/components/reference/sources/hypercms/src/hypercms.js +347 -0
  429. package/examples/components/reference/sources/hypercms/src/morph.js +10 -0
  430. package/examples/components/reference/sources/hypercms/src/path.js +61 -0
  431. package/examples/components/reference/sources/hypercms/src/place.js +131 -0
  432. package/examples/components/reference/sources/hypercms/src/platform.js +131 -0
  433. package/examples/components/reference/sources/hypercms/src/refresh.js +87 -0
  434. package/examples/components/reference/sources/hypercms/src/richclay-bridge.js +140 -0
  435. package/examples/components/reference/sources/hypercms/src/row-identity.js +111 -0
  436. package/examples/components/reference/sources/hypercms/src/scaffold.js +10 -0
  437. package/examples/components/reference/sources/hypercms/src/session.js +303 -0
  438. package/examples/components/reference/sources/hypercms/src/shell.js +248 -0
  439. package/examples/components/reference/sources/hypercms/src/styles.css +298 -0
  440. package/examples/components/reference/sources/hypercms/src/targets.js +144 -0
  441. package/examples/components/reference/sources/hypercms/src/templates.js +656 -0
  442. package/examples/components/reference/sources/hypercms/src/theme/pixel-quiet.overrides.css +761 -0
  443. package/examples/components/reference/sources/hypercms/src/theme.generated.css +1772 -0
  444. package/examples/components/reference/sources/hypercms/src/toggle.js +666 -0
  445. package/examples/components/reference/sources/hypercms/src/unresolved.js +211 -0
  446. package/examples/components/reference/sources/hypercms/src/vendor/mirk.vendor.js +212 -0
  447. package/examples/components/reference/sources/hypercms/src/views/inline-layer.js +421 -0
  448. package/examples/components/reference/sources/hypercms/src/views/inline.js +1072 -0
  449. package/examples/components/reference/sources/hypercms/src/views/sidebar.js +97 -0
  450. package/examples/components/reference/sources/modal-reference.html +301 -0
  451. package/examples/components/reference/sources/quickcrop/quickcrop.css +124 -0
  452. package/examples/components/reference/sources/quickcrop/quickcrop.js +400 -0
  453. package/examples/components/reference/sources/richclay/richclay.css +416 -0
  454. package/examples/components/reference/sources/richclay/richclay.js +2962 -0
  455. package/examples/components/reference/sources/richclay/src/a11y.js +67 -0
  456. package/examples/components/reference/sources/richclay/src/browser-global.js +7 -0
  457. package/examples/components/reference/sources/richclay/src/buttons.js +254 -0
  458. package/examples/components/reference/sources/richclay/src/hyperclay.js +470 -0
  459. package/examples/components/reference/sources/richclay/src/normalize.js +380 -0
  460. package/examples/components/reference/sources/richclay/src/richclay.js +1356 -0
  461. package/examples/components/reference/sources/richclay/src/sanitize.js +189 -0
  462. package/examples/components/reference/sources/richclay/src/styles.js +23 -0
  463. package/examples/components/reference/sources/richclay/src/toolbar-float.js +175 -0
  464. package/examples/components/reference/sources/richclay/src/toolbar.js +394 -0
  465. package/examples/components/reference/sources/richclay/src/vendor-bundle.js +15 -0
  466. package/examples/components/reference/sources/richclay/vendor/DOMPURIFY-LICENSE +202 -0
  467. package/examples/components/reference/sources/richclay/vendor/DOMPURIFY-LICENSE-MPL +373 -0
  468. package/examples/components/reference/sources/richclay/vendor/SQUIRE-LICENSE +21 -0
  469. package/examples/components/reference/sources/richclay/vendor/purify.es.mjs +2249 -0
  470. package/examples/components/reference/sources/richclay/vendor/purify.min.js +3 -0
  471. package/examples/components/reference/sources/richclay/vendor/squire.js +22 -0
  472. package/examples/components/reference/sources/richclay/vendor/squire.mjs +22 -0
  473. package/examples/components/reference/sources/richclay/vendor/squire.provenance.json +19 -0
  474. package/examples/components/rich-text-toolbar.html +43 -0
  475. package/examples/components/save-status-indicator.html +11 -0
  476. package/examples/components/selectable-cards.html +9 -0
  477. package/examples/components/settings-rows.html +10 -0
  478. package/examples/components/sidebar-nav.html +9 -0
  479. package/examples/components/small-charts.html +21 -0
  480. package/examples/components/split-button.html +13 -0
  481. package/examples/components/split-panes-editor.html +6 -0
  482. package/examples/components/split-panes.html +9 -0
  483. package/examples/components/stat-tiles.html +23 -0
  484. package/examples/components/toast-stack.html +21 -0
  485. package/examples/components/tree-view.html +9 -0
  486. package/examples/components/upload-dropzone.html +88 -0
  487. package/examples/components/wizard-shell.html +50 -0
  488. package/examples/datastar/index.html +38 -0
  489. package/examples/datastar/server.mjs +31 -0
  490. package/examples/fixtures/field-guide.pdf +14 -0
  491. package/examples/fixtures/workspace.jpg +0 -0
  492. package/examples/setup-peers.mjs +35 -0
  493. package/fonts/LICENSE-ibm-plex-mono.txt +93 -0
  494. package/fonts/LICENSE-ibm-plex-sans.txt +93 -0
  495. package/fonts/LICENSE-newsreader.txt +93 -0
  496. package/fonts/ibm-plex-mono-latin-400-normal.woff2 +0 -0
  497. package/fonts/ibm-plex-mono-latin-500-normal.woff2 +0 -0
  498. package/fonts/ibm-plex-mono-latin-600-normal.woff2 +0 -0
  499. package/fonts/ibm-plex-sans-latin-400-italic.woff2 +0 -0
  500. package/fonts/ibm-plex-sans-latin-400-normal.woff2 +0 -0
  501. package/fonts/ibm-plex-sans-latin-500-normal.woff2 +0 -0
  502. package/fonts/ibm-plex-sans-latin-600-normal.woff2 +0 -0
  503. package/fonts/newsreader-latin-opsz-italic.woff2 +0 -0
  504. package/fonts/newsreader-latin-opsz-normal.woff2 +0 -0
  505. package/icons/LICENSE +21 -0
  506. package/icons/house.json +71 -0
  507. package/icons/icons.d.ts +17 -0
  508. package/icons/icons.js +648 -0
  509. package/icons/icons.svg +126 -0
  510. package/icons/marks/build-tray.source.mjs +45 -0
  511. package/icons/marks/hyperclay-local.svg +11 -0
  512. package/icons/phosphor.json +53 -0
  513. package/icons/round.json +8 -0
  514. package/integrations/datastar.js +202 -0
  515. package/integrations/quickcrop.css +26 -0
  516. package/integrations/quickcrop.js +56 -0
  517. package/integrations/richclay.css +100 -0
  518. package/integrations/richclay.js +131 -0
  519. package/package.json +630 -0
  520. package/react/README.md +244 -0
  521. package/src/README.md +83 -0
  522. package/vendor/datastar/datastar-1.0.3.js +10 -0
  523. package/vendor/datastar/provenance.json +6 -0
  524. package/vendor/floating-ui/LICENSE-core +20 -0
  525. package/vendor/floating-ui/LICENSE-dom +20 -0
  526. package/vendor/floating-ui/floating-ui.core.umd.min.js +1 -0
  527. package/vendor/floating-ui/floating-ui.dom.umd.min.js +1 -0
  528. package/vendor/floating-ui/provenance.json +17 -0
  529. package/vendor/richclay/LICENSE +16 -0
  530. package/vendor/richclay/THIRD-PARTY-NOTICES.md +45 -0
  531. package/vendor/richclay/provenance.json +17 -0
  532. package/vendor/richclay/richclay.css +404 -0
  533. package/vendor/richclay/richclay.js +2940 -0
  534. package/vendor/richclay/vendor/DOMPURIFY-LICENSE +202 -0
  535. package/vendor/richclay/vendor/DOMPURIFY-LICENSE-MPL +373 -0
  536. package/vendor/richclay/vendor/SQUIRE-LICENSE +21 -0
  537. package/vendor/richclay/vendor/purify.min.js +3 -0
  538. package/vendor/richclay/vendor/squire.js +22 -0
  539. package/vendor/richclay/vendor/squire.provenance.json +30 -0
@@ -0,0 +1,656 @@
1
+ import { ruleAttrIndex } from 'hyper-html-api/engine'
2
+ import { getRuleAtPath } from './path.js'
3
+
4
+ export function humanize(key) {
5
+ return key
6
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
7
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
8
+ .replace(/[-_]/g, ' ')
9
+ .replace(/\s+/g, ' ')
10
+ .trim()
11
+ .replace(/^./, (c) => c.toUpperCase())
12
+ }
13
+
14
+ // The default templates emit real mirk-interface markup so the generated form
15
+ // renders in the Pixel Quiet look out of the box. Every data-hcms-* hook
16
+ // (shape, label, field, action, the .hcms-array-items / .hcms-card-fields slots,
17
+ // the .hcms-error inline slots) is preserved exactly, so the engine, events,
18
+ // add/remove/reorder, and inline-error placement bind unchanged. The CSS that
19
+ // dresses these lives in src/theme.generated.css (scoped mirk + pixel-quiet).
20
+ const SORTABLE_GRIP = `<div class="hcms-drag-handle mirk-sortable__grip" aria-hidden="true"><div class="mirk-sortable__dots"><span class="mirk-sortable__dot"></span><span class="mirk-sortable__dot"></span><span class="mirk-sortable__dot"></span><span class="mirk-sortable__dot"></span><span class="mirk-sortable__dot"></span><span class="mirk-sortable__dot"></span><span class="mirk-sortable__dot"></span><span class="mirk-sortable__dot"></span></div></div>`
21
+
22
+ // Crisp-line × (square caps + crispEdges): a plain pixel-sharp close glyph that
23
+ // stays hard-edged inside the small square corner button on object-array cards.
24
+ const CLOSE_ICON = `<svg class="hcms-x" viewBox="0 0 16 16" shape-rendering="crispEdges" aria-hidden="true"><path d="M4 4 L12 12 M12 4 L4 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square"></path></svg>`
25
+
26
+ const DEFAULT_TEMPLATES = {
27
+ // The default scalar is a one-row auto-growing textarea, not an <input>:
28
+ // page copy is prose and routinely wraps. Growth comes from field-sizing:
29
+ // content in the theme, with a scrollHeight fallback (enhance.js).
30
+ '@scalar': `
31
+ <label class="hcms-field" data-hcms-shape="scalar">
32
+ <span class="hcms-label" data-hcms-label></span>
33
+ <textarea class="mirk-textarea" rows="1" data-hcms-field></textarea>
34
+ <div class="hcms-error" hidden></div>
35
+ </label>
36
+ `,
37
+ '@object': `
38
+ <section class="hcms-object" data-hcms-shape="object">
39
+ <h3 class="hcms-object-title" data-hcms-label></h3>
40
+ <div class="hcms-object-fields"></div>
41
+ <div class="hcms-error" hidden></div>
42
+ </section>
43
+ `,
44
+ '@scalar-array': `
45
+ <section class="hcms-array hcms-scalar-array" data-hcms-shape="scalar-array">
46
+ <header class="hcms-array-header">
47
+ <h3 class="hcms-array-title" data-hcms-label></h3>
48
+ </header>
49
+ <ul class="hcms-array-items"></ul>
50
+ <div class="hcms-error" hidden></div>
51
+ <button type="button" class="hcms-add mirk-button mirk-button--small" data-hcms-action="add"><span class="mirk-button__label">+ Add</span></button>
52
+ </section>
53
+ `,
54
+ '@scalar-array-item': `
55
+ <li class="hcms-array-item" draggable="true">
56
+ <input class="mirk-input" data-hcms-field />
57
+ <button type="button" class="hcms-move hcms-move-up hcms-sr-only" data-hcms-action="move-up" aria-label="Move up">↑</button>
58
+ <button type="button" class="hcms-move hcms-move-down hcms-sr-only" data-hcms-action="move-down" aria-label="Move down">↓</button>
59
+ <button type="button" class="hcms-remove" data-hcms-action="remove" aria-label="Remove">×</button>
60
+ <div class="hcms-error" hidden></div>
61
+ </li>
62
+ `,
63
+ '@object-array': `
64
+ <section class="hcms-array hcms-object-array hcms-array--cards" data-hcms-shape="object-array">
65
+ <header class="hcms-array-header">
66
+ <h3 class="hcms-array-title" data-hcms-label></h3>
67
+ </header>
68
+ <div class="hcms-array-items"></div>
69
+ <div class="hcms-error" hidden></div>
70
+ <button type="button" class="hcms-add mirk-button mirk-button--small" data-hcms-action="add"><span class="mirk-button__label">+ Add</span></button>
71
+ </section>
72
+ `,
73
+ '@object-array-item': `
74
+ <article class="hcms-card mirk-sortable__item" draggable="true">
75
+ ${SORTABLE_GRIP}
76
+ <div class="hcms-card-body mirk-sortable__body">
77
+ <div class="hcms-card-fields"></div>
78
+ <div class="hcms-card-controls">
79
+ <button type="button" class="hcms-move hcms-move-up hcms-sr-only" data-hcms-action="move-up" aria-label="Move up">↑</button>
80
+ <button type="button" class="hcms-move hcms-move-down hcms-sr-only" data-hcms-action="move-down" aria-label="Move down">↓</button>
81
+ <button type="button" class="hcms-remove hcms-remove--card" data-hcms-action="remove" aria-label="Remove">${CLOSE_ICON}</button>
82
+ </div>
83
+ </div>
84
+ <div class="hcms-error" hidden></div>
85
+ </article>
86
+ `,
87
+ // Opt-in upload components. Built on the kit's consolidated mirk chrome (all
88
+ // themed in theme.generated.css), with interactive hooks kept on data-hcms-*
89
+ // so the vendored mirk runtime (which keys off .mirk-*__input / .mirk-*__remove)
90
+ // never double-handles a CMS field. The bound value is the leaf's URL: the
91
+ // <a href> for @file, the <img src> for @image. Empty/filled chrome is driven
92
+ // by that attribute in CSS (.hcms-upload* in pixel-quiet.overrides.css), no JS.
93
+ '@file': `
94
+ <div class="hcms-field hcms-upload hcms-upload--file" data-hcms-shape="scalar">
95
+ <span class="hcms-label" data-hcms-label></span>
96
+ <div class="mirk-file mirk-file--compact mirk-file--round">
97
+ <label class="mirk-button mirk-button--round mirk-button--small">
98
+ <input type="file" data-hcms-upload />
99
+ <span class="mirk-button__label">Choose</span>
100
+ </label>
101
+ <a class="mirk-file__name" data-hcms-field></a>
102
+ <button type="button" class="hcms-upload-clear" data-hcms-action="clear-upload" aria-label="Remove file">${CLOSE_ICON}</button>
103
+ </div>
104
+ <div class="hcms-error" hidden></div>
105
+ </div>
106
+ `,
107
+ '@image': `
108
+ <div class="hcms-field hcms-upload hcms-upload--image" data-hcms-shape="scalar">
109
+ <span class="hcms-label" data-hcms-label></span>
110
+ <div class="mirk-image mirk-image--compact mirk-image--rounded">
111
+ <label class="mirk-button mirk-button--small mirk-image__upload">
112
+ <input type="file" accept="image/*" data-hcms-upload />
113
+ <span class="mirk-button__label">Upload image</span>
114
+ </label>
115
+ <figure class="mirk-image__thumb">
116
+ <span class="mirk-image__frame"><img class="mirk-image__preview" data-hcms-field alt="" /></span>
117
+ <button type="button" class="hcms-upload-clear hcms-upload-clear--badge" data-hcms-action="clear-upload" aria-label="Remove image">${CLOSE_ICON}</button>
118
+ </figure>
119
+ </div>
120
+ <div class="hcms-error" hidden></div>
121
+ </div>
122
+ `,
123
+ // Named built-in controls, opt-in via data-hcms-component on the page element
124
+ // a rule points at. Promoted from the demo custom templates (mirk chrome,
125
+ // already themed in theme.generated.css), so the easy path needs no template
126
+ // authoring. @checkbox/@toggle bind the same input[type=checkbox]@checked
127
+ // machinery; @select/@radio get their entries from data-hcms-options (the
128
+ // form-builder populates the empty <select> / clones the radio prototype).
129
+ '@checkbox': `
130
+ <div class="hcms-field hcms-field--row" data-hcms-shape="scalar">
131
+ <span class="hcms-label" data-hcms-label></span>
132
+ <label class="mirk-checkbox">
133
+ <input type="checkbox" class="mirk-sr-only" data-hcms-field />
134
+ <span class="mirk-checkbox__box"><span class="mirk-checkbox__mark"></span></span>
135
+ </label>
136
+ <div class="hcms-error" hidden></div>
137
+ </div>
138
+ `,
139
+ '@toggle': `
140
+ <div class="hcms-field hcms-field--row" data-hcms-shape="scalar">
141
+ <span class="hcms-label" data-hcms-label></span>
142
+ <label class="mirk-toggle">
143
+ <input type="checkbox" role="switch" class="mirk-sr-only" data-hcms-field />
144
+ <span class="mirk-toggle__track"><span class="mirk-toggle__thumb"></span></span>
145
+ </label>
146
+ <div class="hcms-error" hidden></div>
147
+ </div>
148
+ `,
149
+ '@select': `
150
+ <label class="hcms-field" data-hcms-shape="scalar">
151
+ <span class="hcms-label" data-hcms-label></span>
152
+ <div class="mirk-select">
153
+ <select class="mirk-select__field" data-hcms-field></select>
154
+ <span aria-hidden="true" class="mirk-select__chevron">›</span>
155
+ </div>
156
+ <div class="hcms-error" hidden></div>
157
+ </label>
158
+ `,
159
+ '@radio': `
160
+ <div class="hcms-field" data-hcms-shape="scalar">
161
+ <span class="hcms-label" data-hcms-label></span>
162
+ <div class="hcms-radio-row">
163
+ <label class="mirk-radio">
164
+ <input type="radio" class="mirk-sr-only" data-hcms-field />
165
+ <span class="mirk-radio__ring"><span class="mirk-radio__fill"></span><span class="mirk-radio__dot"></span></span>
166
+ <span class="mirk-radio__label"></span>
167
+ </label>
168
+ </div>
169
+ <div class="hcms-error" hidden></div>
170
+ </div>
171
+ `,
172
+ '@textarea': `
173
+ <label class="hcms-field" data-hcms-shape="scalar">
174
+ <span class="hcms-label" data-hcms-label></span>
175
+ <textarea class="mirk-textarea" rows="3" data-hcms-field></textarea>
176
+ <div class="hcms-error" hidden></div>
177
+ </label>
178
+ `,
179
+ // Rich-text surface for @innerHTML-bound rules: a contenteditable div whose
180
+ // value interface is innerHTML (fieldPropertyFor), so links and inline
181
+ // formatting survive the round-trip. richclay mounts on it when the host
182
+ // page ships it (enhance.js); otherwise it stays a plain contenteditable.
183
+ '@richtext': `
184
+ <div class="hcms-field" data-hcms-shape="scalar">
185
+ <span class="hcms-label" data-hcms-label></span>
186
+ <div class="mirk-textarea hcms-richtext" contenteditable="true" data-hcms-field></div>
187
+ <div class="hcms-error" hidden></div>
188
+ </div>
189
+ `,
190
+ '@number': `
191
+ <label class="hcms-field" data-hcms-shape="scalar">
192
+ <span class="hcms-label" data-hcms-label></span>
193
+ <input class="mirk-input" type="number" data-hcms-field />
194
+ <div class="hcms-error" hidden></div>
195
+ </label>
196
+ `,
197
+ '@chips': `
198
+ <div class="hcms-field hcms-chips" data-hcms-shape="scalar-array">
199
+ <span class="hcms-label" data-hcms-label></span>
200
+ <div class="mirk-tags hcms-array-items"></div>
201
+ <button type="button" class="hcms-add mirk-button mirk-button--small" data-hcms-action="add"><span class="mirk-button__label">+ Add</span></button>
202
+ <div class="hcms-error" hidden></div>
203
+ </div>
204
+ `,
205
+ '@chips-item': `
206
+ <span class="mirk-tags__chip" data-hcms-array-item>
207
+ <input class="hcms-chip-field" data-hcms-field aria-label="Item" placeholder="…" />
208
+ <button type="button" class="hcms-remove" data-hcms-action="remove" aria-label="Remove">×</button>
209
+ </span>
210
+ `,
211
+ }
212
+
213
+ // Shape templates fill-the-gaps on every managed page. The opt-in components
214
+ // (@file/@image uploads + the named controls) are injected on demand the first
215
+ // time a field selects them (the Slice-2 component seam), so pages using none
216
+ // stay clean.
217
+ const ALWAYS_INJECT_KEYS = [
218
+ '@scalar',
219
+ '@object',
220
+ '@scalar-array',
221
+ '@scalar-array-item',
222
+ '@object-array',
223
+ '@object-array-item',
224
+ ]
225
+
226
+ export function injectDefaults(doc) {
227
+ const head = doc.head || doc.documentElement
228
+ if (!head) return
229
+ for (const key of ALWAYS_INJECT_KEYS) injectTemplate(doc, head, key)
230
+ }
231
+
232
+ // Inject one opt-in component template if the page hasn't already defined its
233
+ // own. Called by the component-selection seam the first time a field resolves
234
+ // to a component.
235
+ export function injectComponentTemplate(doc, key) {
236
+ if (!DEFAULT_TEMPLATES[key]) return null
237
+ const head = doc && (doc.head || doc.documentElement)
238
+ if (!head) return null
239
+ return injectTemplate(doc, head, key)
240
+ }
241
+
242
+ // Named-component selection. Explicit beats inferred: a data-hcms-component
243
+ // attribute on the page element a rule points at wins over the @prop-suffix
244
+ // inference, so a checked-bound field can still opt into the @toggle look.
245
+ // Inference stays narrow: @src means image upload (the dominant image-CMS
246
+ // workflow) and @checked means checkbox (a text input showing the literal word
247
+ // "true" helps nobody). @href is NOT inferred: editing a link/URL is far more
248
+ // common than uploading a file, so an a@href rule stays a plain URL field and
249
+ // the file upload is opt-in. Suffix is split like the engine (ruleAttrIndex,
250
+ // see engine/extract.js). Returns a DEFAULT_TEMPLATES key.
251
+ const PROP_TO_COMPONENT = { src: '@image', checked: '@checkbox', innerHTML: '@richtext' }
252
+ // data-hcms-component values for scalar rules. "chips" is array-only (below).
253
+ const SCALAR_COMPONENT_BY_NAME = {
254
+ image: '@image',
255
+ file: '@file',
256
+ checkbox: '@checkbox',
257
+ toggle: '@toggle',
258
+ select: '@select',
259
+ radio: '@radio',
260
+ textarea: '@textarea',
261
+ number: '@number',
262
+ richtext: '@richtext',
263
+ }
264
+ // Every opt-in component injects on demand; only the 6 shape templates are
265
+ // always present.
266
+ const ON_DEMAND_COMPONENT_KEYS = new Set([
267
+ ...Object.values(SCALAR_COMPONENT_BY_NAME),
268
+ '@chips',
269
+ '@chips-item',
270
+ ])
271
+
272
+ export function componentForScalarRule(rule, doc, pathArr, pageRules) {
273
+ if (typeof rule !== 'string') return '@scalar'
274
+ const at = ruleAttrIndex(rule)
275
+ const host = hostSelectorOf(rule, at, pathArr, pageRules)
276
+ const override = readElementAttr(host, doc, 'data-hcms-component')
277
+ if (override && SCALAR_COMPONENT_BY_NAME[override]) {
278
+ const key = SCALAR_COMPONENT_BY_NAME[override]
279
+ // Value guards check exactly the elements the engine binds: under an array
280
+ // the same rule binds one element per item (every match votes), while a
281
+ // plain scalar binds only the FIRST match — a decorative second element
282
+ // sharing the selector must not veto the control.
283
+ const multi = Array.isArray(pathArr) && pathArr.some((s) => s === '*' || typeof s === 'number')
284
+ if (key === '@number' && !currentScalarValues(rule, at, doc, multi, host).every(numberInputCanHold)) {
285
+ return '@scalar'
286
+ }
287
+ if (
288
+ (key === '@checkbox' || key === '@toggle') &&
289
+ (at < 0 || rule.slice(at + 1) !== 'checked') &&
290
+ !currentScalarValues(rule, at, doc, multi, host).every(checkboxCanHold)
291
+ ) {
292
+ return '@scalar'
293
+ }
294
+ return key
295
+ }
296
+ if (at >= 0) {
297
+ const prop = rule.slice(at + 1)
298
+ if (PROP_TO_COMPONENT[prop]) return PROP_TO_COMPONENT[prop]
299
+ }
300
+ return '@scalar'
301
+ }
302
+
303
+ // The data-hcms-component key the page element explicitly declares for this
304
+ // rule, or null (absent / unknown name / value-guard fallback). Lets the
305
+ // builder tell "author asked for this" apart from suffix inference when
306
+ // logging shadowing notices.
307
+ export function declaredComponentKey(rule, doc, pathArr, pageRules) {
308
+ if (typeof rule !== 'string') return null
309
+ const at = ruleAttrIndex(rule)
310
+ const name = readElementAttr(hostSelectorOf(rule, at, pathArr, pageRules), doc, 'data-hcms-component')
311
+ return (name && SCALAR_COMPONENT_BY_NAME[name]) || null
312
+ }
313
+
314
+ // A number input physically rejects any value that isn't a plain number — it
315
+ // reads back '' — and the whole-form commit would then blank the page value on
316
+ // the next edit of ANY field. When any bound value isn't number-shaped, fall
317
+ // back to the plain text control. This runs inside componentForScalarRule so
318
+ // the builder and deriveFormRules stay in lockstep (both call it).
319
+ const NUMBER_VALUE_RE = /^-?\d+(\.\d+)?([eE][+-]?\d+)?$/
320
+
321
+ function numberInputCanHold(value) {
322
+ if (value == null || value === '') return true
323
+ return NUMBER_VALUE_RE.test(String(value))
324
+ }
325
+
326
+ // A checkbox/toggle extracts its checked property — 'true' or 'false' — so any
327
+ // other bound value ("yes", "on", "1") would be clobbered to 'false' on the
328
+ // next whole-form commit. @checked projections are exempt in the caller: they
329
+ // round-trip the checked state faithfully by construction.
330
+ function checkboxCanHold(value) {
331
+ return value == null || value === '' || value === 'true' || value === 'false'
332
+ }
333
+
334
+ // Read the page values the rule binds, the way the engine extracts them:
335
+ // trimmed textContent for text projections (adapter.text trims), the live
336
+ // property for @value, the raw attribute otherwise. Mirrors extraction's
337
+ // skips: cms-template seeds and the shell are never extracted, so their
338
+ // values don't get a vote. `multi` mirrors the engine's binding: all matches
339
+ // under an array (one element per item), only the first match otherwise.
340
+ function currentScalarValues(rule, at, doc, multi, selector) {
341
+ if (!doc || !doc.querySelectorAll) return []
342
+ if (!selector || selector === '.') return []
343
+ let els = null
344
+ try {
345
+ els = doc.querySelectorAll(selector)
346
+ } catch {
347
+ return []
348
+ }
349
+ const prop = at >= 0 ? rule.slice(at + 1) : null
350
+ const out = []
351
+ for (const el of els) {
352
+ if (el.closest && el.closest('[cms-template], [data-hcms-shell]')) continue
353
+ if (prop) {
354
+ if (prop === 'value' && 'value' in el) out.push(el.value)
355
+ else out.push(el.getAttribute ? el.getAttribute(prop) : null)
356
+ } else {
357
+ out.push((el.textContent || '').trim())
358
+ }
359
+ if (!multi) break
360
+ }
361
+ return out
362
+ }
363
+
364
+ // Array-level component selection: data-hcms-component="chips" on the list
365
+ // container (or any ancestor of the items) swaps the scalar-array chrome for
366
+ // the chip list. Resolved through the first item the rule's selector matches,
367
+ // then closest(), so the natural authoring spot — the <ul> — works even though
368
+ // the selector targets the items. Growable-from-zero lists carry a cms-template
369
+ // item, so the item selector always has something to match.
370
+ export function componentForScalarArrayRule(rule, doc) {
371
+ if (typeof rule !== 'string' || !rule.endsWith('[]')) return null
372
+ if (!doc || !doc.querySelector) return null
373
+ const selector = rule.slice(0, -2).trim()
374
+ if (!selector) return null
375
+ let item = null
376
+ try {
377
+ item = doc.querySelector(selector)
378
+ } catch {
379
+ return null
380
+ }
381
+ const host = item && item.closest ? item.closest('[data-hcms-component]') : null
382
+ const name = host && host.getAttribute ? host.getAttribute('data-hcms-component') : null
383
+ if (name === 'chips') return { array: '@chips', item: '@chips-item' }
384
+ return null
385
+ }
386
+
387
+ // Template resolution shared by the builder and deriveFormRules: a custom
388
+ // template at the exact path wins, then a wildcard-path one, then the default.
389
+ export function resolveTemplate(pathArr, defaultKey, doc) {
390
+ const pathStr = pathArr.join('.')
391
+ const wildcardKey = pathArr.map((s) => (typeof s === 'number' ? '*' : s)).join('.')
392
+ return (
393
+ (pathStr && findTemplate(doc, pathStr)) ||
394
+ (wildcardKey && wildcardKey !== pathStr && findTemplate(doc, wildcardKey)) ||
395
+ findTemplate(doc, defaultKey)
396
+ )
397
+ }
398
+
399
+ // The declared array component, but only when its array template actually
400
+ // wins at this path — a custom path/wildcard template that shadows it returns
401
+ // null. The form-builder (item chrome) and deriveFormRules (item leaf
402
+ // selector) MUST share this verdict: if they diverge, the derived selector
403
+ // stops matching the rendered item leaf, every item extracts null, and the
404
+ // whole-form commit writes those nulls back over real page data.
405
+ export function winningScalarArrayComponent(rule, pathArr, doc) {
406
+ const comp = componentForScalarArrayRule(rule, doc)
407
+ if (!comp) return null
408
+ const winner = resolveTemplate(pathArr, comp.array, doc)
409
+ if (winner && winner.getAttribute('data-hcms-tpl') === comp.array) return comp
410
+ return null
411
+ }
412
+
413
+ // Option list for @select/@radio: data-hcms-options="low medium high" on the
414
+ // same page element as data-hcms-component. Space-separated value tokens (the
415
+ // data-rules-name idiom); labels derive via humanize() like every other label.
416
+ export function readOptionsOverride(rule, doc, pathArr, pageRules) {
417
+ if (typeof rule !== 'string') return null
418
+ const at = ruleAttrIndex(rule)
419
+ const raw = readElementAttr(hostSelectorOf(rule, at, pathArr, pageRules), doc, 'data-hcms-options')
420
+ if (raw == null) return null
421
+ const tokens = raw.trim().split(/\s+/).filter(Boolean)
422
+ return tokens.length ? tokens : null
423
+ }
424
+
425
+ // Crop opt-in for @image: data-hcms-crop="1:1" | "16:9" | "free" on the page
426
+ // element. The form-builder copies it onto the built field so the upload path
427
+ // reads it without a second page lookup.
428
+ export function readCropOverride(rule, doc, pathArr, pageRules) {
429
+ if (typeof rule !== 'string') return null
430
+ const at = ruleAttrIndex(rule)
431
+ return readElementAttr(hostSelectorOf(rule, at, pathArr, pageRules), doc, 'data-hcms-crop')
432
+ }
433
+
434
+ function scalarSelectorOf(rule, at) {
435
+ return at >= 0 ? rule.slice(0, at) : rule
436
+ }
437
+
438
+ // The page element that carries this rule's authoring attributes
439
+ // (data-hcms-component / -options / -crop), and whose values the guards read.
440
+ //
441
+ // A rule that binds its own context element — a lone "." or a leading "@attr" —
442
+ // has no selector of its own: scalarSelectorOf yields "" or ".". Inside a list
443
+ // that context element IS the row, so the element to read is the row, and the
444
+ // row selector is the enclosing array's item selector. That is the "state is
445
+ // content" case (data-status on the card), and without this it can never carry
446
+ // a named control. Outside any list the context is the document root, so there
447
+ // is still no element to read and we return "" — readElementAttr and
448
+ // currentScalarValues both treat that as "nothing declared", exactly as before.
449
+ //
450
+ // The component is chosen per RULE, not per row, so any ONE matching row
451
+ // answers the question; readElementAttr's querySelector taking the first match
452
+ // is correct rather than a shortcut.
453
+ function hostSelectorOf(rule, at, pathArr, pageRules) {
454
+ const own = scalarSelectorOf(rule, at)
455
+ if (own && own !== '.') return own
456
+ return enclosingArraySelector(pageRules, pathArr)
457
+ }
458
+
459
+ // The descendant-joined item selectors of every array rule crossed on the way
460
+ // to pathArr, or "" when the path crosses none (or does not resolve). Mirrors
461
+ // the scope chain hyperclay's resolveControl builds for the same path, so the
462
+ // generator stamps the attribute on exactly the elements read back here.
463
+ function enclosingArraySelector(pageRules, pathArr) {
464
+ if (pageRules == null || !Array.isArray(pathArr)) return ''
465
+ const scope = []
466
+ let node = pageRules
467
+ for (const seg of pathArr) {
468
+ if (node == null || typeof node === 'string') break
469
+ if (Array.isArray(node)) {
470
+ if (typeof node[0] !== 'string') return ''
471
+ if (seg !== '*' && typeof seg !== 'number') return ''
472
+ scope.push(node[0])
473
+ node = node[1]
474
+ continue
475
+ }
476
+ if (typeof node !== 'object') return ''
477
+ if (!Object.prototype.hasOwnProperty.call(node, seg)) return ''
478
+ node = node[seg]
479
+ }
480
+ return scope.join(' ')
481
+ }
482
+
483
+ // The only branch that reads the page DOM during selection.
484
+ function readElementAttr(selector, doc, attrName) {
485
+ if (!doc || !doc.querySelector) return null
486
+ if (!selector || selector === '.') return null
487
+ let el = null
488
+ try {
489
+ el = doc.querySelector(selector)
490
+ } catch {
491
+ return null
492
+ }
493
+ return el && el.getAttribute ? el.getAttribute(attrName) : null
494
+ }
495
+
496
+ // Pre-inject the component templates this page's rules actually select, so
497
+ // both deriveFormRules (selectors) and buildForm (DOM) resolve them. Walks the
498
+ // same rule shapes as buildTemplateMap; idempotent and author-template-safe.
499
+ export function injectComponents(doc, pageRules) {
500
+ if (!doc || pageRules == null) return
501
+ walk(pageRules, [])
502
+
503
+ // The path is carried so componentForScalarRule can resolve a context leaf
504
+ // ("." / "@attr") against its enclosing row, the same way the builder does.
505
+ // Without it a row-level named control resolves to @scalar here, its template
506
+ // is never injected, and buildScalar then throws on the missing template.
507
+ function walk(rule, pathArr) {
508
+ const kind = shapeKindOf(rule)
509
+ if (kind === 'scalar') {
510
+ const key = componentForScalarRule(rule, doc, pathArr, pageRules)
511
+ if (ON_DEMAND_COMPONENT_KEYS.has(key)) injectComponentTemplate(doc, key)
512
+ return
513
+ }
514
+ if (kind === 'scalar-array') {
515
+ const comp = componentForScalarArrayRule(rule, doc)
516
+ if (comp) {
517
+ injectComponentTemplate(doc, comp.array)
518
+ injectComponentTemplate(doc, comp.item)
519
+ }
520
+ return
521
+ }
522
+ if (kind === 'object') {
523
+ for (const [k, child] of Object.entries(rule)) walk(child, [...pathArr, k])
524
+ return
525
+ }
526
+ if (kind === 'object-array') {
527
+ const itemShape = rule[1]
528
+ const itemPath = [...pathArr, '*']
529
+ if (itemShape && typeof itemShape === 'object' && !Array.isArray(itemShape)) {
530
+ for (const [k, child] of Object.entries(itemShape)) walk(child, [...itemPath, k])
531
+ } else {
532
+ walk(itemShape, itemPath)
533
+ }
534
+ }
535
+ }
536
+ }
537
+
538
+ function injectTemplate(doc, head, key) {
539
+ const existing = findTemplate(doc, key)
540
+ if (existing) return existing
541
+ const tpl = doc.createElement('template')
542
+ tpl.setAttribute('data-hcms-tpl', key)
543
+ tpl.setAttribute('save-remove', '')
544
+ tpl.innerHTML = DEFAULT_TEMPLATES[key].trim()
545
+ head.appendChild(tpl)
546
+ return tpl
547
+ }
548
+
549
+ export function findTemplate(doc, key) {
550
+ if (!doc || !doc.querySelector) return null
551
+ return doc.querySelector(`template[data-hcms-tpl="${cssEscape(key)}"]`)
552
+ }
553
+
554
+ function cssEscape(value) {
555
+ if (typeof CSS !== 'undefined' && CSS.escape) return CSS.escape(value)
556
+ return String(value).replace(/[^a-zA-Z0-9_\-.*]/g, (c) => '\\' + c)
557
+ }
558
+
559
+ export function shapeKindOf(rule) {
560
+ if (typeof rule === 'string') {
561
+ return rule.endsWith('[]') ? 'scalar-array' : 'scalar'
562
+ }
563
+ if (Array.isArray(rule)) return 'object-array'
564
+ if (typeof rule === 'object' && rule !== null) return 'object'
565
+ return 'scalar'
566
+ }
567
+
568
+ const SHAPE_TO_DEFAULT_KEY = {
569
+ scalar: '@scalar',
570
+ object: '@object',
571
+ 'scalar-array': '@scalar-array',
572
+ 'object-array': '@object-array',
573
+ }
574
+
575
+ const SHAPE_TO_ITEM_KEY = {
576
+ 'scalar-array': '@scalar-array-item',
577
+ 'object-array': '@object-array-item',
578
+ }
579
+
580
+ export function templateKeyForPath(pathArr, pageRules) {
581
+ const rule = getRuleAtPath(pageRules, pathArr)
582
+ const shape = shapeKindOf(rule)
583
+ return SHAPE_TO_DEFAULT_KEY[shape] || '@scalar'
584
+ }
585
+
586
+ export function itemTemplateKeyForArrayPath(pathArr, pageRules) {
587
+ const rule = getRuleAtPath(pageRules, pathArr)
588
+ const shape = shapeKindOf(rule)
589
+ return SHAPE_TO_ITEM_KEY[shape] || null
590
+ }
591
+
592
+ export function buildTemplateMap(pageRules, doc) {
593
+ const map = new Map()
594
+ walk([], pageRules)
595
+ return map
596
+
597
+ function walk(pathArr, rule) {
598
+ const pathStr = pathArr.join('.')
599
+ const wildcardKey = pathArr.map((s) => (typeof s === 'number' ? '*' : s)).join('.')
600
+ const shape = shapeKindOf(rule)
601
+ const arrayComp = shape === 'scalar-array' ? componentForScalarArrayRule(rule, doc) : null
602
+ // Items follow the WINNING component (a shadowed chips array renders
603
+ // default items), matching buildScalarArray.
604
+ const winningComp = shape === 'scalar-array' ? winningScalarArrayComponent(rule, pathArr, doc) : null
605
+ const defaultKey =
606
+ shape === 'scalar'
607
+ ? componentForScalarRule(rule, doc, pathArr)
608
+ : (arrayComp && arrayComp.array) || SHAPE_TO_DEFAULT_KEY[shape] || '@scalar'
609
+
610
+ let tpl =
611
+ (pathStr && findTemplate(doc, pathStr)) ||
612
+ (wildcardKey && wildcardKey !== pathStr && findTemplate(doc, wildcardKey)) ||
613
+ findTemplate(doc, defaultKey)
614
+
615
+ map.set(pathStr, tpl)
616
+
617
+ if (shape === 'object') {
618
+ for (const [k, child] of Object.entries(rule)) walk([...pathArr, k], child)
619
+ } else if (shape === 'object-array' || shape === 'scalar-array') {
620
+ const itemPath = [...pathArr, '*']
621
+ const itemKey = itemPath.map((s) => (typeof s === 'number' ? '*' : s)).join('.')
622
+ const itemShape = shape === 'object-array' ? 'object-array-item' : 'scalar-array-item'
623
+ const itemTpl =
624
+ findTemplate(doc, itemKey) ||
625
+ (winningComp && findTemplate(doc, winningComp.item)) ||
626
+ findTemplate(doc, '@' + itemShape)
627
+ map.set(itemKey, itemTpl)
628
+ if (shape === 'object-array') {
629
+ const itemRule = rule[1]
630
+ if (itemRule && typeof itemRule === 'object' && !Array.isArray(itemRule)) {
631
+ for (const [k, child] of Object.entries(itemRule)) walk([...itemPath, k], child)
632
+ }
633
+ }
634
+ }
635
+ }
636
+ }
637
+
638
+ export function isInlineTemplate(tplEl) {
639
+ if (!tplEl) return false
640
+ const root = tplEl.content || tplEl
641
+ return !!root.querySelector('[data-hcms-field]')
642
+ }
643
+
644
+ export function slotSelectorFor(kind) {
645
+ switch (kind) {
646
+ case 'object':
647
+ return '.hcms-object-fields'
648
+ case 'object-array-item':
649
+ return '.hcms-card-fields'
650
+ case 'scalar-array':
651
+ case 'object-array':
652
+ return '.hcms-array-items'
653
+ default:
654
+ return null
655
+ }
656
+ }