@artenx/dshb 0.1.26 → 0.1.27

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/lib/client.js CHANGED
@@ -510,7 +510,8 @@ window.__ModuleLoader__.load({
510
510
  const dialogStyle = {
511
511
  width: "min(92vw, 560px)",
512
512
  maxWidth: "100%",
513
- maxHeight: "80vh",
513
+ maxHeight: "80dvh",
514
+ paddingBottom: "max(env(safe-area-inset-bottom), 12px)",
514
515
  overflow: "auto",
515
516
  overflowX: "hidden",
516
517
  background: "var(--dsw-alias-bg-layer-1)",
@@ -952,7 +953,8 @@ window.__ModuleLoader__.load({
952
953
  style: {
953
954
  width: "min(92vw, 600px)",
954
955
  maxWidth: "100%",
955
- maxHeight: "85vh",
956
+ maxHeight: "85dvh",
957
+ paddingBottom: "max(env(safe-area-inset-bottom), 12px)",
956
958
  overflow: "auto",
957
959
  overflowX: "hidden",
958
960
  background: "var(--dsw-alias-bg-layer-1)",
@@ -1129,7 +1131,7 @@ window.__ModuleLoader__.load({
1129
1131
  /* footer 容器各项间距 16px 偏松 */
1130
1132
  [data-phase] [class*="_root"][class*="osXY9a"] { gap: 8px !important; }
1131
1133
  /* footer 统计行窄屏可横向滑动看全,不溢出页面 */
1132
- [data-phase] [class*="_actions"] { max-width: 100% !important; overflow-x: auto !important; scrollbar-width: none; touch-action: pan-x pan-y !important; }
1134
+ [data-phase] [class*="_actions"] { max-width: 100% !important; overflow-x: auto !important; scrollbar-width: none; touch-action: pan-x pan-y pinch-zoom !important; }
1133
1135
  [data-phase] [class*="_actions"]::-webkit-scrollbar { display: none; }
1134
1136
 
1135
1137
  /* 模型切换菜单:名称完整展示,长名称在菜单项内换行。 */
@@ -1183,7 +1185,7 @@ window.__ModuleLoader__.load({
1183
1185
  overflow-x: auto !important;
1184
1186
  -webkit-overflow-scrolling: touch;
1185
1187
  scrollbar-width: none;
1186
- touch-action: pan-x pan-y !important;
1188
+ touch-action: pan-x pan-y pinch-zoom !important;
1187
1189
  }
1188
1190
  [data-phase] [class*="resultBlockText"]::-webkit-scrollbar,
1189
1191
  [data-phase] [class*="payload"]::-webkit-scrollbar,
@@ -1201,7 +1203,7 @@ window.__ModuleLoader__.load({
1201
1203
  overflow-x: auto !important;
1202
1204
  -webkit-overflow-scrolling: touch;
1203
1205
  scrollbar-width: none;
1204
- touch-action: pan-x pan-y !important;
1206
+ touch-action: pan-x pan-y pinch-zoom !important;
1205
1207
  }
1206
1208
  [data-phase] [class*="jsonPayload"]::-webkit-scrollbar,
1207
1209
  [data-phase] [class*="jsonPreview"]::-webkit-scrollbar,
@@ -1224,7 +1226,7 @@ window.__ModuleLoader__.load({
1224
1226
  overflow-x: auto !important;
1225
1227
  -webkit-overflow-scrolling: touch;
1226
1228
  scrollbar-width: none;
1227
- touch-action: pan-x pan-y !important;
1229
+ touch-action: pan-x pan-y pinch-zoom !important;
1228
1230
  }
1229
1231
  /* xterm uses a transparent helper textarea for all terminal input. Keep it
1230
1232
  focusable and non-zero-sized so mobile browsers can present their keyboard. */
@@ -1251,7 +1253,7 @@ window.__ModuleLoader__.load({
1251
1253
  max-width: 100% !important;
1252
1254
  overflow-x: auto !important;
1253
1255
  overscroll-behavior-x: contain;
1254
- touch-action: pan-x pan-y !important;
1256
+ touch-action: pan-x pan-y pinch-zoom !important;
1255
1257
  }
1256
1258
  [data-phase] [class*="_prompt_1gdtu_"],
1257
1259
  [data-phase] [class*="_promptLine_1gdtu_"],
@@ -1273,7 +1275,7 @@ window.__ModuleLoader__.load({
1273
1275
  overflow-x: auto !important;
1274
1276
  -webkit-overflow-scrolling: touch;
1275
1277
  scrollbar-width: none;
1276
- touch-action: pan-x pan-y !important;
1278
+ touch-action: pan-x pan-y pinch-zoom !important;
1277
1279
  }
1278
1280
  [data-phase] [class*="_output_1gdtu_"]::-webkit-scrollbar { display: none !important; }
1279
1281
  [data-phase] [class*="_line_1gdtu_"] {
@@ -1286,7 +1288,7 @@ window.__ModuleLoader__.load({
1286
1288
  [data-phase] [class*="_copyButton_"] { touch-action: manipulation !important; }
1287
1289
  [data-phase] [class*="_copyAnchor_"],
1288
1290
  [data-phase] [class*="_body_1ye18_"],
1289
- [data-phase] [class*="_root_4qrvp_"] { touch-action: pan-x pan-y !important; }
1291
+ [data-phase] [class*="_root_4qrvp_"] { touch-action: pan-x pan-y pinch-zoom !important; }
1290
1292
 
1291
1293
  /* 上下文用量弹窗(ContextMeter .JObwrW_panel):上游 dsh-client-ui-trajectory 的
1292
1294
  [class*="panel"] 全局规则给它加了 max-width:100%!important,命中本弹窗,使宽度
@@ -1340,10 +1342,19 @@ window.__ModuleLoader__.load({
1340
1342
  z-index: 2 !important;
1341
1343
  display: inline-flex !important;
1342
1344
  align-items: center; justify-content: center;
1343
- width: 28px; height: 28px;
1345
+ width: 32px; height: 32px;
1344
1346
  padding: 0; border: none; background: none; cursor: pointer; color: inherit;
1345
1347
  -webkit-tap-highlight-color: transparent;
1346
1348
  }
1349
+ /* 触控命中区扩展:视觉尺寸不变,可点区域扩到 ~44px(Apple HIG 建议值) */
1350
+ [${FRAME_ATTR}="toggle"]::after,
1351
+ [${FRAME_ATTR}="fab"]::after,
1352
+ [class*="_iconButton"]::after {
1353
+ content: "";
1354
+ position: absolute;
1355
+ inset: -7px;
1356
+ }
1357
+ [class*="_iconButton"] { position: relative !important; }
1347
1358
 
1348
1359
  /* 首页/hero(无活跃会话,session header 不存在)的抽屉切换 FAB:
1349
1360
  浮在顶部相机带下方,避免与 hero 头部内容重叠 */
@@ -1354,7 +1365,7 @@ window.__ModuleLoader__.load({
1354
1365
  z-index: 21 !important;
1355
1366
  display: inline-flex !important;
1356
1367
  align-items: center; justify-content: center;
1357
- width: 38px; height: 38px;
1368
+ width: 44px; height: 44px;
1358
1369
  padding: 0;
1359
1370
  border: 1px solid var(--dsw-alias-border-l1, rgba(0, 0, 0, .12)) !important;
1360
1371
  border-radius: 50% !important;
@@ -1364,6 +1375,30 @@ window.__ModuleLoader__.load({
1364
1375
  box-shadow: 0 2px 12px rgba(0, 0, 0, .18) !important;
1365
1376
  -webkit-tap-highlight-color: transparent;
1366
1377
  }
1378
+
1379
+ /* iOS 对 computed font-size <16px 的可编辑元素聚焦时自动放大视口;
1380
+ 表单与 composer 提到 16px(消息正文不受影响),聚焦后页面不再错位。 */
1381
+ input, textarea, select, [contenteditable="true"] {
1382
+ font-size: max(16px, 1em) !important;
1383
+ }
1384
+
1385
+ /* 底部安全区(iPhone home 条):viewport-fit=cover 后浏览器 UI 退出底部,
1386
+ home 指示条叠在 composer / 抽屉 / 设置 sheet 上,遮挡发送按钮与会话列表末项。 */
1387
+ [class*="composerSeat"], [data-composer-seat] {
1388
+ padding-bottom: max(env(safe-area-inset-bottom, 0px), 4px) !important;
1389
+ }
1390
+ [${FRAME_ATTR}="frame"] > :first-child {
1391
+ padding-bottom: env(safe-area-inset-bottom, 0px) !important;
1392
+ }
1393
+ [aria-modal="true"]:has(> :first-child > :last-child > button):not(:has([role="navigation"])):not(:has([class*="ZuhsRW"])) {
1394
+ max-height: calc(100dvh - 24px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px)) !important;
1395
+ }
1396
+ [aria-modal="true"]:has(> :first-child > :last-child > button):not(:has([role="navigation"])):not(:has([class*="ZuhsRW"])) > :last-child > :last-child {
1397
+ padding-bottom: max(env(safe-area-inset-bottom, 0px), 24px) !important;
1398
+ }
1399
+
1400
+ /* 会话行触控高度 */
1401
+ [class*="sessionRow"] { min-height: 44px !important; }
1367
1402
  }
1368
1403
 
1369
1404
  /* 宽屏 / 鼠标指针:隐藏切换按钮 */
@@ -1385,7 +1420,7 @@ window.__ModuleLoader__.load({
1385
1420
  if (viewport === null) return () => {};
1386
1421
  const original = viewport.content;
1387
1422
  const sync = () => {
1388
- viewport.content = narrow.matches ? "width=device-width, initial-scale=1, viewport-fit=cover" : original;
1423
+ viewport.content = narrow.matches ? "width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-content" : original;
1389
1424
  };
1390
1425
  sync();
1391
1426
  narrow.addEventListener("change", sync);
@@ -1858,6 +1893,47 @@ window.__ModuleLoader__.load({
1858
1893
  return () => document.removeEventListener("pointerdown", focusInput, true);
1859
1894
  }, "dshb-mobile: terminal input focus");
1860
1895
  }
1896
+ /**
1897
+ * iOS 键盘只缩小 visualViewport,布局视口不动,sticky 在滚动容器底部的
1898
+ * composer 会整个留在键盘后面(发送按钮不可达、最新消息被遮)。监听
1899
+ * visualViewport,键盘开启时把 composer seat 上移键盘高度并在下一帧把
1900
+ * 会话滚动补到最底;Android 由 meta 的 interactive-widget=resizes-content
1901
+ * 让布局视口直接收缩,无需此补偿。
1902
+ */
1903
+ function installComposerKeyboardLift(ctx) {
1904
+ ctx.effect(() => {
1905
+ const mobile = window.matchMedia(MOBILE_QUERY);
1906
+ const vv = window.visualViewport;
1907
+ if (!vv) return () => {};
1908
+ let raf = 0;
1909
+ const seat = () => document.querySelector("[class*=\"composerSeat\"]") ?? document.querySelector("[data-composer-seat]");
1910
+ const sync = () => {
1911
+ if (raf !== 0) return;
1912
+ raf = requestAnimationFrame(() => {
1913
+ raf = 0;
1914
+ if (!mobile.matches) return;
1915
+ const el = seat();
1916
+ if (el === null) return;
1917
+ const occluded = window.innerHeight - vv.height - vv.offsetTop;
1918
+ if (occluded > 150) {
1919
+ el.style.transform = `translateY(${-occluded}px)`;
1920
+ const body = document.querySelector("[class*=\"scrollBody\"]");
1921
+ body?.scrollTo({ top: body.scrollHeight });
1922
+ } else if (el.style.transform !== "") el.style.transform = "";
1923
+ });
1924
+ };
1925
+ sync();
1926
+ vv.addEventListener("resize", sync);
1927
+ vv.addEventListener("scroll", sync);
1928
+ return () => {
1929
+ if (raf !== 0) cancelAnimationFrame(raf);
1930
+ const el = seat();
1931
+ if (el !== null) el.style.transform = "";
1932
+ vv.removeEventListener("resize", sync);
1933
+ vv.removeEventListener("scroll", sync);
1934
+ };
1935
+ }, "dshb-mobile: composer keyboard lift");
1936
+ }
1861
1937
  /** 目录抽屉切换按钮(仅切换,不含文件浏览/日志导出等功能按钮)。 */
1862
1938
  function DrawerToggle({ toggleSidebar }) {
1863
1939
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
@@ -1948,6 +2024,7 @@ window.__ModuleLoader__.load({
1948
2024
  function installMobile(ctx) {
1949
2025
  installStyles(ctx);
1950
2026
  installMobileTerminalInputFocus(ctx);
2027
+ installComposerKeyboardLift(ctx);
1951
2028
  installViewport(ctx);
1952
2029
  installFrameMarker(ctx);
1953
2030
  installStatsLine(ctx);
@@ -1988,7 +2065,7 @@ window.__ModuleLoader__.load({
1988
2065
  const dialog = document.createElement("div");
1989
2066
  dialog.setAttribute("role", "dialog");
1990
2067
  dialog.setAttribute("aria-label", `修改 ${workspaceTitle} 的项目指令`);
1991
- dialog.style.cssText = "box-sizing:border-box;width:min(92vw,600px);max-height:85vh;overflow:auto;padding:20px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)";
2068
+ dialog.style.cssText = "box-sizing:border-box;width:min(92vw,600px);max-height:85dvh;overflow:auto;padding:20px;padding-bottom:max(env(safe-area-inset-bottom),20px);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)";
1992
2069
  const title = document.createElement("h2");
1993
2070
  title.textContent = `项目指令 - ${workspaceTitle}`;
1994
2071
  title.style.cssText = "margin:0 0 10px;font-size:16px";
@@ -3226,9 +3303,9 @@ window.__ModuleLoader__.load({
3226
3303
  onClick: () => copyText(archive.originSessionId),
3227
3304
  style: {
3228
3305
  ...secondaryBtn,
3229
- height: 22,
3230
- padding: "0 6px",
3231
- fontSize: 10
3306
+ height: 30,
3307
+ padding: "0 10px",
3308
+ fontSize: 11
3232
3309
  },
3233
3310
  children: "复制 ID"
3234
3311
  })]
@@ -4643,7 +4720,10 @@ window.__ModuleLoader__.load({
4643
4720
  依赖祖先 overflow:visible 才能展开到输入框之外,禁止给任何中间祖先加裁剪。 */
4644
4721
  html, body { overflow-x: hidden !important; max-width: 100vw !important }
4645
4722
  * { min-width: 0 !important; }
4646
- table { display: block !important; overflow-x: auto !important; }
4723
+ /* 表格不设 display:block:上游 markdown 表格已自带滚动容器(tableScroll),
4724
+ display:block 会破坏 caption/sticky 语义且与上游 width:max-content 冲突;
4725
+ 这里仅保留溢出约束,宽表由上游 wrapper 横向滚动。 */
4726
+ table { max-width: 100% !important; overflow-x: auto !important; }
4647
4727
  img, video, canvas, svg { max-width: 100% !important; height: auto !important }
4648
4728
  pre, code { white-space: pre-wrap !important; word-break: break-all !important }
4649
4729
  input, select, textarea { max-width: 100% !important; }