@aglyn/besigner-ui 1.0.0-beta.143

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 (486) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +7 -0
  3. package/package.json +73 -0
  4. package/src/besigner.d.ts +88 -0
  5. package/src/besigner.js +89 -0
  6. package/src/besigner.js.map +1 -0
  7. package/src/index.d.ts +17 -0
  8. package/src/index.js +18 -0
  9. package/src/index.js.map +1 -0
  10. package/src/lib/box-styler/box-styler.d.ts +57 -0
  11. package/src/lib/box-styler/box-styler.js +240 -0
  12. package/src/lib/box-styler/box-styler.js.map +1 -0
  13. package/src/lib/box-styler/components/box-diagram.d.ts +89 -0
  14. package/src/lib/box-styler/components/box-diagram.js +661 -0
  15. package/src/lib/box-styler/components/box-diagram.js.map +1 -0
  16. package/src/lib/box-styler/components/legend.d.ts +56 -0
  17. package/src/lib/box-styler/components/legend.js +130 -0
  18. package/src/lib/box-styler/components/legend.js.map +1 -0
  19. package/src/lib/box-styler/components/spacing-editor.d.ts +55 -0
  20. package/src/lib/box-styler/components/spacing-editor.js +347 -0
  21. package/src/lib/box-styler/components/spacing-editor.js.map +1 -0
  22. package/src/lib/box-styler/constants.d.ts +17 -0
  23. package/src/lib/box-styler/constants.js +30 -0
  24. package/src/lib/box-styler/constants.js.map +1 -0
  25. package/src/lib/box-styler/index.d.ts +2 -0
  26. package/src/lib/box-styler/index.js +4 -0
  27. package/src/lib/box-styler/index.js.map +1 -0
  28. package/src/lib/box-styler/region-fills.d.ts +107 -0
  29. package/src/lib/box-styler/region-fills.js +139 -0
  30. package/src/lib/box-styler/region-fills.js.map +1 -0
  31. package/src/lib/box-styler/spacing-value.d.ts +104 -0
  32. package/src/lib/box-styler/spacing-value.js +223 -0
  33. package/src/lib/box-styler/spacing-value.js.map +1 -0
  34. package/src/lib/box-styler/types.d.ts +29 -0
  35. package/src/lib/box-styler/types.js +18 -0
  36. package/src/lib/box-styler/types.js.map +1 -0
  37. package/src/lib/components/accordion-list.component.d.ts +50 -0
  38. package/src/lib/components/accordion-list.component.js +228 -0
  39. package/src/lib/components/accordion-list.component.js.map +1 -0
  40. package/src/lib/components/add-controls.component.d.ts +22 -0
  41. package/src/lib/components/add-controls.component.js +50 -0
  42. package/src/lib/components/add-controls.component.js.map +1 -0
  43. package/src/lib/components/app-bar-breadcrumbs.component.d.ts +29 -0
  44. package/src/lib/components/app-bar-breadcrumbs.component.js +279 -0
  45. package/src/lib/components/app-bar-breadcrumbs.component.js.map +1 -0
  46. package/src/lib/components/app-bar-primary.component.d.ts +21 -0
  47. package/src/lib/components/app-bar-primary.component.js +108 -0
  48. package/src/lib/components/app-bar-primary.component.js.map +1 -0
  49. package/src/lib/components/app-bar-secondary.component.d.ts +21 -0
  50. package/src/lib/components/app-bar-secondary.component.js +94 -0
  51. package/src/lib/components/app-bar-secondary.component.js.map +1 -0
  52. package/src/lib/components/aside-panel.component.d.ts +23 -0
  53. package/src/lib/components/aside-panel.component.js +505 -0
  54. package/src/lib/components/aside-panel.component.js.map +1 -0
  55. package/src/lib/components/besigner-conflict-alert.component.d.ts +36 -0
  56. package/src/lib/components/besigner-conflict-alert.component.js +51 -0
  57. package/src/lib/components/besigner-conflict-alert.component.js.map +1 -0
  58. package/src/lib/components/besigner-dnd-context.component.d.ts +32 -0
  59. package/src/lib/components/besigner-dnd-context.component.js +75 -0
  60. package/src/lib/components/besigner-dnd-context.component.js.map +1 -0
  61. package/src/lib/components/besigner-draft-alert.component.d.ts +70 -0
  62. package/src/lib/components/besigner-draft-alert.component.js +155 -0
  63. package/src/lib/components/besigner-draft-alert.component.js.map +1 -0
  64. package/src/lib/components/besigner-root-provider.component.d.ts +33 -0
  65. package/src/lib/components/besigner-root-provider.component.js +68 -0
  66. package/src/lib/components/besigner-root-provider.component.js.map +1 -0
  67. package/src/lib/components/binding-preview-controls.component.d.ts +28 -0
  68. package/src/lib/components/binding-preview-controls.component.js +63 -0
  69. package/src/lib/components/binding-preview-controls.component.js.map +1 -0
  70. package/src/lib/components/closeable-drawer.component.d.ts +32 -0
  71. package/src/lib/components/closeable-drawer.component.js +134 -0
  72. package/src/lib/components/closeable-drawer.component.js.map +1 -0
  73. package/src/lib/components/component-accordion-list.d.ts +28 -0
  74. package/src/lib/components/component-accordion-list.js +205 -0
  75. package/src/lib/components/component-accordion-list.js.map +1 -0
  76. package/src/lib/components/component-icon.component.d.ts +32 -0
  77. package/src/lib/components/component-icon.component.js +51 -0
  78. package/src/lib/components/component-icon.component.js.map +1 -0
  79. package/src/lib/components/component-picker.d.ts +27 -0
  80. package/src/lib/components/component-picker.js +368 -0
  81. package/src/lib/components/component-picker.js.map +1 -0
  82. package/src/lib/components/components-grid-list.component.d.ts +31 -0
  83. package/src/lib/components/components-grid-list.component.js +162 -0
  84. package/src/lib/components/components-grid-list.component.js.map +1 -0
  85. package/src/lib/components/custom-css-form.component.d.ts +115 -0
  86. package/src/lib/components/custom-css-form.component.js +699 -0
  87. package/src/lib/components/custom-css-form.component.js.map +1 -0
  88. package/src/lib/components/device-preview-controls.component.d.ts +22 -0
  89. package/src/lib/components/device-preview-controls.component.js +150 -0
  90. package/src/lib/components/device-preview-controls.component.js.map +1 -0
  91. package/src/lib/components/dnd/canvas-drop-indicator.d.ts +20 -0
  92. package/src/lib/components/dnd/canvas-drop-indicator.js +61 -0
  93. package/src/lib/components/dnd/canvas-drop-indicator.js.map +1 -0
  94. package/src/lib/components/dnd/draggable-droppable.d.ts +31 -0
  95. package/src/lib/components/dnd/draggable-droppable.js +383 -0
  96. package/src/lib/components/dnd/draggable-droppable.js.map +1 -0
  97. package/src/lib/components/dnd/draggable.d.ts +42 -0
  98. package/src/lib/components/dnd/draggable.js +66 -0
  99. package/src/lib/components/dnd/draggable.js.map +1 -0
  100. package/src/lib/components/dnd/drop-indicator.d.ts +31 -0
  101. package/src/lib/components/dnd/drop-indicator.js +139 -0
  102. package/src/lib/components/dnd/drop-indicator.js.map +1 -0
  103. package/src/lib/components/dnd/droppable.d.ts +43 -0
  104. package/src/lib/components/dnd/droppable.js +63 -0
  105. package/src/lib/components/dnd/droppable.js.map +1 -0
  106. package/src/lib/components/element-card.component.d.ts +23 -0
  107. package/src/lib/components/element-card.component.js +49 -0
  108. package/src/lib/components/element-card.component.js.map +1 -0
  109. package/src/lib/components/element-classes-field.component.d.ts +41 -0
  110. package/src/lib/components/element-classes-field.component.js +140 -0
  111. package/src/lib/components/element-classes-field.component.js.map +1 -0
  112. package/src/lib/components/element-detail-overlay.component.d.ts +55 -0
  113. package/src/lib/components/element-detail-overlay.component.js +157 -0
  114. package/src/lib/components/element-detail-overlay.component.js.map +1 -0
  115. package/src/lib/components/element-detail.component.d.ts +56 -0
  116. package/src/lib/components/element-detail.component.js +171 -0
  117. package/src/lib/components/element-detail.component.js.map +1 -0
  118. package/src/lib/components/element-info-details.component.d.ts +18 -0
  119. package/src/lib/components/element-info-details.component.js +169 -0
  120. package/src/lib/components/element-info-details.component.js.map +1 -0
  121. package/src/lib/components/element-interactions-form.component.d.ts +21 -0
  122. package/src/lib/components/element-interactions-form.component.js +199 -0
  123. package/src/lib/components/element-interactions-form.component.js.map +1 -0
  124. package/src/lib/components/element-preview.component.d.ts +75 -0
  125. package/src/lib/components/element-preview.component.js +346 -0
  126. package/src/lib/components/element-preview.component.js.map +1 -0
  127. package/src/lib/components/element-props-form.component.d.ts +565 -0
  128. package/src/lib/components/element-props-form.component.js +2392 -0
  129. package/src/lib/components/element-props-form.component.js.map +1 -0
  130. package/src/lib/components/element-styles-form-template.component.d.ts +27 -0
  131. package/src/lib/components/element-styles-form-template.component.js +89 -0
  132. package/src/lib/components/element-styles-form-template.component.js.map +1 -0
  133. package/src/lib/components/element-styles-form.component.d.ts +52 -0
  134. package/src/lib/components/element-styles-form.component.js +1350 -0
  135. package/src/lib/components/element-styles-form.component.js.map +1 -0
  136. package/src/lib/components/empty-document-slot.d.ts +39 -0
  137. package/src/lib/components/empty-document-slot.js +121 -0
  138. package/src/lib/components/empty-document-slot.js.map +1 -0
  139. package/src/lib/components/empty-results.d.ts +22 -0
  140. package/src/lib/components/empty-results.js +131 -0
  141. package/src/lib/components/empty-results.js.map +1 -0
  142. package/src/lib/components/history-controls.component.d.ts +21 -0
  143. package/src/lib/components/history-controls.component.js +67 -0
  144. package/src/lib/components/history-controls.component.js.map +1 -0
  145. package/src/lib/components/inline-markdown-editor.component.d.ts +17 -0
  146. package/src/lib/components/inline-markdown-editor.component.js +220 -0
  147. package/src/lib/components/inline-markdown-editor.component.js.map +1 -0
  148. package/src/lib/components/inline-text-editor.component.d.ts +48 -0
  149. package/src/lib/components/inline-text-editor.component.js +905 -0
  150. package/src/lib/components/inline-text-editor.component.js.map +1 -0
  151. package/src/lib/components/insert-token-menu.component.d.ts +86 -0
  152. package/src/lib/components/insert-token-menu.component.js +232 -0
  153. package/src/lib/components/insert-token-menu.component.js.map +1 -0
  154. package/src/lib/components/instance-attr-overrides.component.d.ts +50 -0
  155. package/src/lib/components/instance-attr-overrides.component.js +298 -0
  156. package/src/lib/components/instance-attr-overrides.component.js.map +1 -0
  157. package/src/lib/components/interact-controls.component.d.ts +22 -0
  158. package/src/lib/components/interact-controls.component.js +74 -0
  159. package/src/lib/components/interact-controls.component.js.map +1 -0
  160. package/src/lib/components/markdown-attribute-field.component.d.ts +40 -0
  161. package/src/lib/components/markdown-attribute-field.component.js +103 -0
  162. package/src/lib/components/markdown-attribute-field.component.js.map +1 -0
  163. package/src/lib/components/node-card.d.ts +24 -0
  164. package/src/lib/components/node-card.js +86 -0
  165. package/src/lib/components/node-card.js.map +1 -0
  166. package/src/lib/components/node-context-menu.d.ts +25 -0
  167. package/src/lib/components/node-context-menu.js +558 -0
  168. package/src/lib/components/node-context-menu.js.map +1 -0
  169. package/src/lib/components/node-leaf.d.ts +39 -0
  170. package/src/lib/components/node-leaf.js +628 -0
  171. package/src/lib/components/node-leaf.js.map +1 -0
  172. package/src/lib/components/node-outline.d.ts +24 -0
  173. package/src/lib/components/node-outline.js +156 -0
  174. package/src/lib/components/node-outline.js.map +1 -0
  175. package/src/lib/components/node-overlay.d.ts +23 -0
  176. package/src/lib/components/node-overlay.js +299 -0
  177. package/src/lib/components/node-overlay.js.map +1 -0
  178. package/src/lib/components/node-quick-actions.d.ts +24 -0
  179. package/src/lib/components/node-quick-actions.js +284 -0
  180. package/src/lib/components/node-quick-actions.js.map +1 -0
  181. package/src/lib/components/node-tree-view.d.ts +106 -0
  182. package/src/lib/components/node-tree-view.js +820 -0
  183. package/src/lib/components/node-tree-view.js.map +1 -0
  184. package/src/lib/components/panel-controls.component.d.ts +22 -0
  185. package/src/lib/components/panel-controls.component.js +76 -0
  186. package/src/lib/components/panel-controls.component.js.map +1 -0
  187. package/src/lib/components/picker-search-field.d.ts +38 -0
  188. package/src/lib/components/picker-search-field.js +79 -0
  189. package/src/lib/components/picker-search-field.js.map +1 -0
  190. package/src/lib/components/plugin-settings-field.component.d.ts +38 -0
  191. package/src/lib/components/plugin-settings-field.component.js +264 -0
  192. package/src/lib/components/plugin-settings-field.component.js.map +1 -0
  193. package/src/lib/components/properties-dialog.component.d.ts +22 -0
  194. package/src/lib/components/properties-dialog.component.js +40 -0
  195. package/src/lib/components/properties-dialog.component.js.map +1 -0
  196. package/src/lib/components/property-binding-field.component.d.ts +142 -0
  197. package/src/lib/components/property-binding-field.component.js +325 -0
  198. package/src/lib/components/property-binding-field.component.js.map +1 -0
  199. package/src/lib/components/property-values-form.component.d.ts +43 -0
  200. package/src/lib/components/property-values-form.component.js +223 -0
  201. package/src/lib/components/property-values-form.component.js.map +1 -0
  202. package/src/lib/components/scheme-preview-controls.component.d.ts +26 -0
  203. package/src/lib/components/scheme-preview-controls.component.js +56 -0
  204. package/src/lib/components/scheme-preview-controls.component.js.map +1 -0
  205. package/src/lib/components/screen-link-field.component.d.ts +118 -0
  206. package/src/lib/components/screen-link-field.component.js +282 -0
  207. package/src/lib/components/screen-link-field.component.js.map +1 -0
  208. package/src/lib/components/site-theme-color-tokens-provider.component.d.ts +33 -0
  209. package/src/lib/components/site-theme-color-tokens-provider.component.js +53 -0
  210. package/src/lib/components/site-theme-color-tokens-provider.component.js.map +1 -0
  211. package/src/lib/components/subtree-json-dialog.component.d.ts +46 -0
  212. package/src/lib/components/subtree-json-dialog.component.js +125 -0
  213. package/src/lib/components/subtree-json-dialog.component.js.map +1 -0
  214. package/src/lib/components/token-pill.component.d.ts +51 -0
  215. package/src/lib/components/token-pill.component.js +164 -0
  216. package/src/lib/components/token-pill.component.js.map +1 -0
  217. package/src/lib/components/token-text-field.component.d.ts +146 -0
  218. package/src/lib/components/token-text-field.component.js +603 -0
  219. package/src/lib/components/token-text-field.component.js.map +1 -0
  220. package/src/lib/components/tree/tree-list.d.ts +6 -0
  221. package/src/lib/components/tree/tree-list.js +108 -0
  222. package/src/lib/components/tree/tree-list.js.map +1 -0
  223. package/src/lib/components/viewport-canvas.component.d.ts +23 -0
  224. package/src/lib/components/viewport-canvas.component.js +128 -0
  225. package/src/lib/components/viewport-canvas.component.js.map +1 -0
  226. package/src/lib/components/viewport-frame.component.d.ts +47 -0
  227. package/src/lib/components/viewport-frame.component.js +332 -0
  228. package/src/lib/components/viewport-frame.component.js.map +1 -0
  229. package/src/lib/components/viewport-root.component.d.ts +22 -0
  230. package/src/lib/components/viewport-root.component.js +112 -0
  231. package/src/lib/components/viewport-root.component.js.map +1 -0
  232. package/src/lib/components/viewport-zoom-controls.d.ts +29 -0
  233. package/src/lib/components/viewport-zoom-controls.js +147 -0
  234. package/src/lib/components/viewport-zoom-controls.js.map +1 -0
  235. package/src/lib/components/workspace-editor.component.d.ts +23 -0
  236. package/src/lib/components/workspace-editor.component.js +191 -0
  237. package/src/lib/components/workspace-editor.component.js.map +1 -0
  238. package/src/lib/components/workspace-panel.component.d.ts +28 -0
  239. package/src/lib/components/workspace-panel.component.js +147 -0
  240. package/src/lib/components/workspace-panel.component.js.map +1 -0
  241. package/src/lib/constants/sample-data.d.ts +18 -0
  242. package/src/lib/constants/sample-data.js +106 -0
  243. package/src/lib/constants/sample-data.js.map +1 -0
  244. package/src/lib/constants/shared.d.ts +17 -0
  245. package/src/lib/constants/shared.js +18 -0
  246. package/src/lib/constants/shared.js.map +1 -0
  247. package/src/lib/contexts/besigner-app-context.d.ts +30 -0
  248. package/src/lib/contexts/besigner-app-context.js +41 -0
  249. package/src/lib/contexts/besigner-app-context.js.map +1 -0
  250. package/src/lib/contexts/binding-picker-context.d.ts +78 -0
  251. package/src/lib/contexts/binding-picker-context.js +21 -0
  252. package/src/lib/contexts/binding-picker-context.js.map +1 -0
  253. package/src/lib/contexts/canvas-host-tokens-context.d.ts +49 -0
  254. package/src/lib/contexts/canvas-host-tokens-context.js +63 -0
  255. package/src/lib/contexts/canvas-host-tokens-context.js.map +1 -0
  256. package/src/lib/contexts/canvas-reveal-context.d.ts +32 -0
  257. package/src/lib/contexts/canvas-reveal-context.js +34 -0
  258. package/src/lib/contexts/canvas-reveal-context.js.map +1 -0
  259. package/src/lib/contexts/component-promotion-context.d.ts +89 -0
  260. package/src/lib/contexts/component-promotion-context.js +21 -0
  261. package/src/lib/contexts/component-promotion-context.js.map +1 -0
  262. package/src/lib/contexts/components-drawer-context.provider.d.ts +32 -0
  263. package/src/lib/contexts/components-drawer-context.provider.js +80 -0
  264. package/src/lib/contexts/components-drawer-context.provider.js.map +1 -0
  265. package/src/lib/contexts/element-drawer-context.d.ts +1005 -0
  266. package/src/lib/contexts/element-drawer-context.js +45 -0
  267. package/src/lib/contexts/element-drawer-context.js.map +1 -0
  268. package/src/lib/contexts/inspected-selection.d.ts +32 -0
  269. package/src/lib/contexts/inspected-selection.js +38 -0
  270. package/src/lib/contexts/inspected-selection.js.map +1 -0
  271. package/src/lib/contexts/inspector-extras-context.d.ts +56 -0
  272. package/src/lib/contexts/inspector-extras-context.js +35 -0
  273. package/src/lib/contexts/inspector-extras-context.js.map +1 -0
  274. package/src/lib/contexts/interactions-context.d.ts +99 -0
  275. package/src/lib/contexts/interactions-context.js +22 -0
  276. package/src/lib/contexts/interactions-context.js.map +1 -0
  277. package/src/lib/contexts/layout-chrome-context.d.ts +37 -0
  278. package/src/lib/contexts/layout-chrome-context.js +75 -0
  279. package/src/lib/contexts/layout-chrome-context.js.map +1 -0
  280. package/src/lib/contexts/media-asset-facts-context.d.ts +74 -0
  281. package/src/lib/contexts/media-asset-facts-context.js +27 -0
  282. package/src/lib/contexts/media-asset-facts-context.js.map +1 -0
  283. package/src/lib/contexts/media-picker-context.d.ts +88 -0
  284. package/src/lib/contexts/media-picker-context.js +21 -0
  285. package/src/lib/contexts/media-picker-context.js.map +1 -0
  286. package/src/lib/contexts/rendered-canvas-elements.d.ts +42 -0
  287. package/src/lib/contexts/rendered-canvas-elements.js +79 -0
  288. package/src/lib/contexts/rendered-canvas-elements.js.map +1 -0
  289. package/src/lib/contexts/repeat-record-context.d.ts +38 -0
  290. package/src/lib/contexts/repeat-record-context.js +21 -0
  291. package/src/lib/contexts/repeat-record-context.js.map +1 -0
  292. package/src/lib/contexts/repeat-rows-context.d.ts +53 -0
  293. package/src/lib/contexts/repeat-rows-context.js +38 -0
  294. package/src/lib/contexts/repeat-rows-context.js.map +1 -0
  295. package/src/lib/contexts/toolbar-extras-context.d.ts +31 -0
  296. package/src/lib/contexts/toolbar-extras-context.js +33 -0
  297. package/src/lib/contexts/toolbar-extras-context.js.map +1 -0
  298. package/src/lib/drafts/besigner-draft-store.d.ts +110 -0
  299. package/src/lib/drafts/besigner-draft-store.js +125 -0
  300. package/src/lib/drafts/besigner-draft-store.js.map +1 -0
  301. package/src/lib/drafts/besigner-server-draft.d.ts +130 -0
  302. package/src/lib/drafts/besigner-server-draft.js +211 -0
  303. package/src/lib/drafts/besigner-server-draft.js.map +1 -0
  304. package/src/lib/form-fields/components/shared/inline-form-control.d.ts +32 -0
  305. package/src/lib/form-fields/components/shared/inline-form-control.js +85 -0
  306. package/src/lib/form-fields/components/shared/inline-form-control.js.map +1 -0
  307. package/src/lib/form-fields/components/shared/toggle-button-form-control.d.ts +33 -0
  308. package/src/lib/form-fields/components/shared/toggle-button-form-control.js +83 -0
  309. package/src/lib/form-fields/components/shared/toggle-button-form-control.js.map +1 -0
  310. package/src/lib/form-fields/form-fields.d.ts +20 -0
  311. package/src/lib/form-fields/form-fields.js +21 -0
  312. package/src/lib/form-fields/form-fields.js.map +1 -0
  313. package/src/lib/form-fields/index.d.ts +1 -0
  314. package/src/lib/form-fields/index.js +3 -0
  315. package/src/lib/form-fields/index.js.map +1 -0
  316. package/src/lib/hooks/use-add-element-drawer-callback.d.ts +28 -0
  317. package/src/lib/hooks/use-add-element-drawer-callback.js +112 -0
  318. package/src/lib/hooks/use-add-element-drawer-callback.js.map +1 -0
  319. package/src/lib/hooks/use-aglyn-besigner-flag.d.ts +23 -0
  320. package/src/lib/hooks/use-aglyn-besigner-flag.js +47 -0
  321. package/src/lib/hooks/use-aglyn-besigner-flag.js.map +1 -0
  322. package/src/lib/hooks/use-aglyn-besigner-panel-value.d.ts +23 -0
  323. package/src/lib/hooks/use-aglyn-besigner-panel-value.js +54 -0
  324. package/src/lib/hooks/use-aglyn-besigner-panel-value.js.map +1 -0
  325. package/src/lib/hooks/use-aglyn-besigner-panel.d.ts +23 -0
  326. package/src/lib/hooks/use-aglyn-besigner-panel.js +47 -0
  327. package/src/lib/hooks/use-aglyn-besigner-panel.js.map +1 -0
  328. package/src/lib/hooks/use-anchored-rect.d.ts +68 -0
  329. package/src/lib/hooks/use-anchored-rect.js +131 -0
  330. package/src/lib/hooks/use-anchored-rect.js.map +1 -0
  331. package/src/lib/hooks/use-besigner-app-context.d.ts +18 -0
  332. package/src/lib/hooks/use-besigner-app-context.js +19 -0
  333. package/src/lib/hooks/use-besigner-app-context.js.map +1 -0
  334. package/src/lib/hooks/use-besigner-document.d.ts +309 -0
  335. package/src/lib/hooks/use-besigner-document.js +500 -0
  336. package/src/lib/hooks/use-besigner-document.js.map +1 -0
  337. package/src/lib/hooks/use-besigner-draft.d.ts +209 -0
  338. package/src/lib/hooks/use-besigner-draft.js +429 -0
  339. package/src/lib/hooks/use-besigner-draft.js.map +1 -0
  340. package/src/lib/hooks/use-clipboard-callbacks.d.ts +29 -0
  341. package/src/lib/hooks/use-clipboard-callbacks.js +82 -0
  342. package/src/lib/hooks/use-clipboard-callbacks.js.map +1 -0
  343. package/src/lib/hooks/use-clipboard-shortcuts.d.ts +52 -0
  344. package/src/lib/hooks/use-clipboard-shortcuts.js +102 -0
  345. package/src/lib/hooks/use-clipboard-shortcuts.js.map +1 -0
  346. package/src/lib/hooks/use-component-propagation-notice.d.ts +96 -0
  347. package/src/lib/hooks/use-component-propagation-notice.js +177 -0
  348. package/src/lib/hooks/use-component-propagation-notice.js.map +1 -0
  349. package/src/lib/hooks/use-debounced-commit.d.ts +43 -0
  350. package/src/lib/hooks/use-debounced-commit.js +88 -0
  351. package/src/lib/hooks/use-debounced-commit.js.map +1 -0
  352. package/src/lib/hooks/use-delete-element-callback.d.ts +24 -0
  353. package/src/lib/hooks/use-delete-element-callback.js +82 -0
  354. package/src/lib/hooks/use-delete-element-callback.js.map +1 -0
  355. package/src/lib/hooks/use-detail-hover-intent.d.ts +76 -0
  356. package/src/lib/hooks/use-detail-hover-intent.js +123 -0
  357. package/src/lib/hooks/use-detail-hover-intent.js.map +1 -0
  358. package/src/lib/hooks/use-document-repair-callbacks.d.ts +50 -0
  359. package/src/lib/hooks/use-document-repair-callbacks.js +237 -0
  360. package/src/lib/hooks/use-document-repair-callbacks.js.map +1 -0
  361. package/src/lib/hooks/use-insert-token-options.d.ts +52 -0
  362. package/src/lib/hooks/use-insert-token-options.js +230 -0
  363. package/src/lib/hooks/use-insert-token-options.js.map +1 -0
  364. package/src/lib/hooks/use-leaf-drag.d.ts +24 -0
  365. package/src/lib/hooks/use-leaf-drag.js +28 -0
  366. package/src/lib/hooks/use-leaf-drag.js.map +1 -0
  367. package/src/lib/hooks/use-leaf-drop.d.ts +31 -0
  368. package/src/lib/hooks/use-leaf-drop.js +43 -0
  369. package/src/lib/hooks/use-leaf-drop.js.map +1 -0
  370. package/src/lib/hooks/use-markdown-media-picker.d.ts +63 -0
  371. package/src/lib/hooks/use-markdown-media-picker.js +110 -0
  372. package/src/lib/hooks/use-markdown-media-picker.js.map +1 -0
  373. package/src/lib/hooks/use-media-asset-facts-overlay.d.ts +43 -0
  374. package/src/lib/hooks/use-media-asset-facts-overlay.js +133 -0
  375. package/src/lib/hooks/use-media-asset-facts-overlay.js.map +1 -0
  376. package/src/lib/hooks/use-move-node-callbacks.d.ts +22 -0
  377. package/src/lib/hooks/use-move-node-callbacks.js +57 -0
  378. package/src/lib/hooks/use-move-node-callbacks.js.map +1 -0
  379. package/src/lib/hooks/use-node-with-host-tokens.d.ts +42 -0
  380. package/src/lib/hooks/use-node-with-host-tokens.js +59 -0
  381. package/src/lib/hooks/use-node-with-host-tokens.js.map +1 -0
  382. package/src/lib/hooks/use-picker-filter.d.ts +61 -0
  383. package/src/lib/hooks/use-picker-filter.js +122 -0
  384. package/src/lib/hooks/use-picker-filter.js.map +1 -0
  385. package/src/lib/hooks/use-repeat-preview.d.ts +64 -0
  386. package/src/lib/hooks/use-repeat-preview.js +214 -0
  387. package/src/lib/hooks/use-repeat-preview.js.map +1 -0
  388. package/src/lib/hooks/use-repeat-sources.d.ts +17 -0
  389. package/src/lib/hooks/use-repeat-sources.js +41 -0
  390. package/src/lib/hooks/use-repeat-sources.js.map +1 -0
  391. package/src/lib/hooks/use-visible-component-categories.d.ts +37 -0
  392. package/src/lib/hooks/use-visible-component-categories.js +79 -0
  393. package/src/lib/hooks/use-visible-component-categories.js.map +1 -0
  394. package/src/lib/utils/active-host-theme.d.ts +28 -0
  395. package/src/lib/utils/active-host-theme.js +77 -0
  396. package/src/lib/utils/active-host-theme.js.map +1 -0
  397. package/src/lib/utils/attr-target.d.ts +170 -0
  398. package/src/lib/utils/attr-target.js +229 -0
  399. package/src/lib/utils/attr-target.js.map +1 -0
  400. package/src/lib/utils/attribute-field-value.d.ts +21 -0
  401. package/src/lib/utils/attribute-field-value.js +28 -0
  402. package/src/lib/utils/attribute-field-value.js.map +1 -0
  403. package/src/lib/utils/canvas-context-menu.d.ts +28 -0
  404. package/src/lib/utils/canvas-context-menu.js +56 -0
  405. package/src/lib/utils/canvas-context-menu.js.map +1 -0
  406. package/src/lib/utils/canvas-reveal.d.ts +115 -0
  407. package/src/lib/utils/canvas-reveal.js +165 -0
  408. package/src/lib/utils/canvas-reveal.js.map +1 -0
  409. package/src/lib/utils/describe-element.d.ts +72 -0
  410. package/src/lib/utils/describe-element.js +159 -0
  411. package/src/lib/utils/describe-element.js.map +1 -0
  412. package/src/lib/utils/device-preview-styles.d.ts +89 -0
  413. package/src/lib/utils/device-preview-styles.js +228 -0
  414. package/src/lib/utils/device-preview-styles.js.map +1 -0
  415. package/src/lib/utils/docs-help.d.ts +22 -0
  416. package/src/lib/utils/docs-help.generated.d.ts +47 -0
  417. package/src/lib/utils/docs-help.generated.js +229 -0
  418. package/src/lib/utils/docs-help.generated.js.map +1 -0
  419. package/src/lib/utils/docs-help.js +37 -0
  420. package/src/lib/utils/docs-help.js.map +1 -0
  421. package/src/lib/utils/held-answers-store.d.ts +59 -0
  422. package/src/lib/utils/held-answers-store.js +94 -0
  423. package/src/lib/utils/held-answers-store.js.map +1 -0
  424. package/src/lib/utils/in-place-edit-surface.d.ts +118 -0
  425. package/src/lib/utils/in-place-edit-surface.js +164 -0
  426. package/src/lib/utils/in-place-edit-surface.js.map +1 -0
  427. package/src/lib/utils/inline-markdown-edit.store.d.ts +71 -0
  428. package/src/lib/utils/inline-markdown-edit.store.js +90 -0
  429. package/src/lib/utils/inline-markdown-edit.store.js.map +1 -0
  430. package/src/lib/utils/inline-text-edit.store.d.ts +85 -0
  431. package/src/lib/utils/inline-text-edit.store.js +78 -0
  432. package/src/lib/utils/inline-text-edit.store.js.map +1 -0
  433. package/src/lib/utils/instance-leaf-hit.d.ts +39 -0
  434. package/src/lib/utils/instance-leaf-hit.js +56 -0
  435. package/src/lib/utils/instance-leaf-hit.js.map +1 -0
  436. package/src/lib/utils/muted-classes.d.ts +76 -0
  437. package/src/lib/utils/muted-classes.js +108 -0
  438. package/src/lib/utils/muted-classes.js.map +1 -0
  439. package/src/lib/utils/muted-styles.d.ts +125 -0
  440. package/src/lib/utils/muted-styles.js +193 -0
  441. package/src/lib/utils/muted-styles.js.map +1 -0
  442. package/src/lib/utils/numeric-text-value.d.ts +42 -0
  443. package/src/lib/utils/numeric-text-value.js +47 -0
  444. package/src/lib/utils/numeric-text-value.js.map +1 -0
  445. package/src/lib/utils/preset-interactions.d.ts +37 -0
  446. package/src/lib/utils/preset-interactions.js +87 -0
  447. package/src/lib/utils/preset-interactions.js.map +1 -0
  448. package/src/lib/utils/publish-failure-message.d.ts +35 -0
  449. package/src/lib/utils/publish-failure-message.js +51 -0
  450. package/src/lib/utils/publish-failure-message.js.map +1 -0
  451. package/src/lib/utils/rank-picker-results.d.ts +45 -0
  452. package/src/lib/utils/rank-picker-results.js +136 -0
  453. package/src/lib/utils/rank-picker-results.js.map +1 -0
  454. package/src/lib/utils/responsive-sx.d.ts +65 -0
  455. package/src/lib/utils/responsive-sx.js +129 -0
  456. package/src/lib/utils/responsive-sx.js.map +1 -0
  457. package/src/lib/utils/rich-text-commands.d.ts +28 -0
  458. package/src/lib/utils/rich-text-commands.js +43 -0
  459. package/src/lib/utils/rich-text-commands.js.map +1 -0
  460. package/src/lib/utils/sanitize-rich-text.d.ts +52 -0
  461. package/src/lib/utils/sanitize-rich-text.js +173 -0
  462. package/src/lib/utils/sanitize-rich-text.js.map +1 -0
  463. package/src/lib/utils/state-sx.d.ts +255 -0
  464. package/src/lib/utils/state-sx.js +338 -0
  465. package/src/lib/utils/state-sx.js.map +1 -0
  466. package/src/lib/utils/style-field-groups.d.ts +136 -0
  467. package/src/lib/utils/style-field-groups.js +874 -0
  468. package/src/lib/utils/style-field-groups.js.map +1 -0
  469. package/src/lib/utils/style-field-search.d.ts +84 -0
  470. package/src/lib/utils/style-field-search.js +505 -0
  471. package/src/lib/utils/style-field-search.js.map +1 -0
  472. package/src/lib/utils/style-target.d.ts +69 -0
  473. package/src/lib/utils/style-target.js +203 -0
  474. package/src/lib/utils/style-target.js.map +1 -0
  475. package/src/lib/utils/theme-scale-options.d.ts +169 -0
  476. package/src/lib/utils/theme-scale-options.js +702 -0
  477. package/src/lib/utils/theme-scale-options.js.map +1 -0
  478. package/src/lib/utils/token-editable-dom.d.ts +82 -0
  479. package/src/lib/utils/token-editable-dom.js +280 -0
  480. package/src/lib/utils/token-editable-dom.js.map +1 -0
  481. package/src/lib/utils/token-segments.d.ts +111 -0
  482. package/src/lib/utils/token-segments.js +246 -0
  483. package/src/lib/utils/token-segments.js.map +1 -0
  484. package/src/lib/utils/visibility-styles.d.ts +38 -0
  485. package/src/lib/utils/visibility-styles.js +54 -0
  486. package/src/lib/utils/visibility-styles.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/utils/theme-scale-options.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n PresetChoiceOption,\n ThemeScaleOption,\n} from '@aglyn/shared-ui-jsx-forms'\n\n/**\n * The theme scales the styles panel offers for Font Size, Font Weight and\n * Z-Index (AGL-2486, item 12).\n *\n * Every option's `value` is a token path MUI's sx system resolves ITSELF —\n * `fontSize` and `fontWeight` are declared with `themeKey: 'typography'` and\n * `zIndex` with `themeKey: 'zIndex'`, so `h4.fontSize`, `fontWeightBold` and\n * `appBar` behave exactly like `color: 'primary.main'` does. Nothing new has\n * to resolve them and nothing downstream has to know these lists exist: the\n * panel stores a string, the theme turns it into a number.\n *\n * They are built from the SITE theme rather than hardcoded, so a host that\n * has retuned its type scale or added a z-index layer offers its own values,\n * and the `hint` on each option is read out of that theme too — which is the\n * only thing that makes `h4.fontSize` legible to an author.\n */\n\n/** The subset of a theme these builders read. */\nexport interface ThemeScaleSource {\n typography?: Record<string, unknown>\n zIndex?: Record<string, unknown>\n /** A created theme exposes `spacing` as a FUNCTION (`spacing(2)` →\n * `'16px'`); raw theme options carry the bare unit number. Both are\n * accepted because both reach these builders. */\n spacing?: ((factor: number) => string | number) | number\n /** `shape.borderRadius` — the unit a bare `borderRadius` number multiplies. */\n shape?: { borderRadius?: number | string }\n /** `theme.shadows`, MUI's 25-entry elevation ladder. */\n shadows?: ReadonlyArray<string>\n}\n\n/** `mobileStepper` → `Mobile stepper`. */\nfunction humanizeKey(key: string): string {\n const spaced = key\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/[-_]+/g, ' ')\n .trim()\n .toLowerCase()\n return spaced.charAt(0).toUpperCase() + spaced.slice(1)\n}\n\n/** What a theme value reads as in the hint, or '' when it is not a scalar. */\nfunction hintOf(value: unknown): string {\n if (typeof value === 'number') return Number.isFinite(value) ? `${value}` : ''\n return typeof value === 'string' ? value : ''\n}\n\n/**\n * The typography variants offered as font sizes, in the order a type scale\n * is read rather than alphabetically. A variant the theme does not define —\n * or defines without a `fontSize` — is dropped, so a slimmed-down host theme\n * offers only what it really has.\n */\nconst FONT_SIZE_VARIANTS: ReadonlyArray<{ key: string; label: string }> = [\n { key: 'h1', label: 'Heading 1' },\n { key: 'h2', label: 'Heading 2' },\n { key: 'h3', label: 'Heading 3' },\n { key: 'h4', label: 'Heading 4' },\n { key: 'h5', label: 'Heading 5' },\n { key: 'h6', label: 'Heading 6' },\n { key: 'subtitle1', label: 'Subtitle 1' },\n { key: 'subtitle2', label: 'Subtitle 2' },\n { key: 'body1', label: 'Body' },\n { key: 'body2', label: 'Body small' },\n { key: 'button', label: 'Button' },\n { key: 'caption', label: 'Caption' },\n { key: 'overline', label: 'Overline' },\n]\n\n/**\n * Every variant the theme defines, not just the ones MUI ships (AGL-2486).\n *\n * The list above names MUI's own variants in reading order; a host that adds\n * rungs of its own — Aglyn's theme carries `lede`, `bodyCompact` and `micro`\n * for the 17/13/11px steps MUI has no name for — is unreachable from a fixed\n * list, which leaves an author typing the pixels. Discovering the extras keeps\n * the curated order for the familiar ones and appends whatever else the host\n * defined, sorted small to large so the ramp still reads.\n *\n * A variant is anything under `theme.typography` that is an OBJECT carrying a\n * `fontSize`; that skips `fontFamily`, the `fontWeight*` scalars and\n * `pxToRem` without naming them.\n */\nfunction themeTypographyVariants(\n typography: Record<string, unknown> | undefined,\n): Array<{ key: string; label: string }> {\n if (!typography) return []\n const known = new Set(FONT_SIZE_VARIANTS.map((entry) => entry.key))\n const extra: Array<{ key: string; label: string; size: number }> = []\n for (const key of Object.keys(typography)) {\n if (known.has(key)) continue\n const value = typography[key]\n if (!value || typeof value !== 'object') continue\n const size = (value as Record<string, unknown>).fontSize\n const parsed = Number.parseFloat(String(size ?? ''))\n if (!Number.isFinite(parsed)) continue\n extra.push({ key, label: humanizeKey(key), size: parsed })\n }\n extra.sort((a, b) => a.size - b.size)\n return [...FONT_SIZE_VARIANTS, ...extra.map(({ key, label }) => ({ key, label }))]\n}\n\n/** Font sizes from `theme.typography`, e.g. `h4.fontSize` → `2.125rem`. */\nexport function buildFontSizeScaleOptions(\n theme: ThemeScaleSource | undefined,\n): ThemeScaleOption[] {\n const typography = theme?.typography\n if (!typography) return []\n const options: ThemeScaleOption[] = []\n for (const { key, label } of themeTypographyVariants(typography)) {\n const variant = typography[key]\n if (!variant || typeof variant !== 'object') continue\n const fontSize = (variant as Record<string, unknown>)['fontSize']\n const hint = hintOf(fontSize)\n if (!hint) continue\n options.push({ value: `${key}.fontSize`, label, hint })\n }\n return options\n}\n\n/**\n * The four weights MUI's typography names, then the plain CSS ladder.\n *\n * Both halves are offered because both are real answers: `fontWeightBold`\n * follows a host that decides its bold is 600, while `700` is what an author\n * who wants exactly 700 means. The token entries come first so the\n * theme-following answer is the one in reach.\n */\n/**\n * Weight tokens are DISCOVERED, not listed (AGL-2486).\n *\n * Hardcoding MUI's four defaults would hide every weight a host adds to its\n * own ramp — Aglyn's theme carries SemiBold 600, ExtraBold 800 and Black 900 —\n * leaving a raw number as the only way to reach the brand's own weight.\n * Reading the keys off `theme.typography` means any host's ramp shows up with\n * no edit here.\n *\n * Ordered by the weight each resolves to, so the menu reads light → heavy\n * rather than in whatever order the theme object happened to be written.\n */\nconst FONT_WEIGHT_KEY = /^fontWeight(.+)$/\n\nfunction themeFontWeightTokens(\n typography: Record<string, unknown> | undefined,\n): Array<{ key: string; label: string; weight: number }> {\n if (!typography) return []\n const found: Array<{ key: string; label: string; weight: number }> = []\n for (const key of Object.keys(typography)) {\n const match = FONT_WEIGHT_KEY.exec(key)\n if (!match) continue\n const raw = typography[key]\n const weight =\n typeof raw === 'number' ? raw : Number.parseFloat(String(raw ?? ''))\n if (!Number.isFinite(weight)) continue\n found.push({ key, label: `${humanizeKey(match[1])} (theme)`, weight })\n }\n return found.sort((a, b) => a.weight - b.weight)\n}\n\nconst FONT_WEIGHT_LADDER: ReadonlyArray<{ value: string; label: string }> = [\n { value: '100', label: 'Thin' },\n { value: '200', label: 'Extra light' },\n { value: '300', label: 'Light' },\n { value: '400', label: 'Regular' },\n { value: '500', label: 'Medium' },\n { value: '600', label: 'Semi bold' },\n { value: '700', label: 'Bold' },\n { value: '800', label: 'Extra bold' },\n { value: '900', label: 'Black' },\n]\n\nexport function buildFontWeightScaleOptions(\n theme: ThemeScaleSource | undefined,\n): ThemeScaleOption[] {\n const typography = theme?.typography\n const options: ThemeScaleOption[] = []\n for (const { key, label } of themeFontWeightTokens(typography)) {\n const hint = hintOf(typography ? typography[key] : undefined)\n if (!hint) continue\n options.push({ value: key, label, hint })\n }\n for (const entry of FONT_WEIGHT_LADDER) {\n options.push({ value: entry.value, label: entry.label, hint: entry.value })\n }\n return options\n}\n\n/**\n * Stacking layers from `theme.zIndex`, ordered by the layer they sit on\n * rather than alphabetically — an author picking \"above the app bar\" is\n * reading the stack, not the key names.\n *\n * This is the one of the three where a raw number is usually the WRONG\n * answer: typing `1300` next to a modal the theme also puts at 1300 is a\n * coin toss, and a host that re-tunes its layers leaves that number behind.\n */\nexport function buildZIndexScaleOptions(\n theme: ThemeScaleSource | undefined,\n): ThemeScaleOption[] {\n const zIndex = theme?.zIndex\n if (!zIndex) return []\n return Object.keys(zIndex)\n .filter((key) => typeof zIndex[key] === 'number')\n .sort((a, b) => (zIndex[a] as number) - (zIndex[b] as number))\n .map((key) => ({\n value: key,\n label: humanizeKey(key),\n hint: `${zIndex[key]}`,\n }))\n}\n\n/* ── Spacing ──────────────────────────────────────────────────────────── */\n\n/**\n * One rung of the theme's spacing ladder, as the box styler offers it\n * (AGL-2486, item 5).\n *\n * **`value` is a NUMBER and that is the whole point.** MUI's sx system\n * resolves a bare number on a spacing property through `theme.spacing`, so\n * `marginTop: 2` renders 16px under `spacing: 8` and 8px under `spacing: 4`\n * — it keeps following the theme exactly the way `h4.fontSize` and\n * `primary.main` do. Storing the resolved `'16px'` instead would be wrong\n * for the same reason a flattened colour is wrong: it stops tracking the\n * theme the moment anyone retunes it.\n *\n * The numeric form is also the ONLY one that works. MUI multiplies numbers\n * and passes strings through untouched, so the string `'2'` would reach the\n * browser as `margin-top: 2` and be dropped by the CSS parser.\n */\nexport interface SpacingScaleOption {\n /** The theme spacing STEP, stored as a number so MUI resolves it. */\n value: number\n /** The author's name for it (`Medium`) — no CSS vocabulary required. */\n label: string\n /** What it resolves to in this theme today (`16px`). */\n hint: string\n}\n\n/**\n * The ladder offered, in the order a scale is read.\n *\n * Named rather than numbered because this is the one control in the panel\n * a non-developer is guaranteed to meet: \"Medium\" is a choice anyone can\n * make, \"2\" is a question about what the unit is. The resolved value rides\n * along in the hint so the answer is still there for whoever wants it.\n *\n * `0` is on the ladder as **None**, and it is a real value meaning \"no\n * space\", not the absence of one — the styler keeps \"not set\" as a separate\n * answer that removes the property entirely.\n */\nconst SPACING_STEPS: ReadonlyArray<{ step: number; label: string }> = [\n { step: 0, label: 'None' },\n { step: 0.5, label: 'Hairline' },\n { step: 1, label: 'Extra small' },\n { step: 2, label: 'Small' },\n { step: 3, label: 'Medium' },\n { step: 4, label: 'Large' },\n { step: 6, label: 'Extra large' },\n { step: 8, label: 'Huge' },\n { step: 12, label: 'Giant' },\n]\n\n/** What one step resolves to, or `''` when the theme cannot answer. */\nfunction resolveSpacing(\n spacing: ThemeScaleSource['spacing'],\n step: number,\n): string {\n if (typeof spacing === 'function') {\n const resolved = spacing(step)\n if (typeof resolved === 'number') {\n return Number.isFinite(resolved) ? `${resolved}px` : ''\n }\n return typeof resolved === 'string' ? resolved : ''\n }\n // Raw theme options carry the bare unit; mirror MUI's own arithmetic.\n if (typeof spacing === 'number' && Number.isFinite(spacing)) {\n return `${spacing * step}px`\n }\n return ''\n}\n\n/**\n * The spacing ladder read off the SITE theme, so a host that set\n * `spacing: 4` offers its own eight-step ladder rather than Aglyn's.\n *\n * A theme with no usable `spacing` yields an empty list, which leaves the\n * styler on custom amounts only — never a ladder of numbers that resolve to\n * nothing.\n */\nexport function buildSpacingScaleOptions(\n theme: ThemeScaleSource | undefined,\n): SpacingScaleOption[] {\n const spacing = theme?.spacing\n const options: SpacingScaleOption[] = []\n for (const { step, label } of SPACING_STEPS) {\n const hint = resolveSpacing(spacing, step)\n // `'0px'` is truthy, so None survives this guard — the check is for a\n // theme that cannot resolve the step at all, not for a zero value.\n if (hint === '') continue\n options.push({ value: step, label, hint })\n }\n return options\n}\n\n/** Every theme scale the style field groups need, built once per theme. */\nexport interface StyleThemeScales {\n fontSize: ThemeScaleOption[]\n fontWeight: ThemeScaleOption[]\n zIndex: ThemeScaleOption[]\n /** The box styler's spacing ladder (AGL-2486, item 5). */\n spacing: SpacingScaleOption[]\n /** Corner-radius presets on the theme's shape scale (AGL-2486). */\n cornerRadius: PresetChoiceOption[]\n /** Drop-shadow presets named by what they look like (AGL-2486). */\n shadow: PresetChoiceOption[]\n /** The theme's own faces, then web-safe stacks (AGL-2486). */\n fontFamily: PresetChoiceOption[]\n /** Whole typography variants — `typography: 'h2'` (AGL-2486). */\n typographyVariant: PresetChoiceOption[]\n /** Grid/flex gaps on the theme's spacing ladder (AGL-2486). */\n gap: PresetChoiceOption[]\n}\n\nexport function buildStyleThemeScales(\n theme: ThemeScaleSource | undefined,\n): StyleThemeScales {\n return {\n fontSize: buildFontSizeScaleOptions(theme),\n fontWeight: buildFontWeightScaleOptions(theme),\n zIndex: buildZIndexScaleOptions(theme),\n spacing: buildSpacingScaleOptions(theme),\n cornerRadius: buildCornerRadiusChoices(theme),\n shadow: buildShadowChoices(theme),\n fontFamily: buildFontFamilyChoices(theme),\n typographyVariant: buildTypographyVariantChoices(theme),\n gap: buildGapChoices(theme),\n }\n}\n\n/* ── Corner radius ────────────────────────────────────────────────────── */\n\n/**\n * MUI's own unit for a bare `borderRadius` number, and its default.\n *\n * `borderRadius: 2` renders 8px because MUI multiplies the number by\n * `shape.borderRadius` (4 unless a host changed it) — the same\n * theme-following arithmetic `spacing` gets, and the reason the presets\n * below store NUMBERS. A host that set `shape.borderRadius: 6` gets a\n * ladder of its own without anyone editing this file.\n */\nconst DEFAULT_SHAPE_RADIUS = 4\n\nfunction shapeRadiusUnit(theme: ThemeScaleSource | undefined): number {\n const raw = theme?.shape?.borderRadius\n if (typeof raw === 'number' && Number.isFinite(raw)) return raw\n // A theme may carry a CSS length (`'4px'`); read the leading number so\n // the hints stay right rather than silently reverting to the default.\n if (typeof raw === 'string') {\n const parsed = Number.parseFloat(raw)\n if (Number.isFinite(parsed)) return parsed\n }\n return DEFAULT_SHAPE_RADIUS\n}\n\n/**\n * The rounding ladder, named the way an author describes a shape rather\n * than the way CSS spells one (AGL-2486).\n *\n * A text box for corner radius invites three value systems at once — a pixel\n * length, a percentage, or a theme multiple — and two of them are wrong,\n * because the theme scale behind this property is SHAPE, not spacing. Every\n * rung here is a theme multiple except the two that cannot be: a pill needs a\n * radius larger than the box can ever be, and a circle is a percentage.\n */\nconst RADIUS_STEPS: ReadonlyArray<{ step: number; label: string }> = [\n { step: 0, label: 'Square' },\n { step: 1, label: 'Slightly rounded' },\n { step: 2, label: 'Rounded' },\n { step: 3, label: 'More rounded' },\n { step: 4, label: 'Very rounded' },\n]\n\n/**\n * A radius large enough that any box reads as a pill (CSS clamps a radius\n * to half the shorter side), expressed in px rather than as a theme\n * multiple because it is deliberately NOT following the theme — a pill is\n * a shape, not a spacing decision.\n */\nconst PILL_RADIUS = '9999px'\n\n/** Corner-radius presets, with what each resolves to in THIS theme. */\nexport function buildCornerRadiusChoices(\n theme: ThemeScaleSource | undefined,\n): PresetChoiceOption[] {\n const unit = shapeRadiusUnit(theme)\n const options: PresetChoiceOption[] = RADIUS_STEPS.map(({ step, label }) => ({\n value: step,\n label,\n hint: `${step * unit}px`,\n // The menu tile draws the real shape, so the choice is made by looking.\n preview: `${step * unit}px`,\n }))\n options.push({ value: PILL_RADIUS, label: 'Pill', preview: PILL_RADIUS })\n options.push({\n value: '50%',\n label: 'Circle',\n hint: 'square elements only',\n preview: '50%',\n })\n return options\n}\n\n/* ── Shadow ───────────────────────────────────────────────────────────── */\n\n/**\n * Drop-shadow presets named by what they LOOK like (AGL-2486).\n *\n * The labels say what the shadow looks like, `No shadow` is offered as the\n * real value it is (a component or the theme may be drawing one), and the\n * escape hatch is a `Custom…` entry in this very control rather than a helper\n * pointing at the custom-CSS section.\n *\n * ## The menu is SHORT but the values are theme ELEVATIONS\n *\n * Two constraints pull apart here. MUI's ladder is 25 near-identical Material\n * elevations, which is a worse menu than a handful of shadows that visibly\n * differ — nobody should scroll 25 rows. But a literal CSS shadow is a bespoke\n * value that ignores `theme.shadows`, so a host that retunes its elevations\n * leaves every stored shadow behind.\n *\n * Both hold at once by curating INDICES: six rungs off the host's own\n * ladder, each stored as the number `boxShadow` already resolves through\n * (`themeKey: 'shadows'`), and each previewing the CSS that number renders\n * so the row still shows what it looks like. Same trick as Corner Radius —\n * store the theme multiple, preview the resolved value.\n *\n * `none` stays a string because it is the real value it is: a component or\n * the theme may be drawing a shadow this element wants gone.\n */\nconst SHADOW_STEPS: ReadonlyArray<{ elevation: number; label: string }> = [\n { elevation: 1, label: 'Barely there — a hairline lift' },\n { elevation: 3, label: 'Soft — sits on the page' },\n { elevation: 6, label: 'Lifted — floats a little' },\n { elevation: 12, label: 'Raised — floats well above' },\n { elevation: 24, label: 'Highest — dialog level' },\n]\n\n/**\n * Literal CSS shadows, reached only when a theme carries no usable `shadows`\n * array, so the control never degrades to an empty menu on a host with an\n * unusual theme.\n */\nconst FALLBACK_SHADOWS: ReadonlyArray<{ value: string; label: string }> = [\n { value: '0 1px 3px rgba(0,0,0,0.2)', label: 'Soft — sits on the page' },\n { value: '0 4px 12px rgba(0,0,0,0.15)', label: 'Lifted — floats a little' },\n { value: '0 12px 32px rgba(0,0,0,0.25)', label: 'Raised — floats well above' },\n {\n value: 'inset 0 2px 6px rgba(0,0,0,0.2)',\n label: 'Inset — pressed into the page',\n },\n]\n\nexport function buildShadowChoices(\n theme?: ThemeScaleSource | undefined,\n): PresetChoiceOption[] {\n const shadows = theme?.shadows\n const options: PresetChoiceOption[] = [{ value: 'none', label: 'No shadow' }]\n if (!Array.isArray(shadows) || shadows.length === 0) {\n for (const entry of FALLBACK_SHADOWS) {\n options.push({ value: entry.value, label: entry.label, preview: entry.value })\n }\n return options\n }\n for (const { elevation, label } of SHADOW_STEPS) {\n const resolved = shadows[elevation]\n // A host with a shorter ladder simply offers fewer rungs rather than\n // storing an index that resolves to nothing.\n if (typeof resolved !== 'string' || !resolved || resolved === 'none') continue\n options.push({\n value: elevation,\n label,\n hint: `Elevation ${elevation}`,\n preview: resolved,\n })\n }\n return options\n}\n\n/* ── Font family ──────────────────────────────────────────────────────── */\n\n/**\n * The typography variants whose own `fontFamily` is worth offering. A theme\n * that gives headings a display face and body a text face has TWO answers\n * an author should be able to pick, and neither of them is a font name they\n * have to know how to spell.\n */\nconst FONT_FAMILY_VARIANTS: ReadonlyArray<{ key: string; label: string }> = [\n { key: 'h1', label: 'Theme heading font' },\n { key: 'body1', label: 'Theme body font' },\n { key: 'button', label: 'Theme button font' },\n]\n\n/**\n * Web-safe stacks, offered AFTER the theme's own faces.\n *\n * Deliberately short and generic: these are the families that render\n * without a webfont on every platform, so picking one can never cost a\n * page-load or leave a visitor on a fallback the author never saw. Anything\n * else — a Google font, a licensed face — is a Custom… value, which is the\n * honest place for it because it also needs the font to be loaded.\n */\nconst WEB_SAFE_FONTS: ReadonlyArray<{ value: string; label: string }> = [\n { value: 'system-ui, sans-serif', label: 'System sans-serif' },\n { value: 'Georgia, serif', label: 'Georgia (serif)' },\n { value: '\"Times New Roman\", Times, serif', label: 'Times (serif)' },\n { value: 'Arial, Helvetica, sans-serif', label: 'Arial (sans-serif)' },\n { value: 'Verdana, Geneva, sans-serif', label: 'Verdana (sans-serif)' },\n {\n value: '\"Trebuchet MS\", Helvetica, sans-serif',\n label: 'Trebuchet (sans-serif)',\n },\n { value: '\"Courier New\", Courier, monospace', label: 'Courier (monospace)' },\n]\n\n/** The first word of a stack, for a hint that fits a narrow menu row. */\nfunction firstFamily(stack: string): string {\n const first = stack.split(',')[0] ?? ''\n return first.trim().replace(/^[\"']|[\"']$/g, '')\n}\n\n/**\n * Font-family choices: the SITE THEME's own faces first, then web-safe\n *\n * The old field was free text carrying the advice *\"Prefer theme typography\n * when possible\"* — advice with no way to act on it. Leading with the\n * theme's faces makes the recommended answer the first one in reach, and\n * every row renders its own label in its own face so the choice can be made\n * by looking.\n *\n * A theme face is stored as the resolved STACK rather than as a token path,\n * because MUI declares `fontFamily` with `themeKey: 'typography'` and\n * `typography.fontFamily` is the only path that resolves — `h1.fontFamily`\n * does not. Duplicates are collapsed so a theme using one face everywhere\n * offers it once.\n */\nexport function buildFontFamilyChoices(\n theme: ThemeScaleSource | undefined,\n): PresetChoiceOption[] {\n const typography = theme?.typography\n const options: PresetChoiceOption[] = []\n const seen = new Set<string>()\n const push = (value: string, label: string) => {\n const stack = value.trim()\n if (stack === '' || seen.has(stack)) return\n seen.add(stack)\n options.push({ value: stack, label, hint: firstFamily(stack) })\n }\n if (typography) {\n const base = typography['fontFamily']\n if (typeof base === 'string') push(base, 'Theme default font')\n for (const { key, label } of FONT_FAMILY_VARIANTS) {\n const variant = typography[key]\n if (!variant || typeof variant !== 'object') continue\n const family = (variant as Record<string, unknown>)['fontFamily']\n if (typeof family === 'string') push(family, label)\n }\n }\n for (const font of WEB_SAFE_FONTS) push(font.value, font.label)\n return options\n}\n\n/* ── Typography variant ───────────────────────────────────────────────── */\n\n/**\n * Whole text styles from `theme.typography` (AGL-2486).\n *\n * Every other control in this group sets ONE property, so matching a heading\n * to the theme takes five correct picks in a row — face, size, weight, line\n * height, letter spacing — and getting any of them wrong leaves text that\n * looks almost right. `typography: 'h2'` is a single sx key that applies all\n * of them at once, and it is the key MUI itself reaches for.\n *\n * Without this control a page can carry eleven headings at MUI's default `h2`\n * — Light 300 at 60px — while every panel in the besigner reports nothing\n * wrong: no field says \"this is a Heading 2\", only fields that say \"this is\n * 60px\" once somebody types it.\n *\n * The hint names what the variant resolves to in THIS theme rather than in\n * the abstract, because \"Heading 2\" means nothing until you know the host\n * made it 40px semibold.\n */\nexport function buildTypographyVariantChoices(\n theme: ThemeScaleSource | undefined,\n): PresetChoiceOption[] {\n const typography = theme?.typography\n if (!typography) return []\n const options: PresetChoiceOption[] = []\n for (const { key, label } of themeTypographyVariants(typography)) {\n const variant = typography[key]\n if (!variant || typeof variant !== 'object') continue\n const { fontSize, fontWeight } = variant as Record<string, unknown>\n const parts = [hintOf(fontSize), hintOf(fontWeight) && `weight ${hintOf(fontWeight)}`]\n .filter(Boolean)\n .join(' · ')\n options.push({ value: key, label, hint: parts || undefined })\n }\n return options\n}\n\n/* ── Gap ──────────────────────────────────────────────────────────────── */\n\n/**\n * Grid and flex gaps on the theme's spacing ladder (AGL-2486).\n *\n * A free-text box for `gap`, `rowGap` or `columnGap` reads as a CSS length\n * question and gets answered with one — but MUI runs all three through\n * `createUnaryUnit(theme, 'spacing', …)`, exactly like margin and padding. So\n * `gap: 2` is a theme multiple that follows a host retuning its unit, and\n * `gap: '16px'` is a bespoke value that does not.\n *\n * These are the same rungs and the same labels the box styler offers for\n * margin and padding, so the two controls agree; gaps only sit apart because\n * they live in the Grid and Flex groups.\n *\n * A `PresetChoiceOption` rather than a `ThemeScaleOption` because the value\n * STORED is a number and that interface is string-only — the same reason\n * Corner Radius is a preset.\n */\nexport function buildGapChoices(\n theme: ThemeScaleSource | undefined,\n): PresetChoiceOption[] {\n const spacing = theme?.spacing\n const options: PresetChoiceOption[] = []\n for (const { step, label } of SPACING_STEPS) {\n const hint = resolveSpacing(spacing, step)\n if (hint === '') continue\n options.push({ value: step, label, hint })\n }\n return options\n}\n"],"names":["humanizeKey","key","spaced","replace","trim","toLowerCase","charAt","toUpperCase","slice","hintOf","value","Number","isFinite","FONT_SIZE_VARIANTS","label","themeTypographyVariants","typography","known","Set","map","entry","extra","Object","keys","has","size","fontSize","parsed","parseFloat","String","push","sort","a","b","buildFontSizeScaleOptions","theme","options","variant","hint","FONT_WEIGHT_KEY","themeFontWeightTokens","found","match","exec","raw","weight","FONT_WEIGHT_LADDER","buildFontWeightScaleOptions","undefined","buildZIndexScaleOptions","zIndex","filter","SPACING_STEPS","step","resolveSpacing","spacing","resolved","buildSpacingScaleOptions","buildStyleThemeScales","fontWeight","cornerRadius","buildCornerRadiusChoices","shadow","buildShadowChoices","fontFamily","buildFontFamilyChoices","typographyVariant","buildTypographyVariantChoices","gap","buildGapChoices","DEFAULT_SHAPE_RADIUS","shapeRadiusUnit","shape","borderRadius","RADIUS_STEPS","PILL_RADIUS","unit","preview","SHADOW_STEPS","elevation","FALLBACK_SHADOWS","shadows","Array","isArray","length","FONT_FAMILY_VARIANTS","WEB_SAFE_FONTS","firstFamily","stack","first","split","seen","add","base","family","font","parts","Boolean","join"],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import { type ResolvedTokenLabel, type TokenSegment } from './token-segments';
18
+ /**
19
+ * DOM side of the token-pill editors (AGL-586): mapping between a
20
+ * contentEditable surface holding text nodes + atomic pill elements and
21
+ * the segment/unit model in `token-segments.ts`.
22
+ *
23
+ * Pills are `<span data-token="{{...}}" contenteditable="false">` elements
24
+ * whose TEXT is the friendly label — never serialized. Reading the DOM
25
+ * back emits the raw token from the `data-token` attribute, so the stored
26
+ * string always keeps the id-based grammar.
27
+ *
28
+ * Offset mapping mirrors the AGL-582 markdown editor's TreeWalker
29
+ * approach, with one twist: offsets are counted in UNITS (text char = 1,
30
+ * pill = 1 regardless of its label length) so a caret can never address
31
+ * the inside of a pill.
32
+ */
33
+ /** Attribute carrying the raw token on a pill element. */
34
+ export declare const TOKEN_PILL_ATTR = "data-token";
35
+ /** Attribute carrying the pill's color family (see token-pill styles). */
36
+ export declare const TOKEN_PILL_GROUP_ATTR = "data-token-group";
37
+ /**
38
+ * Creates a pill element for direct-DOM surfaces (the inline canvas text
39
+ * editor). React surfaces render the same attributes via `TokenPill`; the
40
+ * container-level styles key off the data attributes, so both kinds of
41
+ * pill look identical.
42
+ */
43
+ export declare function createTokenPillElement(doc: Document, token: string, resolved: ResolvedTokenLabel): HTMLSpanElement;
44
+ /**
45
+ * Reads an editable surface back into segments: text nodes emit text, pill
46
+ * elements emit their raw `data-token`, `<br>` emits a newline, and block
47
+ * wrappers the browser may sneak in (paste, IME) emit a leading newline.
48
+ * The pill LABEL text never leaks into the serialized value.
49
+ */
50
+ export declare function readTokenSegmentsFromDom(root: HTMLElement): TokenSegment[];
51
+ /**
52
+ * Unit offset of a DOM point within `root`. Points inside a pill clamp to
53
+ * the pill's start (a caret can't live inside an atomic token).
54
+ */
55
+ export declare function unitOffsetFromDomPoint(root: HTMLElement, node: Node, offset: number): number;
56
+ /**
57
+ * DOM point for a unit offset. Landing on a pill boundary returns the
58
+ * position in the pill's PARENT (before/after the pill element) so the
59
+ * caret sits beside the atomic token, never inside it.
60
+ */
61
+ export declare function domPointFromUnitOffset(root: HTMLElement, target: number): {
62
+ node: Node;
63
+ offset: number;
64
+ };
65
+ /** Current selection as unit offsets, or null when outside `root`. */
66
+ export declare function selectionUnitsWithin(root: HTMLElement): {
67
+ start: number;
68
+ end: number;
69
+ } | null;
70
+ /** Places the selection at the given unit offsets inside `root`. */
71
+ export declare function setSelectionUnits(root: HTMLElement, start: number, end: number): void;
72
+ /**
73
+ * Replaces raw `{{...}}` occurrences in text nodes under `root` with pill
74
+ * elements (inline-editor open path). Returns how many pills were made.
75
+ */
76
+ export declare function materializeTokenPillsInElement(root: HTMLElement, resolve: (token: string) => ResolvedTokenLabel): number;
77
+ /**
78
+ * Replaces every pill under `root` with a text node holding its raw token
79
+ * (inline-editor commit path — run on a CLONE before sanitizing, so the
80
+ * stored string carries `{{var:id}}` grammar, never pill labels).
81
+ */
82
+ export declare function replacePillsWithTokenText(root: HTMLElement): void;
@@ -0,0 +1,280 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */ import { TOKEN_SEGMENT_PATTERN } from "./token-segments.js";
17
+ /**
18
+ * DOM side of the token-pill editors (AGL-586): mapping between a
19
+ * contentEditable surface holding text nodes + atomic pill elements and
20
+ * the segment/unit model in `token-segments.ts`.
21
+ *
22
+ * Pills are `<span data-token="{{...}}" contenteditable="false">` elements
23
+ * whose TEXT is the friendly label — never serialized. Reading the DOM
24
+ * back emits the raw token from the `data-token` attribute, so the stored
25
+ * string always keeps the id-based grammar.
26
+ *
27
+ * Offset mapping mirrors the AGL-582 markdown editor's TreeWalker
28
+ * approach, with one twist: offsets are counted in UNITS (text char = 1,
29
+ * pill = 1 regardless of its label length) so a caret can never address
30
+ * the inside of a pill.
31
+ */ /** Attribute carrying the raw token on a pill element. */ export const TOKEN_PILL_ATTR = 'data-token';
32
+ /** Attribute carrying the pill's color family (see token-pill styles). */ export const TOKEN_PILL_GROUP_ATTR = 'data-token-group';
33
+ // Deliberately NOT a type predicate: a `node is HTMLElement` guard would
34
+ // narrow an already-HTMLElement argument to `never` in the else branch.
35
+ const isPillElement = (node)=>node.nodeType === Node.ELEMENT_NODE && node.hasAttribute(TOKEN_PILL_ATTR);
36
+ /**
37
+ * Creates a pill element for direct-DOM surfaces (the inline canvas text
38
+ * editor). React surfaces render the same attributes via `TokenPill`; the
39
+ * container-level styles key off the data attributes, so both kinds of
40
+ * pill look identical.
41
+ */ export function createTokenPillElement(doc, token, resolved) {
42
+ const pill = doc.createElement('span');
43
+ pill.setAttribute(TOKEN_PILL_ATTR, token);
44
+ pill.setAttribute(TOKEN_PILL_GROUP_ATTR, resolved.known ? resolved.group : 'unknown');
45
+ pill.setAttribute('contenteditable', 'false');
46
+ pill.setAttribute('role', 'button');
47
+ // The raw token stays inspectable as the tooltip (ids stored, names shown).
48
+ pill.setAttribute('title', token);
49
+ pill.textContent = resolved.label;
50
+ return pill;
51
+ }
52
+ const isBlockElement = (node)=>node.nodeType === Node.ELEMENT_NODE && /^(DIV|P|LI|UL|OL|H[1-6])$/.test(node.tagName);
53
+ /**
54
+ * Reads an editable surface back into segments: text nodes emit text, pill
55
+ * elements emit their raw `data-token`, `<br>` emits a newline, and block
56
+ * wrappers the browser may sneak in (paste, IME) emit a leading newline.
57
+ * The pill LABEL text never leaks into the serialized value.
58
+ */ export function readTokenSegmentsFromDom(root) {
59
+ const segments = [];
60
+ const pushText = (text)=>{
61
+ if (!text) return;
62
+ const last = segments[segments.length - 1];
63
+ if ((last == null ? void 0 : last.type) === 'text') last.value += text;
64
+ else segments.push({
65
+ type: 'text',
66
+ value: text
67
+ });
68
+ };
69
+ const visit = (node)=>{
70
+ if (node.nodeType === Node.TEXT_NODE) {
71
+ var _node_textContent;
72
+ pushText((_node_textContent = node.textContent) != null ? _node_textContent : '');
73
+ return;
74
+ }
75
+ if (node.nodeType !== Node.ELEMENT_NODE) return;
76
+ const element = node;
77
+ if (isPillElement(element)) {
78
+ var _element_getAttribute;
79
+ const token = (_element_getAttribute = element.getAttribute(TOKEN_PILL_ATTR)) != null ? _element_getAttribute : '';
80
+ if (token) segments.push({
81
+ type: 'token',
82
+ value: token,
83
+ token
84
+ });
85
+ return;
86
+ }
87
+ if (element.tagName === 'BR') {
88
+ pushText('\n');
89
+ return;
90
+ }
91
+ if (isBlockElement(element) && segments.length > 0) pushText('\n');
92
+ element.childNodes.forEach(visit);
93
+ };
94
+ root.childNodes.forEach(visit);
95
+ return segments;
96
+ }
97
+ /** Unit length of a node subtree (text chars; pills and `<br>`s count 1). */ function unitLengthOfNode(node) {
98
+ if (node.nodeType === Node.TEXT_NODE) {
99
+ var _node_textContent;
100
+ return ((_node_textContent = node.textContent) != null ? _node_textContent : '').length;
101
+ }
102
+ if (node.nodeType !== Node.ELEMENT_NODE) return 0;
103
+ if (isPillElement(node)) return 1;
104
+ if (node.tagName === 'BR') return 1;
105
+ let length = 0;
106
+ node.childNodes.forEach((child)=>{
107
+ length += unitLengthOfNode(child);
108
+ });
109
+ return length;
110
+ }
111
+ /**
112
+ * Unit offset of a DOM point within `root`. Points inside a pill clamp to
113
+ * the pill's start (a caret can't live inside an atomic token).
114
+ */ export function unitOffsetFromDomPoint(root, node, offset) {
115
+ let units = 0;
116
+ const visit = (current)=>{
117
+ if (current === node) {
118
+ if (current.nodeType === Node.TEXT_NODE) {
119
+ var _current_textContent;
120
+ units += Math.min(offset, ((_current_textContent = current.textContent) != null ? _current_textContent : '').length);
121
+ } else if (!isPillElement(current)) {
122
+ const children = current.childNodes;
123
+ for(let index = 0; index < offset && index < children.length; index++){
124
+ units += unitLengthOfNode(children[index]);
125
+ }
126
+ }
127
+ return true;
128
+ }
129
+ if (current.nodeType === Node.TEXT_NODE) {
130
+ var _current_textContent1;
131
+ units += ((_current_textContent1 = current.textContent) != null ? _current_textContent1 : '').length;
132
+ return false;
133
+ }
134
+ if (current.nodeType !== Node.ELEMENT_NODE) return false;
135
+ if (isPillElement(current)) {
136
+ // A point INSIDE the pill clamps to the pill start.
137
+ if (current.contains(node)) return true;
138
+ units += 1;
139
+ return false;
140
+ }
141
+ if (current.tagName === 'BR') {
142
+ units += 1;
143
+ return false;
144
+ }
145
+ for (const child of Array.from(current.childNodes)){
146
+ if (visit(child)) return true;
147
+ }
148
+ return false;
149
+ };
150
+ visit(root);
151
+ return units;
152
+ }
153
+ /**
154
+ * DOM point for a unit offset. Landing on a pill boundary returns the
155
+ * position in the pill's PARENT (before/after the pill element) so the
156
+ * caret sits beside the atomic token, never inside it.
157
+ */ export function domPointFromUnitOffset(root, target) {
158
+ var _visit;
159
+ let remaining = Math.max(0, target);
160
+ const visit = (parent)=>{
161
+ const children = parent.childNodes;
162
+ for(let index = 0; index < children.length; index++){
163
+ const child = children[index];
164
+ if (child.nodeType === Node.TEXT_NODE) {
165
+ var _child_textContent;
166
+ const length = ((_child_textContent = child.textContent) != null ? _child_textContent : '').length;
167
+ if (remaining <= length) return {
168
+ node: child,
169
+ offset: remaining
170
+ };
171
+ remaining -= length;
172
+ continue;
173
+ }
174
+ if (child.nodeType !== Node.ELEMENT_NODE) continue;
175
+ if (isPillElement(child) || child.tagName === 'BR') {
176
+ if (remaining === 0) return {
177
+ node: parent,
178
+ offset: index
179
+ };
180
+ remaining -= 1;
181
+ if (remaining === 0) return {
182
+ node: parent,
183
+ offset: index + 1
184
+ };
185
+ continue;
186
+ }
187
+ const found = visit(child);
188
+ if (found) return found;
189
+ }
190
+ return null;
191
+ };
192
+ return (_visit = visit(root)) != null ? _visit : {
193
+ node: root,
194
+ offset: root.childNodes.length
195
+ };
196
+ }
197
+ /** Current selection as unit offsets, or null when outside `root`. */ export function selectionUnitsWithin(root) {
198
+ var _root_ownerDocument_defaultView_getSelection, _root_ownerDocument_defaultView;
199
+ const selection = (_root_ownerDocument_defaultView = root.ownerDocument.defaultView) == null ? void 0 : (_root_ownerDocument_defaultView_getSelection = _root_ownerDocument_defaultView.getSelection) == null ? void 0 : _root_ownerDocument_defaultView_getSelection.call(_root_ownerDocument_defaultView);
200
+ if (!selection || selection.rangeCount === 0) return null;
201
+ const range = selection.getRangeAt(0);
202
+ if (!root.contains(range.startContainer) || !root.contains(range.endContainer)) {
203
+ return null;
204
+ }
205
+ const start = unitOffsetFromDomPoint(root, range.startContainer, range.startOffset);
206
+ const end = unitOffsetFromDomPoint(root, range.endContainer, range.endOffset);
207
+ return start <= end ? {
208
+ start,
209
+ end
210
+ } : {
211
+ start: end,
212
+ end: start
213
+ };
214
+ }
215
+ /** Places the selection at the given unit offsets inside `root`. */ export function setSelectionUnits(root, start, end) {
216
+ var _root_ownerDocument_defaultView_getSelection, _root_ownerDocument_defaultView;
217
+ const selection = (_root_ownerDocument_defaultView = root.ownerDocument.defaultView) == null ? void 0 : (_root_ownerDocument_defaultView_getSelection = _root_ownerDocument_defaultView.getSelection) == null ? void 0 : _root_ownerDocument_defaultView_getSelection.call(_root_ownerDocument_defaultView);
218
+ if (!selection) return;
219
+ const from = domPointFromUnitOffset(root, start);
220
+ const to = end === start ? from : domPointFromUnitOffset(root, end);
221
+ const range = root.ownerDocument.createRange();
222
+ range.setStart(from.node, from.offset);
223
+ range.setEnd(to.node, to.offset);
224
+ selection.removeAllRanges();
225
+ selection.addRange(range);
226
+ }
227
+ /**
228
+ * Replaces raw `{{...}}` occurrences in text nodes under `root` with pill
229
+ * elements (inline-editor open path). Returns how many pills were made.
230
+ */ export function materializeTokenPillsInElement(root, resolve) {
231
+ const doc = root.ownerDocument;
232
+ const walker = doc.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
233
+ acceptNode: (node)=>{
234
+ var _node_parentElement;
235
+ return ((_node_parentElement = node.parentElement) == null ? void 0 : _node_parentElement.closest(`[${TOKEN_PILL_ATTR}]`)) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
236
+ }
237
+ });
238
+ const targets = [];
239
+ for(let node = walker.nextNode(); node; node = walker.nextNode()){
240
+ var _node_textContent;
241
+ if (new RegExp(TOKEN_SEGMENT_PATTERN.source).test((_node_textContent = node.textContent) != null ? _node_textContent : '')) {
242
+ targets.push(node);
243
+ }
244
+ }
245
+ let count = 0;
246
+ for (const textNode of targets){
247
+ var _textNode_textContent;
248
+ const text = (_textNode_textContent = textNode.textContent) != null ? _textNode_textContent : '';
249
+ const fragment = doc.createDocumentFragment();
250
+ let cursor = 0;
251
+ const pattern = new RegExp(TOKEN_SEGMENT_PATTERN.source, 'g');
252
+ for(let match = pattern.exec(text); match; match = pattern.exec(text)){
253
+ if (match.index > cursor) {
254
+ fragment.appendChild(doc.createTextNode(text.slice(cursor, match.index)));
255
+ }
256
+ fragment.appendChild(createTokenPillElement(doc, match[0], resolve(match[0])));
257
+ count += 1;
258
+ cursor = match.index + match[0].length;
259
+ }
260
+ if (cursor < text.length) {
261
+ fragment.appendChild(doc.createTextNode(text.slice(cursor)));
262
+ }
263
+ textNode.replaceWith(fragment);
264
+ }
265
+ return count;
266
+ }
267
+ /**
268
+ * Replaces every pill under `root` with a text node holding its raw token
269
+ * (inline-editor commit path — run on a CLONE before sanitizing, so the
270
+ * stored string carries `{{var:id}}` grammar, never pill labels).
271
+ */ export function replacePillsWithTokenText(root) {
272
+ const pills = Array.from(root.querySelectorAll(`[${TOKEN_PILL_ATTR}]`));
273
+ for (const pill of pills){
274
+ var _pill_getAttribute;
275
+ const token = (_pill_getAttribute = pill.getAttribute(TOKEN_PILL_ATTR)) != null ? _pill_getAttribute : '';
276
+ pill.replaceWith(root.ownerDocument.createTextNode(token));
277
+ }
278
+ }
279
+
280
+ //# sourceMappingURL=token-editable-dom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../libs/besigner/feature/designer/src/lib/utils/token-editable-dom.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type ResolvedTokenLabel,\n type TokenSegment,\n TOKEN_SEGMENT_PATTERN,\n} from './token-segments'\n\n/**\n * DOM side of the token-pill editors (AGL-586): mapping between a\n * contentEditable surface holding text nodes + atomic pill elements and\n * the segment/unit model in `token-segments.ts`.\n *\n * Pills are `<span data-token=\"{{...}}\" contenteditable=\"false\">` elements\n * whose TEXT is the friendly label — never serialized. Reading the DOM\n * back emits the raw token from the `data-token` attribute, so the stored\n * string always keeps the id-based grammar.\n *\n * Offset mapping mirrors the AGL-582 markdown editor's TreeWalker\n * approach, with one twist: offsets are counted in UNITS (text char = 1,\n * pill = 1 regardless of its label length) so a caret can never address\n * the inside of a pill.\n */\n\n/** Attribute carrying the raw token on a pill element. */\nexport const TOKEN_PILL_ATTR = 'data-token'\n\n/** Attribute carrying the pill's color family (see token-pill styles). */\nexport const TOKEN_PILL_GROUP_ATTR = 'data-token-group'\n\n// Deliberately NOT a type predicate: a `node is HTMLElement` guard would\n// narrow an already-HTMLElement argument to `never` in the else branch.\nconst isPillElement = (node: Node): boolean =>\n node.nodeType === Node.ELEMENT_NODE &&\n (node as HTMLElement).hasAttribute(TOKEN_PILL_ATTR)\n\n/**\n * Creates a pill element for direct-DOM surfaces (the inline canvas text\n * editor). React surfaces render the same attributes via `TokenPill`; the\n * container-level styles key off the data attributes, so both kinds of\n * pill look identical.\n */\nexport function createTokenPillElement(\n doc: Document,\n token: string,\n resolved: ResolvedTokenLabel,\n): HTMLSpanElement {\n const pill = doc.createElement('span')\n pill.setAttribute(TOKEN_PILL_ATTR, token)\n pill.setAttribute(\n TOKEN_PILL_GROUP_ATTR,\n resolved.known ? resolved.group : 'unknown',\n )\n pill.setAttribute('contenteditable', 'false')\n pill.setAttribute('role', 'button')\n // The raw token stays inspectable as the tooltip (ids stored, names shown).\n pill.setAttribute('title', token)\n pill.textContent = resolved.label\n return pill\n}\n\nconst isBlockElement = (node: Node): boolean =>\n node.nodeType === Node.ELEMENT_NODE &&\n /^(DIV|P|LI|UL|OL|H[1-6])$/.test((node as HTMLElement).tagName)\n\n/**\n * Reads an editable surface back into segments: text nodes emit text, pill\n * elements emit their raw `data-token`, `<br>` emits a newline, and block\n * wrappers the browser may sneak in (paste, IME) emit a leading newline.\n * The pill LABEL text never leaks into the serialized value.\n */\nexport function readTokenSegmentsFromDom(root: HTMLElement): TokenSegment[] {\n const segments: TokenSegment[] = []\n const pushText = (text: string) => {\n if (!text) return\n const last = segments[segments.length - 1]\n if (last?.type === 'text') last.value += text\n else segments.push({ type: 'text', value: text })\n }\n const visit = (node: Node): void => {\n if (node.nodeType === Node.TEXT_NODE) {\n pushText(node.textContent ?? '')\n return\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return\n const element = node as HTMLElement\n if (isPillElement(element)) {\n const token = element.getAttribute(TOKEN_PILL_ATTR) ?? ''\n if (token) segments.push({ type: 'token', value: token, token })\n return\n }\n if (element.tagName === 'BR') {\n pushText('\\n')\n return\n }\n if (isBlockElement(element) && segments.length > 0) pushText('\\n')\n element.childNodes.forEach(visit)\n }\n root.childNodes.forEach(visit)\n return segments\n}\n\n/** Unit length of a node subtree (text chars; pills and `<br>`s count 1). */\nfunction unitLengthOfNode(node: Node): number {\n if (node.nodeType === Node.TEXT_NODE) {\n return (node.textContent ?? '').length\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return 0\n if (isPillElement(node)) return 1\n if ((node as HTMLElement).tagName === 'BR') return 1\n let length = 0\n node.childNodes.forEach((child) => {\n length += unitLengthOfNode(child)\n })\n return length\n}\n\n/**\n * Unit offset of a DOM point within `root`. Points inside a pill clamp to\n * the pill's start (a caret can't live inside an atomic token).\n */\nexport function unitOffsetFromDomPoint(\n root: HTMLElement,\n node: Node,\n offset: number,\n): number {\n let units = 0\n const visit = (current: Node): boolean => {\n if (current === node) {\n if (current.nodeType === Node.TEXT_NODE) {\n units += Math.min(offset, (current.textContent ?? '').length)\n } else if (!isPillElement(current)) {\n const children = current.childNodes\n for (let index = 0; index < offset && index < children.length; index++) {\n units += unitLengthOfNode(children[index] as Node)\n }\n }\n return true\n }\n if (current.nodeType === Node.TEXT_NODE) {\n units += (current.textContent ?? '').length\n return false\n }\n if (current.nodeType !== Node.ELEMENT_NODE) return false\n if (isPillElement(current)) {\n // A point INSIDE the pill clamps to the pill start.\n if (current.contains(node)) return true\n units += 1\n return false\n }\n if ((current as HTMLElement).tagName === 'BR') {\n units += 1\n return false\n }\n for (const child of Array.from(current.childNodes)) {\n if (visit(child)) return true\n }\n return false\n }\n visit(root)\n return units\n}\n\n/**\n * DOM point for a unit offset. Landing on a pill boundary returns the\n * position in the pill's PARENT (before/after the pill element) so the\n * caret sits beside the atomic token, never inside it.\n */\nexport function domPointFromUnitOffset(\n root: HTMLElement,\n target: number,\n): { node: Node; offset: number } {\n let remaining = Math.max(0, target)\n const visit = (parent: Node): { node: Node; offset: number } | null => {\n const children = parent.childNodes\n for (let index = 0; index < children.length; index++) {\n const child = children[index] as Node\n if (child.nodeType === Node.TEXT_NODE) {\n const length = (child.textContent ?? '').length\n if (remaining <= length) return { node: child, offset: remaining }\n remaining -= length\n continue\n }\n if (child.nodeType !== Node.ELEMENT_NODE) continue\n if (isPillElement(child) || (child as HTMLElement).tagName === 'BR') {\n if (remaining === 0) return { node: parent, offset: index }\n remaining -= 1\n if (remaining === 0) return { node: parent, offset: index + 1 }\n continue\n }\n const found = visit(child)\n if (found) return found\n }\n return null\n }\n return visit(root) ?? { node: root, offset: root.childNodes.length }\n}\n\n/** Current selection as unit offsets, or null when outside `root`. */\nexport function selectionUnitsWithin(\n root: HTMLElement,\n): { start: number; end: number } | null {\n const selection = root.ownerDocument.defaultView?.getSelection?.()\n if (!selection || selection.rangeCount === 0) return null\n const range = selection.getRangeAt(0)\n if (\n !root.contains(range.startContainer) ||\n !root.contains(range.endContainer)\n ) {\n return null\n }\n const start = unitOffsetFromDomPoint(\n root,\n range.startContainer,\n range.startOffset,\n )\n const end = unitOffsetFromDomPoint(root, range.endContainer, range.endOffset)\n return start <= end ? { start, end } : { start: end, end: start }\n}\n\n/** Places the selection at the given unit offsets inside `root`. */\nexport function setSelectionUnits(\n root: HTMLElement,\n start: number,\n end: number,\n): void {\n const selection = root.ownerDocument.defaultView?.getSelection?.()\n if (!selection) return\n const from = domPointFromUnitOffset(root, start)\n const to = end === start ? from : domPointFromUnitOffset(root, end)\n const range = root.ownerDocument.createRange()\n range.setStart(from.node, from.offset)\n range.setEnd(to.node, to.offset)\n selection.removeAllRanges()\n selection.addRange(range)\n}\n\n/**\n * Replaces raw `{{...}}` occurrences in text nodes under `root` with pill\n * elements (inline-editor open path). Returns how many pills were made.\n */\nexport function materializeTokenPillsInElement(\n root: HTMLElement,\n resolve: (token: string) => ResolvedTokenLabel,\n): number {\n const doc = root.ownerDocument\n const walker = doc.createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n acceptNode: (node) =>\n node.parentElement?.closest(`[${TOKEN_PILL_ATTR}]`)\n ? NodeFilter.FILTER_REJECT\n : NodeFilter.FILTER_ACCEPT,\n })\n const targets: Text[] = []\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n if (new RegExp(TOKEN_SEGMENT_PATTERN.source).test(node.textContent ?? '')) {\n targets.push(node as Text)\n }\n }\n let count = 0\n for (const textNode of targets) {\n const text = textNode.textContent ?? ''\n const fragment = doc.createDocumentFragment()\n let cursor = 0\n const pattern = new RegExp(TOKEN_SEGMENT_PATTERN.source, 'g')\n for (let match = pattern.exec(text); match; match = pattern.exec(text)) {\n if (match.index > cursor) {\n fragment.appendChild(\n doc.createTextNode(text.slice(cursor, match.index)),\n )\n }\n fragment.appendChild(\n createTokenPillElement(doc, match[0], resolve(match[0])),\n )\n count += 1\n cursor = match.index + match[0].length\n }\n if (cursor < text.length) {\n fragment.appendChild(doc.createTextNode(text.slice(cursor)))\n }\n textNode.replaceWith(fragment)\n }\n return count\n}\n\n/**\n * Replaces every pill under `root` with a text node holding its raw token\n * (inline-editor commit path — run on a CLONE before sanitizing, so the\n * stored string carries `{{var:id}}` grammar, never pill labels).\n */\nexport function replacePillsWithTokenText(root: HTMLElement): void {\n const pills = Array.from(root.querySelectorAll(`[${TOKEN_PILL_ATTR}]`))\n for (const pill of pills) {\n const token = pill.getAttribute(TOKEN_PILL_ATTR) ?? ''\n pill.replaceWith(root.ownerDocument.createTextNode(token))\n }\n}\n"],"names":["TOKEN_SEGMENT_PATTERN","TOKEN_PILL_ATTR","TOKEN_PILL_GROUP_ATTR","isPillElement","node","nodeType","Node","ELEMENT_NODE","hasAttribute","createTokenPillElement","doc","token","resolved","pill","createElement","setAttribute","known","group","textContent","label","isBlockElement","test","tagName","readTokenSegmentsFromDom","root","segments","pushText","text","last","length","type","value","push","visit","TEXT_NODE","element","getAttribute","childNodes","forEach","unitLengthOfNode","child","unitOffsetFromDomPoint","offset","units","current","Math","min","children","index","contains","Array","from","domPointFromUnitOffset","target","remaining","max","parent","found","selectionUnitsWithin","selection","ownerDocument","defaultView","getSelection","rangeCount","range","getRangeAt","startContainer","endContainer","start","startOffset","end","endOffset","setSelectionUnits","to","createRange","setStart","setEnd","removeAllRanges","addRange","materializeTokenPillsInElement","resolve","walker","createTreeWalker","NodeFilter","SHOW_TEXT","acceptNode","parentElement","closest","FILTER_REJECT","FILTER_ACCEPT","targets","nextNode","RegExp","source","count","textNode","fragment","createDocumentFragment","cursor","pattern","match","exec","appendChild","createTextNode","slice","replaceWith","replacePillsWithTokenText","pills","querySelectorAll"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAGEA,qBAAqB,QAChB,sBAAkB;AAEzB;;;;;;;;;;;;;;CAcC,GAED,wDAAwD,GACxD,OAAO,MAAMC,kBAAkB,aAAY;AAE3C,wEAAwE,GACxE,OAAO,MAAMC,wBAAwB,mBAAkB;AAEvD,yEAAyE;AACzE,wEAAwE;AACxE,MAAMC,gBAAgB,CAACC,OACrBA,KAAKC,QAAQ,KAAKC,KAAKC,YAAY,IACnC,AAACH,KAAqBI,YAAY,CAACP;AAErC;;;;;CAKC,GACD,OAAO,SAASQ,uBACdC,GAAa,EACbC,KAAa,EACbC,QAA4B;IAE5B,MAAMC,OAAOH,IAAII,aAAa,CAAC;IAC/BD,KAAKE,YAAY,CAACd,iBAAiBU;IACnCE,KAAKE,YAAY,CACfb,uBACAU,SAASI,KAAK,GAAGJ,SAASK,KAAK,GAAG;IAEpCJ,KAAKE,YAAY,CAAC,mBAAmB;IACrCF,KAAKE,YAAY,CAAC,QAAQ;IAC1B,4EAA4E;IAC5EF,KAAKE,YAAY,CAAC,SAASJ;IAC3BE,KAAKK,WAAW,GAAGN,SAASO,KAAK;IACjC,OAAON;AACT;AAEA,MAAMO,iBAAiB,CAAChB,OACtBA,KAAKC,QAAQ,KAAKC,KAAKC,YAAY,IACnC,4BAA4Bc,IAAI,CAAC,AAACjB,KAAqBkB,OAAO;AAEhE;;;;;CAKC,GACD,OAAO,SAASC,yBAAyBC,IAAiB;IACxD,MAAMC,WAA2B,EAAE;IACnC,MAAMC,WAAW,CAACC;QAChB,IAAI,CAACA,MAAM;QACX,MAAMC,OAAOH,QAAQ,CAACA,SAASI,MAAM,GAAG,EAAE;QAC1C,IAAID,CAAAA,wBAAAA,KAAME,IAAI,MAAK,QAAQF,KAAKG,KAAK,IAAIJ;aACpCF,SAASO,IAAI,CAAC;YAAEF,MAAM;YAAQC,OAAOJ;QAAK;IACjD;IACA,MAAMM,QAAQ,CAAC7B;QACb,IAAIA,KAAKC,QAAQ,KAAKC,KAAK4B,SAAS,EAAE;gBAC3B9B;YAATsB,UAAStB,oBAAAA,KAAKc,WAAW,YAAhBd,oBAAoB;YAC7B;QACF;QACA,IAAIA,KAAKC,QAAQ,KAAKC,KAAKC,YAAY,EAAE;QACzC,MAAM4B,UAAU/B;QAChB,IAAID,cAAcgC,UAAU;gBACZA;YAAd,MAAMxB,SAAQwB,wBAAAA,QAAQC,YAAY,CAACnC,4BAArBkC,wBAAyC;YACvD,IAAIxB,OAAOc,SAASO,IAAI,CAAC;gBAAEF,MAAM;gBAASC,OAAOpB;gBAAOA;YAAM;YAC9D;QACF;QACA,IAAIwB,QAAQb,OAAO,KAAK,MAAM;YAC5BI,SAAS;YACT;QACF;QACA,IAAIN,eAAee,YAAYV,SAASI,MAAM,GAAG,GAAGH,SAAS;QAC7DS,QAAQE,UAAU,CAACC,OAAO,CAACL;IAC7B;IACAT,KAAKa,UAAU,CAACC,OAAO,CAACL;IACxB,OAAOR;AACT;AAEA,2EAA2E,GAC3E,SAASc,iBAAiBnC,IAAU;IAClC,IAAIA,KAAKC,QAAQ,KAAKC,KAAK4B,SAAS,EAAE;YAC5B9B;QAAR,OAAO,EAACA,oBAAAA,KAAKc,WAAW,YAAhBd,oBAAoB,IAAIyB,MAAM;IACxC;IACA,IAAIzB,KAAKC,QAAQ,KAAKC,KAAKC,YAAY,EAAE,OAAO;IAChD,IAAIJ,cAAcC,OAAO,OAAO;IAChC,IAAI,AAACA,KAAqBkB,OAAO,KAAK,MAAM,OAAO;IACnD,IAAIO,SAAS;IACbzB,KAAKiC,UAAU,CAACC,OAAO,CAAC,CAACE;QACvBX,UAAUU,iBAAiBC;IAC7B;IACA,OAAOX;AACT;AAEA;;;CAGC,GACD,OAAO,SAASY,uBACdjB,IAAiB,EACjBpB,IAAU,EACVsC,MAAc;IAEd,IAAIC,QAAQ;IACZ,MAAMV,QAAQ,CAACW;QACb,IAAIA,YAAYxC,MAAM;YACpB,IAAIwC,QAAQvC,QAAQ,KAAKC,KAAK4B,SAAS,EAAE;oBACZU;gBAA3BD,SAASE,KAAKC,GAAG,CAACJ,QAAQ,EAACE,uBAAAA,QAAQ1B,WAAW,YAAnB0B,uBAAuB,IAAIf,MAAM;YAC9D,OAAO,IAAI,CAAC1B,cAAcyC,UAAU;gBAClC,MAAMG,WAAWH,QAAQP,UAAU;gBACnC,IAAK,IAAIW,QAAQ,GAAGA,QAAQN,UAAUM,QAAQD,SAASlB,MAAM,EAAEmB,QAAS;oBACtEL,SAASJ,iBAAiBQ,QAAQ,CAACC,MAAM;gBAC3C;YACF;YACA,OAAO;QACT;QACA,IAAIJ,QAAQvC,QAAQ,KAAKC,KAAK4B,SAAS,EAAE;gBAC7BU;YAAVD,SAAS,EAACC,wBAAAA,QAAQ1B,WAAW,YAAnB0B,wBAAuB,IAAIf,MAAM;YAC3C,OAAO;QACT;QACA,IAAIe,QAAQvC,QAAQ,KAAKC,KAAKC,YAAY,EAAE,OAAO;QACnD,IAAIJ,cAAcyC,UAAU;YAC1B,oDAAoD;YACpD,IAAIA,QAAQK,QAAQ,CAAC7C,OAAO,OAAO;YACnCuC,SAAS;YACT,OAAO;QACT;QACA,IAAI,AAACC,QAAwBtB,OAAO,KAAK,MAAM;YAC7CqB,SAAS;YACT,OAAO;QACT;QACA,KAAK,MAAMH,SAASU,MAAMC,IAAI,CAACP,QAAQP,UAAU,EAAG;YAClD,IAAIJ,MAAMO,QAAQ,OAAO;QAC3B;QACA,OAAO;IACT;IACAP,MAAMT;IACN,OAAOmB;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASS,uBACd5B,IAAiB,EACjB6B,MAAc;QAyBPpB;IAvBP,IAAIqB,YAAYT,KAAKU,GAAG,CAAC,GAAGF;IAC5B,MAAMpB,QAAQ,CAACuB;QACb,MAAMT,WAAWS,OAAOnB,UAAU;QAClC,IAAK,IAAIW,QAAQ,GAAGA,QAAQD,SAASlB,MAAM,EAAEmB,QAAS;YACpD,MAAMR,QAAQO,QAAQ,CAACC,MAAM;YAC7B,IAAIR,MAAMnC,QAAQ,KAAKC,KAAK4B,SAAS,EAAE;oBACrBM;gBAAhB,MAAMX,SAAS,EAACW,qBAAAA,MAAMtB,WAAW,YAAjBsB,qBAAqB,IAAIX,MAAM;gBAC/C,IAAIyB,aAAazB,QAAQ,OAAO;oBAAEzB,MAAMoC;oBAAOE,QAAQY;gBAAU;gBACjEA,aAAazB;gBACb;YACF;YACA,IAAIW,MAAMnC,QAAQ,KAAKC,KAAKC,YAAY,EAAE;YAC1C,IAAIJ,cAAcqC,UAAU,AAACA,MAAsBlB,OAAO,KAAK,MAAM;gBACnE,IAAIgC,cAAc,GAAG,OAAO;oBAAElD,MAAMoD;oBAAQd,QAAQM;gBAAM;gBAC1DM,aAAa;gBACb,IAAIA,cAAc,GAAG,OAAO;oBAAElD,MAAMoD;oBAAQd,QAAQM,QAAQ;gBAAE;gBAC9D;YACF;YACA,MAAMS,QAAQxB,MAAMO;YACpB,IAAIiB,OAAO,OAAOA;QACpB;QACA,OAAO;IACT;IACA,QAAOxB,SAAAA,MAAMT,iBAANS,SAAe;QAAE7B,MAAMoB;QAAMkB,QAAQlB,KAAKa,UAAU,CAACR,MAAM;IAAC;AACrE;AAEA,oEAAoE,GACpE,OAAO,SAAS6B,qBACdlC,IAAiB;QAECA,8CAAAA;IAAlB,MAAMmC,aAAYnC,kCAAAA,KAAKoC,aAAa,CAACC,WAAW,sBAA9BrC,+CAAAA,gCAAgCsC,YAAY,qBAA5CtC,kDAAAA;IAClB,IAAI,CAACmC,aAAaA,UAAUI,UAAU,KAAK,GAAG,OAAO;IACrD,MAAMC,QAAQL,UAAUM,UAAU,CAAC;IACnC,IACE,CAACzC,KAAKyB,QAAQ,CAACe,MAAME,cAAc,KACnC,CAAC1C,KAAKyB,QAAQ,CAACe,MAAMG,YAAY,GACjC;QACA,OAAO;IACT;IACA,MAAMC,QAAQ3B,uBACZjB,MACAwC,MAAME,cAAc,EACpBF,MAAMK,WAAW;IAEnB,MAAMC,MAAM7B,uBAAuBjB,MAAMwC,MAAMG,YAAY,EAAEH,MAAMO,SAAS;IAC5E,OAAOH,SAASE,MAAM;QAAEF;QAAOE;IAAI,IAAI;QAAEF,OAAOE;QAAKA,KAAKF;IAAM;AAClE;AAEA,kEAAkE,GAClE,OAAO,SAASI,kBACdhD,IAAiB,EACjB4C,KAAa,EACbE,GAAW;QAEO9C,8CAAAA;IAAlB,MAAMmC,aAAYnC,kCAAAA,KAAKoC,aAAa,CAACC,WAAW,sBAA9BrC,+CAAAA,gCAAgCsC,YAAY,qBAA5CtC,kDAAAA;IAClB,IAAI,CAACmC,WAAW;IAChB,MAAMR,OAAOC,uBAAuB5B,MAAM4C;IAC1C,MAAMK,KAAKH,QAAQF,QAAQjB,OAAOC,uBAAuB5B,MAAM8C;IAC/D,MAAMN,QAAQxC,KAAKoC,aAAa,CAACc,WAAW;IAC5CV,MAAMW,QAAQ,CAACxB,KAAK/C,IAAI,EAAE+C,KAAKT,MAAM;IACrCsB,MAAMY,MAAM,CAACH,GAAGrE,IAAI,EAAEqE,GAAG/B,MAAM;IAC/BiB,UAAUkB,eAAe;IACzBlB,UAAUmB,QAAQ,CAACd;AACrB;AAEA;;;CAGC,GACD,OAAO,SAASe,+BACdvD,IAAiB,EACjBwD,OAA8C;IAE9C,MAAMtE,MAAMc,KAAKoC,aAAa;IAC9B,MAAMqB,SAASvE,IAAIwE,gBAAgB,CAAC1D,MAAM2D,WAAWC,SAAS,EAAE;QAC9DC,YAAY,CAACjF;gBACXA;mBAAAA,EAAAA,sBAAAA,KAAKkF,aAAa,qBAAlBlF,oBAAoBmF,OAAO,CAAC,CAAC,CAAC,EAAEtF,gBAAgB,CAAC,CAAC,KAC9CkF,WAAWK,aAAa,GACxBL,WAAWM,aAAa;;IAChC;IACA,MAAMC,UAAkB,EAAE;IAC1B,IAAK,IAAItF,OAAO6E,OAAOU,QAAQ,IAAIvF,MAAMA,OAAO6E,OAAOU,QAAQ,GAAI;YACfvF;QAAlD,IAAI,IAAIwF,OAAO5F,sBAAsB6F,MAAM,EAAExE,IAAI,EAACjB,oBAAAA,KAAKc,WAAW,YAAhBd,oBAAoB,KAAK;YACzEsF,QAAQ1D,IAAI,CAAC5B;QACf;IACF;IACA,IAAI0F,QAAQ;IACZ,KAAK,MAAMC,YAAYL,QAAS;YACjBK;QAAb,MAAMpE,QAAOoE,wBAAAA,SAAS7E,WAAW,YAApB6E,wBAAwB;QACrC,MAAMC,WAAWtF,IAAIuF,sBAAsB;QAC3C,IAAIC,SAAS;QACb,MAAMC,UAAU,IAAIP,OAAO5F,sBAAsB6F,MAAM,EAAE;QACzD,IAAK,IAAIO,QAAQD,QAAQE,IAAI,CAAC1E,OAAOyE,OAAOA,QAAQD,QAAQE,IAAI,CAAC1E,MAAO;YACtE,IAAIyE,MAAMpD,KAAK,GAAGkD,QAAQ;gBACxBF,SAASM,WAAW,CAClB5F,IAAI6F,cAAc,CAAC5E,KAAK6E,KAAK,CAACN,QAAQE,MAAMpD,KAAK;YAErD;YACAgD,SAASM,WAAW,CAClB7F,uBAAuBC,KAAK0F,KAAK,CAAC,EAAE,EAAEpB,QAAQoB,KAAK,CAAC,EAAE;YAExDN,SAAS;YACTI,SAASE,MAAMpD,KAAK,GAAGoD,KAAK,CAAC,EAAE,CAACvE,MAAM;QACxC;QACA,IAAIqE,SAASvE,KAAKE,MAAM,EAAE;YACxBmE,SAASM,WAAW,CAAC5F,IAAI6F,cAAc,CAAC5E,KAAK6E,KAAK,CAACN;QACrD;QACAH,SAASU,WAAW,CAACT;IACvB;IACA,OAAOF;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASY,0BAA0BlF,IAAiB;IACzD,MAAMmF,QAAQzD,MAAMC,IAAI,CAAC3B,KAAKoF,gBAAgB,CAAC,CAAC,CAAC,EAAE3G,gBAAgB,CAAC,CAAC;IACrE,KAAK,MAAMY,QAAQ8F,MAAO;YACV9F;QAAd,MAAMF,SAAQE,qBAAAA,KAAKuB,YAAY,CAACnC,4BAAlBY,qBAAsC;QACpDA,KAAK4F,WAAW,CAACjF,KAAKoC,aAAa,CAAC2C,cAAc,CAAC5F;IACrD;AACF"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Aglyn LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ import type { BindingOption } from '../contexts/binding-picker-context';
18
+ /**
19
+ * Token-pill segment model (AGL-586). Stored prop strings keep the raw
20
+ * id-based `{{...}}` grammar (AGL-100/185) — these helpers only SPLIT a
21
+ * string into runs of plain text and atomic tokens so editors can render
22
+ * the tokens as friendly, clickable pills. Serializing the segments always
23
+ * reproduces the exact input string; nothing here ever rewrites a token.
24
+ *
25
+ * Offset model: editor carets address "units", where every plain-text
26
+ * character is 1 unit and every token — however long its raw text — is 1
27
+ * atomic unit. A caret can therefore sit before or after a pill but never
28
+ * inside one, which is exactly how the pills behave in the DOM
29
+ * (`contenteditable="false"`).
30
+ */
31
+ export interface TokenSegment {
32
+ type: 'text' | 'token';
33
+ /** The literal slice of the serialized string (raw `{{...}}` for tokens). */
34
+ value: string;
35
+ /** Set on token segments: the raw token, identical to `value`. */
36
+ token?: string;
37
+ }
38
+ /**
39
+ * Any `{{...}}` occurrence without nested braces — var:/fn:/entry./
40
+ * collection./item.* AND unknown tokens alike. `{{a{{b}}` yields the text
41
+ * `{{a` plus the token `{{b}}` (the opener without a closer is plain text).
42
+ */
43
+ export declare const TOKEN_SEGMENT_PATTERN: RegExp;
44
+ /** Splits `text` on `{{...}}` occurrences into text/token segments. */
45
+ export declare function parseTokenSegments(text: string): TokenSegment[];
46
+ /** Joins segments back to the exact stored string (lossless round-trip). */
47
+ export declare function serializeTokenSegments(segments: TokenSegment[]): string;
48
+ /** True when any text run still holds a complete raw `{{...}}` token. */
49
+ export declare function hasUnmaterializedTokens(segments: TokenSegment[]): boolean;
50
+ /** Unit length of one segment: text = char count, token = 1 atomic unit. */
51
+ export declare function segmentUnitLength(segment: TokenSegment): number;
52
+ /** Total unit length of a segment list (pills count as 1 unit each). */
53
+ export declare function segmentsUnitLength(segments: TokenSegment[]): number;
54
+ /**
55
+ * Extracts [from, to) in unit offsets. Tokens are atomic: since a token is
56
+ * exactly 1 unit, an integer range either includes it wholly or not at all
57
+ * — a caret can never split a pill.
58
+ */
59
+ export declare function sliceSegmentsByUnits(segments: TokenSegment[], from: number, to: number): TokenSegment[];
60
+ /**
61
+ * Splices `replacement` into `segments` at the unit-offset selection,
62
+ * replacing any selected range — the caret-preserving insert used by the
63
+ * {x} picker (AGL-583 semantics, pill-aware). A null/undefined start means
64
+ * "no caret captured": the replacement appends at the end. Returns the new
65
+ * segment list and the caret unit just after the inserted content.
66
+ */
67
+ export declare function spliceSegmentsAtUnits(segments: TokenSegment[], replacement: TokenSegment[], start?: number | null, end?: number | null): {
68
+ segments: TokenSegment[];
69
+ caretUnit: number;
70
+ };
71
+ /** A single token segment for `spliceSegmentsAtUnits` insertion. */
72
+ export declare function tokenSegment(token: string): TokenSegment;
73
+ /** A single text segment for `spliceSegmentsAtUnits` insertion. */
74
+ export declare function textSegment(text: string): TokenSegment;
75
+ /** Which catalog family a token belongs to — drives the pill color. */
76
+ export type TokenGroup = 'variable' | 'function' | 'entry' | 'collection' | 'dataset' | 'property' | 'host' | 'unknown';
77
+ /**
78
+ * Display-name inputs for {@link resolveTokenLabel}: the picker options
79
+ * (which already carry friendly labels for every insertable token), the
80
+ * host's variable/function docs keyed by id (AGL-194), and the ancestor
81
+ * repeatable's dataset model fields (id → current display name).
82
+ */
83
+ export interface TokenLabelContext {
84
+ options?: BindingOption[];
85
+ variables?: Record<string, {
86
+ name?: string;
87
+ } | undefined>;
88
+ functions?: Record<string, {
89
+ name?: string;
90
+ } | undefined>;
91
+ datasetFields?: Array<{
92
+ id: string;
93
+ label: string;
94
+ }>;
95
+ }
96
+ export interface ResolvedTokenLabel {
97
+ /** Friendly display name (the CURRENT name — ids stay in storage). */
98
+ label: string;
99
+ /** Family for the pill color; shape-derived, stable across renames. */
100
+ group: TokenGroup;
101
+ /** False when the referent can't be resolved (warning-colored pill). */
102
+ known: boolean;
103
+ }
104
+ /**
105
+ * Resolves a raw token to its display name (AGL-586 requirement 2: users
106
+ * see NAMES, storage keeps IDS). The group comes from the token's shape so
107
+ * pills stay consistently colored even when the referent is missing;
108
+ * `known: false` marks unresolvable tokens for warning styling with the
109
+ * raw token surfaced as the tooltip.
110
+ */
111
+ export declare function resolveTokenLabel(token: string, context?: TokenLabelContext): ResolvedTokenLabel;