@jsenv/navi 0.29.229 → 0.29.230
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/dev/jsenv_navi.js +174 -143
- package/dist/dev/jsenv_navi.js.map +3 -3
- package/dist/jsenv_navi.js +174 -143
- package/dist/jsenv_navi.js.map +3 -3
- package/docs/scroll.md +9 -3
- package/package.json +1 -1
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -64129,158 +64129,163 @@ const ListSelectable = props => {
|
|
|
64129
64129
|
}
|
|
64130
64130
|
setCurrentId(initialEl.id);
|
|
64131
64131
|
}, []);
|
|
64132
|
-
|
|
64133
|
-
|
|
64134
|
-
|
|
64135
|
-
|
|
64136
|
-
|
|
64137
|
-
|
|
64138
|
-
|
|
64139
|
-
|
|
64140
|
-
|
|
64141
|
-
|
|
64142
|
-
|
|
64143
|
-
|
|
64144
|
-
|
|
64145
|
-
|
|
64146
|
-
|
|
64147
|
-
|
|
64148
|
-
|
|
64149
|
-
|
|
64150
|
-
|
|
64151
|
-
|
|
64152
|
-
|
|
64153
|
-
|
|
64154
|
-
|
|
64155
|
-
|
|
64156
|
-
|
|
64157
|
-
|
|
64158
|
-
|
|
64159
|
-
|
|
64160
|
-
|
|
64161
|
-
|
|
64162
|
-
const {
|
|
64163
|
-
id
|
|
64164
|
-
} = e.detail;
|
|
64165
|
-
if (id === undefined) {
|
|
64166
|
-
return;
|
|
64167
|
-
}
|
|
64168
|
-
const inputId = `${id}_input`;
|
|
64169
|
-
const childController = uiGroupStateController.findChildById(inputId);
|
|
64170
|
-
if (!childController) {
|
|
64171
|
-
return;
|
|
64172
|
-
}
|
|
64173
|
-
const list = ref.current;
|
|
64174
|
-
dispatchRequestInteraction(list, {
|
|
64175
|
-
event: e,
|
|
64176
|
-
name: "select",
|
|
64177
|
-
prevented: () => e.preventDefault(),
|
|
64178
|
-
// tell the requester that we don't want to select this item
|
|
64179
|
-
// Asked of the item too, not only of the list: an item can be the one
|
|
64180
|
-
// refusing (the list already holds all it accepts, see maxLength), and
|
|
64181
|
-
// it is the one that then says why.
|
|
64182
|
-
allowed: () => {
|
|
64183
|
-
dispatchRequestInteraction(childController.ref.current, {
|
|
64184
|
-
event: e,
|
|
64185
|
-
name: "select",
|
|
64186
|
-
prevented: () => e.preventDefault(),
|
|
64187
|
-
allowed: () => childController.setUIState(childController.value, e)
|
|
64188
|
-
});
|
|
64132
|
+
|
|
64133
|
+
// The group's contexts stand around the whole list, never between the <ul>
|
|
64134
|
+
// and the rows: the walk that gives the rows their places is over the <ul>'s
|
|
64135
|
+
// children, and a component sitting there is one child — every row would then
|
|
64136
|
+
// stand in a single slot, and reordering them (a search) would move nothing.
|
|
64137
|
+
const listVnode = jsx(ControlgroupChildrenWrapper, {
|
|
64138
|
+
...childrenWrapperProps,
|
|
64139
|
+
children: jsx(Next, {
|
|
64140
|
+
"navi-selectable": "",
|
|
64141
|
+
...listControlRootProps,
|
|
64142
|
+
...listControlProps,
|
|
64143
|
+
// "loading" is a control prop, so useControlgroupProps consumes it (into
|
|
64144
|
+
// aria-busy / the :-navi-loading pseudo state) and it does not survive
|
|
64145
|
+
// into the props below. ListUI needs it too — it is what makes the list
|
|
64146
|
+
// render skeleton rows instead of its (not yet known) items.
|
|
64147
|
+
loading: props.loading,
|
|
64148
|
+
name: undefined,
|
|
64149
|
+
value: undefined,
|
|
64150
|
+
defaultValue: undefined,
|
|
64151
|
+
selectable: undefined,
|
|
64152
|
+
multiple: undefined,
|
|
64153
|
+
deselectable: undefined,
|
|
64154
|
+
focusGroupDirection: undefined,
|
|
64155
|
+
focusGroupWrap: undefined
|
|
64156
|
+
// Track focus inside the list: whichever item gets focus becomes current.
|
|
64157
|
+
,
|
|
64158
|
+
onFocusIn: e => {
|
|
64159
|
+
const realInput = e.target.closest("[navi-selectable-real-input]");
|
|
64160
|
+
if (!realInput) {
|
|
64161
|
+
return;
|
|
64189
64162
|
}
|
|
64190
|
-
|
|
64191
|
-
|
|
64192
|
-
|
|
64193
|
-
|
|
64194
|
-
|
|
64195
|
-
|
|
64196
|
-
|
|
64197
|
-
|
|
64198
|
-
|
|
64199
|
-
|
|
64200
|
-
|
|
64201
|
-
|
|
64202
|
-
|
|
64203
|
-
|
|
64204
|
-
|
|
64205
|
-
|
|
64206
|
-
|
|
64207
|
-
|
|
64208
|
-
|
|
64209
|
-
|
|
64210
|
-
|
|
64211
|
-
|
|
64212
|
-
|
|
64213
|
-
|
|
64214
|
-
|
|
64215
|
-
|
|
64216
|
-
|
|
64217
|
-
|
|
64218
|
-
|
|
64219
|
-
|
|
64220
|
-
|
|
64221
|
-
|
|
64222
|
-
|
|
64223
|
-
|
|
64224
|
-
|
|
64163
|
+
const itemEl = realInput.closest("[navi-list-item-real]");
|
|
64164
|
+
if (itemEl && itemEl.id) {
|
|
64165
|
+
setCurrentId(itemEl.id, e);
|
|
64166
|
+
}
|
|
64167
|
+
},
|
|
64168
|
+
onnavi_request_select: e => {
|
|
64169
|
+
const {
|
|
64170
|
+
id
|
|
64171
|
+
} = e.detail;
|
|
64172
|
+
if (id === undefined) {
|
|
64173
|
+
return;
|
|
64174
|
+
}
|
|
64175
|
+
const inputId = `${id}_input`;
|
|
64176
|
+
const childController = uiGroupStateController.findChildById(inputId);
|
|
64177
|
+
if (!childController) {
|
|
64178
|
+
return;
|
|
64179
|
+
}
|
|
64180
|
+
const list = ref.current;
|
|
64181
|
+
dispatchRequestInteraction(list, {
|
|
64182
|
+
event: e,
|
|
64183
|
+
name: "select",
|
|
64184
|
+
prevented: () => e.preventDefault(),
|
|
64185
|
+
// tell the requester that we don't want to select this item
|
|
64186
|
+
// Asked of the item too, not only of the list: an item can be the one
|
|
64187
|
+
// refusing (the list already holds all it accepts, see maxLength), and
|
|
64188
|
+
// it is the one that then says why.
|
|
64189
|
+
allowed: () => {
|
|
64190
|
+
dispatchRequestInteraction(childController.ref.current, {
|
|
64191
|
+
event: e,
|
|
64192
|
+
name: "select",
|
|
64193
|
+
prevented: () => e.preventDefault(),
|
|
64194
|
+
allowed: () => childController.setUIState(childController.value, e)
|
|
64195
|
+
});
|
|
64196
|
+
}
|
|
64197
|
+
});
|
|
64198
|
+
},
|
|
64199
|
+
onnavi_request_unselect: e => {
|
|
64200
|
+
const {
|
|
64201
|
+
id
|
|
64202
|
+
} = e.detail;
|
|
64203
|
+
if (id === undefined) {
|
|
64204
|
+
return;
|
|
64205
|
+
}
|
|
64206
|
+
const inputId = `${id}_input`;
|
|
64207
|
+
const childController = uiGroupStateController.findChildById(inputId);
|
|
64208
|
+
if (!childController) {
|
|
64209
|
+
return;
|
|
64210
|
+
}
|
|
64211
|
+
const list = ref.current;
|
|
64212
|
+
dispatchRequestInteraction(list, {
|
|
64213
|
+
event: e,
|
|
64214
|
+
name: "unselect",
|
|
64215
|
+
prevented: () => e.preventDefault(),
|
|
64216
|
+
// tell the requester that we don't want to unselect this item
|
|
64217
|
+
allowed: () => childController.setUIState(undefined, e)
|
|
64218
|
+
});
|
|
64225
64219
|
}
|
|
64226
|
-
|
|
64227
|
-
|
|
64228
|
-
|
|
64229
|
-
|
|
64230
|
-
|
|
64231
|
-
|
|
64232
|
-
|
|
64233
|
-
|
|
64234
|
-
|
|
64235
|
-
|
|
64236
|
-
|
|
64237
|
-
|
|
64220
|
+
// "previous"/"next", not "up"/"down": a list is a line of items whichever
|
|
64221
|
+
// way it is laid out, and a horizontal one walks sideways. The keys that
|
|
64222
|
+
// drive it (arrows, Home/End) map onto that here, and so do the commands
|
|
64223
|
+
// (--navi-previous / --navi-next / --navi-first / --navi-last).
|
|
64224
|
+
,
|
|
64225
|
+
onnavi_request_nav: e => {
|
|
64226
|
+
const {
|
|
64227
|
+
goal
|
|
64228
|
+
} = e.detail;
|
|
64229
|
+
const navigableEls = getNavigableElements();
|
|
64230
|
+
if (navigableEls.length === 0) {
|
|
64231
|
+
return;
|
|
64232
|
+
}
|
|
64233
|
+
const currentId = currentIdRef.current;
|
|
64234
|
+
let currentIndex = -1;
|
|
64235
|
+
if (currentId) {
|
|
64236
|
+
currentIndex = navigableEls.findIndex(el => el.id === currentId);
|
|
64237
|
+
}
|
|
64238
|
+
let targetEl;
|
|
64239
|
+
if (goal === "first") {
|
|
64238
64240
|
targetEl = navigableEls[0];
|
|
64239
|
-
} else if (
|
|
64240
|
-
targetEl = navigableEls[currentIndex + 1];
|
|
64241
|
-
} else {
|
|
64241
|
+
} else if (goal === "last") {
|
|
64242
64242
|
targetEl = navigableEls[navigableEls.length - 1];
|
|
64243
|
+
} else if (goal === "next") {
|
|
64244
|
+
if (currentIndex === -1) {
|
|
64245
|
+
targetEl = navigableEls[0];
|
|
64246
|
+
} else if (currentIndex < navigableEls.length - 1) {
|
|
64247
|
+
targetEl = navigableEls[currentIndex + 1];
|
|
64248
|
+
} else {
|
|
64249
|
+
targetEl = navigableEls[navigableEls.length - 1];
|
|
64250
|
+
}
|
|
64251
|
+
} else if (goal === "previous") {
|
|
64252
|
+
if (currentIndex === -1) {
|
|
64253
|
+
targetEl = navigableEls[0];
|
|
64254
|
+
} else if (currentIndex > 0) {
|
|
64255
|
+
targetEl = navigableEls[currentIndex - 1];
|
|
64256
|
+
} else {
|
|
64257
|
+
targetEl = navigableEls[0];
|
|
64258
|
+
}
|
|
64243
64259
|
}
|
|
64244
|
-
|
|
64245
|
-
|
|
64246
|
-
targetEl = navigableEls[0];
|
|
64247
|
-
} else if (currentIndex > 0) {
|
|
64248
|
-
targetEl = navigableEls[currentIndex - 1];
|
|
64249
|
-
} else {
|
|
64250
|
-
targetEl = navigableEls[0];
|
|
64260
|
+
if (!targetEl) {
|
|
64261
|
+
return;
|
|
64251
64262
|
}
|
|
64252
|
-
|
|
64253
|
-
|
|
64254
|
-
|
|
64255
|
-
|
|
64256
|
-
|
|
64257
|
-
|
|
64258
|
-
|
|
64259
|
-
|
|
64260
|
-
|
|
64261
|
-
|
|
64262
|
-
|
|
64263
|
-
|
|
64264
|
-
|
|
64265
|
-
|
|
64266
|
-
|
|
64267
|
-
|
|
64268
|
-
|
|
64269
|
-
|
|
64270
|
-
|
|
64271
|
-
|
|
64263
|
+
setCurrentId(targetEl.id, e);
|
|
64264
|
+
dispatchCustomEvent(ref.current, "navi_request_scroll", {
|
|
64265
|
+
event: e,
|
|
64266
|
+
id: targetEl.id
|
|
64267
|
+
});
|
|
64268
|
+
},
|
|
64269
|
+
onnavi_request_activate: e => {
|
|
64270
|
+
const currentId = currentIdRef.current;
|
|
64271
|
+
if (!currentId) {
|
|
64272
|
+
return;
|
|
64273
|
+
}
|
|
64274
|
+
if (multiple || deselectable) {
|
|
64275
|
+
const inputId = `${currentId}_input`;
|
|
64276
|
+
const childController = uiGroupStateController.findChildById(inputId);
|
|
64277
|
+
const isSelected = childController && childController.uiState;
|
|
64278
|
+
dispatchCustomEvent(ref.current, isSelected ? "navi_request_unselect" : "navi_request_select", {
|
|
64279
|
+
event: e,
|
|
64280
|
+
id: currentId
|
|
64281
|
+
});
|
|
64282
|
+
return;
|
|
64283
|
+
}
|
|
64284
|
+
dispatchCustomEvent(ref.current, "navi_request_select", {
|
|
64272
64285
|
event: e,
|
|
64273
64286
|
id: currentId
|
|
64274
64287
|
});
|
|
64275
|
-
|
|
64276
|
-
}
|
|
64277
|
-
dispatchCustomEvent(ref.current, "navi_request_select", {
|
|
64278
|
-
event: e,
|
|
64279
|
-
id: currentId
|
|
64280
|
-
});
|
|
64281
|
-
},
|
|
64282
|
-
children: jsx(ControlgroupChildrenWrapper, {
|
|
64283
|
-
...childrenWrapperProps,
|
|
64288
|
+
},
|
|
64284
64289
|
children: props.children
|
|
64285
64290
|
})
|
|
64286
64291
|
});
|
|
@@ -65907,6 +65912,10 @@ const useListScrollSync = ({
|
|
|
65907
65912
|
const block = blockRequested || (event.type === "navi_displayed" ? "center" : "nearest");
|
|
65908
65913
|
const scrollToItemCall = `${getElementSignature(itemEl)}.scrollIntoView({ block: "${block}", container: "nearest" })`;
|
|
65909
65914
|
debugScroll(`${trigger} -> ${scrollToItemCall}`);
|
|
65915
|
+
// The list is going somewhere on purpose, so there is no view to hold
|
|
65916
|
+
// still any more: an anchor captured before this drop it, or it would
|
|
65917
|
+
// put the list back where it was the moment the rows move under it.
|
|
65918
|
+
anchorRef.current = null;
|
|
65910
65919
|
scrollIntoViewScoped(itemEl, {
|
|
65911
65920
|
container: getScroller(),
|
|
65912
65921
|
block
|
|
@@ -68004,6 +68013,28 @@ const createListVirtual = () => {
|
|
|
68004
68013
|
} else {
|
|
68005
68014
|
ownerIdsBySlot.set(slotId, [ownerId]);
|
|
68006
68015
|
}
|
|
68016
|
+
warnIfEveryRowInOneSlot(slotId);
|
|
68017
|
+
};
|
|
68018
|
+
// Rows that all stand in the same slot keep the order they first mounted in:
|
|
68019
|
+
// the walk is over the children the list is given, and a component holding
|
|
68020
|
+
// them is one child however many rows it renders. Everything about a place
|
|
68021
|
+
// then stops following what the caller writes — a search reordering the rows
|
|
68022
|
+
// moves nothing. Said once, and only for the shape that can be nothing else:
|
|
68023
|
+
// the list's whole content is one child, and several rows came out of it.
|
|
68024
|
+
let everyRowInOneSlotWarned = false;
|
|
68025
|
+
const warnIfEveryRowInOneSlot = slotId => {
|
|
68026
|
+
if (everyRowInOneSlotWarned) {
|
|
68027
|
+
return;
|
|
68028
|
+
}
|
|
68029
|
+
const rootSlotIds = slotIdsByParent.get(null);
|
|
68030
|
+
if (!rootSlotIds || rootSlotIds.length !== 1 || rootSlotIds[0] !== slotId) {
|
|
68031
|
+
return;
|
|
68032
|
+
}
|
|
68033
|
+
if (ownerIdsBySlot.get(slotId).length < 2) {
|
|
68034
|
+
return;
|
|
68035
|
+
}
|
|
68036
|
+
everyRowInOneSlotWarned = true;
|
|
68037
|
+
console.warn(`List: every row stands in the same slot, so they keep the order they first rendered in — reordering them (a search, a sort) will not move them. The list's rows must be its own children: give it the rows (or a <List.Items>), not a component rendering them.`);
|
|
68007
68038
|
};
|
|
68008
68039
|
const removeFromSlot = (slotId, ownerId) => {
|
|
68009
68040
|
const ownerIds = ownerIdsBySlot.get(slotId);
|