@nanoporetech-digital/components 5.1.2 → 5.2.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 (218) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/cjs/{component-store-74d25f63.js → component-store-f1dc1276.js} +2 -2
  3. package/dist/cjs/{component-store-74d25f63.js.map → component-store-f1dc1276.js.map} +1 -1
  4. package/dist/cjs/index.cjs.js +1 -1
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/cjs/nano-algolia-filter.cjs.entry.js +2 -2
  7. package/dist/cjs/nano-algolia-input.cjs.entry.js +2 -2
  8. package/dist/cjs/nano-algolia.cjs.entry.js +2 -2
  9. package/dist/cjs/nano-checkbox-group.cjs.entry.js +5 -1
  10. package/dist/cjs/nano-checkbox-group.cjs.entry.js.map +1 -1
  11. package/dist/cjs/nano-components.cjs.js +1 -1
  12. package/dist/cjs/nano-datalist_3.cjs.entry.js +14 -5
  13. package/dist/cjs/nano-datalist_3.cjs.entry.js.map +1 -1
  14. package/dist/cjs/nano-dialog.cjs.entry.js +2 -2
  15. package/dist/cjs/nano-global-nav-user-profile_3.cjs.entry.js +8 -5
  16. package/dist/cjs/nano-global-nav-user-profile_3.cjs.entry.js.map +1 -1
  17. package/dist/cjs/nano-global-nav.cjs.entry.js +2 -2
  18. package/dist/cjs/nano-input.cjs.entry.js +3 -3
  19. package/dist/cjs/nano-input.cjs.entry.js.map +1 -1
  20. package/dist/cjs/nano-overflow-nav.cjs.entry.js +1 -1
  21. package/dist/cjs/nano-range.cjs.entry.js +1 -1
  22. package/dist/cjs/nano-resize-observe_2.cjs.entry.js +3 -1
  23. package/dist/cjs/nano-resize-observe_2.cjs.entry.js.map +1 -1
  24. package/dist/cjs/nano-sortable.cjs.entry.js +18 -8
  25. package/dist/cjs/nano-sortable.cjs.entry.js.map +1 -1
  26. package/dist/cjs/nano-split-pane.cjs.entry.js +1 -1
  27. package/dist/cjs/nano-sticker.cjs.entry.js +4 -2
  28. package/dist/cjs/nano-sticker.cjs.entry.js.map +1 -1
  29. package/dist/cjs/nano-tab-group.cjs.entry.js +2 -2
  30. package/dist/cjs/{nano-table-0a720c5f.js → nano-table-04993bb4.js} +560 -186
  31. package/dist/cjs/nano-table-04993bb4.js.map +1 -0
  32. package/dist/cjs/nano-table.cjs.entry.js +2 -2
  33. package/dist/cjs/{table.worker-347d4d31.js → table.worker-85877b23.js} +4 -4
  34. package/dist/cjs/table.worker-85877b23.js.map +1 -0
  35. package/dist/cjs/{table.worker-bd51e29f.js → table.worker-f258383d.js} +1 -1
  36. package/dist/cjs/{throttle-f55496c8.js → throttle-dfa64b9e.js} +17 -20
  37. package/dist/cjs/throttle-dfa64b9e.js.map +1 -0
  38. package/dist/collection/components/checkbox/checkbox-group.js +4 -0
  39. package/dist/collection/components/checkbox/checkbox-group.js.map +1 -1
  40. package/dist/collection/components/datalist/datalist.js +13 -4
  41. package/dist/collection/components/datalist/datalist.js.map +1 -1
  42. package/dist/collection/components/input/input.css +1 -1
  43. package/dist/collection/components/input/input.js +1 -1
  44. package/dist/collection/components/input/input.js.map +1 -1
  45. package/dist/collection/components/nav-item/nav-item.js +6 -3
  46. package/dist/collection/components/nav-item/nav-item.js.map +1 -1
  47. package/dist/collection/components/resize-observe/resize-observe.js +21 -1
  48. package/dist/collection/components/resize-observe/resize-observe.js.map +1 -1
  49. package/dist/collection/components/select/select.css +1 -2
  50. package/dist/collection/components/sortable/sortable.js +5 -7
  51. package/dist/collection/components/sortable/sortable.js.map +1 -1
  52. package/dist/collection/components/sticker/sticker.js +11 -5
  53. package/dist/collection/components/sticker/sticker.js.map +1 -1
  54. package/dist/collection/components/table/table-interface.js.map +1 -1
  55. package/dist/collection/components/table/table.cell.js +43 -10
  56. package/dist/collection/components/table/table.cell.js.map +1 -1
  57. package/dist/collection/components/table/table.css +38 -55
  58. package/dist/collection/components/table/table.header.js +4 -9
  59. package/dist/collection/components/table/table.header.js.map +1 -1
  60. package/dist/collection/components/table/table.js +104 -48
  61. package/dist/collection/components/table/table.js.map +1 -1
  62. package/dist/collection/components/table/table.pin-service.js +382 -0
  63. package/dist/collection/components/table/table.pin-service.js.map +1 -0
  64. package/dist/collection/components/table/table.row.js +39 -46
  65. package/dist/collection/components/table/table.row.js.map +1 -1
  66. package/dist/collection/components/table/table.utils.js +0 -124
  67. package/dist/collection/components/table/table.utils.js.map +1 -1
  68. package/dist/collection/components/table/table.worker.js +1 -0
  69. package/dist/collection/components/table/table.worker.js.map +1 -1
  70. package/dist/collection/utils/events.js +27 -0
  71. package/dist/collection/utils/events.js.map +1 -0
  72. package/dist/collection/utils/throttle.js +16 -19
  73. package/dist/collection/utils/throttle.js.map +1 -1
  74. package/dist/components/datalist.js +13 -4
  75. package/dist/components/datalist.js.map +1 -1
  76. package/dist/components/input.js +2 -2
  77. package/dist/components/input.js.map +1 -1
  78. package/dist/components/nano-checkbox-group.js +4 -0
  79. package/dist/components/nano-checkbox-group.js.map +1 -1
  80. package/dist/components/nano-sortable.js +17 -7
  81. package/dist/components/nano-sortable.js.map +1 -1
  82. package/dist/components/nav-item.js +6 -3
  83. package/dist/components/nav-item.js.map +1 -1
  84. package/dist/components/resize-observe.js +3 -1
  85. package/dist/components/resize-observe.js.map +1 -1
  86. package/dist/components/select.js +1 -1
  87. package/dist/components/select.js.map +1 -1
  88. package/dist/components/sticker.js +3 -1
  89. package/dist/components/sticker.js.map +1 -1
  90. package/dist/components/table.js +533 -188
  91. package/dist/components/table.js.map +1 -1
  92. package/dist/components/table.worker.js +1 -1
  93. package/dist/components/throttle.js +16 -19
  94. package/dist/components/throttle.js.map +1 -1
  95. package/dist/esm/{component-store-244a8431.js → component-store-c23ebc9c.js} +2 -2
  96. package/dist/esm/{component-store-244a8431.js.map → component-store-c23ebc9c.js.map} +1 -1
  97. package/dist/esm/index.js +1 -1
  98. package/dist/esm/loader.js +1 -1
  99. package/dist/esm/nano-algolia-filter.entry.js +2 -2
  100. package/dist/esm/nano-algolia-input.entry.js +2 -2
  101. package/dist/esm/nano-algolia.entry.js +2 -2
  102. package/dist/esm/nano-checkbox-group.entry.js +5 -1
  103. package/dist/esm/nano-checkbox-group.entry.js.map +1 -1
  104. package/dist/esm/nano-components.js +1 -1
  105. package/dist/esm/nano-datalist_3.entry.js +14 -5
  106. package/dist/esm/nano-datalist_3.entry.js.map +1 -1
  107. package/dist/esm/nano-dialog.entry.js +2 -2
  108. package/dist/esm/nano-global-nav-user-profile_3.entry.js +8 -5
  109. package/dist/esm/nano-global-nav-user-profile_3.entry.js.map +1 -1
  110. package/dist/esm/nano-global-nav.entry.js +2 -2
  111. package/dist/esm/nano-input.entry.js +3 -3
  112. package/dist/esm/nano-input.entry.js.map +1 -1
  113. package/dist/esm/nano-overflow-nav.entry.js +1 -1
  114. package/dist/esm/nano-range.entry.js +1 -1
  115. package/dist/esm/nano-resize-observe_2.entry.js +3 -1
  116. package/dist/esm/nano-resize-observe_2.entry.js.map +1 -1
  117. package/dist/esm/nano-sortable.entry.js +18 -8
  118. package/dist/esm/nano-sortable.entry.js.map +1 -1
  119. package/dist/esm/nano-split-pane.entry.js +1 -1
  120. package/dist/esm/nano-sticker.entry.js +4 -2
  121. package/dist/esm/nano-sticker.entry.js.map +1 -1
  122. package/dist/esm/nano-tab-group.entry.js +2 -2
  123. package/dist/esm/{nano-table-9767860f.js → nano-table-91f09583.js} +561 -187
  124. package/dist/esm/nano-table-91f09583.js.map +1 -0
  125. package/dist/esm/nano-table.entry.js +2 -2
  126. package/dist/esm/{table.worker-d252307c.js → table.worker-625475ba.js} +4 -4
  127. package/dist/esm/table.worker-625475ba.js.map +1 -0
  128. package/dist/esm/{table.worker-bd51e29f.js → table.worker-f258383d.js} +1 -1
  129. package/dist/esm/{throttle-7836544e.js → throttle-ac4fcefa.js} +17 -20
  130. package/dist/esm/throttle-ac4fcefa.js.map +1 -0
  131. package/dist/nano-components/index.esm.js +1 -1
  132. package/dist/nano-components/nano-components.esm.js +1 -1
  133. package/dist/nano-components/nano-components.esm.js.map +1 -1
  134. package/dist/nano-components/{p-7d6065c6.entry.js → p-0697795a.entry.js} +2 -2
  135. package/dist/nano-components/p-0697795a.entry.js.map +1 -0
  136. package/dist/nano-components/p-17ee0c07.entry.js +5 -0
  137. package/dist/nano-components/{p-6975f110.entry.js → p-192902e0.entry.js} +2 -2
  138. package/dist/nano-components/{p-a6ff5ca6.js → p-1a0b5bc3.js} +2 -2
  139. package/dist/nano-components/{p-3a761d77.entry.js → p-1b791810.entry.js} +2 -2
  140. package/dist/nano-components/p-3de3449e.js +5 -0
  141. package/dist/nano-components/p-3de3449e.js.map +1 -0
  142. package/dist/nano-components/p-3eb6d833.entry.js +5 -0
  143. package/dist/nano-components/p-3eb6d833.entry.js.map +1 -0
  144. package/dist/nano-components/{p-a1c0afb6.entry.js → p-4884b65a.entry.js} +2 -2
  145. package/dist/nano-components/{p-75735a91.entry.js → p-565793a2.entry.js} +2 -2
  146. package/dist/nano-components/p-565793a2.entry.js.map +1 -0
  147. package/dist/nano-components/p-5aae2588.entry.js +5 -0
  148. package/dist/nano-components/p-5aae2588.entry.js.map +1 -0
  149. package/dist/nano-components/{p-935aef3d.entry.js → p-6920ad69.entry.js} +2 -2
  150. package/dist/nano-components/{p-1c6c94cb.entry.js → p-7baa9e14.entry.js} +2 -2
  151. package/dist/nano-components/p-7bff5224.js +5 -0
  152. package/dist/nano-components/p-7bff5224.js.map +1 -0
  153. package/dist/nano-components/{p-f60fe933.entry.js → p-898cbac7.entry.js} +2 -2
  154. package/dist/nano-components/{p-ace1ffc2.entry.js → p-a362bd23.entry.js} +2 -2
  155. package/dist/nano-components/{p-eb6c9191.entry.js → p-b72df1aa.entry.js} +2 -2
  156. package/dist/nano-components/p-bf18e298.entry.js +5 -0
  157. package/dist/nano-components/p-bf18e298.entry.js.map +1 -0
  158. package/dist/nano-components/p-ce5efc3f.entry.js +5 -0
  159. package/dist/nano-components/p-ce5efc3f.entry.js.map +1 -0
  160. package/dist/nano-components/{p-1b687f96.entry.js → p-d0eefd52.entry.js} +2 -2
  161. package/dist/nano-components/{p-2d43a82b.entry.js → p-d74e2642.entry.js} +2 -2
  162. package/dist/nano-components/p-d74e2642.entry.js.map +1 -0
  163. package/dist/nano-components/p-dfbf0d56.js +5 -0
  164. package/dist/nano-components/{p-bd51e29f.js → p-f258383d.js} +1 -1
  165. package/dist/types/components/datalist/datalist.d.ts +1 -0
  166. package/dist/types/components/nav-item/nav-item.d.ts +1 -1
  167. package/dist/types/components/resize-observe/resize-observe.d.ts +2 -0
  168. package/dist/types/components/sortable/sortable.d.ts +0 -1
  169. package/dist/types/components/sticker/sticker.d.ts +2 -2
  170. package/dist/types/components/table/table-interface.d.ts +23 -11
  171. package/dist/types/components/table/table.cell.d.ts +0 -7
  172. package/dist/types/components/table/table.d.ts +10 -7
  173. package/dist/types/components/table/table.header.d.ts +0 -1
  174. package/dist/types/components/table/table.pin-service.d.ts +90 -0
  175. package/dist/types/components/table/table.row.d.ts +3 -2
  176. package/dist/types/components/table/table.utils.d.ts +0 -27
  177. package/dist/types/components.d.ts +29 -11
  178. package/dist/types/utils/events.d.ts +15 -0
  179. package/dist/types/utils/throttle.d.ts +1 -1
  180. package/docs-json.json +59 -24
  181. package/docs-vscode.json +2 -2
  182. package/hydrate/index.js +610 -204
  183. package/package.json +2 -2
  184. package/dist/cjs/nano-table-0a720c5f.js.map +0 -1
  185. package/dist/cjs/table.worker-347d4d31.js.map +0 -1
  186. package/dist/cjs/throttle-f55496c8.js.map +0 -1
  187. package/dist/esm/nano-table-9767860f.js.map +0 -1
  188. package/dist/esm/table.worker-d252307c.js.map +0 -1
  189. package/dist/esm/throttle-7836544e.js.map +0 -1
  190. package/dist/nano-components/p-15217442.entry.js +0 -5
  191. package/dist/nano-components/p-15217442.entry.js.map +0 -1
  192. package/dist/nano-components/p-2d43a82b.entry.js.map +0 -1
  193. package/dist/nano-components/p-633c778c.js +0 -5
  194. package/dist/nano-components/p-633c778c.js.map +0 -1
  195. package/dist/nano-components/p-66631f50.js +0 -5
  196. package/dist/nano-components/p-75735a91.entry.js.map +0 -1
  197. package/dist/nano-components/p-7d6065c6.entry.js.map +0 -1
  198. package/dist/nano-components/p-8a79a7ca.entry.js +0 -5
  199. package/dist/nano-components/p-9746b0a5.js +0 -5
  200. package/dist/nano-components/p-9746b0a5.js.map +0 -1
  201. package/dist/nano-components/p-b0c60290.entry.js +0 -5
  202. package/dist/nano-components/p-b0c60290.entry.js.map +0 -1
  203. package/dist/nano-components/p-c8ccb57a.entry.js +0 -5
  204. package/dist/nano-components/p-c8ccb57a.entry.js.map +0 -1
  205. package/dist/nano-components/p-d1a5326f.entry.js +0 -5
  206. package/dist/nano-components/p-d1a5326f.entry.js.map +0 -1
  207. /package/dist/nano-components/{p-66631f50.js.map → p-17ee0c07.entry.js.map} +0 -0
  208. /package/dist/nano-components/{p-6975f110.entry.js.map → p-192902e0.entry.js.map} +0 -0
  209. /package/dist/nano-components/{p-a6ff5ca6.js.map → p-1a0b5bc3.js.map} +0 -0
  210. /package/dist/nano-components/{p-3a761d77.entry.js.map → p-1b791810.entry.js.map} +0 -0
  211. /package/dist/nano-components/{p-a1c0afb6.entry.js.map → p-4884b65a.entry.js.map} +0 -0
  212. /package/dist/nano-components/{p-935aef3d.entry.js.map → p-6920ad69.entry.js.map} +0 -0
  213. /package/dist/nano-components/{p-1c6c94cb.entry.js.map → p-7baa9e14.entry.js.map} +0 -0
  214. /package/dist/nano-components/{p-f60fe933.entry.js.map → p-898cbac7.entry.js.map} +0 -0
  215. /package/dist/nano-components/{p-ace1ffc2.entry.js.map → p-a362bd23.entry.js.map} +0 -0
  216. /package/dist/nano-components/{p-eb6c9191.entry.js.map → p-b72df1aa.entry.js.map} +0 -0
  217. /package/dist/nano-components/{p-1b687f96.entry.js.map → p-d0eefd52.entry.js.map} +0 -0
  218. /package/dist/nano-components/{p-8a79a7ca.entry.js.map → p-dfbf0d56.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * Web Components for Nanopore digital Web Apps
3
3
  */
4
- import { consoleError, h, Fragment, getElement, getRenderingRef, proxyCustomElement, HTMLElement, createEvent, readTask, Build, Host } from '@stencil/core/internal/client';
4
+ import { consoleError, h, Fragment, getElement, getRenderingRef, writeTask, readTask, proxyCustomElement, HTMLElement, createEvent, Host } from '@stencil/core/internal/client';
5
5
  import { a as cyrb53 } from './math.js';
6
6
  import { d as debounce } from './throttle.js';
7
7
  import { c as createStore } from './index2.js';
@@ -367,92 +367,6 @@ function colheadFootRender(col) {
367
367
  const tpl = col === null || col === void 0 ? void 0 : col.columnTemplate;
368
368
  return tpl ? (tpl(h, col)) : (h(Fragment, null, col.title));
369
369
  }
370
- const stickyHIOs = new WeakMap();
371
- const stickyVIOs = new WeakMap();
372
- /**
373
- * Adds element to Intersection Observer. Fires when element changes on the x axis
374
- * @param el - an element to observe
375
- * @param pos - the edge to watch (start or end)
376
- * @param cb - callback when an intersection state changes.
377
- */
378
- function addHObserver(el, pos, cb) {
379
- if (stickyHIOs.get(el))
380
- return;
381
- const store = fetchStores();
382
- const root = store.general.state.scrollParent;
383
- const observer = new IntersectionObserver(([e]) => {
384
- const rootBounds = e.rootBounds || document.scrollingElement.getBoundingClientRect();
385
- const positions = {};
386
- if (pos === 'start') {
387
- positions.start =
388
- e.boundingClientRect.x - (rootBounds.x + root.scrollLeft) < 0 &&
389
- !e.isIntersecting;
390
- }
391
- if (pos === 'end') {
392
- // TODO - sort these out for RtL
393
- positions.end =
394
- e.boundingClientRect.right > e.boundingClientRect.width &&
395
- !e.isIntersecting;
396
- }
397
- if (!!cb)
398
- cb(positions);
399
- }, {
400
- threshold: [1],
401
- rootMargin: '1px 0px 100px 0px',
402
- root: root === document.scrollingElement ? null : root,
403
- });
404
- stickyHIOs.set(el, observer);
405
- if (store.general.state.isReady) {
406
- observer.observe(el);
407
- }
408
- else {
409
- store.general.state.host.addEventListener('nanoTblReady', () => {
410
- observer.observe(el);
411
- }, { once: true });
412
- }
413
- }
414
- /**
415
- * Adds element to Intersection Observer. Fires when element changes on the y axis
416
- * @param el - an element to observe
417
- * @param pos - the edge to watch (start or end)
418
- * @param cb - callback when an intersection state changes.
419
- */
420
- function addVObserver(el, pos, cb) {
421
- if (stickyVIOs.get(el))
422
- return;
423
- const store = fetchStores();
424
- const root = store.general.state.scrollParent;
425
- const observer = new IntersectionObserver(([e]) => {
426
- const rootBounds = e.rootBounds || document.scrollingElement.getBoundingClientRect();
427
- const positions = {};
428
- if (pos === 'top') {
429
- positions.top =
430
- e.boundingClientRect.y - (rootBounds.y + root.scrollTop) < 0 &&
431
- !e.isIntersecting;
432
- }
433
- if (pos === 'bottom') {
434
- const boundingClientRect = e.target.getBoundingClientRect();
435
- positions.bottom =
436
- boundingClientRect.height + boundingClientRect.y >
437
- rootBounds.height && !e.isIntersecting;
438
- }
439
- if (!!cb)
440
- cb(positions);
441
- }, {
442
- threshold: [1],
443
- rootMargin: '0px 100px 0px 100px',
444
- root: root === document.scrollingElement ? null : root,
445
- });
446
- stickyVIOs.set(el, observer);
447
- if (store.general.state.isReady) {
448
- observer.observe(el);
449
- }
450
- else {
451
- store.general.state.host.addEventListener('nanoTblReady', () => {
452
- observer.observe(el);
453
- }, { once: true });
454
- }
455
- }
456
370
  function headerPinClasses(type, vPinned, toString = false) {
457
371
  const classes = {
458
372
  [`${CSSNAMESPACE}__${type}`]: true,
@@ -522,7 +436,7 @@ function isInViewport(el, percentVisible = 100) {
522
436
  percentVisible);
523
437
  }
524
438
 
525
- const TableColHead = ({ column, headRenderer, onColumnSortClick, onColumnPinned, defaults, }) => {
439
+ const TableColHead = ({ column, onColumnSortClick, defaults, }) => {
526
440
  // Sort handling
527
441
  function handleColumnSortClick(e) {
528
442
  let order;
@@ -547,7 +461,7 @@ const TableColHead = ({ column, headRenderer, onColumnSortClick, onColumnPinned,
547
461
  extraProps = column.columnProperties(column) || extraProps;
548
462
  }
549
463
  const baseProps = {
550
- class: Object.assign(Object.assign({}, headerPinClasses('th', headRenderer === null || headRenderer === void 0 ? void 0 : headRenderer.pinned)), { [`${CSSNAMESPACE}__pin--start`]: column.pinned === 'start', [`${CSSNAMESPACE}__pin--end`]: column.pinned === 'end', [`${CSSNAMESPACE}__ordered`]: !!column.order, [`${CSSNAMESPACE}__filtered`]: column.filter !== undefined && column.filter !== null }),
464
+ class: Object.assign(Object.assign({}, headerPinClasses('th', column.pinned)), { [`${CSSNAMESPACE}__pin--start`]: column.pinned === 'start', [`${CSSNAMESPACE}__pin--end`]: column.pinned === 'end', [`${CSSNAMESPACE}__ordered`]: !!column.order, [`${CSSNAMESPACE}__filtered`]: column.filter !== undefined && column.filter !== null }),
551
465
  };
552
466
  let props = extraProps ? mergeProperties(baseProps, extraProps) : baseProps;
553
467
  const content = colheadFootRender(column);
@@ -564,12 +478,7 @@ const TableColHead = ({ column, headRenderer, onColumnSortClick, onColumnPinned,
564
478
  : 'none';
565
479
  props = Object.assign(Object.assign({}, props), { 'aria-sort': sort });
566
480
  }
567
- return (h("th", Object.assign({}, props, { ref: (th) => {
568
- if (['end', 'start'].includes(column.pinned))
569
- addHObserver(th, column.pinned, onColumnPinned);
570
- if (['top', 'bottom'].includes(headRenderer.pinned))
571
- addVObserver(th, headRenderer.pinned, onColumnPinned);
572
- }, key: column.prop }), isSortable() ? (h("button", { class: {
481
+ return (h("th", Object.assign({}, props, { key: column.prop }), isSortable() ? (h("button", { class: {
573
482
  [`${CSSNAMESPACE}__order-btn`]: true,
574
483
  [`${CSSNAMESPACE}__cell-content`]: true,
575
484
  }, onClick: handleColumnSortClick },
@@ -597,6 +506,7 @@ function cellRender(rowIndex, colIndex) {
597
506
  const columns = store.config.state.columns;
598
507
  const tpl = (_a = columns[colIndex]) === null || _a === void 0 ? void 0 : _a.cellTemplate;
599
508
  const model = colDataModel(rowIndex, colIndex);
509
+ const tableInstance = getRenderingRef();
600
510
  if (!!model.cellModel && columns[colIndex].type === 'date') {
601
511
  const d = new Date(model.cellModel);
602
512
  if (d instanceof Date && !isNaN(d)) {
@@ -605,7 +515,28 @@ function cellRender(rowIndex, colIndex) {
605
515
  : d;
606
516
  }
607
517
  }
608
- return tpl ? (tpl(h, model)) : model.cellModel !== undefined && model.cellModel !== null ? (h(Fragment, null, (_b = model.cellModel) === null || _b === void 0 ? void 0 : _b.toString())) : ('');
518
+ // Wrap the h pragma, then we can know if we're using Stencil's
519
+ // jsx renderer or a different one
520
+ let hCalled = false;
521
+ const hWrap = (...args) => {
522
+ hCalled = true;
523
+ return h(...args);
524
+ };
525
+ let tplResult = tpl ? tpl(hWrap, model) : undefined;
526
+ if (tplResult &&
527
+ tableInstance.customRenderer &&
528
+ tplResult['$attrs$'] === undefined &&
529
+ !(tplResult instanceof Element) &&
530
+ typeof tplResult !== 'string' &&
531
+ !hCalled) {
532
+ // template result is jsx *not* from Stencil.
533
+ // Render it now and output it later.
534
+ const templateEle = document.createElement('template');
535
+ // @ts-expect-error
536
+ tableInstance.customRenderer(tplResult, templateEle.content);
537
+ tplResult = templateEle;
538
+ }
539
+ return tplResult ? (tplResult) : model.cellModel !== undefined && model.cellModel !== null ? (h(Fragment, null, (_b = model.cellModel) === null || _b === void 0 ? void 0 : _b.toString())) : ('');
609
540
  }
610
541
  const baseCellClasses = (colIndex, toString = false) => {
611
542
  const store = fetchStores();
@@ -621,11 +552,12 @@ const baseCellClasses = (colIndex, toString = false) => {
621
552
  return classListToStr(classes);
622
553
  return classes;
623
554
  };
624
- const TableCell$1 = ({ rowIndex, colIndex, nestedContent, }) => {
555
+ const TableCell = ({ rowIndex, colIndex, nestedContent, }) => {
625
556
  const Content = () => nestedContent
626
557
  ? nestedContent()
627
558
  : cellRender(rowIndex, colIndex) || (h("span", { class: "placeholder" }, "\u00A0"));
628
559
  let CellType = 'td';
560
+ const tableInstance = getRenderingRef();
629
561
  const store = fetchStores();
630
562
  const column = store.config.state.columns[colIndex];
631
563
  let props = mergeCellProperties(rowIndex, colIndex, {
@@ -637,14 +569,23 @@ const TableCell$1 = ({ rowIndex, colIndex, nestedContent, }) => {
637
569
  ? Object.assign(Object.assign({}, props), { scope: 'rowgroup' }) : Object.assign(Object.assign({}, props), { scope: 'row' });
638
570
  CellType = 'th';
639
571
  }
640
- const ContentWrap = (props) => (h("div", Object.assign({}, props, { class: {
641
- [`${CSSNAMESPACE}__cell-content`]: true,
642
- [`${CSSNAMESPACE}__cell-content--wrap`]: !!column.wrap,
643
- } }),
644
- h(Content, null)));
645
- return (h(CellType
646
- // role="gridcell"
647
- , Object.assign({}, props), column.autoTooltip && !column.wrap ? (h("nano-resize-observe", { notifyContentFit: "x", onNanoResizeContentFitChange: (e) => (e.target.firstElementChild.disabled =
572
+ const ContentWrap = (props) => {
573
+ const content = Content();
574
+ return (h("div", Object.assign({ ref: (d) => {
575
+ if (d && content instanceof Element) {
576
+ d.replaceChildren();
577
+ d.append(content['content'] || content);
578
+ }
579
+ } }, props, { class: {
580
+ [`${CSSNAMESPACE}__cell-content`]: true,
581
+ [`${CSSNAMESPACE}__cell-content--wrap`]: !!column.wrap,
582
+ }, innerHTML: typeof content === 'string' && content.includes('<')
583
+ ? content
584
+ : undefined }), (typeof content !== 'string' || !content.includes('<')) &&
585
+ !(content instanceof Element) &&
586
+ content));
587
+ };
588
+ return (h(CellType, Object.assign({ role: tableInstance.type === 'grid' ? 'gridcell' : undefined }, props), column.autoTooltip && !column.wrap ? (h("nano-resize-observe", { notifyContentFit: "x", onNanoResizeContentFitChange: (e) => (e.target.firstElementChild.disabled =
648
589
  e.detail.x) },
649
590
  h("nano-tooltip", { disabled: true, placement: "top", onNanoShow: (e) => (e.target.closest(CellType).style.zIndex = '100'), onNanoHide: (e) => (e.target.closest(CellType).style.zIndex = '') },
650
591
  h(ContentWrap, null),
@@ -652,14 +593,18 @@ const TableCell$1 = ({ rowIndex, colIndex, nestedContent, }) => {
652
593
  h(Content, null))))) : (h(ContentWrap, null))));
653
594
  };
654
595
 
655
- const TableCell = ({ header, wrap }, children) => {
656
- const cell = (h("div", { class: {
596
+ const tableCellContent = (props, children, ctx) => {
597
+ const cell = (h("div", Object.assign({}, props.wrapperProps, { class: {
657
598
  [`${CSSNAMESPACE}__cell-content`]: true,
658
- [`${CSSNAMESPACE}__cell-content--wrap`]: wrap,
659
- } }, children));
660
- return header ? h("th", { scope: "row" }, cell) : h("td", null, cell);
599
+ [`${CSSNAMESPACE}__cell-content--wrap`]: props.wrap,
600
+ } }), children));
601
+ return props.header ? (h("th", Object.assign({ scope: ctx }, props.cellProps), cell)) : (h("td", Object.assign({}, props.cellProps), cell));
661
602
  };
662
- const TableRow = ({ rowRenderer, rowIndex, rowModel, onColumnPinned }, children, utils) => {
603
+ const TableRow = ({ rowRenderer, rowIndex, rowModel }, children, utils) => {
604
+ // helper, generates <td> or <th>
605
+ const TableCell = ({ header, wrap, cellProps, wrapperProps }, children) => {
606
+ return tableCellContent({ header, wrap, cellProps, wrapperProps }, children, 'row');
607
+ };
663
608
  let extraProps = {};
664
609
  if (!rowModel) {
665
610
  const model = rowDataModel(rowIndex);
@@ -669,13 +614,28 @@ const TableRow = ({ rowRenderer, rowIndex, rowModel, onColumnPinned }, children,
669
614
  extraProps =
670
615
  rowRenderer.rowProperties({ rowModel, rowIndex }) || extraProps;
671
616
  }
672
- let pinned;
617
+ let rowPinned;
673
618
  if ((rowRenderer === null || rowRenderer === void 0 ? void 0 : rowRenderer.pinned) && typeof rowRenderer.pinned === 'function') {
674
- pinned = rowRenderer.pinned();
619
+ rowPinned = rowRenderer.pinned({ rowModel, rowIndex });
675
620
  }
676
- const baseProps = { class: headerPinClasses('tr', pinned) };
677
- const props = extraProps ? mergeProperties(baseProps, extraProps) : baseProps;
621
+ const props = mergeProperties({ class: headerPinClasses('tr', rowPinned, true) }, extraProps);
678
622
  const tpl = rowRenderer === null || rowRenderer === void 0 ? void 0 : rowRenderer.template;
623
+ /**
624
+ * Applies appropriate classes to td / th VNodes;
625
+ * which can be supplied by user defined templates
626
+ * @param children virtual / jsx node array
627
+ * @returns virtual / jsx node array
628
+ */
629
+ const applyCellClasses = (children) => {
630
+ return utils.map(children, (cNode, i) => {
631
+ if (['td', 'th'].includes(cNode.vtag.toString())) {
632
+ cNode.vattrs = mergeProperties({
633
+ class: baseCellClasses(i, true),
634
+ }, cNode.vattrs);
635
+ }
636
+ return cNode;
637
+ });
638
+ };
679
639
  if (tpl) {
680
640
  let toRender = tpl(h, {
681
641
  renderedRow: (h("tr", Object.assign({}, props, { key: rowModel.__uuid }), children)),
@@ -687,24 +647,9 @@ const TableRow = ({ rowRenderer, rowIndex, rowModel, onColumnPinned }, children,
687
647
  if (node.vtag === 'tr') {
688
648
  if (!node.vkey)
689
649
  node.vkey = `${rowModel.__uuid}_${i}`;
690
- node.vattrs = mergeProperties({ class: headerPinClasses('tr', pinned, true) }, node.vattrs);
650
+ node.vattrs = mergeProperties({ class: headerPinClasses('tr', rowPinned, true) }, node.vattrs);
691
651
  if (!!node.vchildren) {
692
- node.vchildren = utils.map(node.vchildren, (cNode, i) => {
693
- if (['td', 'th'].includes(cNode.vtag.toString())) {
694
- cNode.vattrs = mergeProperties({
695
- class: headerPinClasses(cNode.vtag.toString(), pinned, true) + baseCellClasses(i, true),
696
- ref: (th) => {
697
- if ((!!th && pinned === 'top') || pinned === 'bottom')
698
- addVObserver(th, pinned, onColumnPinned);
699
- if (!!th && th.classList.contains('nano-tbl__pin--end'))
700
- addHObserver(th, 'end', onColumnPinned);
701
- if (!!th && th.classList.contains('nano-tbl__pin--start'))
702
- addHObserver(th, 'start', onColumnPinned);
703
- },
704
- }, cNode.vattrs);
705
- }
706
- return cNode;
707
- });
652
+ node.vchildren = applyCellClasses(node.vchildren);
708
653
  }
709
654
  }
710
655
  return node;
@@ -712,28 +657,25 @@ const TableRow = ({ rowRenderer, rowIndex, rowModel, onColumnPinned }, children,
712
657
  }
713
658
  return toRender;
714
659
  }
715
- return (h("tr", Object.assign({}, props, { key: rowModel.__uuid }), children));
660
+ return (h("tr", Object.assign({}, props, { key: rowModel.__uuid }), applyCellClasses(children)));
716
661
  };
717
- const TableHeadFootRow = ({ rowRenderer, onColumnPinned }, children, utils) => {
662
+ const TableHeadFootRow = ({ rowRenderer }, // onRowPinned, onColPinned
663
+ children, utils) => {
718
664
  let extraProps = {};
719
665
  if (rowRenderer.rowProperties) {
720
666
  extraProps = rowRenderer.rowProperties() || {};
721
667
  }
722
- const TableCell = ({ header, wrap }, children) => {
723
- const cell = (h("div", { class: {
724
- [`${CSSNAMESPACE}__cell-content`]: true,
725
- [`${CSSNAMESPACE}__cell-content--wrap`]: wrap,
726
- } }, children));
727
- return header !== false ? h("th", { scope: "col" }, cell) : h("td", null, cell);
668
+ const TableHeadFootCell = ({ header, wrap, cellProps, wrapperProps }, children) => {
669
+ return tableCellContent({ header, wrap, cellProps, wrapperProps }, children, 'col');
728
670
  };
729
671
  const pinned = rowRenderer.pinned || null;
730
- const baseProps = { class: headerPinClasses('tr', null) };
672
+ const baseProps = { class: headerPinClasses('tr', pinned) };
731
673
  const props = extraProps ? mergeProperties(baseProps, extraProps) : baseProps;
732
674
  const tpl = rowRenderer === null || rowRenderer === void 0 ? void 0 : rowRenderer.template;
733
675
  if (tpl) {
734
676
  let toRender = tpl(h, {
735
677
  renderedRow: h("tr", Object.assign({}, props), children),
736
- }, TableCell);
678
+ }, TableHeadFootCell);
737
679
  if (Array.isArray(toRender)) {
738
680
  toRender = utils.map(toRender, (node) => {
739
681
  if (node.vtag === 'tr') {
@@ -743,14 +685,6 @@ const TableHeadFootRow = ({ rowRenderer, onColumnPinned }, children, utils) => {
743
685
  if (['td', 'th'].includes(cNode.vtag.toString())) {
744
686
  cNode.vattrs = mergeProperties({
745
687
  class: headerPinClasses(cNode.vtag.toString(), pinned, true),
746
- ref: (th) => {
747
- if ((!!th && pinned === 'top') || pinned === 'bottom')
748
- addVObserver(th, pinned, onColumnPinned);
749
- if (!!th && th.classList.contains('nano-tbl__pin--end'))
750
- addHObserver(th, 'end', onColumnPinned);
751
- if (!!th && th.classList.contains('nano-tbl__pin--start'))
752
- addHObserver(th, 'start', onColumnPinned);
753
- },
754
688
  }, cNode.vattrs);
755
689
  }
756
690
  return cNode;
@@ -765,11 +699,388 @@ const TableHeadFootRow = ({ rowRenderer, onColumnPinned }, children, utils) => {
765
699
  return h("tr", Object.assign({}, props), children);
766
700
  };
767
701
 
768
- const tableCss = ":host{box-sizing:border-box}*,*::before,*::after{box-sizing:border-box}[hidden]{display:none !important}nano-table{display:block;width:100%;--max-col-width:clamp(200px, 500px, 50vw);--color:var(--nano-color-mediumgrey, #68767e);--font-size:0.87rem;--cell-line-height:1.5;--thead-font-size:0.95rem;--thead-color:#455560;--tfoot-color:#455560;--border-color:#dddbda;--border-style:thin solid var(--border-color);--border-tint-color:#0084a9;--border-tint-style:3px solid var(--border-tint-color);--cell-bg-rgb:var(--nano-color-white-rgb, 255 255 255);--head-bg-rgb:250 250 249;--foot-bg-rgb:var(--head-bg-rgb);--th-row-bg-rgb:var(--cell-bg-rgb);--ordered-bg-rgb:var(--nano-color-offwhite-rgb, 249 249 251);--td-padding-start:0.625rem;--td-padding-end:0.625rem;--td-padding-top:0.5rem;--td-padding-bottom:0.4125rem;--th-padding-start:0.625rem;--th-padding-end:0.625rem;--th-padding-top:0.875rem;--th-padding-bottom:0.6875rem;--td-padding-v:var(--td-padding-top) var(--td-padding-bottom);--td-padding-h:var(--td-padding-start) var(--td-padding-end);--th-padding-v:var(--th-padding-top) var(--th-padding-bottom);--th-padding-h:var(--th-padding-start) var(--th-padding-end);--foot-th-padding-v:var(--td-padding-top) var(--td-padding-bottom);--foot-th-padding-h:var(--td-padding-start) var(--td-padding-end);--head-th-padding-v:var(--th-padding-top) var(--th-padding-bottom);--head-th-padding-h:var(--th-padding-start) var(--th-padding-end);--bookend-col-padding:2rem}.nano-tbl{color:var(--color);text-align:start;width:100%;font-size:var(--font-size);border-spacing:0 0;border-collapse:separate;background:rgb(var(--cell-bg-rgb));-webkit-border-end:1px solid transparent;border-inline-end:1px solid transparent;-webkit-border-before:1px solid transparent;border-block-start:1px solid transparent;position:relative;z-index:1}.nano-tbl__wrap{display:table;min-width:100%}.nano-tbl__top-anchor{clip:rect(1px, 1px, 1px, 1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);block-size:1px;inline-size:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;position:relative}.nano-tbl__ordered{background-color:var(--ordered-bg);-webkit-border-start:var(--border-style);border-inline-start:var(--border-style);-webkit-border-end:var(--border-style);border-inline-end:var(--border-style)}.nano-tbl__order-btn{padding:0;border:none;outline:none;font:inherit;background:none;-webkit-appearance:none;appearance:none;color:inherit;display:flex;gap:10px;align-items:center;width:100%}.nano-tbl__order-btn:focus-visible{outline:none;box-shadow:var(--nano-control-focus-shadow, 0 0 0 0.1875rem var(--nano-control-focus-color, rgba(144, 198, 231, 0.8))) inset}.nano-tbl__status-icons{margin-inline:auto 10px;display:flex;gap:10px}.nano-tbl__progress-bar{font-size:0.2rem;position:sticky;inset-block-start:0;inset-inline:0;z-index:10;transition:scale 0.25s;transform:scale(0);width:100%;height:0}.nano-tbl__progress-bar--show{transform:scale(1);height:auto}.nano-tbl__caption--hide{clip:rect(1px, 1px, 1px, 1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);block-size:1px;inline-size:1px;margin:-1px;overflow:hidden;padding:0;position:absolute}.nano-tbl__td,.nano-tbl__th{line-height:var(--cell-line-height);text-align:start;-webkit-border-before:var(--border-style);border-block-start:var(--border-style);max-width:var(--max-col-width);background-color:rgb(var(--cell-bg-rgb))}tbody:first-of-type tr:first-child .nano-tbl__td,tbody:first-of-type tr:first-child .nano-tbl__th{-webkit-border-before:none;border-block-start:none}tbody:last-of-type tr:last-child .nano-tbl__td,tbody:last-of-type tr:last-child .nano-tbl__th{-webkit-border-after:var(--border-style);border-block-end:var(--border-style)}.md .nano-tbl__td:first-child .nano-tbl__cell-content,.md .nano-tbl__th:first-child .nano-tbl__cell-content{-webkit-padding-start:var(--bookend-col-padding);padding-inline-start:var(--bookend-col-padding)}.md .nano-tbl__td:last-child .nano-tbl__cell-content,.md .nano-tbl__th:last-child .nano-tbl__cell-content{-webkit-padding-end:var(--bookend-col-padding);padding-inline-end:var(--bookend-col-padding)}@media (max-width: 768px){.nano-tbl__td:first-child .nano-tbl__cell-content,.nano-tbl__th:first-child .nano-tbl__cell-content{-webkit-padding-start:var(--td-padding-start) !important;padding-inline-start:var(--td-padding-start) !important}.nano-tbl__td:last-child .nano-tbl__cell-content,.nano-tbl__th:last-child .nano-tbl__cell-content{-webkit-padding-end:var(--td-padding-end) !important;padding-inline-end:var(--td-padding-end) !important}}thead .nano-tbl__td,thead .nano-tbl__th{color:var(--thead-color);font-weight:800;background:rgb(var(--head-bg-rgb)/90%);font-size:var(--thead-font-size);-webkit-border-before:none !important;border-block-start:none !important}thead .nano-tbl__td .nano-tbl__cell-content,thead .nano-tbl__th .nano-tbl__cell-content{padding-block:var(--head-th-padding-v);padding-inline:var(--head-th-padding-h)}thead .nano-tbl__td .nano-sortable__keyboard-handle,thead .nano-tbl__th .nano-sortable__keyboard-handle{position:absolute;inset-inline-end:5px;inset-block-start:50%;transform:translateY(-50%);background:white;z-index:10}tfoot .nano-tbl__td,tfoot .nano-tbl__th{color:var(--tfoot-color);font-weight:800;-webkit-border-before:none;border-block-start:none;background:rgb(var(--foot-bg-rgb)/90%);font-size:var(--thead-font-size)}tfoot .nano-tbl__td .nano-tbl__cell-content,tfoot .nano-tbl__th .nano-tbl__cell-content{padding-block:var(--foot-th-padding-v);padding-inline:var(--foot-th-padding-h)}.nano-tbl__td.nano-tbl__ordered,.nano-tbl__th.nano-tbl__ordered{background-color:rgb(var(--ordered-bg-rgb)/80%) !important}.nano-tbl__cell-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-block:var(--td-padding-v);padding-inline:var(--td-padding-h)}.nano-tbl__cell-content--no-result{padding-block:2rem}.nano-tbl__cell-content--wrap{white-space:normal;overflow:visible}.nano-tbl tbody{will-change:scroll-position;opacity:1;transition:0.1s ease opacity;transform:translateZ(0)}.nano-tbl tbody.nano-tbl__inactive{opacity:0}.nano-tbl tbody .nano-tbl__tr:has(~.nano-tbl__tr--placeholder){display:none}.nano-tbl tbody .nano-tbl__tr--placeholder~.nano-tbl__tr{display:none}.nano-tbl th[scope=row]{font-weight:800;margin:0}.nano-tbl__pin{position:sticky;transform:translateZ(0)}.nano-tbl__pin--start{inset-inline:-1px auto;transition:max-width 0.25s ease}.nano-tbl__pin--start::after{content:\"\";position:absolute;inset:0;box-shadow:5px 1px 4px 0 rgba(0, 0, 0, 0.2);opacity:0;z-index:-1}.nano-tbl__pinned--start .nano-tbl__pin--start{z-index:2;max-width:125px !important}.sm .nano-tbl__pinned--start .nano-tbl__pin--start{max-width:var(--max-col-width) !important}.nano-tbl__pinned--start .nano-tbl__pin--start::after{opacity:1}.nano-tbl__pin--end{}.nano-tbl__pin--start+.nano-tbl__pin--end{inset-inline:auto auto}.nano-tbl__pin--start+.nano-tbl__pin--end::after{display:none}.sm .nano-tbl__pin--end{inset-inline:auto -1px !important;max-width:min(50vw, 200px)}.sm .nano-tbl__pin--end::after{display:block !important;content:\"\";position:absolute;inset:0;box-shadow:-5px 1px 4px 0 rgba(0, 0, 0, 0.2);opacity:0;z-index:-1}.sm .nano-tbl__pinned--end .nano-tbl__pin--end::after{opacity:1}.nano-tbl__pin--top{inset-block:-1px auto}.nano-tbl__pinned--top .nano-tbl__pin--top{z-index:4 !important}.nano-tbl__pin--bottom{inset-block:auto -1px}.nano-tbl__pinned--bottom .nano-tbl__pin--bottom{z-index:5 !important}.nano-tbl__pinned--start .nano-tbl__pin--top.nano-tbl__pin--start{z-index:5 !important}.nano-tbl__pinned--top.nano-tbl__pinned--start .nano-tbl__pin--top.nano-tbl__pin--start{z-index:6 !important}.nano-tbl__pinned--end .nano-tbl__pin--top.nano-tbl__pin--end{z-index:5 !important}.nano-tbl__pinned--top.nano-tbl__pinned--end .nano-tbl__pin--top.nano-tbl__pin--end{z-index:6 !important}.nano-tbl__pinned--start .nano-tbl__pin--bottom.nano-tbl__pin--start{z-index:5 !important}.nano-tbl__pinned--bottom.nano-tbl__pinned--start .nano-tbl__pin--bottom.nano-tbl__pin--start{z-index:6 !important}.nano-tbl__pinned--end .nano-tbl__pin--bottom.nano-tbl__pin--end{z-index:5 !important}.nano-tbl__pinned--bottom.nano-tbl__pinned--end .nano-tbl__pin--bottom.nano-tbl__pin--end{z-index:6 !important}.nano-tbl thead tr:last-of-type td,.nano-tbl thead tr:last-of-type th{-webkit-border-after:var(--border-tint-style);border-block-end:var(--border-tint-style)}.nano-tbl tfoot tr:first-of-type td,.nano-tbl tfoot tr:first-of-type th{-webkit-border-before:none;border-block-start:none}.nano-tbl tfoot tr:last-of-type td,.nano-tbl tfoot tr:last-of-type th{-webkit-border-after:var(--border-tint-style);border-block-end:var(--border-tint-style)}.nano-tbl__pinned--bottom .nano-tbl tfoot tr.nano-tbl__pin--bottom:first-of-type td,.nano-tbl__pinned--bottom .nano-tbl tfoot tr.nano-tbl__pin--bottom:first-of-type th{-webkit-border-before:var(--border-tint-style) !important;border-block-start:var(--border-tint-style) !important}.nano-tbl__pinned--bottom .nano-tbl tfoot tr.nano-tbl__pin--bottom:last-of-type td,.nano-tbl__pinned--bottom .nano-tbl tfoot tr.nano-tbl__pin--bottom:last-of-type th{-webkit-border-after:none !important;border-block-end:none !important}.nano-tbl .unlimited-width{max-width:none}.nano-tbl__spinner{font-size:1.5rem;transition:scale 0.25s;scale:0;padding:0.5rem;position:absolute;inset-block-end:0;inset-inline-start:calc(50% - 0.75rem);z-index:0}.nano-tbl__spinner--show{scale:1;position:sticky}.nano-tbl nano-skeleton{line-height:var(--cell-line-height)}";
702
+ function addStyleSheet(id, css) {
703
+ const styleSheet = document.getElementById(id) ||
704
+ document.createElement('style');
705
+ styleSheet.id = id;
706
+ styleSheet.innerHTML = css;
707
+ if (!styleSheet.isConnected)
708
+ document.head.append(styleSheet);
709
+ }
710
+ /**
711
+ * Manages the complex business of table 'pinning'; sticking columns and rows to the scrolling parent element.
712
+ *
713
+ * *knowing* when an element is pinned is tricky.
714
+ * Managing the display of multiple, side-by-side pinned elements is trickier still.
715
+ *
716
+ * Pinning table columns are very different from pinning table rows:
717
+ * - Rows are actual elements we can select, measure and apply styles to.
718
+ * - Columns are disparate collections of elements that are much harder to select, measure and apply styles to.
719
+ *
720
+ * With this in mind, how columns and rows are pinned is different:
721
+ * Rows can have changes applied directly, Columns have changes applied via dynamic stylesheets.
722
+ *
723
+ * The service is slightly opinionated on how it pins rows and columns (with some room for override):
724
+ * - Pinned columns are stuck consecutively, without overlapping.
725
+ * e.g. If column 'name' and 'surname' are both `pin: 'start'`; 'surname' will display **next** to name.
726
+ * Both columns are important for context
727
+ *
728
+ * - Pinned rows are set to overlap *when* they have the same ancestor,
729
+ * and stuck consecutively when they have a different ancestor.
730
+ * e.g. `tbody > tr.pin ~ tr.pin` the second row will **overlap** the first; it's unlikely both rows will be important for context.
731
+ * `thead > tr.pin`, `tbody > tr.pin`. Both rows are required for context so will require next to each other.
732
+ *
733
+ * Devs can override this behaviour by setting `--pin-start`, `--pin-end`, `--pin-top`, `--pin-bottom` custom vars.
734
+ */
735
+ class TablePinService {
736
+ constructor(table, scrollElement) {
737
+ // Private state
738
+ this.cachedColMeta = new WeakMap();
739
+ this._pinnedStart = [];
740
+ this._pinnedEnd = [];
741
+ this._cssColDimensionCacheKey = '';
742
+ this.cacheX = 0;
743
+ this.cacheY = 0;
744
+ this.tableEle = table;
745
+ this.tableId = this.tableEle.id;
746
+ this.scrollElement = scrollElement;
747
+ // Secret sauce - `getElementsByClassName` is a live collection.
748
+ // An HTMLCollection will keep itself up-to-date as elements come and go
749
+ // So we can keep assessing on scroll
750
+ this.startColumns = table
751
+ .querySelector('thead')
752
+ .getElementsByClassName(`${CSSNAMESPACE}__pin--start`);
753
+ this.endColumns = table
754
+ .querySelector('thead')
755
+ .getElementsByClassName(`${CSSNAMESPACE}__pin--end`);
756
+ this.topRows = table.getElementsByClassName(`${CSSNAMESPACE}__pin--top`);
757
+ this.bottomRows = table.getElementsByClassName(`${CSSNAMESPACE}__pin--bottom`);
758
+ this.onResize();
759
+ }
760
+ // Pinned cols & change detection
761
+ get pinnedStart() {
762
+ return this._pinnedStart;
763
+ }
764
+ set pinnedStart(cols) {
765
+ this._pinnedStart = cols;
766
+ this.handlePinnedStartChange();
767
+ }
768
+ /**
769
+ * Called when columns are either pinned or unpinned.
770
+ * Attaches a tiny stylesheet to target the 'last' start column.
771
+ * (e.g. We only want to apply drop shadow on last pinned start column - not all pinned columns)
772
+ */
773
+ handlePinnedStartChange() {
774
+ writeTask(() => {
775
+ if (this.pinnedStart.length) {
776
+ this.tableEle.classList.add(`${CSSNAMESPACE}__pinned--start`);
777
+ const lastActiveCol = this.cachedColMeta.get(this.pinnedStart[this.pinnedStart.length - 1]);
778
+ addStyleSheet(`${this.tableId}-col-start-active-style`,
779
+ /* css */ `
780
+ #${this.tableId} tr > :nth-child(${lastActiveCol.idx + 1}) {
781
+ --pin-start-active: 1;
782
+ }
783
+ `);
784
+ }
785
+ else {
786
+ this.tableEle.classList.remove(`${CSSNAMESPACE}__pinned--start`);
787
+ addStyleSheet(`${this.tableId}-col-start-active-style`, ``);
788
+ }
789
+ });
790
+ }
791
+ get pinnedEnd() {
792
+ return this._pinnedEnd;
793
+ }
794
+ set pinnedEnd(cols) {
795
+ this._pinnedEnd = cols;
796
+ this.handlePinnedEndChange();
797
+ }
798
+ /**
799
+ * Called when columns are either pinned or unpinned.
800
+ * Attaches a tiny stylesheet to target the 'first' end column.
801
+ * (e.g. We only want to apply drop shadow on first pinned end column - not all pinned columns)
802
+ */
803
+ handlePinnedEndChange() {
804
+ writeTask(() => {
805
+ if (this.pinnedEnd.length) {
806
+ this.tableEle.classList.add(`${CSSNAMESPACE}__pinned--end`);
807
+ const firstActiveCol = this.cachedColMeta.get(this.pinnedEnd[0]);
808
+ addStyleSheet(`${this.tableId}-col-end-active-style`,
809
+ /* css */ `
810
+ #${this.tableId} tr > :nth-child(${firstActiveCol.idx + 1}) { --pin-end-active: 1; }
811
+ `);
812
+ }
813
+ else {
814
+ this.tableEle.classList.remove(`${CSSNAMESPACE}__pinned--end`);
815
+ addStyleSheet(`${this.tableId}-col-end-active-style`, ``);
816
+ }
817
+ });
818
+ }
819
+ get cssColDimensionCacheKey() {
820
+ return this._cssColDimensionCacheKey;
821
+ }
822
+ set cssColDimensionCacheKey(key) {
823
+ if (key === this._cssColDimensionCacheKey)
824
+ return;
825
+ this._cssColDimensionCacheKey = key;
826
+ this.createPinnedColDimensionStyles();
827
+ }
828
+ /**
829
+ * To only generate column dimension styles when necessary we
830
+ * maintain a cache key string via serialised column meta.
831
+ * Only when this key changes do we generate a new stylesheet
832
+ */
833
+ generateCssCacheKey() {
834
+ let key = '';
835
+ for (const col of this.startColumns) {
836
+ const colMeta = this.cachedColMeta.get(col);
837
+ key += `${colMeta.idx}-start-${colMeta.width}`;
838
+ }
839
+ for (const col of this.endColumns) {
840
+ const colMeta = this.cachedColMeta.get(col);
841
+ key += `${colMeta.idx}-start-${colMeta.width}`;
842
+ }
843
+ this.cssColDimensionCacheKey = key;
844
+ }
845
+ /**
846
+ * Generates pinned column width offset styles
847
+ * so pinned columns can appear stuck together,
848
+ * then attaches a stylesheet.
849
+ */
850
+ createPinnedColDimensionStyles() {
851
+ let widthS = 0;
852
+ let widthE = 0;
853
+ const startCols = Array.from(this.startColumns);
854
+ const endCols = Array.from(this.endColumns).reverse();
855
+ const css = /* css */ `
856
+ ${startCols
857
+ .map((col) => {
858
+ const colMeta = this.cachedColMeta.get(col);
859
+ widthS += colMeta.width || 0;
860
+ return /* css */ `
861
+ #${this.tableId} tr > :nth-child(${colMeta.idx + 1}) ~ td,
862
+ #${this.tableId} tr > :nth-child(${colMeta.idx + 1}) ~ th {
863
+ --pin-start: ${widthS - 1}px;
864
+ }
865
+ `;
866
+ })
867
+ .join('')}
868
+ ${endCols
869
+ .map((col) => {
870
+ const colMeta = this.cachedColMeta.get(col);
871
+ widthE += colMeta.width;
872
+ return /* css */ `
873
+ #${this.tableId} tr > td:has(~ :nth-child(${colMeta.idx + 1})),
874
+ #${this.tableId} tr > th:has(~ :nth-child(${colMeta.idx + 1})) {
875
+ --pin-end: ${widthE - 1}px;
876
+ }
877
+ `;
878
+ })
879
+ .join('')}
880
+ `;
881
+ addStyleSheet(`${this.tableId}-dimension-style`, css);
882
+ }
883
+ getParentOffsets() {
884
+ const { x, y } = this.scrollElement.getBoundingClientRect();
885
+ let offsetX = x;
886
+ let offsetY = y;
887
+ if (this.scrollElement === document.documentElement) {
888
+ offsetX = this.scrollElement.offsetLeft;
889
+ offsetY = this.scrollElement.offsetTop;
890
+ }
891
+ return { offsetX, offsetY };
892
+ }
893
+ /**
894
+ * Loops through all 'top' & 'bottom' rows (on scroll or resize)
895
+ * Manages their visual state by applying classes on stuck / unstuck
896
+ * And their pinned offset / distance
897
+ */
898
+ assessRows() {
899
+ if (!this.topRows.length && !this.bottomRows.length)
900
+ return;
901
+ // top rows
902
+ if (this.topRows.length) {
903
+ readTask(async () => {
904
+ let heightAggregate = 0;
905
+ let cacheParent;
906
+ const { offsetY } = this.getParentOffsets();
907
+ for (const topRow of this.topRows) {
908
+ const { y, height } = topRow.getBoundingClientRect();
909
+ const currParent = topRow.parentElement;
910
+ // we'll use the applied `--pin-top` css var to decide row offset.
911
+ // This allows devs to override this behaviour through selector specificity
912
+ const pinTop = getComputedStyle(topRow).getPropertyValue('--pin-top');
913
+ const offset = pinTop !== '' ? parseFloat(pinTop) : heightAggregate;
914
+ // we need to wait for the row to finish sticking
915
+ // and generating it's offset (`--pin-top`) so we can see, on
916
+ // subsequent rows *if* the offset was applied
917
+ await new Promise((resolve) => writeTask(() => {
918
+ if (y - offsetY <= offset) {
919
+ topRow.classList.add(`${CSSNAMESPACE}__pinned`, `${CSSNAMESPACE}__pinned--top`);
920
+ }
921
+ else {
922
+ topRow.classList.remove(`${CSSNAMESPACE}__pinned`, `${CSSNAMESPACE}__pinned--top`);
923
+ }
924
+ // by default, we only want to stick one row from each parental block (thead, tbody, tfoot)
925
+ // so only aggregate height / offset when cacheParent is different from current parent.
926
+ // Devs can override this behaviour by manually setting `--pin-bottom` on the table row
927
+ if (cacheParent !== currParent) {
928
+ currParent.style.setProperty('--pin-top', `${heightAggregate}px`);
929
+ heightAggregate += height;
930
+ cacheParent = currParent;
931
+ }
932
+ resolve();
933
+ }));
934
+ }
935
+ });
936
+ }
937
+ // bottom rows
938
+ if (this.bottomRows.length) {
939
+ const bottomRows = Array.from(this.bottomRows).reverse();
940
+ readTask(async () => {
941
+ let cacheParent;
942
+ let heightAggregate = 0;
943
+ const { offsetY } = this.getParentOffsets();
944
+ for (const bottomRow of bottomRows) {
945
+ if (!bottomRow.isConnected)
946
+ continue;
947
+ const { y, height } = bottomRow.getBoundingClientRect();
948
+ const currParent = bottomRow.parentElement;
949
+ // we'll use the applied `--pin-bottom` css var to decide row offset.
950
+ // This allows devs to override this behaviour through selector specificity
951
+ const pinBottom = getComputedStyle(bottomRow).getPropertyValue('--pin-bottom');
952
+ const offset = pinBottom !== '' ? parseFloat(pinBottom) : heightAggregate;
953
+ // we need to wait for the row to finish sticking
954
+ // and generating it's offset (`--pin-bottom`) to we can see, on
955
+ // subsequent rows *if* the offset was applied
956
+ await new Promise((resolve) => writeTask(() => {
957
+ if (this.tableDims.height + offsetY - (y + height) <= offset) {
958
+ bottomRow.classList.add(`${CSSNAMESPACE}__pinned`, `${CSSNAMESPACE}__pinned--bottom`);
959
+ }
960
+ else {
961
+ bottomRow.classList.remove(`${CSSNAMESPACE}__pinned`, `${CSSNAMESPACE}__pinned--bottom`);
962
+ }
963
+ // by default, we only want to stick one row from each parental block (thead, tbody, tfoot)
964
+ // so only aggregate height / offset when cacheParent is different from current parent.
965
+ // Devs can override this behaviour by manually setting `--pin-bottom` on the table row
966
+ if (cacheParent !== currParent) {
967
+ currParent.style.setProperty('--pin-bottom', `${heightAggregate}px`);
968
+ heightAggregate += height;
969
+ cacheParent = currParent;
970
+ }
971
+ resolve();
972
+ }));
973
+ }
974
+ });
975
+ }
976
+ }
977
+ /**
978
+ * Loops through all 'start' & 'end' columns (on scroll or resize)
979
+ * Caches meta about each column (e.g. size, position-index)
980
+ * and decides which columns are pinned
981
+ */
982
+ async assessCols() {
983
+ if (!this.startColumns.length && !this.endColumns.length)
984
+ return;
985
+ let boundBox;
986
+ let currPinned;
987
+ let parentEles;
988
+ const done = new Promise((resolve) => {
989
+ // start cols
990
+ if (this.startColumns.length) {
991
+ readTask(() => {
992
+ const { offsetX } = this.getParentOffsets();
993
+ // cumulatively add widths of columns together
994
+ // 'cos columns stick together
995
+ let widthAggregate = offsetX;
996
+ parentEles = Array.from(this.startColumns[0].parentElement.children);
997
+ for (const startCol of this.startColumns) {
998
+ boundBox = startCol.getBoundingClientRect();
999
+ // cache meta for later
1000
+ this.cachedColMeta.set(startCol, {
1001
+ width: boundBox.width,
1002
+ idx: parentEles.indexOf(startCol),
1003
+ });
1004
+ currPinned = this.pinnedStart.find((c) => c === startCol);
1005
+ if (boundBox.x < widthAggregate) {
1006
+ // this column is pinned
1007
+ if (!currPinned)
1008
+ this.pinnedStart = [
1009
+ ...this.pinnedStart,
1010
+ startCol,
1011
+ ];
1012
+ }
1013
+ else if (currPinned) {
1014
+ // this column is unpinned
1015
+ this.pinnedStart = this.pinnedStart.filter((c) => c !== startCol);
1016
+ }
1017
+ widthAggregate += boundBox.width;
1018
+ }
1019
+ if (!this.endColumns.length)
1020
+ resolve();
1021
+ });
1022
+ }
1023
+ // end cols
1024
+ if (this.endColumns.length) {
1025
+ readTask(() => {
1026
+ const endCols = Array.from(this.endColumns).reverse();
1027
+ parentEles = Array.from(this.endColumns[0].parentElement.children);
1028
+ const { offsetX } = this.getParentOffsets();
1029
+ // cumulatively add widths of columns together
1030
+ // 'cos columns stick together
1031
+ let widthAggregate = 0;
1032
+ for (const endCol of endCols) {
1033
+ boundBox = endCol.getBoundingClientRect();
1034
+ // cache meta for later
1035
+ this.cachedColMeta.set(endCol, {
1036
+ width: boundBox.width,
1037
+ idx: parentEles.indexOf(endCol),
1038
+ });
1039
+ currPinned = this.pinnedEnd.find((c) => c === endCol);
1040
+ if (this.tableDims.width + offsetX - boundBox.right <=
1041
+ widthAggregate) {
1042
+ // this column is pinned
1043
+ if (!currPinned)
1044
+ this.pinnedEnd = [endCol, ...this.pinnedEnd];
1045
+ }
1046
+ else if (currPinned) {
1047
+ // this column is unpinned
1048
+ this.pinnedEnd = this.pinnedEnd.filter((c) => c !== endCol);
1049
+ }
1050
+ widthAggregate += boundBox.width;
1051
+ }
1052
+ resolve();
1053
+ });
1054
+ }
1055
+ });
1056
+ await done;
1057
+ // potentially generate a new css stylesheet if anything changed
1058
+ this.generateCssCacheKey();
1059
+ }
1060
+ onScroll(pos) {
1061
+ if (this.cacheX !== pos.x) {
1062
+ this.cacheX = pos.x;
1063
+ this.assessCols();
1064
+ }
1065
+ if (this.cacheY !== pos.y) {
1066
+ this.cacheY = pos.y;
1067
+ this.assessRows();
1068
+ }
1069
+ }
1070
+ onResize() {
1071
+ const width = this.scrollElement.clientWidth;
1072
+ const height = this.scrollElement.clientHeight;
1073
+ this.tableDims = { width, height };
1074
+ this.assessCols();
1075
+ this.assessRows();
1076
+ }
1077
+ }
1078
+
1079
+ const tableCss = ":host{box-sizing:border-box}*,*::before,*::after{box-sizing:border-box}[hidden]{display:none !important}nano-table{display:block;width:100%;--max-col-width:clamp(200px, 500px, 50vw);--color:var(--nano-color-mediumgrey, #68767e);--font-size:0.87rem;--cell-line-height:1.5;--thead-font-size:0.95rem;--thead-color:#455560;--tfoot-color:#455560;--border-color:#dddbda;--border-style:thin solid var(--border-color);--border-tint-color:#0084a9;--border-tint-style:3px solid var(--border-tint-color);--cell-bg-rgb:var(--nano-color-white-rgb, 255 255 255);--head-bg-rgb:250 250 249;--foot-bg-rgb:var(--head-bg-rgb);--th-row-bg-rgb:var(--cell-bg-rgb);--ordered-bg-rgb:var(--nano-color-offwhite-rgb, 249 249 251);--td-padding-start:0.625rem;--td-padding-end:0.625rem;--td-padding-top:0.6rem;--td-padding-bottom:0.6125rem;--th-padding-start:0.725rem;--th-padding-end:0.625rem;--th-padding-top:0.875rem;--th-padding-bottom:0.6875rem;--td-padding-v:var(--td-padding-top) var(--td-padding-bottom);--td-padding-h:var(--td-padding-start) var(--td-padding-end);--th-padding-v:var(--th-padding-top) var(--th-padding-bottom);--th-padding-h:var(--th-padding-start) var(--th-padding-end);--foot-th-padding-v:var(--td-padding-top) var(--td-padding-bottom);--foot-th-padding-h:var(--td-padding-start) var(--td-padding-end);--head-th-padding-v:var(--th-padding-top) var(--th-padding-bottom);--head-th-padding-h:var(--th-padding-start) var(--th-padding-end);--bookend-col-padding:2rem}.nano-tbl{color:var(--color);text-align:start;width:100%;font-size:var(--font-size);border-spacing:0 0;border-collapse:separate;background:rgb(var(--cell-bg-rgb));-webkit-border-end:1px solid transparent;border-inline-end:1px solid transparent;-webkit-border-before:1px solid transparent;border-block-start:1px solid transparent;position:relative;z-index:1}.nano-tbl__wrap{display:table;min-width:100%}.nano-tbl__top-anchor{clip:rect(1px, 1px, 1px, 1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);block-size:1px;inline-size:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;position:relative}.nano-tbl__ordered{background-color:var(--ordered-bg);-webkit-border-start:var(--border-style);border-inline-start:var(--border-style);-webkit-border-end:var(--border-style);border-inline-end:var(--border-style)}.nano-tbl__order-btn{padding:0;border:none;outline:none;font:inherit;background:none;-webkit-appearance:none;appearance:none;color:inherit;display:flex;gap:10px;align-items:center;width:100%}.nano-tbl__order-btn:focus-visible{outline:none;box-shadow:var(--nano-control-focus-shadow, 0 0 0 0.1875rem var(--nano-control-focus-color, rgba(144, 198, 231, 0.8))) inset}.nano-tbl__status-icons{margin-inline:auto 10px;display:flex;gap:10px}.nano-tbl__progress-bar{font-size:0.2rem;position:sticky;inset-block-start:0;inset-inline:0;z-index:10;transition:scale 0.25s;transform:scale(0);width:100%;height:0}.nano-tbl__progress-bar--show{transform:scale(1);height:auto}.nano-tbl__caption--hide{clip:rect(1px, 1px, 1px, 1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);block-size:1px;inline-size:1px;margin:-1px;overflow:hidden;padding:0;position:absolute}.nano-tbl__td,.nano-tbl__th{line-height:var(--cell-line-height);text-align:start;-webkit-border-before:var(--border-style);border-block-start:var(--border-style);max-width:var(--max-col-width);background-color:rgb(var(--cell-bg-rgb))}tbody:first-of-type tr:first-child .nano-tbl__td,tbody:first-of-type tr:first-child .nano-tbl__th{-webkit-border-before:none;border-block-start:none}tbody:last-of-type tr:last-child .nano-tbl__td,tbody:last-of-type tr:last-child .nano-tbl__th{-webkit-border-after:var(--border-style);border-block-end:var(--border-style)}.md .nano-tbl__td:first-child .nano-tbl__cell-content,.md .nano-tbl__th:first-child .nano-tbl__cell-content{-webkit-padding-start:var(--bookend-col-padding);padding-inline-start:var(--bookend-col-padding)}.md .nano-tbl__td:last-child .nano-tbl__cell-content,.md .nano-tbl__th:last-child .nano-tbl__cell-content{-webkit-padding-end:var(--bookend-col-padding);padding-inline-end:var(--bookend-col-padding)}@media (max-width: 768px){.nano-tbl__td:first-child .nano-tbl__cell-content,.nano-tbl__th:first-child .nano-tbl__cell-content{-webkit-padding-start:var(--td-padding-start) !important;padding-inline-start:var(--td-padding-start) !important}.nano-tbl__td:last-child .nano-tbl__cell-content,.nano-tbl__th:last-child .nano-tbl__cell-content{-webkit-padding-end:var(--td-padding-end) !important;padding-inline-end:var(--td-padding-end) !important}}thead .nano-tbl__td,thead .nano-tbl__th{color:var(--thead-color);font-weight:800;background:rgb(var(--head-bg-rgb)/100%);font-size:var(--thead-font-size);-webkit-border-before:none !important;border-block-start:none !important}thead .nano-tbl__td .nano-tbl__cell-content,thead .nano-tbl__th .nano-tbl__cell-content{padding-block:var(--head-th-padding-v);padding-inline:var(--head-th-padding-h)}thead .nano-tbl__td .nano-sortable__keyboard-handle,thead .nano-tbl__th .nano-sortable__keyboard-handle{position:absolute;inset-inline-end:5px;inset-block-start:50%;transform:translateY(-50%);background:white;z-index:10}tfoot .nano-tbl__td,tfoot .nano-tbl__th{color:var(--tfoot-color);font-weight:800;-webkit-border-before:none;border-block-start:none;background:rgb(var(--foot-bg-rgb)/100%);font-size:var(--thead-font-size)}tfoot .nano-tbl__td .nano-tbl__cell-content,tfoot .nano-tbl__th .nano-tbl__cell-content{padding-block:var(--foot-th-padding-v);padding-inline:var(--foot-th-padding-h)}.nano-tbl__td.nano-tbl__ordered,.nano-tbl__th.nano-tbl__ordered{background-color:rgb(var(--ordered-bg-rgb)/80%) !important}.nano-tbl__cell-content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding-block:var(--td-padding-v);padding-inline:var(--td-padding-h)}.nano-tbl__cell-content--no-result{padding-block:2rem}.nano-tbl__cell-content--wrap{white-space:normal;overflow:visible}.nano-tbl tbody{will-change:scroll-position;opacity:1;transition:0.1s ease opacity}.nano-tbl tbody.nano-tbl__loading{z-index:-1;position:relative}.nano-tbl tbody.nano-tbl__inactive{opacity:0}.nano-tbl tbody .nano-tbl__tr:has(~.nano-tbl__tr--placeholder){display:none}.nano-tbl tbody .nano-tbl__tr--placeholder~.nano-tbl__tr{display:none}.nano-tbl th[scope=row]{font-weight:800;margin:0}.nano-tbl__pin--start{position:sticky;inset-inline-start:var(--pin-start, -1px)}.nano-tbl__pin--start::after{content:\"\";position:absolute;inset:0;box-shadow:5px 0 4px -1px rgba(0, 0, 0, 0.2);opacity:var(--pin-start-active, 0);z-index:-1}.nano-tbl__pinned--start .nano-tbl__pin--start{z-index:2}.nano-tbl__pin--end{position:sticky}.nano-tbl__pin--start+.nano-tbl__pin--end{inset-inline-end:auto !important}.nano-tbl__pin--start+.nano-tbl__pin--end::after{display:none}.sm .nano-tbl__pin--end{inset-inline-end:var(--pin-end, -1px);max-width:min(50vw, 200px)}.sm .nano-tbl__pin--end::after{display:block !important;content:\"\";position:absolute;inset:0;box-shadow:-5px 1px 4px -1px rgba(0, 0, 0, 0.2);opacity:var(--pin-end-active, 0);z-index:-1}.sm .nano-tbl__pinned--end .nano-tbl__pin--end{z-index:3}.nano-tbl__pin--top .nano-tbl__th,.nano-tbl__pin--top .nano-tbl__td{position:sticky;inset-block-start:var(--pin-top, -1px)}.nano-tbl__pin--top.nano-tbl__pinned--top .nano-tbl__th,.nano-tbl__pin--top.nano-tbl__pinned--top .nano-tbl__td{z-index:4 !important}.nano-tbl__pinned--start .nano-tbl__pin--top.nano-tbl__pinned--top .nano-tbl__pin--start{z-index:6 !important}tbody .nano-tbl__pin--top.nano-tbl__pinned--top .nano-tbl__th,tbody .nano-tbl__pin--top.nano-tbl__pinned--top .nano-tbl__td{box-shadow:1px 3px 4px -1px rgba(0, 0, 0, 0.1)}.nano-tbl__pin--bottom .nano-tbl__th,.nano-tbl__pin--bottom .nano-tbl__td{position:sticky;inset-block-end:var(--pin-bottom, -1px)}.nano-tbl__pin--bottom.nano-tbl__pinned--bottom .nano-tbl__th,.nano-tbl__pin--bottom.nano-tbl__pinned--bottom .nano-tbl__td{z-index:5 !important}.nano-tbl__pin--bottom.nano-tbl__pinned--bottom:has(~.nano-tbl__pin--bottom.nano-tbl__pinned--bottom) .nano-tbl__th,.nano-tbl__pin--bottom.nano-tbl__pinned--bottom:has(~.nano-tbl__pin--bottom.nano-tbl__pinned--bottom) .nano-tbl__td{z-index:6 !important}.nano-tbl__pinned--start .nano-tbl__pin--bottom.nano-tbl__pinned--bottom .nano-tbl__pin--start{z-index:6 !important}tbody .nano-tbl__pin--bottom.nano-tbl__pinned--bottom .nano-tbl__th,tbody .nano-tbl__pin--bottom.nano-tbl__pinned--bottom .nano-tbl__td{box-shadow:1px -3px 4px -1px rgba(0, 0, 0, 0.07)}.nano-tbl thead tr:last-of-type td,.nano-tbl thead tr:last-of-type th{-webkit-border-after:var(--border-tint-style);border-block-end:var(--border-tint-style)}.nano-tbl tfoot tr:first-of-type td,.nano-tbl tfoot tr:first-of-type th{-webkit-border-before:none;border-block-start:none}.nano-tbl tfoot tr:last-of-type td,.nano-tbl tfoot tr:last-of-type th{-webkit-border-before:var(--border-style);border-block-start:var(--border-style);-webkit-border-after:var(--border-tint-style);border-block-end:var(--border-tint-style)}.nano-tbl__pinned--bottom .nano-tbl tfoot tr.nano-tbl__pin--bottom:first-of-type td,.nano-tbl__pinned--bottom .nano-tbl tfoot tr.nano-tbl__pin--bottom:first-of-type th{-webkit-border-before:var(--border-tint-style) !important;border-block-start:var(--border-tint-style) !important}.nano-tbl__pinned--bottom .nano-tbl tfoot tr.nano-tbl__pin--bottom:last-of-type td,.nano-tbl__pinned--bottom .nano-tbl tfoot tr.nano-tbl__pin--bottom:last-of-type th{-webkit-border-after:none !important;border-block-end:none !important}.nano-tbl .unlimited-width{max-width:none}.nano-tbl__spinner{font-size:1.5rem;transition:scale 0.25s;scale:0;padding:0.5rem;position:absolute;inset-block-end:0;inset-inline-start:calc(50% - 0.75rem);z-index:0}.nano-tbl__spinner--show{scale:1;position:sticky}.nano-tbl nano-skeleton{line-height:var(--cell-line-height)}";
769
1080
 
770
1081
  const measurePerf = false;
771
1082
  function perMark(name, end = false) {
772
- if (!Build.isDev || Build.isTesting || !performance || !measurePerf)
1083
+ if (!performance || !measurePerf)
773
1084
  return;
774
1085
  if (end) {
775
1086
  performance === null || performance === void 0 ? void 0 : performance.mark('end' + name);
@@ -862,11 +1173,24 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
862
1173
  * stop loop - it's on the current active block.
863
1174
  */
864
1175
  this.scrollHandler = () => {
1176
+ var _a;
1177
+ perMark('scrollHandler');
865
1178
  // don't listen if this table isn't in the viewport
866
- if (!this.store.general.state.isActive)
1179
+ if (!((_a = this.store) === null || _a === void 0 ? void 0 : _a.general.state.isActive) || !this.rows)
867
1180
  return;
1181
+ if (this.primaryBlockIndex === undefined)
1182
+ this.primaryBlockIndex = 0;
868
1183
  readTask(() => {
869
- this.cacheScrollPosition = this.scrollParent.scrollTop || window.scrollY;
1184
+ this.cacheScrollPosition =
1185
+ typeof this.scrollParent.scrollTop !== 'undefined'
1186
+ ? this.scrollParent.scrollTop
1187
+ : window.scrollY;
1188
+ if (this.tablePinnedService) {
1189
+ this.tablePinnedService.onScroll({
1190
+ x: this.scrollParent.scrollLeft || window.scrollX,
1191
+ y: this.cacheScrollPosition,
1192
+ });
1193
+ }
870
1194
  let cumulativeHeight = this.host.offsetTop;
871
1195
  let blockIndex = 0;
872
1196
  const blockLen = this.blocks.length;
@@ -877,21 +1201,18 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
877
1201
  const potentialBlocks = [
878
1202
  blockIndex,
879
1203
  blockIndex + 1,
880
- Math.max(0, blockIndex - 1),
1204
+ this.cacheScrollPosition,
1205
+ cumulativeHeight,
1206
+ // Math.max(0, blockIndex - 1),
881
1207
  ];
882
1208
  if (potentialBlocks.toString() !== this.activeBlocks.toString()) {
883
1209
  this.activeBlocks = potentialBlocks;
884
- this.setBlockHeight();
885
1210
  }
886
1211
  this.primaryBlockIndex = blockIndex;
887
1212
  }
888
1213
  blockIndex++;
889
1214
  }
890
- });
891
- };
892
- this.handleColumnPinned = (positions) => {
893
- Object.entries(positions).forEach(([key, applied]) => {
894
- this.tableEle.classList.toggle(`${CSSNAMESPACE}__pinned--${key}`, applied);
1215
+ perMark('scrollHandler', true);
895
1216
  });
896
1217
  };
897
1218
  this.handleResizeChange = (e) => {
@@ -902,12 +1223,12 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
902
1223
  classes = [...e.target.className.split(' '), ...classes];
903
1224
  this.tableWrapperEle.classList.add(...classes.filter((cl) => !!cl));
904
1225
  };
905
- this.jsxRenderer = undefined;
1226
+ this.customRenderer = undefined;
906
1227
  this.type = 'table';
907
1228
  this.caption = undefined;
908
1229
  this.showCaption = false;
909
1230
  this.loading = undefined;
910
- this.internalLoading = false;
1231
+ this.internalLoading = true;
911
1232
  this.placeholderSize = 5;
912
1233
  this.rows = undefined;
913
1234
  this.columns = [];
@@ -915,14 +1236,14 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
915
1236
  this.rowRender = undefined;
916
1237
  this.footRender = { pinned: 'bottom' };
917
1238
  this.showFooter = false;
918
- this.perBlock = 40;
1239
+ this.perBlock = 50;
919
1240
  this.searchTerm = undefined;
920
1241
  this.customFilterFn = undefined;
921
1242
  this.customSortFn = undefined;
922
1243
  this.defaultSort = true;
923
1244
  this.virtualTotalItems = 0;
924
1245
  this.blocks = [];
925
- this.activeBlocks = [0, 1, 2];
1246
+ this.activeBlocks = [0, 1];
926
1247
  this.debounceSetLoading = debounce(this.debounceSetLoading.bind(this), 50);
927
1248
  }
928
1249
  get _loading() {
@@ -951,6 +1272,8 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
951
1272
  if (!this.isReady)
952
1273
  requestAnimationFrame(() => this.setInitialBlockDimension());
953
1274
  this._loading = false;
1275
+ if (this.tablePinnedService)
1276
+ this.tablePinnedService.assessRows();
954
1277
  });
955
1278
  }
956
1279
  async handleColsChange() {
@@ -968,6 +1291,10 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
968
1291
  virtualTotalItemsChangeHandler() {
969
1292
  this.setBlocks();
970
1293
  }
1294
+ /** @readonly - shows the currently applied filters */
1295
+ get appliedFilters() {
1296
+ return this.filters;
1297
+ }
971
1298
  /** Remove any column sorts currently applied
972
1299
  * @returns a promise which resolves when complete */
973
1300
  async resetSorting() {
@@ -1010,8 +1337,6 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1010
1337
  }
1011
1338
  /** Updates a row model at a given index
1012
1339
  * @param row - the row to update.
1013
- * *Note* - this should come from the `col.cellTemplate` or `row.rowRender.template` `rowModel` property
1014
- * - rows are augmented with certain properties to aid with efficient rendering
1015
1340
  * @param rowIndex - the row index to insert this row
1016
1341
  */
1017
1342
  async updateRow(row, rowIndex) {
@@ -1042,7 +1367,9 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1042
1367
  ? document
1043
1368
  : this._scrollParent).removeEventListener('scroll', this.scrollHandler);
1044
1369
  }
1045
- (ele === document.documentElement ? document : ele).addEventListener('scroll', this.scrollHandler);
1370
+ (ele === document.documentElement ? document : ele).addEventListener('scroll', this.scrollHandler
1371
+ // {passive: true}
1372
+ );
1046
1373
  this._scrollParent = ele;
1047
1374
  }
1048
1375
  // used to fire `nanoTblBlockRendered` on block render change
@@ -1145,10 +1472,11 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1145
1472
  const res = await this.customFilterFn(this.filters);
1146
1473
  // if the response is 'true', the custom filter did it's thing
1147
1474
  // handover to finish and stop loading state.
1148
- // if response is falsey, carry on to do a FE filter
1475
+ // if response is falsy, carry on to do a FE filter
1149
1476
  if (res === true) {
1150
1477
  this.filterComplete();
1151
1478
  this._loading = false;
1479
+ return;
1152
1480
  }
1153
1481
  }
1154
1482
  catch (e) {
@@ -1157,8 +1485,8 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1157
1485
  console.warn('custom filter failed', e);
1158
1486
  this.currentFilters = '';
1159
1487
  this._loading = false;
1488
+ return;
1160
1489
  }
1161
- return;
1162
1490
  }
1163
1491
  try {
1164
1492
  await storeFilter(this.host, this.filters);
@@ -1174,9 +1502,17 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1174
1502
  filterComplete() {
1175
1503
  this.columns = this.columns.map((c) => {
1176
1504
  const cFilter = this.filters.find((f) => f.prop === c.prop);
1177
- if (cFilter)
1505
+ // if we found a filter AND
1506
+ // it isn't true / false and has a length OR
1507
+ // it is true or false
1508
+ if (cFilter &&
1509
+ ((typeof cFilter.filter !== 'boolean' && cFilter.filter.length) ||
1510
+ typeof cFilter.filter === 'boolean'))
1178
1511
  c.filter = cFilter.filter;
1179
- else if (c.filter !== null && c.filter !== undefined)
1512
+ // if a filter value is not set OR
1513
+ // it isn't true / false and has no length
1514
+ else if ((c.filter !== null && c.filter !== undefined) ||
1515
+ (!!c.filter && typeof c.filter !== 'boolean' && !c.filter.length))
1180
1516
  c.filter = undefined;
1181
1517
  return c;
1182
1518
  });
@@ -1265,6 +1601,8 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1265
1601
  if (!!col) {
1266
1602
  await this.sortStart(col.order, col.prop);
1267
1603
  }
1604
+ if (this.tablePinnedService)
1605
+ this.tablePinnedService.assessCols();
1268
1606
  }
1269
1607
  /** Split up all incoming rows into 'blocks' split amongst tbody elements.
1270
1608
  * These can then be hidden / shown to improve performance.
@@ -1311,14 +1649,14 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1311
1649
  getBlockHeight(blockIndex) {
1312
1650
  if (this.blockHeights.length) {
1313
1651
  const cachedBlockHeight = this.blockHeights.find((bh) => bh.blockIndex === blockIndex);
1314
- if (cachedBlockHeight)
1652
+ if (cachedBlockHeight && cachedBlockHeight.height)
1315
1653
  return cachedBlockHeight.height;
1316
1654
  }
1317
1655
  const blockLength = this.blocks[blockIndex].rows.length;
1318
1656
  if (blockLength === this.perBlock && this.measureHeight) {
1319
1657
  return this.measureHeight;
1320
1658
  }
1321
- return this.unitHeight ? this.unitHeight * blockLength : undefined;
1659
+ return this.unitHeight ? this.unitHeight * blockLength : 100;
1322
1660
  }
1323
1661
  /** cache the height for all active blocks for later renders */
1324
1662
  setBlockHeight() {
@@ -1371,7 +1709,9 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1371
1709
  // setup stores
1372
1710
  this.store = await generateStore(this.host, this.columns, this.scrollParent, this.isReady);
1373
1711
  await this.handleRowsChange();
1374
- this.store.general.onChange('isActive', this.scrollHandler);
1712
+ this.store.general.onChange('isActive', () => {
1713
+ this.scrollHandler();
1714
+ });
1375
1715
  this.store.data.onChange('rows', () => this.setBlocks());
1376
1716
  // setup dom and attach listeners
1377
1717
  this.processSlots();
@@ -1385,6 +1725,9 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1385
1725
  }
1386
1726
  componentDidLoad() {
1387
1727
  this.setInitialBlockDimension();
1728
+ if (!this.tablePinnedService) {
1729
+ this.tablePinnedService = new TablePinService(this.tableEle, this.scrollParent);
1730
+ }
1388
1731
  }
1389
1732
  componentShouldUpdate(_newVal, _oldVal, stateName) {
1390
1733
  // stop double rendering - we use the store for rendering internally
@@ -1392,14 +1735,12 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1392
1735
  // but we don't want it to cause renders
1393
1736
  if (['rows', 'columns'].includes(stateName))
1394
1737
  return false;
1395
- if (Build.isDev && !Build.isTesting && measurePerf)
1396
- console.log(stateName, _newVal, _oldVal);
1397
1738
  }
1398
1739
  componentWillRender() {
1399
1740
  perMark('render');
1400
1741
  }
1401
1742
  componentDidRender() {
1402
- this.setMeasureElement();
1743
+ this.setMeasureElement().then(() => this.setBlockHeight());
1403
1744
  perMark('render', true);
1404
1745
  }
1405
1746
  disconnectedCallback() {
@@ -1413,28 +1754,31 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1413
1754
  }
1414
1755
  render() {
1415
1756
  this.blockElements = [];
1416
- return (h(Host, null, h("div", { class: `${CSSNAMESPACE}__top-anchor`, ref: (a) => (this.topAnchorEle = a) }, "\u00A0"), h("nano-resize-observe", { states: "576w sm, 768w md", class: "sm md", onNanoResizeStateChange: this.handleResizeChange }), h("div", { class: `${CSSNAMESPACE}__wrap sm md`, ref: (div) => (this.tableWrapperEle = div), "aria-labelledby": 'table-caption-' + this.renderId, tabindex: this.type === 'grid' ? '0' : undefined }, h("nano-progress-bar", { indeterminate: true, class: {
1757
+ return (h(Host, null, h("div", { class: `${CSSNAMESPACE}__top-anchor`, ref: (a) => (this.topAnchorEle = a) }, "\u00A0"), h("nano-resize-observe", { states: "576w sm, 768w md", class: "sm md", onNanoResizeStateChange: this.handleResizeChange, onNanoResize: () => {
1758
+ if (this.tablePinnedService)
1759
+ this.tablePinnedService.onResize();
1760
+ } }), h("div", { class: `${CSSNAMESPACE}__wrap sm md`, ref: (div) => (this.tableWrapperEle = div), "aria-labelledby": 'nano-table-caption-' + this.renderId, tabindex: this.type === 'grid' ? '0' : undefined }, h("nano-progress-bar", { indeterminate: true, class: {
1417
1761
  [`${CSSNAMESPACE}__progress-bar`]: true,
1418
1762
  [`${CSSNAMESPACE}__progress-bar--show`]: this._loading,
1419
- } }), h("table", { role: this.type === 'grid' ? 'grid' : undefined, "aria-rowcount": this.store.data.state.rows.length, "aria-colcount": this.store.config.state.columns.length, class: `${CSSNAMESPACE}`, ref: (tbl) => (this.tableEle = tbl) }, h("caption", { class: {
1763
+ } }), h("table", { role: this.type === 'grid' ? 'grid' : undefined, "aria-rowcount": this.store.data.state.rows.length, "aria-colcount": this.store.config.state.columns.length, class: `${CSSNAMESPACE}`, ref: (tbl) => (this.tableEle = tbl), id: 'nano-table-' + this.renderId }, h("caption", { class: {
1420
1764
  [`${CSSNAMESPACE}__caption`]: true,
1421
1765
  [`${CSSNAMESPACE}__caption--hide`]: !this.showCaption,
1422
- }, id: 'table-caption-' + this.renderId }, h("slot", { name: "caption" }, this.caption)), h("thead", null, h(TableHeadFootRow, { rowRenderer: this.headRender, onColumnPinned: this.handleColumnPinned }, this.store.config.state.columns.map((colModel) => [
1423
- h(TableColHead, { column: colModel, headRenderer: this.headRender, onColumnSortClick: this.sortStart, onColumnPinned: this.handleColumnPinned, defaults: {
1766
+ }, id: 'nano-table-caption-' + this.renderId }, h("slot", { name: "caption" }, this.caption)), h("thead", null, h(TableHeadFootRow, { rowRenderer: this.headRender }, this.store.config.state.columns.map((colModel) => [
1767
+ h(TableColHead, { column: colModel, headRenderer: this.headRender, onColumnSortClick: this.sortStart, defaults: {
1424
1768
  sortable: this.defaultSort,
1425
1769
  } }),
1426
- ]))), 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$1, { rowIndex: rowIndex, colIndex: colIndex, nestedContent: () => h("nano-skeleton", null) })))))))), h("tr", { hidden: !!this._loading || !!this.blocks.length }, 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) => {
1770
+ ]))), this._loading && !this.blocks.length && (h("tbody", { class: `${CSSNAMESPACE}__active ${CSSNAMESPACE}__loading` }, [...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) })))))))), h("tr", { hidden: !!this._loading || !!this.blocks.length }, 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) => {
1427
1771
  this.blockElements.push(tb);
1428
1772
  }, class: {
1429
1773
  [`${CSSNAMESPACE}__inactive`]: !this.activeBlocks.includes(blockIndex),
1430
1774
  [`${CSSNAMESPACE}__active`]: this.activeBlocks.includes(blockIndex),
1431
1775
  } }, this.activeBlocks.includes(blockIndex) ? (block.rows.map((row, i) => {
1432
1776
  const rowIndex = blockIndex > 0 ? blockIndex * this.perBlock + i : i;
1433
- return (h(TableRow, { rowRenderer: this.rowRender, rowModel: row, rowIndex: rowIndex }, this.store.config.state.columns.map((_colModel, colIndex) => (h(TableCell$1, { rowIndex: rowIndex, colIndex: colIndex })))));
1434
- })) : (h("tr", null, h("td", { colSpan: this.store.config.state.columns.length, style: {
1777
+ return (h(TableRow, { rowRenderer: this.rowRender, rowModel: row, rowIndex: rowIndex }, this.store.config.state.columns.map((_colModel, colIndex) => (h(TableCell, { rowIndex: rowIndex, colIndex: colIndex })))));
1778
+ })) : (h("tr", { class: `${CSSNAMESPACE}__tr--placeholder` }, h("td", { colSpan: this.store.config.state.columns.length, style: {
1435
1779
  height: this.getBlockHeight(blockIndex) + 'px',
1436
- } })))))), this.showFooter && (h("tfoot", null, h(TableHeadFootRow, { rowRenderer: this.footRender, onColumnPinned: this.handleColumnPinned }, this.store.config.state.columns.map((colModel) => [
1437
- h(TableColHead, { column: colModel, headRenderer: this.footRender, onColumnPinned: this.handleColumnPinned, onColumnSortClick: this.sortStart, defaults: {
1780
+ } })))))), this.showFooter && (h("tfoot", null, h(TableHeadFootRow, { rowRenderer: this.footRender }, this.store.config.state.columns.map((colModel) => [
1781
+ h(TableColHead, { column: colModel, headRenderer: this.footRender, onColumnSortClick: this.sortStart, defaults: {
1438
1782
  sortable: this.defaultSort,
1439
1783
  } }),
1440
1784
  ]))))), !!this.blocks.length && (h("nano-spinner", { type: "circle", class: {
@@ -1451,7 +1795,7 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1451
1795
  }; }
1452
1796
  static get style() { return tableCss; }
1453
1797
  }, [4, "nano-table", {
1454
- "jsxRenderer": [16],
1798
+ "customRenderer": [16],
1455
1799
  "type": [1],
1456
1800
  "caption": [1],
1457
1801
  "showCaption": [4, "show-caption"],
@@ -1470,6 +1814,7 @@ const Table = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
1470
1814
  "customSortFn": [16],
1471
1815
  "defaultSort": [4, "default-sort"],
1472
1816
  "virtualTotalItems": [2, "virtual-total-items"],
1817
+ "appliedFilters": [2064],
1473
1818
  "internalLoading": [32],
1474
1819
  "blocks": [32],
1475
1820
  "activeBlocks": [32],