@limetech/lime-crm-building-blocks 2.3.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/{condition-tree-translate-B_qIQz9s.js → condition-tree-translate-BQwKtiNZ.js} +1 -1
  3. package/dist/cjs/{filter-group-logic-Bt5tIbfP.js → filter-group-logic-CeGmYgsu.js} +1 -1
  4. package/dist/cjs/{filter-operators-CzIq9qKC.js → filter-operators-C3T2czC_.js} +1 -1
  5. package/dist/cjs/{index-mDIvByXc.js → index-Du4GyM0Y.js} +13 -8
  6. package/dist/cjs/index.cjs.js +3 -3
  7. package/dist/cjs/{index.esm-D1EzGa8X.js → index.esm-C2zw0QJK.js} +2 -2
  8. package/dist/cjs/lime-crm-building-blocks.cjs.js +3 -3
  9. package/dist/cjs/{lime-query-validation-Df4GZRGm.js → lime-query-validation-CzYkphmi.js} +1 -1
  10. package/dist/cjs/limebb-alert-dialog.cjs.entry.js +1 -1
  11. package/dist/cjs/limebb-browser.cjs.entry.js +2 -2
  12. package/dist/cjs/limebb-chat-icon-list_3.cjs.entry.js +2 -2
  13. package/dist/cjs/limebb-chat-list.cjs.entry.js +2 -2
  14. package/dist/cjs/limebb-color-palette-picker.cjs.entry.js +1 -1
  15. package/dist/cjs/limebb-color-palette-swatches.cjs.entry.js +1 -1
  16. package/dist/cjs/limebb-component-config.cjs.entry.js +3 -3
  17. package/dist/cjs/limebb-component-picker.cjs.entry.js +2 -2
  18. package/dist/cjs/limebb-composer-toolbar.cjs.entry.js +2 -2
  19. package/dist/cjs/limebb-condition-tree-editor.cjs.entry.js +24 -9
  20. package/dist/cjs/limebb-condition-tree.cjs.entry.js +121 -34
  21. package/dist/cjs/limebb-currency-picker.cjs.entry.js +2 -2
  22. package/dist/cjs/limebb-dashboard-widget.cjs.entry.js +1 -1
  23. package/dist/cjs/limebb-data-cells.cjs.entry.js +2 -2
  24. package/dist/cjs/limebb-date-picker.cjs.entry.js +2 -2
  25. package/dist/cjs/limebb-date-range.cjs.entry.js +1 -1
  26. package/dist/cjs/limebb-document-chips.cjs.entry.js +1 -1
  27. package/dist/cjs/limebb-document-item.cjs.entry.js +1 -1
  28. package/dist/cjs/limebb-document-picker.cjs.entry.js +1 -1
  29. package/dist/cjs/limebb-empty-state.cjs.entry.js +1 -1
  30. package/dist/cjs/limebb-feed-item-thumbnail-file-info.cjs.entry.js +1 -1
  31. package/dist/cjs/limebb-feed-timeline-item.cjs.entry.js +2 -2
  32. package/dist/cjs/limebb-feed.cjs.entry.js +2 -2
  33. package/dist/cjs/limebb-filter-chip_6.cjs.entry.js +4 -4
  34. package/dist/cjs/limebb-icon-picker.cjs.entry.js +1 -1
  35. package/dist/cjs/limebb-info-tile-currency-format.cjs.entry.js +1 -1
  36. package/dist/cjs/limebb-info-tile-date-format.cjs.entry.js +1 -1
  37. package/dist/cjs/limebb-info-tile-decimal-format.cjs.entry.js +1 -1
  38. package/dist/cjs/limebb-info-tile-format.cjs.entry.js +1 -1
  39. package/dist/cjs/limebb-info-tile-relative-date-format.cjs.entry.js +1 -1
  40. package/dist/cjs/limebb-info-tile-unit-format.cjs.entry.js +1 -1
  41. package/dist/cjs/limebb-info-tile.cjs.entry.js +3 -3
  42. package/dist/cjs/limebb-inline-image.cjs.entry.js +2 -2
  43. package/dist/cjs/limebb-kanban-group.cjs.entry.js +2 -2
  44. package/dist/cjs/limebb-kanban-item.cjs.entry.js +2 -2
  45. package/dist/cjs/limebb-kanban.cjs.entry.js +1 -1
  46. package/dist/cjs/limebb-lime-query-builder.cjs.entry.js +3 -3
  47. package/dist/cjs/limebb-lime-query-filter-builder.cjs.entry.js +3 -3
  48. package/dist/cjs/limebb-lime-query-filter-comparison_2.cjs.entry.js +4 -4
  49. package/dist/cjs/limebb-lime-query-order-by-editor_2.cjs.entry.js +3 -3
  50. package/dist/cjs/limebb-lime-query-order-by-item.cjs.entry.js +1 -1
  51. package/dist/cjs/limebb-lime-query-response-format-builder.cjs.entry.js +3 -3
  52. package/dist/cjs/limebb-lime-query-response-format-editor_2.cjs.entry.js +1 -1
  53. package/dist/cjs/limebb-limeobject-file-viewer.cjs.entry.js +2 -2
  54. package/dist/cjs/limebb-live-docs-info.cjs.entry.js +1 -1
  55. package/dist/cjs/limebb-loader.cjs.entry.js +2 -2
  56. package/dist/cjs/limebb-locale-picker.cjs.entry.js +2 -2
  57. package/dist/cjs/limebb-mention-group-counter.cjs.entry.js +1 -1
  58. package/dist/cjs/limebb-mention.cjs.entry.js +2 -2
  59. package/dist/cjs/limebb-navigation-button_2.cjs.entry.js +1 -1
  60. package/dist/cjs/limebb-notification-item.cjs.entry.js +2 -2
  61. package/dist/cjs/limebb-notification-list.cjs.entry.js +2 -2
  62. package/dist/cjs/limebb-object-chip.cjs.entry.js +3 -3
  63. package/dist/cjs/limebb-percentage-visualizer.cjs.entry.js +2 -2
  64. package/dist/cjs/limebb-property-selector.cjs.entry.js +3 -3
  65. package/dist/cjs/limebb-rule-arg-filter-editor.cjs.entry.js +2 -2
  66. package/dist/cjs/limebb-rule-condition-chip.cjs.entry.js +71 -0
  67. package/dist/cjs/limebb-rule-condition-editor-CHWTMOmi.js +285 -0
  68. package/dist/cjs/limebb-rule-condition-editor.cjs.entry.js +9 -0
  69. package/dist/cjs/limebb-rule-editor.cjs.entry.js +217 -573
  70. package/dist/cjs/limebb-rule-gate.cjs.entry.js +2 -2
  71. package/dist/cjs/limebb-text-editor-picker.cjs.entry.js +1 -1
  72. package/dist/cjs/limebb-text-editor.cjs.entry.js +3 -3
  73. package/dist/cjs/limebb-trend-indicator.cjs.entry.js +2 -2
  74. package/dist/cjs/limebb-value-comparison-editor.cjs.entry.js +3 -3
  75. package/dist/cjs/{limetype-BPuuRLtH.js → limetype-BzVDjAKS.js} +1 -1
  76. package/dist/cjs/loader.cjs.js +2 -2
  77. package/dist/cjs/{web-component-template-DRMW9wHN.js → web-component-template-C-AkY5as.js} +1 -1
  78. package/dist/collection/collection-manifest.json +3 -2
  79. package/dist/collection/components/condition-tree/condition-tree-editor/condition-tree-editor.js +46 -5
  80. package/dist/collection/components/condition-tree/condition-tree-nodes.js +13 -6
  81. package/dist/collection/components/condition-tree/condition-tree.js +69 -18
  82. package/dist/collection/components/condition-tree/group-node-view.js +41 -5
  83. package/dist/collection/components/condition-tree/leaf-node-view.js +19 -2
  84. package/dist/collection/components/rule-editor/condition-tree-adapter.js +229 -0
  85. package/dist/collection/components/rule-editor/rule-condition-chip/rule-condition-chip.css +4 -0
  86. package/dist/collection/components/rule-editor/rule-condition-chip/rule-condition-chip.js +322 -0
  87. package/dist/collection/components/rule-editor/rule-condition-editor/rule-condition-editor.css +5 -0
  88. package/dist/collection/components/rule-editor/rule-condition-editor/rule-condition-editor.js +259 -0
  89. package/dist/collection/components/rule-editor/rule-editor.css +1 -73
  90. package/dist/collection/components/rule-editor/rule-editor.js +143 -153
  91. package/dist/collection/components/rule-editor/rule-issues.js +89 -0
  92. package/dist/collection/components/rule-editor/view-helpers.js +19 -41
  93. package/dist/components/condition-tree-adapter.js +1 -0
  94. package/dist/components/condition-tree-editor.js +1 -1
  95. package/dist/components/condition-tree.js +1 -0
  96. package/dist/components/limebb-condition-tree.js +1 -1
  97. package/dist/components/limebb-rule-condition-chip.d.ts +11 -0
  98. package/dist/components/limebb-rule-condition-chip.js +1 -0
  99. package/dist/components/limebb-rule-condition-editor.d.ts +11 -0
  100. package/dist/components/limebb-rule-condition-editor.js +1 -0
  101. package/dist/components/limebb-rule-editor.js +1 -1
  102. package/dist/esm/{condition-tree-translate-CBeXbZ_z.js → condition-tree-translate-ZQptbaXF.js} +1 -1
  103. package/dist/esm/{filter-group-logic-CzThKf85.js → filter-group-logic-nqCMmV0e.js} +1 -1
  104. package/dist/esm/{filter-operators-u3T1PKhm.js → filter-operators-QbKK26m2.js} +1 -1
  105. package/dist/esm/{index-COtSgrC5.js → index-BK566_jX.js} +13 -8
  106. package/dist/esm/{index.esm-B9D_MXA6.js → index.esm-C__n3hug.js} +1 -1
  107. package/dist/esm/index.js +3 -3
  108. package/dist/esm/lime-crm-building-blocks.js +4 -4
  109. package/dist/esm/{lime-query-validation-dGoN_93p.js → lime-query-validation-BvB2v-yP.js} +1 -1
  110. package/dist/esm/limebb-alert-dialog.entry.js +1 -1
  111. package/dist/esm/limebb-browser.entry.js +2 -2
  112. package/dist/esm/limebb-chat-icon-list_3.entry.js +2 -2
  113. package/dist/esm/limebb-chat-list.entry.js +2 -2
  114. package/dist/esm/limebb-color-palette-picker.entry.js +1 -1
  115. package/dist/esm/limebb-color-palette-swatches.entry.js +1 -1
  116. package/dist/esm/limebb-component-config.entry.js +3 -3
  117. package/dist/esm/limebb-component-picker.entry.js +2 -2
  118. package/dist/esm/limebb-composer-toolbar.entry.js +2 -2
  119. package/dist/esm/limebb-condition-tree-editor.entry.js +24 -9
  120. package/dist/esm/limebb-condition-tree.entry.js +121 -34
  121. package/dist/esm/limebb-currency-picker.entry.js +2 -2
  122. package/dist/esm/limebb-dashboard-widget.entry.js +1 -1
  123. package/dist/esm/limebb-data-cells.entry.js +2 -2
  124. package/dist/esm/limebb-date-picker.entry.js +2 -2
  125. package/dist/esm/limebb-date-range.entry.js +1 -1
  126. package/dist/esm/limebb-document-chips.entry.js +1 -1
  127. package/dist/esm/limebb-document-item.entry.js +1 -1
  128. package/dist/esm/limebb-document-picker.entry.js +1 -1
  129. package/dist/esm/limebb-empty-state.entry.js +1 -1
  130. package/dist/esm/limebb-feed-item-thumbnail-file-info.entry.js +1 -1
  131. package/dist/esm/limebb-feed-timeline-item.entry.js +2 -2
  132. package/dist/esm/limebb-feed.entry.js +2 -2
  133. package/dist/esm/limebb-filter-chip_6.entry.js +4 -4
  134. package/dist/esm/limebb-icon-picker.entry.js +1 -1
  135. package/dist/esm/limebb-info-tile-currency-format.entry.js +1 -1
  136. package/dist/esm/limebb-info-tile-date-format.entry.js +1 -1
  137. package/dist/esm/limebb-info-tile-decimal-format.entry.js +1 -1
  138. package/dist/esm/limebb-info-tile-format.entry.js +1 -1
  139. package/dist/esm/limebb-info-tile-relative-date-format.entry.js +1 -1
  140. package/dist/esm/limebb-info-tile-unit-format.entry.js +1 -1
  141. package/dist/esm/limebb-info-tile.entry.js +3 -3
  142. package/dist/esm/limebb-inline-image.entry.js +2 -2
  143. package/dist/esm/limebb-kanban-group.entry.js +2 -2
  144. package/dist/esm/limebb-kanban-item.entry.js +2 -2
  145. package/dist/esm/limebb-kanban.entry.js +1 -1
  146. package/dist/esm/limebb-lime-query-builder.entry.js +3 -3
  147. package/dist/esm/limebb-lime-query-filter-builder.entry.js +3 -3
  148. package/dist/esm/limebb-lime-query-filter-comparison_2.entry.js +4 -4
  149. package/dist/esm/limebb-lime-query-order-by-editor_2.entry.js +3 -3
  150. package/dist/esm/limebb-lime-query-order-by-item.entry.js +1 -1
  151. package/dist/esm/limebb-lime-query-response-format-builder.entry.js +3 -3
  152. package/dist/esm/limebb-lime-query-response-format-editor_2.entry.js +1 -1
  153. package/dist/esm/limebb-limeobject-file-viewer.entry.js +2 -2
  154. package/dist/esm/limebb-live-docs-info.entry.js +1 -1
  155. package/dist/esm/limebb-loader.entry.js +2 -2
  156. package/dist/esm/limebb-locale-picker.entry.js +2 -2
  157. package/dist/esm/limebb-mention-group-counter.entry.js +1 -1
  158. package/dist/esm/limebb-mention.entry.js +2 -2
  159. package/dist/esm/limebb-navigation-button_2.entry.js +1 -1
  160. package/dist/esm/limebb-notification-item.entry.js +2 -2
  161. package/dist/esm/limebb-notification-list.entry.js +2 -2
  162. package/dist/esm/limebb-object-chip.entry.js +3 -3
  163. package/dist/esm/limebb-percentage-visualizer.entry.js +2 -2
  164. package/dist/esm/limebb-property-selector.entry.js +3 -3
  165. package/dist/esm/limebb-rule-arg-filter-editor.entry.js +2 -2
  166. package/dist/esm/limebb-rule-condition-chip.entry.js +69 -0
  167. package/dist/esm/limebb-rule-condition-editor-DeY758N-.js +281 -0
  168. package/dist/esm/limebb-rule-condition-editor.entry.js +3 -0
  169. package/dist/esm/limebb-rule-editor.entry.js +217 -573
  170. package/dist/esm/limebb-rule-gate.entry.js +2 -2
  171. package/dist/esm/limebb-text-editor-picker.entry.js +1 -1
  172. package/dist/esm/limebb-text-editor.entry.js +3 -3
  173. package/dist/esm/limebb-trend-indicator.entry.js +2 -2
  174. package/dist/esm/limebb-value-comparison-editor.entry.js +3 -3
  175. package/dist/esm/{limetype-BcELY1NF.js → limetype-Muf9VutX.js} +1 -1
  176. package/dist/esm/loader.js +3 -3
  177. package/dist/esm/{web-component-template-DxbwHsvw.js → web-component-template-D1JpeNy_.js} +1 -1
  178. package/dist/lime-crm-building-blocks/index.esm.js +1 -1
  179. package/dist/lime-crm-building-blocks/lime-crm-building-blocks.esm.js +1 -1
  180. package/dist/lime-crm-building-blocks/p-0621e884.entry.js +1 -0
  181. package/dist/lime-crm-building-blocks/{p-ab0f8170.entry.js → p-087d5651.entry.js} +1 -1
  182. package/dist/lime-crm-building-blocks/{p-ce2755a0.entry.js → p-1917956c.entry.js} +1 -1
  183. package/dist/lime-crm-building-blocks/{p-07a9c8f2.entry.js → p-1ae4962d.entry.js} +1 -1
  184. package/dist/lime-crm-building-blocks/{p-021e452a.entry.js → p-23d2632b.entry.js} +1 -1
  185. package/dist/lime-crm-building-blocks/{p-ffca266e.entry.js → p-251784bf.entry.js} +1 -1
  186. package/dist/lime-crm-building-blocks/{p-635a45ad.entry.js → p-27240bb0.entry.js} +1 -1
  187. package/dist/lime-crm-building-blocks/p-2adeac66.entry.js +1 -0
  188. package/dist/lime-crm-building-blocks/{p-6a8422d2.entry.js → p-32339f09.entry.js} +1 -1
  189. package/dist/lime-crm-building-blocks/{p-1990e369.entry.js → p-3446290c.entry.js} +1 -1
  190. package/dist/lime-crm-building-blocks/{p-d495cc19.entry.js → p-35d9b3ad.entry.js} +1 -1
  191. package/dist/lime-crm-building-blocks/{p-eed0b2c2.entry.js → p-3865eec4.entry.js} +1 -1
  192. package/dist/lime-crm-building-blocks/{p-dacf9e77.entry.js → p-394b521a.entry.js} +1 -1
  193. package/dist/lime-crm-building-blocks/{p-8c36b847.entry.js → p-39a36450.entry.js} +1 -1
  194. package/dist/lime-crm-building-blocks/{p-97e75dee.entry.js → p-3b672249.entry.js} +1 -1
  195. package/dist/lime-crm-building-blocks/{p-ad5dcefd.entry.js → p-47b56a75.entry.js} +1 -1
  196. package/dist/lime-crm-building-blocks/{p-402a9c97.entry.js → p-4af3ea2c.entry.js} +1 -1
  197. package/dist/lime-crm-building-blocks/{p-0cc47cad.entry.js → p-4bdaf436.entry.js} +1 -1
  198. package/dist/lime-crm-building-blocks/{p-cf66256a.entry.js → p-4f60b7bc.entry.js} +1 -1
  199. package/dist/lime-crm-building-blocks/{p-90f0c96b.entry.js → p-4fd9d615.entry.js} +1 -1
  200. package/dist/lime-crm-building-blocks/{p-28550961.entry.js → p-53b44865.entry.js} +1 -1
  201. package/dist/lime-crm-building-blocks/{p-7ae27308.entry.js → p-550606f6.entry.js} +1 -1
  202. package/dist/lime-crm-building-blocks/p-573f9e95.entry.js +1 -0
  203. package/dist/lime-crm-building-blocks/{p-a5f3913d.entry.js → p-5c541d0c.entry.js} +1 -1
  204. package/dist/lime-crm-building-blocks/{p-ce723c21.entry.js → p-612c6b28.entry.js} +1 -1
  205. package/dist/lime-crm-building-blocks/{p-5f682c06.entry.js → p-627b0c79.entry.js} +1 -1
  206. package/dist/lime-crm-building-blocks/{p-49d042aa.entry.js → p-6303201b.entry.js} +1 -1
  207. package/dist/lime-crm-building-blocks/{p-6f923112.entry.js → p-687640ed.entry.js} +1 -1
  208. package/dist/lime-crm-building-blocks/{p-8e9fcf3c.entry.js → p-6bd61290.entry.js} +1 -1
  209. package/dist/lime-crm-building-blocks/{p-dcb49a62.entry.js → p-6d2dba20.entry.js} +1 -1
  210. package/dist/lime-crm-building-blocks/{p-0193ed83.entry.js → p-6e2553b4.entry.js} +1 -1
  211. package/dist/lime-crm-building-blocks/{p-Cz5s8qGk.js → p-7DQ7qvMa.js} +1 -1
  212. package/dist/lime-crm-building-blocks/p-7c3d3e06.entry.js +1 -0
  213. package/dist/lime-crm-building-blocks/{p-dd02821e.entry.js → p-7d53756b.entry.js} +1 -1
  214. package/dist/lime-crm-building-blocks/{p-79d743bb.entry.js → p-895c8966.entry.js} +1 -1
  215. package/dist/lime-crm-building-blocks/{p-da35bcc7.entry.js → p-8c0455e4.entry.js} +1 -1
  216. package/dist/lime-crm-building-blocks/{p-a201df35.entry.js → p-8f80d024.entry.js} +1 -1
  217. package/dist/lime-crm-building-blocks/{p-32a81271.entry.js → p-949ed056.entry.js} +1 -1
  218. package/dist/lime-crm-building-blocks/{p-cf03a756.entry.js → p-985ae787.entry.js} +1 -1
  219. package/dist/lime-crm-building-blocks/p-9959019d.entry.js +1 -0
  220. package/dist/lime-crm-building-blocks/{p-DLec4QaM.js → p-B7whyaAL.js} +1 -1
  221. package/dist/lime-crm-building-blocks/{p-COtSgrC5.js → p-BK566_jX.js} +1 -1
  222. package/dist/lime-crm-building-blocks/p-ClYOFrOo.js +1 -0
  223. package/dist/lime-crm-building-blocks/{p-DVypQWZ4.js → p-Cve-3L4y.js} +1 -1
  224. package/dist/lime-crm-building-blocks/p-DOULPRTn.js +1 -0
  225. package/dist/lime-crm-building-blocks/{p-Cj_3f9vm.js → p-DhGRAeCH.js} +1 -1
  226. package/dist/lime-crm-building-blocks/p-DjoMDjMo.js +1 -0
  227. package/dist/lime-crm-building-blocks/p-DuWEcQ7n.js +1 -0
  228. package/dist/lime-crm-building-blocks/{p-dfaef740.entry.js → p-a1052482.entry.js} +1 -1
  229. package/dist/lime-crm-building-blocks/{p-3babfbe0.entry.js → p-a14bed52.entry.js} +1 -1
  230. package/dist/lime-crm-building-blocks/{p-cc53a8ca.entry.js → p-a2e291b4.entry.js} +1 -1
  231. package/dist/lime-crm-building-blocks/{p-8a17a7ea.entry.js → p-a2ebd5a4.entry.js} +1 -1
  232. package/dist/lime-crm-building-blocks/{p-0cbe2180.entry.js → p-a4556649.entry.js} +1 -1
  233. package/dist/lime-crm-building-blocks/{p-f5c1ed0c.entry.js → p-a598f92f.entry.js} +1 -1
  234. package/dist/lime-crm-building-blocks/{p-b44b9dbc.entry.js → p-a938384f.entry.js} +1 -1
  235. package/dist/lime-crm-building-blocks/{p-f3539042.entry.js → p-ab0210b2.entry.js} +1 -1
  236. package/dist/lime-crm-building-blocks/{p-c0d49532.entry.js → p-b272730c.entry.js} +1 -1
  237. package/dist/lime-crm-building-blocks/{p-0370200d.entry.js → p-b4571d32.entry.js} +1 -1
  238. package/dist/lime-crm-building-blocks/{p-551a36f6.entry.js → p-b72c748b.entry.js} +1 -1
  239. package/dist/lime-crm-building-blocks/{p-0ed9a7cc.entry.js → p-bac9d3a9.entry.js} +1 -1
  240. package/dist/lime-crm-building-blocks/p-bd6c12bc.entry.js +1 -0
  241. package/dist/lime-crm-building-blocks/{p-81783bd4.entry.js → p-bf693702.entry.js} +1 -1
  242. package/dist/lime-crm-building-blocks/{p-e6cc320a.entry.js → p-c58067ec.entry.js} +1 -1
  243. package/dist/lime-crm-building-blocks/{p-08797129.entry.js → p-c7bfa2e4.entry.js} +1 -1
  244. package/dist/lime-crm-building-blocks/{p-a953d48e.entry.js → p-d4635a39.entry.js} +1 -1
  245. package/dist/lime-crm-building-blocks/{p-d3c58bc1.entry.js → p-d6099dc7.entry.js} +1 -1
  246. package/dist/lime-crm-building-blocks/{p-bf05d9de.entry.js → p-d6c7cf0f.entry.js} +1 -1
  247. package/dist/lime-crm-building-blocks/{p-1ebe45b8.entry.js → p-da79c5fc.entry.js} +1 -1
  248. package/dist/lime-crm-building-blocks/p-e18a2cef.entry.js +1 -0
  249. package/dist/lime-crm-building-blocks/{p-f9991c35.entry.js → p-e19f4b3b.entry.js} +1 -1
  250. package/dist/lime-crm-building-blocks/{p-46aec244.entry.js → p-eb95767a.entry.js} +1 -1
  251. package/dist/lime-crm-building-blocks/{p-ddc4ede8.entry.js → p-ec9b5e30.entry.js} +1 -1
  252. package/dist/lime-crm-building-blocks/{p-95ba7a84.entry.js → p-f49250f3.entry.js} +1 -1
  253. package/dist/types/components/condition-tree/condition-tree-editor/condition-tree-editor.d.ts +20 -3
  254. package/dist/types/components/condition-tree/condition-tree-nodes.d.ts +11 -4
  255. package/dist/types/components/condition-tree/condition-tree-view-context.d.ts +3 -2
  256. package/dist/types/components/condition-tree/condition-tree.d.ts +41 -8
  257. package/dist/types/components/condition-tree/condition-tree.types.d.ts +21 -2
  258. package/dist/types/components/rule-editor/condition-tree-adapter.d.ts +67 -0
  259. package/dist/types/components/rule-editor/rule-condition-chip/rule-condition-chip.d.ts +82 -0
  260. package/dist/types/components/rule-editor/rule-condition-editor/rule-condition-editor.d.ts +61 -0
  261. package/dist/types/components/rule-editor/rule-editor.d.ts +105 -47
  262. package/dist/types/components/rule-editor/rule-issues.d.ts +12 -0
  263. package/dist/types/components/rule-editor/view-helpers.d.ts +16 -35
  264. package/dist/types/components.d.ts +304 -79
  265. package/dist/types/stencil-public-runtime.d.ts +61 -55
  266. package/package.json +4 -4
  267. package/dist/cjs/limebb-rule-chip-popover.cjs.entry.js +0 -82
  268. package/dist/collection/components/rule-editor/chip-picker-view.js +0 -148
  269. package/dist/collection/components/rule-editor/group-node-view.js +0 -79
  270. package/dist/collection/components/rule-editor/rule-chip-popover/rule-chip-popover.css +0 -36
  271. package/dist/collection/components/rule-editor/rule-chip-popover/rule-chip-popover.js +0 -344
  272. package/dist/collection/components/rule-editor/rule-editor-views.js +0 -43
  273. package/dist/collection/components/rule-editor/rule-operations.js +0 -145
  274. package/dist/components/limebb-rule-chip-popover.d.ts +0 -11
  275. package/dist/components/limebb-rule-chip-popover.js +0 -1
  276. package/dist/components/rule-chip-popover.js +0 -1
  277. package/dist/esm/limebb-rule-chip-popover.entry.js +0 -80
  278. package/dist/lime-crm-building-blocks/p-1578c8f0.entry.js +0 -1
  279. package/dist/lime-crm-building-blocks/p-229d018c.entry.js +0 -1
  280. package/dist/lime-crm-building-blocks/p-6331f9c5.entry.js +0 -1
  281. package/dist/lime-crm-building-blocks/p-705c53c0.entry.js +0 -1
  282. package/dist/lime-crm-building-blocks/p-84ad9159.entry.js +0 -1
  283. package/dist/lime-crm-building-blocks/p-BxCq236x.js +0 -1
  284. package/dist/lime-crm-building-blocks/p-Css8537O.js +0 -1
  285. package/dist/lime-crm-building-blocks/p-a58c9e1e.entry.js +0 -1
  286. package/dist/lime-crm-building-blocks/p-hsyotUav.js +0 -1
  287. package/dist/types/components/rule-editor/chip-picker-view.d.ts +0 -35
  288. package/dist/types/components/rule-editor/group-node-view.d.ts +0 -11
  289. package/dist/types/components/rule-editor/rule-chip-popover/rule-chip-popover.d.ts +0 -43
  290. package/dist/types/components/rule-editor/rule-editor-views.d.ts +0 -58
  291. package/dist/types/components/rule-editor/rule-operations.d.ts +0 -70
@@ -1,179 +1,108 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-mDIvByXc.js');
4
- var index_esm = require('./index.esm-D1EzGa8X.js');
3
+ var index = require('./index-Du4GyM0Y.js');
4
+ var index_esm = require('./index.esm-C2zw0QJK.js');
5
+ var conditionTreeTranslate = require('./condition-tree-translate-BQwKtiNZ.js');
6
+ var limebbRuleConditionEditor_entry = require('./limebb-rule-condition-editor-CHWTMOmi.js');
7
+ require('./limebb-rule-condition-chip.cjs.entry.js');
5
8
  var ruleEditorModes = require('./rule-editor-modes-Dc6rnwD2.js');
6
9
  var randomString = require('./random-string-BdZGIsGg.js');
10
+ require('./web-component-template-C-AkY5as.js');
7
11
 
8
12
  /**
9
- * Remove the node at `path`.
13
+ * The problems the registry found, gathered by the node each belongs to.
10
14
  *
11
- * Removing the root yields an empty `all`-group so the tree always has
12
- * something to render. Returns `rule` unchanged when `path` does not
13
- * address a removable node.
14
- * @param rule
15
- * @param path
16
- */
17
- function deleteNode(rule, path) {
18
- if (path.length === 0) {
19
- return { type: 'all', rules: [] };
20
- }
21
- const parentPath = path.slice(0, -1);
22
- const key = path.at(-1);
23
- const parent = getNode(rule, parentPath);
24
- if (parent === undefined) {
25
- return rule;
26
- }
27
- if ((parent.type === 'all' || parent.type === 'any') &&
28
- typeof key === 'number') {
29
- const rules = [...parent.rules];
30
- rules.splice(key, 1);
31
- return replaceAt(rule, parentPath, Object.assign(Object.assign({}, parent), { rules }));
32
- }
33
- if (parent.type === 'not' && key === 'rule') {
34
- return replaceAt(rule, parentPath, { type: 'all', rules: [] });
35
- }
36
- return rule;
37
- }
38
- /**
39
- * Replace the `args` of a `ref` node. Returns `rule` unchanged when
40
- * `path` does not resolve to a `ref`.
41
- * @param rule
42
- * @param path
43
- * @param args
44
- */
45
- function updateArgs(rule, path, args) {
46
- const node = getNode(rule, path);
47
- if (node === undefined || node.type !== 'ref') {
48
- return rule;
49
- }
50
- return replaceAt(rule, path, Object.assign(Object.assign({}, node), { args }));
51
- }
52
- /**
53
- * Replace the node at `path` with `replacement`, returning a new rule
54
- * tree. Used by callers that need to apply a non-atomic change as a
55
- * single emit (e.g. updating a group's whole `rules` array at once).
56
- * @param rule
57
- * @param path
58
- * @param replacement
59
- */
60
- function replaceNode(rule, path, replacement) {
61
- return replaceAt(rule, path, replacement);
62
- }
63
- /**
64
- * Wrap `group` in a `not` when `isNegated`, otherwise return it
65
- * unchanged. Used when re-emitting a group whose negation flag should
66
- * be preserved.
67
- * @param group
68
- * @param isNegated
69
- */
70
- function wrapNegated(group, isNegated) {
71
- return isNegated ? { type: 'not', rule: group } : group;
72
- }
73
- /**
74
- * Append `child` to a group's `rules`, returning a new group. The
75
- * input is not mutated.
76
- * @param group
77
- * @param child
15
+ * The registry addresses an issue by path — `['rules', 0, 'rule']` for
16
+ * `root.rules[0].rule` — while the tree asks about one node at a time and never
17
+ * says where it is. Resolving the paths once, here, bridges the two.
18
+ * @param root
19
+ * @param issues
78
20
  */
79
- function appendChild(group, child) {
80
- return Object.assign(Object.assign({}, group), { rules: [...group.rules, child] });
21
+ function collectRuleIssues(root, issues) {
22
+ var _a, _b;
23
+ const owners = displayOwners(root);
24
+ const byNode = new Map();
25
+ for (const issue of issues) {
26
+ const node = nodeAt(root, issue.path);
27
+ // An empty path means the rule as a whole, and one the path cannot
28
+ // reach has nowhere better to go than the root either.
29
+ const owner = (_a = (node && owners.get(node))) !== null && _a !== void 0 ? _a : root;
30
+ byNode.set(owner, [...((_b = byNode.get(owner)) !== null && _b !== void 0 ? _b : []), issue.message]);
31
+ }
32
+ return byNode;
81
33
  }
82
34
  /**
83
- * Structural equality on two paths.
84
- * @param a
85
- * @param b
35
+ * Which node each node is drawn as part of. Most stand for themselves; the
36
+ * exception is everything under a `not`, which is drawn as that `not` — the
37
+ * two are one thing on screen, and only the wrapper has somewhere to show it.
38
+ * @param root
86
39
  */
87
- function pathsEqual(a, b) {
88
- if (a.length !== b.length) {
89
- return false;
90
- }
91
- return a.every((value, index) => value === b[index]);
92
- }
93
- /**
94
- * Filter validation issues to those whose `path` matches `path`.
95
- * @param issues
96
- * @param path
97
- */
98
- function issuesAt(issues, path) {
99
- return issues.filter((issue) => pathsEqual(issue.path, path));
40
+ function displayOwners(root) {
41
+ const owners = new Map();
42
+ const visit = (node, owner) => {
43
+ // A hand-edited rule can hold a `null` where a node should be. It is
44
+ // drawn, as something that cannot be read, so it is walked past here.
45
+ if (typeof node !== 'object' || node === null) {
46
+ return;
47
+ }
48
+ owners.set(node, owner);
49
+ if (node.type === 'not') {
50
+ visit(node.rule, owner);
51
+ return;
52
+ }
53
+ if ((node.type === 'all' || node.type === 'any') &&
54
+ Array.isArray(node.rules)) {
55
+ for (const child of node.rules) {
56
+ visit(child, child);
57
+ }
58
+ }
59
+ };
60
+ visit(root, root);
61
+ return owners;
100
62
  }
101
63
  /**
102
- * Resolve the node at `path` by walking each segment from the root.
103
- * Returns `undefined` when a segment indexes past the end of a
104
- * combinator's `rules`, so callers must guard the result.
105
- * @param rule
64
+ * The node a validation path addresses, or nothing when it addresses none.
65
+ *
66
+ * Walked one hop at a time because the two the registry emits have different
67
+ * shapes: into a negation is the single segment `rule`, into the *n*-th child
68
+ * of a group is the pair `rules`, *n*. Anything else is not a path this rule
69
+ * can be walked by.
70
+ * @param root
106
71
  * @param path
107
72
  */
108
- function getNode(rule, path) {
109
- let node = rule;
110
- for (const key of path) {
111
- if (node === undefined) {
73
+ function nodeAt(root, path) {
74
+ let node = root;
75
+ let index = 0;
76
+ while (index < path.length) {
77
+ // The same `null` can be standing one hop short of the path's end,
78
+ // with no hop to take from it. Asked for `type`, it would throw.
79
+ if (node === null || typeof node !== 'object') {
112
80
  return undefined;
113
81
  }
114
- node = stepIntoNode(node, key);
115
- }
116
- return node;
117
- }
118
- function replaceAt(root, path, replacement) {
119
- if (path.length === 0) {
120
- return replacement;
121
- }
122
- const [head, ...tail] = path;
123
- if (root.type === 'not' && head === 'rule') {
124
- return Object.assign(Object.assign({}, root), { rule: replaceAt(root.rule, tail, replacement) });
125
- }
126
- if ((root.type === 'all' || root.type === 'any') && head === 'rules') {
127
- if (tail.length === 0) {
128
- return replacement;
82
+ const key = path[index];
83
+ if (key === 'rule' && node.type === 'not') {
84
+ node = node.rule;
85
+ index += 1;
86
+ continue;
129
87
  }
130
- const [index, ...rest] = tail;
131
- if (typeof index !== 'number') {
132
- return root;
88
+ const child = path[index + 1];
89
+ if (key === 'rules' &&
90
+ (node.type === 'all' || node.type === 'any') &&
91
+ Array.isArray(node.rules) &&
92
+ typeof child === 'number') {
93
+ node = node.rules[child];
94
+ index += 2;
95
+ continue;
133
96
  }
134
- const rules = [...root.rules];
135
- rules[index] = replaceAt(rules[index], rest, replacement);
136
- return Object.assign(Object.assign({}, root), { rules });
137
- }
138
- return root;
139
- }
140
- function stepIntoNode(node, key) {
141
- if (node.type === 'not' && key === 'rule') {
142
- return node.rule;
143
- }
144
- if ((node.type === 'all' || node.type === 'any') && key === 'rules') {
145
- return node;
146
- }
147
- if ((node.type === 'all' || node.type === 'any') &&
148
- typeof key === 'number') {
149
- return node.rules[key];
97
+ return undefined;
150
98
  }
151
99
  return node;
152
100
  }
153
101
 
154
- const UNKNOWN_ICON = {
155
- name: 'question',
156
- color: 'rgb(var(--color-glaucous-light))',
157
- };
158
- /**
159
- * Class map for a rule-node container. Adds the type modifier and an
160
- * `invalid` flag when validation issues attach to this node.
161
- * @param type
162
- * @param issues
163
- */
164
- function nodeClasses(type, issues) {
165
- return {
166
- 'rule-node': true,
167
- [`rule-node--${type}`]: true,
168
- 'rule-node--invalid': issues.length > 0,
169
- };
170
- }
171
102
  /**
172
- * Build the searchable list shown by the primitive pickers. Cached on
173
- * the render context so it isn't recomputed per node. `meta.title` and
174
- * `meta.description` are passed through the translator so callers can
175
- * register translation keys as metadata — plain strings travel through
176
- * unchanged.
103
+ * The primitives the add button offers. Titles and descriptions go through the
104
+ * translator, so a caller can register translation keys as metadata — plain
105
+ * strings travel through unchanged.
177
106
  * @param metadataById
178
107
  * @param translator
179
108
  */
@@ -181,7 +110,7 @@ function createPrimitiveOptions(metadataById, translator) {
181
110
  return [...metadataById.values()]
182
111
  .map((meta) => ({
183
112
  value: meta.id,
184
- text: meta.title ? translator.get(meta.title) : meta.id,
113
+ text: primitiveTitle(meta, translator),
185
114
  secondaryText: meta.description
186
115
  ? translator.get(meta.description)
187
116
  : '',
@@ -189,6 +118,15 @@ function createPrimitiveOptions(metadataById, translator) {
189
118
  }))
190
119
  .sort((a, b) => a.text.localeCompare(b.text));
191
120
  }
121
+ /**
122
+ * How a primitive reads: its translated title, or its bare id when it has none
123
+ * to give. The add menu and the chip both read it from here, so they agree.
124
+ * @param meta
125
+ * @param translator
126
+ */
127
+ function primitiveTitle(meta, translator) {
128
+ return meta.title ? translator.get(meta.title) : meta.id;
129
+ }
192
130
  /**
193
131
  * Whether every context key a primitive reads is in the reachable set.
194
132
  * A primitive that reads nothing is always covered.
@@ -199,23 +137,9 @@ function primitiveReadsCovered(meta, reachable) {
199
137
  return meta.reads.every((key) => reachable.has(key));
200
138
  }
201
139
  /**
202
- * Find the picker item for `id`, falling back to a placeholder marked
203
- * with the unknown-primitive icon when the id isn't in the registry.
204
- * @param allItems
205
- * @param id
206
- */
207
- function resolveItem(allItems, id) {
208
- var _a;
209
- return ((_a = allItems.find((item) => item.value === id)) !== null && _a !== void 0 ? _a : {
210
- value: id,
211
- text: id,
212
- icon: UNKNOWN_ICON,
213
- });
214
- }
215
- /**
216
- * Build a picker `searcher` bound to a fixed item list. Both the ref
217
- * picker and the chip picker want exactly this — wrapping
218
- * {@link searchItems} in a promise — and deserve to share it.
140
+ * Narrow the primitives as the user types, for the search field at the top of
141
+ * the add menu. Every word has to match somewhere — title, description or id —
142
+ * so that "deal won" finds "Won deals".
219
143
  * @param items
220
144
  */
221
145
  function createSearcher(items) {
@@ -230,273 +154,12 @@ function searchItems(allItems, query) {
230
154
  var _a, _b;
231
155
  return item.text.toLocaleLowerCase().includes(part) ||
232
156
  ((_a = item.secondaryText) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase().includes(part)) ||
233
- ((_b = item.value) === null || _b === void 0 ? void 0 : _b.toLocaleLowerCase().includes(part));
157
+ String((_b = item.value) !== null && _b !== void 0 ? _b : '')
158
+ .toLocaleLowerCase()
159
+ .includes(part);
234
160
  }));
235
161
  }
236
162
 
237
- const CHIP_TOKEN_PREFIX = '__chip__:';
238
- function chipTokenFor(index) {
239
- return `${CHIP_TOKEN_PREFIX}${index}`;
240
- }
241
- // The address of a chip inside a group is the group's path followed
242
- // by a two-segment suffix `['rules', index]`. Build and parse via
243
- // these helpers so both sides stay in sync.
244
- const CHIP_PATH_SUFFIX_LENGTH = 2;
245
- /**
246
- * Address of the chip at `index` inside a group: the group's path plus
247
- * the `['rules', index]` suffix. Built here so the picker and popover
248
- * address chips the same way.
249
- * @param groupPath
250
- * @param index
251
- */
252
- function buildChipPath(groupPath, index) {
253
- return [...groupPath, 'rules', index];
254
- }
255
- function parentGroupPath(chipPath) {
256
- return chipPath.slice(0, -CHIP_PATH_SUFFIX_LENGTH);
257
- }
258
- /**
259
- * If `node` is a `ref` or a `not(ref)`, return the underlying ref
260
- * together with its negation flag. Used to decide whether a child of a
261
- * group renders as a chip (this returns non-null) or as a nested box
262
- * (this returns null).
263
- * @param node
264
- */
265
- function extractRef(node) {
266
- if (node.type === 'ref') {
267
- return { ref: node, isNegated: false };
268
- }
269
- if (node.type === 'not' && node.rule.type === 'ref') {
270
- return { ref: node.rule, isNegated: true };
271
- }
272
- return null;
273
- }
274
- const GroupChipsView = ({ groupNode, groupPath, chipChildren, ctx }) => {
275
- const chipsByToken = new Map();
276
- const value = chipChildren.map((entry) => {
277
- const token = chipTokenFor(entry.index);
278
- chipsByToken.set(token, entry);
279
- const base = resolveItem(ctx.allPrimitiveOptions, entry.ref.id);
280
- return Object.assign(Object.assign({}, base), { text: entry.isNegated ? `¬ ${base.text}` : base.text, value: token });
281
- });
282
- const searcher = createSearcher(ctx.availablePrimitiveOptions);
283
- const openChip = findOpenChip(chipChildren, groupPath, ctx.openChipPath);
284
- const delimiter = groupNode.type === 'all' ? '&' : '|';
285
- return (index.h("limel-popover", { class: "rule-node__chips-popover", open: openChip !== null, openDirection: "bottom-start", onClose: ctx.onPopoverClose }, index.h("div", { slot: "trigger", class: "rule-node__chips" }, index.h("limel-picker", { multiple: true, label: ctx.translator.get('webclient.rule-editor.rules-label'), value: value, searcher: searcher, delimiter: delimiter, readonly: ctx.readonly, disabled: ctx.disabled, onChange: chipsChangeHandler(groupNode, groupPath, chipsByToken, ctx), onInteract: chipInteractHandler(groupPath, chipsByToken, ctx) })), index.h("div", null, renderChipPopoverContent(openChip, groupPath, ctx))));
286
- };
287
- function renderChipPopoverContent(openChip, groupPath, ctx) {
288
- if (!openChip) {
289
- return null;
290
- }
291
- const openChipPath = buildChipPath(groupPath, openChip.index);
292
- return (index.h("limebb-rule-chip-popover", { platform: ctx.platform, context: ctx.context, refNode: openChip.ref, isNegated: openChip.isNegated, metadata: ctx.metadataById.get(openChip.ref.id), readonly: ctx.readonly, disabled: ctx.disabled, isMutable: ctx.isMutable, focusOnOpen: ctx.focusOnOpen, onNegate: chipNegateHandler(openChip, openChipPath, ctx), onUpdateArgs: chipArgsHandler(openChip, openChipPath, ctx), onDeleteChip: chipDeleteHandler(openChipPath, ctx) }));
293
- }
294
- const chipsChangeHandler = (groupNode, groupPath, chipsByToken, ctx) => (event) => {
295
- event.stopPropagation();
296
- const items = Array.isArray(event.detail) ? event.detail : [];
297
- const openIndex = openChipIndexInGroup(groupPath, ctx.openChipPath);
298
- if (openIndex !== null) {
299
- const openToken = chipTokenFor(openIndex);
300
- if (items.every((item) => item.value !== openToken)) {
301
- ctx.onPopoverClose();
302
- }
303
- }
304
- const newChipNodes = items.flatMap((item) => {
305
- if (typeof item.value !== 'string') {
306
- return [];
307
- }
308
- const existing = chipsByToken.get(item.value);
309
- if (existing) {
310
- return [
311
- existing.isNegated
312
- ? { type: 'not', rule: existing.ref }
313
- : existing.ref,
314
- ];
315
- }
316
- return [{ type: 'ref', id: item.value }];
317
- });
318
- const nestedGroupRules = groupNode.rules.filter((rule) => extractRef(rule) === null);
319
- ctx.onReplaceNode(groupPath, Object.assign(Object.assign({}, groupNode), { rules: [...newChipNodes, ...nestedGroupRules] }));
320
- };
321
- const chipInteractHandler = (groupPath, chipsByToken, ctx) => (event) => {
322
- event.stopPropagation();
323
- const token = interactedToken(event.detail);
324
- const chip = token ? chipsByToken.get(token) : undefined;
325
- if (!chip) {
326
- return;
327
- }
328
- ctx.onChipInteract([...groupPath, 'rules', chip.index]);
329
- };
330
- const chipNegateHandler = (openChip, openChipPath, ctx) => (event) => {
331
- event.stopPropagation();
332
- const next = event.detail
333
- ? { type: 'not', rule: openChip.ref }
334
- : openChip.ref;
335
- ctx.onReplaceNode(openChipPath, next);
336
- };
337
- const chipArgsHandler = (openChip, openChipPath, ctx) => (event) => {
338
- event.stopPropagation();
339
- const argsPath = openChip.isNegated
340
- ? [...openChipPath, 'rule']
341
- : openChipPath;
342
- ctx.onUpdateArgs(argsPath, event.detail);
343
- };
344
- const chipDeleteHandler = (openChipPath, ctx) => () => {
345
- ctx.onDelete(openChipPath);
346
- };
347
- /**
348
- * `limel-picker` declares its `interact` event as
349
- * `EventEmitter<ListItem<PickerValue>>` but the runtime actually emits
350
- * the chip's value (a string) — see picker.tsx's handleInteract. This
351
- * unwraps either shape into the string token.
352
- * @param detail
353
- */
354
- function interactedToken(detail) {
355
- if (typeof detail === 'string') {
356
- return detail;
357
- }
358
- if (detail && typeof detail === 'object' && 'value' in detail) {
359
- const value = detail.value;
360
- return typeof value === 'string' ? value : undefined;
361
- }
362
- return undefined;
363
- }
364
- function findOpenChip(chipChildren, groupPath, openChipPath) {
365
- var _a;
366
- const index = openChipIndexInGroup(groupPath, openChipPath);
367
- if (index === null) {
368
- return null;
369
- }
370
- return (_a = chipChildren.find((entry) => entry.index === index)) !== null && _a !== void 0 ? _a : null;
371
- }
372
- function openChipIndexInGroup(groupPath, openChipPath) {
373
- if (!openChipPath || openChipPath.length < CHIP_PATH_SUFFIX_LENGTH) {
374
- return null;
375
- }
376
- if (!pathsEqual(parentGroupPath(openChipPath), groupPath)) {
377
- return null;
378
- }
379
- const lastKey = openChipPath.at(-1);
380
- return typeof lastKey === 'number' ? lastKey : null;
381
- }
382
-
383
- const GroupNodeView = ({ node, path, isNegated, ctx }) => {
384
- const groupBasePath = isNegated ? [...path, 'rule'] : path;
385
- const issuesHere = isNegated
386
- ? [
387
- ...issuesAt(ctx.issues, path),
388
- ...issuesAt(ctx.issues, groupBasePath),
389
- ]
390
- : issuesAt(ctx.issues, path);
391
- const chipChildren = [];
392
- const nestedGroups = [];
393
- for (const [index, child] of node.rules.entries()) {
394
- const extracted = extractRef(child);
395
- if (extracted) {
396
- chipChildren.push(Object.assign(Object.assign({}, extracted), { index }));
397
- }
398
- else {
399
- nestedGroups.push({ child, index });
400
- }
401
- }
402
- const options = combinatorOptions(ctx);
403
- const selectedCombinator = options.find((option) => option.value === node.type);
404
- return (index.h("div", { class: nodeClasses(node.type, issuesHere), key: pathKey(path) }, index.h("div", { class: "rule-node__header" }, index.h("limel-select", { class: "rule-node__combinator-select", value: selectedCombinator, options: options, disabled: !ctx.isMutable, onChange: combinatorChangeHandler(node, path, isNegated, ctx) }), renderMutableGroupActions(node, path, isNegated, ctx)), index.h("div", { class: "rule-node__body" }, index.h(IssuesView, { issues: issuesHere }), index.h(GroupChipsView, { groupNode: node, groupPath: groupBasePath, chipChildren: chipChildren, ctx: ctx }), renderNestedGroups(nestedGroups, groupBasePath, ctx), renderAddGroupFooter(node, path, isNegated, ctx))));
405
- };
406
- function pathKey(path) {
407
- return path.length === 0 ? 'root' : path.join('/');
408
- }
409
- function combinatorOptions(ctx) {
410
- return [
411
- {
412
- value: 'all',
413
- text: ctx.translator.get('webclient.combinator.all'),
414
- },
415
- {
416
- value: 'any',
417
- text: ctx.translator.get('webclient.combinator.any'),
418
- },
419
- ];
420
- }
421
- function renderMutableGroupActions(node, path, isNegated, ctx) {
422
- if (!ctx.isMutable) {
423
- return null;
424
- }
425
- return (index.h("div", { class: "rule-node__header-actions" }, index.h("limel-switch", { class: "rule-node__negate-switch", label: ctx.translator.get('webclient.negate'), value: isNegated, onChange: negateGroupHandler(node, path, ctx) }), index.h("limel-icon-button", { icon: "trash", label: ctx.translator.get('webclient.rule-editor.delete'), onClick: () => ctx.onDelete(path) })));
426
- }
427
- function renderNestedGroups(nestedGroups, groupBasePath, ctx) {
428
- if (nestedGroups.length === 0) {
429
- return null;
430
- }
431
- return (index.h("div", { class: "rule-node__children" }, nestedGroups.map((entry) => (index.h(RuleNodeView, { node: entry.child, path: [...groupBasePath, 'rules', entry.index], ctx: ctx })))));
432
- }
433
- function renderAddGroupFooter(node, path, isNegated, ctx) {
434
- if (!ctx.isMutable) {
435
- return null;
436
- }
437
- return (index.h("div", { class: "rule-node__footer" }, index.h("limel-button", { icon: "add", label: ctx.translator.get('webclient.rule-editor.add-nested-group'), onClick: addGroupHandler(node, path, isNegated, ctx) })));
438
- }
439
- function replaceGroup(nextGroup, path, isNegated, ctx) {
440
- ctx.onReplaceNode(path, wrapNegated(nextGroup, isNegated));
441
- }
442
- const combinatorChangeHandler = (node, path, isNegated, ctx) => (event) => {
443
- event.stopPropagation();
444
- const newType = event.detail.value;
445
- if (newType !== node.type) {
446
- replaceGroup(Object.assign(Object.assign({}, node), { type: newType }), path, isNegated, ctx);
447
- }
448
- };
449
- const addGroupHandler = (node, path, isNegated, ctx) => () => {
450
- const expanded = appendChild(node, { type: 'all', rules: [] });
451
- replaceGroup(expanded, path, isNegated, ctx);
452
- };
453
- const negateGroupHandler = (node, path, ctx) => (event) => {
454
- event.stopPropagation();
455
- ctx.onReplaceNode(path, wrapNegated(node, event.detail));
456
- };
457
-
458
- /**
459
- * Render a `Rule` node and recurse into its children.
460
- * @param props
461
- */
462
- const RuleNodeView = (props) => {
463
- const { node, path, ctx } = props;
464
- const group = extractGroup(node);
465
- if (!group) {
466
- return null;
467
- }
468
- return (index.h(GroupNodeView, { node: group.node, path: path, isNegated: group.isNegated, ctx: ctx }));
469
- };
470
- const isNegatedGroup = (node) => node.type === 'not' &&
471
- (node.rule.type === 'all' || node.rule.type === 'any');
472
- /**
473
- * If `node` is a group (`all`/`any`) or a negated group, return the
474
- * inner group together with its negation flag. Otherwise `null`.
475
- * Used by the dispatcher and by the editor's input normalization.
476
- * @param node
477
- */
478
- function extractGroup(node) {
479
- if (node.type === 'all' || node.type === 'any') {
480
- return { node, isNegated: false };
481
- }
482
- if (isNegatedGroup(node)) {
483
- return { node: node.rule, isNegated: true };
484
- }
485
- if (node.type === 'not') {
486
- const inner = extractGroup(node.rule);
487
- if (inner) {
488
- return { node: inner.node, isNegated: !inner.isNegated };
489
- }
490
- }
491
- return null;
492
- }
493
- const IssuesView = ({ issues }) => {
494
- if (issues.length === 0) {
495
- return null;
496
- }
497
- return issues.map((issue) => (index.h("div", { class: "rule-node__issue" }, issue.message)));
498
- };
499
-
500
163
  /**
501
164
  * The shared string each mode is labelled from. Adverbs answering "when
502
165
  * does this apply?", so they carry no rule-editor namespace and are
@@ -529,7 +192,7 @@ const RuleModeView = (props) => {
529
192
  } }));
530
193
  };
531
194
 
532
- const ruleEditorCss = () => `@charset "UTF-8";:host{display:block;position:relative}.limel-notched-outline{--limel-notched-outline-background-color:transparent;padding:0.5rem 0 0 0}limel-notched-outline:not([invalid]:not([invalid=false])) .limel-notched-outline{--limel-notched-outline-border-color:transparent}.rule-editor--disabled{opacity:0.6;pointer-events:none}.rule-node{border:1px solid rgb(var(--contrast-500));border-radius:0.5rem;margin:0.25rem 0;overflow:hidden;background-color:rgb(var(--contrast-100))}.rule-node--invalid{border-color:rgb(var(--color-red-default))}.rule-node--all>.rule-node__header,.rule-node--any>.rule-node__header{background-color:rgb(var(--contrast-300));padding:0.375rem 0.75rem;border-bottom:1px solid rgb(var(--contrast-500))}.rule-node__header{display:flex;align-items:center;gap:0.5rem}.rule-node__header-actions{margin-left:auto;display:grid;grid-auto-flow:column;grid-gap:0.5rem;padding:0.125rem;align-items:center}.rule-node__combinator-select{min-width:6rem}.rule-node__body{padding:0.75rem;display:flex;flex-direction:column;gap:0.75rem}limel-popover.rule-node__chips-popover{display:contents;--popover-surface-width:min(calc(100vw - 4rem), 50rem)}.rule-node__chips{display:block;width:100%}.rule-node__chips limel-picker{display:block;width:100%}.rule-node__children{display:flex;flex-direction:column;gap:0.5rem}.rule-node__footer{display:flex;justify-content:center}.rule-node__issue{color:rgb(var(--color-red-default));font-size:0.875rem}:host(limebb-rule-editor:focus),:host(limebb-rule-editor:focus-visible),:host(limebb-rule-editor:focus-within){--limel-h-l-grid-template-rows-transition-speed:0.46s;--limel-h-l-grid-template-rows:1fr}:host(limebb-rule-editor){--limel-h-l-grid-template-rows-transition-speed:0.3s;--limel-h-l-grid-template-rows:0fr}:host(limebb-rule-editor:focus) limel-helper-line,:host(limebb-rule-editor:focus-visible) limel-helper-line,:host(limebb-rule-editor:focus-within) limel-helper-line,:host(limebb-rule-editor:hover) limel-helper-line{will-change:grid-template-rows}limel-help{position:absolute;top:calc(var(--form-row-gap, 1rem) * -0.5);left:calc(var(--form-column-gap, 1rem) * -0.5);z-index:1}`;
195
+ const ruleEditorCss = () => `@charset "UTF-8";:host{display:block;position:relative}.limel-notched-outline{--limel-notched-outline-background-color:transparent;padding:0.5rem 0 0 0}limel-notched-outline:not([invalid]:not([invalid=false])) .limel-notched-outline{--limel-notched-outline-border-color:transparent}.rule-editor--disabled{opacity:0.6;pointer-events:none}limebb-condition-tree{--popover-surface-width:min(calc(100vw - 4rem), 50rem)}:host(limebb-rule-editor:focus),:host(limebb-rule-editor:focus-visible),:host(limebb-rule-editor:focus-within){--limel-h-l-grid-template-rows-transition-speed:0.46s;--limel-h-l-grid-template-rows:1fr}:host(limebb-rule-editor){--limel-h-l-grid-template-rows-transition-speed:0.3s;--limel-h-l-grid-template-rows:0fr}:host(limebb-rule-editor:focus) limel-helper-line,:host(limebb-rule-editor:focus-visible) limel-helper-line,:host(limebb-rule-editor:focus-within) limel-helper-line,:host(limebb-rule-editor:hover) limel-helper-line{will-change:grid-template-rows}limel-help{position:absolute;top:calc(var(--form-row-gap, 1rem) * -0.5);left:calc(var(--form-column-gap, 1rem) * -0.5);z-index:1}`;
533
196
 
534
197
  var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
535
198
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -545,8 +208,6 @@ const RuleEditor = class {
545
208
  constructor(hostRef) {
546
209
  index.registerInstance(this, hostRef);
547
210
  this.change = index.createEvent(this, "change");
548
- this.issues = [];
549
- this.openChipPath = null;
550
211
  /**
551
212
  * The mode the author last clicked, held until `value` reads back
552
213
  * as it.
@@ -557,10 +218,27 @@ const RuleEditor = class {
557
218
  * what the author just clicked.
558
219
  */
559
220
  this.modeOverride = null;
560
- this.focusOnOpen = false;
561
221
  this.metadataById = new Map();
562
- this.allPrimitiveOptions = [];
222
+ /**
223
+ * How each registered primitive reads, by id. Translated once here
224
+ * because the platform's translator parses the message afresh on
225
+ * every call, and the adapter would otherwise do that per condition,
226
+ * several times over, on every edit.
227
+ */
228
+ this.primitiveTitles = new Map();
563
229
  this.availablePrimitiveOptions = [];
230
+ this.searcher = createSearcher([]);
231
+ /**
232
+ * What validation found, by the node it belongs to.
233
+ */
234
+ this.issuesByNode = new Map();
235
+ /**
236
+ * The conditions added here rather than loaded, which a `RuleRef`
237
+ * does not record. The adapter reads it to decide which condition
238
+ * opens itself. Replaced when the tree goes, since a condition still
239
+ * listed when the author comes back would open itself again.
240
+ */
241
+ this.created = new WeakSet();
564
242
  this.reachableSlots = new Set();
565
243
  this.normalizedCache = null;
566
244
  this.hasLoaded = false;
@@ -574,6 +252,9 @@ const RuleEditor = class {
574
252
  * conditions are gone, rather than handing back the ones they
575
253
  * removed. With nothing stashed, `conditional` emits no rule, which
576
254
  * is how the editor already says "the author cleared this".
255
+ *
256
+ * What is not stashed is which conditions had just been added, so
257
+ * that none of them opens itself again on the way back.
577
258
  * @param mode
578
259
  */
579
260
  this.handleModeChange = (mode) => {
@@ -581,32 +262,28 @@ const RuleEditor = class {
581
262
  if (this.currentMode === 'conditional') {
582
263
  this.stashedTree = this.value;
583
264
  }
265
+ if (mode !== 'conditional') {
266
+ this.created = new WeakSet();
267
+ }
584
268
  this.modeOverride = mode;
585
269
  this.change.emit((_a = ruleEditorModes.ruleForMode(mode)) !== null && _a !== void 0 ? _a : this.stashedTree);
586
270
  };
587
- this.handleDelete = (path) => {
588
- this.openChipPath = null;
589
- this.focusOnOpen = false;
590
- this.emitIfChanged(deleteNode(this.normalizedValue, path));
591
- };
592
- this.handleUpdateArgs = (path, args) => {
593
- this.emitIfChanged(updateArgs(this.normalizedValue, path, args));
594
- };
595
- this.handleReplaceNode = (path, replacement) => {
596
- const autoOpenPath = this.autoOpenPathFor(path, replacement);
597
- this.focusOnOpen = autoOpenPath !== null;
598
- if (autoOpenPath !== null) {
599
- this.openChipPath = autoOpenPath;
600
- }
601
- this.emitIfChanged(replaceNode(this.normalizedValue, path, replacement));
602
- };
603
- this.handleChipInteract = (path) => {
604
- this.openChipPath = path;
605
- this.focusOnOpen = false;
606
- };
607
- this.handlePopoverClose = () => {
608
- this.openChipPath = null;
609
- this.focusOnOpen = false;
271
+ /**
272
+ * Take in a tree the author changed. The tree reports `null` when
273
+ * the last condition goes, which for a rule means there is none —
274
+ * the same thing an emptied editor has always emitted.
275
+ *
276
+ * Editing the tree is only possible in `conditional`, so the edit
277
+ * itself records the mode: without this, a tree emptied to nothing
278
+ * would read back as the first offered mode and rewrite the setting
279
+ * under the author.
280
+ * @param event
281
+ */
282
+ this.handleTreeChange = (event) => {
283
+ var _a;
284
+ event.stopPropagation();
285
+ this.modeOverride = 'conditional';
286
+ this.change.emit((_a = event.detail) !== null && _a !== void 0 ? _a : undefined);
610
287
  };
611
288
  }
612
289
  componentWillLoad() {
@@ -617,6 +294,7 @@ const RuleEditor = class {
617
294
  this.indexMetadata();
618
295
  this.rebuildAvailableOptions();
619
296
  this.runValidation();
297
+ this.rebuildAdapter();
620
298
  }
621
299
  /**
622
300
  * Re-walk reachable slots when the editor is re-attached to the DOM,
@@ -631,6 +309,7 @@ const RuleEditor = class {
631
309
  this.computeReachableSlots();
632
310
  this.rebuildAvailableOptions();
633
311
  this.runValidation();
312
+ this.rebuildAdapter();
634
313
  }
635
314
  componentDidLoad() {
636
315
  this.hasLoaded = true;
@@ -647,7 +326,7 @@ const RuleEditor = class {
647
326
  this.rebuildFromRegistries();
648
327
  }
649
328
  render() {
650
- return (index.h(index.Host, { key: '98380987c6687ce58cca822ea2fd2f106787897b' }, this.renderHelp(), index.h("limel-notched-outline", { key: 'bbf2d6da192524c4cf8e2e616ca2dab6206a43a6', label: this.label, labelId: this.labelId, required: this.required, readonly: this.readonly, disabled: this.disabled, invalid: this.invalid, hasValue: true, hasFloatingLabel: true }, index.h("div", { key: '9e7043bae1b8f60f9ead7b0ed1874dae32944e9e', slot: "content", class: {
329
+ return (index.h(index.Host, { key: 'eb89af0c748f82d8e60b1209c4fcce3475ac2934' }, this.renderHelp(), index.h("limel-notched-outline", { key: '9d454ec87268aa9ff07776d38882365a544a64e7', label: this.label, labelId: this.labelId, required: this.required, readonly: this.readonly, disabled: this.disabled, invalid: this.invalid, hasValue: true, hasFloatingLabel: true }, index.h("div", { key: '57293e75c641d4909a4d2e1d3a3d2c20a60a4512', slot: "content", class: {
651
330
  'rule-editor': true,
652
331
  'rule-editor--disabled': this.disabled,
653
332
  }, role: "group", "aria-labelledby": this.label ? this.labelId : undefined, "aria-describedby": this.helperText ? this.helperTextId : undefined }, this.renderModes(), this.renderTree())), this.renderHelperLine()));
@@ -664,13 +343,18 @@ const RuleEditor = class {
664
343
  * The condition tree, shown unless a mode other than `conditional`
665
344
  * is selected — an unconditional rule has no conditions to show.
666
345
  * A caller offering no modes at all gets the tree, as before.
346
+ *
347
+ * An unset rule is handed over as unset, rather than as an empty
348
+ * group: the tree draws the group an author's first condition will
349
+ * land in, and drawing one here would only be a second opinion on
350
+ * what that looks like.
667
351
  */
668
352
  renderTree() {
669
353
  const mode = this.currentMode;
670
354
  if (mode && mode !== 'conditional') {
671
355
  return null;
672
356
  }
673
- return (index.h(RuleNodeView, { node: this.normalizedValue, path: [], ctx: this.createRenderContext() }));
357
+ return (index.h("limebb-condition-tree", { platform: this.platform, context: this.effectiveContext, value: this.normalizedValue, adapter: this.adapter, addOptions: this.availablePrimitiveOptions, addSearcher: this.searcher, readonly: this.readonly, disabled: this.disabled, onChange: this.handleTreeChange }));
674
358
  }
675
359
  renderHelperLine() {
676
360
  if (!this.helperText) {
@@ -684,27 +368,6 @@ const RuleEditor = class {
684
368
  }
685
369
  return index.h("limel-help", { value: this.help });
686
370
  }
687
- createRenderContext() {
688
- return {
689
- issues: this.issues,
690
- metadataById: this.metadataById,
691
- allPrimitiveOptions: this.allPrimitiveOptions,
692
- availablePrimitiveOptions: this.availablePrimitiveOptions,
693
- isMutable: !this.readonly && !this.disabled,
694
- readonly: this.readonly,
695
- disabled: this.disabled,
696
- platform: this.platform,
697
- context: this.effectiveContext,
698
- translator: this.translator,
699
- openChipPath: this.openChipPath,
700
- focusOnOpen: this.focusOnOpen,
701
- onDelete: this.handleDelete,
702
- onUpdateArgs: this.handleUpdateArgs,
703
- onReplaceNode: this.handleReplaceNode,
704
- onChipInteract: this.handleChipInteract,
705
- onPopoverClose: this.handlePopoverClose,
706
- };
707
- }
708
371
  /**
709
372
  * The mode the editor is in, or `undefined` when it offers none —
710
373
  * then it is the plain tree editor it was before modes existed.
@@ -738,51 +401,14 @@ const RuleEditor = class {
738
401
  this.modeOverride = null;
739
402
  }
740
403
  }
741
- /**
742
- * Path of a newly added chip whose primitive declares a config
743
- * component, so its args editor opens immediately on add. The new
744
- * ref is found by object identity — the picker reuses existing ref
745
- * objects and only the added chip is a fresh node — so adding a
746
- * second instance of a primitive already in the group is still
747
- * detected. Returns `null` unless exactly one ref was added and it
748
- * has an editor, leaving the open chip untouched for removals,
749
- * multi-adds, and negation.
750
- * @param path
751
- * @param replacement
752
- */
753
- autoOpenPathFor(path, replacement) {
754
- var _a;
755
- if (replacement.type !== 'all' && replacement.type !== 'any') {
756
- return null;
757
- }
758
- const previous = getNode(this.normalizedValue, path);
759
- if (previous === undefined ||
760
- (previous.type !== 'all' && previous.type !== 'any')) {
761
- return null;
762
- }
763
- const previousRefs = new Set(previous.rules
764
- .map((rule) => { var _a; return (_a = extractRef(rule)) === null || _a === void 0 ? void 0 : _a.ref; })
765
- .filter((ref) => ref !== undefined));
766
- const added = replacement.rules
767
- .map((rule, index) => {
768
- var _a;
769
- const ref = (_a = extractRef(rule)) === null || _a === void 0 ? void 0 : _a.ref;
770
- return ref && !previousRefs.has(ref) ? { ref, index } : null;
771
- })
772
- .filter((entry) => entry !== null);
773
- if (added.length !== 1) {
774
- return null;
775
- }
776
- const [{ ref, index }] = added;
777
- return ((_a = this.metadataById.get(ref.id)) === null || _a === void 0 ? void 0 : _a.configComponent)
778
- ? buildChipPath(path, index)
779
- : null;
780
- }
781
404
  indexMetadata() {
782
405
  var _a, _b, _c;
783
406
  const metadata = (_c = (_b = (_a = this.ruleRegistry).listMetadata) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : [];
784
407
  this.metadataById = new Map(metadata.map((item) => [item.id, item]));
785
- this.allPrimitiveOptions = createPrimitiveOptions(this.metadataById, this.translator);
408
+ this.primitiveTitles = new Map(metadata.map((item) => [
409
+ item.id,
410
+ primitiveTitle(item, this.translator),
411
+ ]));
786
412
  }
787
413
  /**
788
414
  * Recompute the cached add-palette options. The inputs — indexed
@@ -792,6 +418,7 @@ const RuleEditor = class {
792
418
  */
793
419
  rebuildAvailableOptions() {
794
420
  this.availablePrimitiveOptions = createPrimitiveOptions(this.availablePrimitiveMetadata(), this.translator);
421
+ this.searcher = createSearcher(this.availablePrimitiveOptions);
795
422
  }
796
423
  /**
797
424
  * The subset of registered metadata offered for adding in the
@@ -799,7 +426,7 @@ const RuleEditor = class {
799
426
  * reachable slots are dropped, and so is the always primitive —
800
427
  * it reads nothing, so it is always covered, but an "Always" chip
801
428
  * among a group's conditions says nothing. Filtering only the
802
- * palette — not the full `allPrimitiveOptions` — keeps
429
+ * palette — the adapter still reads the whole index — keeps
803
430
  * already-placed chips resolving to their proper title even when
804
431
  * their read slot isn't reachable.
805
432
  */
@@ -839,45 +466,81 @@ const RuleEditor = class {
839
466
  ]);
840
467
  }
841
468
  runValidation() {
842
- if (!this.value) {
843
- this.issues = [];
844
- return;
845
- }
846
- const result = this.ruleRegistry.validate(this.normalizedValue, [
847
- ...this.reachableSlots,
848
- ]);
849
- this.issues = result.ok ? [] : result.issues;
469
+ this.issuesByNode = this.findIssues();
850
470
  }
851
471
  /**
852
- * Emit an edited tree. Editing the tree is only possible in
853
- * `conditional`, so the edit itself records the mode: an edit that
854
- * empties the tree emits no rule, and without this the empty value
855
- * would read back as the first offered mode.
856
- * @param next
472
+ * What the registry finds wrong with the rule, gathered by the node
473
+ * each problem belongs to. Validation runs against the normalized
474
+ * rule, which is also what the tree is handed, so the paths the
475
+ * registry reports address the very nodes the tree draws.
476
+ *
477
+ * A rule the registry cannot even walk — one hand-edited into a shape
478
+ * that is not a rule — makes it throw rather than report. That is the
479
+ * rule an author most needs the editor for, so the throw is caught
480
+ * and the editor drawn anyway: the tree marks the offending condition
481
+ * unreadable itself, which is the same thing validation would have
482
+ * said and in the place it belongs.
857
483
  */
858
- emitIfChanged(next) {
859
- if (next === this.normalizedValue) {
860
- return;
484
+ findIssues() {
485
+ const root = this.normalizedValue;
486
+ if (!root) {
487
+ return new Map();
488
+ }
489
+ try {
490
+ const result = this.ruleRegistry.validate(root, [
491
+ ...this.reachableSlots,
492
+ ]);
493
+ return result.ok
494
+ ? new Map()
495
+ : collectRuleIssues(root, result.issues);
496
+ }
497
+ catch (error) {
498
+ // The throw names the node it choked on. What the author needs is
499
+ // already in the tree; this is what tells a developer an unreadable
500
+ // rule from a registry that could not answer for a readable one.
501
+ console.warn('rule-editor could not validate the rule', {
502
+ rule: root,
503
+ error,
504
+ });
505
+ return new Map();
861
506
  }
862
- this.modeOverride = 'conditional';
863
- this.change.emit(collapseEmptyRoot(next));
864
507
  }
865
508
  /**
866
- * Wrap any non-group `value` in a top-level `all` so the editor
867
- * always has a group to render against. When `value` is unset,
868
- * returns a fresh empty `all`-group as a render-only placeholder —
869
- * `emitNormalization` will *not* push that placeholder back to the
870
- * caller, so an unset value stays unset until the user edits.
509
+ * Gather what the tree draws from into a new adapter, which is how a
510
+ * change the rule does not carry reaches the screen at all.
511
+ *
512
+ * Not rebuilt for a validation pass: that runs because the rule
513
+ * changed, and the tree is already redrawing for the same reason.
514
+ * Rebuilding there would sync its open state twice for one edit.
515
+ */
516
+ rebuildAdapter() {
517
+ this.adapter = limebbRuleConditionEditor_entry.createRuleConditionTreeAdapter({
518
+ metadata: this.metadataById,
519
+ titles: this.primitiveTitles,
520
+ translate: conditionTreeTranslate.createTranslator(this.platform),
521
+ issues: () => this.issuesByNode,
522
+ created: () => this.created,
523
+ });
524
+ }
525
+ /**
526
+ * Wrap any non-group `value` in a top-level `all`, so that a lone
527
+ * condition has a group to grow in. An unset value stays unset: the
528
+ * tree draws the group a first condition will land in, and
529
+ * `emitNormalization` never pushes that placeholder back to the
530
+ * caller, so "no rule yet" stays distinguishable from "the author
531
+ * cleared this".
871
532
  *
872
533
  * An unconditional mode is the exception: its sentinel is left
873
534
  * exactly as it came in, because wrapping it would rewrite the
874
535
  * shape the mode is read back from.
875
536
  *
876
- * Memoized so callers that read this several times in one handler
877
- * see the same reference — the identity check in `emitIfChanged`
878
- * depends on it.
537
+ * Memoized, so that the tree is handed the same rule on every
538
+ * render and redraws only when the rule itself changes.
879
539
  */
880
540
  get normalizedValue() {
541
+ if (!this.value) {
542
+ return undefined;
543
+ }
881
544
  const mode = this.currentMode;
882
545
  if (this.normalizedCache !== null &&
883
546
  this.normalizedCache.source === this.value &&
@@ -944,35 +607,16 @@ const EMPTY_CONTEXT = Object.freeze({
944
607
  id: null,
945
608
  });
946
609
  function normalize(value, mode) {
947
- if (!value) {
948
- return { type: 'all', rules: [] };
949
- }
950
610
  // Neither sentinel is a group, and wrapping one would rewrite the
951
611
  // very shape the mode is read back from.
952
612
  if (mode === 'always' || mode === 'never') {
953
613
  return value;
954
614
  }
955
- if (extractGroup(value)) {
615
+ if (limebbRuleConditionEditor_entry.groupOf(value)) {
956
616
  return value;
957
617
  }
958
618
  return { type: 'all', rules: [value] };
959
619
  }
960
- /**
961
- * Treat an empty root `all`/`any` as "no rule". Mapping that back to
962
- * `undefined` on emit keeps the form contract a clean
963
- * `Rule | undefined` — callers don't have to inspect rule shape to
964
- * tell "user cleared this" from "user has a real rule". A negated
965
- * empty group (`not(all())` etc.) is left intact — vacuous either
966
- * direction, but the user explicitly opted into the wrapper, so we
967
- * don't second-guess.
968
- * @param rule
969
- */
970
- function collapseEmptyRoot(rule) {
971
- if (rule.type !== 'all' && rule.type !== 'any') {
972
- return rule;
973
- }
974
- return rule.rules.length === 0 ? undefined : rule;
975
- }
976
620
  RuleEditor.style = ruleEditorCss();
977
621
 
978
622
  exports.limebb_rule_editor = RuleEditor;