@lightningtv/solid 3.1.14 → 3.1.16
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/src/core/dom-renderer/domRenderer.js +67 -10
- package/dist/src/core/dom-renderer/domRenderer.js.map +1 -1
- package/dist/src/primitives/KeepAlive.d.ts +7 -2
- package/dist/src/primitives/KeepAlive.jsx +108 -50
- package/dist/src/primitives/KeepAlive.jsx.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/core/dom-renderer/domRenderer.ts +79 -11
- package/src/primitives/KeepAlive.tsx +172 -66
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Route, RoutePreloadFuncArgs, RouteProps } from
|
|
1
|
+
import { Route, RoutePreloadFuncArgs, RouteProps } from '@solidjs/router';
|
|
2
2
|
import * as s from 'solid-js';
|
|
3
|
-
import { ElementNode } from
|
|
3
|
+
import { ElementNode, activeElement } from '@lightningtv/solid';
|
|
4
|
+
import { chainFunctions } from './utils/chainFunctions.js';
|
|
4
5
|
|
|
5
6
|
export interface KeepAliveElement {
|
|
6
7
|
id: string;
|
|
@@ -11,26 +12,56 @@ export interface KeepAliveElement {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
const keepAliveElements = new Map<string, KeepAliveElement>();
|
|
15
|
+
export const keepAliveRouteElements = new Map<string, KeepAliveElement>();
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
const _storeKeepAlive = (
|
|
18
|
+
map: Map<string, KeepAliveElement>,
|
|
19
|
+
element: KeepAliveElement,
|
|
17
20
|
): KeepAliveElement | undefined => {
|
|
18
|
-
if (
|
|
19
|
-
console.warn(
|
|
21
|
+
if (map.has(element.id)) {
|
|
22
|
+
console.warn(
|
|
23
|
+
`[KeepAlive] Element with id "${element.id}" already in cache.`,
|
|
24
|
+
);
|
|
20
25
|
return element;
|
|
21
26
|
}
|
|
22
|
-
|
|
27
|
+
map.set(element.id, element);
|
|
23
28
|
return element;
|
|
24
29
|
};
|
|
25
30
|
|
|
26
|
-
export const
|
|
27
|
-
|
|
31
|
+
export const storeKeepAlive = (element: KeepAliveElement) =>
|
|
32
|
+
_storeKeepAlive(keepAliveElements, element);
|
|
33
|
+
export const storeKeepAliveRoute = (element: KeepAliveElement) =>
|
|
34
|
+
_storeKeepAlive(keepAliveRouteElements, element);
|
|
35
|
+
|
|
36
|
+
const _removeKeepAlive = (
|
|
37
|
+
map: Map<string, KeepAliveElement>,
|
|
38
|
+
id: string,
|
|
39
|
+
): void => {
|
|
40
|
+
const element = map.get(id);
|
|
28
41
|
if (element) {
|
|
42
|
+
(element.children as unknown as ElementNode).destroy();
|
|
29
43
|
element.dispose();
|
|
30
|
-
|
|
44
|
+
map.delete(id);
|
|
31
45
|
}
|
|
32
46
|
};
|
|
33
47
|
|
|
48
|
+
export const removeKeepAlive = (id: string): void =>
|
|
49
|
+
_removeKeepAlive(keepAliveElements, id);
|
|
50
|
+
export const removeKeepAliveRoute = (id: string): void =>
|
|
51
|
+
_removeKeepAlive(keepAliveRouteElements, id);
|
|
52
|
+
|
|
53
|
+
const _clearKeepAlive = (map: Map<string, KeepAliveElement>): void => {
|
|
54
|
+
map.forEach((element) => {
|
|
55
|
+
(element.children as unknown as ElementNode).destroy();
|
|
56
|
+
element.dispose();
|
|
57
|
+
});
|
|
58
|
+
map.clear();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const clearKeepAlive = (): void => _clearKeepAlive(keepAliveElements);
|
|
62
|
+
export const clearKeepAliveRoute = (): void =>
|
|
63
|
+
_clearKeepAlive(keepAliveRouteElements);
|
|
64
|
+
|
|
34
65
|
interface KeepAliveProps {
|
|
35
66
|
id: string;
|
|
36
67
|
shouldDispose?: (key: string) => boolean;
|
|
@@ -40,8 +71,16 @@ interface KeepAliveProps {
|
|
|
40
71
|
}
|
|
41
72
|
|
|
42
73
|
function wrapChildren(props: s.ParentProps<KeepAliveProps>) {
|
|
43
|
-
const onRemove =
|
|
44
|
-
|
|
74
|
+
const onRemove =
|
|
75
|
+
props.onRemove ||
|
|
76
|
+
((elm: ElementNode) => {
|
|
77
|
+
elm.alpha = 0;
|
|
78
|
+
});
|
|
79
|
+
const onRender =
|
|
80
|
+
props.onRender ||
|
|
81
|
+
((elm: ElementNode) => {
|
|
82
|
+
elm.alpha = 1;
|
|
83
|
+
});
|
|
45
84
|
const transition = props.transition || { alpha: true };
|
|
46
85
|
|
|
47
86
|
return (
|
|
@@ -52,73 +91,140 @@ function wrapChildren(props: s.ParentProps<KeepAliveProps>) {
|
|
|
52
91
|
forwardFocus={0}
|
|
53
92
|
transition={transition}
|
|
54
93
|
{...props}
|
|
55
|
-
/>
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
56
96
|
}
|
|
57
97
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
existing = undefined;
|
|
65
|
-
}
|
|
98
|
+
const createKeepAliveComponent = (
|
|
99
|
+
map: Map<string, KeepAliveElement>,
|
|
100
|
+
storeFn: (element: KeepAliveElement) => KeepAliveElement | undefined,
|
|
101
|
+
) => {
|
|
102
|
+
return (props: s.ParentProps<KeepAliveProps>) => {
|
|
103
|
+
let existing = map.get(props.id);
|
|
66
104
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
children,
|
|
74
|
-
dispose,
|
|
75
|
-
});
|
|
76
|
-
return children;
|
|
77
|
-
});
|
|
78
|
-
} else if (existing && !existing.children) {
|
|
79
|
-
existing.children = s.runWithOwner(existing.owner, () => wrapChildren(props));
|
|
80
|
-
}
|
|
81
|
-
return existing.children;
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const KeepAliveRoute = <S extends string>(props: RouteProps<S> & {
|
|
85
|
-
id?: string,
|
|
86
|
-
path: string,
|
|
87
|
-
component: s.Component<RouteProps<S>>,
|
|
88
|
-
shouldDispose?: (key: string) => boolean,
|
|
89
|
-
onRemove?: ElementNode['onRemove'];
|
|
90
|
-
onRender?: ElementNode['onRender'];
|
|
91
|
-
transition?: ElementNode['transition'];
|
|
92
|
-
}) => {
|
|
93
|
-
const key = props.id || props.path;
|
|
94
|
-
|
|
95
|
-
const preload = props.preload ? (preloadProps: RoutePreloadFuncArgs) => {
|
|
96
|
-
let existing = keepAliveElements.get(key)
|
|
97
|
-
|
|
98
|
-
if (existing && props.shouldDispose?.(key)) {
|
|
105
|
+
if (
|
|
106
|
+
existing &&
|
|
107
|
+
(props.shouldDispose?.(props.id) ||
|
|
108
|
+
(existing.children as unknown as ElementNode)?.destroyed)
|
|
109
|
+
) {
|
|
110
|
+
(existing.children as unknown as ElementNode).destroy();
|
|
99
111
|
existing.dispose();
|
|
100
|
-
|
|
112
|
+
map.delete(props.id);
|
|
101
113
|
existing = undefined;
|
|
102
114
|
}
|
|
103
115
|
|
|
104
116
|
if (!existing) {
|
|
105
117
|
return s.createRoot((dispose) => {
|
|
106
|
-
|
|
107
|
-
|
|
118
|
+
const children = wrapChildren(props);
|
|
119
|
+
storeFn({
|
|
120
|
+
id: props.id,
|
|
108
121
|
owner: s.getOwner(),
|
|
122
|
+
children,
|
|
109
123
|
dispose,
|
|
110
|
-
children: null,
|
|
111
124
|
});
|
|
112
|
-
return
|
|
125
|
+
return children;
|
|
113
126
|
});
|
|
114
|
-
} else if (existing.children) {
|
|
115
|
-
|
|
127
|
+
} else if (existing && !existing.children) {
|
|
128
|
+
existing.children = s.runWithOwner(existing.owner, () =>
|
|
129
|
+
wrapChildren(props),
|
|
130
|
+
);
|
|
116
131
|
}
|
|
117
|
-
|
|
132
|
+
return existing.children;
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const KeepAlive = createKeepAliveComponent(
|
|
137
|
+
keepAliveElements,
|
|
138
|
+
storeKeepAlive,
|
|
139
|
+
);
|
|
140
|
+
const KeepAliveRouteInternal = createKeepAliveComponent(
|
|
141
|
+
keepAliveRouteElements,
|
|
142
|
+
storeKeepAliveRoute,
|
|
143
|
+
);
|
|
118
144
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
145
|
+
export const KeepAliveRoute = <S extends string>(
|
|
146
|
+
props: RouteProps<S> & {
|
|
147
|
+
id?: string;
|
|
148
|
+
path: string;
|
|
149
|
+
component: s.Component<RouteProps<S>>;
|
|
150
|
+
shouldDispose?: (key: string) => boolean;
|
|
151
|
+
onRemove?: ElementNode['onRemove'];
|
|
152
|
+
onRender?: ElementNode['onRender'];
|
|
153
|
+
transition?: ElementNode['transition'];
|
|
154
|
+
},
|
|
155
|
+
) => {
|
|
156
|
+
const key = props.id || props.path;
|
|
157
|
+
let savedFocusedElement: ElementNode | undefined;
|
|
158
|
+
|
|
159
|
+
const onRemove = chainFunctions(props.onRemove, (elm: ElementNode) => {
|
|
160
|
+
savedFocusedElement = activeElement() as ElementNode;
|
|
161
|
+
elm.alpha = 0;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const onRender = chainFunctions(props.onRender, (elm: ElementNode) => {
|
|
165
|
+
let isChild = false;
|
|
166
|
+
let current = savedFocusedElement;
|
|
167
|
+
while (current) {
|
|
168
|
+
if (current === elm) {
|
|
169
|
+
isChild = true;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
current = current.parent as ElementNode | undefined;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (isChild && savedFocusedElement) {
|
|
176
|
+
savedFocusedElement.setFocus();
|
|
177
|
+
} else {
|
|
178
|
+
elm.setFocus();
|
|
179
|
+
}
|
|
180
|
+
elm.alpha = 1;
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const preload = props.preload
|
|
184
|
+
? (preloadProps: RoutePreloadFuncArgs) => {
|
|
185
|
+
let existing = keepAliveRouteElements.get(key);
|
|
186
|
+
|
|
187
|
+
if (
|
|
188
|
+
existing &&
|
|
189
|
+
(props.shouldDispose?.(key) ||
|
|
190
|
+
(existing.children as unknown as ElementNode)?.destroyed)
|
|
191
|
+
) {
|
|
192
|
+
(existing.children as unknown as ElementNode).destroy();
|
|
193
|
+
existing.dispose();
|
|
194
|
+
keepAliveRouteElements.delete(key);
|
|
195
|
+
existing = undefined;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!existing) {
|
|
199
|
+
return s.createRoot((dispose) => {
|
|
200
|
+
storeKeepAliveRoute({
|
|
201
|
+
id: key,
|
|
202
|
+
owner: s.getOwner(),
|
|
203
|
+
dispose,
|
|
204
|
+
children: null,
|
|
205
|
+
});
|
|
206
|
+
return props.preload!(preloadProps);
|
|
207
|
+
});
|
|
208
|
+
} else if (existing.children) {
|
|
209
|
+
(existing.children as unknown as ElementNode)?.setFocus();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
: undefined;
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<Route
|
|
216
|
+
{...props}
|
|
217
|
+
preload={preload}
|
|
218
|
+
component={(childProps) => (
|
|
219
|
+
<KeepAliveRouteInternal
|
|
220
|
+
id={key}
|
|
221
|
+
onRemove={onRemove}
|
|
222
|
+
onRender={onRender}
|
|
223
|
+
transition={props.transition}
|
|
224
|
+
>
|
|
225
|
+
{props.component(childProps)}
|
|
226
|
+
</KeepAliveRouteInternal>
|
|
227
|
+
)}
|
|
228
|
+
/>
|
|
229
|
+
);
|
|
124
230
|
};
|