@likable-hair/svelte 4.0.6 → 4.0.7

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.
@@ -2,6 +2,8 @@
2
2
  --quick-actions-default-background-color: rgb(var(--global-color-background-200));
3
3
  --quick-actions-default-selected-items-button-background-color: rgb(var(--global-color-background-500));
4
4
  --quick-actions-default-selected-items-button-background-color-hover: rgb(var(--global-color-background-300));
5
+ --quick-actions-default-selected-items-button-background-color-disabled: rgb(var(--global-color-background-300), .5);
6
+ --quick-actions-default-selected-items-button-color-disabled: rgb(var(--global-color-contrast-900), .5);
5
7
  --quick-actions-default-z-index: 48;
6
8
 
7
9
  --quick-actions-default-buttons-background-color: var(--quick-actions-background-color, var(--quick-actions-default-background-color));
@@ -2,13 +2,12 @@
2
2
  </script>
3
3
 
4
4
  <script lang="ts">import { Button, Icon, mediaQuery, ToolTip } from "../../..";
5
- import DynamicTable from "../list/DynamicTable.svelte";
6
5
  import { fly } from "svelte/transition";
7
6
  import { cubicIn } from "svelte/easing";
8
7
  import MenuOrDrawer from "./MenuOrDrawer.svelte";
9
8
  import './QuickActions.css';
10
- let { selectedItems, showSelectContainer, isSelectedAll, totalRows, slotSelectActionsContainer = $bindable(), disabled, loading, actionsForSelectedItems, position = 'top', lang = 'en' } = $props();
11
- let actions = $state([]), extraActions = $state([]), moreActionsActivator = $state(), openMoreActions = $state(false), infoActivators = $state({}), disabledInfoActivators = $state({});
9
+ let { selectedItems, disabled, actionsForSelectedItems, position = 'top', lang = 'en', onClose, } = $props();
10
+ let actions = $state([]), extraActions = $state([]), slotSelectActionsContainer = $state(), moreActionsActivator = $state(), openMoreActions = $state(false), infoActivators = $state({}), disabledInfoActivators = $state({});
12
11
  $effect(() => {
13
12
  if (!!slotSelectActionsContainer) {
14
13
  let numberOfSplit = $mediaQuery.xl ? 5 :
@@ -28,7 +27,7 @@ $effect(() => {
28
27
  });
29
28
  </script>
30
29
 
31
- {#if selectedItems && selectedItems.length > 0 && showSelectContainer}
30
+ {#if selectedItems > 0}
32
31
  <div
33
32
  class="container-{position}"
34
33
  transition:fly={{ delay: 150, duration: 150, y: -10, easing: cubicIn }}
@@ -37,8 +36,13 @@ $effect(() => {
37
36
  class="select-container"
38
37
  >
39
38
  <div>
40
- <button class="select-info" onclick={() => (selectedItems = [], infoActivators = {}, disabledInfoActivators = {})}>
41
- {!!isSelectedAll ? totalRows : selectedItems.length} {lang == 'en' ? 'items selected' : 'righe selezionate'}
39
+ <button class="select-info" {disabled} onclick={() => {
40
+ infoActivators = {}
41
+ disabledInfoActivators = {}
42
+ if(onClose) onClose()
43
+ }}
44
+ >
45
+ {selectedItems} {lang == 'en' ? 'items selected' : 'righe selezionate'}
42
46
  <Icon name="mdi-close" />
43
47
  </button>
44
48
  </div>
@@ -59,7 +63,9 @@ $effect(() => {
59
63
  --button-box-shadow: none;
60
64
  '
61
65
  --button-height="20px"
62
- disabled={action.disabled}
66
+ --circular-loader-height="17px"
67
+ disabled={action.disabled || action.loading || disabled}
68
+ loading={action.loading}
63
69
  onclick={action.onClick}
64
70
  >
65
71
  <div class="action" bind:this={disabledInfoActivators[action.label]}>
@@ -74,7 +80,7 @@ $effect(() => {
74
80
  />
75
81
  </div>
76
82
  <ToolTip
77
- appearTimeout={1000}
83
+ appearTimeout={500}
78
84
  activator={infoActivators[action.label]}
79
85
  >
80
86
  <div
@@ -90,7 +96,7 @@ $effect(() => {
90
96
  {action.label}
91
97
  {#if !!action.disabledInfo && action.disabled}
92
98
  <ToolTip
93
- appearTimeout={1000}
99
+ appearTimeout={300}
94
100
  activator={disabledInfoActivators[action.label]}
95
101
  >
96
102
  <div
@@ -124,7 +130,6 @@ $effect(() => {
124
130
  margin-left: 8px;
125
131
  '
126
132
  --button-height="20px"
127
- disabled={disabled || loading}
128
133
  onclick={(e) => {
129
134
  openMoreActions = !openMoreActions;
130
135
  }}
@@ -172,8 +177,10 @@ $effect(() => {
172
177
  --button-disabled-color: var(--quick-actions-buttons-color-disabled, var(--quick-actions-default-buttons-color-disabled));
173
178
  --button-box-shadow: none;
174
179
  '
175
- --button-height="35px"
176
- disabled={action.disabled}
180
+ --button-height="30px"
181
+ --circular-loader-height="25px"
182
+ disabled={action.disabled || action.loading || disabled}
183
+ loading={action.loading}
177
184
  onclick={action.onClick}
178
185
  >
179
186
  <div class="action" bind:this={disabledInfoActivators[action.label]}>
@@ -188,7 +195,7 @@ $effect(() => {
188
195
  />
189
196
  </div>
190
197
  <ToolTip
191
- appearTimeout={1000}
198
+ appearTimeout={500}
192
199
  activator={infoActivators[action.label]}
193
200
  >
194
201
  <div
@@ -204,7 +211,7 @@ $effect(() => {
204
211
  {action.label}
205
212
  {#if !!action.disabledInfo && action.disabled}
206
213
  <ToolTip
207
- appearTimeout={1000}
214
+ appearTimeout={300}
208
215
  activator={disabledInfoActivators[action.label]}
209
216
  >
210
217
  <div
@@ -292,6 +299,19 @@ $effect(() => {
292
299
  --quick-actions-selected-items-button-background-color-hover,
293
300
  var(--quick-actions-default-selected-items-button-background-color-hover)
294
301
  );
302
+ cursor: pointer;
303
+ }
304
+
305
+ .select-info:disabled {
306
+ background-color: var(
307
+ --quick-actions-selected-items-button-background-color-disabled,
308
+ var(--quick-actions-default-selected-items-button-background-color-disabled)
309
+ );
310
+ color: var(
311
+ --quick-actions-selected-items-button-color-disabled,
312
+ var(--quick-actions-default-selected-items-button-color-disabled)
313
+ );
314
+ cursor: not-allowed;
295
315
  }
296
316
 
297
317
  .select-actions-container {
@@ -2,26 +2,22 @@ export type Action = {
2
2
  label: string;
3
3
  icon?: string;
4
4
  disabled?: boolean;
5
+ loading?: boolean;
5
6
  info?: string;
6
7
  disabledInfo?: string;
7
8
  onClick: NonNullable<ComponentProps<typeof Button>['onclick']>;
8
9
  };
9
10
  import { Button } from "../../..";
10
11
  import type { ComponentProps } from "svelte";
11
- import DynamicTable from "../list/DynamicTable.svelte";
12
12
  import './QuickActions.css';
13
13
  interface Props {
14
- selectedItems: ComponentProps<typeof DynamicTable>["selectedItems"];
15
- showSelectContainer: boolean;
16
- isSelectedAll: boolean;
17
- totalRows: number;
18
- slotSelectActionsContainer?: HTMLElement;
14
+ selectedItems: number;
19
15
  disabled: boolean;
20
- loading: boolean;
21
16
  actionsForSelectedItems: Action[];
22
17
  position?: 'top' | 'bottom';
23
18
  lang?: 'it' | 'en';
19
+ onClose?: () => void;
24
20
  }
25
- declare const QuickActions: import("svelte").Component<Props, {}, "slotSelectActionsContainer">;
21
+ declare const QuickActions: import("svelte").Component<Props, {}, "">;
26
22
  type QuickActions = ReturnType<typeof QuickActions>;
27
23
  export default QuickActions;
@@ -25,25 +25,23 @@ onMount(() => {
25
25
  updateHeaderHeight();
26
26
  window.addEventListener('resize', updateHeaderHeight);
27
27
  tableContainer?.addEventListener("scroll", setReachedBottomOrTop);
28
- if (tableContainer?.scrollHeight && tableContainer.clientHeight && tableContainer?.scrollHeight <= tableContainer?.clientHeight) {
29
- tableContainer.style.marginRight = '0px';
30
- }
31
- if (resizableColumns) {
32
- for (const head of [...headers, { value: 'non-resizable', minWidth: DEFAULT_MIN_WIDTH_PX + 'px', maxWidth: DEFAULT_MAX_WIDTH_PX + 'px' }, { value: 'slot-append', minWidth: DEFAULT_MIN_WIDTH_PX + 'px', maxWidth: DEFAULT_MAX_WIDTH_PX + 'px' }]) {
33
- let th;
34
- if (head.value == 'non-resizable' || head.value == 'slot-append') {
35
- th = document.getElementsByClassName(head.value).item(0);
36
- }
37
- else {
38
- th = document.getElementById(head.value);
39
- }
40
- if (!!th) {
41
- resizeHeader(th, head);
42
- }
28
+ if (tableContainer?.scrollHeight && tableContainer.clientHeight) {
29
+ hideScrollbar = tableContainer.scrollHeight > tableContainer.clientHeight;
30
+ }
31
+ for (const head of [...headers, { value: 'non-resizable', minWidth: DEFAULT_MIN_WIDTH_PX + 'px', maxWidth: DEFAULT_MAX_WIDTH_PX + 'px' }, { value: 'slot-append', minWidth: DEFAULT_MIN_WIDTH_PX + 'px', maxWidth: DEFAULT_MAX_WIDTH_PX + 'px' }]) {
32
+ let th;
33
+ if (head.value == 'non-resizable' || head.value == 'slot-append') {
34
+ th = document.getElementsByClassName(head.value).item(0);
35
+ }
36
+ else {
37
+ th = document.getElementById(head.value);
38
+ }
39
+ if (!!th) {
40
+ resizeHeader(th, head);
43
41
  }
44
- let table = document.getElementsByClassName('table')[0];
45
- table.classList.add('resizable');
46
42
  }
43
+ let table = document.getElementsByClassName('table')[0];
44
+ table.classList.add('resizable');
47
45
  return () => {
48
46
  window.removeEventListener('resize', updateHeaderHeight);
49
47
  tableContainer?.removeEventListener("scroll", setReachedBottomOrTop);
@@ -60,6 +58,7 @@ function setReachedBottomOrTop() {
60
58
  if (tableContainer) {
61
59
  reachedBottom = tableContainer.scrollHeight - tableContainer.scrollTop === tableContainer.clientHeight;
62
60
  reachedTop = tableContainer.scrollTop === 0;
61
+ hideScrollbar = tableContainer.scrollHeight > tableContainer.clientHeight;
63
62
  }
64
63
  }
65
64
  $effect(() => {
@@ -95,8 +94,8 @@ const [send, receive] = crossfade({
95
94
  };
96
95
  },
97
96
  });
98
- let { headers = [], headersToShowInTable = headers, subHeaders = [], customizeHeaders = false, rows = [], sortedBy = $bindable(), sortDirection = $bindable("asc"), cellEdit = false, lang = "en", noItemsText = lang == 'en' ? "No items to show" : 'Nessun elemento da visualizzare', showSelect = false, showSelectContainer = true, selectMode = "single", selectedItems = $bindable([]), showExpand = false, loading = false, disabled = false, filters = $bindable([]), searchBarColumns, searchBarVisible = false, searchBarPlaceholder = lang == 'en' ? "Type to search..." : "Scrivi per cercare...", filtersVisible = false, quickFiltersVisible = false, editFilterMode = "one-edit", showActiveFilters = true, quickFilters = [], actionsForSelectedItems = [], totalRows = rows.length, searchText = $bindable(), renderedRowsNumber = 100, sectionRowsNumber = 20, sectionThreshold = 2, backwardThresholdPixel = 100, forwardThresholdPixel = 100, uniqueKey = 'id', numberOfResultsVisible = false, endLineVisible = false, resizableColumns = false, resizedColumnSizeWithPadding = {}, class: clazz = {}, onapplyCustomQuickFilter, oncellClick, onfetchData, onfiltersChange, onsort, onremoveAllFilters, onremoveCustomQuickFilter, onremoveFilter, onrowClick, onsaveCellEdit, onsaveHeadersToShow, oncolumnResize, searchBarSnippet, customFilterChipSnippet, customFilterSnippet, filterAppendSnippet, onscroll, selectionSnippet: selectionInternalSnippet, itemLabelSnippet: itemLabelInternalSnippet, chipLabelSnippet, headerSnippet, headerLabelSnippet, rowAppendSnippet, rowActionsSnippet, customRowSnippet, subRowAppendSnippet, subHeaderLabelSnippet, subHeaderSnippet, subRowActionsSnippet, customSubRowSnippet, customQuickFilterSnippet, appendSnippet, } = $props();
99
- let openCellEditor = $state(false), cellEditorActivator = $state(), cellEditorContainer = $state(), menuElementCellEditor = $state(), menuElementQuickFilters = $state(), cellEditorInfoActive = $state(), saveEditDisabled = $state(false), searchBarInput = $state(undefined), openQuickFilter = $state(false), quickFilterActivator = $state(), quickFilterActive = $state(), globalBuilder = new FilterBuilder(), slotSelectActionsContainer, isSelectedAll = $state(false), calendarOpened = $state(false), calendarOpened2 = $state(false), selectedIndexes = [], cellEditorIndexRow = $state(), cellEditorIndexHeader = $state(), cellEditorSubItem = $state(), currentSectionNumber = $state(0), tableBody = $state(), tableContainer = $state(), userScrolling = $state(true), reachedBottom = $state(false), reachedTop = false, resizing = false, remainingWidth = $state(0);
97
+ let { headers = [], headersToShowInTable = headers, subHeaders = [], customizeHeaders = false, rows = [], sortedBy = $bindable(), sortDirection = $bindable("asc"), cellEdit = false, lang = "en", dateLocale, noItemsText = lang == 'en' ? "No items to show" : 'Nessun elemento da visualizzare', showSelect = false, showActions = true, selectMode = "single", selectedItems = $bindable([]), unselectedItems = $bindable([]), selectedAll = $bindable(false), showExpand = false, loading = false, disabled = false, filters = $bindable([]), searchBarColumns, searchBarVisible = false, searchBarPlaceholder = lang == 'en' ? "Type to search..." : "Scrivi per cercare...", filtersVisible = false, quickFiltersVisible = false, editFilterMode = "one-edit", showActiveFilters = true, quickFilters = [], actionsForSelectedItems = [], quickActionsDisabled = false, totalRows = rows.length, searchText = $bindable(), renderedRowsNumber = 100, sectionRowsNumber = 20, sectionThreshold = 2, backwardThresholdPixel = 100, forwardThresholdPixel = 100, uniqueKey = 'id', numberOfResultsVisible = false, endLineVisible = false, resizableColumns = false, resizedColumnSizeWithPadding = {}, class: clazz = {}, onapplyCustomQuickFilter, oncellClick, onfetchData, onfiltersChange, onsort, onremoveAllFilters, onremoveCustomQuickFilter, onremoveFilter, onrowClick, onsaveCellEdit, onsaveHeadersToShow, oncolumnResize, searchBarSnippet, customFilterChipSnippet, customFilterSnippet, filterAppendSnippet, onscroll, selectionSnippet: selectionInternalSnippet, itemLabelSnippet: itemLabelInternalSnippet, chipLabelSnippet, headerSnippet, headerLabelSnippet, rowAppendSnippet, rowActionsSnippet, customRowSnippet, subRowAppendSnippet, subHeaderLabelSnippet, subHeaderSnippet, subRowActionsSnippet, customSubRowSnippet, customQuickFilterSnippet, appendSnippet, } = $props();
98
+ let openCellEditor = $state(false), cellEditorActivator = $state(), cellEditorContainer = $state(), menuElementCellEditor = $state(), menuElementQuickFilters = $state(), cellEditorInfoActive = $state(), saveEditDisabled = $state(false), searchBarInput = $state(undefined), openQuickFilter = $state(false), quickFilterActivator = $state(), quickFilterActive = $state(), globalBuilder = new FilterBuilder(), calendarOpened = $state(false), calendarOpened2 = $state(false), selectedIndexes = [], cellEditorIndexRow = $state(), cellEditorIndexHeader = $state(), cellEditorSubItem = $state(), currentSectionNumber = $state(0), tableBody = $state(), tableContainer = $state(), userScrolling = $state(true), reachedBottom = $state(false), reachedTop = false, resizing = false, remainingWidth = $state(0), hideScrollbar = $state(false), sortModify;
100
99
  const DEFAULT_MIN_WIDTH_PX = 100, DEFAULT_MAX_WIDTH_PX = 400;
101
100
  let totalSections = $derived((totalRows - renderedRowsNumber) / sectionRowsNumber);
102
101
  let hasMoreToRender = $derived(totalSections > currentSectionNumber);
@@ -137,11 +136,13 @@ function handleHeaderClick(header) {
137
136
  sortDirection = "desc";
138
137
  else if (sortDirection == "desc") {
139
138
  sortedBy = undefined;
139
+ sortModify = undefined;
140
140
  }
141
141
  }
142
142
  else {
143
143
  sortedBy = header.value;
144
144
  sortDirection = "asc";
145
+ sortModify = header.sortModify;
145
146
  }
146
147
  handleSearchChange(searchText);
147
148
  if (onsort) {
@@ -231,15 +232,21 @@ function handleCancelClick() {
231
232
  openQuickFilter = false;
232
233
  }
233
234
  function handleSelect(item, shiftKeyPressed) {
234
- let index = selectedItems.findIndex((i) => i[uniqueKey] == item[uniqueKey]);
235
- // if item is not in the selected items array, add it
235
+ let index = -1;
236
+ if (selectedAll) {
237
+ index = unselectedItems.findIndex((i) => i[uniqueKey] == item[uniqueKey]);
238
+ }
239
+ else {
240
+ index = selectedItems.findIndex((i) => i[uniqueKey] == item[uniqueKey]);
241
+ }
242
+ // if item is not in the selected/unselected items array, add it
236
243
  if (index == -1) {
237
244
  if (selectMode == "single") {
238
245
  selectedItems = [item];
239
246
  selectedIndexes = [rows.findIndex(r => r.item[uniqueKey] == item[uniqueKey])];
240
247
  }
241
248
  else if (selectMode == "multiple") {
242
- if (shiftKeyPressed && selectedIndexes.length > 0 && !isSelectedAll) {
249
+ if (shiftKeyPressed && selectedIndexes.length > 0) {
243
250
  let lastSelectedIndex = selectedIndexes[selectedIndexes.length - 1], selectedIndex = rows.findIndex(r => r.item[uniqueKey] == item[uniqueKey]);
244
251
  if (selectedIndex != -1) {
245
252
  if (selectedIndex < lastSelectedIndex) {
@@ -248,35 +255,46 @@ function handleSelect(item, shiftKeyPressed) {
248
255
  selectedIndex = x;
249
256
  }
250
257
  for (let i = lastSelectedIndex + 1; i <= selectedIndex; i++) {
251
- if (!selectedItems.find((selectedItem) => selectedItem[uniqueKey] == rows[i].item[uniqueKey])) {
252
- selectedItems = [...selectedItems, rows[i].item];
258
+ if (selectedAll) {
259
+ if (!unselectedItems.find((unselectedItem) => unselectedItem[uniqueKey] == rows[i].item[uniqueKey])) {
260
+ unselectedItems = [...unselectedItems, rows[i].item];
261
+ }
262
+ }
263
+ else {
264
+ if (!selectedItems.find((selectedItem) => selectedItem[uniqueKey] == rows[i].item[uniqueKey])) {
265
+ selectedItems = [...selectedItems, rows[i].item];
266
+ }
253
267
  }
254
268
  }
255
269
  }
256
270
  }
257
271
  else {
258
- selectedItems = [...selectedItems, item];
272
+ if (selectedAll) {
273
+ unselectedItems = [...unselectedItems, item];
274
+ }
275
+ else {
276
+ selectedItems = [...selectedItems, item];
277
+ }
259
278
  selectedIndexes.push(rows.findIndex(r => r.item[uniqueKey] == item[uniqueKey]));
260
279
  }
261
280
  }
262
281
  }
263
282
  else {
264
- selectedItems = selectedItems.filter((i) => i[uniqueKey] != item[uniqueKey]);
283
+ if (selectedAll) {
284
+ unselectedItems = unselectedItems.filter((i) => i[uniqueKey] != item[uniqueKey]);
285
+ }
286
+ else {
287
+ selectedItems = selectedItems.filter((i) => i[uniqueKey] != item[uniqueKey]);
288
+ }
265
289
  selectedIndexes = selectedIndexes.filter(r => r != rows.findIndex(r => r.item[uniqueKey] == item[uniqueKey]));
266
- isSelectedAll = false;
267
290
  }
268
291
  }
269
292
  function handleSelectAll() {
270
293
  if (selectMode == "multiple") {
271
- if (selectedItems.length == rows.length) {
272
- selectedItems = [];
273
- selectedIndexes = [];
274
- isSelectedAll = false;
275
- }
276
- else {
277
- selectedItems = rows.map((r) => r.item);
278
- isSelectedAll = true;
279
- }
294
+ selectedItems = [];
295
+ selectedIndexes = [];
296
+ unselectedItems = [];
297
+ selectedAll = !selectedAll;
280
298
  }
281
299
  }
282
300
  function expandRow(row) {
@@ -309,13 +327,6 @@ $effect(() => {
309
327
  else {
310
328
  saveEditDisabled = false;
311
329
  }
312
- if (!!isSelectedAll &&
313
- rows.length > 0 &&
314
- !loading &&
315
- !disabled &&
316
- selectedItems.length < rows.length) {
317
- selectedItems = rows.map((r) => r.item);
318
- }
319
330
  });
320
331
  function searchTextBuilder(searchText) {
321
332
  let builder;
@@ -331,9 +342,6 @@ function searchTextBuilder(searchText) {
331
342
  }
332
343
  });
333
344
  }
334
- if (!!sortedBy) {
335
- builder.orderBy(sortedBy, sortDirection || "asc");
336
- }
337
345
  return builder;
338
346
  }
339
347
  let syncTimer;
@@ -358,6 +366,14 @@ function handleFiltersChange() {
358
366
  tableContainer.scrollTop = 0;
359
367
  setTimeout(() => userScrolling = true, 20);
360
368
  }
369
+ if (!!sortedBy) {
370
+ if (sortModify) {
371
+ globalBuilder = sortModify({ builder: globalBuilder, sortDirection });
372
+ }
373
+ else {
374
+ globalBuilder.orderBy(sortedBy, sortDirection || "asc");
375
+ }
376
+ }
361
377
  if (onfiltersChange) {
362
378
  onfiltersChange({
363
379
  detail: {
@@ -630,9 +646,6 @@ function quickFilterBuilder(builder, quickFilter, clearPreaviousValue = true) {
630
646
  }
631
647
  }
632
648
  }
633
- if (!!sortedBy) {
634
- builder.orderBy(sortedBy, sortDirection || "asc");
635
- }
636
649
  return builder;
637
650
  }
638
651
  function updateFilterValues(filter, updateMultiFilterValues) {
@@ -663,10 +676,7 @@ function updateFilterValues(filter, updateMultiFilterValues) {
663
676
  }
664
677
  updateMultiFilterValues(filter.name, newValue, newValid, newMode);
665
678
  }
666
- function handleRemoveAllFilters(removeAllFilters) {
667
- if (!!removeAllFilters) {
668
- removeAllFilters();
669
- }
679
+ function handleRemoveAllFilters() {
670
680
  if (onremoveAllFilters) {
671
681
  onremoveAllFilters();
672
682
  }
@@ -879,17 +889,19 @@ function resizeHeader(th, header) {
879
889
  </script>
880
890
 
881
891
  {#if !!rows && Array.isArray(rows) && !!headersToShowInTable && Array.isArray(headersToShowInTable)}
882
- <QuickActions
883
- {selectedItems}
884
- {showSelectContainer}
885
- {isSelectedAll}
886
- {totalRows}
887
- {slotSelectActionsContainer}
888
- {disabled}
889
- {loading}
890
- {actionsForSelectedItems}
891
- {lang}
892
- />
892
+ {#if showActions}
893
+ <QuickActions
894
+ selectedItems={selectedAll ? totalRows - unselectedItems.length : selectedItems.length}
895
+ disabled={quickActionsDisabled}
896
+ {actionsForSelectedItems}
897
+ {lang}
898
+ onClose={() => {
899
+ selectedAll = false
900
+ unselectedItems = []
901
+ selectedItems = []
902
+ }}
903
+ />
904
+ {/if}
893
905
 
894
906
  {#if searchBarVisible || filtersVisible || appendSnippet}
895
907
  <div class="filter-container">
@@ -926,22 +938,23 @@ function resizeHeader(th, header) {
926
938
  onremoveAllFilters={() => handleRemoveAllFilters()}
927
939
  --filters-default-wrapper-width="100%"
928
940
  {lang}
941
+ {dateLocale}
929
942
  {editFilterMode}
930
943
  {showActiveFilters}
931
944
  appendSnippet={filterAppendSnippet}
932
945
  customChipSnippet={customFilterChipSnippet}
933
946
  >
934
- {#snippet contentSnippet({ filters, mAndDown, updateMultiFilterValues, handleRemoveAllFilters: removeAllFilters })}
947
+ {#snippet contentSnippet({ filters, mAndDown, updateMultiFilterValues, })}
935
948
  {#key filters}
936
949
  <DynamicFilters
937
950
  {lang}
938
951
  {filters}
939
952
  {mAndDown}
940
953
  onchange={e => updateFilterValues(e.detail.filter, updateMultiFilterValues)}
941
- onremoveAllFilters={() => handleRemoveAllFilters(removeAllFilters)}
954
+ {updateMultiFilterValues}
942
955
  >
943
- {#snippet customSnippet({ filter })}
944
- {@render customFilterSnippet?.({ filter, updateMultiFilterValues })}
956
+ {#snippet customSnippet({ filter, mAndDown, updateCustomFilterValues })}
957
+ {@render customFilterSnippet?.({ filter, mAndDown, updateCustomFilterValues })}
945
958
  {/snippet}
946
959
  </DynamicFilters>
947
960
  {/key}
@@ -1007,7 +1020,7 @@ function resizeHeader(th, header) {
1007
1020
  {/if}
1008
1021
 
1009
1022
  <div class="outer-container">
1010
- <div class="inner-container" bind:this={tableContainer} {onscroll}>
1023
+ <div class="inner-container" class:hide-scrollbar={hideScrollbar} bind:this={tableContainer} {onscroll}>
1011
1024
  <InfiniteScroll
1012
1025
  onloadMore={handleLoadBackward}
1013
1026
  threshold={backwardThresholdPixel}
@@ -1027,7 +1040,7 @@ function resizeHeader(th, header) {
1027
1040
  {#if selectMode === "multiple"}
1028
1041
  <Checkbox
1029
1042
  id="select-all"
1030
- value={selectedItems.length == totalBatchLength}
1043
+ value={selectedAll}
1031
1044
  disabled={disabled || loading}
1032
1045
  onchange={handleSelectAll}
1033
1046
  />
@@ -1046,6 +1059,7 @@ function resizeHeader(th, header) {
1046
1059
  <th
1047
1060
  style={`${resizableColumns || !header.width ? '' : `width: ${header.width}`}`}
1048
1061
  style:min-width={header.minWidth}
1062
+ style:max-width={header.maxWidth}
1049
1063
  class:sortable={header.sortable}
1050
1064
  onclick={() => handleHeaderClick(header)}
1051
1065
  id={header.value}
@@ -1167,15 +1181,19 @@ function resizeHeader(th, header) {
1167
1181
  class="item-row"
1168
1182
  data-key={row.item[uniqueKey]}
1169
1183
  style:background-color={
1170
- !!row.item.disableEdit ?
1171
- !!row.item.rowDisableBackgroundColor ?
1172
- row.item.rowDisableBackgroundColor :
1173
- 'var(--dynamic-table-row-disabled-background-color, var(--dynamic-table-default-row-disabled-background-color))' :
1174
- expandedRows.findIndex((r) => r.item[uniqueKey] == row.item[uniqueKey] ) != -1 ?
1175
- 'var(--dynamic-table-expanded-row-background-color, var(--dynamic-table-default-expanded-row-background-color))' :
1176
- !!selectedItems.find(i => i[uniqueKey] == row.item[uniqueKey]) ?
1177
- 'var(--dynamic-table-selected-row-background-color, var(--dynamic-table-default-selected-row-background-color))' :
1178
- ""
1184
+ !!row.item.disableEdit
1185
+ ? !!row.item.rowDisableBackgroundColor
1186
+ ? row.item.rowDisableBackgroundColor
1187
+ : 'var(--dynamic-table-row-disabled-background-color, var(--dynamic-table-default-row-disabled-background-color))'
1188
+ : expandedRows.findIndex(r => r.item[uniqueKey] == row.item[uniqueKey]) != -1
1189
+ ? 'var(--dynamic-table-expanded-row-background-color, var(--dynamic-table-default-expanded-row-background-color))'
1190
+ : selectedAll
1191
+ ? !unselectedItems.find(i => i[uniqueKey] == row.item[uniqueKey])
1192
+ ? 'var(--dynamic-table-selected-row-background-color, var(--dynamic-table-default-selected-row-background-color))'
1193
+ : ''
1194
+ : selectedItems.find(i => i[uniqueKey] == row.item[uniqueKey])
1195
+ ? 'var(--dynamic-table-selected-row-background-color, var(--dynamic-table-default-selected-row-background-color))'
1196
+ : ''
1179
1197
  }
1180
1198
  class:row-activator={cellEditorIndexRow == indexRow && !cellEditorSubItem}
1181
1199
  onclick={() => handleRowClick(row.item)}
@@ -1184,9 +1202,15 @@ function resizeHeader(th, header) {
1184
1202
  <td style:padding-left="0px" style:text-align="center">
1185
1203
  <Checkbox
1186
1204
  id={row.item[uniqueKey]}
1187
- value={selectedItems.findIndex(
1188
- (i) => i[uniqueKey] == row.item[uniqueKey]
1189
- ) != -1}
1205
+ value={
1206
+ selectedAll ?
1207
+ unselectedItems.findIndex(
1208
+ (i) => i[uniqueKey] == row.item[uniqueKey]
1209
+ ) == -1 :
1210
+ selectedItems.findIndex(
1211
+ (i) => i[uniqueKey] == row.item[uniqueKey]
1212
+ ) != -1
1213
+ }
1190
1214
  disabled={disabled || loading}
1191
1215
  onchange={(e) => handleSelect(row.item, e.detail.shiftKeyPressed)}
1192
1216
  />
@@ -1270,6 +1294,7 @@ function resizeHeader(th, header) {
1270
1294
  <th
1271
1295
  style:width={subHeader.width}
1272
1296
  style:min-width={subHeader.minWidth}
1297
+ style:max-width={subHeader.maxWidth}
1273
1298
  class:sortable={subHeader.sortable}
1274
1299
  onclick={() => handleHeaderClick(subHeader)}
1275
1300
  >
@@ -1648,6 +1673,7 @@ function resizeHeader(th, header) {
1648
1673
  : quickFilterActive.description,
1649
1674
  multiple: true,
1650
1675
  }}
1676
+ --autocomplete-border-radius= 0.5rem
1651
1677
  --autocomplete-border="1px solid rgb(var(--global-color-background-500))"
1652
1678
  --autocomplete-focus-box-shadow="0 0 0 2px rgb(var(--global-color-primary-500))"
1653
1679
  />
@@ -1833,10 +1859,13 @@ function resizeHeader(th, header) {
1833
1859
 
1834
1860
  .inner-container {
1835
1861
  overflow-y: auto;
1836
- margin-right: -15px;
1837
1862
  max-height: var(--dynamic-table-max-height, var(--dynamic-table-default-max-height));
1838
1863
  }
1839
1864
 
1865
+ .hide-scrollbar {
1866
+ margin-right: -15px;
1867
+ }
1868
+
1840
1869
  .table {
1841
1870
  background-color: var(
1842
1871
  --dynamic-table-background-color,
@@ -127,12 +127,17 @@ declare class __sveltets_Render<Item extends {
127
127
  cellEdit?: boolean;
128
128
  noItemsText?: string;
129
129
  showSelect?: boolean;
130
- showSelectContainer?: boolean;
130
+ showActions?: boolean;
131
131
  selectMode?: "single" | "multiple";
132
132
  selectedItems?: (Item & {
133
133
  disableEdit?: boolean;
134
134
  rowDisableBackgroundColor?: string;
135
135
  })[] | undefined;
136
+ unselectedItems?: (Item & {
137
+ disableEdit?: boolean;
138
+ rowDisableBackgroundColor?: string;
139
+ })[] | undefined;
140
+ selectedAll?: boolean;
136
141
  showExpand?: boolean;
137
142
  loading?: boolean;
138
143
  disabled?: boolean;
@@ -143,10 +148,12 @@ declare class __sveltets_Render<Item extends {
143
148
  filtersVisible?: boolean;
144
149
  quickFiltersVisible?: boolean;
145
150
  lang?: "it" | "en";
151
+ dateLocale?: "it" | "en";
146
152
  editFilterMode?: "one-edit" | "multi-edit";
147
153
  showActiveFilters?: boolean;
148
154
  quickFilters?: QuickFilter[];
149
155
  actionsForSelectedItems?: Action[];
156
+ quickActionsDisabled?: boolean;
150
157
  totalRows?: number;
151
158
  searchText?: string;
152
159
  renderedRowsNumber?: number;
@@ -238,7 +245,8 @@ declare class __sveltets_Render<Item extends {
238
245
  customFilterChipSnippet?: ComponentProps<typeof Filters>["customChipSnippet"];
239
246
  customFilterSnippet?: Snippet<[{
240
247
  filter: Filter | undefined;
241
- updateMultiFilterValues: Parameters<NonNullable<ComponentProps<typeof Filters>["contentSnippet"]>>[0]["updateMultiFilterValues"];
248
+ mAndDown: boolean;
249
+ updateCustomFilterValues: Parameters<NonNullable<ComponentProps<typeof Filters>["contentSnippet"]>>[0]["updateMultiFilterValues"];
242
250
  }]> | undefined;
243
251
  onscroll?: UIEventHandler<HTMLDivElement>;
244
252
  selectionSnippet?: ComponentProps<typeof Autocomplete>["selectionSnippet"];
@@ -522,7 +530,7 @@ declare class __sveltets_Render<Item extends {
522
530
  };
523
531
  events(): {};
524
532
  slots(): {};
525
- bindings(): "searchText" | "sortedBy" | "sortDirection" | "filters" | "selectedItems";
533
+ bindings(): "searchText" | "sortedBy" | "sortDirection" | "filters" | "selectedItems" | "unselectedItems" | "selectedAll";
526
534
  exports(): {};
527
535
  }
528
536
  interface $$IsomorphicComponent {
@@ -13,7 +13,7 @@ let { headers = [], items = [], sortedBy = $bindable(undefined), sortDirection =
13
13
  { label: "50", value: 50 },
14
14
  { label: "100", value: 100 },
15
15
  ], hideRowsPerPage = false, totalElements = undefined, rowsPerPage = $bindable(20), filters = $bindable([]), searchBarColumns = undefined, searchBarVisible = true, searchBarPlaceholder = "Type something to search...", lang = "en", editFilterMode = "one-edit", showActiveFilters = true, resizableColumns = false, resizedColumnSizeWithPadding = {}, pointerOnRowHover = undefined, doubleClickActive = false, doubleClickDelay = 250, calculateRowStyles = undefined, calculateRowClasses = undefined, class: clazz = {}, onfiltersChange, onpaginationChange, onremoveFilter, onremoveAllFilters, customFilterChipSnippet, customFilterSnippet, filterAppendSnippet, onrowClick, onrowDoubleClick, appendSnippet, customSnippet, headerLabelSnippet, headerSnippet, rowActionsSnippet, onsort, footerSnippet, rangeDescriptorSnippet, searchBarSnippet, noDataSnippet, oncolumnResize, } = $props();
16
- let searchBarInput = $state(), searchText = $state();
16
+ let searchBarInput = $state(), searchText = $state(), sortModify;
17
17
  let rowsPerPageSelection = $state([]);
18
18
  $effect(() => {
19
19
  rowsPerPageSelection = [
@@ -74,6 +74,7 @@ function handleRemoveAllFilters() {
74
74
  }
75
75
  }
76
76
  function handleOnSort(event) {
77
+ sortModify = event.detail.sortModify;
77
78
  handleFiltersChange();
78
79
  if (onsort) {
79
80
  onsort(event);
@@ -94,7 +95,12 @@ function buildFilters(params) {
94
95
  });
95
96
  }
96
97
  if (!!sortedBy) {
97
- builder.orderBy(sortedBy, sortDirection || 'asc');
98
+ if (sortModify) {
99
+ builder = sortModify({ builder, sortDirection: sortDirection || 'asc' });
100
+ }
101
+ else {
102
+ builder.orderBy(sortedBy, sortDirection || "asc");
103
+ }
98
104
  }
99
105
  return builder;
100
106
  }
@@ -31,6 +31,7 @@ declare const PaginatedTable: import("svelte").Component<Omit<{
31
31
  detail: {
32
32
  sortedBy: string | undefined;
33
33
  sortDirection: string;
34
+ sortModify: import("../../simple/lists/SimpleTable.svelte").Header["sortModify"];
34
35
  };
35
36
  }) => void) | undefined;
36
37
  onrowClick?: ((event: {
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">import { FilterEditor, Icon } from "../../..";
2
2
  import {} from "svelte";
3
- let { filters = [], lang = "en", mAndDown = false, onchange, onremoveAllFilters, customSnippet, } = $props();
3
+ let { filters = [], lang = "en", mAndDown = false, onchange, updateMultiFilterValues, customSnippet: customSnippetInternal, } = $props();
4
4
  let selectedFilter = $state();
5
5
  let tmpFilters = $state(filters.reduce((acc, f) => {
6
6
  if (f.active) {
@@ -8,14 +8,6 @@ let tmpFilters = $state(filters.reduce((acc, f) => {
8
8
  }
9
9
  return acc;
10
10
  }, {}));
11
- let activeFilter = $derived(Object.values(tmpFilters).reduce((count, filter) => {
12
- if (filter.value !== undefined ||
13
- filter.from !== undefined ||
14
- filter.to !== undefined ||
15
- (filter.values !== undefined && filter.values.length > 0))
16
- count++;
17
- return count;
18
- }, 0));
19
11
  let labelsMapper = lang == 'en' ? {
20
12
  equal: { extended: "equal to", short: "equal" },
21
13
  like: { short: "includes" },
@@ -43,46 +35,78 @@ function handleKeyPress(event, filter) {
43
35
  selectFilter(filter);
44
36
  }
45
37
  }
46
- function clearFilters() {
47
- tmpFilters = {};
48
- if (onremoveAllFilters) {
49
- onremoveAllFilters();
50
- }
51
- }
52
38
  function handleFilterChange() {
53
- if (!!selectedFilter && onchange) {
54
- onchange({
55
- detail: {
56
- filter: tmpFilters[selectedFilter.name]
39
+ if (!!selectedFilter) {
40
+ if (!!onchange) {
41
+ onchange({
42
+ detail: {
43
+ filter: tmpFilters[selectedFilter.name]
44
+ }
45
+ });
46
+ }
47
+ filters = filters.map(f => {
48
+ if (f.name === selectedFilter?.name) {
49
+ return tmpFilters[selectedFilter.name];
57
50
  }
51
+ return f;
58
52
  });
59
53
  }
60
54
  }
55
+ function isActiveFilter(filter) {
56
+ let newValue = {}, newValid = false;
57
+ if (filter.type == 'select') {
58
+ newValue = filter.values;
59
+ if (!!newValue && newValue.length > 0) {
60
+ newValid = true;
61
+ }
62
+ }
63
+ else if ('mode' in filter && filter.mode == 'between') {
64
+ newValue.to = filter.to;
65
+ newValue.from = filter.from;
66
+ if (!!newValue.from || !!newValue.to) {
67
+ newValid = true;
68
+ }
69
+ }
70
+ else if (filter.type == 'custom') {
71
+ newValue = filter.value;
72
+ if ((Array.isArray(newValue) && newValue.length > 0) || (!Array.isArray(newValue) && !!newValue)) {
73
+ newValid = true;
74
+ }
75
+ }
76
+ else {
77
+ newValue = filter.value;
78
+ if (!!newValue) {
79
+ newValid = true;
80
+ }
81
+ }
82
+ return newValid;
83
+ }
84
+ function updateCustomFilterValues(filterName, newValue, newValid, mode) {
85
+ let filter = filters.find(f => f.name === filterName);
86
+ if (!filter)
87
+ throw new Error('cannot find filter with name ' + filterName);
88
+ if (filter.type != 'custom')
89
+ throw new Error('filter is not custom');
90
+ filter.value = newValue;
91
+ filter.active = newValid;
92
+ if (updateMultiFilterValues) {
93
+ updateMultiFilterValues(filterName, newValue, newValid, mode);
94
+ }
95
+ }
61
96
  </script>
62
97
 
63
- <div class="custom-filters-container">
98
+ <div class="custom-filters-container" class:yscroll={mAndDown}>
64
99
  <div class="filters-selection">
65
-
66
- {#if activeFilter > 0}
67
- <div class="filter-info">
68
- {activeFilter} {lang == 'en' ? 'applied' : activeFilter == 1 ? 'applicato' : 'applicati'}
69
- <button class="clear-button" onclick={clearFilters}>✕</button>
70
- </div>
71
- {/if}
72
-
73
-
74
100
  {#each filters as filter}
75
101
  <div
76
102
  tabindex="0"
77
103
  role="button"
78
104
  class="filters-selection-item"
79
- class:selected={filter === selectedFilter}
80
- onclick={() => selectFilter(filter)}
105
+ class:selected={filter.name === selectedFilter?.name || isActiveFilter(filter)} onclick={() => selectFilter(filter)}
81
106
  onkeydown={(event) => handleKeyPress(event, filter)}
82
- aria-pressed={filter === selectedFilter}
83
- >
107
+ aria-pressed={filter.name === selectedFilter?.name} >
84
108
  <div class="filters-selection-title">
85
- {filter.label}
109
+ <div class="filters-selection-title-label">{filter.label}</div>
86
110
  <Icon name="mdi-chevron-right-circle-outline" />
87
111
  </div>
88
112
  </div>
@@ -93,20 +117,32 @@ function handleFilterChange() {
93
117
  <div class="filters-content">
94
118
  {#if selectedFilter}
95
119
  <div class="filters-content-box">
96
- <h2>{selectedFilter.label}</h2>
97
- <FilterEditor
98
- bind:filter={selectedFilter}
99
- {lang}
100
- {labelsMapper}
101
- editFilterMode="one-edit"
102
- bind:tmpFilter={tmpFilters[selectedFilter.name]}
103
- mobile={mAndDown}
104
- onchange={handleFilterChange}
105
- --simple-textfield-border-radius="5px"
106
- --chip-default-color="rgb(var(--global-color-primary-foreground))"
107
- {customSnippet}
108
- >
109
- </FilterEditor>
120
+ <h2>{selectedFilter.label}</h2>
121
+ {#key selectedFilter.label}
122
+ <FilterEditor
123
+ bind:filter={selectedFilter}
124
+ {lang}
125
+ {labelsMapper}
126
+ editFilterMode="one-edit"
127
+ bind:tmpFilter={tmpFilters[selectedFilter?.name || '']}
128
+ mobile={mAndDown}
129
+ onchange={handleFilterChange}
130
+ --simple-textfield-border-radius= 0.5rem
131
+ --simple-textfield-background-color= transparent
132
+ --simple-textfield-box-shadow= 'inset 0 0 0 1px rgb(var(--global-color-background-500))'
133
+ --simple-textfield-focus-box-shadow='inset 0 0 0 2px rgb(var(--global-color-primary-500))'
134
+ --chip-default-color="rgb(var(--global-color-primary-foreground))"
135
+ --autocomplete-border-radius= 0.5rem
136
+ --autocomplete-border="1px solid rgb(var(--global-color-background-500))"
137
+ --autocomplete-focus-box-shadow="0 0 0 2px rgb(var(--global-color-primary-500))"
138
+ --autocomplete-padding="9.6px 16px"
139
+ --autocomplete-background-color="transparent"
140
+ >
141
+ {#snippet customSnippet({ filter })}
142
+ {@render customSnippetInternal?.({ filter, mAndDown, updateCustomFilterValues })}
143
+ {/snippet}
144
+ </FilterEditor>
145
+ {/key}
110
146
  </div>
111
147
  {:else}
112
148
  <div class="filters-content-box">
@@ -115,19 +151,20 @@ function handleFilterChange() {
115
151
  {/if}
116
152
  </div>
117
153
  </div>
118
-
119
154
  <style>
120
-
121
155
  .custom-filters-container {
122
156
  display: flex;
123
157
  height: 70vh;
124
- overflow-y: scroll;
125
158
  }
126
159
 
160
+ .yscroll {
161
+ overflow-y: auto;
162
+ }
163
+
127
164
  .filters-selection {
128
165
  width: 40%;
129
166
  padding: 1rem;
130
-
167
+ overflow-y: auto;
131
168
  }
132
169
 
133
170
  .filters-selection-item {
@@ -145,13 +182,19 @@ function handleFilterChange() {
145
182
  justify-content: space-between;
146
183
  }
147
184
 
185
+ .filters-selection-title-label{
186
+ overflow: hidden;
187
+ text-overflow: ellipsis;
188
+ }
189
+
148
190
  .filters-selection-item.selected {
149
191
  border: 1px solid rgb(var(--global-color-primary-500));
150
192
  background-color: rgb(var(--global-color-background-500));
151
193
  }
152
194
 
153
195
  .filters-content {
154
- width: 60%;
196
+ min-width: 60%;
197
+ max-width: 60%;
155
198
  }
156
199
  .filters-content-box {
157
200
  padding: 1rem;
@@ -162,36 +205,4 @@ function handleFilterChange() {
162
205
  text-align: center;
163
206
  font-weight: bold;
164
207
  }
165
-
166
- .filter-info {
167
- display: inline-flex;
168
- align-items: center;
169
- padding: 0.25rem 0.5rem;
170
- background-color: rgb(var(--global-color-background-700));
171
- color: rgb(var(--global-color-primary-600));
172
- border-radius: 1rem;
173
- font-weight: bold;
174
- font-size: 0.9rem;
175
- margin-bottom: 10px;
176
- }
177
-
178
- .clear-button {
179
- display: inline-flex;
180
- justify-content: center;
181
- align-items: center;
182
- width: 1rem;
183
- height: 1rem;
184
- margin-left: 0.5rem;
185
- border-radius: 50%;
186
- background-color: rgb(var(--global-color-background-700));
187
- color: rgb(var(--global-color-primary-600));
188
- font-weight: bold;
189
- cursor: pointer;
190
- font-size: 0.8rem;
191
- border: none;
192
- }
193
-
194
- .clear-button:hover {
195
- background-color: rgb(var(--global-color-background-500));
196
- }
197
208
  </style>
@@ -1,18 +1,20 @@
1
- import { FilterEditor } from "../../..";
2
- import type { Filter } from "../../../utils/filters/filters";
3
- import { type ComponentProps } from "svelte";
4
- interface Props {
1
+ import type { DateMode, Filter, NumberMode, SelectMode, StringMode } from "../../../utils/filters/filters";
2
+ import { type Snippet } from "svelte";
3
+ declare const DynamicFilters: import("svelte").Component<{
5
4
  filters?: Filter[];
6
5
  lang?: "it" | "en";
7
6
  mAndDown?: boolean;
8
- onremoveAllFilters?: () => void;
9
7
  onchange?: (event: {
10
8
  detail: {
11
9
  filter: Filter;
12
10
  };
13
11
  }) => void;
14
- customSnippet?: ComponentProps<typeof FilterEditor>['customSnippet'];
15
- }
16
- declare const DynamicFilters: import("svelte").Component<Props, {}, "">;
12
+ customSnippet?: Snippet<[{
13
+ filter: Filter | undefined;
14
+ mAndDown: boolean;
15
+ updateCustomFilterValues: (filterName: string, newValue: any, newValid: boolean, mode?: NumberMode | StringMode | SelectMode | DateMode) => void;
16
+ }]>;
17
+ updateMultiFilterValues?: (filterName: string, newValue: any, newValid: boolean, mode?: NumberMode | StringMode | SelectMode | DateMode) => void;
18
+ }, {}, "">;
17
19
  type DynamicFilters = ReturnType<typeof DynamicFilters>;
18
20
  export default DynamicFilters;
@@ -195,7 +195,8 @@ function onclick(event) {
195
195
  --simple-text-field-margin-left="0px"
196
196
  mobileDrawer={mobile}
197
197
  onchange={handleChangeValue}
198
- ></Autocomplete>
198
+ placeholder={editFilterMode == 'one-edit' ? tmpFilter?.label : undefined}
199
+ ></Autocomplete>
199
200
  </div>
200
201
  {:else if tmpFilter.type === "select" && (tmpFilter.view === 'toggle')}
201
202
  <div
@@ -2,4 +2,5 @@
2
2
  --filters-button-cancel-default-background-color: transparent;
3
3
  --filters-button-cancel-default-color: rgb(var(--global-color-primary-400));
4
4
  --filters-default-wrapper-width: auto;
5
+ --filters-default-button-height: 28px;
5
6
  }
@@ -117,8 +117,9 @@ function handleApplyFilterClick() {
117
117
  let activeFilters = $derived(filters.filter((f) => f.active));
118
118
  function handleRemoveFilter(filter) {
119
119
  let filterIndex = filters.findIndex((f) => f.name === filter.name);
120
- filters[filterIndex].active = false;
121
120
  let filterName = filter.name;
121
+ filters[filterIndex].active = false;
122
+ tmpFilters[filterName].active = false;
122
123
  if (Object.keys(filters[filterIndex]).includes('value')) {
123
124
  //@ts-ignore
124
125
  filters[filterIndex].value = undefined;
@@ -265,8 +266,12 @@ function updateMultiFilterValues(filterName, newValue, newValid, mode) {
265
266
  }
266
267
  else if ('mode' in tmpFilter && tmpFilter.mode == 'between') {
267
268
  if (tmpFilter.type == 'date') {
268
- tmpFilter.from = DateTime.fromJSDate(newValue.to).setLocale('it-IT').startOf('day').toJSDate();
269
- tmpFilter.to = DateTime.fromJSDate(newValue.to).setLocale('it-IT').endOf('day').toJSDate();
269
+ if (newValue.from) {
270
+ tmpFilter.from = DateTime.fromJSDate(newValue.from).setLocale('it-IT').startOf('day').toJSDate();
271
+ }
272
+ if (newValue.to) {
273
+ tmpFilter.to = DateTime.fromJSDate(newValue.to).setLocale('it-IT').endOf('day').toJSDate();
274
+ }
270
275
  }
271
276
  else {
272
277
  tmpFilter.from = newValue.from;
@@ -402,6 +407,7 @@ function onclick(event, stopPropagation = false) {
402
407
  >
403
408
  <Button
404
409
  --button-color="var(--chip-color, var(--chip-default-color))"
410
+ --button-height="var(--filters-button-height, var(--filters-default-button-height))"
405
411
  onclick={handleAddFilterClick}
406
412
  >
407
413
  <div class="filter-button-content">
@@ -423,6 +429,7 @@ function onclick(event, stopPropagation = false) {
423
429
  >
424
430
  <Button
425
431
  --button-color="var(--chip-color, var(--chip-default-color))"
432
+ --button-height="var(--filters-button-height, var(--filters-default-button-height))"
426
433
  onclick={handleAddFilterClick}
427
434
  >
428
435
  <div class="filter-button-content">
@@ -842,7 +849,7 @@ function onclick(event, stopPropagation = false) {
842
849
 
843
850
  .filters-wrapper {
844
851
  display: flex;
845
- align-items: center;
852
+ align-items: start;
846
853
  gap: 20px;
847
854
  max-width: 100%;
848
855
  width: var(
@@ -10,7 +10,7 @@ let { headers = [], items = [], sortedBy = $bindable(undefined), sortDirection =
10
10
  if (!onrowClick && !!onrowDoubleClick) {
11
11
  throw new Error('cannot define an onrowDoubleClick event without defining an onrowClick event');
12
12
  }
13
- let clickTimeout = undefined;
13
+ let clickTimeout = undefined, sortModify;
14
14
  onMount(() => {
15
15
  if (resizableColumns) {
16
16
  if (!resizedColumnSizeWithPadding)
@@ -59,17 +59,20 @@ function handleHeaderClick(header) {
59
59
  sortDirection = 'desc';
60
60
  else if (sortDirection == 'desc') {
61
61
  sortedBy = undefined;
62
+ sortModify = undefined;
62
63
  }
63
64
  }
64
65
  else {
65
66
  sortedBy = header.value;
66
67
  sortDirection = 'asc';
68
+ sortModify = header.sortModify;
67
69
  }
68
70
  if (onsort) {
69
71
  onsort({
70
72
  detail: {
71
73
  sortedBy,
72
- sortDirection
74
+ sortDirection,
75
+ sortModify
73
76
  }
74
77
  });
75
78
  }
@@ -6,6 +6,10 @@ export type Header<Data = any> = {
6
6
  width?: string;
7
7
  minWidth?: string;
8
8
  sortable?: boolean;
9
+ sortModify?: (params: {
10
+ builder: FilterBuilder;
11
+ sortDirection: 'asc' | 'desc';
12
+ }) => FilterBuilder;
9
13
  data?: Data;
10
14
  };
11
15
  export type CalculateRowStyles<T> = (item: T) => {
@@ -18,6 +22,7 @@ import '../../../css/main.css';
18
22
  import './SimpleTable.css';
19
23
  import { type Snippet } from 'svelte';
20
24
  import type { ColumnBoolean, ColumnCheckBox, ColumnCustom, ColumnDate, ColumnIcon, ColumnNumber, ColumnString } from './columnTypes';
25
+ import type { FilterBuilder } from '../../..';
21
26
  declare class __sveltets_Render<Item extends {
22
27
  [key: string]: any;
23
28
  }, Data> {
@@ -40,6 +45,7 @@ declare class __sveltets_Render<Item extends {
40
45
  detail: {
41
46
  sortedBy: string | undefined;
42
47
  sortDirection: string;
48
+ sortModify: Header["sortModify"];
43
49
  };
44
50
  }) => void) | undefined;
45
51
  onrowClick?: ((event: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@likable-hair/svelte",
3
3
  "description": "A Svelte component for likablehair and others",
4
- "version": "4.0.6",
4
+ "version": "4.0.7",
5
5
  "scripts": {
6
6
  "host": "vite --host",
7
7
  "dev": "vite dev",