svelte-infinite 0.1.0 → 0.1.2
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.
- package/LICENSE +0 -0
- package/README.md +101 -33
- package/dist/InfiniteLoader.svelte +69 -52
- package/dist/InfiniteLoader.svelte.d.ts +1 -0
- package/package.json +44 -41
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -1,49 +1,84 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img align="center" src="https://raw.githubusercontent.com/ndom91/svelte-infinite/51683d459ae954a99e7c5c25817ed667678a0840/src/assets/SvelteLogo.svg" height="96" />
|
|
3
|
+
<h1 align="center">
|
|
4
|
+
Svelte Infinite
|
|
5
|
+
</h1>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+

|
|
10
|
+
[](https://npmjs.org/packages/svelte-infinite)
|
|
11
|
+
[](https://npmjs.org/packages/svelte-infinite)
|
|
12
|
+
[](https://npmjs.org/packages/svelte-infinite)
|
|
13
|
+
[](https://svelte-5-infinite.vercel.app)
|
|
14
|
+
|
|
15
|
+
> Svelte Infinite Loader designed and rebuilt specifically for use in **Svelte 5** with runes
|
|
16
|
+
|
|
17
|
+
✨ Flexible
|
|
18
|
+
⏰ Infinite Loop Detection
|
|
19
|
+
📣 Control Loader State
|
|
20
|
+
🔎 `IntersectionObserver` based
|
|
21
|
+
🧑🔧 **Demo**: [svelte-5-infinite.vercel.app](https://svelte-5-infinite.vercel.app)
|
|
14
22
|
|
|
15
23
|
## 🏗️ Getting Started
|
|
16
24
|
|
|
17
25
|
1. Install `svelte-infinite`
|
|
18
26
|
|
|
19
27
|
```bash
|
|
28
|
+
npm install svelte-infinite
|
|
20
29
|
pnpm install svelte-infinite
|
|
30
|
+
yarn add svelte-infinite
|
|
21
31
|
```
|
|
22
32
|
|
|
23
33
|
2. Import both `InfiniteLoader` and `stateChanger` from `svelte-infinite`
|
|
24
34
|
|
|
25
|
-
|
|
35
|
+
```svelte
|
|
36
|
+
<script lang="ts">
|
|
37
|
+
import { InfiniteLoader, stateChanger } from "svelte-infinite"
|
|
38
|
+
|
|
39
|
+
const allItems = $state([])
|
|
40
|
+
|
|
41
|
+
const loadMore = async () => {
|
|
42
|
+
const res = fetch("...")
|
|
43
|
+
const data = await jes.json()
|
|
44
|
+
allItems.push(...data)
|
|
45
|
+
stateChanger.loaded()
|
|
46
|
+
}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<InfiniteLoader triggerLoad={loadMore}>
|
|
50
|
+
{#each allItems as user (user.id)}
|
|
51
|
+
<div>{user.name}</div>
|
|
52
|
+
{/each}
|
|
53
|
+
</InfiniteLoader>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The component should wrap your list of items, and `stateChanger` should be used in your `triggerLoad` function (and/or elsewhere) to interact with the internal state of the Loader component. You tell it whether you're out of data, ran into an error, etc.
|
|
26
57
|
|
|
27
|
-
|
|
58
|
+
See the example below and [in this repository](https://github.com/ndom91/svelte-infinite/blob/main/src/routes/%2Bpage.svelte#L12-L50) for more details.
|
|
59
|
+
|
|
60
|
+
## 🍍 Example
|
|
28
61
|
|
|
29
62
|
```svelte
|
|
30
63
|
<script lang="ts">
|
|
31
64
|
import { InfiniteLoader, stateChanger } from "svelte-infinite"
|
|
65
|
+
import UserCard from "$components/UserCard.svelte"
|
|
32
66
|
|
|
33
67
|
const LOAD_LIMIT = 20
|
|
34
|
-
const allItems = $state<number[]>($page.data.items)
|
|
68
|
+
const allItems = $state<{ id: number, body: string }[]>($page.data.items)
|
|
35
69
|
let pageNumber = $state(1)
|
|
36
70
|
|
|
37
71
|
// 1. You'll have to pass the InfiniteLoader component a load function
|
|
38
72
|
// to its `triggerLoad` prop.
|
|
39
73
|
const loadMore = async () => {
|
|
74
|
+
// This is a relatively straight-forward load function with support for pagination
|
|
40
75
|
try {
|
|
41
76
|
pageNumber += 1
|
|
42
|
-
const limit = LOAD_LIMIT
|
|
43
|
-
const skip = LOAD_LIMIT * (pageNumber - 1)
|
|
77
|
+
const limit = String(LOAD_LIMIT)
|
|
78
|
+
const skip = String(LOAD_LIMIT * (pageNumber - 1))
|
|
44
79
|
|
|
45
|
-
// If there are less results on the first page
|
|
46
|
-
// don't keep trying to fetch more. We're done.
|
|
80
|
+
// If there are less results on the first page (page.server loaded data)
|
|
81
|
+
// than the limit, don't keep trying to fetch more. We're done.
|
|
47
82
|
if (allItems.length < LOAD_LIMIT) {
|
|
48
83
|
stateChanger.complete()
|
|
49
84
|
return
|
|
@@ -51,20 +86,28 @@ pnpm install svelte-infinite
|
|
|
51
86
|
|
|
52
87
|
const searchParams = new URLSearchParams({ limit, skip })
|
|
53
88
|
|
|
89
|
+
// Execute the API call to grab more data
|
|
54
90
|
const dataResponse = await fetch(`/api/data?${searchParams}`)
|
|
55
91
|
|
|
92
|
+
// Ideally, like most paginated endpoints, this should return the data
|
|
93
|
+
// you've requested for your page, as well as the total amount of data
|
|
94
|
+
// available to page through
|
|
95
|
+
|
|
56
96
|
if (!dataResponse.ok) {
|
|
57
97
|
stateChanger.error()
|
|
98
|
+
pageNumber -= 1
|
|
58
99
|
return
|
|
59
100
|
}
|
|
60
101
|
const data = await dataResponse.json()
|
|
61
102
|
|
|
103
|
+
// If we've received data, push it to the reactive state variable
|
|
104
|
+
// rendering our items inside the `<InfiniteLoader />` below.
|
|
62
105
|
if (data.items.length) {
|
|
63
106
|
allItems.push(...data.items)
|
|
64
107
|
}
|
|
65
108
|
|
|
66
|
-
//
|
|
67
|
-
// don't keep trying to fetch more. We're done.
|
|
109
|
+
// If there are more (or equal) number of items loaded as are totally available
|
|
110
|
+
// from the API, don't keep trying to fetch more. We're done.
|
|
68
111
|
if (allItems.length >= data.totalCount) {
|
|
69
112
|
stateChanger.complete()
|
|
70
113
|
} else {
|
|
@@ -73,6 +116,7 @@ pnpm install svelte-infinite
|
|
|
73
116
|
} catch (error) {
|
|
74
117
|
console.error(error)
|
|
75
118
|
stateChanger.error()
|
|
119
|
+
pageNumber -= 1
|
|
76
120
|
}
|
|
77
121
|
}
|
|
78
122
|
</script>
|
|
@@ -85,6 +129,11 @@ pnpm install svelte-infinite
|
|
|
85
129
|
{#each allItems as user (user.id)}
|
|
86
130
|
<UserCard {user} />
|
|
87
131
|
{/each}
|
|
132
|
+
|
|
133
|
+
<!-- There are a few optional slots for customizing what is shown at the bottom
|
|
134
|
+
of the scroller in various states, see README.md for more details -->
|
|
135
|
+
<div slot="loading">Loading...</div>
|
|
136
|
+
<div slot="no-data">Thats it, no more users left!</div>
|
|
88
137
|
</InfiniteLoader>
|
|
89
138
|
</main>
|
|
90
139
|
|
|
@@ -101,23 +150,42 @@ However, there is also a `stateChanger` export which you should use to interact
|
|
|
101
150
|
|
|
102
151
|
The `stateChanger` import is an object with 4 methods on it:
|
|
103
152
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
153
|
+
- `stateChanger.loaded()`
|
|
154
|
+
- Designed to be called after a successful fetch.
|
|
155
|
+
- `stateChanger.error()`
|
|
156
|
+
- Designed to be called after a failed fetch or any other error. This will cause the `InfiniteLoader` to render a "Retry" button by default, or the `error` slot.
|
|
157
|
+
- `stateChanger.complete()`
|
|
158
|
+
- Designed to be called when you've reached the end of your list and there are no more items to fetch. This will render a "No more data" string, or the `no-data` slot.
|
|
159
|
+
- `stateChanger.reset()`
|
|
160
|
+
- Designed to be called when you want to reset the state of the `InfiniteLoader` to its initial state, for example if there is a search input tied to your infinite list and the user enters a new query.
|
|
108
161
|
|
|
109
162
|
### Props
|
|
110
163
|
|
|
111
|
-
- `triggerLoad: () => Promise<void>` - **required**
|
|
112
|
-
-
|
|
113
|
-
- `
|
|
164
|
+
- `triggerLoad: () => Promise<void>` - **required**
|
|
165
|
+
- The async function to call when we should attempt to load more data to show.
|
|
166
|
+
- `intersectionOptions` - optional
|
|
167
|
+
- The options to pass to the `IntersectionObserver` instance. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver#options) for more details. Default is `{ rootMargin: "0px 0px 200px 0px" }`, making it trigger the `loadMore` function 200px before it actually intersects with the root element (window by default). This has the effect of beginning to load the next page of data before the user has actually reached the bottom of the list, making the experience feel more smooth.
|
|
168
|
+
- It may also be required to pass in a reference to your scroll container as the `root` option, if your scroll container is not the window.
|
|
169
|
+
- `loopTimeout: number = 1000` - optional
|
|
170
|
+
- If the `loopMaxCalls` is reached within this duration (in milliseconds), a cool down period is triggered.
|
|
171
|
+
- `loopMaxCalls: number = 5` - optional
|
|
172
|
+
- The number of calls to the `triggerLoad` function within timeout which should trigger cool down period.
|
|
114
173
|
|
|
115
174
|
### Slots
|
|
116
175
|
|
|
117
|
-
- `loading`
|
|
118
|
-
-
|
|
119
|
-
- `no-
|
|
120
|
-
-
|
|
176
|
+
- `loading`
|
|
177
|
+
- Shown while calling `triggerLoad` and waiting on a response.
|
|
178
|
+
- `no-results`
|
|
179
|
+
- Shown when there are no more results to display and we haven't fetched any data yet (i.e. data is less than count of items to be shown on first "page").
|
|
180
|
+
- `no-data`
|
|
181
|
+
- Shown when `stateChanger.complete()` is called, indicating we've fetched and displayed all available data.
|
|
182
|
+
- `error`
|
|
183
|
+
- Shown when there is an error or `stateChanger.error()` has been called. The slot has an `attemptLoad` prop passed to it which is just the internal `triggerLoad` function, designed for a "Retry" button or similar.
|
|
184
|
+
|
|
185
|
+
## 📦 Contributing
|
|
186
|
+
|
|
187
|
+
- Initially inspired by [jonasgeiler/svelte-infinite-loading](https://github.com/jonasgeiler/svelte-infinite-loading)
|
|
188
|
+
- Open to contributions, issues, and feedback 🙏
|
|
121
189
|
|
|
122
190
|
## 📝 License
|
|
123
191
|
|
|
@@ -25,7 +25,13 @@ export const stateChanger = {
|
|
|
25
25
|
};
|
|
26
26
|
</script>
|
|
27
27
|
|
|
28
|
-
<script>
|
|
28
|
+
<script>import { onDestroy } from "svelte";
|
|
29
|
+
const {
|
|
30
|
+
triggerLoad,
|
|
31
|
+
loopTimeout = 1e3,
|
|
32
|
+
loopMaxCalls = 5,
|
|
33
|
+
intersectionOptions = {}
|
|
34
|
+
} = $props();
|
|
29
35
|
const ERROR_INFINITE_LOOP = `Executed load function ${loopMaxCalls} or more times within a short period. Cooling off..`;
|
|
30
36
|
class LoopTracker {
|
|
31
37
|
coolingOff = false;
|
|
@@ -67,105 +73,116 @@ async function attemptLoad() {
|
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
$effect(() => {
|
|
70
|
-
if (!
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
);
|
|
80
|
-
observer.observe(intersectionTarget);
|
|
81
|
-
return observer;
|
|
76
|
+
if (observer || !intersectionTarget)
|
|
77
|
+
return;
|
|
78
|
+
const appliedIntersectionOptions = {
|
|
79
|
+
rootMargin: "0px 0px 200px 0px",
|
|
80
|
+
...intersectionOptions
|
|
81
|
+
};
|
|
82
|
+
observer = new IntersectionObserver((entries) => {
|
|
83
|
+
if (entries[0]?.isIntersecting) {
|
|
84
|
+
attemptLoad();
|
|
82
85
|
}
|
|
86
|
+
}, appliedIntersectionOptions);
|
|
87
|
+
observer.observe(intersectionTarget);
|
|
88
|
+
});
|
|
89
|
+
onDestroy(() => {
|
|
90
|
+
if (observer) {
|
|
91
|
+
observer.disconnect();
|
|
83
92
|
}
|
|
84
|
-
return () => observer?.disconnect();
|
|
85
93
|
});
|
|
86
94
|
</script>
|
|
87
95
|
|
|
88
|
-
<div class="loader-wrapper">
|
|
96
|
+
<div class="infinite-loader-wrapper">
|
|
89
97
|
<slot />
|
|
90
98
|
|
|
91
|
-
{
|
|
92
|
-
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
{#if showNoResults}
|
|
98
|
-
<slot name="no-results">
|
|
99
|
-
<div class="no-results">No results</div>
|
|
100
|
-
</slot>
|
|
101
|
-
{/if}
|
|
99
|
+
<div class="infinite-intersection-target" bind:this={intersectionTarget}>
|
|
100
|
+
{#if showLoading}
|
|
101
|
+
<slot name="loading">
|
|
102
|
+
<div class="infinite-loading">Loading...</div>
|
|
103
|
+
</slot>
|
|
104
|
+
{/if}
|
|
102
105
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
{#if showNoResults}
|
|
107
|
+
<slot name="no-results">
|
|
108
|
+
<div class="infinite-no-results">No results</div>
|
|
109
|
+
</slot>
|
|
110
|
+
{/if}
|
|
108
111
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
</div>
|
|
115
|
-
</slot>
|
|
116
|
-
{/if}
|
|
112
|
+
{#if showNoMore}
|
|
113
|
+
<slot name="no-data">
|
|
114
|
+
<div class="infinite-no-data">No more data</div>
|
|
115
|
+
</slot>
|
|
116
|
+
{/if}
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
{#if showError}
|
|
119
|
+
<slot name="error" {attemptLoad}>
|
|
120
|
+
<div class="infinite-error">
|
|
121
|
+
<div class="infinite-label">Oops, something went wrong</div>
|
|
122
|
+
<button class="infinite-btn" disabled={status === STATUS.COMPLETE} onclick={attemptLoad}>
|
|
123
|
+
Retry
|
|
124
|
+
</button>
|
|
125
|
+
</div>
|
|
126
|
+
</slot>
|
|
127
|
+
{/if}
|
|
128
|
+
</div>
|
|
119
129
|
</div>
|
|
120
130
|
|
|
121
131
|
<style>
|
|
122
|
-
.loader-wrapper {
|
|
132
|
+
.infinite-loader-wrapper {
|
|
123
133
|
display: grid;
|
|
124
134
|
width: 100%;
|
|
125
135
|
place-items: center;
|
|
126
|
-
margin-block: 2rem;
|
|
127
136
|
|
|
128
|
-
.loading {
|
|
137
|
+
.infinite-loading {
|
|
129
138
|
margin-top: 1rem;
|
|
130
139
|
font-size: 1.5rem;
|
|
131
140
|
}
|
|
132
141
|
|
|
133
|
-
.no-results {
|
|
142
|
+
.infinite-no-results {
|
|
134
143
|
margin-top: 1rem;
|
|
135
144
|
font-size: 1.5rem;
|
|
136
145
|
}
|
|
137
146
|
|
|
138
|
-
.no-data {
|
|
147
|
+
.infinite-no-data {
|
|
139
148
|
margin-top: 1rem;
|
|
140
149
|
font-size: 1.5rem;
|
|
141
150
|
}
|
|
142
151
|
|
|
143
|
-
.error {
|
|
152
|
+
.infinite-error {
|
|
144
153
|
display: flex;
|
|
145
154
|
flex-direction: column;
|
|
146
155
|
gap: 1rem;
|
|
147
156
|
font-size: 1.5rem;
|
|
148
157
|
margin-block: 1rem;
|
|
149
158
|
|
|
150
|
-
.label {
|
|
151
|
-
color:
|
|
159
|
+
.infinite-label {
|
|
160
|
+
color: crimson;
|
|
152
161
|
}
|
|
153
162
|
|
|
154
|
-
.btn {
|
|
163
|
+
.infinite-btn {
|
|
155
164
|
color: white;
|
|
156
165
|
background-color: #333;
|
|
157
166
|
padding-inline: 1.5rem;
|
|
158
167
|
padding-block: 0.75rem;
|
|
159
168
|
border-radius: 0.25rem;
|
|
160
169
|
border: none;
|
|
170
|
+
transition: background-color 0.3s;
|
|
171
|
+
line-height: normal;
|
|
161
172
|
}
|
|
162
|
-
.btn:hover {
|
|
173
|
+
.infinite-btn:hover {
|
|
163
174
|
cursor: pointer;
|
|
175
|
+
background-color: #222;
|
|
164
176
|
}
|
|
165
177
|
}
|
|
166
178
|
|
|
167
|
-
.target {
|
|
168
|
-
|
|
179
|
+
.infinite-intersection-target {
|
|
180
|
+
width: 100%;
|
|
181
|
+
min-height: 1px;
|
|
182
|
+
display: flex;
|
|
183
|
+
flex-direction: column;
|
|
184
|
+
align-items: center;
|
|
185
|
+
justify-content: center;
|
|
169
186
|
}
|
|
170
187
|
}
|
|
171
188
|
</style>
|
|
@@ -10,6 +10,7 @@ declare const __propDef: {
|
|
|
10
10
|
triggerLoad: () => Promise<void>;
|
|
11
11
|
loopTimeout?: number | undefined;
|
|
12
12
|
loopMaxCalls?: number | undefined;
|
|
13
|
+
intersectionOptions?: IntersectionObserverInit | undefined;
|
|
13
14
|
} & {
|
|
14
15
|
children?: ((this: void) => typeof import("svelte").SnippetReturn & {
|
|
15
16
|
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
package/package.json
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-infinite",
|
|
3
3
|
"description": "Infinite scroll for Svelte 5 with Runes",
|
|
4
|
-
"author":
|
|
5
|
-
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "Nico Domino",
|
|
6
|
+
"email": "yo@ndo.dev",
|
|
7
|
+
"url": "https://ndo.dev"
|
|
8
|
+
},
|
|
9
|
+
"version": "0.1.2",
|
|
6
10
|
"license": "MIT",
|
|
7
|
-
"homepage": "https://
|
|
11
|
+
"homepage": "https://svelte-5-infinite.vercel.app",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"infinite-loader",
|
|
14
|
+
"svelte",
|
|
15
|
+
"svelte5",
|
|
16
|
+
"sveltekit"
|
|
17
|
+
],
|
|
8
18
|
"repository": {
|
|
9
19
|
"type": "git",
|
|
10
20
|
"url": "git+https://github.com/ndom91/svelte-infinite.git"
|
|
@@ -12,24 +22,9 @@
|
|
|
12
22
|
"bugs": {
|
|
13
23
|
"url": "https://github.com/ndom91/svelte-infinite/issues"
|
|
14
24
|
},
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"preview": "vite preview",
|
|
19
|
-
"package": "svelte-kit sync && svelte-package && publint",
|
|
20
|
-
"prepublishOnly": "npm run package",
|
|
21
|
-
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
22
|
-
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
23
|
-
"test": "vitest",
|
|
24
|
-
"lint": "prettier --check . && eslint .",
|
|
25
|
-
"format": "prettier --write ."
|
|
26
|
-
},
|
|
27
|
-
"keywords": [
|
|
28
|
-
"infinite-loader",
|
|
29
|
-
"svelte",
|
|
30
|
-
"svelte5",
|
|
31
|
-
"sveltekit"
|
|
32
|
-
],
|
|
25
|
+
"svelte": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"type": "module",
|
|
33
28
|
"exports": {
|
|
34
29
|
".": {
|
|
35
30
|
"types": "./dist/index.d.ts",
|
|
@@ -45,27 +40,35 @@
|
|
|
45
40
|
"svelte": "^5.0.0"
|
|
46
41
|
},
|
|
47
42
|
"devDependencies": {
|
|
48
|
-
"@sveltejs/adapter-auto": "^3.
|
|
49
|
-
"@sveltejs/kit": "^2.
|
|
50
|
-
"@sveltejs/package": "^2.
|
|
51
|
-
"@sveltejs/vite-plugin-svelte": "^3.0.
|
|
52
|
-
"@types/eslint": "^8.56.
|
|
53
|
-
"@typescript-eslint/eslint-plugin": "^7.
|
|
54
|
-
"@typescript-eslint/parser": "^7.
|
|
55
|
-
"eslint": "^8.
|
|
43
|
+
"@sveltejs/adapter-auto": "^3.1.1",
|
|
44
|
+
"@sveltejs/kit": "^2.5.2",
|
|
45
|
+
"@sveltejs/package": "^2.2.7",
|
|
46
|
+
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
|
47
|
+
"@types/eslint": "^8.56.5",
|
|
48
|
+
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
|
49
|
+
"@typescript-eslint/parser": "^7.1.0",
|
|
50
|
+
"eslint": "^8.57.0",
|
|
56
51
|
"eslint-config-prettier": "^9.1.0",
|
|
57
52
|
"eslint-plugin-svelte": "^2.36.0-next.4",
|
|
58
|
-
"prettier": "^3.
|
|
59
|
-
"prettier-plugin-svelte": "^3.
|
|
60
|
-
"publint": "^0.
|
|
53
|
+
"prettier": "^3.2.5",
|
|
54
|
+
"prettier-plugin-svelte": "^3.2.2",
|
|
55
|
+
"publint": "^0.2.7",
|
|
61
56
|
"svelte": "^5.0.0-beta.70",
|
|
62
|
-
"svelte-check": "^3.6.
|
|
63
|
-
"tslib": "^2.
|
|
64
|
-
"typescript": "^5.
|
|
65
|
-
"vite": "^5.
|
|
66
|
-
"vitest": "^1.
|
|
57
|
+
"svelte-check": "^3.6.6",
|
|
58
|
+
"tslib": "^2.6.2",
|
|
59
|
+
"typescript": "^5.3.3",
|
|
60
|
+
"vite": "^5.1.4",
|
|
61
|
+
"vitest": "^1.3.1"
|
|
67
62
|
},
|
|
68
|
-
"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
63
|
+
"scripts": {
|
|
64
|
+
"dev": "vite dev",
|
|
65
|
+
"build": "vite build && npm run package",
|
|
66
|
+
"preview": "vite preview",
|
|
67
|
+
"package": "svelte-kit sync && svelte-package && publint",
|
|
68
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
69
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
70
|
+
"test": "vitest",
|
|
71
|
+
"lint": "prettier --check . && eslint .",
|
|
72
|
+
"format": "prettier --write ."
|
|
73
|
+
}
|
|
74
|
+
}
|