@limetech/lime-crm-building-blocks 1.125.0 → 1.126.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.
- package/CHANGELOG.md +11 -0
- package/dist/cjs/lime-crm-building-blocks.cjs.js +1 -1
- package/dist/cjs/limebb-alert-dialog.cjs.entry.js +1 -1
- package/dist/cjs/limebb-browser.cjs.entry.js +2 -2
- package/dist/cjs/limebb-chat-icon-list_3.cjs.entry.js +4 -4
- package/dist/cjs/limebb-chat-list.cjs.entry.js +1 -1
- package/dist/cjs/limebb-color-palette-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-color-palette-swatches.cjs.entry.js +1 -1
- package/dist/cjs/limebb-component-config.cjs.entry.js +2 -14
- package/dist/cjs/limebb-composer-toolbar.cjs.entry.js +3 -3
- package/dist/cjs/limebb-currency-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-dashboard-widget.cjs.entry.js +1 -1
- package/dist/cjs/limebb-date-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-date-range.cjs.entry.js +1 -1
- package/dist/cjs/limebb-document-chips.cjs.entry.js +1 -1
- package/dist/cjs/limebb-document-item.cjs.entry.js +2 -2
- package/dist/cjs/limebb-document-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-feed-item-thumbnail-file-info.cjs.entry.js +1 -1
- package/dist/cjs/limebb-feed-timeline-item.cjs.entry.js +1 -1
- package/dist/cjs/limebb-feed.cjs.entry.js +1 -1
- package/dist/cjs/limebb-icon-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-info-tile-format.cjs.entry.js +1 -1
- package/dist/cjs/limebb-info-tile.cjs.entry.js +1 -1
- package/dist/cjs/limebb-kanban-group.cjs.entry.js +1 -1
- package/dist/cjs/limebb-kanban-item.cjs.entry.js +1 -1
- package/dist/cjs/limebb-lime-query-builder.cjs.entry.js +1 -1
- package/dist/cjs/limebb-lime-query-filter-builder_3.cjs.entry.js +2 -2
- package/dist/cjs/limebb-lime-query-filter-comparison_2.cjs.entry.js +1 -1
- package/dist/cjs/limebb-lime-query-filter-group_3.cjs.entry.js +3 -3
- package/dist/cjs/limebb-lime-query-order-by-item.cjs.entry.js +2 -2
- package/dist/cjs/limebb-lime-query-response-format-builder.cjs.entry.js +1 -1
- package/dist/cjs/limebb-lime-query-response-format-editor_2.cjs.entry.js +1 -1
- package/dist/cjs/limebb-live-docs-info.cjs.entry.js +2 -2
- package/dist/cjs/limebb-locale-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-mention-group-counter.cjs.entry.js +2 -2
- package/dist/cjs/limebb-navigation-button_2.cjs.entry.js +2 -2
- package/dist/cjs/limebb-notification-item.cjs.entry.js +1 -1
- package/dist/cjs/limebb-percentage-visualizer.cjs.entry.js +2 -2
- package/dist/cjs/limebb-rule-chip-popover.cjs.entry.js +59 -0
- package/dist/cjs/limebb-rule-editor.cjs.entry.js +646 -0
- package/dist/cjs/limebb-rule-gate.cjs.entry.js +5 -1
- package/dist/cjs/limebb-text-editor.cjs.entry.js +1 -1
- package/dist/cjs/limebb-trend-indicator.cjs.entry.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/web-component-template-BWCutZB6.js +18 -0
- package/dist/collection/collection-manifest.json +2 -0
- package/dist/collection/components/alert-dialog/alert-dialog.js +1 -1
- package/dist/collection/components/browser/browser.js +2 -2
- package/dist/collection/components/chat-list/chat-icon-list/chat-icon-list.js +1 -1
- package/dist/collection/components/chat-list/chat-item/chat-item.js +2 -2
- package/dist/collection/components/chat-list/chat-list.js +1 -1
- package/dist/collection/components/chat-list/typing-indicator/typing-indicator.js +1 -1
- package/dist/collection/components/color-palette-picker/color-palette-picker.js +1 -1
- package/dist/collection/components/color-palette-picker/color-palette-swatches/color-palette-swatches.js +1 -1
- package/dist/collection/components/composer-toolbar/composer-toolbar.js +3 -3
- package/dist/collection/components/currency-picker/currency-picker.js +1 -1
- package/dist/collection/components/dashboard-widget/dashboard-widget.js +1 -1
- package/dist/collection/components/date-picker/date-picker.js +1 -1
- package/dist/collection/components/date-range/date-range.js +1 -1
- package/dist/collection/components/document-chips/document-chips.js +1 -1
- package/dist/collection/components/document-picker/document-item/document-item.js +2 -2
- package/dist/collection/components/document-picker/document-picker.js +1 -1
- package/dist/collection/components/feed/feed-item/feed-timeline-item.js +1 -1
- package/dist/collection/components/feed/feed-item-thumbnail-file-info/feed-item-thumbnail-file-info.js +1 -1
- package/dist/collection/components/feed/feed.js +1 -1
- package/dist/collection/components/icon-picker/icon-picker.js +1 -1
- package/dist/collection/components/info-tile/format/config/info-tile-format.js +1 -1
- package/dist/collection/components/info-tile/info-tile.js +1 -1
- package/dist/collection/components/kanban/kanban-group/kanban-group.js +1 -1
- package/dist/collection/components/kanban/kanban-item/kanban-item.js +1 -1
- package/dist/collection/components/lime-query-builder/expressions/lime-query-filter-comparison.js +1 -1
- package/dist/collection/components/lime-query-builder/expressions/lime-query-filter-group.js +2 -2
- package/dist/collection/components/lime-query-builder/expressions/lime-query-filter-not.js +1 -1
- package/dist/collection/components/lime-query-builder/lime-query-builder.js +1 -1
- package/dist/collection/components/lime-query-builder/lime-query-response-format-builder.js +1 -1
- package/dist/collection/components/lime-query-builder/limetype-field/limetype-field.js +1 -1
- package/dist/collection/components/lime-query-builder/order-by/order-by-editor.js +1 -1
- package/dist/collection/components/lime-query-builder/order-by/order-by-item.js +2 -2
- package/dist/collection/components/lime-query-builder/response-format/response-format-item.js +1 -1
- package/dist/collection/components/limeobject/file-viewer/live-docs-info.js +2 -2
- package/dist/collection/components/locale-picker/locale-picker.js +1 -1
- package/dist/collection/components/notification-list/notification-item/notification-item.js +1 -1
- package/dist/collection/components/percentage-visualizer/percentage-visualizer.js +2 -2
- package/dist/collection/components/rule-editor/chip-picker-view.js +141 -0
- package/dist/collection/components/rule-editor/group-node-view.js +79 -0
- package/dist/collection/components/rule-editor/rule-chip-popover/rule-chip-popover.css +36 -0
- package/dist/collection/components/rule-editor/rule-chip-popover/rule-chip-popover.js +301 -0
- package/dist/collection/components/rule-editor/rule-editor-views.js +43 -0
- package/dist/collection/components/rule-editor/rule-editor.css +96 -0
- package/dist/collection/components/rule-editor/rule-editor.js +457 -0
- package/dist/collection/components/rule-editor/rule-operations.js +132 -0
- package/dist/collection/components/rule-editor/view-helpers.js +70 -0
- package/dist/collection/components/rule-gate/rule-gate.js +9 -4
- package/dist/collection/components/summary-popover/summary-popover.js +2 -2
- package/dist/collection/components/text-editor/mention-group-counter.js +2 -2
- package/dist/collection/components/text-editor/text-editor.js +1 -1
- package/dist/collection/components/trend-indicator/trend-indicator.js +1 -1
- package/dist/components/chat-icon-list.js +1 -1
- package/dist/components/chat-item.js +1 -1
- package/dist/components/currency-picker.js +1 -1
- package/dist/components/date-picker.js +1 -1
- package/dist/components/document-item.js +1 -1
- package/dist/components/feed-item-thumbnail-file-info.js +1 -1
- package/dist/components/feed-timeline-item.js +1 -1
- package/dist/components/kanban-group.js +1 -1
- package/dist/components/kanban-item.js +1 -1
- package/dist/components/lime-query-filter-comparison.js +1 -1
- package/dist/components/lime-query-filter-expression.js +1 -1
- package/dist/components/limebb-alert-dialog.js +1 -1
- package/dist/components/limebb-browser.js +1 -1
- package/dist/components/limebb-chat-list.js +1 -1
- package/dist/components/limebb-color-palette-picker.js +1 -1
- package/dist/components/limebb-color-palette-swatches.js +1 -1
- package/dist/components/limebb-component-config.js +1 -1
- package/dist/components/limebb-composer-toolbar.js +1 -1
- package/dist/components/limebb-dashboard-widget.js +1 -1
- package/dist/components/limebb-date-range.js +1 -1
- package/dist/components/limebb-document-chips.js +1 -1
- package/dist/components/limebb-document-picker.js +1 -1
- package/dist/components/limebb-feed.js +1 -1
- package/dist/components/limebb-icon-picker.js +1 -1
- package/dist/components/limebb-info-tile-format.js +1 -1
- package/dist/components/limebb-info-tile.js +1 -1
- package/dist/components/limebb-lime-query-builder.js +1 -1
- package/dist/components/limebb-lime-query-response-format-builder.js +1 -1
- package/dist/components/limebb-locale-picker.js +1 -1
- package/dist/components/limebb-mention-group-counter.js +1 -1
- package/dist/components/limebb-rule-chip-popover.d.ts +11 -0
- package/dist/components/limebb-rule-chip-popover.js +1 -0
- package/dist/components/limebb-rule-editor.d.ts +11 -0
- package/dist/components/limebb-rule-editor.js +1 -0
- package/dist/components/limebb-rule-gate.js +1 -1
- package/dist/components/limebb-text-editor.js +1 -1
- package/dist/components/limebb-trend-indicator.js +1 -1
- package/dist/components/limetype-field.js +1 -1
- package/dist/components/live-docs-info.js +1 -1
- package/dist/components/notification-item.js +1 -1
- package/dist/components/order-by-editor.js +1 -1
- package/dist/components/order-by-item.js +1 -1
- package/dist/components/percentage-visualizer.js +1 -1
- package/dist/components/response-format-item.js +1 -1
- package/dist/components/rule-chip-popover.js +1 -0
- package/dist/components/summary-popover.js +1 -1
- package/dist/components/typing-indicator.js +1 -1
- package/dist/components/web-component-template.js +1 -0
- package/dist/esm/lime-crm-building-blocks.js +1 -1
- package/dist/esm/limebb-alert-dialog.entry.js +1 -1
- package/dist/esm/limebb-browser.entry.js +2 -2
- package/dist/esm/limebb-chat-icon-list_3.entry.js +4 -4
- package/dist/esm/limebb-chat-list.entry.js +1 -1
- package/dist/esm/limebb-color-palette-picker.entry.js +1 -1
- package/dist/esm/limebb-color-palette-swatches.entry.js +1 -1
- package/dist/esm/limebb-component-config.entry.js +2 -14
- package/dist/esm/limebb-composer-toolbar.entry.js +3 -3
- package/dist/esm/limebb-currency-picker.entry.js +1 -1
- package/dist/esm/limebb-dashboard-widget.entry.js +1 -1
- package/dist/esm/limebb-date-picker.entry.js +1 -1
- package/dist/esm/limebb-date-range.entry.js +1 -1
- package/dist/esm/limebb-document-chips.entry.js +1 -1
- package/dist/esm/limebb-document-item.entry.js +2 -2
- package/dist/esm/limebb-document-picker.entry.js +1 -1
- package/dist/esm/limebb-feed-item-thumbnail-file-info.entry.js +1 -1
- package/dist/esm/limebb-feed-timeline-item.entry.js +1 -1
- package/dist/esm/limebb-feed.entry.js +1 -1
- package/dist/esm/limebb-icon-picker.entry.js +1 -1
- package/dist/esm/limebb-info-tile-format.entry.js +1 -1
- package/dist/esm/limebb-info-tile.entry.js +1 -1
- package/dist/esm/limebb-kanban-group.entry.js +1 -1
- package/dist/esm/limebb-kanban-item.entry.js +1 -1
- package/dist/esm/limebb-lime-query-builder.entry.js +1 -1
- package/dist/esm/limebb-lime-query-filter-builder_3.entry.js +2 -2
- package/dist/esm/limebb-lime-query-filter-comparison_2.entry.js +1 -1
- package/dist/esm/limebb-lime-query-filter-group_3.entry.js +3 -3
- package/dist/esm/limebb-lime-query-order-by-item.entry.js +2 -2
- package/dist/esm/limebb-lime-query-response-format-builder.entry.js +1 -1
- package/dist/esm/limebb-lime-query-response-format-editor_2.entry.js +1 -1
- package/dist/esm/limebb-live-docs-info.entry.js +2 -2
- package/dist/esm/limebb-locale-picker.entry.js +1 -1
- package/dist/esm/limebb-mention-group-counter.entry.js +2 -2
- package/dist/esm/limebb-navigation-button_2.entry.js +2 -2
- package/dist/esm/limebb-notification-item.entry.js +1 -1
- package/dist/esm/limebb-percentage-visualizer.entry.js +2 -2
- package/dist/esm/limebb-rule-chip-popover.entry.js +57 -0
- package/dist/esm/limebb-rule-editor.entry.js +644 -0
- package/dist/esm/limebb-rule-gate.entry.js +5 -1
- package/dist/esm/limebb-text-editor.entry.js +1 -1
- package/dist/esm/limebb-trend-indicator.entry.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/web-component-template-6zRYia86.js +16 -0
- package/dist/lime-crm-building-blocks/lime-crm-building-blocks.esm.js +1 -1
- package/dist/lime-crm-building-blocks/{p-f3c412b3.entry.js → p-057e1638.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-b35ebf4d.entry.js → p-0c572fe9.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-8b11a02c.entry.js → p-11494f30.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-fc1aec12.entry.js → p-1747221f.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/p-1831e571.entry.js +1 -0
- package/dist/lime-crm-building-blocks/{p-a4584260.entry.js → p-184ae23d.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-0be33708.entry.js → p-20206710.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-fa7597f7.entry.js → p-24fc049c.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-900b74c0.entry.js → p-277b6ad4.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-b74fe1ed.entry.js → p-2cb31064.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-c93314a6.entry.js → p-3313e357.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-593340d9.entry.js → p-3781a766.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-a3d4f2e1.entry.js → p-43a7facd.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-152b4f92.entry.js → p-6cceabf1.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-c5f0582c.entry.js → p-6d3a9ed3.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-b5d84fff.entry.js → p-71a6f624.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-4c255e2f.entry.js → p-731820f0.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/p-74455a30.entry.js +1 -0
- package/dist/lime-crm-building-blocks/p-7922726c.entry.js +1 -0
- package/dist/lime-crm-building-blocks/{p-f3ba4ed1.entry.js → p-7a125570.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-5c420ada.entry.js → p-7d51a34c.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-f04ca19d.entry.js → p-7fee7ef3.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-a27e9bbb.entry.js → p-8084e825.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-6a27184b.entry.js → p-861ac606.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-b4ae3ed3.entry.js → p-8d3fa274.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-70957bab.entry.js → p-9f7992b0.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/p-C_tMNOSt.js +1 -0
- package/dist/lime-crm-building-blocks/{p-6941de0b.entry.js → p-abcb1e49.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-9041e7aa.entry.js → p-b1a8d1a0.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/p-b8d9ff68.entry.js +1 -0
- package/dist/lime-crm-building-blocks/{p-8f70f909.entry.js → p-bec4231f.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-8e6446b5.entry.js → p-c139ab98.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-e84ff80f.entry.js → p-c4f41ec4.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-24004bf3.entry.js → p-c609b5ec.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-ebd152ab.entry.js → p-c6a913af.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-c60673a4.entry.js → p-dd38e0ba.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-53b19393.entry.js → p-de6f4670.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-fc6d9cea.entry.js → p-e6ed33ff.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/p-e717bdff.entry.js +1 -0
- package/dist/lime-crm-building-blocks/{p-da248a53.entry.js → p-ef62c7d8.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-23188fe0.entry.js → p-f0a567f3.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-befd1d3c.entry.js → p-fd6dcfe3.entry.js} +1 -1
- package/dist/types/components/rule-editor/chip-picker-view.d.ts +27 -0
- package/dist/types/components/rule-editor/group-node-view.d.ts +11 -0
- package/dist/types/components/rule-editor/rule-chip-popover/rule-chip-popover.d.ts +31 -0
- package/dist/types/components/rule-editor/rule-editor-views.d.ts +51 -0
- package/dist/types/components/rule-editor/rule-editor.d.ts +118 -0
- package/dist/types/components/rule-editor/rule-operations.d.ts +62 -0
- package/dist/types/components/rule-editor/view-helpers.d.ts +40 -0
- package/dist/types/components/rule-gate/rule-gate.d.ts +5 -2
- package/dist/types/components.d.ts +300 -6
- package/package.json +4 -4
- package/dist/lime-crm-building-blocks/p-4a93a4df.entry.js +0 -1
- package/dist/lime-crm-building-blocks/p-6318fd46.entry.js +0 -1
- package/dist/lime-crm-building-blocks/p-e3a3c291.entry.js +0 -1
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var index = require('./index-C_OnxXhP.js');
|
|
4
|
+
var index_esm = require('./index.esm-QC7n_5ug.js');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Remove the node at `path`.
|
|
8
|
+
*
|
|
9
|
+
* Removing the root yields an empty `all`-group so the tree always has
|
|
10
|
+
* something to render. Returns `rule` unchanged when `path` does not
|
|
11
|
+
* address a removable node.
|
|
12
|
+
* @param rule
|
|
13
|
+
* @param path
|
|
14
|
+
*/
|
|
15
|
+
function deleteNode(rule, path) {
|
|
16
|
+
if (path.length === 0) {
|
|
17
|
+
return { type: 'all', rules: [] };
|
|
18
|
+
}
|
|
19
|
+
const parentPath = path.slice(0, -1);
|
|
20
|
+
const key = path.at(-1);
|
|
21
|
+
const parent = getNode(rule, parentPath);
|
|
22
|
+
if ((parent.type === 'all' || parent.type === 'any') &&
|
|
23
|
+
typeof key === 'number') {
|
|
24
|
+
const rules = [...parent.rules];
|
|
25
|
+
rules.splice(key, 1);
|
|
26
|
+
return replaceAt(rule, parentPath, Object.assign(Object.assign({}, parent), { rules }));
|
|
27
|
+
}
|
|
28
|
+
if (parent.type === 'not' && key === 'rule') {
|
|
29
|
+
return replaceAt(rule, parentPath, { type: 'all', rules: [] });
|
|
30
|
+
}
|
|
31
|
+
return rule;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Replace the `args` of a `ref` node. Returns `rule` unchanged when
|
|
35
|
+
* `path` does not resolve to a `ref`.
|
|
36
|
+
* @param rule
|
|
37
|
+
* @param path
|
|
38
|
+
* @param args
|
|
39
|
+
*/
|
|
40
|
+
function updateArgs(rule, path, args) {
|
|
41
|
+
const node = getNode(rule, path);
|
|
42
|
+
if (node.type !== 'ref') {
|
|
43
|
+
return rule;
|
|
44
|
+
}
|
|
45
|
+
return replaceAt(rule, path, Object.assign(Object.assign({}, node), { args }));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Replace the node at `path` with `replacement`, returning a new rule
|
|
49
|
+
* tree. Used by callers that need to apply a non-atomic change as a
|
|
50
|
+
* single emit (e.g. updating a group's whole `rules` array at once).
|
|
51
|
+
* @param rule
|
|
52
|
+
* @param path
|
|
53
|
+
* @param replacement
|
|
54
|
+
*/
|
|
55
|
+
function replaceNode(rule, path, replacement) {
|
|
56
|
+
return replaceAt(rule, path, replacement);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Wrap `group` in a `not` when `isNegated`, otherwise return it
|
|
60
|
+
* unchanged. Used when re-emitting a group whose negation flag should
|
|
61
|
+
* be preserved.
|
|
62
|
+
* @param group
|
|
63
|
+
* @param isNegated
|
|
64
|
+
*/
|
|
65
|
+
function wrapNegated(group, isNegated) {
|
|
66
|
+
return isNegated ? { type: 'not', rule: group } : group;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Append `child` to a group's `rules`, returning a new group. The
|
|
70
|
+
* input is not mutated.
|
|
71
|
+
* @param group
|
|
72
|
+
* @param child
|
|
73
|
+
*/
|
|
74
|
+
function appendChild(group, child) {
|
|
75
|
+
return Object.assign(Object.assign({}, group), { rules: [...group.rules, child] });
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Structural equality on two paths.
|
|
79
|
+
* @param a
|
|
80
|
+
* @param b
|
|
81
|
+
*/
|
|
82
|
+
function pathsEqual(a, b) {
|
|
83
|
+
if (a.length !== b.length) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return a.every((value, index) => value === b[index]);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Filter validation issues to those whose `path` matches `path`.
|
|
90
|
+
* @param issues
|
|
91
|
+
* @param path
|
|
92
|
+
*/
|
|
93
|
+
function issuesAt(issues, path) {
|
|
94
|
+
return issues.filter((issue) => pathsEqual(issue.path, path));
|
|
95
|
+
}
|
|
96
|
+
function getNode(rule, path) {
|
|
97
|
+
let node = rule;
|
|
98
|
+
for (const key of path) {
|
|
99
|
+
node = stepIntoNode(node, key);
|
|
100
|
+
}
|
|
101
|
+
return node;
|
|
102
|
+
}
|
|
103
|
+
function replaceAt(root, path, replacement) {
|
|
104
|
+
if (path.length === 0) {
|
|
105
|
+
return replacement;
|
|
106
|
+
}
|
|
107
|
+
const [head, ...tail] = path;
|
|
108
|
+
if (root.type === 'not' && head === 'rule') {
|
|
109
|
+
return Object.assign(Object.assign({}, root), { rule: replaceAt(root.rule, tail, replacement) });
|
|
110
|
+
}
|
|
111
|
+
if ((root.type === 'all' || root.type === 'any') && head === 'rules') {
|
|
112
|
+
if (tail.length === 0) {
|
|
113
|
+
return replacement;
|
|
114
|
+
}
|
|
115
|
+
const [index, ...rest] = tail;
|
|
116
|
+
if (typeof index !== 'number') {
|
|
117
|
+
return root;
|
|
118
|
+
}
|
|
119
|
+
const rules = [...root.rules];
|
|
120
|
+
rules[index] = replaceAt(rules[index], rest, replacement);
|
|
121
|
+
return Object.assign(Object.assign({}, root), { rules });
|
|
122
|
+
}
|
|
123
|
+
return root;
|
|
124
|
+
}
|
|
125
|
+
function stepIntoNode(node, key) {
|
|
126
|
+
if (node.type === 'not' && key === 'rule') {
|
|
127
|
+
return node.rule;
|
|
128
|
+
}
|
|
129
|
+
if ((node.type === 'all' || node.type === 'any') && key === 'rules') {
|
|
130
|
+
return node;
|
|
131
|
+
}
|
|
132
|
+
if ((node.type === 'all' || node.type === 'any') &&
|
|
133
|
+
typeof key === 'number') {
|
|
134
|
+
return node.rules[key];
|
|
135
|
+
}
|
|
136
|
+
return node;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const UNKNOWN_ICON = {
|
|
140
|
+
name: 'question',
|
|
141
|
+
color: 'rgb(var(--color-glaucous-light))',
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Class map for a rule-node container. Adds the type modifier and an
|
|
145
|
+
* `invalid` flag when validation issues attach to this node.
|
|
146
|
+
* @param type
|
|
147
|
+
* @param issues
|
|
148
|
+
*/
|
|
149
|
+
function nodeClasses(type, issues) {
|
|
150
|
+
return {
|
|
151
|
+
'rule-node': true,
|
|
152
|
+
[`rule-node--${type}`]: true,
|
|
153
|
+
'rule-node--invalid': issues.length > 0,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Build the searchable list shown by the primitive pickers. Cached on
|
|
158
|
+
* the render context so it isn't recomputed per node.
|
|
159
|
+
* @param metadataById
|
|
160
|
+
*/
|
|
161
|
+
function createPrimitiveOptions(metadataById) {
|
|
162
|
+
return [...metadataById.values()]
|
|
163
|
+
.map((meta) => {
|
|
164
|
+
var _a, _b;
|
|
165
|
+
return ({
|
|
166
|
+
value: meta.id,
|
|
167
|
+
text: (_a = meta.title) !== null && _a !== void 0 ? _a : meta.id,
|
|
168
|
+
secondaryText: (_b = meta.description) !== null && _b !== void 0 ? _b : '',
|
|
169
|
+
icon: meta.icon,
|
|
170
|
+
});
|
|
171
|
+
})
|
|
172
|
+
.sort((a, b) => a.text.localeCompare(b.text));
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Find the picker item for `id`, falling back to a placeholder marked
|
|
176
|
+
* with the unknown-primitive icon when the id isn't in the registry.
|
|
177
|
+
* @param allItems
|
|
178
|
+
* @param id
|
|
179
|
+
*/
|
|
180
|
+
function resolveItem(allItems, id) {
|
|
181
|
+
var _a;
|
|
182
|
+
return ((_a = allItems.find((item) => item.value === id)) !== null && _a !== void 0 ? _a : {
|
|
183
|
+
value: id,
|
|
184
|
+
text: id,
|
|
185
|
+
icon: UNKNOWN_ICON,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Build a picker `searcher` bound to a fixed item list. Both the ref
|
|
190
|
+
* picker and the chip picker want exactly this — wrapping
|
|
191
|
+
* {@link searchItems} in a promise — and deserve to share it.
|
|
192
|
+
* @param items
|
|
193
|
+
*/
|
|
194
|
+
function createSearcher(items) {
|
|
195
|
+
return (query) => Promise.resolve(searchItems(items, query));
|
|
196
|
+
}
|
|
197
|
+
function searchItems(allItems, query) {
|
|
198
|
+
if (!query) {
|
|
199
|
+
return allItems;
|
|
200
|
+
}
|
|
201
|
+
const parts = query.toLocaleLowerCase().split(/\s+/);
|
|
202
|
+
return allItems.filter((item) => parts.every((part) => {
|
|
203
|
+
var _a, _b;
|
|
204
|
+
return item.text.toLocaleLowerCase().includes(part) ||
|
|
205
|
+
((_a = item.secondaryText) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase().includes(part)) ||
|
|
206
|
+
((_b = item.value) === null || _b === void 0 ? void 0 : _b.toLocaleLowerCase().includes(part));
|
|
207
|
+
}));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const CHIP_TOKEN_PREFIX = '__chip__:';
|
|
211
|
+
function chipTokenFor(index) {
|
|
212
|
+
return `${CHIP_TOKEN_PREFIX}${index}`;
|
|
213
|
+
}
|
|
214
|
+
// The address of a chip inside a group is the group's path followed
|
|
215
|
+
// by a two-segment suffix `['rules', index]`. Build and parse via
|
|
216
|
+
// these helpers so both sides stay in sync.
|
|
217
|
+
const CHIP_PATH_SUFFIX_LENGTH = 2;
|
|
218
|
+
function buildChipPath(groupPath, index) {
|
|
219
|
+
return [...groupPath, 'rules', index];
|
|
220
|
+
}
|
|
221
|
+
function parentGroupPath(chipPath) {
|
|
222
|
+
return chipPath.slice(0, -CHIP_PATH_SUFFIX_LENGTH);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* If `node` is a `ref` or a `not(ref)`, return the underlying ref
|
|
226
|
+
* together with its negation flag. Used to decide whether a child of a
|
|
227
|
+
* group renders as a chip (this returns non-null) or as a nested box
|
|
228
|
+
* (this returns null).
|
|
229
|
+
* @param node
|
|
230
|
+
*/
|
|
231
|
+
function extractRef(node) {
|
|
232
|
+
if (node.type === 'ref') {
|
|
233
|
+
return { ref: node, isNegated: false };
|
|
234
|
+
}
|
|
235
|
+
if (node.type === 'not' && node.rule.type === 'ref') {
|
|
236
|
+
return { ref: node.rule, isNegated: true };
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
const GroupChipsView = ({ groupNode, groupPath, chipChildren, ctx }) => {
|
|
241
|
+
const chipsByToken = new Map();
|
|
242
|
+
const value = chipChildren.map((entry) => {
|
|
243
|
+
const token = chipTokenFor(entry.index);
|
|
244
|
+
chipsByToken.set(token, entry);
|
|
245
|
+
const base = resolveItem(ctx.primitiveOptions, entry.ref.id);
|
|
246
|
+
return Object.assign(Object.assign({}, base), { text: entry.isNegated ? `¬ ${base.text}` : base.text, value: token });
|
|
247
|
+
});
|
|
248
|
+
const searcher = createSearcher(ctx.primitiveOptions);
|
|
249
|
+
const openChip = findOpenChip(chipChildren, groupPath, ctx.openChipPath);
|
|
250
|
+
const delimiter = groupNode.type === 'all' ? '&' : '|';
|
|
251
|
+
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))));
|
|
252
|
+
};
|
|
253
|
+
function renderChipPopoverContent(openChip, groupPath, ctx) {
|
|
254
|
+
if (!openChip) {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
const openChipPath = buildChipPath(groupPath, openChip.index);
|
|
258
|
+
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, onNegate: chipNegateHandler(openChip, openChipPath, ctx), onUpdateArgs: chipArgsHandler(openChip, openChipPath, ctx), onDeleteChip: chipDeleteHandler(openChipPath, ctx) }));
|
|
259
|
+
}
|
|
260
|
+
const chipsChangeHandler = (groupNode, groupPath, chipsByToken, ctx) => (event) => {
|
|
261
|
+
event.stopPropagation();
|
|
262
|
+
const items = Array.isArray(event.detail) ? event.detail : [];
|
|
263
|
+
const openIndex = openChipIndexInGroup(groupPath, ctx.openChipPath);
|
|
264
|
+
if (openIndex !== null) {
|
|
265
|
+
const openToken = chipTokenFor(openIndex);
|
|
266
|
+
if (items.every((item) => item.value !== openToken)) {
|
|
267
|
+
ctx.onPopoverClose();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const newChipNodes = items.flatMap((item) => {
|
|
271
|
+
if (typeof item.value !== 'string') {
|
|
272
|
+
return [];
|
|
273
|
+
}
|
|
274
|
+
const existing = chipsByToken.get(item.value);
|
|
275
|
+
if (existing) {
|
|
276
|
+
return [
|
|
277
|
+
existing.isNegated
|
|
278
|
+
? { type: 'not', rule: existing.ref }
|
|
279
|
+
: existing.ref,
|
|
280
|
+
];
|
|
281
|
+
}
|
|
282
|
+
return [{ type: 'ref', id: item.value }];
|
|
283
|
+
});
|
|
284
|
+
const nestedGroupRules = groupNode.rules.filter((rule) => extractRef(rule) === null);
|
|
285
|
+
ctx.onReplaceNode(groupPath, Object.assign(Object.assign({}, groupNode), { rules: [...newChipNodes, ...nestedGroupRules] }));
|
|
286
|
+
};
|
|
287
|
+
const chipInteractHandler = (groupPath, chipsByToken, ctx) => (event) => {
|
|
288
|
+
event.stopPropagation();
|
|
289
|
+
const token = interactedToken(event.detail);
|
|
290
|
+
const chip = token ? chipsByToken.get(token) : undefined;
|
|
291
|
+
if (!chip) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
ctx.onChipInteract([...groupPath, 'rules', chip.index]);
|
|
295
|
+
};
|
|
296
|
+
const chipNegateHandler = (openChip, openChipPath, ctx) => (event) => {
|
|
297
|
+
event.stopPropagation();
|
|
298
|
+
const next = event.detail
|
|
299
|
+
? { type: 'not', rule: openChip.ref }
|
|
300
|
+
: openChip.ref;
|
|
301
|
+
ctx.onReplaceNode(openChipPath, next);
|
|
302
|
+
};
|
|
303
|
+
const chipArgsHandler = (openChip, openChipPath, ctx) => (event) => {
|
|
304
|
+
event.stopPropagation();
|
|
305
|
+
const argsPath = openChip.isNegated
|
|
306
|
+
? [...openChipPath, 'rule']
|
|
307
|
+
: openChipPath;
|
|
308
|
+
ctx.onUpdateArgs(argsPath, event.detail);
|
|
309
|
+
};
|
|
310
|
+
const chipDeleteHandler = (openChipPath, ctx) => () => {
|
|
311
|
+
ctx.onDelete(openChipPath);
|
|
312
|
+
};
|
|
313
|
+
/**
|
|
314
|
+
* `limel-picker` declares its `interact` event as
|
|
315
|
+
* `EventEmitter<ListItem<PickerValue>>` but the runtime actually emits
|
|
316
|
+
* the chip's value (a string) — see picker.tsx's handleInteract. This
|
|
317
|
+
* unwraps either shape into the string token.
|
|
318
|
+
* @param detail
|
|
319
|
+
*/
|
|
320
|
+
function interactedToken(detail) {
|
|
321
|
+
if (typeof detail === 'string') {
|
|
322
|
+
return detail;
|
|
323
|
+
}
|
|
324
|
+
if (detail && typeof detail === 'object' && 'value' in detail) {
|
|
325
|
+
const value = detail.value;
|
|
326
|
+
return typeof value === 'string' ? value : undefined;
|
|
327
|
+
}
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
function findOpenChip(chipChildren, groupPath, openChipPath) {
|
|
331
|
+
var _a;
|
|
332
|
+
const index = openChipIndexInGroup(groupPath, openChipPath);
|
|
333
|
+
if (index === null) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
return (_a = chipChildren.find((entry) => entry.index === index)) !== null && _a !== void 0 ? _a : null;
|
|
337
|
+
}
|
|
338
|
+
function openChipIndexInGroup(groupPath, openChipPath) {
|
|
339
|
+
if (!openChipPath || openChipPath.length < CHIP_PATH_SUFFIX_LENGTH) {
|
|
340
|
+
return null;
|
|
341
|
+
}
|
|
342
|
+
if (!pathsEqual(parentGroupPath(openChipPath), groupPath)) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
const lastKey = openChipPath.at(-1);
|
|
346
|
+
return typeof lastKey === 'number' ? lastKey : null;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const GroupNodeView = ({ node, path, isNegated, ctx }) => {
|
|
350
|
+
const groupBasePath = isNegated ? [...path, 'rule'] : path;
|
|
351
|
+
const issuesHere = isNegated
|
|
352
|
+
? [
|
|
353
|
+
...issuesAt(ctx.issues, path),
|
|
354
|
+
...issuesAt(ctx.issues, groupBasePath),
|
|
355
|
+
]
|
|
356
|
+
: issuesAt(ctx.issues, path);
|
|
357
|
+
const chipChildren = [];
|
|
358
|
+
const nestedGroups = [];
|
|
359
|
+
for (const [index, child] of node.rules.entries()) {
|
|
360
|
+
const extracted = extractRef(child);
|
|
361
|
+
if (extracted) {
|
|
362
|
+
chipChildren.push(Object.assign(Object.assign({}, extracted), { index }));
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
nestedGroups.push({ child, index });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const options = combinatorOptions(ctx);
|
|
369
|
+
const selectedCombinator = options.find((option) => option.value === node.type);
|
|
370
|
+
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))));
|
|
371
|
+
};
|
|
372
|
+
function pathKey(path) {
|
|
373
|
+
return path.length === 0 ? 'root' : path.join('/');
|
|
374
|
+
}
|
|
375
|
+
function combinatorOptions(ctx) {
|
|
376
|
+
return [
|
|
377
|
+
{
|
|
378
|
+
value: 'all',
|
|
379
|
+
text: ctx.translator.get('webclient.rule-editor.combinator.all'),
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
value: 'any',
|
|
383
|
+
text: ctx.translator.get('webclient.rule-editor.combinator.any'),
|
|
384
|
+
},
|
|
385
|
+
];
|
|
386
|
+
}
|
|
387
|
+
function renderMutableGroupActions(node, path, isNegated, ctx) {
|
|
388
|
+
if (!ctx.isMutable) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
return (index.h("div", { class: "rule-node__header-actions" }, index.h("limel-switch", { class: "rule-node__negate-switch", label: ctx.translator.get('webclient.rule-editor.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) })));
|
|
392
|
+
}
|
|
393
|
+
function renderNestedGroups(nestedGroups, groupBasePath, ctx) {
|
|
394
|
+
if (nestedGroups.length === 0) {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
return (index.h("div", { class: "rule-node__children" }, nestedGroups.map((entry) => (index.h(RuleNodeView, { node: entry.child, path: [...groupBasePath, 'rules', entry.index], ctx: ctx })))));
|
|
398
|
+
}
|
|
399
|
+
function renderAddGroupFooter(node, path, isNegated, ctx) {
|
|
400
|
+
if (!ctx.isMutable) {
|
|
401
|
+
return null;
|
|
402
|
+
}
|
|
403
|
+
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) })));
|
|
404
|
+
}
|
|
405
|
+
function replaceGroup(nextGroup, path, isNegated, ctx) {
|
|
406
|
+
ctx.onReplaceNode(path, wrapNegated(nextGroup, isNegated));
|
|
407
|
+
}
|
|
408
|
+
const combinatorChangeHandler = (node, path, isNegated, ctx) => (event) => {
|
|
409
|
+
event.stopPropagation();
|
|
410
|
+
const newType = event.detail.value;
|
|
411
|
+
if (newType !== node.type) {
|
|
412
|
+
replaceGroup(Object.assign(Object.assign({}, node), { type: newType }), path, isNegated, ctx);
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
const addGroupHandler = (node, path, isNegated, ctx) => () => {
|
|
416
|
+
const expanded = appendChild(node, { type: 'all', rules: [] });
|
|
417
|
+
replaceGroup(expanded, path, isNegated, ctx);
|
|
418
|
+
};
|
|
419
|
+
const negateGroupHandler = (node, path, ctx) => (event) => {
|
|
420
|
+
event.stopPropagation();
|
|
421
|
+
ctx.onReplaceNode(path, wrapNegated(node, event.detail));
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Render a `Rule` node and recurse into its children.
|
|
426
|
+
* @param props
|
|
427
|
+
*/
|
|
428
|
+
const RuleNodeView = (props) => {
|
|
429
|
+
const { node, path, ctx } = props;
|
|
430
|
+
const group = extractGroup(node);
|
|
431
|
+
if (!group) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
return (index.h(GroupNodeView, { node: group.node, path: path, isNegated: group.isNegated, ctx: ctx }));
|
|
435
|
+
};
|
|
436
|
+
const isNegatedGroup = (node) => node.type === 'not' &&
|
|
437
|
+
(node.rule.type === 'all' || node.rule.type === 'any');
|
|
438
|
+
/**
|
|
439
|
+
* If `node` is a group (`all`/`any`) or a negated group, return the
|
|
440
|
+
* inner group together with its negation flag. Otherwise `null`.
|
|
441
|
+
* Used by the dispatcher and by the editor's input normalization.
|
|
442
|
+
* @param node
|
|
443
|
+
*/
|
|
444
|
+
function extractGroup(node) {
|
|
445
|
+
if (node.type === 'all' || node.type === 'any') {
|
|
446
|
+
return { node, isNegated: false };
|
|
447
|
+
}
|
|
448
|
+
if (isNegatedGroup(node)) {
|
|
449
|
+
return { node: node.rule, isNegated: true };
|
|
450
|
+
}
|
|
451
|
+
if (node.type === 'not') {
|
|
452
|
+
const inner = extractGroup(node.rule);
|
|
453
|
+
if (inner) {
|
|
454
|
+
return { node: inner.node, isNegated: !inner.isNegated };
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
const IssuesView = ({ issues }) => {
|
|
460
|
+
if (issues.length === 0) {
|
|
461
|
+
return null;
|
|
462
|
+
}
|
|
463
|
+
return issues.map((issue) => (index.h("div", { class: "rule-node__issue" }, issue.message)));
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
const ruleEditorCss = () => `:host{display:block}.rule-editor--disabled{opacity:0.6;pointer-events:none}.rule-editor__label{font-size:0.75rem;font-weight:600;color:rgb(var(--contrast-1500));margin-bottom:0.25rem}.rule-editor__helper-text{font-size:0.75rem;color:rgb(var(--contrast-1300));margin-top:0.25rem}.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}.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}`;
|
|
467
|
+
|
|
468
|
+
const RuleEditor = class {
|
|
469
|
+
constructor(hostRef) {
|
|
470
|
+
index.registerInstance(this, hostRef);
|
|
471
|
+
this.change = index.createEvent(this, "change");
|
|
472
|
+
this.issues = [];
|
|
473
|
+
this.openChipPath = null;
|
|
474
|
+
this.metadataById = new Map();
|
|
475
|
+
this.primitiveOptions = [];
|
|
476
|
+
this.normalizedCache = null;
|
|
477
|
+
this.handleDelete = (path) => {
|
|
478
|
+
this.openChipPath = null;
|
|
479
|
+
this.emitIfChanged(deleteNode(this.normalizedValue, path));
|
|
480
|
+
};
|
|
481
|
+
this.handleUpdateArgs = (path, args) => {
|
|
482
|
+
this.emitIfChanged(updateArgs(this.normalizedValue, path, args));
|
|
483
|
+
};
|
|
484
|
+
this.handleReplaceNode = (path, replacement) => {
|
|
485
|
+
this.emitIfChanged(replaceNode(this.normalizedValue, path, replacement));
|
|
486
|
+
};
|
|
487
|
+
this.handleChipInteract = (path) => {
|
|
488
|
+
this.openChipPath = path;
|
|
489
|
+
};
|
|
490
|
+
this.handlePopoverClose = () => {
|
|
491
|
+
this.openChipPath = null;
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
componentWillLoad() {
|
|
495
|
+
this.indexMetadata();
|
|
496
|
+
this.runValidation();
|
|
497
|
+
}
|
|
498
|
+
componentDidLoad() {
|
|
499
|
+
this.emitNormalization();
|
|
500
|
+
}
|
|
501
|
+
onValueChange() {
|
|
502
|
+
if (this.emitNormalization()) {
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
this.runValidation();
|
|
506
|
+
}
|
|
507
|
+
onAvailableSubjectsChange() {
|
|
508
|
+
this.runValidation();
|
|
509
|
+
}
|
|
510
|
+
render() {
|
|
511
|
+
const containerClasses = {
|
|
512
|
+
'rule-editor': true,
|
|
513
|
+
'rule-editor--disabled': this.disabled,
|
|
514
|
+
};
|
|
515
|
+
return (index.h("div", { key: 'd179f399433b3c80aa09e52baa19713eef7c1921', class: containerClasses }, this.renderLabel(), index.h(RuleNodeView, { key: '14cac42e37f52f0a32390a1f374f014b60e31dde', node: this.normalizedValue, path: [], ctx: this.createRenderContext() }), this.renderHelperText()));
|
|
516
|
+
}
|
|
517
|
+
renderLabel() {
|
|
518
|
+
if (!this.label) {
|
|
519
|
+
return null;
|
|
520
|
+
}
|
|
521
|
+
return index.h("div", { class: "rule-editor__label" }, this.label);
|
|
522
|
+
}
|
|
523
|
+
renderHelperText() {
|
|
524
|
+
if (!this.helperText) {
|
|
525
|
+
return null;
|
|
526
|
+
}
|
|
527
|
+
return index.h("div", { class: "rule-editor__helper-text" }, this.helperText);
|
|
528
|
+
}
|
|
529
|
+
createRenderContext() {
|
|
530
|
+
return {
|
|
531
|
+
issues: this.issues,
|
|
532
|
+
metadataById: this.metadataById,
|
|
533
|
+
primitiveOptions: this.primitiveOptions,
|
|
534
|
+
isMutable: !this.readonly && !this.disabled,
|
|
535
|
+
readonly: this.readonly,
|
|
536
|
+
disabled: this.disabled,
|
|
537
|
+
platform: this.platform,
|
|
538
|
+
context: this.context,
|
|
539
|
+
translator: this.platform.get(index_esm.n.Translate),
|
|
540
|
+
openChipPath: this.openChipPath,
|
|
541
|
+
onDelete: this.handleDelete,
|
|
542
|
+
onUpdateArgs: this.handleUpdateArgs,
|
|
543
|
+
onReplaceNode: this.handleReplaceNode,
|
|
544
|
+
onChipInteract: this.handleChipInteract,
|
|
545
|
+
onPopoverClose: this.handlePopoverClose,
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
indexMetadata() {
|
|
549
|
+
var _a, _b, _c;
|
|
550
|
+
const metadata = (_c = (_b = (_a = this.ruleRegistry).listMetadata) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : [];
|
|
551
|
+
this.metadataById = new Map(metadata.map((item) => [item.id, item]));
|
|
552
|
+
this.primitiveOptions = createPrimitiveOptions(this.metadataById);
|
|
553
|
+
}
|
|
554
|
+
runValidation() {
|
|
555
|
+
if (!this.value) {
|
|
556
|
+
this.issues = [];
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
const result = this.ruleRegistry.validate(this.normalizedValue, this.availableSubjects);
|
|
560
|
+
this.issues = result.ok ? [] : result.issues;
|
|
561
|
+
}
|
|
562
|
+
emitIfChanged(next) {
|
|
563
|
+
if (next === this.normalizedValue) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
this.change.emit(collapseEmptyRoot(next));
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Wrap any non-group `value` in a top-level `all` so the editor
|
|
570
|
+
* always has a group to render against. When `value` is unset,
|
|
571
|
+
* returns a fresh empty `all`-group as a render-only placeholder —
|
|
572
|
+
* `emitNormalization` will *not* push that placeholder back to the
|
|
573
|
+
* caller, so an unset value stays unset until the user edits.
|
|
574
|
+
*
|
|
575
|
+
* Memoized so callers that read this several times in one handler
|
|
576
|
+
* see the same reference — the identity check in `emitIfChanged`
|
|
577
|
+
* depends on it.
|
|
578
|
+
*/
|
|
579
|
+
get normalizedValue() {
|
|
580
|
+
if (this.normalizedCache !== null &&
|
|
581
|
+
this.normalizedCache.source === this.value) {
|
|
582
|
+
return this.normalizedCache.normalized;
|
|
583
|
+
}
|
|
584
|
+
const normalized = normalize(this.value);
|
|
585
|
+
this.normalizedCache = { source: this.value, normalized };
|
|
586
|
+
return normalized;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* If `value` wasn't already a group, emit the normalized form so
|
|
590
|
+
* the caller's stored state catches up. Skipped when `value` is
|
|
591
|
+
* unset — we render a placeholder group locally but don't push it
|
|
592
|
+
* back to the caller, so callers can't tell "no rule yet" apart
|
|
593
|
+
* from "user cleared a rule" by inspecting the emitted shape.
|
|
594
|
+
* Returns `true` when an emit happened so callers can short-circuit.
|
|
595
|
+
*/
|
|
596
|
+
emitNormalization() {
|
|
597
|
+
if (!this.value) {
|
|
598
|
+
return false;
|
|
599
|
+
}
|
|
600
|
+
const normalized = this.normalizedValue;
|
|
601
|
+
if (normalized === this.value) {
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
this.change.emit(normalized);
|
|
605
|
+
return true;
|
|
606
|
+
}
|
|
607
|
+
get ruleRegistry() {
|
|
608
|
+
return this.platform.get(index_esm.n.RuleRegistry);
|
|
609
|
+
}
|
|
610
|
+
static get watchers() { return {
|
|
611
|
+
"value": [{
|
|
612
|
+
"onValueChange": 0
|
|
613
|
+
}],
|
|
614
|
+
"availableSubjects": [{
|
|
615
|
+
"onAvailableSubjectsChange": 0
|
|
616
|
+
}]
|
|
617
|
+
}; }
|
|
618
|
+
};
|
|
619
|
+
function normalize(value) {
|
|
620
|
+
if (!value) {
|
|
621
|
+
return { type: 'all', rules: [] };
|
|
622
|
+
}
|
|
623
|
+
if (extractGroup(value)) {
|
|
624
|
+
return value;
|
|
625
|
+
}
|
|
626
|
+
return { type: 'all', rules: [value] };
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Treat an empty root `all`/`any` as "no rule". Mapping that back to
|
|
630
|
+
* `undefined` on emit keeps the form contract a clean
|
|
631
|
+
* `Rule | undefined` — callers don't have to inspect rule shape to
|
|
632
|
+
* tell "user cleared this" from "user has a real rule". A negated
|
|
633
|
+
* empty group (`not(all())` etc.) is left intact — vacuous either
|
|
634
|
+
* direction, but the user explicitly opted into the wrapper, so we
|
|
635
|
+
* don't second-guess.
|
|
636
|
+
* @param rule
|
|
637
|
+
*/
|
|
638
|
+
function collapseEmptyRoot(rule) {
|
|
639
|
+
if (rule.type !== 'all' && rule.type !== 'any') {
|
|
640
|
+
return rule;
|
|
641
|
+
}
|
|
642
|
+
return rule.rules.length === 0 ? undefined : rule;
|
|
643
|
+
}
|
|
644
|
+
RuleEditor.style = ruleEditorCss();
|
|
645
|
+
|
|
646
|
+
exports.limebb_rule_editor = RuleEditor;
|
|
@@ -20,13 +20,17 @@ const RuleGate = class {
|
|
|
20
20
|
this.compileAndEvaluate();
|
|
21
21
|
}
|
|
22
22
|
render() {
|
|
23
|
-
return (index.h(index.Host, { key: '
|
|
23
|
+
return (index.h(index.Host, { key: 'b3663501f4878923c36018812e60bfad702c1173', hidden: !this.shouldRender }, index.h("slot", { key: '1d3193332f682bd6ccb0f0ecc065b8c757f504eb' })));
|
|
24
24
|
}
|
|
25
25
|
get ruleRegistry() {
|
|
26
26
|
return this.platform.get(index_esm.n.RuleRegistry);
|
|
27
27
|
}
|
|
28
28
|
compileAndEvaluate() {
|
|
29
29
|
var _a;
|
|
30
|
+
if (!this.rule) {
|
|
31
|
+
this.shouldRender = true;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
30
34
|
const compiled = this.ruleRegistry.compile(this.rule);
|
|
31
35
|
const scope = (_a = this.scope) !== null && _a !== void 0 ? _a : this.ruleRegistry.scope({ host: this.host });
|
|
32
36
|
this.shouldRender = compiled(scope);
|
|
@@ -1517,7 +1517,7 @@ const LimeBBTextEditor = class {
|
|
|
1517
1517
|
}
|
|
1518
1518
|
render() {
|
|
1519
1519
|
return [
|
|
1520
|
-
index.h("limel-text-editor", { key: '
|
|
1520
|
+
index.h("limel-text-editor", { key: '38d692ec58c569a0429caddf7ecfe418e21ac14b', ref: (el) => (this.textEditor = el), tabindex: this.disabled ? -1 : 0, value: this.value, contentType: this.contentType, customElements: this.registeredCustomElements, "aria-disabled": this.disabled, language: this.language, triggers: this.registeredTriggers, onTriggerStart: this.handleTriggerStart, onTriggerStop: this.handleTriggerStop, onTriggerChange: this.handleTriggerChange, onImagePasted: this.handleImagePasted, onMetadataChange: this.handleMetadataChange, ui: this.ui, allowResize: this.allowResize, required: this.required, disabled: this.disabled, readonly: this.readonly, helperText: this.helperText, placeholder: this.placeholder, label: this.label, invalid: this.invalid }),
|
|
1521
1521
|
this.renderPicker(),
|
|
1522
1522
|
];
|
|
1523
1523
|
}
|
|
@@ -51,7 +51,7 @@ const TrendIndicator = class {
|
|
|
51
51
|
this.numValue = this.parseValue(this.value);
|
|
52
52
|
}
|
|
53
53
|
render() {
|
|
54
|
-
return (index.h(index.Host, { key: '
|
|
54
|
+
return (index.h(index.Host, { key: 'fd3bce29b7cd49a4642904fa630616b10e7d55b8', class: this.getContainerClassList() }, index.h("limel-notched-outline", { key: '3502f060569abb0e12c5b6bca84fdf9b190e840f', id: this.tooltipId, label: this.label, labelId: this.labelId, invalid: this.invalid, required: this.required, hasValue: true, hasFloatingLabel: true, "aria-labelledby": this.labelId, "aria-describedby": this.helperTextId, "aria-controls": this.helperTextId }, index.h("div", { key: '4f007fec33a71fe2205c1fbb861b45b8d41f440e', slot: "content", tabIndex: 0 }, this.renderVisualization())), this.renderHelperLine(), this.renderTooltip()));
|
|
55
55
|
}
|
|
56
56
|
renderVisualization() {
|
|
57
57
|
if (this.reducePresence && (this.numValue === 0 || !this.hasValue())) {
|