@nemigo/svelte 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,59 @@
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
+ private pushStateSafe;
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;
@@ -0,0 +1,116 @@
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
+ pushState(url, parsify(ctate));
37
+ }
38
+ /**
39
+ * Безопасно от прокси заменяет текущее состояние в истории браузера
40
+ */
41
+ replaceStateSafe(url, ctate = this.get()) {
42
+ replaceState(url, parsify(ctate));
43
+ }
44
+ //...
45
+ /**
46
+ * Возвращает текущий URL
47
+ */
48
+ getCurrentURL() {
49
+ return new URL(window.location.href);
50
+ }
51
+ /**
52
+ * Преобразует абсолютный URL в относительный
53
+ */
54
+ toRelative(url) {
55
+ return url.toString().replace(url.origin, "");
56
+ }
57
+ //...
58
+ /**
59
+ * Очищает указанные параметры из текущего URL
60
+ */
61
+ clearParams(params) {
62
+ return this.toRelative(clearParams(this.getCurrentURL(), params));
63
+ }
64
+ /**
65
+ * Добавляет указанные параметры в текущий URL
66
+ */
67
+ pushParams(params) {
68
+ return this.toRelative(pushParams(this.getCurrentURL(), params, true));
69
+ }
70
+ //...
71
+ /**
72
+ * Открывает новое мета-состояние с указанными параметрами
73
+ */
74
+ open(ctate, params = [], call) {
75
+ this.push({ method: "open", state: ctate, params, call });
76
+ }
77
+ /**
78
+ * Закрывает текущее мета-состояние с указанными параметрами
79
+ */
80
+ close(ctate, params = [], call) {
81
+ if (this._queue.length > 0) {
82
+ const last = this._queue[this._queue.length - 1];
83
+ if (last.method === "close") {
84
+ last.state = this.join(last.state, ctate);
85
+ last.params = mergeClearParams(last.params, params);
86
+ if (call) {
87
+ if (last.call) {
88
+ last.call = () => {
89
+ last.call?.();
90
+ call();
91
+ };
92
+ }
93
+ else {
94
+ last.call = call;
95
+ }
96
+ }
97
+ return;
98
+ }
99
+ }
100
+ this.push({ method: "close", state: ctate, params, call });
101
+ }
102
+ /**
103
+ * Обработка очереди состояния
104
+ */
105
+ handle(item) {
106
+ const ctate = this.join(this.get(), item.state);
107
+ if (item.method === "open") {
108
+ this.pushStateSafe(this.pushParams(item.params), ctate);
109
+ }
110
+ else {
111
+ this.replaceStateSafe(this.clearParams(item.params), ctate);
112
+ }
113
+ void tick().then(() => item.call?.());
114
+ }
115
+ }
116
+ export const stateCTX = new StateCTX();
@@ -0,0 +1,43 @@
1
+ import type { Property } from "csstype";
2
+ import { linear } from "svelte/easing";
3
+ import type { SlideParams, TransitionConfig } from "svelte/transition";
4
+ export interface ClassNameTransitionParams {
5
+ animationClassName: string;
6
+ /**
7
+ * @default "reverse"
8
+ */
9
+ reverseDirectionStyle?: Property.AnimationDirection;
10
+ /**
11
+ * @default ""
12
+ */
13
+ normalDirectionStyle?: Property.AnimationDirection;
14
+ /**
15
+ * @default 325
16
+ */
17
+ duration?: number;
18
+ }
19
+ export declare const classNameTransition: (node: HTMLElement, { animationClassName, reverseDirectionStyle, normalDirectionStyle, duration }: ClassNameTransitionParams) => TransitionConfig;
20
+ /**
21
+ * Слайд-анимация с добавлением лёгкого fade-эффекта
22
+ */
23
+ export declare function slide(node: Element, { delay, duration, easing, axis, classic }?: SlideParams & {
24
+ classic?: boolean;
25
+ }): TransitionConfig;
26
+ /**
27
+ * Микс-анимация из scale и translate с добавлением лёгкого fade-эффекта
28
+ */
29
+ export declare const upper: (node: HTMLElement, { delay, duration, x, y, opacity }: {
30
+ delay?: number | undefined;
31
+ duration?: number | undefined;
32
+ x?: number | undefined;
33
+ y?: number | undefined;
34
+ opacity?: number | undefined;
35
+ }) => TransitionConfig;
36
+ /**
37
+ * Просто анимация изменения размера через font-size (0 ~ 1)
38
+ */
39
+ export declare const fontSizeScale: (_: HTMLElement, { delay, duration, easing }?: {
40
+ delay?: number | undefined;
41
+ duration?: number | undefined;
42
+ easing?: typeof linear | undefined;
43
+ }) => TransitionConfig;
@@ -0,0 +1,132 @@
1
+ import { toRound } from "@nemigo/helpers/phymath";
2
+ import { linear, quadInOut, quadOut } from "svelte/easing";
3
+ import { slide as svelte_slide } from "svelte/transition";
4
+ export const classNameTransition = (node, { animationClassName, reverseDirectionStyle = "reverse", normalDirectionStyle = "", duration = 325 }) => {
5
+ let before = null;
6
+ let reversed = false;
7
+ const reverse = () => {
8
+ reversed = true;
9
+ node.style.animationDirection = reverseDirectionStyle;
10
+ };
11
+ const unreverse = () => {
12
+ reversed = false;
13
+ node.style.animationDirection = normalDirectionStyle;
14
+ };
15
+ return {
16
+ duration,
17
+ tick(t) {
18
+ if (t === before)
19
+ return;
20
+ if (before === null) {
21
+ node.classList.add(animationClassName);
22
+ if (t === 1)
23
+ reverse();
24
+ else if (t === 0)
25
+ unreverse();
26
+ }
27
+ else {
28
+ if (t === 1 || t === 0) {
29
+ node.classList.remove(animationClassName);
30
+ node.style.animationDirection = normalDirectionStyle;
31
+ before = null;
32
+ return;
33
+ }
34
+ if (before < t) {
35
+ if (reversed)
36
+ unreverse();
37
+ }
38
+ else {
39
+ if (!reversed)
40
+ reverse();
41
+ }
42
+ }
43
+ before = t;
44
+ },
45
+ };
46
+ };
47
+ //...
48
+ const css_delay = (t, v = 1 / 3) => {
49
+ if (t <= v)
50
+ return 0;
51
+ if (t >= 1)
52
+ return 1;
53
+ return (t - v) / (1 - v);
54
+ };
55
+ const css_boost = (t, v = 1 / 3) => {
56
+ if (t <= 0)
57
+ return 0;
58
+ if (t >= 1 - v)
59
+ return 1;
60
+ return t / (1 - v);
61
+ };
62
+ /**
63
+ * Слайд-анимация с добавлением лёгкого fade-эффекта
64
+ */
65
+ export function slide(node, { delay = 0, duration = 325, easing, axis = "y", classic } = {}) {
66
+ if (classic)
67
+ return svelte_slide(node, { delay, duration, easing, axis });
68
+ if (!easing)
69
+ easing = quadInOut;
70
+ const style = getComputedStyle(node);
71
+ const prop = axis === "y" ? "height" : "width";
72
+ const propValue = parseFloat(style[prop]);
73
+ const secProps = axis === "y" ? ["top", "bottom"] : ["left", "right"];
74
+ const capSecProps = secProps.map((e) => `${e[0].toUpperCase()}${e.slice(1)}`);
75
+ const padStart = parseFloat(style[`padding${capSecProps[0]}`]);
76
+ const padEnd = parseFloat(style[`padding${capSecProps[1]}`]);
77
+ const marStart = parseFloat(style[`margin${capSecProps[0]}`]);
78
+ const marEnd = parseFloat(style[`margin${capSecProps[1]}`]);
79
+ const borStart = parseFloat(style[`border${capSecProps[0]}Width`]);
80
+ const borEnd = parseFloat(style[`border${capSecProps[1]}Width`]);
81
+ return {
82
+ delay,
83
+ duration,
84
+ easing,
85
+ css: (t) => {
86
+ const boosted = css_boost(t, 2 / 5);
87
+ const delayed = css_delay(t, 1 / 3);
88
+ return `
89
+ overflow: hidden;
90
+ opacity: ${delayed};
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;
98
+ min-${prop}: 0
99
+ `;
100
+ },
101
+ };
102
+ }
103
+ //...
104
+ /**
105
+ * Микс-анимация из scale и translate с добавлением лёгкого fade-эффекта
106
+ */
107
+ export const upper = (node, { delay = 0, duration = 400, x = 0, y = 0, opacity = 0 }) => {
108
+ const style = getComputedStyle(node);
109
+ const target_opacity = +style.opacity;
110
+ const od = target_opacity * (1 - opacity);
111
+ return {
112
+ delay,
113
+ duration,
114
+ easing: quadOut,
115
+ css: (t, u) => {
116
+ return `
117
+ transform: scale(${toRound(0.6 + t / 2.5, 5)}) translate(${toRound((1 - t) * x)}px, ${toRound((1 - t) * y)}px);
118
+ opacity: ${toRound(target_opacity - od * u)};
119
+ `;
120
+ },
121
+ };
122
+ };
123
+ //...
124
+ /**
125
+ * Просто анимация изменения размера через font-size (0 ~ 1)
126
+ */
127
+ export const fontSizeScale = (_, { delay = 0, duration = 300, easing = linear } = {}) => ({
128
+ delay,
129
+ duration,
130
+ easing,
131
+ css: (t) => `font-size:${toRound(t, 3)}em;will-change:font-size`,
132
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nemigo/svelte",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "private": false,
5
5
  "author": {
6
6
  "name": "Vlad Logvin",
@@ -19,6 +19,10 @@
19
19
  "svelte": "./dist/value.svelte.js",
20
20
  "default": "./dist/value.svelte.js"
21
21
  },
22
+ "./kit/state": {
23
+ "types": "./dist/kit/state.d.ts",
24
+ "default": "./dist/kit/state.js"
25
+ },
22
26
  "./loader": {
23
27
  "types": "./dist/loader.d.ts",
24
28
  "default": "./dist/loader.js"
@@ -26,11 +30,19 @@
26
30
  },
27
31
  "peerDependencies": {
28
32
  "@nemigo/helpers": "^0.3.0",
33
+ "@sveltejs/kit": "^2.12.0",
29
34
  "svelte": "^5.0.0"
30
35
  },
36
+ "peerDependenciesMeta": {
37
+ "@sveltejs/kit": {
38
+ "optional": true
39
+ }
40
+ },
41
+ "dependencies": {
42
+ "csstype": "^3.0.0"
43
+ },
31
44
  "devDependencies": {
32
45
  "@nemigo/configs": "workspace:*",
33
- "@nemigo/helpers": "workspace:*",
34
- "svelte": "5.38.6"
46
+ "@nemigo/helpers": "workspace:*"
35
47
  }
36
48
  }