feat(editor): перетаскивание кнопки настроек комнаты (#645)

Кнопка сохраняет положение в пределах комнаты только на время сессии редактора,
корректно отменяется при pinch/cancel и учитывается подписями Resize.

Issue: #645
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-09-25 08:33:07 +03:00
parent 27ba3f2ee0
commit 62d0f50593
82 changed files with 1360 additions and 658 deletions
+13 -2
View File
@@ -334,8 +334,14 @@ export const LOW_HEADROOM_WARNING_BYTES = 15_000;
* неиспользуемые импорты; rollup выбрасывал их и раньше, но не всё: минус
* 1 593 Б gzip в стартовом графе. Факт оставляет 952 Б сверху и 1 048 Б до
* нижней границы; общий бюджет не меняется.
*
* 2026-09-25, #645: 290 400 → 291 000 (замер 290 022). Арбитраж второго
* touch-контакта с перетаскиваемой кнопкой комнаты обязан быть в eager-карточке:
* он передаёт начавшийся на кнопке жест существующему pinch-навигационному
* контуру. Факт оставляет 978 Б сверху и 1 022 Б до нижней границы; общий
* бюджет не меняется.
*/
export const INITIAL_VIEW_GZIP_CEILING = 290_400;
export const INITIAL_VIEW_GZIP_CEILING = 291_000;
export const INITIAL_VIEW_CEILING_BAND = 2_000;
/**
@@ -574,8 +580,13 @@ export const LAZY_FURNITURE_ART_GZIP_CEILING = 17_900;
* чистые функции пакета в `device-inbox.ts`, девять строк `device_inbox.*`
* на четыре локали — они в основных словарях, не в ленивых чанках #627.
* Центр оставляет 992 Б сверху и 1 008 Б до нижней границы полосы.
* - #645: 231 200 → 232 900 (замер 231 888, +1 680 Б к базе #618).
* Перетаскивание кнопки комнаты живёт только в ленивом редакторе: отдельный
* контроллер хранит сессионные позиции, ограничивает их геометрией комнаты
* и арбитрирует pointer/pinch/cancel. Центр оставляет 1 012 Б сверху и
* 988 Б до нижней границы полосы.
*/
export const LAZY_EDITOR_GZIP_CEILING = 231_200;
export const LAZY_EDITOR_GZIP_CEILING = 232_900;
export const LAZY_GRAPH_CEILING_BAND = 2_000;
/**
+1 -1
View File
@@ -4,5 +4,5 @@
"hostRefs": 4883,
"portPrivates": 94,
"harnessPrivates": 101,
"bundleBytes": 2515825
"bundleBytes": 2521909
}
+37 -2
View File
@@ -10677,8 +10677,8 @@ const MUTANT_DEFINITIONS = [
+ 'сломанной шестерёнке; фасад нажимает её по-настоящему и обязан это заметить (#629 AC6)',
patches: [{
file: 'src/houseplan-editor-runtime.ts',
find: ' @click=${(e: Event) => { e.stopPropagation(); this._openRoomEdit(r); }}>',
replace: ' @click=${(e: Event) => { e.stopPropagation(); }}>',
find: ' @click=${(e: MouseEvent) => this.roomGear.click(e, r)}>',
replace: ' @click=${(e: MouseEvent) => e.stopPropagation()}>',
}],
},
{
@@ -11981,6 +11981,41 @@ const MUTANT_DEFINITIONS = [
replace: ' <input type="checkbox" name=${name} value=${option.value} .checked=${option.value === value}',
}],
},
{
id: 'room-gear-drag-reopens-settings',
guard: 'node demo/smoke_room_gear_drag.mjs',
because: '#645 AC3: pointerup after moving the room-settings capsule must consume the '
+ 'browser synthetic click once; removing the barrier reopens the dialog over the element '
+ 'the user just uncovered',
patches: [{
file: 'src/room-gear-drag.ts',
find: ' this.suppressClickUntil = performance.now() + 700;',
replace: ' this.suppressClickUntil = 0; // mutant: drag click reopens settings',
}],
},
{
id: 'room-gear-second-touch-keeps-drag',
guard: 'node demo/smoke_room_gear_drag.mjs',
because: '#645 AC6: the second touch must cancel and roll back a room-button drag before '
+ 'the sequence becomes pinch navigation; skipping this hook leaves the capsule grabbed '
+ 'and may also activate it at gesture end',
patches: [{
file: 'src/houseplan-card.ts',
find: 'if (this._editorRuntime?._cancelRoomGearForMultitouch()) this._roomGearTouchNavigation = true;',
replace: ' void this._editorRuntime; // mutant: room-button drag survives second touch',
}],
},
{
id: 'resize-label-uses-old-room-gear-centre',
guard: 'node demo/smoke_resize_labels.mjs',
because: '#645 AC11: live Resize area labels must avoid the session position actually '
+ 'rendered for the room button, not reserve the now-empty automatic centre',
patches: [{
file: 'src/houseplan-editor-runtime.ts',
find: ' ? (this.roomGear.center(room, poly, space!.id) || poleOfInaccessibility(poly))',
replace: ' ? poleOfInaccessibility(poly) // mutant: ignore the moved room button',
}],
},
];
const mutationCardSource = readFileSync(join(repoRoot, 'src/houseplan-card.ts'), 'utf8');
+11
View File
@@ -365,6 +365,17 @@ export const SMOKE_LINKS = [
+ 'build before editor state is installed (#337), and that a stale cached entry shows a '
+ 'localized reload panel instead of dying silently (#353)',
},
{
symbols: [
'ROOM_GEAR_DRAG_THRESHOLD_PX', 'roomGearPointAllowed', 'roomGearAutoCenter',
'resolveRoomGearCenter', 'roomGearDragMoved', 'clampRoomGearPointAlongPath',
'RoomGearDragController', '_cancelRoomGearForMultitouch',
],
smokes: ['smoke_room_gear_drag.mjs', 'smoke_resize_labels.mjs'],
because: 'the #645 production gestures prove temporary room-button movement, click/drag '
+ 'arbitration, room-boundary clamping, cancel/multitouch rollback and session reset; the '
+ 'Resize smoke proves its live area labels avoid the actually rendered room button',
},
{
symbols: [
'placeResizeAreaLabel', 'resizeInwardNormal', 'resizeMeasuredEdges',