@nemigo/svelte 0.3.4 → 1.5.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.
package/dist/loader.d.ts CHANGED
@@ -1,15 +1,55 @@
1
- export type LoaderHook = ReturnType<LoaderStore["hook"]>;
2
- export declare class LoaderStore {
3
- state: import("./value.svelte.js").ValueStateType<boolean>;
4
- private queue;
5
- private caller;
6
- _hydratable: boolean;
7
- constructor(hydratable?: boolean);
8
- private check;
9
- private awaiter;
10
- private reset;
11
- push(promise: Promise<unknown>): void;
12
- hook(): () => void;
13
- run<T = any>(call: () => Promise<T>, external?: (v: boolean) => void): Promise<T>;
1
+ import type { ISvelteState } from "./state.svelte.js";
2
+ import { Loader } from "@nemigo/helpers/async/loader";
3
+ import type { IState } from "@nemigo/helpers/types";
4
+ export type { LoaderHook } from "@nemigo/helpers/async/loader";
5
+ /**
6
+ * Менеджер состояния выполнения для асинхронных операций.
7
+ * Поддерживает гидратацию true-значения после SSR
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // Создание экземпляра
12
+ * const loader = new LoaderStore(true); // в SSR значение будет true
13
+ *
14
+ * loader.hydrate(); // Если значение состояния `true`, добавляет onMount-проверку должно ли оно быть таковым
15
+ *
16
+ * $effect(() => {
17
+ * if (loader.state()) {
18
+ * console.log("Loading...");
19
+ * } else {
20
+ * console.log("Not loading");
21
+ * }
22
+ * });
23
+ *
24
+ * // Передача промиса
25
+ * async function fetchData() {
26
+ * const promise = fetch("/api/data");
27
+ * loader.push(promise);
28
+ * const data = await promise;
29
+ * return data;
30
+ * }
31
+ *
32
+ * // Запуск операции
33
+ * async function fetchData() {
34
+ * const data = await loader.run(() => fetch("/api/data"));
35
+ * return data;
36
+ * }
37
+ *
38
+ * // Ручное хук (создаёт промис внутри)
39
+ * const complete = loader.hook();
40
+ * try {
41
+ * await someAsyncOperation();
42
+ * } finally {
43
+ * complete();
44
+ * }
45
+ * ```
46
+ */
47
+ export declare class LoaderStore<State extends IState<boolean> = ISvelteState<boolean>> extends Loader {
48
+ state: State;
49
+ static default(init?: boolean): LoaderStore<ISvelteState<boolean>>;
50
+ constructor(state: State);
51
+ /**
52
+ * Создаёт {@link onMount} проверку, если в стейте значение `true`
53
+ */
14
54
  hydrate(): this;
15
55
  }
package/dist/loader.js CHANGED
@@ -1,65 +1,65 @@
1
- import { ValueState } from "./value.svelte.js";
2
- import { delay } from "@nemigo/helpers/async";
3
- import { isSSR } from "@nemigo/helpers/html";
1
+ import { createSvelteState } from "./state.svelte.js";
2
+ import { Loader } from "@nemigo/helpers/async/loader";
4
3
  import { onMount } from "svelte";
5
- export class LoaderStore {
6
- state = ValueState(false);
7
- queue = [];
8
- caller = 0;
9
- _hydratable;
10
- constructor(hydratable = false) {
11
- this._hydratable = hydratable;
12
- this.state.set(this._hydratable);
4
+ /**
5
+ * Менеджер состояния выполнения для асинхронных операций.
6
+ * Поддерживает гидратацию true-значения после SSR
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * // Создание экземпляра
11
+ * const loader = new LoaderStore(true); // в SSR значение будет true
12
+ *
13
+ * loader.hydrate(); // Если значение состояния `true`, добавляет onMount-проверку должно ли оно быть таковым
14
+ *
15
+ * $effect(() => {
16
+ * if (loader.state()) {
17
+ * console.log("Loading...");
18
+ * } else {
19
+ * console.log("Not loading");
20
+ * }
21
+ * });
22
+ *
23
+ * // Передача промиса
24
+ * async function fetchData() {
25
+ * const promise = fetch("/api/data");
26
+ * loader.push(promise);
27
+ * const data = await promise;
28
+ * return data;
29
+ * }
30
+ *
31
+ * // Запуск операции
32
+ * async function fetchData() {
33
+ * const data = await loader.run(() => fetch("/api/data"));
34
+ * return data;
35
+ * }
36
+ *
37
+ * // Ручное хук (создаёт промис внутри)
38
+ * const complete = loader.hook();
39
+ * try {
40
+ * await someAsyncOperation();
41
+ * } finally {
42
+ * complete();
43
+ * }
44
+ * ```
45
+ */
46
+ export class LoaderStore extends Loader {
47
+ state;
48
+ static default(init = false) {
49
+ return new LoaderStore(createSvelteState(init));
13
50
  }
14
- check(caller) {
15
- if (this.queue.length === 0)
16
- return this.reset(caller);
17
- void Promise.allSettled(this.queue).then(() => {
18
- if (this.caller !== caller)
19
- return;
20
- void delay(20).then(() => this.reset(caller));
21
- });
22
- }
23
- awaiter(caller) {
24
- this.state.set(true);
25
- this.check(caller);
26
- }
27
- reset(caller) {
28
- if (this.caller !== caller)
29
- return;
30
- this.state.set(false);
31
- this.caller = 0;
32
- this.queue = [];
33
- }
34
- push(promise) {
35
- this.caller++;
36
- this.queue.push(promise);
37
- this.awaiter(this.caller);
38
- }
39
- hook() {
40
- if (isSSR)
41
- return () => { };
42
- let resolver;
43
- const promise = new Promise((resolve) => (resolver = resolve));
44
- this.push(promise);
45
- return resolver;
46
- }
47
- async run(call, external) {
48
- const hook = this.hook();
49
- external?.(true);
50
- try {
51
- return await call();
52
- }
53
- finally {
54
- external?.(false);
55
- hook();
56
- }
51
+ constructor(state) {
52
+ super((v) => state.set(v));
53
+ this.state = state;
57
54
  }
55
+ /**
56
+ * Создаёт {@link onMount} проверку, если в стейте значение `true`
57
+ */
58
58
  hydrate() {
59
- if (this._hydratable) {
59
+ if (this.state.get()) {
60
60
  onMount(() => {
61
- if (this.state.value)
62
- this.check(this.caller);
61
+ if (this.state.get())
62
+ this.__check(this.__version);
63
63
  });
64
64
  }
65
65
  return this;
@@ -0,0 +1,42 @@
1
+ import type { IState } from "@nemigo/helpers/types";
2
+ /**
3
+ * Интерфейс $state-хранилища значения из {@link createSvelteState}
4
+ */
5
+ export interface ISvelteState<V = boolean | undefined> extends IState<V> {
6
+ /**
7
+ * @reactive
8
+ */
9
+ signal: V;
10
+ /**
11
+ * Получает текущее значение состояния без подписки на изменения.
12
+ */
13
+ get(): V;
14
+ /**
15
+ * Безопасно устанавливает новое значение состояния (внутри {@link untrack}).
16
+ */
17
+ set(state: V): void;
18
+ /**
19
+ * Вызов коллбэка внутри {@link untrack}
20
+ */
21
+ untrack<R>(call: (state: V) => R): R;
22
+ }
23
+ /**
24
+ * Создание $state-хранилища значения
25
+ *
26
+ * @template T - Тип значения
27
+ * @return {ISvelteState<T | undefined>}
28
+ *
29
+ * @see https://svelte.dev/docs/svelte/what-are-runes
30
+ */
31
+ declare function createSvelteState<T = boolean>(): ISvelteState<T | undefined>;
32
+ /**
33
+ * Создание $state-хранилища значения
34
+ *
35
+ * @template T - Тип значения
36
+ * @param {T} initial
37
+ * @return {ISvelteState<T>}
38
+ *
39
+ * @see https://svelte.dev/docs/svelte/what-are-runes
40
+ */
41
+ declare function createSvelteState<T = boolean>(initial: T): ISvelteState<T>;
42
+ export { createSvelteState };
@@ -0,0 +1,33 @@
1
+ import { untrack } from "svelte";
2
+ /**
3
+ * Создание $state-хранилища значения
4
+ *
5
+ * @template T - Тип значения
6
+ * @param {T} [initial]
7
+ * @return {ISvelteState<T | undefined>}
8
+ *
9
+ * @see https://svelte.dev/docs/svelte/what-are-runes
10
+ */
11
+ function createSvelteState(initial) {
12
+ let signal = $state(initial);
13
+ return {
14
+ get signal() {
15
+ return signal;
16
+ },
17
+ set signal(state) {
18
+ signal = state;
19
+ },
20
+ get() {
21
+ return untrack(() => signal);
22
+ },
23
+ set(state) {
24
+ untrack(() => {
25
+ signal = state;
26
+ });
27
+ },
28
+ untrack(call) {
29
+ return untrack(() => call(signal));
30
+ },
31
+ };
32
+ }
33
+ export { createSvelteState };
@@ -1,4 +1,4 @@
1
- import { toRound } from "@nemigo/helpers/phymath";
1
+ import { round } from "@nemigo/helpers/phymath";
2
2
  import { linear, quadInOut, quadOut } from "svelte/easing";
3
3
  import { slide as svelte_slide } from "svelte/transition";
4
4
  export const classNameTransition = (node, { animationClassName, reverseDirectionStyle = "reverse", normalDirectionStyle = "", duration = 325 }) => {
@@ -89,12 +89,12 @@ export function slide(node, { delay = 0, duration = 325, easing, axis = "y", cla
89
89
  overflow: hidden;
90
90
  opacity: ${delayed};
91
91
  ${prop}: ${boosted * propValue}px;
92
- padding-${secProps[0]}: ${toRound(boosted * padStart, 4)}px;
93
- padding-${secProps[1]}: ${toRound(boosted * padEnd, 4)}px;
94
- margin-${secProps[0]}: ${toRound(boosted * marStart, 4)}px;
95
- margin-${secProps[1]}: ${toRound(boosted * marEnd, 4)}px;
96
- border-${secProps[0]}-width: ${toRound(boosted * borStart, 4)}px;
97
- border-${secProps[1]}-width: ${toRound(boosted * borEnd, 4)}px;
92
+ padding-${secProps[0]}: ${round(boosted * padStart, 4)}px;
93
+ padding-${secProps[1]}: ${round(boosted * padEnd, 4)}px;
94
+ margin-${secProps[0]}: ${round(boosted * marStart, 4)}px;
95
+ margin-${secProps[1]}: ${round(boosted * marEnd, 4)}px;
96
+ border-${secProps[0]}-width: ${round(boosted * borStart, 4)}px;
97
+ border-${secProps[1]}-width: ${round(boosted * borEnd, 4)}px;
98
98
  min-${prop}: 0
99
99
  `;
100
100
  },
@@ -141,8 +141,8 @@ export const upper = (node, { delay = 0, duration = 400, x = 0, y = 0, opacity =
141
141
  easing: quadOut,
142
142
  css: (t, u) => {
143
143
  return `
144
- transform: scale(${toRound(0.6 + t / 2.5, 5)}) translate(${toRound((1 - t) * x)}px, ${toRound((1 - t) * y)}px);
145
- opacity: ${toRound(target_opacity - od * u)};
144
+ transform: scale(${round(0.6 + t / 2.5, 5)}) translate(${round((1 - t) * x)}px, ${round((1 - t) * y)}px);
145
+ opacity: ${round(target_opacity - od * u)};
146
146
  `;
147
147
  },
148
148
  };
@@ -154,5 +154,5 @@ export const fontSizeScale = (_, { delay = 0, duration = 300, easing = linear }
154
154
  delay,
155
155
  duration,
156
156
  easing,
157
- css: (t) => `font-size:${toRound(t, 3)}em;will-change:font-size`,
157
+ css: (t) => `font-size:${round(t, 3)}em;will-change:font-size`,
158
158
  });
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "@nemigo/svelte",
3
- "version": "0.3.4",
3
+ "version": "1.5.0",
4
4
  "private": false,
5
5
  "author": {
6
6
  "name": "Vlad Logvin",
7
7
  "email": "vlad.logvin84@gmail.com"
8
8
  },
9
9
  "type": "module",
10
+ "engines": {
11
+ "node": ">=22",
12
+ "pnpm": ">=10.9.0"
13
+ },
10
14
  "scripts": {
11
15
  "build": "svelte-package && rimraf .svelte-kit",
12
16
  "check": "tsc --noemit",
@@ -15,12 +19,8 @@
15
19
  },
16
20
  "exports": {
17
21
  ".": {
18
- "types": "./dist/value.svelte.d.ts",
19
- "svelte": "./dist/value.svelte.js"
20
- },
21
- "./kit/state": {
22
- "types": "./dist/kit/state.d.ts",
23
- "svelte": "./dist/kit/state.js"
22
+ "types": "./dist/state.svelte.d.ts",
23
+ "svelte": "./dist/state.svelte.js"
24
24
  },
25
25
  "./loader": {
26
26
  "types": "./dist/loader.d.ts",
@@ -32,9 +32,9 @@
32
32
  }
33
33
  },
34
34
  "peerDependencies": {
35
- "@nemigo/helpers": ">0.3.0",
36
- "@sveltejs/kit": "^2.12.0",
37
- "svelte": "^5.0.0"
35
+ "@nemigo/helpers": ">=1.5.0",
36
+ "@sveltejs/kit": ">=2.12.0",
37
+ "svelte": ">=5.0.0"
38
38
  },
39
39
  "peerDependenciesMeta": {
40
40
  "@sveltejs/kit": {
@@ -42,7 +42,7 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "csstype": "^3.0.0"
45
+ "csstype": ">=3.0.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@nemigo/configs": "workspace:*",
@@ -1,59 +0,0 @@
1
- import { Queue } from "@nemigo/helpers/queue";
2
- import type { CanBePromise } from "@nemigo/helpers/types";
3
- import type { Params } from "@nemigo/helpers/url";
4
- interface QueueItem {
5
- method: "close" | "open";
6
- state: App.PageState;
7
- params: Params;
8
- call?: () => CanBePromise;
9
- }
10
- declare class StateCTX extends Queue<QueueItem> {
11
- /**
12
- * Возвращает текущее мета-состояние страницы
13
- */
14
- get(clone?: boolean): App.PageState;
15
- set(v: App.PageState): void;
16
- hook(call: () => Promise<void>): Promise<void>;
17
- /**
18
- * Объединяет несколько состояний в одно
19
- */
20
- private join;
21
- /**
22
- * Безопасно от прокси добавляет новое состояние в историю браузера
23
- */
24
- pushStateSafe(url: string | URL, ctate?: App.PageState): void;
25
- /**
26
- * Безопасно от прокси заменяет текущее состояние в истории браузера
27
- */
28
- replaceStateSafe(url: string | URL, ctate?: App.PageState): void;
29
- /**
30
- * Возвращает текущий URL
31
- */
32
- getCurrentURL(): URL;
33
- /**
34
- * Преобразует абсолютный URL в относительный
35
- */
36
- toRelative(url: URL): string;
37
- /**
38
- * Очищает указанные параметры из текущего URL
39
- */
40
- clearParams(params: Params): string;
41
- /**
42
- * Добавляет указанные параметры в текущий URL
43
- */
44
- pushParams(params: Params): string;
45
- /**
46
- * Открывает новое мета-состояние с указанными параметрами
47
- */
48
- open(ctate: App.PageState, params?: Params, call?: () => CanBePromise): void;
49
- /**
50
- * Закрывает текущее мета-состояние с указанными параметрами
51
- */
52
- close(ctate: App.PageState, params?: Params, call?: () => CanBePromise): void;
53
- /**
54
- * Обработка очереди состояния
55
- */
56
- protected handle(item: QueueItem): void;
57
- }
58
- export type { StateCTX };
59
- export declare const stateCTX: StateCTX;
package/dist/kit/state.js DELETED
@@ -1,118 +0,0 @@
1
- import { pushState, replaceState } from "$app/navigation";
2
- import { page } from "$app/state";
3
- import { parsify } from "@nemigo/helpers";
4
- import { isSSR } from "@nemigo/helpers/html";
5
- import { Queue } from "@nemigo/helpers/queue";
6
- import { clearParams, mergeClearParams, pushParams } from "@nemigo/helpers/url";
7
- import { tick } from "svelte";
8
- class StateCTX extends Queue {
9
- /**
10
- * Возвращает текущее мета-состояние страницы
11
- */
12
- get(clone = false) {
13
- if (isSSR)
14
- return {};
15
- return clone ? parsify(page.state) : page.state;
16
- }
17
- set(v) {
18
- replaceState("", parsify(v));
19
- }
20
- async hook(call) {
21
- const copy = parsify(page.state);
22
- await call();
23
- replaceState("", copy);
24
- }
25
- /**
26
- * Объединяет несколько состояний в одно
27
- */
28
- join(...states) {
29
- return states.reduce((acc, ctate) => ({ ...acc, ...ctate }), {});
30
- }
31
- //...
32
- /**
33
- * Безопасно от прокси добавляет новое состояние в историю браузера
34
- */
35
- pushStateSafe(url, ctate = this.get()) {
36
- // eslint-disable-next-line svelte/no-navigation-without-resolve
37
- pushState(url, parsify(ctate));
38
- }
39
- /**
40
- * Безопасно от прокси заменяет текущее состояние в истории браузера
41
- */
42
- replaceStateSafe(url, ctate = this.get()) {
43
- // eslint-disable-next-line svelte/no-navigation-without-resolve
44
- replaceState(url, parsify(ctate));
45
- }
46
- //...
47
- /**
48
- * Возвращает текущий URL
49
- */
50
- getCurrentURL() {
51
- return new URL(window.location.href);
52
- }
53
- /**
54
- * Преобразует абсолютный URL в относительный
55
- */
56
- toRelative(url) {
57
- return url.toString().replace(url.origin, "");
58
- }
59
- //...
60
- /**
61
- * Очищает указанные параметры из текущего URL
62
- */
63
- clearParams(params) {
64
- return this.toRelative(clearParams(this.getCurrentURL(), params));
65
- }
66
- /**
67
- * Добавляет указанные параметры в текущий URL
68
- */
69
- pushParams(params) {
70
- return this.toRelative(pushParams(this.getCurrentURL(), params, true));
71
- }
72
- //...
73
- /**
74
- * Открывает новое мета-состояние с указанными параметрами
75
- */
76
- open(ctate, params = [], call) {
77
- this.push({ method: "open", state: ctate, params, call });
78
- }
79
- /**
80
- * Закрывает текущее мета-состояние с указанными параметрами
81
- */
82
- close(ctate, params = [], call) {
83
- if (this._queue.length > 0) {
84
- const last = this._queue[this._queue.length - 1];
85
- if (last.method === "close") {
86
- last.state = this.join(last.state, ctate);
87
- last.params = mergeClearParams(last.params, params);
88
- if (call) {
89
- if (last.call) {
90
- last.call = () => {
91
- last.call?.();
92
- call();
93
- };
94
- }
95
- else {
96
- last.call = call;
97
- }
98
- }
99
- return;
100
- }
101
- }
102
- this.push({ method: "close", state: ctate, params, call });
103
- }
104
- /**
105
- * Обработка очереди состояния
106
- */
107
- handle(item) {
108
- const ctate = this.join(this.get(), item.state);
109
- if (item.method === "open") {
110
- this.pushStateSafe(this.pushParams(item.params), ctate);
111
- }
112
- else {
113
- this.replaceStateSafe(this.clearParams(item.params), ctate);
114
- }
115
- void tick().then(() => item.call?.());
116
- }
117
- }
118
- export const stateCTX = new StateCTX();
@@ -1,12 +0,0 @@
1
- export interface ValueStateType<T = boolean | undefined> {
2
- /**
3
- * @reactive
4
- */
5
- value: T;
6
- get(): T;
7
- set(state: T): void;
8
- untrack<R>(call: (state: T) => R): R;
9
- }
10
- declare function ValueState<T = boolean>(): ValueStateType<T | undefined>;
11
- declare function ValueState<T = boolean>(initial: T): ValueStateType<T>;
12
- export { ValueState };
@@ -1,24 +0,0 @@
1
- import { untrack } from "svelte";
2
- function ValueState(initial) {
3
- let _value = $state(initial);
4
- return {
5
- get value() {
6
- return _value;
7
- },
8
- set value(state) {
9
- _value = state;
10
- },
11
- get() {
12
- return untrack(() => this.value);
13
- },
14
- set(state) {
15
- untrack(() => {
16
- _value = state;
17
- });
18
- },
19
- untrack(call) {
20
- return untrack(() => call(_value));
21
- },
22
- };
23
- }
24
- export { ValueState };