@fluid-topics/ft-tree-selector 1.3.31 → 1.3.33

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.
@@ -2,6 +2,10 @@ import { PropertyValues } from "lit";
2
2
  import { ElementDefinitionsMap, FtLitElement } from "@fluid-topics/ft-wc-utils";
3
3
  import { FtTree, FtTreeChangedDetail, FtTreeNode } from "./model/FtTree";
4
4
  import { FtButton } from "@fluid-topics/ft-button";
5
+ import { FtTreeSelectorModes } from "./ft-tree-selector.properties";
6
+ export declare class FtTreeChangeEvent extends CustomEvent<FtTree> {
7
+ constructor(detail: FtTree);
8
+ }
5
9
  export declare class TreeNodeChangeEvent extends CustomEvent<FtTreeChangedDetail> {
6
10
  constructor(values: FtTreeChangedDetail);
7
11
  }
@@ -11,6 +15,7 @@ export declare class TreeNodeClearAll extends CustomEvent<void> {
11
15
  export declare class FtTreeSelector extends FtLitElement {
12
16
  static elementDefinitions: ElementDefinitionsMap;
13
17
  static styles: import("lit").CSSResult;
18
+ mode: FtTreeSelectorModes;
14
19
  data: FtTree;
15
20
  userOpenedNodes: Set<string>;
16
21
  userClosedNodes: Set<string>;
@@ -25,10 +30,10 @@ export declare class FtTreeSelector extends FtLitElement {
25
30
  expandAllLabel: string;
26
31
  collapseAllLabel: string;
27
32
  clearLabel: string;
28
- protected update(changedProperties: PropertyValues): void;
33
+ protected willUpdate(changedProperties: PropertyValues): void;
29
34
  protected render(): import("lit-html").TemplateResult<1>;
35
+ protected renderNode(breadcrumb: FtTreeNode[], node: FtTreeNode): unknown;
30
36
  private clear;
31
- protected renderNode(node: FtTreeNode): unknown;
32
37
  private toggleNode;
33
38
  private renderOpenCloseButton;
34
39
  private userChangeNodeExpandStatus;
@@ -6,26 +6,34 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { html, nothing } from "lit";
8
8
  import { classMap } from "lit/directives/class-map.js";
9
- import { flatDeep, FtLitElement, hasChanged, ParametrizedLabelResolver, } from "@fluid-topics/ft-wc-utils";
9
+ import { deepCopy, flatDeep, forEachDeep, FtLitElement, hasChanged, ParametrizedLabelResolver } from "@fluid-topics/ft-wc-utils";
10
10
  import { styles } from "./ft-tree-selector.styles";
11
11
  import { FtCheckbox } from "@fluid-topics/ft-checkbox";
12
- import { FtTypography } from "@fluid-topics/ft-typography";
12
+ import { FtTypography, FtTypographyVariants } from "@fluid-topics/ft-typography";
13
13
  import { repeat } from "lit/directives/repeat.js";
14
14
  import { property, queryAll, state } from "lit/decorators.js";
15
15
  import { FtButton } from "@fluid-topics/ft-button";
16
+ import { FtTreeSelectorModes } from "./ft-tree-selector.properties";
17
+ import { when } from "lit/directives/when.js";
18
+ export class FtTreeChangeEvent extends CustomEvent {
19
+ constructor(detail) {
20
+ super("tree-change", { detail: deepCopy(detail) });
21
+ }
22
+ }
16
23
  export class TreeNodeChangeEvent extends CustomEvent {
17
24
  constructor(values) {
18
- super("treenode-change", { detail: values, bubbles: true, composed: true });
25
+ super("treenode-change", { detail: values });
19
26
  }
20
27
  }
21
28
  export class TreeNodeClearAll extends CustomEvent {
22
29
  constructor() {
23
- super("treenode-clear-all", { bubbles: true, composed: true });
30
+ super("treenode-clear-all");
24
31
  }
25
32
  }
26
33
  class FtTreeSelector extends FtLitElement {
27
34
  constructor() {
28
35
  super(...arguments);
36
+ this.mode = FtTreeSelectorModes.auto;
29
37
  this.userOpenedNodes = new Set();
30
38
  this.userClosedNodes = new Set();
31
39
  this.currentExpandButtonFocusedIndex = 0;
@@ -38,20 +46,20 @@ class FtTreeSelector extends FtLitElement {
38
46
  this.collapseAllLabel = "Collapse all";
39
47
  this.clearLabel = "Clear";
40
48
  }
41
- update(changedProperties) {
42
- super.update(changedProperties);
49
+ willUpdate(changedProperties) {
50
+ super.willUpdate(changedProperties);
43
51
  if (this.data && this.isTreeSelectorCollapsed == undefined) {
44
- this.isTreeSelectorCollapsed = this.data.rootNodes.every(entry => !this.isNodeExpanded(entry));
52
+ this.isTreeSelectorCollapsed = this.data.rootNodes.every((entry) => !this.isNodeExpanded(entry));
45
53
  }
46
54
  }
47
55
  render() {
48
56
  var _a;
49
- const atLeastOneRootNodeIsExpandable = this.data.rootNodes.some(rootNode => rootNode.children.length > 0);
57
+ const atLeastOneRootNodeIsExpandable = this.data.rootNodes.some((rootNode) => rootNode.children.length > 0);
50
58
  return html `
51
59
  <div class="ft-tree-selector ${atLeastOneRootNodeIsExpandable ? "with-expandable" : ""}">
52
60
  <div part="header">
53
61
  ${this.label.length > 0 ? html `
54
- <ft-typography variant="overline" part="label">
62
+ <ft-typography variant="${FtTypographyVariants.overline}" part="label">
55
63
  ${this.label}
56
64
  </ft-typography>
57
65
  ` : nothing}
@@ -59,36 +67,28 @@ class FtTreeSelector extends FtLitElement {
59
67
  <ft-button dense
60
68
  tooltipposition="bottom"
61
69
  part="expand-button"
62
- icon=${this.isTreeSelectorCollapsed ? "ICON_EXPAND" : "ICON_COLLAPSE"}
70
+ icon="${this.isTreeSelectorCollapsed ? "ICON_EXPAND" : "ICON_COLLAPSE"}"
63
71
  label="${this.isTreeSelectorCollapsed ? this.expandAllLabel : this.collapseAllLabel}"
64
72
  aria-expanded="${this.isTreeSelectorCollapsed}"
65
- @click="${() => this.toggleExpandAll()}">
73
+ @click=${() => this.toggleExpandAll()}>
66
74
  </ft-button>
67
75
  ` : nothing}
68
76
 
69
- ${((_a = this.data) === null || _a === void 0 ? void 0 : _a.rootNodes.some(node => node.selected || node.indeterminate)) ?
70
- html `
71
- <ft-button icon="close" dense @click=${() => this.clear()} part="clear-button">
72
- ${this.clearLabel}
73
- </ft-button>
74
- ` : nothing}
77
+ ${((_a = this.data) === null || _a === void 0 ? void 0 : _a.rootNodes.some((node) => node.selected || node.indeterminate))
78
+ ? html `
79
+ <ft-button icon="close" dense @click=${() => this.clear()} part="clear-button">
80
+ ${this.clearLabel}
81
+ </ft-button>
82
+ ` : nothing}
75
83
  </div>
76
84
  ${repeat(this.data.rootNodes, (node) => node.value, (node) => {
77
- return this.renderNode(node);
85
+ return this.renderNode([], node);
78
86
  })}
79
87
  </div>
80
88
  </div>
81
89
  `;
82
90
  }
83
- clear() {
84
- flatDeep(this.data.rootNodes, n => n.children).forEach(n => {
85
- n.selected = false;
86
- n.indeterminate = false;
87
- });
88
- this.requestUpdate();
89
- this.dispatchEvent(new TreeNodeClearAll());
90
- }
91
- renderNode(node) {
91
+ renderNode(breadcrumb, node) {
92
92
  const isNodeExpanded = this.isNodeExpanded(node);
93
93
  const childrenClasses = {
94
94
  "expanded": isNodeExpanded,
@@ -102,31 +102,67 @@ class FtTreeSelector extends FtLitElement {
102
102
  ${this.renderOpenCloseButton(node)}
103
103
  <ft-checkbox part="checkbox"
104
104
  name="${node.label}"
105
- ?checked="${node.selected}"
106
- ?indeterminate="${node.indeterminate}"
107
- @change=${(e) => this.toggleNode(node, e)}>
105
+ ?checked=${node.selected}
106
+ ?indeterminate=${node.indeterminate}
107
+ @change=${(e) => this.toggleNode(breadcrumb, node, e)}>
108
108
  ${node.label}
109
109
  </ft-checkbox>
110
110
  </div>
111
111
  ${node.children.length != 0 && this.isNodeExpanded(node)
112
112
  ? html `
113
- <div part="children" class=${classMap(childrenClasses)} id=${this.getAriaControlId(node)}>
114
- ${isNodeExpanded
115
- ? html `${repeat(node.children, (c) => c.value, (c) => this.renderNode(c))}`
116
- : nothing}
113
+ <div part="children" class="${classMap(childrenClasses)}" id="${this.getAriaControlId(node)}">
114
+ ${when(isNodeExpanded, () => repeat(node.children, (c) => c.value, (c) => this.renderNode([...breadcrumb, node], c)))}
117
115
  </div>`
118
116
  : nothing}
119
117
  </div>
120
118
  `;
121
119
  }
122
- toggleNode(node, e) {
123
- node.selected = e.detail;
124
- node.indeterminate = false;
120
+ clear() {
121
+ flatDeep(this.data.rootNodes, (n) => n.children).forEach((n) => {
122
+ n.selected = false;
123
+ n.indeterminate = false;
124
+ });
125
125
  this.requestUpdate();
126
- return this.dispatchEvent(new TreeNodeChangeEvent({
127
- value: node.value,
128
- selected: e.detail
129
- }));
126
+ switch (this.mode) {
127
+ case FtTreeSelectorModes.auto:
128
+ case FtTreeSelectorModes.downward:
129
+ this.dispatchEvent(new FtTreeChangeEvent(this.data));
130
+ break;
131
+ default:
132
+ this.dispatchEvent(new TreeNodeClearAll());
133
+ break;
134
+ }
135
+ }
136
+ toggleNode(breadcrumb, node, e) {
137
+ const update = (n) => {
138
+ n.selected = e.detail;
139
+ n.indeterminate = false;
140
+ };
141
+ update(node);
142
+ const parents = [...breadcrumb].reverse();
143
+ switch (this.mode) {
144
+ case FtTreeSelectorModes.auto:
145
+ forEachDeep(node.children, (n) => n.children, update);
146
+ parents.forEach((n) => {
147
+ n.selected = n.children.every((c) => c.selected);
148
+ n.indeterminate = !n.selected && n.children.some((c) => c.selected || c.indeterminate);
149
+ });
150
+ this.requestUpdate();
151
+ this.dispatchEvent(new FtTreeChangeEvent(this.data));
152
+ break;
153
+ case FtTreeSelectorModes.downward:
154
+ forEachDeep(node.children, (n) => n.children, update);
155
+ this.requestUpdate();
156
+ this.dispatchEvent(new FtTreeChangeEvent(this.data));
157
+ break;
158
+ default:
159
+ this.requestUpdate();
160
+ this.dispatchEvent(new TreeNodeChangeEvent({
161
+ value: node.value,
162
+ selected: e.detail,
163
+ }));
164
+ break;
165
+ }
130
166
  }
131
167
  renderOpenCloseButton(node) {
132
168
  if (node.children.length === 0) {
@@ -134,18 +170,18 @@ class FtTreeSelector extends FtLitElement {
134
170
  <div part="expand"></div>
135
171
  `;
136
172
  }
137
- let isNodeExpanded = this.isNodeExpanded(node);
173
+ const isNodeExpanded = this.isNodeExpanded(node);
138
174
  return html `
139
175
  <ft-button dense part="expand" tooltipposition="bottom"
140
- icon=${isNodeExpanded ? "TRIANGLE_BOTTOM" : "TRIANGLE_RIGHT"}
176
+ icon="${isNodeExpanded ? "TRIANGLE_BOTTOM" : "TRIANGLE_RIGHT"}"
141
177
  label="${isNodeExpanded ? this.collapseLabel : this.expandLabel}"
142
178
  aria-label="${ParametrizedLabelResolver.replaceParameters(isNodeExpanded
143
179
  ? this.collapseParametrizedLabel
144
180
  : this.expandParametrizedLabel, node.label)}"
145
181
  aria-expanded="${isNodeExpanded}"
146
- aria-control=${this.getAriaControlId(node)}
147
- @keydown="${(e) => this.onKeydown(e, node)}"
148
- @click="${() => this.userChangeNodeExpandStatus(!isNodeExpanded, node.value)}">
182
+ aria-controls="${this.getAriaControlId(node)}"
183
+ @keydown=${(e) => this.onKeydown(e, node)}
184
+ @click=${() => this.userChangeNodeExpandStatus(!isNodeExpanded, node.value)}>
149
185
  </ft-button>
150
186
  `;
151
187
  }
@@ -198,19 +234,19 @@ class FtTreeSelector extends FtLitElement {
198
234
  }
199
235
  }
200
236
  focusPreviousButton(currentButton) {
201
- let currentIndex = this.currentLevelExpandButtons.indexOf(currentButton);
237
+ const currentIndex = this.currentLevelExpandButtons.indexOf(currentButton);
202
238
  this.currentLevelExpandButtons[currentIndex == 0 ? this.currentLevelExpandButtons.length - 1 : currentIndex - 1].focus();
203
239
  }
204
240
  focusNextButton(currentButton) {
205
- let ftButtons = [...this.currentLevelExpandButtons];
206
- let currentIndex = ftButtons.indexOf(currentButton);
241
+ const ftButtons = [...this.currentLevelExpandButtons];
242
+ const currentIndex = ftButtons.indexOf(currentButton);
207
243
  ftButtons[currentIndex == ftButtons.length - 1 ? 0 : currentIndex + 1].focus();
208
244
  }
209
245
  isNodeExpanded(node) {
210
246
  return !this.userClosedNodes.has(node.value) && (node.expanded || this.userOpenedNodes.has(node.value));
211
247
  }
212
248
  hasExpandableChildren(node) {
213
- return node.children.some(child => child.children.length > 0);
249
+ return node.children.some((child) => child.children.length > 0);
214
250
  }
215
251
  toggleExpandAll() {
216
252
  if (this.isTreeSelectorCollapsed) {
@@ -222,20 +258,17 @@ class FtTreeSelector extends FtLitElement {
222
258
  }
223
259
  expandAll() {
224
260
  this.userClosedNodes = new Set();
225
- this.userOpenedNodes = new Set(this.data.rootNodes.flatMap((n) => this.getAllClosedNodes(n)));
261
+ this.userOpenedNodes = new Set(this.getAllClosedNodes());
226
262
  this.isTreeSelectorCollapsed = false;
227
263
  }
228
- getAllClosedNodes(node) {
229
- if (node.children.length !== 0) {
230
- return [...(!node.expanded ? [node.value] : []), ...node.children.flatMap((c) => this.getAllClosedNodes(c))];
231
- }
232
- else {
233
- return [];
234
- }
264
+ getAllClosedNodes() {
265
+ return flatDeep(this.data.rootNodes, (n) => n.children)
266
+ .filter((n) => !n.expanded)
267
+ .map((n) => n.value);
235
268
  }
236
269
  collapseAll() {
237
270
  this.userOpenedNodes = new Set();
238
- this.userClosedNodes = new Set(this.data.rootNodes.filter((n) => n.expanded).map(n => n.value));
271
+ this.userClosedNodes = new Set(this.data.rootNodes.filter((n) => n.expanded).map((n) => n.value));
239
272
  this.isTreeSelectorCollapsed = true;
240
273
  }
241
274
  getAriaControlId(node) {
@@ -245,9 +278,12 @@ class FtTreeSelector extends FtLitElement {
245
278
  FtTreeSelector.elementDefinitions = {
246
279
  "ft-checkbox": FtCheckbox,
247
280
  "ft-typography": FtTypography,
248
- "ft-button": FtButton
281
+ "ft-button": FtButton,
249
282
  };
250
283
  FtTreeSelector.styles = styles;
284
+ __decorate([
285
+ property()
286
+ ], FtTreeSelector.prototype, "mode", void 0);
251
287
  __decorate([
252
288
  property()
253
289
  ], FtTreeSelector.prototype, "data", void 0);