@fluid-topics/ft-tree-list 1.3.21 → 1.3.23

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.
@@ -21,6 +21,7 @@ export declare class FtdsTreeList extends FtLitElement implements FtdsTreeListPr
21
21
  expandAllLabel: string;
22
22
  collapseAllLabel: string;
23
23
  emptyState?: EmptyStateConfiguration;
24
+ loading: boolean;
24
25
  nodeToFocus?: FtTreeNode;
25
26
  isTreeSelectorCollapsed?: boolean;
26
27
  childrenCounts: Map<string, number>;
@@ -33,6 +34,9 @@ export declare class FtdsTreeList extends FtLitElement implements FtdsTreeListPr
33
34
  setFocusToTreeItem(item: FtTreeNode): void;
34
35
  selectNodeByBreadcrumb(breadcrumb: string[]): Promise<void>;
35
36
  protected render(): TemplateResult<1>;
37
+ protected renderBody(): TemplateResult;
38
+ protected renderLoadingState(): TemplateResult;
39
+ protected renderLeftHeader(): TemplateResult;
36
40
  protected renderNode(node: FtTreeNode): unknown;
37
41
  protected renderChildNodes(isNodeExpanded: boolean, visibleChildren: FtTreeNode[], node: FtTreeNode, childrenClasses: {
38
42
  expanded: boolean;
@@ -47,6 +51,8 @@ export declare class FtdsTreeList extends FtLitElement implements FtdsTreeListPr
47
51
  "with-children": boolean;
48
52
  }): TemplateResult<1>;
49
53
  protected renderEmptyState(): TemplateResult<1>;
54
+ protected renderEmptyStateTitle(): TemplateResult | symbol;
55
+ protected renderEmptyStateDescription(): TemplateResult | symbol;
50
56
  protected willUpdate(props: PropertyValues): void;
51
57
  protected updated(props: PropertyValues): void;
52
58
  protected onKeydown(event: KeyboardEvent, currentNode: FtTreeNode, isLoadMore: boolean, parentNode?: FtTreeNode): void;
@@ -17,6 +17,7 @@ import { FtdsButton } from "@fluid-topics/ft-button";
17
17
  import { styles } from "./ftds-tree-list.styles";
18
18
  import { createLoadMoreNode, getPathToNode, TraversalInstruction, traverseVisibleTree } from "./model/FtTreeListData";
19
19
  import { cactusSvg } from "@fluid-topics/ft-assets";
20
+ import { FtSkeleton } from "@fluid-topics/ft-skeleton";
20
21
  export class NodeSelectedEvent extends CustomEvent {
21
22
  constructor(node) {
22
23
  super("node-selected", { detail: node });
@@ -34,6 +35,7 @@ class FtdsTreeList extends FtLitElement {
34
35
  this.collapseParametrizedLabel = "Collapse {0}";
35
36
  this.expandAllLabel = "Expand all";
36
37
  this.collapseAllLabel = "Collapse all";
38
+ this.loading = false;
37
39
  this.childrenCounts = new Map();
38
40
  this.userOpenedNodes = new Set();
39
41
  this.userClosedNodes = new Set();
@@ -72,20 +74,12 @@ class FtdsTreeList extends FtLitElement {
72
74
  this.selectNode(currentNode);
73
75
  }
74
76
  render() {
75
- var _a;
76
77
  const atLeastOneRootNodeIsExpandable = this.data && this.data.rootNodes && this.data.rootNodes.length > 0
77
78
  ? this.data.rootNodes.some((rootNode) => rootNode.children.length > 0)
78
79
  : false;
79
80
  return html `
80
81
  <div part="header">
81
- ${when(this.label.length > 0, () => html `
82
- <ft-typography class="header-label" variant="${FtTypographyVariants.body1semibold}">
83
- ${this.label}
84
- <ft-typography variant="${FtTypographyVariants.body2medium}" class="node-children-count">
85
- (${this.getEntriesCount()})
86
- </ft-typography>
87
- </ft-typography>
88
- `)}
82
+ ${when(this.label.length > 0, () => this.renderLeftHeader())}
89
83
  ${when(atLeastOneRootNodeIsExpandable, () => html `
90
84
  <ftds-button
91
85
  dense
@@ -100,12 +94,59 @@ class FtdsTreeList extends FtLitElement {
100
94
  </ftds-button>
101
95
  `)}
102
96
  </div>
103
- ${(!((_a = this.data) === null || _a === void 0 ? void 0 : _a.rootNodes) || this.data.rootNodes.length <= 0) ? this.renderEmptyState() : html `
97
+ ${this.renderBody()}
98
+ `;
99
+ }
100
+ renderBody() {
101
+ var _a;
102
+ if (this.loading) {
103
+ return this.renderLoadingState();
104
+ }
105
+ else if (!((_a = this.data) === null || _a === void 0 ? void 0 : _a.rootNodes) || this.data.rootNodes.length <= 0) {
106
+ return this.renderEmptyState();
107
+ }
108
+ else {
109
+ return html `
104
110
  <ul role="tree" class="ft-tree-list" aria-labelledby="${this.label}">
105
111
  ${repeat(this.data.rootNodes, (node) => node.value, (node) => this.renderNode(node))}
106
- </ul>
107
- `}
112
+ </ul>`;
113
+ }
114
+ }
115
+ renderLoadingState() {
116
+ const skeletons = [
117
+ 50, 45, 30, 35, 25,
118
+ 44, 35, 27, 42, 25,
119
+ 47, 30, 29, 45, 49,
120
+ ].map(width => html `
121
+ <li>
122
+ <div class="ft-tree-list--item">
123
+ <ft-skeleton style="--ft-skeleton--width: ${width}%"></ft-skeleton>
124
+ </div>
125
+ </li>`);
126
+ return html `
127
+ <ul class="ft-tree-list loading-state">${skeletons}</ul>`;
128
+ }
129
+ renderLeftHeader() {
130
+ if (this.loading) {
131
+ return html `
132
+ <div class="header-left">
133
+ <ft-typography class="header-label" variant="${FtTypographyVariants.body1semibold}">
134
+ ${this.label}
135
+ </ft-typography>
136
+ <ft-skeleton class="node-count-loader"></ft-skeleton>
137
+ </div>
108
138
  `;
139
+ }
140
+ else {
141
+ return html `
142
+ <ft-typography class="header-label" variant="${FtTypographyVariants.body1semibold}">
143
+ ${this.label}
144
+ <ft-typography variant="${FtTypographyVariants.body2medium}" class="node-children-count">
145
+ (${this.getEntriesCount()})
146
+ </ft-typography>
147
+ </ft-typography>
148
+ `;
149
+ }
109
150
  }
110
151
  renderNode(node) {
111
152
  var _a;
@@ -128,7 +169,7 @@ class FtdsTreeList extends FtLitElement {
128
169
  role="treeitem"
129
170
  data-value="${node.value}"
130
171
  aria-expanded="${ifDefined(isNodeExpanded)}"
131
- class="${classMap(childrenClasses)}"
172
+ class="ft-tree-list--item ${classMap(childrenClasses)}"
132
173
  tabindex="-1"
133
174
  @keydown="${(e) => this.onKeydown(e, node, false)}"
134
175
  >
@@ -176,7 +217,7 @@ class FtdsTreeList extends FtLitElement {
176
217
  icon="${FtIcons.ARROW_DOWN}"
177
218
  tabindex="-1"
178
219
  aria-expanded="false"
179
- class="${classMap(childrenClasses)}"
220
+ class="ft-tree-list--item ${classMap(childrenClasses)}"
180
221
  @click="${() => this.loadMore(node)}"
181
222
  @keydown="${(e) => this.onKeydown(e, createLoadMoreNode(node), true, node)}">
182
223
  <ft-icon value=${FtIcons.ARROW_DOWN}></ft-icon>
@@ -191,16 +232,49 @@ class FtdsTreeList extends FtLitElement {
191
232
  `;
192
233
  }
193
234
  renderEmptyState() {
194
- var _a, _b;
235
+ var _a;
195
236
  return html `
196
237
  <div class="empty-state">
197
238
  ${((_a = this.emptyState) === null || _a === void 0 ? void 0 : _a.noImage) ? nothing : cactusSvg}
198
- <ft-typography variant="${FtTypographyVariants.body2medium}">
199
- ${(_b = this.emptyState) === null || _b === void 0 ? void 0 : _b.content}
200
- </ft-typography>
239
+ ${this.renderEmptyStateTitle()}
240
+ ${this.renderEmptyStateDescription()}
201
241
  </div>
202
242
  `;
203
243
  }
244
+ renderEmptyStateTitle() {
245
+ if (!this.emptyState) {
246
+ return nothing;
247
+ }
248
+ if (typeof this.emptyState.title === "string") {
249
+ return html `
250
+ <ft-typography class="empty-state--title" variant="${FtTypographyVariants.body1medium}">
251
+ ${this.emptyState.title}
252
+ </ft-typography>`;
253
+ }
254
+ else {
255
+ return this.emptyState.title;
256
+ }
257
+ }
258
+ renderEmptyStateDescription() {
259
+ var _a;
260
+ if (!((_a = this.emptyState) === null || _a === void 0 ? void 0 : _a.description)) {
261
+ return nothing;
262
+ }
263
+ if (typeof this.emptyState.description === "string") {
264
+ this.emptyState.description = [this.emptyState.description];
265
+ }
266
+ if (this.emptyState.description instanceof Array) {
267
+ const labels = this.emptyState.description.map(label => html `
268
+ <ft-typography variant="${FtTypographyVariants.body1medium}">
269
+ ${label}
270
+ </ft-typography>`);
271
+ return html `
272
+ <div class="empty-state--description">${labels}</div>`;
273
+ }
274
+ else {
275
+ return this.emptyState.description;
276
+ }
277
+ }
204
278
  willUpdate(props) {
205
279
  var _a, _b;
206
280
  super.willUpdate(props);
@@ -444,7 +518,8 @@ class FtdsTreeList extends FtLitElement {
444
518
  FtdsTreeList.elementDefinitions = {
445
519
  "ft-typography": FtTypography,
446
520
  "ftds-button": FtdsButton,
447
- "ft-icon": FtIcon
521
+ "ft-icon": FtIcon,
522
+ "ft-skeleton": FtSkeleton,
448
523
  };
449
524
  FtdsTreeList.styles = styles;
450
525
  __decorate([
@@ -481,8 +556,11 @@ __decorate([
481
556
  property()
482
557
  ], FtdsTreeList.prototype, "collapseAllLabel", void 0);
483
558
  __decorate([
484
- jsonProperty([])
559
+ jsonProperty(undefined)
485
560
  ], FtdsTreeList.prototype, "emptyState", void 0);
561
+ __decorate([
562
+ property({ type: Boolean })
563
+ ], FtdsTreeList.prototype, "loading", void 0);
486
564
  __decorate([
487
565
  state()
488
566
  ], FtdsTreeList.prototype, "nodeToFocus", void 0);
@@ -11,8 +11,11 @@ export interface FtdsTreeListProperties {
11
11
  collapseParametrizedLabel: string;
12
12
  expandAllLabel: string;
13
13
  collapseAllLabel: string;
14
+ emptyState?: EmptyStateConfiguration;
15
+ loading?: boolean;
14
16
  }
15
17
  export interface EmptyStateConfiguration {
16
18
  noImage: boolean;
17
- content: string | TemplateResult;
19
+ title: string | TemplateResult;
20
+ description?: string | string[] | TemplateResult;
18
21
  }
@@ -1,5 +1,5 @@
1
1
  import { css } from "lit";
2
- import { setVariable } from "@fluid-topics/ft-wc-utils";
2
+ import { foundation, setVariable } from "@fluid-topics/ft-wc-utils";
3
3
  import { FtTypographyCssVariables, FtTypographyVariants } from "@fluid-topics/ft-typography";
4
4
  import { treeList } from "@fluid-topics/design-system-variables";
5
5
  import { FtIconCssVariables } from "@fluid-topics/ft-icon";
@@ -24,38 +24,54 @@ export const styles = css `
24
24
  align-items: baseline;
25
25
  }
26
26
 
27
+ .header-left {
28
+ display: flex;
29
+ flex-direction: row;
30
+ align-items: center;
31
+ gap: 8px;
32
+ }
33
+
34
+ .node-count-loader {
35
+ width: 30px;
36
+ }
37
+
27
38
  /* Tree */
28
- ul[role="tree"] {
39
+ ul.ft-tree-list {
29
40
  padding: 0;
30
41
  margin: 0;
31
42
  position: relative;
32
43
  overflow-x: clip;
33
44
  }
34
45
 
35
- ul[role="tree"]:before {
46
+ ul.ft-tree-list:before {
36
47
  border-width: 0 ${treeList.listContainerBorderWidth};
37
48
  border-style: solid;
38
49
  border-color: ${treeList.listContainerBorderColor};
39
50
  background-color: ${treeList.listContainerBackgroundColor};
40
51
  }
41
52
 
42
- ul[role="tree"],
43
- ul[role="tree"] li {
53
+ ul.ft-tree-list,
54
+ ul.ft-tree-list li {
44
55
  list-style: none;
45
56
  width: max-content;
46
57
  min-width: 100%;
47
58
  }
48
59
 
49
- ul[role="tree"] > li {
60
+ ul.ft-tree-list > li {
50
61
  padding-left: ${treeList.nodeRootPaddingLeft};
51
62
  }
52
63
 
53
- ul[role="tree"] a[role="treeitem"] {
64
+ ul.ft-tree-list .ft-tree-list--item {
54
65
  height: ${treeList.nodeHeight};
55
66
  line-height: ${treeList.nodeHeight};
56
67
  width: calc(100% - ${treeList.nodeRootPaddingLeft});
57
68
  }
58
69
 
70
+ ul.loading-state .ft-tree-list--item {
71
+ display: flex;
72
+ align-items: center;
73
+ }
74
+
59
75
  li a[role="treeitem"] {
60
76
  display: inline-flex;
61
77
  align-items: baseline;
@@ -71,7 +87,7 @@ export const styles = css `
71
87
  padding-left: ${treeList.nodeChildPaddingLeft};
72
88
  }
73
89
 
74
- li a[role="treeitem"]:before {
90
+ li .ft-tree-list--item:before {
75
91
  content: '';
76
92
  position: absolute;
77
93
  left: 0;
@@ -83,7 +99,7 @@ export const styles = css `
83
99
  border-color: ${treeList.nodeUnselectedDefaultBorderColor};
84
100
  }
85
101
 
86
- ul[role="tree"] > li:first-of-type a[role="treeitem"]:before {
102
+ ul.ft-tree-list > li:first-of-type .ft-tree-list--item:before {
87
103
  border-top-width: ${treeList.nodeBorderWidth};
88
104
  }
89
105
 
@@ -214,5 +230,26 @@ export const styles = css `
214
230
  display: flex;
215
231
  flex-direction: column;
216
232
  align-items: center;
233
+ padding-top: ${treeList.emptyStateContainerPaddingTop};
234
+ padding-bottom: ${treeList.emptyStateContainerPaddingBottom};
235
+ }
236
+
237
+ .empty-state--title {
238
+ margin-bottom: ${treeList.emptyStateTitleMarginBottom};
239
+ color: ${treeList.emptyStateTitleLabelColor};
240
+ }
241
+
242
+ .empty-state--description {
243
+ display: flex;
244
+ flex-direction: column;
245
+ align-items: center;
246
+ gap: ${foundation.spacing2};
247
+ color: ${treeList.emptyStateDescriptionLabelColor};
248
+ }
249
+
250
+ .empty-state svg {
251
+ height: ${treeList.emptyStateIllustrationHeight};
252
+ width: ${treeList.emptyStateIllustrationWidth};
253
+ margin-bottom: ${treeList.emptyStateIllustrationMarginBottom};
217
254
  }
218
255
  `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluid-topics/ft-tree-list",
3
- "version": "1.3.21",
3
+ "version": "1.3.23",
4
4
  "description": "A tree list component",
5
5
  "keywords": [
6
6
  "Lit"
@@ -19,13 +19,13 @@
19
19
  "url": "ssh://git@scm.mrs.antidot.net:2222/fluidtopics/ft-web-components.git"
20
20
  },
21
21
  "dependencies": {
22
- "@fluid-topics/design-system-variables": "2.52.1",
23
- "@fluid-topics/ft-assets": "1.3.21",
24
- "@fluid-topics/ft-wc-utils": "1.3.21",
22
+ "@fluid-topics/design-system-variables": "2.53.0",
23
+ "@fluid-topics/ft-assets": "1.3.23",
24
+ "@fluid-topics/ft-wc-utils": "1.3.23",
25
25
  "lit": "3.1.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@fluid-topics/ft-wc-test-utils": "1.3.21"
28
+ "@fluid-topics/ft-wc-test-utils": "1.3.23"
29
29
  },
30
- "gitHead": "fd30595cd89395cbcac48ca8146aecef2e9b8673"
30
+ "gitHead": "1449ae5b73dbdbe40583d414fc5d8e5395694146"
31
31
  }