@limetech/lime-crm-building-blocks 2.0.4 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/dist/cjs/condition-tree-translate-B_qIQz9s.js +27 -0
- package/dist/cjs/lime-crm-building-blocks.cjs.js +1 -1
- package/dist/cjs/limebb-condition-tree-editor.cjs.entry.js +90 -0
- package/dist/cjs/limebb-condition-tree.cjs.entry.js +882 -0
- 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-filter-chip_6.cjs.entry.js +2 -2
- package/dist/cjs/limebb-rule-chip-popover.cjs.entry.js +1 -1
- package/dist/cjs/limebb-rule-editor.cjs.entry.js +3 -3
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/collection-manifest.json +3 -1
- package/dist/collection/components/condition-tree/condition-tree-combinators.js +78 -0
- package/dist/collection/components/condition-tree/condition-tree-editor/condition-tree-editor.css +17 -0
- package/dist/collection/components/condition-tree/condition-tree-editor/condition-tree-editor.js +333 -0
- package/dist/collection/components/condition-tree/condition-tree-nodes.js +218 -0
- package/dist/collection/components/condition-tree/condition-tree-open-state.js +127 -0
- package/dist/collection/components/condition-tree/condition-tree-translate.js +22 -0
- package/dist/collection/components/condition-tree/condition-tree-view-context.js +22 -0
- package/dist/collection/components/condition-tree/condition-tree.css +132 -0
- package/dist/collection/components/condition-tree/condition-tree.js +461 -0
- package/dist/collection/components/condition-tree/condition-tree.types.js +1 -0
- package/dist/collection/components/condition-tree/group-node-view.js +153 -0
- package/dist/collection/components/condition-tree/leaf-node-view.js +74 -0
- 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/filter-chip/filter-chip.js +2 -2
- package/dist/collection/components/rule-editor/group-node-view.js +3 -3
- package/dist/collection/components/rule-editor/rule-chip-popover/rule-chip-popover.js +1 -1
- package/dist/components/condition-tree-editor.js +1 -0
- 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/filter-chip.js +1 -1
- package/dist/components/limebb-condition-tree-editor.d.ts +11 -0
- package/dist/components/limebb-condition-tree-editor.js +1 -0
- package/dist/components/limebb-condition-tree.d.ts +11 -0
- package/dist/components/limebb-condition-tree.js +1 -0
- 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-rule-editor.js +1 -1
- package/dist/components/rule-chip-popover.js +1 -1
- package/dist/esm/condition-tree-translate-CBeXbZ_z.js +25 -0
- package/dist/esm/lime-crm-building-blocks.js +1 -1
- package/dist/esm/limebb-condition-tree-editor.entry.js +88 -0
- package/dist/esm/limebb-condition-tree.entry.js +880 -0
- 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-filter-chip_6.entry.js +2 -2
- package/dist/esm/limebb-rule-chip-popover.entry.js +1 -1
- package/dist/esm/limebb-rule-editor.entry.js +3 -3
- package/dist/esm/loader.js +1 -1
- package/dist/lime-crm-building-blocks/lime-crm-building-blocks.esm.js +1 -1
- package/dist/lime-crm-building-blocks/{p-7bb2788b.entry.js → p-11b41423.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/p-1578c8f0.entry.js +1 -0
- package/dist/lime-crm-building-blocks/{p-c2c181f1.entry.js → p-1731f5c3.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-247fcace.entry.js → p-3c72400d.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-f9f7020f.entry.js → p-3fe4f3f4.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-542047c4.entry.js → p-5b000748.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-4f0a4893.entry.js → p-5b80d92a.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/p-705c53c0.entry.js +1 -0
- package/dist/lime-crm-building-blocks/p-BxCq236x.js +1 -0
- package/dist/lime-crm-building-blocks/{p-76151fce.entry.js → p-a0dee52a.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-ac97c7cc.entry.js → p-b46722c8.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-2bfd351d.entry.js → p-b48c23f4.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-2628fe8e.entry.js → p-c4e40c2c.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-ac4bddfc.entry.js → p-d0c75083.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/p-e6605577.entry.js +1 -0
- package/dist/lime-crm-building-blocks/p-fb45e6d5.entry.js +1 -0
- package/dist/types/components/condition-tree/condition-tree-combinators.d.ts +47 -0
- package/dist/types/components/condition-tree/condition-tree-editor/condition-tree-editor.d.ts +84 -0
- package/dist/types/components/condition-tree/condition-tree-nodes.d.ts +130 -0
- package/dist/types/components/condition-tree/condition-tree-open-state.d.ts +76 -0
- package/dist/types/components/condition-tree/condition-tree-translate.d.ts +11 -0
- package/dist/types/components/condition-tree/condition-tree-view-context.d.ts +48 -0
- package/dist/types/components/condition-tree/condition-tree.d.ts +177 -0
- package/dist/types/components/condition-tree/condition-tree.types.d.ts +323 -0
- package/dist/types/components/condition-tree/group-node-view.d.ts +30 -0
- package/dist/types/components/condition-tree/leaf-node-view.d.ts +21 -0
- package/dist/types/components.d.ts +348 -4
- package/dist/types/interface.d.ts +1 -0
- package/package.json +2 -2
- package/dist/lime-crm-building-blocks/p-1e83a491.entry.js +0 -1
- package/dist/lime-crm-building-blocks/p-73f79d42.entry.js +0 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PlatformServiceName, } from "@limetech/lime-web-components";
|
|
2
|
+
/**
|
|
3
|
+
* A translate function that falls back to the given English wording when the
|
|
4
|
+
* platform is absent or has no translation for the key.
|
|
5
|
+
*
|
|
6
|
+
* The tree is presentational and is rendered in docs and tests without a fully
|
|
7
|
+
* loaded platform, so it must read sensibly either way.
|
|
8
|
+
* @param platform
|
|
9
|
+
*/
|
|
10
|
+
export function createTranslator(platform) {
|
|
11
|
+
return (key, fallback) => {
|
|
12
|
+
var _a;
|
|
13
|
+
let translated;
|
|
14
|
+
try {
|
|
15
|
+
translated = (_a = platform === null || platform === void 0 ? void 0 : platform.get(PlatformServiceName.Translate)) === null || _a === void 0 ? void 0 : _a.get(key);
|
|
16
|
+
}
|
|
17
|
+
catch (_b) {
|
|
18
|
+
return fallback;
|
|
19
|
+
}
|
|
20
|
+
return translated && translated !== key ? translated : fallback;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { h } from "@stencil/core";
|
|
2
|
+
/**
|
|
3
|
+
* Problems reported on a node, listed beneath it.
|
|
4
|
+
* @param props
|
|
5
|
+
*/
|
|
6
|
+
export const IssuesView = (props) => {
|
|
7
|
+
var _a;
|
|
8
|
+
if (!((_a = props.issues) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return props.issues.map((issue) => h("div", { class: "issue" }, issue));
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Throwing a node away. Shared because both kinds offer it: a group through
|
|
15
|
+
* the button in its header, a condition through the cross on its chip.
|
|
16
|
+
* @param path
|
|
17
|
+
* @param ctx
|
|
18
|
+
*/
|
|
19
|
+
export const handleDelete = (path, ctx) => (event) => {
|
|
20
|
+
event.stopPropagation();
|
|
21
|
+
ctx.onDelete(path);
|
|
22
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
*,
|
|
2
|
+
*:before,
|
|
3
|
+
*::after {
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
:host {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
gap: 1.5rem;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.group {
|
|
14
|
+
position: relative;
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
gap: 1rem;
|
|
18
|
+
padding: 0.5rem;
|
|
19
|
+
border-radius: 0.75rem;
|
|
20
|
+
background-color: rgb(var(--contrast-800), 0.15);
|
|
21
|
+
transition: box-shadow 120ms ease;
|
|
22
|
+
}
|
|
23
|
+
.group:before {
|
|
24
|
+
content: "";
|
|
25
|
+
position: absolute;
|
|
26
|
+
top: 1rem;
|
|
27
|
+
bottom: calc(1rem + 1.75rem);
|
|
28
|
+
left: 0;
|
|
29
|
+
width: 0.125rem;
|
|
30
|
+
transform: translateX(-50%);
|
|
31
|
+
border-radius: 1rem;
|
|
32
|
+
background-color: var(--group-rail-color);
|
|
33
|
+
}
|
|
34
|
+
.group:has(> .group-header > limel-icon-button.delete-group:not([disabled]):hover), .group:has(> .group-header > limel-icon-button.delete-group:not([disabled]):focus-within) {
|
|
35
|
+
box-shadow: var(--shadow-error-state);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.group-header {
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: 0.5rem;
|
|
42
|
+
min-height: 2.5rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
limel-select.combinator {
|
|
46
|
+
min-width: 12rem;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
limel-icon-button.delete-group {
|
|
50
|
+
margin-left: auto;
|
|
51
|
+
opacity: 0;
|
|
52
|
+
transition: opacity 120ms ease;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.group:hover > .group-header > limel-icon-button.delete-group,
|
|
56
|
+
.group:focus-within > .group-header > limel-icon-button.delete-group {
|
|
57
|
+
opacity: 1;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
limel-chip.add-group {
|
|
61
|
+
--lime-elevated-surface-background-color: transparent;
|
|
62
|
+
--button-shadow-normal: none;
|
|
63
|
+
isolation: isolate;
|
|
64
|
+
position: relative;
|
|
65
|
+
margin-right: auto;
|
|
66
|
+
}
|
|
67
|
+
limel-chip.add-group:after {
|
|
68
|
+
content: "";
|
|
69
|
+
position: absolute;
|
|
70
|
+
width: 0.5rem;
|
|
71
|
+
height: 1.75rem;
|
|
72
|
+
top: 0;
|
|
73
|
+
left: calc(0.5rem * -1 - 0.125rem / 2);
|
|
74
|
+
border-width: 0 0 0.125rem 0.125rem;
|
|
75
|
+
border-color: var(--group-rail-color);
|
|
76
|
+
border-style: solid;
|
|
77
|
+
border-radius: 0 0 0 0.5rem;
|
|
78
|
+
transform: translateY(calc(-50% - 0.125rem / 2));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
ul.rows {
|
|
82
|
+
list-style: none;
|
|
83
|
+
margin: 0;
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: row;
|
|
86
|
+
flex-wrap: wrap;
|
|
87
|
+
align-items: center;
|
|
88
|
+
column-gap: 0.5rem;
|
|
89
|
+
row-gap: 0.5rem;
|
|
90
|
+
padding: 0 0.5rem 0.5rem 0.5rem;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
li.row {
|
|
94
|
+
list-style: none;
|
|
95
|
+
position: relative;
|
|
96
|
+
}
|
|
97
|
+
li.row.row--group {
|
|
98
|
+
flex-basis: 100%;
|
|
99
|
+
align-self: stretch;
|
|
100
|
+
}
|
|
101
|
+
li.row + li.row:before {
|
|
102
|
+
content: attr(data-marker);
|
|
103
|
+
color: var(--group-rail-color);
|
|
104
|
+
font-size: 0.75rem;
|
|
105
|
+
font-weight: 600;
|
|
106
|
+
line-height: normal;
|
|
107
|
+
}
|
|
108
|
+
li.row + li.row.row--group:before {
|
|
109
|
+
position: absolute;
|
|
110
|
+
left: 0;
|
|
111
|
+
top: 0;
|
|
112
|
+
transform: translate(-50%, -50%);
|
|
113
|
+
}
|
|
114
|
+
li.row + li.row:not(.row--group) {
|
|
115
|
+
display: inline-flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
flex-wrap: wrap;
|
|
118
|
+
}
|
|
119
|
+
li.row + li.row:not(.row--group):before {
|
|
120
|
+
margin-right: 0.5rem;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
limel-popover.leaf {
|
|
124
|
+
display: inline-block;
|
|
125
|
+
max-width: 25rem;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.issue {
|
|
129
|
+
color: rgb(var(--color-red-default));
|
|
130
|
+
font-size: 0.875rem;
|
|
131
|
+
flex-basis: 100%;
|
|
132
|
+
}
|
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import { Host, h, } from "@stencil/core";
|
|
2
|
+
import { CONDITION_TREE_COMBINATORS, oppositeCombinator, } from "./condition-tree-combinators";
|
|
3
|
+
import { ConditionTreeWalker } from "./condition-tree-nodes";
|
|
4
|
+
import { ConditionTreeOpenState } from "./condition-tree-open-state";
|
|
5
|
+
import { GroupView, NodeView } from "./group-node-view";
|
|
6
|
+
import { createTranslator } from "./condition-tree-translate";
|
|
7
|
+
/**
|
|
8
|
+
* The group drawn when there is no tree yet. Nothing is inside it, so no
|
|
9
|
+
* combinator is offered and there is nothing to delete or to group.
|
|
10
|
+
*/
|
|
11
|
+
const EMPTY_GROUP = {
|
|
12
|
+
kind: 'group',
|
|
13
|
+
combinator: 'all',
|
|
14
|
+
children: [],
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The shared skeleton for editing a tree of conditions: nested groups joined by
|
|
18
|
+
* "All of the following" or "Any of the following", or the negations of those
|
|
19
|
+
* two, each holding conditions shown as chips, with the buttons that add,
|
|
20
|
+
* remove and regroup them.
|
|
21
|
+
*
|
|
22
|
+
* This component is deliberately ignorant of what a condition *is*.
|
|
23
|
+
*
|
|
24
|
+
* A condition is visualized as a chip, plus the tag name of an editor to open.
|
|
25
|
+
* So the same skeleton serves a condition that tests a property ("Deal value is
|
|
26
|
+
* greater than 100 000") and one that is opaque ("User is a member of a group")
|
|
27
|
+
* without either model leaking into it.
|
|
28
|
+
*
|
|
29
|
+
* It holds no tree of its own either. The consumer passes in its own tree, and
|
|
30
|
+
* an adapter that reads one node and rebuilds one group. Every structural edit
|
|
31
|
+
* — add, delete, regroup, rejoin, negate — is applied here and handed back as a
|
|
32
|
+
* tree of the same kind, so no consumer has to write that code twice.
|
|
33
|
+
*
|
|
34
|
+
* @exampleComponent limebb-example-condition-tree-basic
|
|
35
|
+
* @exampleComponent limebb-example-condition-tree-combinators
|
|
36
|
+
* @exampleComponent limebb-example-condition-tree-editors
|
|
37
|
+
* @exampleComponent limebb-example-condition-tree-palette
|
|
38
|
+
*
|
|
39
|
+
* @beta
|
|
40
|
+
*/
|
|
41
|
+
export class ConditionTree {
|
|
42
|
+
constructor() {
|
|
43
|
+
/**
|
|
44
|
+
* Which combinators to offer in the group dropdowns, in the order given.
|
|
45
|
+
*
|
|
46
|
+
* All four are offered by default. "Not all of the following" and "None of
|
|
47
|
+
* the following" are harder to reason about than the two they negate, so a
|
|
48
|
+
* consumer whose users would be better served without them passes
|
|
49
|
+
* `['all', 'any']`. A group that already uses a combinator left off this
|
|
50
|
+
* list still shows it, rather than misrepresenting itself as using one of
|
|
51
|
+
* the offered ones.
|
|
52
|
+
*/
|
|
53
|
+
this.combinators = [
|
|
54
|
+
...CONDITION_TREE_COMBINATORS,
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* Set to `true` when the tree is not the viewer's to change: the add,
|
|
58
|
+
* delete and negate controls are not rendered at all, leaving the
|
|
59
|
+
* conditions to be read. Use it where the tree is being shown rather than
|
|
60
|
+
* edited — a saved filter summarized on a card, or a rule the viewer has
|
|
61
|
+
* no rights over.
|
|
62
|
+
*/
|
|
63
|
+
this.readonly = false;
|
|
64
|
+
/**
|
|
65
|
+
* Set to `true` when the tree *is* the viewer's to change, but not at this
|
|
66
|
+
* moment: every control stays where it is, dimmed and inert. Use it for a
|
|
67
|
+
* state that will pass — a form mid-save, or a tree behind an "Apply a
|
|
68
|
+
* filter" switch that is currently off.
|
|
69
|
+
*/
|
|
70
|
+
this.disabled = false;
|
|
71
|
+
/**
|
|
72
|
+
* Which editor is open, and what the user has already been through — see
|
|
73
|
+
* `condition-tree-open-state.ts`.
|
|
74
|
+
*/
|
|
75
|
+
this.openState = ConditionTreeOpenState.empty();
|
|
76
|
+
}
|
|
77
|
+
componentWillLoad() {
|
|
78
|
+
this.buildWalker();
|
|
79
|
+
}
|
|
80
|
+
buildWalker() {
|
|
81
|
+
this.walker = new ConditionTreeWalker(this.adapter, (node) => this.openState.hasSeen(node));
|
|
82
|
+
this.syncOpenState();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Nothing can be read out of a tree until there is an adapter to read it
|
|
86
|
+
* with, so a tree that arrives first waits here. `buildWalker` catches it
|
|
87
|
+
* up when the adapter turns up.
|
|
88
|
+
*/
|
|
89
|
+
syncOpenState() {
|
|
90
|
+
if (!this.adapter) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this.openState = this.openState.sync(this.value, this.walker);
|
|
94
|
+
}
|
|
95
|
+
render() {
|
|
96
|
+
if (!this.adapter) {
|
|
97
|
+
return h(Host, null);
|
|
98
|
+
}
|
|
99
|
+
return (h(Host, null, this.isEmpty ? (this.renderEmptyState()) : (h(NodeView, { node: this.value, description: this.walker.describe(this.value), path: [], ctx: this.renderContext() }))));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The empty tree is drawn as the group it is about to become, rather than
|
|
103
|
+
* as a lone button: every condition here ends up inside a group, so the
|
|
104
|
+
* first one lands in a frame that was already on screen instead of
|
|
105
|
+
* conjuring one around itself. It can be filled either way round, with a
|
|
106
|
+
* condition or with a nested group.
|
|
107
|
+
*/
|
|
108
|
+
renderEmptyState() {
|
|
109
|
+
if (this.readonly) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
return (h(GroupView, { description: EMPTY_GROUP, path: [], ctx: this.renderContext(), placeholder: true }));
|
|
113
|
+
}
|
|
114
|
+
renderContext() {
|
|
115
|
+
return {
|
|
116
|
+
platform: this.platform,
|
|
117
|
+
context: this.context,
|
|
118
|
+
walker: this.walker,
|
|
119
|
+
translate: createTranslator(this.platform),
|
|
120
|
+
combinators: this.combinators,
|
|
121
|
+
readonly: this.readonly,
|
|
122
|
+
disabled: this.disabled,
|
|
123
|
+
negatable: !!this.adapter.negate,
|
|
124
|
+
openNode: this.openState.openNode,
|
|
125
|
+
addOptions: this.addOptions,
|
|
126
|
+
onAddLeaf: (path, item) => this.addLeaf(path, item),
|
|
127
|
+
onAddGroup: (path) => this.addGroup(path),
|
|
128
|
+
onDelete: (path) => this.applyEdit((root) => this.walker.replaceAt(root, path, undefined)),
|
|
129
|
+
onCombinator: (path, combinator) => this.applyEdit((root) => this.walker.rejoinAt(root, path, combinator)),
|
|
130
|
+
onNegate: (path, negated) => this.applyEdit((root) => this.walker.negateAt(root, path, negated)),
|
|
131
|
+
onConditionChange: (path, next) => {
|
|
132
|
+
this.openState = this.openState.expect(next);
|
|
133
|
+
this.applyEdit((root) => this.walker.replaceAt(root, path, next));
|
|
134
|
+
},
|
|
135
|
+
onOpen: (node) => {
|
|
136
|
+
this.openState = this.openState.moveTo(node);
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
addLeaf(path, item) {
|
|
141
|
+
this.grow(path, this.adapter.createLeaf(item));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* A nested group is joined the other way round from the one holding it: a
|
|
145
|
+
* group joined the same way as its parent would say nothing the parent does
|
|
146
|
+
* not already say.
|
|
147
|
+
* @param path
|
|
148
|
+
*/
|
|
149
|
+
addGroup(path) {
|
|
150
|
+
var _a, _b;
|
|
151
|
+
const combinator = (_b = (_a = this.walker.groupAt(this.value, path)) === null || _a === void 0 ? void 0 : _a.combinator) !== null && _b !== void 0 ? _b : this.rootCombinator();
|
|
152
|
+
this.grow(path, this.adapter.group(oppositeCombinator(combinator), this.newGroupChildren()));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* What a new group starts with: one blank condition, so that a group is
|
|
156
|
+
* never handed over saying nothing — the same rule by which a group emptied
|
|
157
|
+
* of its last condition is dropped rather than kept. A consumer offering a
|
|
158
|
+
* menu of kinds is the exception, since the tree cannot know which kind to
|
|
159
|
+
* make.
|
|
160
|
+
*/
|
|
161
|
+
newGroupChildren() {
|
|
162
|
+
var _a;
|
|
163
|
+
if ((_a = this.addOptions) === null || _a === void 0 ? void 0 : _a.length) {
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
return [this.adapter.createLeaf()];
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Add a condition, or a group to put conditions in.
|
|
170
|
+
*
|
|
171
|
+
* Everything in this tree lives inside a group, so the first thing added
|
|
172
|
+
* to an empty one gets a root group to live in. After that the walker
|
|
173
|
+
* places it.
|
|
174
|
+
* @param path
|
|
175
|
+
* @param child
|
|
176
|
+
*/
|
|
177
|
+
grow(path, child) {
|
|
178
|
+
if (this.isEmpty) {
|
|
179
|
+
this.emitChange(this.adapter.group(this.rootCombinator(), [child]));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
this.emitChange(this.walker.appendAt(this.value, path, child));
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* An empty tree has nothing to edit.
|
|
186
|
+
* @param edit
|
|
187
|
+
*/
|
|
188
|
+
applyEdit(edit) {
|
|
189
|
+
if (this.isEmpty) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
this.emitChange(edit(this.value));
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Announce a tree the user has changed — unless it was not theirs to
|
|
196
|
+
* change. Every control is hidden or dimmed by then, so what this catches
|
|
197
|
+
* is an editor: the tree mounts whatever component a condition names, and
|
|
198
|
+
* has no way to make it honour the `readonly` it was handed.
|
|
199
|
+
* @param next
|
|
200
|
+
*/
|
|
201
|
+
emitChange(next) {
|
|
202
|
+
if (this.readonly || this.disabled) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
this.change.emit(next);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Whether there is no tree yet — which is not the same as a tree that
|
|
209
|
+
* happens to be an empty group.
|
|
210
|
+
*/
|
|
211
|
+
get isEmpty() {
|
|
212
|
+
return this.value === undefined || this.value === null;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* The combinator a group made here is joined by: the first one the consumer
|
|
216
|
+
* offers, so a tree that never offers "All of the following" never invents
|
|
217
|
+
* one.
|
|
218
|
+
*/
|
|
219
|
+
rootCombinator() {
|
|
220
|
+
var _a;
|
|
221
|
+
return (_a = this.combinators[0]) !== null && _a !== void 0 ? _a : 'all';
|
|
222
|
+
}
|
|
223
|
+
static get is() { return "limebb-condition-tree"; }
|
|
224
|
+
static get encapsulation() { return "shadow"; }
|
|
225
|
+
static get originalStyleUrls() {
|
|
226
|
+
return {
|
|
227
|
+
"$": ["condition-tree.scss"]
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
static get styleUrls() {
|
|
231
|
+
return {
|
|
232
|
+
"$": ["condition-tree.css"]
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
static get properties() {
|
|
236
|
+
return {
|
|
237
|
+
"platform": {
|
|
238
|
+
"type": "unknown",
|
|
239
|
+
"mutable": false,
|
|
240
|
+
"complexType": {
|
|
241
|
+
"original": "LimeWebComponentPlatform",
|
|
242
|
+
"resolved": "LimeWebComponentPlatform",
|
|
243
|
+
"references": {
|
|
244
|
+
"LimeWebComponentPlatform": {
|
|
245
|
+
"location": "import",
|
|
246
|
+
"path": "@limetech/lime-web-components",
|
|
247
|
+
"id": "node_modules::LimeWebComponentPlatform",
|
|
248
|
+
"referenceLocation": "LimeWebComponentPlatform"
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
"required": false,
|
|
253
|
+
"optional": false,
|
|
254
|
+
"docs": {
|
|
255
|
+
"tags": [],
|
|
256
|
+
"text": "Platform service provider"
|
|
257
|
+
},
|
|
258
|
+
"getter": false,
|
|
259
|
+
"setter": false
|
|
260
|
+
},
|
|
261
|
+
"context": {
|
|
262
|
+
"type": "unknown",
|
|
263
|
+
"mutable": false,
|
|
264
|
+
"complexType": {
|
|
265
|
+
"original": "LimeWebComponentContext",
|
|
266
|
+
"resolved": "LimeWebComponentContext",
|
|
267
|
+
"references": {
|
|
268
|
+
"LimeWebComponentContext": {
|
|
269
|
+
"location": "import",
|
|
270
|
+
"path": "@limetech/lime-web-components",
|
|
271
|
+
"id": "node_modules::LimeWebComponentContext",
|
|
272
|
+
"referenceLocation": "LimeWebComponentContext"
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
"required": false,
|
|
277
|
+
"optional": false,
|
|
278
|
+
"docs": {
|
|
279
|
+
"tags": [],
|
|
280
|
+
"text": "Component context, forwarded to each condition's editor."
|
|
281
|
+
},
|
|
282
|
+
"getter": false,
|
|
283
|
+
"setter": false
|
|
284
|
+
},
|
|
285
|
+
"value": {
|
|
286
|
+
"type": "any",
|
|
287
|
+
"mutable": false,
|
|
288
|
+
"complexType": {
|
|
289
|
+
"original": "any",
|
|
290
|
+
"resolved": "any",
|
|
291
|
+
"references": {}
|
|
292
|
+
},
|
|
293
|
+
"required": false,
|
|
294
|
+
"optional": true,
|
|
295
|
+
"docs": {
|
|
296
|
+
"tags": [],
|
|
297
|
+
"text": "The consumer's own tree, rendered as-is \u2014 the root node, in whatever\nshape `adapter` reads. Leave it unset for a tree with nothing in it yet,\nwhich draws an empty group asking for its first condition."
|
|
298
|
+
},
|
|
299
|
+
"getter": false,
|
|
300
|
+
"setter": false,
|
|
301
|
+
"reflect": false,
|
|
302
|
+
"attribute": "value"
|
|
303
|
+
},
|
|
304
|
+
"adapter": {
|
|
305
|
+
"type": "unknown",
|
|
306
|
+
"mutable": false,
|
|
307
|
+
"complexType": {
|
|
308
|
+
"original": "ConditionTreeAdapter<any>",
|
|
309
|
+
"resolved": "ConditionTreeAdapter<any>",
|
|
310
|
+
"references": {
|
|
311
|
+
"ConditionTreeAdapter": {
|
|
312
|
+
"location": "import",
|
|
313
|
+
"path": "./condition-tree.types",
|
|
314
|
+
"id": "src/components/condition-tree/condition-tree.types.ts::ConditionTreeAdapter",
|
|
315
|
+
"referenceLocation": "ConditionTreeAdapter"
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
"required": false,
|
|
320
|
+
"optional": false,
|
|
321
|
+
"docs": {
|
|
322
|
+
"tags": [],
|
|
323
|
+
"text": "How to read and rebuild `value`. Build it once and hold on to it: one\nbuilt inside a consumer's `render()` is a new object every time, which\nmakes this component re-render for no reason.\n\nA Stencil element cannot be generic, so this is typed loosely here.\nDeclare the adapter as `ConditionTreeAdapter<YourNode>` where you write\nit, and the compiler checks it against your own model."
|
|
324
|
+
},
|
|
325
|
+
"getter": false,
|
|
326
|
+
"setter": false
|
|
327
|
+
},
|
|
328
|
+
"combinators": {
|
|
329
|
+
"type": "unknown",
|
|
330
|
+
"mutable": false,
|
|
331
|
+
"complexType": {
|
|
332
|
+
"original": "ConditionTreeCombinator[]",
|
|
333
|
+
"resolved": "ConditionTreeCombinator[]",
|
|
334
|
+
"references": {
|
|
335
|
+
"ConditionTreeCombinator": {
|
|
336
|
+
"location": "import",
|
|
337
|
+
"path": "./condition-tree.types",
|
|
338
|
+
"id": "src/components/condition-tree/condition-tree.types.ts::ConditionTreeCombinator",
|
|
339
|
+
"referenceLocation": "ConditionTreeCombinator"
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
"required": false,
|
|
344
|
+
"optional": false,
|
|
345
|
+
"docs": {
|
|
346
|
+
"tags": [],
|
|
347
|
+
"text": "Which combinators to offer in the group dropdowns, in the order given.\n\nAll four are offered by default. \"Not all of the following\" and \"None of\nthe following\" are harder to reason about than the two they negate, so a\nconsumer whose users would be better served without them passes\n`['all', 'any']`. A group that already uses a combinator left off this\nlist still shows it, rather than misrepresenting itself as using one of\nthe offered ones."
|
|
348
|
+
},
|
|
349
|
+
"getter": false,
|
|
350
|
+
"setter": false,
|
|
351
|
+
"defaultValue": "[\n ...CONDITION_TREE_COMBINATORS,\n ]"
|
|
352
|
+
},
|
|
353
|
+
"addOptions": {
|
|
354
|
+
"type": "unknown",
|
|
355
|
+
"mutable": false,
|
|
356
|
+
"complexType": {
|
|
357
|
+
"original": "Array<MenuItem | ListSeparator>",
|
|
358
|
+
"resolved": "(ListSeparator | MenuItem<any>)[] | undefined",
|
|
359
|
+
"references": {
|
|
360
|
+
"Array": {
|
|
361
|
+
"location": "global",
|
|
362
|
+
"id": "global::Array"
|
|
363
|
+
},
|
|
364
|
+
"MenuItem": {
|
|
365
|
+
"location": "import",
|
|
366
|
+
"path": "@limetech/lime-elements",
|
|
367
|
+
"id": "node_modules::MenuItem",
|
|
368
|
+
"referenceLocation": "MenuItem"
|
|
369
|
+
},
|
|
370
|
+
"ListSeparator": {
|
|
371
|
+
"location": "import",
|
|
372
|
+
"path": "@limetech/lime-elements",
|
|
373
|
+
"id": "node_modules::ListSeparator",
|
|
374
|
+
"referenceLocation": "ListSeparator"
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
"required": false,
|
|
379
|
+
"optional": true,
|
|
380
|
+
"docs": {
|
|
381
|
+
"tags": [],
|
|
382
|
+
"text": "The kinds of condition a user can add, offered as a menu when the add\nbutton is pressed. The chosen item is passed to `adapter.createLeaf`.\n\nLeave it unset when every condition in the tree is of the same kind:\na blank one can simply be inserted, and its editor settles the rest, so\npressing the button is the whole interaction. Set it when conditions come\nin kinds that have nothing in common \u2014 \"the deal is worth more than\n100 000\", \"the user belongs to a group\", \"it is the first day of the\nmonth\" \u2014 where nothing can be inserted until the user says which.\n\nThe menu has to be rendered here rather than by the consumer, because\nthe button it hangs from lives inside this component."
|
|
383
|
+
},
|
|
384
|
+
"getter": false,
|
|
385
|
+
"setter": false
|
|
386
|
+
},
|
|
387
|
+
"readonly": {
|
|
388
|
+
"type": "boolean",
|
|
389
|
+
"mutable": false,
|
|
390
|
+
"complexType": {
|
|
391
|
+
"original": "boolean",
|
|
392
|
+
"resolved": "boolean",
|
|
393
|
+
"references": {}
|
|
394
|
+
},
|
|
395
|
+
"required": false,
|
|
396
|
+
"optional": false,
|
|
397
|
+
"docs": {
|
|
398
|
+
"tags": [],
|
|
399
|
+
"text": "Set to `true` when the tree is not the viewer's to change: the add,\ndelete and negate controls are not rendered at all, leaving the\nconditions to be read. Use it where the tree is being shown rather than\nedited \u2014 a saved filter summarized on a card, or a rule the viewer has\nno rights over."
|
|
400
|
+
},
|
|
401
|
+
"getter": false,
|
|
402
|
+
"setter": false,
|
|
403
|
+
"reflect": true,
|
|
404
|
+
"attribute": "readonly",
|
|
405
|
+
"defaultValue": "false"
|
|
406
|
+
},
|
|
407
|
+
"disabled": {
|
|
408
|
+
"type": "boolean",
|
|
409
|
+
"mutable": false,
|
|
410
|
+
"complexType": {
|
|
411
|
+
"original": "boolean",
|
|
412
|
+
"resolved": "boolean",
|
|
413
|
+
"references": {}
|
|
414
|
+
},
|
|
415
|
+
"required": false,
|
|
416
|
+
"optional": false,
|
|
417
|
+
"docs": {
|
|
418
|
+
"tags": [],
|
|
419
|
+
"text": "Set to `true` when the tree *is* the viewer's to change, but not at this\nmoment: every control stays where it is, dimmed and inert. Use it for a\nstate that will pass \u2014 a form mid-save, or a tree behind an \"Apply a\nfilter\" switch that is currently off."
|
|
420
|
+
},
|
|
421
|
+
"getter": false,
|
|
422
|
+
"setter": false,
|
|
423
|
+
"reflect": true,
|
|
424
|
+
"attribute": "disabled",
|
|
425
|
+
"defaultValue": "false"
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
static get states() {
|
|
430
|
+
return {
|
|
431
|
+
"openState": {}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
static get events() {
|
|
435
|
+
return [{
|
|
436
|
+
"method": "change",
|
|
437
|
+
"name": "change",
|
|
438
|
+
"bubbles": true,
|
|
439
|
+
"cancelable": true,
|
|
440
|
+
"composed": true,
|
|
441
|
+
"docs": {
|
|
442
|
+
"tags": [],
|
|
443
|
+
"text": "Emitted with the whole tree, of the consumer's own kind, whenever the\nuser changes it. `null` means the last condition went and there is\nnothing left \u2014 an event carries no detail otherwise."
|
|
444
|
+
},
|
|
445
|
+
"complexType": {
|
|
446
|
+
"original": "any",
|
|
447
|
+
"resolved": "any",
|
|
448
|
+
"references": {}
|
|
449
|
+
}
|
|
450
|
+
}];
|
|
451
|
+
}
|
|
452
|
+
static get watchers() {
|
|
453
|
+
return [{
|
|
454
|
+
"propName": "adapter",
|
|
455
|
+
"methodName": "buildWalker"
|
|
456
|
+
}, {
|
|
457
|
+
"propName": "value",
|
|
458
|
+
"methodName": "syncOpenState"
|
|
459
|
+
}];
|
|
460
|
+
}
|
|
461
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|