solid-ctrl-flow 2.2.1 → 2.2.3
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/index.d.ts +11 -4
- package/dist/index.mjs +49 -28
- package/dist/index.umd.js +48 -27
- package/package.json +1 -1
- package/readMe.md +73 -1
package/dist/index.d.ts
CHANGED
|
@@ -43,6 +43,9 @@ declare type Equals = MemoOptions<unknown>["equals"];
|
|
|
43
43
|
* <e.Source>
|
|
44
44
|
* This text will be shown instead of `e.Dest`
|
|
45
45
|
* </e.Source>
|
|
46
|
+
*
|
|
47
|
+
* This would have been shown if there wasn't any `e.Dest`
|
|
48
|
+
* <e.Fallback />
|
|
46
49
|
* </div>
|
|
47
50
|
* </e.Joint>
|
|
48
51
|
* </>
|
|
@@ -54,7 +57,10 @@ export declare class Extractor {
|
|
|
54
57
|
Joint: (props: {
|
|
55
58
|
children?: JSX;
|
|
56
59
|
}) => JSX;
|
|
57
|
-
|
|
60
|
+
Fallback: () => JSX;
|
|
61
|
+
Dest: (props: {
|
|
62
|
+
hidden?: boolean | undefined;
|
|
63
|
+
}) => JSX;
|
|
58
64
|
Source: (props: Info) => JSX;
|
|
59
65
|
/**
|
|
60
66
|
* Returns the number of destinations available for the current {@link Extractor}.
|
|
@@ -174,9 +180,10 @@ declare type Standard<T> = ParentProps<{
|
|
|
174
180
|
}>;
|
|
175
181
|
|
|
176
182
|
/** Type of the data stored in the {@link Context} created by each {@link Extractor} */
|
|
177
|
-
declare
|
|
178
|
-
|
|
179
|
-
|
|
183
|
+
declare class State {
|
|
184
|
+
#private;
|
|
185
|
+
get sources(): OrderedLinkedList<Info>;
|
|
186
|
+
get destCount(): number;
|
|
180
187
|
shift(k: number): void;
|
|
181
188
|
force(): void;
|
|
182
189
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createMemo, splitProps, untrack, createRoot, getOwner, createComponent, Show, createContext, useContext,
|
|
1
|
+
import { createMemo, splitProps, untrack, createRoot, getOwner, createComponent, Show, createContext, useContext, createRenderEffect, on, onCleanup, For, createSignal, createSelector, equalFn, Match } from "solid-js";
|
|
2
2
|
function memoProps(obj, keys = Reflect.ownKeys(obj), equals = false) {
|
|
3
3
|
const out = {};
|
|
4
4
|
for (const elm of keys)
|
|
@@ -92,6 +92,28 @@ class OrderedLinkedListNode extends OrderedLinkedList {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
const COMPARATOR = (a, b) => (a.order ?? 0) - (b.order ?? 0);
|
|
95
|
+
const SOURCES_OPTS = {
|
|
96
|
+
internal: true,
|
|
97
|
+
equals: false
|
|
98
|
+
}, DEST_COUNT_OPTS = {
|
|
99
|
+
internal: true
|
|
100
|
+
};
|
|
101
|
+
class State {
|
|
102
|
+
#sources = createSignal(new OrderedLinkedList(), SOURCES_OPTS);
|
|
103
|
+
#destCount = createSignal(0, DEST_COUNT_OPTS);
|
|
104
|
+
get sources() {
|
|
105
|
+
return this.#sources[0]();
|
|
106
|
+
}
|
|
107
|
+
get destCount() {
|
|
108
|
+
return this.#destCount[0]();
|
|
109
|
+
}
|
|
110
|
+
shift(k) {
|
|
111
|
+
this.#destCount[1]((v) => v + k);
|
|
112
|
+
}
|
|
113
|
+
force() {
|
|
114
|
+
this.#sources[1]((v) => v);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
95
117
|
class Extractor {
|
|
96
118
|
constructor(name) {
|
|
97
119
|
this.ctx = createContext(void 0, {
|
|
@@ -100,6 +122,7 @@ class Extractor {
|
|
|
100
122
|
}
|
|
101
123
|
ctx;
|
|
102
124
|
Joint = Joint.bind(this);
|
|
125
|
+
Fallback = Fallback.bind(this);
|
|
103
126
|
Dest = Dest.bind(this);
|
|
104
127
|
Source = Source.bind(this);
|
|
105
128
|
/**
|
|
@@ -109,11 +132,11 @@ class Extractor {
|
|
|
109
132
|
*/
|
|
110
133
|
get getDestCount() {
|
|
111
134
|
const state = useContext(this.ctx);
|
|
112
|
-
return state && (() => state.
|
|
135
|
+
return state && (() => state.destCount);
|
|
113
136
|
}
|
|
114
137
|
}
|
|
115
138
|
function Joint(props) {
|
|
116
|
-
const state =
|
|
139
|
+
const state = new State();
|
|
117
140
|
return createComponent(this.ctx.Provider, {
|
|
118
141
|
value: state,
|
|
119
142
|
get children() {
|
|
@@ -121,12 +144,30 @@ function Joint(props) {
|
|
|
121
144
|
}
|
|
122
145
|
});
|
|
123
146
|
}
|
|
124
|
-
function
|
|
147
|
+
function Fallback() {
|
|
148
|
+
const _self$ = this;
|
|
149
|
+
const f = this.getDestCount;
|
|
150
|
+
return createComponent(Show, {
|
|
151
|
+
get when() {
|
|
152
|
+
return !f?.();
|
|
153
|
+
},
|
|
154
|
+
get children() {
|
|
155
|
+
return createComponent(_self$.Dest, {
|
|
156
|
+
hidden: true
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
function Dest(props) {
|
|
125
162
|
const state = useContext(this.ctx);
|
|
126
163
|
if (!state)
|
|
127
164
|
throw new Error("An extractor's destination must be inside one of its joints");
|
|
128
|
-
|
|
129
|
-
|
|
165
|
+
createRenderEffect(on(createMemo(() => props.hidden), (x) => {
|
|
166
|
+
if (x)
|
|
167
|
+
return;
|
|
168
|
+
onCleanup(() => state.shift(-1));
|
|
169
|
+
state.shift(1);
|
|
170
|
+
}));
|
|
130
171
|
return createComponent(For, {
|
|
131
172
|
get each() {
|
|
132
173
|
return [...state.sources];
|
|
@@ -139,8 +180,7 @@ function Source(props) {
|
|
|
139
180
|
if (!state)
|
|
140
181
|
throw new Error("An extractor's source must be inside one of its joints");
|
|
141
182
|
const {
|
|
142
|
-
sources
|
|
143
|
-
force
|
|
183
|
+
sources
|
|
144
184
|
} = state;
|
|
145
185
|
const order = createMemo(() => props.order);
|
|
146
186
|
const info = {
|
|
@@ -155,29 +195,10 @@ function Source(props) {
|
|
|
155
195
|
createRenderEffect(on(order, () => {
|
|
156
196
|
onCleanup(() => node.remove());
|
|
157
197
|
sources.add(node, COMPARATOR);
|
|
158
|
-
force();
|
|
198
|
+
state.force();
|
|
159
199
|
}));
|
|
160
200
|
return [];
|
|
161
201
|
}
|
|
162
|
-
function createState() {
|
|
163
|
-
const [getExtracting, setExtracting] = createSignal(0, {
|
|
164
|
-
internal: true
|
|
165
|
-
});
|
|
166
|
-
const [getSources, setSources] = createSignal(new OrderedLinkedList(), {
|
|
167
|
-
internal: true,
|
|
168
|
-
equals: false
|
|
169
|
-
});
|
|
170
|
-
return {
|
|
171
|
-
get sources() {
|
|
172
|
-
return getSources();
|
|
173
|
-
},
|
|
174
|
-
get extracting() {
|
|
175
|
-
return getExtracting();
|
|
176
|
-
},
|
|
177
|
-
shift: (k) => setExtracting((v) => v + k),
|
|
178
|
-
force: () => setSources((s) => s)
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
202
|
const ctx = createContext(void 0, {
|
|
182
203
|
name: "on-case"
|
|
183
204
|
});
|
package/dist/index.umd.js
CHANGED
|
@@ -95,6 +95,28 @@
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
const COMPARATOR = (a, b) => (a.order ?? 0) - (b.order ?? 0);
|
|
98
|
+
const SOURCES_OPTS = {
|
|
99
|
+
internal: true,
|
|
100
|
+
equals: false
|
|
101
|
+
}, DEST_COUNT_OPTS = {
|
|
102
|
+
internal: true
|
|
103
|
+
};
|
|
104
|
+
class State {
|
|
105
|
+
#sources = solidJs.createSignal(new OrderedLinkedList(), SOURCES_OPTS);
|
|
106
|
+
#destCount = solidJs.createSignal(0, DEST_COUNT_OPTS);
|
|
107
|
+
get sources() {
|
|
108
|
+
return this.#sources[0]();
|
|
109
|
+
}
|
|
110
|
+
get destCount() {
|
|
111
|
+
return this.#destCount[0]();
|
|
112
|
+
}
|
|
113
|
+
shift(k) {
|
|
114
|
+
this.#destCount[1]((v) => v + k);
|
|
115
|
+
}
|
|
116
|
+
force() {
|
|
117
|
+
this.#sources[1]((v) => v);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
98
120
|
class Extractor {
|
|
99
121
|
constructor(name) {
|
|
100
122
|
this.ctx = solidJs.createContext(void 0, {
|
|
@@ -103,6 +125,7 @@
|
|
|
103
125
|
}
|
|
104
126
|
ctx;
|
|
105
127
|
Joint = Joint.bind(this);
|
|
128
|
+
Fallback = Fallback.bind(this);
|
|
106
129
|
Dest = Dest.bind(this);
|
|
107
130
|
Source = Source.bind(this);
|
|
108
131
|
/**
|
|
@@ -112,11 +135,11 @@
|
|
|
112
135
|
*/
|
|
113
136
|
get getDestCount() {
|
|
114
137
|
const state = solidJs.useContext(this.ctx);
|
|
115
|
-
return state && (() => state.
|
|
138
|
+
return state && (() => state.destCount);
|
|
116
139
|
}
|
|
117
140
|
}
|
|
118
141
|
function Joint(props) {
|
|
119
|
-
const state =
|
|
142
|
+
const state = new State();
|
|
120
143
|
return solidJs.createComponent(this.ctx.Provider, {
|
|
121
144
|
value: state,
|
|
122
145
|
get children() {
|
|
@@ -124,12 +147,30 @@
|
|
|
124
147
|
}
|
|
125
148
|
});
|
|
126
149
|
}
|
|
127
|
-
function
|
|
150
|
+
function Fallback() {
|
|
151
|
+
const _self$ = this;
|
|
152
|
+
const f = this.getDestCount;
|
|
153
|
+
return solidJs.createComponent(solidJs.Show, {
|
|
154
|
+
get when() {
|
|
155
|
+
return !f?.();
|
|
156
|
+
},
|
|
157
|
+
get children() {
|
|
158
|
+
return solidJs.createComponent(_self$.Dest, {
|
|
159
|
+
hidden: true
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function Dest(props) {
|
|
128
165
|
const state = solidJs.useContext(this.ctx);
|
|
129
166
|
if (!state)
|
|
130
167
|
throw new Error("An extractor's destination must be inside one of its joints");
|
|
131
|
-
|
|
132
|
-
|
|
168
|
+
solidJs.createRenderEffect(solidJs.on(solidJs.createMemo(() => props.hidden), (x) => {
|
|
169
|
+
if (x)
|
|
170
|
+
return;
|
|
171
|
+
solidJs.onCleanup(() => state.shift(-1));
|
|
172
|
+
state.shift(1);
|
|
173
|
+
}));
|
|
133
174
|
return solidJs.createComponent(solidJs.For, {
|
|
134
175
|
get each() {
|
|
135
176
|
return [...state.sources];
|
|
@@ -142,8 +183,7 @@
|
|
|
142
183
|
if (!state)
|
|
143
184
|
throw new Error("An extractor's source must be inside one of its joints");
|
|
144
185
|
const {
|
|
145
|
-
sources
|
|
146
|
-
force
|
|
186
|
+
sources
|
|
147
187
|
} = state;
|
|
148
188
|
const order = solidJs.createMemo(() => props.order);
|
|
149
189
|
const info = {
|
|
@@ -158,29 +198,10 @@
|
|
|
158
198
|
solidJs.createRenderEffect(solidJs.on(order, () => {
|
|
159
199
|
solidJs.onCleanup(() => node.remove());
|
|
160
200
|
sources.add(node, COMPARATOR);
|
|
161
|
-
force();
|
|
201
|
+
state.force();
|
|
162
202
|
}));
|
|
163
203
|
return [];
|
|
164
204
|
}
|
|
165
|
-
function createState() {
|
|
166
|
-
const [getExtracting, setExtracting] = solidJs.createSignal(0, {
|
|
167
|
-
internal: true
|
|
168
|
-
});
|
|
169
|
-
const [getSources, setSources] = solidJs.createSignal(new OrderedLinkedList(), {
|
|
170
|
-
internal: true,
|
|
171
|
-
equals: false
|
|
172
|
-
});
|
|
173
|
-
return {
|
|
174
|
-
get sources() {
|
|
175
|
-
return getSources();
|
|
176
|
-
},
|
|
177
|
-
get extracting() {
|
|
178
|
-
return getExtracting();
|
|
179
|
-
},
|
|
180
|
-
shift: (k) => setExtracting((v) => v + k),
|
|
181
|
-
force: () => setSources((s) => s)
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
205
|
const ctx = solidJs.createContext(void 0, {
|
|
185
206
|
name: "on-case"
|
|
186
207
|
});
|
package/package.json
CHANGED
package/readMe.md
CHANGED
|
@@ -145,7 +145,79 @@ return <>
|
|
|
145
145
|
</a.Joint>
|
|
146
146
|
</>
|
|
147
147
|
```
|
|
148
|
-
The output of this code is ***1***, ***5***, 3, ***1***, ***5***, 4, 0, 2, ***8***, 7, ***8
|
|
148
|
+
The output of this code is ***1***, ***5***, 3, ***1***, ***5***, 4, 0, 2, ***8***, 7, ***8***.
|
|
149
|
+
<br />
|
|
150
|
+
You can detect the number of destinations available for a given extractor through `Extractor.getDestCount()`
|
|
151
|
+
```tsx
|
|
152
|
+
const e = new Extractor();
|
|
153
|
+
const [ g, s ] = createSignal(true);
|
|
154
|
+
return <>
|
|
155
|
+
{void untrack(() => {
|
|
156
|
+
// The function is `undefined` when we're not under an `Extractor.Joint`
|
|
157
|
+
console.log(e.getDestCount); //→ undefined
|
|
158
|
+
})}
|
|
159
|
+
<e.Joint>
|
|
160
|
+
{untrack(() => {
|
|
161
|
+
// The founction is returned by a getter that bounds it to the current context
|
|
162
|
+
const f = e.getDestCount!;
|
|
163
|
+
return <>
|
|
164
|
+
{untrack(() => {
|
|
165
|
+
// (This scope is not reactive, so it doesn't know about the destinations that will come up later)
|
|
166
|
+
console.log(f()); //→ 0
|
|
167
|
+
})}
|
|
168
|
+
|
|
169
|
+
<e.Dest />
|
|
170
|
+
{untrack(() => {
|
|
171
|
+
console.log(f()); //→ 1
|
|
172
|
+
})}
|
|
173
|
+
|
|
174
|
+
<e.Dest />
|
|
175
|
+
|
|
176
|
+
<Show when={g()}>
|
|
177
|
+
<e.Dest />
|
|
178
|
+
</Show>
|
|
179
|
+
|
|
180
|
+
<button onClick={() => s(x => !x)}>
|
|
181
|
+
Toggle
|
|
182
|
+
</button>
|
|
183
|
+
<br />
|
|
184
|
+
{/* This is reactive and will contain the number 2 or 3 depending on `g()` */}
|
|
185
|
+
{JSON.stringify(g())} - {f()}
|
|
186
|
+
|
|
187
|
+
<e.Joint>
|
|
188
|
+
{untrack(() => {
|
|
189
|
+
// Since `f()` is bound, it will return the destination count of ITS `Extractor.Joint`, not the closest one
|
|
190
|
+
console.log(f()); //→ 3
|
|
191
|
+
console.log(e.getDestCount!()); //→ 0
|
|
192
|
+
})}
|
|
193
|
+
</e.Joint>
|
|
194
|
+
</>
|
|
195
|
+
})}
|
|
196
|
+
</e.Joint>
|
|
197
|
+
</>
|
|
198
|
+
```
|
|
199
|
+
You can NOT do this to create a fallback destination for when there aren't any other
|
|
200
|
+
```tsx
|
|
201
|
+
return <>
|
|
202
|
+
<Show when={!someExtractor.getDestCount!()}>
|
|
203
|
+
<someExtractor.Dest />
|
|
204
|
+
</Show>
|
|
205
|
+
</>
|
|
206
|
+
```
|
|
207
|
+
Because it would start a strange loop due to which the new destination would disable itself. To do that you must use the `hidden` attribute, which will made sure that the destination is not considered by `Extractor.getDestCount()` at all
|
|
208
|
+
```tsx
|
|
209
|
+
return <>
|
|
210
|
+
<Show when={!someExtractor.getDestCount!()}>
|
|
211
|
+
<someExtractor.Dest hidden />
|
|
212
|
+
</Show>
|
|
213
|
+
</>
|
|
214
|
+
```
|
|
215
|
+
Due to this pattern being fairly common, there's the `Extractor.Fallback` component that does that exact thing
|
|
216
|
+
```tsx
|
|
217
|
+
return <>
|
|
218
|
+
<someExtractor.Fallback />
|
|
219
|
+
</>
|
|
220
|
+
```
|
|
149
221
|
|
|
150
222
|
## Utility
|
|
151
223
|
|