@ydant/transition 0.1.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/LICENSE +21 -0
- package/README.md +232 -0
- package/dist/Transition.d.ts +76 -0
- package/dist/TransitionGroup.d.ts +38 -0
- package/dist/global.d.ts +6 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.es.js +139 -0
- package/dist/index.umd.js +1 -0
- package/dist/utils.d.ts +37 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 cwd-k2
|
|
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,232 @@
|
|
|
1
|
+
# @ydant/transition
|
|
2
|
+
|
|
3
|
+
CSS transition components for Ydant.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @ydant/transition
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Transition (Enter-only)
|
|
14
|
+
|
|
15
|
+
For simple show/hide with enter animation only:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { div, button, text, on, type Component, type Slot } from "@ydant/core";
|
|
19
|
+
import { Transition } from "@ydant/transition";
|
|
20
|
+
|
|
21
|
+
const App: Component = () => {
|
|
22
|
+
let show = true;
|
|
23
|
+
let transitionSlot: Slot;
|
|
24
|
+
|
|
25
|
+
return div(function* () {
|
|
26
|
+
yield* button(() => [
|
|
27
|
+
on("click", () => {
|
|
28
|
+
show = !show;
|
|
29
|
+
transitionSlot.refresh(() =>
|
|
30
|
+
Transition({
|
|
31
|
+
show,
|
|
32
|
+
name: "fade",
|
|
33
|
+
children: () => div(() => [text("Fade me!")]),
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
36
|
+
}),
|
|
37
|
+
text("Toggle"),
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
transitionSlot = yield* div(() =>
|
|
41
|
+
Transition({
|
|
42
|
+
show,
|
|
43
|
+
name: "fade",
|
|
44
|
+
children: () => div(() => [text("Fade me!")]),
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### createTransition (Enter + Leave)
|
|
52
|
+
|
|
53
|
+
For full enter/leave animation support with programmatic control:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { div, button, text, on, classes, type Component } from "@ydant/core";
|
|
57
|
+
import { createTransition, type TransitionHandle } from "@ydant/transition";
|
|
58
|
+
|
|
59
|
+
const App: Component = () => {
|
|
60
|
+
let fadeTransition: TransitionHandle;
|
|
61
|
+
|
|
62
|
+
return div(function* () {
|
|
63
|
+
yield* button(function* () {
|
|
64
|
+
yield* on("click", async () => {
|
|
65
|
+
const isVisible = fadeTransition.slot.node.firstElementChild !== null;
|
|
66
|
+
await fadeTransition.setShow(!isVisible);
|
|
67
|
+
});
|
|
68
|
+
yield* text("Toggle");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
fadeTransition = yield* createTransition({
|
|
72
|
+
enter: "fade-enter",
|
|
73
|
+
enterFrom: "fade-enter-from",
|
|
74
|
+
enterTo: "fade-enter-to",
|
|
75
|
+
leave: "fade-leave",
|
|
76
|
+
leaveFrom: "fade-leave-from",
|
|
77
|
+
leaveTo: "fade-leave-to",
|
|
78
|
+
children: () => div(() => [text("Animated content")]),
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### CSS Classes
|
|
85
|
+
|
|
86
|
+
#### For `Transition` (name-based)
|
|
87
|
+
|
|
88
|
+
| Class | When Applied |
|
|
89
|
+
| --------------------- | -------------- |
|
|
90
|
+
| `{name}-enter` | Start of enter |
|
|
91
|
+
| `{name}-enter-active` | During enter |
|
|
92
|
+
| `{name}-enter-to` | End of enter |
|
|
93
|
+
| `{name}-leave` | Start of leave |
|
|
94
|
+
| `{name}-leave-active` | During leave |
|
|
95
|
+
| `{name}-leave-to` | End of leave |
|
|
96
|
+
|
|
97
|
+
#### For `createTransition` (explicit classes)
|
|
98
|
+
|
|
99
|
+
| Prop | When Applied |
|
|
100
|
+
| ----------- | -------------------------- |
|
|
101
|
+
| `enter` | During enter animation |
|
|
102
|
+
| `enterFrom` | Initial state before enter |
|
|
103
|
+
| `enterTo` | Final state after enter |
|
|
104
|
+
| `leave` | During leave animation |
|
|
105
|
+
| `leaveFrom` | Initial state before leave |
|
|
106
|
+
| `leaveTo` | Final state after leave |
|
|
107
|
+
|
|
108
|
+
### Example CSS
|
|
109
|
+
|
|
110
|
+
```css
|
|
111
|
+
/* For Transition (name="fade") */
|
|
112
|
+
.fade-enter-active,
|
|
113
|
+
.fade-leave-active {
|
|
114
|
+
transition: opacity 0.3s ease;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.fade-enter,
|
|
118
|
+
.fade-leave-to {
|
|
119
|
+
opacity: 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* For createTransition */
|
|
123
|
+
.fade-enter {
|
|
124
|
+
transition: opacity 300ms ease;
|
|
125
|
+
}
|
|
126
|
+
.fade-enter-from {
|
|
127
|
+
opacity: 0;
|
|
128
|
+
}
|
|
129
|
+
.fade-enter-to {
|
|
130
|
+
opacity: 1;
|
|
131
|
+
}
|
|
132
|
+
.fade-leave {
|
|
133
|
+
transition: opacity 300ms ease;
|
|
134
|
+
}
|
|
135
|
+
.fade-leave-from {
|
|
136
|
+
opacity: 1;
|
|
137
|
+
}
|
|
138
|
+
.fade-leave-to {
|
|
139
|
+
opacity: 0;
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### TransitionGroup
|
|
144
|
+
|
|
145
|
+
For animating lists of items:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { TransitionGroup } from "@ydant/transition";
|
|
149
|
+
|
|
150
|
+
const App: Component = () => {
|
|
151
|
+
const items = [{ id: 1, text: "Item 1" }];
|
|
152
|
+
|
|
153
|
+
return div(function* () {
|
|
154
|
+
const { slot, refresh } = yield* TransitionGroup({
|
|
155
|
+
name: "list",
|
|
156
|
+
items,
|
|
157
|
+
keyFn: (item) => item.id,
|
|
158
|
+
renderItem: (item) => div(() => [text(item.text)]),
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// To update:
|
|
162
|
+
// items.push({ id: 2, text: "Item 2" });
|
|
163
|
+
// refresh(items);
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## API
|
|
169
|
+
|
|
170
|
+
### Transition
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
function Transition(props: TransitionProps): ElementGenerator;
|
|
174
|
+
|
|
175
|
+
interface TransitionProps {
|
|
176
|
+
show: boolean;
|
|
177
|
+
name: string;
|
|
178
|
+
children: () => Render;
|
|
179
|
+
onEnter?: () => void;
|
|
180
|
+
onLeave?: () => void;
|
|
181
|
+
onAfterEnter?: () => void;
|
|
182
|
+
onAfterLeave?: () => void;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### createTransition
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
function* createTransition(
|
|
190
|
+
props: CreateTransitionProps
|
|
191
|
+
): Generator<unknown, TransitionHandle, Slot>;
|
|
192
|
+
|
|
193
|
+
interface CreateTransitionProps {
|
|
194
|
+
enter: string;
|
|
195
|
+
enterFrom: string;
|
|
196
|
+
enterTo: string;
|
|
197
|
+
leave: string;
|
|
198
|
+
leaveFrom: string;
|
|
199
|
+
leaveTo: string;
|
|
200
|
+
children: () => Render;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
interface TransitionHandle {
|
|
204
|
+
slot: Slot;
|
|
205
|
+
setShow(show: boolean): Promise<void>;
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### TransitionGroup
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
function TransitionGroup<T>(props: TransitionGroupProps<T>): ElementGenerator;
|
|
213
|
+
|
|
214
|
+
interface TransitionGroupProps<T> {
|
|
215
|
+
name: string;
|
|
216
|
+
items: T[];
|
|
217
|
+
keyFn: (item: T) => string | number;
|
|
218
|
+
renderItem: (item: T) => Render;
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Low-level APIs
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
function enterTransition(el: HTMLElement, props: EnterProps): Promise<void>;
|
|
226
|
+
function leaveTransition(el: HTMLElement, props: LeaveProps): Promise<void>;
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Module Structure
|
|
230
|
+
|
|
231
|
+
- `Transition.ts` - Single element transitions (Transition, createTransition)
|
|
232
|
+
- `TransitionGroup.ts` - List transitions
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ChildContent, Render } from '@ydant/core';
|
|
2
|
+
import { Slot, Element } from '@ydant/base';
|
|
3
|
+
export interface TransitionProps {
|
|
4
|
+
/** 要素を表示するかどうか */
|
|
5
|
+
show: boolean;
|
|
6
|
+
/** 入場トランジションの基本クラス */
|
|
7
|
+
enter?: string;
|
|
8
|
+
/** 入場開始時のクラス */
|
|
9
|
+
enterFrom?: string;
|
|
10
|
+
/** 入場終了時のクラス */
|
|
11
|
+
enterTo?: string;
|
|
12
|
+
/** 退場トランジションの基本クラス */
|
|
13
|
+
leave?: string;
|
|
14
|
+
/** 退場開始時のクラス */
|
|
15
|
+
leaveFrom?: string;
|
|
16
|
+
/** 退場終了時のクラス */
|
|
17
|
+
leaveTo?: string;
|
|
18
|
+
/** トランジション対象の子要素 */
|
|
19
|
+
children: () => ChildContent;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 入場トランジションを実行
|
|
23
|
+
*/
|
|
24
|
+
export declare function enterTransition(el: HTMLElement, props: TransitionProps): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* 退場トランジションを実行
|
|
27
|
+
*/
|
|
28
|
+
export declare function leaveTransition(el: HTMLElement, props: TransitionProps): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Transition コンポーネント
|
|
31
|
+
*
|
|
32
|
+
* show の変化に応じて enter アニメーションを実行する。
|
|
33
|
+
*
|
|
34
|
+
* 注意: 現在の実装では enter アニメーションのみサポート。
|
|
35
|
+
* leave アニメーションが必要な場合は `createTransition` を使用すること。
|
|
36
|
+
*
|
|
37
|
+
* @see createTransition - leave アニメーションをサポートする代替 API
|
|
38
|
+
*/
|
|
39
|
+
export declare function Transition(props: TransitionProps): Render;
|
|
40
|
+
/**
|
|
41
|
+
* 状態管理付き Transition コンポーネント
|
|
42
|
+
*
|
|
43
|
+
* leave アニメーションをサポートするために、
|
|
44
|
+
* 専用の refresh 関数を提供する。
|
|
45
|
+
*/
|
|
46
|
+
export interface TransitionHandle {
|
|
47
|
+
/** Transition の Slot */
|
|
48
|
+
slot: Slot;
|
|
49
|
+
/** show 状態を更新(アニメーション付き) */
|
|
50
|
+
setShow: (show: boolean) => Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
/** createTransition の戻り値型。yield* で使用し、TransitionHandle を返す。 */
|
|
53
|
+
export type TransitionInstruction = Generator<Element, TransitionHandle, Slot>;
|
|
54
|
+
/**
|
|
55
|
+
* 状態管理付き Transition を作成
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const transition = yield* createTransition({
|
|
60
|
+
* enter: "fade-enter",
|
|
61
|
+
* enterFrom: "fade-enter-from",
|
|
62
|
+
* enterTo: "fade-enter-to",
|
|
63
|
+
* leave: "fade-leave",
|
|
64
|
+
* leaveFrom: "fade-leave-from",
|
|
65
|
+
* leaveTo: "fade-leave-to",
|
|
66
|
+
* children: () => div(() => [text("Content")]),
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* // Show with animation
|
|
70
|
+
* await transition.setShow(true);
|
|
71
|
+
*
|
|
72
|
+
* // Hide with animation
|
|
73
|
+
* await transition.setShow(false);
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function createTransition(props: Omit<TransitionProps, "show">): TransitionInstruction;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Slot, ElementRender } from '@ydant/base';
|
|
2
|
+
export interface TransitionGroupProps<T> {
|
|
3
|
+
/** トランジション対象のアイテム配列 */
|
|
4
|
+
items: T[];
|
|
5
|
+
/** 各アイテムのユニークキーを返す関数 */
|
|
6
|
+
keyFn: (item: T) => string | number;
|
|
7
|
+
/** 入場トランジションの基本クラス */
|
|
8
|
+
enter?: string;
|
|
9
|
+
/** 入場開始時のクラス */
|
|
10
|
+
enterFrom?: string;
|
|
11
|
+
/** 入場終了時のクラス */
|
|
12
|
+
enterTo?: string;
|
|
13
|
+
/** 退場トランジションの基本クラス */
|
|
14
|
+
leave?: string;
|
|
15
|
+
/** 退場開始時のクラス */
|
|
16
|
+
leaveFrom?: string;
|
|
17
|
+
/** 退場終了時のクラス */
|
|
18
|
+
leaveTo?: string;
|
|
19
|
+
/** 各アイテムをレンダリングする関数(要素を返す必要がある) */
|
|
20
|
+
children: (item: T, index: number) => ElementRender;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* TransitionGroup コンポーネント
|
|
24
|
+
*
|
|
25
|
+
* keyed() と Slot.refresh() を組み合わせて、
|
|
26
|
+
* リスト要素の追加・削除時にトランジションを適用する。
|
|
27
|
+
*/
|
|
28
|
+
export declare function TransitionGroup<T>(props: TransitionGroupProps<T>): ElementRender;
|
|
29
|
+
/**
|
|
30
|
+
* TransitionGroup のリフレッシュ用ヘルパー(stateful)
|
|
31
|
+
*
|
|
32
|
+
* Slot.refresh() と組み合わせて使用する。
|
|
33
|
+
* 新しいアイテムリストを受け取り、トランジション付きで更新する。
|
|
34
|
+
*
|
|
35
|
+
* 削除されるアイテムには leave トランジションが適用され、
|
|
36
|
+
* トランジション完了後に DOM から削除される。
|
|
37
|
+
*/
|
|
38
|
+
export declare function createTransitionGroupRefresher<T>(props: Omit<TransitionGroupProps<T>, "items">): (slot: Slot, items: T[]) => void;
|
package/dist/global.d.ts
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/// <reference path="./global.d.ts" />
|
|
2
|
+
export type { TransitionProps, TransitionHandle, TransitionInstruction } from './Transition';
|
|
3
|
+
export type { TransitionGroupProps } from './TransitionGroup';
|
|
4
|
+
export { Transition, createTransition, enterTransition, leaveTransition } from './Transition';
|
|
5
|
+
export { TransitionGroup, createTransitionGroupRefresher } from './TransitionGroup';
|
package/dist/index.es.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { div as m, onMount as v, keyed as S } from "@ydant/base";
|
|
2
|
+
function c(e, t) {
|
|
3
|
+
t && e.classList.add(...t.split(" ").filter(Boolean));
|
|
4
|
+
}
|
|
5
|
+
function f(e, t) {
|
|
6
|
+
t && e.classList.remove(...t.split(" ").filter(Boolean));
|
|
7
|
+
}
|
|
8
|
+
function u(e) {
|
|
9
|
+
return new Promise((t) => {
|
|
10
|
+
const o = getComputedStyle(e), a = parseFloat(o.transitionDuration) * 1e3;
|
|
11
|
+
if (a === 0) {
|
|
12
|
+
t();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const r = () => {
|
|
16
|
+
e.removeEventListener("transitionend", r), t();
|
|
17
|
+
};
|
|
18
|
+
e.addEventListener("transitionend", r), setTimeout(t, a + 50);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async function T(e, t) {
|
|
22
|
+
c(e, t.enter), c(e, t.enterFrom), e.offsetHeight, await new Promise((o) => {
|
|
23
|
+
requestAnimationFrame(() => {
|
|
24
|
+
c(e, t.enterTo), f(e, t.enterFrom), o();
|
|
25
|
+
});
|
|
26
|
+
}), await u(e), f(e, t.enter), f(e, t.enterTo);
|
|
27
|
+
}
|
|
28
|
+
async function K(e, t) {
|
|
29
|
+
c(e, t.leave), c(e, t.leaveFrom), e.offsetHeight, await new Promise((o) => {
|
|
30
|
+
requestAnimationFrame(() => {
|
|
31
|
+
c(e, t.leaveTo), f(e, t.leaveFrom), o();
|
|
32
|
+
});
|
|
33
|
+
}), await u(e), f(e, t.leave), f(e, t.leaveTo);
|
|
34
|
+
}
|
|
35
|
+
const h = /* @__PURE__ */ new WeakMap();
|
|
36
|
+
function B(e) {
|
|
37
|
+
const { show: t, children: o } = e;
|
|
38
|
+
return m(function* () {
|
|
39
|
+
const a = yield* m(function* () {
|
|
40
|
+
t && (yield* o());
|
|
41
|
+
});
|
|
42
|
+
yield* v(() => {
|
|
43
|
+
const r = a.node;
|
|
44
|
+
let n = h.get(r);
|
|
45
|
+
n || (n = {
|
|
46
|
+
isShowing: !1,
|
|
47
|
+
isAnimating: !1,
|
|
48
|
+
childSlot: null
|
|
49
|
+
}, h.set(r, n));
|
|
50
|
+
const s = r.firstElementChild;
|
|
51
|
+
return t && !n.isShowing ? (n.isShowing = !0, s && T(s, e)) : !t && n.isShowing && !n.isAnimating && (n.isShowing = !1), () => {
|
|
52
|
+
h.delete(r);
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function* E(e) {
|
|
58
|
+
const { children: t } = e;
|
|
59
|
+
let o = !1, a = !1;
|
|
60
|
+
const r = function* () {
|
|
61
|
+
o && (yield* t());
|
|
62
|
+
}, n = yield* m(r);
|
|
63
|
+
return {
|
|
64
|
+
slot: n,
|
|
65
|
+
setShow: async (d) => {
|
|
66
|
+
if (!(d === o || a)) {
|
|
67
|
+
if (a = !0, d) {
|
|
68
|
+
o = !0, n.refresh(r);
|
|
69
|
+
const i = n.node.firstElementChild;
|
|
70
|
+
i && await T(i, e);
|
|
71
|
+
} else {
|
|
72
|
+
const i = n.node.firstElementChild;
|
|
73
|
+
i && await K(i, e), o = !1, n.refresh(r);
|
|
74
|
+
}
|
|
75
|
+
a = !1;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function g(e, t) {
|
|
81
|
+
c(e, t.enter), c(e, t.enterFrom), e.offsetHeight, requestAnimationFrame(() => {
|
|
82
|
+
f(e, t.enterFrom), c(e, t.enterTo);
|
|
83
|
+
}), await u(e), f(e, t.enter), f(e, t.enterTo);
|
|
84
|
+
}
|
|
85
|
+
async function A(e, t) {
|
|
86
|
+
if (!t.leave && !t.leaveFrom && !t.leaveTo) {
|
|
87
|
+
e.remove();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
c(e, t.leave), c(e, t.leaveFrom), e.offsetHeight, requestAnimationFrame(() => {
|
|
91
|
+
f(e, t.leaveFrom), c(e, t.leaveTo);
|
|
92
|
+
}), await u(e), e.remove();
|
|
93
|
+
}
|
|
94
|
+
function* k(e) {
|
|
95
|
+
const { items: t, keyFn: o, children: a } = e, r = /* @__PURE__ */ new Set();
|
|
96
|
+
for (const s of t)
|
|
97
|
+
r.add(o(s));
|
|
98
|
+
return yield* m(function* () {
|
|
99
|
+
for (let s = 0; s < t.length; s++) {
|
|
100
|
+
const d = t[s], i = o(d), l = yield* S(i, a)(d, s);
|
|
101
|
+
yield* v(() => {
|
|
102
|
+
g(l.node, e);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function q(e) {
|
|
108
|
+
const { keyFn: t, children: o } = e, a = {
|
|
109
|
+
prevItems: [],
|
|
110
|
+
elementsByKey: /* @__PURE__ */ new Map()
|
|
111
|
+
};
|
|
112
|
+
return (r, n) => {
|
|
113
|
+
const s = /* @__PURE__ */ new Set();
|
|
114
|
+
for (const i of n)
|
|
115
|
+
s.add(t(i));
|
|
116
|
+
const d = new Set(a.prevItems.map(t));
|
|
117
|
+
for (const i of d)
|
|
118
|
+
if (!s.has(i)) {
|
|
119
|
+
const l = a.elementsByKey.get(i);
|
|
120
|
+
l && (A(l, e), a.elementsByKey.delete(i));
|
|
121
|
+
}
|
|
122
|
+
r.refresh(function* () {
|
|
123
|
+
for (let i = 0; i < n.length; i++) {
|
|
124
|
+
const l = n[i], y = t(l), F = !d.has(y), w = yield* S(y, o)(l, i);
|
|
125
|
+
a.elementsByKey.set(y, w.node), F && (yield* v(() => {
|
|
126
|
+
g(w.node, e);
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
}), a.prevItems = [...n];
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
B as Transition,
|
|
134
|
+
k as TransitionGroup,
|
|
135
|
+
E as createTransition,
|
|
136
|
+
q as createTransitionGroupRefresher,
|
|
137
|
+
T as enterTransition,
|
|
138
|
+
K as leaveTransition
|
|
139
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(c,s){typeof exports=="object"&&typeof module<"u"?s(exports,require("@ydant/base")):typeof define=="function"&&define.amd?define(["exports","@ydant/base"],s):(c=typeof globalThis<"u"?globalThis:c||self,s(c.YdantTransition={},c.YdantBase))})(this,(function(c,s){"use strict";function d(e,n){n&&e.classList.add(...n.split(" ").filter(Boolean))}function u(e,n){n&&e.classList.remove(...n.split(" ").filter(Boolean))}function y(e){return new Promise(n=>{const o=getComputedStyle(e),a=parseFloat(o.transitionDuration)*1e3;if(a===0){n();return}const r=()=>{e.removeEventListener("transitionend",r),n()};e.addEventListener("transitionend",r),setTimeout(n,a+50)})}async function h(e,n){d(e,n.enter),d(e,n.enterFrom),e.offsetHeight,await new Promise(o=>{requestAnimationFrame(()=>{d(e,n.enterTo),u(e,n.enterFrom),o()})}),await y(e),u(e,n.enter),u(e,n.enterTo)}async function w(e,n){d(e,n.leave),d(e,n.leaveFrom),e.offsetHeight,await new Promise(o=>{requestAnimationFrame(()=>{d(e,n.leaveTo),u(e,n.leaveFrom),o()})}),await y(e),u(e,n.leave),u(e,n.leaveTo)}const v=new WeakMap;function F(e){const{show:n,children:o}=e;return s.div(function*(){const a=yield*s.div(function*(){n&&(yield*o())});yield*s.onMount(()=>{const r=a.node;let t=v.get(r);t||(t={isShowing:!1,isAnimating:!1,childSlot:null},v.set(r,t));const f=r.firstElementChild;return n&&!t.isShowing?(t.isShowing=!0,f&&h(f,e)):!n&&t.isShowing&&!t.isAnimating&&(t.isShowing=!1),()=>{v.delete(r)}})})}function*K(e){const{children:n}=e;let o=!1,a=!1;const r=function*(){o&&(yield*n())},t=yield*s.div(r);return{slot:t,setShow:async l=>{if(!(l===o||a)){if(a=!0,l){o=!0,t.refresh(r);const i=t.node.firstElementChild;i&&await h(i,e)}else{const i=t.node.firstElementChild;i&&await w(i,e),o=!1,t.refresh(r)}a=!1}}}}async function S(e,n){d(e,n.enter),d(e,n.enterFrom),e.offsetHeight,requestAnimationFrame(()=>{u(e,n.enterFrom),d(e,n.enterTo)}),await y(e),u(e,n.enter),u(e,n.enterTo)}async function A(e,n){if(!n.leave&&!n.leaveFrom&&!n.leaveTo){e.remove();return}d(e,n.leave),d(e,n.leaveFrom),e.offsetHeight,requestAnimationFrame(()=>{u(e,n.leaveFrom),d(e,n.leaveTo)}),await y(e),e.remove()}function*B(e){const{items:n,keyFn:o,children:a}=e,r=new Set;for(const f of n)r.add(o(f));return yield*s.div(function*(){for(let f=0;f<n.length;f++){const l=n[f],i=o(l),m=yield*s.keyed(i,a)(l,f);yield*s.onMount(()=>{S(m.node,e)})}})}function C(e){const{keyFn:n,children:o}=e,a={prevItems:[],elementsByKey:new Map};return(r,t)=>{const f=new Set;for(const i of t)f.add(n(i));const l=new Set(a.prevItems.map(n));for(const i of l)if(!f.has(i)){const m=a.elementsByKey.get(i);m&&(A(m,e),a.elementsByKey.delete(i))}r.refresh(function*(){for(let i=0;i<t.length;i++){const m=t[i],T=n(m),M=!l.has(T),g=yield*s.keyed(T,o)(m,i);a.elementsByKey.set(T,g.node),M&&(yield*s.onMount(()=>{S(g.node,e)}))}}),a.prevItems=[...t]}}c.Transition=F,c.TransitionGroup=B,c.createTransition=K,c.createTransitionGroupRefresher=C,c.enterTransition=h,c.leaveTransition=w,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})}));
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transition ユーティリティ関数
|
|
3
|
+
*
|
|
4
|
+
* Transition, TransitionGroup コンポーネントで共通使用される
|
|
5
|
+
* CSS クラス操作とトランジション待機のヘルパー関数。
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* 要素に CSS クラスを追加する
|
|
9
|
+
*
|
|
10
|
+
* スペース区切りのクラス文字列を分割して追加する。
|
|
11
|
+
* 空文字列や undefined は無視される。
|
|
12
|
+
*
|
|
13
|
+
* @param el - 対象の HTML 要素
|
|
14
|
+
* @param classes - スペース区切りのクラス文字列
|
|
15
|
+
*/
|
|
16
|
+
export declare function addClasses(el: HTMLElement, classes: string | undefined): void;
|
|
17
|
+
/**
|
|
18
|
+
* 要素から CSS クラスを削除する
|
|
19
|
+
*
|
|
20
|
+
* スペース区切りのクラス文字列を分割して削除する。
|
|
21
|
+
* 空文字列や undefined は無視される。
|
|
22
|
+
*
|
|
23
|
+
* @param el - 対象の HTML 要素
|
|
24
|
+
* @param classes - スペース区切りのクラス文字列
|
|
25
|
+
*/
|
|
26
|
+
export declare function removeClasses(el: HTMLElement, classes: string | undefined): void;
|
|
27
|
+
/**
|
|
28
|
+
* CSS トランジションの終了を待機する
|
|
29
|
+
*
|
|
30
|
+
* 要素の transitionDuration を取得し、transitionend イベントを待つ。
|
|
31
|
+
* duration が 0 の場合は即座に resolve する。
|
|
32
|
+
* 安全のため、duration + 50ms でタイムアウトを設定する。
|
|
33
|
+
*
|
|
34
|
+
* @param el - 対象の HTML 要素
|
|
35
|
+
* @returns トランジション終了時に resolve する Promise
|
|
36
|
+
*/
|
|
37
|
+
export declare function waitForTransition(el: HTMLElement): Promise<void>;
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ydant/transition",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Transition components for Ydant",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"animation",
|
|
7
|
+
"css",
|
|
8
|
+
"transition",
|
|
9
|
+
"ydant"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/cwd-k2/ydant#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/cwd-k2/ydant/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "cwd-k2",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/cwd-k2/ydant.git",
|
|
20
|
+
"directory": "packages/transition"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"main": "./dist/index.umd.js",
|
|
28
|
+
"module": "./dist/index.es.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"@ydant/dev": {
|
|
34
|
+
"types": "./src/index.ts",
|
|
35
|
+
"default": "./src/index.ts"
|
|
36
|
+
},
|
|
37
|
+
"import": "./dist/index.es.js",
|
|
38
|
+
"require": "./dist/index.umd.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@ydant/base": "0.1.0",
|
|
43
|
+
"@ydant/core": "0.1.0"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "vite build",
|
|
47
|
+
"typecheck": "tsc --noEmit"
|
|
48
|
+
}
|
|
49
|
+
}
|