feat(tgu-ui): Shift+клик ближе к якорю сжимает выделение полосы
This commit is contained in:
@@ -781,7 +781,8 @@ export function TguSlotsTab({ range }: TguSlotsTabProps) {
|
||||
return !(slot && slotIsBusy(slot));
|
||||
});
|
||||
setSelectedKeys((current) => selectStripRange(current, members, anchorKey, targetKey));
|
||||
setAnchorKey(targetKey);
|
||||
// Якорь НЕ двигаем: остаётся первым кликом, чтобы повторный Shift+клик задавал диапазон
|
||||
// от того же якоря — ближе к нему «сжимал» выделение, дальше — расширял.
|
||||
return;
|
||||
}
|
||||
setSelectedKeys((current) =>
|
||||
|
||||
@@ -60,6 +60,20 @@ describe("selectStripRange", () => {
|
||||
expect([...next]).toEqual(["c"]);
|
||||
});
|
||||
|
||||
it("сжимает выделение: повторный диапазон ближе к якорю снимает хвост полосы", () => {
|
||||
// якорь "a", сначала растянули до "d" (a..d), потом Shift+клик по "b" → остаётся a..b, c и d сняты.
|
||||
const expanded = selectStripRange(new Set(), members, "a", "d");
|
||||
expect([...expanded].sort()).toEqual(["a", "b", "c", "d"]);
|
||||
const shrunk = selectStripRange(expanded, members, "a", "b");
|
||||
expect([...shrunk].sort()).toEqual(["a", "b"]);
|
||||
});
|
||||
|
||||
it("снимает хвост полосы, но не трогает выбор в других полосах", () => {
|
||||
const current = new Set(["a", "b", "c", "d", "x"]);
|
||||
const next = selectStripRange(current, members, "a", "b");
|
||||
expect([...next].sort()).toEqual(["a", "b", "x"]);
|
||||
});
|
||||
|
||||
it("сохраняет уже выбранное за пределами полосы", () => {
|
||||
const next = selectStripRange(new Set(["x"]), members, "a", "b");
|
||||
expect([...next].sort()).toEqual(["a", "b", "x"]);
|
||||
|
||||
@@ -40,15 +40,17 @@ export function selectionAfterCheck(
|
||||
}
|
||||
|
||||
/**
|
||||
* Новое множество выбора после жеста «полоса от первого к последнему»: добавляет всех членов
|
||||
* полосы между fromKey и toKey включительно (в порядке времени). Это ВЫДЕЛЕНИЕ, не toggle —
|
||||
* существующий выбор сохраняется. Жест ограничен одной полосой: вызывающий передаёт members
|
||||
* именно её (один КА, один крен, подряд по времени); граница полосы — гарантия «нельзя выделить
|
||||
* не полосу». Если fromKey или toKey не из members — выбор не меняется (страховка). Вход не мутируется.
|
||||
* Новое множество выбора после жеста «полоса от первого к последнему»: выбор полосы становится
|
||||
* РОВНО диапазоном [fromKey..toKey] (в порядке времени). Члены полосы вне диапазона снимаются —
|
||||
* так Shift+клик по слоту ближе к якорю «сжимает» выделение. Выбор за пределами полосы (другие
|
||||
* полосы/КА) сохраняется: снимаем/добавляем только ключи из members. Жест ограничен одной полосой:
|
||||
* вызывающий передаёт members именно её (один КА, один крен, подряд по времени); граница полосы —
|
||||
* гарантия «нельзя выделить не полосу». Если fromKey или toKey не из members — выбор не меняется
|
||||
* (страховка). Вход не мутируется.
|
||||
*
|
||||
* @param current Текущее множество выбранных ключей.
|
||||
* @param members Ключи членов полосы в порядке времени.
|
||||
* @param fromKey Ключ первого клика (якорь).
|
||||
* @param fromKey Ключ якоря (первый клик).
|
||||
* @param toKey Ключ второго клика.
|
||||
*/
|
||||
export function selectStripRange(
|
||||
@@ -63,7 +65,10 @@ export function selectStripRange(
|
||||
if (from < 0 || to < 0) return next
|
||||
const lo = Math.min(from, to)
|
||||
const hi = Math.max(from, to)
|
||||
for (let i = lo; i <= hi; i++) next.add(members[i]!)
|
||||
members.forEach((key, i) => {
|
||||
if (i >= lo && i <= hi) next.add(key)
|
||||
else next.delete(key)
|
||||
})
|
||||
return next
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user