@jsenv/navi 0.29.95 → 0.29.97
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 +709 -140
- package/dist/jsenv_navi.js.map +40 -2
- package/docs/control_object.md +47 -8
- package/package.json +1 -1
package/docs/control_object.md
CHANGED
|
@@ -177,7 +177,7 @@ 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
|
-
|
|
180
|
+
Five things follow, and each of them was paid for twice before being written
|
|
181
181
|
here:
|
|
182
182
|
|
|
183
183
|
- **the group's value has to be the view that carries the MOST.** Four seats say
|
|
@@ -188,15 +188,54 @@ here:
|
|
|
188
188
|
can be computed from;
|
|
189
189
|
- **the Map must name EVERY child**, the derived view included. A child the Map
|
|
190
190
|
does not name is left where it is — which reads as "the list never fills";
|
|
191
|
-
- **
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
+
- **and when the in-between cannot be avoided, the aggregate says so.** Two
|
|
216
|
+
people swapping seats means one leaves before the other arrives, whichever
|
|
217
|
+
order the writes take. What is avoidable is PUBLISHING that half-state: an
|
|
218
|
+
aggregate that returns **what the group already holds** says "not yet, ask me
|
|
219
|
+
again" — nothing is placed, nothing is handed to the row above, and the next
|
|
220
|
+
assembly publishes the whole answer. Returning `undefined` says the opposite
|
|
221
|
+
("there is no answer"), and wipes the row.
|
|
222
|
+
|
|
223
|
+
```js
|
|
224
|
+
// "not yet": the moving person is picked and seated nowhere, and it is not
|
|
225
|
+
// somebody who was just ticked — so this is a gesture in flight
|
|
226
|
+
const midMove = picked.some(
|
|
227
|
+
(id) => !seatedNow.includes(id) && lastAnswer.includes(id),
|
|
228
|
+
);
|
|
229
|
+
if (midMove) {
|
|
230
|
+
return lastAnswer; // what the group already holds
|
|
231
|
+
}
|
|
232
|
+
```
|
|
198
233
|
|
|
199
234
|
```jsx
|
|
235
|
+
// the seats are found by name, never as "everything that is not the list"
|
|
236
|
+
const seatChildren = (children) =>
|
|
237
|
+
SEAT_NAMES.map((name) => children.find((child) => child.name === name));
|
|
238
|
+
|
|
200
239
|
// the value IS the seating; the list is a view of it
|
|
201
240
|
<ControlGroup
|
|
202
241
|
aggregateChildStates={(children) => {…}} // seats, minus who the list dropped, plus who it added
|