@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,203 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * build-theme.js — generate hypercms's pixel-quiet shell stylesheet.
4
+ *
5
+ * mirk.css styles a whole document (:root tokens, body font, universal
6
+ * box-sizing, a relative @font-face url). hypercms injects a sidebar into an
7
+ * arbitrary host page, so mirk must be SCOPED to .hcms-shell or it would
8
+ * repaint the host body, change its box model, and fail to load the font.
9
+ *
10
+ * This reads the canonical mirk.css (single source of truth in mirk-interface),
11
+ * scopes every rule to .hcms-shell, rewrites the font url to the absolute CDN,
12
+ * then appends the hypercms-owned pixel-quiet overrides. Output:
13
+ * src/theme.generated.css, which the bundle entry installs as the shell CSS.
14
+ *
15
+ * Also vendors mirk.js (the delegated component runtime) into src/vendor so the
16
+ * bundle can import it for its side effect.
17
+ *
18
+ * Run: npm run build:theme (also runs first in `npm run build`).
19
+ */
20
+ import fs from 'fs'
21
+ import path from 'path'
22
+ import { fileURLToPath } from 'url'
23
+
24
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
25
+ const root = path.join(__dirname, '..')
26
+
27
+ // mirk-interface normally sits next to the hypercms checkout, but in a git
28
+ // worktree (.claude/worktrees/<name>) the repo root is nested deeper, so walk
29
+ // up until a directory contains mirk-interface/mirk.css.
30
+ function findMirkRepo(from) {
31
+ for (let dir = from; ; dir = path.dirname(dir)) {
32
+ const candidate = path.join(dir, 'mirk-interface')
33
+ if (fs.existsSync(path.join(candidate, 'mirk.css'))) return candidate
34
+ if (path.dirname(dir) === dir) throw new Error('mirk-interface/mirk.css not found above ' + from)
35
+ }
36
+ }
37
+ const mirkRepo = findMirkRepo(root)
38
+
39
+ const MIRK_VERSION = '2.2.0'
40
+ const FONT_CDN =
41
+ `https://cdn.jsdelivr.net/npm/mirk-interface@${MIRK_VERSION}/fonts/DepartureMono-1.500/DepartureMono-Regular.woff2`
42
+
43
+ const SCOPE = '.hcms-shell'
44
+
45
+ // ---- selector scoping -------------------------------------------------------
46
+
47
+ // Split a string on a top-level separator, ignoring separators inside () or [].
48
+ function splitTopLevel(str, sep) {
49
+ const out = []
50
+ let depth = 0
51
+ let buf = ''
52
+ for (const ch of str) {
53
+ if (ch === '(' || ch === '[') depth++
54
+ else if (ch === ')' || ch === ']') depth--
55
+ if (ch === sep && depth === 0) {
56
+ out.push(buf)
57
+ buf = ''
58
+ } else {
59
+ buf += ch
60
+ }
61
+ }
62
+ if (buf.trim() !== '') out.push(buf)
63
+ return out
64
+ }
65
+
66
+ function stripComments(s) {
67
+ return s.replace(/\/\*[\s\S]*?\*\//g, '')
68
+ }
69
+
70
+ // Map one mirk selector to its .hcms-shell-scoped form. Root-level selectors
71
+ // (:root / body / html, and the theme flags .light / .dark / [data-theme]) bind
72
+ // to the shell element itself; everything else binds to a descendant.
73
+ function scopeOne(sel) {
74
+ sel = stripComments(sel).trim()
75
+ if (!sel) return ''
76
+ if (sel === ':root' || sel === 'body' || sel === 'html') return SCOPE
77
+ if (sel === '*') return `${SCOPE} *`
78
+ if (sel === '::before') return `${SCOPE} *::before`
79
+ if (sel === '::after') return `${SCOPE} *::after`
80
+ if (/^\.light\b/.test(sel) || /^\.dark\b/.test(sel) || sel.startsWith('[data-theme')) {
81
+ return SCOPE + sel
82
+ }
83
+ return `${SCOPE} ${sel}`
84
+ }
85
+
86
+ function scopeSelectorList(list) {
87
+ return splitTopLevel(list, ',').map(scopeOne).filter(Boolean).join(', ')
88
+ }
89
+
90
+ function rewriteFontFace(body) {
91
+ return body.replace(
92
+ /url\(\s*(['"]?)[^)'"]*DepartureMono-Regular\.woff2\1\s*\)/,
93
+ `url('${FONT_CDN}')`
94
+ )
95
+ }
96
+
97
+ // ---- block walker -----------------------------------------------------------
98
+
99
+ // Transform a sequence of rules (a stylesheet, or the inside of an at-rule
100
+ // block). Style rules get their selector list scoped; nested at-rules recurse.
101
+ function transformBlock(css) {
102
+ let i = 0
103
+ let out = ''
104
+ const n = css.length
105
+ while (i < n) {
106
+ const ch = css[i]
107
+ if (/\s/.test(ch)) { out += ch; i++; continue }
108
+ if (ch === '/' && css[i + 1] === '*') {
109
+ const end = css.indexOf('*/', i + 2)
110
+ const stop = end === -1 ? n : end + 2
111
+ out += css.slice(i, stop)
112
+ i = stop
113
+ continue
114
+ }
115
+ // Read the prelude up to a top-level '{' or ';'.
116
+ let j = i
117
+ let depth = 0
118
+ while (j < n) {
119
+ const c = css[j]
120
+ if (c === '/' && css[j + 1] === '*') { const e = css.indexOf('*/', j + 2); j = e === -1 ? n : e + 2; continue }
121
+ if (c === '{' && depth === 0) break
122
+ if (c === ';' && depth === 0) break
123
+ if (c === '(' || c === '[') depth++
124
+ else if (c === ')' || c === ']') depth--
125
+ j++
126
+ }
127
+ if (j >= n) { out += css.slice(i); break }
128
+ const prelude = css.slice(i, j)
129
+ if (css[j] === ';') {
130
+ // statement at-rule, e.g. `@layer base, components;`
131
+ out += prelude + ';'
132
+ i = j + 1
133
+ continue
134
+ }
135
+ // css[j] === '{' — find the matching close brace.
136
+ const bodyStart = j + 1
137
+ let d = 1
138
+ let k = bodyStart
139
+ while (k < n && d > 0) {
140
+ const c = css[k]
141
+ if (c === '/' && css[k + 1] === '*') { const e = css.indexOf('*/', k + 2); k = e === -1 ? n : e + 2; continue }
142
+ if (c === '{') d++
143
+ else if (c === '}') { d--; if (d === 0) break }
144
+ k++
145
+ }
146
+ const body = css.slice(bodyStart, k)
147
+ i = k + 1
148
+ const trimmed = prelude.trim()
149
+ if (trimmed.startsWith('@')) {
150
+ const atName = trimmed.split(/[\s({]/)[0]
151
+ if (atName === '@font-face') {
152
+ out += prelude + '{' + rewriteFontFace(body) + '}'
153
+ } else if (atName === '@keyframes' || atName === '@-webkit-keyframes') {
154
+ out += prelude + '{' + body + '}'
155
+ } else {
156
+ // @media / @layer / @supports / @scope — recurse into inner rules.
157
+ out += prelude + '{' + transformBlock(body) + '}'
158
+ }
159
+ } else {
160
+ out += scopeSelectorList(prelude) + ' {' + body + '}'
161
+ }
162
+ }
163
+ return out
164
+ }
165
+
166
+ // ---- main -------------------------------------------------------------------
167
+
168
+ function read(p) { return fs.readFileSync(p, 'utf8') }
169
+
170
+ const mirkCss = read(path.join(mirkRepo, 'mirk.css'))
171
+ const scopedMirk = transformBlock(mirkCss)
172
+ const overrides = read(path.join(root, 'src', 'theme', 'pixel-quiet.overrides.css'))
173
+
174
+ const banner =
175
+ '/* GENERATED by scripts/build-theme.js from mirk-interface/mirk.css — DO NOT EDIT.\n' +
176
+ ' Source of truth: mirk-interface/mirk.css + src/theme/pixel-quiet.overrides.css.\n' +
177
+ ' Regenerate with: npm run build:theme */\n\n'
178
+
179
+ const themeOut =
180
+ banner +
181
+ '/* ===== mirk-interface@' + MIRK_VERSION + ', scoped to .hcms-shell ===== */\n' +
182
+ scopedMirk.trim() + '\n\n' +
183
+ '/* ===== pixel-quiet overrides (hypercms-owned) ===== */\n' +
184
+ overrides.trim() + '\n'
185
+
186
+ fs.writeFileSync(path.join(root, 'src', 'theme.generated.css'), themeOut, 'utf8')
187
+ console.log('✓ wrote src/theme.generated.css (' + themeOut.length + ' bytes)')
188
+
189
+ // Vendor the mirk.js delegated runtime so the bundle can import it.
190
+ const vendorDir = path.join(root, 'src', 'vendor')
191
+ fs.mkdirSync(vendorDir, { recursive: true })
192
+ const mirkJs = read(path.join(mirkRepo, 'mirk.js'))
193
+ const vendorBanner =
194
+ '/* VENDORED from mirk-interface/mirk.js — DO NOT EDIT. Regenerate: npm run build:theme */\n'
195
+ // Guard so this is import-safe in non-browser realms (e.g. Node tests that load
196
+ // hypercms before a jsdom window exists). In the browser the guard is a no-op.
197
+ const guarded =
198
+ vendorBanner +
199
+ 'if (typeof window !== "undefined" && typeof document !== "undefined") {\n' +
200
+ mirkJs.trimEnd() + '\n' +
201
+ '}\n'
202
+ fs.writeFileSync(path.join(vendorDir, 'mirk.vendor.js'), guarded, 'utf8')
203
+ console.log('✓ wrote src/vendor/mirk.vendor.js')
@@ -0,0 +1,24 @@
1
+ // Can the inline view hang a control on this page element right now?
2
+ //
3
+ // Deliberately a question about the CURRENT state, never a cached verdict. A
4
+ // target inside a closed <details> or an inactive tab answers false now and
5
+ // true the moment the page reveals it, which is why the inline view re-runs
6
+ // this on every visibility change instead of classifying once at open.
7
+ //
8
+ // The area floor is not cosmetic padding and it is not redundant with
9
+ // IntersectionObserver. Measured in Chrome: an empty inline <span> reports
10
+ // isIntersecting true, ratio 1, on a zero-width box. Without the floor that
11
+ // draws a camera handle on a 0px target.
12
+ export const MIN_ANCHOR_PX = 8
13
+
14
+ // [cms-template] is the hidden list seed; [data-hcms-shell] is the CMS's own
15
+ // chrome, which both the sidebar panel and the inline host carry. Neither is
16
+ // page content, so neither ever gets a control.
17
+ const NEVER_ANCHOR = '[cms-template], [data-hcms-shell]'
18
+
19
+ export function isAnchorable(el) {
20
+ if (!el || typeof el.getBoundingClientRect !== 'function') return false
21
+ if (typeof el.closest === 'function' && el.closest(NEVER_ANCHOR)) return false
22
+ const r = el.getBoundingClientRect()
23
+ return r.width >= MIN_ANCHOR_PX && r.height >= MIN_ANCHOR_PX
24
+ }
@@ -0,0 +1,167 @@
1
+ import { engine } from 'hyper-html-api'
2
+ import { fromString as pathFromString, getRuleAtPath } from './path.js'
3
+ import { rowIdentityHooks } from './row-identity.js'
4
+
5
+ const ENGINE_OPTS = { skip: '[data-hcms-shell]', templateAttr: 'cms-template' }
6
+
7
+ // Engine reads/writes against pageRoot pass skip + templateAttr so the
8
+ // engine never traverses into the form's own DOM, and so [cms-template]
9
+ // nodes are treated as seed templates (not real data). Scalar applies skip
10
+ // snapshot — string user input can't produce a ShapeMismatch and the focused
11
+ // input must survive every keystroke.
12
+ //
13
+ // Structural applies (add/remove/reorder) can hit EmptyListInsert and other
14
+ // engine errors. We snapshot just the affected array container's slot so
15
+ // rollback restores only the failing subtree; listeners and state elsewhere
16
+ // on the page survive.
17
+ export function applyWithRollback(pageRoot, pageRules, newData, options = {}) {
18
+ const { observerHandle, shellRoot, structural, structuralPath, formRoot } = options
19
+ // The form's own row elements are the only stable handle across an apply, so
20
+ // when we have the form we let it say which page row each item is. Without it
21
+ // the engine matches by content, which is exact except between two rows that
22
+ // read identically.
23
+ const engineOpts = formRoot ? { ...ENGINE_OPTS, ...rowIdentityHooks(formRoot) } : ENGINE_OPTS
24
+ observerHandle?.pause?.()
25
+ try {
26
+ if (!structural) {
27
+ try {
28
+ engine.apply(pageRoot, pageRules, newData, engineOpts)
29
+ return { ok: true }
30
+ } catch (err) {
31
+ return { ok: false, error: err }
32
+ }
33
+ }
34
+
35
+ // Structural path: snapshot the smallest container that the change
36
+ // touches, falling back to non-shell page content if we can't resolve
37
+ // a specific container.
38
+ const target = resolveStructuralTarget(pageRoot, pageRules, structuralPath)
39
+ const subtreeSnapshot = target ? captureChildren(target) : null
40
+ const pageSnapshot = target ? null : captureNonShellSnapshot(pageRoot, shellRoot)
41
+ try {
42
+ engine.apply(pageRoot, pageRules, newData, engineOpts)
43
+ return { ok: true }
44
+ } catch (err) {
45
+ if (subtreeSnapshot) {
46
+ restoreChildren(target, subtreeSnapshot)
47
+ } else if (pageSnapshot) {
48
+ restoreNonShellSnapshot(pageRoot, shellRoot, pageSnapshot)
49
+ }
50
+ return { ok: false, error: err }
51
+ }
52
+ } finally {
53
+ observerHandle?.resume?.()
54
+ }
55
+ }
56
+
57
+ // Walk pageRules along structuralPath to find the array rule that the change
58
+ // targets, then ask the engine to locate its matching container in pageRoot.
59
+ // Returns the live container element (so its child cards can be snapshotted),
60
+ // or null if the path doesn't resolve to a single array container.
61
+ function resolveStructuralTarget(pageRoot, pageRules, structuralPath) {
62
+ if (!structuralPath || !pageRoot) return null
63
+ const segs = pathFromString(structuralPath)
64
+ // Walk to the array rule. Add/remove paths can be either the array itself
65
+ // ("products") or an item path ("products.0"); both resolve to the same
66
+ // array container.
67
+ let arrPath = []
68
+ let node = pageRules
69
+ for (const seg of segs) {
70
+ if (typeof node === 'string' || node == null) break
71
+ if (Array.isArray(node)) {
72
+ // We're at an array — this segment is the index; stop walking, we have
73
+ // the container.
74
+ break
75
+ }
76
+ if (typeof node === 'object' && seg in node) {
77
+ arrPath.push(seg)
78
+ node = node[seg]
79
+ if (Array.isArray(node) || (typeof node === 'string' && node.endsWith('[]'))) break
80
+ } else {
81
+ return null
82
+ }
83
+ }
84
+ if (!Array.isArray(node) && !(typeof node === 'string' && node.endsWith('[]'))) return null
85
+ // arrPath is the prefix that leads to the array. Walk pageRoot via the
86
+ // engine using a stripped pageRules so we land on the container.
87
+ return resolveContainerByPath(pageRoot, pageRules, arrPath)
88
+ }
89
+
90
+ // Walk pageRoot by following each parent rule's selector until we reach the
91
+ // array container. For paths with no parent (root-level array), use pageRoot
92
+ // itself; otherwise descend through each named rule.
93
+ function resolveContainerByPath(pageRoot, pageRules, arrPath) {
94
+ if (arrPath.length === 0) return null
95
+ let ctx = pageRoot
96
+ let rule = pageRules
97
+ for (let i = 0; i < arrPath.length; i++) {
98
+ const key = arrPath[i]
99
+ if (!rule || typeof rule !== 'object' || Array.isArray(rule)) return null
100
+ const sub = rule[key]
101
+ if (sub == null) return null
102
+ if (i === arrPath.length - 1) {
103
+ // Final step: the array's selector resolves to ITEMS, not the
104
+ // container. Walk to the items' shared parent so the snapshot covers
105
+ // the whole list (cards/scalars siblings). Without this, an object
106
+ // array's selector like `.product` returns the first item, and
107
+ // rollback restores only that item's children — leaving any earlier
108
+ // list-level insert/reorder mutated.
109
+ if (Array.isArray(sub)) {
110
+ const [selector] = sub
111
+ const first = ctx.querySelector?.(selector)
112
+ return first?.parentElement || null
113
+ }
114
+ if (typeof sub === 'string' && sub.endsWith('[]')) {
115
+ const selector = sub.slice(0, -2)
116
+ const first = ctx.querySelector?.(selector)
117
+ return first?.parentElement || null
118
+ }
119
+ return null
120
+ }
121
+ // Intermediate: must be an object subrule. Engine extract treats objects
122
+ // as same-ctx, so we don't narrow ctx.
123
+ rule = sub
124
+ }
125
+ return null
126
+ }
127
+
128
+ function captureChildren(parent) {
129
+ const clones = []
130
+ for (const child of Array.from(parent.childNodes)) {
131
+ clones.push(child.cloneNode(true))
132
+ }
133
+ return clones
134
+ }
135
+
136
+ function restoreChildren(parent, clones) {
137
+ while (parent.firstChild) parent.removeChild(parent.firstChild)
138
+ for (const clone of clones) parent.appendChild(clone)
139
+ }
140
+
141
+ function captureNonShellSnapshot(pageRoot, shellRoot) {
142
+ const clones = []
143
+ for (const child of Array.from(pageRoot.childNodes)) {
144
+ if (child === shellRoot || (shellRoot && child.contains?.(shellRoot))) continue
145
+ clones.push(child.cloneNode(true))
146
+ }
147
+ return clones
148
+ }
149
+
150
+ function restoreNonShellSnapshot(pageRoot, shellRoot, clones) {
151
+ for (const child of Array.from(pageRoot.childNodes)) {
152
+ if (child === shellRoot || (shellRoot && child.contains?.(shellRoot))) continue
153
+ pageRoot.removeChild(child)
154
+ }
155
+ const host = findShellHostChild(pageRoot, shellRoot)
156
+ for (const clone of clones) {
157
+ pageRoot.insertBefore(clone, host || null)
158
+ }
159
+ }
160
+
161
+ function findShellHostChild(pageRoot, shellRoot) {
162
+ if (!shellRoot) return null
163
+ for (const child of Array.from(pageRoot.childNodes)) {
164
+ if (child === shellRoot || child.contains?.(shellRoot)) return child
165
+ }
166
+ return null
167
+ }
@@ -0,0 +1,44 @@
1
+ import { shapeKindOf } from './templates.js'
2
+
3
+ const PREFIX = '[hypercms]'
4
+
5
+ export function warnUnmatchedTemplates(doc, pageRules) {
6
+ if (!doc || !doc.querySelectorAll || !pageRules) return
7
+ const validKeys = collectValidKeys(pageRules)
8
+ const tpls = doc.querySelectorAll('template[data-hcms-tpl]')
9
+ tpls.forEach((tpl) => {
10
+ const key = tpl.getAttribute('data-hcms-tpl')
11
+ if (!key) return
12
+ if (key.startsWith('@')) return
13
+ if (!validKeys.has(key)) {
14
+ console.warn(`${PREFIX} template "${key}" doesn't match any rule path; ignored`)
15
+ }
16
+ })
17
+ }
18
+
19
+ function collectValidKeys(pageRules) {
20
+ const keys = new Set()
21
+ walk([], pageRules)
22
+ return keys
23
+
24
+ function walk(pathArr, rule) {
25
+ const pathStr = pathArr.join('.')
26
+ const wildcardKey = pathArr.map((s) => (typeof s === 'number' ? '*' : s)).join('.')
27
+ if (pathStr) keys.add(pathStr)
28
+ if (wildcardKey) keys.add(wildcardKey)
29
+ const shape = shapeKindOf(rule)
30
+ if (shape === 'object') {
31
+ for (const [k, child] of Object.entries(rule)) walk([...pathArr, k], child)
32
+ } else if (shape === 'object-array' || shape === 'scalar-array') {
33
+ const itemPath = [...pathArr, '*']
34
+ const itemWildcardKey = itemPath.map((s) => (typeof s === 'number' ? '*' : s)).join('.')
35
+ keys.add(itemWildcardKey)
36
+ if (shape === 'object-array') {
37
+ const itemRule = rule[1]
38
+ if (itemRule && typeof itemRule === 'object' && !Array.isArray(itemRule)) {
39
+ for (const [k, child] of Object.entries(itemRule)) walk([...itemPath, k], child)
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,173 @@
1
+ // Post-mount field enhancements + the rich-text rule upgrade.
2
+ //
3
+ // Bare scalar rules bind textContent, which flattens inline HTML (links,
4
+ // bold, code) on extract and destroys it on the first apply. When the bound
5
+ // page element actually contains child elements, the rule is upgraded to
6
+ // @innerHTML so the round-trip preserves markup and the form renders the
7
+ // @richtext component (a contenteditable surface, richclay-powered when the
8
+ // host page ships richclay). Explicit @prop rules, array rules, and rules
9
+ // whose element holds only text are left untouched. Hosts opt out with
10
+ // cms.open({ richText: false }).
11
+
12
+ import { BOUND_ATTR, resolveRichClay } from './richclay-bridge.js'
13
+ import { ruleAttrIndex } from 'hyper-html-api/engine'
14
+
15
+ export function upgradeRichTextRules(rules, pageRoot) {
16
+ if (!pageRoot || rules == null) return rules
17
+ return walk(rules)
18
+
19
+ function walk(rule) {
20
+ if (typeof rule === 'string') {
21
+ if (rule.endsWith('[]')) return rule
22
+ if (ruleAttrIndex(rule) !== -1) return rule
23
+ let el = null
24
+ try {
25
+ el = pageRoot.querySelector(rule)
26
+ } catch (_) {
27
+ return rule
28
+ }
29
+ return el && el.children.length > 0 ? rule + '@innerHTML' : rule
30
+ }
31
+ // Array rules ([itemSelector, shape]) scope their inner selectors per
32
+ // item; a document-level querySelector can't answer "does THIS item's
33
+ // element hold markup", so array subtrees are never upgraded.
34
+ if (Array.isArray(rule)) return rule
35
+ if (rule && typeof rule === 'object') {
36
+ const out = Object.create(null)
37
+ for (const [k, v] of Object.entries(rule)) out[k] = walk(v)
38
+ return out
39
+ }
40
+ return rule
41
+ }
42
+ }
43
+
44
+ // The inline view's upgrade. Identical to the one above for a scalar or an
45
+ // object rule, and different for the one case that one deliberately refuses:
46
+ // the rules inside an array.
47
+ //
48
+ // The narrow version cannot answer "does THIS row's element hold markup" from a
49
+ // document-level querySelector, so it leaves array subtrees alone. Here the item
50
+ // elements are resolved first, so the question IS answerable — once per rule
51
+ // rather than once per row, because the rule language has no per-row rule. ANY
52
+ // row holding markup upgrades the rule for every row, and that costs nothing:
53
+ // @innerHTML round-trips plain text unchanged.
54
+ //
55
+ // It matters because the inline view binds rich text to the row element itself.
56
+ // A row left on textContent loses its links and its bold on the first commit.
57
+ export function upgradeInlineTextRules(rules, pageRoot) {
58
+ if (!pageRoot || rules == null) return rules
59
+ return walk(rules, [pageRoot])
60
+
61
+ function walk(rule, contexts) {
62
+ if (typeof rule === 'string') {
63
+ if (rule.endsWith('[]')) return rule
64
+ if (ruleAttrIndex(rule) !== -1) return rule
65
+ return contexts.some((ctx) => holdsMarkup(ctx, rule)) ? rule + '@innerHTML' : rule
66
+ }
67
+ if (Array.isArray(rule)) {
68
+ const [selector, shape] = rule
69
+ if (typeof selector !== 'string' || !selector) return rule
70
+ const items = queryAll(pageRoot, selector)
71
+ if (!items.length) return rule
72
+ return [selector, walk(shape, items)]
73
+ }
74
+ if (rule && typeof rule === 'object') {
75
+ const out = Object.create(null)
76
+ for (const [k, v] of Object.entries(rule)) out[k] = walk(v, contexts)
77
+ return out
78
+ }
79
+ return rule
80
+ }
81
+ }
82
+
83
+ function holdsMarkup(context, selector) {
84
+ let el = null
85
+ try {
86
+ el = context.querySelector(selector)
87
+ } catch (_) {
88
+ return false
89
+ }
90
+ if (!el) return false
91
+ // An element hypercms has an editor on cannot answer this from its live DOM.
92
+ // Squire wraps the content of a block it binds in a <div>, so a plain
93
+ // paragraph grows a child the instant someone clicks it, and reading that
94
+ // back as author markup upgrades the rule to @innerHTML and turns a
95
+ // plain-text field into a rich-text one just by being clicked. The marker
96
+ // carries the verdict from before the editor arrived, which is the only
97
+ // moment the question had an honest answer. Measured in Chrome: the wrapper
98
+ // lands at t+0 and the upgrade followed on the next observer batch.
99
+ if (el.hasAttribute(BOUND_ATTR)) return el.getAttribute(BOUND_ATTR) === 'rich'
100
+ return el.children.length > 0
101
+ }
102
+
103
+ function queryAll(root, selector) {
104
+ try {
105
+ return [...root.querySelectorAll(selector)]
106
+ } catch (_) {
107
+ return []
108
+ }
109
+ }
110
+
111
+ // Grow a form textarea to fit its content. Browsers with `field-sizing:
112
+ // content` handle this in CSS (the theme sets it); everywhere else the
113
+ // height is pinned to scrollHeight on populate and on every input.
114
+ export function autosizeTextarea(el) {
115
+ if (!el || el.tagName !== 'TEXTAREA') return
116
+ const win = el.ownerDocument.defaultView || (typeof window !== 'undefined' ? window : null)
117
+ if (win && win.CSS && win.CSS.supports && win.CSS.supports('field-sizing: content')) return
118
+ el.style.height = 'auto'
119
+ el.style.height = el.scrollHeight + 'px'
120
+ }
121
+
122
+ // Runs after any form (or form fragment) lands in the live DOM: sizes the
123
+ // autosize fallback and mounts richclay on rich-text surfaces when the host
124
+ // page ships it (window.richclay / window.hyperclay.RichClay). Without
125
+ // richclay the surface stays a plain contenteditable bound via @innerHTML,
126
+ // which still round-trips markup — richclay only adds the editing chrome.
127
+ //
128
+ // `formRichText` is the view's, read off view.enhanceFormRichText. The inline
129
+ // view passes false: its form fields are never focused (rich text is edited on
130
+ // the page element itself), and each instance installs five document-level
131
+ // capture listeners that test event.target against their element on every
132
+ // keydown, beforeinput, cut, paste and drop. Twenty rich fields is a hundred
133
+ // dead listeners. The autosize pass runs either way — the popover shows those
134
+ // same fields for every non-text target.
135
+ export function enhanceFields(root, doc, formRichText = true) {
136
+ if (!root || !root.querySelectorAll) return
137
+ root.querySelectorAll('textarea[data-hcms-field]').forEach(autosizeTextarea)
138
+ if (formRichText === false) return
139
+
140
+ const win = (doc && doc.defaultView) || (typeof window !== 'undefined' ? window : null)
141
+ const RichClay = resolveRichClay(win)
142
+ if (!RichClay) return
143
+
144
+ root.querySelectorAll('[contenteditable][data-hcms-field]').forEach((el) => {
145
+ if (el.__hcmsRichclay) return
146
+ let editor
147
+ try {
148
+ // hyperclay:false keeps the form field out of the page's save/undo
149
+ // machinery (page writes go through commit) and activates the editor
150
+ // regardless of the host's edit-mode signal.
151
+ editor = new RichClay(el, {
152
+ inline: true,
153
+ hyperclay: false,
154
+ toolbar: ['bold', 'italic', 'link', 'undo', 'redo'],
155
+ })
156
+ } catch (err) {
157
+ console.warn('[hypercms] richclay activation failed; field stays plain contenteditable', err)
158
+ return
159
+ }
160
+ el.__hcmsRichclay = editor
161
+ // Toolbar commands mutate the DOM through squire, which doesn't always
162
+ // fire a native input event; mirror squire's own input signal so the
163
+ // form's delegated listener commits the change. Duplicate events are
164
+ // harmless — commits are fingerprinted.
165
+ const squire = editor && editor.squire
166
+ if (squire && typeof squire.addEventListener === 'function') {
167
+ squire.addEventListener('input', () => {
168
+ const Ev = (win && win.Event) || Event
169
+ el.dispatchEvent(new Ev('input', { bubbles: true }))
170
+ })
171
+ }
172
+ })
173
+ }