@nanoporetech-digital/components 3.5.0 → 3.6.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.
Files changed (226) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/cjs/{date-utils-c581f187.js → date-utils-42fbcb42.js} +5 -3
  3. package/dist/cjs/date-utils-42fbcb42.js.map +1 -0
  4. package/dist/cjs/index-41582c2a.js +2 -6
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/cjs/nano-components.cjs.js +1 -1
  7. package/dist/cjs/nano-datalist_3.cjs.entry.js +10 -5
  8. package/dist/cjs/nano-datalist_3.cjs.entry.js.map +1 -1
  9. package/dist/cjs/nano-date-input.cjs.entry.js +1 -1
  10. package/dist/cjs/nano-date-picker.cjs.entry.js +1 -1
  11. package/dist/cjs/nano-demo.cjs.entry.js +3 -2
  12. package/dist/cjs/nano-demo.cjs.entry.js.map +1 -1
  13. package/dist/cjs/nano-dropdown.cjs.entry.js +5 -2
  14. package/dist/cjs/nano-dropdown.cjs.entry.js.map +1 -1
  15. package/dist/cjs/nano-file-upload.cjs.entry.js +4 -0
  16. package/dist/cjs/nano-file-upload.cjs.entry.js.map +1 -1
  17. package/dist/cjs/nano-global-nav-user-profile_3.cjs.entry.js +1 -2
  18. package/dist/cjs/nano-global-nav-user-profile_3.cjs.entry.js.map +1 -1
  19. package/dist/cjs/nano-icon-button.cjs.entry.js +1 -1
  20. package/dist/cjs/nano-icon-button.cjs.entry.js.map +1 -1
  21. package/dist/cjs/nano-icon.cjs.entry.js.map +1 -1
  22. package/dist/cjs/{nano-tooltip.cjs.entry.js → nano-progress-bar_2.cjs.entry.js} +28 -4
  23. package/dist/cjs/nano-progress-bar_2.cjs.entry.js.map +1 -0
  24. package/dist/cjs/nano-resize-observe_2.cjs.entry.js +74 -12
  25. package/dist/cjs/nano-resize-observe_2.cjs.entry.js.map +1 -1
  26. package/dist/cjs/nano-sticker.cjs.entry.js +2 -0
  27. package/dist/cjs/nano-sticker.cjs.entry.js.map +1 -1
  28. package/dist/cjs/nano-tab-group.cjs.entry.js +1 -1
  29. package/dist/cjs/nano-tab-group.cjs.entry.js.map +1 -1
  30. package/dist/cjs/{nano-table-83e46f68.js → nano-table-b031ec24.js} +164 -84
  31. package/dist/cjs/nano-table-b031ec24.js.map +1 -0
  32. package/dist/cjs/nano-table.cjs.entry.js +1 -1
  33. package/dist/cjs/{table.worker-525ec230.js → table.worker-dadd1eb0.js} +3 -3
  34. package/dist/cjs/table.worker-dadd1eb0.js.map +1 -0
  35. package/dist/{esm/table.worker-e9fb087e.js → cjs/table.worker-e2f9ccfa.js} +1 -1
  36. package/dist/collection/components/datalist/datalist.js +3 -3
  37. package/dist/collection/components/datalist/datalist.js.map +1 -1
  38. package/dist/collection/components/demo/demo.js +3 -2
  39. package/dist/collection/components/demo/demo.js.map +1 -1
  40. package/dist/collection/components/dropdown/dropdown.js +5 -2
  41. package/dist/collection/components/dropdown/dropdown.js.map +1 -1
  42. package/dist/collection/components/file-upload/file-upload.js +4 -0
  43. package/dist/collection/components/file-upload/file-upload.js.map +1 -1
  44. package/dist/collection/components/icon/icon.js +1 -1
  45. package/dist/collection/components/icon/icon.js.map +1 -1
  46. package/dist/collection/components/icon-button/icon-button.js +1 -1
  47. package/dist/collection/components/icon-button/icon-button.js.map +1 -1
  48. package/dist/collection/components/menu/menu.js +8 -3
  49. package/dist/collection/components/menu/menu.js.map +1 -1
  50. package/dist/collection/components/nav-item/nav-item.js +1 -2
  51. package/dist/collection/components/nav-item/nav-item.js.map +1 -1
  52. package/dist/collection/components/resize-observe/resize-observe.js +118 -14
  53. package/dist/collection/components/resize-observe/resize-observe.js.map +1 -1
  54. package/dist/collection/components/sticker/sticker.js +2 -0
  55. package/dist/collection/components/sticker/sticker.js.map +1 -1
  56. package/dist/collection/components/table/table-interface.js.map +1 -1
  57. package/dist/collection/components/table/table.cell.js +10 -5
  58. package/dist/collection/components/table/table.cell.js.map +1 -1
  59. package/dist/collection/components/table/table.css +9 -23
  60. package/dist/collection/components/table/table.js +227 -88
  61. package/dist/collection/components/table/table.js.map +1 -1
  62. package/dist/collection/components/table/table.row.js +19 -12
  63. package/dist/collection/components/table/table.row.js.map +1 -1
  64. package/dist/collection/components/table/table.store.js +1 -1
  65. package/dist/collection/components/table/table.store.js.map +1 -1
  66. package/dist/collection/components/table/table.utils.js +4 -4
  67. package/dist/collection/components/table/table.utils.js.map +1 -1
  68. package/dist/collection/components/table/table.worker.js +8 -0
  69. package/dist/collection/components/table/table.worker.js.map +1 -1
  70. package/dist/collection/components/tabs/tab-group.js +1 -1
  71. package/dist/collection/components/tabs/tab-group.js.map +1 -1
  72. package/dist/collection/components/tooltip/tooltip.js +25 -3
  73. package/dist/collection/components/tooltip/tooltip.js.map +1 -1
  74. package/dist/collection/utils/date-utils.js +4 -2
  75. package/dist/collection/utils/date-utils.js.map +1 -1
  76. package/dist/collection/utils/testing/index.js +15 -8
  77. package/dist/collection/utils/testing/index.js.map +1 -1
  78. package/dist/components/datalist.js +3 -3
  79. package/dist/components/datalist.js.map +1 -1
  80. package/dist/components/date-picker.js +4 -2
  81. package/dist/components/date-picker.js.map +1 -1
  82. package/dist/components/dropdown.js +5 -2
  83. package/dist/components/dropdown.js.map +1 -1
  84. package/dist/components/icon-button.js +1 -1
  85. package/dist/components/icon-button.js.map +1 -1
  86. package/dist/components/icon.js.map +1 -1
  87. package/dist/components/menu.js +8 -3
  88. package/dist/components/menu.js.map +1 -1
  89. package/dist/components/nano-demo.js +21 -14
  90. package/dist/components/nano-demo.js.map +1 -1
  91. package/dist/components/nano-file-upload.js +4 -0
  92. package/dist/components/nano-file-upload.js.map +1 -1
  93. package/dist/components/nano-tab-group.js +1 -1
  94. package/dist/components/nano-tab-group.js.map +1 -1
  95. package/dist/components/nav-item.js +1 -2
  96. package/dist/components/nav-item.js.map +1 -1
  97. package/dist/components/resize-observe.js +80 -14
  98. package/dist/components/resize-observe.js.map +1 -1
  99. package/dist/components/sticker.js +2 -0
  100. package/dist/components/sticker.js.map +1 -1
  101. package/dist/components/table.js +187 -98
  102. package/dist/components/table.js.map +1 -1
  103. package/dist/components/table.worker.js +1 -1
  104. package/dist/components/tooltip.js +6 -3
  105. package/dist/components/tooltip.js.map +1 -1
  106. package/dist/custom-elements/index.js +277 -116
  107. package/dist/custom-elements/index.js.map +1 -1
  108. package/dist/esm/{date-utils-bb82b123.js → date-utils-6b7a6e1f.js} +5 -3
  109. package/dist/esm/date-utils-6b7a6e1f.js.map +1 -0
  110. package/dist/esm/index-3c280603.js +2 -6
  111. package/dist/esm/loader.js +1 -1
  112. package/dist/esm/nano-components.js +1 -1
  113. package/dist/esm/nano-datalist_3.entry.js +10 -5
  114. package/dist/esm/nano-datalist_3.entry.js.map +1 -1
  115. package/dist/esm/nano-date-input.entry.js +1 -1
  116. package/dist/esm/nano-date-picker.entry.js +1 -1
  117. package/dist/esm/nano-demo.entry.js +3 -2
  118. package/dist/esm/nano-demo.entry.js.map +1 -1
  119. package/dist/esm/nano-dropdown.entry.js +5 -2
  120. package/dist/esm/nano-dropdown.entry.js.map +1 -1
  121. package/dist/esm/nano-file-upload.entry.js +4 -0
  122. package/dist/esm/nano-file-upload.entry.js.map +1 -1
  123. package/dist/esm/nano-global-nav-user-profile_3.entry.js +1 -2
  124. package/dist/esm/nano-global-nav-user-profile_3.entry.js.map +1 -1
  125. package/dist/esm/nano-icon-button.entry.js +1 -1
  126. package/dist/esm/nano-icon-button.entry.js.map +1 -1
  127. package/dist/esm/nano-icon.entry.js.map +1 -1
  128. package/dist/esm/{nano-tooltip.entry.js → nano-progress-bar_2.entry.js} +29 -6
  129. package/dist/esm/nano-progress-bar_2.entry.js.map +1 -0
  130. package/dist/esm/nano-resize-observe_2.entry.js +74 -12
  131. package/dist/esm/nano-resize-observe_2.entry.js.map +1 -1
  132. package/dist/esm/nano-sticker.entry.js +2 -0
  133. package/dist/esm/nano-sticker.entry.js.map +1 -1
  134. package/dist/esm/nano-tab-group.entry.js +1 -1
  135. package/dist/esm/nano-tab-group.entry.js.map +1 -1
  136. package/dist/esm/{nano-table-e2405350.js → nano-table-74d627a5.js} +164 -84
  137. package/dist/esm/nano-table-74d627a5.js.map +1 -0
  138. package/dist/esm/nano-table.entry.js +1 -1
  139. package/dist/esm/{table.worker-739c193f.js → table.worker-2908df63.js} +3 -3
  140. package/dist/esm/table.worker-2908df63.js.map +1 -0
  141. package/dist/{nano-components/p-e9fb087e.js → esm/table.worker-e2f9ccfa.js} +1 -1
  142. package/dist/nano-components/nano-components.esm.js +1 -1
  143. package/dist/nano-components/nano-components.esm.js.map +1 -1
  144. package/dist/nano-components/p-135fed16.entry.js +5 -0
  145. package/dist/nano-components/p-135fed16.entry.js.map +1 -0
  146. package/dist/nano-components/{p-2cb4615b.entry.js → p-2a97ef51.entry.js} +2 -2
  147. package/dist/nano-components/{p-2cb4615b.entry.js.map → p-2a97ef51.entry.js.map} +0 -0
  148. package/dist/nano-components/{p-751927d1.entry.js → p-3f25fc76.entry.js} +2 -2
  149. package/dist/nano-components/p-3f25fc76.entry.js.map +1 -0
  150. package/dist/nano-components/p-5d149792.entry.js +5 -0
  151. package/dist/nano-components/p-5d149792.entry.js.map +1 -0
  152. package/dist/nano-components/p-69e5a37d.entry.js.map +1 -1
  153. package/dist/nano-components/p-6ad194e4.entry.js +5 -0
  154. package/dist/nano-components/p-6ad194e4.entry.js.map +1 -0
  155. package/dist/nano-components/{p-46b348b7.entry.js → p-6cb77d5c.entry.js} +2 -2
  156. package/dist/nano-components/{p-46b348b7.entry.js.map → p-6cb77d5c.entry.js.map} +0 -0
  157. package/dist/nano-components/{p-85cfb0af.entry.js → p-9a4297e1.entry.js} +2 -2
  158. package/dist/nano-components/p-9a4297e1.entry.js.map +1 -0
  159. package/dist/nano-components/{p-d1c8eca4.entry.js → p-b55ffa92.entry.js} +2 -2
  160. package/dist/nano-components/p-b55ffa92.entry.js.map +1 -0
  161. package/dist/nano-components/p-cc5e7acb.entry.js +5 -0
  162. package/dist/nano-components/p-cc5e7acb.entry.js.map +1 -0
  163. package/dist/nano-components/p-cecb9af1.js +5 -0
  164. package/dist/nano-components/p-cecb9af1.js.map +1 -0
  165. package/dist/nano-components/{p-601e18d5.entry.js → p-d5303933.entry.js} +2 -2
  166. package/dist/nano-components/p-d5303933.entry.js.map +1 -0
  167. package/dist/nano-components/{p-4f0e14b5.entry.js → p-d565991d.entry.js} +2 -2
  168. package/dist/nano-components/p-d565991d.entry.js.map +1 -0
  169. package/dist/nano-components/p-d7ed2d6e.js +5 -0
  170. package/dist/nano-components/p-d7ed2d6e.js.map +1 -0
  171. package/dist/nano-components/p-d81d40d9.js +5 -0
  172. package/dist/nano-components/{p-a71989f3.js.map → p-d81d40d9.js.map} +0 -0
  173. package/dist/nano-components/{p-244223f0.entry.js → p-dc50b93c.entry.js} +2 -2
  174. package/dist/nano-components/p-dc50b93c.entry.js.map +1 -0
  175. package/dist/{cjs/table.worker-e9fb087e.js → nano-components/p-e2f9ccfa.js} +1 -1
  176. package/dist/nano-components/{p-e4a28360.entry.js → p-f5ee07b3.entry.js} +2 -2
  177. package/dist/nano-components/{p-e4a28360.entry.js.map → p-f5ee07b3.entry.js.map} +0 -0
  178. package/dist/types/components/icon/icon.d.ts +1 -1
  179. package/dist/types/components/menu/menu.d.ts +1 -0
  180. package/dist/types/components/resize-observe/resize-observe.d.ts +20 -1
  181. package/dist/types/components/table/table-interface.d.ts +35 -24
  182. package/dist/types/components/table/table.cell.d.ts +1 -1
  183. package/dist/types/components/table/table.d.ts +48 -15
  184. package/dist/types/components/table/table.row.d.ts +1 -1
  185. package/dist/types/components/table/table.store.d.ts +1 -1
  186. package/dist/types/components/table/table.utils.d.ts +1 -1
  187. package/dist/types/components/table/table.worker.d.ts +3 -3
  188. package/dist/types/components/tooltip/tooltip.d.ts +5 -0
  189. package/dist/types/components.d.ts +59 -14
  190. package/dist/types/utils/date-utils.d.ts +1 -1
  191. package/docs-json.json +179 -31
  192. package/docs-vscode.json +26 -3
  193. package/package.json +3 -3
  194. package/dist/cjs/date-utils-c581f187.js.map +0 -1
  195. package/dist/cjs/nano-progress-bar.cjs.entry.js +0 -33
  196. package/dist/cjs/nano-progress-bar.cjs.entry.js.map +0 -1
  197. package/dist/cjs/nano-table-83e46f68.js.map +0 -1
  198. package/dist/cjs/nano-tooltip.cjs.entry.js.map +0 -1
  199. package/dist/cjs/table.worker-525ec230.js.map +0 -1
  200. package/dist/esm/date-utils-bb82b123.js.map +0 -1
  201. package/dist/esm/nano-progress-bar.entry.js +0 -29
  202. package/dist/esm/nano-progress-bar.entry.js.map +0 -1
  203. package/dist/esm/nano-table-e2405350.js.map +0 -1
  204. package/dist/esm/nano-tooltip.entry.js.map +0 -1
  205. package/dist/esm/table.worker-739c193f.js.map +0 -1
  206. package/dist/nano-components/p-15a60f7e.js +0 -5
  207. package/dist/nano-components/p-15a60f7e.js.map +0 -1
  208. package/dist/nano-components/p-244223f0.entry.js.map +0 -1
  209. package/dist/nano-components/p-28fdfa6b.js +0 -5
  210. package/dist/nano-components/p-28fdfa6b.js.map +0 -1
  211. package/dist/nano-components/p-4f0e14b5.entry.js.map +0 -1
  212. package/dist/nano-components/p-601e18d5.entry.js.map +0 -1
  213. package/dist/nano-components/p-751927d1.entry.js.map +0 -1
  214. package/dist/nano-components/p-85cfb0af.entry.js.map +0 -1
  215. package/dist/nano-components/p-9e8c9bac.entry.js +0 -5
  216. package/dist/nano-components/p-9e8c9bac.entry.js.map +0 -1
  217. package/dist/nano-components/p-a2e38472.entry.js +0 -5
  218. package/dist/nano-components/p-a2e38472.entry.js.map +0 -1
  219. package/dist/nano-components/p-a71989f3.js +0 -5
  220. package/dist/nano-components/p-b9c8b99f.entry.js +0 -5
  221. package/dist/nano-components/p-b9c8b99f.entry.js.map +0 -1
  222. package/dist/nano-components/p-d1c8eca4.entry.js.map +0 -1
  223. package/dist/nano-components/p-f43d1d8e.entry.js +0 -5
  224. package/dist/nano-components/p-f43d1d8e.entry.js.map +0 -1
  225. package/dist/nano-components/p-feb9f164.entry.js +0 -5
  226. package/dist/nano-components/p-feb9f164.entry.js.map +0 -1
@@ -42,21 +42,31 @@ let id = 0;
42
42
  export class Table {
43
43
  constructor() {
44
44
  this.debounceSetLoading = (l) => {
45
- this._loading = l;
45
+ this.internalLoading = l;
46
46
  };
47
47
  this.renderId = 'tbl-' + id++;
48
48
  this.filters = [];
49
49
  this.currentFilters = '[]';
50
50
  this.currentSort = '';
51
+ this.measureHeight = 0;
51
52
  this.blockIos = new WeakMap();
52
53
  this.blockHeights = [];
53
54
  this.unitHeight = 0;
54
55
  // Scroll / IO used for hiding / showing blocks
55
56
  this.ignoreIO = true;
56
57
  this._isReady = false;
58
+ /**
59
+ * Fired when a column is dragged
60
+ * @param column
61
+ */
57
62
  this.colDrag = (column) => {
58
63
  this.nanoTblColDrag.emit({ column });
59
64
  };
65
+ /**
66
+ * Fired when a column is dropped after being dragged
67
+ * @param fromCol
68
+ * @param toCol
69
+ */
60
70
  this.colDrop = (fromCol, toCol) => {
61
71
  const cols = this.store.config.state.columns;
62
72
  const toIndex = cols.findIndex((col) => col.prop === toCol);
@@ -69,7 +79,7 @@ export class Table {
69
79
  });
70
80
  if (dropEvent.defaultPrevented)
71
81
  return;
72
- this.store.config.state.columns = arrMove(fromIndex, toIndex, cols);
82
+ this.columns = arrMove(fromIndex, toIndex, cols);
73
83
  };
74
84
  /**
75
85
  * Start a sort - can be cancelled by `preventDefault`
@@ -81,7 +91,7 @@ export class Table {
81
91
  // did order change?
82
92
  if (this.currentSort === order + ':' + column)
83
93
  return;
84
- this.loading = true;
94
+ this._loading = true;
85
95
  const sortEvent = this.nanoTblBeforeSort.emit({ column: column, order });
86
96
  if (sortEvent.defaultPrevented)
87
97
  return;
@@ -91,13 +101,24 @@ export class Table {
91
101
  this.scrollToTop(element);
92
102
  if (this.customSortFn) {
93
103
  try {
94
- await this.customSortFn(column, order);
95
- this.sortComplete(order, column);
104
+ const res = await this.customSortFn(column, order);
105
+ // if the response is 'true', the custom sort did it's thing
106
+ // handover to finish and stop loading state.
107
+ // if response is falsey, carry on to do a FE sort
108
+ if (res === true) {
109
+ this.sortComplete(order, column);
110
+ this._loading = false;
111
+ return;
112
+ }
96
113
  }
97
114
  catch (e) {
115
+ // if response errored, stop loading state
116
+ // clear current sort cache
98
117
  console.warn('custom sort failed', e);
118
+ this.currentSort = '';
119
+ this._loading = false;
120
+ return;
99
121
  }
100
- return;
101
122
  }
102
123
  try {
103
124
  await storeSort(this.host, column, order);
@@ -108,7 +129,8 @@ export class Table {
108
129
  this.currentSort = '';
109
130
  }
110
131
  finally {
111
- this.loading = false;
132
+ if (this.blocks.length)
133
+ this._loading = false;
112
134
  }
113
135
  };
114
136
  /**
@@ -121,31 +143,35 @@ export class Table {
121
143
  if (!el || this.blockIos.has(el))
122
144
  return;
123
145
  const blockIo = new IntersectionObserver(([ioEntry]) => {
124
- if (this.ignoreIO)
146
+ if (ioEntry.intersectionRatio === 0)
125
147
  return;
126
- if (ioEntry.isIntersecting) {
127
- // This is a bit gross
128
- // The Intersection Observer (IO) fires in an incorrect order when the scrolling is very fast
129
- // i.e. we go past blocks 3, 2, 1 and land on 0, but 3 can fire as 'intersecting' after 0.
130
- // To fix that, we check - for realzies - if the block IS visible.
131
- // BUT that test is not as sensitive to a block being visible via the IO,
132
- // so doesn't always fire if scrolling slowly
133
- // *sigh*
134
- readTask(() => {
135
- if (this.scrollSpeed < 100 || isInViewport(el, 0.01)) {
136
- this.activeBlocks = [
148
+ // This is a bit gross
149
+ // The Intersection Observer (IO) fires in an incorrect order when the scrolling is very fast
150
+ // i.e. we go past blocks 3, 2, 1 and land on 0, but 3 can fire as 'intersecting' after 0.
151
+ // To fix that, we check - for realzies - if the block IS visible.
152
+ // BUT that test is not as sensitive to a block being visible via the IO,
153
+ // so doesn't always fire if scrolling slowly
154
+ // *sigh*
155
+ readTask(() => {
156
+ if (this.scrollSpeed < 100 || isInViewport(el, 0.01)) {
157
+ if (!this.ignoreIO) {
158
+ const potentialBlocks = [
137
159
  blockIndex,
138
160
  blockIndex + 1,
139
161
  Math.max(0, blockIndex - 1),
140
162
  ];
141
- this.nanoTblBlockRendered.emit({
142
- block: blockIndex,
143
- totalBlocks: this.blockElements.length,
144
- });
145
- requestAnimationFrame(() => this.setBlockHeight());
163
+ if (potentialBlocks.toString() !== this.activeBlocks.toString()) {
164
+ this.activeBlocks = potentialBlocks;
165
+ this.setBlockHeight();
166
+ }
146
167
  }
147
- });
148
- }
168
+ // fire the event regardless
169
+ this.nanoTblBlockRendered.emit({
170
+ block: blockIndex,
171
+ totalBlocks: this.blockElements.length,
172
+ });
173
+ }
174
+ });
149
175
  }, {
150
176
  threshold: [0],
151
177
  root: this.scrollParent === document.scrollingElement
@@ -167,7 +193,8 @@ export class Table {
167
193
  this.type = 'table';
168
194
  this.caption = undefined;
169
195
  this.showCaption = false;
170
- this._loading = false;
196
+ this.loading = undefined;
197
+ this.internalLoading = false;
171
198
  this.placeholderSize = 5;
172
199
  this.rows = undefined;
173
200
  this.columns = [];
@@ -181,26 +208,25 @@ export class Table {
181
208
  this.customSortFn = undefined;
182
209
  this.defaultSort = true;
183
210
  this.defaultColDraggable = false;
211
+ this.virtualTotalItems = 0;
184
212
  this.blocks = [];
185
213
  this.activeBlocks = [0, 1, 2];
186
- this.measureHeight = 0;
187
214
  this.debounceSetLoading = debounce(this.debounceSetLoading.bind(this), 50);
188
215
  }
189
- /** Will show a loading state when true.
190
- * Will be shown automatically if `rows` is a promise waiting to resolve
191
- * or when performing custom filtering or sorting */
192
- get loading() {
193
- return this._loading;
216
+ get _loading() {
217
+ return this.loading !== undefined ? this.loading : this.internalLoading;
194
218
  }
195
- set loading(l) {
219
+ set _loading(l) {
220
+ if (this.loading !== undefined)
221
+ return;
196
222
  this.debounceSetLoading(l);
197
223
  }
198
224
  handleRowsChange() {
199
225
  if (!this.rows) {
200
- this.loading = true;
226
+ this._loading = true;
201
227
  return;
202
228
  }
203
- this.loading = true;
229
+ this._loading = true;
204
230
  Promise.resolve(this.rows).then(async (rows) => {
205
231
  await storeSetData(this.host, rows);
206
232
  // reset everything
@@ -209,7 +235,7 @@ export class Table {
209
235
  await this.columnInit();
210
236
  if (!this.isReady)
211
237
  this.setInitialBlockDimension();
212
- this.loading = false;
238
+ this._loading = false;
213
239
  });
214
240
  }
215
241
  async handleColsChange() {
@@ -224,6 +250,9 @@ export class Table {
224
250
  handleSearchTermChange() {
225
251
  this.searchStart();
226
252
  }
253
+ virtualTotalItemsChangeHandler() {
254
+ this.setBlocks();
255
+ }
227
256
  /** Remove any column sorts currently applied
228
257
  * @returns a promise which resolves when complete */
229
258
  async resetSorting() {
@@ -264,11 +293,25 @@ export class Table {
264
293
  this.filters = this.filters.filter((f) => !columnNames.includes(f.prop));
265
294
  return this.filterStart();
266
295
  }
296
+ /** Updates a row model at a given index
297
+ * @param row - the row to update.
298
+ * *Note* - this should come from the `col.cellTemplate` or `row.rowRender.template` `rowModel` property
299
+ * - rows are augmented with certain properties to aid with efficient rendering
300
+ * @param rowIndex - the row index to insert this row
301
+ */
302
+ async updateRow(row, rowIndex) {
303
+ this.rows.splice(rowIndex, 1, row);
304
+ this.handleRowsChange();
305
+ }
267
306
  // uses the first 'tr' of an active block as our yard stick
268
307
  set measureEle(el) {
269
308
  if (!el)
270
309
  return;
271
- this.measureHeight = el.getBoundingClientRect().height;
310
+ const potentialHeight = el.getBoundingClientRect().height;
311
+ this.measureHeight =
312
+ Math.abs(this.measureHeight - potentialHeight) < 5
313
+ ? this.measureHeight
314
+ : potentialHeight;
272
315
  this.unitHeight =
273
316
  el.querySelector('tr')?.getBoundingClientRect().height || this.unitHeight;
274
317
  }
@@ -315,7 +358,7 @@ export class Table {
315
358
  perMark('sort', true);
316
359
  }
317
360
  async searchStart() {
318
- this.loading = true;
361
+ this._loading = true;
319
362
  const sortEvent = this.nanoTblBeforeSearch.emit({ term: this.searchTerm });
320
363
  if (sortEvent.defaultPrevented)
321
364
  return;
@@ -331,7 +374,7 @@ export class Table {
331
374
  console.warn('search failed', e);
332
375
  }
333
376
  finally {
334
- this.loading = false;
377
+ this._loading = false;
335
378
  }
336
379
  }
337
380
  async filterStart(filters, additive = true) {
@@ -348,7 +391,7 @@ export class Table {
348
391
  }
349
392
  if (this.currentFilters === JSON.stringify(this.filters))
350
393
  return;
351
- this.loading = true;
394
+ this._loading = true;
352
395
  const sortEvent = this.nanoTblBeforeFilter.emit({ filters: this.filters });
353
396
  if (sortEvent.defaultPrevented)
354
397
  return;
@@ -358,12 +401,21 @@ export class Table {
358
401
  this.scrollToTop();
359
402
  if (this.customFilterFn) {
360
403
  try {
361
- await this.customFilterFn(this.filters);
362
- this.filterComplete();
404
+ const res = await this.customFilterFn(this.filters);
405
+ // if the response is 'true', the custom filter did it's thing
406
+ // handover to finish and stop loading state.
407
+ // if response is falsey, carry on to do a FE filter
408
+ if (res === true) {
409
+ this.filterComplete();
410
+ this._loading = false;
411
+ }
363
412
  }
364
413
  catch (e) {
414
+ // if response errored, stop loading state
415
+ // clear current sort cache
365
416
  console.warn('custom filter failed', e);
366
417
  this.currentFilters = '';
418
+ this._loading = false;
367
419
  }
368
420
  return;
369
421
  }
@@ -375,7 +427,7 @@ export class Table {
375
427
  console.warn('filter failed', e);
376
428
  }
377
429
  finally {
378
- this.loading = false;
430
+ this._loading = false;
379
431
  }
380
432
  }
381
433
  filterComplete() {
@@ -467,24 +519,34 @@ export class Table {
467
519
  * These can then be hidden / shown to improve performance.
468
520
  */
469
521
  setBlocks() {
522
+ const dRows = this.store.data.state.rows;
523
+ if (!dRows.length) {
524
+ this.blocks = [];
525
+ return;
526
+ }
470
527
  perMark('setBlocks');
471
- this.activeBlocks = [0, 1, 2];
472
528
  this.ignoreIO = true;
473
529
  let i = 1;
474
- const l = this.store.data.state.rows.length;
530
+ const l = this.virtualTotalItems > dRows.length
531
+ ? this.virtualTotalItems
532
+ : dRows.length;
475
533
  let rows = [];
476
534
  const blocks = [];
477
535
  this.blockHeights = [];
478
536
  // old skool loop for perf
479
537
  for (i; i <= l; i++) {
480
- rows.push(this.store.data.state.rows[i - 1]);
538
+ rows.push(this.store.data.state.rows[i - 1] || { __uuid: '' });
481
539
  if (i % this.perBlock === 0) {
540
+ // assign a UUID for the whole block
541
+ // for block diffing
482
542
  blocks.push({ rows, __uuid: cyrb53(rows.map((b) => b.__uuid).join()) });
483
543
  rows = [];
484
544
  }
485
545
  }
486
- if (rows.length)
546
+ // any leftover rows
547
+ if (rows.length) {
487
548
  blocks.push({ rows, __uuid: cyrb53(rows.map((b) => b.__uuid).join()) });
549
+ }
488
550
  this.blocks = blocks;
489
551
  perMark('setBlocks', true);
490
552
  }
@@ -512,11 +574,11 @@ export class Table {
512
574
  }
513
575
  /** cache the height for all active blocks for later renders */
514
576
  setBlockHeight() {
515
- readTask(() => {
516
- this.activeBlocks.forEach((blockIndex) => {
517
- const el = this.blockElements[blockIndex];
518
- if (!el)
519
- return;
577
+ this.activeBlocks.forEach((blockIndex) => {
578
+ const el = this.blockElements[blockIndex];
579
+ if (!el)
580
+ return;
581
+ readTask(() => {
520
582
  const height = el.getBoundingClientRect().height;
521
583
  // cache height to our block heights array
522
584
  // for subsequent renders
@@ -558,6 +620,8 @@ export class Table {
558
620
  // but we don't want it to cause renders
559
621
  if (['rows', 'columns'].includes(stateName))
560
622
  return false;
623
+ if (Build.isDev)
624
+ console.log(stateName, _newVal, _oldVal);
561
625
  }
562
626
  componentWillRender() {
563
627
  perMark('render');
@@ -580,15 +644,15 @@ export class Table {
580
644
  sortable: this.defaultSort,
581
645
  draggable: this.defaultColDraggable,
582
646
  } }),
583
- ]))), this._loading && !this.blocks.length && (h("tbody", { class: `${CSSNAMESPACE}__active` }, [...Array(10).keys()].map((rowIndex) => (h("tr", null, this.store.config.state.columns.map((_colModel, colIndex) => (h(TableCell, { rowIndex: rowIndex, colIndex: colIndex, nestedContent: h("nano-skeleton", null) })))))))), !this._loading && !this.blocks.length && (h("tr", null, h("th", { class: `${CSSNAMESPACE}__th`, colSpan: this.store.config.state.columns.length }, h("div", { class: "nano-tbl__cell-content nano-tbl__cell-content--no-result" }, h("slot", { name: "no-results" }, "No results found"))))), this.blocks.map((block, blockIndex) => (h("tbody", { key: block.__uuid, id: `tbody-${this.renderId}-${blockIndex}`, ref: (tb) => {
647
+ ]))), this._loading && !this.blocks.length && (h("tbody", { class: `${CSSNAMESPACE}__active` }, [...Array(10).keys()].map((rowIndex) => (h("tr", null, this.store.config.state.columns.map((_colModel, colIndex) => (h(TableCell, { rowIndex: rowIndex, colIndex: colIndex, nestedContent: () => h("nano-skeleton", null) })))))))), !this._loading && !this.blocks.length && (h("tr", null, h("th", { class: `${CSSNAMESPACE}__th`, colSpan: this.store.config.state.columns.length }, h("div", { class: "nano-tbl__cell-content nano-tbl__cell-content--no-result" }, h("slot", { name: "no-results" }, "No results found"))))), this.blocks.map((block, blockIndex) => (h("tbody", { key: block.__uuid, id: `tbody-${this.renderId}-${blockIndex}`, ref: (tb) => {
584
648
  this.blockElements.push(tb);
585
- this.setupBlockIO(tb, blockIndex);
649
+ requestAnimationFrame(() => this.setupBlockIO(tb, blockIndex));
586
650
  }, class: {
587
651
  [`${CSSNAMESPACE}__inactive`]: !this.activeBlocks.includes(blockIndex),
588
652
  [`${CSSNAMESPACE}__active`]: this.activeBlocks.includes(blockIndex),
589
653
  } }, this.activeBlocks.includes(blockIndex) ? (block.rows.map((row, i) => {
590
654
  const rowIndex = blockIndex > 0 ? blockIndex * this.perBlock + i : i;
591
- return (h(TableRow, { rowRenderer: this.rowRender, row: row, rowIndex: rowIndex }, this.store.config.state.columns.map((_colModel, colIndex) => (h(TableCell, { rowIndex: rowIndex, colIndex: colIndex })))));
655
+ return (h(TableRow, { rowRenderer: this.rowRender, rowModel: row, rowIndex: rowIndex }, this.store.config.state.columns.map((_colModel, colIndex) => (h(TableCell, { rowIndex: rowIndex, colIndex: colIndex })))));
592
656
  })) : (h("td", { colSpan: this.store.config.state.columns.length, style: {
593
657
  height: this.getBlockHeight(blockIndex),
594
658
  } }))))), this.showFooter && (h("tfoot", null, h(TableHeadFootRow, { rowRenderer: this.footRender, onColumnPinned: this.handleColumnPinned }, this.store.config.state.columns.map((colModel) => [
@@ -685,13 +749,13 @@ export class Table {
685
749
  "optional": false,
686
750
  "docs": {
687
751
  "tags": [],
688
- "text": "Will show a loading state when true.\nWill be shown automatically if `rows` is a promise waiting to resolve\nor when performing custom filtering or sorting"
752
+ "text": "Will show a loading state when set to true.\nBy default, will be shown automatically if `rows` is a promise waiting to resolve\nor when performing custom filtering or sorting.\n*Note* when set manually, will overwrite any internal loading state.\nSet to 'undefined' to revert to default behaviour."
689
753
  },
690
- "getter": true,
691
- "setter": true,
754
+ "getter": false,
755
+ "setter": false,
692
756
  "attribute": "loading",
693
757
  "reflect": false,
694
- "defaultValue": "false"
758
+ "defaultValue": "undefined"
695
759
  },
696
760
  "placeholderSize": {
697
761
  "type": "number",
@@ -715,10 +779,10 @@ export class Table {
715
779
  },
716
780
  "rows": {
717
781
  "type": "unknown",
718
- "mutable": false,
782
+ "mutable": true,
719
783
  "complexType": {
720
784
  "original": "| TableTypes.NanoTable['rows']\n | Promise<TableTypes.NanoTable['rows']>",
721
- "resolved": "Promise<RowData[]> | RowData[]",
785
+ "resolved": "Promise<RowGeneric[]> | RowGeneric[]",
722
786
  "references": {
723
787
  "TableTypes": {
724
788
  "location": "import",
@@ -743,7 +807,7 @@ export class Table {
743
807
  "mutable": true,
744
808
  "complexType": {
745
809
  "original": "TableTypes.NanoTable['columns']",
746
- "resolved": "ColumnConfig<RowData>[]",
810
+ "resolved": "ColumnConfig<RowGeneric>[]",
747
811
  "references": {
748
812
  "TableTypes": {
749
813
  "location": "import",
@@ -755,7 +819,7 @@ export class Table {
755
819
  "optional": false,
756
820
  "docs": {
757
821
  "tags": [],
758
- "text": "The column config used to generate present the rows of data"
822
+ "text": "The column config used to present the rows of data"
759
823
  },
760
824
  "getter": false,
761
825
  "setter": false,
@@ -789,7 +853,7 @@ export class Table {
789
853
  "mutable": false,
790
854
  "complexType": {
791
855
  "original": "TableTypes.RowRenderer",
792
- "resolved": "RowRenderer",
856
+ "resolved": "RowRenderer<RowData<RowGeneric>>",
793
857
  "references": {
794
858
  "TableTypes": {
795
859
  "location": "import",
@@ -911,8 +975,8 @@ export class Table {
911
975
  "type": "unknown",
912
976
  "mutable": false,
913
977
  "complexType": {
914
- "original": "(filters: TableTypes.Filter[]) => Promise<void>",
915
- "resolved": "(filters: Filter[]) => Promise<void>",
978
+ "original": "(\n filters: TableTypes.Filter[]\n ) => Promise<true | TableTypes.Falsy>",
979
+ "resolved": "(filters: Filter[]) => Promise<true | Falsy>",
916
980
  "references": {
917
981
  "TableTypes": {
918
982
  "location": "import",
@@ -927,7 +991,7 @@ export class Table {
927
991
  "optional": true,
928
992
  "docs": {
929
993
  "tags": [],
930
- "text": "A custom filtering function. Should return a promise.\nOn successful completion the column UI will be updated.\nA good use-case would be performing the filter on a server / via fetch.\nThen on success, updating the table's data via the `rows` property"
994
+ "text": "A custom filtering function. Should return a promise.\nIf the promise resolves as `true` the column UI will be updated.\nIf the promise resolves as falsey, the sort will be performed by the component.\nA good use-case would be performing the filter on a server / via fetch.\nThen on success, updating the table's data via the `rows` property"
931
995
  },
932
996
  "getter": false,
933
997
  "setter": false
@@ -936,8 +1000,8 @@ export class Table {
936
1000
  "type": "unknown",
937
1001
  "mutable": false,
938
1002
  "complexType": {
939
- "original": "(\n property: TableTypes.Prop,\n order: TableTypes.Order\n ) => Promise<void>",
940
- "resolved": "(property: keyof RowData, order: Order) => Promise<void>",
1003
+ "original": "(\n property: TableTypes.Prop,\n order: TableTypes.Order\n ) => Promise<true | TableTypes.Falsy>",
1004
+ "resolved": "(property: keyof RowGeneric, order: Order) => Promise<true | Falsy>",
941
1005
  "references": {
942
1006
  "TableTypes": {
943
1007
  "location": "import",
@@ -952,7 +1016,7 @@ export class Table {
952
1016
  "optional": true,
953
1017
  "docs": {
954
1018
  "tags": [],
955
- "text": "A custom sorting function. Should return a promise.\nOn successful completion the column UI will be updated.\nA good use-case would be performing the sort on a server / via fetch.\nThen on success, updating the table's data via the `rows` property"
1019
+ "text": "A custom sorting function. Should return a promise.\nIf the promise resolves as `true` the column UI will be updated.\nIf the promise resolves as falsey, the sort will be performed by the component.\nA good use-case would be performing the sort on a server / via fetch.\nThen on success, updating the table's data via the `rows` property"
956
1020
  },
957
1021
  "getter": false,
958
1022
  "setter": false
@@ -996,46 +1060,65 @@ export class Table {
996
1060
  "attribute": "default-col-draggable",
997
1061
  "reflect": false,
998
1062
  "defaultValue": "false"
1063
+ },
1064
+ "virtualTotalItems": {
1065
+ "type": "number",
1066
+ "mutable": false,
1067
+ "complexType": {
1068
+ "original": "number",
1069
+ "resolved": "number",
1070
+ "references": {}
1071
+ },
1072
+ "required": false,
1073
+ "optional": false,
1074
+ "docs": {
1075
+ "tags": [],
1076
+ "text": "Use this to render the table with roughly the correct dimensions.\na use-case might be; fetch a small initial dataset to minimise load-time,\nrender the table with the correct dimensions, the table becomes interactive,\nload the rest of the data"
1077
+ },
1078
+ "getter": false,
1079
+ "setter": false,
1080
+ "attribute": "virtual-total-items",
1081
+ "reflect": false,
1082
+ "defaultValue": "0"
999
1083
  }
1000
1084
  };
1001
1085
  }
1002
1086
  static get states() {
1003
1087
  return {
1004
- "_loading": {},
1088
+ "internalLoading": {},
1005
1089
  "blocks": {},
1006
- "activeBlocks": {},
1007
- "measureHeight": {}
1090
+ "activeBlocks": {}
1008
1091
  };
1009
1092
  }
1010
1093
  static get events() {
1011
1094
  return [{
1012
- "method": "nanoTblBlockRendered",
1013
- "name": "nanoTblBlockRendered",
1095
+ "method": "nanoTblReady",
1096
+ "name": "nanoTblReady",
1014
1097
  "bubbles": true,
1015
1098
  "cancelable": true,
1016
1099
  "composed": true,
1017
1100
  "docs": {
1018
1101
  "tags": [],
1019
- "text": "Fired whenever a block is activated by scrolling into view / becoming visible\nThis could be leveraged for infinite scrolling / to fetch more data."
1102
+ "text": "Fired when the table has done it's first complete render"
1020
1103
  },
1021
1104
  "complexType": {
1022
- "original": "{\n block: number;\n totalBlocks: number;\n }",
1023
- "resolved": "{ block: number; totalBlocks: number; }",
1105
+ "original": "any",
1106
+ "resolved": "any",
1024
1107
  "references": {}
1025
1108
  }
1026
1109
  }, {
1027
- "method": "nanoTblReady",
1028
- "name": "nanoTblReady",
1110
+ "method": "nanoTblBlockRendered",
1111
+ "name": "nanoTblBlockRendered",
1029
1112
  "bubbles": true,
1030
1113
  "cancelable": true,
1031
1114
  "composed": true,
1032
1115
  "docs": {
1033
1116
  "tags": [],
1034
- "text": "Fired when the table has done it's first complete render"
1117
+ "text": "Fired whenever a block is activated by scrolling into view / becoming visible\nThis could be leveraged for infinite scrolling / to fetch more data."
1035
1118
  },
1036
1119
  "complexType": {
1037
- "original": "any",
1038
- "resolved": "any",
1120
+ "original": "{\n block: number;\n totalBlocks: number;\n }",
1121
+ "resolved": "{ block: number; totalBlocks: number; }",
1039
1122
  "references": {}
1040
1123
  }
1041
1124
  }, {
@@ -1050,7 +1133,7 @@ export class Table {
1050
1133
  },
1051
1134
  "complexType": {
1052
1135
  "original": "{\n column: TableTypes.Prop;\n order: TableTypes.Order;\n }",
1053
- "resolved": "{ column: keyof RowData; order: Order; }",
1136
+ "resolved": "{ column: keyof RowGeneric; order: Order; }",
1054
1137
  "references": {
1055
1138
  "TableTypes": {
1056
1139
  "location": "import",
@@ -1070,7 +1153,7 @@ export class Table {
1070
1153
  },
1071
1154
  "complexType": {
1072
1155
  "original": "{\n column: TableTypes.Prop;\n order: TableTypes.Order;\n }",
1073
- "resolved": "{ column: keyof RowData; order: Order; }",
1156
+ "resolved": "{ column: keyof RowGeneric; order: Order; }",
1074
1157
  "references": {
1075
1158
  "TableTypes": {
1076
1159
  "location": "import",
@@ -1090,7 +1173,7 @@ export class Table {
1090
1173
  },
1091
1174
  "complexType": {
1092
1175
  "original": "{\n column: TableTypes.Prop;\n }",
1093
- "resolved": "{ column: keyof RowData; }",
1176
+ "resolved": "{ column: keyof RowGeneric; }",
1094
1177
  "references": {
1095
1178
  "TableTypes": {
1096
1179
  "location": "import",
@@ -1110,7 +1193,7 @@ export class Table {
1110
1193
  },
1111
1194
  "complexType": {
1112
1195
  "original": "{\n fromCol: TableTypes.Prop;\n toCol: TableTypes.Prop;\n fromIndex: number;\n toIndex: number;\n }",
1113
- "resolved": "{ fromCol: keyof RowData; toCol: keyof RowData; fromIndex: number; toIndex: number; }",
1196
+ "resolved": "{ fromCol: keyof RowGeneric; toCol: keyof RowGeneric; fromIndex: number; toIndex: number; }",
1114
1197
  "references": {
1115
1198
  "TableTypes": {
1116
1199
  "location": "import",
@@ -1188,6 +1271,21 @@ export class Table {
1188
1271
  "resolved": "{ term: string; }",
1189
1272
  "references": {}
1190
1273
  }
1274
+ }, {
1275
+ "method": "nanoTblBeforeEdit",
1276
+ "name": "nanoTblBeforeEdit",
1277
+ "bubbles": true,
1278
+ "cancelable": true,
1279
+ "composed": true,
1280
+ "docs": {
1281
+ "tags": [],
1282
+ "text": "Fired before a general search.\n`event.preventDefault()` to stop searching."
1283
+ },
1284
+ "complexType": {
1285
+ "original": "{ term: string }",
1286
+ "resolved": "{ term: string; }",
1287
+ "references": {}
1288
+ }
1191
1289
  }];
1192
1290
  }
1193
1291
  static get methods() {
@@ -1331,6 +1429,44 @@ export class Table {
1331
1429
  "text": "a promise which resolves when complete"
1332
1430
  }]
1333
1431
  }
1432
+ },
1433
+ "updateRow": {
1434
+ "complexType": {
1435
+ "signature": "(row: TableTypes.RowData, rowIndex: number) => Promise<void>",
1436
+ "parameters": [{
1437
+ "tags": [{
1438
+ "name": "param",
1439
+ "text": "row - the row to update.\n*Note* - this should come from the `col.cellTemplate` or `row.rowRender.template` `rowModel` property\n- rows are augmented with certain properties to aid with efficient rendering"
1440
+ }],
1441
+ "text": "- the row to update.\n*Note* - this should come from the `col.cellTemplate` or `row.rowRender.template` `rowModel` property\n- rows are augmented with certain properties to aid with efficient rendering"
1442
+ }, {
1443
+ "tags": [{
1444
+ "name": "param",
1445
+ "text": "rowIndex - the row index to insert this row"
1446
+ }],
1447
+ "text": "- the row index to insert this row"
1448
+ }],
1449
+ "references": {
1450
+ "Promise": {
1451
+ "location": "global"
1452
+ },
1453
+ "TableTypes": {
1454
+ "location": "import",
1455
+ "path": "../../interface"
1456
+ }
1457
+ },
1458
+ "return": "Promise<void>"
1459
+ },
1460
+ "docs": {
1461
+ "text": "Updates a row model at a given index",
1462
+ "tags": [{
1463
+ "name": "param",
1464
+ "text": "row - the row to update.\n*Note* - this should come from the `col.cellTemplate` or `row.rowRender.template` `rowModel` property\n- rows are augmented with certain properties to aid with efficient rendering"
1465
+ }, {
1466
+ "name": "param",
1467
+ "text": "rowIndex - the row index to insert this row"
1468
+ }]
1469
+ }
1334
1470
  }
1335
1471
  };
1336
1472
  }
@@ -1345,6 +1481,9 @@ export class Table {
1345
1481
  }, {
1346
1482
  "propName": "searchTerm",
1347
1483
  "methodName": "handleSearchTermChange"
1484
+ }, {
1485
+ "propName": "virtualTotalItems",
1486
+ "methodName": "virtualTotalItemsChangeHandler"
1348
1487
  }];
1349
1488
  }
1350
1489
  static get listeners() {