@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
package/dist/collection/components/condition-tree/condition-tree-editor/condition-tree-editor.js
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
|
|
4
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else
|
|
6
|
+
for (var i = decorators.length - 1; i >= 0; i--)
|
|
7
|
+
if (d = decorators[i])
|
|
8
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
9
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
10
|
+
};
|
|
11
|
+
import { h } from "@stencil/core";
|
|
12
|
+
import { ProvideContext, } from "@limetech/lime-web-components";
|
|
13
|
+
import { LimeWebComponentTemplate } from "../../../util/web-component-template";
|
|
14
|
+
import { createTranslator } from "../condition-tree-translate";
|
|
15
|
+
/**
|
|
16
|
+
* The body of a condition's editor popover: the consumer's editor, and — for a
|
|
17
|
+
* condition that cannot express its own negation — a switch that negates it.
|
|
18
|
+
*
|
|
19
|
+
* It is an element of its own rather than markup inside the tree because
|
|
20
|
+
* `limel-popover` portals its content out of the tree's shadow DOM, leaving it
|
|
21
|
+
* behind. Carrying its own shadow root means its styles travel with it.
|
|
22
|
+
*
|
|
23
|
+
* @private
|
|
24
|
+
*/
|
|
25
|
+
export class ConditionTreeEditor {
|
|
26
|
+
constructor() {
|
|
27
|
+
/**
|
|
28
|
+
* Whether the popover holding this element is open.
|
|
29
|
+
*
|
|
30
|
+
* The element itself stays in place while closed, because `limel-popover`
|
|
31
|
+
* moves its content into the popover surface once and for all when that
|
|
32
|
+
* surface first loads — anything not there by then is never moved. Drawing
|
|
33
|
+
* nothing until asked is what keeps the consumer's editor from being built
|
|
34
|
+
* for every condition in the tree.
|
|
35
|
+
*/
|
|
36
|
+
this.open = false;
|
|
37
|
+
/**
|
|
38
|
+
* @inheritdoc
|
|
39
|
+
*/
|
|
40
|
+
this.readonly = false;
|
|
41
|
+
/**
|
|
42
|
+
* @inheritdoc
|
|
43
|
+
*/
|
|
44
|
+
this.disabled = false;
|
|
45
|
+
this.handleNegate = (event) => {
|
|
46
|
+
event.stopPropagation();
|
|
47
|
+
this.negateChange.emit(event.detail);
|
|
48
|
+
};
|
|
49
|
+
this.handleConditionChange = (event) => {
|
|
50
|
+
event.stopPropagation();
|
|
51
|
+
this.conditionChange.emit(event.detail);
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
render() {
|
|
55
|
+
if (!this.open) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return [this.renderHeader(), this.renderBody()];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The header exists only to hold the negation switch, so a condition that
|
|
62
|
+
* owns its polarity gets no header at all — its editor is the whole
|
|
63
|
+
* popover, exactly as if this element weren't here.
|
|
64
|
+
*/
|
|
65
|
+
renderHeader() {
|
|
66
|
+
if (this.negated === undefined || this.readonly) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return (h("limel-header", { class: "header is-narrow", heading: this.heading }, h("div", { slot: "actions", class: "header-actions" }, h("limel-switch", { class: "negate", label: this.negateLabel, value: this.negated, disabled: this.disabled, onChange: this.handleNegate }))));
|
|
70
|
+
}
|
|
71
|
+
renderBody() {
|
|
72
|
+
if (!this.editor) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return (h(LimeWebComponentTemplate, { class: "editor", platform: this.platform, context: this.context, name: this.editor.name, props: Object.assign(Object.assign({}, this.editor.props), {
|
|
76
|
+
// The condition itself, and the tree's own state, win over
|
|
77
|
+
// the descriptor: an editor that stayed open while the tree
|
|
78
|
+
// was locked must not be the one place the lock does not
|
|
79
|
+
// reach.
|
|
80
|
+
value: this.value, readonly: this.readonly, disabled: this.disabled, onConditionChange: this.handleConditionChange
|
|
81
|
+
}) }));
|
|
82
|
+
}
|
|
83
|
+
get negateLabel() {
|
|
84
|
+
return createTranslator(this.platform)('webclient.negate', 'Negate');
|
|
85
|
+
}
|
|
86
|
+
static get is() { return "limebb-condition-tree-editor"; }
|
|
87
|
+
static get encapsulation() { return "shadow"; }
|
|
88
|
+
static get originalStyleUrls() {
|
|
89
|
+
return {
|
|
90
|
+
"$": ["condition-tree-editor.scss"]
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
static get styleUrls() {
|
|
94
|
+
return {
|
|
95
|
+
"$": ["condition-tree-editor.css"]
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
static get properties() {
|
|
99
|
+
return {
|
|
100
|
+
"platform": {
|
|
101
|
+
"type": "unknown",
|
|
102
|
+
"mutable": false,
|
|
103
|
+
"complexType": {
|
|
104
|
+
"original": "LimeWebComponentPlatform",
|
|
105
|
+
"resolved": "LimeWebComponentPlatform",
|
|
106
|
+
"references": {
|
|
107
|
+
"LimeWebComponentPlatform": {
|
|
108
|
+
"location": "import",
|
|
109
|
+
"path": "@limetech/lime-web-components",
|
|
110
|
+
"id": "node_modules::LimeWebComponentPlatform",
|
|
111
|
+
"referenceLocation": "LimeWebComponentPlatform"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"required": false,
|
|
116
|
+
"optional": false,
|
|
117
|
+
"docs": {
|
|
118
|
+
"tags": [],
|
|
119
|
+
"text": "Platform service provider"
|
|
120
|
+
},
|
|
121
|
+
"getter": false,
|
|
122
|
+
"setter": false
|
|
123
|
+
},
|
|
124
|
+
"context": {
|
|
125
|
+
"type": "unknown",
|
|
126
|
+
"mutable": false,
|
|
127
|
+
"complexType": {
|
|
128
|
+
"original": "LimeWebComponentContext",
|
|
129
|
+
"resolved": "LimeWebComponentContext",
|
|
130
|
+
"references": {
|
|
131
|
+
"LimeWebComponentContext": {
|
|
132
|
+
"location": "import",
|
|
133
|
+
"path": "@limetech/lime-web-components",
|
|
134
|
+
"id": "node_modules::LimeWebComponentContext",
|
|
135
|
+
"referenceLocation": "LimeWebComponentContext"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"required": false,
|
|
140
|
+
"optional": false,
|
|
141
|
+
"docs": {
|
|
142
|
+
"tags": [],
|
|
143
|
+
"text": "Bridges the tree's context across the `limel-popover` portal."
|
|
144
|
+
},
|
|
145
|
+
"getter": false,
|
|
146
|
+
"setter": false
|
|
147
|
+
},
|
|
148
|
+
"open": {
|
|
149
|
+
"type": "boolean",
|
|
150
|
+
"mutable": false,
|
|
151
|
+
"complexType": {
|
|
152
|
+
"original": "boolean",
|
|
153
|
+
"resolved": "boolean",
|
|
154
|
+
"references": {}
|
|
155
|
+
},
|
|
156
|
+
"required": false,
|
|
157
|
+
"optional": false,
|
|
158
|
+
"docs": {
|
|
159
|
+
"tags": [],
|
|
160
|
+
"text": "Whether the popover holding this element is open.\n\nThe element itself stays in place while closed, because `limel-popover`\nmoves its content into the popover surface once and for all when that\nsurface first loads \u2014 anything not there by then is never moved. Drawing\nnothing until asked is what keeps the consumer's editor from being built\nfor every condition in the tree."
|
|
161
|
+
},
|
|
162
|
+
"getter": false,
|
|
163
|
+
"setter": false,
|
|
164
|
+
"reflect": false,
|
|
165
|
+
"attribute": "open",
|
|
166
|
+
"defaultValue": "false"
|
|
167
|
+
},
|
|
168
|
+
"editor": {
|
|
169
|
+
"type": "unknown",
|
|
170
|
+
"mutable": false,
|
|
171
|
+
"complexType": {
|
|
172
|
+
"original": "ComponentDescriptor",
|
|
173
|
+
"resolved": "ComponentDescriptor<unknown> | undefined",
|
|
174
|
+
"references": {
|
|
175
|
+
"ComponentDescriptor": {
|
|
176
|
+
"location": "import",
|
|
177
|
+
"path": "@limetech/lime-web-components",
|
|
178
|
+
"id": "node_modules::ComponentDescriptor",
|
|
179
|
+
"referenceLocation": "ComponentDescriptor"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"required": false,
|
|
184
|
+
"optional": true,
|
|
185
|
+
"docs": {
|
|
186
|
+
"tags": [],
|
|
187
|
+
"text": "The editor to mount, as given on the condition."
|
|
188
|
+
},
|
|
189
|
+
"getter": false,
|
|
190
|
+
"setter": false
|
|
191
|
+
},
|
|
192
|
+
"value": {
|
|
193
|
+
"type": "any",
|
|
194
|
+
"mutable": false,
|
|
195
|
+
"complexType": {
|
|
196
|
+
"original": "any",
|
|
197
|
+
"resolved": "any",
|
|
198
|
+
"references": {}
|
|
199
|
+
},
|
|
200
|
+
"required": false,
|
|
201
|
+
"optional": true,
|
|
202
|
+
"docs": {
|
|
203
|
+
"tags": [],
|
|
204
|
+
"text": "The condition being edited, in the consumer's own model. Handed to the\nmounted editor as `value`."
|
|
205
|
+
},
|
|
206
|
+
"getter": false,
|
|
207
|
+
"setter": false,
|
|
208
|
+
"reflect": false,
|
|
209
|
+
"attribute": "value"
|
|
210
|
+
},
|
|
211
|
+
"heading": {
|
|
212
|
+
"type": "string",
|
|
213
|
+
"mutable": false,
|
|
214
|
+
"complexType": {
|
|
215
|
+
"original": "string",
|
|
216
|
+
"resolved": "string | undefined",
|
|
217
|
+
"references": {}
|
|
218
|
+
},
|
|
219
|
+
"required": false,
|
|
220
|
+
"optional": true,
|
|
221
|
+
"docs": {
|
|
222
|
+
"tags": [],
|
|
223
|
+
"text": "Title of the condition, shown above the editor when there is a header to\nshow at all."
|
|
224
|
+
},
|
|
225
|
+
"getter": false,
|
|
226
|
+
"setter": false,
|
|
227
|
+
"reflect": false,
|
|
228
|
+
"attribute": "heading"
|
|
229
|
+
},
|
|
230
|
+
"negated": {
|
|
231
|
+
"type": "boolean",
|
|
232
|
+
"mutable": false,
|
|
233
|
+
"complexType": {
|
|
234
|
+
"original": "boolean",
|
|
235
|
+
"resolved": "boolean | undefined",
|
|
236
|
+
"references": {}
|
|
237
|
+
},
|
|
238
|
+
"required": false,
|
|
239
|
+
"optional": true,
|
|
240
|
+
"docs": {
|
|
241
|
+
"tags": [],
|
|
242
|
+
"text": "Whether the condition is negated. `undefined` means the condition\nexpresses its own polarity and no switch is offered."
|
|
243
|
+
},
|
|
244
|
+
"getter": false,
|
|
245
|
+
"setter": false,
|
|
246
|
+
"reflect": false,
|
|
247
|
+
"attribute": "negated"
|
|
248
|
+
},
|
|
249
|
+
"readonly": {
|
|
250
|
+
"type": "boolean",
|
|
251
|
+
"mutable": false,
|
|
252
|
+
"complexType": {
|
|
253
|
+
"original": "boolean",
|
|
254
|
+
"resolved": "boolean",
|
|
255
|
+
"references": {}
|
|
256
|
+
},
|
|
257
|
+
"required": false,
|
|
258
|
+
"optional": false,
|
|
259
|
+
"docs": {
|
|
260
|
+
"tags": [{
|
|
261
|
+
"name": "inheritdoc",
|
|
262
|
+
"text": undefined
|
|
263
|
+
}],
|
|
264
|
+
"text": ""
|
|
265
|
+
},
|
|
266
|
+
"getter": false,
|
|
267
|
+
"setter": false,
|
|
268
|
+
"reflect": true,
|
|
269
|
+
"attribute": "readonly",
|
|
270
|
+
"defaultValue": "false"
|
|
271
|
+
},
|
|
272
|
+
"disabled": {
|
|
273
|
+
"type": "boolean",
|
|
274
|
+
"mutable": false,
|
|
275
|
+
"complexType": {
|
|
276
|
+
"original": "boolean",
|
|
277
|
+
"resolved": "boolean",
|
|
278
|
+
"references": {}
|
|
279
|
+
},
|
|
280
|
+
"required": false,
|
|
281
|
+
"optional": false,
|
|
282
|
+
"docs": {
|
|
283
|
+
"tags": [{
|
|
284
|
+
"name": "inheritdoc",
|
|
285
|
+
"text": undefined
|
|
286
|
+
}],
|
|
287
|
+
"text": ""
|
|
288
|
+
},
|
|
289
|
+
"getter": false,
|
|
290
|
+
"setter": false,
|
|
291
|
+
"reflect": true,
|
|
292
|
+
"attribute": "disabled",
|
|
293
|
+
"defaultValue": "false"
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
static get events() {
|
|
298
|
+
return [{
|
|
299
|
+
"method": "negateChange",
|
|
300
|
+
"name": "negateChange",
|
|
301
|
+
"bubbles": true,
|
|
302
|
+
"cancelable": true,
|
|
303
|
+
"composed": true,
|
|
304
|
+
"docs": {
|
|
305
|
+
"tags": [],
|
|
306
|
+
"text": "Emitted when the user toggles the negation switch."
|
|
307
|
+
},
|
|
308
|
+
"complexType": {
|
|
309
|
+
"original": "boolean",
|
|
310
|
+
"resolved": "boolean",
|
|
311
|
+
"references": {}
|
|
312
|
+
}
|
|
313
|
+
}, {
|
|
314
|
+
"method": "conditionChange",
|
|
315
|
+
"name": "conditionChange",
|
|
316
|
+
"bubbles": true,
|
|
317
|
+
"cancelable": true,
|
|
318
|
+
"composed": true,
|
|
319
|
+
"docs": {
|
|
320
|
+
"tags": [],
|
|
321
|
+
"text": "Emitted with the replacement condition when the mounted editor reports\none.\n\n`limel-popover` portals this element out of the tree's shadow DOM, so an\nevent from the editor never reaches the tree on its own. Catching it here\nand emitting it again is what carries it back across."
|
|
322
|
+
},
|
|
323
|
+
"complexType": {
|
|
324
|
+
"original": "any",
|
|
325
|
+
"resolved": "any",
|
|
326
|
+
"references": {}
|
|
327
|
+
}
|
|
328
|
+
}];
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
__decorate([
|
|
332
|
+
ProvideContext('context')
|
|
333
|
+
], ConditionTreeEditor.prototype, "context", void 0);
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A stable string form of a path, for `key` attributes and for comparing two
|
|
3
|
+
* paths without an element-by-element loop at every call site.
|
|
4
|
+
* @param path
|
|
5
|
+
*/
|
|
6
|
+
export function pathKey(path) {
|
|
7
|
+
return path.length === 0 ? 'root' : path.join('.');
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Reads and rebuilds a consumer's tree through its adapter.
|
|
11
|
+
*
|
|
12
|
+
* Walking down goes through `describe`, so the tree never has to know how a
|
|
13
|
+
* consumer nests its nodes. Rebuilding goes up through `group`, and only groups
|
|
14
|
+
* are rebuilt: a condition is moved as the object it already is.
|
|
15
|
+
*/
|
|
16
|
+
export class ConditionTreeWalker {
|
|
17
|
+
/**
|
|
18
|
+
* @param adapter
|
|
19
|
+
* @param isVisited - Whether the user has opened and closed a node's
|
|
20
|
+
* editor. Read through a function rather than taken as a set, so that the
|
|
21
|
+
* walker outlives the tree's tally growing.
|
|
22
|
+
*/
|
|
23
|
+
constructor(adapter, isVisited = () => false) {
|
|
24
|
+
this.adapter = adapter;
|
|
25
|
+
this.isVisited = isVisited;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* What the tree should draw for `node`.
|
|
29
|
+
* @param node
|
|
30
|
+
*/
|
|
31
|
+
describe(node) {
|
|
32
|
+
return this.adapter.describe(node, {
|
|
33
|
+
visited: this.isVisited(node),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* How `node` reads as a group, or `undefined` when it is a single
|
|
38
|
+
* condition rather than a group of them.
|
|
39
|
+
* @param node
|
|
40
|
+
*/
|
|
41
|
+
groupOf(node) {
|
|
42
|
+
const description = this.describe(node);
|
|
43
|
+
return description.kind === 'group' ? description : undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The children of a group, or `undefined` for a single condition.
|
|
47
|
+
* @param node
|
|
48
|
+
*/
|
|
49
|
+
childrenOf(node) {
|
|
50
|
+
var _a;
|
|
51
|
+
return (_a = this.groupOf(node)) === null || _a === void 0 ? void 0 : _a.children;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The node at `path`, or `undefined` when the path leads nowhere — which
|
|
55
|
+
* happens routinely when the consumer replaces the tree while an editor is
|
|
56
|
+
* open.
|
|
57
|
+
* @param root
|
|
58
|
+
* @param path
|
|
59
|
+
*/
|
|
60
|
+
nodeAt(root, path) {
|
|
61
|
+
let node = root;
|
|
62
|
+
for (const index of path) {
|
|
63
|
+
if (node === undefined) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
const children = this.childrenOf(node);
|
|
67
|
+
if (!children) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
node = children[index];
|
|
71
|
+
}
|
|
72
|
+
return node;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The group at `path`, or `undefined` when the path leads nowhere or to a
|
|
76
|
+
* condition. Every caller that wants to look inside a group first has to
|
|
77
|
+
* find it and then find out whether it is one, so both steps live here.
|
|
78
|
+
* @param root
|
|
79
|
+
* @param path
|
|
80
|
+
*/
|
|
81
|
+
groupAt(root, path) {
|
|
82
|
+
const node = this.nodeAt(root, path);
|
|
83
|
+
return node === undefined ? undefined : this.groupOf(node);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Whether `node` is still somewhere in the tree, by identity.
|
|
87
|
+
*
|
|
88
|
+
* Identity rather than equality: a condition the tree did not touch is the
|
|
89
|
+
* very object the consumer handed over, so one that merely looks the same
|
|
90
|
+
* is a different condition.
|
|
91
|
+
* @param root
|
|
92
|
+
* @param node
|
|
93
|
+
*/
|
|
94
|
+
contains(root, node) {
|
|
95
|
+
if (root === undefined) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
if (root === node) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
const children = this.childrenOf(root);
|
|
102
|
+
return !!(children === null || children === void 0 ? void 0 : children.some((child) => this.contains(child, node)));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Every condition asking to be opened, in display order.
|
|
106
|
+
*
|
|
107
|
+
* All of them rather than the first, because a consumer that leaves the
|
|
108
|
+
* flag on a condition it has already added would otherwise keep pointing at
|
|
109
|
+
* that one, and the next condition added would never get its turn.
|
|
110
|
+
* @param root
|
|
111
|
+
*/
|
|
112
|
+
autoOpenNodes(root) {
|
|
113
|
+
if (root === undefined) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
const description = this.describe(root);
|
|
117
|
+
if (description.kind === 'leaf') {
|
|
118
|
+
return description.autoOpen ? [root] : [];
|
|
119
|
+
}
|
|
120
|
+
return description.children.flatMap((child) => this.autoOpenNodes(child));
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* The tree with the node at `path` replaced by `next`, or removed when
|
|
124
|
+
* `next` is `undefined`.
|
|
125
|
+
* @param root
|
|
126
|
+
* @param path
|
|
127
|
+
* @param next
|
|
128
|
+
*/
|
|
129
|
+
replaceAt(root, path, next) {
|
|
130
|
+
if (path.length === 0) {
|
|
131
|
+
return next;
|
|
132
|
+
}
|
|
133
|
+
const group = this.groupOf(root);
|
|
134
|
+
if (!group) {
|
|
135
|
+
return root;
|
|
136
|
+
}
|
|
137
|
+
const [index, ...rest] = path;
|
|
138
|
+
const children = group.children;
|
|
139
|
+
if (!(index in children)) {
|
|
140
|
+
return root;
|
|
141
|
+
}
|
|
142
|
+
const child = this.replaceAt(children[index], rest, next);
|
|
143
|
+
return this.rebuild(group.combinator, spliced(children, index, child));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The tree with `child` added to the end of the group at `path`. A path
|
|
147
|
+
* leading to a condition rather than a group leaves the tree alone: there
|
|
148
|
+
* is nothing there to add to.
|
|
149
|
+
* @param root
|
|
150
|
+
* @param path
|
|
151
|
+
* @param child
|
|
152
|
+
*/
|
|
153
|
+
appendAt(root, path, child) {
|
|
154
|
+
const group = this.groupAt(root, path);
|
|
155
|
+
if (!group) {
|
|
156
|
+
return root;
|
|
157
|
+
}
|
|
158
|
+
return this.replaceAt(root, path, this.adapter.group(group.combinator, [...group.children, child]));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The tree with the group at `path` joined by `combinator` instead, and
|
|
162
|
+
* what is inside it left alone. A path leading anywhere but a group leaves
|
|
163
|
+
* the tree as it was.
|
|
164
|
+
* @param root
|
|
165
|
+
* @param path
|
|
166
|
+
* @param combinator
|
|
167
|
+
*/
|
|
168
|
+
rejoinAt(root, path, combinator) {
|
|
169
|
+
const group = this.groupAt(root, path);
|
|
170
|
+
if (!group) {
|
|
171
|
+
return root;
|
|
172
|
+
}
|
|
173
|
+
return this.replaceAt(root, path, this.adapter.group(combinator, group.children));
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* The tree with the condition at `path` negated, or not.
|
|
177
|
+
*
|
|
178
|
+
* An adapter with no way to rebuild a negated condition leaves the tree
|
|
179
|
+
* alone: it has already told the tree not to offer the control.
|
|
180
|
+
* @param root
|
|
181
|
+
* @param path
|
|
182
|
+
* @param negated
|
|
183
|
+
*/
|
|
184
|
+
negateAt(root, path, negated) {
|
|
185
|
+
const target = this.nodeAt(root, path);
|
|
186
|
+
if (target === undefined || !this.adapter.negate) {
|
|
187
|
+
return root;
|
|
188
|
+
}
|
|
189
|
+
return this.replaceAt(root, path, this.adapter.negate(target, negated));
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* A group holding `children`, or nothing at all when there are none left: a
|
|
193
|
+
* group with nothing in it says nothing, so it goes the way of its last
|
|
194
|
+
* condition — and so, in turn, does the group that held it.
|
|
195
|
+
* @param combinator
|
|
196
|
+
* @param children
|
|
197
|
+
*/
|
|
198
|
+
rebuild(combinator, children) {
|
|
199
|
+
if (children.length === 0) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
return this.adapter.group(combinator, children);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* The same list with the entry at `index` swapped for `replacement`, or dropped
|
|
207
|
+
* when there is no replacement.
|
|
208
|
+
* @param children
|
|
209
|
+
* @param index
|
|
210
|
+
* @param replacement
|
|
211
|
+
*/
|
|
212
|
+
function spliced(children, index, replacement) {
|
|
213
|
+
return [
|
|
214
|
+
...children.slice(0, index),
|
|
215
|
+
...(replacement === undefined ? [] : [replacement]),
|
|
216
|
+
...children.slice(index + 1),
|
|
217
|
+
];
|
|
218
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which condition's editor is open, and what the tree remembers about the user
|
|
3
|
+
* having been there.
|
|
4
|
+
*
|
|
5
|
+
* All of it is held by condition rather than by place in the tree, so that it
|
|
6
|
+
* survives the tree being rearranged around it.
|
|
7
|
+
*
|
|
8
|
+
* Every method returns a new state rather than changing this one, because
|
|
9
|
+
* `limebb-condition-tree` keeps it in `@State` and Stencil redraws on a new
|
|
10
|
+
* reference, not on a changed field.
|
|
11
|
+
*/
|
|
12
|
+
export class ConditionTreeOpenState {
|
|
13
|
+
constructor(fields) {
|
|
14
|
+
this.fields = fields;
|
|
15
|
+
}
|
|
16
|
+
static empty() {
|
|
17
|
+
return new ConditionTreeOpenState({
|
|
18
|
+
open: null,
|
|
19
|
+
pending: null,
|
|
20
|
+
seen: new Set(),
|
|
21
|
+
autoOpened: new Set(),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
get openNode() {
|
|
25
|
+
return this.fields.open;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Whether the user has opened this condition's editor and closed it again.
|
|
29
|
+
* @param node
|
|
30
|
+
*/
|
|
31
|
+
hasSeen(node) {
|
|
32
|
+
return this.fields.seen.has(node);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The open editor moved onto `next`, or onto nothing at all, remembering
|
|
36
|
+
* the condition left behind — the moment the user is done with it for now,
|
|
37
|
+
* and the earliest anything can fairly judge it. Losing a condition because
|
|
38
|
+
* it went away is not the user leaving it: see `dropIfGone`.
|
|
39
|
+
* @param next
|
|
40
|
+
*/
|
|
41
|
+
moveTo(next) {
|
|
42
|
+
const previous = this.fields.open;
|
|
43
|
+
const moved = this.with({
|
|
44
|
+
open: next,
|
|
45
|
+
// Whatever the consumer was about to send back is no longer the
|
|
46
|
+
// condition being edited, so it must not be chased later.
|
|
47
|
+
pending: null,
|
|
48
|
+
});
|
|
49
|
+
if (previous === null || previous === next) {
|
|
50
|
+
return moved;
|
|
51
|
+
}
|
|
52
|
+
return moved.with({ seen: new Set(this.fields.seen).add(previous) });
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The same state, now waiting for `next` — the condition an editor just
|
|
56
|
+
* reported — to turn up in a tree from the consumer.
|
|
57
|
+
* @param next
|
|
58
|
+
*/
|
|
59
|
+
expect(next) {
|
|
60
|
+
return this.with({ pending: next });
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The state brought up to date with a tree the consumer has just handed
|
|
64
|
+
* over: follow the condition that replaced the one being edited, open
|
|
65
|
+
* whatever is asking to be opened, and let go of a condition that is no
|
|
66
|
+
* longer there.
|
|
67
|
+
* @param root
|
|
68
|
+
* @param walker
|
|
69
|
+
*/
|
|
70
|
+
sync(root, walker) {
|
|
71
|
+
return this.followPending(root, walker)
|
|
72
|
+
.openWhatAsks(root, walker)
|
|
73
|
+
.dropIfGone(root, walker);
|
|
74
|
+
}
|
|
75
|
+
with(changes) {
|
|
76
|
+
return new ConditionTreeOpenState(Object.assign(Object.assign({}, this.fields), changes));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Move the editor onto the replacement, once the consumer has sent a tree
|
|
80
|
+
* holding it. One that reports the edit elsewhere, or normalizes the
|
|
81
|
+
* condition on the way through, never sends it back at all — the editor
|
|
82
|
+
* then stays where it is, and `dropIfGone` settles it if that has gone too.
|
|
83
|
+
* @param root
|
|
84
|
+
* @param walker
|
|
85
|
+
*/
|
|
86
|
+
followPending(root, walker) {
|
|
87
|
+
if (this.fields.pending === null) {
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
if (!walker.contains(root, this.fields.pending)) {
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
return this.with({ open: this.fields.pending, pending: null });
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Open the condition that is asking for it and has not had its turn yet.
|
|
97
|
+
*
|
|
98
|
+
* A consumer is free to leave the flag on conditions it added earlier, so
|
|
99
|
+
* what settles this is not the flag alone but whether that condition has
|
|
100
|
+
* already been opened once. Conditions that stop asking are forgotten
|
|
101
|
+
* again, so one that is removed and put back opens anew.
|
|
102
|
+
* @param root
|
|
103
|
+
* @param walker
|
|
104
|
+
*/
|
|
105
|
+
openWhatAsks(root, walker) {
|
|
106
|
+
const nodes = walker.autoOpenNodes(root);
|
|
107
|
+
const fresh = nodes.find((node) => !this.fields.autoOpened.has(node));
|
|
108
|
+
const remembered = this.with({ autoOpened: new Set(nodes) });
|
|
109
|
+
return fresh === undefined ? remembered : remembered.moveTo(fresh);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Let go of the open condition when it is no longer there — the user
|
|
113
|
+
* removed it, or the consumer replaced the tree under it. That is not the
|
|
114
|
+
* user finishing with it, so it does not count as having been seen.
|
|
115
|
+
* @param root
|
|
116
|
+
* @param walker
|
|
117
|
+
*/
|
|
118
|
+
dropIfGone(root, walker) {
|
|
119
|
+
if (this.fields.open === null) {
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
if (walker.contains(root, this.fields.open)) {
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
return this.with({ open: null });
|
|
126
|
+
}
|
|
127
|
+
}
|