@likable-hair/svelte 3.3.12 → 3.3.14

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.
@@ -15,7 +15,7 @@
15
15
  import { DateTime } from "luxon";
16
16
  import { createEventDispatcher, onMount } from "svelte";
17
17
  import { quintOut } from "svelte/easing";
18
- import { crossfade } from "svelte/transition";
18
+ import { crossfade, fade } from "svelte/transition";
19
19
  import Filters from "../search/Filters.svelte";
20
20
  import ConfirmOrCancelButtons from "../forms/ConfirmOrCancelButtons.svelte";
21
21
  import { flip } from "svelte/animate";
@@ -31,10 +31,15 @@ import DynamicFilters from "../search/DynamicFilters.svelte";
31
31
  import QuickActions, {} from "../common/QuickActions.svelte";
32
32
  import "./DynamicTable.css";
33
33
  import Switch from "../../simple/forms/Switch.svelte";
34
+ import CircularLoader from "../../simple/loaders/CircularLoader.svelte";
34
35
  onMount(() => {
35
36
  updateHeaderHeight();
36
37
  window.addEventListener("resize", updateHeaderHeight);
37
- return () => window.removeEventListener("resize", updateHeaderHeight);
38
+ tableContainer.addEventListener("scroll", setReachedBottomOrTop);
39
+ return () => {
40
+ window.removeEventListener("resize", updateHeaderHeight);
41
+ tableContainer.removeEventListener("scroll", setReachedBottomOrTop);
42
+ };
38
43
  });
39
44
  let mainHeader;
40
45
  function updateHeaderHeight() {
@@ -43,6 +48,26 @@ function updateHeaderHeight() {
43
48
  document.documentElement.style.setProperty("--main-header-height", headerHeight + "px");
44
49
  }
45
50
  }
51
+ function setReachedBottomOrTop() {
52
+ reachedBottom = tableContainer.scrollHeight - tableContainer.scrollTop === tableContainer.clientHeight;
53
+ reachedTop = tableContainer.scrollTop === 0;
54
+ }
55
+ $:
56
+ if (reachedBottom && rows.length < totalRows) {
57
+ setTimeout(() => {
58
+ if (reachedBottom) {
59
+ handleLoadForward();
60
+ }
61
+ }, 30);
62
+ }
63
+ $:
64
+ if (reachedTop && currentSectionNumber > 0) {
65
+ setTimeout(() => {
66
+ if (reachedTop) {
67
+ handleLoadBackward();
68
+ }
69
+ }, 30);
70
+ }
46
71
  const [send, receive] = crossfade({
47
72
  duration: 500,
48
73
  fallback(node, params) {
@@ -61,8 +86,10 @@ const [send, receive] = crossfade({
61
86
  let clazz = {};
62
87
  export { clazz as class };
63
88
  const dispatch = createEventDispatcher();
64
- export let headers = [], headersToShowInTable = headers, subHeaders = [], customizeHeaders = false, rows = [], sortedBy = void 0, sortDirection = "asc", cellEdit = false, noItemsText = "No items to show", showSelect = false, showSelectContainer = true, selectMode = "single", selectedItems = [], showExpand = false, loading = false, disabled = false, filters = [], searchBarColumns = void 0, searchBarVisible = false, searchBarPlaceholder = "Type to search for identification code, description and MRN...", filtersVisible = false, quickFiltersVisible = false, lang = "en", editFilterMode = "one-edit", showActiveFilters = true, quickFilters = [], actionsForSelectedItems = [], totalRows = rows.length, searchText = void 0, renderedRowsNumber = 100, sectionRowsNumber = 20, sectionTreshold = 2, backwardTresholdPixel = 100, forwardTresholdPixel = 100;
65
- let openCellEditor = false, cellEditorActivator, cellEditorContainer, menuElementCellEditor, menuElementQuickFilters, cellEditorInfoActive, saveEditDisabled = false, searchBarInput = void 0, openQuickFilter = false, quickFilterActivator, quickFilterActive, globalBuilder = new FilterBuilder(), slotSelectActionsContainer, isSelectedAll = false, calendarOpened = false, calendarOpened2 = false, selectedIndexes = [], cellEditorIndexRow, cellEditorIndexHeader, cellEditorSubItem, currentSectionNumber = 0, tableBody, tableContainer, userScrolling = true, totalSections = (totalRows - renderedRowsNumber) / sectionRowsNumber;
89
+ export let headers = [], headersToShowInTable = headers, subHeaders = [], customizeHeaders = false, rows = [], sortedBy = void 0, sortDirection = "asc", cellEdit = false, noItemsText = "No items to show", showSelect = false, showSelectContainer = true, selectMode = "single", selectedItems = [], showExpand = false, loading = false, disabled = false, filters = [], searchBarColumns = void 0, searchBarVisible = false, searchBarPlaceholder = "Type to search for identification code, description and MRN...", filtersVisible = false, quickFiltersVisible = false, lang = "en", editFilterMode = "one-edit", showActiveFilters = true, quickFilters = [], actionsForSelectedItems = [], totalRows = rows.length, searchText = void 0, renderedRowsNumber = 100, sectionRowsNumber = 20, sectionThreshold = 2, backwardThresholdPixel = 100, forwardThresholdPixel = 100, uniqueKey = "id", numberOfResultsVisible = false, endLineVisible = false;
90
+ let openCellEditor = false, cellEditorActivator, cellEditorContainer, menuElementCellEditor, menuElementQuickFilters, cellEditorInfoActive, saveEditDisabled = false, searchBarInput = void 0, openQuickFilter = false, quickFilterActivator, quickFilterActive, globalBuilder = new FilterBuilder(), slotSelectActionsContainer, isSelectedAll = false, calendarOpened = false, calendarOpened2 = false, selectedIndexes = [], cellEditorIndexRow, cellEditorIndexHeader, cellEditorSubItem, currentSectionNumber = 0, tableBody, tableContainer, userScrolling = true, reachedBottom = false, reachedTop = false;
91
+ $:
92
+ totalSections = (totalRows - renderedRowsNumber) / sectionRowsNumber;
66
93
  $:
67
94
  hasMoreToRender = totalSections > currentSectionNumber;
68
95
  $:
@@ -172,14 +199,14 @@ function handleCancelClick() {
172
199
  openQuickFilter = false;
173
200
  }
174
201
  function handleSelect(item, shiftKeyPressed) {
175
- let index = selectedItems.findIndex((i) => i.id == item.id);
202
+ let index = selectedItems.findIndex((i) => i[uniqueKey] == item[uniqueKey]);
176
203
  if (index == -1) {
177
204
  if (selectMode == "single") {
178
205
  selectedItems = [item];
179
- selectedIndexes = [rows.findIndex((r) => r.item.id == item.id)];
206
+ selectedIndexes = [rows.findIndex((r) => r.item[uniqueKey] == item[uniqueKey])];
180
207
  } else if (selectMode == "multiple") {
181
208
  if (shiftKeyPressed && selectedIndexes.length > 0 && !isSelectedAll) {
182
- let lastSelectedIndex = selectedIndexes[selectedIndexes.length - 1], selectedIndex = rows.findIndex((r) => r.item.id == item.id);
209
+ let lastSelectedIndex = selectedIndexes[selectedIndexes.length - 1], selectedIndex = rows.findIndex((r) => r.item[uniqueKey] == item[uniqueKey]);
183
210
  if (selectedIndex != -1) {
184
211
  if (selectedIndex < lastSelectedIndex) {
185
212
  let x = lastSelectedIndex;
@@ -187,19 +214,19 @@ function handleSelect(item, shiftKeyPressed) {
187
214
  selectedIndex = x;
188
215
  }
189
216
  for (let i = lastSelectedIndex + 1; i <= selectedIndex; i++) {
190
- if (!selectedItems.find((selectedItem) => selectedItem.id == rows[i].item.id)) {
217
+ if (!selectedItems.find((selectedItem) => selectedItem[uniqueKey] == rows[i].item[uniqueKey])) {
191
218
  selectedItems = [...selectedItems, rows[i].item];
192
219
  }
193
220
  }
194
221
  }
195
222
  } else {
196
223
  selectedItems = [...selectedItems, item];
197
- selectedIndexes.push(rows.findIndex((r) => r.item.id == item.id));
224
+ selectedIndexes.push(rows.findIndex((r) => r.item[uniqueKey] == item[uniqueKey]));
198
225
  }
199
226
  }
200
227
  } else {
201
- selectedItems = selectedItems.filter((i) => i.id != item.id);
202
- selectedIndexes = selectedIndexes.filter((r) => r != rows.findIndex((r2) => r2.item.id == item.id));
228
+ selectedItems = selectedItems.filter((i) => i[uniqueKey] != item[uniqueKey]);
229
+ selectedIndexes = selectedIndexes.filter((r) => r != rows.findIndex((r2) => r2.item[uniqueKey] == item[uniqueKey]));
203
230
  isSelectedAll = false;
204
231
  }
205
232
  }
@@ -216,11 +243,11 @@ function handleSelectAll() {
216
243
  }
217
244
  }
218
245
  function expandRow(row) {
219
- let index = expandedRows.findIndex((r) => r.item.id == row.item.id);
246
+ let index = expandedRows.findIndex((r) => r.item[uniqueKey] == row.item[uniqueKey]);
220
247
  if (index == -1) {
221
248
  expandedRows = [...expandedRows, row];
222
249
  } else {
223
- expandedRows = expandedRows.filter((r) => r.item.id != row.item.id);
250
+ expandedRows = expandedRows.filter((r) => r.item[uniqueKey] != row.item[uniqueKey]);
224
251
  }
225
252
  }
226
253
  function formatDate(dateTime, dateFormat) {
@@ -278,10 +305,12 @@ $:
278
305
  if (searchText != void 0)
279
306
  handleSearchChange(searchText);
280
307
  function handleFiltersChange() {
281
- userScrolling = false;
282
- currentSectionNumber = 0;
283
- tableContainer.scrollTop = 0;
284
- setTimeout(() => userScrolling = true, 20);
308
+ if (!!tableContainer) {
309
+ userScrolling = false;
310
+ currentSectionNumber = 0;
311
+ tableContainer.scrollTop = 0;
312
+ setTimeout(() => userScrolling = true, 20);
313
+ }
285
314
  dispatch("filtersChange", {
286
315
  builder: globalBuilder
287
316
  });
@@ -477,14 +506,14 @@ function quickFilterBuilder(builder, quickFilter, clearPreaviousValue = true) {
477
506
  builder.where(
478
507
  quickFilter.column,
479
508
  ">=",
480
- DateTime.fromJSDate(from).toString()
509
+ DateTime.fromJSDate(from).setLocale("it-IT").startOf("day").toString()
481
510
  );
482
511
  }
483
512
  if (!!to) {
484
513
  builder.where(
485
514
  quickFilter.column,
486
515
  "<=",
487
- DateTime.fromJSDate(to).toString()
516
+ DateTime.fromJSDate(to).setLocale("it-IT").endOf("day").toString()
488
517
  );
489
518
  }
490
519
  }
@@ -567,27 +596,68 @@ function handleRemoveFilter(filter) {
567
596
  handleSearchChange(searchText);
568
597
  }
569
598
  function handleLoadForward() {
570
- userScrolling = false;
571
- let topElementsHeight = 0;
572
- for (let i = 0; i < sectionRowsNumber; i++) {
573
- topElementsHeight += tableBody?.children.item(i)?.getBoundingClientRect().height || 0;
574
- }
575
- currentSectionNumber = currentSectionNumber + 1;
576
- tableContainer.scrollTop -= topElementsHeight;
577
- setTimeout(() => userScrolling = true, 20);
578
- if (totalCachedSections - sectionTreshold <= currentSectionNumber && !loading && totalRows > rows.length) {
599
+ if (renderedRows.length >= renderedRowsNumber) {
600
+ userScrolling = false;
601
+ const anchorIndex = renderedRowsNumber - 1;
602
+ const anchorUniqueKey = renderedRows[anchorIndex].item[uniqueKey];
603
+ const anchorElement = findAnchorElement(anchorUniqueKey);
604
+ const anchorOffsetBefore = anchorElement?.getBoundingClientRect().top || 0;
605
+ let removedRowCount = 0;
606
+ for (let i = 0; removedRowCount < sectionRowsNumber; i++) {
607
+ let row = tableBody.children.item(i);
608
+ removedRowCount++;
609
+ const rowKey = row?.getAttribute("data-key");
610
+ const isExpanded = expandedRows.some((r) => r.item[uniqueKey] == rowKey);
611
+ if (isExpanded) {
612
+ i++;
613
+ }
614
+ }
615
+ currentSectionNumber = currentSectionNumber + 1;
616
+ setTimeout(() => {
617
+ const anchorElementAfter = findAnchorElement(anchorUniqueKey);
618
+ const anchorOffsetAfter = anchorElementAfter?.getBoundingClientRect().top || 0;
619
+ const offsetDiff = anchorOffsetAfter - anchorOffsetBefore;
620
+ tableContainer.scrollTop += offsetDiff;
621
+ userScrolling = true;
622
+ }, 10);
623
+ }
624
+ if (totalCachedSections - sectionThreshold <= currentSectionNumber && !loading && totalRows > rows.length) {
579
625
  dispatch("fetchData", {});
580
626
  }
581
627
  }
582
628
  function handleLoadBackward() {
583
629
  userScrolling = false;
584
- let topElementsHeight = 0;
585
- for (let i = renderedRows.length - 1; i > renderedRows.length - sectionRowsNumber + 1; i--) {
586
- topElementsHeight += tableBody?.children.item(i)?.getBoundingClientRect().height || 0;
630
+ const anchorIndex = 0;
631
+ const anchorUniqueKey = renderedRows[anchorIndex].item[uniqueKey];
632
+ const anchorElement = findAnchorElement(anchorUniqueKey);
633
+ const anchorOffsetBefore = anchorElement?.getBoundingClientRect().top || 0;
634
+ let removedRowCount = 0;
635
+ for (let i = renderedRows.length - 1; removedRowCount < sectionRowsNumber; i--) {
636
+ let row = tableBody.children.item(i);
637
+ removedRowCount++;
638
+ const rowKey = row?.getAttribute("data-key");
639
+ const isExpanded = expandedRows.some((r) => r.item[uniqueKey] == rowKey);
640
+ if (isExpanded) {
641
+ i--;
642
+ }
587
643
  }
588
644
  currentSectionNumber = currentSectionNumber - 1;
589
- tableContainer.scrollTop += topElementsHeight;
590
- setTimeout(() => userScrolling = true, 20);
645
+ setTimeout(() => {
646
+ const anchorElementAfter = findAnchorElement(anchorUniqueKey);
647
+ const anchorOffsetAfter = anchorElementAfter?.getBoundingClientRect().top || 0;
648
+ const offsetDiff = anchorOffsetAfter - anchorOffsetBefore;
649
+ tableContainer.scrollTop += offsetDiff;
650
+ userScrolling = true;
651
+ }, 10);
652
+ }
653
+ function findAnchorElement(key) {
654
+ for (let i = 0; i < tableBody.children.length; i++) {
655
+ const child = tableBody.children.item(i);
656
+ if (child?.getAttribute("data-key") == key) {
657
+ return child;
658
+ }
659
+ }
660
+ return void 0;
591
661
  }
592
662
  </script>
593
663
 
@@ -605,75 +675,78 @@ function handleLoadBackward() {
605
675
  />
606
676
 
607
677
  <slot name="search-bar" {handleSearchChange}>
608
- <div class="search-bar-container">
609
- {#if searchBarVisible}
610
- <SimpleTextField
611
- placeholder={searchBarPlaceholder}
612
- appendInnerIcon="mdi-magnify"
613
- bind:value={searchText}
614
- bind:input={searchBarInput}
615
- on:keydown={handleSearchBoxKeydown}
616
- --simple-textfield-default-width="450px"
617
- --simple-textfield-border-radius= 0.5rem
618
- --simple-textfield-background-color= transparent
619
- --simple-textfield-box-shadow= 'inset 0 0 0 1px rgb(var(--global-color-background-500))'
620
- --simple-textfield-focus-box-shadow='inset 0 0 0 2px rgb(var(--global-color-primary-500))'
621
- />
622
- {/if}
678
+ {#if searchBarVisible || filtersVisible}
679
+ <div class="search-bar-container">
680
+ {#if searchBarVisible}
681
+ <SimpleTextField
682
+ placeholder={searchBarPlaceholder}
683
+ appendInnerIcon="mdi-magnify"
684
+ bind:value={searchText}
685
+ bind:input={searchBarInput}
686
+ on:keydown={handleSearchBoxKeydown}
687
+ --simple-textfield-default-width="450px"
688
+ --simple-textfield-border-radius= 0.5rem
689
+ --simple-textfield-background-color= transparent
690
+ --simple-textfield-box-shadow= 'inset 0 0 0 1px rgb(var(--global-color-background-500))'
691
+ --simple-textfield-focus-box-shadow='inset 0 0 0 2px rgb(var(--global-color-primary-500))'
692
+ />
693
+ {/if}
623
694
 
624
- {#if filtersVisible}
625
- <div style="margin-left: 20px;">
626
- <Filters
627
- bind:filters
628
- on:applyFilter={() => {
629
- handleSearchChange(searchText);
630
- }}
631
- on:removeFilter={e => { handleRemoveFilter(e.detail.filter) }}
632
- on:removeAllFilters={() => handleRemoveAllFilters()}
633
- --filters-default-wrapper-width="100%"
634
- {lang}
635
- {editFilterMode}
636
- {showActiveFilters}
637
- >
638
- <svelte:fragment slot="append">
639
- <slot name="filter-append" />
640
- </svelte:fragment>
641
- <svelte:fragment slot="custom-chip" let:filter>
642
- <slot name="custom-filter-chip" {filter} />
643
- </svelte:fragment>
644
- <svelte:fragment
645
- slot="custom"
646
- let:filter
647
- let:updateFunction
648
- let:mAndDown
695
+ {#if filtersVisible}
696
+ <div style="margin-left: 20px;">
697
+ <Filters
698
+ bind:filters
699
+ on:applyFilter={() => {
700
+ handleSearchChange(searchText);
701
+ }}
702
+ on:removeFilter={e => { handleRemoveFilter(e.detail.filter) }}
703
+ on:removeAllFilters={() => handleRemoveAllFilters()}
704
+ --filters-default-wrapper-width="100%"
705
+ {lang}
706
+ {editFilterMode}
707
+ {showActiveFilters}
649
708
  >
650
- <slot name="custom-filter" {filter} {updateFunction} {mAndDown} />
651
- </svelte:fragment>
709
+ <svelte:fragment slot="append">
710
+ <slot name="filter-append" />
711
+ </svelte:fragment>
712
+ <svelte:fragment slot="custom-chip" let:filter>
713
+ <slot name="custom-filter-chip" {filter} />
714
+ </svelte:fragment>
715
+ <svelte:fragment
716
+ slot="custom"
717
+ let:filter
718
+ let:updateFunction
719
+ let:mAndDown
720
+ >
721
+ <slot name="custom-filter" {filter} {updateFunction} {mAndDown} />
722
+ </svelte:fragment>
652
723
 
653
- <svelte:fragment slot="content" let:mAndDown let:filters let:updateMultiFilterValues let:handleRemoveAllFilters={removeAllFilters}>
654
- {#key filters}
655
- <DynamicFilters
656
- {lang}
657
- {filters}
658
- {mAndDown}
659
- on:change={e => updateFilterValues(e.detail.filter, updateMultiFilterValues)}
660
- on:removeAllFilters={() => handleRemoveAllFilters(removeAllFilters)}
661
- >
662
- <svelte:fragment slot="custom" let:filter let:mAndDown>
663
- <slot name="custom-filter" {filter} {updateMultiFilterValues} {mAndDown}></slot>
664
- </svelte:fragment>
665
- </DynamicFilters>
666
- {/key}
667
- </svelte:fragment>
668
- </Filters>
669
- </div>
670
- {/if}
671
- </div>
724
+ <svelte:fragment slot="content" let:mAndDown let:filters let:updateMultiFilterValues let:handleRemoveAllFilters={removeAllFilters}>
725
+ {#key filters}
726
+ <DynamicFilters
727
+ {lang}
728
+ {filters}
729
+ {mAndDown}
730
+ on:change={e => updateFilterValues(e.detail.filter, updateMultiFilterValues)}
731
+ on:removeAllFilters={() => handleRemoveAllFilters(removeAllFilters)}
732
+ >
733
+ <svelte:fragment slot="custom" let:filter let:mAndDown>
734
+ <slot name="custom-filter" {filter} {updateMultiFilterValues} {mAndDown}></slot>
735
+ </svelte:fragment>
736
+ </DynamicFilters>
737
+ {/key}
738
+ </svelte:fragment>
739
+ </Filters>
740
+ </div>
741
+ {/if}
742
+ </div>
743
+ {/if}
672
744
  </slot>
673
745
 
674
- {#if quickFiltersVisible}
746
+ {#if quickFiltersVisible || numberOfResultsVisible}
747
+ <div class="quick-filters-results-container">
675
748
  <div class="quick-filters">
676
- {#if !!quickFilters && quickFilters.length > 0}
749
+ {#if !!quickFilters && quickFilters.length > 0 && quickFiltersVisible}
677
750
  {#each quickFilters as quickFilter}
678
751
  <div
679
752
  class={quickFilter.active ? "active-quick-filters" : "non-active-quick-filters"}
@@ -704,13 +777,28 @@ function handleLoadBackward() {
704
777
  {/each}
705
778
  {/if}
706
779
  </div>
780
+ {#if numberOfResultsVisible}
781
+ <div class='results-number'>
782
+ { lang == 'en' ? 'Results: ' : 'Risultati: '}
783
+ {#if !loading}
784
+ {totalRows || rows.length}
785
+ {:else}
786
+ <CircularLoader
787
+ {loading}
788
+ --circular-loader-height='10px'
789
+ ></CircularLoader>
790
+ {/if}
791
+ </div>
792
+ {/if}
793
+ </div>
707
794
  {/if}
795
+
708
796
  <div class="outer-container">
709
- <div class="inner-container" bind:this={tableContainer}>
797
+ <div class="inner-container" bind:this={tableContainer} on:scroll>
710
798
  <!-- <div class="table-container" bind:this={tableContainer}> -->
711
799
  <InfiniteScroll
712
800
  on:loadMore={handleLoadBackward}
713
- treshold={backwardTresholdPixel}
801
+ threshold={backwardThresholdPixel}
714
802
  hasMore={currentSectionNumber > 0 && userScrolling}
715
803
  direction='backward'
716
804
  />
@@ -843,15 +931,16 @@ function handleLoadBackward() {
843
931
  {#each renderedRows as row, indexRow}
844
932
  <tr
845
933
  class="item-row"
934
+ data-key={row.item[uniqueKey]}
846
935
  style:background-color={
847
936
  !!row.item.disableEdit ?
848
937
  !!row.item.rowDisableBackgroundColor ?
849
938
  row.item.rowDisableBackgroundColor :
850
- 'var(--dynamic-table-row-disabled-background-color, var(--dynamic-table-row-default-disabled-background-color))' :
851
- expandedRows.findIndex((r) => r.item.id == row.item.id ) != -1 ?
852
- 'var(--dynamic-table-expanded-row-background-color, var(--dynamic-table-expanded-row-default-background-color))' :
853
- !!selectedItems.find(i => i.id == row.item.id) ?
854
- 'var(--dynamic-table-selected-row-background-color, var(--dynamic-table-selected-row-default-background-color))' :
939
+ 'var(--dynamic-table-row-disabled-background-color, var(--dynamic-table-default-row-disabled-background-color))' :
940
+ expandedRows.findIndex((r) => r.item[uniqueKey] == row.item[uniqueKey] ) != -1 ?
941
+ 'var(--dynamic-table-expanded-row-background-color, var(--dynamic-table-default-expanded-row-background-color))' :
942
+ !!selectedItems.find(i => i[uniqueKey] == row.item[uniqueKey]) ?
943
+ 'var(--dynamic-table-selected-row-background-color, var(--dynamic-table-default-selected-row-background-color))' :
855
944
  ""
856
945
  }
857
946
  class:row-activator={cellEditorIndexRow == indexRow && !cellEditorSubItem}
@@ -860,9 +949,9 @@ function handleLoadBackward() {
860
949
  {#if !!showSelect && !showExpand}
861
950
  <td style:padding-left="0px" style:text-align="center">
862
951
  <Checkbox
863
- id={row.item.id}
952
+ id={row.item[uniqueKey]}
864
953
  value={selectedItems.findIndex(
865
- (i) => i.id == row.item.id
954
+ (i) => i[uniqueKey] == row.item[uniqueKey]
866
955
  ) != -1}
867
956
  disabled={disabled || loading}
868
957
  on:change={(e) => handleSelect(row.item, e.detail.shiftKeyPressed)}
@@ -873,7 +962,7 @@ function handleLoadBackward() {
873
962
  <td style:padding-left="0px" style:text-align="center">
874
963
  <Icon
875
964
  name={expandedRows.findIndex(
876
- (r) => r.item.id == row.item.id
965
+ (r) => r.item[uniqueKey] == row.item[uniqueKey]
877
966
  ) == -1
878
967
  ? "mdi-chevron-down"
879
968
  : "mdi-chevron-up"}
@@ -940,7 +1029,7 @@ function handleLoadBackward() {
940
1029
  {/if}
941
1030
  </tr>
942
1031
  {#if showExpand}
943
- {#if expandedRows.findIndex((r) => r.item.id == row.item.id) != -1}
1032
+ {#if expandedRows.findIndex((r) => r.item[uniqueKey] == row.item[uniqueKey]) != -1}
944
1033
  <tr>
945
1034
  <td
946
1035
  colspan={headersToShowInTable.length + 1}
@@ -1000,7 +1089,7 @@ function handleLoadBackward() {
1000
1089
  {#each subHeaders as subHeader, indexSubHeader}
1001
1090
  <td
1002
1091
  class:cell-edit-activator={cellEditorIndexHeader == indexSubHeader && cellEditorIndexRow == indexSubItem && cellEditorSubItem}
1003
- class:hover-cell={cellEdit}
1092
+ class:hover-cell={cellEdit && !loading && !!subHeader.cellEditorInfo}
1004
1093
  on:click={(e) => {
1005
1094
  handleCellClick(
1006
1095
  e,
@@ -1042,7 +1131,7 @@ function handleLoadBackward() {
1042
1131
  {subHeader.type.params.nullText}
1043
1132
  {/if}
1044
1133
  {:else}
1045
- {subItem[subHeader.value]}
1134
+ <div style="display: flex; justify-content: center;">-</div>
1046
1135
  {/if}
1047
1136
  {:else}
1048
1137
  {subItem[subHeader.value]}
@@ -1077,10 +1166,17 @@ function handleLoadBackward() {
1077
1166
  </table>
1078
1167
  <InfiniteScroll
1079
1168
  on:loadMore={handleLoadForward}
1080
- treshold={forwardTresholdPixel}
1169
+ threshold={forwardThresholdPixel}
1081
1170
  hasMore={hasMoreToRender && userScrolling}
1082
1171
  />
1083
1172
  </div>
1173
+ {#if totalSections - 1 < currentSectionNumber && reachedBottom && endLineVisible}
1174
+ <div class="line-container" transition:fade>
1175
+ <span class="line"></span>
1176
+ <span class="text">{lang == 'en' ? 'End' : 'Fine'}</span>
1177
+ <span class="line"></span>
1178
+ </div>
1179
+ {/if}
1084
1180
  </div>
1085
1181
  {/if}
1086
1182
 
@@ -1234,55 +1330,58 @@ function handleLoadBackward() {
1234
1330
  >
1235
1331
  {/if}
1236
1332
  </div>
1237
- <Autocomplete
1238
- multiple
1239
- items={quickFilterActive.type.items}
1240
- bind:values={quickFilterActive.type.values}
1241
- --autocomplete-border="1px solid rgb(var(--global-color-background-500))"
1242
- --autocomplete-focus-box-shadow="0 0 0 2px rgb(var(--global-color-primary-500))"
1243
- >
1244
- <svelte:fragment slot="selection" let:selection let:unselect>
1245
- <slot name="selection" {selection} {unselect}>
1246
- <div tabindex="-1">
1247
- <Chip
1248
- close={true}
1249
- on:close={() => unselect(selection)}
1250
- --chip-default-border-radius="var(--autocomplete-border-radius, var(--autocomplete-default-border-radius))"
1251
- buttonTabIndex={-1}
1252
- truncateText
1253
- >
1254
- <slot name="chip-label" {selection}>
1255
- {#if !!quickFilterActive.type.countriesAlpha2 && quickFilterActive.type.countriesAlpha2.find((c) => c.value == selection.value)}
1256
- <div>
1257
- <FlagIcon
1258
- alpha2={quickFilterActive.type.countriesAlpha2
1259
- .find((c) => c.value == selection.value)
1260
- ?.label?.toString()
1261
- .toLowerCase() ?? ""}
1262
- --flag-icon-size="16px"
1263
- />
1264
- </div>
1265
- {/if}
1266
- {selection.label}
1267
- </slot>
1268
- </Chip>
1269
- </div>
1270
- </slot>
1271
- </svelte:fragment>
1272
- <svelte:fragment slot="item-label" let:item>
1273
- <slot name="item-label" {item}>
1274
- {#if !!quickFilterActive.type.countriesAlpha2 && quickFilterActive.type.countriesAlpha2.find((c) => c.value == item.value)}
1275
- <FlagIcon
1276
- alpha2={quickFilterActive.type.countriesAlpha2
1277
- .find((c) => c.value == item.value)
1278
- ?.label?.toString()
1279
- .toLowerCase() ?? ""}
1280
- />
1281
- {/if}
1282
- {item.label}
1283
- </slot>
1284
- </svelte:fragment>
1285
- </Autocomplete>
1333
+ <div on:click|stopPropagation role="presentation" tabindex="-1">
1334
+ <Autocomplete
1335
+ multiple
1336
+ items={quickFilterActive.type.items}
1337
+ bind:values={quickFilterActive.type.values}
1338
+ --autocomplete-border-radius= 0.5rem
1339
+ --autocomplete-border="1px solid rgb(var(--global-color-background-500))"
1340
+ --autocomplete-focus-box-shadow="0 0 0 2px rgb(var(--global-color-primary-500))"
1341
+ >
1342
+ <svelte:fragment slot="selection" let:selection let:unselect>
1343
+ <slot name="selection" {selection} {unselect}>
1344
+ <div tabindex="-1">
1345
+ <Chip
1346
+ close={true}
1347
+ on:close={() => unselect(selection)}
1348
+ --chip-default-border-radius="var(--autocomplete-border-radius, var(--autocomplete-default-border-radius))"
1349
+ buttonTabIndex={-1}
1350
+ truncateText
1351
+ >
1352
+ <slot name="chip-label" {selection}>
1353
+ {#if !!quickFilterActive.type.countriesAlpha2 && quickFilterActive.type.countriesAlpha2.find((c) => c.value == selection.value)}
1354
+ <div>
1355
+ <FlagIcon
1356
+ alpha2={quickFilterActive.type.countriesAlpha2
1357
+ .find((c) => c.value == selection.value)
1358
+ ?.label?.toString()
1359
+ .toLowerCase() ?? ""}
1360
+ --flag-icon-size="16px"
1361
+ />
1362
+ </div>
1363
+ {/if}
1364
+ {selection.label}
1365
+ </slot>
1366
+ </Chip>
1367
+ </div>
1368
+ </slot>
1369
+ </svelte:fragment>
1370
+ <svelte:fragment slot="item-label" let:item>
1371
+ <slot name="item-label" {item}>
1372
+ {#if !!quickFilterActive.type.countriesAlpha2 && quickFilterActive.type.countriesAlpha2.find((c) => c.value == item.value)}
1373
+ <FlagIcon
1374
+ alpha2={quickFilterActive.type.countriesAlpha2
1375
+ .find((c) => c.value == item.value)
1376
+ ?.label?.toString()
1377
+ .toLowerCase() ?? ""}
1378
+ />
1379
+ {/if}
1380
+ {item.label}
1381
+ </slot>
1382
+ </svelte:fragment>
1383
+ </Autocomplete>
1384
+ </div>
1286
1385
  {:else if quickFilterActive.type.key === "boolean"}
1287
1386
  {#if quickFilterActive.type.params}
1288
1387
  <div class="vertical-quick-filters">
@@ -1314,22 +1413,24 @@ function handleLoadBackward() {
1314
1413
  >
1315
1414
  {/if}
1316
1415
  </div>
1317
- <CountriesAutocomplete
1318
- bind:selected={quickFilterActive.type.selected}
1319
- {...((!!quickFilterActive.type.countriesOptions && quickFilterActive.type.countriesOptions.length > 0) && {
1320
- items: quickFilterActive.type.countriesOptions,
1321
- })}
1322
- autocompleteProps={{
1323
- placeholder: !!quickFilterActive.type.selected
1324
- ? quickFilterActive.type.selected.length > 0
1325
- ? ""
1326
- : quickFilterActive.description
1327
- : quickFilterActive.description,
1328
- multiple: true,
1329
- }}
1330
- --autocomplete-border="1px solid rgb(var(--global-color-background-500))"
1331
- --autocomplete-focus-box-shadow="0 0 0 2px rgb(var(--global-color-primary-500))"
1332
- />
1416
+ <div on:click|stopPropagation role="presentation" tabindex="-1">
1417
+ <CountriesAutocomplete
1418
+ bind:selected={quickFilterActive.type.selected}
1419
+ {...((!!quickFilterActive.type.countriesOptions && quickFilterActive.type.countriesOptions.length > 0) && {
1420
+ items: quickFilterActive.type.countriesOptions,
1421
+ })}
1422
+ autocompleteProps={{
1423
+ placeholder: !!quickFilterActive.type.selected
1424
+ ? quickFilterActive.type.selected.length > 0
1425
+ ? ""
1426
+ : quickFilterActive.description
1427
+ : quickFilterActive.description,
1428
+ multiple: true,
1429
+ }}
1430
+ --autocomplete-border="1px solid rgb(var(--global-color-background-500))"
1431
+ --autocomplete-focus-box-shadow="0 0 0 2px rgb(var(--global-color-primary-500))"
1432
+ />
1433
+ </div>
1333
1434
  {:else if quickFilterActive.type.key === "date"}
1334
1435
  <div on:click|stopPropagation role="presentation" tabindex="-1">
1335
1436
  <div>
@@ -1495,7 +1596,6 @@ function handleLoadBackward() {
1495
1596
  .inner-container {
1496
1597
  overflow-y: auto;
1497
1598
  margin-right: -15px;
1498
- padding-right: 15px;
1499
1599
  max-height: var(--dynamic-table-max-height, var(--dynamic-table-default-max-height));
1500
1600
  }
1501
1601
 
@@ -1513,10 +1613,18 @@ function handleLoadBackward() {
1513
1613
  z-index: 2;
1514
1614
  }
1515
1615
 
1616
+ @media not all and (min-resolution:.001dpcm) {
1617
+ .table-header {
1618
+ position: sticky;
1619
+ top: -2px;
1620
+ z-index: 2;
1621
+ }
1622
+ }
1623
+
1516
1624
  .table-subheader {
1517
- top: var(--main-header-height);
1518
- z-index: 1;
1519
- }
1625
+ top: var(--main-header-height);
1626
+ z-index: 1;
1627
+ }
1520
1628
  .table-header th {
1521
1629
  padding: var(
1522
1630
  --dynamic-table-header-padding,
@@ -1599,7 +1707,7 @@ function handleLoadBackward() {
1599
1707
  }
1600
1708
 
1601
1709
  table {
1602
- border-collapse: collapse;
1710
+ border-collapse: separate;
1603
1711
  width: 100%;
1604
1712
  }
1605
1713
 
@@ -1620,10 +1728,17 @@ function handleLoadBackward() {
1620
1728
  border-radius: 5px;
1621
1729
  }
1622
1730
 
1731
+ .item-row > td {
1732
+ height: var(
1733
+ --dynamic-table-row-min-height,
1734
+ var(--dynamic-table-default-row-min-height)
1735
+ );
1736
+ }
1737
+
1623
1738
  .item-row:hover {
1624
1739
  background-color: var(
1625
1740
  --dynamic-table-row-background-color-hover,
1626
- var(--dynamic-table-row-default-background-color-hover)
1741
+ var(--dynamic-table-default-row-background-color-hover)
1627
1742
  );
1628
1743
  }
1629
1744
 
@@ -1638,7 +1753,7 @@ function handleLoadBackward() {
1638
1753
  border-radius: 10px;
1639
1754
  background-color: var(
1640
1755
  --dynamic-table-cell-editor-background-color,
1641
- var(--dynamic-table-cell-editor-default-background-color)
1756
+ var(--dynamic-table-default-cell-editor-background-color)
1642
1757
  );
1643
1758
  height: 200px;
1644
1759
  width: 500px;
@@ -1647,7 +1762,7 @@ function handleLoadBackward() {
1647
1762
  .row-activator {
1648
1763
  background-color: var(
1649
1764
  --dynamic-table-row-background-color-hover,
1650
- var(--dynamic-table-row-default-background-color-hover)
1765
+ var(--dynamic-table-default-row-background-color-hover)
1651
1766
  );
1652
1767
  }
1653
1768
 
@@ -1662,7 +1777,7 @@ function handleLoadBackward() {
1662
1777
  border-radius: 10px;
1663
1778
  background-color: var(
1664
1779
  --dynamic-table-quick-filter-background-color,
1665
- var(--dynamic-table-quick-filter-default-background-color)
1780
+ var(--dynamic-table-default-quick-filter-background-color)
1666
1781
  );
1667
1782
  }
1668
1783
 
@@ -1709,6 +1824,11 @@ function handleLoadBackward() {
1709
1824
  margin-bottom: 10px;
1710
1825
  }
1711
1826
 
1827
+ .quick-filters-results-container {
1828
+ display: flex;
1829
+ justify-content: space-between;
1830
+ }
1831
+
1712
1832
  .vertical-quick-filters {
1713
1833
  display: flex;
1714
1834
  flex-direction: column;
@@ -1766,4 +1886,43 @@ function handleLoadBackward() {
1766
1886
  gap: 12px;
1767
1887
  padding: 8px;
1768
1888
  }
1769
- </style>
1889
+
1890
+ .line-container {
1891
+ position: sticky;
1892
+ bottom: 0;
1893
+ left: 0;
1894
+ width: 100%;
1895
+ background: var(
1896
+ --dynamic-table-end-line-background-color,
1897
+ var(--dynamic-table-default-end-line-background-color)
1898
+ );
1899
+ display: flex;
1900
+ justify-content: center;
1901
+ align-items: center;
1902
+ z-index: 3;
1903
+ }
1904
+
1905
+ .line {
1906
+ flex-grow: 1;
1907
+ height: 1px;
1908
+ background: var(
1909
+ --dynamic-table-end-line-color,
1910
+ var(--dynamic-table-default-end-line-color)
1911
+ );
1912
+ margin: 0 10px;
1913
+ }
1914
+
1915
+ .text {
1916
+ color: var(
1917
+ --dynamic-table-end-line-text-color,
1918
+ var(--dynamic-table-default-end-line-text-color)
1919
+ );
1920
+ }
1921
+
1922
+ .results-number {
1923
+ margin: 0px 0px 4px 4px;
1924
+ display: flex;
1925
+ align-items: center;
1926
+ gap: 4px;
1927
+ }
1928
+ </style>