@koobiq/components 20.4.1 → 20.4.3

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.
@@ -978,20 +978,7 @@ class KbqTreeOption extends KbqTreeNode {
978
978
  this.updateCheckboxState = () => {
979
979
  if (this.selectAllRow())
980
980
  return;
981
- if (this.checkboxThirdState() && this.isExpandable) {
982
- if (this.descendantsAllSelected()) {
983
- this.checkboxState = 'checked';
984
- }
985
- else if (this.descendantsPartiallySelected()) {
986
- this.checkboxState = 'indeterminate';
987
- }
988
- else {
989
- this.checkboxState = this.selected ? 'checked' : 'unchecked';
990
- }
991
- }
992
- else {
993
- this.checkboxState = this.selected ? 'checked' : 'unchecked';
994
- }
981
+ this.syncCheckboxState();
995
982
  this.updateParentsCheckboxState(this.data);
996
983
  };
997
984
  this.tree = tree;
@@ -999,7 +986,9 @@ class KbqTreeOption extends KbqTreeNode {
999
986
  ngAfterContentInit() {
1000
987
  if (this.selectAllRow())
1001
988
  return;
1002
- Promise.resolve().then(this.updateCheckboxState);
989
+ // Its own state only: rendering a row changes no ancestor's, and the tree recomputes every row once the data
990
+ // nodes change.
991
+ Promise.resolve().then(() => this.syncCheckboxState());
1003
992
  this.value = this.tree.treeControl.getValue(this.data);
1004
993
  }
1005
994
  descendantsAllSelected() {
@@ -1011,9 +1000,13 @@ class KbqTreeOption extends KbqTreeNode {
1011
1000
  return descendants.some((child) => this.tree?.selectionModel.isSelected(child));
1012
1001
  }
1013
1002
  updateParentsCheckboxState(node) {
1014
- this.tree.treeControl.getParents(node, []).forEach((parent) => {
1015
- const parentOption = this.tree.unorderedOptions.find((option) => option.data === parent);
1016
- parentOption?.updateCheckboxState();
1003
+ const parents = new Set(this.tree.treeControl.getParents(node, []));
1004
+ if (!parents.size)
1005
+ return;
1006
+ // Each ancestor reads its state off the selection rather than off its children, so recomputing it is enough.
1007
+ this.tree.unorderedOptions.forEach((option) => {
1008
+ if (parents.has(option.data))
1009
+ option.syncCheckboxState();
1017
1010
  });
1018
1011
  }
1019
1012
  toggle() {
@@ -1119,8 +1112,9 @@ class KbqTreeOption extends KbqTreeNode {
1119
1112
  }
1120
1113
  markForCheck() {
1121
1114
  this.changeDetectorRef.markForCheck();
1115
+ // Its own state only: after a selection or data change the tree calls this on every option.
1122
1116
  if (this.showCheckbox) {
1123
- this.updateCheckboxState();
1117
+ this.syncCheckboxState();
1124
1118
  }
1125
1119
  }
1126
1120
  /** @docs-private */
@@ -1129,6 +1123,25 @@ class KbqTreeOption extends KbqTreeNode {
1129
1123
  return;
1130
1124
  this.focus('mouse');
1131
1125
  }
1126
+ /** Recomputes the option's own checkbox state, leaving its ancestors as they are. */
1127
+ syncCheckboxState() {
1128
+ if (this.selectAllRow())
1129
+ return;
1130
+ if (this.checkboxThirdState() && this.isExpandable) {
1131
+ if (this.descendantsAllSelected()) {
1132
+ this.checkboxState = 'checked';
1133
+ }
1134
+ else if (this.descendantsPartiallySelected()) {
1135
+ this.checkboxState = 'indeterminate';
1136
+ }
1137
+ else {
1138
+ this.checkboxState = this.selected ? 'checked' : 'unchecked';
1139
+ }
1140
+ }
1141
+ else {
1142
+ this.checkboxState = this.selected ? 'checked' : 'unchecked';
1143
+ }
1144
+ }
1132
1145
  /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqTreeOption, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1133
1146
  /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: KbqTreeOption, isStandalone: true, selector: "kbq-tree-option", inputs: { checkboxThirdState: { classPropertyName: "checkboxThirdState", publicName: "checkboxThirdState", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, selectAllRow: { classPropertyName: "selectAllRow", publicName: "selectAllRow", isSignal: true, isRequired: false, transformFunction: null }, showCheckbox: { classPropertyName: "showCheckbox", publicName: "showCheckbox", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onSelectionChange: "onSelectionChange" }, host: { listeners: { "focusin": "focus()", "mouseenter": "onMouseenter()", "blur": "blur()", "click": "selectViaInteraction($event)", "keydown": "onKeydown($event)" }, properties: { "class.kbq-tree-option_multiple": "tree.multiple", "class.kbq-selected": "selected", "class.kbq-focused": "hasFocus", "class.kbq-disabled": "disabled", "class.kbq-action-button-focused": "actionButton()?.active", "attr.id": "id", "attr.tabindex": "-1", "attr.disabled": "disabled || null" }, classAttribute: "kbq-tree-option" }, providers: [
1134
1147
  { provide: KbqTreeNode, useExisting: KbqTreeOption },
@@ -1480,6 +1493,8 @@ class KbqTreeSelection extends KbqTreeBase {
1480
1493
  this.optionShouldHoldFocusOnBlur = false;
1481
1494
  /** Reference to the built-in "select all" row, rendered only while `selectAll` is on. */
1482
1495
  this.selectAllOption = viewChild(KbqTreeOption, ...(ngDevMode ? [{ debugName: "selectAllOption" }] : []));
1496
+ /** `treeControl.dataNodes` the options' checkbox states were last recomputed against. */
1497
+ this.checkboxSyncedDataNodes = null;
1483
1498
  this.navigationChange = output();
1484
1499
  this.selectionChange = new EventEmitter();
1485
1500
  this.onSelectAll = output();
@@ -1780,6 +1795,21 @@ class KbqTreeSelection extends KbqTreeBase {
1780
1795
  super.renderNodeChanges(data, dataDiffer, viewContainer, parentData);
1781
1796
  this.sortedNodes = this.getSortedNodes(viewContainer);
1782
1797
  this.nodeOutlet.changeDetectorRef.detectChanges();
1798
+ this.scheduleCheckboxSync();
1799
+ }
1800
+ /**
1801
+ * Recomputes every option's checkbox state after `dataNodes` is replaced, which moves the descendants a branch
1802
+ * counts: no selection change follows to do it. A microtask later, as a flat data source assigns `dataNodes` only
1803
+ * after it emits.
1804
+ */
1805
+ scheduleCheckboxSync() {
1806
+ Promise.resolve().then(() => {
1807
+ const dataNodes = this.treeControl?.dataNodes ?? null;
1808
+ if (this.destroyRef.destroyed || dataNodes === this.checkboxSyncedDataNodes)
1809
+ return;
1810
+ this.checkboxSyncedDataNodes = dataNodes;
1811
+ this.unorderedOptions?.forEach((option) => option.markForCheck());
1812
+ });
1783
1813
  }
1784
1814
  emitNavigationEvent(option) {
1785
1815
  this.navigationChange.emit(new KbqTreeNavigationChange(this, option));