@softwareone/spi-sv5-library 1.12.3 → 1.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +15 -15
  2. package/dist/Announcement/Announcement.svelte +5 -3
  3. package/dist/Breadcrumbs/Breadcrumbs.svelte +3 -2
  4. package/dist/Breadcrumbs/breadcrumbsState.svelte.js +3 -3
  5. package/dist/Controls/AttachFile/AttachFile.svelte +1 -1
  6. package/dist/Controls/AttachFile/FileManager.svelte +4 -2
  7. package/dist/Controls/AttachFile/Warnings.svelte +1 -1
  8. package/dist/Controls/Input/Input.svelte +8 -4
  9. package/dist/Controls/Input/InputIcon.svelte +2 -2
  10. package/dist/Controls/Select/Select.svelte +13 -6
  11. package/dist/Controls/TextArea/TextArea.svelte +1 -2
  12. package/dist/ErrorPage/ErrorPage.svelte +3 -1
  13. package/dist/Footer/Footer.svelte +3 -1
  14. package/dist/Header/Header.svelte +3 -1
  15. package/dist/Header/Header.svelte.d.ts +1 -0
  16. package/dist/Header/HeaderAccount.svelte +6 -5
  17. package/dist/Header/HeaderAccount.svelte.d.ts +2 -1
  18. package/dist/Header/HeaderLoader.svelte +2 -4
  19. package/dist/HighlightPanel/HighlightPanel.svelte +1 -1
  20. package/dist/Home/Home.svelte +1 -1
  21. package/dist/Menu/Menu.svelte +3 -2
  22. package/dist/Menu/MenuItem.svelte +0 -1
  23. package/dist/Menu/Sidebar.svelte +7 -4
  24. package/dist/Modal/Modal.svelte +1 -0
  25. package/dist/Modal/ModalHeader.svelte +2 -1
  26. package/dist/Processing/Processing.svelte +3 -1
  27. package/dist/ProgressWizard/ProgressWizard.svelte +1 -1
  28. package/dist/ProgressWizard/context.js +1 -1
  29. package/dist/Search/Search.svelte +6 -1
  30. package/dist/Switcher/Switcher.svelte +4 -2
  31. package/dist/Table/ActionsColumn.svelte +11 -4
  32. package/dist/Table/AdvancedFilter.svelte +17 -4
  33. package/dist/Table/Body.svelte +1 -1
  34. package/dist/Table/ColumnVisibilityDropdown.svelte +3 -2
  35. package/dist/Table/Header.svelte +12 -4
  36. package/dist/Table/PageSize.svelte +1 -1
  37. package/dist/Table/Skeleton.svelte +3 -4
  38. package/dist/Table/Table.svelte +8 -4
  39. package/dist/Table/Table.svelte.d.ts +5 -5
  40. package/dist/Table/adapter/flex-render.svelte +25 -32
  41. package/dist/Table/adapter/flex-render.svelte.d.ts +1 -1
  42. package/dist/Table/adapter/render-component.d.ts +1 -1
  43. package/dist/Table/adapter/table.svelte.d.ts +1 -1
  44. package/dist/Table/adapter/table.svelte.js +6 -6
  45. package/dist/Table/consts.d.ts +2 -2
  46. package/dist/Table/excel-setting.d.ts +1 -1
  47. package/dist/Table/excel.js +1 -0
  48. package/dist/Table/tanstack-types.d.ts +2 -1
  49. package/dist/Table/types.d.ts +1 -1
  50. package/dist/Table/types.js +1 -1
  51. package/dist/Tabs/Tabs.svelte +2 -2
  52. package/dist/Toast/Toast.svelte +4 -2
  53. package/package.json +8 -2
package/README.md CHANGED
@@ -65,16 +65,16 @@ import {
65
65
  - ErrorPage
66
66
  - Footer
67
67
  - Form
68
- - Input
69
- - TextArea
70
- - Toggle
68
+ - Input
69
+ - TextArea
70
+ - Toggle
71
71
  - Header (including a loader)
72
- - HeaderAccount
73
- - HeaderLoader
74
- - HeaderLogo
72
+ - HeaderAccount
73
+ - HeaderLoader
74
+ - HeaderLogo
75
75
  - HighlightPanel
76
76
  - Menu
77
- - Sidebar
77
+ - Sidebar
78
78
  - Modal
79
79
  - ProgressWizard
80
80
  - Spinner
@@ -85,18 +85,18 @@ import {
85
85
  # List of types per component
86
86
 
87
87
  - Breadcrumbs
88
- - BreadcrumbsNameMap
88
+ - BreadcrumbsNameMap
89
89
  - Chips
90
- - ChipType
90
+ - ChipType
91
91
  - HighlightPanel
92
- - ColumnType
93
- - HighlightPanelColumn
94
- - ImageType
92
+ - ColumnType
93
+ - HighlightPanelColumn
94
+ - ImageType
95
95
  - Menu
96
- - MenuItem
96
+ - MenuItem
97
97
  - Modal
98
- - ModalProps
98
+ - ModalProps
99
99
  - ProgressWizard
100
- - ProgressWizardStep
100
+ - ProgressWizardStep
101
101
  - Tab
102
102
  - Toast
@@ -38,14 +38,15 @@
38
38
 
39
39
  {#if announcementItems.length}
40
40
  <div class="announcements-list">
41
- {#each announcementItems as announcement}
41
+ {#each announcementItems as announcement, index (index)}
42
42
  <article class={['announcement-item', !announcement.isRead && 'unread']}>
43
43
  <div class="item-header">
44
44
  <div class="icon-container">
45
45
  {#if !announcement.isRead}
46
46
  <div class="unread-indicator"></div>
47
47
  {/if}
48
- <span class="material-icons-outlined announcement-icon">notifications_active</span
48
+ <span class="material-icons-outlined announcement-icon"
49
+ >notifications_active</span
49
50
  >
50
51
  </div>
51
52
  <div class="item-info">
@@ -60,7 +61,8 @@
60
61
  </div>
61
62
  {:else}
62
63
  <div class="empty-state">
63
- <span class="material-icons-outlined empty-icon icon-gradient">hide_source</span>
64
+ <span class="material-icons-outlined empty-icon icon-gradient">hide_source</span
65
+ >
64
66
  <div class="empty-content">
65
67
  <p class="empty-title">No announcements yet</p>
66
68
  <p class="empty-description">Check back later for updates</p>
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { page } from '$app/state';
3
- import { getBreadcrumbsNameMap, formatString } from './breadcrumbsState.svelte';
3
+
4
+ import { formatString, getBreadcrumbsNameMap } from './breadcrumbsState.svelte';
4
5
 
5
6
  // Mapping for human-readable names
6
7
  const map = getBreadcrumbsNameMap();
@@ -18,7 +19,7 @@
18
19
  <nav aria-label="Breadcrumb">
19
20
  <ul class="breadcrumb">
20
21
  <li><a href="/">Home</a></li>
21
- {#each getBreadcrumbs() as { name, path }, i}
22
+ {#each getBreadcrumbs() as { name, path }, i (i)}
22
23
  <li>
23
24
  {#if i === getBreadcrumbs().length - 1}
24
25
  <span class="breadcrumbActive">{name}</span>
@@ -1,5 +1,5 @@
1
1
  const breadcrumbsState = $state({
2
- names: {},
2
+ names: {}
3
3
  });
4
4
  export function getBreadcrumbsNameMap() {
5
5
  return breadcrumbsState;
@@ -8,13 +8,13 @@ export function addBreadcrumbsNameMap(breadcrumbs) {
8
8
  breadcrumbsState.names = breadcrumbs;
9
9
  }
10
10
  export function formatString(input) {
11
- return input
11
+ return (input
12
12
  // Replace hyphens and underscores with spaces
13
13
  .replace(/[-_]/g, ' ')
14
14
  // Insert spaces before uppercase letters (preserving the first letter)
15
15
  .replace(/([a-z])([A-Z])/g, '$1 $2')
16
16
  // Capitalize each word
17
- .replace(/\b\w/g, char => char.toUpperCase());
17
+ .replace(/\b\w/g, (char) => char.toUpperCase()));
18
18
  }
19
19
  // const nameMap: Record<string, string> = {
20
20
  // "dashboard": "Dashboard",
@@ -153,7 +153,7 @@
153
153
  <Notification type="info">
154
154
  {#snippet content()}
155
155
  <ul class="message">
156
- {#each reviewMessages as message}
156
+ {#each reviewMessages as message, index (index)}
157
157
  <li>{message}</li>
158
158
  {/each}
159
159
  </ul>
@@ -7,7 +7,9 @@
7
7
 
8
8
  let { files, fileSizeLimitMB, updateFiles }: Props = $props();
9
9
 
10
- let totalSize = $derived(files ? Array.from(files).reduce((sum, file) => sum + file.size, 0) : 0);
10
+ let totalSize = $derived(
11
+ files ? Array.from(files).reduce((sum, file) => sum + file.size, 0) : 0
12
+ );
11
13
  const MB_IN_BYTES = 1048576;
12
14
 
13
15
  const removeFile = (index: number) => {
@@ -26,7 +28,7 @@
26
28
 
27
29
  <ul class="container">
28
30
  {#if files?.length}
29
- {#each Array.from(files) as file, index}
31
+ {#each Array.from(files) as file, index (index)}
30
32
  <li class="list-detail">
31
33
  <span class="material-icons-outlined">description</span>
32
34
 
@@ -13,7 +13,7 @@
13
13
 
14
14
  <section class="detail-section">
15
15
  <ul class="list-inside">
16
- {#each validationMessages as message}
16
+ {#each validationMessages as message, index (index)}
17
17
  <li class="item">
18
18
  {message}
19
19
  </li>
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLInputAttributes } from 'svelte/elements';
3
3
 
4
- import type { LabelProps } from '../Label/labelState.svelte.js';
5
4
  import Label from '../Label/Label.svelte';
5
+ import type { LabelProps } from '../Label/labelState.svelte.js';
6
6
  import InputIcon from './InputIcon.svelte';
7
7
 
8
8
  type InputType = 'text' | 'password' | 'number' | 'date' | 'money';
@@ -28,7 +28,6 @@
28
28
  id,
29
29
  disabled,
30
30
  readonly,
31
- oninput,
32
31
  disableValidationColor = false,
33
32
  infoTooltip,
34
33
  ...props
@@ -89,7 +88,10 @@
89
88
  ]}
90
89
  >
91
90
  {#if !disableValidationColor && hasStatus}
92
- <InputIcon type={isInvalid ? 'error' : 'success'} isDateInput={showDatePicker} />
91
+ <InputIcon
92
+ type={isInvalid ? 'error' : 'success'}
93
+ isDateInput={showDatePicker}
94
+ />
93
95
  {/if}
94
96
 
95
97
  {#if type === 'password'}
@@ -310,7 +312,9 @@
310
312
  }
311
313
 
312
314
  .form-input-wrapper.error,
313
- .form-input-wrapper.error:hover:not(:has(.form-input:disabled)):not(:has(.form-input:read-only)),
315
+ .form-input-wrapper.error:hover:not(:has(.form-input:disabled)):not(
316
+ :has(.form-input:read-only)
317
+ ),
314
318
  .form-input-wrapper.error:focus-within {
315
319
  border-color: #dc2626;
316
320
  }
@@ -30,8 +30,8 @@
30
30
  {:else}
31
31
  <span
32
32
  class="material-icons-outlined form-input-icon form-input-icon--{type}"
33
- class:form-input-icon--date-status={isDateInput && (type === 'error' || type === 'success')}
34
- >{icons[type]}</span
33
+ class:form-input-icon--date-status={isDateInput &&
34
+ (type === 'error' || type === 'success')}>{icons[type]}</span
35
35
  >
36
36
  {/if}
37
37
  </div>
@@ -4,8 +4,8 @@
4
4
  import type { Attachment } from 'svelte/attachments';
5
5
 
6
6
  import { Search, type SelectOption } from '../../index.js';
7
- import type { LabelProps } from '../Label/labelState.svelte.js';
8
7
  import Label from '../Label/Label.svelte';
8
+ import type { LabelProps } from '../Label/labelState.svelte.js';
9
9
 
10
10
  interface SelectProps extends LabelProps {
11
11
  options: string[] | SelectOption[];
@@ -75,7 +75,9 @@
75
75
  );
76
76
 
77
77
  const originalOptions = $derived<SelectOption[]>(
78
- isStringArray(options) ? options.map((option) => ({ label: option, value: option })) : options
78
+ isStringArray(options)
79
+ ? options.map((option) => ({ label: option, value: option }))
80
+ : options
79
81
  );
80
82
 
81
83
  const selectedOptions = $derived<SelectOption[]>(
@@ -128,7 +130,11 @@
128
130
  }
129
131
  };
130
132
 
131
- const setDropdownStyles = (element: HTMLElement, rect: DOMRect, showInTopPosition: boolean) => {
133
+ const setDropdownStyles = (
134
+ element: HTMLElement,
135
+ rect: DOMRect,
136
+ showInTopPosition: boolean
137
+ ) => {
132
138
  element.style.setProperty('--dropdown-width', `${rect.width}px`);
133
139
  element.style.setProperty('--dropdown-left', `${rect.left}px`);
134
140
 
@@ -234,7 +240,7 @@
234
240
  <div class="dropdown-container-selected-options">
235
241
  {#if selectedOption || selectedOptions.length}
236
242
  {#if multiple}
237
- {#each selectedOptions as selectedOption, index}
243
+ {#each selectedOptions as selectedOption, index (index)}
238
244
  {@render selectedOptionTemplate(selectedOption, index)}
239
245
  {/each}
240
246
  {:else if customSelection}
@@ -279,9 +285,10 @@
279
285
  <p class="dropdown-list-no-options-message">No options</p>
280
286
  {:else}
281
287
  <ul class="dropdown-list-options-container">
282
- {#each filteredOptions as filteredOption}
288
+ {#each filteredOptions as filteredOption, index (index)}
283
289
  {@const isVisible = multiple ? canBeVisible(filteredOption) : true}
284
- {@const isActive = !multiple && filteredOption.value === selectedOption?.value}
290
+ {@const isActive =
291
+ !multiple && filteredOption.value === selectedOption?.value}
285
292
 
286
293
  {#if isVisible}
287
294
  <li
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLTextareaAttributes } from 'svelte/elements';
3
-
3
+
4
4
  import type { LabelProps } from '../Label/labelState.svelte.js';
5
5
  import Label from '../Label/Label.svelte';
6
6
 
@@ -207,7 +207,6 @@
207
207
  box-shadow: 0px 0px 0px 3px rgba(220, 38, 38, 0.2);
208
208
  }
209
209
 
210
-
211
210
  .form-textarea-wrapper.success,
212
211
  .form-textarea-wrapper.success:hover:not(:has(.form-textarea:disabled)):not(
213
212
  :has(.form-textarea:read-only)
@@ -40,7 +40,9 @@
40
40
 
41
41
  <div class="feedback-footer">
42
42
  <Button type="button" variant="outline" onclick={() => window.history.back()}>Back</Button>
43
- <Button type="button" variant="primary" onclick={() => goto(page.url.origin)}>Go home</Button>
43
+ <Button type="button" variant="primary" onclick={() => goto(page.url.origin)}
44
+ >Go home</Button
45
+ >
44
46
  </div>
45
47
  </section>
46
48
 
@@ -17,7 +17,9 @@
17
17
  </a>
18
18
  <ul class="links">
19
19
  <li>
20
- <a href="mailto:servicedesk@softwareone.com" title="servicedesk@softwareone.com">Support</a>
20
+ <a href="mailto:servicedesk@softwareone.com" title="servicedesk@softwareone.com"
21
+ >Support</a
22
+ >
21
23
  </li>
22
24
  <li>
23
25
  <a
@@ -13,6 +13,7 @@
13
13
  homeUrl?: string;
14
14
  hideAccount?: boolean;
15
15
  accountName?: string;
16
+ accountDescription?: string;
16
17
  userName?: string;
17
18
  hideLoader?: boolean;
18
19
  hideAnnouncement?: boolean;
@@ -28,6 +29,7 @@
28
29
  homeUrl = '/',
29
30
  hideAccount,
30
31
  accountName = '',
32
+ accountDescription,
31
33
  userName = '',
32
34
  hideLoader,
33
35
  hideAnnouncement,
@@ -135,7 +137,7 @@
135
137
  {/if}
136
138
  {#if !hideAccount}
137
139
  <nav class="header-section">
138
- <HeaderAccount {accountName} {userName} {profileMenuItems} />
140
+ <HeaderAccount {accountName} {accountDescription} {userName} {profileMenuItems} />
139
141
  </nav>
140
142
  {/if}
141
143
  </div>
@@ -5,6 +5,7 @@ interface HeaderProps {
5
5
  homeUrl?: string;
6
6
  hideAccount?: boolean;
7
7
  accountName?: string;
8
+ accountDescription?: string;
8
9
  userName?: string;
9
10
  hideLoader?: boolean;
10
11
  hideAnnouncement?: boolean;
@@ -1,15 +1,16 @@
1
1
  <script lang="ts">
2
- import { fade } from 'svelte/transition';
3
2
  import { goto } from '$app/navigation';
4
3
  import { Avatar, type MenuItem } from '../index.js';
4
+ import { fade } from 'svelte/transition';
5
5
 
6
6
  interface Props {
7
- accountName: string;
8
7
  userName: string;
8
+ accountName?: string;
9
+ accountDescription?: string;
9
10
  profileMenuItems?: MenuItem[];
10
11
  }
11
12
 
12
- let { accountName, userName, profileMenuItems }: Props = $props();
13
+ let { userName, accountName, accountDescription, profileMenuItems }: Props = $props();
13
14
 
14
15
  let showProfileItems = $state(false);
15
16
 
@@ -35,7 +36,7 @@
35
36
  <Avatar text={userName} />
36
37
  <div class="account-info">
37
38
  <p class="account-name">{accountName}</p>
38
- <p class="account-more-name">Operations | {userName}</p>
39
+ <p class="account-more-name">{accountDescription}</p>
39
40
  </div>
40
41
  {/snippet}
41
42
 
@@ -66,7 +67,7 @@
66
67
  aria-label="Close profile menu"
67
68
  ></div>
68
69
  <menu class="account-dropdown" transition:fade={{ delay: 50, duration: 250 }}>
69
- {#each profileMenuItems as item}
70
+ {#each profileMenuItems as item, index (index)}
70
71
  <li>
71
72
  <button
72
73
  class="account-menu-item"
@@ -1,7 +1,8 @@
1
1
  import { type MenuItem } from '../index.js';
2
2
  interface Props {
3
- accountName: string;
4
3
  userName: string;
4
+ accountName?: string;
5
+ accountDescription?: string;
5
6
  profileMenuItems?: MenuItem[];
6
7
  }
7
8
  declare const HeaderAccount: import("svelte").Component<Props, {}, "">;
@@ -2,7 +2,6 @@
2
2
  import { navigating } from '$app/state';
3
3
  import { expoOut } from 'svelte/easing';
4
4
  import { slide } from 'svelte/transition';
5
-
6
5
  </script>
7
6
 
8
7
  {#if navigating.to}
@@ -16,8 +15,7 @@
16
15
  <div
17
16
  class="navigation-loader"
18
17
  in:slide={{ delay: 100, duration: 12000, axis: 'x', easing: expoOut }}
19
- >
20
- </div>
18
+ ></div>
21
19
  {/if}
22
20
 
23
21
  <style>
@@ -28,6 +26,6 @@
28
26
  left: 0px;
29
27
  height: 3px;
30
28
  z-index: 9999;
31
- background: linear-gradient(90deg, #392D9C, #472AFF, #00c9cd);
29
+ background: linear-gradient(90deg, #392d9c, #472aff, #00c9cd);
32
30
  }
33
31
  </style>
@@ -14,7 +14,7 @@
14
14
 
15
15
  <div class="highlight-panel">
16
16
  <section class="panel-section-{distributionType}">
17
- {#each columns as column}
17
+ {#each columns as column, index (index)}
18
18
  <div class="panel-element">
19
19
  {#if column.type === ColumnType.Text}
20
20
  <h2>{column.label}</h2>
@@ -14,7 +14,7 @@
14
14
  </h1>
15
15
 
16
16
  <section class="home-container grid">
17
- {#each homeItems as homeItem}
17
+ {#each homeItems as homeItem, index (index)}
18
18
  <a href={homeItem.url} class="home-item">
19
19
  <img src={homeItem.homeIcon} alt={homeItem.text} />
20
20
  <div>
@@ -15,7 +15,8 @@
15
15
  let activeItem = $state('');
16
16
 
17
17
  const setActiveMenuItem = () => {
18
- activeItem = menuItems.find((menuItem: MenuItem) => isActiveMenuItem(menuItem.url))?.text || '';
18
+ activeItem =
19
+ menuItems.find((menuItem: MenuItem) => isActiveMenuItem(menuItem.url))?.text || '';
19
20
  };
20
21
 
21
22
  const isActiveMenuItem = (url: string) => {
@@ -53,7 +54,7 @@
53
54
 
54
55
  <nav class="menu-nav" transition:fade={{ duration: 250 }}>
55
56
  <menu class="menu-list">
56
- {#each menuItems as menuItem}
57
+ {#each menuItems as menuItem, index (index)}
57
58
  <MainMenuItem
58
59
  item={menuItem}
59
60
  isCollapsed={false}
@@ -23,7 +23,6 @@
23
23
  ]}
24
24
  onclick={() => onClick?.(item)}
25
25
  >
26
-
27
26
  <span class="material-icons-outlined icon-span">{item.icon}</span>
28
27
  <h2 class="item-name-span" class:hidden={isCollapsed}>{item.text}</h2>
29
28
  </a>
@@ -18,7 +18,8 @@
18
18
  .flatMap((item) => item.menuItems)
19
19
  .find(
20
20
  (menuItem) =>
21
- page.url.pathname === menuItem.url || page.url.pathname.startsWith(menuItem.url + '/')
21
+ page.url.pathname === menuItem.url ||
22
+ page.url.pathname.startsWith(menuItem.url + '/')
22
23
  )
23
24
  );
24
25
 
@@ -51,12 +52,14 @@
51
52
  </header>
52
53
 
53
54
  <section class="content">
54
- {#each subMenuItems as subMenuItem}
55
+ {#each subMenuItems as subMenuItem, index (index)}
55
56
  <section class="category-content">
56
- <h2 class="category-span" class:hidden={isCollapsed}>{subMenuItem.category}</h2>
57
+ <h2 class="category-span" class:hidden={isCollapsed}>
58
+ {subMenuItem.category}
59
+ </h2>
57
60
  <menu class="category-items-details">
58
61
  {#if subMenuItem.menuItems}
59
- {#each subMenuItem.menuItems as menuItem}
62
+ {#each subMenuItem.menuItems as menuItem, index (index)}
60
63
  <SidebarMenuItem
61
64
  item={menuItem}
62
65
  {isCollapsed}
@@ -7,6 +7,7 @@
7
7
  import type { ModalProps } from './modalState.svelte.js';
8
8
 
9
9
  let {
10
+ // eslint-disable-next-line no-useless-assignment
10
11
  showModal = $bindable(false),
11
12
  title,
12
13
  width = 'xs',
@@ -17,7 +17,8 @@
17
17
  {/if}
18
18
  <h2>{title}</h2>
19
19
  </div>
20
- <button type="button" class="close-button material-icons-outlined" onclick={onclose}>close</button
20
+ <button type="button" class="close-button material-icons-outlined" onclick={onclose}
21
+ >close</button
21
22
  >
22
23
  </header>
23
24
  {/if}
@@ -27,7 +27,9 @@
27
27
  <stop offset="100%" stop-color="#000000" />
28
28
  </linearGradient>
29
29
  </defs>
30
- <path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2" />
30
+ <path
31
+ d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"
32
+ />
31
33
  </svg>
32
34
  <div class="processing-content">
33
35
  <h2 class="processing-title">{title}</h2>
@@ -65,7 +65,7 @@
65
65
  <div class="progress-wizard">
66
66
  <section class="progress-wizard-container">
67
67
  <ol class={['progress-wizard-steps', readonly ? 'readonly' : 'editing-mode']}>
68
- {#each steps as step, index}
68
+ {#each steps as step, index (index)}
69
69
  {@const stepIndex = index + 1}
70
70
  {@const isActive = stepIndex === currentStep}
71
71
  {@const isPreviousStep = currentStep > stepIndex}
@@ -2,7 +2,7 @@ import { getContext, setContext } from 'svelte';
2
2
  import { writable } from 'svelte/store';
3
3
  const stepsKey = Symbol('steps');
4
4
  export const setProgressWizardStepsContext = (steps) => {
5
- const stepsContext = writable(steps.map(step => ({ ...step })));
5
+ const stepsContext = writable(steps.map((step) => ({ ...step })));
6
6
  setContext(stepsKey, stepsContext);
7
7
  return stepsContext;
8
8
  };
@@ -56,7 +56,12 @@
56
56
  />
57
57
 
58
58
  {#if hasValue && !disabled}
59
- <button type="button" class="clear-button" onclick={handleClear} aria-label="Clear search">
59
+ <button
60
+ type="button"
61
+ class="clear-button"
62
+ onclick={handleClear}
63
+ aria-label="Clear search"
64
+ >
60
65
  <span class="material-icons-outlined" aria-hidden="true">close</span>
61
66
  </button>
62
67
  {/if}
@@ -12,12 +12,14 @@
12
12
  typeof items[0] === 'string';
13
13
 
14
14
  const originalOptions = $derived<SwitcherOption[]>(
15
- isStringArray(options) ? options.map((option) => ({ label: option, value: option })) : options
15
+ isStringArray(options)
16
+ ? options.map((option) => ({ label: option, value: option }))
17
+ : options
16
18
  );
17
19
  </script>
18
20
 
19
21
  <div class="switcher-container">
20
- {#each originalOptions as option}
22
+ {#each originalOptions as option, index (index)}
21
23
  <button
22
24
  type="button"
23
25
  class={['switcher-option', option.value === value && 'active']}
@@ -32,7 +32,9 @@
32
32
  const showAbove = rect.bottom + element.offsetHeight > window.innerHeight;
33
33
 
34
34
  const left = rect.left + rect.width / 2 - element.offsetWidth / 2;
35
- const top = showAbove ? rect.top - element.offsetHeight + MENU_GAP : rect.bottom + MENU_GAP;
35
+ const top = showAbove
36
+ ? rect.top - element.offsetHeight + MENU_GAP
37
+ : rect.bottom + MENU_GAP;
36
38
 
37
39
  element.style.setProperty('--menu-left', `${Math.max(0, left)}px`);
38
40
  element.style.setProperty('--menu-top', `${top}px`);
@@ -77,15 +79,20 @@
77
79
  >
78
80
  <span class="actions-trigger">...</span>
79
81
  {#if isOpen}
80
- <div class="actions-menu" {@attach autoPosition} transition:fade={{ duration: 100 }}>
82
+ <div
83
+ class="actions-menu"
84
+ {@attach autoPosition}
85
+ transition:fade={{ duration: 100 }}
86
+ >
81
87
  <ul class="actions-list">
82
- {#each actions as action, index}
88
+ {#each actions as action, index (index)}
83
89
  <li>
84
90
  <button
85
91
  type="button"
86
92
  onclick={action.onClick}
87
93
  class="action-button"
88
- class:action-button--delete={action.isDelete && action.isEnabled}
94
+ class:action-button--delete={action.isDelete &&
95
+ action.isEnabled}
89
96
  disabled={!action.isEnabled}
90
97
  >
91
98
  <span>{action.name}</span>
@@ -58,7 +58,11 @@
58
58
 
59
59
  const toggleModal = () => {
60
60
  isOpen = !isOpen;
61
- isOpen ? initializeEditingFilters() : clearFilters();
61
+ if (isOpen) {
62
+ initializeEditingFilters();
63
+ } else {
64
+ clearFilters();
65
+ }
62
66
  };
63
67
 
64
68
  const initializeEditingFilters = () => {
@@ -112,7 +116,12 @@
112
116
  >
113
117
  <div class="filter-header">
114
118
  <h2 id="filter-dialog-title" class="filter-title">Filters</h2>
115
- <button type="button" onclick={toggleModal} class="filter-close-button" aria-label="Close">
119
+ <button
120
+ type="button"
121
+ onclick={toggleModal}
122
+ class="filter-close-button"
123
+ aria-label="Close"
124
+ >
116
125
  <span class="material-icons">close</span>
117
126
  </button>
118
127
  </div>
@@ -165,7 +174,9 @@
165
174
  {/each}
166
175
 
167
176
  <div class="filter-actions">
168
- <Button variant="outline-none" type="button" onclick={addFilterRow}>Add condition</Button>
177
+ <Button variant="outline-none" type="button" onclick={addFilterRow}
178
+ >Add condition</Button
179
+ >
169
180
  {#if editingFilters.length}
170
181
  <Button variant="outline-none" type="button" onclick={clearAllFilters}>
171
182
  Reset filters
@@ -179,7 +190,9 @@
179
190
  <Button
180
191
  type="button"
181
192
  onclick={applyFilters}
182
- disabled={editingFilters.every((filter) => !filter.column || !filter.value.trim())}
193
+ disabled={editingFilters.every(
194
+ (filter) => !filter.column || !filter.value.trim()
195
+ )}
183
196
  >
184
197
  Apply Filters
185
198
  </Button>
@@ -31,7 +31,7 @@
31
31
  ]}
32
32
  onclick={enableChecked ? (event) => handleRowClick(row, event.target) : undefined}
33
33
  >
34
- {#each row.getVisibleCells() as cell}
34
+ {#each row.getVisibleCells() as cell (cell.id)}
35
35
  {@const alignColumn = cell.column.columnDef.meta?.alignColumn}
36
36
  {@const columnWidth = cell.column.columnDef.meta?.columnWidth}
37
37
  {@const columnStyle = cell.column.columnDef.meta?.style}
@@ -30,9 +30,10 @@
30
30
  </div>
31
31
 
32
32
  <div class="column-visibility-list">
33
- {#each columns as column}
33
+ {#each columns as column (column.id)}
34
34
  {@const columnDef = column.columnDef}
35
- {@const header = typeof columnDef.header === 'string' ? columnDef.header : column.id}
35
+ {@const header =
36
+ typeof columnDef.header === 'string' ? columnDef.header : column.id}
36
37
 
37
38
  <label class="column-visibility-item">
38
39
  <input
@@ -28,7 +28,7 @@
28
28
  <thead class="container">
29
29
  {#each headerGroups as headerGroup (headerGroup.id)}
30
30
  <tr class="table-header-row">
31
- {#each headerGroup.headers as header}
31
+ {#each headerGroup.headers as header (header.id)}
32
32
  {@const alignColumn = header.column.columnDef.meta?.alignColumn}
33
33
  {@const className = header.column.columnDef.meta?.className}
34
34
  {@const columnWidth = header.column.columnDef.meta?.columnWidth}
@@ -40,7 +40,11 @@
40
40
  {@const isActive = isSorted || isFiltered}
41
41
  <th
42
42
  colSpan={header.colSpan}
43
- class={['table-header-cell', className, isActive && 'table-header-cell--active']}
43
+ class={[
44
+ 'table-header-cell',
45
+ className,
46
+ isActive && 'table-header-cell--active'
47
+ ]}
44
48
  style:width={columnWidth}
45
49
  style={columnStyle}
46
50
  >
@@ -58,7 +62,10 @@
58
62
  style:justify-content={justifyContent}
59
63
  onclick={header.column.getToggleSortingHandler()}
60
64
  >
61
- <span class="table-header-label" class:table-header-label--sortable={canSort}>
65
+ <span
66
+ class="table-header-label"
67
+ class:table-header-label--sortable={canSort}
68
+ >
62
69
  <FlexRender
63
70
  content={header.column.columnDef.header}
64
71
  context={header.getContext()}
@@ -83,7 +90,8 @@
83
90
  {#if enableColumnSearch && !hideColumnFilter}
84
91
  <div class="table-header-search" style:justify-content={justifyContent}>
85
92
  <Search
86
- oninput={({ currentTarget }) => header.column.setFilterValue(currentTarget.value)}
93
+ oninput={({ currentTarget }) =>
94
+ header.column.setFilterValue(currentTarget.value)}
87
95
  onclear={() => header.column.setFilterValue('')}
88
96
  disabled={!header.column.getCanFilter()}
89
97
  />
@@ -42,7 +42,7 @@
42
42
  table.setPageSize(Number(e.currentTarget.value));
43
43
  }}
44
44
  >
45
- {#each DEFAULT_ITEMS_PER_PAGE_OPTIONS as itemPerPage}
45
+ {#each DEFAULT_ITEMS_PER_PAGE_OPTIONS as itemPerPage (itemPerPage)}
46
46
  <option class="page-size-option" value={itemPerPage}>{itemPerPage}</option>
47
47
  {/each}
48
48
  </select>
@@ -11,7 +11,7 @@
11
11
  <table class="table-skeleton-table">
12
12
  <thead>
13
13
  <tr>
14
- {#each Array(columns) as _}
14
+ {#each Array(columns).keys() as index (index)}
15
15
  <th class="table-skeleton-header">
16
16
  <div class="table-skeleton-header-placeholder"></div>
17
17
  </th>
@@ -19,9 +19,9 @@
19
19
  </tr>
20
20
  </thead>
21
21
  <tbody>
22
- {#each Array(rows) as _}
22
+ {#each Array(rows).keys() as index (index)}
23
23
  <tr>
24
- {#each Array(columns) as _}
24
+ {#each Array(columns).keys() as index (index)}
25
25
  <td class="table-skeleton-cell">
26
26
  <div class="table-skeleton-cell-placeholder"></div>
27
27
  </td>
@@ -33,7 +33,6 @@
33
33
  </section>
34
34
 
35
35
  <style>
36
-
37
36
  .table-skeleton {
38
37
  --color-black: #000;
39
38
  --color-gray-300: #d1d5db;
@@ -1,4 +1,4 @@
1
- <script lang="ts" generics="T">
1
+ <script lang="ts" generics="T extends object">
2
2
  import { goto } from '$app/navigation';
3
3
  import { page } from '$app/state';
4
4
  import { type Snippet } from 'svelte';
@@ -159,7 +159,7 @@
159
159
  getFilteredRowModel: getFilteredRowModel(),
160
160
  getSortedRowModel: getSortedRowModel(),
161
161
  getExpandedRowModel: getExpandedRowModel(),
162
- getSubRows: (row) => (row as any)?.children,
162
+ getSubRows: (row) => ('children' in row ? (row.children as T[]) : undefined),
163
163
  manualPagination,
164
164
  paginateExpandedRows: false,
165
165
  enableColumnFilters: true,
@@ -259,7 +259,9 @@
259
259
  </div>
260
260
  {#if enableAdvancedFilter}
261
261
  <AdvancedFilter
262
- columns={table.getAllLeafColumns().filter((column) => column.getCanHide())}
262
+ columns={table
263
+ .getAllLeafColumns()
264
+ .filter((column) => column.getCanHide())}
263
265
  onfilterschange={changeFilters}
264
266
  />
265
267
  {/if}
@@ -270,7 +272,9 @@
270
272
  <div class="table-actions">
271
273
  {#if enableColumnVisibility}
272
274
  <ColumnVisibilityDropdown
273
- columns={table.getAllLeafColumns().filter((column) => column.getCanHide())}
275
+ columns={table
276
+ .getAllLeafColumns()
277
+ .filter((column) => column.getCanHide())}
274
278
  />
275
279
  {/if}
276
280
  {#if enableExportExcel}
@@ -2,7 +2,7 @@ import { type Snippet } from 'svelte';
2
2
  import { type ColumnDef } from './adapter/index.js';
3
3
  import type { ExcelSetting } from './excel-setting.js';
4
4
  import { type Pagination } from './types.js';
5
- declare function $$render<T>(): {
5
+ declare function $$render<T extends object>(): {
6
6
  props: {
7
7
  columns: ColumnDef<T, any>[];
8
8
  isLoading?: boolean;
@@ -28,7 +28,7 @@ declare function $$render<T>(): {
28
28
  slots: {};
29
29
  events: {};
30
30
  };
31
- declare class __sveltets_Render<T> {
31
+ declare class __sveltets_Render<T extends object> {
32
32
  props(): ReturnType<typeof $$render<T>>['props'];
33
33
  events(): ReturnType<typeof $$render<T>>['events'];
34
34
  slots(): ReturnType<typeof $$render<T>>['slots'];
@@ -36,12 +36,12 @@ declare class __sveltets_Render<T> {
36
36
  exports(): {};
37
37
  }
38
38
  interface $$IsomorphicComponent {
39
- new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
39
+ new <T extends object>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
40
40
  $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
41
41
  } & ReturnType<__sveltets_Render<T>['exports']>;
42
- <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
42
+ <T extends object>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
43
43
  z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
44
44
  }
45
45
  declare const Table: $$IsomorphicComponent;
46
- type Table<T> = InstanceType<typeof Table<T>>;
46
+ type Table<T extends object> = InstanceType<typeof Table<T>>;
47
47
  export default Table;
@@ -1,40 +1,33 @@
1
1
  <script
2
- lang="ts"
3
- generics="TData, TValue, TContext extends HeaderContext<TData, TValue> | CellContext<TData, TValue>"
2
+ lang="ts"
3
+ generics="TData, TValue, TContext extends HeaderContext<TData, TValue> | CellContext<TData, TValue>"
4
4
  >
5
- import type {
6
- CellContext,
7
- ColumnDefTemplate,
8
- HeaderContext,
9
- } from "@tanstack/table-core";
10
- import {
11
- RenderComponentConfig,
12
- RenderSnippetConfig,
13
- } from "./render-component.js";
5
+ import type { CellContext, ColumnDefTemplate, HeaderContext } from '@tanstack/table-core';
6
+ import { RenderComponentConfig, RenderSnippetConfig } from './render-component.js';
14
7
 
15
- type Props = {
16
- content?: TContext extends HeaderContext<TData, TValue>
17
- ? ColumnDefTemplate<HeaderContext<TData, TValue>>
18
- : TContext extends CellContext<TData, TValue>
19
- ? ColumnDefTemplate<CellContext<TData, TValue>>
20
- : never;
21
- context: TContext;
22
- };
8
+ type Props = {
9
+ content?: TContext extends HeaderContext<TData, TValue>
10
+ ? ColumnDefTemplate<HeaderContext<TData, TValue>>
11
+ : TContext extends CellContext<TData, TValue>
12
+ ? ColumnDefTemplate<CellContext<TData, TValue>>
13
+ : never;
14
+ context: TContext;
15
+ };
23
16
 
24
- let { content, context }: Props = $props();
17
+ let { content, context }: Props = $props();
25
18
  </script>
26
19
 
27
- {#if typeof content === "string"}
28
- {content}
20
+ {#if typeof content === 'string'}
21
+ {content}
29
22
  {:else if content instanceof Function}
30
- {@const result = content(context as any)}
31
- {#if result instanceof RenderComponentConfig}
32
- {@const { component: Component, props } = result}
33
- <Component {...props} />
34
- {:else if result instanceof RenderSnippetConfig}
35
- {@const { snippet, params } = result}
36
- {@render snippet(params)}
37
- {:else}
38
- {result}
39
- {/if}
23
+ {@const result = content(context as any)}
24
+ {#if result instanceof RenderComponentConfig}
25
+ {@const { component: Component, props } = result}
26
+ <Component {...props} />
27
+ {:else if result instanceof RenderSnippetConfig}
28
+ {@const { snippet, params } = result}
29
+ {@render snippet(params)}
30
+ {:else}
31
+ {result}
32
+ {/if}
40
33
  {/if}
@@ -1,4 +1,4 @@
1
- import type { CellContext, ColumnDefTemplate, HeaderContext } from "@tanstack/table-core";
1
+ import type { CellContext, ColumnDefTemplate, HeaderContext } from '@tanstack/table-core';
2
2
  declare function $$render<TData, TValue, TContext extends HeaderContext<TData, TValue> | CellContext<TData, TValue>>(): {
3
3
  props: {
4
4
  content?: TContext extends HeaderContext<TData, TValue> ? ColumnDefTemplate<HeaderContext<TData, TValue>> : TContext extends CellContext<TData, TValue> ? ColumnDefTemplate<CellContext<TData, TValue>> : never;
@@ -1,4 +1,4 @@
1
- import type { Component, ComponentProps, Snippet } from "svelte";
1
+ import type { Component, ComponentProps, Snippet } from 'svelte';
2
2
  export declare class RenderComponentConfig<TComponent extends Component> {
3
3
  component: TComponent;
4
4
  props: ComponentProps<TComponent> | Record<string, never>;
@@ -1,4 +1,4 @@
1
- import { type RowData, type Table, type TableOptions } from "@tanstack/table-core";
1
+ import { type RowData, type Table, type TableOptions } from '@tanstack/table-core';
2
2
  export declare function createSvelteTable<TData extends RowData>(options: TableOptions<TData>): Table<TData>;
3
3
  export declare function mergeObjects<T>(source: T): T;
4
4
  export declare function mergeObjects<T, U>(source: T, source1: U): T & U;
@@ -1,4 +1,4 @@
1
- import { createTable, } from "@tanstack/table-core";
1
+ import { createTable } from '@tanstack/table-core';
2
2
  export function createSvelteTable(options) {
3
3
  const resolvedOptions = mergeObjects(createDefaultOptions(), options);
4
4
  const table = createTable(resolvedOptions);
@@ -15,7 +15,7 @@ export function createSvelteTable(options) {
15
15
  state = mergeObjects(state, updater);
16
16
  }
17
17
  options.onStateChange?.(updater);
18
- },
18
+ }
19
19
  });
20
20
  });
21
21
  }
@@ -32,14 +32,14 @@ function createDefaultOptions() {
32
32
  renderFallbackValue: null,
33
33
  mergeOptions: (defaultOptions, options) => {
34
34
  return mergeObjects(defaultOptions, options);
35
- },
35
+ }
36
36
  };
37
37
  }
38
38
  export function mergeObjects(...sources) {
39
39
  const target = {};
40
40
  for (let i = 0; i < sources.length; i++) {
41
41
  let source = sources[i];
42
- if (typeof source === "function")
42
+ if (typeof source === 'function')
43
43
  source = source();
44
44
  if (source) {
45
45
  const descriptors = Object.getOwnPropertyDescriptors(source);
@@ -51,13 +51,13 @@ export function mergeObjects(...sources) {
51
51
  get() {
52
52
  for (let i = sources.length - 1; i >= 0; i--) {
53
53
  let s = sources[i];
54
- if (typeof s === "function")
54
+ if (typeof s === 'function')
55
55
  s = s();
56
56
  const v = (s || {})[key];
57
57
  if (v !== undefined)
58
58
  return v;
59
59
  }
60
- },
60
+ }
61
61
  });
62
62
  }
63
63
  }
@@ -10,5 +10,5 @@ export declare const Operation: {
10
10
  export declare const Operator: {
11
11
  readonly Eq: "eq";
12
12
  };
13
- export type Operation = typeof Operation[keyof typeof Operation];
14
- export type Operator = typeof Operator[keyof typeof Operator];
13
+ export type Operation = (typeof Operation)[keyof typeof Operation];
14
+ export type Operator = (typeof Operator)[keyof typeof Operator];
@@ -6,4 +6,4 @@ export interface ExcelSetting {
6
6
  export declare const ColumnFormat: {
7
7
  readonly NUMBER: "#,##0.00";
8
8
  };
9
- export type ColumnFormat = typeof ColumnFormat[keyof typeof ColumnFormat];
9
+ export type ColumnFormat = (typeof ColumnFormat)[keyof typeof ColumnFormat];
@@ -1,3 +1,4 @@
1
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
1
2
  /// <reference path="./tanstack-types.d.ts" />
2
3
  import ExcelJS from 'exceljs';
3
4
  import saveAs from 'file-saver';
@@ -1,9 +1,10 @@
1
1
  import '@tanstack/table-core';
2
- import { RowData } from "@tanstack/table-core";
2
+ import { RowData } from '@tanstack/table-core';
3
3
 
4
4
  import { ColumnFormat } from './excel-setting.ts';
5
5
 
6
6
  declare module '@tanstack/table-core' {
7
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
7
8
  interface ColumnMeta<TData extends RowData, TValue> {
8
9
  alignColumn?: 'left' | 'right' | 'center';
9
10
  className?: string;
@@ -1,4 +1,4 @@
1
- import { Operation } from "./consts.js";
1
+ import { Operation } from './consts.js';
2
2
  export interface Action {
3
3
  name: string;
4
4
  isEnabled: boolean;
@@ -1 +1 @@
1
- import { Operation } from "./consts.js";
1
+ import { Operation } from './consts.js';
@@ -20,7 +20,7 @@
20
20
 
21
21
  <div class="tabs-container">
22
22
  <div class="tabs-list" role="tablist" aria-label="tabs">
23
- {#each tabs as tab}
23
+ {#each tabs as tab (tab.index)}
24
24
  {#if !tab.hidden}
25
25
  {@const isActiveTab = activeTab === tab.index}
26
26
  <button
@@ -39,7 +39,7 @@
39
39
  {/each}
40
40
  </div>
41
41
 
42
- {#each tabs as tab}
42
+ {#each tabs as tab, index (index)}
43
43
  {#if activeTab === tab.index}
44
44
  <div
45
45
  class={['tabs-content', !tab.disablePadding && 'padding']}
@@ -24,14 +24,16 @@
24
24
 
25
25
  {#if toastNotifications.toasts.length > 0}
26
26
  <div class="toast-container" in:fly={transitionConfig} out:fly={transitionConfig}>
27
- {#each toastNotifications.toasts as toast}
27
+ {#each toastNotifications.toasts as toast (toast.id)}
28
28
  <div class="toast" in:fly={transitionConfig} out:fly={transitionConfig}>
29
29
  <span class="status-indicator {toast.type}"></span>
30
30
  <div class="toast-content-container">
31
31
  <div class="toast-content">
32
32
  <span>{toast.message}</span>
33
33
  {#if toast.link}
34
- <a class="toast-content-link" href={toast.link} title="View details">View details</a>
34
+ <a class="toast-content-link" href={toast.link} title="View details"
35
+ >View details</a
36
+ >
35
37
  {/if}
36
38
  </div>
37
39
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softwareone/spi-sv5-library",
3
- "version": "1.12.3",
3
+ "version": "1.12.4",
4
4
  "description": "Svelte components",
5
5
  "keywords": [
6
6
  "svelte",
@@ -21,7 +21,7 @@
21
21
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
22
22
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
23
23
  "format": "prettier --write .",
24
- "lint": "prettier --check ."
24
+ "lint": "prettier --check . && eslint ."
25
25
  },
26
26
  "files": [
27
27
  "dist",
@@ -74,6 +74,8 @@
74
74
  }
75
75
  },
76
76
  "devDependencies": {
77
+ "@eslint/compat": "^2.0.3",
78
+ "@eslint/js": "^10.0.1",
77
79
  "@sveltejs/adapter-auto": "^7.0.1",
78
80
  "@sveltejs/adapter-node": "^5.5.4",
79
81
  "@sveltejs/kit": "^2.55.0",
@@ -81,6 +83,9 @@
81
83
  "@sveltejs/vite-plugin-svelte": "^6.2.4",
82
84
  "@tanstack/table-core": "^8.21.3",
83
85
  "@types/file-saver": "^2.0.7",
86
+ "eslint": "^10.1.0",
87
+ "eslint-config-prettier": "^10.1.8",
88
+ "eslint-plugin-svelte": "^3.16.0",
84
89
  "exceljs": "^4.4.0",
85
90
  "file-saver": "^2.0.5",
86
91
  "prettier": "^3.8.1",
@@ -90,6 +95,7 @@
90
95
  "svelte-check": "^4.4.5",
91
96
  "sveltekit-superforms": "^2.30.0",
92
97
  "typescript": "^5.9.3",
98
+ "typescript-eslint": "^8.57.2",
93
99
  "vite": "^7.3.1",
94
100
  "zod": "^4.3.6"
95
101
  },