dsh-mobile 0.5.3 → 0.5.5
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 +22 -0
- package/CONTRIBUTORS.md +10 -5
- package/README.en.md +23 -9
- package/README.md +24 -10
- package/SECURITY.md +1 -1
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/docs/CLOUDFLARE_TUNNEL.en.md +3 -1
- package/docs/CLOUDFLARE_TUNNEL.md +3 -1
- package/docs/README.md +1 -0
- package/docs/SLOW_CONNECTIONS.en.md +77 -0
- package/docs/SLOW_CONNECTIONS.md +77 -0
- package/lib/client.js +52 -10
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +46 -5
- package/lib/index.mjs +662 -238
- package/lib/index.mjs.map +1 -1
- package/lib/mobile-layout.js +135 -2
- package/lib/mobile-layout.js.map +1 -1
- package/node_modules/dsh-mobile-question-fixes/package.json +1 -1
- package/package.json +11 -2
- package/packages/question-fixes/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -1212,7 +1212,7 @@ window.__ModuleLoader__.load({
|
|
|
1212
1212
|
cloudflaredBadge: "Account optional",
|
|
1213
1213
|
cloudflaredDescription: "Installs the official cloudflared client on demand. A quick tunnel needs no account and gives a temporary public address; a named tunnel uses a Cloudflare account token and keeps one hostname that survives restarts.",
|
|
1214
1214
|
prepareCloudflared: "Prepare cloudflared",
|
|
1215
|
-
cloudflaredUnsupported: "Windows x64 and
|
|
1215
|
+
cloudflaredUnsupported: "Windows x64, Linux x64/arm64, and macOS x64/arm64 are supported.",
|
|
1216
1216
|
cloudflaredNotInstalled: "Not installed. A fixed version is downloaded from the official cloudflared release page only after you click the button below.",
|
|
1217
1217
|
cloudflaredReady: "Official component {version} is ready.",
|
|
1218
1218
|
cloudflaredQuickNote: "Quick tunnel: no Cloudflare account is needed, but Cloudflare positions quick tunnels for testing — the address is random, rate-limited, and carries no uptime guarantee. Do not rely on one for access that must stay reachable.",
|
|
@@ -1280,7 +1280,7 @@ window.__ModuleLoader__.load({
|
|
|
1280
1280
|
cloudflaredBadge: "Account facoltativo",
|
|
1281
1281
|
cloudflaredDescription: "Installa su richiesta il client cloudflared ufficiale. Il tunnel rapido non richiede account e fornisce un indirizzo pubblico temporaneo; il tunnel con nome usa il token di un account Cloudflare e mantiene un hostname stabile tra i riavvii.",
|
|
1282
1282
|
prepareCloudflared: "Prepara cloudflared",
|
|
1283
|
-
cloudflaredUnsupported: "
|
|
1283
|
+
cloudflaredUnsupported: "Sono supportati Windows x64, Linux x64/arm64 e macOS x64/arm64.",
|
|
1284
1284
|
cloudflaredNotInstalled: "Non installato. Una versione fissa viene scaricata dalla pagina ufficiale di cloudflared solo dopo aver premuto il pulsante.",
|
|
1285
1285
|
cloudflaredReady: "Componente ufficiale {version} pronto.",
|
|
1286
1286
|
cloudflaredQuickNote: "Tunnel rapido: non serve un account Cloudflare, ma Cloudflare li considera pensati per i test — l’indirizzo è casuale, soggetto a limiti di frequenza e senza garanzia di disponibilità. Non usarlo per un accesso che deve restare raggiungibile.",
|
|
@@ -1348,7 +1348,7 @@ window.__ModuleLoader__.load({
|
|
|
1348
1348
|
cloudflaredBadge: "账号可选",
|
|
1349
1349
|
cloudflaredDescription: "按需安装官方 cloudflared 客户端。快速隧道无需账号,提供临时公网地址;命名隧道使用 Cloudflare 账号令牌,地址固定、重启不变。",
|
|
1350
1350
|
prepareCloudflared: "准备 cloudflared",
|
|
1351
|
-
cloudflaredUnsupported: "
|
|
1351
|
+
cloudflaredUnsupported: "支持 Windows x64、Linux x64/arm64 与 macOS x64/arm64。",
|
|
1352
1352
|
cloudflaredNotInstalled: "尚未安装。只有点击下方按钮后,才会从 cloudflared 官方发布页下载固定版本。",
|
|
1353
1353
|
cloudflaredReady: "官方组件 {version} 已就绪。",
|
|
1354
1354
|
cloudflaredQuickNote: "快速隧道:无需 Cloudflare 账号,但官方定位是测试用途 —— 地址随机、有限流、无可用性保证。请勿用于必须长期可达的访问。",
|
|
@@ -2631,6 +2631,14 @@ window.__ModuleLoader__.load({
|
|
|
2631
2631
|
the query restores the fixed scrim, and its more specific [hidden] rule
|
|
2632
2632
|
keeps winning there. */
|
|
2633
2633
|
.dsh-native-mobile-backdrop,.dsh-mobile-branch-toast,.dsh-mobile-media-toast { display:none; }
|
|
2634
|
+
/* The content-font preference may exceed Safari's focused-editable minimum.
|
|
2635
|
+
The html-level class exists on every non-desktop mobile page, so it also
|
|
2636
|
+
covers body-level portals (model picker search) the center column never
|
|
2637
|
+
contained; the center marker stays alongside it because a disposed
|
|
2638
|
+
surface removes the html class while styles applied from its string can
|
|
2639
|
+
outlive the class on a page that still carries the center column. */
|
|
2640
|
+
html.dsh-native-mobile-active :is(input,textarea,[contenteditable="true"],[contenteditable="plaintext-only"],[contenteditable=""]),
|
|
2641
|
+
[data-dsh-mobile-center] :is(input,textarea,[contenteditable="true"],[contenteditable="plaintext-only"],[contenteditable=""]) { font-size:max(16px,1em,var(--dsh-content-font-size,1em)) !important; }
|
|
2634
2642
|
.dsh-mobile-settings_row { display:flex; align-items:center; gap:8px; padding:16px 0; border-bottom:0.5px solid var(--dsw-alias-border-l2); }
|
|
2635
2643
|
.dsh-mobile-settings_rowText { flex:1; min-width:0; display:flex; flex-direction:column; gap:4px; padding-right:48px; }
|
|
2636
2644
|
.dsh-mobile-settings_title { color:var(--dsw-alias-label-primary); font-size:14px; font-weight:400; line-height:22px; }
|
|
@@ -2723,7 +2731,6 @@ window.__ModuleLoader__.load({
|
|
|
2723
2731
|
[data-dsh-mobile-settings-options] [class*="_rowActions"] button { flex:none !important; width:auto !important; min-width:44px !important; max-width:none !important; min-height:44px !important; padding-inline:10px !important; white-space:nowrap !important; word-break:keep-all !important; writing-mode:horizontal-tb !important; }
|
|
2724
2732
|
[data-dsh-mobile-settings-content][data-dsh-mobile-view-transition="true"],
|
|
2725
2733
|
[data-dsh-mobile-view][data-dsh-mobile-view-transition="true"] { animation:dsh-mobile-view-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }
|
|
2726
|
-
[data-dsh-mobile-center] textarea { font-size:16px !important; }
|
|
2727
2734
|
/* Markdown tables use content-sized columns. Small tables fill the phone;
|
|
2728
2735
|
wider tables keep readable cells and scroll inside their own region. */
|
|
2729
2736
|
[data-dsh-mobile-table-scroll] { box-sizing:border-box; width:100%; max-width:100%; overflow-x:auto; overscroll-behavior-x:contain; -webkit-overflow-scrolling:touch; }
|
|
@@ -2750,12 +2757,15 @@ window.__ModuleLoader__.load({
|
|
|
2750
2757
|
[data-dsh-mobile-message-column] [class*="_body"] { max-width:100% !important; overflow-wrap:anywhere; }
|
|
2751
2758
|
/* Keep folded and expanded reasoning visually separate from the reply. */
|
|
2752
2759
|
[data-dsh-mobile-message-column] [class*="_body"] > div:has(> [data-variant="think"]) { margin-bottom:12px !important; }
|
|
2753
|
-
[data-dsh-mobile-center] [data-composer-card] ~ [class*="_root"],
|
|
2754
|
-
[data-dsh-mobile-center] [data-composer-card] ~ * [class*="_root"] { box-sizing:border-box !important; width:100% !important; max-width:100% !important; margin-bottom:-6px !important; padding:3px 4px 0 !important; font-size:11px !important; line-height:18px !important; white-space:normal !important; overflow:visible !important; text-overflow:clip !important; }
|
|
2760
|
+
[data-dsh-mobile-center] [data-composer-card] ~ [class*="_root"]:not(:where(input,textarea,[contenteditable])),
|
|
2761
|
+
[data-dsh-mobile-center] [data-composer-card] ~ * [class*="_root"]:not(:where(input,textarea,[contenteditable])) { box-sizing:border-box !important; width:100% !important; max-width:100% !important; margin-bottom:-6px !important; padding:3px 4px 0 !important; font-size:11px !important; line-height:18px !important; white-space:normal !important; overflow:visible !important; text-overflow:clip !important; }
|
|
2755
2762
|
[data-dsh-mobile-center] [data-composer-card] ~ [class*="_root"] [class*="_sep"],
|
|
2756
2763
|
[data-dsh-mobile-center] [data-composer-card] ~ * [class*="_root"] [class*="_sep"] { margin:0 6px !important; }
|
|
2757
|
-
/* Composer dock stats strip (turns/steps/tokens) reads small on phones.
|
|
2758
|
-
|
|
2764
|
+
/* Composer dock stats strip (turns/steps/tokens) reads small on phones.
|
|
2765
|
+
:not(:where(...)) keeps editables exempt at zero specificity cost, so
|
|
2766
|
+
the small !important fonts cannot beat the 16px editable floor while
|
|
2767
|
+
the dock spacing rules keep their cascade position. */
|
|
2768
|
+
[data-dsh-mobile-center] [data-slot="conversation.composer.dock"] [class*="_root"]:not(:where(input,textarea,[contenteditable])) { font-size:10px !important; line-height:16px !important; }
|
|
2759
2769
|
/* The context ring is a composer-metadata _root too, so the metadata rule
|
|
2760
2770
|
above stretched it across the whole dock. It cannot shrink, which left the
|
|
2761
2771
|
session statistics beside it a few pixels wide, every number clipped to an
|
|
@@ -2812,7 +2822,13 @@ window.__ModuleLoader__.load({
|
|
|
2812
2822
|
.dsh-mobile-media-action svg { flex:none; width:16px; height:16px; color:var(--dsw-alias-label-tertiary,currentColor); }
|
|
2813
2823
|
.dsh-mobile-media-action span { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
2814
2824
|
[data-dsh-mobile-center] [class*="_composer"] { padding-left:8px !important; padding-right:8px !important; padding-bottom:max(8px,env(safe-area-inset-bottom)) !important; }
|
|
2815
|
-
/*
|
|
2825
|
+
/* Collapse the scroll viewport only; the editor, draft and attachments stay
|
|
2826
|
+
owned by DSH. Toolbar focus keeps the card expanded during menu taps. */
|
|
2827
|
+
[data-dsh-mobile-center] [data-composer-card]:not(:focus-within) > [data-input-scroll] { max-height:72px !important; overflow-y:auto !important; }
|
|
2828
|
+
/* Stock Send/Queue/Steer and Stop keep their handlers and disabled state. */
|
|
2829
|
+
[data-dsh-mobile-composer-row] button { min-height:44px !important; touch-action:manipulation; }
|
|
2830
|
+
[data-dsh-mobile-composer-row] button[class*="_primary"] { min-width:44px !important; flex-shrink:0 !important; }
|
|
2831
|
+
/* The desktop composer intentionally wraps whole toolbar groups. On a phone,
|
|
2816
2832
|
dynamic model and status labels made that row alternate between one and
|
|
2817
2833
|
two lines. Keep two stable columns and let only the model label shrink. */
|
|
2818
2834
|
[data-dsh-mobile-composer-row] { display:grid !important; grid-template-columns:max-content minmax(0,1fr) !important; align-items:center !important; gap:4px 8px !important; }
|
|
@@ -3996,6 +4012,7 @@ window.__ModuleLoader__.load({
|
|
|
3996
4012
|
}
|
|
3997
4013
|
/**
|
|
3998
4014
|
* Consume page-level surfaces and dismissible DSH overlays before layout navigation.
|
|
4015
|
+
* Composer model popups use DSH's Escape handling to return from a pane before closing.
|
|
3999
4016
|
* @param view - the page window receiving the native Back request.
|
|
4000
4017
|
* @param page - the current DSH document.
|
|
4001
4018
|
* @param blocked - feedback for a foreground layer without a safe close action.
|
|
@@ -4014,10 +4031,35 @@ window.__ModuleLoader__.load({
|
|
|
4014
4031
|
claim();
|
|
4015
4032
|
return;
|
|
4016
4033
|
}
|
|
4017
|
-
const
|
|
4034
|
+
const modelPopups = /* @__PURE__ */ new Map();
|
|
4035
|
+
for (const trigger of page.querySelectorAll("[data-dsh-mobile-composer-model-trigger][aria-expanded=\"true\"]")) {
|
|
4036
|
+
const popupId = trigger.getAttribute("aria-controls");
|
|
4037
|
+
const popup = popupId === null ? null : page.getElementById(popupId);
|
|
4038
|
+
if (popup !== null && visibleBackLayer(view, trigger) && visibleBackLayer(view, popup) && (popup.getAttribute("role") === "menu" || popup.getAttribute("role") === "group")) modelPopups.set(popup, trigger);
|
|
4039
|
+
}
|
|
4040
|
+
const layers = [...page.querySelectorAll("[role=\"dialog\"][aria-modal=\"true\"], [role=\"menu\"], [role=\"group\"][id]")].filter((element) => visibleBackLayer(view, element) && (element.getAttribute("role") !== "group" || modelPopups.has(element)));
|
|
4018
4041
|
const top = layers.at(-1);
|
|
4019
4042
|
if (top === void 0) return;
|
|
4020
4043
|
claim();
|
|
4044
|
+
const modelEntry = [...modelPopups].find(([popup]) => popup.contains(top));
|
|
4045
|
+
if (modelEntry !== void 0) {
|
|
4046
|
+
const [modelPopup, trigger] = modelEntry;
|
|
4047
|
+
if (layers.some((layer) => !modelPopup.contains(layer))) {
|
|
4048
|
+
blocked();
|
|
4049
|
+
return;
|
|
4050
|
+
}
|
|
4051
|
+
const focused = page.activeElement;
|
|
4052
|
+
const target = focused !== null && modelPopup.contains(focused) ? focused : trigger;
|
|
4053
|
+
const escape = new KeyboardEvent("keydown", {
|
|
4054
|
+
key: "Escape",
|
|
4055
|
+
code: "Escape",
|
|
4056
|
+
bubbles: true,
|
|
4057
|
+
cancelable: true
|
|
4058
|
+
});
|
|
4059
|
+
target.dispatchEvent(escape);
|
|
4060
|
+
if (!escape.defaultPrevented) blocked();
|
|
4061
|
+
return;
|
|
4062
|
+
}
|
|
4021
4063
|
if (top.getAttribute("role") === "dialog") {
|
|
4022
4064
|
const wrapper = top.parentElement;
|
|
4023
4065
|
const mask = wrapper?.firstElementChild;
|