@qzsy/dsh-bridge 3.4.1 → 3.4.3
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/CHANGELOG.md +28 -0
- package/README.md +1 -1
- package/client/client.js +65 -8
- package/client/mobile.js +69 -12
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
+
## [v3.4.3] - 2026-11-02
|
|
4
|
+
|
|
5
|
+
### 🐛 修复
|
|
6
|
+
|
|
7
|
+
- **模型 sheet 默认不聚焦搜索框**:宿主打开模型菜单时会自动 focus「搜索模型」,iOS 键盘随即弹起、把 sheet 顶掉一半;现在 sheet 套用后立即以及 80/260ms 内自动 `blur`,键盘不会默认弹出。
|
|
8
|
+
- **保留手动搜索**:用户主动点搜索框(`pointerdown`/`touchstart`)后不再被 blur,需要搜索时仍可正常输入。
|
|
9
|
+
- 模型数量少的场景默认直接看到完整模型列表,不再被键盘遮挡。
|
|
10
|
+
|
|
11
|
+
### 🧪 验证
|
|
12
|
+
|
|
13
|
+
- 模拟宿主自动 focus:打开后 `activeElement` 从 input 回到 BODY,sheet 正常显示,4/4 通过;用户主动 pointerdown 后 focus 保持输入框。
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## [v3.4.2] - 2026-11-02
|
|
17
|
+
|
|
18
|
+
### 🐛 修复
|
|
19
|
+
|
|
20
|
+
- **侧滑跟手**:水平拖动期间动态注册非 passive `touchmove` 阻止页面横滑/边缘返回,抽屉真正 1:1 跟手;纵向滚动不拦截。
|
|
21
|
+
- **首滑不卡**:手机首屏后在屏幕外预热展开侧栏,第一次侧滑不再在手指下触发宿主重排/挂载完整会话列表。
|
|
22
|
+
- **起手不跳**:拖动起点与 CSS `-102%` 关闭位对齐,修掉第一帧约 6px 跳变。
|
|
23
|
+
- **内容不弹**:拖动期间也强制侧栏内容 `100%` 宽,松手时不再出现 `280px → 300px` 宽度跳变。
|
|
24
|
+
- **松手更轻**:打开距离阈值从 90px 降到约 66px、速度阈值降低;移除松手时重复的展开点击;`box-shadow` 改为过渡。
|
|
25
|
+
|
|
26
|
+
### 🧪 验证
|
|
27
|
+
|
|
28
|
+
- 真实触摸事件模拟:预热展开、dx=20 首帧 -286、水平移动 `defaultPrevented=true`、纵向不拦截、短滑 110px 吸附打开、阴影过渡,7/7 通过。
|
|
29
|
+
|
|
30
|
+
|
|
3
31
|
## [v3.4.1] - 2026-11-02
|
|
4
32
|
|
|
5
33
|
### 🐛 修复
|
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ dsh plugin --profile <name> add @qzsy/dsh-bridge
|
|
|
48
48
|
|
|
49
49
|
- 内容区占满屏宽,左上角「菜单」按钮打开会话 / 工作区 / 插件入口;
|
|
50
50
|
- 支持手势:左缘向右滑打开、抽屉内向左滑关闭,拖动时跟手,松手吸附;
|
|
51
|
-
- 模型切换器在手机上改为底部 sheet
|
|
51
|
+
- 模型切换器在手机上改为底部 sheet:全宽、抓手、遮罩,支持下拉/点遮罩关闭;默认不聚焦搜索框(不弹键盘),需要搜索时再点;
|
|
52
52
|
- 全面屏自动避开安全区:刘海 / 状态栏 / 底部 home indicator 不遮挡内容;
|
|
53
53
|
- 点遮罩、点会话行、按 Esc 或转回桌面宽度都会自动收起;
|
|
54
54
|
- 桌面端保持 DSH 原生布局,不受影响。
|
package/client/client.js
CHANGED
|
@@ -300,17 +300,19 @@ var MOBILE_DRAWER_CSS = `
|
|
|
300
300
|
transform: translateX(-102%) !important;
|
|
301
301
|
overflow: hidden !important;
|
|
302
302
|
overscroll-behavior: contain;
|
|
303
|
+
touch-action: pan-y;
|
|
303
304
|
will-change: transform;
|
|
304
305
|
}
|
|
305
306
|
/* \u9996\u5E27\u5148\u5C31\u4F4D\u3001\u4E0D\u64AD\u653E\u5165\u573A\u52A8\u753B\uFF0C\u907F\u514D\u9875\u9762\u52A0\u8F7D\u65F6\u4FA7\u680F\u4ECE 0 \u6ED1\u51FA */
|
|
306
307
|
body.qzsy-drawer-ready div[class*="_sidebarCol"] {
|
|
307
|
-
transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1) !important;
|
|
308
|
+
transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1), box-shadow 280ms ease !important;
|
|
308
309
|
}
|
|
309
310
|
body.qzsy-drawer-open div[class*="_sidebarCol"] {
|
|
310
311
|
transform: translateX(0) !important;
|
|
311
312
|
box-shadow: 8px 0 32px rgba(0, 0, 0, 0.18) !important;
|
|
312
313
|
}
|
|
313
|
-
body.qzsy-drawer-open div[class*="_sidebarCol"] > div > div[class*="_root"]
|
|
314
|
+
body.qzsy-drawer-open div[class*="_sidebarCol"] > div > div[class*="_root"],
|
|
315
|
+
body.qzsy-drawer-dragging div[class*="_sidebarCol"] > div > div[class*="_root"] {
|
|
314
316
|
width: 100% !important;
|
|
315
317
|
}
|
|
316
318
|
|
|
@@ -514,6 +516,17 @@ function setupMobileDrawer() {
|
|
|
514
516
|
let modelChainUntil = 0;
|
|
515
517
|
let modelDrag = null;
|
|
516
518
|
let modelDragHandlers = null;
|
|
519
|
+
const preventDrawerScroll = (event) => {
|
|
520
|
+
if (!gesture || !event.cancelable) return;
|
|
521
|
+
const touch = event.touches?.[0];
|
|
522
|
+
if (!touch) return;
|
|
523
|
+
const dx = touch.clientX - gesture.startX;
|
|
524
|
+
const dy = touch.clientY - gesture.startY;
|
|
525
|
+
if (Math.abs(dx) > 4 && Math.abs(dx) > Math.abs(dy) * 1.2) event.preventDefault();
|
|
526
|
+
};
|
|
527
|
+
const removeDrawerPrevent = () => {
|
|
528
|
+
window.removeEventListener("touchmove", preventDrawerScroll);
|
|
529
|
+
};
|
|
517
530
|
const ensureElements = () => {
|
|
518
531
|
if (disposed || !document.body) return;
|
|
519
532
|
injectStyles();
|
|
@@ -561,8 +574,9 @@ function setupMobileDrawer() {
|
|
|
561
574
|
}
|
|
562
575
|
};
|
|
563
576
|
const setDragProgress = (x, width) => {
|
|
577
|
+
const span = Math.max(1, width * 1.02);
|
|
564
578
|
document.body.style.setProperty("--qzsy-drawer-x", `${x}px`);
|
|
565
|
-
document.body.style.setProperty("--qzsy-drawer-progress", String(Math.max(0, Math.min(1, 1 - Math.abs(x) /
|
|
579
|
+
document.body.style.setProperty("--qzsy-drawer-progress", String(Math.max(0, Math.min(1, 1 - Math.abs(x) / span))));
|
|
566
580
|
};
|
|
567
581
|
const clearDrag = () => {
|
|
568
582
|
document.body.classList.remove(DRAGGING_CLASS);
|
|
@@ -789,6 +803,33 @@ function setupMobileDrawer() {
|
|
|
789
803
|
portal.classList.add("qzsy-model-sheet");
|
|
790
804
|
attachModelDrag(portal);
|
|
791
805
|
ensureModelBackdrop();
|
|
806
|
+
const input = portal.querySelector('input[placeholder*="\u641C\u7D22\u6A21\u578B"], input[placeholder*="Search model"], input[type="search"], input');
|
|
807
|
+
if (input) {
|
|
808
|
+
let userIntent = false;
|
|
809
|
+
const markUserIntent = () => {
|
|
810
|
+
userIntent = true;
|
|
811
|
+
};
|
|
812
|
+
input.addEventListener("pointerdown", markUserIntent, { once: true });
|
|
813
|
+
input.addEventListener("touchstart", markUserIntent, { once: true, passive: true });
|
|
814
|
+
const blurIfAutoFocused = () => {
|
|
815
|
+
if (!input.isConnected || userIntent) return;
|
|
816
|
+
if (document.activeElement === input) {
|
|
817
|
+
try {
|
|
818
|
+
input.blur();
|
|
819
|
+
} catch {
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
const onFocus = () => {
|
|
824
|
+
if (!userIntent) blurIfAutoFocused();
|
|
825
|
+
};
|
|
826
|
+
input.addEventListener("focus", onFocus);
|
|
827
|
+
blurIfAutoFocused();
|
|
828
|
+
window.requestAnimationFrame(blurIfAutoFocused);
|
|
829
|
+
window.setTimeout(blurIfAutoFocused, 80);
|
|
830
|
+
window.setTimeout(blurIfAutoFocused, 260);
|
|
831
|
+
window.setTimeout(() => input.removeEventListener("focus", onFocus), 900);
|
|
832
|
+
}
|
|
792
833
|
window.requestAnimationFrame(() => {
|
|
793
834
|
if (!disposed && modelPortal === portal) document.body.classList.add("qzsy-model-sheet-open");
|
|
794
835
|
});
|
|
@@ -888,6 +929,7 @@ function setupMobileDrawer() {
|
|
|
888
929
|
active: false,
|
|
889
930
|
dx: 0
|
|
890
931
|
};
|
|
932
|
+
window.addEventListener("touchmove", preventDrawerScroll, { passive: false });
|
|
891
933
|
return;
|
|
892
934
|
}
|
|
893
935
|
if (!sidebar.contains(event.target)) return;
|
|
@@ -901,6 +943,7 @@ function setupMobileDrawer() {
|
|
|
901
943
|
active: false,
|
|
902
944
|
dx: 0
|
|
903
945
|
};
|
|
946
|
+
window.addEventListener("touchmove", preventDrawerScroll, { passive: false });
|
|
904
947
|
};
|
|
905
948
|
const onTouchMove = (event) => {
|
|
906
949
|
if (modelPortal || !gesture || disposed) return;
|
|
@@ -912,14 +955,17 @@ function setupMobileDrawer() {
|
|
|
912
955
|
if (Math.abs(dx) < DRAG_THRESHOLD) return;
|
|
913
956
|
if (Math.abs(dx) < Math.abs(dy) * 1.2) {
|
|
914
957
|
gesture = null;
|
|
958
|
+
removeDrawerPrevent();
|
|
915
959
|
return;
|
|
916
960
|
}
|
|
917
961
|
if (gesture.mode === "open" && dx <= 0) {
|
|
918
962
|
gesture = null;
|
|
963
|
+
removeDrawerPrevent();
|
|
919
964
|
return;
|
|
920
965
|
}
|
|
921
966
|
if (gesture.mode === "close" && dx >= 0) {
|
|
922
967
|
gesture = null;
|
|
968
|
+
removeDrawerPrevent();
|
|
923
969
|
return;
|
|
924
970
|
}
|
|
925
971
|
gesture.active = true;
|
|
@@ -928,8 +974,12 @@ function setupMobileDrawer() {
|
|
|
928
974
|
}
|
|
929
975
|
const width = Math.max(1, gesture.width);
|
|
930
976
|
let x;
|
|
931
|
-
if (gesture.mode === "open")
|
|
932
|
-
|
|
977
|
+
if (gesture.mode === "open") {
|
|
978
|
+
const startOffset = -width * 1.02;
|
|
979
|
+
x = Math.max(startOffset, Math.min(0, startOffset + dx));
|
|
980
|
+
} else {
|
|
981
|
+
x = Math.max(-width, Math.min(0, dx));
|
|
982
|
+
}
|
|
933
983
|
gesture.dx = dx;
|
|
934
984
|
setDragProgress(x, width);
|
|
935
985
|
};
|
|
@@ -937,15 +987,15 @@ function setupMobileDrawer() {
|
|
|
937
987
|
if (!gesture) return;
|
|
938
988
|
const current = gesture;
|
|
939
989
|
gesture = null;
|
|
990
|
+
removeDrawerPrevent();
|
|
940
991
|
if (!current.active) return;
|
|
941
992
|
const endX = touch ? touch.clientX : current.startX + current.dx;
|
|
942
993
|
const dx = endX - current.startX;
|
|
943
994
|
const elapsed = Math.max(1, Date.now() - current.startT);
|
|
944
995
|
const velocity = dx / elapsed;
|
|
945
|
-
const threshold = Math.min(
|
|
946
|
-
const openNow = current.mode === "open" ? dx > threshold || velocity > 0.
|
|
996
|
+
const threshold = Math.min(80, Math.max(50, current.width * 0.22));
|
|
997
|
+
const openNow = current.mode === "open" ? dx > threshold || velocity > 0.35 : !(dx < -Math.max(40, threshold * 0.6) || velocity < -0.3);
|
|
947
998
|
document.body.classList.toggle(OPEN_CLASS, openNow);
|
|
948
|
-
if (openNow) ensureSidebarExpanded();
|
|
949
999
|
syncAria();
|
|
950
1000
|
suppressClickUntil = Date.now() + 250;
|
|
951
1001
|
window.requestAnimationFrame(clearDrag);
|
|
@@ -971,6 +1021,12 @@ function setupMobileDrawer() {
|
|
|
971
1021
|
window.requestAnimationFrame(() => {
|
|
972
1022
|
if (!disposed && document.body) document.body.classList.add("qzsy-drawer-ready");
|
|
973
1023
|
});
|
|
1024
|
+
const preExpandSidebar = () => {
|
|
1025
|
+
if (disposed || !isMobileViewport()) return;
|
|
1026
|
+
ensureSidebarExpanded();
|
|
1027
|
+
};
|
|
1028
|
+
window.setTimeout(preExpandSidebar, 600);
|
|
1029
|
+
window.setTimeout(preExpandSidebar, 1600);
|
|
974
1030
|
if (typeof MutationObserver === "function" && document.body) {
|
|
975
1031
|
observer = new MutationObserver(() => {
|
|
976
1032
|
if (!document.querySelector(`.${HEADER_CLASS}`) || !document.querySelector(`.${MENU_CLASS}`) || !document.querySelector(`.${BACKDROP_CLASS}`) || !document.getElementById(MOBILE_DRAWER_CSS_ID)) {
|
|
@@ -997,6 +1053,7 @@ function setupMobileDrawer() {
|
|
|
997
1053
|
window.removeEventListener("touchmove", onTouchMove);
|
|
998
1054
|
window.removeEventListener("touchend", onTouchEnd);
|
|
999
1055
|
window.removeEventListener("touchcancel", onTouchCancel);
|
|
1056
|
+
removeDrawerPrevent();
|
|
1000
1057
|
clearModelSheet();
|
|
1001
1058
|
clearDrag();
|
|
1002
1059
|
document.body?.classList.remove(OPEN_CLASS);
|
package/client/mobile.js
CHANGED
|
@@ -97,17 +97,19 @@ export const MOBILE_DRAWER_CSS = `
|
|
|
97
97
|
transform: translateX(-102%) !important;
|
|
98
98
|
overflow: hidden !important;
|
|
99
99
|
overscroll-behavior: contain;
|
|
100
|
+
touch-action: pan-y;
|
|
100
101
|
will-change: transform;
|
|
101
102
|
}
|
|
102
103
|
/* 首帧先就位、不播放入场动画,避免页面加载时侧栏从 0 滑出 */
|
|
103
104
|
body.qzsy-drawer-ready div[class*="_sidebarCol"] {
|
|
104
|
-
transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1) !important;
|
|
105
|
+
transition: transform 280ms cubic-bezier(0.16, 1, 0.3, 1), box-shadow 280ms ease !important;
|
|
105
106
|
}
|
|
106
107
|
body.qzsy-drawer-open div[class*="_sidebarCol"] {
|
|
107
108
|
transform: translateX(0) !important;
|
|
108
109
|
box-shadow: 8px 0 32px rgba(0, 0, 0, 0.18) !important;
|
|
109
110
|
}
|
|
110
|
-
body.qzsy-drawer-open div[class*="_sidebarCol"] > div > div[class*="_root"]
|
|
111
|
+
body.qzsy-drawer-open div[class*="_sidebarCol"] > div > div[class*="_root"],
|
|
112
|
+
body.qzsy-drawer-dragging div[class*="_sidebarCol"] > div > div[class*="_root"] {
|
|
111
113
|
width: 100% !important;
|
|
112
114
|
}
|
|
113
115
|
|
|
@@ -321,6 +323,19 @@ export function setupMobileDrawer() {
|
|
|
321
323
|
let modelDrag = null;
|
|
322
324
|
let modelDragHandlers = null;
|
|
323
325
|
|
|
326
|
+
const preventDrawerScroll = (event) => {
|
|
327
|
+
if (!gesture || !event.cancelable) return;
|
|
328
|
+
const touch = event.touches?.[0];
|
|
329
|
+
if (!touch) return;
|
|
330
|
+
const dx = touch.clientX - gesture.startX;
|
|
331
|
+
const dy = touch.clientY - gesture.startY;
|
|
332
|
+
if (Math.abs(dx) > 4 && Math.abs(dx) > Math.abs(dy) * 1.2) event.preventDefault();
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const removeDrawerPrevent = () => {
|
|
336
|
+
window.removeEventListener('touchmove', preventDrawerScroll);
|
|
337
|
+
};
|
|
338
|
+
|
|
324
339
|
const ensureElements = () => {
|
|
325
340
|
if (disposed || !document.body) return;
|
|
326
341
|
injectStyles();
|
|
@@ -371,8 +386,9 @@ export function setupMobileDrawer() {
|
|
|
371
386
|
};
|
|
372
387
|
|
|
373
388
|
const setDragProgress = (x, width) => {
|
|
389
|
+
const span = Math.max(1, width * 1.02);
|
|
374
390
|
document.body.style.setProperty('--qzsy-drawer-x', `${x}px`);
|
|
375
|
-
document.body.style.setProperty('--qzsy-drawer-progress', String(Math.max(0, Math.min(1, 1 - Math.abs(x) /
|
|
391
|
+
document.body.style.setProperty('--qzsy-drawer-progress', String(Math.max(0, Math.min(1, 1 - Math.abs(x) / span))));
|
|
376
392
|
};
|
|
377
393
|
|
|
378
394
|
const clearDrag = () => {
|
|
@@ -610,6 +626,30 @@ export function setupMobileDrawer() {
|
|
|
610
626
|
portal.classList.add('qzsy-model-sheet');
|
|
611
627
|
attachModelDrag(portal);
|
|
612
628
|
ensureModelBackdrop();
|
|
629
|
+
|
|
630
|
+
// 宿主菜单默认会聚焦「搜索模型」,手机上会直接弹起键盘把 sheet 顶掉一半。
|
|
631
|
+
// 移动端模型数量通常很少,默认不聚焦;用户主动点搜索框时再允许聚焦。
|
|
632
|
+
const input = portal.querySelector('input[placeholder*="搜索模型"], input[placeholder*="Search model"], input[type="search"], input');
|
|
633
|
+
if (input) {
|
|
634
|
+
let userIntent = false;
|
|
635
|
+
const markUserIntent = () => { userIntent = true; };
|
|
636
|
+
input.addEventListener('pointerdown', markUserIntent, { once: true });
|
|
637
|
+
input.addEventListener('touchstart', markUserIntent, { once: true, passive: true });
|
|
638
|
+
const blurIfAutoFocused = () => {
|
|
639
|
+
if (!input.isConnected || userIntent) return;
|
|
640
|
+
if (document.activeElement === input) {
|
|
641
|
+
try { input.blur(); } catch { /* 忽略 */ }
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
const onFocus = () => { if (!userIntent) blurIfAutoFocused(); };
|
|
645
|
+
input.addEventListener('focus', onFocus);
|
|
646
|
+
blurIfAutoFocused();
|
|
647
|
+
window.requestAnimationFrame(blurIfAutoFocused);
|
|
648
|
+
window.setTimeout(blurIfAutoFocused, 80);
|
|
649
|
+
window.setTimeout(blurIfAutoFocused, 260);
|
|
650
|
+
window.setTimeout(() => input.removeEventListener('focus', onFocus), 900);
|
|
651
|
+
}
|
|
652
|
+
|
|
613
653
|
window.requestAnimationFrame(() => {
|
|
614
654
|
if (!disposed && modelPortal === portal) document.body.classList.add('qzsy-model-sheet-open');
|
|
615
655
|
});
|
|
@@ -729,6 +769,7 @@ export function setupMobileDrawer() {
|
|
|
729
769
|
active: false,
|
|
730
770
|
dx: 0,
|
|
731
771
|
};
|
|
772
|
+
window.addEventListener('touchmove', preventDrawerScroll, { passive: false });
|
|
732
773
|
return;
|
|
733
774
|
}
|
|
734
775
|
|
|
@@ -743,6 +784,7 @@ export function setupMobileDrawer() {
|
|
|
743
784
|
active: false,
|
|
744
785
|
dx: 0,
|
|
745
786
|
};
|
|
787
|
+
window.addEventListener('touchmove', preventDrawerScroll, { passive: false });
|
|
746
788
|
};
|
|
747
789
|
|
|
748
790
|
const onTouchMove = (event) => {
|
|
@@ -755,9 +797,9 @@ export function setupMobileDrawer() {
|
|
|
755
797
|
if (!gesture.active) {
|
|
756
798
|
if (Math.abs(dx) < DRAG_THRESHOLD) return;
|
|
757
799
|
// 纵向为主:交还给宿主滚动,本次不拦截
|
|
758
|
-
if (Math.abs(dx) < Math.abs(dy) * 1.2) { gesture = null; return; }
|
|
759
|
-
if (gesture.mode === 'open' && dx <= 0) { gesture = null; return; }
|
|
760
|
-
if (gesture.mode === 'close' && dx >= 0) { gesture = null; return; }
|
|
800
|
+
if (Math.abs(dx) < Math.abs(dy) * 1.2) { gesture = null; removeDrawerPrevent(); return; }
|
|
801
|
+
if (gesture.mode === 'open' && dx <= 0) { gesture = null; removeDrawerPrevent(); return; }
|
|
802
|
+
if (gesture.mode === 'close' && dx >= 0) { gesture = null; removeDrawerPrevent(); return; }
|
|
761
803
|
gesture.active = true;
|
|
762
804
|
suppressClickUntil = Date.now() + 450;
|
|
763
805
|
document.body.classList.add(DRAGGING_CLASS);
|
|
@@ -765,8 +807,13 @@ export function setupMobileDrawer() {
|
|
|
765
807
|
|
|
766
808
|
const width = Math.max(1, gesture.width);
|
|
767
809
|
let x;
|
|
768
|
-
if (gesture.mode === 'open')
|
|
769
|
-
|
|
810
|
+
if (gesture.mode === 'open') {
|
|
811
|
+
// 与 CSS 的 -102% 起点对齐,避免起手第一帧跳 6px
|
|
812
|
+
const startOffset = -width * 1.02;
|
|
813
|
+
x = Math.max(startOffset, Math.min(0, startOffset + dx));
|
|
814
|
+
} else {
|
|
815
|
+
x = Math.max(-width, Math.min(0, dx));
|
|
816
|
+
}
|
|
770
817
|
gesture.dx = dx;
|
|
771
818
|
setDragProgress(x, width);
|
|
772
819
|
};
|
|
@@ -775,19 +822,19 @@ export function setupMobileDrawer() {
|
|
|
775
822
|
if (!gesture) return;
|
|
776
823
|
const current = gesture;
|
|
777
824
|
gesture = null;
|
|
825
|
+
removeDrawerPrevent();
|
|
778
826
|
if (!current.active) return;
|
|
779
827
|
|
|
780
828
|
const endX = touch ? touch.clientX : current.startX + current.dx;
|
|
781
829
|
const dx = endX - current.startX;
|
|
782
830
|
const elapsed = Math.max(1, Date.now() - current.startT);
|
|
783
831
|
const velocity = dx / elapsed;
|
|
784
|
-
const threshold = Math.min(
|
|
832
|
+
const threshold = Math.min(80, Math.max(50, current.width * 0.22));
|
|
785
833
|
const openNow = current.mode === 'open'
|
|
786
|
-
? dx > threshold || velocity > 0.
|
|
787
|
-
: !(dx < -Math.max(
|
|
834
|
+
? dx > threshold || velocity > 0.35
|
|
835
|
+
: !(dx < -Math.max(40, threshold * 0.6) || velocity < -0.3);
|
|
788
836
|
|
|
789
837
|
document.body.classList.toggle(OPEN_CLASS, openNow);
|
|
790
|
-
if (openNow) ensureSidebarExpanded();
|
|
791
838
|
syncAria();
|
|
792
839
|
suppressClickUntil = Date.now() + 250;
|
|
793
840
|
// 等一帧让浏览器接住当前拖动位置,再撤掉拖动样式做吸附动画
|
|
@@ -820,6 +867,15 @@ export function setupMobileDrawer() {
|
|
|
820
867
|
if (!disposed && document.body) document.body.classList.add('qzsy-drawer-ready');
|
|
821
868
|
});
|
|
822
869
|
|
|
870
|
+
// 预热:手机端首屏后把宿主侧栏展开好(它在屏幕外),这样第一次侧滑不会在
|
|
871
|
+
// 手指下触发宿主重排/挂载完整会话列表,起手更稳。
|
|
872
|
+
const preExpandSidebar = () => {
|
|
873
|
+
if (disposed || !isMobileViewport()) return;
|
|
874
|
+
ensureSidebarExpanded();
|
|
875
|
+
};
|
|
876
|
+
window.setTimeout(preExpandSidebar, 600);
|
|
877
|
+
window.setTimeout(preExpandSidebar, 1600);
|
|
878
|
+
|
|
823
879
|
if (typeof MutationObserver === 'function' && document.body) {
|
|
824
880
|
observer = new MutationObserver(() => {
|
|
825
881
|
if (!document.querySelector(`.${HEADER_CLASS}`) || !document.querySelector(`.${MENU_CLASS}`) || !document.querySelector(`.${BACKDROP_CLASS}`) || !document.getElementById(MOBILE_DRAWER_CSS_ID)) {
|
|
@@ -845,6 +901,7 @@ export function setupMobileDrawer() {
|
|
|
845
901
|
window.removeEventListener('touchmove', onTouchMove);
|
|
846
902
|
window.removeEventListener('touchend', onTouchEnd);
|
|
847
903
|
window.removeEventListener('touchcancel', onTouchCancel);
|
|
904
|
+
removeDrawerPrevent();
|
|
848
905
|
clearModelSheet();
|
|
849
906
|
clearDrag();
|
|
850
907
|
document.body?.classList.remove(OPEN_CLASS);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qzsy/dsh-bridge",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.3",
|
|
4
4
|
"description": "DSH 远程隧道云官方客户端插件:一条命令把本机 DeepSeek Harness 接入云端隧道(设备码绑定、短期令牌、本地门禁代理、HTTP/SSE/WebSocket 反向隧道)。",
|
|
5
|
-
"releaseNotes": "【v3.4.
|
|
5
|
+
"releaseNotes": "【v3.4.3】模型 sheet 默认不弹键盘\\n• 宿主打开模型菜单会自动聚焦搜索框,iOS 键盘把 sheet 顶掉一半;现在自动 blur\\n• 模型数量少时默认直接看到完整列表;需要搜索时主动点搜索框仍可输入\\n• 立即 / 80ms / 260ms 三次兜底 blur,不误伤用户主动点击",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "lib/index.js",
|
|
8
8
|
"exports": {
|