@jsenv/navi 0.29.94 → 0.29.96
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/jsenv_navi.js +530 -167
- package/dist/jsenv_navi.js.map +33 -2
- package/docs/control_object.md +61 -12
- package/package.json +1 -1
package/docs/control_object.md
CHANGED
|
@@ -177,18 +177,67 @@ it. It matters most inside a picker's popup, where nothing else would bring the
|
|
|
177
177
|
value back down: a picker's value IS what the control in its popup holds, so the
|
|
178
178
|
façade never echoes it back.
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
180
|
+
Four things follow, and each of them was paid for twice before being written
|
|
181
|
+
here:
|
|
182
|
+
|
|
183
|
+
- **the group's value has to be the view that carries the MOST.** Four seats say
|
|
184
|
+
who plays AND who sits where; a list of who plays says half of that. Make the
|
|
185
|
+
seating the value and the list is derived from it (`value.filter(Boolean)`);
|
|
186
|
+
make the list the value and every gesture on a seat has to be guessed at. The
|
|
187
|
+
rule to apply: between two views of one answer, the value is the one the other
|
|
188
|
+
can be computed from;
|
|
189
|
+
- **the Map must name EVERY child**, the derived view included. A child the Map
|
|
190
|
+
does not name is left where it is — which reads as "the list never fills";
|
|
191
|
+
- **name the children you WANT, never exclude the one you don't.** A group holds
|
|
192
|
+
more than the views: a search box, a filter, whatever the popup needs. Reading
|
|
193
|
+
the seats as "every child except the list" collects those too, and the value
|
|
194
|
+
ends up with five slots for four seats. Finding them by name says what it
|
|
195
|
+
means;
|
|
196
|
+
- **a gesture that moves two children must never leave the value in an
|
|
197
|
+
in-between.** Dragging somebody from one seat to another is one intention and
|
|
198
|
+
two writes, and the group aggregates between them: for one instant the person
|
|
199
|
+
is in the list and in no seat, which a value that IS the seating has no room
|
|
200
|
+
for. Measured, that instant costs the person — the aggregate drops them and
|
|
201
|
+
the distribute unticks them before the second write lands. Two ways out, and
|
|
202
|
+
the first is the one to prefer:
|
|
203
|
+
|
|
204
|
+
1. **write the group's value once.** `rowSignal.value = slots` with both seats
|
|
205
|
+
already moved: there is no in-between at all. Available when the row is
|
|
206
|
+
where the placement lives;
|
|
207
|
+
2. **write the destination first**, when the seats are the truth and must stay
|
|
208
|
+
separate signals. The person is somewhere at every observable moment (in
|
|
209
|
+
two seats for an instant, which the rule then resolves), instead of nowhere.
|
|
210
|
+
Source-first loses them — measured, and silently.
|
|
211
|
+
|
|
212
|
+
Wrapping the two writes in a signal `batch()` does NOT help: the group
|
|
213
|
+
aggregates on each child's change, not on the render that follows.
|
|
214
|
+
|
|
215
|
+
```jsx
|
|
216
|
+
// the seats are found by name, never as "everything that is not the list"
|
|
217
|
+
const seatChildren = (children) =>
|
|
218
|
+
SEAT_NAMES.map((name) => children.find((child) => child.name === name));
|
|
219
|
+
|
|
220
|
+
// the value IS the seating; the list is a view of it
|
|
221
|
+
<ControlGroup
|
|
222
|
+
aggregateChildStates={(children) => {…}} // seats, minus who the list dropped, plus who it added
|
|
223
|
+
distributeChildStates={(slots, children) =>
|
|
224
|
+
new Map([
|
|
225
|
+
...seats.map((seat, i) => [seat, slots[i]]),
|
|
226
|
+
[list, slots.filter(Boolean)],
|
|
227
|
+
])
|
|
228
|
+
}
|
|
229
|
+
>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
```js
|
|
233
|
+
// and a drag is one write
|
|
234
|
+
const moveTo = (from, to) => {
|
|
235
|
+
const slots = [...rowSignal.value];
|
|
236
|
+
slots[to] = slots[from];
|
|
237
|
+
slots[from] = undefined;
|
|
238
|
+
rowSignal.value = slots;
|
|
239
|
+
};
|
|
240
|
+
```
|
|
192
241
|
|
|
193
242
|
## One line, one key
|
|
194
243
|
|