dsh-life-pack 0.3.4 → 0.3.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/dist/client.js +137 -13
- package/dist/client.js.map +1 -1
- package/dist/directory-browser-api.d.ts +7 -5
- package/dist/directory-browser-api.d.ts.map +1 -1
- package/dist/directory-browser-api.js +5 -4
- package/dist/directory-browser-api.js.map +1 -1
- package/dist/directory-browser-contract.d.ts +13 -2
- package/dist/directory-browser-contract.d.ts.map +1 -1
- package/dist/directory-browser-contract.js.map +1 -1
- package/dist/directory-browser-parts.d.ts +68 -0
- package/dist/directory-browser-parts.d.ts.map +1 -0
- package/dist/directory-browser-parts.js +195 -0
- package/dist/directory-browser-parts.js.map +1 -0
- package/dist/directory-browser-roots.d.ts +21 -0
- package/dist/directory-browser-roots.d.ts.map +1 -0
- package/dist/directory-browser-roots.js +40 -0
- package/dist/directory-browser-roots.js.map +1 -0
- package/dist/directory-browser-state.d.ts +9 -1
- package/dist/directory-browser-state.d.ts.map +1 -1
- package/dist/directory-browser-state.js +23 -0
- package/dist/directory-browser-state.js.map +1 -1
- package/dist/directory-browser-ui.d.ts +4 -22
- package/dist/directory-browser-ui.d.ts.map +1 -1
- package/dist/directory-browser-ui.js +3 -148
- package/dist/directory-browser-ui.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/roots.d.ts +34 -0
- package/dist/roots.d.ts.map +1 -0
- package/dist/roots.js +95 -0
- package/dist/roots.js.map +1 -0
- package/dist/update-contract.d.ts +7 -0
- package/dist/update-contract.d.ts.map +1 -1
- package/dist/update-contract.js +7 -0
- package/dist/update-contract.js.map +1 -1
- package/dist/update-host.d.ts.map +1 -1
- package/dist/update-host.js +5 -1
- package/dist/update-host.js.map +1 -1
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -179,7 +179,14 @@ window.__ModuleLoader__.load({
|
|
|
179
179
|
* 宿主读**自己这份已安装包**的 `package.json`(`manager-version.ts`),面板只渲染读到的值。
|
|
180
180
|
* 为什么走电话:面板是浏览器产物,禁 node 内建(`test/client-bundle-48.test.mjs` 看门),
|
|
181
181
|
* 读盘只许在宿主半;与卡路里 #130 同一条路(host 读 → RPC → client 纯渲染)。 */
|
|
182
|
-
version: "ilife-manager.version"
|
|
182
|
+
version: "ilife-manager.version",
|
|
183
|
+
/** 本机「根」清单(票 #744):入参 `{}`,回包 `{roots: [{path, kind}]}`。
|
|
184
|
+
*
|
|
185
|
+
* 为什么这条能力住在总管:浏览器里没有卷清单接口,而宿主那条目录选择接缝只有
|
|
186
|
+
* `list`/`createDirectory` 两格——「这台机器上有哪些盘」只能由宿主去问操作系统。
|
|
187
|
+
* 六家的目录浏览器都取这一通电话,故名字与实现都只有这一处(清单本身见 `roots.ts`)。
|
|
188
|
+
* 回包**恒成功**:列不出来是空清单,不是错误码(界面据此只是不画那一行)。 */
|
|
189
|
+
roots: "ilife-manager.roots"
|
|
183
190
|
};
|
|
184
191
|
/** 版本读不到时两侧共用的降级字面量(面板照原样显示,不假装知道版本)。
|
|
185
192
|
*
|
|
@@ -1884,7 +1891,8 @@ window.__ModuleLoader__.load({
|
|
|
1884
1891
|
draft: deps.initialPath,
|
|
1885
1892
|
filter: "",
|
|
1886
1893
|
creating: null,
|
|
1887
|
-
notice: null
|
|
1894
|
+
notice: null,
|
|
1895
|
+
roots: []
|
|
1888
1896
|
};
|
|
1889
1897
|
/** 每次列举带一个序号:晚回来的旧回执直接丢掉,不许覆盖新一层。 */
|
|
1890
1898
|
let generation = 0;
|
|
@@ -1895,6 +1903,18 @@ window.__ModuleLoader__.load({
|
|
|
1895
1903
|
};
|
|
1896
1904
|
for (const listener of [...listeners]) listener(state);
|
|
1897
1905
|
};
|
|
1906
|
+
/** 根清单只问一次:取不到就是空(不报错、不重试——它只是图上的一行入口)。
|
|
1907
|
+
*
|
|
1908
|
+
* 「问一次」钉在这里而不是图里:视图那半每次重画都会重新求值,问在这里才谈得上一次。 */
|
|
1909
|
+
let rootsAsked = false;
|
|
1910
|
+
const loadRoots = async () => {
|
|
1911
|
+
if (rootsAsked || deps.rootsSource === void 0) return;
|
|
1912
|
+
rootsAsked = true;
|
|
1913
|
+
try {
|
|
1914
|
+
const roots = await deps.rootsSource();
|
|
1915
|
+
if (roots.length > 0) emit({ roots });
|
|
1916
|
+
} catch {}
|
|
1917
|
+
};
|
|
1898
1918
|
const humanize = (cause) => {
|
|
1899
1919
|
const raw = typeof cause === "object" && cause !== null ? cause : {};
|
|
1900
1920
|
const message = typeof raw.message === "string" && raw.message.trim() !== "" ? raw.message.trim() : String(cause);
|
|
@@ -1952,6 +1972,7 @@ window.__ModuleLoader__.load({
|
|
|
1952
1972
|
return () => listeners.delete(listener);
|
|
1953
1973
|
},
|
|
1954
1974
|
async open() {
|
|
1975
|
+
loadRoots();
|
|
1955
1976
|
const wanted = deps.initialPath.trim();
|
|
1956
1977
|
if (wanted !== "") {
|
|
1957
1978
|
await load(wanted);
|
|
@@ -2064,7 +2085,8 @@ window.__ModuleLoader__.load({
|
|
|
2064
2085
|
initialPath: deps.initialPath,
|
|
2065
2086
|
onPicked: deps.onPicked,
|
|
2066
2087
|
onClose: () => deps.onClosed?.(),
|
|
2067
|
-
...deps.failureLabel === void 0 ? {} : { failureLabel: deps.failureLabel }
|
|
2088
|
+
...deps.failureLabel === void 0 ? {} : { failureLabel: deps.failureLabel },
|
|
2089
|
+
...deps.rootsSource === void 0 ? {} : { rootsSource: deps.rootsSource }
|
|
2068
2090
|
});
|
|
2069
2091
|
return {
|
|
2070
2092
|
open: () => controller.open(),
|
|
@@ -2086,18 +2108,22 @@ window.__ModuleLoader__.load({
|
|
|
2086
2108
|
};
|
|
2087
2109
|
}
|
|
2088
2110
|
//#endregion
|
|
2089
|
-
//#region src/directory-browser-
|
|
2090
|
-
/**
|
|
2111
|
+
//#region src/directory-browser-parts.ts
|
|
2112
|
+
/** 文件浏览器视图半的**零件**:样式表与四行控件(面包屑/根/一行子目录/新建行)。
|
|
2091
2113
|
*
|
|
2092
|
-
*
|
|
2093
|
-
*
|
|
2114
|
+
* 为什么拆出来:整张对话框的组版与这些零件的变化频率不同——零件跟着「图上多一行/少一行」动,
|
|
2115
|
+
* 组版跟着「对话框长什么样」动。拆开之后两边都在 350 行告警线内,而对外面不变
|
|
2116
|
+
* (`directory-browser-ui.ts` 照旧转出组件与两个接线函数)。
|
|
2117
|
+
*
|
|
2118
|
+
* 本件与视图半同样**不认识宿主**:只认状态与文案。
|
|
2094
2119
|
*/
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2120
|
+
/** 根的类型说明(悬停可见):**本件自己的词汇**,与取数方无关。 */
|
|
2121
|
+
const ROOT_KIND_TEXT = {
|
|
2122
|
+
fixed: "固定磁盘",
|
|
2123
|
+
network: "网络驱动器",
|
|
2124
|
+
removable: "可移动磁盘",
|
|
2125
|
+
optical: "光驱",
|
|
2126
|
+
other: "磁盘"
|
|
2101
2127
|
};
|
|
2102
2128
|
const S$1 = {
|
|
2103
2129
|
scrim: {
|
|
@@ -2163,6 +2189,24 @@ window.__ModuleLoader__.load({
|
|
|
2163
2189
|
opacity: .45,
|
|
2164
2190
|
fontSize: 12
|
|
2165
2191
|
},
|
|
2192
|
+
roots: {
|
|
2193
|
+
display: "flex",
|
|
2194
|
+
flexWrap: "wrap",
|
|
2195
|
+
alignItems: "center",
|
|
2196
|
+
gap: 6,
|
|
2197
|
+
padding: "0 12px 8px",
|
|
2198
|
+
fontSize: 12
|
|
2199
|
+
},
|
|
2200
|
+
rootsLabel: {
|
|
2201
|
+
opacity: .72,
|
|
2202
|
+
marginRight: 2
|
|
2203
|
+
},
|
|
2204
|
+
rootButton: {
|
|
2205
|
+
border: "1px solid var(--dsw-alias-border-l2, rgba(128,128,128,0.35))",
|
|
2206
|
+
borderRadius: 6,
|
|
2207
|
+
padding: "3px 8px",
|
|
2208
|
+
opacity: 1
|
|
2209
|
+
},
|
|
2166
2210
|
pathRow: {
|
|
2167
2211
|
display: "flex",
|
|
2168
2212
|
gap: 6,
|
|
@@ -2241,6 +2285,7 @@ window.__ModuleLoader__.load({
|
|
|
2241
2285
|
},
|
|
2242
2286
|
error: { color: "var(--dsw-alias-label-error, #e66)" }
|
|
2243
2287
|
};
|
|
2288
|
+
/** 面包屑:从文件系统根到当前层,每一格都是跳转目标(`listing.crumbs` 由取数方给)。 */
|
|
2244
2289
|
function crumbRow(state, onEnter) {
|
|
2245
2290
|
const listing = state.listing;
|
|
2246
2291
|
if (listing === null || listing.crumbs.length === 0) return null;
|
|
@@ -2264,6 +2309,30 @@ window.__ModuleLoader__.load({
|
|
|
2264
2309
|
});
|
|
2265
2310
|
return react.createElement("div", { style: S$1.crumbs }, parts);
|
|
2266
2311
|
}
|
|
2312
|
+
/** 可跳转的根那一行(Windows 上的盘符等)。**少于两个根就不画**:一个根没有「跳到别处」可言。 */
|
|
2313
|
+
function rootsRow(state, labels, onEnter) {
|
|
2314
|
+
if (state.roots.length < 2) return null;
|
|
2315
|
+
const parts = [react.createElement("span", {
|
|
2316
|
+
key: "roots-label",
|
|
2317
|
+
style: S$1.rootsLabel
|
|
2318
|
+
}, labels.roots)];
|
|
2319
|
+
for (const root of state.roots) parts.push(react.createElement("button", {
|
|
2320
|
+
key: root.path,
|
|
2321
|
+
type: "button",
|
|
2322
|
+
style: {
|
|
2323
|
+
...S$1.chromeButton,
|
|
2324
|
+
...S$1.rootButton
|
|
2325
|
+
},
|
|
2326
|
+
title: ROOT_KIND_TEXT[root.kind] ?? ROOT_KIND_TEXT.other,
|
|
2327
|
+
onClick: () => onEnter(root.path)
|
|
2328
|
+
}, root.path));
|
|
2329
|
+
return react.createElement("div", {
|
|
2330
|
+
style: S$1.roots,
|
|
2331
|
+
role: "group",
|
|
2332
|
+
"aria-label": labels.roots
|
|
2333
|
+
}, parts);
|
|
2334
|
+
}
|
|
2335
|
+
/** 一行子目录:点名字进它,点「选」把它当目标(「选」再点一次取消)。 */
|
|
2267
2336
|
function entryRow(entry, selected, labels, onToggleSelect, onEnter) {
|
|
2268
2337
|
return react.createElement("div", {
|
|
2269
2338
|
key: entry.path,
|
|
@@ -2292,6 +2361,7 @@ window.__ModuleLoader__.load({
|
|
|
2292
2361
|
onClick: () => onToggleSelect(entry.path)
|
|
2293
2362
|
}, selected ? "✓" : labels.select));
|
|
2294
2363
|
}
|
|
2364
|
+
/** 「新建文件夹」那一行(`creatingName === null` 时收起)。 */
|
|
2295
2365
|
function createRow(labels, onName, onCancel, onCreate, creatingName) {
|
|
2296
2366
|
if (creatingName === null) return null;
|
|
2297
2367
|
return react.createElement("div", { style: {
|
|
@@ -2317,6 +2387,21 @@ window.__ModuleLoader__.load({
|
|
|
2317
2387
|
onClick: onCancel
|
|
2318
2388
|
}, labels.createCancel));
|
|
2319
2389
|
}
|
|
2390
|
+
//#endregion
|
|
2391
|
+
//#region src/directory-browser-ui.ts
|
|
2392
|
+
/** 文件浏览器的视图半:把 `BrowseState` 画成一张对话框。**不认识宿主**,也不自己做 IO。
|
|
2393
|
+
*
|
|
2394
|
+
* 手写 `React.createElement`(本包 client 束禁 JSX,见 `tsdown.config.ts` 的既成口径)。
|
|
2395
|
+
* 只读状态、只回调;进哪一层、选到什么由操作半(`directory-browser-state.ts`)算。
|
|
2396
|
+
* 样式与四行控件在 `directory-browser-parts.ts`(那里跟着「多一行/少一行」动,本件只管组版)。
|
|
2397
|
+
*/
|
|
2398
|
+
const EMPTY_LISTING = {
|
|
2399
|
+
path: "",
|
|
2400
|
+
home: "",
|
|
2401
|
+
crumbs: [],
|
|
2402
|
+
entries: [],
|
|
2403
|
+
truncated: false
|
|
2404
|
+
};
|
|
2320
2405
|
/** 画一张文件浏览器对话框。`open=false` 时返回 null(本件不挂 portal,由调用方决定挂在哪)。 */
|
|
2321
2406
|
function DirectoryBrowser(props) {
|
|
2322
2407
|
const { open, state, labels } = props;
|
|
@@ -2327,6 +2412,7 @@ window.__ModuleLoader__.load({
|
|
|
2327
2412
|
const hidden = hiddenCount(listing);
|
|
2328
2413
|
const body = [];
|
|
2329
2414
|
body.push(crumbRow(state, props.onEnter));
|
|
2415
|
+
body.push(rootsRow(state, labels, props.onEnter));
|
|
2330
2416
|
body.push(react.createElement("div", { style: S$1.pathRow }, react.createElement("input", {
|
|
2331
2417
|
style: S$1.input,
|
|
2332
2418
|
value: state.draft,
|
|
@@ -2421,6 +2507,42 @@ window.__ModuleLoader__.load({
|
|
|
2421
2507
|
});
|
|
2422
2508
|
}
|
|
2423
2509
|
//#endregion
|
|
2510
|
+
//#region src/directory-browser-roots.ts
|
|
2511
|
+
/** 认一认某个值像不像一个根(认不出的行丢掉:图的干净比多画一行重要)。 */
|
|
2512
|
+
function isRootRow(raw) {
|
|
2513
|
+
if (typeof raw !== "object" || raw === null) return false;
|
|
2514
|
+
const row = raw;
|
|
2515
|
+
return typeof row.path === "string" && row.path !== "" && typeof row.kind === "string";
|
|
2516
|
+
}
|
|
2517
|
+
/** 信封 → 根清单(纯函数,**永不抛**):`{ok:true, value:{roots:[…]}}` 之外的形状一律当空。 */
|
|
2518
|
+
function readRootsAnswer(raw) {
|
|
2519
|
+
const answer = typeof raw === "object" && raw !== null ? raw : {};
|
|
2520
|
+
if (answer.ok !== true) return [];
|
|
2521
|
+
const value = typeof answer.value === "object" && answer.value !== null ? answer.value : {};
|
|
2522
|
+
if (!Array.isArray(value.roots)) return [];
|
|
2523
|
+
return value.roots.filter(isRootRow).map((row) => ({
|
|
2524
|
+
path: row.path,
|
|
2525
|
+
kind: row.kind
|
|
2526
|
+
}));
|
|
2527
|
+
}
|
|
2528
|
+
/** 建一个「根清单取数器」:给调用口与三个名字,回一个 `() => Promise<RootRow[]>`。
|
|
2529
|
+
*
|
|
2530
|
+
* 界面按需调它(开图一次),不在渲染里调,也不缓存到这里——缓存是宿主半的事。 */
|
|
2531
|
+
function createRootsSource(input) {
|
|
2532
|
+
return async () => {
|
|
2533
|
+
const call = input.getCall();
|
|
2534
|
+
if (typeof call !== "function") return [];
|
|
2535
|
+
try {
|
|
2536
|
+
return readRootsAnswer(await call(input.base, input.endpoint, {
|
|
2537
|
+
method: input.method,
|
|
2538
|
+
payload: {}
|
|
2539
|
+
}));
|
|
2540
|
+
} catch {
|
|
2541
|
+
return [];
|
|
2542
|
+
}
|
|
2543
|
+
};
|
|
2544
|
+
}
|
|
2545
|
+
//#endregion
|
|
2424
2546
|
//#region src/client.ts
|
|
2425
2547
|
/** dsh-life-pack client 适配器(六边形:browser 侧;爱生活单卡方案)。
|
|
2426
2548
|
*
|
|
@@ -2811,10 +2933,12 @@ window.__ModuleLoader__.load({
|
|
|
2811
2933
|
exports.canGoUp = canGoUp;
|
|
2812
2934
|
exports.createBrowseController = createBrowseController;
|
|
2813
2935
|
exports.createDirectoryRowBrowser = createDirectoryRowBrowser;
|
|
2936
|
+
exports.createRootsSource = createRootsSource;
|
|
2814
2937
|
exports.entryPath = entryPath;
|
|
2815
2938
|
exports.inject = inject;
|
|
2816
2939
|
exports.pickerModeOf = pickerModeOf;
|
|
2817
2940
|
exports.readPickAnswer = readPickAnswer;
|
|
2941
|
+
exports.readRootsAnswer = readRootsAnswer;
|
|
2818
2942
|
exports.rowsOf = rowsOf;
|
|
2819
2943
|
exports.targetOf = targetOf;
|
|
2820
2944
|
return module.exports;
|