reactjs-signal 1.0.0

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.
@@ -0,0 +1,95 @@
1
+ ## Git Commit Message Convention
2
+
3
+ > This is adapted from [Commit convention](https://www.conventionalcommits.org/en/v1.0.0/).
4
+
5
+ #### TL;DR:
6
+
7
+ Messages must be matched by the following regex:
8
+
9
+ ```js
10
+ /^((feat|fix|docs|style|core|i18n|report|misc|cli|audits|refactor|perf|test|workflow|build|ci|chore|types|wip|release|deps?|merge|examples?|revert)(\(.+\))?(\:|\!\:)|(Merge|Revert|Version)) .{1,50}$/;
11
+ ```
12
+
13
+ #### Examples
14
+
15
+ Appears under "Features" header, `compiler` subheader:
16
+
17
+ ```
18
+ feat(compiler): add 'comments' option
19
+ ```
20
+
21
+ Appears under "Bug Fixes" header, `v-model` subheader, with a link to issue #28:
22
+
23
+ ```
24
+ fix(v-model): handle events on blur
25
+
26
+ close #28
27
+ ```
28
+
29
+ Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
30
+
31
+ ```
32
+ perf(core): improve vdom diffing by removing 'foo' option
33
+
34
+ BREAKING CHANGE: The 'foo' option has been removed.
35
+ ```
36
+
37
+ The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
38
+
39
+ ```
40
+ revert: feat(compiler): add 'comments' option
41
+
42
+ This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
43
+ ```
44
+
45
+ ### Full Message Format
46
+
47
+ A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:
48
+
49
+ ```
50
+ <type>(<scope>): <subject>
51
+ <BLANK LINE>
52
+ <body>
53
+ <BLANK LINE>
54
+ <footer>
55
+ ```
56
+
57
+ The **header** is mandatory and the **scope** of the header is optional.
58
+
59
+ ### Revert
60
+
61
+ If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body, it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
62
+
63
+ ### Type
64
+
65
+ If the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However, if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.
66
+
67
+ Other prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.
68
+
69
+ ### Scope
70
+
71
+ The scope could be anything specifying the place of the commit change. For example `core`, `compiler`, `ssr`, `v-model`, `transition` etc...
72
+
73
+ ### Subject
74
+
75
+ The subject contains a succinct description of the change:
76
+
77
+ - use the imperative, present tense: "change" not "changed" nor "changes"
78
+ - don't capitalize the first letter
79
+ - no dot (.) at the end
80
+
81
+ ### Body
82
+
83
+ Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
84
+ The body should include the motivation for the change and contrast this with previous behavior.
85
+
86
+ ### Footer
87
+
88
+ The footer should contain any information about **Breaking Changes** and is also the place to
89
+ reference GitHub issues that this commit **Closes**.
90
+
91
+ **Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
92
+
93
+ ```
94
+ feat!: breaking change / feat(scope)!: rework API
95
+ ```
@@ -0,0 +1,21 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches:
5
+ - master
6
+
7
+ pull_request:
8
+ branches:
9
+ - master
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v3
16
+ - uses: actions/setup-node@v3
17
+ with:
18
+ node-version: 18.x
19
+
20
+ - run: npm install
21
+ - run: npm run lint && npm run build
@@ -0,0 +1,29 @@
1
+ name: Release
2
+
3
+ permissions:
4
+ contents: write
5
+
6
+ on:
7
+ push:
8
+ tags:
9
+ - 'v*'
10
+
11
+ jobs:
12
+ release:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v3
16
+ with:
17
+ fetch-depth: 0
18
+
19
+ - uses: actions/setup-node@v3
20
+ with:
21
+ node-version: 18.x
22
+
23
+ - run: npx changeloggithub@latest
24
+ env:
25
+ GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
26
+
27
+ - name: Publish
28
+ run: |
29
+ echo "Publishing"
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 opensource
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # Template create npm package
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "reactjs-signal",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "type": "module",
6
+ "types": "./dist/index.d.ts",
7
+ "module": "./dist/index.js",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "watch": "npm run build -- --watch src",
17
+ "prepublishOnly": "npm run build",
18
+ "lint": "tsc",
19
+ "start": "esno src/index.ts",
20
+ "test": "vitest",
21
+ "verify-commit": "verify-commit-msg",
22
+ "prepare": "git-scm-hooks",
23
+ "release": "bumpp -r && npm publish"
24
+ },
25
+ "keywords": [],
26
+ "author": "",
27
+ "license": "ISC",
28
+ "devDependencies": {
29
+ "@types/react": "^19.0.2",
30
+ "bumpp": "^9.2.1",
31
+ "git-scm-hooks": "^0.0.7",
32
+ "tsup": "^8.0.1",
33
+ "typescript": "^5.3.3",
34
+ "verify-commit-msg": "^0.0.10"
35
+ },
36
+ "git-hooks": {
37
+ "pre-commit": "npm run lint",
38
+ "commit-msg": "npm run verify-commit"
39
+ },
40
+ "peerDependencies": {
41
+ "alien-signals": ">=0.4",
42
+ "react": ">=18"
43
+ }
44
+ }
package/src/index.ts ADDED
@@ -0,0 +1,450 @@
1
+ 'use client';
2
+ /**
3
+ *
4
+ * React Alien Signals is a **TypeScript** library that provides hooks built on top of [Alien Signals](https://github.com/stackblitz/alien-signals).
5
+ * It offers a seamless integration with React, ensuring concurrency-safe re-renders without tearing.
6
+ *
7
+ * @module reactjs-signal
8
+ */
9
+
10
+ import {
11
+ computed as alienComputed,
12
+ effect as alienEffect,
13
+ effectScope as alienEffectScope,
14
+ signal as alienSignal,
15
+ unstable as alienUnstable,
16
+ type Effect,
17
+ type Computed,
18
+ type Dependency,
19
+ type EffectScope,
20
+ type ISignal,
21
+ type IWritableSignal,
22
+ } from 'alien-signals';
23
+ import { useEffect, useMemo, useState, useSyncExternalStore } from 'react';
24
+
25
+ declare class AsyncComputed<T = any> extends Computed {
26
+ get(): Promise<T>;
27
+ //@ts-ignore
28
+ update(): Promise<boolean>;
29
+ }
30
+
31
+ /**
32
+ * Creates a writable Alien Signal.
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const countSignal = createSignal(0);
37
+ * countSignal.set(10); // sets the value to 10
38
+ * ```
39
+ *
40
+ * @template T - The type of the signal value.
41
+ * @param {T} initialValue - The initial value of the signal.
42
+ * @returns {IWritableSignal<T>} The created Alien Signal.
43
+ */
44
+ export function createSignal<T>(initialValue: T): IWritableSignal<T> {
45
+ return alienSignal<T>(initialValue);
46
+ }
47
+
48
+ /**
49
+ * Creates a computed Alien Signal based on a getter function.
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * const countSignal = createSignal(1);
54
+ * const doubleSignal = createComputed(() => countSignal.get() * 2);
55
+ * ```
56
+ *
57
+ * @template T - The type of the computed value.
58
+ * @param {() => T} fn - A getter function returning a computed value.
59
+ * @returns {ISignal<T>} The created computed signal.
60
+ */
61
+ export function createComputed<T>(fn: () => T): ISignal<T> {
62
+ return alienComputed<T>(fn);
63
+ }
64
+
65
+ /**
66
+ * Creates a side effect in Alien Signals.
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const countSignal = createSignal(1);
71
+ * createEffect(() => {
72
+ * console.log('Count is', countSignal.get());
73
+ * });
74
+ * ```
75
+ *
76
+ * @template T - The type of the effect value.
77
+ * @param {() => T} fn - A function that will run whenever its tracked signals update.
78
+ * @returns {Effect<T>} The created effect object.
79
+ */
80
+ export function createEffect<T>(fn: () => T): Effect<T> {
81
+ return alienEffect(fn);
82
+ }
83
+
84
+ /**
85
+ * Creates an Alien Signals effect scope. This scope can manage multiple effects,
86
+ * allowing you to stop or start them together.
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * const scope = createSignalScope();
91
+ * scope.run(() => {
92
+ * // create effects in here...
93
+ * });
94
+ * ```
95
+ *
96
+ * @returns {EffectScope} The created effect scope.
97
+ */
98
+ export function createSignalScope(): EffectScope {
99
+ return alienEffectScope();
100
+ }
101
+
102
+ /**
103
+ * Creates an async computed signal in Alien Signals. The getter is an async generator
104
+ * that yields dependencies and finally resolves to a computed value.
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * const asyncComp = createAsyncComputed<number>(async function* () {
109
+ * yield someDependency;
110
+ * return 42;
111
+ * });
112
+ * ```
113
+ *
114
+ * @template T - The type of the computed value.
115
+ * @param {() => AsyncGenerator<Dependency, T>} getter - An async generator returning dependencies and ultimately a value.
116
+ * @returns {AsyncComputed<T>} The created async computed signal.
117
+ * @experimental
118
+ */
119
+ export function unstable_createAsyncComputed<T>(
120
+ getter: () => AsyncGenerator<Dependency, T>,
121
+ ): AsyncComputed<T> {
122
+ return alienUnstable.asyncComputed<T>(getter);
123
+ }
124
+
125
+ /**
126
+ * Creates an async effect in Alien Signals. The function is an async generator
127
+ * that yields dependencies as they are discovered.
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * createAsyncEffect(async function* () {
132
+ * yield someDependency;
133
+ * console.log('Async effect done!');
134
+ * });
135
+ * ```
136
+ *
137
+ * @template T - The type of the effect value.
138
+ * @param {() => AsyncGenerator<Dependency, T>} fn - An async generator returning dependencies.
139
+ * @returns {Promise<T>} The created async effect object.
140
+ */
141
+ export async function unstable_createAsyncEffect<T>(
142
+ fn: () => AsyncGenerator<Dependency, T>,
143
+ ): Promise<T> {
144
+ const eff = alienUnstable.asyncEffect(fn);
145
+
146
+ // Immediately run the effect and return its promise
147
+ const final = await eff.run();
148
+ return final;
149
+ }
150
+
151
+ /**
152
+ * Creates a computed array signal in Alien Signals, deriving a reactive
153
+ * array from an original signal array.
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * const numbersSignal = createSignal([1, 2, 3]);
158
+ * const compArray = createComputedArray(numbersSignal, (itemSignal, i) => () => {
159
+ * return itemSignal.get() * 2;
160
+ * });
161
+ * ```
162
+ *
163
+ * @template I - The type of the items in the input array.
164
+ * @template O - The type of the items in the output array.
165
+ * @param {ISignal<I[]>} arr - Signal containing an array.
166
+ * @param {(itemSignal: ISignal<I>, index: number) => () => O} getGetter - A function returning a getter for each item signal.
167
+ * @returns {Readonly<O[]>} A proxied array signal.
168
+ * @experimental
169
+ */
170
+ export function unstable_createComputedArray<I, O>(
171
+ arr: ISignal<I[]>,
172
+ getGetter: (itemSignal: ISignal<I>, index: number) => () => O,
173
+ ): Readonly<O[]> {
174
+ return alienUnstable.computedArray<I, O>(arr, getGetter);
175
+ }
176
+
177
+ /**
178
+ * Creates a computed Set signal in Alien Signals that tracks changes
179
+ * to a source Set signal.
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * const setSignal = createSignal(new Set([1, 2]));
184
+ * const compSet = createComputedSet(setSignal);
185
+ * ```
186
+ *
187
+ * @template T - The type of the items in the Set.
188
+ * @param {IWritableSignal<Set<T>>} source - A signal containing a Set.
189
+ * @returns {ISignal<Set<T>>} A computed signal referencing that Set.
190
+ * @experimental
191
+ */
192
+ export function unstable_createComputedSet<T>(source: IWritableSignal<Set<T>>): ISignal<Set<T>> {
193
+ return alienUnstable.computedSet<T>(source);
194
+ }
195
+
196
+ /**
197
+ * Creates an equality-based computed signal, only updating when the new value
198
+ * is not deeply equal to the old value.
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * const eqComp = createEqualityComputed(() => {
203
+ * return { foo: 'bar' };
204
+ * });
205
+ * ```
206
+ *
207
+ * @template T - The type of the computed value.
208
+ * @param {() => T} getter - A function returning the value to compare.
209
+ * @returns {ISignal<T>} An equality computed signal.
210
+ * @experimental
211
+ */
212
+ export function unstable_createEqualityComputed<T>(getter: () => T): ISignal<T> {
213
+ return alienUnstable.equalityComputed(getter);
214
+ }
215
+
216
+ /**
217
+ * React hook returning `[value, setValue]` for a given Alien Signal.
218
+ * Uses useSyncExternalStore for concurrency-safe re-renders.
219
+ *
220
+ * @example
221
+ * ```typescript
222
+ * const countSignal = createSignal(0);
223
+ * function Counter() {
224
+ * const [count, setCount] = useSignal(countSignal);
225
+ * return <button onClick={() => setCount(count + 1)}>{count}</button>;
226
+ * }
227
+ * ```
228
+ *
229
+ * @template T - The type of the signal value.
230
+ * @param {IWritableSignal<T>} alienSignal - The signal to read/write.
231
+ * @returns {[T, (val: T | ((oldVal: T) => T)) => void]} A tuple [currentValue, setValue].
232
+ */
233
+ export function useSignal<T>(
234
+ alienSignal: IWritableSignal<T>,
235
+ ): [T, (val: T | ((oldVal: T) => T)) => void] {
236
+ const value = useSyncExternalStore(
237
+ (callback) => {
238
+ const eff = alienEffect(() => {
239
+ alienSignal.get(); // track
240
+ callback();
241
+ });
242
+ return () => eff.stop();
243
+ },
244
+ () => alienSignal.get(),
245
+ () => alienSignal.get(), // server snapshot
246
+ );
247
+
248
+ const setValue = (val: T | ((oldVal: T) => T)) => {
249
+ if (typeof val === 'function') {
250
+ alienSignal.set((val as (oldVal: T) => T)(alienSignal.get()));
251
+ } else {
252
+ alienSignal.set(val);
253
+ }
254
+ };
255
+
256
+ return [value, setValue];
257
+ }
258
+
259
+ /**
260
+ * React hook returning only the current value of an Alien Signal (or computed).
261
+ * No setter is provided.
262
+ *
263
+ * @example
264
+ * ```typescript
265
+ * const countSignal = createSignal(0);
266
+ * const doubleSignal = createComputed(() => countSignal.get() * 2);
267
+ * function Display() {
268
+ * const count = useSignalValue(countSignal);
269
+ * const double = useSignalValue(doubleSignal);
270
+ * return <div>{count}, {double}</div>;
271
+ * }
272
+ * ```
273
+ *
274
+ * @template T - The type of the signal value.
275
+ * @param {IWritableSignal<T>} alienSignal - The signal to read.
276
+ * @returns {T} The current value.
277
+ */
278
+ export function useSignalValue<T>(alienSignal: IWritableSignal<T>): T {
279
+ return useSyncExternalStore(
280
+ (callback) => {
281
+ const eff = alienEffect(() => {
282
+ alienSignal.get();
283
+ callback();
284
+ });
285
+ return () => eff.stop();
286
+ },
287
+ () => alienSignal.get(),
288
+ );
289
+ }
290
+
291
+ /**
292
+ * React hook returning only a setter function for an Alien Signal.
293
+ * No current value is provided, similar to Jotai's useSetAtom.
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * const countSignal = createSignal(0);
298
+ * function Incrementor() {
299
+ * const setCount = useSetSignal(countSignal);
300
+ * return <button onClick={() => setCount((c) => c + 1)}>+1</button>;
301
+ * }
302
+ * ```
303
+ *
304
+ * @template T - The type of the signal value.
305
+ * @param {IWritableSignal<T>} alienSignal - The signal to write.
306
+ * @returns {(val: T | ((oldVal: T) => T)) => void} A setter function.
307
+ */
308
+ export function useSetSignal<T>(
309
+ alienSignal: IWritableSignal<T>,
310
+ ): (val: T | ((oldVal: T) => T)) => void {
311
+ return (val) => {
312
+ if (typeof val === 'function') {
313
+ alienSignal.set((val as (oldVal: T) => T)(alienSignal.get()));
314
+ } else {
315
+ alienSignal.set(val);
316
+ }
317
+ };
318
+ }
319
+
320
+ /**
321
+ * React hook for running a side effect whenever Alien Signals' dependencies
322
+ * used in `fn` change. The effect is cleaned up on component unmount.
323
+ *
324
+ * @example
325
+ * ```typescript
326
+ * function Logger() {
327
+ * useSignalEffect(() => {
328
+ * console.log('Signal changed:', someSignal.get());
329
+ * });
330
+ * return null;
331
+ * }
332
+ * ```
333
+ *
334
+ * @param {() => void} fn - The effect function to run.
335
+ */
336
+ export function useSignalEffect(fn: () => void): void {
337
+ useEffect(() => {
338
+ const eff = alienEffect(fn);
339
+ return () => eff.stop();
340
+ }, [fn]);
341
+ }
342
+
343
+ /**
344
+ * React hook for managing an Alien Signals effect scope.
345
+ * All signals/effects created inside this scope run when the component mounts,
346
+ * and are stopped automatically when the component unmounts.
347
+ *
348
+ * @example
349
+ * ```typescript
350
+ * function ScopedEffects() {
351
+ * const scope = useSignalScope();
352
+ * useEffect(() => {
353
+ * scope.run(() => {
354
+ * createEffect(() => {
355
+ * console.log('Scoped effect:', someSignal.get());
356
+ * });
357
+ * });
358
+ * }, [scope]);
359
+ * return null;
360
+ * }
361
+ * ```
362
+ *
363
+ * @returns {EffectScope} The created effect scope.
364
+ */
365
+ export function useSignalScope(): EffectScope {
366
+ const scope = useMemo(() => alienEffectScope(), []);
367
+ useEffect(() => {
368
+ return () => {
369
+ scope.stop();
370
+ };
371
+ }, [scope]);
372
+ return scope;
373
+ }
374
+
375
+ /**
376
+ * React hook to read from an async computed signal.
377
+ * The hook fetches the current value, subscribing to changes via useSyncExternalStore,
378
+ * and triggers a get() call to retrieve updated data. Maintains an internal state
379
+ * for the resolved value of the promise.
380
+ *
381
+ * @example
382
+ * ```typescript
383
+ * const asyncSignal = createAsyncComputed<number>(async function*() {
384
+ * const val = someSignal.get();
385
+ * yield Promise.resolve(someSignal); // track async dep
386
+ * return val * 2;
387
+ * });
388
+ *
389
+ * function AsyncDisplay() {
390
+ * const value = useAsyncComputedValue(asyncSignal);
391
+ * return <div>Value: {String(value)}</div>;
392
+ * }
393
+ * ```
394
+ *
395
+ * @template T - The type of the computed value.
396
+ * @param {AsyncComputed<T>} alienAsyncComp - The async computed signal to read.
397
+ * @returns {T | undefined} The resolved value (or undefined if not yet resolved).
398
+ * @experimental
399
+ */
400
+ export function unstable_useAsyncComputedValue<T>(alienAsyncComp: AsyncComputed<T>): T | undefined {
401
+ const [value, setValue] = useState<T | undefined>(alienAsyncComp.currentValue);
402
+
403
+ useSyncExternalStore(
404
+ (callback) => {
405
+ const eff = alienEffect(() => {
406
+ alienAsyncComp.currentValue; // track
407
+ callback();
408
+ });
409
+ return () => eff.stop();
410
+ },
411
+ () => alienAsyncComp.currentValue,
412
+ );
413
+
414
+ useEffect(() => {
415
+ let active = true;
416
+ const fetchValue = async () => {
417
+ const val = await alienAsyncComp.get();
418
+ if (active) setValue(val);
419
+ };
420
+ fetchValue();
421
+ return () => {
422
+ active = false;
423
+ };
424
+ }, [alienAsyncComp]);
425
+
426
+ return value;
427
+ }
428
+
429
+ /**
430
+ * React hook to run an asynchronous effect whenever the component mounts,
431
+ * cleaning up when it unmounts.
432
+ *
433
+ * @example
434
+ * ```typescript
435
+ * useAsyncEffect(async function* () {
436
+ * yield someDependency;
437
+ * console.log('Async side effect complete!');
438
+ * });
439
+ * ```
440
+ *
441
+ * @template T - The type of the effect value.
442
+ * @param {() => AsyncGenerator<Dependency, T>} fn - An async generator representing the effect logic.
443
+ * @experimental
444
+ */
445
+ export function unstable_useAsyncEffect<T>(fn: () => AsyncGenerator<Dependency, T>): void {
446
+ useEffect(() => {
447
+ const eff = alienUnstable.asyncEffect(fn);
448
+ return () => eff.stop();
449
+ }, [fn]);
450
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Enable latest features
4
+ "lib": ["ESNext", "DOM"],
5
+ "target": "ESNext",
6
+ "module": "ESNext",
7
+ "moduleDetection": "force",
8
+ "allowJs": true,
9
+
10
+ // Bundler mode
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "noEmit": true,
15
+
16
+ // Best practices
17
+ "strict": true,
18
+ "skipLibCheck": true,
19
+ "noFallthroughCasesInSwitch": true,
20
+
21
+ // Some stricter flags (disabled by default)
22
+ "noUnusedLocals": false,
23
+ "noUnusedParameters": false,
24
+ "noPropertyAccessFromIndexSignature": false
25
+ }
26
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: ["src/index.ts"],
5
+ format: "esm",
6
+ treeshake: true,
7
+ clean: true,
8
+ dts: true,
9
+ platform: "browser",
10
+ splitting: true,
11
+ minify: true,
12
+ });