@linxin666/dsh-remote-web-ui 0.1.14 → 0.1.15

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
@@ -2217,7 +2217,7 @@ window.__ModuleLoader__.load({
2217
2217
  }
2218
2218
  //#endregion
2219
2219
  //#region \0dsh-css:packages/dsh-remote-web-ui/src/client/settings-card.module.css.mjs
2220
- const css = ".Kwoi6G_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.Kwoi6G_card:hover{border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.Kwoi6G_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Kwoi6G_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Kwoi6G_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.Kwoi6G_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.Kwoi6G_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Kwoi6G_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Kwoi6G_chevronOpen{transform:rotate(180deg)}.Kwoi6G_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.Kwoi6G_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.Kwoi6G_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.Kwoi6G_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.Kwoi6G_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.Kwoi6G_discard,.Kwoi6G_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.Kwoi6G_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.Kwoi6G_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.Kwoi6G_discard:disabled,.Kwoi6G_save:disabled{opacity:.4;cursor:default}.Kwoi6G_discard:focus-visible,.Kwoi6G_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Kwoi6G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.Kwoi6G_field+.Kwoi6G_field{border-top:1px solid var(--dsw-alias-border-l2)}.Kwoi6G_head{align-items:center;gap:8px;display:flex}.Kwoi6G_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.Kwoi6G_badges{align-items:center;gap:8px;display:inline-flex}.Kwoi6G_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Kwoi6G_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.Kwoi6G_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Kwoi6G_reset:disabled{cursor:default}.Kwoi6G_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.Kwoi6G_input,.Kwoi6G_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Kwoi6G_input:focus-visible,.Kwoi6G_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.Kwoi6G_input:disabled,.Kwoi6G_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.Kwoi6G_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Kwoi6G_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.Kwoi6G_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.Kwoi6G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.Kwoi6G_card,.Kwoi6G_header,.Kwoi6G_chevron,.Kwoi6G_chevronOpen,.Kwoi6G_discard,.Kwoi6G_save{transition:none}}";
2220
+ const css = ".Kwoi6G_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.Kwoi6G_card:hover{border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.Kwoi6G_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.Kwoi6G_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Kwoi6G_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.Kwoi6G_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.Kwoi6G_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Kwoi6G_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.Kwoi6G_chevronOpen{transform:rotate(180deg)}.Kwoi6G_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.Kwoi6G_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.Kwoi6G_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.Kwoi6G_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.Kwoi6G_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.Kwoi6G_discard,.Kwoi6G_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.Kwoi6G_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.Kwoi6G_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.Kwoi6G_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.Kwoi6G_discard:disabled,.Kwoi6G_save:disabled{opacity:.4;cursor:default}.Kwoi6G_discard:focus-visible,.Kwoi6G_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Kwoi6G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.Kwoi6G_field+.Kwoi6G_field{border-top:1px solid var(--dsw-alias-border-l2)}.Kwoi6G_head{align-items:center;gap:8px;display:flex}.Kwoi6G_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.Kwoi6G_badges{align-items:center;gap:8px;display:inline-flex}.Kwoi6G_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.Kwoi6G_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.Kwoi6G_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Kwoi6G_reset:disabled{cursor:default}.Kwoi6G_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.Kwoi6G_input,.Kwoi6G_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Kwoi6G_input:focus-visible,.Kwoi6G_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.Kwoi6G_input:disabled,.Kwoi6G_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.Kwoi6G_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.Kwoi6G_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.Kwoi6G_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.Kwoi6G_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.Kwoi6G_card,.Kwoi6G_header,.Kwoi6G_chevron,.Kwoi6G_chevronOpen,.Kwoi6G_discard,.Kwoi6G_save{transition:none}}";
2221
2221
  const tagId = "@linxin666/dsh-remote-web-ui/settings-card.module.css";
2222
2222
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
2223
2223
  const tag = document.createElement("style");
@@ -2258,12 +2258,12 @@ window.__ModuleLoader__.load({
2258
2258
  //#endregion
2259
2259
  //#region src/client/PluginSettingsCard.tsx
2260
2260
  /**
2261
- * Shared chrome for the plugin settings card: a disclosure header naming the
2262
- * plugin and what its settings govern, the controls inside, and the save that
2263
- * writes them. Renders nothing while the namespace is unavailable — a
2261
+ * Family-shared chrome for plugin settings cards: a disclosure header naming
2262
+ * the plugin and what its settings govern, the controls inside, and the save
2263
+ * that writes them. Renders nothing while the namespace is unavailable — a
2264
2264
  * deployment that does not compose the owning plugin should show no trace of
2265
- * it. Mirrors the official ui-plugin-config PluginCard in a self-contained
2266
- * slice (this package must not depend on a sibling UI package).
2265
+ * it. Inlined into each consumer's client bundle; mirrors the official
2266
+ * ui-plugin-config PluginCard in a self-contained slice.
2267
2267
  */
2268
2268
  /**
2269
2269
  * Render one plugin settings card.
@@ -2275,6 +2275,7 @@ window.__ModuleLoader__.load({
2275
2275
  const { state } = props;
2276
2276
  if (!state.available) return null;
2277
2277
  const title = props.t(props.titleKey);
2278
+ const description = props.t(props.descriptionKey);
2278
2279
  const blocked = !state.dirty || state.invalid || state.saving;
2279
2280
  const cardClass = open ? `${settings_card_module_css_default.cardOpen} ${settings_card_module_css_default.card}` : settings_card_module_css_default.card;
2280
2281
  if (!state.exposed) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
@@ -2291,10 +2292,12 @@ window.__ModuleLoader__.load({
2291
2292
  className: settings_card_module_css_default.headText,
2292
2293
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2293
2294
  className: settings_card_module_css_default.name,
2295
+ title,
2294
2296
  children: title
2295
2297
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2296
2298
  className: settings_card_module_css_default.description,
2297
- children: props.t(props.descriptionKey)
2299
+ title: description,
2300
+ children: description
2298
2301
  })]
2299
2302
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2300
2303
  width: "14",
@@ -2332,14 +2335,17 @@ window.__ModuleLoader__.load({
2332
2335
  className: settings_card_module_css_default.headText,
2333
2336
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2334
2337
  className: settings_card_module_css_default.name,
2338
+ title,
2335
2339
  children: title
2336
2340
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2337
2341
  className: settings_card_module_css_default.description,
2338
- children: props.t(props.descriptionKey)
2342
+ title: description,
2343
+ children: description
2339
2344
  })]
2340
2345
  }),
2341
2346
  state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2342
2347
  className: settings_card_module_css_default.pending,
2348
+ title: props.t("settings.unsaved"),
2343
2349
  children: props.t("settings.unsaved")
2344
2350
  }) : null,
2345
2351
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
@@ -2494,8 +2500,9 @@ window.__ModuleLoader__.load({
2494
2500
  }
2495
2501
  //#endregion
2496
2502
  //#region src/client/settings-form.ts
2497
- /** A whole-number field. An empty draft clears the field; any other draft that is not a finite number blocks the save. */
2498
- function numberField(field) {
2503
+ /** A whole- or decimal-number field. An empty draft clears the field; any other draft that is not a finite number within the constraints blocks the save. */
2504
+ function numberField(field, constraints = {}) {
2505
+ const { integer = false, min } = constraints;
2499
2506
  return {
2500
2507
  field,
2501
2508
  format: (value) => typeof value === "number" ? String(value) : "",
@@ -2503,10 +2510,13 @@ window.__ModuleLoader__.load({
2503
2510
  const trimmed = text.trim();
2504
2511
  if (trimmed === "") return { kind: "clear" };
2505
2512
  const parsed = Number(trimmed);
2506
- return Number.isFinite(parsed) ? {
2513
+ if (!Number.isFinite(parsed)) return void 0;
2514
+ if (integer && !Number.isInteger(parsed)) return void 0;
2515
+ if (min !== void 0 && parsed < min) return void 0;
2516
+ return {
2507
2517
  kind: "set",
2508
2518
  value: parsed
2509
- } : void 0;
2519
+ };
2510
2520
  }
2511
2521
  };
2512
2522
  }
@@ -2530,11 +2540,13 @@ window.__ModuleLoader__.load({
2530
2540
  field,
2531
2541
  format: (value) => typeof value === "boolean" ? String(value) : "",
2532
2542
  parse: (text) => {
2533
- if (text === "true") return {
2543
+ const trimmed = text.trim();
2544
+ if (trimmed === "") return { kind: "clear" };
2545
+ if (trimmed === "true") return {
2534
2546
  kind: "set",
2535
2547
  value: true
2536
2548
  };
2537
- if (text === "false") return {
2549
+ if (trimmed === "false") return {
2538
2550
  kind: "set",
2539
2551
  value: false
2540
2552
  };
@@ -2636,12 +2648,13 @@ window.__ModuleLoader__.load({
2636
2648
  const plan = this.plan();
2637
2649
  const writes = plan.flatMap((item) => item.run === void 0 ? [] : [item.run]);
2638
2650
  if (plan.length === 0 || this.saving || writes.length !== plan.length) return;
2651
+ const fields = new Set(plan.map((item) => item.field));
2639
2652
  this.saving = true;
2640
2653
  this.failed = false;
2641
2654
  this.publish();
2642
2655
  let landed = true;
2643
2656
  for (const write of writes) landed = await write() && landed;
2644
- if (landed) this.staged.clear();
2657
+ if (landed) for (const field of fields) this.staged.delete(field);
2645
2658
  this.saving = false;
2646
2659
  this.failed = !landed;
2647
2660
  this.publish();