@softwareone/spi-sv5-library 1.11.0 → 1.11.1

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.
@@ -223,13 +223,13 @@
223
223
  }
224
224
 
225
225
  .caption {
226
- font-size: 16px;
226
+ font-size: 14px;
227
227
  line-height: 24px;
228
228
  color: var(--color-gray-outer);
229
229
  }
230
230
 
231
231
  .text-small {
232
- font-size: 14px;
232
+ font-size: 12px;
233
233
  line-height: 20px;
234
234
  color: var(--color-gray-auro);
235
235
  margin-top: 4px;
@@ -262,6 +262,7 @@
262
262
 
263
263
  .file-select {
264
264
  display: inline-block;
265
+ font-size: 14px;
265
266
  background: var(--color-bg-select);
266
267
  color: var(--color-text-select);
267
268
  padding: var(--spacing-sm) var(--spacing-md);
@@ -3,8 +3,9 @@
3
3
 
4
4
  import { Button, Input, Select, type SelectOption } from '../index.js';
5
5
  import type { Column } from './adapter/index.js';
6
- import { Operator } from './consts.js';
6
+ import { Operation } from './consts.js';
7
7
  import { type Filter } from './types.js';
8
+ import { sanitizeFilters } from './util.js';
8
9
 
9
10
  interface Props {
10
11
  columns: Column<T, unknown>[];
@@ -15,16 +16,8 @@
15
16
 
16
17
  let isOpen = $state(false);
17
18
  let editingFilters = $state<Filter[]>([]);
18
- const operatorOptions: Operator[] = Object.values(Operator);
19
-
20
- const filters = $derived.by<Filter[]>(() => {
21
- const filterParams = page.url.searchParams.getAll('filter');
22
- return filterParams
23
- .filter((param) => param.trim())
24
- .map(parseFilterParam)
25
- .filter((filter): filter is Filter => filter !== null);
26
- });
27
-
19
+ const operationOptions: Operation[] = Object.values(Operation);
20
+ const filters = $derived(sanitizeFilters(page.url.searchParams.getAll('filter')));
28
21
  const hasActiveFilters = $derived(filters.length > 0);
29
22
  const columnOptions = $derived<SelectOption[]>(
30
23
  columns
@@ -36,30 +29,30 @@
36
29
  );
37
30
 
38
31
  const addFilterRow = () => {
39
- editingFilters = [...editingFilters, { column: '', value: '', operator: Operator.And }];
32
+ editingFilters = [...editingFilters, { column: '', value: '', operation: Operation.And }];
40
33
  };
41
34
 
42
35
  const removeFilterRow = (index: number) => {
43
36
  const remainingFilters = editingFilters.filter((_, filterIndex) => filterIndex !== index);
44
-
45
- editingFilters =
46
- remainingFilters.length === 1
47
- ? [{ ...remainingFilters[0], operator: undefined }]
48
- : remainingFilters;
37
+ editingFilters = normalizeFilters(remainingFilters);
49
38
  };
50
39
 
51
40
  const applyFilters = () => {
52
- const validFilters = getValidFilters();
53
- handleFilters(validFilters);
41
+ editingFilters = normalizeFilters(getValidFilters());
42
+ handleFilters();
43
+ };
44
+
45
+ const normalizeFilters = (filters: Filter[]) => {
46
+ return filters.length === 1 ? [{ ...filters[0], operation: undefined }] : filters;
54
47
  };
55
48
 
56
49
  const clearAllFilters = () => {
57
50
  editingFilters = [];
58
- handleFilters(editingFilters);
51
+ handleFilters();
59
52
  };
60
53
 
61
- const handleFilters = (filters: Filter[]) => {
62
- onfilterschange?.(filters);
54
+ const handleFilters = () => {
55
+ onfilterschange?.(editingFilters);
63
56
  isOpen = false;
64
57
  };
65
58
 
@@ -72,7 +65,7 @@
72
65
  if (!editingFilters.length) {
73
66
  editingFilters = filters.length
74
67
  ? filters.map((filter) => ({ ...filter }))
75
- : [{ column: '', value: '', operator: undefined }];
68
+ : [{ column: '', value: '', operation: undefined }];
76
69
  }
77
70
  };
78
71
 
@@ -86,33 +79,6 @@
86
79
  const getValidFilters = () => {
87
80
  return editingFilters.filter((filter) => filter.column && filter.value.trim());
88
81
  };
89
-
90
- const parseFilterParam = (filterValue: string) => {
91
- const parts = filterValue.split(':');
92
- if (parts.length === 3) return parseSimpleFilter(parts);
93
- if (parts.length === 4) return parseOperatorFilter(parts);
94
- return null;
95
- };
96
-
97
- const parseSimpleFilter = (parts: string[]): Filter | null => {
98
- const [column, operator, value] = parts;
99
- return isValidFilter(column, operator, value) ? { column, value, operator: undefined } : null;
100
- };
101
-
102
- const parseOperatorFilter = (parts: string[]): Filter | null => {
103
- const [operator, column, eq, value] = parts;
104
- return isValidFilter(column, eq, value) && isValidOperator(operator)
105
- ? { column, value, operator }
106
- : null;
107
- };
108
-
109
- const isValidFilter = (column: string, operator: string, value: string) => {
110
- return operator === 'eq' && !!column && !!value;
111
- };
112
-
113
- const isValidOperator = (operator: string): operator is Operator => {
114
- return operatorOptions.includes(operator as Operator);
115
- };
116
82
  </script>
117
83
 
118
84
  <div class="filter-container">
@@ -155,16 +121,16 @@
155
121
  {#each editingFilters as filter, index (index)}
156
122
  <div class="filter-row">
157
123
  {#if index > 0}
158
- <div class="filter-operator">
124
+ <div class="filter-operation">
159
125
  <Select
160
- options={operatorOptions}
126
+ options={operationOptions}
161
127
  disableValidationColor
162
- bind:value={filter.operator}
128
+ bind:value={filter.operation}
163
129
  hideClearButton
164
130
  />
165
131
  </div>
166
132
  {:else}
167
- <div class="filter-operator"></div>
133
+ <div class="filter-operation"></div>
168
134
  {/if}
169
135
 
170
136
  <div class="filter-column">
@@ -246,7 +212,7 @@
246
212
  --button-size: 40px;
247
213
  --delete-button-size: 48px;
248
214
  --modal-width: 640px;
249
- --operator-column-width: 80px;
215
+ --operation-column-width: 80px;
250
216
  --transition-speed: 0.2s;
251
217
 
252
218
  position: relative;
@@ -335,12 +301,12 @@
335
301
 
336
302
  .filter-row {
337
303
  display: grid;
338
- grid-template-columns: var(--operator-column-width) 1fr 1fr var(--delete-button-size);
304
+ grid-template-columns: var(--operation-column-width) 1fr 1fr var(--delete-button-size);
339
305
  align-items: end;
340
306
  gap: var(--spacing-md);
341
307
  }
342
308
 
343
- .filter-operator,
309
+ .filter-operation,
344
310
  .filter-column,
345
311
  .filter-value {
346
312
  display: flex;
@@ -3,6 +3,7 @@
3
3
 
4
4
  import { Search } from '../index.js';
5
5
  import { FlexRender, type HeaderGroup, type RowData } from './adapter/index.js';
6
+ import { sanitizeFilters } from './util.js';
6
7
 
7
8
  interface Props {
8
9
  headerGroups: HeaderGroup<T>[];
@@ -17,15 +18,10 @@
17
18
  false: 'swap_vert'
18
19
  };
19
20
 
21
+ const filters = $derived(sanitizeFilters(page.url.searchParams.getAll('filter')));
22
+
20
23
  const isColumnFiltered = (columnId: string): boolean => {
21
- const filterParams = page.url.searchParams.getAll('filter');
22
- return filterParams.some((filterValue) => {
23
- const parts = filterValue.split(':');
24
- return (
25
- (parts.length === 3 && parts[0] === columnId) ||
26
- (parts.length === 4 && parts[1] === columnId)
27
- );
28
- });
24
+ return filters.some((filter) => filter.column === columnId);
29
25
  };
30
26
  </script>
31
27
 
@@ -23,7 +23,7 @@
23
23
  import AdvancedFilter from './AdvancedFilter.svelte';
24
24
  import Body from './Body.svelte';
25
25
  import ColumnVisibilityDropdown from './ColumnVisibilityDropdown.svelte';
26
- import { DEFAULT_MIN_PAGE_LIMIT, DEFAULT_PAGE_LIMIT } from './consts.js';
26
+ import { DEFAULT_MIN_PAGE_LIMIT, DEFAULT_PAGE_LIMIT, Operator } from './consts.js';
27
27
  import { setPaginationTableContext } from './context.js';
28
28
  import type { ExcelSetting } from './excel-setting.js';
29
29
  import exportExcel from './excel.js';
@@ -208,8 +208,8 @@
208
208
  };
209
209
 
210
210
  const buildFilterValue = (filter: Filter) => {
211
- const operator = filter.operator ? `${filter.operator}:` : '';
212
- return `${operator}${filter.column}:eq:${filter.value}`;
211
+ const operation = filter.operation ? `${filter.operation}:` : '';
212
+ return `${operation}${filter.column}:${Operator.Eq}:${filter.value}`;
213
213
  };
214
214
 
215
215
  const buildUrl = (searchParams: URLSearchParams) => {
@@ -2,9 +2,13 @@ export declare const DEFAULT_PAGE = 1;
2
2
  export declare const DEFAULT_PAGE_LIMIT = 10;
3
3
  export declare const DEFAULT_MIN_PAGE_LIMIT = 5;
4
4
  export declare const DEFAULT_ITEMS_PER_PAGE_OPTIONS: number[];
5
- export declare const Operator: {
5
+ export declare const Operation: {
6
6
  readonly And: "AND";
7
7
  readonly Or: "OR";
8
8
  readonly Not: "NOT";
9
9
  };
10
+ export declare const Operator: {
11
+ readonly Eq: "eq";
12
+ };
13
+ export type Operation = typeof Operation[keyof typeof Operation];
10
14
  export type Operator = typeof Operator[keyof typeof Operator];
@@ -2,8 +2,11 @@ export const DEFAULT_PAGE = 1;
2
2
  export const DEFAULT_PAGE_LIMIT = 10;
3
3
  export const DEFAULT_MIN_PAGE_LIMIT = 5;
4
4
  export const DEFAULT_ITEMS_PER_PAGE_OPTIONS = [10, 25, 50, 75, 100];
5
- export const Operator = {
5
+ export const Operation = {
6
6
  And: 'AND',
7
7
  Or: 'OR',
8
8
  Not: 'NOT'
9
9
  };
10
+ export const Operator = {
11
+ Eq: 'eq'
12
+ };
@@ -5,4 +5,4 @@ export { ColumnFormat, type ExcelSetting } from './excel-setting.js';
5
5
  export * from './excel.js';
6
6
  export { default as Table } from './Table.svelte';
7
7
  export * from './types.js';
8
- export { createActionsColumn, createStaticTable, getPage, getPageLimit } from './util.js';
8
+ export { createActionsColumn, createStaticTable, getPage, getPageLimit, sanitizeFilters } from './util.js';
@@ -5,4 +5,4 @@ export { ColumnFormat } from './excel-setting.js';
5
5
  export * from './excel.js';
6
6
  export { default as Table } from './Table.svelte';
7
7
  export * from './types.js';
8
- export { createActionsColumn, createStaticTable, getPage, getPageLimit } from './util.js';
8
+ export { createActionsColumn, createStaticTable, getPage, getPageLimit, sanitizeFilters } from './util.js';
@@ -1 +1 @@
1
- import { Operator } from "./consts.js";
1
+ import { Operation } from "./consts.js";
@@ -1,7 +1,8 @@
1
1
  import { type ColumnDef, type Row } from './adapter/index.js';
2
- import type { Action } from './types.js';
2
+ import type { Action, Filter } from './types.js';
3
3
  export declare const createCheckedColumn: <T>() => import("./adapter/index.js").DisplayColumnDef<T, unknown>;
4
4
  export declare const createActionsColumn: <T>(getActions: (row: Row<T>) => Action[]) => import("./adapter/index.js").DisplayColumnDef<T, unknown>;
5
5
  export declare const createStaticTable: <TData>(columns: ColumnDef<TData, any>[], data: TData[]) => import("./adapter/index.js").Table<TData>;
6
6
  export declare const getPageLimit: (urlSearchParams: URLSearchParams) => number;
7
7
  export declare const getPage: (urlSearchParams: URLSearchParams) => number;
8
+ export declare const sanitizeFilters: (filterParams: string[]) => Filter[];
@@ -1,7 +1,7 @@
1
1
  import ActionsColumn from './ActionsColumn.svelte';
2
2
  import RowCheckBox from './RowCheckBox.svelte';
3
3
  import { createColumnHelper, createTable, getCoreRowModel, renderComponent } from './adapter/index.js';
4
- import { DEFAULT_ITEMS_PER_PAGE_OPTIONS, DEFAULT_PAGE, DEFAULT_PAGE_LIMIT } from './consts.js';
4
+ import { DEFAULT_ITEMS_PER_PAGE_OPTIONS, DEFAULT_PAGE, DEFAULT_PAGE_LIMIT, Operation, Operator } from './consts.js';
5
5
  export const createCheckedColumn = () => {
6
6
  const columnHelper = createColumnHelper();
7
7
  return columnHelper.display({
@@ -72,3 +72,33 @@ export const getPage = (urlSearchParams) => {
72
72
  const isPageValid = pageParam && !Number.isNaN(page) && page > 0;
73
73
  return isPageValid ? page : DEFAULT_PAGE;
74
74
  };
75
+ export const sanitizeFilters = (filterParams) => {
76
+ return filterParams
77
+ .filter((param) => param.trim())
78
+ .map(parseFilterParam)
79
+ .filter((filter) => filter !== null);
80
+ };
81
+ const parseFilterParam = (filterValue) => {
82
+ const parts = filterValue.split(':');
83
+ if (parts.length === 3)
84
+ return parseSimpleFilter(parts);
85
+ if (parts.length === 4)
86
+ return parseOperationFilter(parts);
87
+ return null;
88
+ };
89
+ const parseSimpleFilter = (parts) => {
90
+ const [column, operator, value] = parts;
91
+ return isValidFilter(column, operator, value) ? { column, value, operation: undefined } : null;
92
+ };
93
+ const parseOperationFilter = (parts) => {
94
+ const [operation, column, operator, value] = parts;
95
+ return isValidFilter(column, operator, value) && isValidOperation(operation)
96
+ ? { column, value, operation }
97
+ : null;
98
+ };
99
+ const isValidFilter = (column, operator, value) => {
100
+ return operator === Operator.Eq && !!column && !!value;
101
+ };
102
+ const isValidOperation = (operation) => {
103
+ return Object.values(Operation).includes(operation);
104
+ };
@@ -10,5 +10,5 @@ type TabComponent<TComponent extends Component<any>> = BaseTab & {
10
10
  component: TComponent;
11
11
  props: ComponentProps<TComponent>;
12
12
  };
13
- export declare const createTab: <TComponent extends Component<any>>(tab: Tab<TComponent>) => Tab<TComponent>;
13
+ export declare const createTabComponent: <TComponent extends Component<any>>(tab: Tab<TComponent>) => Tab<TComponent>;
14
14
  export {};
@@ -1,3 +1,3 @@
1
- export const createTab = (tab) => {
1
+ export const createTabComponent = (tab) => {
2
2
  return tab;
3
3
  };
package/dist/index.d.ts CHANGED
@@ -34,7 +34,7 @@ import Toggle from './Controls/Toggle/Toggle.svelte';
34
34
  import Tooltip from './Tooltip/Tooltip.svelte';
35
35
  import Waffle from './Waffle/Waffle.svelte';
36
36
  import AttachFile from './Controls/AttachFile/AttachFile.svelte';
37
- import { createTab } from './Tabs/tabsState.svelte.js';
37
+ import { createTabComponent } from './Tabs/tabsState.svelte.js';
38
38
  import { addBreadcrumbsNameMap } from './Breadcrumbs/breadcrumbsState.svelte.js';
39
39
  import { ChipType } from './Chips/chipsState.svelte.js';
40
40
  import { ColumnType, ImageType } from './HighlightPanel/highlightPanelState.svelte.js';
@@ -54,4 +54,4 @@ import type { Tab } from './Tabs/tabsState.svelte.js';
54
54
  import type { Toast } from './Toast/toastState.svelte';
55
55
  import type { WaffleItem } from './Waffle/waffleState.svelte.js';
56
56
  import type { NotificationProps } from './Notification/notificationState.svelte.js';
57
- export { Accordion, AttachFile, Avatar, Breadcrumbs, Button, Card, Chips, DeleteConfirmationModal, ErrorPage, Footer, Header, HeaderAccount, HeaderLoader, HeaderLogo, HighlightPanel, Home, Input, Label, Link, Menu, Modal, Notification, Processing, ProgressPage, ProgressWizard, Search, Select, Sidebar, Spinner, Switcher, Tabs, TextArea, Toaster, Toggle, Tooltip, Waffle, addBreadcrumbsNameMap, addToast, getProgressWizardContext, setProgressWizardStepsContext, setStepValidity, getSubMenuItemsFromMenu, createTab, ChipType, ColumnType, ImageType, type BreadcrumbsNameMap, type HighlightPanelColumn, type HomeItem, type MainMenu, type MenuItem, type ModalProps, type ProgressWizardStep, type SelectOption, type SwitcherOption, type Tab, type Toast, type WaffleItem, type SubMenuItem, type NotificationProps };
57
+ export { Accordion, AttachFile, Avatar, Breadcrumbs, Button, Card, Chips, DeleteConfirmationModal, ErrorPage, Footer, Header, HeaderAccount, HeaderLoader, HeaderLogo, HighlightPanel, Home, Input, Label, Link, Menu, Modal, Notification, Processing, ProgressPage, ProgressWizard, Search, Select, Sidebar, Spinner, Switcher, Tabs, TextArea, Toaster, Toggle, Tooltip, Waffle, addBreadcrumbsNameMap, addToast, getProgressWizardContext, setProgressWizardStepsContext, setStepValidity, getSubMenuItemsFromMenu, createTabComponent, ChipType, ColumnType, ImageType, type BreadcrumbsNameMap, type HighlightPanelColumn, type HomeItem, type MainMenu, type MenuItem, type ModalProps, type ProgressWizardStep, type SelectOption, type SwitcherOption, type Tab, type Toast, type WaffleItem, type SubMenuItem, type NotificationProps };
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ import Toggle from './Controls/Toggle/Toggle.svelte';
35
35
  import Tooltip from './Tooltip/Tooltip.svelte';
36
36
  import Waffle from './Waffle/Waffle.svelte';
37
37
  import AttachFile from './Controls/AttachFile/AttachFile.svelte';
38
- import { createTab } from './Tabs/tabsState.svelte.js';
38
+ import { createTabComponent } from './Tabs/tabsState.svelte.js';
39
39
  // State, enums, and helpers
40
40
  import { addBreadcrumbsNameMap } from './Breadcrumbs/breadcrumbsState.svelte.js';
41
41
  import { ChipType } from './Chips/chipsState.svelte.js';
@@ -48,6 +48,6 @@ export {
48
48
  // Components
49
49
  Accordion, AttachFile, Avatar, Breadcrumbs, Button, Card, Chips, DeleteConfirmationModal, ErrorPage, Footer, Header, HeaderAccount, HeaderLoader, HeaderLogo, HighlightPanel, Home, Input, Label, Link, Menu, Modal, Notification, Processing, ProgressPage, ProgressWizard, Search, Select, Sidebar, Spinner, Switcher, Tabs, TextArea, Toaster, Toggle, Tooltip, Waffle,
50
50
  // Functions and helpers
51
- addBreadcrumbsNameMap, addToast, getProgressWizardContext, setProgressWizardStepsContext, setStepValidity, getSubMenuItemsFromMenu, createTab,
51
+ addBreadcrumbsNameMap, addToast, getProgressWizardContext, setProgressWizardStepsContext, setStepValidity, getSubMenuItemsFromMenu, createTabComponent,
52
52
  // Enums
53
53
  ChipType, ColumnType, ImageType };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softwareone/spi-sv5-library",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "Svelte components",
5
5
  "keywords": [
6
6
  "svelte",